deepline 0.3.88 → 0.3.90

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 (280) hide show
  1. package/contracts/install-commands.json +29 -0
  2. package/dist/bundling-sources/sdk/src/client.ts +652 -39
  3. package/dist/bundling-sources/sdk/src/config.ts +77 -0
  4. package/dist/bundling-sources/sdk/src/http.ts +76 -30
  5. package/dist/bundling-sources/sdk/src/index.ts +10 -0
  6. package/dist/bundling-sources/sdk/src/monitor-fleet-contract.ts +1 -1
  7. package/dist/bundling-sources/sdk/src/pagination.ts +25 -0
  8. package/dist/bundling-sources/sdk/src/play.ts +15 -1
  9. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +3 -3
  10. package/dist/bundling-sources/sdk/src/release.ts +16 -9
  11. package/dist/bundling-sources/sdk/src/types.ts +106 -4
  12. package/dist/bundling-sources/shared_libs/integration-contracts/AGENTS.md +9 -0
  13. package/dist/bundling-sources/shared_libs/integration-contracts/README.md +3 -0
  14. package/dist/bundling-sources/shared_libs/integration-contracts/index.ts +2 -0
  15. package/dist/bundling-sources/shared_libs/monitors/analytics-install-guides.ts +77 -0
  16. package/dist/bundling-sources/shared_libs/monitors/analytics-public.ts +10 -0
  17. package/dist/bundling-sources/shared_libs/monitors/billing/charges.ts +125 -0
  18. package/dist/bundling-sources/shared_libs/monitors/billing/policy-builders.ts +686 -0
  19. package/dist/bundling-sources/shared_libs/monitors/billing/pricing.ts +54 -0
  20. package/dist/bundling-sources/shared_libs/monitors/billing/public-pricing.ts +72 -0
  21. package/dist/bundling-sources/shared_libs/monitors/billing/session.ts +45 -0
  22. package/dist/bundling-sources/shared_libs/monitors/billing/state.ts +454 -0
  23. package/dist/bundling-sources/shared_libs/monitors/billing/tamradar.ts +260 -0
  24. package/dist/bundling-sources/shared_libs/monitors/billing/types.ts +215 -0
  25. package/dist/bundling-sources/shared_libs/monitors/callback-security.ts +333 -0
  26. package/dist/bundling-sources/shared_libs/monitors/cursor-page.ts +42 -0
  27. package/dist/bundling-sources/shared_libs/monitors/deactivation-reasons.ts +16 -0
  28. package/dist/bundling-sources/shared_libs/monitors/framework-managed-payload-fields.ts +71 -0
  29. package/dist/bundling-sources/shared_libs/monitors/generated/provider-monitor-callback-admission-targets.ts +16 -0
  30. package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +270 -0
  31. package/dist/bundling-sources/shared_libs/monitors/inbound-publish-key.ts +39 -0
  32. package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +82 -0
  33. package/dist/bundling-sources/shared_libs/monitors/inventory-reconciliation.ts +59 -0
  34. package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +471 -0
  35. package/dist/bundling-sources/shared_libs/monitors/org-monitor-limits.ts +1 -1
  36. package/dist/bundling-sources/shared_libs/monitors/package.json +36 -0
  37. package/dist/bundling-sources/shared_libs/monitors/provider-callback-verification.ts +1125 -0
  38. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +305 -0
  39. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-capability.ts +964 -0
  40. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-consumer-health.ts +56 -0
  41. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-errors.ts +131 -0
  42. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-identity-claims.ts +535 -0
  43. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-legacy-aliases.ts +16 -0
  44. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-priority-execution.ts +56 -0
  45. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-public-aliases.ts +28 -0
  46. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-runtime-read-eligibility.ts +38 -0
  47. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-state.ts +122 -0
  48. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-status.ts +10 -0
  49. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-upstream-identity.ts +112 -0
  50. package/dist/bundling-sources/shared_libs/monitors/provider-webhook-monitor-runtime.ts +300 -0
  51. package/dist/bundling-sources/shared_libs/monitors/quickstart-prompts.ts +22 -0
  52. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-dead-letter.ts +245 -0
  53. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-message.ts +38 -0
  54. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue-ack-probe.ts +94 -0
  55. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue-delivery.ts +60 -0
  56. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue.ts +60 -0
  57. package/dist/bundling-sources/shared_libs/monitors/snitcher-install-validation.ts +93 -0
  58. package/dist/bundling-sources/shared_libs/monitors/snitcher-ip2company.ts +332 -0
  59. package/dist/bundling-sources/shared_libs/monitors/snitcher-radar.ts +221 -0
  60. package/dist/bundling-sources/shared_libs/monitors/starter-templates.ts +105 -0
  61. package/dist/bundling-sources/shared_libs/monitors/tracking-provider-guidance.ts +73 -0
  62. package/dist/bundling-sources/shared_libs/monitors/tracking-provider-integrations.ts +81 -0
  63. package/dist/bundling-sources/shared_libs/monitors/tsconfig.json +10 -0
  64. package/dist/bundling-sources/shared_libs/observability/build-context.ts +13 -0
  65. package/dist/bundling-sources/shared_libs/observability/log-metadata.ts +160 -0
  66. package/dist/bundling-sources/shared_libs/observability/request-context.ts +68 -0
  67. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +654 -0
  68. package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +35 -0
  69. package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +5 -0
  70. package/dist/bundling-sources/shared_libs/play-data-plane/neon-constants.ts +9 -0
  71. package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +272 -0
  72. package/dist/bundling-sources/shared_libs/play-runtime/activity-observation.ts +6 -11
  73. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +135 -12
  74. package/dist/bundling-sources/shared_libs/play-runtime/async-operation.ts +66 -1
  75. package/dist/bundling-sources/shared_libs/play-runtime/async-play-invocation.ts +77 -0
  76. package/dist/bundling-sources/shared_libs/play-runtime/bounceban-batching.ts +137 -0
  77. package/dist/bundling-sources/shared_libs/play-runtime/checkpoint-boundaries.ts +70 -0
  78. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +1159 -166
  79. package/dist/bundling-sources/shared_libs/play-runtime/coordinator-headers.ts +1 -32
  80. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +103 -0
  81. package/dist/bundling-sources/shared_libs/play-runtime/daytona-payload-contract.ts +68 -0
  82. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-janitor.ts +103 -0
  83. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-reaper.ts +725 -0
  84. package/dist/bundling-sources/shared_libs/play-runtime/default-batch-strategies.ts +20 -1
  85. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +29 -0
  86. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +29 -0
  87. package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-invocation-fence.ts +442 -0
  88. package/dist/bundling-sources/shared_libs/play-runtime/execution-protocol.ts +7 -1
  89. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +18 -0
  90. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +9 -0
  91. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +1 -1
  92. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +1 -1
  93. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +66 -0
  94. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +145 -0
  95. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/ports.ts +21 -0
  96. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/postgres-store.ts +170 -0
  97. package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +1322 -0
  98. package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +2 -2
  99. package/dist/bundling-sources/shared_libs/play-runtime/lane-retirement-gate.ts +189 -0
  100. package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +112 -0
  101. package/dist/bundling-sources/shared_libs/play-runtime/map-execution-frame.ts +8 -0
  102. package/dist/bundling-sources/shared_libs/play-runtime/perf-trace.ts +127 -0
  103. package/dist/bundling-sources/shared_libs/play-runtime/play-artifact-runtime-contract.ts +5 -0
  104. package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +24 -1
  105. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +56 -0
  106. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/index.ts +13 -0
  107. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/job.ts +41 -0
  108. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/ports.ts +17 -0
  109. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +54 -0
  110. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/contracts.ts +114 -0
  111. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/engine-suspension.ts +108 -0
  112. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/index.ts +36 -0
  113. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/job.ts +97 -0
  114. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/ports.ts +104 -0
  115. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/postgres-fence-adapter.ts +263 -0
  116. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/worker-terminal-projection.ts +64 -0
  117. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/contracts.ts +29 -0
  118. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/gateway-adapter.ts +56 -0
  119. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/index.ts +15 -0
  120. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/job.ts +65 -0
  121. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/ports.ts +17 -0
  122. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/contracts.ts +42 -0
  123. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/index.ts +17 -0
  124. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/job.ts +142 -0
  125. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/ports.ts +42 -0
  126. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/postgres-adapter.ts +102 -0
  127. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +60 -0
  128. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/index.ts +16 -0
  129. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +78 -0
  130. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +54 -0
  131. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +71 -0
  132. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-batching-registry.ts +4 -0
  133. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-semantics.ts +28 -0
  134. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +4 -0
  135. package/dist/bundling-sources/shared_libs/play-runtime/receipt-status.ts +5 -8
  136. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +23 -2
  137. package/dist/bundling-sources/shared_libs/play-runtime/run-identity.ts +168 -0
  138. package/dist/bundling-sources/shared_libs/play-runtime/run-snapshot-stream.ts +1 -1
  139. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +90 -13
  140. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +6 -12
  141. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-start-admission.ts +68 -0
  142. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +21 -0
  143. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/bundle.ts +0 -1
  144. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +14 -43
  145. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +67 -213
  146. package/dist/bundling-sources/shared_libs/play-runtime/runtime-authority.ts +201 -0
  147. package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +20 -0
  148. package/dist/bundling-sources/shared_libs/play-runtime/runtime-contract.ts +6 -0
  149. package/dist/bundling-sources/shared_libs/play-runtime/runtime-env.ts +12 -0
  150. package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +67 -0
  151. package/dist/bundling-sources/shared_libs/play-runtime/runtime-release-environment.ts +2 -0
  152. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-contract.ts +68 -0
  153. package/dist/bundling-sources/shared_libs/play-runtime/runtime-scheduler-topology.ts +38 -2
  154. package/dist/bundling-sources/shared_libs/play-runtime/runtime-telemetry.ts +108 -0
  155. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +4 -0
  156. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +3 -0
  157. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +37 -1
  158. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-deadline-reconciliation.ts +88 -0
  159. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +124 -0
  160. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-run-task.ts +68 -0
  161. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool.ts +193 -0
  162. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-queue-lifecycle.ts +269 -0
  163. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-queue-suffix.ts +73 -0
  164. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +6642 -0
  165. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +897 -0
  166. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-metrics.ts +120 -0
  167. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +76 -0
  168. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +476 -0
  169. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +47 -0
  170. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +147 -0
  171. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/index.ts +27 -0
  172. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/lazy.ts +50 -0
  173. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/play-run-recovery.ts +98 -0
  174. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-budget-state.ts +260 -0
  175. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +1416 -0
  176. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +1255 -0
  177. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +942 -0
  178. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +14636 -0
  179. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +888 -0
  180. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +355 -0
  181. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +46 -0
  182. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runner-push.ts +60 -0
  183. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-api-origin.ts +33 -0
  184. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-gateway-health.ts +64 -0
  185. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +835 -0
  186. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-ledger-reconciliation.ts +1218 -0
  187. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-operation.ts +207 -0
  188. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-scheduler-schema.ts +10 -0
  189. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/scheduler-capacity.ts +123 -0
  190. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/scheduler-launch-read-observability.ts +78 -0
  191. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/submit-admission.ts +169 -0
  192. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/terminal-contract.ts +20 -0
  193. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-queue-metrics.ts +34 -0
  194. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +249 -0
  195. package/dist/bundling-sources/shared_libs/play-runtime/sheet-attempt-sql.ts +7 -0
  196. package/dist/bundling-sources/shared_libs/play-runtime/step-progress.ts +296 -0
  197. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/native-batch.ts +3 -3
  198. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +20 -1
  199. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +60 -15
  200. package/dist/bundling-sources/shared_libs/play-runtime/tool-execution-outcome.ts +20 -0
  201. package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +1 -1
  202. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +1 -1
  203. package/dist/bundling-sources/shared_libs/play-runtime/transient-service-error.ts +12 -0
  204. package/dist/bundling-sources/shared_libs/play-runtime/vercel-protection.ts +14 -1
  205. package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-storage-contract.ts +165 -0
  206. package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +15 -23
  207. package/dist/bundling-sources/shared_libs/play-runtime/workflow-executor-auth.ts +169 -0
  208. package/dist/bundling-sources/shared_libs/play-runtime/zerobounce-batching.ts +122 -0
  209. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +8 -3
  210. package/dist/bundling-sources/shared_libs/plays/authoring-contract.ts +454 -17
  211. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +19 -4
  212. package/dist/bundling-sources/shared_libs/plays/contracts.ts +8 -14
  213. package/dist/bundling-sources/shared_libs/plays/core.ts +11 -6
  214. package/dist/bundling-sources/shared_libs/plays/deployment-status.ts +1 -1
  215. package/dist/bundling-sources/shared_libs/plays/docflow-binding-owner.ts +16 -11
  216. package/dist/bundling-sources/shared_libs/plays/docflow.ts +1 -1
  217. package/dist/bundling-sources/shared_libs/plays/email-status.ts +1 -1
  218. package/dist/bundling-sources/shared_libs/plays/play-grep-search.ts +39 -0
  219. package/dist/bundling-sources/shared_libs/plays/resolve-static-pipeline.ts +1 -1
  220. package/dist/bundling-sources/shared_libs/plays/share/copy.ts +271 -0
  221. package/dist/bundling-sources/shared_libs/plays/share/metrics.ts +140 -0
  222. package/dist/bundling-sources/shared_libs/plays/share/public-read-model.ts +86 -0
  223. package/dist/bundling-sources/shared_libs/plays/share/seo-quality.ts +181 -0
  224. package/dist/bundling-sources/shared_libs/plays/share/static-pipeline-summary.ts +658 -0
  225. package/dist/bundling-sources/shared_libs/plays/share/types.ts +197 -0
  226. package/dist/bundling-sources/shared_libs/plays/slack-hitl-timeout-error.ts +37 -0
  227. package/dist/bundling-sources/shared_libs/plays/slug.ts +115 -0
  228. package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +50 -15
  229. package/dist/bundling-sources/shared_libs/plays/tool-category-descriptions.ts +2 -2
  230. package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +1 -1
  231. package/dist/bundling-sources/shared_libs/product-notifications/catalog.ts +877 -0
  232. package/dist/bundling-sources/shared_libs/product-notifications/configuration-draft.ts +456 -0
  233. package/dist/bundling-sources/shared_libs/product-notifications/configuration.ts +566 -0
  234. package/dist/bundling-sources/shared_libs/product-notifications/content.ts +28 -0
  235. package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +60 -0
  236. package/dist/bundling-sources/shared_libs/product-notifications/email.ts +246 -0
  237. package/dist/bundling-sources/shared_libs/product-notifications/evaluation.ts +280 -0
  238. package/dist/bundling-sources/shared_libs/product-notifications/events.ts +433 -0
  239. package/dist/bundling-sources/shared_libs/product-notifications/legacy-slack.ts +80 -0
  240. package/dist/bundling-sources/shared_libs/product-notifications/overflow.ts +18 -0
  241. package/dist/bundling-sources/shared_libs/product-notifications/rolling-limit.ts +24 -0
  242. package/dist/bundling-sources/shared_libs/product-notifications/slack-delivery.ts +624 -0
  243. package/dist/bundling-sources/shared_libs/product-notifications/slack-payload.ts +140 -0
  244. package/dist/bundling-sources/shared_libs/product-notifications/slack-transport.ts +75 -0
  245. package/dist/bundling-sources/shared_libs/product-notifications/workspace.ts +38 -0
  246. package/dist/bundling-sources/shared_libs/runtime-env.ts +12 -0
  247. package/dist/bundling-sources/shared_libs/security/email-blacklist.ts +42 -0
  248. package/dist/bundling-sources/shared_libs/security/header-safe-env.ts +35 -0
  249. package/dist/bundling-sources/shared_libs/security/internal-actor.ts +50 -0
  250. package/dist/bundling-sources/shared_libs/security/secret-redaction.ts +267 -0
  251. package/dist/bundling-sources/shared_libs/security/slack-sanitize.ts +133 -0
  252. package/dist/cli/getting-started.d.mts +52 -0
  253. package/dist/cli/getting-started.d.ts +52 -0
  254. package/dist/cli/getting-started.js +65 -0
  255. package/dist/cli/getting-started.mjs +36 -0
  256. package/dist/cli/index.d.mts +9 -0
  257. package/dist/cli/index.d.ts +9 -0
  258. package/dist/cli/index.js +1611 -453
  259. package/dist/cli/index.mjs +1596 -447
  260. package/dist/{compiler-manifest-Dbov16F7.d.mts → compiler-manifest-BaJfE-5H.d.mts} +136 -10
  261. package/dist/{compiler-manifest-Dbov16F7.d.ts → compiler-manifest-BaJfE-5H.d.ts} +136 -10
  262. package/dist/index.d.mts +910 -155
  263. package/dist/index.d.ts +910 -155
  264. package/dist/index.js +550 -64
  265. package/dist/index.mjs +550 -64
  266. package/dist/install-integrity.json +193 -4
  267. package/dist/monitor-fleet-contract.d.mts +138 -0
  268. package/dist/monitor-fleet-contract.d.ts +138 -0
  269. package/dist/monitor-fleet-contract.js +404 -0
  270. package/dist/monitor-fleet-contract.mjs +367 -0
  271. package/dist/plays/bundle-play-file.d.mts +8 -3
  272. package/dist/plays/bundle-play-file.d.ts +8 -3
  273. package/dist/plays/bundle-play-file.mjs +100 -20
  274. package/dist/release.d.mts +255 -0
  275. package/dist/release.d.ts +255 -0
  276. package/dist/release.js +215 -0
  277. package/dist/release.mjs +188 -0
  278. package/package.json +23 -4
  279. /package/dist/bundling-sources/shared_libs/{integrations/bettercontact-execution-policy.ts → integration-contracts/bettercontact/execution-policy.ts} +0 -0
  280. /package/dist/bundling-sources/shared_libs/{integrations/theirstack-execution-policy.ts → integration-contracts/theirstack/execution-policy.ts} +0 -0
