@lostgradient/weft 0.23.1 → 0.24.1

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 (469) hide show
  1. package/README.md +72 -4
  2. package/dist/cli/codegen-emit-dedup.d.ts +81 -0
  3. package/dist/cli/codegen-emit-dedup.js +45 -0
  4. package/dist/cli/codegen-emit-registry.d.ts +90 -0
  5. package/dist/cli/codegen-emit-registry.js +50 -0
  6. package/dist/cli/codegen-emit.d.ts +26 -39
  7. package/dist/cli/codegen-emit.js +4 -27
  8. package/dist/cli/codegen-validate.d.ts +49 -0
  9. package/dist/cli/codegen-validate.js +186 -0
  10. package/dist/cli/codegen.js +6 -87
  11. package/dist/cli/conformance.js +5 -2
  12. package/dist/cli/generated/operation-catalog.snapshot.json +381 -3
  13. package/dist/cli/generated/operation-client.generated.d.ts +350 -10
  14. package/dist/cli/generated/operation-client.generated.js +14 -0
  15. package/dist/cli/output.js +1 -1
  16. package/dist/cli/parse-schedule-arguments.js +15 -3
  17. package/dist/cli/schedule.js +2 -1
  18. package/dist/cli/storage-factory.js +2 -0
  19. package/dist/cli/types.d.ts +2 -1
  20. package/dist/cli/workflow-commands.js +2 -0
  21. package/dist/cli-main.js +1 -1
  22. package/dist/client/http-client-requests.js +6 -9
  23. package/dist/client/start-body.js +1 -0
  24. package/dist/core/application-payload-digest.d.ts +42 -0
  25. package/dist/core/application-payload-digest.js +76 -0
  26. package/dist/core/application-primitive-abort.d.ts +50 -0
  27. package/dist/core/application-primitive-abort.js +40 -0
  28. package/dist/core/application-primitive-attempt-registry.d.ts +74 -0
  29. package/dist/core/application-primitive-attempt-registry.js +73 -0
  30. package/dist/core/application-primitive-codec.d.ts +36 -0
  31. package/dist/core/application-primitive-codec.js +56 -0
  32. package/dist/core/application-primitive-commit.d.ts +67 -0
  33. package/dist/core/application-primitive-commit.js +66 -0
  34. package/dist/core/application-primitive-guards.d.ts +62 -0
  35. package/dist/core/application-primitive-guards.js +89 -0
  36. package/dist/core/application-primitive-payload.d.ts +29 -0
  37. package/dist/core/application-primitive-payload.js +65 -0
  38. package/dist/core/application-primitive-timing.d.ts +18 -0
  39. package/dist/core/application-primitive-timing.js +22 -0
  40. package/dist/core/atomic-state.js +2 -0
  41. package/dist/core/catalog/codec.d.ts +40 -0
  42. package/dist/core/catalog/codec.js +45 -0
  43. package/dist/core/catalog/errors.d.ts +104 -0
  44. package/dist/core/catalog/errors.js +41 -0
  45. package/dist/core/catalog/index.d.ts +25 -0
  46. package/dist/core/catalog/index.js +22 -0
  47. package/dist/core/catalog/reference-counts.d.ts +120 -0
  48. package/dist/core/catalog/reference-counts.js +28 -0
  49. package/dist/core/catalog/removal.d.ts +105 -0
  50. package/dist/core/catalog/removal.js +30 -0
  51. package/dist/core/catalog/storage-io.d.ts +101 -0
  52. package/dist/core/catalog/storage-io.js +106 -0
  53. package/dist/core/catalog/types.d.ts +108 -0
  54. package/dist/core/catalog/types.js +0 -0
  55. package/dist/core/catalog/workflow-catalog.d.ts +165 -0
  56. package/dist/core/catalog/workflow-catalog.js +198 -0
  57. package/dist/core/compare-codepoint.d.ts +13 -0
  58. package/dist/core/compare-codepoint.js +7 -0
  59. package/dist/core/compression.js +2 -0
  60. package/dist/core/context/attributes.d.ts +1 -1
  61. package/dist/core/context/durable-operations.d.ts +2 -2
  62. package/dist/core/context/index.js +5 -3
  63. package/dist/core/context/state-namespace.d.ts +1 -1
  64. package/dist/core/contract/build.d.ts +64 -0
  65. package/dist/core/contract/build.js +99 -0
  66. package/dist/core/contract/compatibility.d.ts +187 -0
  67. package/dist/core/contract/compatibility.js +37 -0
  68. package/dist/core/contract/failure.d.ts +64 -0
  69. package/dist/core/contract/failure.js +4 -0
  70. package/dist/core/contract/hash.d.ts +92 -0
  71. package/dist/core/contract/hash.js +34 -0
  72. package/dist/core/contract/index.d.ts +21 -0
  73. package/dist/core/contract/index.js +22 -0
  74. package/dist/core/contract/limits.d.ts +74 -0
  75. package/dist/core/contract/limits.js +1 -0
  76. package/dist/core/contract/manifest-parse-schema.d.ts +37 -0
  77. package/dist/core/contract/manifest-parse-schema.js +106 -0
  78. package/dist/core/contract/manifest-parse.d.ts +76 -0
  79. package/dist/core/contract/manifest-parse.js +189 -0
  80. package/dist/core/contract/manifest.d.ts +56 -0
  81. package/dist/core/contract/manifest.js +31 -0
  82. package/dist/core/contract/normalize.d.ts +97 -0
  83. package/dist/core/contract/normalize.js +127 -0
  84. package/dist/core/contract/revision.d.ts +29 -0
  85. package/dist/core/contract/revision.js +5 -0
  86. package/dist/core/contract/types.d.ts +274 -0
  87. package/dist/core/contract/types.js +1 -0
  88. package/dist/core/engine/activity-resolution.js +17 -17
  89. package/dist/core/engine/bulk-operations-purge.js +14 -20
  90. package/dist/core/engine/bulk-operations-retry.d.ts +9 -0
  91. package/dist/core/engine/bulk-operations-retry.js +177 -0
  92. package/dist/core/engine/bulk-operations-shared.d.ts +18 -0
  93. package/dist/core/engine/bulk-operations-shared.js +14 -0
  94. package/dist/core/engine/bulk-operations.js +8 -167
  95. package/dist/core/engine/callback-creators-bundles.js +4 -2
  96. package/dist/core/engine/callback-creators-core.js +9 -1
  97. package/dist/core/engine/callback-creators-schedule.js +2 -2
  98. package/dist/core/engine/catalog-activation.d.ts +40 -0
  99. package/dist/core/engine/catalog-activation.js +17 -0
  100. package/dist/core/engine/catalog-events.d.ts +36 -0
  101. package/dist/core/engine/catalog-events.js +15 -0
  102. package/dist/core/engine/catalog-readiness.d.ts +49 -0
  103. package/dist/core/engine/catalog-readiness.js +61 -0
  104. package/dist/core/engine/catalog-removal.d.ts +236 -0
  105. package/dist/core/engine/catalog-removal.js +123 -0
  106. package/dist/core/engine/catalog-tombstone-recovery.d.ts +56 -0
  107. package/dist/core/engine/catalog-tombstone-recovery.js +39 -0
  108. package/dist/core/engine/constraints.js +5 -1
  109. package/dist/core/engine/construction.d.ts +2 -2
  110. package/dist/core/engine/construction.js +4 -2
  111. package/dist/core/engine/decode-revision.d.ts +32 -0
  112. package/dist/core/engine/decode-revision.js +9 -0
  113. package/dist/core/engine/disposal.d.ts +6 -2
  114. package/dist/core/engine/disposal.js +26 -3
  115. package/dist/core/engine/dynamic-source-errors.d.ts +81 -0
  116. package/dist/core/engine/dynamic-source-errors.js +25 -0
  117. package/dist/core/engine/dynamic-source-execution.d.ts +173 -0
  118. package/dist/core/engine/dynamic-source-execution.js +108 -0
  119. package/dist/core/engine/engine-internal-types.d.ts +16 -0
  120. package/dist/core/engine/engine-workflows-namespace.d.ts +140 -0
  121. package/dist/core/engine/engine-workflows-namespace.js +51 -0
  122. package/dist/core/engine/finalizer-metadata.d.ts +22 -0
  123. package/dist/core/engine/finalizer-metadata.js +12 -0
  124. package/dist/core/engine/handle-result.js +2 -0
  125. package/dist/core/engine/index.d.ts +91 -0
  126. package/dist/core/engine/index.js +78 -6
  127. package/dist/core/engine/inline-launch-queue.js +1 -1
  128. package/dist/core/engine/internals.d.ts +54 -15
  129. package/dist/core/engine/internals.js +6 -0
  130. package/dist/core/engine/lifecycle/checkpoint-launch.d.ts +29 -0
  131. package/dist/core/engine/lifecycle/checkpoint-launch.js +75 -0
  132. package/dist/core/engine/lifecycle/delayed-start-registration.d.ts +30 -0
  133. package/dist/core/engine/lifecycle/delayed-start-registration.js +11 -0
  134. package/dist/core/engine/lifecycle/fork-helpers.d.ts +33 -1
  135. package/dist/core/engine/lifecycle/fork-helpers.js +3 -1
  136. package/dist/core/engine/lifecycle/recovery-revision-groups.d.ts +75 -0
  137. package/dist/core/engine/lifecycle/recovery-revision-groups.js +64 -0
  138. package/dist/core/engine/lifecycle/resume-generation-guard.d.ts +58 -0
  139. package/dist/core/engine/lifecycle/resume-generation-guard.js +11 -0
  140. package/dist/core/engine/lifecycle/resume.js +18 -9
  141. package/dist/core/engine/lifecycle/shared.d.ts +43 -0
  142. package/dist/core/engine/lifecycle/standalone-claim-acquire.d.ts +12 -0
  143. package/dist/core/engine/lifecycle/standalone-claim-acquire.js +6 -0
  144. package/dist/core/engine/lifecycle/start-commit-errors.d.ts +12 -0
  145. package/dist/core/engine/lifecycle/start-commit-errors.js +6 -0
  146. package/dist/core/engine/lifecycle/start-commit.d.ts +22 -7
  147. package/dist/core/engine/lifecycle/start-commit.js +49 -15
  148. package/dist/core/engine/lifecycle/start-exec.d.ts +18 -2
  149. package/dist/core/engine/lifecycle/start-exec.js +7 -5
  150. package/dist/core/engine/lifecycle/start-or-signal-create.js +1 -3
  151. package/dist/core/engine/lifecycle/start-or-signal.js +1 -1
  152. package/dist/core/engine/lifecycle/start-precondition-attribution.d.ts +49 -0
  153. package/dist/core/engine/lifecycle/start-precondition-attribution.js +13 -0
  154. package/dist/core/engine/lifecycle/start-revision-resolution.d.ts +34 -0
  155. package/dist/core/engine/lifecycle/start-revision-resolution.js +11 -0
  156. package/dist/core/engine/lifecycle/start-state.d.ts +16 -0
  157. package/dist/core/engine/lifecycle/start-state.js +60 -0
  158. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +66 -3
  159. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +13 -3
  160. package/dist/core/engine/lifecycle/start.d.ts +16 -6
  161. package/dist/core/engine/lifecycle/start.js +39 -66
  162. package/dist/core/engine/lifecycle/transition.d.ts +3 -4
  163. package/dist/core/engine/lifecycle/transition.js +30 -80
  164. package/dist/core/engine/lifecycle.d.ts +4 -2
  165. package/dist/core/engine/lifecycle.js +6 -6
  166. package/dist/core/engine/listing.js +15 -1
  167. package/dist/core/engine/memo-durable-activity.js +4 -1
  168. package/dist/core/engine/nonterminal-revision-count.d.ts +25 -0
  169. package/dist/core/engine/nonterminal-revision-count.js +16 -0
  170. package/dist/core/engine/operations-time.d.ts +5 -23
  171. package/dist/core/engine/operations-time.js +13 -11
  172. package/dist/core/engine/ownership-bootstrap.d.ts +1 -1
  173. package/dist/core/engine/pinned-schedule-revision-count.d.ts +26 -0
  174. package/dist/core/engine/pinned-schedule-revision-count.js +19 -0
  175. package/dist/core/engine/pinned-schedule-revision.d.ts +76 -0
  176. package/dist/core/engine/pinned-schedule-revision.js +53 -0
  177. package/dist/core/engine/registration.d.ts +106 -0
  178. package/dist/core/engine/registration.js +28 -7
  179. package/dist/core/engine/retention.js +9 -2
  180. package/dist/core/engine/revision-errors.d.ts +71 -0
  181. package/dist/core/engine/revision-errors.js +13 -0
  182. package/dist/core/engine/schedule-revision-fire.d.ts +17 -0
  183. package/dist/core/engine/schedule-revision-fire.js +3 -0
  184. package/dist/core/engine/schedule-run.js +2 -1
  185. package/dist/core/engine/schedules.d.ts +2 -1
  186. package/dist/core/engine/schedules.js +28 -9
  187. package/dist/core/engine/source-diagnostics.d.ts +76 -0
  188. package/dist/core/engine/source-diagnostics.js +105 -0
  189. package/dist/core/engine/source-registration.d.ts +42 -0
  190. package/dist/core/engine/source-registration.js +38 -0
  191. package/dist/core/engine/source-resolution.d.ts +101 -0
  192. package/dist/core/engine/source-resolution.js +154 -0
  193. package/dist/core/engine/source-runtime-state.d.ts +92 -0
  194. package/dist/core/engine/source-runtime-state.js +36 -0
  195. package/dist/core/engine/storage-io.d.ts +19 -2
  196. package/dist/core/engine/storage-io.js +21 -2
  197. package/dist/core/engine/termination/finalizer-registration.d.ts +18 -0
  198. package/dist/core/engine/termination/finalizer-registration.js +21 -0
  199. package/dist/core/engine/termination/finalizer.d.ts +16 -19
  200. package/dist/core/engine/termination/finalizer.js +3 -3
  201. package/dist/core/engine/time-operation-callbacks.d.ts +32 -0
  202. package/dist/core/engine/time-operation-callbacks.js +0 -0
  203. package/dist/core/engine/validation/schedule-cadence.d.ts +16 -0
  204. package/dist/core/engine/validation/schedule-cadence.js +20 -0
  205. package/dist/core/engine/validation/schedule-options.d.ts +4 -1
  206. package/dist/core/engine/validation/schedule-options.js +14 -0
  207. package/dist/core/engine/validation/schedule-revision.d.ts +24 -0
  208. package/dist/core/engine/validation/schedule-revision.js +21 -0
  209. package/dist/core/engine/validation/schedule-warnings.d.ts +11 -0
  210. package/dist/core/engine/validation/schedule-warnings.js +5 -0
  211. package/dist/core/engine/validation/schedule.d.ts +4 -3
  212. package/dist/core/engine/validation/schedule.js +15 -26
  213. package/dist/core/engine/validation.js +5 -2
  214. package/dist/core/engine/workflow-claim-reclaim-target.d.ts +1 -1
  215. package/dist/core/engine/workflow-claim-reclaim-target.js +16 -2
  216. package/dist/core/engine/workflow-retention-deadline.d.ts +16 -0
  217. package/dist/core/engine/workflow-retention-deadline.js +33 -0
  218. package/dist/core/events/catalog-events.d.ts +117 -0
  219. package/dist/core/events/catalog-events.js +62 -0
  220. package/dist/core/events/event-map.d.ts +11 -0
  221. package/dist/core/events/index.d.ts +2 -0
  222. package/dist/core/events/index.js +2 -0
  223. package/dist/core/events/workflow-source-events.d.ts +102 -0
  224. package/dist/core/events/workflow-source-events.js +57 -0
  225. package/dist/core/execution-strategy.d.ts +7 -0
  226. package/dist/core/inline-execution-strategy.context-options.d.ts +1 -1
  227. package/dist/core/inline-execution-strategy.js +1 -1
  228. package/dist/core/mailbox-admission.d.ts +26 -0
  229. package/dist/core/mailbox-admission.js +130 -0
  230. package/dist/core/mailbox-claims.d.ts +251 -0
  231. package/dist/core/mailbox-claims.js +0 -0
  232. package/dist/core/mailbox-codec.d.ts +32 -0
  233. package/dist/core/mailbox-codec.js +221 -0
  234. package/dist/core/mailbox-contract.d.ts +290 -0
  235. package/dist/core/mailbox-contract.js +0 -0
  236. package/dist/core/mailbox-delivery.d.ts +37 -0
  237. package/dist/core/mailbox-delivery.js +193 -0
  238. package/dist/core/mailbox-guards.d.ts +78 -0
  239. package/dist/core/mailbox-guards.js +58 -0
  240. package/dist/core/mailbox-index-codec.d.ts +41 -0
  241. package/dist/core/mailbox-index-codec.js +71 -0
  242. package/dist/core/mailbox-internals.d.ts +156 -0
  243. package/dist/core/mailbox-internals.js +154 -0
  244. package/dist/core/mailbox-maintenance.d.ts +29 -0
  245. package/dist/core/mailbox-maintenance.js +196 -0
  246. package/dist/core/mailbox-settlement.d.ts +69 -0
  247. package/dist/core/mailbox-settlement.js +206 -0
  248. package/dist/core/mailbox-storage.d.ts +117 -0
  249. package/dist/core/mailbox-storage.js +115 -0
  250. package/dist/core/mailbox-transition-helpers.d.ts +70 -0
  251. package/dist/core/mailbox-transition-helpers.js +43 -0
  252. package/dist/core/mailbox-transitions-recovery.d.ts +28 -0
  253. package/dist/core/mailbox-transitions-recovery.js +64 -0
  254. package/dist/core/mailbox-transitions.d.ts +138 -0
  255. package/dist/core/mailbox-transitions.js +180 -0
  256. package/dist/core/mailbox-types.d.ts +406 -0
  257. package/dist/core/mailbox-types.js +16 -0
  258. package/dist/core/mailbox-validation.d.ts +65 -0
  259. package/dist/core/mailbox-validation.js +73 -0
  260. package/dist/core/mailbox-waits.d.ts +50 -0
  261. package/dist/core/mailbox-waits.js +97 -0
  262. package/dist/core/mailbox.d.ts +163 -0
  263. package/dist/core/mailbox.js +211 -0
  264. package/dist/core/outbox-claims.d.ts +307 -0
  265. package/dist/core/outbox-claims.js +0 -0
  266. package/dist/core/outbox-codec.d.ts +24 -0
  267. package/dist/core/outbox-codec.js +257 -0
  268. package/dist/core/outbox-contract.d.ts +346 -0
  269. package/dist/core/outbox-contract.js +0 -0
  270. package/dist/core/outbox-delivery.d.ts +34 -0
  271. package/dist/core/outbox-delivery.js +149 -0
  272. package/dist/core/outbox-drain.d.ts +29 -0
  273. package/dist/core/outbox-drain.js +158 -0
  274. package/dist/core/outbox-enqueue.d.ts +24 -0
  275. package/dist/core/outbox-enqueue.js +115 -0
  276. package/dist/core/outbox-guards.d.ts +76 -0
  277. package/dist/core/outbox-guards.js +60 -0
  278. package/dist/core/outbox-index-codec.d.ts +33 -0
  279. package/dist/core/outbox-index-codec.js +71 -0
  280. package/dist/core/outbox-internals.d.ts +99 -0
  281. package/dist/core/outbox-internals.js +159 -0
  282. package/dist/core/outbox-listing.d.ts +12 -0
  283. package/dist/core/outbox-listing.js +38 -0
  284. package/dist/core/outbox-maintenance.d.ts +28 -0
  285. package/dist/core/outbox-maintenance.js +191 -0
  286. package/dist/core/outbox-operations.d.ts +18 -0
  287. package/dist/core/outbox-operations.js +46 -0
  288. package/dist/core/outbox-runner.d.ts +30 -0
  289. package/dist/core/outbox-runner.js +217 -0
  290. package/dist/core/outbox-settlement.d.ts +57 -0
  291. package/dist/core/outbox-settlement.js +183 -0
  292. package/dist/core/outbox-storage.d.ts +107 -0
  293. package/dist/core/outbox-storage.js +127 -0
  294. package/dist/core/outbox-transition-helpers.d.ts +83 -0
  295. package/dist/core/outbox-transition-helpers.js +63 -0
  296. package/dist/core/outbox-transitions-recovery.d.ts +30 -0
  297. package/dist/core/outbox-transitions-recovery.js +42 -0
  298. package/dist/core/outbox-transitions.d.ts +145 -0
  299. package/dist/core/outbox-transitions.js +236 -0
  300. package/dist/core/outbox-types.d.ts +400 -0
  301. package/dist/core/outbox-types.js +20 -0
  302. package/dist/core/outbox-validation.d.ts +101 -0
  303. package/dist/core/outbox-validation.js +127 -0
  304. package/dist/core/outbox-waits.d.ts +39 -0
  305. package/dist/core/outbox-waits.js +88 -0
  306. package/dist/core/outbox.d.ts +156 -0
  307. package/dist/core/outbox.js +234 -0
  308. package/dist/core/registry-limits.d.ts +49 -0
  309. package/dist/core/registry-limits.js +10 -0
  310. package/dist/core/registry-schema-conversion.d.ts +20 -0
  311. package/dist/core/registry-schema-conversion.js +22 -0
  312. package/dist/core/registry-snapshot.d.ts +91 -42
  313. package/dist/core/registry-snapshot.js +39 -77
  314. package/dist/core/registry-workflow-contract-draft.d.ts +32 -0
  315. package/dist/core/registry-workflow-contract-draft.js +28 -0
  316. package/dist/core/registry-workflow-manifest.d.ts +122 -0
  317. package/dist/core/registry-workflow-manifest.js +92 -0
  318. package/dist/core/source/errors.d.ts +55 -0
  319. package/dist/core/source/errors.js +13 -0
  320. package/dist/core/source/index.d.ts +19 -0
  321. package/dist/core/source/index.js +4 -0
  322. package/dist/core/source/resolvers.d.ts +45 -0
  323. package/dist/core/source/resolvers.js +9 -0
  324. package/dist/core/source/types.d.ts +211 -0
  325. package/dist/core/source/types.js +0 -0
  326. package/dist/core/source/validate.d.ts +91 -0
  327. package/dist/core/source/validate.js +62 -0
  328. package/dist/core/source/workflow-source.d.ts +43 -0
  329. package/dist/core/source/workflow-source.js +16 -0
  330. package/dist/core/types/checkpoint.d.ts +14 -0
  331. package/dist/core/types/schedules.d.ts +52 -1
  332. package/dist/core/types/state.d.ts +16 -0
  333. package/dist/core/types/workflow-registries.d.ts +7 -0
  334. package/dist/core/types/workflow-registry.d.ts +12 -0
  335. package/dist/core/versioning.js +2 -0
  336. package/dist/core/weft-error.d.ts +1 -1
  337. package/dist/core/weft-error.js +12 -1
  338. package/dist/core/worker-execution-strategy.d.ts +1 -0
  339. package/dist/core/worker-execution-strategy.js +13 -1
  340. package/dist/core/worker-fault-handling.d.ts +10 -0
  341. package/dist/core/worker-fault-handling.js +1 -0
  342. package/dist/core/worker-inbound-message.d.ts +1 -0
  343. package/dist/core/worker-inbound-message.js +1 -0
  344. package/dist/core/worker-protocol-guard.js +4 -0
  345. package/dist/core/worker-protocol.d.ts +7 -0
  346. package/dist/core/worker-protocol.js +2 -1
  347. package/dist/core/worker-turn-watchdog.d.ts +8 -1
  348. package/dist/core/worker-turn-watchdog.js +3 -2
  349. package/dist/diagnostics/format.js +5 -0
  350. package/dist/diagnostics/types.d.ts +24 -0
  351. package/dist/diagnostics/version-check.js +8 -2
  352. package/dist/http.js +2 -2
  353. package/dist/index.d.ts +25 -4
  354. package/dist/index.js +57 -0
  355. package/dist/indexeddb.js +1 -1
  356. package/dist/json-schema.js +3 -3
  357. package/dist/mcp/resources.js +2 -0
  358. package/dist/runtime/portable.d.ts +9 -1
  359. package/dist/server/fault-to-json-rpc.js +4 -1
  360. package/dist/server/handler/auth-context-principal.js +4 -0
  361. package/dist/server/index.d.ts +11 -0
  362. package/dist/server/json-rpc-http.js +2 -0
  363. package/dist/server/json-rpc-websocket.js +6 -4
  364. package/dist/server/operation-catalog/index.d.ts +1 -1
  365. package/dist/server/operation-catalog/pipeline-helpers.js +2 -0
  366. package/dist/server/operation-catalog/types.d.ts +17 -0
  367. package/dist/server/operation-fault.d.ts +5 -0
  368. package/dist/server/operation-fault.js +4 -1
  369. package/dist/server/operations/activate-workflow-revision.d.ts +30 -0
  370. package/dist/server/operations/activate-workflow-revision.js +69 -0
  371. package/dist/server/operations/create-schedule.d.ts +2 -0
  372. package/dist/server/operations/create-schedule.js +10 -6
  373. package/dist/server/operations/fleet-events-subscription.js +1 -1
  374. package/dist/server/operations/fork-workflow.js +1 -1
  375. package/dist/server/operations/get-active-workflow-revision.d.ts +32 -0
  376. package/dist/server/operations/get-active-workflow-revision.js +46 -0
  377. package/dist/server/operations/get-catalog-diagnostics.d.ts +113 -0
  378. package/dist/server/operations/get-catalog-diagnostics.js +65 -0
  379. package/dist/server/operations/get-registry.js +17 -4
  380. package/dist/server/operations/get-task-detail-schema.d.ts +8 -0
  381. package/dist/server/operations/get-task-detail-schema.js +1 -0
  382. package/dist/server/operations/get-task-detail.d.ts +8 -0
  383. package/dist/server/operations/get-task-detail.js +1 -0
  384. package/dist/server/operations/get-task-diagnostics.d.ts +4 -4
  385. package/dist/server/operations/get-workflow-revision.d.ts +25 -0
  386. package/dist/server/operations/get-workflow-revision.js +50 -0
  387. package/dist/server/operations/install-workflow-revision.d.ts +27 -0
  388. package/dist/server/operations/install-workflow-revision.js +46 -0
  389. package/dist/server/operations/list-workflow-revisions.d.ts +20 -0
  390. package/dist/server/operations/list-workflow-revisions.js +40 -0
  391. package/dist/server/operations/preload-workflow-revision.d.ts +28 -0
  392. package/dist/server/operations/preload-workflow-revision.js +60 -0
  393. package/dist/server/operations/schedule-faults.d.ts +1 -0
  394. package/dist/server/operations/schedule-faults.js +32 -4
  395. package/dist/server/operations/schedule-rest-body.d.ts +1 -0
  396. package/dist/server/operations/schedule-rest-body.js +2 -1
  397. package/dist/server/operations/start-or-signal-workflow.js +1 -1
  398. package/dist/server/operations/start-workflow.js +1 -1
  399. package/dist/server/operations/static-registrations.js +42 -0
  400. package/dist/server/operations/storage.js +2 -2
  401. package/dist/server/operations/submit-review-decision.js +1 -1
  402. package/dist/server/operations/update-schedule.d.ts +2 -0
  403. package/dist/server/operations/update-schedule.js +4 -2
  404. package/dist/server/operations/workflow-catalog-operation-helpers.d.ts +59 -0
  405. package/dist/server/operations/workflow-catalog-operation-helpers.js +162 -0
  406. package/dist/server/runtime/task-dispatch-envelope.d.ts +14 -0
  407. package/dist/server/runtime/task-dispatch-envelope.js +32 -0
  408. package/dist/server/runtime/task-dispatch-revision.d.ts +29 -0
  409. package/dist/server/runtime/task-dispatch-revision.js +13 -0
  410. package/dist/server/runtime/task-dispatch.js +12 -37
  411. package/dist/server/runtime/task-ledger-recovery.js +1 -1
  412. package/dist/server/runtime/task-ledger-runtime.d.ts +14 -2
  413. package/dist/server/runtime/task-ledger-runtime.js +5 -3
  414. package/dist/server/runtime/task-polling.js +9 -3
  415. package/dist/server/runtime/task-reconciliation.js +2 -1
  416. package/dist/server/runtime/websocket-upgrade.js +2 -0
  417. package/dist/server/runtime/websocket-worker.js +9 -0
  418. package/dist/server/task-ledger-codec.d.ts +9 -0
  419. package/dist/server/task-ledger-codec.js +4 -1
  420. package/dist/server/task-ledger-transition-helpers.js +1 -0
  421. package/dist/server/task-ledger-types.d.ts +9 -0
  422. package/dist/server/task-ledger.d.ts +1 -1
  423. package/dist/server/task-ledger.js +2 -1
  424. package/dist/server/task-queue-types.d.ts +2 -0
  425. package/dist/storage/bun-sql.js +51 -6
  426. package/dist/storage/catalog-keys.d.ts +64 -0
  427. package/dist/storage/catalog-keys.js +8 -0
  428. package/dist/storage/compressed-storage.js +1 -1
  429. package/dist/storage/derived-operations.js +1 -1
  430. package/dist/storage/index.d.ts +28 -1
  431. package/dist/storage/interface.d.ts +28 -1
  432. package/dist/storage/interface.js +1 -1
  433. package/dist/storage/key-encoding.d.ts +15 -0
  434. package/dist/storage/key-encoding.js +3 -0
  435. package/dist/storage/key-prefixes.d.ts +1 -1
  436. package/dist/storage/key-prefixes.js +16 -0
  437. package/dist/storage/lmdb.d.ts +54 -1
  438. package/dist/storage/lmdb.js +1 -1
  439. package/dist/storage/mailbox-keys.d.ts +80 -0
  440. package/dist/storage/mailbox-keys.js +14 -0
  441. package/dist/storage/memory.js +1 -1
  442. package/dist/storage/neon.js +2 -2
  443. package/dist/storage/node-sqlite-loader.d.ts +1 -1
  444. package/dist/storage/node-sqlite.js +51 -6
  445. package/dist/storage/outbox-keys.d.ts +77 -0
  446. package/dist/storage/outbox-keys.js +14 -0
  447. package/dist/storage/postgres.js +2 -2
  448. package/dist/storage/resolve.js +1 -1
  449. package/dist/storage/scoped-storage.js +1 -1
  450. package/dist/storage/storage-configuration.d.ts +6 -0
  451. package/dist/storage/testing.js +1 -1
  452. package/dist/storage/turso.js +2 -2
  453. package/dist/version.d.ts +1 -1
  454. package/dist/version.js +1 -1
  455. package/dist/web-extension.js +1 -1
  456. package/dist/worker/manifest/registry-contract-builder.d.ts +21 -3
  457. package/dist/worker/manifest/registry-contract-builder.js +40 -31
  458. package/dist/worker/protocol-messages.d.ts +17 -0
  459. package/dist/worker/protocol-schemas.d.ts +32 -0
  460. package/dist/worker/protocol-schemas.js +7 -3
  461. package/dist/worker/protocol-task-result.js +35 -3
  462. package/dist/worker/protocol.js +1 -1
  463. package/dist/worker/registry/types.d.ts +2 -0
  464. package/dist/worker/registry.d.ts +1 -1
  465. package/dist/worker/registry.js +3 -1
  466. package/dist/workers/workflow-runner.d.ts +9 -0
  467. package/dist/workers/workflow-runner.js +9 -2
  468. package/dist/workers/workflow-worker-entry.js +9 -4
  469. package/package.json +2 -2
