@adcp/sdk 14.0.0-beta.12 → 14.0.0-beta.13

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 (175) hide show
  1. package/dist/lib/index.d.mts +3 -3
  2. package/dist/lib/index.d.ts +3 -3
  3. package/dist/lib/index.d.ts.map +1 -1
  4. package/dist/lib/index.js +2 -0
  5. package/dist/lib/index.js.map +1 -1
  6. package/dist/lib/index.mjs +3 -1
  7. package/dist/lib/index.mjs.map +1 -1
  8. package/dist/lib/schemas-data/v2.5/_provenance.json +1 -1
  9. package/dist/lib/server/create-adcp-server.d.mts +2 -2
  10. package/dist/lib/server/create-adcp-server.d.ts +2 -2
  11. package/dist/lib/server/create-adcp-server.d.ts.map +1 -1
  12. package/dist/lib/server/create-adcp-server.js +6 -1
  13. package/dist/lib/server/create-adcp-server.js.map +1 -1
  14. package/dist/lib/server/create-adcp-server.mjs +6 -1
  15. package/dist/lib/server/create-adcp-server.mjs.map +1 -1
  16. package/dist/lib/server/decisioning/index.d.mts +3 -3
  17. package/dist/lib/server/decisioning/index.d.ts +3 -3
  18. package/dist/lib/server/decisioning/index.d.ts.map +1 -1
  19. package/dist/lib/server/decisioning/index.js.map +1 -1
  20. package/dist/lib/server/decisioning/index.mjs.map +1 -1
  21. package/dist/lib/server/decisioning/runtime/from-platform.d.mts +24 -17
  22. package/dist/lib/server/decisioning/runtime/from-platform.d.ts +24 -17
  23. package/dist/lib/server/decisioning/runtime/from-platform.d.ts.map +1 -1
  24. package/dist/lib/server/decisioning/runtime/from-platform.js +71 -42
  25. package/dist/lib/server/decisioning/runtime/from-platform.js.map +1 -1
  26. package/dist/lib/server/decisioning/runtime/from-platform.mjs +75 -43
  27. package/dist/lib/server/decisioning/runtime/from-platform.mjs.map +1 -1
  28. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.mts +15 -21
  29. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts +15 -21
  30. package/dist/lib/server/decisioning/runtime/postgres-task-registry.d.ts.map +1 -1
  31. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js +100 -30
  32. package/dist/lib/server/decisioning/runtime/postgres-task-registry.js.map +1 -1
  33. package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs +100 -30
  34. package/dist/lib/server/decisioning/runtime/postgres-task-registry.mjs.map +1 -1
  35. package/dist/lib/server/decisioning/runtime/task-registry.d.mts +30 -16
  36. package/dist/lib/server/decisioning/runtime/task-registry.d.ts +30 -16
  37. package/dist/lib/server/decisioning/runtime/task-registry.d.ts.map +1 -1
  38. package/dist/lib/server/decisioning/runtime/task-registry.js +40 -20
  39. package/dist/lib/server/decisioning/runtime/task-registry.js.map +1 -1
  40. package/dist/lib/server/decisioning/runtime/task-registry.mjs +38 -19
  41. package/dist/lib/server/decisioning/runtime/task-registry.mjs.map +1 -1
  42. package/dist/lib/server/decisioning/runtime/to-context.d.mts +2 -2
  43. package/dist/lib/server/decisioning/runtime/to-context.d.ts +2 -2
  44. package/dist/lib/server/decisioning/runtime/to-context.d.ts.map +1 -1
  45. package/dist/lib/server/decisioning/runtime/to-context.js +2 -2
  46. package/dist/lib/server/decisioning/runtime/to-context.js.map +1 -1
  47. package/dist/lib/server/decisioning/runtime/to-context.mjs +2 -2
  48. package/dist/lib/server/decisioning/runtime/to-context.mjs.map +1 -1
  49. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.mts +3 -2
  50. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts +3 -2
  51. package/dist/lib/server/decisioning/specialisms/creative-ad-server.d.ts.map +1 -1
  52. package/dist/lib/server/decisioning/specialisms/creative-ad-server.js.map +1 -1
  53. package/dist/lib/server/decisioning/specialisms/creative.d.mts +10 -10
  54. package/dist/lib/server/decisioning/specialisms/creative.d.ts +10 -10
  55. package/dist/lib/server/decisioning/specialisms/creative.d.ts.map +1 -1
  56. package/dist/lib/server/decisioning/specialisms/creative.js.map +1 -1
  57. package/dist/lib/server/index.d.mts +1 -1
  58. package/dist/lib/server/index.d.ts +1 -1
  59. package/dist/lib/server/index.d.ts.map +1 -1
  60. package/dist/lib/server/index.js.map +1 -1
  61. package/dist/lib/server/index.mjs.map +1 -1
  62. package/dist/lib/testing/storyboard/default-invariants.d.ts.map +1 -1
  63. package/dist/lib/testing/storyboard/default-invariants.js +11 -2
  64. package/dist/lib/testing/storyboard/default-invariants.js.map +1 -1
  65. package/dist/lib/testing/storyboard/default-invariants.mjs +11 -2
  66. package/dist/lib/testing/storyboard/default-invariants.mjs.map +1 -1
  67. package/dist/lib/testing/storyboard/index.d.mts +1 -1
  68. package/dist/lib/testing/storyboard/index.d.ts +1 -1
  69. package/dist/lib/testing/storyboard/index.d.ts.map +1 -1
  70. package/dist/lib/testing/storyboard/index.js.map +1 -1
  71. package/dist/lib/testing/storyboard/index.mjs.map +1 -1
  72. package/dist/lib/testing/storyboard/loader.d.ts.map +1 -1
  73. package/dist/lib/testing/storyboard/loader.js +14 -0
  74. package/dist/lib/testing/storyboard/loader.js.map +1 -1
  75. package/dist/lib/testing/storyboard/loader.mjs +14 -0
  76. package/dist/lib/testing/storyboard/loader.mjs.map +1 -1
  77. package/dist/lib/testing/storyboard/phase-condition.d.mts +41 -0
  78. package/dist/lib/testing/storyboard/phase-condition.d.ts +42 -0
  79. package/dist/lib/testing/storyboard/phase-condition.d.ts.map +1 -0
  80. package/dist/lib/testing/storyboard/phase-condition.js +215 -0
  81. package/dist/lib/testing/storyboard/phase-condition.js.map +1 -0
  82. package/dist/lib/testing/storyboard/phase-condition.mjs +189 -0
  83. package/dist/lib/testing/storyboard/phase-condition.mjs.map +1 -0
  84. package/dist/lib/testing/storyboard/request-builder.d.ts.map +1 -1
  85. package/dist/lib/testing/storyboard/request-builder.js +15 -2
  86. package/dist/lib/testing/storyboard/request-builder.js.map +1 -1
  87. package/dist/lib/testing/storyboard/request-builder.mjs +15 -2
  88. package/dist/lib/testing/storyboard/request-builder.mjs.map +1 -1
  89. package/dist/lib/testing/storyboard/runner.d.ts.map +1 -1
  90. package/dist/lib/testing/storyboard/runner.js +57 -23
  91. package/dist/lib/testing/storyboard/runner.js.map +1 -1
  92. package/dist/lib/testing/storyboard/runner.mjs +57 -23
  93. package/dist/lib/testing/storyboard/runner.mjs.map +1 -1
  94. package/dist/lib/testing/storyboard/task-map.d.ts.map +1 -1
  95. package/dist/lib/testing/storyboard/task-map.js +6 -2
  96. package/dist/lib/testing/storyboard/task-map.js.map +1 -1
  97. package/dist/lib/testing/storyboard/task-map.mjs +6 -2
  98. package/dist/lib/testing/storyboard/task-map.mjs.map +1 -1
  99. package/dist/lib/testing/storyboard/types.d.mts +5 -4
  100. package/dist/lib/testing/storyboard/types.d.ts +5 -4
  101. package/dist/lib/testing/storyboard/types.d.ts.map +1 -1
  102. package/dist/lib/testing/storyboard/types.js.map +1 -1
  103. package/dist/lib/testing/storyboard/types.mjs.map +1 -1
  104. package/dist/lib/testing/storyboard/validations.d.mts +1 -1
  105. package/dist/lib/testing/storyboard/validations.d.ts +1 -1
  106. package/dist/lib/testing/storyboard/webhook-assertions.d.ts.map +1 -1
  107. package/dist/lib/testing/storyboard/webhook-assertions.js +60 -4
  108. package/dist/lib/testing/storyboard/webhook-assertions.js.map +1 -1
  109. package/dist/lib/testing/storyboard/webhook-assertions.mjs +60 -4
  110. package/dist/lib/testing/storyboard/webhook-assertions.mjs.map +1 -1
  111. package/dist/lib/testing/storyboard/webhook-receiver.d.mts +15 -0
  112. package/dist/lib/testing/storyboard/webhook-receiver.d.ts +15 -0
  113. package/dist/lib/testing/storyboard/webhook-receiver.d.ts.map +1 -1
  114. package/dist/lib/testing/storyboard/webhook-receiver.js +57 -6
  115. package/dist/lib/testing/storyboard/webhook-receiver.js.map +1 -1
  116. package/dist/lib/testing/storyboard/webhook-receiver.mjs +57 -6
  117. package/dist/lib/testing/storyboard/webhook-receiver.mjs.map +1 -1
  118. package/dist/lib/testing/types.d.mts +2 -0
  119. package/dist/lib/testing/types.d.ts +2 -0
  120. package/dist/lib/testing/types.d.ts.map +1 -1
  121. package/dist/lib/testing/types.js.map +1 -1
  122. package/dist/lib/types/core.generated.d.mts +5 -2
  123. package/dist/lib/types/core.generated.d.ts +5 -2
  124. package/dist/lib/types/core.generated.d.ts.map +1 -1
  125. package/dist/lib/types/core.generated.js.map +1 -1
  126. package/dist/lib/types/index.d.mts +1 -1
  127. package/dist/lib/types/index.d.ts +1 -1
  128. package/dist/lib/types/index.d.ts.map +1 -1
  129. package/dist/lib/types/index.js.map +1 -1
  130. package/dist/lib/types/index.mjs.map +1 -1
  131. package/dist/lib/types/list-transformers.d.ts +9 -5
  132. package/dist/lib/types/schemas.generated.d.ts +21 -298
  133. package/dist/lib/types/schemas.generated.d.ts.map +1 -1
  134. package/dist/lib/types/schemas.generated.js +5 -2
  135. package/dist/lib/types/schemas.generated.js.map +1 -1
  136. package/dist/lib/types/schemas.generated.mjs +4 -2
  137. package/dist/lib/types/schemas.generated.mjs.map +1 -1
  138. package/dist/lib/types/server-payload-aliases.d.mts +2 -1
  139. package/dist/lib/types/server-payload-aliases.d.ts +2 -1
  140. package/dist/lib/types/server-payload-aliases.d.ts.map +1 -1
  141. package/dist/lib/types/server-payload-aliases.js.map +1 -1
  142. package/dist/lib/types/tools.generated.d.mts +5 -2
  143. package/dist/lib/types/tools.generated.d.ts +5 -2
  144. package/dist/lib/types/tools.generated.d.ts.map +1 -1
  145. package/dist/lib/types/tools.generated.js.map +1 -1
  146. package/dist/lib/utils/build-creative-return-builders.d.mts +5 -1
  147. package/dist/lib/utils/build-creative-return-builders.d.ts +5 -1
  148. package/dist/lib/utils/build-creative-return-builders.d.ts.map +1 -1
  149. package/dist/lib/utils/build-creative-return-builders.js +9 -3
  150. package/dist/lib/utils/build-creative-return-builders.js.map +1 -1
  151. package/dist/lib/utils/build-creative-return-builders.mjs +7 -2
  152. package/dist/lib/utils/build-creative-return-builders.mjs.map +1 -1
  153. package/dist/lib/utils/response-unwrapper.js +1 -1
  154. package/dist/lib/utils/response-unwrapper.js.map +1 -1
  155. package/dist/lib/utils/response-unwrapper.mjs +1 -1
  156. package/dist/lib/utils/response-unwrapper.mjs.map +1 -1
  157. package/dist/lib/validation/schema-loader.d.ts.map +1 -1
  158. package/dist/lib/validation/schema-loader.js +16 -7
  159. package/dist/lib/validation/schema-loader.js.map +1 -1
  160. package/dist/lib/validation/schema-loader.mjs +16 -7
  161. package/dist/lib/validation/schema-loader.mjs.map +1 -1
  162. package/dist/lib/version.d.mts +3 -3
  163. package/dist/lib/version.d.ts +3 -3
  164. package/dist/lib/version.js +3 -3
  165. package/dist/lib/version.js.map +1 -1
  166. package/dist/lib/version.mjs +3 -3
  167. package/dist/lib/version.mjs.map +1 -1
  168. package/docs/llms.txt +2 -2
  169. package/docs/migration-5.x-to-6.x.md +3 -2
  170. package/docs/migration-task-registry-scoping.md +61 -0
  171. package/examples/hello_seller_adapter_guaranteed.ts +1 -1
  172. package/package.json +4 -4
  173. package/skills/build-decisioning-creative-template/SKILL.md +2 -2
  174. package/skills/build-decisioning-platform/SKILL.md +4 -2
  175. package/skills/build-decisioning-platform/advanced/REFERENCE.md +7 -6
