@lostgradient/weft 0.24.0 → 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 (243) hide show
  1. package/README.md +2 -2
  2. package/dist/cli/conformance.js +5 -2
  3. package/dist/cli/generated/operation-catalog.snapshot.json +95 -1
  4. package/dist/cli/generated/operation-client.generated.d.ts +28 -2
  5. package/dist/cli/generated/operation-client.generated.js +2 -0
  6. package/dist/cli/parse-schedule-arguments.js +15 -3
  7. package/dist/cli/schedule.js +2 -1
  8. package/dist/cli/types.d.ts +2 -1
  9. package/dist/client/http-client-requests.js +6 -9
  10. package/dist/client/start-body.js +1 -0
  11. package/dist/core/catalog/index.d.ts +2 -2
  12. package/dist/core/catalog/index.js +9 -2
  13. package/dist/core/catalog/reference-counts.d.ts +29 -14
  14. package/dist/core/catalog/removal.d.ts +63 -10
  15. package/dist/core/catalog/removal.js +18 -2
  16. package/dist/core/catalog/storage-io.d.ts +23 -0
  17. package/dist/core/catalog/storage-io.js +1 -1
  18. package/dist/core/engine/activity-resolution.js +17 -17
  19. package/dist/core/engine/bulk-operations-purge.js +14 -20
  20. package/dist/core/engine/bulk-operations-retry.d.ts +9 -0
  21. package/dist/core/engine/bulk-operations-retry.js +177 -0
  22. package/dist/core/engine/bulk-operations-shared.d.ts +18 -0
  23. package/dist/core/engine/bulk-operations-shared.js +14 -0
  24. package/dist/core/engine/bulk-operations.js +8 -167
  25. package/dist/core/engine/callback-creators-bundles.js +4 -2
  26. package/dist/core/engine/callback-creators-core.js +9 -1
  27. package/dist/core/engine/callback-creators-schedule.js +2 -2
  28. package/dist/core/engine/catalog-readiness.js +2 -0
  29. package/dist/core/engine/catalog-removal.d.ts +107 -3
  30. package/dist/core/engine/catalog-removal.js +66 -13
  31. package/dist/core/engine/catalog-tombstone-recovery.d.ts +56 -0
  32. package/dist/core/engine/catalog-tombstone-recovery.js +39 -0
  33. package/dist/core/engine/constraints.js +5 -1
  34. package/dist/core/engine/construction.d.ts +1 -1
  35. package/dist/core/engine/decode-revision.d.ts +32 -0
  36. package/dist/core/engine/decode-revision.js +9 -0
  37. package/dist/core/engine/disposal.d.ts +6 -2
  38. package/dist/core/engine/disposal.js +24 -10
  39. package/dist/core/engine/dynamic-source-errors.d.ts +81 -0
  40. package/dist/core/engine/dynamic-source-errors.js +25 -0
  41. package/dist/core/engine/dynamic-source-execution.d.ts +173 -0
  42. package/dist/core/engine/dynamic-source-execution.js +108 -0
  43. package/dist/core/engine/engine-internal-types.d.ts +16 -0
  44. package/dist/core/engine/engine-workflows-namespace.d.ts +10 -0
  45. package/dist/core/engine/engine-workflows-namespace.js +3 -1
  46. package/dist/core/engine/index.d.ts +18 -10
  47. package/dist/core/engine/index.js +21 -10
  48. package/dist/core/engine/inline-launch-queue.js +1 -1
  49. package/dist/core/engine/internals.d.ts +26 -30
  50. package/dist/core/engine/lifecycle/checkpoint-launch.d.ts +29 -0
  51. package/dist/core/engine/lifecycle/checkpoint-launch.js +75 -0
  52. package/dist/core/engine/lifecycle/delayed-start-registration.d.ts +30 -0
  53. package/dist/core/engine/lifecycle/delayed-start-registration.js +11 -0
  54. package/dist/core/engine/lifecycle/fork-helpers.d.ts +33 -1
  55. package/dist/core/engine/lifecycle/fork-helpers.js +3 -1
  56. package/dist/core/engine/lifecycle/recovery-revision-groups.d.ts +75 -0
  57. package/dist/core/engine/lifecycle/recovery-revision-groups.js +64 -0
  58. package/dist/core/engine/lifecycle/resume-generation-guard.d.ts +58 -0
  59. package/dist/core/engine/lifecycle/resume-generation-guard.js +11 -0
  60. package/dist/core/engine/lifecycle/resume.js +18 -9
  61. package/dist/core/engine/lifecycle/shared.d.ts +43 -0
  62. package/dist/core/engine/lifecycle/standalone-claim-acquire.d.ts +12 -0
  63. package/dist/core/engine/lifecycle/standalone-claim-acquire.js +6 -0
  64. package/dist/core/engine/lifecycle/start-commit-errors.d.ts +12 -0
  65. package/dist/core/engine/lifecycle/start-commit-errors.js +6 -0
  66. package/dist/core/engine/lifecycle/start-commit.d.ts +22 -7
  67. package/dist/core/engine/lifecycle/start-commit.js +49 -15
  68. package/dist/core/engine/lifecycle/start-exec.d.ts +18 -2
  69. package/dist/core/engine/lifecycle/start-exec.js +7 -5
  70. package/dist/core/engine/lifecycle/start-or-signal-create.js +1 -3
  71. package/dist/core/engine/lifecycle/start-or-signal.js +1 -1
  72. package/dist/core/engine/lifecycle/start-precondition-attribution.d.ts +49 -0
  73. package/dist/core/engine/lifecycle/start-precondition-attribution.js +13 -0
  74. package/dist/core/engine/lifecycle/start-revision-resolution.d.ts +34 -0
  75. package/dist/core/engine/lifecycle/start-revision-resolution.js +11 -0
  76. package/dist/core/engine/lifecycle/start-state.d.ts +16 -0
  77. package/dist/core/engine/lifecycle/start-state.js +60 -0
  78. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.d.ts +66 -3
  79. package/dist/core/engine/lifecycle/start-terminal-conflict-purge.js +13 -3
  80. package/dist/core/engine/lifecycle/start.d.ts +16 -6
  81. package/dist/core/engine/lifecycle/start.js +38 -68
  82. package/dist/core/engine/lifecycle/transition.d.ts +3 -4
  83. package/dist/core/engine/lifecycle/transition.js +30 -80
  84. package/dist/core/engine/lifecycle.d.ts +4 -2
  85. package/dist/core/engine/lifecycle.js +6 -6
  86. package/dist/core/engine/listing.js +15 -1
  87. package/dist/core/engine/memo-durable-activity.js +4 -1
  88. package/dist/core/engine/nonterminal-revision-count.d.ts +25 -0
  89. package/dist/core/engine/nonterminal-revision-count.js +16 -0
  90. package/dist/core/engine/operations-time.d.ts +5 -23
  91. package/dist/core/engine/operations-time.js +13 -11
  92. package/dist/core/engine/ownership-bootstrap.d.ts +1 -1
  93. package/dist/core/engine/pinned-schedule-revision-count.d.ts +26 -0
  94. package/dist/core/engine/pinned-schedule-revision-count.js +19 -0
  95. package/dist/core/engine/pinned-schedule-revision.d.ts +76 -0
  96. package/dist/core/engine/pinned-schedule-revision.js +53 -0
  97. package/dist/core/engine/registration.d.ts +30 -0
  98. package/dist/core/engine/registration.js +17 -2
  99. package/dist/core/engine/retention.js +9 -2
  100. package/dist/core/engine/revision-errors.d.ts +71 -0
  101. package/dist/core/engine/revision-errors.js +13 -0
  102. package/dist/core/engine/schedule-revision-fire.d.ts +17 -0
  103. package/dist/core/engine/schedule-revision-fire.js +3 -0
  104. package/dist/core/engine/schedule-run.js +2 -1
  105. package/dist/core/engine/schedules.d.ts +2 -1
  106. package/dist/core/engine/schedules.js +28 -9
  107. package/dist/core/engine/source-diagnostics.d.ts +76 -0
  108. package/dist/core/engine/source-diagnostics.js +105 -0
  109. package/dist/core/engine/source-registration.js +4 -2
  110. package/dist/core/engine/source-resolution.d.ts +25 -9
  111. package/dist/core/engine/source-resolution.js +49 -14
  112. package/dist/core/engine/source-runtime-state.d.ts +92 -0
  113. package/dist/core/engine/source-runtime-state.js +36 -0
  114. package/dist/core/engine/storage-io.d.ts +19 -2
  115. package/dist/core/engine/storage-io.js +21 -2
  116. package/dist/core/engine/termination/finalizer-registration.d.ts +18 -0
  117. package/dist/core/engine/termination/finalizer-registration.js +21 -0
  118. package/dist/core/engine/termination/finalizer.d.ts +16 -19
  119. package/dist/core/engine/termination/finalizer.js +3 -3
  120. package/dist/core/engine/time-operation-callbacks.d.ts +32 -0
  121. package/dist/core/engine/time-operation-callbacks.js +0 -0
  122. package/dist/core/engine/validation/schedule-cadence.d.ts +16 -0
  123. package/dist/core/engine/validation/schedule-cadence.js +20 -0
  124. package/dist/core/engine/validation/schedule-options.d.ts +4 -1
  125. package/dist/core/engine/validation/schedule-options.js +14 -0
  126. package/dist/core/engine/validation/schedule-revision.d.ts +24 -0
  127. package/dist/core/engine/validation/schedule-revision.js +21 -0
  128. package/dist/core/engine/validation/schedule-warnings.d.ts +11 -0
  129. package/dist/core/engine/validation/schedule-warnings.js +5 -0
  130. package/dist/core/engine/validation/schedule.d.ts +4 -3
  131. package/dist/core/engine/validation/schedule.js +15 -26
  132. package/dist/core/engine/validation.js +3 -0
  133. package/dist/core/engine/workflow-claim-reclaim-target.d.ts +1 -1
  134. package/dist/core/engine/workflow-claim-reclaim-target.js +16 -2
  135. package/dist/core/engine/workflow-retention-deadline.d.ts +16 -0
  136. package/dist/core/engine/workflow-retention-deadline.js +33 -0
  137. package/dist/core/events/event-map.d.ts +5 -0
  138. package/dist/core/events/index.d.ts +1 -0
  139. package/dist/core/events/index.js +1 -0
  140. package/dist/core/events/workflow-source-events.d.ts +102 -0
  141. package/dist/core/events/workflow-source-events.js +57 -0
  142. package/dist/core/execution-strategy.d.ts +7 -0
  143. package/dist/core/inline-execution-strategy.context-options.d.ts +1 -1
  144. package/dist/core/inline-execution-strategy.js +1 -1
  145. package/dist/core/types/checkpoint.d.ts +14 -0
  146. package/dist/core/types/schedules.d.ts +52 -1
  147. package/dist/core/types/state.d.ts +16 -0
  148. package/dist/core/weft-error.d.ts +1 -1
  149. package/dist/core/weft-error.js +4 -1
  150. package/dist/core/worker-execution-strategy.d.ts +1 -0
  151. package/dist/core/worker-execution-strategy.js +13 -1
  152. package/dist/core/worker-fault-handling.d.ts +10 -0
  153. package/dist/core/worker-fault-handling.js +1 -0
  154. package/dist/core/worker-inbound-message.d.ts +1 -0
  155. package/dist/core/worker-inbound-message.js +1 -0
  156. package/dist/core/worker-protocol-guard.js +4 -0
  157. package/dist/core/worker-protocol.d.ts +7 -0
  158. package/dist/core/worker-protocol.js +2 -1
  159. package/dist/core/worker-turn-watchdog.d.ts +8 -1
  160. package/dist/core/worker-turn-watchdog.js +3 -2
  161. package/dist/diagnostics/format.js +5 -0
  162. package/dist/diagnostics/types.d.ts +24 -0
  163. package/dist/diagnostics/version-check.js +8 -2
  164. package/dist/http.js +1 -1
  165. package/dist/index.d.ts +3 -3
  166. package/dist/index.js +7 -0
  167. package/dist/indexeddb.js +1 -1
  168. package/dist/json-schema.js +3 -3
  169. package/dist/server/fault-to-json-rpc.js +2 -1
  170. package/dist/server/index.d.ts +11 -0
  171. package/dist/server/operation-fault.d.ts +2 -0
  172. package/dist/server/operation-fault.js +2 -1
  173. package/dist/server/operations/create-schedule.d.ts +2 -0
  174. package/dist/server/operations/create-schedule.js +10 -6
  175. package/dist/server/operations/get-catalog-diagnostics.d.ts +28 -0
  176. package/dist/server/operations/get-catalog-diagnostics.js +10 -2
  177. package/dist/server/operations/get-task-detail-schema.d.ts +8 -0
  178. package/dist/server/operations/get-task-detail-schema.js +1 -0
  179. package/dist/server/operations/get-task-detail.d.ts +8 -0
  180. package/dist/server/operations/get-task-detail.js +1 -0
  181. package/dist/server/operations/get-task-diagnostics.d.ts +4 -4
  182. package/dist/server/operations/preload-workflow-revision.d.ts +28 -0
  183. package/dist/server/operations/preload-workflow-revision.js +60 -0
  184. package/dist/server/operations/schedule-faults.d.ts +1 -0
  185. package/dist/server/operations/schedule-faults.js +32 -4
  186. package/dist/server/operations/schedule-rest-body.d.ts +1 -0
  187. package/dist/server/operations/schedule-rest-body.js +2 -1
  188. package/dist/server/operations/static-registrations.js +6 -0
  189. package/dist/server/operations/update-schedule.d.ts +2 -0
  190. package/dist/server/operations/update-schedule.js +4 -2
  191. package/dist/server/operations/workflow-catalog-operation-helpers.js +27 -0
  192. package/dist/server/runtime/task-dispatch-envelope.d.ts +14 -0
  193. package/dist/server/runtime/task-dispatch-envelope.js +32 -0
  194. package/dist/server/runtime/task-dispatch-revision.d.ts +29 -0
  195. package/dist/server/runtime/task-dispatch-revision.js +13 -0
  196. package/dist/server/runtime/task-dispatch.js +12 -37
  197. package/dist/server/runtime/task-ledger-recovery.js +1 -1
  198. package/dist/server/runtime/task-ledger-runtime.d.ts +14 -2
  199. package/dist/server/runtime/task-ledger-runtime.js +5 -3
  200. package/dist/server/runtime/task-polling.js +9 -3
  201. package/dist/server/runtime/task-reconciliation.js +2 -1
  202. package/dist/server/runtime/websocket-worker.js +9 -0
  203. package/dist/server/task-ledger-codec.d.ts +9 -0
  204. package/dist/server/task-ledger-codec.js +4 -1
  205. package/dist/server/task-ledger-transition-helpers.js +1 -0
  206. package/dist/server/task-ledger-types.d.ts +9 -0
  207. package/dist/server/task-ledger.d.ts +1 -1
  208. package/dist/server/task-ledger.js +2 -1
  209. package/dist/server/task-queue-types.d.ts +2 -0
  210. package/dist/storage/bun-sql.js +3 -1
  211. package/dist/storage/catalog-keys.d.ts +19 -0
  212. package/dist/storage/catalog-keys.js +3 -1
  213. package/dist/storage/compressed-storage.js +1 -1
  214. package/dist/storage/index.d.ts +3 -1
  215. package/dist/storage/interface.d.ts +2 -0
  216. package/dist/storage/interface.js +1 -1
  217. package/dist/storage/key-prefixes.d.ts +1 -1
  218. package/dist/storage/key-prefixes.js +1 -0
  219. package/dist/storage/lmdb.d.ts +30 -2
  220. package/dist/storage/lmdb.js +1 -1
  221. package/dist/storage/memory.js +1 -1
  222. package/dist/storage/neon.js +2 -2
  223. package/dist/storage/node-sqlite.js +3 -1
  224. package/dist/storage/postgres.js +2 -2
  225. package/dist/storage/resolve.js +1 -1
  226. package/dist/storage/scoped-storage.js +1 -1
  227. package/dist/storage/testing.js +1 -1
  228. package/dist/storage/turso.js +1 -1
  229. package/dist/version.d.ts +1 -1
  230. package/dist/version.js +1 -1
  231. package/dist/web-extension.js +1 -1
  232. package/dist/worker/protocol-messages.d.ts +17 -0
  233. package/dist/worker/protocol-schemas.d.ts +32 -0
  234. package/dist/worker/protocol-schemas.js +7 -3
  235. package/dist/worker/protocol-task-result.js +35 -3
  236. package/dist/worker/protocol.js +1 -1
  237. package/dist/worker/registry/types.d.ts +2 -0
  238. package/dist/worker/registry.d.ts +1 -1
  239. package/dist/worker/registry.js +3 -1
  240. package/dist/workers/workflow-runner.d.ts +9 -0
  241. package/dist/workers/workflow-runner.js +9 -2
  242. package/dist/workers/workflow-worker-entry.js +9 -4
  243. package/package.json +2 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Weft
