@empire-builder-kit/nx 1.0.0-rc.37 → 1.0.0-rc.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (637) hide show
  1. package/README.md +18 -0
  2. package/executors.json +5 -0
  3. package/generators.json +10 -0
  4. package/package.json +20 -3
  5. package/src/aws-authority/index.d.ts +1 -0
  6. package/src/aws-authority/index.js +1 -0
  7. package/src/aws-authority/lambda-policy-ordering.d.ts +38 -0
  8. package/src/aws-authority/lambda-policy-ordering.js +56 -0
  9. package/src/aws-authority/stage-authority.d.ts +11 -3
  10. package/src/aws-authority/stage-authority.js +615 -29
  11. package/src/blueprints/external-sandbox.js +21 -9
  12. package/src/blueprints/manifest.d.ts +1 -1
  13. package/src/blueprints/resolver.js +28 -15
  14. package/src/cli/bootstrap.d.ts +1 -1
  15. package/src/cli/deploy-runtime.d.ts +6 -0
  16. package/src/cli/deploy-runtime.js +58 -0
  17. package/src/cli/dev-command.d.ts +16 -4
  18. package/src/cli/dev-command.js +63 -0
  19. package/src/cli/main.d.ts +7 -1
  20. package/src/cli/main.js +128 -20
  21. package/src/cli/output.d.ts +1 -1
  22. package/src/developer-agent/context.js +41 -9
  23. package/src/developer-agent/generator-planning.js +16 -2
  24. package/src/developer-agent/git-inspection.d.ts +6 -2
  25. package/src/developer-agent/git-inspection.js +78 -6
  26. package/src/developer-agent/model.d.ts +4 -2
  27. package/src/developer-agent/operation-registry.d.ts +5 -0
  28. package/src/developer-agent/operation-registry.js +179 -23
  29. package/src/developer-agent/preview-changes.d.ts +2 -0
  30. package/src/developer-agent/preview-changes.js +14 -2
  31. package/src/developer-agent/preview-source.js +3 -0
  32. package/src/developer-agent/validation.js +20 -8
  33. package/src/developer-agent/workspace-inspection.js +37 -3
  34. package/src/executors/deployment-plan/deployment-plan.d.ts +2 -0
  35. package/src/executors/deployment-plan/deployment-plan.js +51 -4
  36. package/src/executors/dev-doctor/dev-doctor.js +13 -6
  37. package/src/executors/dev-task-cleanup/dev-task-cleanup.d.ts +23 -0
  38. package/src/executors/dev-task-cleanup/dev-task-cleanup.js +145 -0
  39. package/src/executors/dev-task-cleanup/schema.json +9 -0
  40. package/src/executors/dev-task-cleanup/task-stack-absence.d.ts +27 -0
  41. package/src/executors/dev-task-cleanup/task-stack-absence.js +281 -0
  42. package/src/executors/dev-task-cleanup/task-stack-checkpoint.d.ts +12 -0
  43. package/src/executors/dev-task-cleanup/task-stack-checkpoint.js +92 -0
  44. package/src/executors/fleet/fleet.js +1 -1
  45. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js +28 -1
  46. package/src/executors/local-deploy/local-deploy.d.ts +8 -1
  47. package/src/executors/local-deploy/local-deploy.js +97 -24
  48. package/src/executors/local-deploy/schema.json +8 -0
  49. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js +30 -18
  50. package/src/executors/sst-lifecycle/governed-native-operation.d.ts +2 -0
  51. package/src/executors/sst-lifecycle/governed-native-operation.js +9 -0
  52. package/src/executors/sst-lifecycle/run-sst-command.d.ts +5 -0
  53. package/src/executors/sst-lifecycle/run-sst-command.js +220 -32
  54. package/src/executors/sst-lifecycle/sst-environment-source.d.ts +8 -0
  55. package/src/executors/sst-lifecycle/sst-environment-source.js +54 -0
  56. package/src/executors/sst-lifecycle/task-unlock.d.ts +15 -0
  57. package/src/executors/sst-lifecycle/task-unlock.js +126 -0
  58. package/src/foundation/capability-plan.d.ts +43 -0
  59. package/src/foundation/capability-plan.js +168 -0
  60. package/src/foundation/discovery.d.ts +14 -11
  61. package/src/foundation/discovery.js +32 -6
  62. package/src/foundation/index.d.ts +1 -0
  63. package/src/foundation/index.js +1 -0
  64. package/src/foundation/local-database-contract.d.ts +20 -0
  65. package/src/foundation/local-database-contract.js +262 -13
  66. package/src/foundation/local-private-smoke-access.d.ts +20 -0
  67. package/src/foundation/local-private-smoke-access.js +197 -0
  68. package/src/foundation/preflight.js +37 -18
  69. package/src/foundation/private-smoke-access.js +10 -2
  70. package/src/foundation/private-smoke-admission.d.ts +3 -1
  71. package/src/foundation/private-smoke-admission.js +29 -8
  72. package/src/foundation/private-smoke-control-plane.js +17 -6
  73. package/src/foundation/provision-database-bindings.d.ts +5 -0
  74. package/src/foundation/provision-database-bindings.js +41 -8
  75. package/src/foundation/provision-logical-database.js +13 -8
  76. package/src/foundation/requirements.d.ts +3 -3
  77. package/src/foundation/requirements.js +24 -12
  78. package/src/foundation/router-waf.d.ts +1 -0
  79. package/src/foundation/router-waf.js +14 -1
  80. package/src/generators/blueprint/blueprint.d.ts +5 -0
  81. package/src/generators/blueprint/blueprint.js +102 -0
  82. package/src/generators/blueprint/files.d.ts +6 -0
  83. package/src/generators/blueprint/files.js +217 -0
  84. package/src/generators/blueprint/schema.d.ts +4 -0
  85. package/src/generators/blueprint/schema.json +18 -0
  86. package/src/generators/formatting.js +24 -1
  87. package/src/generators/logging-registry.d.ts +2 -0
  88. package/src/generators/logging-registry.js +22 -0
  89. package/src/generators/preset/workspace-files-adopter-skills.d.ts +7 -0
  90. package/src/generators/preset/workspace-files-adopter-skills.js +301 -0
  91. package/src/generators/preset/workspace-files-ci-install.d.ts +2 -0
  92. package/src/generators/preset/workspace-files-ci-install.js +196 -0
  93. package/src/generators/preset/workspace-files-developer-agent.js +40 -13
  94. package/src/generators/preset/workspace-files-performance-load.js +8 -0
  95. package/src/generators/preset/workspace-files-stage-authority.js +40 -1
  96. package/src/generators/preset/workspace-files-thin-deploy.js +66 -34
  97. package/src/generators/preset/workspace-files-thin-docs.js +64 -18
  98. package/src/generators/preset/workspace-files.d.ts +4 -0
  99. package/src/generators/preset/workspace-files.js +159 -91
  100. package/src/generators/repository-policy/repository-policy.js +37 -0
  101. package/src/generators/slice/built-in-plan-api-contract-files.js +42 -7
  102. package/src/generators/slice/built-in-plan-api-files.d.ts +1 -1
  103. package/src/generators/slice/built-in-plan-api-files.js +47 -389
  104. package/src/generators/slice/built-in-plan-async-work-files.js +19 -1912
  105. package/src/generators/slice/built-in-plan-authorization-files.js +92 -329
  106. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js +36 -2
  107. package/src/generators/slice/built-in-plan-authorization-storage.d.ts +3 -0
  108. package/src/generators/slice/built-in-plan-authorization-storage.js +119 -0
  109. package/src/generators/slice/built-in-plan-background-work-files.d.ts +1 -1
  110. package/src/generators/slice/built-in-plan-background-work-files.js +15 -5
  111. package/src/generators/slice/built-in-plan-data-deletion-files.js +2 -830
  112. package/src/generators/slice/built-in-plan-data-files.d.ts +1 -1
  113. package/src/generators/slice/built-in-plan-data-files.js +61 -1164
  114. package/src/generators/slice/built-in-plan-data-lifecycle-files.js +53 -28
  115. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js +18 -2
  116. package/src/generators/slice/built-in-plan-data-retention-job-files.js +7 -2446
  117. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js +30 -6
  118. package/src/generators/slice/built-in-plan-data-rights-files.js +6 -4482
  119. package/src/generators/slice/built-in-plan-database-lifecycle-files.js +4 -15
  120. package/src/generators/slice/built-in-plan-foundation-files.d.ts +2 -1
  121. package/src/generators/slice/built-in-plan-foundation-files.js +34 -10
  122. package/src/generators/slice/built-in-plan-frontend-files.js +2 -2
  123. package/src/generators/slice/built-in-plan-infrastructure-files.d.ts +1 -1
  124. package/src/generators/slice/built-in-plan-infrastructure-files.js +180 -522
  125. package/src/generators/slice/built-in-plan-key-value-cleanup.d.ts +4 -0
  126. package/src/generators/slice/built-in-plan-key-value-cleanup.js +100 -0
  127. package/src/generators/slice/built-in-plan-key-value-consumer.d.ts +4 -0
  128. package/src/generators/slice/built-in-plan-key-value-consumer.js +151 -0
  129. package/src/generators/slice/built-in-plan-key-value-deletion.d.ts +2 -0
  130. package/src/generators/slice/built-in-plan-key-value-deletion.js +377 -0
  131. package/src/generators/slice/built-in-plan-key-value-delivery.d.ts +2 -0
  132. package/src/generators/slice/built-in-plan-key-value-delivery.js +120 -0
  133. package/src/generators/slice/built-in-plan-key-value-export.d.ts +2 -0
  134. package/src/generators/slice/built-in-plan-key-value-export.js +595 -0
  135. package/src/generators/slice/built-in-plan-key-value-files.d.ts +2 -0
  136. package/src/generators/slice/built-in-plan-key-value-files.js +31 -0
  137. package/src/generators/slice/built-in-plan-key-value-holds.d.ts +2 -0
  138. package/src/generators/slice/built-in-plan-key-value-holds.js +189 -0
  139. package/src/generators/slice/built-in-plan-key-value-infrastructure.d.ts +2 -0
  140. package/src/generators/slice/built-in-plan-key-value-infrastructure.js +102 -0
  141. package/src/generators/slice/built-in-plan-key-value-performance.d.ts +5 -0
  142. package/src/generators/slice/built-in-plan-key-value-performance.js +530 -0
  143. package/src/generators/slice/built-in-plan-key-value-provider.d.ts +4 -0
  144. package/src/generators/slice/built-in-plan-key-value-provider.js +366 -0
  145. package/src/generators/slice/built-in-plan-key-value-records.d.ts +3 -0
  146. package/src/generators/slice/built-in-plan-key-value-records.js +232 -0
  147. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.d.ts +2 -0
  148. package/src/generators/slice/built-in-plan-key-value-retention-infrastructure.js +103 -0
  149. package/src/generators/slice/built-in-plan-key-value-retention-job-files.d.ts +2 -0
  150. package/src/generators/slice/built-in-plan-key-value-retention-job-files.js +160 -0
  151. package/src/generators/slice/built-in-plan-key-value-retention-maintenance.d.ts +2 -0
  152. package/src/generators/slice/built-in-plan-key-value-retention-maintenance.js +329 -0
  153. package/src/generators/slice/built-in-plan-key-value-retention-worker.d.ts +2 -0
  154. package/src/generators/slice/built-in-plan-key-value-retention-worker.js +477 -0
  155. package/src/generators/slice/built-in-plan-key-value-retention.d.ts +2 -0
  156. package/src/generators/slice/built-in-plan-key-value-retention.js +184 -0
  157. package/src/generators/slice/built-in-plan-metadata-files.d.ts +1 -1
  158. package/src/generators/slice/built-in-plan-metadata-files.js +140 -28
  159. package/src/generators/slice/built-in-plan-native-runtime-authority-files.d.ts +1 -1
  160. package/src/generators/slice/built-in-plan-native-runtime-authority-files.js +36 -19
  161. package/src/generators/slice/built-in-plan-operations-files.d.ts +1 -1
  162. package/src/generators/slice/built-in-plan-operations-files.js +89 -50
  163. package/src/generators/slice/built-in-plan-performance-files.js +84 -1010
  164. package/src/generators/slice/built-in-plan-project-files.js +116 -67
  165. package/src/generators/slice/built-in-plan-release-files.d.ts +1 -1
  166. package/src/generators/slice/built-in-plan-release-files.js +64 -15
  167. package/src/generators/slice/built-in-plan-reliability-files.js +54 -28
  168. package/src/generators/slice/built-in-plan-shared.d.ts +4 -2
  169. package/src/generators/slice/built-in-plan-shared.js +41 -19
  170. package/src/generators/slice/built-in-plan-sql-events.d.ts +2 -0
  171. package/src/generators/slice/built-in-plan-sql-events.js +257 -0
  172. package/src/generators/slice/built-in-plan-testing-files.d.ts +1 -1
  173. package/src/generators/slice/built-in-plan-testing-files.js +184 -132
  174. package/src/generators/slice/built-in-plan-testing-persistence-files.d.ts +2 -0
  175. package/src/generators/slice/built-in-plan-testing-persistence-files.js +178 -0
  176. package/src/generators/slice/built-in-plan-thin-release-files.d.ts +1 -1
  177. package/src/generators/slice/built-in-plan-thin-release-files.js +35 -2
  178. package/src/generators/slice/built-in-plan-verification-files.js +70 -0
  179. package/src/generators/slice/built-in-plan-web-files.d.ts +1 -1
  180. package/src/generators/slice/built-in-plan-web-files.js +206 -14
  181. package/src/generators/slice/built-in-plan-workload-role-files.d.ts +1 -1
  182. package/src/generators/slice/built-in-plan-workload-role-files.js +113 -274
  183. package/src/generators/slice/built-in-plan.d.ts +9 -1
  184. package/src/generators/slice/built-in-plan.js +49 -21
  185. package/src/generators/slice/data-policy-review-seed.d.ts +2 -0
  186. package/src/generators/slice/data-policy-review-seed.js +22 -0
  187. package/src/generators/slice/deployed-smoke-readiness.d.ts +2 -0
  188. package/src/generators/slice/deployed-smoke-readiness.js +214 -0
  189. package/src/generators/slice/local-source-identity.d.ts +2 -0
  190. package/src/generators/slice/local-source-identity.js +31 -0
  191. package/src/generators/slice/persistence-contract.d.ts +14 -0
  192. package/src/generators/slice/persistence-contract.js +32 -0
  193. package/src/generators/slice/slice.js +29 -24
  194. package/src/generators/sql/schema.d.ts +7 -0
  195. package/src/generators/sql/schema.json +38 -0
  196. package/src/generators/sql/sql.d.ts +6 -0
  197. package/src/generators/sql/sql.js +53 -0
  198. package/src/generators/upgrade/sql-seeded-reconciliation.d.ts +2 -0
  199. package/src/generators/upgrade/sql-seeded-reconciliation.js +170 -0
  200. package/src/generators/upgrade/upgrade.d.ts +2 -0
  201. package/src/generators/upgrade/upgrade.js +136 -9
  202. package/src/generators/workload/workload.js +51 -2
  203. package/src/local-dev/browser-verification.d.ts +37 -0
  204. package/src/local-dev/browser-verification.js +281 -0
  205. package/src/local-dev/contracts.d.ts +10 -1
  206. package/src/local-dev/contracts.js +114 -13
  207. package/src/local-dev/dev-command-core.js +24 -5
  208. package/src/local-dev/docker-credential-health.d.ts +14 -0
  209. package/src/local-dev/docker-credential-health.js +94 -0
  210. package/src/local-dev/environment-inspector.d.ts +7 -0
  211. package/src/local-dev/environment-inspector.js +42 -15
  212. package/src/local-dev/environment-state.js +2 -2
  213. package/src/local-dev/errors.d.ts +1 -1
  214. package/src/local-dev/errors.js +2 -0
  215. package/src/local-dev/fleet-client.js +2 -2
  216. package/src/local-dev/fleet-configuration.js +57 -25
  217. package/src/local-dev/fleet-inventory.js +46 -18
  218. package/src/local-dev/fleet-ipc.d.ts +7 -0
  219. package/src/local-dev/fleet-ipc.js +14 -2
  220. package/src/local-dev/fleet-launcher.d.ts +6 -0
  221. package/src/local-dev/fleet-launcher.js +14 -2
  222. package/src/local-dev/fleet-logs.js +50 -22
  223. package/src/local-dev/fleet-process.d.ts +20 -1
  224. package/src/local-dev/fleet-process.js +197 -41
  225. package/src/local-dev/fleet-runner-evidence.d.ts +5 -0
  226. package/src/local-dev/fleet-runner-evidence.js +56 -0
  227. package/src/local-dev/fleet-runtime.js +268 -229
  228. package/src/local-dev/fleet-session.d.ts +2 -0
  229. package/src/local-dev/fleet-session.js +28 -11
  230. package/src/local-dev/fleet-slice-runner-daemon.js +4 -0
  231. package/src/local-dev/fleet-state.d.ts +5 -2
  232. package/src/local-dev/fleet-state.js +25 -4
  233. package/src/local-dev/fleet-supervisor.d.ts +3 -0
  234. package/src/local-dev/fleet-supervisor.js +66 -11
  235. package/src/local-dev/fleet-web-start.d.ts +12 -0
  236. package/src/local-dev/fleet-web-start.js +48 -0
  237. package/src/local-dev/identity.js +3 -14
  238. package/src/local-dev/index.d.ts +1 -0
  239. package/src/local-dev/index.js +1 -0
  240. package/src/local-dev/native-completion.d.ts +9 -0
  241. package/src/local-dev/native-completion.js +130 -0
  242. package/src/local-dev/nx-workspace.d.ts +4 -2
  243. package/src/local-dev/nx-workspace.js +11 -6
  244. package/src/local-dev/personal-stage.d.ts +4 -5
  245. package/src/local-dev/personal-stage.js +6 -54
  246. package/src/local-dev/port-claims.d.ts +13 -0
  247. package/src/local-dev/port-claims.js +46 -0
  248. package/src/local-dev/ports.d.ts +14 -2
  249. package/src/local-dev/ports.js +78 -3
  250. package/src/local-dev/private-state.d.ts +6 -0
  251. package/src/local-dev/private-state.js +126 -34
  252. package/src/local-dev/process-group.d.ts +4 -0
  253. package/src/local-dev/process-group.js +29 -0
  254. package/src/local-dev/process-identity.d.ts +8 -0
  255. package/src/local-dev/process-identity.js +31 -1
  256. package/src/local-dev/proxy.js +11 -12
  257. package/src/local-dev/runtime-paths.js +1 -1
  258. package/src/local-dev/slice-claim.js +1 -1
  259. package/src/local-dev/slice-runner.d.ts +15 -6
  260. package/src/local-dev/slice-runner.js +189 -54
  261. package/src/local-dev/task-attachment.d.ts +17 -0
  262. package/src/local-dev/task-attachment.js +73 -0
  263. package/src/local-dev/task-authority.d.ts +10 -0
  264. package/src/local-dev/task-authority.js +27 -0
  265. package/src/local-dev/task-identity.d.ts +33 -0
  266. package/src/local-dev/task-identity.js +418 -0
  267. package/src/local-dev/task-native-writer.d.ts +18 -0
  268. package/src/local-dev/task-native-writer.js +329 -0
  269. package/src/local-dev/tls.js +3 -1
  270. package/src/local-dev/web-launch.d.ts +9 -0
  271. package/src/local-dev/web-launch.js +130 -0
  272. package/src/ownership/composition.d.ts +2 -1
  273. package/src/ownership/composition.js +1 -0
  274. package/src/performance/scenario.d.ts +22 -0
  275. package/src/performance/scenario.js +100 -92
  276. package/src/repository-policy/deployment-plan.d.ts +2 -2
  277. package/src/repository-policy/deployment-plan.js +2 -1
  278. package/src/repository-policy/policy.js +38 -3
  279. package/src/schemas/blueprint-v1.json +5 -4
  280. package/src/schemas/foundation-requirement-v1.json +5 -4
  281. package/src/schemas/testing-evidence-result-v1.json +1 -1
  282. package/src/secrets/operator.d.ts +3 -1
  283. package/src/secrets/operator.js +22 -3
  284. package/src/sst-environment-source-format.d.ts +3 -0
  285. package/src/sst-environment-source-format.js +20 -0
  286. package/src/supply-chain/blueprint-trust-git.js +13 -3
  287. package/src/supply-chain/build-output.js +15 -0
  288. package/src/supply-chain/generated-blueprint-trust-command.js +18 -1
  289. package/src/testing-evidence/fixture-scope.d.ts +2 -1
  290. package/src/testing-evidence/fixture-scope.js +4 -2
  291. package/src/testing-evidence/result.d.ts +2 -1
  292. package/src/testing-evidence/result.js +18 -4
  293. package/src/workload-roles/standard-slice.js +2 -3
  294. package/src/api-contract/baseline-update.js.map +0 -1
  295. package/src/api-contract/compatibility.js.map +0 -1
  296. package/src/api-contract/contract-graph.js.map +0 -1
  297. package/src/api-contract/evidence.js.map +0 -1
  298. package/src/api-contract/index.js.map +0 -1
  299. package/src/api-contract/model.fixtures.d.ts +0 -2
  300. package/src/api-contract/model.fixtures.js +0 -81
  301. package/src/api-contract/model.fixtures.js.map +0 -1
  302. package/src/api-contract/model.js.map +0 -1
  303. package/src/api-contract/rollout.js.map +0 -1
  304. package/src/authorization/compatibility.js.map +0 -1
  305. package/src/authorization/index.js.map +0 -1
  306. package/src/aws/child-environment.js.map +0 -1
  307. package/src/aws/identity.js.map +0 -1
  308. package/src/aws-authority/index.js.map +0 -1
  309. package/src/aws-authority/stage-authority.js.map +0 -1
  310. package/src/blueprints/execution.js.map +0 -1
  311. package/src/blueprints/external-sandbox.js.map +0 -1
  312. package/src/blueprints/index.js.map +0 -1
  313. package/src/blueprints/inputs.js.map +0 -1
  314. package/src/blueprints/manifest.js.map +0 -1
  315. package/src/blueprints/resolver.js.map +0 -1
  316. package/src/blueprints/transitions.js.map +0 -1
  317. package/src/cli/agent-command.js.map +0 -1
  318. package/src/cli/agent-runtime.js.map +0 -1
  319. package/src/cli/blueprint-authority.js.map +0 -1
  320. package/src/cli/blueprint-command.js.map +0 -1
  321. package/src/cli/bootstrap.js.map +0 -1
  322. package/src/cli/dev-command.js.map +0 -1
  323. package/src/cli/main.js.map +0 -1
  324. package/src/cli/output.js.map +0 -1
  325. package/src/cli/personal-secret-runtime.js.map +0 -1
  326. package/src/cli/secret-terminal.js.map +0 -1
  327. package/src/container-images.js.map +0 -1
  328. package/src/data-lifecycle/index.js.map +0 -1
  329. package/src/data-lifecycle/model.fixtures.d.ts +0 -2
  330. package/src/data-lifecycle/model.fixtures.js +0 -244
  331. package/src/data-lifecycle/model.fixtures.js.map +0 -1
  332. package/src/data-lifecycle/model.js.map +0 -1
  333. package/src/data-lifecycle/sensitive-artifacts.js.map +0 -1
  334. package/src/data-lifecycle/validation.js.map +0 -1
  335. package/src/database-retirement/contract.js.map +0 -1
  336. package/src/database-retirement/index.js.map +0 -1
  337. package/src/deterministic-order.js.map +0 -1
  338. package/src/developer-agent/context.js.map +0 -1
  339. package/src/developer-agent/generator-planning.js.map +0 -1
  340. package/src/developer-agent/generator-preview.js.map +0 -1
  341. package/src/developer-agent/git-inspection.js.map +0 -1
  342. package/src/developer-agent/handoff.js.map +0 -1
  343. package/src/developer-agent/index.js.map +0 -1
  344. package/src/developer-agent/model.js.map +0 -1
  345. package/src/developer-agent/operation-registry.js.map +0 -1
  346. package/src/developer-agent/ordering.js.map +0 -1
  347. package/src/developer-agent/planning.js.map +0 -1
  348. package/src/developer-agent/preview-changes.js.map +0 -1
  349. package/src/developer-agent/preview-source.js.map +0 -1
  350. package/src/developer-agent/validation.js.map +0 -1
  351. package/src/developer-agent/workspace-inspection.js.map +0 -1
  352. package/src/developer-agent/workspace-path.js.map +0 -1
  353. package/src/executors/blueprint-trust/blueprint-trust.js.map +0 -1
  354. package/src/executors/blueprint-verification/blueprint-verification.js.map +0 -1
  355. package/src/executors/deploy/deploy.js.map +0 -1
  356. package/src/executors/deployment-plan/deployment-plan.js.map +0 -1
  357. package/src/executors/dev/dev.js.map +0 -1
  358. package/src/executors/dev-doctor/dev-doctor.js.map +0 -1
  359. package/src/executors/dev-setup/dev-setup.js.map +0 -1
  360. package/src/executors/developer-context/developer-context.js.map +0 -1
  361. package/src/executors/fleet/fleet.js.map +0 -1
  362. package/src/executors/foundation-preflight/foundation-preflight.js.map +0 -1
  363. package/src/executors/foundation-profile-preflight/foundation-profile-preflight.js.map +0 -1
  364. package/src/executors/foundation-profile-preflight/production-database-safeguard.js.map +0 -1
  365. package/src/executors/foundation-remove-preflight/foundation-remove-preflight.js.map +0 -1
  366. package/src/executors/github-bootstrap/github-bootstrap.js.map +0 -1
  367. package/src/executors/infrastructure-plan/infrastructure-plan.js.map +0 -1
  368. package/src/executors/local-deploy/federated-credential-transport.js.map +0 -1
  369. package/src/executors/local-deploy/fixtures/local-deploy-state-machine.mjs +0 -53
  370. package/src/executors/local-deploy/local-approval.js.map +0 -1
  371. package/src/executors/local-deploy/local-deploy.js.map +0 -1
  372. package/src/executors/refresh/refresh.js.map +0 -1
  373. package/src/executors/remove/remove.js.map +0 -1
  374. package/src/executors/router-waf-rehearsal/router-waf-rehearsal.js.map +0 -1
  375. package/src/executors/secret-guardrails/secret-guardrails.js.map +0 -1
  376. package/src/executors/secret-initialize/secret-initialize.js.map +0 -1
  377. package/src/executors/secret-metadata/secret-metadata.js.map +0 -1
  378. package/src/executors/sst-lifecycle/generated-secret-retirement.js.map +0 -1
  379. package/src/executors/sst-lifecycle/governed-native-operation.js.map +0 -1
  380. package/src/executors/sst-lifecycle/logging-preflight.js.map +0 -1
  381. package/src/executors/sst-lifecycle/run-sst-command.js.map +0 -1
  382. package/src/executors/sst-lifecycle/secret-preflight.js.map +0 -1
  383. package/src/executors/sst-lifecycle/sst-environment-source.js.map +0 -1
  384. package/src/executors/unlock/unlock.js.map +0 -1
  385. package/src/executors/work-markers/work-markers.js.map +0 -1
  386. package/src/foundation/discovery.js.map +0 -1
  387. package/src/foundation/index.js.map +0 -1
  388. package/src/foundation/local-database-contract.js.map +0 -1
  389. package/src/foundation/logging-preflight.js.map +0 -1
  390. package/src/foundation/logging.js.map +0 -1
  391. package/src/foundation/partial-state.js.map +0 -1
  392. package/src/foundation/preflight.js.map +0 -1
  393. package/src/foundation/private-smoke-access.js.map +0 -1
  394. package/src/foundation/private-smoke-admission.js.map +0 -1
  395. package/src/foundation/private-smoke-control-plane.js.map +0 -1
  396. package/src/foundation/provision-database-bindings.js.map +0 -1
  397. package/src/foundation/provision-logical-database.js.map +0 -1
  398. package/src/foundation/requirements.js.map +0 -1
  399. package/src/foundation/router-origin-proof.js.map +0 -1
  400. package/src/foundation/router-waf-rate-rehearsal.js.map +0 -1
  401. package/src/foundation/router-waf.js.map +0 -1
  402. package/src/foundation/stages.js.map +0 -1
  403. package/src/frontend-security/index.js.map +0 -1
  404. package/src/frontend-security/security-headers.js.map +0 -1
  405. package/src/generators/feature-registry.js.map +0 -1
  406. package/src/generators/formatting.js.map +0 -1
  407. package/src/generators/function/function.js.map +0 -1
  408. package/src/generators/job/job.js.map +0 -1
  409. package/src/generators/logging-registry.js.map +0 -1
  410. package/src/generators/post-generation-install.js.map +0 -1
  411. package/src/generators/preset/dependency-overrides.js.map +0 -1
  412. package/src/generators/preset/generator.js.map +0 -1
  413. package/src/generators/preset/tool-versions.js.map +0 -1
  414. package/src/generators/preset/workspace-files-ci-acceptance.js.map +0 -1
  415. package/src/generators/preset/workspace-files-developer-agent.js.map +0 -1
  416. package/src/generators/preset/workspace-files-ecr-inspector.js.map +0 -1
  417. package/src/generators/preset/workspace-files-foundation-workload-roles.js.map +0 -1
  418. package/src/generators/preset/workspace-files-performance-cost.js.map +0 -1
  419. package/src/generators/preset/workspace-files-performance-load.js.map +0 -1
  420. package/src/generators/preset/workspace-files-stage-authority.js.map +0 -1
  421. package/src/generators/preset/workspace-files-thin-deploy.js.map +0 -1
  422. package/src/generators/preset/workspace-files-thin-docs.js.map +0 -1
  423. package/src/generators/preset/workspace-files-thin-release.js.map +0 -1
  424. package/src/generators/preset/workspace-files-workload-role-baseline.js.map +0 -1
  425. package/src/generators/preset/workspace-files.js.map +0 -1
  426. package/src/generators/repository-policy/repository-policy.js.map +0 -1
  427. package/src/generators/repository-policy/tree-policy.js.map +0 -1
  428. package/src/generators/service/service.js.map +0 -1
  429. package/src/generators/slice/built-in-plan-api-contract-files.js.map +0 -1
  430. package/src/generators/slice/built-in-plan-api-files.js.map +0 -1
  431. package/src/generators/slice/built-in-plan-async-work-files.js.map +0 -1
  432. package/src/generators/slice/built-in-plan-authorization-files.js.map +0 -1
  433. package/src/generators/slice/built-in-plan-authorization-infrastructure-files.js.map +0 -1
  434. package/src/generators/slice/built-in-plan-background-work-files.js.map +0 -1
  435. package/src/generators/slice/built-in-plan-data-deletion-files.js.map +0 -1
  436. package/src/generators/slice/built-in-plan-data-export-infrastructure-files.js.map +0 -1
  437. package/src/generators/slice/built-in-plan-data-files.js.map +0 -1
  438. package/src/generators/slice/built-in-plan-data-lifecycle-files.js.map +0 -1
  439. package/src/generators/slice/built-in-plan-data-lifecycle-runtime-files.js.map +0 -1
  440. package/src/generators/slice/built-in-plan-data-retention-job-files.js.map +0 -1
  441. package/src/generators/slice/built-in-plan-data-retention-launcher-files.js.map +0 -1
  442. package/src/generators/slice/built-in-plan-data-rights-files.js.map +0 -1
  443. package/src/generators/slice/built-in-plan-database-lifecycle-files.js.map +0 -1
  444. package/src/generators/slice/built-in-plan-database-retirement-rehearsal-files.js.map +0 -1
  445. package/src/generators/slice/built-in-plan-foundation-files.js.map +0 -1
  446. package/src/generators/slice/built-in-plan-frontend-files.js.map +0 -1
  447. package/src/generators/slice/built-in-plan-infrastructure-files.js.map +0 -1
  448. package/src/generators/slice/built-in-plan-infrastructure-safety-files.js.map +0 -1
  449. package/src/generators/slice/built-in-plan-metadata-files.js.map +0 -1
  450. package/src/generators/slice/built-in-plan-native-runtime-authority-files.js.map +0 -1
  451. package/src/generators/slice/built-in-plan-operations-files.js.map +0 -1
  452. package/src/generators/slice/built-in-plan-performance-files.js.map +0 -1
  453. package/src/generators/slice/built-in-plan-project-files.js.map +0 -1
  454. package/src/generators/slice/built-in-plan-release-files.js.map +0 -1
  455. package/src/generators/slice/built-in-plan-reliability-files.js.map +0 -1
  456. package/src/generators/slice/built-in-plan-secret-runtime-files.js.map +0 -1
  457. package/src/generators/slice/built-in-plan-shared.js.map +0 -1
  458. package/src/generators/slice/built-in-plan-testing-files.js.map +0 -1
  459. package/src/generators/slice/built-in-plan-thin-release-files.js.map +0 -1
  460. package/src/generators/slice/built-in-plan-verification-files.js.map +0 -1
  461. package/src/generators/slice/built-in-plan-web-files.js.map +0 -1
  462. package/src/generators/slice/built-in-plan-workload-role-files.js.map +0 -1
  463. package/src/generators/slice/built-in-plan.js.map +0 -1
  464. package/src/generators/slice/slice.js.map +0 -1
  465. package/src/generators/upgrade/upgrade.js.map +0 -1
  466. package/src/generators/workload/frozen-container.js.map +0 -1
  467. package/src/generators/workload/performance-registration.js.map +0 -1
  468. package/src/generators/workload/reliability-registration.js.map +0 -1
  469. package/src/generators/workload/service-performance-files.js.map +0 -1
  470. package/src/generators/workload/workload.js.map +0 -1
  471. package/src/git-policy/action-pins.js.map +0 -1
  472. package/src/git-policy/github-bootstrap.js.map +0 -1
  473. package/src/git-policy/index.js.map +0 -1
  474. package/src/git-policy/routing.js.map +0 -1
  475. package/src/index.js.map +0 -1
  476. package/src/infrastructure-change/convergence.js.map +0 -1
  477. package/src/infrastructure-change/drift.js.map +0 -1
  478. package/src/infrastructure-change/index.js.map +0 -1
  479. package/src/infrastructure-change/local-capability.js.map +0 -1
  480. package/src/infrastructure-change/model.js.map +0 -1
  481. package/src/infrastructure-change/normalize.js.map +0 -1
  482. package/src/infrastructure-change/plan.js.map +0 -1
  483. package/src/infrastructure-change/risk.js.map +0 -1
  484. package/src/infrastructure-change/summary.js.map +0 -1
  485. package/src/local-dev/context-discovery.js.map +0 -1
  486. package/src/local-dev/contract-validation.js.map +0 -1
  487. package/src/local-dev/contracts.js.map +0 -1
  488. package/src/local-dev/control-contract.js.map +0 -1
  489. package/src/local-dev/dev-command-core.js.map +0 -1
  490. package/src/local-dev/effects.js.map +0 -1
  491. package/src/local-dev/environment-inspector.js.map +0 -1
  492. package/src/local-dev/environment-state.js.map +0 -1
  493. package/src/local-dev/errors.js.map +0 -1
  494. package/src/local-dev/fleet-client.js.map +0 -1
  495. package/src/local-dev/fleet-configuration.js.map +0 -1
  496. package/src/local-dev/fleet-inventory.js.map +0 -1
  497. package/src/local-dev/fleet-ipc.js.map +0 -1
  498. package/src/local-dev/fleet-launcher.js.map +0 -1
  499. package/src/local-dev/fleet-lock.js.map +0 -1
  500. package/src/local-dev/fleet-logs.js.map +0 -1
  501. package/src/local-dev/fleet-process.js.map +0 -1
  502. package/src/local-dev/fleet-runtime.js.map +0 -1
  503. package/src/local-dev/fleet-session.js.map +0 -1
  504. package/src/local-dev/fleet-slice-runner-daemon.js.map +0 -1
  505. package/src/local-dev/fleet-startup.js.map +0 -1
  506. package/src/local-dev/fleet-state.js.map +0 -1
  507. package/src/local-dev/fleet-supervisor-daemon.js.map +0 -1
  508. package/src/local-dev/fleet-supervisor.js.map +0 -1
  509. package/src/local-dev/gateway-daemon.js.map +0 -1
  510. package/src/local-dev/gateway.js.map +0 -1
  511. package/src/local-dev/identity.js.map +0 -1
  512. package/src/local-dev/index.js.map +0 -1
  513. package/src/local-dev/local-context.js.map +0 -1
  514. package/src/local-dev/nx-workspace.js.map +0 -1
  515. package/src/local-dev/personal-secret-ledger.js.map +0 -1
  516. package/src/local-dev/personal-stage.js.map +0 -1
  517. package/src/local-dev/portless.js.map +0 -1
  518. package/src/local-dev/ports.js.map +0 -1
  519. package/src/local-dev/private-state.js.map +0 -1
  520. package/src/local-dev/process-identity.js.map +0 -1
  521. package/src/local-dev/proxy.js.map +0 -1
  522. package/src/local-dev/runtime-paths.js.map +0 -1
  523. package/src/local-dev/secret-slice-claim.js.map +0 -1
  524. package/src/local-dev/slice-claim.js.map +0 -1
  525. package/src/local-dev/slice-runner.js.map +0 -1
  526. package/src/local-dev/tls.js.map +0 -1
  527. package/src/ownership/composition.js.map +0 -1
  528. package/src/ownership/foundation-record.js.map +0 -1
  529. package/src/ownership/hash.js.map +0 -1
  530. package/src/ownership/index.js.map +0 -1
  531. package/src/ownership/json-ownership.js.map +0 -1
  532. package/src/ownership/record.js.map +0 -1
  533. package/src/ownership/workspace-record.js.map +0 -1
  534. package/src/performance/cost-collection.js.map +0 -1
  535. package/src/performance/cost-controls.js.map +0 -1
  536. package/src/performance/evidence.js.map +0 -1
  537. package/src/performance/index.js.map +0 -1
  538. package/src/performance/load-safety.js.map +0 -1
  539. package/src/performance/model.js.map +0 -1
  540. package/src/performance/pr-artifact-budget.js.map +0 -1
  541. package/src/performance/runner.js.map +0 -1
  542. package/src/performance/scenario-endpoint.js.map +0 -1
  543. package/src/performance/scenario.js.map +0 -1
  544. package/src/performance/test-fixtures.d.ts +0 -7
  545. package/src/performance/test-fixtures.js +0 -167
  546. package/src/performance/test-fixtures.js.map +0 -1
  547. package/src/performance/unit-cost.js.map +0 -1
  548. package/src/release/index.js.map +0 -1
  549. package/src/release/lifecycle.js.map +0 -1
  550. package/src/release/manifest.js.map +0 -1
  551. package/src/release/rollout.js.map +0 -1
  552. package/src/release/source-authority.js.map +0 -1
  553. package/src/repository-policy/aurora-preflight.js.map +0 -1
  554. package/src/repository-policy/capacity-migration.js.map +0 -1
  555. package/src/repository-policy/deployment-plan.js.map +0 -1
  556. package/src/repository-policy/foundation-profile.js.map +0 -1
  557. package/src/repository-policy/index.js.map +0 -1
  558. package/src/repository-policy/policy.js.map +0 -1
  559. package/src/secrets/adapters.js.map +0 -1
  560. package/src/secrets/aws-control-plane.js.map +0 -1
  561. package/src/secrets/declaration-verification.js.map +0 -1
  562. package/src/secrets/generated-aws-control-plane.js.map +0 -1
  563. package/src/secrets/guardrails.js.map +0 -1
  564. package/src/secrets/index.js.map +0 -1
  565. package/src/secrets/metadata.js.map +0 -1
  566. package/src/secrets/model.js.map +0 -1
  567. package/src/secrets/operator.js.map +0 -1
  568. package/src/secrets/permissions.js.map +0 -1
  569. package/src/secrets/personal-command.js.map +0 -1
  570. package/src/secrets/personal-ledger.js.map +0 -1
  571. package/src/secrets/registry.js.map +0 -1
  572. package/src/secrets/verification.js.map +0 -1
  573. package/src/secrets/workload-access.js.map +0 -1
  574. package/src/sst-environment-source-format.js.map +0 -1
  575. package/src/supply-chain/action-pins.js.map +0 -1
  576. package/src/supply-chain/blueprint-trust-git.js.map +0 -1
  577. package/src/supply-chain/blueprint-trust-process.js.map +0 -1
  578. package/src/supply-chain/blueprint-trust.js.map +0 -1
  579. package/src/supply-chain/blueprint-verification-authority.js.map +0 -1
  580. package/src/supply-chain/blueprint-verification-execution.js.map +0 -1
  581. package/src/supply-chain/build-output-bounds.js.map +0 -1
  582. package/src/supply-chain/build-output.js.map +0 -1
  583. package/src/supply-chain/common.js.map +0 -1
  584. package/src/supply-chain/container-artifact-contract.js.map +0 -1
  585. package/src/supply-chain/container-release.js.map +0 -1
  586. package/src/supply-chain/ecr-applicability.js.map +0 -1
  587. package/src/supply-chain/ecr-scanning.js.map +0 -1
  588. package/src/supply-chain/ecs-deployed-image.js.map +0 -1
  589. package/src/supply-chain/errors.js.map +0 -1
  590. package/src/supply-chain/generated-blueprint-trust-command.js.map +0 -1
  591. package/src/supply-chain/generated-command.js.map +0 -1
  592. package/src/supply-chain/generated-container-release-command.js.map +0 -1
  593. package/src/supply-chain/generated-ecr-collector-command.js.map +0 -1
  594. package/src/supply-chain/generated-files.js.map +0 -1
  595. package/src/supply-chain/generated-scanner-command.js.map +0 -1
  596. package/src/supply-chain/index.js.map +0 -1
  597. package/src/supply-chain/inventory.js.map +0 -1
  598. package/src/supply-chain/license-expression.js.map +0 -1
  599. package/src/supply-chain/pnpm-toolchain-authority.js.map +0 -1
  600. package/src/supply-chain/policy.js.map +0 -1
  601. package/src/supply-chain/publication.js.map +0 -1
  602. package/src/supply-chain/sbom.js.map +0 -1
  603. package/src/supply-chain/scanner.js.map +0 -1
  604. package/src/supply-chain/vendored-source.js.map +0 -1
  605. package/src/testing-evidence/fixture-scope.js.map +0 -1
  606. package/src/testing-evidence/index.js.map +0 -1
  607. package/src/testing-evidence/quarantine.js.map +0 -1
  608. package/src/testing-evidence/result.js.map +0 -1
  609. package/src/testing-evidence/runner-adapter.js.map +0 -1
  610. package/src/testing-evidence/sensitive-artifacts.js.map +0 -1
  611. package/src/validation.js.map +0 -1
  612. package/src/work-markers/index.js.map +0 -1
  613. package/src/work-markers/work-markers.js.map +0 -1
  614. package/src/workload-roles/account-baseline.js.map +0 -1
  615. package/src/workload-roles/authority.js.map +0 -1
  616. package/src/workload-roles/aws-adapter.js.map +0 -1
  617. package/src/workload-roles/aws-internal-handler.js.map +0 -1
  618. package/src/workload-roles/aws-s3-state.js.map +0 -1
  619. package/src/workload-roles/aws-sdk-control-plane.js.map +0 -1
  620. package/src/workload-roles/boundary.js.map +0 -1
  621. package/src/workload-roles/convergence.js.map +0 -1
  622. package/src/workload-roles/effective-policy.js.map +0 -1
  623. package/src/workload-roles/handler.js.map +0 -1
  624. package/src/workload-roles/history.js.map +0 -1
  625. package/src/workload-roles/index.js.map +0 -1
  626. package/src/workload-roles/injection.js.map +0 -1
  627. package/src/workload-roles/manifest.js.map +0 -1
  628. package/src/workload-roles/provisioner.js.map +0 -1
  629. package/src/workload-roles/registration.js.map +0 -1
  630. package/src/workload-roles/stage-boundary.js.map +0 -1
  631. package/src/workload-roles/standard-slice.js.map +0 -1
  632. package/src/workspace-deployment/affected-lifecycle.js.map +0 -1
  633. package/src/workspace-deployment/identity.js.map +0 -1
  634. package/src/workspace-deployment/index.js.map +0 -1
  635. package/src/workspace-deployment/migration-evidence.js.map +0 -1
  636. package/src/workspace-deployment/migration.js.map +0 -1
  637. package/src/workspace-deployment/ownership.js.map +0 -1