@@ -0,0 +1,30 @@
1
+ import type { TimerEntry } from '../../types.ts';
2
+ import type { ExecutableRegistration } from '../dynamic-source-execution.ts';
3
+ import type { EngineInternals } from '../internals.ts';
4
+ import type { TimeOperationCallbacks } from '../operations-time.ts';
5
+ /**
6
+ * Resolve `type`'s registration for a delayed-start fire, failing the
7
+ * workflow (via `callbacks.failWorkflow`) and returning `null` on any
8
+ * resolution error instead of throwing. ADR 0002: acquires this workflow's
9
+ * claim standalone + hydrates cleanup tracking BEFORE failing — the
10
+ * happy-path pending→running fold later in `startDelayedWorkflow` would
11
+ * otherwise establish both.
12
+ *
13
+ * Resolved against `revision` — the pending run's own persisted
14
+ * `WorkflowState.revision` (WFT-17), `undefined` for a legacy record —
15
+ * never the catalog's active pointer, so a delayed-start fire honors the
16
+ * exact revision this run was created against, matching
17
+ * `resumeWorkflowFromStorage()`'s use of the same resolver.
18
+ *
19
+ * Returns the FULL `{ entry, revision }` pair, not just `entry` — mirroring
20
+ * `resolveExecutableRegistrationOrRenamedNotFound()`'s shape used by
21
+ * `resume.ts`/`transition.ts`. For a legacy, pre-revision-pinning pending
22
+ * record with exactly one registered `registerSource()` candidate, the
23
+ * resolver can unambiguously resolve that candidate even though the input
24
+ * `revision` was `undefined` — the caller MUST thread this returned
25
+ * `revision` (not the input `revision` or the persisted state's own,
26
+ * still-`undefined` `revision`) through the pending→running transition and
27
+ * into `beginWorkflowExecution`, or the per-instance identity cache ends up
28
+ * stamped with the wrong (missing) revision (WFT-19 review round 7).
29
+ */
30
+ export declare function resolveDelayedStartRegistrationOrFail(internals: EngineInternals, entry: TimerEntry, type: string, revision: string | undefined, callbacks: Pick<TimeOperationCallbacks, 'failWorkflow' | 'resolveExecutableRegistrationForRevision'>): Promise<ExecutableRegistration | null>;
@@ -0,0 +1,11 @@
1
+ import { ensureDelayedStartClaimAndCleanupBeforeFailure } from "./standalone-claim-acquire.js";
2
+ export async function resolveDelayedStartRegistrationOrFail(internals, entry, type, revision, callbacks) {
3
+ try {
4
+ return await callbacks.resolveExecutableRegistrationForRevision(type, revision);
5
+ } catch (error) {
6
+ await ensureDelayedStartClaimAndCleanupBeforeFailure(internals, entry.workflowId);
7
+ const asError = error instanceof Error ? error : Error(String(error));
8
+ await callbacks.failWorkflow(entry.workflowId, asError);
9
+ return null;
10
+ }
11
+ }
@@ -5,5 +5,37 @@ import type { EngineInternals } from '../internals.ts';
5
5
  import { type LifecycleCallbacks } from './shared.ts';
