@empire-builder-kit/nx 1.0.0-rc.4 → 1.0.0-rc.40

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