@adcp/sdk 16.0.0-beta.3 → 16.0.0-beta.4

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 (182) hide show
  1. package/dist/lib/auth/oauth/diagnose.js +3 -11
  2. package/dist/lib/auth/oauth/diagnose.mjs +4 -12
  3. package/dist/lib/auth/oauth/diagnostics.d.mts +2 -1
  4. package/dist/lib/auth/oauth/diagnostics.d.ts +2 -1
  5. package/dist/lib/auth/oauth/diagnostics.js +8 -10
  6. package/dist/lib/auth/oauth/diagnostics.mjs +7 -10
  7. package/dist/lib/index.d.mts +1 -1
  8. package/dist/lib/index.d.ts +1 -1
  9. package/dist/lib/index.js +2 -0
  10. package/dist/lib/index.mjs +7 -1
  11. package/dist/lib/reporting/consumer-runtime.js +2 -1
  12. package/dist/lib/reporting/consumer-runtime.mjs +2 -1
  13. package/dist/lib/reporting/ledger/handler.js +50 -11
  14. package/dist/lib/reporting/ledger/handler.mjs +50 -12
  15. package/dist/lib/reporting/ledger/index.d.mts +17 -14
  16. package/dist/lib/reporting/ledger/index.d.ts +17 -14
  17. package/dist/lib/reporting/ledger/index.js +32 -20
  18. package/dist/lib/reporting/ledger/index.mjs +21 -10
  19. package/dist/lib/reporting/ledger/offering-validation.d.mts +9 -0
  20. package/dist/lib/reporting/ledger/offering-validation.d.ts +9 -0
  21. package/dist/lib/reporting/{gcs/bucket-policy.js → ledger/offering-validation.js} +9 -8
  22. package/dist/lib/reporting/ledger/offering-validation.mjs +8 -0
  23. package/dist/lib/reporting/ledger/receipts.d.mts +48 -0
  24. package/dist/lib/reporting/ledger/receipts.d.ts +48 -0
  25. package/dist/lib/reporting/ledger/receipts.js +186 -0
  26. package/dist/lib/reporting/ledger/receipts.mjs +161 -0
  27. package/dist/lib/reporting/ledger/status-ingest.js +3 -3
  28. package/dist/lib/reporting/ledger/status-ingest.mjs +4 -5
  29. package/dist/lib/reporting/ledger/types.d.mts +43 -0
  30. package/dist/lib/reporting/ledger/types.d.ts +43 -0
  31. package/dist/lib/reporting/ledger/types.js +31 -2
  32. package/dist/lib/reporting/ledger/types.mjs +26 -1
  33. package/dist/lib/reporting/pagination.d.mts +6 -0
  34. package/dist/lib/reporting/pagination.d.ts +6 -0
  35. package/dist/lib/reporting/{gcs/errors.js → pagination.js} +12 -17
  36. package/dist/lib/reporting/pagination.mjs +12 -0
  37. package/dist/lib/reporting/reconciliation.d.mts +1 -0
  38. package/dist/lib/reporting/reconciliation.d.ts +1 -0
  39. package/dist/lib/reporting/reconciliation.js +3 -2
  40. package/dist/lib/reporting/reconciliation.mjs +3 -2
  41. package/dist/lib/reporting/service/index.d.mts +79 -153
  42. package/dist/lib/reporting/service/index.d.ts +79 -153
  43. package/dist/lib/reporting/service/index.js +34 -491
  44. package/dist/lib/reporting/service/index.mjs +36 -510
  45. package/dist/lib/reporting/service/scheduler-support.d.mts +43 -0
  46. package/dist/lib/reporting/service/scheduler-support.d.ts +43 -0
  47. package/dist/lib/reporting/service/scheduler-support.js +125 -0
  48. package/dist/lib/reporting/service/scheduler-support.mjs +96 -0
  49. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  50. package/dist/lib/signing/canonicalize.d.mts +4 -0
  51. package/dist/lib/signing/canonicalize.d.ts +4 -0
  52. package/dist/lib/signing/canonicalize.js +14 -8
  53. package/dist/lib/signing/canonicalize.mjs +14 -8
  54. package/dist/lib/signing/content-digest.d.mts +8 -0
  55. package/dist/lib/signing/content-digest.d.ts +8 -0
  56. package/dist/lib/signing/content-digest.js +11 -5
  57. package/dist/lib/signing/content-digest.mjs +10 -5
  58. package/dist/lib/signing/signer.js +9 -6
  59. package/dist/lib/signing/signer.mjs +10 -7
  60. package/dist/lib/signing/web-bot-auth.js +103 -37
  61. package/dist/lib/signing/web-bot-auth.mjs +108 -37
  62. package/dist/lib/testing/storyboard/junit.js +16 -3
  63. package/dist/lib/testing/storyboard/junit.mjs +16 -3
  64. package/dist/lib/testing/storyboard/request-signing/builder.js +10 -9
  65. package/dist/lib/testing/storyboard/request-signing/builder.mjs +10 -9
  66. package/dist/lib/testing/storyboard/runner.js +94 -25
  67. package/dist/lib/testing/storyboard/runner.mjs +94 -25
  68. package/dist/lib/testing/storyboard/types.d.mts +6 -0
  69. package/dist/lib/testing/storyboard/types.d.ts +6 -0
  70. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  71. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  72. package/dist/lib/version.d.mts +3 -3
  73. package/dist/lib/version.d.ts +3 -3
  74. package/dist/lib/version.js +3 -3
  75. package/dist/lib/version.mjs +3 -3
  76. package/docs/TYPE-SUMMARY.md +23 -5
  77. package/docs/guides/REPORTING-GCS-FENCE.md +3 -3
  78. package/docs/guides/REPORTING-GCS-MANAGED.md +4 -4
  79. package/docs/guides/REPORTING-LEDGER-CUTOVER.md +7 -7
  80. package/docs/guides/REPORTING-LEDGER.md +107 -51
  81. package/docs/guides/REPORTING-OPERATIONS.md +66 -5
  82. package/docs/guides/REPORTING-STABILITY.md +36 -32
  83. package/docs/llms.txt +4 -3
  84. package/docs/migration-14.x-rc-worksheet.md +4 -7
  85. package/docs/migration-reporting-storage-package.md +186 -0
  86. package/examples/README.md +1 -1
  87. package/package.json +13 -78
  88. package/dist/lib/reporting/azure/index.d.mts +0 -31
  89. package/dist/lib/reporting/azure/index.d.ts +0 -31
  90. package/dist/lib/reporting/azure/index.js +0 -266
  91. package/dist/lib/reporting/azure/index.mjs +0 -249
  92. package/dist/lib/reporting/bigquery/index.d.mts +0 -246
  93. package/dist/lib/reporting/bigquery/index.d.ts +0 -246
  94. package/dist/lib/reporting/bigquery/index.js +0 -633
  95. package/dist/lib/reporting/bigquery/index.mjs +0 -594
  96. package/dist/lib/reporting/gcs/adapter.d.mts +0 -38
  97. package/dist/lib/reporting/gcs/adapter.d.ts +0 -38
  98. package/dist/lib/reporting/gcs/adapter.js +0 -342
  99. package/dist/lib/reporting/gcs/adapter.mjs +0 -325
  100. package/dist/lib/reporting/gcs/bucket-policy.d.mts +0 -3
  101. package/dist/lib/reporting/gcs/bucket-policy.d.ts +0 -3
  102. package/dist/lib/reporting/gcs/bucket-policy.mjs +0 -7
  103. package/dist/lib/reporting/gcs/errors.d.mts +0 -11
  104. package/dist/lib/reporting/gcs/errors.d.ts +0 -11
  105. package/dist/lib/reporting/gcs/errors.mjs +0 -16
  106. package/dist/lib/reporting/gcs/fence.d.mts +0 -41
  107. package/dist/lib/reporting/gcs/fence.d.ts +0 -41
  108. package/dist/lib/reporting/gcs/fence.js +0 -250
  109. package/dist/lib/reporting/gcs/fence.mjs +0 -230
  110. package/dist/lib/reporting/gcs/index.d.mts +0 -18
  111. package/dist/lib/reporting/gcs/index.d.ts +0 -18
  112. package/dist/lib/reporting/gcs/index.js +0 -44
  113. package/dist/lib/reporting/gcs/index.mjs +0 -14
  114. package/dist/lib/reporting/gcs/io.d.mts +0 -7
  115. package/dist/lib/reporting/gcs/io.d.ts +0 -7
  116. package/dist/lib/reporting/gcs/io.js +0 -95
  117. package/dist/lib/reporting/gcs/io.mjs +0 -69
  118. package/dist/lib/reporting/gcs/reader.d.mts +0 -67
  119. package/dist/lib/reporting/gcs/reader.d.ts +0 -67
  120. package/dist/lib/reporting/gcs/reader.js +0 -193
  121. package/dist/lib/reporting/gcs/reader.mjs +0 -169
  122. package/dist/lib/reporting/gcs/row-provider.d.mts +0 -39
  123. package/dist/lib/reporting/gcs/row-provider.d.ts +0 -39
  124. package/dist/lib/reporting/gcs/row-provider.js +0 -225
  125. package/dist/lib/reporting/gcs/row-provider.mjs +0 -208
  126. package/dist/lib/reporting/gcs/validation.d.mts +0 -5
  127. package/dist/lib/reporting/gcs/validation.d.ts +0 -5
  128. package/dist/lib/reporting/gcs/validation.js +0 -49
  129. package/dist/lib/reporting/gcs/validation.mjs +0 -25
  130. package/dist/lib/reporting/ledger/change-feed.d.mts +0 -69
  131. package/dist/lib/reporting/ledger/change-feed.d.ts +0 -69
  132. package/dist/lib/reporting/ledger/change-feed.js +0 -107
  133. package/dist/lib/reporting/ledger/change-feed.mjs +0 -80
  134. package/dist/lib/reporting/ledger/managed-postgres.d.mts +0 -293
  135. package/dist/lib/reporting/ledger/managed-postgres.d.ts +0 -293
  136. package/dist/lib/reporting/ledger/managed-postgres.js +0 -2346
  137. package/dist/lib/reporting/ledger/managed-postgres.mjs +0 -2332
  138. package/dist/lib/reporting/ledger/managed-router.d.mts +0 -148
  139. package/dist/lib/reporting/ledger/managed-router.d.ts +0 -148
  140. package/dist/lib/reporting/ledger/managed-router.js +0 -280
  141. package/dist/lib/reporting/ledger/managed-router.mjs +0 -258
  142. package/dist/lib/reporting/ledger/managed.d.mts +0 -535
  143. package/dist/lib/reporting/ledger/managed.d.ts +0 -535
  144. package/dist/lib/reporting/ledger/managed.js +0 -761
  145. package/dist/lib/reporting/ledger/managed.mjs +0 -729
  146. package/dist/lib/reporting/ledger/notification-activity.d.mts +0 -332
  147. package/dist/lib/reporting/ledger/notification-activity.d.ts +0 -332
  148. package/dist/lib/reporting/ledger/notification-activity.js +0 -1366
  149. package/dist/lib/reporting/ledger/notification-activity.mjs +0 -1337
  150. package/dist/lib/reporting/ledger/object-writes.d.mts +0 -128
  151. package/dist/lib/reporting/ledger/object-writes.d.ts +0 -128
  152. package/dist/lib/reporting/ledger/object-writes.js +0 -147
  153. package/dist/lib/reporting/ledger/object-writes.mjs +0 -114
  154. package/dist/lib/reporting/ledger/postgres.d.mts +0 -689
  155. package/dist/lib/reporting/ledger/postgres.d.ts +0 -689
  156. package/dist/lib/reporting/ledger/postgres.js +0 -4462
  157. package/dist/lib/reporting/ledger/postgres.mjs +0 -4462
  158. package/dist/lib/reporting/ledger/row-storage-migration.d.mts +0 -59
  159. package/dist/lib/reporting/ledger/row-storage-migration.d.ts +0 -59
  160. package/dist/lib/reporting/ledger/row-storage-migration.js +0 -365
  161. package/dist/lib/reporting/ledger/row-storage-migration.mjs +0 -339
  162. package/dist/lib/reporting/ledger/row-storage-object.d.mts +0 -203
  163. package/dist/lib/reporting/ledger/row-storage-object.d.ts +0 -203
  164. package/dist/lib/reporting/ledger/row-storage-object.js +0 -379
  165. package/dist/lib/reporting/ledger/row-storage-object.mjs +0 -335
  166. package/dist/lib/reporting/ledger/row-storage-provider-io.d.mts +0 -44
  167. package/dist/lib/reporting/ledger/row-storage-provider-io.d.ts +0 -44
  168. package/dist/lib/reporting/ledger/row-storage-provider-io.js +0 -142
  169. package/dist/lib/reporting/ledger/row-storage-provider-io.mjs +0 -111
  170. package/dist/lib/reporting/ledger/row-storage.d.mts +0 -316
  171. package/dist/lib/reporting/ledger/row-storage.d.ts +0 -316
  172. package/dist/lib/reporting/ledger/row-storage.js +0 -812
  173. package/dist/lib/reporting/ledger/row-storage.mjs +0 -802
  174. package/dist/lib/reporting/s3/index.d.mts +0 -34
  175. package/dist/lib/reporting/s3/index.d.ts +0 -34
  176. package/dist/lib/reporting/s3/index.js +0 -347
  177. package/dist/lib/reporting/s3/index.mjs +0 -340
  178. package/dist/lib/reporting/service/maintenance.d.mts +0 -148
  179. package/dist/lib/reporting/service/maintenance.d.ts +0 -148
  180. package/dist/lib/reporting/service/maintenance.js +0 -185
  181. package/dist/lib/reporting/service/maintenance.mjs +0 -159
  182. package/examples/reliable-reporting-service/README.md +0 -169
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * AdCP SDK library version
3
3
  */