@@ -0,0 +1,1218 @@
1
+ import type {
2
+ PostgresSchedulerOptions,
3
+ PostgresSchedulerQueryClient,
4
+ } from './postgres';
5
+ import {
6
+ RuntimeSandboxOperationState,
7
+ RuntimeSandboxProvider,
8
+ } from './runtime-sandbox-operation';
9
+
10
+ const DAYTONA_PROVIDER = RuntimeSandboxProvider.Daytona;
11
+ const DEFAULT_BATCH_SIZE = 500;
12
+ const MAX_BATCH_SIZE = 1_000;
13
+ /** Never classify a very recent resource from a provider snapshot as absent. */
14
+ export const RUNTIME_SANDBOX_LEDGER_RECONCILIATION_MINIMUM_AGE_MS =
15
+ 10 * 60 * 1_000;
16
+
17
+ function quoteIdent(value: string): string {
18
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(value)) {
19
+ throw new Error(`Invalid runtime scheduler schema: ${value}`);
20
+ }
21
+ return `"${value}"`;
22
+ }
23
+
24
+ function tables(options?: Pick<PostgresSchedulerOptions, 'schema'>) {
25
+ const schema = quoteIdent(options?.schema ?? 'runtime_scheduler');
26
+ return {
27
+ attempts: `${schema}."attempts"`,
28
+ runs: `${schema}."runs"`,
29
+ operations: `${schema}."runtime_sandbox_operations"`,
30
+ cleanup: `${schema}."sandbox_cleanup_jobs_v2"`,
31
+ cleanupEvents: `${schema}."sandbox_cleanup_events_v2"`,
32
+ leases: `${schema}."runtime_sandbox_capacity_leases"`,
33
+ control: `${schema}."control"`,
34
+ };
35
+ }
36
+
37
+ /** A provider inventory item is a physical-sandbox identity, never an id-only
38
+ * guess. Daytona's operation label lets recovery fence a create whose HTTP
39
+ * response was lost after Daytona had already accepted it. */
40
+ export type DaytonaSandboxInventoryEntry = {
41
+ sandboxId: string;
42
+ operationKey: string | null;
43
+ routingDomain: string | null;
44
+ };
45
+
46
+ function normalizeProviderInventory(
47
+ values: readonly DaytonaSandboxInventoryEntry[],
48
+ ): DaytonaSandboxInventoryEntry[] {
49
+ const byIdentity = new Map<string, DaytonaSandboxInventoryEntry>();
50
+ for (const value of values) {
51
+ const sandboxId = value.sandboxId.trim();
52
+ if (!sandboxId)
53
+ throw new Error('Provider inventory sandboxId is required.');
54
+ const operationKey = value.operationKey?.trim() || null;
55
+ const routingDomain = value.routingDomain?.trim() || null;
56
+ byIdentity.set(
57
+ `${sandboxId}\u0000${routingDomain ?? ''}\u0000${operationKey ?? ''}`,
58
+ { sandboxId, operationKey, routingDomain },
59
+ );
60
+ }
61
+ return [...byIdentity.values()];
62
+ }
63
+
64
+ function batchSize(value: number | undefined): number {
65
+ if (value === undefined) return DEFAULT_BATCH_SIZE;
66
+ if (!Number.isSafeInteger(value) || value < 1 || value > MAX_BATCH_SIZE) {
67
+ throw new Error(
68
+ `batchSize must be an integer from 1 through ${MAX_BATCH_SIZE}.`,
69
+ );
70
+ }
71
+ return value;
72
+ }
73
+
74
+ export type RuntimeSandboxLedgerReconciliationSummary = {
75
+ provider: RuntimeSandboxProvider.Daytona;
76
+ providerSandboxCount: number;
77
+ matchedLiveSandboxes: number;
78
+ unmatchedProviderSandboxIds: string[];
79
+ liveLeasesToSeed: number;
80
+ absentLedgerRows: number;
81
+ seededLeases: number;
82
+ /** Historical or raced leases released because deletion was already durable. */
83
+ releasedTerminalLeases: number;
84
+ markedDeleted: number;
85
+ /** Reserved creates recovered from Daytona's exact operation-key label. */
86
+ recoveredReservedOperations: number;
87
+ hasMoreAbsentLedgerRows: boolean;
88
+ dryRun: boolean;
89
+ diagnostics: readonly RuntimeSandboxLedgerReconciliationDiagnostic[];
90
+ };
91
+
92
+ export enum RuntimeSandboxLedgerReconciliationPhase {
93
+ ReleaseTerminalCapacity = 'release_terminal_capacity',
94
+ MatchProviderInventory = 'match_provider_inventory',
95
+ RecoverReservedOperations = 'recover_reserved_operations',
96
+ FindAbsentOperations = 'find_absent_operations',
97
+ InspectCapacityBindings = 'inspect_capacity_bindings',
98
+ SeedCapacityBindings = 'seed_capacity_bindings',
99
+ MarkProviderConfirmedAbsent = 'mark_provider_confirmed_absent',
100
+ }
101
+
102
+ export type RuntimeSandboxLedgerReconciliationDiagnostic = {
103
+ phase: RuntimeSandboxLedgerReconciliationPhase;
104
+ durationMs: number;
105
+ rowCount: number;
106
+ };
107
+
108
+ export type RuntimeSandboxOperationBackfillCursor = {
109
+ /** Exact PostgreSQL timestamptz text; milliseconds are insufficient. */
110
+ updatedAt: string;
111
+ runId: string;
112
+ attempt: number;
113
+ resourceOrdinal: number;
114
+ };
115
+
116
+ export type RuntimeSandboxOperationBackfillSummary = {
117
+ scannedAttempts: number;
118
+ insertedOperations: number;
119
+ hasMore: boolean;
120
+ nextCursor: RuntimeSandboxOperationBackfillCursor | null;
121
+ /** Redacted, approval-safe resource targets in this bounded page. */
122
+ targets: readonly RuntimeSandboxOperationBackfillTarget[];
123
+ };
124
+
125
+ export type RuntimeSandboxOperationBackfillTarget = {
126
+ runId: string;
127
+ attempt: number;
128
+ resourceOrdinal: number;
129
+ provider: RuntimeSandboxProvider;
130
+ sandboxId: string;
131
+ wouldInsert: boolean;
132
+ };
133
+
134
+ export enum RuntimeSandboxOperationBackfillPhase {
135
+ Pending = 'pending',
136
+ Complete = 'complete',
137
+ }
138
+
139
+ const RUNTIME_SANDBOX_OPERATION_BACKFILL_CONTROL_KEY =
140
+ 'runtime_sandbox_operation_backfill_v1';
141
+
142
+ type RuntimeSandboxOperationBackfillCheckpoint = {
143
+ phase: RuntimeSandboxOperationBackfillPhase;
144
+ cursor: RuntimeSandboxOperationBackfillCursor | null;
145
+ };
146
+
147
+ async function readRuntimeSandboxOperationBackfillCheckpoint(
148
+ client: PostgresSchedulerQueryClient,
149
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
150
+ ): Promise<RuntimeSandboxOperationBackfillCheckpoint> {
151
+ const { control } = tables(options);
152
+ const result = await client.query<{ value: unknown }>(
153
+ `SELECT value FROM ${control} WHERE key = $1`,
154
+ [RUNTIME_SANDBOX_OPERATION_BACKFILL_CONTROL_KEY],
155
+ );
156
+ const value = result.rows[0]?.value;
157
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
158
+ return {
159
+ phase: RuntimeSandboxOperationBackfillPhase.Pending,
160
+ cursor: null,
161
+ };
162
+ }
163
+ const checkpoint = value as { phase?: unknown; cursor?: unknown };
164
+ if (checkpoint.phase === RuntimeSandboxOperationBackfillPhase.Complete) {
165
+ return {
166
+ phase: RuntimeSandboxOperationBackfillPhase.Complete,
167
+ cursor: null,
168
+ };
169
+ }
170
+ const cursor =
171
+ checkpoint.cursor as RuntimeSandboxOperationBackfillCursor | null;
172
+ return {
173
+ phase: RuntimeSandboxOperationBackfillPhase.Pending,
174
+ cursor:
175
+ cursor &&
176
+ typeof cursor.updatedAt === 'string' &&
177
+ typeof cursor.runId === 'string' &&
178
+ typeof cursor.attempt === 'number' &&
179
+ typeof cursor.resourceOrdinal === 'number'
180
+ ? cursor
181
+ : null,
182
+ };
183
+ }
184
+
185
+ export type RuntimeSandboxOperationBackfillProgress = {
186
+ phase: RuntimeSandboxOperationBackfillPhase;
187
+ dryRun: boolean;
188
+ batches: number;
189
+ scannedAttempts: number;
190
+ insertedOperations: number;
191
+ projectedOperations: number;
192
+ targets: readonly RuntimeSandboxOperationBackfillTarget[];
193
+ nextCursor: RuntimeSandboxOperationBackfillCursor | null;
194
+ };
195
+
196
+ /** Read one bounded resource-element page without writes. */
197
+ async function previewRuntimeSandboxOperationBackfillPage(
198
+ client: PostgresSchedulerQueryClient,
199
+ input: {
200
+ batchSize?: number;
201
+ cursor: RuntimeSandboxOperationBackfillCursor | null;
202
+ },
203
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
204
+ ): Promise<RuntimeSandboxOperationBackfillSummary> {
205
+ const limit = batchSize(input.batchSize);
206
+ const { attempts, operations } = tables(options);
207
+ const page = await client.query<{
208
+ run_id: string;
209
+ attempt: number;
210
+ updated_at: string;
211
+ resource_ordinal: number;
212
+ provider: RuntimeSandboxProvider;
213
+ sandbox_id: string;
214
+ would_insert: boolean;
215
+ }>(
216
+ `
217
+ WITH candidates AS (
218
+ SELECT attempt.run_id, attempt.attempt, attempt.updated_at,
219
+ resource.ordinal::integer AS resource_ordinal,
220
+ CASE resource.value->>'kind' WHEN 'modal_sandbox' THEN $6 ELSE $7 END AS provider,
221
+ resource.value->>'sandboxId' AS sandbox_id,
222
+ coalesce(CASE resource.value->>'kind'
223
+ WHEN 'modal_sandbox' THEN NULLIF(resource.value->>'modalAppId', '')
224
+ ELSE NULLIF(resource.value->>'daytonaOrganizationId', '') END, '')
225
+ AS routing_domain_key
226
+ FROM ${attempts} AS attempt
227
+ CROSS JOIN LATERAL jsonb_array_elements(
228
+ CASE WHEN jsonb_typeof(attempt.resource_json) = 'array'
229
+ THEN attempt.resource_json ELSE jsonb_build_array(attempt.resource_json) END
230
+ ) WITH ORDINALITY AS resource(value, ordinal)
231
+ WHERE attempt.resource_json IS NOT NULL
232
+ AND resource.value->>'kind' IN ('daytona_sandbox', 'modal_sandbox')
233
+ AND NULLIF(resource.value->>'sandboxId', '') IS NOT NULL
234
+ AND ($1::text IS NULL OR
235
+ (attempt.updated_at, attempt.run_id, attempt.attempt, resource.ordinal) >
236
+ ($1::timestamptz, $2::text, $3::integer, $4::bigint))
237
+ ), page AS (
238
+ SELECT *, row_number() OVER (
239
+ PARTITION BY provider, sandbox_id, routing_domain_key
240
+ ORDER BY updated_at, run_id, attempt, resource_ordinal
241
+ ) AS conflict_rank
242
+ FROM candidates
243
+ ORDER BY updated_at, run_id, attempt, resource_ordinal
244
+ LIMIT $5
245
+ )
246
+ SELECT page.run_id, page.attempt, page.updated_at::text AS updated_at,
247
+ page.resource_ordinal, page.provider, page.sandbox_id,
248
+ page.conflict_rank = 1 AND
249
+ NOT EXISTS (
250
+ SELECT 1 FROM ${operations} AS operation
251
+ WHERE operation.provider = page.provider
252
+ AND operation.sandbox_id = page.sandbox_id
253
+ AND operation.routing_domain_key = page.routing_domain_key
254
+ ) AS would_insert
255
+ FROM page
256
+ ORDER BY page.updated_at, page.run_id, page.attempt, page.resource_ordinal
257
+ `,
258
+ [
259
+ input.cursor?.updatedAt ?? null,
260
+ input.cursor?.runId ?? '',
261
+ input.cursor?.attempt ?? 0,
262
+ input.cursor?.resourceOrdinal ?? 0,
263
+ limit + 1,
264
+ RuntimeSandboxProvider.Modal,
265
+ RuntimeSandboxProvider.Daytona,
266
+ ],
267
+ );
268
+ const hasMore = page.rows.length > limit;
269
+ const items = page.rows.slice(0, limit);
270
+ const last = items.at(-1) ?? null;
271
+ return {
272
+ scannedAttempts: items.length,
273
+ insertedOperations: 0,
274
+ hasMore,
275
+ nextCursor: last
276
+ ? {
277
+ updatedAt: last.updated_at,
278
+ runId: last.run_id,
279
+ attempt: Number(last.attempt),
280
+ resourceOrdinal: Number(last.resource_ordinal),
281
+ }
282
+ : null,
283
+ targets: items.map((item) => ({
284
+ runId: item.run_id,
285
+ attempt: Number(item.attempt),
286
+ resourceOrdinal: Number(item.resource_ordinal),
287
+ provider: item.provider,
288
+ sandboxId: item.sandbox_id,
289
+ wouldInsert: item.would_insert,
290
+ })),
291
+ };
292
+ }
293
+
294
+ /** Persisted, resumable orchestrator. Dry-run performs no JSON expansion or writes. */
295
+ export async function advanceRuntimeSandboxOperationBackfill(
296
+ client: PostgresSchedulerQueryClient,
297
+ input: { dryRun: boolean; batchSize?: number; maxBatches?: number },
298
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
299
+ ): Promise<RuntimeSandboxOperationBackfillProgress> {
300
+ const checkpoint = await readRuntimeSandboxOperationBackfillCheckpoint(
301
+ client,
302
+ options,
303
+ );
304
+ if (input.dryRun) {
305
+ if (checkpoint.phase === RuntimeSandboxOperationBackfillPhase.Complete) {
306
+ return {
307
+ phase: checkpoint.phase,
308
+ dryRun: true,
309
+ batches: 0,
310
+ scannedAttempts: 0,
311
+ insertedOperations: 0,
312
+ projectedOperations: 0,
313
+ targets: [],
314
+ nextCursor: null,
315
+ };
316
+ }
317
+ const preview = await previewRuntimeSandboxOperationBackfillPage(
318
+ client,
319
+ { batchSize: input.batchSize, cursor: checkpoint.cursor },
320
+ options,
321
+ );
322
+ return {
323
+ phase: RuntimeSandboxOperationBackfillPhase.Pending,
324
+ dryRun: true,
325
+ batches: preview.scannedAttempts > 0 ? 1 : 0,
326
+ scannedAttempts: preview.scannedAttempts,
327
+ insertedOperations: 0,
328
+ projectedOperations: preview.targets.filter(
329
+ (target) => target.wouldInsert,
330
+ ).length,
331
+ targets: preview.targets,
332
+ nextCursor: preview.nextCursor,
333
+ };
334
+ }
335
+ if (checkpoint.phase === RuntimeSandboxOperationBackfillPhase.Complete) {
336
+ return {
337
+ phase: checkpoint.phase,
338
+ dryRun: false,
339
+ batches: 0,
340
+ scannedAttempts: 0,
341
+ insertedOperations: 0,
342
+ projectedOperations: 0,
343
+ targets: [],
344
+ nextCursor: null,
345
+ };
346
+ }
347
+ const maxBatches = Math.max(
348
+ 1,
349
+ Math.min(200, Math.floor(input.maxBatches ?? 1)),
350
+ );
351
+ let cursor = checkpoint.cursor;
352
+ let scannedAttempts = 0;
353
+ let insertedOperations = 0;
354
+ for (let batch = 0; batch < maxBatches; batch += 1) {
355
+ const page = await backfillRuntimeSandboxOperationsFromAttemptResources(
356
+ client,
357
+ { batchSize: input.batchSize, cursor: cursor ?? undefined },
358
+ options,
359
+ );
360
+ scannedAttempts += page.scannedAttempts;
361
+ insertedOperations += page.insertedOperations;
362
+ cursor = page.nextCursor;
363
+ const phase = page.hasMore
364
+ ? RuntimeSandboxOperationBackfillPhase.Pending
365
+ : RuntimeSandboxOperationBackfillPhase.Complete;
366
+ await client.query(
367
+ `INSERT INTO ${tables(options).control} (key, value)
368
+ VALUES ($1, $2::jsonb)
369
+ ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value`,
370
+ [
371
+ RUNTIME_SANDBOX_OPERATION_BACKFILL_CONTROL_KEY,
372
+ JSON.stringify({
373
+ phase,
374
+ cursor:
375
+ phase === RuntimeSandboxOperationBackfillPhase.Complete
376
+ ? null
377
+ : cursor,
378
+ }),
379
+ ],
380
+ );
381
+ if (phase === RuntimeSandboxOperationBackfillPhase.Complete) {
382
+ return {
383
+ phase,
384
+ dryRun: false,
385
+ batches: batch + 1,
386
+ scannedAttempts,
387
+ insertedOperations,
388
+ projectedOperations: scannedAttempts,
389
+ targets: [],
390
+ nextCursor: null,
391
+ };
392
+ }
393
+ }
394
+ return {
395
+ phase: RuntimeSandboxOperationBackfillPhase.Pending,
396
+ dryRun: false,
397
+ batches: maxBatches,
398
+ scannedAttempts,
399
+ insertedOperations,
400
+ projectedOperations: scannedAttempts,
401
+ targets: [],
402
+ nextCursor: cursor,
403
+ };
404
+ }
405
+
406
+ /**
407
+ * One bounded compatibility migration from the old audit projection.
408
+ *
409
+ * This is intentionally separate from reconciliation: it keyset-scans one
410
+ * indexed attempt page, expands JSON only inside that page, and writes the
411
+ * normalized operation table. Reconciliation itself therefore never starts
412
+ * a full-history JSON expansion. Callers must persist `nextCursor` between
413
+ * batches; a fresh cursor intentionally restarts at the oldest page.
414
+ */
415
+ export async function backfillRuntimeSandboxOperationsFromAttemptResources(
416
+ client: PostgresSchedulerQueryClient,
417
+ input: { batchSize?: number; cursor?: RuntimeSandboxOperationBackfillCursor },
418
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
419
+ ): Promise<RuntimeSandboxOperationBackfillSummary> {
420
+ const limit = batchSize(input.batchSize);
421
+ const cursor = input.cursor;
422
+ if (
423
+ cursor &&
424
+ (!cursor.updatedAt.trim() ||
425
+ Number.isNaN(Date.parse(cursor.updatedAt)) ||
426
+ !cursor.runId.trim() ||
427
+ !Number.isSafeInteger(cursor.attempt) ||
428
+ cursor.attempt < 1 ||
429
+ !Number.isSafeInteger(cursor.resourceOrdinal) ||
430
+ cursor.resourceOrdinal < 1)
431
+ ) {
432
+ throw new Error('Invalid runtime sandbox operation backfill cursor.');
433
+ }
434
+ const { attempts, runs, operations } = tables(options);
435
+ const result = await client.query<{
436
+ run_id: string;
437
+ attempt: number;
438
+ updated_at: string;
439
+ resource_ordinal: number;
440
+ provider: RuntimeSandboxProvider;
441
+ sandbox_id: string;
442
+ would_insert: boolean;
443
+ inserted_operations: number;
444
+ }>(
445
+ `
446
+ WITH resources AS MATERIALIZED (
447
+ SELECT attempt.run_id, attempt.attempt, attempt.updated_at, run.org_id,
448
+ resource.value AS resource, resource.ordinal::integer AS resource_ordinal,
449
+ CASE resource.value->>'kind'
450
+ WHEN 'modal_sandbox' THEN 'modal' ELSE 'daytona' END AS provider,
451
+ COALESCE(NULLIF(resource.value->>'runtimeEnvironment', ''),
452
+ NULLIF(resource.value->>'daytonaEnvironment', ''), 'production') AS environment,
453
+ CASE resource.value->>'kind'
454
+ WHEN 'modal_sandbox' THEN NULLIF(resource.value->>'modalAppId', '')
455
+ ELSE NULLIF(resource.value->>'daytonaOrganizationId', '') END AS routing_domain
456
+ FROM ${attempts} AS attempt
457
+ JOIN ${runs} AS run ON run.run_id = attempt.run_id
458
+ CROSS JOIN LATERAL jsonb_array_elements(
459
+ CASE WHEN jsonb_typeof(attempt.resource_json) = 'array'
460
+ THEN attempt.resource_json ELSE jsonb_build_array(attempt.resource_json) END
461
+ ) WITH ORDINALITY AS resource(value, ordinal)
462
+ WHERE attempt.resource_json IS NOT NULL
463
+ AND resource.value->>'kind' IN ('daytona_sandbox', 'modal_sandbox')
464
+ AND NULLIF(resource.value->>'sandboxId', '') IS NOT NULL
465
+ AND (
466
+ $1::text IS NULL
467
+ OR (attempt.updated_at, attempt.run_id, attempt.attempt, resource.ordinal) >
468
+ ($1::timestamptz, $2::text, $3::integer, $4::bigint)
469
+ )
470
+ ORDER BY attempt.updated_at, attempt.run_id, attempt.attempt, resource.ordinal
471
+ LIMIT $5
472
+ ), ranked_resources AS (
473
+ SELECT resources.*,
474
+ coalesce(routing_domain, '') AS routing_domain_key,
475
+ row_number() OVER (
476
+ PARTITION BY provider, (resource::jsonb)->>'sandboxId', coalesce(routing_domain, '')
477
+ ORDER BY updated_at, run_id, attempt, resource_ordinal
478
+ ) AS conflict_rank
479
+ FROM resources
480
+ ), inserted AS (
481
+ INSERT INTO ${operations} (
482
+ operation_key, provider, run_id, attempt, org_id, environment,
483
+ sandbox_id, routing_domain, state, provider_created_at
484
+ )
485
+ SELECT
486
+ 'backfill:' || provider || ':' || ((resource::jsonb)->>'sandboxId') || ':' || coalesce(routing_domain, ''),
487
+ provider,
488
+ run_id,
489
+ attempt,
490
+ org_id,
491
+ environment,
492
+ (resource::jsonb)->>'sandboxId',
493
+ routing_domain,
494
+ $6,
495
+ updated_at
496
+ FROM ranked_resources
497
+ WHERE conflict_rank = 1
498
+ ON CONFLICT (provider, sandbox_id, routing_domain_key) DO NOTHING
499
+ RETURNING provider, sandbox_id, routing_domain_key
500
+ )
501
+ SELECT
502
+ resource.run_id,
503
+ resource.attempt,
504
+ resource.updated_at::text AS updated_at,
505
+ resource.resource_ordinal,
506
+ resource.provider,
507
+ (resource.resource::jsonb)->>'sandboxId' AS sandbox_id,
508
+ resource.conflict_rank = 1 AND EXISTS (
509
+ SELECT 1
510
+ FROM inserted
511
+ WHERE inserted.provider = resource.provider
512
+ AND inserted.sandbox_id = (resource.resource::jsonb)->>'sandboxId'
513
+ AND inserted.routing_domain_key = resource.routing_domain_key
514
+ ) AS would_insert,
515
+ (SELECT count(*)::integer FROM inserted) AS inserted_operations
516
+ FROM ranked_resources AS resource
517
+ ORDER BY resource.updated_at, resource.run_id, resource.attempt, resource.resource_ordinal
518
+ `,
519
+ [
520
+ cursor?.updatedAt ?? null,
521
+ cursor?.runId ?? '',
522
+ cursor?.attempt ?? 0,
523
+ cursor?.resourceOrdinal ?? 0,
524
+ limit,
525
+ RuntimeSandboxOperationState.Live,
526
+ ],
527
+ );
528
+ const last = result.rows[0] ?? null;
529
+ const scannedAttempts = result.rows.length;
530
+ // A full page asks callers to fetch once more. This is conservative at an
531
+ // exact page boundary, but never skips a row by mutating an over-fetch.
532
+ const hasMore = scannedAttempts === limit;
533
+ const page = result.rows;
534
+ const next = page.at(-1) ?? null;
535
+ return {
536
+ scannedAttempts: page.length,
537
+ insertedOperations: Number(last?.inserted_operations ?? 0),
538
+ hasMore,
539
+ nextCursor: next
540
+ ? {
541
+ updatedAt: next.updated_at,
542
+ runId: next.run_id,
543
+ attempt: Number(next.attempt),
544
+ resourceOrdinal: Number(next.resource_ordinal),
545
+ }
546
+ : null,
547
+ targets: page.map((item) => ({
548
+ runId: item.run_id,
549
+ attempt: Number(item.attempt),
550
+ resourceOrdinal: Number(item.resource_ordinal),
551
+ provider: item.provider,
552
+ sandboxId: item.sandbox_id,
553
+ wouldInsert: item.would_insert,
554
+ })),
555
+ };
556
+ }
557
+
558
+ async function releaseTerminalSandboxCapacityLeases(
559
+ client: PostgresSchedulerQueryClient,
560
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
561
+ ): Promise<number> {
562
+ const { cleanup, leases } = tables(options);
563
+ const released = await client.query<{ lease_id: string }>(
564
+ `
565
+ UPDATE ${leases} AS lease
566
+ SET released_at = clock_timestamp()
567
+ FROM ${cleanup} AS cleanup
568
+ WHERE lease.provider = '${DAYTONA_PROVIDER}'
569
+ AND cleanup.provider = lease.provider
570
+ AND cleanup.sandbox_id = lease.sandbox_id
571
+ AND cleanup.routing_domain IS NOT DISTINCT FROM lease.routing_domain
572
+ AND cleanup.run_id = lease.run_id
573
+ AND cleanup.status = 'deleted'
574
+ AND cleanup.deleted_at IS NOT NULL
575
+ AND lease.released_at IS NULL
576
+ RETURNING lease.lease_id
577
+ `,
578
+ );
579
+ return released.rows.length;
580
+ }
581
+
582
+ /**
583
+ * Reconcile durable sandbox records against one complete Daytona inventory.
584
+ *
585
+ * This is intentionally a rollout/migration operation, not a hot-path read:
586
+ * Daytona's label-scoped list is the authority for provider presence. A live
587
+ * provider resource is seeded into the soft-capacity lease table. An older
588
+ * durable resource absent from that inventory is completed in the cleanup
589
+ * ledger with a provider-confirmed-absent audit event; the resource history is
590
+ * never deleted or rewritten.
591
+ */
592
+ export async function reconcileRuntimeDaytonaSandboxLedger(
593
+ client: PostgresSchedulerQueryClient,
594
+ input: {
595
+ /** Complete source-labelled Daytona inventory, retaining ownership labels. */
596
+ providerSandboxes: readonly DaytonaSandboxInventoryEntry[];
597
+ /**
598
+ * Epoch time immediately after the complete provider inventory finished.
599
+ * Resources recorded later than this snapshot are never classified absent.
600
+ */
601
+ inventoryCapturedAtMs: number;
602
+ dryRun: boolean;
603
+ batchSize?: number;
604
+ minimumAgeMs?: number;
605
+ },
606
+ options?: Pick<PostgresSchedulerOptions, 'schema'>,
607
+ ): Promise<RuntimeSandboxLedgerReconciliationSummary> {
608
+ const providerSandboxes = normalizeProviderInventory(input.providerSandboxes);
609
+ const limit = batchSize(input.batchSize);
610
+ if (
611
+ !Number.isSafeInteger(input.inventoryCapturedAtMs) ||
612
+ input.inventoryCapturedAtMs <= 0
613
+ ) {
614
+ throw new Error(
615
+ 'inventoryCapturedAtMs must be a positive epoch milliseconds value.',
616
+ );
617
+ }
618
+ const minimumAgeMs =
619
+ input.minimumAgeMs ?? RUNTIME_SANDBOX_LEDGER_RECONCILIATION_MINIMUM_AGE_MS;
620
+ if (!Number.isSafeInteger(minimumAgeMs) || minimumAgeMs < 0) {
621
+ throw new Error('minimumAgeMs must be a non-negative safe integer.');
622
+ }
623
+ const { operations, cleanup, cleanupEvents, leases } = tables(options);
624
+ const operationStateType = `${quoteIdent(
625
+ options?.schema ?? 'runtime_scheduler',
626
+ )}.${quoteIdent('runtime_sandbox_operation_state')}`;
627
+ const diagnostics: RuntimeSandboxLedgerReconciliationDiagnostic[] = [];
628
+ async function measuredQuery<Row extends Record<string, unknown>>(
629
+ phase: RuntimeSandboxLedgerReconciliationPhase,
630
+ sql: string,
631
+ parameters?: unknown[],
632
+ ): Promise<{ rows: Row[] }> {
633
+ const startedAt = performance.now();
634
+ try {
635
+ const result = await client.query<Row>(sql, parameters);
636
+ diagnostics.push({
637
+ phase,
638
+ durationMs: performance.now() - startedAt,
639
+ rowCount: result.rows.length,
640
+ });
641
+ return result;
642
+ } catch (error) {
643
+ diagnostics.push({
644
+ phase,
645
+ durationMs: performance.now() - startedAt,
646
+ rowCount: 0,
647
+ });
648
+ throw error;
649
+ }
650
+ }
651
+ // A previous reconciliation may have observed a sandbox just before its
652
+ // normal cleanup completed. Repair those terminal rows before calculating
653
+ // the next snapshot's capacity state. This is idempotent and is deliberately
654
+ // a migration-only convergence step, never a worker hot-path lock.
655
+ let releasedTerminalLeases = 0;
656
+ if (!input.dryRun) {
657
+ const startedAt = performance.now();
658
+ releasedTerminalLeases = await releaseTerminalSandboxCapacityLeases(
659
+ client,
660
+ options,
661
+ );
662
+ diagnostics.push({
663
+ phase: RuntimeSandboxLedgerReconciliationPhase.ReleaseTerminalCapacity,
664
+ durationMs: performance.now() - startedAt,
665
+ rowCount: releasedTerminalLeases,
666
+ });
667
+ }
668
+
669
+ const inventoryJson = JSON.stringify(
670
+ providerSandboxes.map((sandbox) => ({
671
+ sandbox_id: sandbox.sandboxId,
672
+ operation_key: sandbox.operationKey,
673
+ routing_domain: sandbox.routingDomain,
674
+ })),
675
+ );
676
+ const duplicateOperationTokens = new Set<string>();
677
+ const operationTokenCounts = new Map<string, number>();
678
+ for (const sandbox of providerSandboxes) {
679
+ if (sandbox.operationKey) {
680
+ operationTokenCounts.set(
681
+ sandbox.operationKey,
682
+ (operationTokenCounts.get(sandbox.operationKey) ?? 0) + 1,
683
+ );
684
+ }
685
+ }
686
+ for (const [token, count] of operationTokenCounts) {
687
+ if (count > 1) duplicateOperationTokens.add(token);
688
+ }
689
+ // A Daytona create can commit at the provider and lose its response before
690
+ // the worker records it. The exact operation label is the only selector
691
+ // allowed to recover that state; an id-only inventory item remains unowned
692
+ // and fails closed below. Provider acceptance never proves runner liveness.
693
+ const reservedOwned = providerSandboxes.length
694
+ ? await measuredQuery<{
695
+ sandbox_id: string;
696
+ provider_operation_token: string;
697
+ routing_domain: string | null;
698
+ }>(
699
+ RuntimeSandboxLedgerReconciliationPhase.RecoverReservedOperations,
700
+ `
701
+ SELECT item.sandbox_id, operation.provider_operation_token, item.routing_domain
702
+ FROM jsonb_to_recordset($1::jsonb) AS item(
703
+ sandbox_id text, operation_key text, routing_domain text
704
+ )
705
+ JOIN ${operations} AS operation
706
+ ON operation.provider_operation_token = item.operation_key
707
+ AND operation.provider = $2
708
+ AND operation.environment = 'production'
709
+ AND operation.state = $3
710
+ JOIN ${leases} AS lease
711
+ ON lease.lease_id = operation.operation_key
712
+ AND lease.released_at IS NULL
713
+ `,
714
+ [
715
+ inventoryJson,
716
+ DAYTONA_PROVIDER,
717
+ RuntimeSandboxOperationState.Reserved,
718
+ ],
719
+ )
720
+ : { rows: [] };
721
+ let recoveredReservedOperations = 0;
722
+ if (!input.dryRun && reservedOwned.rows.length > 0) {
723
+ const recovered = await measuredQuery<{ operation_key: string }>(
724
+ RuntimeSandboxLedgerReconciliationPhase.RecoverReservedOperations,
725
+ `
726
+ WITH inventory AS (
727
+ SELECT item.*
728
+ FROM jsonb_to_recordset($1::jsonb) AS item(
729
+ sandbox_id text, operation_key text, routing_domain text
730
+ )
731
+ WHERE operation_key IS NOT NULL
732
+ AND 1 = (
733
+ SELECT count(*)
734
+ FROM jsonb_to_recordset($1::jsonb) AS sibling(
735
+ sandbox_id text, operation_key text, routing_domain text
736
+ )
737
+ WHERE sibling.operation_key = item.operation_key
738
+ )
739
+ ), promoted AS (
740
+ UPDATE ${operations} AS operation
741
+ SET sandbox_id = inventory.sandbox_id,
742
+ routing_domain = inventory.routing_domain,
743
+ state = $3::${operationStateType},
744
+ provider_created_at = clock_timestamp(),
745
+ updated_at = clock_timestamp()
746
+ FROM inventory
747
+ JOIN ${leases} AS lease
748
+ ON TRUE
749
+ WHERE operation.provider_operation_token = inventory.operation_key
750
+ AND operation.provider = $2
751
+ AND operation.environment = 'production'
752
+ AND operation.state = $4
753
+ AND lease.lease_id = operation.operation_key
754
+ AND lease.released_at IS NULL
755
+ RETURNING operation.operation_key, operation.run_id, operation.attempt,
756
+ operation.environment, operation.sandbox_id,
757
+ operation.routing_domain, operation.state
758
+ ), resource_fact AS (
759
+ SELECT promoted.*,
760
+ jsonb_build_object(
761
+ 'kind', 'daytona_sandbox',
762
+ 'sandboxId', promoted.sandbox_id,
763
+ 'runtimeEnvironment', promoted.environment,
764
+ 'daytonaOrganizationId', promoted.routing_domain,
765
+ 'billingStartedAt', extract(epoch FROM clock_timestamp()) * 1000,
766
+ 'sandboxCapacityLeaseId', promoted.operation_key,
767
+ 'lateAcquired', true
768
+ ) AS resource
769
+ FROM promoted
770
+ ), recorded_attempt AS (
771
+ -- Preserve the provider fact as a compatibility/audit projection in
772
+ -- the same atomic recovery transition. It is explicitly late: this
773
+ -- path never re-opens execution.
774
+ UPDATE ${tables(options).attempts} AS attempt
775
+ SET resource_json = CASE
776
+ WHEN attempt.resource_json IS NULL THEN jsonb_build_array(resource_fact.resource)
777
+ WHEN jsonb_typeof(attempt.resource_json) = 'array'
778
+ THEN attempt.resource_json || jsonb_build_array(resource_fact.resource)
779
+ ELSE jsonb_build_array(attempt.resource_json, resource_fact.resource)
780
+ END,
781
+ updated_at = clock_timestamp()
782
+ FROM resource_fact
783
+ WHERE attempt.run_id = resource_fact.run_id
784
+ AND attempt.attempt = resource_fact.attempt
785
+ RETURNING attempt.run_id, attempt.attempt
786
+ ), bound AS (
787
+ UPDATE ${leases} AS lease
788
+ SET provider = $2,
789
+ sandbox_id = promoted.sandbox_id,
790
+ routing_domain = promoted.routing_domain
791
+ FROM promoted
792
+ JOIN recorded_attempt
793
+ ON recorded_attempt.run_id = promoted.run_id
794
+ AND recorded_attempt.attempt = promoted.attempt
795
+ WHERE lease.lease_id = promoted.operation_key
796
+ AND lease.released_at IS NULL
797
+ RETURNING lease.lease_id
798
+ ), cleanup_inserted AS (
799
+ INSERT INTO ${cleanup} (
800
+ provider, sandbox_id, run_id, attempt, environment, routing_domain
801
+ )
802
+ SELECT $2, sandbox_id, run_id, attempt, environment, routing_domain
803
+ FROM promoted
804
+ JOIN bound ON bound.lease_id = promoted.operation_key
805
+ ON CONFLICT (provider, sandbox_id, routing_domain_key) DO NOTHING
806
+ )
807
+ SELECT promoted.operation_key
808
+ FROM promoted
809
+ JOIN bound ON bound.lease_id = promoted.operation_key
810
+ `,
811
+ [
812
+ inventoryJson,
813
+ DAYTONA_PROVIDER,
814
+ RuntimeSandboxOperationState.Deleting,
815
+ RuntimeSandboxOperationState.Reserved,
816
+ ],
817
+ );
818
+ recoveredReservedOperations = recovered.rows.length;
819
+ }
820
+
821
+ const liveRows = providerSandboxes.length
822
+ ? await measuredQuery<{
823
+ sandbox_id: string;
824
+ run_id: string;
825
+ attempt: number;
826
+ org_id: string;
827
+ environment: string;
828
+ routing_domain: string | null;
829
+ operation_key: string;
830
+ }>(
831
+ RuntimeSandboxLedgerReconciliationPhase.MatchProviderInventory,
832
+ `
833
+ SELECT operation.sandbox_id, operation.run_id, operation.attempt,
834
+ operation.org_id, operation.environment, operation.routing_domain,
835
+ operation.operation_key
836
+ FROM jsonb_to_recordset($4::jsonb) AS item(
837
+ sandbox_id text, operation_key text, routing_domain text
838
+ )
839
+ JOIN ${operations} AS operation
840
+ ON operation.sandbox_id = item.sandbox_id
841
+ AND operation.routing_domain IS NOT DISTINCT FROM item.routing_domain
842
+ WHERE operation.provider = $1
843
+ AND operation.environment = 'production'
844
+ AND operation.state IN ($2, $3)
845
+ `,
846
+ [
847
+ DAYTONA_PROVIDER,
848
+ RuntimeSandboxOperationState.Live,
849
+ RuntimeSandboxOperationState.Deleting,
850
+ inventoryJson,
851
+ ],
852
+ )
853
+ : { rows: [] };
854
+ const live = liveRows.rows.map((row) => ({
855
+ sandboxId: row.sandbox_id,
856
+ runId: row.run_id,
857
+ attempt: Number(row.attempt),
858
+ orgId: row.org_id,
859
+ environment: row.environment,
860
+ routingDomain: row.routing_domain,
861
+ operationKey: row.operation_key,
862
+ }));
863
+ const matchedIdentities = new Set(
864
+ live.map((row) => `${row.sandboxId}\u0000${row.routingDomain ?? ''}`),
865
+ );
866
+ const unmatchedProviderSandboxIds = providerSandboxes
867
+ .filter(
868
+ (sandbox) =>
869
+ !matchedIdentities.has(
870
+ `${sandbox.sandboxId}\u0000${sandbox.routingDomain ?? ''}`,
871
+ ) &&
872
+ !reservedOwned.rows.some(
873
+ (owned) =>
874
+ owned.sandbox_id === sandbox.sandboxId &&
875
+ owned.routing_domain === sandbox.routingDomain &&
876
+ owned.provider_operation_token === sandbox.operationKey &&
877
+ !duplicateOperationTokens.has(sandbox.operationKey ?? ''),
878
+ ),
879
+ )
880
+ .map((sandbox) => sandbox.sandboxId);
881
+
882
+ // Do not write an incomplete migration: a listed sandbox lacking durable
883
+ // ownership cannot safely be assigned to an organization for enforcement.
884
+ if (unmatchedProviderSandboxIds.length > 0) {
885
+ return {
886
+ provider: DAYTONA_PROVIDER,
887
+ providerSandboxCount: providerSandboxes.length,
888
+ matchedLiveSandboxes: live.length,
889
+ unmatchedProviderSandboxIds,
890
+ liveLeasesToSeed: 0,
891
+ absentLedgerRows: 0,
892
+ seededLeases: 0,
893
+ releasedTerminalLeases,
894
+ markedDeleted: 0,
895
+ recoveredReservedOperations,
896
+ hasMoreAbsentLedgerRows: false,
897
+ dryRun: input.dryRun,
898
+ diagnostics,
899
+ };
900
+ }
901
+
902
+ const candidates = await measuredQuery<{
903
+ sandbox_id: string;
904
+ run_id: string;
905
+ attempt: number;
906
+ org_id: string;
907
+ environment: string;
908
+ routing_domain: string | null;
909
+ }>(
910
+ RuntimeSandboxLedgerReconciliationPhase.FindAbsentOperations,
911
+ `
912
+ SELECT sandbox_id, run_id, attempt, org_id, environment, routing_domain
913
+ FROM ${operations}
914
+ WHERE provider = $1
915
+ AND environment = 'production'
916
+ AND state = $2
917
+ AND NOT EXISTS (
918
+ SELECT 1
919
+ FROM jsonb_to_recordset($3::jsonb) AS inventory(
920
+ sandbox_id text, operation_key text, routing_domain text
921
+ )
922
+ WHERE inventory.sandbox_id = ${operations}.sandbox_id
923
+ AND inventory.routing_domain IS NOT DISTINCT FROM ${operations}.routing_domain
924
+ )
925
+ AND NOT EXISTS (
926
+ SELECT 1
927
+ FROM ${cleanup} AS existing
928
+ WHERE existing.provider = '${DAYTONA_PROVIDER}'
929
+ AND existing.sandbox_id = ${operations}.sandbox_id
930
+ AND existing.routing_domain IS NOT DISTINCT FROM ${operations}.routing_domain
931
+ AND existing.status = 'deleted'
932
+ )
933
+ -- Provider inventory is a point-in-time observation. Never classify
934
+ -- an operation recorded after it as absent.
935
+ AND provider_created_at <= to_timestamp($4::double precision / 1000.0)
936
+ AND provider_created_at <= clock_timestamp() - ($5::integer * interval '1 millisecond')
937
+ ORDER BY provider_created_at, operation_key
938
+ LIMIT $6
939
+ `,
940
+ [
941
+ DAYTONA_PROVIDER,
942
+ RuntimeSandboxOperationState.Live,
943
+ inventoryJson,
944
+ input.inventoryCapturedAtMs,
945
+ minimumAgeMs,
946
+ limit + 1,
947
+ ],
948
+ );
949
+ const hasMoreAbsentLedgerRows = candidates.rows.length > limit;
950
+ const absent = candidates.rows.slice(0, limit).map((row) => ({
951
+ sandboxId: row.sandbox_id,
952
+ runId: row.run_id,
953
+ attempt: Number(row.attempt),
954
+ orgId: row.org_id,
955
+ environment: row.environment,
956
+ routingDomain: row.routing_domain,
957
+ }));
958
+
959
+ const leaseRows = live.length
960
+ ? await measuredQuery<{
961
+ sandbox_id: string;
962
+ routing_domain: string | null;
963
+ }>(
964
+ RuntimeSandboxLedgerReconciliationPhase.InspectCapacityBindings,
965
+ `
966
+ SELECT DISTINCT sandbox_id, routing_domain
967
+ FROM ${leases}
968
+ WHERE provider = '${DAYTONA_PROVIDER}'
969
+ AND sandbox_id = ANY($1::text[])
970
+ `,
971
+ [live.map((row) => row.sandboxId)],
972
+ )
973
+ : { rows: [] };
974
+ const existingLeaseIdentities = new Set(
975
+ leaseRows.rows.map(
976
+ (row) => `${row.sandbox_id}\u0000${row.routing_domain ?? ''}`,
977
+ ),
978
+ );
979
+ const terminalLiveRows = live.length
980
+ ? await measuredQuery<{
981
+ sandbox_id: string;
982
+ routing_domain: string | null;
983
+ }>(
984
+ RuntimeSandboxLedgerReconciliationPhase.InspectCapacityBindings,
985
+ `
986
+ SELECT DISTINCT cleanup.sandbox_id, cleanup.routing_domain
987
+ FROM ${cleanup} AS cleanup
988
+ WHERE cleanup.provider = '${DAYTONA_PROVIDER}'
989
+ AND cleanup.status = 'deleted'
990
+ AND cleanup.deleted_at IS NOT NULL
991
+ AND cleanup.sandbox_id = ANY($1::text[])
992
+ `,
993
+ [live.map((row) => row.sandboxId)],
994
+ )
995
+ : { rows: [] };
996
+ const terminalLiveSandboxIdentities = new Set(
997
+ terminalLiveRows.rows.map(
998
+ (row) => `${row.sandbox_id}\u0000${row.routing_domain ?? ''}`,
999
+ ),
1000
+ );
1001
+ const liveLeasesToSeed = live.filter(
1002
+ (row) =>
1003
+ !existingLeaseIdentities.has(
1004
+ `${row.sandboxId}\u0000${row.routingDomain ?? ''}`,
1005
+ ) &&
1006
+ !terminalLiveSandboxIdentities.has(
1007
+ `${row.sandboxId}\u0000${row.routingDomain ?? ''}`,
1008
+ ),
1009
+ );
1010
+
1011
+ if (input.dryRun) {
1012
+ return {
1013
+ provider: DAYTONA_PROVIDER,
1014
+ providerSandboxCount: providerSandboxes.length,
1015
+ matchedLiveSandboxes: live.length,
1016
+ unmatchedProviderSandboxIds,
1017
+ liveLeasesToSeed: liveLeasesToSeed.length,
1018
+ absentLedgerRows: absent.length,
1019
+ seededLeases: 0,
1020
+ releasedTerminalLeases,
1021
+ markedDeleted: 0,
1022
+ recoveredReservedOperations,
1023
+ hasMoreAbsentLedgerRows,
1024
+ dryRun: true,
1025
+ diagnostics,
1026
+ };
1027
+ }
1028
+
1029
+ let seededLeases = 0;
1030
+ if (liveLeasesToSeed.length > 0) {
1031
+ const seeded = await measuredQuery<{ lease_id: string }>(
1032
+ RuntimeSandboxLedgerReconciliationPhase.SeedCapacityBindings,
1033
+ `
1034
+ INSERT INTO ${leases} (
1035
+ lease_id, org_id, run_id, provider, sandbox_id, routing_domain, expires_at, released_at
1036
+ )
1037
+ SELECT
1038
+ item.operation_key,
1039
+ item.org_id,
1040
+ item.run_id,
1041
+ '${DAYTONA_PROVIDER}',
1042
+ item.sandbox_id,
1043
+ item.routing_domain,
1044
+ clock_timestamp(),
1045
+ NULL
1046
+ FROM jsonb_to_recordset($1::jsonb) AS item(
1047
+ operation_key text, sandbox_id text, org_id text, run_id text,
1048
+ routing_domain text
1049
+ )
1050
+ WHERE NOT EXISTS (
1051
+ SELECT 1
1052
+ FROM ${cleanup} AS terminal_cleanup
1053
+ WHERE terminal_cleanup.provider = '${DAYTONA_PROVIDER}'
1054
+ AND terminal_cleanup.sandbox_id = item.sandbox_id
1055
+ AND terminal_cleanup.run_id = item.run_id
1056
+ AND terminal_cleanup.routing_domain IS NOT DISTINCT FROM item.routing_domain
1057
+ AND terminal_cleanup.status = 'deleted'
1058
+ AND terminal_cleanup.deleted_at IS NOT NULL
1059
+ )
1060
+ ON CONFLICT (lease_id) DO UPDATE
1061
+ SET org_id = EXCLUDED.org_id,
1062
+ run_id = EXCLUDED.run_id,
1063
+ provider = EXCLUDED.provider,
1064
+ sandbox_id = EXCLUDED.sandbox_id,
1065
+ routing_domain = EXCLUDED.routing_domain,
1066
+ expires_at = EXCLUDED.expires_at
1067
+ WHERE ${leases}.released_at IS NULL
1068
+ AND NOT EXISTS (
1069
+ SELECT 1
1070
+ FROM ${cleanup} AS terminal_cleanup
1071
+ WHERE terminal_cleanup.provider = '${DAYTONA_PROVIDER}'
1072
+ AND terminal_cleanup.sandbox_id = EXCLUDED.sandbox_id
1073
+ AND terminal_cleanup.run_id = EXCLUDED.run_id
1074
+ AND terminal_cleanup.routing_domain IS NOT DISTINCT FROM EXCLUDED.routing_domain
1075
+ AND terminal_cleanup.status = 'deleted'
1076
+ AND terminal_cleanup.deleted_at IS NOT NULL
1077
+ )
1078
+ RETURNING lease_id
1079
+ `,
1080
+ [
1081
+ JSON.stringify(
1082
+ liveLeasesToSeed.map((row) => ({
1083
+ operation_key: row.operationKey,
1084
+ sandbox_id: row.sandboxId,
1085
+ org_id: row.orgId,
1086
+ run_id: row.runId,
1087
+ routing_domain: row.routingDomain,
1088
+ })),
1089
+ ),
1090
+ ],
1091
+ );
1092
+ seededLeases = seeded.rows.length;
1093
+ }
1094
+
1095
+ const marked = absent.length
1096
+ ? await measuredQuery<{ sandbox_id: string }>(
1097
+ RuntimeSandboxLedgerReconciliationPhase.MarkProviderConfirmedAbsent,
1098
+ `
1099
+ WITH candidates AS (
1100
+ SELECT *
1101
+ FROM jsonb_to_recordset($1::jsonb) AS item(
1102
+ sandbox_id text,
1103
+ run_id text,
1104
+ attempt integer,
1105
+ environment text,
1106
+ routing_domain text
1107
+ )
1108
+ ),
1109
+ changed AS (
1110
+ INSERT INTO ${cleanup} (
1111
+ provider, sandbox_id, run_id, attempt, environment, routing_domain,
1112
+ status, deleted_at, available_at, updated_at, last_error
1113
+ )
1114
+ SELECT
1115
+ '${DAYTONA_PROVIDER}', sandbox_id, run_id, attempt, environment, routing_domain,
1116
+ 'deleted', clock_timestamp(), clock_timestamp(), clock_timestamp(),
1117
+ 'reconciled_provider_confirmed_absent'
1118
+ FROM candidates
1119
+ ON CONFLICT (provider, sandbox_id, routing_domain_key) DO UPDATE
1120
+ SET status = 'deleted',
1121
+ deleted_at = clock_timestamp(),
1122
+ lease_owner = NULL,
1123
+ lease_expires_at = NULL,
1124
+ updated_at = clock_timestamp(),
1125
+ last_error = 'reconciled_provider_confirmed_absent'
1126
+ -- A real cleanup worker owns deleting rows. Do not erase its
1127
+ -- lease/fencing state; its normal completion records the outcome.
1128
+ WHERE ${cleanup}.status = 'pending'
1129
+ AND ${cleanup}.lease_owner IS NULL
1130
+ RETURNING sandbox_id, routing_domain, run_id, attempt
1131
+ ),
1132
+ events AS (
1133
+ INSERT INTO ${cleanupEvents} (
1134
+ provider, sandbox_id, routing_domain, run_id, attempt,
1135
+ cleanup_attempt, lease_owner, event_type, details_json
1136
+ )
1137
+ SELECT
1138
+ '${DAYTONA_PROVIDER}', sandbox_id, routing_domain, run_id, attempt,
1139
+ 0, NULL, 'reconciled_provider_confirmed_absent',
1140
+ jsonb_build_object('source', 'runtime-sandbox-ledger-reconciliation')
1141
+ FROM changed
1142
+ ),
1143
+ operation_deleted AS (
1144
+ UPDATE ${operations} AS operation
1145
+ SET state = $2,
1146
+ delete_confirmed_at = COALESCE(
1147
+ operation.delete_confirmed_at,
1148
+ clock_timestamp()
1149
+ ),
1150
+ updated_at = clock_timestamp()
1151
+ FROM changed
1152
+ WHERE operation.provider = '${DAYTONA_PROVIDER}'
1153
+ AND operation.sandbox_id = changed.sandbox_id
1154
+ AND operation.routing_domain IS NOT DISTINCT FROM changed.routing_domain
1155
+ AND operation.state = $3
1156
+ RETURNING operation.operation_key
1157
+ ),
1158
+ released_leases AS (
1159
+ UPDATE ${leases} AS lease
1160
+ SET released_at = clock_timestamp()
1161
+ FROM changed
1162
+ WHERE lease.provider = '${DAYTONA_PROVIDER}'
1163
+ AND lease.run_id = changed.run_id
1164
+ AND lease.sandbox_id = changed.sandbox_id
1165
+ AND lease.routing_domain IS NOT DISTINCT FROM changed.routing_domain
1166
+ AND lease.released_at IS NULL
1167
+ )
1168
+ SELECT sandbox_id FROM changed
1169
+ `,
1170
+ [
1171
+ JSON.stringify(
1172
+ absent.map((row) => ({
1173
+ sandbox_id: row.sandboxId,
1174
+ run_id: row.runId,
1175
+ attempt: row.attempt,
1176
+ environment: row.environment,
1177
+ routing_domain: row.routingDomain,
1178
+ })),
1179
+ ),
1180
+ RuntimeSandboxOperationState.Deleted,
1181
+ RuntimeSandboxOperationState.Live,
1182
+ ],
1183
+ )
1184
+ : { rows: [] };
1185
+
1186
+ // Covers the narrow race where a normal cleanup reaches provider-confirmed
1187
+ // deletion after the pre-seed repair but before this reconciliation returns.
1188
+ // The worker path also releases its own leases; this makes the migration
1189
+ // converge even when an older worker completed cleanup first.
1190
+ if (!input.dryRun) {
1191
+ const startedAt = performance.now();
1192
+ releasedTerminalLeases += await releaseTerminalSandboxCapacityLeases(
1193
+ client,
1194
+ options,
1195
+ );
1196
+ diagnostics.push({
1197
+ phase: RuntimeSandboxLedgerReconciliationPhase.ReleaseTerminalCapacity,
1198
+ durationMs: performance.now() - startedAt,
1199
+ rowCount: releasedTerminalLeases,
1200
+ });
1201
+ }
1202
+
1203
+ return {
1204
+ provider: DAYTONA_PROVIDER,
1205
+ providerSandboxCount: providerSandboxes.length,
1206
+ matchedLiveSandboxes: live.length,
1207
+ unmatchedProviderSandboxIds,
1208
+ liveLeasesToSeed: liveLeasesToSeed.length,
1209
+ absentLedgerRows: absent.length,
1210
+ seededLeases,
1211
+ releasedTerminalLeases,
1212
+ markedDeleted: marked.rows.length,
1213
+ recoveredReservedOperations,
1214
+ hasMoreAbsentLedgerRows,
1215
+ dryRun: false,
1216
+ diagnostics,
1217
+ };
1218
+ }