@@ -2,17 +2,23 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.renderProductAsyncWorkFiles = renderProductAsyncWorkFiles;
4
4
  const built_in_plan_shared_js_1 = require("./built-in-plan-shared.js");
5
+ const built_in_plan_key_value_provider_js_1 = require("./built-in-plan-key-value-provider.js");
6
+ const built_in_plan_key_value_performance_js_1 = require("./built-in-plan-key-value-performance.js");
7
+ const built_in_plan_key_value_cleanup_js_1 = require("./built-in-plan-key-value-cleanup.js");
5
8
  /** @internal */
6
9
  function renderProductAsyncWorkFiles(name, pascalName) {
7
10
  const recordExportWorkflowName = (0, built_in_plan_shared_js_1.stableGeneratedName)(40, name);
8
11
  return {
12
+ ...(0, built_in_plan_key_value_provider_js_1.renderKeyValueProviderFiles)(name),
13
+ ...(0, built_in_plan_key_value_performance_js_1.renderKeyValuePerformanceFiles)(name),
14
+ ...(0, built_in_plan_key_value_cleanup_js_1.renderKeyValueCleanupFiles)(name),
9
15
  'async/work-contract.json': (0, built_in_plan_shared_js_1.json)({
10
16
  capabilities: [
11
17
  {
12
18
  id: 'domain-events',
13
19
  owner: name,
14
20
  primitive: 'eventbridge-event',
15
- recovery: 'not-configured',
21
+ recovery: 'streams-and-bounded-reconciliation',
16
22
  },
17
23
  {
18
24
  id: 'durable-work',
@@ -40,15 +46,15 @@ function renderProductAsyncWorkFiles(name, pascalName) {
40
46
  },
41
47
  ],
42
48
  consistency: {
43
- inboxTable: 'ebk_inbox',
44
- outboxTable: 'data_lifecycle_outbox',
45
- transactionBoundary: 'injected-adapter',
49
+ inboxTable: 'slice-key-value',
50
+ outboxTable: 'slice-key-value',
51
+ transactionBoundary: 'native-dynamodb-transaction',
46
52
  },
47
53
  queue: {
48
54
  batchItemFailures: true,
49
55
  conflictPolicy: 'same-id-different-payload-fails',
50
56
  idempotencyWindowSeconds: 2_592_000,
51
- inboxCleanupBatchSize: 1_000,
57
+ inboxCleanupBatchSize: 20,
52
58
  inboxCleanupIntervalSeconds: 3_600,
53
59
  inboxCleanupInvocationLimit: 10_000,
54
60
  performanceCleanupDeadlineSeconds: 86_400,
@@ -912,535 +918,6 @@ export function createAsyncRecoveryAdapters(): AsyncRecoveryAdapters {
912
918
  }
913
919
 
914
920
  export type { BackfillReportV1 };
915
- `,
916
- 'async/provider-worker.ts': `import { randomUUID } from 'node:crypto';
917
- import {
918
- asyncWorkDigest,
919
- processSqsBatch,
920
- runProviderDelivery,
921
- type ProviderDeliveryV1,
922
- } from '@empire-builder-kit/runtime/async-work';
923
- import { deriveOperationalRolloutStableKey } from '@empire-builder-kit/runtime/configuration';
924
- import { createLogger, type Logger } from '@empire-builder-kit/runtime/logging';
925
- import type { Client } from 'pg';
926
- import {
927
- createSliceAwsConfigurationProvider,
928
- createSliceLocalConfigurationProvider,
929
- } from '../configuration/provider.js';
930
- import { evaluateLambdaProviderDelivery } from '../configuration/rollout.js';
931
- import { withPrimaryDatabase } from '../database/runtime-client.js';
932
- import {
933
- asyncAdapterDeclaration,
934
- createAsyncRecoveryAdapters,
935
- } from './recovery-adapters.js';
936
-
937
- const providerWorkerRolloutStableKey =
938
- deriveOperationalRolloutStableKey({
939
- kind: 'lambda',
940
- slice: '${name}',
941
- workload: 'provider-worker',
942
- });
943
-
944
- interface QueueRecord { body: string; messageId: string }
945
- interface QueueEvent { Records: QueueRecord[] }
946
-
947
- interface InboxRow {
948
- attempts: number;
949
- lastAttemptAt: Date;
950
- payloadDigest: string;
951
- resultReference: string | null;
952
- status: 'claimed' | 'failed' | 'succeeded';
953
- }
954
-
955
- const HANDLER_ID = '${name}.provider-worker';
956
- const HANDLER_VERSION = '1';
957
- const CLAIM_LEASE_MILLISECONDS = 120_000;
958
- const INBOX_RETENTION_DAYS = 30;
959
- const protectedStage =
960
- process.env.EBK_STAGE === 'staging' ||
961
- process.env.EBK_STAGE === 'production';
962
-
963
- function requiredConfigurationIdentifier(name: string): string {
964
- const value = process.env[name]?.trim();
965
- if (!value) throw new Error(name + ' is required.');
966
- return value;
967
- }
968
-
969
- const configurationProvider = protectedStage
970
- ? createSliceAwsConfigurationProvider({
971
- applicationIdentifier: requiredConfigurationIdentifier(
972
- 'EBK_APPCONFIG_APPLICATION_ID',
973
- ),
974
- environmentIdentifier: requiredConfigurationIdentifier(
975
- 'EBK_APPCONFIG_ENVIRONMENT_ID',
976
- ),
977
- profileIdentifier: requiredConfigurationIdentifier(
978
- 'EBK_APPCONFIG_PROFILE_ID',
979
- ),
980
- })
981
- : createSliceLocalConfigurationProvider();
982
-
983
- function expiresAt(createdAt: string) {
984
- const value = new Date(createdAt);
985
- value.setUTCDate(value.getUTCDate() + INBOX_RETENTION_DAYS);
986
- return value.toISOString();
987
- }
988
-
989
- function parseDelivery(body: string): ProviderDeliveryV1<unknown> {
990
- const delivery = JSON.parse(body) as ProviderDeliveryV1<unknown>;
991
- if (
992
- delivery?.version !== 1 ||
993
- typeof delivery.deliveryId !== 'string' ||
994
- typeof delivery.requestDigest !== 'string' ||
995
- asyncWorkDigest(delivery.request) !== delivery.requestDigest
996
- ) {
997
- throw new Error('provider-delivery-invalid');
998
- }
999
- return delivery;
1000
- }
1001
-
1002
- export type ProviderClaimResult =
1003
- | { attemptToken: string; outcome: 'claimed' }
1004
- | {
1005
- outcome:
1006
- | 'conflict'
1007
- | 'duplicate'
1008
- | 'retry'
1009
- | 'terminal-permanent'
1010
- | 'terminal-reconciliation';
1011
- };
1012
-
1013
- function attemptReference(
1014
- state: 'effect-started' | 'prepared',
1015
- attemptToken: string,
1016
- ): string {
1017
- return state + '-' + attemptToken;
1018
- }
1019
-
1020
- export async function claimProviderDelivery(
1021
- client: Client,
1022
- delivery: ProviderDeliveryV1<unknown>,
1023
- now: string,
1024
- createAttemptToken: () => string = randomUUID,
1025
- ): Promise<ProviderClaimResult> {
1026
- const attemptToken = createAttemptToken();
1027
- const preparedReference = attemptReference('prepared', attemptToken);
1028
- await client.query('BEGIN');
1029
- try {
1030
- const inserted = await client.query(
1031
- \`INSERT INTO ebk_inbox
1032
- (handler_id, handler_version, message_id, payload_digest, status,
1033
- attempts, first_seen_at, last_attempt_at, expires_at,
1034
- result_reference)
1035
- VALUES ($1, $2, $3, $4, 'claimed', 1, $5, $5, $6, $7)
1036
- ON CONFLICT (handler_id, message_id) DO NOTHING
1037
- RETURNING message_id\`,
1038
- [
1039
- HANDLER_ID,
1040
- HANDLER_VERSION,
1041
- delivery.deliveryId,
1042
- delivery.requestDigest,
1043
- now,
1044
- expiresAt(delivery.createdAt),
1045
- preparedReference,
1046
- ],
1047
- );
1048
- if (inserted.rowCount === 1) {
1049
- await client.query('COMMIT');
1050
- return { attemptToken, outcome: 'claimed' };
1051
- }
1052
- const existing = await client.query<InboxRow>(
1053
- \`SELECT attempts, last_attempt_at AS "lastAttemptAt",
1054
- payload_digest AS "payloadDigest",
1055
- result_reference AS "resultReference", status
1056
- FROM ebk_inbox
1057
- WHERE handler_id = $1 AND message_id = $2
1058
- FOR UPDATE\`,
1059
- [HANDLER_ID, delivery.deliveryId],
1060
- );
1061
- const row = existing.rows[0];
1062
- if (!row || row.payloadDigest !== delivery.requestDigest) {
1063
- await client.query('COMMIT');
1064
- return { outcome: 'conflict' };
1065
- }
1066
- if (row.status === 'succeeded') {
1067
- await client.query('COMMIT');
1068
- return { outcome: 'duplicate' };
1069
- }
1070
- if (row.status === 'failed' && row.resultReference) {
1071
- if (row.resultReference.startsWith('terminal-reconciliation-')) {
1072
- await client.query('COMMIT');
1073
- return { outcome: 'terminal-reconciliation' };
1074
- }
1075
- if (row.resultReference.startsWith('terminal-permanent-')) {
1076
- await client.query('COMMIT');
1077
- return { outcome: 'terminal-permanent' };
1078
- }
1079
- }
1080
- if (
1081
- row.status === 'claimed' &&
1082
- Date.parse(now) - row.lastAttemptAt.getTime() <
1083
- CLAIM_LEASE_MILLISECONDS
1084
- ) {
1085
- await client.query('COMMIT');
1086
- return { outcome: 'retry' };
1087
- }
1088
- if (
1089
- row.status === 'claimed' &&
1090
- row.resultReference?.startsWith('effect-started-') &&
1091
- delivery.contract.idempotencyRepeatSafety === 'unproven'
1092
- ) {
1093
- const terminal = await client.query(
1094
- \`UPDATE ebk_inbox
1095
- SET handler_version = $3, last_attempt_at = $4, status = 'failed',
1096
- result_reference = $5
1097
- WHERE handler_id = $1 AND message_id = $2
1098
- AND status = 'claimed' AND result_reference = $6\`,
1099
- [
1100
- HANDLER_ID,
1101
- delivery.deliveryId,
1102
- HANDLER_VERSION,
1103
- now,
1104
- 'terminal-reconciliation-' +
1105
- asyncWorkDigest({
1106
- deliveryId: delivery.deliveryId,
1107
- result: 'provider-effect-outcome-unknown',
1108
- }),
1109
- row.resultReference,
1110
- ],
1111
- );
1112
- if (terminal.rowCount !== 1) {
1113
- throw new Error('provider-reconciliation-transition-lost');
1114
- }
1115
- await client.query('COMMIT');
1116
- return { outcome: 'terminal-reconciliation' };
1117
- }
1118
- await client.query(
1119
- \`UPDATE ebk_inbox
1120
- SET attempts = attempts + 1, handler_version = $3,
1121
- last_attempt_at = $4, result_reference = $5, status = 'claimed'
1122
- WHERE handler_id = $1 AND message_id = $2\`,
1123
- [
1124
- HANDLER_ID,
1125
- delivery.deliveryId,
1126
- HANDLER_VERSION,
1127
- now,
1128
- preparedReference,
1129
- ],
1130
- );
1131
- await client.query('COMMIT');
1132
- return { attemptToken, outcome: 'claimed' };
1133
- } catch (error) {
1134
- await client.query('ROLLBACK').catch(() => undefined);
1135
- throw error;
1136
- }
1137
- }
1138
-
1139
- export async function markProviderEffectStarted(
1140
- client: Client,
1141
- deliveryId: string,
1142
- attemptToken: string,
1143
- now: string,
1144
- ): Promise<boolean> {
1145
- const result = await client.query(
1146
- \`UPDATE ebk_inbox
1147
- SET result_reference = $4, last_attempt_at = $5
1148
- WHERE handler_id = $1 AND message_id = $2 AND status = 'claimed'
1149
- AND result_reference = $3\`,
1150
- [
1151
- HANDLER_ID,
1152
- deliveryId,
1153
- attemptReference('prepared', attemptToken),
1154
- attemptReference('effect-started', attemptToken),
1155
- now,
1156
- ],
1157
- );
1158
- return result.rowCount === 1;
1159
- }
1160
-
1161
- export async function finishProviderDelivery(
1162
- client: Client,
1163
- deliveryId: string,
1164
- attemptToken: string,
1165
- input: {
1166
- expectedState?: 'effect-started' | 'prepared';
1167
- resultReference?: string;
1168
- status: 'failed' | 'succeeded';
1169
- },
1170
- ): Promise<boolean> {
1171
- const result = await client.query(
1172
- \`UPDATE ebk_inbox
1173
- SET completed_at = CASE WHEN $3 = 'succeeded' THEN now() ELSE NULL END,
1174
- result_reference = $4, status = $3, last_attempt_at = now()
1175
- WHERE handler_id = $1 AND message_id = $2
1176
- AND status = 'claimed' AND result_reference = $5\`,
1177
- [
1178
- HANDLER_ID,
1179
- deliveryId,
1180
- input.status,
1181
- input.resultReference ?? null,
1182
- attemptReference(input.expectedState ?? 'effect-started', attemptToken),
1183
- ],
1184
- );
1185
- return result.rowCount === 1;
1186
- }
1187
-
1188
- interface ProviderWorkerDependencies {
1189
- createAttemptToken(): string;
1190
- deliver: typeof runProviderDelivery;
1191
- evaluateRollout: typeof evaluateLambdaProviderDelivery;
1192
- logger: Logger;
1193
- now(): string;
1194
- withDatabase: typeof withPrimaryDatabase;
1195
- }
1196
-
1197
- export function createProviderWorkerHandler(
1198
- dependencies: ProviderWorkerDependencies,
1199
- ) {
1200
- const processRecord = async (record: QueueRecord) => {
1201
- let delivery: ProviderDeliveryV1<unknown>;
1202
- try {
1203
- delivery = parseDelivery(record.body);
1204
- } catch (error) {
1205
- dependencies.logger.warn('Provider delivery rejected', {
1206
- attributes: {
1207
- errorCode: 'provider-delivery-invalid',
1208
- messageIdDigest: asyncWorkDigest(record.messageId),
1209
- },
1210
- error,
1211
- outcome: 'failure',
1212
- });
1213
- return { errorCode: 'provider-delivery-invalid', outcome: 'terminal' as const };
1214
- }
1215
- const correlationId = delivery.deliveryId;
1216
- const claimResult = await dependencies.withDatabase(
1217
- { correlationId },
1218
- 'async-provider-worker',
1219
- (client) =>
1220
- claimProviderDelivery(
1221
- client,
1222
- delivery,
1223
- dependencies.now(),
1224
- dependencies.createAttemptToken,
1225
- ),
1226
- );
1227
- if (claimResult.outcome === 'conflict') {
1228
- dependencies.logger.error('Provider delivery idempotency conflict', {
1229
- attributes: { deliveryIdDigest: asyncWorkDigest(delivery.deliveryId) },
1230
- context: { correlationId },
1231
- outcome: 'failure',
1232
- });
1233
- return { errorCode: 'idempotency-payload-conflict', outcome: 'terminal' as const };
1234
- }
1235
- if (claimResult.outcome === 'duplicate') {
1236
- dependencies.logger.info('Provider delivery deduplicated', {
1237
- attributes: { deliveryIdDigest: asyncWorkDigest(delivery.deliveryId) },
1238
- context: { correlationId },
1239
- outcome: 'success',
1240
- });
1241
- return { outcome: 'succeeded' as const };
1242
- }
1243
- if (claimResult.outcome === 'terminal-permanent') {
1244
- return {
1245
- errorCode: 'provider-permanent-failure',
1246
- outcome: 'terminal' as const,
1247
- };
1248
- }
1249
- if (claimResult.outcome === 'terminal-reconciliation') {
1250
- dependencies.logger.error('Provider delivery requires reconciliation', {
1251
- attributes: { deliveryIdDigest: asyncWorkDigest(delivery.deliveryId) },
1252
- context: { correlationId },
1253
- outcome: 'failure',
1254
- });
1255
- return {
1256
- errorCode: 'provider-reconciliation-required',
1257
- outcome: 'terminal' as const,
1258
- };
1259
- }
1260
- if (claimResult.outcome === 'retry') {
1261
- return { errorCode: 'idempotency-claim-active', outcome: 'retry' as const };
1262
- }
1263
- if (claimResult.outcome !== 'claimed') {
1264
- throw new Error('provider-delivery-claim-outcome-unhandled');
1265
- }
1266
- const attemptToken = claimResult.attemptToken;
1267
- let rollout;
1268
- try {
1269
- rollout = await dependencies.evaluateRollout(
1270
- configurationProvider,
1271
- providerWorkerRolloutStableKey,
1272
- );
1273
- } catch (error) {
1274
- await dependencies.withDatabase(
1275
- { correlationId },
1276
- 'async-provider-worker',
1277
- (client) =>
1278
- finishProviderDelivery(
1279
- client,
1280
- delivery.deliveryId,
1281
- attemptToken,
1282
- {
1283
- expectedState: 'prepared',
1284
- resultReference: 'configuration-invalid',
1285
- status: 'failed',
1286
- },
1287
- ),
1288
- );
1289
- dependencies.logger.error('Provider delivery configuration failed', {
1290
- context: { correlationId },
1291
- error,
1292
- outcome: 'failure',
1293
- });
1294
- return {
1295
- errorCode: 'provider-delivery-configuration-invalid',
1296
- outcome: 'retry' as const,
1297
- };
1298
- }
1299
- if (!rollout.assigned) {
1300
- await dependencies.withDatabase(
1301
- { correlationId },
1302
- 'async-provider-worker',
1303
- (client) =>
1304
- finishProviderDelivery(
1305
- client,
1306
- delivery.deliveryId,
1307
- attemptToken,
1308
- {
1309
- expectedState: 'prepared',
1310
- resultReference: 'configuration-disabled',
1311
- status: 'failed',
1312
- },
1313
- ),
1314
- );
1315
- return {
1316
- errorCode: 'provider-delivery-disabled',
1317
- outcome: 'retry' as const,
1318
- };
1319
- }
1320
- const effectStarted = await dependencies.withDatabase(
1321
- { correlationId },
1322
- 'async-provider-worker',
1323
- (client) =>
1324
- markProviderEffectStarted(
1325
- client,
1326
- delivery.deliveryId,
1327
- attemptToken,
1328
- dependencies.now(),
1329
- ),
1330
- );
1331
- if (!effectStarted) {
1332
- return {
1333
- errorCode: 'idempotency-claim-lost',
1334
- outcome: 'retry' as const,
1335
- };
1336
- }
1337
- const result = await dependencies.deliver({
1338
- adapter: createAsyncRecoveryAdapters().providerDelivery,
1339
- delivery,
1340
- });
1341
- if (result.outcome === 'confirmed') {
1342
- const persisted = await dependencies.withDatabase(
1343
- { correlationId },
1344
- 'async-provider-worker',
1345
- (client) =>
1346
- finishProviderDelivery(
1347
- client,
1348
- delivery.deliveryId,
1349
- attemptToken,
1350
- {
1351
- resultReference: result.providerReference,
1352
- status: 'succeeded',
1353
- },
1354
- ),
1355
- );
1356
- if (!persisted) {
1357
- throw new Error('provider-delivery-confirmation-state-lost');
1358
- }
1359
- dependencies.logger.info('Provider delivery completed', {
1360
- attributes: {
1361
- attempts: result.attempts,
1362
- deliveryIdDigest: asyncWorkDigest(delivery.deliveryId),
1363
- },
1364
- context: { correlationId },
1365
- outcome: 'success',
1366
- });
1367
- return { outcome: 'succeeded' as const };
1368
- }
1369
- await dependencies.withDatabase(
1370
- { correlationId },
1371
- 'async-provider-worker',
1372
- (client) =>
1373
- finishProviderDelivery(
1374
- client,
1375
- delivery.deliveryId,
1376
- attemptToken,
1377
- {
1378
- resultReference:
1379
- result.outcome === 'permanent-failure'
1380
- ? 'terminal-permanent-' + result.reconciliationId
1381
- : 'terminal-reconciliation-' + result.reconciliationId,
1382
- status: 'failed',
1383
- },
1384
- ),
1385
- );
1386
- dependencies.logger.error('Provider delivery terminated', {
1387
- attributes: {
1388
- deliveryIdDigest: asyncWorkDigest(delivery.deliveryId),
1389
- errorCode: result.errorCode,
1390
- requiresReconciliation:
1391
- result.outcome === 'reconciliation-required',
1392
- },
1393
- context: { correlationId },
1394
- outcome: 'failure',
1395
- });
1396
- return {
1397
- errorCode: result.errorCode,
1398
- outcome: 'terminal' as const,
1399
- };
1400
- };
1401
-
1402
- return async (event: QueueEvent) => {
1403
- if (!asyncAdapterDeclaration.configured) {
1404
- throw new Error('async-provider-adapter-disabled');
1405
- }
1406
- const result = await processSqsBatch({
1407
- handler: async (record) => {
1408
- try {
1409
- return await processRecord(record);
1410
- } catch (error) {
1411
- dependencies.logger.error('Provider delivery handler failed', {
1412
- attributes: {
1413
- messageIdDigest: asyncWorkDigest(record.messageId),
1414
- },
1415
- error,
1416
- outcome: 'failure',
1417
- });
1418
- throw error;
1419
- }
1420
- },
1421
- records: event.Records,
1422
- });
1423
- return result.response;
1424
- };
1425
- }
1426
-
1427
- const logger = createLogger({
1428
- component: 'provider-worker',
1429
- feature: 'async-work',
1430
- operation: 'provider-delivery',
1431
- slice: '${name}',
1432
- stage: process.env.EBK_STAGE ?? 'local',
1433
- workspace: process.env.EBK_WORKSPACE ?? '${name}',
1434
- });
1435
-
1436
- export const handler = createProviderWorkerHandler({
1437
- createAttemptToken: randomUUID,
1438
- deliver: runProviderDelivery,
1439
- evaluateRollout: evaluateLambdaProviderDelivery,
1440
- logger,
1441
- now: () => new Date().toISOString(),
1442
- withDatabase: withPrimaryDatabase,
1443
- });
1444
921
  `,
1445
922
  'async/webhook-ingress.ts': `import {
1446
923
  SendMessageCommand,
@@ -1774,771 +1251,6 @@ export async function handler(event: { time?: string }) {
1774
1251
  });
1775
1252
  return { accepted: true, scheduledAt };
1776
1253
  }
1777
- `,
1778
- 'async/outbox-relay.ts': `import { randomUUID } from 'node:crypto';
1779
- import {
1780
- EventBridgeClient,
1781
- PutEventsCommand,
1782
- type PutEventsRequestEntry,
1783
- } from '@aws-sdk/client-eventbridge';
1784
- import { createLogger, type Logger } from '@empire-builder-kit/runtime/logging';
1785
- import {
1786
- createMetricEmitter,
1787
- type MetricEmitter,
1788
- } from '@empire-builder-kit/runtime/observability';
1789
- import { withPrimaryDatabase } from '../database/runtime-client.js';
1790
-
1791
- interface OutboxRow {
1792
- eventJson: PutEventsRequestEntry;
1793
- idempotencyKey: string;
1794
- }
1795
-
1796
- const eventBridge = new EventBridgeClient({ maxAttempts: 2 });
1797
-
1798
- function emitOutboxBacklog(metrics: MetricEmitter, value: number) {
1799
- metrics.emit({
1800
- dimensions: {
1801
- component: 'outbox-relay',
1802
- feature: 'async-work',
1803
- operation: 'outbox-relay',
1804
- slice: '${name}',
1805
- stage: process.env.EBK_STAGE ?? 'local',
1806
- },
1807
- metricName: 'OutboxBacklog',
1808
- namespace: 'EBK/Async',
1809
- unit: 'Count',
1810
- value,
1811
- });
1812
- }
1813
-
1814
- interface OutboxRelayDependencies {
1815
- logger: Logger;
1816
- metrics: MetricEmitter;
1817
- publish(entries: PutEventsRequestEntry[]): Promise<{
1818
- Entries?: Array<{ ErrorCode?: string; EventId?: string }>;
1819
- }>;
1820
- withDatabase: typeof withPrimaryDatabase;
1821
- }
1822
-
1823
- export function createOutboxRelayHandler(
1824
- dependencies: OutboxRelayDependencies,
1825
- ) {
1826
- return async (event: { id?: string } = {}) => {
1827
- const correlationId = event.id ?? randomUUID();
1828
- return dependencies.withDatabase(
1829
- { correlationId },
1830
- 'async-outbox-relay',
1831
- async (client) => {
1832
- await client.query('BEGIN');
1833
- try {
1834
- const isolatedPerformance = await client.query<{ effectId: string }>(
1835
- \`WITH claimed AS (
1836
- SELECT effect_id
1837
- FROM performance_load_async_effects
1838
- WHERE processed_at IS NULL AND expires_at > now()
1839
- ORDER BY created_at, effect_id
1840
- LIMIT 10
1841
- FOR UPDATE SKIP LOCKED
1842
- )
1843
- UPDATE performance_load_async_effects AS effects
1844
- SET processed_at = now()
1845
- FROM claimed
1846
- WHERE effects.effect_id = claimed.effect_id
1847
- RETURNING effects.effect_id AS "effectId"\`,
1848
- );
1849
- const processedPerformance = isolatedPerformance.rows.length;
1850
- const pending = await client.query<OutboxRow>(
1851
- \`SELECT idempotency_key AS "idempotencyKey",
1852
- event_json AS "eventJson"
1853
- FROM data_lifecycle_outbox
1854
- WHERE published_at IS NULL AND expires_at > now()
1855
- ORDER BY created_at, idempotency_key
1856
- LIMIT 10
1857
- FOR UPDATE SKIP LOCKED\`,
1858
- );
1859
- if (pending.rows.length === 0) {
1860
- emitOutboxBacklog(dependencies.metrics, 0);
1861
- await client.query('COMMIT');
1862
- dependencies.logger.info('Outbox relay converged', {
1863
- attributes: { processedPerformance },
1864
- context: { correlationId },
1865
- outcome: 'success',
1866
- });
1867
- return {
1868
- failed: 0,
1869
- outcome: 'converged',
1870
- processedPerformance,
1871
- published: 0,
1872
- };
1873
- }
1874
- const result = await dependencies.publish(
1875
- pending.rows.map(({ eventJson }) => eventJson),
1876
- );
1877
- let failed = 0;
1878
- let published = 0;
1879
- for (const [index, row] of pending.rows.entries()) {
1880
- const entry = result.Entries?.[index];
1881
- if (!entry?.EventId || entry.ErrorCode) {
1882
- failed += 1;
1883
- await client.query(
1884
- \`UPDATE data_lifecycle_outbox
1885
- SET attempts = attempts + 1,
1886
- last_error_code = $2
1887
- WHERE idempotency_key = $1\`,
1888
- [row.idempotencyKey, entry?.ErrorCode ?? 'event-publication-failed'],
1889
- );
1890
- continue;
1891
- }
1892
- published += 1;
1893
- await client.query(
1894
- \`UPDATE data_lifecycle_outbox
1895
- SET attempts = attempts + 1, last_error_code = NULL,
1896
- published_at = now()
1897
- WHERE idempotency_key = $1 AND published_at IS NULL\`,
1898
- [row.idempotencyKey],
1899
- );
1900
- }
1901
- const remaining = await client.query<{ count: string }>(
1902
- \`SELECT count(*)::text AS count
1903
- FROM data_lifecycle_outbox
1904
- WHERE published_at IS NULL AND expires_at > now()\`,
1905
- );
1906
- emitOutboxBacklog(
1907
- dependencies.metrics,
1908
- Number(remaining.rows[0]?.count ?? 0),
1909
- );
1910
- await client.query('COMMIT');
1911
- dependencies.logger.info('Outbox relay batch completed', {
1912
- attributes: { failed, processedPerformance, published },
1913
- context: { correlationId },
1914
- outcome: failed === 0 ? 'success' : 'failure',
1915
- });
1916
- return {
1917
- failed,
1918
- outcome: failed === 0 ? 'converged' : 'retry-required',
1919
- processedPerformance,
1920
- published,
1921
- };
1922
- } catch (error) {
1923
- await client.query('ROLLBACK').catch(() => undefined);
1924
- dependencies.logger.error('Outbox relay batch failed', {
1925
- context: { correlationId },
1926
- error,
1927
- outcome: 'failure',
1928
- });
1929
- throw error;
1930
- }
1931
- },
1932
- );
1933
- };
1934
- }
1935
-
1936
- const logger = createLogger({
1937
- component: 'outbox-relay',
1938
- feature: 'async-work',
1939
- operation: 'outbox-relay',
1940
- slice: '${name}',
1941
- stage: process.env.EBK_STAGE ?? 'local',
1942
- workspace: process.env.EBK_WORKSPACE ?? '${name}',
1943
- });
1944
-
1945
- export const handler = createOutboxRelayHandler({
1946
- logger,
1947
- metrics: createMetricEmitter(),
1948
- publish: (Entries) => eventBridge.send(new PutEventsCommand({ Entries })),
1949
- withDatabase: withPrimaryDatabase,
1950
- });
1951
- `,
1952
- 'async/inbox-cleanup.ts': `import { randomUUID } from 'node:crypto';
1953
- import { createLogger, type Logger } from '@empire-builder-kit/runtime/logging';
1954
- import {
1955
- createMetricEmitter,
1956
- type MetricEmitter,
1957
- } from '@empire-builder-kit/runtime/observability';
1958
- import type { Client as PgClient } from 'pg';
1959
- import { withPrimaryDatabase } from '../database/runtime-client.js';
1960
-
1961
- const CLEANUP_BATCH_SIZE = 1_000;
1962
- const CLEANUP_MAXIMUM_ROWS = 10_000;
1963
- const CLEANUP_MAXIMUM_RUNTIME_MILLISECONDS = 4 * 60_000;
1964
- const PERFORMANCE_CLEANUP_BATCH_SIZE = 500;
1965
- const PERFORMANCE_CLEANUP_MAXIMUM_ROWS = 5_000;
1966
- const PERFORMANCE_CLEANUP_DEADLINE_HOURS = 24;
1967
- const PERFORMANCE_CLEANUP_FEATURE = 'performance-load';
1968
- const PERFORMANCE_CLEANUP_MAXIMUM_PENDING_REPORTS = 10_000;
1969
- const PERFORMANCE_AUDIT_RETENTION_DAYS = 30;
1970
-
1971
- interface InboxCleanupDependencies {
1972
- logger: Logger;
1973
- metrics: MetricEmitter;
1974
- now(): number;
1975
- withDatabase: typeof withPrimaryDatabase;
1976
- }
1977
-
1978
- function emitInboxCleanupBacklog(metrics: MetricEmitter, value: number) {
1979
- metrics.emit({
1980
- dimensions: {
1981
- component: 'inbox-cleanup',
1982
- feature: 'async-work',
1983
- operation: 'inbox-cleanup',
1984
- slice: '${name}',
1985
- stage: process.env.EBK_STAGE ?? 'local',
1986
- },
1987
- metricName: 'InboxCleanupBacklog',
1988
- namespace: 'EBK/Async',
1989
- unit: 'Count',
1990
- value,
1991
- });
1992
- }
1993
-
1994
- function emitPerformanceCleanupBacklog(
1995
- metrics: MetricEmitter,
1996
- value: number,
1997
- ) {
1998
- metrics.emit({
1999
- dimensions: {
2000
- component: 'performance-load-cleanup',
2001
- feature: 'performance',
2002
- operation: 'expiry-cleanup',
2003
- slice: '${name}',
2004
- stage: process.env.EBK_STAGE ?? 'local',
2005
- },
2006
- metricName: 'PerformanceLoadCleanupBacklog',
2007
- namespace: 'EBK/Performance',
2008
- unit: 'Count',
2009
- value,
2010
- });
2011
- }
2012
-
2013
- function emitPerformanceCleanupDeadlineBreaches(
2014
- metrics: MetricEmitter,
2015
- value: number,
2016
- ) {
2017
- return metrics.emit({
2018
- dimensions: {
2019
- component: 'performance-load-cleanup',
2020
- feature: 'performance',
2021
- operation: 'expiry-cleanup',
2022
- slice: '${name}',
2023
- stage: process.env.EBK_STAGE ?? 'local',
2024
- },
2025
- metricName: 'PerformanceLoadCleanupDeadlineBreaches',
2026
- namespace: 'EBK/Performance',
2027
- unit: 'Count',
2028
- value,
2029
- });
2030
- }
2031
-
2032
- async function reportPerformanceCleanupDeadlineBreaches(
2033
- client: PgClient,
2034
- metrics: MetricEmitter,
2035
- ): Promise<{ continuationRequired: boolean; reported: number }> {
2036
- await client.query('BEGIN');
2037
- try {
2038
- const pending = await client.query<{ resourceRef: string }>(
2039
- \`SELECT resource_ref AS "resourceRef"
2040
- FROM cleanup_deadline_reports
2041
- WHERE feature = $1
2042
- ORDER BY observed_at, resource_ref
2043
- LIMIT $2
2044
- FOR UPDATE\`,
2045
- [PERFORMANCE_CLEANUP_FEATURE, PERFORMANCE_CLEANUP_MAXIMUM_ROWS + 1],
2046
- );
2047
- const selected = pending.rows.slice(0, PERFORMANCE_CLEANUP_MAXIMUM_ROWS);
2048
- if (
2049
- emitPerformanceCleanupDeadlineBreaches(
2050
- metrics,
2051
- selected.length,
2052
- ) === undefined
2053
- ) {
2054
- throw new Error(
2055
- 'Performance cleanup deadline metric delivery failed.',
2056
- );
2057
- }
2058
- if (selected.length > 0) {
2059
- await client.query(
2060
- \`DELETE FROM cleanup_deadline_reports
2061
- WHERE feature = $1 AND resource_ref = ANY($2::text[])\`,
2062
- [
2063
- PERFORMANCE_CLEANUP_FEATURE,
2064
- selected.map(({ resourceRef }) => resourceRef),
2065
- ],
2066
- );
2067
- }
2068
- await client.query('COMMIT');
2069
- return {
2070
- continuationRequired:
2071
- pending.rows.length > PERFORMANCE_CLEANUP_MAXIMUM_ROWS,
2072
- reported: selected.length,
2073
- };
2074
- } catch (error) {
2075
- await client.query('ROLLBACK').catch(() => undefined);
2076
- throw error;
2077
- }
2078
- }
2079
-
2080
- async function recordPerformanceCleanupDeadlineReports(
2081
- client: PgClient,
2082
- resourceKind: 'async-effect' | 'record',
2083
- resources: readonly { expiresAt: Date; resourceId: string }[],
2084
- ): Promise<void> {
2085
- if (resources.length === 0) return;
2086
- const recorded = await client.query<{
2087
- candidateCount: string;
2088
- recordedCount: string;
2089
- }>(
2090
- \`WITH deadline_candidates AS (
2091
- SELECT
2092
- $1 || ':' || resource_id AS resource_ref,
2093
- expires_at + make_interval(hours => $2) AS deadline_at
2094
- FROM unnest($3::text[], $4::timestamptz[])
2095
- AS deleted(resource_id, expires_at)
2096
- WHERE expires_at + make_interval(hours => $2) <= clock_timestamp()
2097
- ), recorded AS (
2098
- INSERT INTO cleanup_deadline_reports
2099
- (deadline_at, feature, resource_ref)
2100
- SELECT deadline_at, $5, resource_ref
2101
- FROM deadline_candidates
2102
- ON CONFLICT (feature, resource_ref) DO UPDATE
2103
- SET deadline_at = cleanup_deadline_reports.deadline_at
2104
- WHERE cleanup_deadline_reports.deadline_at = EXCLUDED.deadline_at
2105
- RETURNING resource_ref
2106
- )
2107
- SELECT
2108
- (SELECT count(*)::text FROM deadline_candidates)
2109
- AS "candidateCount",
2110
- (SELECT count(*)::text FROM recorded) AS "recordedCount"\`,
2111
- [
2112
- resourceKind,
2113
- PERFORMANCE_CLEANUP_DEADLINE_HOURS,
2114
- resources.map(({ resourceId }) => resourceId),
2115
- resources.map(({ expiresAt }) => expiresAt),
2116
- PERFORMANCE_CLEANUP_FEATURE,
2117
- ],
2118
- );
2119
- if (
2120
- recorded.rows[0]?.candidateCount !== recorded.rows[0]?.recordedCount
2121
- ) {
2122
- throw new Error(
2123
- 'Persisted performance cleanup deadline report is inconsistent.',
2124
- );
2125
- }
2126
- const pending = await client.query<{ count: string }>(
2127
- \`SELECT count(*)::text AS count
2128
- FROM (
2129
- SELECT 1
2130
- FROM cleanup_deadline_reports
2131
- WHERE feature = $1
2132
- LIMIT $2
2133
- ) AS bounded_pending_reports\`,
2134
- [
2135
- PERFORMANCE_CLEANUP_FEATURE,
2136
- PERFORMANCE_CLEANUP_MAXIMUM_PENDING_REPORTS + 1,
2137
- ],
2138
- );
2139
- if (
2140
- Number(pending.rows[0]?.count ?? 0) >
2141
- PERFORMANCE_CLEANUP_MAXIMUM_PENDING_REPORTS
2142
- ) {
2143
- throw new Error(
2144
- 'Performance cleanup pending deadline report inventory was exceeded.',
2145
- );
2146
- }
2147
- }
2148
-
2149
- export function createInboxCleanupHandler(
2150
- dependencies: InboxCleanupDependencies,
2151
- ) {
2152
- return async (event: { id?: string } = {}) => {
2153
- const correlationId = event.id ?? randomUUID();
2154
- const startedAt = dependencies.now();
2155
- return dependencies.withDatabase(
2156
- { correlationId },
2157
- 'async-inbox-cleanup',
2158
- async (client) => {
2159
- let remainingExpired = 0;
2160
- let remainingPerformanceExpired = 0;
2161
- let reportedPerformanceDeadlineBreaches = 0;
2162
- let reportContinuationRequired = false;
2163
- let reportFailure: unknown;
2164
- let removedTotal = 0;
2165
- let removedPerformanceTotal = 0;
2166
- try {
2167
- const reportPendingBreaches = async () => {
2168
- try {
2169
- const result =
2170
- await reportPerformanceCleanupDeadlineBreaches(
2171
- client,
2172
- dependencies.metrics,
2173
- );
2174
- reportedPerformanceDeadlineBreaches += result.reported;
2175
- reportContinuationRequired ||=
2176
- result.continuationRequired;
2177
- } catch (error) {
2178
- reportFailure ??= error;
2179
- }
2180
- };
2181
- await reportPendingBreaches();
2182
- for (;;) {
2183
- await client.query('BEGIN');
2184
- const inboxLimit = Math.min(
2185
- CLEANUP_BATCH_SIZE,
2186
- CLEANUP_MAXIMUM_ROWS - removedTotal,
2187
- );
2188
- const removed =
2189
- inboxLimit > 0
2190
- ? await client.query<{ messageId: string }>(
2191
- \`WITH expired AS (
2192
- SELECT handler_id, message_id
2193
- FROM ebk_inbox
2194
- WHERE expires_at <= now()
2195
- AND (
2196
- status = 'succeeded'
2197
- OR (
2198
- status = 'failed'
2199
- AND (
2200
- result_reference LIKE 'terminal-permanent-%'
2201
- OR result_reference LIKE 'terminal-reconciliation-%'
2202
- OR result_reference IN (
2203
- 'configuration-disabled',
2204
- 'configuration-invalid'
2205
- )
2206
- )
2207
- )
2208
- )
2209
- ORDER BY expires_at, handler_id, message_id
2210
- LIMIT $1
2211
- FOR UPDATE SKIP LOCKED
2212
- )
2213
- DELETE FROM ebk_inbox AS inbox
2214
- USING expired
2215
- WHERE inbox.handler_id = expired.handler_id
2216
- AND inbox.message_id = expired.message_id
2217
- RETURNING inbox.message_id AS "messageId"\`,
2218
- [inboxLimit],
2219
- )
2220
- : { rowCount: 0, rows: [] };
2221
-
2222
- let removedPerformanceThisPage = 0;
2223
- let performanceLimit = Math.min(
2224
- PERFORMANCE_CLEANUP_BATCH_SIZE,
2225
- PERFORMANCE_CLEANUP_MAXIMUM_ROWS -
2226
- removedPerformanceTotal -
2227
- removedPerformanceThisPage,
2228
- );
2229
- if (performanceLimit > 0) {
2230
- const expiredEffects = await client.query<{
2231
- expiresAt: Date;
2232
- resourceId: string;
2233
- }>(
2234
- \`WITH expired AS (
2235
- SELECT effect_id, expires_at
2236
- FROM performance_load_async_effects
2237
- WHERE expires_at <= now()
2238
- ORDER BY expires_at, effect_id
2239
- LIMIT $1
2240
- FOR UPDATE SKIP LOCKED
2241
- )
2242
- DELETE FROM performance_load_async_effects AS effects
2243
- USING expired
2244
- WHERE effects.effect_id = expired.effect_id
2245
- RETURNING effects.effect_id AS "resourceId",
2246
- effects.expires_at AS "expiresAt"\`,
2247
- [performanceLimit],
2248
- );
2249
- await recordPerformanceCleanupDeadlineReports(
2250
- client,
2251
- 'async-effect',
2252
- expiredEffects.rows,
2253
- );
2254
- removedPerformanceThisPage += expiredEffects.rows.length;
2255
- }
2256
- performanceLimit = Math.min(
2257
- PERFORMANCE_CLEANUP_BATCH_SIZE,
2258
- PERFORMANCE_CLEANUP_MAXIMUM_ROWS -
2259
- removedPerformanceTotal -
2260
- removedPerformanceThisPage,
2261
- );
2262
- if (performanceLimit > 0) {
2263
- const expiredRecords = await client.query<{
2264
- expiresAt: Date;
2265
- resourceId: string;
2266
- }>(
2267
- \`WITH expired AS (
2268
- SELECT id, test_expires_at
2269
- FROM records
2270
- WHERE owner_id = 'ebk-performance'
2271
- AND name = 'ebk-protected-performance-load'
2272
- AND test_expires_at <= now()
2273
- ORDER BY test_expires_at, id
2274
- LIMIT $1
2275
- FOR UPDATE SKIP LOCKED
2276
- )
2277
- DELETE FROM records AS records
2278
- USING expired
2279
- WHERE records.id = expired.id
2280
- AND records.owner_id = 'ebk-performance'
2281
- AND records.name = 'ebk-protected-performance-load'
2282
- AND records.test_expires_at <= now()
2283
- RETURNING records.id::text AS "resourceId",
2284
- records.test_expires_at AS "expiresAt"\`,
2285
- [performanceLimit],
2286
- );
2287
- await recordPerformanceCleanupDeadlineReports(
2288
- client,
2289
- 'record',
2290
- expiredRecords.rows,
2291
- );
2292
- removedPerformanceThisPage += expiredRecords.rows.length;
2293
- }
2294
- performanceLimit = Math.min(
2295
- PERFORMANCE_CLEANUP_BATCH_SIZE,
2296
- PERFORMANCE_CLEANUP_MAXIMUM_ROWS -
2297
- removedPerformanceTotal -
2298
- removedPerformanceThisPage,
2299
- );
2300
- if (performanceLimit > 0) {
2301
- const expiredRequests = await client.query(
2302
- \`WITH expired AS (
2303
- SELECT request.plan_digest, request.request_ordinal
2304
- FROM performance_load_requests AS request
2305
- INNER JOIN performance_load_runs AS run
2306
- ON run.plan_digest = request.plan_digest
2307
- WHERE run.expires_at <=
2308
- now() - make_interval(days => $2)
2309
- ORDER BY run.expires_at, request.plan_digest,
2310
- request.request_ordinal
2311
- LIMIT $1
2312
- FOR UPDATE OF request SKIP LOCKED
2313
- )
2314
- DELETE FROM performance_load_requests AS request
2315
- USING expired
2316
- WHERE request.plan_digest = expired.plan_digest
2317
- AND request.request_ordinal = expired.request_ordinal\`,
2318
- [performanceLimit, PERFORMANCE_AUDIT_RETENTION_DAYS],
2319
- );
2320
- removedPerformanceThisPage += expiredRequests.rowCount ?? 0;
2321
- }
2322
- performanceLimit = Math.min(
2323
- PERFORMANCE_CLEANUP_BATCH_SIZE,
2324
- PERFORMANCE_CLEANUP_MAXIMUM_ROWS -
2325
- removedPerformanceTotal -
2326
- removedPerformanceThisPage,
2327
- );
2328
- if (performanceLimit > 0) {
2329
- const expiredRuns = await client.query(
2330
- \`WITH expired AS (
2331
- SELECT run.plan_digest
2332
- FROM performance_load_runs AS run
2333
- WHERE run.expires_at <=
2334
- now() - make_interval(days => $2)
2335
- AND NOT EXISTS (
2336
- SELECT 1
2337
- FROM performance_load_requests AS request
2338
- WHERE request.plan_digest = run.plan_digest
2339
- )
2340
- AND NOT EXISTS (
2341
- SELECT 1
2342
- FROM performance_load_async_effects AS effects
2343
- WHERE effects.plan_digest = run.plan_digest
2344
- )
2345
- AND NOT EXISTS (
2346
- SELECT 1
2347
- FROM records AS performance_record
2348
- WHERE performance_record.owner_id = 'ebk-performance'
2349
- AND performance_record.name =
2350
- 'ebk-protected-performance-load'
2351
- AND performance_record.run_scope = run.plan_digest
2352
- )
2353
- ORDER BY run.expires_at, run.plan_digest
2354
- LIMIT $1
2355
- FOR UPDATE OF run SKIP LOCKED
2356
- )
2357
- DELETE FROM performance_load_runs AS run
2358
- USING expired
2359
- WHERE run.plan_digest = expired.plan_digest\`,
2360
- [performanceLimit, PERFORMANCE_AUDIT_RETENTION_DAYS],
2361
- );
2362
- removedPerformanceThisPage += expiredRuns.rowCount ?? 0;
2363
- }
2364
- const remaining = await client.query<{ count: string }>(
2365
- \`SELECT count(*)::text AS count
2366
- FROM ebk_inbox
2367
- WHERE expires_at <= now()
2368
- AND (
2369
- status = 'succeeded'
2370
- OR (
2371
- status = 'failed'
2372
- AND (
2373
- result_reference LIKE 'terminal-permanent-%'
2374
- OR result_reference LIKE 'terminal-reconciliation-%'
2375
- OR result_reference IN (
2376
- 'configuration-disabled',
2377
- 'configuration-invalid'
2378
- )
2379
- )
2380
- )
2381
- )\`,
2382
- );
2383
- const remainingPerformance = await client.query<{
2384
- count: string;
2385
- }>(
2386
- \`SELECT count(*)::text AS count
2387
- FROM (
2388
- SELECT 1
2389
- FROM performance_load_async_effects
2390
- WHERE expires_at <= now()
2391
- UNION ALL
2392
- SELECT 1
2393
- FROM records
2394
- WHERE owner_id = 'ebk-performance'
2395
- AND name = 'ebk-protected-performance-load'
2396
- AND test_expires_at <= now()
2397
- UNION ALL
2398
- SELECT 1
2399
- FROM performance_load_requests AS request
2400
- INNER JOIN performance_load_runs AS run
2401
- ON run.plan_digest = request.plan_digest
2402
- WHERE run.expires_at <=
2403
- now() - make_interval(days => $1)
2404
- UNION ALL
2405
- SELECT 1
2406
- FROM performance_load_runs AS run
2407
- WHERE run.expires_at <=
2408
- now() - make_interval(days => $1)
2409
- AND NOT EXISTS (
2410
- SELECT 1
2411
- FROM performance_load_requests AS request
2412
- WHERE request.plan_digest = run.plan_digest
2413
- )
2414
- AND NOT EXISTS (
2415
- SELECT 1
2416
- FROM performance_load_async_effects AS effects
2417
- WHERE effects.plan_digest = run.plan_digest
2418
- )
2419
- AND NOT EXISTS (
2420
- SELECT 1
2421
- FROM records AS performance_record
2422
- WHERE performance_record.owner_id = 'ebk-performance'
2423
- AND performance_record.name =
2424
- 'ebk-protected-performance-load'
2425
- AND performance_record.run_scope = run.plan_digest
2426
- )
2427
- LIMIT $2
2428
- ) AS bounded_backlog\`,
2429
- [
2430
- PERFORMANCE_AUDIT_RETENTION_DAYS,
2431
- PERFORMANCE_CLEANUP_MAXIMUM_ROWS + 1,
2432
- ],
2433
- );
2434
- await client.query('COMMIT');
2435
- const removedThisBatch = removed.rowCount ?? 0;
2436
- removedTotal += removedThisBatch;
2437
- removedPerformanceTotal += removedPerformanceThisPage;
2438
- remainingExpired = Number(remaining.rows[0]?.count ?? 0);
2439
- remainingPerformanceExpired = Number(
2440
- remainingPerformance.rows[0]?.count ?? 0,
2441
- );
2442
- const inboxCanContinue =
2443
- remainingExpired > 0 &&
2444
- removedTotal < CLEANUP_MAXIMUM_ROWS;
2445
- const performanceCanContinue =
2446
- remainingPerformanceExpired > 0 &&
2447
- removedPerformanceTotal <
2448
- PERFORMANCE_CLEANUP_MAXIMUM_ROWS;
2449
- if (
2450
- (!inboxCanContinue && !performanceCanContinue) ||
2451
- removedThisBatch + removedPerformanceThisPage === 0 ||
2452
- dependencies.now() - startedAt >=
2453
- CLEANUP_MAXIMUM_RUNTIME_MILLISECONDS
2454
- ) {
2455
- break;
2456
- }
2457
- }
2458
- emitInboxCleanupBacklog(dependencies.metrics, remainingExpired);
2459
- emitPerformanceCleanupBacklog(
2460
- dependencies.metrics,
2461
- remainingPerformanceExpired,
2462
- );
2463
- await reportPendingBreaches();
2464
- if (reportFailure !== undefined) {
2465
- throw reportFailure;
2466
- }
2467
- if (
2468
- reportedPerformanceDeadlineBreaches > 0 ||
2469
- reportContinuationRequired
2470
- ) {
2471
- throw new Error('performance-load-cleanup-deadline-breached');
2472
- }
2473
- dependencies.logger.info('Async inbox cleanup completed', {
2474
- attributes: {
2475
- batchLimit: CLEANUP_BATCH_SIZE,
2476
- invocationLimit: CLEANUP_MAXIMUM_ROWS,
2477
- performanceAuditRetentionDays:
2478
- PERFORMANCE_AUDIT_RETENTION_DAYS,
2479
- performanceBatchLimit: PERFORMANCE_CLEANUP_BATCH_SIZE,
2480
- performanceCleanupDeadlineHours:
2481
- PERFORMANCE_CLEANUP_DEADLINE_HOURS,
2482
- performanceInvocationLimit:
2483
- PERFORMANCE_CLEANUP_MAXIMUM_ROWS,
2484
- reportedPerformanceDeadlineBreaches,
2485
- remainingPerformanceExpired,
2486
- remainingExpired,
2487
- removedPerformance: removedPerformanceTotal,
2488
- removed: removedTotal,
2489
- },
2490
- context: { correlationId },
2491
- outcome:
2492
- remainingExpired === 0 &&
2493
- remainingPerformanceExpired === 0
2494
- ? 'success'
2495
- : 'unknown',
2496
- });
2497
- return {
2498
- batchLimit: CLEANUP_BATCH_SIZE,
2499
- invocationLimit: CLEANUP_MAXIMUM_ROWS,
2500
- performanceAuditRetentionDays:
2501
- PERFORMANCE_AUDIT_RETENTION_DAYS,
2502
- performanceBatchLimit: PERFORMANCE_CLEANUP_BATCH_SIZE,
2503
- performanceCleanupDeadlineHours:
2504
- PERFORMANCE_CLEANUP_DEADLINE_HOURS,
2505
- performanceInvocationLimit:
2506
- PERFORMANCE_CLEANUP_MAXIMUM_ROWS,
2507
- reportedPerformanceDeadlineBreaches,
2508
- remainingPerformanceExpired,
2509
- remainingExpired,
2510
- removedPerformance: removedPerformanceTotal,
2511
- removed: removedTotal,
2512
- };
2513
- } catch (error) {
2514
- await client.query('ROLLBACK').catch(() => undefined);
2515
- dependencies.logger.error('Async inbox cleanup failed', {
2516
- context: { correlationId },
2517
- error,
2518
- outcome: 'failure',
2519
- });
2520
- throw error;
2521
- }
2522
- },
2523
- );
2524
- };
2525
- }
2526
-
2527
- const logger = createLogger({
2528
- component: 'inbox-cleanup',
2529
- feature: 'async-work',
2530
- operation: 'inbox-cleanup',
2531
- slice: '${name}',
2532
- stage: process.env.EBK_STAGE ?? 'local',
2533
- workspace: process.env.EBK_WORKSPACE ?? '${name}',
2534
- });
2535
-
2536
- export const handler = createInboxCleanupHandler({
2537
- logger,
2538
- metrics: createMetricEmitter(),
2539
- now: Date.now,
2540
- withDatabase: withPrimaryDatabase,
2541
- });
2542
1254
  `,
2543
1255
  'async/workflow-task.ts': `import {
2544
1256
  DeleteItemCommand,
@@ -3298,6 +2010,7 @@ describe('generated async failure fixture', () => {
3298
2010
  it,
3299
2011
  vi,
3300
2012
  } from 'vitest';
2013
+ ${"import { DynamoDBClient, GetItemCommand, TransactWriteItemsCommand, type AttributeValue } from '@aws-sdk/client-dynamodb';\nimport { createDynamoPersistence } from '@empire-builder-kit/runtime/key-value';\nimport { markProviderEffectStarted } from '../async/provider-inbox.js';\n"}\
3301
2014
  import { createInboxCleanupHandler } from '../async/inbox-cleanup.js';
3302
2015
  import { createOutboxRelayHandler } from '../async/outbox-relay.js';
3303
2016
  import {
@@ -3335,175 +2048,7 @@ afterEach(() => {
3335
2048
  });
3336
2049
 
3337
2050
  describe('generated async handlers', () => {
3338
- it('routes a stale unproven provider effect to reconciliation without delivery', async () => {
3339
- const delivery = createQueuedProviderDelivery({
3340
- createdAt: '2026-01-01T00:00:00.000Z',
3341
- operationId: 'operation-one',
3342
- request: { value: true },
3343
- });
3344
- const deliver = vi.fn();
3345
- const client = {
3346
- async query(statement: string) {
3347
- if (statement === 'BEGIN' || statement === 'COMMIT') {
3348
- return { rowCount: null, rows: [] };
3349
- }
3350
- if (statement.includes('INSERT INTO ebk_inbox')) {
3351
- return { rowCount: 0, rows: [] };
3352
- }
3353
- if (statement.includes('SELECT attempts')) {
3354
- return {
3355
- rowCount: 1,
3356
- rows: [{
3357
- attempts: 1,
3358
- lastAttemptAt: new Date('2026-01-01T00:00:00.000Z'),
3359
- payloadDigest: delivery.requestDigest,
3360
- resultReference: 'effect-started-prior-attempt',
3361
- status: 'claimed',
3362
- }],
3363
- };
3364
- }
3365
- if (statement.includes("status = 'failed'")) {
3366
- return { rowCount: 1, rows: [] };
3367
- }
3368
- throw new Error('Unexpected provider query: ' + statement);
3369
- },
3370
- };
3371
- const handler = createProviderWorkerHandler({
3372
- createAttemptToken: () => 'new-attempt',
3373
- deliver: deliver as never,
3374
- evaluateRollout: vi.fn() as never,
3375
- logger: logger as never,
3376
- now: () => '2026-01-01T00:03:00.000Z',
3377
- withDatabase: (async (_context, _workload, work) =>
3378
- work(client as never)) as never,
3379
- });
3380
-
3381
- const response = await handler({
3382
- Records: [{
3383
- body: JSON.stringify(delivery),
3384
- messageId: 'queue-message-one',
3385
- }],
3386
- });
3387
-
3388
- expect(response.batchItemFailures).toEqual([
3389
- { itemIdentifier: 'queue-message-one' },
3390
- ]);
3391
- expect(deliver).not.toHaveBeenCalled();
3392
- });
3393
-
3394
- it('rolls back when an unproven terminal reconciliation transition is lost', async () => {
3395
- const delivery = createQueuedProviderDelivery({
3396
- createdAt: '2026-01-01T00:00:00.000Z',
3397
- operationId: 'operation-transition-lost',
3398
- request: { value: true },
3399
- });
3400
- const statements: string[] = [];
3401
- const client = {
3402
- async query(statement: string) {
3403
- statements.push(statement);
3404
- if (statement === 'BEGIN' || statement === 'ROLLBACK') {
3405
- return { rowCount: null, rows: [] };
3406
- }
3407
- if (statement.includes('INSERT INTO ebk_inbox')) {
3408
- return { rowCount: 0, rows: [] };
3409
- }
3410
- if (statement.includes('SELECT attempts')) {
3411
- return {
3412
- rowCount: 1,
3413
- rows: [{
3414
- attempts: 1,
3415
- lastAttemptAt: new Date('2026-01-01T00:00:00.000Z'),
3416
- payloadDigest: delivery.requestDigest,
3417
- resultReference: 'effect-started-prior-attempt',
3418
- status: 'claimed',
3419
- }],
3420
- };
3421
- }
3422
- if (statement.includes("status = 'failed'")) {
3423
- return { rowCount: 0, rows: [] };
3424
- }
3425
- throw new Error('Unexpected provider query: ' + statement);
3426
- },
3427
- };
3428
-
3429
- await expect(
3430
- claimProviderDelivery(
3431
- client as never,
3432
- delivery,
3433
- '2026-01-01T00:03:00.000Z',
3434
- ),
3435
- ).rejects.toThrow('provider-reconciliation-transition-lost');
3436
- expect(statements).toContain('ROLLBACK');
3437
- expect(statements).not.toContain('COMMIT');
3438
- });
3439
-
3440
- it('retries a stale effect only when provider repeat safety is guaranteed', async () => {
3441
- const unproven = createQueuedProviderDelivery({
3442
- createdAt: '2026-01-01T00:00:00.000Z',
3443
- operationId: 'operation-guaranteed',
3444
- request: { value: true },
3445
- });
3446
- const delivery = {
3447
- ...unproven,
3448
- contract: {
3449
- ...unproven.contract,
3450
- idempotencyRepeatSafety: 'provider-guaranteed' as const,
3451
- },
3452
- };
3453
- const client = {
3454
- async query(statement: string) {
3455
- if (statement === 'BEGIN' || statement === 'COMMIT') {
3456
- return { rowCount: null, rows: [] };
3457
- }
3458
- if (statement.includes('INSERT INTO ebk_inbox')) {
3459
- return { rowCount: 0, rows: [] };
3460
- }
3461
- if (statement.includes('SELECT attempts')) {
3462
- return {
3463
- rowCount: 1,
3464
- rows: [{
3465
- attempts: 1,
3466
- lastAttemptAt: new Date('2026-01-01T00:00:00.000Z'),
3467
- payloadDigest: delivery.requestDigest,
3468
- resultReference: 'effect-started-prior-attempt',
3469
- status: 'claimed',
3470
- }],
3471
- };
3472
- }
3473
- if (statement.includes('UPDATE ebk_inbox')) {
3474
- return { rowCount: 1, rows: [] };
3475
- }
3476
- throw new Error('Unexpected provider query: ' + statement);
3477
- },
3478
- };
3479
- const deliver = vi.fn().mockResolvedValue({
3480
- attempts: 1,
3481
- deliveryId: delivery.deliveryId,
3482
- outcome: 'confirmed',
3483
- providerReference: 'provider-reference',
3484
- statusCode: 202,
3485
- });
3486
- const handler = createProviderWorkerHandler({
3487
- createAttemptToken: () => 'guaranteed-attempt',
3488
- deliver: deliver as never,
3489
- evaluateRollout: vi.fn().mockResolvedValue({ assigned: true }) as never,
3490
- logger: logger as never,
3491
- now: () => '2026-01-01T00:03:00.000Z',
3492
- withDatabase: (async (_context, _workload, work) =>
3493
- work(client as never)) as never,
3494
- });
3495
-
3496
- await expect(
3497
- handler({
3498
- Records: [{
3499
- body: JSON.stringify(delivery),
3500
- messageId: 'queue-message-guaranteed',
3501
- }],
3502
- }),
3503
- ).resolves.toEqual({ batchItemFailures: [] });
3504
- expect(deliver).toHaveBeenCalledTimes(1);
3505
- });
3506
-
2051
+ ${(0, built_in_plan_key_value_provider_js_1.renderKeyValueProviderTestCases)(name)}
3507
2052
  it('treats a retry after a workflow effect marker as compensation-required', async () => {
3508
2053
  const runStep = vi.fn();
3509
2054
  const transition = vi.fn();
@@ -4093,446 +2638,8 @@ describe('generated async handlers', () => {
4093
2638
  );
4094
2639
  });
4095
2640
 
4096
- it('publishes and acknowledges an outbox row before converging', async () => {
4097
- const statements: string[] = [];
4098
- const client = {
4099
- async query(statement: string) {
4100
- statements.push(statement);
4101
- if (statement.includes('FROM data_lifecycle_outbox') &&
4102
- statement.includes('FOR UPDATE')) {
4103
- return {
4104
- rows: [{
4105
- eventJson: { Detail: '{}', DetailType: 'Fixture' },
4106
- idempotencyKey: 'outbox-one',
4107
- }],
4108
- };
4109
- }
4110
- if (statement.includes('count(*)')) {
4111
- return { rows: [{ count: '0' }] };
4112
- }
4113
- return { rowCount: 1, rows: [] };
4114
- },
4115
- };
4116
- const publish = vi.fn().mockResolvedValue({
4117
- Entries: [{ EventId: 'event-one' }],
4118
- });
4119
- const handler = createOutboxRelayHandler({
4120
- logger: logger as never,
4121
- metrics: { emit: vi.fn() },
4122
- publish: publish as never,
4123
- withDatabase: (async (_context, _workload, work) =>
4124
- work(client as never)) as never,
4125
- });
4126
-
4127
- await expect(handler({ id: 'correlation-one' })).resolves.toMatchObject({
4128
- failed: 0,
4129
- outcome: 'converged',
4130
- published: 1,
4131
- });
4132
- expect(publish).toHaveBeenCalledTimes(1);
4133
- expect(statements.some((value) => value.includes('published_at = now()')))
4134
- .toBe(true);
4135
- });
4136
-
4137
- it('processes protected performance work through an isolated sink', async () => {
4138
- const client = {
4139
- async query(statement: string) {
4140
- if (statement.includes('UPDATE performance_load_async_effects')) {
4141
- return { rows: [{ effectId: 'effect-one' }] };
4142
- }
4143
- if (
4144
- statement.includes('FROM data_lifecycle_outbox') &&
4145
- statement.includes('FOR UPDATE')
4146
- ) {
4147
- return { rows: [] };
4148
- }
4149
- return { rowCount: 1, rows: [] };
4150
- },
4151
- };
4152
- const publish = vi.fn();
4153
- const handler = createOutboxRelayHandler({
4154
- logger: logger as never,
4155
- metrics: { emit: vi.fn() },
4156
- publish: publish as never,
4157
- withDatabase: (async (_context, _workload, work) =>
4158
- work(client as never)) as never,
4159
- });
4160
-
4161
- await expect(handler({ id: 'performance-one' })).resolves.toMatchObject({
4162
- failed: 0,
4163
- outcome: 'converged',
4164
- processedPerformance: 1,
4165
- published: 0,
4166
- });
4167
- expect(publish).not.toHaveBeenCalled();
4168
- });
4169
-
4170
- it('drains terminal inbox rows in bounded pages and never selects active claims', async () => {
4171
- const metrics = { emit: vi.fn(() => ({} as never)) };
4172
- const deleteCounts = [1_000, 500];
4173
- const remainingCounts = ['500', '0'];
4174
- const performanceDeleteCounts = new Map([
4175
- ['performance_load_async_effects', [1, 0]],
4176
- ['records', [1, 0]],
4177
- ['performance_load_requests', [1, 0]],
4178
- ['performance_load_runs', [1, 0]],
4179
- ]);
4180
- const performanceStatements: string[] = [];
4181
- const client = {
4182
- async query(statement: string, parameters?: readonly unknown[]) {
4183
- if (
4184
- statement === 'BEGIN' ||
4185
- statement === 'COMMIT' ||
4186
- statement === 'ROLLBACK'
4187
- ) {
4188
- return { rowCount: null, rows: [] };
4189
- }
4190
- if (
4191
- statement.includes('SELECT resource_ref AS "resourceRef"') &&
4192
- statement.includes('FROM cleanup_deadline_reports')
4193
- ) {
4194
- return { rows: [] };
4195
- }
4196
- if (statement.includes('DELETE FROM cleanup_deadline_reports')) {
4197
- return { rowCount: 0, rows: [] };
4198
- }
4199
- if (statement.includes('WITH deadline_candidates AS')) {
4200
- expect(statement).toContain('clock_timestamp()');
4201
- expect(statement).toContain(
4202
- 'ON CONFLICT (feature, resource_ref) DO UPDATE',
4203
- );
4204
- return {
4205
- rows: [{ candidateCount: '0', recordedCount: '0' }],
4206
- };
4207
- }
4208
- if (statement.includes('bounded_pending_reports')) {
4209
- return { rows: [{ count: '0' }] };
4210
- }
4211
- if (statement.includes('DELETE FROM ebk_inbox')) {
4212
- expect(statement).toContain("status = 'succeeded'");
4213
- expect(statement).toContain(
4214
- "result_reference LIKE 'terminal-permanent-%'",
4215
- );
4216
- expect(statement).toContain(
4217
- "result_reference LIKE 'terminal-reconciliation-%'",
4218
- );
4219
- expect(statement).toContain("'configuration-disabled'");
4220
- expect(statement).toContain("'configuration-invalid'");
4221
- return { rowCount: deleteCounts.shift() ?? 0, rows: [] };
4222
- }
4223
- if (
4224
- statement.includes('SELECT count(*)') &&
4225
- statement.includes('FROM ebk_inbox')
4226
- ) {
4227
- expect(statement).toContain("status = 'succeeded'");
4228
- expect(statement).toContain(
4229
- "result_reference LIKE 'terminal-permanent-%'",
4230
- );
4231
- expect(statement).toContain("'configuration-disabled'");
4232
- expect(statement).toContain("'configuration-invalid'");
4233
- expect(statement).not.toContain("status = 'claimed'");
4234
- return { rows: [{ count: remainingCounts.shift() ?? '0' }] };
4235
- }
4236
- if (
4237
- statement.includes('DELETE FROM performance_load_async_effects')
4238
- ) {
4239
- performanceStatements.push(statement);
4240
- expect(statement).toContain('expires_at <= now()');
4241
- const count =
4242
- performanceDeleteCounts
4243
- .get('performance_load_async_effects')
4244
- ?.shift() ?? 0;
4245
- return {
4246
- rowCount: count,
4247
- rows: Array.from({ length: count }, (_, index) => ({
4248
- expiresAt: new Date('2026-08-03T00:00:00.000Z'),
4249
- resourceId: 'effect-' + String(index),
4250
- })),
4251
- };
4252
- }
4253
- if (statement.includes('DELETE FROM records')) {
4254
- performanceStatements.push(statement);
4255
- expect(statement).toContain("owner_id = 'ebk-performance'");
4256
- expect(statement).toContain(
4257
- "name = 'ebk-protected-performance-load'",
4258
- );
4259
- expect(statement).toContain('test_expires_at <= now()');
4260
- const count =
4261
- performanceDeleteCounts.get('records')?.shift() ?? 0;
4262
- return {
4263
- rowCount: count,
4264
- rows: Array.from({ length: count }, (_, index) => ({
4265
- expiresAt: new Date('2026-08-03T00:00:00.000Z'),
4266
- resourceId: 'record-' + String(index),
4267
- })),
4268
- };
4269
- }
4270
- if (statement.includes('DELETE FROM performance_load_requests')) {
4271
- performanceStatements.push(statement);
4272
- expect(statement).toContain(
4273
- 'now() - make_interval(days => $2)',
4274
- );
4275
- expect(parameters?.[1]).toBe(30);
4276
- return {
4277
- rowCount:
4278
- performanceDeleteCounts
4279
- .get('performance_load_requests')
4280
- ?.shift() ?? 0,
4281
- rows: [],
4282
- };
4283
- }
4284
- if (statement.includes('DELETE FROM performance_load_runs')) {
4285
- performanceStatements.push(statement);
4286
- expect(statement).toContain(
4287
- 'FROM performance_load_requests AS request',
4288
- );
4289
- expect(statement).toContain(
4290
- 'FROM performance_load_async_effects AS effects',
4291
- );
4292
- expect(statement).toContain('FROM records AS performance_record');
4293
- expect(parameters?.[1]).toBe(30);
4294
- return {
4295
- rowCount:
4296
- performanceDeleteCounts
4297
- .get('performance_load_runs')
4298
- ?.shift() ?? 0,
4299
- rows: [],
4300
- };
4301
- }
4302
- if (
4303
- statement.includes('AS count') &&
4304
- statement.includes('performance_load_async_effects')
4305
- ) {
4306
- expect(statement).toContain("owner_id = 'ebk-performance'");
4307
- expect(statement).toContain(
4308
- "name = 'ebk-protected-performance-load'",
4309
- );
4310
- expect(statement).toContain('FROM records AS performance_record');
4311
- expect(statement).toContain('LIMIT $2');
4312
- expect(parameters).toEqual([30, 5_001]);
4313
- return { rows: [{ count: '0' }] };
4314
- }
4315
- throw new Error('Unexpected cleanup query: ' + statement);
4316
- },
4317
- };
4318
- const handler = createInboxCleanupHandler({
4319
- logger: logger as never,
4320
- metrics,
4321
- now: () => 0,
4322
- withDatabase: (async (_context, _workload, work) =>
4323
- work(client as never)) as never,
4324
- });
4325
-
4326
- await expect(handler({ id: 'cleanup-one' })).resolves.toMatchObject({
4327
- performanceCleanupDeadlineHours: 24,
4328
- remainingExpired: 0,
4329
- reportedPerformanceDeadlineBreaches: 0,
4330
- remainingPerformanceExpired: 0,
4331
- removed: 1_500,
4332
- removedPerformance: 4,
4333
- });
4334
- expect(metrics.emit).toHaveBeenCalledWith(
4335
- expect.objectContaining({
4336
- metricName: 'InboxCleanupBacklog',
4337
- value: 0,
4338
- }),
4339
- );
4340
- expect(metrics.emit).toHaveBeenCalledWith(
4341
- expect.objectContaining({
4342
- metricName: 'PerformanceLoadCleanupBacklog',
4343
- value: 0,
4344
- }),
4345
- );
4346
- expect(metrics.emit).toHaveBeenCalledWith(
4347
- expect.objectContaining({
4348
- metricName: 'PerformanceLoadCleanupDeadlineBreaches',
4349
- value: 0,
4350
- }),
4351
- );
4352
- expect(performanceStatements).toHaveLength(8);
4353
- });
4354
-
4355
- it('fails the scheduled invocation when protected load residue exceeds the cleanup deadline', async () => {
4356
- const metrics = { emit: vi.fn(() => ({} as never)) };
4357
- const pendingReports = new Set(['async-effect:effect-one']);
4358
- const client = {
4359
- async query(statement: string, parameters?: readonly unknown[]) {
4360
- if (
4361
- statement === 'BEGIN' ||
4362
- statement === 'COMMIT' ||
4363
- statement === 'ROLLBACK'
4364
- ) {
4365
- return { rowCount: null, rows: [] };
4366
- }
4367
- if (statement.includes('SELECT resource_ref AS "resourceRef"')) {
4368
- return {
4369
- rows: [...pendingReports].map((resourceRef) => ({ resourceRef })),
4370
- };
4371
- }
4372
- if (statement.includes('DELETE FROM cleanup_deadline_reports')) {
4373
- for (const resourceRef of parameters?.[1] as readonly string[]) {
4374
- pendingReports.delete(resourceRef);
4375
- }
4376
- return { rowCount: 1, rows: [] };
4377
- }
4378
- if (
4379
- statement.includes('DELETE FROM performance_load_async_effects') ||
4380
- statement.includes('DELETE FROM records')
4381
- ) {
4382
- return { rowCount: 0, rows: [] };
4383
- }
4384
- if (statement.includes('DELETE FROM')) {
4385
- return { rowCount: 0, rows: [] };
4386
- }
4387
- if (statement.includes('SELECT count(*)')) {
4388
- return { rows: [{ count: '0' }] };
4389
- }
4390
- throw new Error('Unexpected cleanup deadline query: ' + statement);
4391
- },
4392
- };
4393
- const handler = createInboxCleanupHandler({
4394
- logger: { error: vi.fn(), info: vi.fn() } as never,
4395
- metrics,
4396
- now: () => 0,
4397
- withDatabase: (async (_context, _workload, work) =>
4398
- work(client as never)) as never,
4399
- });
4400
-
4401
- await expect(handler({ id: 'cleanup-deadline' })).rejects.toThrow(
4402
- 'performance-load-cleanup-deadline-breached',
4403
- );
4404
- expect(metrics.emit).toHaveBeenCalledWith(
4405
- expect.objectContaining({
4406
- metricName: 'PerformanceLoadCleanupDeadlineBreaches',
4407
- value: 1,
4408
- }),
4409
- );
4410
- expect(pendingReports.size).toBe(0);
4411
- });
4412
-
4413
- it('retries deadline telemetry when its post-emission commit fails', async () => {
4414
- const pendingReports = new Set(['record:record-one']);
4415
- let failReportCommits = true;
4416
- let reportTransaction = false;
4417
- let snapshot = new Set<string>();
4418
- const client = {
4419
- async query(statement: string, parameters?: readonly unknown[]) {
4420
- if (statement === 'BEGIN') {
4421
- snapshot = new Set(pendingReports);
4422
- reportTransaction = false;
4423
- return { rowCount: null, rows: [] };
4424
- }
4425
- if (statement === 'COMMIT') {
4426
- if (reportTransaction && failReportCommits) {
4427
- throw new Error('simulated report commit crash');
4428
- }
4429
- return { rowCount: null, rows: [] };
4430
- }
4431
- if (statement === 'ROLLBACK') {
4432
- pendingReports.clear();
4433
- for (const resourceRef of snapshot) pendingReports.add(resourceRef);
4434
- return { rowCount: null, rows: [] };
4435
- }
4436
- if (statement.includes('SELECT resource_ref AS "resourceRef"')) {
4437
- reportTransaction = true;
4438
- return {
4439
- rows: [...pendingReports].map((resourceRef) => ({ resourceRef })),
4440
- };
4441
- }
4442
- if (statement.includes('DELETE FROM cleanup_deadline_reports')) {
4443
- for (const resourceRef of parameters?.[1] as readonly string[]) {
4444
- pendingReports.delete(resourceRef);
4445
- }
4446
- return { rowCount: 1, rows: [] };
4447
- }
4448
- if (
4449
- statement.includes('DELETE FROM performance_load_async_effects') ||
4450
- statement.includes('DELETE FROM records')
4451
- ) {
4452
- return { rowCount: 0, rows: [] };
4453
- }
4454
- if (statement.includes('DELETE FROM')) {
4455
- return { rowCount: 0, rows: [] };
4456
- }
4457
- if (statement.includes('SELECT count(*)')) {
4458
- return { rows: [{ count: '0' }] };
4459
- }
4460
- throw new Error('Unexpected cleanup retry query: ' + statement);
4461
- },
4462
- };
4463
- const firstMetrics = { emit: vi.fn(() => ({} as never)) };
4464
- const createHandler = (metrics: typeof firstMetrics) =>
4465
- createInboxCleanupHandler({
4466
- logger: { error: vi.fn(), info: vi.fn() } as never,
4467
- metrics,
4468
- now: () => 0,
4469
- withDatabase: (async (_context, _workload, work) =>
4470
- work(client as never)) as never,
4471
- });
4472
-
4473
- await expect(
4474
- createHandler(firstMetrics)({ id: 'cleanup-report-crash' }),
4475
- ).rejects.toThrow('simulated report commit crash');
4476
- expect(pendingReports.size).toBe(1);
4477
- expect(firstMetrics.emit).toHaveBeenCalledWith(
4478
- expect.objectContaining({
4479
- metricName: 'PerformanceLoadCleanupDeadlineBreaches',
4480
- value: 1,
4481
- }),
4482
- );
4483
-
4484
- failReportCommits = false;
4485
- const retryMetrics = { emit: vi.fn(() => ({} as never)) };
4486
- await expect(
4487
- createHandler(retryMetrics)({ id: 'cleanup-report-retry' }),
4488
- ).rejects.toThrow('performance-load-cleanup-deadline-breached');
4489
- expect(pendingReports.size).toBe(0);
4490
- expect(retryMetrics.emit).toHaveBeenCalledWith(
4491
- expect.objectContaining({
4492
- metricName: 'PerformanceLoadCleanupDeadlineBreaches',
4493
- value: 1,
4494
- }),
4495
- );
4496
- });
4497
-
4498
- it('surfaces publish-before-database-ack as retryable at-least-once work', async () => {
4499
- const client = {
4500
- async query(statement: string) {
4501
- if (statement.includes('FROM data_lifecycle_outbox') &&
4502
- statement.includes('FOR UPDATE')) {
4503
- return {
4504
- rows: [{
4505
- eventJson: { Detail: '{}', DetailType: 'Fixture' },
4506
- idempotencyKey: 'outbox-crash',
4507
- }],
4508
- };
4509
- }
4510
- if (statement.includes('published_at = now()')) {
4511
- throw new Error('database unavailable after publish');
4512
- }
4513
- return { rowCount: 1, rows: [] };
4514
- },
4515
- };
4516
- const publish = vi.fn().mockResolvedValue({
4517
- Entries: [{ EventId: 'event-one' }],
4518
- });
4519
- const handler = createOutboxRelayHandler({
4520
- logger: logger as never,
4521
- metrics: { emit: vi.fn() },
4522
- publish: publish as never,
4523
- withDatabase: (async (_context, _workload, work) =>
4524
- work(client as never)) as never,
4525
- });
4526
-
4527
- await expect(handler({ id: 'correlation-crash' })).rejects.toThrow(
4528
- 'database unavailable after publish',
4529
- );
4530
- await expect(handler({ id: 'correlation-retry' })).rejects.toThrow(
4531
- 'database unavailable after publish',
4532
- );
4533
- expect(publish).toHaveBeenCalledTimes(2);
4534
- });
4535
-
2641
+ ${(0, built_in_plan_key_value_performance_js_1.renderKeyValueOutboxTests)()}
2642
+ ${(0, built_in_plan_key_value_cleanup_js_1.renderKeyValueCleanupTests)()}
4536
2643
  it('enforces archive hard caps and cancels an active unsafe replay', async () => {
4537
2644
  expect(() =>
4538
2645
  assertReplayArchiveHardCaps({
@@ -4579,9 +2686,9 @@ if (contract.schemaVersion !== 1 || contract.slice !== '${name}') {
4579
2686
  fail('work contract identity is invalid.');
4580
2687
  }
4581
2688
  if (
4582
- contract.consistency?.inboxTable !== 'ebk_inbox' ||
4583
- !contract.consistency?.outboxTable ||
4584
- contract.consistency?.transactionBoundary !== 'injected-adapter'
2689
+ contract.consistency?.inboxTable !== '${'slice-key-value'}' ||
2690
+ contract.consistency?.outboxTable !== '${'slice-key-value'}' ||
2691
+ contract.consistency?.transactionBoundary !== '${'native-dynamodb-transaction'}'
4585
2692
  ) {
4586
2693
  fail('the explicit inbox/outbox transaction contract is missing.');
4587
2694
  }
@@ -4589,7 +2696,7 @@ if (
4589
2696
  contract.queue?.batchItemFailures !== true ||
4590
2697
  contract.queue?.conflictPolicy !== 'same-id-different-payload-fails' ||
4591
2698
  contract.queue?.idempotencyWindowSeconds !== 2_592_000 ||
4592
- contract.queue?.inboxCleanupBatchSize !== 1_000 ||
2699
+ contract.queue?.inboxCleanupBatchSize !== ${20} ||
4593
2700
  contract.queue?.inboxCleanupIntervalSeconds !== 3_600 ||
4594
2701
  contract.queue?.inboxCleanupInvocationLimit !== 10_000 ||
4595
2702
  contract.queue?.performanceCleanupDeadlineSeconds !== 86_400 ||