6
6
  export declare function createForkLineage(_internals: EngineInternals, sourceWorkflowId: string, checkpoint: Checkpoint, _callbacks: LifecycleCallbacks): ForkLineage;
7
7
  export declare function buildForkSearchAttributes(_internals: EngineInternals, checkpoint: Checkpoint, lineage: ForkLineage, _callbacks: LifecycleCallbacks): Record<string, SearchAttributeValue>;
8
- export declare function createForkedWorkflowState(_internals: EngineInternals, workflowId: string, sourceState: WorkflowState, versionTuple: WorkflowVersionTuple, lineage: ForkLineage, forkedAt: number, _callbacks: LifecycleCallbacks): WorkflowState;
8
+ export declare function createForkedWorkflowState(_internals: EngineInternals, workflowId: string, sourceState: WorkflowState, versionTuple: WorkflowVersionTuple, lineage: ForkLineage, forkedAt: number, _callbacks: LifecycleCallbacks,
9
+ /**
10
+ * `fork()`'s own resolver-returned revision — used to fill in the fork's
11
+ * persisted `revision` ONLY when `sourceState.revision` is itself
12
+ * `undefined` (WFT-19 review round 6, Codex, P1). Never overrides an
13
+ * already-defined `sourceState.revision`: `resolveExecutableRegistrationForRevision()`
14
+ * ALWAYS returns `revision: undefined` for an eager registration (eager
15
+ * has no ambiguity to resolve against — see `canResolveRevisionLocally`'s
16
+ * doc), even though the eager source run's own `sourceState.revision` is
17
+ * a real, independently-meaningful value (`resolveCachedStartRevision()`'s
18
+ * `registeredCatalogRevisions` fallback stamps it at ordinary start time,
19
+ * for every registration kind). Blindly preferring `resolvedRevision`
20
+ * here would have dropped that real value for every eager-type fork —
21
+ * caught by `tests/replay-fixtures/fork-from-checkpoint.json`'s golden
22
+ * byte comparison. For a legacy (pre-revision-pinning) source run on a
23
+ * dynamic-source type with exactly one registered candidate,
24
+ * `sourceState.revision` genuinely IS `undefined` even though the
25
+ * resolver resolved — and the fork launches against — that sole
26
+ * candidate's code; `sourceState.revision ?? resolvedRevision` falls
27
+ * through to the resolver's answer only in that case. Stamping the fork's
28
+ * persisted `revision` with the raw `undefined` legacy pin (as this
29
+ * function did before this fix existed) left the fork durably unpinned:
30
+ * it would run correctly until the next restart, but a fresh-process
31
+ * `recoverAll()` after a second candidate is later registered would
32
+ * classify the fork `legacy-ambiguous` and refuse to resume it, even
33
+ * though the fork's own resolver already knew exactly which revision it
34
+ * belonged to at creation time. Mirrors the identical fix already applied
35
+ * to the process-local identity cache in `checkpoint-launch.ts`'s
36
+ * `launchWorkflowFromCheckpoint()` (WFT-19 review round 5) — that fix
37
+ * closed the in-memory gap; this one closes the matching durable-state
38
+ * gap the same bug left behind, for the one case it actually applies to.
39
+ */
40
+ resolvedRevision: string | undefined): WorkflowState;
9
41
  export declare function buildForkBatchOperations(_internals: EngineInternals, workflowId: string, state: WorkflowState, checkpoint: Checkpoint, serializedCheckpoint: Uint8Array, workflowStartHeaders: Map<string, string> | undefined, _callbacks: LifecycleCallbacks): BatchOperation[];