2
2
 
3
- A Bun-native durable execution engine. Current release: `0.24.0`.
3
+ A Bun-native durable execution engine. Current release: `0.24.1`.
4
4
 
5
5
  Install the library from npm as `@lostgradient/weft`:
6
6
 
@@ -435,7 +435,7 @@ await using server = serve({ engine, port: 7233 });
435
435
  // server.url is e.g. "http://0.0.0.0:7233"
436
436
  ```
437
437
 
438
- Endpoints under `/api/v1/` cover the full lifecycle: start workflows, list, signal, update, query, cancel, fork, and stream events. JSON-RPC over WebSocket also exposes workflow and fleet event subscriptions for operator UIs that need live state without polling. Content negotiation supports JSON and MessagePack. `engine.workflows` and the matching `/v1/registry/` operations expose the durable workflow catalog for admin tooling — install a revision's manifest and activate it as the advertised active revision — bookkeeping only, never workflow execution routing; see [`workflow-versioning.md`](documentation/guides/workflow-versioning.md#engineworkflows-public-catalog-control). `workflowSource()` pairs a typed, serializable source descriptor with a never-serialized loader capability, so one workflow can register lazily while another stays eagerly registered; `engine.registerSource()` records the candidate without importing it, and `engine.resolveWorkflowSource()` loads, validates, and installs it into the same catalog with single-flight deduplication per `(name, revision)`; see [Dynamic Workflow Sources](documentation/guides/workflow-versioning.md#dynamic-workflow-sources). The server can also mount an externally supplied dashboard shell at known page routes; see the [server guide](documentation/guides/server.md#external-dashboard-mounting) for the hosting contract.
438
+ Endpoints under `/api/v1/` cover the full lifecycle: start workflows, list, signal, update, query, cancel, fork, and stream events. JSON-RPC over WebSocket also exposes workflow and fleet event subscriptions for operator UIs that need live state without polling. Content negotiation supports JSON and MessagePack. `engine.workflows` and the matching `/v1/registry/` operations expose the durable workflow catalog for admin tooling — install a revision's manifest and activate it as the advertised active revision — bookkeeping only, never workflow execution routing; see [`workflow-versioning.md`](documentation/guides/workflow-versioning.md#engineworkflows-public-catalog-control). `workflowSource()` pairs a typed, serializable source descriptor with a never-serialized loader capability, so one workflow can register lazily while another stays eagerly registered; `engine.registerSource()` records the candidate without importing it, and `engine.resolveWorkflowSource()` (or its `engine.workflows.preload()` alias) loads, validates, and installs it into the same catalog with single-flight deduplication per `(name, revision)`. Every execution entry point — `start()`, `startOrSignal()`, `schedule()`, `fork()`, `resume()`, and recovery — awaits resolution for a lazy type before running any handler code, with bounded diagnostics and process-local events for the load pipeline; see [Engine Integration](documentation/guides/workflow-versioning.md#engine-integration-wft-1516). The server can also mount an externally supplied dashboard shell at known page routes; see the [server guide](documentation/guides/server.md#external-dashboard-mounting) for the hosting contract.
439
439
 
440
440
  ### Remote Workers
441
441
 
@@ -119,14 +119,15 @@ async function readResolvedStatus(storage, operationId) {
119
119
  async function waitForResolvedStatus(storage, operationId, status, timeoutMs) {
120
120
  await waitForCondition(async () => await readResolvedStatus(storage, operationId) === status, timeoutMs, `${operationId} to resolve as ${status}`);
121
121
  }
122
- async function dispatchAndWait(server, storage, operationId, activityName, input, expectedStatus, timeoutMs) {
122
+ async function dispatchAndWait(server, storage, operationId, activityName, input, expectedStatus, timeoutMs, workflowRevision) {
123
123
  if (!await server.dispatchTask({
124
124
  operationId,
125
125
  activityName,
126
126
  workflowType: "conformance",
127
127
  input,
128
128
  queue: CONFORMANCE_QUEUE,
129
- visibilityTimeout: Math.max(500, timeoutMs)
129
+ visibilityTimeout: Math.max(500, timeoutMs),
130
+ ...workflowRevision !== void 0 && { workflowRevision }
130
131
  }))
131
132
  throw Error(`Could not dispatch ${operationId}`);
132
133
  await waitForResolvedStatus(storage, operationId, expectedStatus, timeoutMs);
@@ -184,6 +185,8 @@ async function runConformanceChecks(command, timeoutMs) {
184
185
  await waitForWorkerIdle(server, replacementWorkerId, timeoutMs);
185
186
  await waitForResolvedStatus(storage, reconnectOperationId, "completed", timeoutMs);
186
187
  checks.push(createCheck("reconnect", !0, "in-flight task completed after reconnect"));
188
+ await dispatchAndWait(server, storage, "conformance-revision-echo", "conformance.echo", { ok: !0 }, "completed", timeoutMs, "conformance-revision-1");
189
+ checks.push(createCheck("revision echo", !0, "workflowRevision echoed and accepted"));
187
190
  const shutdownWorkerId = server.registry.getWorker(replacementWorkerId)?.id;
188
191
  if (shutdownWorkerId === void 0)
189
192
  throw Error("No worker available for graceful shutdown check");
@@ -173,7 +173,7 @@
173
173
  "name": "weft.catalog.diagnostics",
174
174
  "kind": "unary",
175
175
  "summary": "Get bounded reference-count and removability diagnostics for one workflow revision",
176
- "description": "Report whether a `(name, revision)` workflow catalog entry is installed, whether it is currently the active revision, its full reference-count breakdown, and whether it's currently removable. Never returns manifest or contract content.",
176
+ "description": "Report whether a `(name, revision)` workflow catalog entry is installed, whether it is currently the active revision, its full reference-count breakdown, and whether it's currently removable. When `name` was ever registered as a dynamic workflow source (`engine.registerSource()`), also reports its bounded load-state diagnostics: source kind, load state, load duration, last failure category, and outstanding waiter count. Never returns manifest or contract content.",
177
177
  "tags": ["Observability"],
178
178
  "destructive": false,
179
179
  "access": {
@@ -272,6 +272,37 @@
272
272
  },
273
273
  "revision": {
274
274
  "type": "string"
275
+ },
276
+ "source": {
277
+ "additionalProperties": false,
278
+ "properties": {
279
+ "kind": {
280
+ "const": "module",
281
+ "type": "string"
282
+ },
283
+ "lastFailureCategory": {
284
+ "enum": ["application", "timeout", "cancellation", "resource", "system"],
285
+ "type": "string"
286
+ },
287
+ "loadDurationMs": {
288
+ "minimum": 0,
289
+ "type": "number"
290
+ },
291
+ "requestedRevision": {
292
+ "type": "string"
293
+ },
294
+ "state": {
295
+ "enum": ["idle", "loading", "ready", "failed", "cancelled"],
296
+ "type": "string"
297
+ },
298
+ "waiterCount": {
299
+ "maximum": 9007199254740991,
300
+ "minimum": 0,
301
+ "type": "integer"
302
+ }
303
+ },
304
+ "required": ["kind", "requestedRevision", "state", "waiterCount"],
305
+ "type": "object"
275
306
  }
276
307
  },
277
308
  "required": ["name", "revision", "installed", "active", "references", "removable"],
@@ -926,6 +957,9 @@
926
957
  "input": {},
927
958
  "jitter": {},
928
959
  "overlap": {},
960
+ "revisionPolicy": {
961
+ "description": "Revision policy (WFT-20). Runtime validation requires \"active-at-fire\" or \"pinned\"; defaults to \"active-at-fire\"."
962
+ },
929
963
  "type": {
930
964
  "description": "Workflow type name. Runtime validation requires a non-empty string."
931
965
  }
@@ -1095,6 +1129,9 @@
1095
1129
  },
1096
1130
  "jitter": {},
1097
1131
  "overlap": {},
1132
+ "revisionPolicy": {
1133
+ "description": "Revision policy (WFT-20). Runtime validation requires \"active-at-fire\" or \"pinned\". Omitted preserves the current policy (and pin); \"pinned\" always re-resolves and re-captures the pin against the revision active right now."
1134
+ },
1098
1135
  "scheduleId": {
1099
1136
  "minLength": 1,
1100
1137
  "type": "string"
@@ -2351,6 +2388,9 @@
2351
2388
  "workflowId": {
2352
2389
  "type": "string"
2353
2390
  },
2391
+ "workflowRevision": {
2392
+ "type": "string"
2393
+ },
2354
2394
  "workflowType": {
2355
2395
  "type": "string"
2356
2396
  }
@@ -2512,6 +2552,9 @@
2512
2552
  "workflowId": {
2513
2553
  "type": "string"
2514
2554
  },
2555
+ "workflowRevision": {
2556
+ "type": "string"
2557
+ },
2515
2558
  "workflowType": {
2516
2559
  "type": "string"
2517
2560
  }
@@ -2682,6 +2725,9 @@
2682
2725
  "workflowId": {
2683
2726
  "type": "string"
2684
2727
  },
2728
+ "workflowRevision": {
2729
+ "type": "string"
2730
+ },
2685
2731
  "workflowType": {
2686
2732
  "type": "string"
2687
2733
  }
@@ -2853,6 +2899,9 @@
2853
2899
  "workflowId": {
2854
2900
  "type": "string"
2855
2901
  },
2902
+ "workflowRevision": {
2903
+ "type": "string"
2904
+ },
2856
2905
  "workflowType": {
2857
2906
  "type": "string"
2858
2907
  }
@@ -3020,6 +3069,9 @@
3020
3069
  "workflowId": {
3021
3070
  "type": "string"
3022
3071
  },
3072
+ "workflowRevision": {
3073
+ "type": "string"
3074
+ },
3023
3075
  "workflowType": {
3024
3076
  "type": "string"
3025
3077
  }
@@ -3174,6 +3226,9 @@
3174
3226
  "workflowId": {
3175
3227
  "type": "string"
3176
3228
  },
3229
+ "workflowRevision": {
3230
+ "type": "string"
3231
+ },
3177
3232
  "workflowType": {
3178
3233
  "type": "string"
3179
3234
  }
@@ -3327,6 +3382,9 @@
3327
3382
  "workflowId": {
3328
3383
  "type": "string"
3329
3384
  },
3385
+ "workflowRevision": {
3386
+ "type": "string"
3387
+ },
3330
3388
  "workflowType": {
3331
3389
  "type": "string"
3332
3390
  }
@@ -3490,6 +3548,9 @@
3490
3548
  "workflowId": {
3491
3549
  "type": "string"
3492
3550
  },
3551
+ "workflowRevision": {
3552
+ "type": "string"
3553
+ },
3493
3554
  "workflowType": {
3494
3555
  "type": "string"
3495
3556
  }
@@ -7750,6 +7811,39 @@
7750
7811
  },
7751
7812
  "outputSchema": {}
7752
7813
  },
7814
+ {
7815
+ "name": "weft.workflows.revisions.preload",
7816
+ "kind": "unary",
7817
+ "summary": "Load, validate, and install a registered dynamic workflow source revision",
7818
+ "description": "Load, validate, and install `(name, revision)` — previously recorded via engine.registerSource() — durably into the workflow catalog. Faults NotFound when no source was ever registered for this exact key, and Conflict when the load fails or the loaded module fails validation.",
7819
+ "tags": ["Workflow Catalog"],
7820
+ "destructive": false,
7821
+ "access": {
7822
+ "kind": "scoped",
7823
+ "scopes": ["workflows:admin"]
7824
+ },
7825
+ "transports": {
7826
+ "http": true,
7827
+ "jsonRpcHttp": true,
7828
+ "jsonRpcWebSocket": true,
7829
+ "jsonRpcStdio": true
7830
+ },
7831
+ "producibleFaults": ["Conflict", "InvalidParams", "NotFound"],
7832
+ "inputSchema": {
7833
+ "additionalProperties": false,
7834
+ "properties": {
7835
+ "name": {
7836
+ "description": "Workflow name. Runtime validation requires a wire-safe identifier."
7837
+ },
7838
+ "revision": {
7839
+ "description": "The registerSource()-registered revision to load, validate, and install. Runtime validation requires a non-empty string."
7840
+ }
7841
+ },
7842
+ "required": ["name", "revision"],
7843
+ "type": "object"
7844
+ },
7845
+ "outputSchema": {}
7846
+ },
7753
7847
  {
7754
7848
  "name": "weft.workflows.scheduleprovenance.get",
7755
7849
  "kind": "unary",
@@ -1,7 +1,7 @@
1
1
  import { type CatalogWeftClient, type WeftClientConnection } from '../operation-client-runtime.ts';
2
- export declare const CATALOG_OPERATION_NAMES: readonly ["weft.activities.complete", "weft.activities.fail", "weft.alerts.list", "weft.catalog.diagnostics", "weft.recover.all", "weft.retention.get", "weft.reviews.decision.submit", "weft.reviews.get", "weft.reviews.list", "weft.schedules.cancel", "weft.schedules.create", "weft.schedules.get", "weft.schedules.list", "weft.schedules.pause", "weft.schedules.resume", "weft.schedules.update", "weft.storage.capabilities", "weft.system.lease", "weft.system.metrics", "weft.system.principal", "weft.system.registry", "weft.task.queues.list", "weft.tasks.diagnostics", "weft.tasks.get", "weft.updates.result.get", "weft.worker.deployments.drain", "weft.worker.deployments.resume", "weft.workers.diagnostics", "weft.workers.drain", "weft.workers.list", "weft.workers.rejections", "weft.workers.resume", "weft.workflows.active.get", "weft.workflows.activities.pending.list", "weft.workflows.aggregate", "weft.workflows.attributes.get", "weft.workflows.attributes.set", "weft.workflows.bulk.cancel", "weft.workflows.bulk.delete", "weft.workflows.bulk.retryfailed", "weft.workflows.bulk.signal", "weft.workflows.bulk.tags", "weft.workflows.cancel", "weft.workflows.checkpoints.get", "weft.workflows.checkpoints.list", "weft.workflows.events.list", "weft.workflows.finalizer.get", "weft.workflows.fork", "weft.workflows.get", "weft.workflows.list", "weft.workflows.purge", "weft.workflows.query", "weft.workflows.replay", "weft.workflows.result.get", "weft.workflows.resume", "weft.workflows.revisions.activate", "weft.workflows.revisions.get", "weft.workflows.revisions.install", "weft.workflows.revisions.list", "weft.workflows.scheduleprovenance.get", "weft.workflows.signal", "weft.workflows.start", "weft.workflows.startorsignal", "weft.workflows.streams.chunks", "weft.workflows.suspend", "weft.workflows.tags.add", "weft.workflows.tags.remove", "weft.workflows.timeline.get", "weft.workflows.timeout", "weft.workflows.update"];
2
+ export declare const CATALOG_OPERATION_NAMES: readonly ["weft.activities.complete", "weft.activities.fail", "weft.alerts.list", "weft.catalog.diagnostics", "weft.recover.all", "weft.retention.get", "weft.reviews.decision.submit", "weft.reviews.get", "weft.reviews.list", "weft.schedules.cancel", "weft.schedules.create", "weft.schedules.get", "weft.schedules.list", "weft.schedules.pause", "weft.schedules.resume", "weft.schedules.update", "weft.storage.capabilities", "weft.system.lease", "weft.system.metrics", "weft.system.principal", "weft.system.registry", "weft.task.queues.list", "weft.tasks.diagnostics", "weft.tasks.get", "weft.updates.result.get", "weft.worker.deployments.drain", "weft.worker.deployments.resume", "weft.workers.diagnostics", "weft.workers.drain", "weft.workers.list", "weft.workers.rejections", "weft.workers.resume", "weft.workflows.active.get", "weft.workflows.activities.pending.list", "weft.workflows.aggregate", "weft.workflows.attributes.get", "weft.workflows.attributes.set", "weft.workflows.bulk.cancel", "weft.workflows.bulk.delete", "weft.workflows.bulk.retryfailed", "weft.workflows.bulk.signal", "weft.workflows.bulk.tags", "weft.workflows.cancel", "weft.workflows.checkpoints.get", "weft.workflows.checkpoints.list", "weft.workflows.events.list", "weft.workflows.finalizer.get", "weft.workflows.fork", "weft.workflows.get", "weft.workflows.list", "weft.workflows.purge", "weft.workflows.query", "weft.workflows.replay", "weft.workflows.result.get", "weft.workflows.resume", "weft.workflows.revisions.activate", "weft.workflows.revisions.get", "weft.workflows.revisions.install", "weft.workflows.revisions.list", "weft.workflows.revisions.preload", "weft.workflows.scheduleprovenance.get", "weft.workflows.signal", "weft.workflows.start", "weft.workflows.startorsignal", "weft.workflows.streams.chunks", "weft.workflows.suspend", "weft.workflows.tags.add", "weft.workflows.tags.remove", "weft.workflows.timeline.get", "weft.workflows.timeout", "weft.workflows.update"];
3
3
  export type CatalogOperationName = (typeof CATALOG_OPERATION_NAMES)[number];
4
- export declare const CLIENT_OPERATION_NAMES: readonly ["weft.activities.complete", "weft.activities.fail", "weft.alerts.list", "weft.catalog.diagnostics", "weft.recover.all", "weft.retention.get", "weft.reviews.decision.submit", "weft.reviews.get", "weft.reviews.list", "weft.schedules.cancel", "weft.schedules.create", "weft.schedules.get", "weft.schedules.list", "weft.schedules.pause", "weft.schedules.resume", "weft.schedules.update", "weft.storage.capabilities", "weft.system.lease", "weft.system.metrics", "weft.system.principal", "weft.system.registry", "weft.task.queues.list", "weft.tasks.diagnostics", "weft.tasks.diagnostics.deadletters.clear", "weft.tasks.get", "weft.updates.result.get", "weft.worker.deployments.drain", "weft.worker.deployments.resume", "weft.workers.diagnostics", "weft.workers.drain", "weft.workers.list", "weft.workers.rejections", "weft.workers.resume", "weft.workflows.active.get", "weft.workflows.activities.pending.list", "weft.workflows.aggregate", "weft.workflows.attributes.get", "weft.workflows.attributes.set", "weft.workflows.bulk.cancel", "weft.workflows.bulk.delete", "weft.workflows.bulk.retryfailed", "weft.workflows.bulk.signal", "weft.workflows.bulk.tags", "weft.workflows.cancel", "weft.workflows.checkpoints.get", "weft.workflows.checkpoints.list", "weft.workflows.events.list", "weft.workflows.finalizer.get", "weft.workflows.fork", "weft.workflows.get", "weft.workflows.list", "weft.workflows.purge", "weft.workflows.query", "weft.workflows.replay", "weft.workflows.result.get", "weft.workflows.resume", "weft.workflows.revisions.activate", "weft.workflows.revisions.get", "weft.workflows.revisions.install", "weft.workflows.revisions.list", "weft.workflows.scheduleprovenance.get", "weft.workflows.signal", "weft.workflows.start", "weft.workflows.startorsignal", "weft.workflows.streams.chunks", "weft.workflows.suspend", "weft.workflows.tags.add", "weft.workflows.tags.remove", "weft.workflows.timeline.get", "weft.workflows.timeout", "weft.workflows.update"];
4
+ export declare const CLIENT_OPERATION_NAMES: readonly ["weft.activities.complete", "weft.activities.fail", "weft.alerts.list", "weft.catalog.diagnostics", "weft.recover.all", "weft.retention.get", "weft.reviews.decision.submit", "weft.reviews.get", "weft.reviews.list", "weft.schedules.cancel", "weft.schedules.create", "weft.schedules.get", "weft.schedules.list", "weft.schedules.pause", "weft.schedules.resume", "weft.schedules.update", "weft.storage.capabilities", "weft.system.lease", "weft.system.metrics", "weft.system.principal", "weft.system.registry", "weft.task.queues.list", "weft.tasks.diagnostics", "weft.tasks.diagnostics.deadletters.clear", "weft.tasks.get", "weft.updates.result.get", "weft.worker.deployments.drain", "weft.worker.deployments.resume", "weft.workers.diagnostics", "weft.workers.drain", "weft.workers.list", "weft.workers.rejections", "weft.workers.resume", "weft.workflows.active.get", "weft.workflows.activities.pending.list", "weft.workflows.aggregate", "weft.workflows.attributes.get", "weft.workflows.attributes.set", "weft.workflows.bulk.cancel", "weft.workflows.bulk.delete", "weft.workflows.bulk.retryfailed", "weft.workflows.bulk.signal", "weft.workflows.bulk.tags", "weft.workflows.cancel", "weft.workflows.checkpoints.get", "weft.workflows.checkpoints.list", "weft.workflows.events.list", "weft.workflows.finalizer.get", "weft.workflows.fork", "weft.workflows.get", "weft.workflows.list", "weft.workflows.purge", "weft.workflows.query", "weft.workflows.replay", "weft.workflows.result.get", "weft.workflows.resume", "weft.workflows.revisions.activate", "weft.workflows.revisions.get", "weft.workflows.revisions.install", "weft.workflows.revisions.list", "weft.workflows.revisions.preload", "weft.workflows.scheduleprovenance.get", "weft.workflows.signal", "weft.workflows.start", "weft.workflows.startorsignal", "weft.workflows.streams.chunks", "weft.workflows.suspend", "weft.workflows.tags.add", "weft.workflows.tags.remove", "weft.workflows.timeline.get", "weft.workflows.timeout", "weft.workflows.update"];
5
5
  export type ClientOperationName = (typeof CLIENT_OPERATION_NAMES)[number];
6
6
  export declare const CLIENT_REST_OPERATION_BINDINGS: {
7
7
  readonly 'weft.tasks.diagnostics.deadletters.clear': {
@@ -155,6 +155,14 @@ export type ClientOperationTypes = {
155
155
  };
156
156
  readonly removable: boolean;
157
157
  readonly revision: string;
158
+ readonly source?: {
159
+ readonly kind: 'module';
160
+ readonly lastFailureCategory?: 'application' | 'timeout' | 'cancellation' | 'resource' | 'system';
161
+ readonly loadDurationMs?: number;
162
+ readonly requestedRevision: string;
163
+ readonly state: 'idle' | 'loading' | 'ready' | 'failed' | 'cancelled';
164
+ readonly waiterCount: number;
165
+ };
158
166
  };
159
167
  readonly faults: never;
160
168
  };
@@ -247,6 +255,7 @@ export type ClientOperationTypes = {
247
255
  readonly input?: unknown;
248
256
  readonly jitter?: unknown;
249
257
  readonly overlap?: unknown;
258
+ readonly revisionPolicy?: unknown;
250
259
  readonly type: unknown;
251
260
  };
252
261
  readonly output: {
@@ -293,6 +302,7 @@ export type ClientOperationTypes = {
293
302
  readonly every?: unknown;
294
303
  readonly jitter?: unknown;
295
304
  readonly overlap?: unknown;
305
+ readonly revisionPolicy?: unknown;
296
306
  readonly scheduleId: string;
297
307
  };
298
308
  readonly output: null;
@@ -470,6 +480,7 @@ export type ClientOperationTypes = {
470
480
  readonly visibilityTimeoutMilliseconds: number;
471
481
  readonly workflowExecutionToken?: string;
472
482
  readonly workflowId?: string;
483
+ readonly workflowRevision?: string;
473
484
  readonly workflowType: string;
474
485
  } | {
475
486
  readonly activityName: string;
@@ -496,6 +507,7 @@ export type ClientOperationTypes = {
496
507
  readonly visibilityTimeoutMilliseconds: number;
497
508
  readonly workflowExecutionToken?: string;
498
509
  readonly workflowId?: string;
510
+ readonly workflowRevision?: string;
499
511
  readonly workflowType: string;
500
512
  } | {
501
513
  readonly activityName: string;
@@ -524,6 +536,7 @@ export type ClientOperationTypes = {
524
536
  readonly visibilityTimeoutMilliseconds: number;
525
537
  readonly workflowExecutionToken?: string;
526
538
  readonly workflowId?: string;
539
+ readonly workflowRevision?: string;
527
540
  readonly workflowType: string;
528
541
  } | {
529
542
  readonly activityName: string;
@@ -552,6 +565,7 @@ export type ClientOperationTypes = {
552
565
  readonly visibilityTimeoutMilliseconds: number;
553
566
  readonly workflowExecutionToken?: string;
554
567
  readonly workflowId?: string;
568
+ readonly workflowRevision?: string;
555
569
  readonly workflowType: string;
556
570
  } | {
557
571
  readonly activityName: string;
@@ -577,6 +591,7 @@ export type ClientOperationTypes = {
577
591
  readonly visibilityTimeoutMilliseconds: number;
578
592
  readonly workflowExecutionToken?: string;
579
593
  readonly workflowId?: string;
594
+ readonly workflowRevision?: string;
580
595
  readonly workflowType: string;
581
596
  } | {
582
597
  readonly activityName: string;
@@ -600,6 +615,7 @@ export type ClientOperationTypes = {
600
615
  readonly visibilityTimeoutMilliseconds: number;
601
616
  readonly workflowExecutionToken?: string;
602
617
  readonly workflowId?: string;
618
+ readonly workflowRevision?: string;
603
619
  readonly workflowType: string;
604
620
  } | {
605
621
  readonly activityName: string;
@@ -623,6 +639,7 @@ export type ClientOperationTypes = {
623
639
  readonly visibilityTimeoutMilliseconds: number;
624
640
  readonly workflowExecutionToken?: string;
625
641
  readonly workflowId?: string;
642
+ readonly workflowRevision?: string;
626
643
  readonly workflowType: string;
627
644
  } | {
628
645
  readonly activityName: string;
@@ -649,6 +666,7 @@ export type ClientOperationTypes = {
649
666
  readonly visibilityTimeoutMilliseconds: number;
650
667
  readonly workflowExecutionToken?: string;
651
668
  readonly workflowId?: string;
669
+ readonly workflowRevision?: string;
652
670
  readonly workflowType: string;
653
671
  };
654
672
  readonly faults: 'NotFound';
@@ -1060,6 +1078,14 @@ export type ClientOperationTypes = {
1060
1078
  readonly output: unknown;
1061
1079
  readonly faults: 'InvalidParams';
1062
1080
  };
1081
+ 'weft.workflows.revisions.preload': {
1082
+ readonly input: {
1083
+ readonly name: unknown;
1084
+ readonly revision: unknown;
1085
+ };
1086
+ readonly output: unknown;
1087
+ readonly faults: 'Conflict' | 'InvalidParams' | 'NotFound';
1088
+ };
1063
1089
  'weft.workflows.scheduleprovenance.get': {
1064
1090
  readonly input: {
1065
1091
  readonly workflowId: string;
@@ -62,6 +62,7 @@ export const CATALOG_OPERATION_NAMES = [
62
62
  "weft.workflows.revisions.get",
63
63
  "weft.workflows.revisions.install",
64
64
  "weft.workflows.revisions.list",
65
+ "weft.workflows.revisions.preload",
65
66
  "weft.workflows.scheduleprovenance.get",
66
67
  "weft.workflows.signal",
67
68
  "weft.workflows.start",
@@ -134,6 +135,7 @@ export const CATALOG_OPERATION_NAMES = [
134
135
  "weft.workflows.revisions.get",
135
136
  "weft.workflows.revisions.install",
136
137
  "weft.workflows.revisions.list",
138
+ "weft.workflows.revisions.preload",
137
139
  "weft.workflows.scheduleprovenance.get",
138
140
  "weft.workflows.signal",
139
141
  "weft.workflows.start",
@@ -1,6 +1,6 @@
1
1
  import { parseArgs } from "node:util";
2
2
  import { parsePersistentStorageBackend } from "./storage-backend-arguments.js";
3
- const SCHEDULE_ACTIONS = new Set(["list", "create", "pause", "resume", "cancel"]), VALID_SCHEDULE_OVERLAP_POLICIES = new Set(["skip", "queue", "cancel-running", "allow"]);
3
+ const SCHEDULE_ACTIONS = new Set(["list", "create", "pause", "resume", "cancel"]), VALID_SCHEDULE_OVERLAP_POLICIES = new Set(["skip", "queue", "cancel-running", "allow"]), VALID_SCHEDULE_REVISION_POLICIES = new Set(["active-at-fire", "pinned"]);
4
4
  function parseScheduleCliValues(args) {
5
5
  return parseArgs({
6
6
  args,
@@ -14,6 +14,7 @@ function parseScheduleCliValues(args) {
14
14
  overlap: { type: "string" },
15
15
  backfill: { type: "boolean", default: !1 },
16
16
  jitter: { type: "string" },
17
+ "revision-policy": { type: "string" },
17
18
  help: { type: "boolean", short: "h", default: !1 },
18
19
  json: { type: "boolean", short: "j", default: !1 }
19
20
  },
@@ -76,12 +77,23 @@ function requireScheduleAction(positionals) {
76
77
  throw Error(`Unknown schedule action "${action}". Expected one of: ${formatScheduleActionList()}`);
77
78
  return action;
78
79
  }
80
+ function isScheduleRevisionPolicy(value) {
81
+ return VALID_SCHEDULE_REVISION_POLICIES.has(value);
82
+ }
83
+ function parseScheduleRevisionPolicy(value) {
84
+ if (value === void 0)
85
+ return;
86
+ if (!isScheduleRevisionPolicy(value))
87
+ throw Error(`Invalid revision policy '${value}'. Must be one of: active-at-fire, pinned`);
88
+ return value;
89
+ }
79
90
  function buildScheduleCreateOptionalFields(values) {
80
- const overlap = parseScheduleOverlapPolicy(values.overlap);
91
+ const overlap = parseScheduleOverlapPolicy(values.overlap), revisionPolicy = parseScheduleRevisionPolicy(values["revision-policy"]);
81
92
  return {
82
93
  ...values.id !== void 0 ? { id: values.id } : {},
83
94
  ...overlap !== void 0 ? { overlap } : {},
84
- ...values.jitter !== void 0 ? { jitter: values.jitter } : {}
95
+ ...values.jitter !== void 0 ? { jitter: values.jitter } : {},
96
+ ...revisionPolicy !== void 0 ? { revisionPolicy } : {}
85
97
  };
86
98
  }
87
99
  function buildScheduleCreateCommand(values, positionals) {
@@ -64,7 +64,8 @@ async function executeScheduleCreate(options, engine, loadRegistrationsFromModul
64
64
  ...options.id !== void 0 ? { id: options.id } : {},
65
65
  ...options.overlap !== void 0 ? { overlap: options.overlap } : {},
66
66
  ...options.backfill ? { backfill: !0 } : {},
67
- ...options.jitter !== void 0 ? { jitter: options.jitter } : {}
67
+ ...options.jitter !== void 0 ? { jitter: options.jitter } : {},
68
+ ...options.revisionPolicy !== void 0 ? { revisionPolicy: options.revisionPolicy } : {}
68
69
  }), schedule = await handle.describe();
69
70
  return {
70
71
  stdout: formatScheduleCommandOutput(schedule, options.json, `Created schedule ${handle.id}`),
@@ -1,4 +1,4 @@
1
- import type { ScheduleOverlapPolicy } from '../core/types.ts';
1
+ import type { ScheduleOverlapPolicy, ScheduleRevisionPolicy } from '../core/types.ts';
2
2
  /** Supported storage backend identifiers for the `--storage` flag. */
3
3
  export type StorageBackend = 'sqlite' | 'lmdb' | 'memory';
4
4
  /** Storage backends suitable for commands that must survive process exit. */
@@ -86,6 +86,7 @@ export type CliCommand = {
86
86
  overlap?: ScheduleOverlapPolicy;
87
87
  backfill: boolean;
88
88
  jitter?: string;
89
+ revisionPolicy?: ScheduleRevisionPolicy;
89
90
  help: boolean;
90
91
  json: boolean;
91
92
  } | {
@@ -1,7 +1,7 @@
1
1
  import { assertScopedBulkWorkflowFilter } from "../core/bulk-workflow-filter.js";
2
2
  import { HttpClientError, request } from "./http-request.js";
3
3
  import { buildReviewListSearchParams } from "./search-params.js";
4
- import { scheduleSpecToWireFields } from "./start-body.js";
4
+ import { scheduleSpecToWireFields, setIfDefined } from "./start-body.js";
5
5
  export async function listReviewRequests(context, filter) {
6
6
  const search = buildReviewListSearchParams(filter).toString(), path = search.length > 0 ? `/reviews?${search}` : "/reviews";
7
7
  return (await request(context.baseUrl, path, context.headers)).items;
@@ -187,14 +187,11 @@ export function cancelScheduleRequest(context, id) {
187
187
  }
188
188
  export function updateScheduleRequest(context, id, newSpec, options) {
189
189
  const body = scheduleSpecToWireFields(newSpec);
190
- if (options?.description !== void 0)
191
- body.description = options.description;
192
- if (options?.overlap !== void 0)
193
- body.overlap = options.overlap;
194
- if (options?.backfill !== void 0)
195
- body.backfill = options.backfill;
196
- if (options?.jitter !== void 0)
197
- body.jitter = options.jitter;
190
+ setIfDefined(body, "description", options?.description);
191
+ setIfDefined(body, "overlap", options?.overlap);
192
+ setIfDefined(body, "backfill", options?.backfill);
193
+ setIfDefined(body, "jitter", options?.jitter);
194
+ setIfDefined(body, "revisionPolicy", options?.revisionPolicy);
198
195
  return request(context.baseUrl, `/schedules/${encodeURIComponent(id)}`, context.headers, {
199
196
  method: "PATCH",
200
197
  body: JSON.stringify(body)
@@ -16,6 +16,7 @@ export function buildScheduleBody(type, input, spec, options) {
16
16
  setIfDefined(body, "overlap", options?.overlap);
17
17
  setIfDefined(body, "backfill", options?.backfill);
18
18
  setIfDefined(body, "jitter", options?.jitter);
19
+ setIfDefined(body, "revisionPolicy", options?.revisionPolicy);
19
20
  return body;
20
21
  }
21
22
  function applyStartOptionsToBody(body, options) {
@@ -19,7 +19,7 @@
19
19
  */
20
20
  export { WorkflowCatalogActivationConflictError, WorkflowCatalogActiveEntryMissingError, WorkflowCatalogConflictError, WorkflowRevisionNotInstalledError, } from './errors.ts';
21
21
  export { decrementNestedRevisionCount, incrementNestedRevisionCount, readNestedRevisionCount, totalWorkflowRevisionReferences, type WorkflowRevisionReferenceCounts, } from './reference-counts.ts';
22
- export { removeCatalogEntry, type WorkflowCatalogRemovalOutcome } from './removal.ts';
23
- export { restoreWorkflowCatalog, type RestoredWorkflowCatalogState } from './storage-io.ts';
22
+ export { finalizeCatalogTombstone, removeCatalogEntry, restoreCatalogEntryFromTombstone, type WorkflowCatalogRemovalOutcome, } from './removal.ts';
23
+ export { decodeCatalogEntryRecord, restoreWorkflowCatalog, type RestoredWorkflowCatalogState, } from './storage-io.ts';
24
24
  export type { WorkflowCatalogActivationResult, WorkflowCatalogActivePointer, WorkflowCatalogEntry, WorkflowRevisionRecord, } from './types.ts';
25
25
  export { WorkflowCatalog, type ActivateCandidateOptions } from './workflow-catalog.ts';
@@ -10,6 +10,13 @@ export {
10
10
  readNestedRevisionCount,
11
11
  totalWorkflowRevisionReferences
12
12
  } from "./reference-counts.js";
13
- export { removeCatalogEntry } from "./removal.js";
14
- export { restoreWorkflowCatalog } from "./storage-io.js";
13
+ export {
14
+ finalizeCatalogTombstone,
15
+ removeCatalogEntry,
16
+ restoreCatalogEntryFromTombstone
17
+ } from "./removal.js";
18
+ export {
19
+ decodeCatalogEntryRecord,
20
+ restoreWorkflowCatalog
21
+ } from "./storage-io.js";
15
22
  export { WorkflowCatalog } from "./workflow-catalog.js";
@@ -3,10 +3,17 @@
3
3
  * `(name, revision)` removal decision is gated on (WFT-12).
4
4
  *
5
5
  * Seven fields, all always present so a consumer never has to special-case
6
- * an "unknown" reference kind. Two are wired to real in-process signals this
7
- * batch; the remaining five stay structurally present but always `0` until
8
- * run-level revision pinning lands (WFT-17) gives them something real to
9
- * count — see each field's own doc for its specific WFT-17 dependency. This
6
+ * an "unknown" reference kind. Four are wired to real in-process/durable
7
+ * signals: `registeredDefinitions` and `inFlightStarts` from WFT-12,
8
+ * `nonTerminalRuns` from WFT-17 (a bounded storage scan of persisted
9
+ * `WorkflowState.revision` pins — see {@link countNonTerminalRunsForRevision}),
10
+ * and `pinnedSchedules` from WFT-20 (a bounded storage scan of persisted
11
+ * `revisionPolicy: 'pinned'` schedules — see
12
+ * {@link import('../engine/pinned-schedule-revision-count.ts').countPinnedSchedulesForRevision}).
13
+ * The remaining three stay structurally present but always `0` — each
14
+ * awaits revision identity in a different, later-owned subsystem (dispatch
15
+ * ledger, execution realms, and retained recovery records: not yet
16
+ * scheduled) — see each field's own doc for its specific dependency. This
10
17
  * mirrors `workflow-catalog.ts`'s own precedent of describing a forward
11
18
  * dependency in prose rather than leaving a `TODO`/`FIXME` marker.
12
19
  *
@@ -56,32 +63,40 @@ export type WorkflowRevisionReferenceCounts = Readonly<{
56
63
  */
57
64
  inFlightStarts: number;
58
65
  /**
59
- * Non-terminal runs whose `WorkflowState` pins exactly this revision.
60
- * Always `0` until run-level revision pinning (WFT-17) gives a run's
61
- * persisted state a `revision` field to count against.
66
+ * Non-terminal (`running`/`pending`/`suspended`) runs whose `WorkflowState`
67
+ * pins exactly this revision. Wired now (WFT-17), via a bounded
68
+ * `storage.scan('wf:')` see
69
+ * {@link import('../engine/nonterminal-revision-count.ts').countNonTerminalRunsForRevision}.
70
+ * A legacy run with no persisted `revision` never counts against any
71
+ * specific revision here.
62
72
  */
63
73
  nonTerminalRuns: number;
64
74
  /**
65
- * Schedules pinned to exactly this revision. Always `0` until WFT-17
66
- * introduces schedule-level revision pinning.
75
+ * Non-cancelled schedules with `revisionPolicy: 'pinned'` and
76
+ * `pinnedRevision` equal to exactly this revision. Wired now (WFT-20), via
77
+ * a bounded `storage.scan('schedule:')` — see
78
+ * {@link import('../engine/pinned-schedule-revision-count.ts').countPinnedSchedulesForRevision}.
79
+ * An `'active-at-fire'` schedule never counts here, regardless of its
80
+ * `workflowType` — it resolves whatever revision is active at each future
81
+ * fire, so it holds no standing reference to any one revision.
67
82
  */
68
83
  pinnedSchedules: number;
69
84
  /**
70
85
  * Queued dispatches (delayed starts, retries) targeting exactly this
71
- * revision. Always `0` until WFT-17 threads revision identity through the
72
- * dispatch ledger.
86
+ * revision. Always `0` until a later batch threads revision identity
87
+ * through the dispatch ledger.
73
88
  */
74
89
  pendingDispatches: number;
75
90
  /**
76
91
  * Active execution realms (remote worker sessions) currently running
77
- * exactly this revision. Always `0` until WFT-17 gives a realm's
92
+ * exactly this revision. Always `0` until a later batch gives a realm's
78
93
  * advertised contract a revision this accounting can compare against.
79
94
  */
80
95
  activeExecutionRealms: number;
81
96
  /**
82
97
  * Retained recovery records (crash-recovery checkpoints, dead letters)
83
- * referencing exactly this revision. Always `0` until WFT-17 threads
84
- * revision identity through those retained records.
98
+ * referencing exactly this revision. Always `0` until a later batch
99
+ * threads revision identity through those retained records.
85
100
  */
86
101
  retainedRecoveryRecords: number;
87
102
  }>;