@@ -269,11 +269,12 @@ In-memory task registry refuses to construct outside `NODE_ENV=test/development`
269
269
  ```ts
270
270
  import { createPostgresTaskRegistry, getDecisioningTaskRegistryMigration } from '@adcp/sdk/server';
271
271
 
272
- await pool.query(getDecisioningTaskRegistryMigration());
272
+ const taskRegistryNamespace = 'tenant:my-agent';
273
+ await pool.query(getDecisioningTaskRegistryMigration({ namespace: taskRegistryNamespace }));
273
274
 
274
275
  createAdcpServerFromPlatform(platform, {
275
276
  name: '...', version: '...',
276
- taskRegistry: createPostgresTaskRegistry({ pool }),
277
+ taskRegistry: createPostgresTaskRegistry({ pool, namespace: taskRegistryNamespace }),
277
278
  });
278
279
  ```
279
280
 
@@ -0,0 +1,61 @@
1
+ # Task registry scope migration
2
+
3
+ Task registry reads, writes, and background waits now require the account and
4
+ authenticated owner scope that created the task. This prevents a known task ID
5
+ from crossing account or principal boundaries.
6
+
7
+ ```ts
8
+ const scope = { accountId: account.id, ownerScope: `api_key:${keyId}` };
9
+
10
+ await registry.getTask(taskId, scope);
11
+ await registry.updateProgress(taskId, scope, progress);
12
+ await registry.complete(taskId, scope, result);
13
+ await registry.fail(taskId, scope, error, failureArtifact);
14
+ await registry.awaitTask(taskId, scope);
15
+ ```
16
+
17
+ Custom `TaskRegistry` implementations must apply every scope component in the
18
+ storage query. Do not derive `ownerScope` from request parameters; use the
19
+ authenticated server context. Set `scopeVersion: 1` only after migrating those
20
+ method signatures; the platform factory rejects unmarked legacy registries so
21
+ an old `(taskId, result)` write cannot mistake the new scope argument for a
22
+ result.
23
+
24
+ `DecisioningAdcpServer.getTaskState()` and `.awaitTask()` accept the same scope.
25
+ Administrative and test code that intentionally has no buyer context can use
26
+ the explicitly named `getTaskStateUnsafe()` and `awaitTaskUnsafe()` helpers.
27
+ Unsafe reads return `null` when the same public task ID exists in more than one
28
+ scope.
29
+
30
+ PostgreSQL registries additionally require a trusted deployment or tenant
31
+ namespace:
32
+
33
+ ```ts
34
+ const taskRegistryNamespace = 'tenant:my-agent';
35
+ createPostgresTaskRegistry({
36
+ pool,
37
+ namespace: taskRegistryNamespace,
38
+ });
39
+ ```
40
+
41
+ Run the migration with that same namespace before deploying the new registry:
42
+
43
+ ```ts
44
+ await pool.query(
45
+ getDecisioningTaskRegistryMigration({ namespace: taskRegistryNamespace })
46
+ );
47
+ ```
48
+
49
+ It backfills legacy rows to the supplied registry namespace and account fallback
50
+ owner scope, then migrates the primary key to
51
+ `(registry_namespace, account_id, owner_scope, task_id)`. The namespace must be
52
+ stable across deploys and unique for every hosted tenant. A single in-memory
53
+ registry instance must likewise not be shared across tenants unless the host
54
+ includes tenant identity in both `accountId` and `ownerScope`.
55
+
56
+ The legacy table did not store a tenant identifier. If multiple hosted tenants
57
+ previously shared one legacy table, the SDK cannot infer which tenant owns each
58
+ row: the first migration would otherwise assign every legacy row to its supplied
59
+ namespace. Before migrating, drain in-flight tasks or explicitly map legacy rows
60
+ to tenant namespaces in an operator-managed migration. Do not run separate
61
+ tenant migrations over an ambiguous shared legacy table.
@@ -1355,7 +1355,7 @@ const mediaBuyStore = createMediaBuyStore({ store: stateStore });
1355
1355
  // instance persists across requests — a fresh registry per request would