@@ -16,7 +16,8 @@ export function buildForkSearchAttributes(_internals, checkpoint, lineage, _call
16
16
  [FORK_LINEAGE_ATTRIBUTE]: lineage.workflowId
17
17
  };
18
18
  }
19
- export function createForkedWorkflowState(_internals, workflowId, sourceState, versionTuple, lineage, forkedAt, _callbacks) {
19
+ export function createForkedWorkflowState(_internals, workflowId, sourceState, versionTuple, lineage, forkedAt, _callbacks, resolvedRevision) {
20
+ const forkRevision = sourceState.revision ?? resolvedRevision;
20
21
  return {
21
22
  id: workflowId,
22
23
  type: sourceState.type,
@@ -24,6 +25,7 @@ export function createForkedWorkflowState(_internals, workflowId, sourceState, v
24
25
  input: sourceState.input,
25
26
  workflowExecutionToken: crypto.randomUUID(),
26
27
  versionTuple,
28
+ ...forkRevision !== void 0 && { revision: forkRevision },
27
29
  executionStateOwnerId: workflowId,
28
30
  createdAt: forkedAt,
29
31
  startedAt: forkedAt,
@@ -0,0 +1,75 @@
1
+ /**
2
+ * `recoverAll()`'s per-`(type, revision)` preload barrier (WFT-17/WFT-18),
3
+ * replacing the per-`type`-only barrier `recovery-dynamic-sources.ts` used
4
+ * to own. Split out of `transition.ts`, which has no headroom under the
5
+ * repository's 500-line implementation-file ceiling for this logic inline
6
+ * — the same reason `recovery-dynamic-sources.ts` was split out for
7
+ * WFT-15/16.
8
+ *
9
+ * Recovery scans non-terminal workflow states, groups them by their exact
10
+ * `(type, revision)` pin (a legacy record with no persisted `revision`
11
+ * groups under `undefined` for its type), and preloads/classifies every
12
+ * group BEFORE any group's runs advance — ready, or unavailable with the
13
+ * error every run in that group fails with. Grouping and classification use
14
+ * nested `Map<type, Map<revision, …>>` structures rather than a
15
+ * delimiter-joined composite key, so an arbitrary workflow `type` or
16
+ * `revision` string can never collide with a delimiter.
17
+ *
18
+ * @module core/engine/lifecycle/recovery-revision-groups
19
+ */
20
+ import { DynamicWorkflowSourceUnavailableError } from '../dynamic-source-errors.ts';
21
+ import type { EngineInternals } from '../internals.ts';
22
+ import { WorkflowRevisionUnavailableError } from '../revision-errors.ts';
23
+ import type { LifecycleCallbacks } from './shared.ts';
24
+ /** One preflight-recoverable entry's identity, as `transition.ts`'s preflight scan produces it. */
25
+ export type RecoverableRevisionEntry = {
26
+ readonly workflowId: string;
27
+ readonly type: string;
28
+ readonly revision: string | undefined;
29
+ };
30
+ /** One `(type, revision)` group: every non-terminal run pinned to that exact revision. */
31
+ export type RecoveryRevisionGroup = {
32
+ readonly type: string;
33
+ readonly revision: string | undefined;
34
+ readonly workflowIds: readonly string[];
35
+ };
36
+ /** `type -> revision -> group`. A legacy entry (no persisted `revision`) groups under the `undefined` key. */
37
+ export type RecoveryRevisionGroups = ReadonlyMap<string, ReadonlyMap<string | undefined, RecoveryRevisionGroup>>;
38
+ /**
39
+ * Group preflight-recoverable entries by their exact `(type, revision)` pin.
40
+ * Every non-terminal run pinned to the same revision of the same type lands
41
+ * in one group, regardless of scan order.
42
+ */
43
+ export declare function buildRecoveryRevisionGroups(entries: readonly RecoverableRevisionEntry[]): RecoveryRevisionGroups;
44
+ /** Outcome of classifying one `(type, revision)` group. */
45
+ export type RevisionGroupClassification = {
46
+ readonly status: 'ready';
47
+ } | {
48
+ readonly status: 'unavailable';
49
+ readonly error: WorkflowRevisionUnavailableError | DynamicWorkflowSourceUnavailableError;
50
+ };
51
+ /** `type -> revision -> classification`, mirroring {@link RecoveryRevisionGroups}'s shape. */
52
+ export type RevisionGroupClassifications = ReadonlyMap<string, ReadonlyMap<string | undefined, RevisionGroupClassification>>;
53
+ /**
54
+ * Resolve every `(type, revision)` group to `'ready'` or `'unavailable'`,
55
+ * concurrently, one `resolveExecutableRegistrationForRevision()` call per
56
+ * group — even when many non-terminal runs share the same pin. An eager
57
+ * type's groups are omitted from the result entirely (eager is always
58
+ * ready and needs no preload call); only dynamic-source groups are
59
+ * classified. A disposal mid-preload aborts the whole barrier by
60
+ * rethrowing, matching `recoverEntryOrIsolateFailure`'s own un-isolated
61
+ * treatment of {@link EngineDisposedError}.
62
+ */
63
+ export declare function classifyRevisionGroups(internals: EngineInternals, callbacks: LifecycleCallbacks, groups: RecoveryRevisionGroups): Promise<RevisionGroupClassifications>;
64
+ /**
65
+ * Wrap `callbacks` so `recoverAll()`'s own per-entry `resume()` calls below
66
+ * see a batch's cached `classifyRevisionGroups()` failure for the entry's
67
+ * `(type, revision)` group, WITHOUT touching any state shared with other
68
+ * callers. `classifications` is a plain, closure-local `Map` structure —
69
+ * nothing outside `recoverAll()` ever sees it, so a concurrent, unrelated
70
+ * `engine.start()`, `engine.resume()`, or a second concurrent `recoverAll()`
71
+ * batch for the SAME `(type, revision)` keeps using the real, un-wrapped
72
+ * `callbacks.resolveExecutableRegistrationForRevision` and can never observe
73
+ * (or race the reset of) this batch's classification.
74
+ */
75
+ export declare function createRecoveryScopedRevisionCallbacks(callbacks: LifecycleCallbacks, classifications: RevisionGroupClassifications): LifecycleCallbacks;
@@ -0,0 +1,64 @@
1
+ import { DynamicWorkflowSourceUnavailableError } from "../dynamic-source-errors.js";
2
+ import { EngineDisposedError } from "../errors.js";
3
+ import { WorkflowRevisionUnavailableError } from "../revision-errors.js";
4
+ export function buildRecoveryRevisionGroups(entries) {
5
+ const groups = new Map;
6
+ for (const entry of entries) {
7
+ let byRevision = groups.get(entry.type);
8
+ if (byRevision === void 0) {
9
+ byRevision = new Map;
10
+ groups.set(entry.type, byRevision);
11
+ }
12
+ const existing = byRevision.get(entry.revision);
13
+ if (existing === void 0)
14
+ byRevision.set(entry.revision, {
15
+ type: entry.type,
16
+ revision: entry.revision,
17
+ workflowIds: [entry.workflowId]
18
+ });
19
+ else
20
+ existing.workflowIds.push(entry.workflowId);
21
+ }
22
+ return groups;
23
+ }
24
+ export async function classifyRevisionGroups(internals, callbacks, groups) {
25
+ const dynamicGroups = [];
26
+ for (const [type, byRevision] of groups) {
27
+ if (internals.registrations.has(type))
28
+ continue;
29
+ dynamicGroups.push(...byRevision.values());
30
+ }
31
+ const results = new Map;
32
+ if (dynamicGroups.length === 0)
33
+ return results;
34
+ const settled = await Promise.allSettled(dynamicGroups.map((group) => callbacks.resolveExecutableRegistrationForRevision(group.type, group.revision)));
35
+ for (const [index, outcome] of settled.entries()) {
36
+ const group = dynamicGroups[index];
37
+ let byRevision = results.get(group.type);
38
+ if (byRevision === void 0) {
39
+ byRevision = new Map;
40
+ results.set(group.type, byRevision);
41
+ }
42
+ if (outcome.status === "fulfilled") {
43
+ byRevision.set(group.revision, { status: "ready" });
44
+ continue;
45
+ }
46
+ const reason = outcome.reason;
47
+ if (reason instanceof EngineDisposedError)
48
+ throw reason;
49
+ const error = reason instanceof WorkflowRevisionUnavailableError || reason instanceof DynamicWorkflowSourceUnavailableError ? reason : new DynamicWorkflowSourceUnavailableError(group.type, group.revision, "load-failed", reason);
50
+ byRevision.set(group.revision, { status: "unavailable", error });
51
+ }
52
+ return results;
53
+ }
54
+ export function createRecoveryScopedRevisionCallbacks(callbacks, classifications) {
55
+ return {
56
+ ...callbacks,
57
+ resolveExecutableRegistrationForRevision: (type, revision) => {
58
+ const classification = classifications.get(type)?.get(revision);
59
+ if (classification?.status === "unavailable")
60
+ return Promise.reject(classification.error);
61
+ return callbacks.resolveExecutableRegistrationForRevision(type, revision);
62
+ }
63
+ };
64
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * `resumeWorkflowFromStorage()`'s generation-identity re-check (WFT-19
3
+ * review round 7, chatgpt-codex-connector + stevekinney) — split out of
4
+ * `resume.ts`, which has no headroom under the repository's 500-line
5
+ * implementation-file ceiling for this doc-heavy addition.
6
+ *
7
+ * @module core/engine/lifecycle/resume-generation-guard
8
+ */
9
+ import type { WorkflowState } from '../../types.ts';
10
+ /**
11
+ * The generation a resume's `registration`/`resumeCheckpoint`/`resolvedRevision`
12
+ * were all resolved against — captured from the SAME `WorkflowState` decoded
13
+ * at the very top of `resumeWorkflowFromStorage()`, before
14
+ * `acquireStandaloneClaimBeforeResume`, the checkpoint load, and registration
15
+ * resolution all ran.
16
+ *
17
+ * `performSerializedResume()` re-reads workflow state fresh inside its
18
+ * serialized section but (before this guard existed) only re-checked
19
+ * `status` — never identity. An `onTerminalConflict: 'start-new'`
20
+ * replacement landing on this SAME `workflowId` between the top-of-function
21
+ * read and the serialized section's fresh read (e.g. a concurrent
22
+ * cancel/timeout terminalizes this run, then a fresh `start()` call replaces
23
+ * it) purges the old record and writes a brand-new one — new
24
+ * `type`/`revision` possibly, and ALWAYS a fresh `workflowExecutionToken`
25
+ * (`crypto.randomUUID()`, minted by every `start()` — see
26
+ * `start-state.ts`'s `buildInitialIdentitySlice`). Without
27
+ * {@link assertSameGeneration}, the stale `registration`/
28
+ * `resumeCheckpoint` a resume closure already built would replay against the
29
+ * replacement's fresh state: `commitSerializedResumeState` populates
30
+ * `internals.checkpoints` from the OLD checkpoint, and
31
+ * `relaunchInlineWorkflowAfterResume` drives the OLD handler — silently
32
+ * corrupting the replacement's run.
33
+ *
34
+ * A DIFFERENT engine's replacement is additionally caught earlier, by
35
+ * `acquireStandaloneClaimBeforeResume`'s durable `wakeOwnershipCheck`
36
+ * (workflow-lease mode only) — but that check compares only holder
37
+ * identity/epoch, never workflow identity, so a SAME-engine replacement
38
+ * (whose fold-acquire updates this engine's own already-held claim in
39
+ * place, leaving the epoch check trivially satisfied) is not caught there.
40
+ * This guard closes that gap for every ownership mode, not just
41
+ * workflow-lease.
42
+ */
43
+ export type ResumeGeneration = {
44
+ type: string;
45
+ revision: string | undefined;
46
+ workflowExecutionToken: string | undefined;
47
+ };
48
+ /** Captures {@link ResumeGeneration} off the `WorkflowState` a resume decoded at its top, before any `await`. */
49
+ export declare function deriveResumeGeneration(state: WorkflowState): ResumeGeneration;
50
+ /**
51
+ * Throws when `latestState` — freshly re-read inside `performSerializedResume()`'s
52
+ * serialized section — no longer belongs to the same generation `expected`
53
+ * names. See {@link ResumeGeneration}'s doc for the exact race this
54
+ * closes. All three fields are compared — `workflowExecutionToken` alone
55
+ * would miss a legacy record that carries `undefined` on both sides of the
56
+ * race.
57
+ */
58
+ export declare function assertSameGeneration(workflowId: string, latestState: WorkflowState, expected: ResumeGeneration): void;
@@ -0,0 +1,11 @@
1
+ export function deriveResumeGeneration(state) {
2
+ return {
3
+ type: state.type,
4
+ revision: state.revision,
5
+ workflowExecutionToken: state.workflowExecutionToken
6
+ };
7
+ }
8
+ export function assertSameGeneration(workflowId, latestState, expected) {
9
+ if (latestState.workflowExecutionToken !== expected.workflowExecutionToken || latestState.type !== expected.type || latestState.revision !== expected.revision)
10
+ throw Error(`Cannot resume workflow "${workflowId}": its persisted state changed generation (a replacement run landed at this same id) between resume's registration lookup ` + "and its serialized commit \u2014 retry against the new generation instead of replaying " + "stale state.");
11
+ }
@@ -8,6 +8,7 @@ import { buildTimerBatchOperations } from "../../scheduler.js";
8
8
  import { createCancelHandlerRegistration, resetCancelHandlers } from "../cancel-handlers.js";
9
9
  import { rememberCommittedCheckpointBytes } from "../checkpoint-commit-snapshots.js";
10
10
  import { rehydrateChildCancellationHandlers } from "../child-workflow-cancellation.js";
11
+ import { resolveExecutableRegistrationOrRenamedNotFound } from "../dynamic-source-execution.js";
11
12
  import { commitFencedEngineWrite } from "../fenced-write.js";
12
13
  import { getWorkflowExecutionStartedAt } from "../handles.js";
13
14
  import { loadWorkflowState } from "../storage-io.js";
@@ -19,6 +20,7 @@ import {
19
20
  reprovideRecoveredServices,
20
21
  workflowServicesResolverInfoFromState
21
22
  } from "./recovered-services.js";
23
+ import { assertSameGeneration, deriveResumeGeneration } from "./resume-generation-guard.js";
22
24
  import {
23
25
  enforceHistoryPolicyBeforeReplay,
24
26
  loadTerminalCleanupTrackedState,
@@ -79,7 +81,11 @@ function commitSerializedResumeState(internals, args) {
79
81
  internals.parkedInlineWorkflows.delete(workflowId);
80
82
  }
81
83
  async function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
82
- const { workflowId, resumeCheckpoint, registration, callbacks } = args, accumulatedResults = new Map(resumeCheckpoint.accumulatedResults), workflowAbort = new AbortController;
84
+ const { workflowId, resumeCheckpoint, registration, resolvedRevision, callbacks } = args, accumulatedResults = new Map(resumeCheckpoint.accumulatedResults), workflowAbort = new AbortController;
85
+ internals.workflowTypeByWorkflowId.set(workflowId, {
86
+ type: latestState.type,
87
+ revision: resolvedRevision
88
+ });
83
89
  resetCancelHandlers(internals, workflowId);
84
90
  await rehydrateChildCancellationHandlers(internals, workflowId, callbacks);
85
91
  const context = new Context({
@@ -115,7 +121,11 @@ async function relaunchInlineWorkflowAfterResume(internals, latestState, args) {
115
121
  inlineStrategy.continueWorkflow(workflowId, void 0);
116
122
  }
117
123
  async function relaunchWorkerWorkflowAfterResume(internals, latestState, args) {
118
- const { workflowId, resumeCheckpoint, workflowStartHeaders, callbacks } = args;
124
+ const { workflowId, resumeCheckpoint, workflowStartHeaders, resolvedRevision, callbacks } = args;
125
+ internals.workflowTypeByWorkflowId.set(workflowId, {
126
+ type: latestState.type,
127
+ revision: resolvedRevision
128
+ });
119
129
  resetCancelHandlers(internals, workflowId);
120
130
  await rehydrateChildCancellationHandlers(internals, workflowId, callbacks);
121
131
  const serialized = serializeCheckpoint(resumeCheckpoint);
@@ -146,6 +156,7 @@ async function performSerializedResume(internals, args) {
146
156
  throw Error(`Workflow "${workflowId}" not found in storage`);
147
157
  if (latestState.status !== "running" && latestState.status !== "suspended")
148
158
  throw Error(`Cannot resume workflow "${workflowId}": status is "${latestState.status}", expected "running" or "suspended"`);
159
+ assertSameGeneration(workflowId, latestState, args.expectedGeneration);
149
160
  await reactivateSuspendedWorkflowState(internals, latestState);
150
161
  commitSerializedResumeState(internals, args);
151
162
  if (internals.inlineStrategy) {
@@ -179,18 +190,14 @@ export async function resumeWorkflowFromStorage(internals, workflowId, dispatchR
179
190
  if (state.status !== "running" && state.status !== "suspended")
180
191
  throw Error(`Cannot resume workflow "${workflowId}": status is "${state.status}", expected "running" or "suspended"`);
181
192
  await acquireStandaloneClaimBeforeResume(internals, workflowId);
193
+ await loadTerminalCleanupTrackedState(internals, workflowId, callbacks);
182
194
  const checkpointBytes = await internals.storage.get(KEYS.checkpoint(workflowId));
183
195
  if (!checkpointBytes)
184
196
  throw Error(`Checkpoint not found for workflow "${workflowId}"`);
185
- const checkpoint = deserializeCheckpoint(checkpointBytes), registration = internals.registrations.get(state.type);
186
- if (!registration)
187
- throw Error(`No workflow registered with name "${state.type}" (needed to resume "${workflowId}")`);
188
- const preparedResumeState = await prepareResumeState(internals, workflowId, state, checkpoint, checkpointBytes, registration, callbacks), resumeCheckpoint = preparedResumeState.checkpoint, registeredVersionTuple = preparedResumeState.versionTuple, restoredHead = await new EventLog(internals.storage, workflowId).loadHead();
197
+ const checkpoint = deserializeCheckpoint(checkpointBytes), { entry: registration, revision: resolvedRevision } = await resolveExecutableRegistrationOrRenamedNotFound((type) => callbacks.resolveExecutableRegistrationForRevision(type, state.revision), state.type, () => Error(`No workflow registered with name "${state.type}" (needed to resume "${workflowId}")`)), preparedResumeState = await prepareResumeState(internals, workflowId, state, checkpoint, checkpointBytes, registration, callbacks), resumeCheckpoint = preparedResumeState.checkpoint, registeredVersionTuple = preparedResumeState.versionTuple, restoredHead = await new EventLog(internals.storage, workflowId).loadHead();
189
198
  if (await enforceHistoryPolicyBeforeReplay(internals, workflowId, restoredHead, callbacks))
190
199
  return callbacks.getHandle(workflowId);
191
- const workflowStartHeaders = await loadWorkflowStartHeaders(internals, workflowId, callbacks);
192
- await loadTerminalCleanupTrackedState(internals, workflowId, callbacks);
193
- const { handle, shouldStop } = await prepareRecoveredWorkflowOrFail(internals, state, callbacks, onRecoveredWorkflow);
200
+ const workflowStartHeaders = await loadWorkflowStartHeaders(internals, workflowId, callbacks), { handle, shouldStop } = await prepareRecoveredWorkflowOrFail(internals, state, callbacks, onRecoveredWorkflow);
194
201
  if (shouldStop)
195
202
  return handle;
196
203
  await callbacks.runSerializedWorkflowStateWrite(workflowId, () => performSerializedResume(internals, {
@@ -201,6 +208,8 @@ export async function resumeWorkflowFromStorage(internals, workflowId, dispatchR
201
208
  restoredHead,
202
209
  workflowStartHeaders,
203
210
  registration,
211
+ resolvedRevision,
212
+ expectedGeneration: deriveResumeGeneration(state),
204
213
  callbacks
205
214
  }));
206
215
  if (dispatchResumedEvent)
@@ -1,5 +1,6 @@
1
1
  import type { ComposedWorkflowInterceptor } from '../../interceptor.ts';
2
2
  import type { WorkflowServicesResolverLaunchOptions, WorkflowServicesResolverScheduleInfo } from '../../types.ts';
3
+ import type { ExecutableRegistration } from '../dynamic-source-execution.ts';
3
4
  import type { QueuedInlineWorkflowExecutionStart } from '../engine-internal-types.ts';
4
5
  import { type WorkflowHandle } from '../handles.ts';
5
6
  import type { EngineInternals } from '../internals.ts';
@@ -125,6 +126,48 @@ export type LifecycleCallbacks = {
125
126
  * {@link RecoverAllOptions.versionMismatchPolicy}.
126
127
  */
127
128
  failWorkflowForVersionMismatch: (workflowId: string, error: Error) => Promise<void>;
129
+ /**
130
+ * Turn a workflow `type` into an executable registration, awaiting
131
+ * dynamic-source resolution when `type` is not eagerly registered
132
+ * (WFT-15/16). See `dynamic-source-execution.ts`'s own doc for the full
133
+ * contract.
134
+ *
135
+ * `onRevisionChosen`, when given, fires synchronously the moment a lazy
136
+ * `type`'s target revision is picked — BEFORE the (potentially slow)
137
+ * loader is awaited — so a caller like `startWorkflow` can reserve an
138
+ * `inFlightStarts` slot for that exact revision immediately, closing the
139
+ * window where a concurrent `removeWorkflowRevision()` could observe zero
140
+ * references against a revision this call's own source load is about to
141
+ * durably (re)install. Never fires for an eager type (no revision to
142
+ * choose) or when resolution fails before a revision is picked (the
143
+ * ambiguous-revision case).
144
+ */
145
+ resolveExecutableRegistration: (type: string, onRevisionChosen?: (revision: string) => void) => Promise<ExecutableRegistration>;
146
+ /**
147
+ * Force a recovered workflow to a terminal `failed` state because its
148
+ * dynamic workflow source could not be resolved during the recovery
149
+ * preload barrier — only this run fails; `recoverAll()` continues
150
+ * recovering sibling types.
151
+ */
152
+ failWorkflowForUnavailableDynamicSource: (workflowId: string, error: Error) => Promise<void>;
153
+ /**
154
+ * Resolve workflow `type` against its EXACT pinned revision (WFT-17's
155
+ * `WorkflowState.revision`, `undefined` for a legacy pre-pinning record)
156
+ * instead of whichever revision the catalog currently considers active.
157
+ * Used by every resume path (`resumeWorkflowFromStorage`) so a pinned run
158
+ * never falls back to the active pointer. See
159
+ * `dynamic-source-execution.ts`'s `resolveExecutableRegistrationForRevision()`
160
+ * for the full classification contract.
161
+ */
162
+ resolveExecutableRegistrationForRevision: (type: string, revision: string | undefined) => Promise<ExecutableRegistration>;
163
+ /**
164
+ * Force a recovered workflow to a terminal `failed` state because its
165
+ * pinned revision could not be resolved during the recovery preload
166
+ * barrier (WFT-18) — a {@link import('../revision-errors.ts').WorkflowRevisionUnavailableError}.
167
+ * Only this run fails; `recoverAll()` continues recovering sibling
168
+ * `(type, revision)` groups, including other revisions of the same type.
169
+ */
170
+ failWorkflowForRevisionUnavailable: (workflowId: string, error: Error) => Promise<void>;
128
171
  };
129
172
  /**
130
173
  * Pre-replay history circuit breaker. Called at every restore-from-checkpoint
@@ -31,3 +31,15 @@
31
31
  */
32
32
  import type { EngineInternals } from '../internals.ts';
33
33
  export declare function acquireStandaloneClaimBeforeResume(internals: EngineInternals, workflowId: string): Promise<void>;
34
+ /**
35
+ * Standalone-acquire `workflowId`'s claim (see {@link acquireStandaloneClaimBeforeResume},
36
+ * a no-op once already held) and hydrate its terminal-cleanup tracking from
37
+ * the durable marker — the two preconditions a `'self'`-fenced `failWorkflow()`
38
+ * write needs. Used by `operations-time.ts`'s `startDelayedWorkflow` on every
39
+ * failure exit (dynamic-source resolve, invalid execution-timeout) BEFORE
40
+ * failing: a delayed-start's pending→running write is the only other place
41
+ * this claim would otherwise get acquired (folded atomically, per ADR 0002),
42
+ * so a failure committed ahead of that write needs this standalone path
43
+ * instead, exactly like a recovered `running`/`suspended` workflow does.
44
+ */
45
+ export declare function ensureDelayedStartClaimAndCleanupBeforeFailure(internals: EngineInternals, workflowId: string): Promise<void>;
@@ -1,3 +1,4 @@
1
+ import { KEYS, storageHas } from "../../../storage/interface.js";
1
2
  import { WorkflowClaimUnavailableError } from "../lease-errors.js";
2
3
  import { wakeOwnershipCheck } from "../wake-ownership-check.js";
3
4
  export async function acquireStandaloneClaimBeforeResume(internals, workflowId) {
@@ -23,3 +24,8 @@ export async function acquireStandaloneClaimBeforeResume(internals, workflowId)
23
24
  if (result.status === "lost-race")
24
25
  throw new WorkflowClaimUnavailableError(workflowId, result.heldBy);
25
26
  }
27
+ export async function ensureDelayedStartClaimAndCleanupBeforeFailure(internals, workflowId) {
28
+ await acquireStandaloneClaimBeforeResume(internals, workflowId);
29
+ if (await storageHas(internals.storage, KEYS.terminalCleanupNeeded(workflowId)))
30
+ internals.workflowsNeedingTerminalCleanup.add(workflowId);
31
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Internal sentinel: the idempotent create batch lost its compare-and-swap to a
3
+ * concurrent caller holding the same idempotency key. Never surfaced to users —
4
+ * `start` / `startOrSignal` catch it and resolve to the winning run's handle.
5
+ *
6
+ * Lives in its own module so both `start-commit.ts` and the attribution helper it
7
+ * delegates to (`start-precondition-attribution.ts`) can raise it without an import
8
+ * cycle between them.
9
+ */
10
+ export declare class StartIdempotencyRaceLostError extends Error {
11
+ constructor();
12
+ }
@@ -0,0 +1,6 @@
1
+ export class StartIdempotencyRaceLostError extends Error {
2
+ constructor() {
3
+ super("start idempotency compare-and-swap lost to a concurrent caller");
4
+ this.name = "StartIdempotencyRaceLostError";
5
+ }
6
+ }
@@ -1,4 +1,4 @@
1
- import type { BatchOperation, ConditionalBatchCondition } from '../../../storage/interface.ts';
1
+ import { type BatchOperation, type ConditionalBatchCondition } from '../../../storage/interface.ts';
2
2
  import type { Checkpoint, StartOptions, TimerEntry, WorkflowState } from '../../types.ts';
3
3
  import type { EngineInternals } from '../internals.ts';
4
4
  import type { WorkflowConcurrencyStartOperations } from '../workflow-concurrency.ts';
@@ -17,13 +17,19 @@ export type BuildIdempotentStartOperations = (workflowId: string) => {
17
17
  conditions: ConditionalBatchCondition[];
18
18
  };
19
19
  /**
20
- * Internal sentinel: the idempotent create batch lost its compare-and-swap to a
21
- * concurrent caller holding the same idempotency key. Never surfaced to users
22
- * `start` / `startOrSignal` catch it and resolve to the winning run's handle.
20
+ * The `conditionalBatch` precondition half of {@link buildCatalogEntryStartPrecondition}
21
+ * a bare `type`/`revision` pair rather than a full `WorkflowState`, so it
22
+ * is also reusable by a checkpoint-backed failed-run retry's reactivation
23
+ * commit (`bulk-operations-retry.ts`, WFT-17/18 Codex review on PR #958),
24
+ * which has no `WorkflowState & { revision: string }` narrowing of its own
25
+ * and — unlike a fresh start — carries no `inFlightStartsByRevision`
26
+ * reservation to close the SAME-process half of this race, so it needs this
27
+ * fence unconditionally rather than only under `ownershipMode !== 'none'`.
28
+ * Exported (rather than kept local to this module) specifically for that
29
+ * reuse; returns the bare {@link ConditionalBatchCondition} so callers never
30
+ * need this module's own non-exported {@link TaggedStartCondition} shape.
23
31
  */
24
- export declare class StartIdempotencyRaceLostError extends Error {
25
- constructor();
26
- }
32
+ export declare function buildCatalogEntryRevisionCondition(internals: EngineInternals, type: string, revision: string): Promise<ConditionalBatchCondition>;
27
33
  /** Everything {@link buildAndCommitStartBatch} needs to assemble the start batch. */
28
34
  export type StartBatchContext = {
29
35
  internals: EngineInternals;
@@ -44,6 +50,15 @@ export type StartBatchContext = {
44
50
  * {@link buildStartBatchOperations}). Undefined for an ordinary start.
45
51
  */
46
52
  purgeDeleteOperations: BatchOperation[] | undefined;
53
+ /**
54
+ * Compare-and-swap precondition making the caller-supplied-id duplicate check
55
+ * atomic with this commit (WFT-152). Built by `resolveTerminalConflictForRestart`
56
+ * from the exact bytes its duplicate-id read observed, and carried here as the
57
+ * `duplicateIdCondition` of the `StartDuplicateIdDecision` it returns. Undefined
58
+ * for a generated id, which cannot collide and so keeps the unconditioned hot
59
+ * path.
60
+ */
61
+ duplicateIdCondition: ConditionalBatchCondition | undefined;
47
62
  };
48
63
  /**
49
64
  * Assemble the start batch — folding in the id-dependent idempotency mapping and