4
- export declare const LIBRARY_VERSION = "16.0.0-beta.3";
4
+ export declare const LIBRARY_VERSION = "16.0.0-beta.4";
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: "16.0.0-beta.3";
36
+ readonly library: "16.0.0-beta.4";
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-15T18:57:32.995Z";
39
+ readonly generatedAt: "2026-10-16T14:15:27.258Z";
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 = "16.0.0-beta.3";
4
+ export declare const LIBRARY_VERSION = "16.0.0-beta.4";
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: "16.0.0-beta.3";
36
+ readonly library: "16.0.0-beta.4";
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-15T18:57:32.995Z";
39
+ readonly generatedAt: "2026-10-16T14:15:27.258Z";
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 = "16.0.0-beta.3";
34
+ const LIBRARY_VERSION = "16.0.0-beta.4";
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: "16.0.0-beta.3",
101
+ library: "16.0.0-beta.4",
102
102
  adcp: "3.2.4",
103
103
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
104
- generatedAt: "2026-10-15T18:57:32.995Z"
104
+ generatedAt: "2026-10-16T14:15:27.258Z"
105
105
  };
106
106
  function getAdcpVersion() {
107
107
  return ADCP_VERSION;
@@ -1,4 +1,4 @@
1
- const LIBRARY_VERSION = "16.0.0-beta.3";
1
+ const LIBRARY_VERSION = "16.0.0-beta.4";
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: "16.0.0-beta.3",
68
+ library: "16.0.0-beta.4",
69
69
  adcp: "3.2.4",
70
70
  compatibleVersions: COMPATIBLE_ADCP_VERSIONS,
71
- generatedAt: "2026-10-15T18:57:32.995Z"
71
+ generatedAt: "2026-10-16T14:15:27.258Z"
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-15
4
- > @adcp/sdk v16.0.0-beta.3
3
+ > Generated at: 2026-10-16
4
+ > @adcp/sdk v16.0.0-beta.4
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
 
@@ -2900,9 +2900,23 @@ interface InlineReportingAvailabilityEvidenceV1 {
2900
2900
 
2901
2901
  ## Seller Reporting Ledger
2902
2902
 
2903
- Ledger symbols import from `@adcp/sdk/reporting/ledger`; `createPostgresPersistentNotificationRuntime` is a server symbol and imports from `@adcp/sdk/server`.
2903
+ The ledger interface, handlers and producer import from `@adcp/sdk/reporting/ledger`. The PostgreSQL store, its migrations, row storage and maintenance import from `@adcp/reporting-storage`, managed delivery from `@adcp/reporting-storage/managed` and notification activity from `@adcp/reporting-storage/notifications` (install `@adcp/reporting-storage` next to `@adcp/sdk`; it is pre-1.0 and every export is experimental). `createPostgresPersistentNotificationRuntime` is a server symbol and imports from `@adcp/sdk/server`.
2904
2904
 
2905
2905
  ```typescript
2906
+ import { Pool } from 'pg';
2907
+ import { createPostgresPersistentNotificationRuntime } from '@adcp/sdk/server';
2908
+ import {
2909
+ createReportingDeliveryHandler,
2910
+ createReportingProducer,
2911
+ createReportingStatusHandler,
2912
+ createSyncReportingStatusHandler,
2913
+ } from '@adcp/sdk/reporting/ledger';
2914
+ import { PostgresReportingLedgerStore, REPORTING_LEDGER_MIGRATION } from '@adcp/reporting-storage';
2915
+ import {
2916
+ createPostgresReportingNotificationActivityRuntime,
2917
+ createPostgresReportingNotificationAttemptCheckpoint,
2918
+ } from '@adcp/reporting-storage/notifications';
2919
+
2906
2920
  // Build the notification path first: the store must be constructed with the
2907
2921
  // activity port, or lifecycle transitions record no activity and notify nobody.
2908
2922
  const attemptCheckpoint = createPostgresReportingNotificationAttemptCheckpoint({
@@ -2965,6 +2979,9 @@ The store freezes configuration lineage and period-end denominators, retains imm
2965
2979
  Import from `@adcp/sdk/reporting/service`. This is the adapter-first lifecycle owner over the source and ledger primitives; it does not introduce another store or transport.
2966
2980
 
2967
2981
  ```typescript
2982
+ import { createReliableReportingService } from '@adcp/sdk/reporting/service';
2983
+ import { PostgresReportingLedgerStore, reportingLedgerMaintenance } from '@adcp/reporting-storage';
2984
+
2968
2985
  interface ReliableReportingAdapterV1 {
2969
2986
  readonly sourceOffering: ReportingSourceOfferingV1;
2970
2987
  readonly deliveryOffering: ReportingDeliveryOffering;
@@ -2987,9 +3004,10 @@ const reporting = createReliableReportingService({
2987
3004
  resolveCurrency: account => currency,
2988
3005
  resolveCoverage: account => ({ constituents }), // authorized media-buy/package denominator
2989
3006
  resolveConsumerId, // optional; controls consumer-status handler/capability
3007
+ maintenance: reportingLedgerMaintenance({ retention: { enabled: true } }), // optional factory from @adcp/reporting-storage
2990
3008
  });
2991
3009
 
2992
- await pool.query(reporting.setup.migrations[0]);
3010
+ for (const sql of reporting.setup.migrations) await pool.query(sql);
2993
3011
  const installedPlatform = reporting.install(platform);
2994
3012
  await reporting.installConfiguration(configuration, { account: ctx.account });
2995
3013
  await reporting.runCycle({ accountId }); // tenant-partitioned
@@ -2999,7 +3017,7 @@ await reporting.stop();
2999
3017
 
3000
3018
  Account identity comes only from the framework-resolved context. Trusted host callbacks derive adapter routing, credential-free `sourceScope`, source timezone, currency, and the authorized constituent denominator. A declaration cannot supply `account`, `sourceScope`, `sourceTimezone`, `contract`, `currency`, `constituents`, or `mediaBuyIds`; `mediaBuyIds` is derived from `resolveCoverage`, so a buyer cannot name another buyer's media buys on a shared upstream network. Currency is frozen into configuration and obligation lineage. Capabilities are Core-only and derived from installed adapters and handlers; managed delivery, reconciled billing, receipts, webhook activity, and notifications are not advertised. Installation requires `platform.accounts.upsert`, which owns the advertised `sync_accounts` configuration path.
3001
3019
 
3002
- For complete seller production assembly, use async `createPostgresReliableReportingProductionService` from `@adcp/sdk/reporting/service`. It owns the PostgreSQL Core/Managed stores, receipts, all three reporting notifications, webhook activity, migrations, probes, recovery, and capability publication. Supply `activity.tenantScopeForAccount`; Reconciled Billing offerings also require a trusted `obligatedConsumers` roster. Its scheduler and `recoverOnce` require explicit `deploymentWide: true` because recovery scans the whole namespace. See `docs/guides/REPORTING-LEDGER.md` and `docs/guides/REPORTING-OPERATIONS.md`.
3020
+ For complete seller production assembly, use async `createPostgresReliableReportingProductionService` from `@adcp/reporting-storage/service`. It owns the PostgreSQL Core/Managed stores, receipts, all three reporting notifications, webhook activity, migrations, probes, recovery, and capability publication. Supply `activity.tenantScopeForAccount`; Reconciled Billing offerings also require a trusted `obligatedConsumers` roster. Its scheduler and `recoverOnce` require explicit `deploymentWide: true` because recovery scans the whole namespace. See `docs/guides/REPORTING-LEDGER.md` and `docs/guides/REPORTING-OPERATIONS.md`.
3003
3021
 
3004
3022
  Buyer production processes use `createPostgresReportingConsumerRuntimeV1` with `createReliableReportingConsumerV1` from the package root. Verify webhook signatures before passing authenticated hints, preserve seller/principal scope, and configure `evaluateAdjustment` to authorize integrity-valid post-official corrections; the default defers them. See `docs/guides/REPORTING-RECONCILIATION.md`.
3005
3023
 
@@ -1,12 +1,12 @@
1
1
  # Durable GCS reporting write fence
2
2
 
3
- `@adcp/sdk/reporting/gcs` provides a provider write-fence primitive backed by the existing PostgreSQL destination authority. It is a building block for a managed delivery adapter; it does not advertise Managed Delivery or Reconciled Billing capabilities or implement `ReportingManagedDeliveryAdapterV1`.
3
+ `@adcp/reporting-storage/gcs` provides a provider write-fence primitive backed by the existing PostgreSQL destination authority. It is a building block for a managed delivery adapter; it does not advertise Managed Delivery or Reconciled Billing capabilities or implement `ReportingManagedDeliveryAdapterV1`.
4
4
 
5
- Install the optional official Google client with `npm install @google-cloud/storage@^7.22.0` for Node 20 or Node 22+. Google client `^8.2.0` is also supported on Node 22+. This peer is required when compiling or using the GCS subpath, including its public types; other SDK subpaths remain independent. Apply `REPORTING_LEDGER_MIGRATION`, `REPORTING_MANAGED_DELIVERY_MIGRATION`, then the additive `REPORTING_OBJECT_WRITE_MIGRATION` from `@adcp/sdk/reporting/ledger` in the same isolated tenant schema. Apply the final migration to a fresh object-write schema if experimenting with earlier, unpublished versions of these tables: `CREATE TABLE IF NOT EXISTS` does not upgrade incompatible prerelease tables.
5
+ Install the optional official Google client with `npm install @google-cloud/storage@^7.22.0` for Node 20 or Node 22+. Google client `^8.2.0` is also supported on Node 22+. This peer is required when compiling or using the GCS subpath, including its public types; other subpaths remain independent. Apply `REPORTING_LEDGER_MIGRATION`, `REPORTING_MANAGED_DELIVERY_MIGRATION`, then the additive `REPORTING_OBJECT_WRITE_MIGRATION` from `@adcp/reporting-storage` (and `@adcp/reporting-storage/managed` for the managed-delivery one) in the same isolated tenant schema. Apply the final migration to a fresh object-write schema if experimenting with earlier, unpublished versions of these tables: `CREATE TABLE IF NOT EXISTS` does not upgrade incompatible prerelease tables.
6
6
 
7
7
  ```typescript
8
8
  import { Storage } from '@google-cloud/storage';
9
- import { createGcsReportingObjectFenceV1 } from '@adcp/sdk/reporting/gcs';
9
+ import { createGcsReportingObjectFenceV1 } from '@adcp/reporting-storage/gcs';
10
10
 
11
11
  const fence = createGcsReportingObjectFenceV1({
12
12
  storage: new Storage({ retryOptions: { totalTimeout: 60, maxRetries: 3 } }), // Host-owned ADC; retry timeout is in seconds.
@@ -1,17 +1,17 @@
1
1
  # Managed reporting delivery on GCS
2
2
 
3
- `@adcp/sdk/reporting/gcs` supplies a complete `ReportingManagedDeliveryAdapterV1` for private GCS file transfer. It supports `manifest_checksums` and `canonical_digest` by uploading deterministic JSONL and manifest bytes, then inspecting actual provider bytes and digest-pinned private contracts. The managed runtime owns materialization settlement, cleanup leases, retries and capability publication. Verification is attributed to the producer; independent buyer qualification is a separate gate.
3
+ `@adcp/reporting-storage/gcs` supplies a complete `ReportingManagedDeliveryAdapterV1` for private GCS file transfer. It supports `manifest_checksums` and `canonical_digest` by uploading deterministic JSONL and manifest bytes, then inspecting actual provider bytes and digest-pinned private contracts. The managed runtime owns materialization settlement, cleanup leases, retries and capability publication. Verification is attributed to the producer; independent buyer qualification is a separate gate.
4
4
 
5
5
  Install the optional official `@google-cloud/storage` peer. Use 7.22.x on Node 20.19 or later; Storage 8.2.x requires Node 22 or later. The default SDK import does not load Google Storage. Supply a host-owned official Storage client using ADC, workload identity or short-lived impersonation. Never persist credentials in reporting descriptors, contract URIs, `ctx_metadata`, inventory or error envelopes.
6
6
 
7
- Apply `REPORTING_LEDGER_MIGRATION`, the applicable Core writer-fence migration, `REPORTING_MANAGED_DELIVERY_MIGRATION`, `REPORTING_OBJECT_WRITE_MIGRATION`, then `REPORTING_OBJECT_WRITE_AUTHORITY_MIGRATION` from `@adcp/sdk/reporting/ledger`. The last migration requires PostgreSQL 13 or later and creates one persistent installation UUID per isolated schema. Reapplying it preserves the UUID. Keep that row in backups and restores. **Never run delivery or cleanup from an independently writable clone of live authorization, inventory or materialization tables.** Such a clone would still address the original objects. Start a fresh isolated schema with a distinct deployment namespace and installation UUID, provision new destination grants, and import only the needed immutable Core facts. A restored replica of the same authority keeps its identity. Do not replace an identity while old write plans still exist. The adapter combines the UUID with your stable deployment namespace to avoid collisions between isolated schemas sharing a bucket.
7
+ Apply `REPORTING_LEDGER_MIGRATION`, the applicable Core writer-fence migration, `REPORTING_MANAGED_DELIVERY_MIGRATION`, `REPORTING_OBJECT_WRITE_MIGRATION`, then `REPORTING_OBJECT_WRITE_AUTHORITY_MIGRATION` from `@adcp/reporting-storage` (`REPORTING_MANAGED_DELIVERY_MIGRATION` is on `@adcp/reporting-storage/managed`). The last migration requires PostgreSQL 13 or later and creates one persistent installation UUID per isolated schema. Reapplying it preserves the UUID. Keep that row in backups and restores. **Never run delivery or cleanup from an independently writable clone of live authorization, inventory or materialization tables.** Such a clone would still address the original objects. Start a fresh isolated schema with a distinct deployment namespace and installation UUID, provision new destination grants, and import only the needed immutable Core facts. A restored replica of the same authority keeps its identity. Do not replace an identity while old write plans still exist. The adapter combines the UUID with your stable deployment namespace to avoid collisions between isolated schemas sharing a bucket.
8
8
 
9
9
  Core and managed stores must share the exact same PostgreSQL pool, and Core must enable `managedDelivery: true`. The factory probes both stores and the provider policy before returning an adapter. Hosts supply pool acquisition/connect timeouts; transactions started with a signal additionally limit lock and statement waits. Readiness is bounded by the operation deadline, at most 60 seconds.
10
10
 
11
11
  ```typescript
12
12
  import { Storage } from '@google-cloud/storage';
13
- import { createGcsReportingManagedDeliveryAdapterV1 } from '@adcp/sdk/reporting/gcs';
14
- import { createReportingManagedDeliveryRuntime } from '@adcp/sdk/reporting/ledger';
13
+ import { createGcsReportingManagedDeliveryAdapterV1 } from '@adcp/reporting-storage/gcs';
14
+ import { createReportingManagedDeliveryRuntime } from '@adcp/reporting-storage/managed';
15
15
 
16
16
  const adapter = await createGcsReportingManagedDeliveryAdapterV1({
17
17
  storage: new Storage(), // ADC/workload identity; no keys in reporting state
@@ -3,7 +3,7 @@
3
3
  This guide is for a seller that already runs its own Reliable Reporting ledger
4
4
  (tables for configuration generations, obligations and revisions, row files in
5
5
  object storage and a warehouse, status issues and transitions) and wants
6
- `@adcp/sdk` to own the ledger from now on. Read the
6
+ `@adcp/sdk` and `@adcp/reporting-storage` to own the ledger from now on. Read the
7
7
  [ledger guide](REPORTING-LEDGER.md) first for the SDK side, and the
8
8
  [operations runbook](REPORTING-OPERATIONS.md) for production practice.
9
9
 
@@ -28,7 +28,7 @@ You have two ways to run the SDK's service on top of what you have.
28
28
  | Change feed | `changeFeed: true`: `changesAfter`, current-revision reads, consumer cursors | You implement it, or go without host reads and the warehouse sink |
29
29
  | Retention | `maintenance.retention`: period-aligned retirement honouring the change-feed hold | You implement `retireExpiredPeriods` and tombstones, or never retire |
30
30
  | Maintenance | `maintenance`: snapshot sweep, abandoned-upload sweep, feed pruning | You write all of it |
31
- | Warehouse | `@adcp/sdk/reporting/bigquery` sink | Not available: it reads the SDK store |
31
+ | Warehouse | `@adcp/reporting-storage/bigquery` sink | Not available: it reads the SDK store |
32
32
  | Correctness | Lease fencing, gap-free status checkpoints, immutable generations and the revision binding are enforced in one tested place | Every one of those guarantees is yours to prove |
33
33
  | Existing data | Starts empty; old tables stay behind a read-only hook | Old data served natively |
34
34
 
@@ -52,8 +52,8 @@ advertise Managed Delivery or Reconciled Billing today, read
52
52
  ```ts
53
53
  import { Pool } from 'pg';
54
54
  import { Storage } from '@google-cloud/storage';
55
- import { PostgresReportingLedgerStore } from '@adcp/sdk/reporting/ledger';
56
- import { createGcsReportingRowObjectProviderV1 } from '@adcp/sdk/reporting/gcs';
55
+ import { PostgresReportingLedgerStore, reportingLedgerMaintenance } from '@adcp/reporting-storage';
56
+ import { createGcsReportingRowObjectProviderV1 } from '@adcp/reporting-storage/gcs';
57
57
  import { createReliableReportingService } from '@adcp/sdk/reporting/service';
58
58
 
59
59
  // Apply once, in order, with your migration owner (PostgreSQL 13+):
@@ -86,10 +86,10 @@ const reporting = createReliableReportingService({
86
86
  statusRetentionDays: 90, // the commitment advertised to buyers; retention uses it
87
87
  // ...adapters, contact, resolveSource, resolveCurrency, resolveCoverage
88
88
  legacyRevisionReader, // see "The legacy fallback hook"
89
- maintenance: {
89
+ maintenance: reportingLedgerMaintenance({
90
90
  retention: { enabled: true, recordRetentionDays: 120, limit: 100 },
91
91
  changeFeed: { changeRetentionDays: 30, maxFeedHoldDays: 7 },
92
- },
92
+ }),
93
93
  });
94
94
  ```
95
95
 
@@ -118,7 +118,7 @@ state. The bytes live in your bucket.
118
118
 
119
119
  ### Keeping your BigQuery tables fed
120
120
 
121
- `@adcp/sdk/reporting/bigquery` follows the change feed and loads every
121
+ `@adcp/reporting-storage/bigquery` follows the change feed and loads every
122
122
  committed revision's verified rows into BigQuery tables you name
123
123
  ([sink details](REPORTING-LEDGER.md#bigquery-warehouse-sink)). The warehouse
124
124
  copy is derived and never served.
@@ -1,8 +1,10 @@
1
1
  # Seller Reporting Ledger
2
2
 
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.
3
+ Reliable Reporting Core turns a conforming reporting source into durable seller-side reporting. 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).
5
+ Two packages make it up. `@adcp/sdk` holds the protocol layer: the `ReportingLedgerStore` interface, the protocol handlers, the producer, `createReliableReportingService` and row encoding (`@adcp/sdk/reporting/ledger`, `@adcp/sdk/reporting/service`). [`@adcp/reporting-storage`](https://github.com/adcontextprotocol/adcp-client/blob/main/packages/reporting-storage/README.md) holds the storage behind it: the PostgreSQL ledger store and migrations, row storage and its GCS, S3 and Azure providers, managed delivery, notification activity, the BigQuery sink and the production composition. Install both (`npm install @adcp/sdk@beta @adcp/reporting-storage@beta pg` while SDK 16 is in beta). Moving from the pre-split `@adcp/sdk/reporting/*` imports? See [Reliable Reporting storage moved to `@adcp/reporting-storage`](../migration-reporting-storage-package.md).
6
+
7
+ > **Stability:** `@adcp/reporting-storage` is pre-1.0 and every export of it is experimental: breaking changes ship in its minor releases. Pin it with `~`. The store, transaction, lease and row-read interfaces in `@adcp/sdk/reporting/ledger` that it implements are `@experimental` too. See the [Reliable Reporting stability policy](REPORTING-STABILITY.md).
6
8
 
7
9
  ## Recommended: install the lifecycle service
8
10
 
@@ -13,7 +15,7 @@ producer, handlers, and decisioning-platform account resolver.
13
15
 
14
16
  ```ts
15
17
  import { Pool } from 'pg';
16
- import { PostgresReportingLedgerStore } from '@adcp/sdk/reporting/ledger';
18
+ import { PostgresReportingLedgerStore } from '@adcp/reporting-storage';
17
19
  import { createReliableReportingService } from '@adcp/sdk/reporting/service';
18
20
  import { createAdcpServerFromPlatform } from '@adcp/sdk/server';
19
21
 
@@ -53,7 +55,7 @@ const reporting = createReliableReportingService({
53
55
  },
54
56
  });
55
57
 
56
- await pool.query(reporting.setup.migrations[0]);
58
+ for (const sql of reporting.setup.migrations) await pool.query(sql);
57
59
  const installedPlatform = reporting.install(platform);
58
60
  const server = createAdcpServerFromPlatform(installedPlatform, serverOptions);
59
61
 
@@ -86,7 +88,7 @@ still use an `accountIds` roster. Production setup requires
86
88
  `activity.tenantScopeForAccount`; when an offering uses `consumer_receipt`, it
87
89
  also requires a trusted `obligatedConsumers` callback so lifecycle health can
88
90
  become reconciled only after every obligated consumer has accepted.
89
- See the [integrated seller example](../../examples/reliable-reporting-service/README.md#integrated-seller-production-service)
91
+ See the [integrated seller example](https://github.com/adcontextprotocol/adcp-client/blob/main/packages/reporting-storage/examples/reliable-reporting-service/README.md#integrated-seller-production-service)
90
92
  for the full option shape.
91
93
 
92
94
  Install a buyer declaration after the account and its media-buy scope have
@@ -135,6 +137,8 @@ import {
135
137
  PostgresReportingLedgerStore,
136
138
  REPORTING_LEDGER_MIGRATION,
137
139
  sweepExpiredReportingLedgerState,
140
+ } from '@adcp/reporting-storage';
141
+ import {
138
142
  createReportingDeliveryHandler,
139
143
  createReportingProducer,
140
144
  createReportingStatusHandler,
@@ -162,7 +166,7 @@ const getMediaBuyDelivery = createReportingDeliveryHandler(store);
162
166
  await sweepExpiredReportingLedgerState(pool);
163
167
  ```
164
168
 
165
- Pass `getReportingStatus` and `getMediaBuyDelivery` directly to the matching `createAdcpServer` slots. The delivery helper serves only exact `reporting_revision_id` reads and returns the row payload bound by the ledger revision. Advertise `media_buy.reporting_delivery` in `experimental_features` together with a `media_buy.reporting_delivery` capability whose Reliable Reporting version is `1.0` only after both handlers are wired. Configure account resolution on the server: both handlers require the framework-resolved, caller-scoped account identity and never trust a request-body identity as an authorization boundary. If two callers can name the same upstream account, the resolver must issue distinct internal account IDs for their ledger namespaces. Install immutable delivery-configuration generations through `producer.installConfiguration`, call `planObligations()` after period close, and run `runWorker()` from a durable scheduler. Multiple workers are safe: PostgreSQL claims use `SKIP LOCKED`, expiring leases, and fencing generations.
169
+ Pass `getReportingStatus` and `getMediaBuyDelivery` directly to the matching `createAdcpServer` slots. The delivery helper serves only exact `reporting_revision_id` reads and returns the row payload bound by the ledger revision. Both handlers take `pagination.max_results` as AdCP defines it, from `core/pagination-request.json`: an integer from 1 to 100, 50 when omitted. Any other value (and a `pagination` that is not an object or a `cursor` that is not a string) is refused with `VALIDATION_ERROR` (`field: 'pagination.max_results'`, `'pagination'` or `'pagination.cursor'`) before the ledger is read, so the same request behaves the same on every seller; page with `pagination.cursor`. The buyer-side walkers ask for the schema maximum, 100. Advertise `media_buy.reporting_delivery` in `experimental_features` together with a `media_buy.reporting_delivery` capability whose Reliable Reporting version is `1.0` only after both handlers are wired. Configure account resolution on the server: both handlers require the framework-resolved, caller-scoped account identity and never trust a request-body identity as an authorization boundary. If two callers can name the same upstream account, the resolver must issue distinct internal account IDs for their ledger namespaces. Install immutable delivery-configuration generations through `producer.installConfiguration`, call `planObligations()` after period close, and run `runWorker()` from a durable scheduler. Multiple workers are safe: PostgreSQL claims use `SKIP LOCKED`, expiring leases, and fencing generations.
166
170
 
167
171
  The planner supports fixed millisecond schedules and an explicit source-calendar
168
172
  day schedule. For the latter, set the existing schedule identity fields to
@@ -291,7 +295,7 @@ rows as verified canonical JSONL chunks (the shared SDK persistence layout,
291
295
  adcontextprotocol/adcp#7996):
292
296
 
293
297
  ```ts
294
- import { REPORTING_ROW_STORAGE_MIGRATION } from '@adcp/sdk/reporting/ledger';
298
+ import { REPORTING_ROW_STORAGE_MIGRATION } from '@adcp/reporting-storage';
295
299
 
296
300
  await pool.query(REPORTING_ROW_STORAGE_MIGRATION); // after REPORTING_LEDGER_MIGRATION; PostgreSQL 13+
297
301
  const store = new PostgresReportingLedgerStore(pool, {
@@ -364,7 +368,7 @@ point reads or writes at a destination the host did not configure.
364
368
  import {
365
369
  PostgresReportingLedgerStore,
366
370
  createFilesystemReportingRowObjectProviderV1,
367
- } from '@adcp/sdk/reporting/ledger';
371
+ } from '@adcp/reporting-storage';
368
372
 
369
373
  const store = new PostgresReportingLedgerStore(pool, {
370
374
  acknowledgeIsolatedDatabase: true,
@@ -462,6 +466,14 @@ await store.readyRowStorage();
462
466
  version at the recorded size is the same bytes) instead of downloading it
463
467
  while holding the account and object locks. A provider without `stat` falls
464
468
  back to reading the whole object there. All bundled providers implement it.
469
+ Also implement the optional `list({ prefix, pageToken, pageSize })`, which
470
+ returns `{ objects: [{ objectRef, nativeVersionRef, sizeBytes, createdAt }],
471
+ nextPageToken? }`: every stored version under the prefix once, in a stable
472
+ order (on a versioned store, noncurrent versions too, never delete markers),
473
+ with the version exactly as `putIfAbsent` recorded it and the time it was
474
+ written. The orphan collector needs it; a binding whose provider has no `list`
475
+ is reported as unsupported there. The conformance suite checks it (`list`) when
476
+ present. All bundled providers implement it.
465
477
 
466
478
  #### Cloud providers
467
479
 
@@ -472,12 +484,12 @@ reference fails `UNSAFE_BINDING`. Provider errors surface only as stable
472
484
  `ReportingRowStoreError` codes. Row buckets are separate from Managed Delivery
473
485
  buckets.
474
486
 
475
- **Google Cloud Storage** (`@adcp/sdk/reporting/gcs`, optional peer
487
+ **Google Cloud Storage** (`@adcp/reporting-storage/gcs`, optional peer
476
488
  `@google-cloud/storage`):
477
489
 
478
490
  ```ts
479
491
  import { Storage } from '@google-cloud/storage';
480
- import { createGcsReportingRowObjectProviderV1 } from '@adcp/sdk/reporting/gcs';
492
+ import { createGcsReportingRowObjectProviderV1 } from '@adcp/reporting-storage/gcs';
481
493
 
482
494
  const gcs = createGcsReportingRowObjectProviderV1({
483
495
  storage: new Storage(), // keyless credentials (workload identity / ADC)
@@ -500,12 +512,12 @@ const gcs = createGcsReportingRowObjectProviderV1({
500
512
  - The client needs `storage.buckets.get` for the probe plus object create, get
501
513
  and delete on the bucket.
502
514
 
503
- **Amazon S3 and S3-compatible stores** (`@adcp/sdk/reporting/s3`, optional peer
515
+ **Amazon S3 and S3-compatible stores** (`@adcp/reporting-storage/s3`, optional peer
504
516
  `@aws-sdk/client-s3`):
505
517
 
506
518
  ```ts
507
519
  import { S3Client } from '@aws-sdk/client-s3';
508
- import { createS3ReportingRowObjectProviderV1 } from '@adcp/sdk/reporting/s3';
520
+ import { createS3ReportingRowObjectProviderV1 } from '@adcp/reporting-storage/s3';
509
521
 
510
522
  const s3 = createS3ReportingRowObjectProviderV1({
511
523
  client: new S3Client({ region: 'us-east-1' }), // default credential chain
@@ -542,13 +554,13 @@ const s3 = createS3ReportingRowObjectProviderV1({
542
554
  `s3:GetBucketPolicyStatus` is optional. For stores without flexible
543
555
  checksums, construct the client with `requestChecksumCalculation: 'WHEN_REQUIRED'`.
544
556
 
545
- **Azure Blob Storage** (`@adcp/sdk/reporting/azure`, optional peer
557
+ **Azure Blob Storage** (`@adcp/reporting-storage/azure`, optional peer
546
558
  `@azure/storage-blob`):
547
559
 
548
560
  ```ts
549
561
  import { DefaultAzureCredential } from '@azure/identity';
550
562
  import { BlobServiceClient } from '@azure/storage-blob';
551
- import { createAzureBlobReportingRowObjectProviderV1 } from '@adcp/sdk/reporting/azure';
563
+ import { createAzureBlobReportingRowObjectProviderV1 } from '@adcp/reporting-storage/azure';
552
564
 
553
565
  const azure = createAzureBlobReportingRowObjectProviderV1({
554
566
  client: new BlobServiceClient('https://acmerows.blob.core.windows.net', new DefaultAzureCredential()),
@@ -677,7 +689,7 @@ an unknown ID. A revision in (a) to (d) whose content cannot be served is
677
689
  // Core-only service
678
690
  createReliableReportingService({
679
691
  // ...
680
- maintenance: { compaction: { enabled: true, limit: 100 } },
692
+ maintenance: reportingLedgerMaintenance({ compaction: { enabled: true, limit: 100 } }),
681
693
  });
682
694
 
683
695
  // Production service
@@ -751,7 +763,8 @@ and `compactSupersededSnapshots` re-check before compacting.
751
763
 
752
764
  You do not need the production service (managed delivery, notifications and
753
765
  activity) to keep a ledger tidy. Build the store with the options you want and
754
- give `createReliableReportingService` a `maintenance` option. The production
766
+ give `createReliableReportingService` a `maintenance` option built by
767
+ `reportingLedgerMaintenance` from `@adcp/reporting-storage`. The production
755
768
  service does the same work automatically; the two share one implementation, so
756
769
  partial-failure reporting, the `maxFeedHoldDays` that retention honours, per-task
757
770
  limits and abort handling are identical.
@@ -762,7 +775,8 @@ import {
762
775
  REPORTING_LEDGER_MIGRATION,
763
776
  REPORTING_ROW_STORAGE_MIGRATION,
764
777
  REPORTING_LEDGER_CHANGES_MIGRATION,
765
- } from '@adcp/sdk/reporting/ledger';
778
+ reportingLedgerMaintenance,
779
+ } from '@adcp/reporting-storage';
766
780
  import { createReliableReportingService } from '@adcp/sdk/reporting/service';
767
781
 
768
782
  // Apply the three migrations, then:
@@ -777,11 +791,11 @@ const reporting = createReliableReportingService({
777
791
  store,
778
792
  statusRetentionDays: 90, // the commitment advertised to buyers; retention uses it
779
793
  // ...adapters, contact, resolveSource, resolveCurrency, resolveCoverage
780
- maintenance: {
794
+ maintenance: reportingLedgerMaintenance({
781
795
  intervalMilliseconds: 300_000, // default: at most one pass per 5 minutes
782
796
  retention: { enabled: true, recordRetentionDays: 120, limit: 100 },
783
797
  changeFeed: { changeRetentionDays: 30, maxFeedHoldDays: 7 },
784
- },
798
+ }),
785
799
  });
786
800
 
787
801
  reporting.start({ intervalMilliseconds: 60_000, deploymentWide: true, onError });
@@ -813,12 +827,18 @@ Tasks, in order:
813
827
  | `change-feed pruning` | when `maintenance.changeFeed` is set | `pruneChanges` with `changeRetentionDays` and `maxFeedHoldDays`. |
814
828
  | `retention` | when `maintenance.retention.enabled` is `true` | `retireExpiredPeriods` with the service's `statusRetentionDays` and the feed's `maxFeedHoldDays`. |
815
829
  | `snapshot compaction` | when `maintenance.compaction.enabled` is `true` | `compactSupersededSnapshots` with the service's `statusRetentionDays` and `automatedRecoveryWindowSeconds` (see [Compacting superseded snapshots](#compacting-superseded-snapshots-opt-in)). |
830
+ | `orphan object collection` | when `maintenance.orphanCollection.enabled` is `true` | `collectOrphanedRowObjects`: lists each object binding under `{prefix}/{namespace_key}/` and deletes old objects nothing names. Opt-in, rate-limited and resumable; see [Orphaned object collection](REPORTING-OPERATIONS.md#adopting-row-storage-retention-and-the-change-feed). |
816
831
 
817
832
  Notes:
818
833
 
819
- - `maintenance` requires a `PostgresReportingLedgerStore` (or a store with the
834
+ - The service's `maintenance` option takes a factory, not an options object:
835
+ the SDK does not know what maintenance a store needs, so it calls the factory
836
+ once at construction with the store and the retention and recovery-window
837
+ commitments it advertises. `reportingLedgerMaintenance(options)` is the
838
+ PostgreSQL one. It requires a `PostgresReportingLedgerStore` (or a store with the
820
839
  same `retireExpiredPeriods`, `pruneChanges` and `sweepRowWriteIntents`
821
- methods) and fails at construction otherwise. `maintenance.changeFeed` also
840
+ methods, plus `collectOrphanedRowObjects` when `orphanCollection` is set) and
841
+ fails at construction otherwise. `maintenance.changeFeed` also
822
842
  requires `changeFeed: true` on the store, since pruning is otherwise a silent
823
843
  no-op.
824
844
  - Retention takes `statusRetentionDays` from the service, so it can never retire
@@ -838,7 +858,7 @@ In-process consumers such as pacing, alerts and warehouse loaders read from the
838
858
  ledger, never from a warehouse copy.
839
859
 
840
860
  ```ts
841
- import { REPORTING_LEDGER_CHANGES_MIGRATION } from '@adcp/sdk/reporting/ledger';
861
+ import { REPORTING_LEDGER_CHANGES_MIGRATION } from '@adcp/reporting-storage';
842
862
 
843
863
  await pool.query(REPORTING_LEDGER_CHANGES_MIGRATION); // PostgreSQL 13+
844
864
  const store = new PostgresReportingLedgerStore(pool, { acknowledgeIsolatedDatabase: true, changeFeed: true });
@@ -860,30 +880,60 @@ await store.saveFeedConsumerCursor('pacing', page.cursor); // holds back pruning
860
880
  highest-numbered snapshot. An official revision is terminal, so this is always
861
881
  one index lookup.
862
882
  - `changesAfter` lists committed obligation, revision, adjustment and retirement
863
- changes. Account feeds order by sequence. The deployment-wide feed (omit
864
- `account_id`) orders by `(xid, seq)` and returns only changes whose
865
- transaction precedes every transaction still in flight, so a slow commit is
866
- never skipped. The account feed applies the same guard: a page ends before the
867
- first change whose transaction has not finished (`xid` at or above the reading
868
- snapshot's `xmin`), so the cursor never passes a change that commits late. The
869
- page is cut there rather than filtered, because seq order and xid order can
870
- differ and a filter would hand out a later change while skipping an earlier
871
- one it excluded. The cost is that any older open transaction on the cluster,
872
- including an idle one in another database, holds both kinds of feed back until
873
- it ends; keep transactions short. An empty page therefore means either caught
874
- up or held back, so poll again rather than treating it as the end of the feed.
883
+ changes. Every feed, account-scoped or deployment-wide (omit `account_id`),
884
+ orders by `(xid, seq)` and returns only changes whose transaction precedes
885
+ every transaction still in flight (`xid` below the reading snapshot's
886
+ `xmin`), so a slow commit is never skipped. The order does not depend on the
887
+ account lock, on the order a writer drew `seq` in, or on which lock key a
888
+ writer took: a change with a lower `seq` and a higher `xid` that commits late
889
+ is simply returned on a later page, after the cursor. The cost is that any
890
+ older open transaction on the cluster, including an idle one in another
891
+ database, holds every feed back until it ends; keep transactions short. An
892
+ empty page therefore means either caught up or held back, so poll again rather
893
+ than treating it as the end of the feed. The account scan is served by the
894
+ `(account_id, xid, seq)` index that `REPORTING_LEDGER_CHANGES_MIGRATION`
895
+ creates.
875
896
  - **A ledger database has exactly one writer SDK.** The store writes each change
876
- row under the account advisory lock, taking the sequence value only after it,
877
- so per-account `seq` order equals commit order. The in-flight guard above is
878
- defense in depth, not a substitute: a second SDK (for example a Python
879
- deployment, or a hand-written writer) that takes a different lock key, or
880
- writes change rows outside the account lock, can allocate a lower `seq` that
881
- commits after a higher one. The guard narrows that window but cannot close it
882
- for every interleaving, so run one writer SDK per ledger database and give
883
- another SDK its own database. `pruneChanges` only deletes changes older than
884
- `changeRetentionDays`, far longer than any transaction should stay open, and
885
- consumer holds compare against cursors the feed itself returned, so neither
886
- adds a new ordering assumption.
897
+ row under the account advisory lock. The feed no longer needs that lock for
898
+ its order, but a second SDK is still unsupported: it can write rows the first
899
+ SDK's lifecycle, retention and idempotency logic does not know about. Give
900
+ another SDK (for example a Python deployment) its own database. `pruneChanges`
901
+ only deletes changes older than `changeRetentionDays`, far longer than any
902
+ transaction should stay open, and consumer holds compare against cursors the
903
+ feed itself returned, so neither adds an ordering assumption.
904
+ - **Upgrading from account cursors that carry only `seq`.** Account feeds used
905
+ to order by `seq` and cut each page before the first in-flight change. An old
906
+ account cursor is `{ seq }` with no `xid`. `changesAfter` accepts it and maps
907
+ it to the position `(xid, seq)` where `xid` is the smaller of the oldest `xid`
908
+ among the account's changes after that `seq` and the reading snapshot's `xmin`.
909
+ Every change after the old `seq` has an `xid` at or above both (a change that
910
+ has not committed yet belongs to a transaction at or above `xmin`), so nothing
911
+ is skipped. The cost is that changes the consumer already read can be returned
912
+ again: those with a lower `seq` and a higher `xid`, and, when a long
913
+ transaction was open at that moment, every change committed since it began.
914
+ Treat redelivery as normal, as for any at-least-once consumer. The returned cursor is in the new
915
+ format, even on an empty page. A legacy cursor fails with `CURSOR_EXPIRED` if
916
+ any change with a higher `seq` was pruned (`adcp_reporting_change_account_horizon.pruned_through_seq`
917
+ still records the highest pruned `seq` for this check). A consumer row saved
918
+ before the upgrade has a NULL `cursor_xid` and holds retention by `seq` until
919
+ the consumer saves its next cursor; `saveFeedConsumerCursor` given a legacy
920
+ cursor maps it the same way. Re-apply `REPORTING_LEDGER_CHANGES_MIGRATION`
921
+ before starting the new binary: it adds the account horizon's `xid` columns,
922
+ replaces the consumer table's check constraint, and creates the new index. On
923
+ a large changes table, create the index first with `CREATE INDEX CONCURRENTLY
924
+ IF NOT EXISTS adcp_reporting_changes_account_xid ON adcp_reporting_changes
925
+ (account_id, xid, seq)`, because a plain `CREATE INDEX` blocks appends while it
926
+ builds; the migration then skips it. The older
927
+ `adcp_reporting_changes_account (account_id, seq)` index is left in place and
928
+ serves the legacy-cursor mapping; drop it once no legacy cursor remains.
929
+ - **Do not run the old and new SDK's change-feed maintenance together.** An older
930
+ host's `pruneChanges`, `retireExpiredPeriods` and compaction hold an account
931
+ consumer's changes by `seq` alone and record only `pruned_through_seq`, so
932
+ against a consumer that holds new-format cursors they can prune a change the
933
+ consumer has not read and never advance the horizon the new reader checks.
934
+ Stop the older hosts' maintenance (or the hosts) before the new binary reads
935
+ the feed. Rolling back is not supported once a consumer has saved a new-format
936
+ account cursor: the older SDK rejects it, so reset those consumers.
887
937
  - `pruneChanges` deletes changes older than `changeRetentionDays` (default 30)
888
938
  that every consumer updated within `maxFeedHoldDays` (default 7) has passed.
889
939
  An older cursor throws `ReportingChangeCursorExpiredError`; resynchronize from
@@ -918,7 +968,7 @@ await store.saveFeedConsumerCursor('pacing', page.cursor); // holds back pruning
918
968
 
919
969
  ### BigQuery warehouse sink
920
970
 
921
- `@adcp/sdk/reporting/bigquery` loads committed revisions into your own BigQuery
971
+ `@adcp/reporting-storage/bigquery` loads committed revisions into your own BigQuery
922
972
  tables for analysts. The warehouse copy is derived and non-authoritative. It
923
973
  is never read for serving or verification, so its table names, columns,
924
974
  partitioning and retention are yours.
@@ -928,7 +978,7 @@ import { BigQuery } from '@google-cloud/bigquery';
928
978
  import {
929
979
  REPORTING_WAREHOUSE_SINK_MIGRATION,
930
980
  createBigQueryReportingWarehouseSinkV1,
931
- } from '@adcp/sdk/reporting/bigquery';
981
+ } from '@adcp/reporting-storage/bigquery';
932
982
 
933
983
  await pool.query(REPORTING_WAREHOUSE_SINK_MIGRATION); // after REPORTING_LEDGER_CHANGES_MIGRATION
934
984
  const bigquery = new BigQuery({ projectId: 'analytics-prod' }); // ADC / workload identity
@@ -1109,9 +1159,13 @@ Core remains the default and has no destination, external-resource, or receipt d
1109
1159
  ```ts
1110
1160
  import {
1111
1161
  PostgresReportingLedgerStore,
1162
+ } from '@adcp/reporting-storage';
1163
+ import {
1112
1164
  PostgresReportingManagedDeliveryStore,
1113
1165
  REPORTING_MANAGED_DELIVERY_MIGRATION,
1114
1166
  createReportingManagedDeliveryRuntime,
1167
+ } from '@adcp/reporting-storage/managed';
1168
+ import {
1115
1169
  reportingManagedDeliveryBindingV1,
1116
1170
  } from '@adcp/sdk/reporting/ledger';
1117
1171
 
@@ -1182,7 +1236,7 @@ A seller often delivers one feed through several transports: one buyer takes fil
1182
1236
  import {
1183
1237
  createReportingManagedDeliveryAdapterRouterV1,
1184
1238
  createReportingManagedDeliveryRuntime,
1185
- } from '@adcp/sdk/reporting/ledger';
1239
+ } from '@adcp/reporting-storage/managed';
1186
1240
 
1187
1241
  const adapter = createReportingManagedDeliveryAdapterRouterV1({
1188
1242
  routes: [
@@ -1262,12 +1316,14 @@ only for health changes:
1262
1316
  ```ts
1263
1317
  import { createPostgresPersistentNotificationRuntime } from '@adcp/sdk/server';
1264
1318
  import {
1265
- createPostgresReportingNotificationActivityRuntime,
1266
- createPostgresReportingNotificationAttemptCheckpoint,
1267
1319
  PostgresReportingLedgerStore,
1268
1320
  REPORTING_LEDGER_FINALITY_WRITER_FENCE_MIGRATION,
1269
1321
  REPORTING_LEDGER_MIGRATION,
1270
- } from '@adcp/sdk/reporting/ledger';
1322
+ } from '@adcp/reporting-storage';
1323
+ import {
1324
+ createPostgresReportingNotificationActivityRuntime,
1325
+ createPostgresReportingNotificationAttemptCheckpoint,
1326
+ } from '@adcp/reporting-storage/notifications';
1271
1327
 
1272
1328
  // Build the durable pre-POST checkpoint first. The notification runtime needs
1273
1329
  // it, and the activity runtime verifies it targets the same durable store —