1356
1356
  // lose every submitted task between create_media_buy and the buyer's
1357
1357
  // first tasks_get poll. SWAP `createInMemoryTaskRegistry()` for
1358
- // `createPostgresTaskRegistry({ pool })` in production; in-memory
1358
+ // `createPostgresTaskRegistry({ pool, namespace: tenantId })` in production; in-memory
1359
1359
  // in-flight tasks are lost on process restart.
1360
1360
  const taskRegistry = createInMemoryTaskRegistry();
1361
1361
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adcp/sdk",
3
- "version": "14.0.0-beta.12",
3
+ "version": "14.0.0-beta.13",
4
4
  "description": "AdCP SDK — client, server, and compliance harnesses for the AdContext Protocol (MCP + A2A)",
5
5
  "workspaces": [
6
6
  ".",
@@ -485,9 +485,9 @@
485
485
  "pretest": "npm run schemas:ensure",
486
486
  "test": "npm run test:node && npm test --workspace=packages/eslint-plugin --if-present && npm test --workspace=@adcp/reference-renderers",
487
487
  "test:node": "npm run test:node:fast && npm run test:node:slow",
488
- "test:node:fast": "NODE_ENV=test node --test-timeout=60000 --test-force-exit --test $(find test -maxdepth 1 -name '*.test.js' ! -name 'canonical-creatives-a2a-e2e.test.js' ! -name 'generate-zod-object-intersections.test.js' -print) $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
489
- "test:node:fast:shard": "test -n \"$TEST_SHARD\" && NODE_ENV=test node --test-timeout=60000 --test-force-exit --test-shard=$TEST_SHARD --test $(find test -maxdepth 1 -name '*.test.js' ! -name 'canonical-creatives-a2a-e2e.test.js' ! -name 'generate-zod-object-intersections.test.js' -print) $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
490
- "test:node:slow": "NODE_ENV=test node --test-timeout=180000 --test-force-exit --test test/canonical-creatives-a2a-e2e.test.js test/generate-zod-object-intersections.test.js test/lib/cli-auth-scheme.test.js test/lib/cli-soft-fail.test.js test/lib/cli-webhook-receiver-flag.test.js test/lib/conformance-cli.test.js test/lib/conformance-seeder.test.js test/lib/media-buy-lifecycle-release-gate.test.js test/lib/storyboard-notices.test.js test/lib/storyboard-requires-gate.test.js",
488
+ "test:node:fast": "NODE_ENV=test node --test-timeout=60000 --test-force-exit --test $(find test -maxdepth 1 -name '*.test.js' ! -name 'canonical-creatives-a2a-e2e.test.js' ! -name 'generate-zod-object-intersections.test.js' ! -name 'server-decisioning-from-platform.test.js' -print) $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
489
+ "test:node:fast:shard": "test -n \"$TEST_SHARD\" && NODE_ENV=test node --test-timeout=60000 --test-force-exit --test-shard=$TEST_SHARD --test $(find test -maxdepth 1 -name '*.test.js' ! -name 'canonical-creatives-a2a-e2e.test.js' ! -name 'generate-zod-object-intersections.test.js' ! -name 'server-decisioning-from-platform.test.js' -print) $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
490
+ "test:node:slow": "NODE_ENV=test node --test-timeout=180000 --test-force-exit --test test/canonical-creatives-a2a-e2e.test.js test/generate-zod-object-intersections.test.js test/server-decisioning-from-platform.test.js test/lib/cli-auth-scheme.test.js test/lib/cli-soft-fail.test.js test/lib/cli-webhook-receiver-flag.test.js test/lib/conformance-cli.test.js test/lib/conformance-seeder.test.js test/lib/media-buy-lifecycle-release-gate.test.js test/lib/storyboard-notices.test.js test/lib/storyboard-requires-gate.test.js",
491
491
  "pretest:lib": "npm run schemas:ensure",
492
492
  "test:lib": "npm run test:lib:fast && npm run test:lib:slow",
493
493
  "test:lib:fast": "NODE_ENV=test node --test-timeout=60000 --test-force-exit --test $(find test/lib -maxdepth 1 -name '*.test.js' ! -name 'cli-auth-scheme.test.js' ! -name 'cli-soft-fail.test.js' ! -name 'cli-webhook-receiver-flag.test.js' ! -name 'conformance-cli.test.js' ! -name 'conformance-seeder.test.js' ! -name 'media-buy-lifecycle-release-gate.test.js' ! -name 'storyboard-notices.test.js' ! -name 'storyboard-requires-gate.test.js' -print)",
@@ -405,7 +405,7 @@ serve(() => server, {
405
405
 
406
406
  - Calls `validatePlatform()` — throws if you advertise a specialism but don't implement it, or define both halves of a method-pair
407
407
  - Wraps each method with `AdcpError`-catch + `submitted`-envelope projection for HITL
408
- - Returns a `DecisioningAdcpServer` (extends `AdcpServer`) with `getTaskState(taskId)` + `awaitTask(taskId)` for HITL inspection
408
+ - Returns a `DecisioningAdcpServer` (extends `AdcpServer`) with scoped `getTaskState(taskId, scope)` + `awaitTask(taskId, scope)` for HITL inspection. Trusted admin/tests may use the explicitly unsafe `getTaskStateUnsafe(taskId)` + `awaitTaskUnsafe(taskId)` helpers.
409
409
 
410
410
  `serve()` accepts the server and binds HTTP transport for both MCP and A2A.
411
411
 
@@ -483,7 +483,7 @@ console.log(result.structuredContent);
483
483
 
484
484
  `dispatchTestRequest` is the canonical loop for unit-testing platform behavior without HTTP. It's available on `DecisioningAdcpServer` (the type returned by `createAdcpServerFromPlatform`). Set `validation: { requests: 'off' }` while iterating; turn it back to `strict` for end-to-end tests.
485
485
 
486
- For HITL platforms, `server.awaitTask(taskId)` settles the background promise; `server.getTaskState(taskId)` reads terminal status.
486
+ For HITL platforms, `server.awaitTask(taskId, scope)` settles the background promise; `server.getTaskState(taskId, scope)` reads terminal status. Use the `*Unsafe(taskId)` variants only in trusted admin or test code.
487
487
 
488
488
  ## What NOT to do
489
489
 
@@ -289,13 +289,15 @@ import { Pool } from 'pg';
289
289
  import { createAdcpServerFromPlatform, getAllAdcpMigrations, serve } from '@adcp/sdk/server';
290
290
 
291
291
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
292
- await pool.query(getAllAdcpMigrations()); // one DDL call, all 3 tables
292
+ const taskRegistryNamespace = 'tenant:my-agent';
293
+ await pool.query(getAllAdcpMigrations({ taskRegistryNamespace })); // one DDL call, all 3 tables
293
294
 
294
295
  const platform = new MyPlatform(myAdServer);
295
296
  const server = createAdcpServerFromPlatform(platform, {
296
297
  name: 'My Sales Agent',
297
298
  version: '1.0.0',
298
299
  pool, // wires idempotency + ctxMetadata + taskRegistry
300
+ taskRegistryNamespace,
299
301
  });
300
302
 
301
303
  serve(() => server, { port: process.env.PORT });
@@ -310,7 +312,7 @@ For dev / single-process: omit `pool` entirely. Framework defaults to in-memory
310
312
  Things you set up once at deploy time:
311
313
 
312
314
  - [ ] `DATABASE_URL` env var pointing at your Postgres instance
313
- - [ ] Run `getAllAdcpMigrations()` once per database (idempotent — safe to re-run)
315
+ - [ ] Run `getAllAdcpMigrations({ taskRegistryNamespace })` once per database with a stable, trusted namespace (idempotent — safe to re-run)
314
316
  - [ ] OAuth provider config — see `advanced/OAUTH.md` if buyers authenticate via OIDC
315
317
  - [ ] `ADCP_VERSION` env (default `3.0.0`) if pinning a specific spec version
316
318
 
@@ -267,7 +267,7 @@ sales: SalesPlatform<MyMeta> = {
267
267
  **The buyer gets terminal state two ways:**
268
268
 
269
269
  1. **Webhook push** — buyer included `push_notification_config: { url, token }` in the original request. Framework signs (RFC 9421) + delivers to that URL with the spec's `mcp-webhook-payload.json` envelope on terminal state. URL is validated server-side: rejects RFC 1918, loopback, link-local, CGNAT, IPv6 unique-local, alternate IPv4 forms, and IPv4-mapped IPv6 before delivery (SSRF guard). Bad URLs FAIL FAST with `INVALID_REQUEST` at the request boundary — buyers see their config error immediately, not as silent webhook drops.
270
- 2. **Polling** — framework auto-registers a `tasks_get` custom tool. Buyers call it with `{ task_id, account }` and receive the spec-flat lifecycle shape (`task_id`, `task_type`, `status`, `created_at`, `updated_at`, `completed_at` on terminal, `result` on completed, top-level `error: { code, message, details? }` on failed). Tenant-scoped — passes `account` through `accounts.resolve(ref, ctx)` and refuses cross-tenant probes with `REFERENCE_NOT_FOUND`. You don't write this tool; it's wired in by the framework. Programmatic access for ops / cron code is via `server.getTaskState(taskId, accountId)`.
270
+ 2. **Polling** — framework auto-registers a `tasks_get` custom tool. Buyers call it with `{ task_id, account }` and receive the spec-flat lifecycle shape (`task_id`, `task_type`, `status`, `created_at`, `updated_at`, `completed_at` on terminal, `result` on completed, top-level `error: { code, message, details? }` on failed). Tenant-scoped — passes `account` through `accounts.resolve(ref, ctx)` and refuses cross-tenant probes with `REFERENCE_NOT_FOUND`. You don't write this tool; it's wired in by the framework. Scoped application code uses `server.getTaskState(taskId, { accountId, ownerScope })`; explicitly trusted ops and test code can use `server.getTaskStateUnsafe(taskId)`.
271
271
 
272
272
  **Sync-only tools that need long-running completion** use `publishStatusChange(...)` for lifecycle updates instead of HITL. The per-tool wire response schemas don't include `Submitted` arms for `update_media_buy`, `build_creative`, `sync_catalogs`, or `get_products` (a spec inconsistency tracked as [adcp#3392](https://github.com/adcontextprotocol/adcp/issues/3392) — the Submitted schemas exist but aren't rolled into each tool's response `oneOf`). Until the spec consolidates, long-running work on those tools publishes status changes (`media_buy` → `active` → `completed`) on the event bus and buyers subscribe. When adcp#3392 lands, the SDK will widen the unified shape to `update_media_buy`, `build_creative`, and `sync_catalogs` — but NOT to `get_products` (see "Proposal generation" below).
273
273
 
@@ -528,7 +528,7 @@ Same pattern for stdio + http transports — `authenticate` runs at the transpor
528
528
 
529
529
  The framework's default in-memory `TaskRegistry` is gated by `NODE_ENV` — refuses to construct outside `{test, development}` unless `ADCP_DECISIONING_ALLOW_INMEMORY_TASKS=1` is explicitly set. Every HITL-eligible production deployment needs a durable task registry so task state survives process restarts and load-balancer failover.
530
530
 
531
- Ship `createPostgresTaskRegistry({ pool, tableName? })`:
531
+ Ship `createPostgresTaskRegistry({ pool, namespace, tableName? })`:
532
532
 
533
533
  ```ts
534
534
  import { Pool } from 'pg';
@@ -540,19 +540,20 @@ import {
540
540
 
541
541
  const pool = new Pool({ connectionString: process.env.DATABASE_URL });
542
542
 
543
- // Once at boot — idempotent CREATE TABLE IF NOT EXISTS, safe to re-run
544
- await pool.query(getDecisioningTaskRegistryMigration());
543
+ const taskRegistryNamespace = 'tenant:my-agent';
544
+ // Once at boot — idempotent and safe to re-run with the same namespace
545
+ await pool.query(getDecisioningTaskRegistryMigration({ namespace: taskRegistryNamespace }));
545
546
 
546
547
  const server = createAdcpServerFromPlatform(platform, {
547
548
  name: 'My Ad Network',
548
549
  version: '1.0.0',
549
- taskRegistry: createPostgresTaskRegistry({ pool }),
550
+ taskRegistry: createPostgresTaskRegistry({ pool, namespace: taskRegistryNamespace }),
550
551
  });
551
552
  ```
552
553
 
553
554
  Cross-instance reads work — process A allocates the task, process B reads the lifecycle for `tasks_get`. Terminal-state idempotency is enforced via SQL `WHERE status = 'submitted'` so concurrent webhook deliveries can't race to overwrite each other. Background-completion tracking (`_registerBackground`) is process-local — promises don't serialize, so production HITL flows that span process boundaries drive completion via webhook → an explicit `complete()` / `fail()` from the receiving process.
554
555
 
555
- Custom backend? Implement the `TaskRegistry` interface (8 methods) for Redis / DynamoDB / Spanner / etc. the framework awaits each call so all 4 mutators (`create`, `complete`, `fail`, `getTask`) can be storage-backed.
556
+ Custom backend? Implement the scoped `TaskRegistry` interface for Redis / DynamoDB / Spanner / etc. The framework awaits every storage method; apply both `accountId` and `ownerScope` on every read and write, then set `scopeVersion: 1`. Keep the explicitly named unsafe methods limited to trusted administrative and test paths.
556
557
 
557
558
  **Adopter `*Task` return size cap.** Postgres-backed registries cap `result` / `error` JSONB rows at 4MB. Returns over the cap surface via `onTaskTransition` with `errorCode: 'REGISTRY_WRITE_FAILED'` and skip webhook delivery (registry state is inconsistent, so the framework refuses to push). Offload large payloads to blob storage and return references in the result body instead. The cap protects the DB write path only — adopter code that serializes `result` for logs/metrics MUST impose its own bound.
558
559