@smthrs/engine-store 0.0.0-stage → 1.0.0-rc.3

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 (787) hide show
  1. package/CHANGELOG.md +247 -0
  2. package/LICENSE +21 -0
  3. package/README.md +146 -2
  4. package/dist/cjs/ArtifactGc.d.ts +235 -0
  5. package/dist/cjs/ArtifactGc.d.ts.map +1 -0
  6. package/dist/cjs/ArtifactGc.js +183 -0
  7. package/dist/cjs/ArtifactGc.js.map +7 -0
  8. package/dist/cjs/ArtifactSync.d.ts +164 -0
  9. package/dist/cjs/ArtifactSync.d.ts.map +1 -0
  10. package/dist/cjs/ArtifactSync.js +144 -0
  11. package/dist/cjs/ArtifactSync.js.map +7 -0
  12. package/dist/cjs/CacheSync.d.ts +112 -0
  13. package/dist/cjs/CacheSync.d.ts.map +1 -0
  14. package/dist/cjs/CacheSync.js +64 -0
  15. package/dist/cjs/CacheSync.js.map +7 -0
  16. package/dist/cjs/DeferredClockFold.d.ts +354 -0
  17. package/dist/cjs/DeferredClockFold.d.ts.map +1 -0
  18. package/dist/cjs/DeferredClockFold.js +335 -0
  19. package/dist/cjs/DeferredClockFold.js.map +7 -0
  20. package/dist/cjs/DisasterRecovery.d.ts +431 -0
  21. package/dist/cjs/DisasterRecovery.d.ts.map +1 -0
  22. package/dist/cjs/DisasterRecovery.js +453 -0
  23. package/dist/cjs/DisasterRecovery.js.map +7 -0
  24. package/dist/cjs/DurableEngineState.d.ts +776 -0
  25. package/dist/cjs/DurableEngineState.d.ts.map +1 -0
  26. package/dist/cjs/DurableEngineState.js +1536 -0
  27. package/dist/cjs/DurableEngineState.js.map +7 -0
  28. package/dist/cjs/EngineStore.d.ts +158 -0
  29. package/dist/cjs/EngineStore.d.ts.map +1 -0
  30. package/dist/cjs/EngineStore.js +398 -0
  31. package/dist/cjs/EngineStore.js.map +7 -0
  32. package/dist/cjs/EngineStoreMetrics.d.ts +276 -0
  33. package/dist/cjs/EngineStoreMetrics.d.ts.map +1 -0
  34. package/dist/cjs/EngineStoreMetrics.js +135 -0
  35. package/dist/cjs/EngineStoreMetrics.js.map +7 -0
  36. package/dist/cjs/Errors.d.ts +22 -0
  37. package/dist/cjs/Errors.d.ts.map +1 -0
  38. package/dist/cjs/Errors.js +39 -0
  39. package/dist/cjs/Errors.js.map +7 -0
  40. package/dist/cjs/EventTypes.d.ts +27 -0
  41. package/dist/cjs/EventTypes.d.ts.map +1 -0
  42. package/dist/cjs/EventTypes.js +37 -0
  43. package/dist/cjs/EventTypes.js.map +7 -0
  44. package/dist/cjs/ExecutionFacts.d.ts +59 -0
  45. package/dist/cjs/ExecutionFacts.d.ts.map +1 -0
  46. package/dist/cjs/ExecutionFacts.js +123 -0
  47. package/dist/cjs/ExecutionFacts.js.map +7 -0
  48. package/dist/cjs/ExecutionSnapshot.d.ts +117 -0
  49. package/dist/cjs/ExecutionSnapshot.d.ts.map +1 -0
  50. package/dist/cjs/ExecutionSnapshot.js +111 -0
  51. package/dist/cjs/ExecutionSnapshot.js.map +7 -0
  52. package/dist/cjs/Inconsistency.d.ts +154 -0
  53. package/dist/cjs/Inconsistency.d.ts.map +1 -0
  54. package/dist/cjs/Inconsistency.js +135 -0
  55. package/dist/cjs/Inconsistency.js.map +7 -0
  56. package/dist/cjs/Migrations.d.ts +56 -0
  57. package/dist/cjs/Migrations.d.ts.map +1 -0
  58. package/dist/cjs/Migrations.js +78 -0
  59. package/dist/cjs/Migrations.js.map +7 -0
  60. package/dist/cjs/OwnerIdentity.d.ts +91 -0
  61. package/dist/cjs/OwnerIdentity.d.ts.map +1 -0
  62. package/dist/cjs/OwnerIdentity.js +65 -0
  63. package/dist/cjs/OwnerIdentity.js.map +7 -0
  64. package/dist/cjs/PlanInputStore.d.ts +110 -0
  65. package/dist/cjs/PlanInputStore.d.ts.map +1 -0
  66. package/dist/cjs/PlanInputStore.js +224 -0
  67. package/dist/cjs/PlanInputStore.js.map +7 -0
  68. package/dist/cjs/PlanMergeStore.d.ts +113 -0
  69. package/dist/cjs/PlanMergeStore.d.ts.map +1 -0
  70. package/dist/cjs/PlanMergeStore.js +255 -0
  71. package/dist/cjs/PlanMergeStore.js.map +7 -0
  72. package/dist/cjs/PlanScheduler.d.ts +363 -0
  73. package/dist/cjs/PlanScheduler.d.ts.map +1 -0
  74. package/dist/cjs/PlanScheduler.js +1090 -0
  75. package/dist/cjs/PlanScheduler.js.map +7 -0
  76. package/dist/cjs/Reconciliation.d.ts +175 -0
  77. package/dist/cjs/Reconciliation.d.ts.map +1 -0
  78. package/dist/cjs/Reconciliation.js +119 -0
  79. package/dist/cjs/Reconciliation.js.map +7 -0
  80. package/dist/cjs/ReplayOnly.d.ts +91 -0
  81. package/dist/cjs/ReplayOnly.d.ts.map +1 -0
  82. package/dist/cjs/ReplayOnly.js +52 -0
  83. package/dist/cjs/ReplayOnly.js.map +7 -0
  84. package/dist/cjs/Retention.d.ts +113 -0
  85. package/dist/cjs/Retention.d.ts.map +1 -0
  86. package/dist/cjs/Retention.js +99 -0
  87. package/dist/cjs/Retention.js.map +7 -0
  88. package/dist/cjs/RunCatalogRead.d.ts +17 -0
  89. package/dist/cjs/RunCatalogRead.d.ts.map +1 -0
  90. package/dist/cjs/RunCatalogRead.js +33 -0
  91. package/dist/cjs/RunCatalogRead.js.map +7 -0
  92. package/dist/cjs/RunChangeFeed.d.ts +75 -0
  93. package/dist/cjs/RunChangeFeed.d.ts.map +1 -0
  94. package/dist/cjs/RunChangeFeed.js +96 -0
  95. package/dist/cjs/RunChangeFeed.js.map +7 -0
  96. package/dist/cjs/RunState.d.ts +116 -0
  97. package/dist/cjs/RunState.d.ts.map +1 -0
  98. package/dist/cjs/RunState.js +76 -0
  99. package/dist/cjs/RunState.js.map +7 -0
  100. package/dist/cjs/Selection.d.ts +495 -0
  101. package/dist/cjs/Selection.d.ts.map +1 -0
  102. package/dist/cjs/Selection.js +288 -0
  103. package/dist/cjs/Selection.js.map +7 -0
  104. package/dist/cjs/SelectionStore.d.ts +141 -0
  105. package/dist/cjs/SelectionStore.d.ts.map +1 -0
  106. package/dist/cjs/SelectionStore.js +229 -0
  107. package/dist/cjs/SelectionStore.js.map +7 -0
  108. package/dist/cjs/StepBoundary.d.ts +501 -0
  109. package/dist/cjs/StepBoundary.d.ts.map +1 -0
  110. package/dist/cjs/StepBoundary.js +619 -0
  111. package/dist/cjs/StepBoundary.js.map +7 -0
  112. package/dist/cjs/StepCacheFold.d.ts +148 -0
  113. package/dist/cjs/StepCacheFold.d.ts.map +1 -0
  114. package/dist/cjs/StepCacheFold.js +131 -0
  115. package/dist/cjs/StepCacheFold.js.map +7 -0
  116. package/dist/cjs/StepSandbox.d.ts +78 -0
  117. package/dist/cjs/StepSandbox.d.ts.map +1 -0
  118. package/dist/cjs/StepSandbox.js +75 -0
  119. package/dist/cjs/StepSandbox.js.map +7 -0
  120. package/dist/cjs/WakeBus.d.ts +116 -0
  121. package/dist/cjs/WakeBus.d.ts.map +1 -0
  122. package/dist/cjs/WakeBus.js +89 -0
  123. package/dist/cjs/WakeBus.js.map +7 -0
  124. package/dist/cjs/WorkspaceSandbox.d.ts +619 -0
  125. package/dist/cjs/WorkspaceSandbox.d.ts.map +1 -0
  126. package/dist/cjs/WorkspaceSandbox.js +711 -0
  127. package/dist/cjs/WorkspaceSandbox.js.map +7 -0
  128. package/dist/cjs/index.d.ts +157 -0
  129. package/dist/cjs/index.d.ts.map +1 -0
  130. package/dist/cjs/index.js +95 -0
  131. package/dist/cjs/index.js.map +7 -0
  132. package/dist/cjs/internal/ActionPersistence.d.ts +276 -0
  133. package/dist/cjs/internal/ActionPersistence.d.ts.map +1 -0
  134. package/dist/cjs/internal/ActionPersistence.js +1395 -0
  135. package/dist/cjs/internal/ActionPersistence.js.map +7 -0
  136. package/dist/cjs/internal/ArtifactRoots.d.ts +38 -0
  137. package/dist/cjs/internal/ArtifactRoots.d.ts.map +1 -0
  138. package/dist/cjs/internal/ArtifactRoots.js +89 -0
  139. package/dist/cjs/internal/ArtifactRoots.js.map +7 -0
  140. package/dist/cjs/internal/AttemptAdmission.d.ts +53 -0
  141. package/dist/cjs/internal/AttemptAdmission.d.ts.map +1 -0
  142. package/dist/cjs/internal/AttemptAdmission.js +52 -0
  143. package/dist/cjs/internal/AttemptAdmission.js.map +7 -0
  144. package/dist/cjs/internal/AttemptLifecycle.d.ts +245 -0
  145. package/dist/cjs/internal/AttemptLifecycle.d.ts.map +1 -0
  146. package/dist/cjs/internal/AttemptLifecycle.js +112 -0
  147. package/dist/cjs/internal/AttemptLifecycle.js.map +7 -0
  148. package/dist/cjs/internal/AttemptProbe.d.ts +53 -0
  149. package/dist/cjs/internal/AttemptProbe.d.ts.map +1 -0
  150. package/dist/cjs/internal/AttemptProbe.js +66 -0
  151. package/dist/cjs/internal/AttemptProbe.js.map +7 -0
  152. package/dist/cjs/internal/CacheAdmission.d.ts +79 -0
  153. package/dist/cjs/internal/CacheAdmission.d.ts.map +1 -0
  154. package/dist/cjs/internal/CacheAdmission.js +71 -0
  155. package/dist/cjs/internal/CacheAdmission.js.map +7 -0
  156. package/dist/cjs/internal/CacheAgeHistory.d.ts +27 -0
  157. package/dist/cjs/internal/CacheAgeHistory.d.ts.map +1 -0
  158. package/dist/cjs/internal/CacheAgeHistory.js +61 -0
  159. package/dist/cjs/internal/CacheAgeHistory.js.map +7 -0
  160. package/dist/cjs/internal/CacheAgeVerdicts.d.ts +15 -0
  161. package/dist/cjs/internal/CacheAgeVerdicts.d.ts.map +1 -0
  162. package/dist/cjs/internal/CacheAgeVerdicts.js +73 -0
  163. package/dist/cjs/internal/CacheAgeVerdicts.js.map +7 -0
  164. package/dist/cjs/internal/CacheOutputPolicy.d.ts +24 -0
  165. package/dist/cjs/internal/CacheOutputPolicy.d.ts.map +1 -0
  166. package/dist/cjs/internal/CacheOutputPolicy.js +75 -0
  167. package/dist/cjs/internal/CacheOutputPolicy.js.map +7 -0
  168. package/dist/cjs/internal/CachePublication.d.ts +97 -0
  169. package/dist/cjs/internal/CachePublication.d.ts.map +1 -0
  170. package/dist/cjs/internal/CachePublication.js +80 -0
  171. package/dist/cjs/internal/CachePublication.js.map +7 -0
  172. package/dist/cjs/internal/CallFacts.d.ts +15 -0
  173. package/dist/cjs/internal/CallFacts.d.ts.map +1 -0
  174. package/dist/cjs/internal/CallFacts.js +97 -0
  175. package/dist/cjs/internal/CallFacts.js.map +7 -0
  176. package/dist/cjs/internal/CopiedRecord.d.ts +61 -0
  177. package/dist/cjs/internal/CopiedRecord.d.ts.map +1 -0
  178. package/dist/cjs/internal/CopiedRecord.js +134 -0
  179. package/dist/cjs/internal/CopiedRecord.js.map +7 -0
  180. package/dist/cjs/internal/DeferredPersistence.d.ts +108 -0
  181. package/dist/cjs/internal/DeferredPersistence.d.ts.map +1 -0
  182. package/dist/cjs/internal/DeferredPersistence.js +270 -0
  183. package/dist/cjs/internal/DeferredPersistence.js.map +7 -0
  184. package/dist/cjs/internal/EffectRecords.d.ts +92 -0
  185. package/dist/cjs/internal/EffectRecords.d.ts.map +1 -0
  186. package/dist/cjs/internal/EffectRecords.js +63 -0
  187. package/dist/cjs/internal/EffectRecords.js.map +7 -0
  188. package/dist/cjs/internal/EngineJj.d.ts +30 -0
  189. package/dist/cjs/internal/EngineJj.d.ts.map +1 -0
  190. package/dist/cjs/internal/EngineJj.js +42 -0
  191. package/dist/cjs/internal/EngineJj.js.map +7 -0
  192. package/dist/cjs/internal/EngineStateSchema.d.ts +68 -0
  193. package/dist/cjs/internal/EngineStateSchema.d.ts.map +1 -0
  194. package/dist/cjs/internal/EngineStateSchema.js +58 -0
  195. package/dist/cjs/internal/EngineStateSchema.js.map +7 -0
  196. package/dist/cjs/internal/ExecutionSnapshotRead.d.ts +162 -0
  197. package/dist/cjs/internal/ExecutionSnapshotRead.d.ts.map +1 -0
  198. package/dist/cjs/internal/ExecutionSnapshotRead.js +199 -0
  199. package/dist/cjs/internal/ExecutionSnapshotRead.js.map +7 -0
  200. package/dist/cjs/internal/ExecutionSnapshotRelations.d.ts +39 -0
  201. package/dist/cjs/internal/ExecutionSnapshotRelations.d.ts.map +1 -0
  202. package/dist/cjs/internal/ExecutionSnapshotRelations.js +105 -0
  203. package/dist/cjs/internal/ExecutionSnapshotRelations.js.map +7 -0
  204. package/dist/cjs/internal/ExitEncoding.d.ts +180 -0
  205. package/dist/cjs/internal/ExitEncoding.d.ts.map +1 -0
  206. package/dist/cjs/internal/ExitEncoding.js +236 -0
  207. package/dist/cjs/internal/ExitEncoding.js.map +7 -0
  208. package/dist/cjs/internal/FileBoundarySnapshot.d.ts +14 -0
  209. package/dist/cjs/internal/FileBoundarySnapshot.d.ts.map +1 -0
  210. package/dist/cjs/internal/FileBoundarySnapshot.js +51 -0
  211. package/dist/cjs/internal/FileBoundarySnapshot.js.map +7 -0
  212. package/dist/cjs/internal/FileEnumeration.d.ts +127 -0
  213. package/dist/cjs/internal/FileEnumeration.d.ts.map +1 -0
  214. package/dist/cjs/internal/FileEnumeration.js +194 -0
  215. package/dist/cjs/internal/FileEnumeration.js.map +7 -0
  216. package/dist/cjs/internal/HostReflection.d.ts +80 -0
  217. package/dist/cjs/internal/HostReflection.d.ts.map +1 -0
  218. package/dist/cjs/internal/HostReflection.js +43 -0
  219. package/dist/cjs/internal/HostReflection.js.map +7 -0
  220. package/dist/cjs/internal/JournalRecords.d.ts +325 -0
  221. package/dist/cjs/internal/JournalRecords.d.ts.map +1 -0
  222. package/dist/cjs/internal/JournalRecords.js +122 -0
  223. package/dist/cjs/internal/JournalRecords.js.map +7 -0
  224. package/dist/cjs/internal/NodeJournal.d.ts +157 -0
  225. package/dist/cjs/internal/NodeJournal.d.ts.map +1 -0
  226. package/dist/cjs/internal/NodeJournal.js +192 -0
  227. package/dist/cjs/internal/NodeJournal.js.map +7 -0
  228. package/dist/cjs/internal/Ordering.d.ts +14 -0
  229. package/dist/cjs/internal/Ordering.d.ts.map +1 -0
  230. package/dist/cjs/internal/Ordering.js +25 -0
  231. package/dist/cjs/internal/Ordering.js.map +7 -0
  232. package/dist/cjs/internal/PlanInputs.d.ts +14 -0
  233. package/dist/cjs/internal/PlanInputs.d.ts.map +1 -0
  234. package/dist/cjs/internal/PlanInputs.js +78 -0
  235. package/dist/cjs/internal/PlanInputs.js.map +7 -0
  236. package/dist/cjs/internal/PlanMerges.d.ts +178 -0
  237. package/dist/cjs/internal/PlanMerges.d.ts.map +1 -0
  238. package/dist/cjs/internal/PlanMerges.js +125 -0
  239. package/dist/cjs/internal/PlanMerges.js.map +7 -0
  240. package/dist/cjs/internal/ProvenanceSlot.d.ts +30 -0
  241. package/dist/cjs/internal/ProvenanceSlot.d.ts.map +1 -0
  242. package/dist/cjs/internal/ProvenanceSlot.js +53 -0
  243. package/dist/cjs/internal/ProvenanceSlot.js.map +7 -0
  244. package/dist/cjs/internal/ResultEnvelope.d.ts +88 -0
  245. package/dist/cjs/internal/ResultEnvelope.d.ts.map +1 -0
  246. package/dist/cjs/internal/ResultEnvelope.js +90 -0
  247. package/dist/cjs/internal/ResultEnvelope.js.map +7 -0
  248. package/dist/cjs/internal/RetentionOps.d.ts +414 -0
  249. package/dist/cjs/internal/RetentionOps.d.ts.map +1 -0
  250. package/dist/cjs/internal/RetentionOps.js +354 -0
  251. package/dist/cjs/internal/RetentionOps.js.map +7 -0
  252. package/dist/cjs/internal/RunCatalogOps.d.ts +118 -0
  253. package/dist/cjs/internal/RunCatalogOps.d.ts.map +1 -0
  254. package/dist/cjs/internal/RunCatalogOps.js +85 -0
  255. package/dist/cjs/internal/RunCatalogOps.js.map +7 -0
  256. package/dist/cjs/internal/RunCoordinator.d.ts +78 -0
  257. package/dist/cjs/internal/RunCoordinator.d.ts.map +1 -0
  258. package/dist/cjs/internal/RunCoordinator.js +123 -0
  259. package/dist/cjs/internal/RunCoordinator.js.map +7 -0
  260. package/dist/cjs/internal/RunDriver.d.ts +192 -0
  261. package/dist/cjs/internal/RunDriver.d.ts.map +1 -0
  262. package/dist/cjs/internal/RunDriver.js +1584 -0
  263. package/dist/cjs/internal/RunDriver.js.map +7 -0
  264. package/dist/cjs/internal/RunLifecycle.d.ts +22 -0
  265. package/dist/cjs/internal/RunLifecycle.d.ts.map +1 -0
  266. package/dist/cjs/internal/RunLifecycle.js +63 -0
  267. package/dist/cjs/internal/RunLifecycle.js.map +7 -0
  268. package/dist/cjs/internal/RunListing.d.ts +78 -0
  269. package/dist/cjs/internal/RunListing.d.ts.map +1 -0
  270. package/dist/cjs/internal/RunListing.js +171 -0
  271. package/dist/cjs/internal/RunListing.js.map +7 -0
  272. package/dist/cjs/internal/RunListingError.d.ts +35 -0
  273. package/dist/cjs/internal/RunListingError.d.ts.map +1 -0
  274. package/dist/cjs/internal/RunListingError.js +47 -0
  275. package/dist/cjs/internal/RunListingError.js.map +7 -0
  276. package/dist/cjs/internal/RuntimeGraph.d.ts +73 -0
  277. package/dist/cjs/internal/RuntimeGraph.d.ts.map +1 -0
  278. package/dist/cjs/internal/RuntimeGraph.js +180 -0
  279. package/dist/cjs/internal/RuntimeGraph.js.map +7 -0
  280. package/dist/cjs/internal/SandboxedExecution.d.ts +80 -0
  281. package/dist/cjs/internal/SandboxedExecution.d.ts.map +1 -0
  282. package/dist/cjs/internal/SandboxedExecution.js +104 -0
  283. package/dist/cjs/internal/SandboxedExecution.js.map +7 -0
  284. package/dist/cjs/internal/StateTransaction.d.ts +44 -0
  285. package/dist/cjs/internal/StateTransaction.d.ts.map +1 -0
  286. package/dist/cjs/internal/StateTransaction.js +52 -0
  287. package/dist/cjs/internal/StateTransaction.js.map +7 -0
  288. package/dist/cjs/internal/StepFacts.d.ts +14 -0
  289. package/dist/cjs/internal/StepFacts.d.ts.map +1 -0
  290. package/dist/cjs/internal/StepFacts.js +58 -0
  291. package/dist/cjs/internal/StepFacts.js.map +7 -0
  292. package/dist/cjs/internal/TypedEvents.d.ts +14 -0
  293. package/dist/cjs/internal/TypedEvents.d.ts.map +1 -0
  294. package/dist/cjs/internal/TypedEvents.js +37 -0
  295. package/dist/cjs/internal/TypedEvents.js.map +7 -0
  296. package/dist/cjs/migrations/0001_initial.d.ts +17 -0
  297. package/dist/cjs/migrations/0001_initial.d.ts.map +1 -0
  298. package/dist/cjs/migrations/0001_initial.js +61 -0
  299. package/dist/cjs/migrations/0001_initial.js.map +7 -0
  300. package/dist/cjs/migrations/0002_selection_store.d.ts +15 -0
  301. package/dist/cjs/migrations/0002_selection_store.d.ts.map +1 -0
  302. package/dist/cjs/migrations/0002_selection_store.js +56 -0
  303. package/dist/cjs/migrations/0002_selection_store.js.map +7 -0
  304. package/dist/cjs/migrations/0003_plan_inputs.d.ts +13 -0
  305. package/dist/cjs/migrations/0003_plan_inputs.d.ts.map +1 -0
  306. package/dist/cjs/migrations/0003_plan_inputs.js +90 -0
  307. package/dist/cjs/migrations/0003_plan_inputs.js.map +7 -0
  308. package/dist/cjs/migrations/0004_plan_environment.d.ts +14 -0
  309. package/dist/cjs/migrations/0004_plan_environment.d.ts.map +1 -0
  310. package/dist/cjs/migrations/0004_plan_environment.js +56 -0
  311. package/dist/cjs/migrations/0004_plan_environment.js.map +7 -0
  312. package/dist/cjs/migrations/0005_plan_merges.d.ts +14 -0
  313. package/dist/cjs/migrations/0005_plan_merges.d.ts.map +1 -0
  314. package/dist/cjs/migrations/0005_plan_merges.js +82 -0
  315. package/dist/cjs/migrations/0005_plan_merges.js.map +7 -0
  316. package/dist/cjs/migrations/0006_execution_listing.d.ts +15 -0
  317. package/dist/cjs/migrations/0006_execution_listing.d.ts.map +1 -0
  318. package/dist/cjs/migrations/0006_execution_listing.js +101 -0
  319. package/dist/cjs/migrations/0006_execution_listing.js.map +7 -0
  320. package/dist/cjs/migrations/0007_run_parent_sequence.d.ts +15 -0
  321. package/dist/cjs/migrations/0007_run_parent_sequence.d.ts.map +1 -0
  322. package/dist/cjs/migrations/0007_run_parent_sequence.js +40 -0
  323. package/dist/cjs/migrations/0007_run_parent_sequence.js.map +7 -0
  324. package/dist/cjs/migrations/0008_deferred_consumption.d.ts +16 -0
  325. package/dist/cjs/migrations/0008_deferred_consumption.d.ts.map +1 -0
  326. package/dist/cjs/migrations/0008_deferred_consumption.js +45 -0
  327. package/dist/cjs/migrations/0008_deferred_consumption.js.map +7 -0
  328. package/dist/cjs/migrations/0009_deferred_clock_facts.d.ts +24 -0
  329. package/dist/cjs/migrations/0009_deferred_clock_facts.d.ts.map +1 -0
  330. package/dist/cjs/migrations/0009_deferred_clock_facts.js +141 -0
  331. package/dist/cjs/migrations/0009_deferred_clock_facts.js.map +7 -0
  332. package/dist/cjs/migrations/0010_pending_cancellation.d.ts +15 -0
  333. package/dist/cjs/migrations/0010_pending_cancellation.d.ts.map +1 -0
  334. package/dist/cjs/migrations/0010_pending_cancellation.js +41 -0
  335. package/dist/cjs/migrations/0010_pending_cancellation.js.map +7 -0
  336. package/dist/cjs/package.json +1 -0
  337. package/dist/cjs/test/TestStores.d.ts +89 -0
  338. package/dist/cjs/test/TestStores.d.ts.map +1 -0
  339. package/dist/cjs/test/TestStores.js +98 -0
  340. package/dist/cjs/test/TestStores.js.map +7 -0
  341. package/dist/esm/ArtifactGc.d.ts +235 -0
  342. package/dist/esm/ArtifactGc.d.ts.map +1 -0
  343. package/dist/esm/ArtifactGc.js +268 -0
  344. package/dist/esm/ArtifactGc.js.map +1 -0
  345. package/dist/esm/ArtifactSync.d.ts +164 -0
  346. package/dist/esm/ArtifactSync.d.ts.map +1 -0
  347. package/dist/esm/ArtifactSync.js +176 -0
  348. package/dist/esm/ArtifactSync.js.map +1 -0
  349. package/dist/esm/CacheSync.d.ts +112 -0
  350. package/dist/esm/CacheSync.d.ts.map +1 -0
  351. package/dist/esm/CacheSync.js +94 -0
  352. package/dist/esm/CacheSync.js.map +1 -0
  353. package/dist/esm/DeferredClockFold.d.ts +354 -0
  354. package/dist/esm/DeferredClockFold.d.ts.map +1 -0
  355. package/dist/esm/DeferredClockFold.js +472 -0
  356. package/dist/esm/DeferredClockFold.js.map +1 -0
  357. package/dist/esm/DisasterRecovery.d.ts +431 -0
  358. package/dist/esm/DisasterRecovery.d.ts.map +1 -0
  359. package/dist/esm/DisasterRecovery.js +523 -0
  360. package/dist/esm/DisasterRecovery.js.map +1 -0
  361. package/dist/esm/DurableEngineState.d.ts +776 -0
  362. package/dist/esm/DurableEngineState.d.ts.map +1 -0
  363. package/dist/esm/DurableEngineState.js +1648 -0
  364. package/dist/esm/DurableEngineState.js.map +1 -0
  365. package/dist/esm/EngineStore.d.ts +158 -0
  366. package/dist/esm/EngineStore.d.ts.map +1 -0
  367. package/dist/esm/EngineStore.js +403 -0
  368. package/dist/esm/EngineStore.js.map +1 -0
  369. package/dist/esm/EngineStoreMetrics.d.ts +276 -0
  370. package/dist/esm/EngineStoreMetrics.d.ts.map +1 -0
  371. package/dist/esm/EngineStoreMetrics.js +260 -0
  372. package/dist/esm/EngineStoreMetrics.js.map +1 -0
  373. package/dist/esm/Errors.d.ts +22 -0
  374. package/dist/esm/Errors.d.ts.map +1 -0
  375. package/dist/esm/Errors.js +22 -0
  376. package/dist/esm/Errors.js.map +1 -0
  377. package/dist/esm/EventTypes.d.ts +27 -0
  378. package/dist/esm/EventTypes.d.ts.map +1 -0
  379. package/dist/esm/EventTypes.js +27 -0
  380. package/dist/esm/EventTypes.js.map +1 -0
  381. package/dist/esm/ExecutionFacts.d.ts +59 -0
  382. package/dist/esm/ExecutionFacts.d.ts.map +1 -0
  383. package/dist/esm/ExecutionFacts.js +96 -0
  384. package/dist/esm/ExecutionFacts.js.map +1 -0
  385. package/dist/esm/ExecutionSnapshot.d.ts +117 -0
  386. package/dist/esm/ExecutionSnapshot.d.ts.map +1 -0
  387. package/dist/esm/ExecutionSnapshot.js +95 -0
  388. package/dist/esm/ExecutionSnapshot.js.map +1 -0
  389. package/dist/esm/Inconsistency.d.ts +154 -0
  390. package/dist/esm/Inconsistency.d.ts.map +1 -0
  391. package/dist/esm/Inconsistency.js +133 -0
  392. package/dist/esm/Inconsistency.js.map +1 -0
  393. package/dist/esm/Migrations.d.ts +56 -0
  394. package/dist/esm/Migrations.d.ts.map +1 -0
  395. package/dist/esm/Migrations.js +91 -0
  396. package/dist/esm/Migrations.js.map +1 -0
  397. package/dist/esm/OwnerIdentity.d.ts +91 -0
  398. package/dist/esm/OwnerIdentity.d.ts.map +1 -0
  399. package/dist/esm/OwnerIdentity.js +99 -0
  400. package/dist/esm/OwnerIdentity.js.map +1 -0
  401. package/dist/esm/PlanInputStore.d.ts +110 -0
  402. package/dist/esm/PlanInputStore.d.ts.map +1 -0
  403. package/dist/esm/PlanInputStore.js +207 -0
  404. package/dist/esm/PlanInputStore.js.map +1 -0
  405. package/dist/esm/PlanMergeStore.d.ts +113 -0
  406. package/dist/esm/PlanMergeStore.d.ts.map +1 -0
  407. package/dist/esm/PlanMergeStore.js +244 -0
  408. package/dist/esm/PlanMergeStore.js.map +1 -0
  409. package/dist/esm/PlanScheduler.d.ts +363 -0
  410. package/dist/esm/PlanScheduler.d.ts.map +1 -0
  411. package/dist/esm/PlanScheduler.js +1321 -0
  412. package/dist/esm/PlanScheduler.js.map +1 -0
  413. package/dist/esm/Reconciliation.d.ts +175 -0
  414. package/dist/esm/Reconciliation.d.ts.map +1 -0
  415. package/dist/esm/Reconciliation.js +175 -0
  416. package/dist/esm/Reconciliation.js.map +1 -0
  417. package/dist/esm/ReplayOnly.d.ts +91 -0
  418. package/dist/esm/ReplayOnly.d.ts.map +1 -0
  419. package/dist/esm/ReplayOnly.js +59 -0
  420. package/dist/esm/ReplayOnly.js.map +1 -0
  421. package/dist/esm/Retention.d.ts +113 -0
  422. package/dist/esm/Retention.d.ts.map +1 -0
  423. package/dist/esm/Retention.js +139 -0
  424. package/dist/esm/Retention.js.map +1 -0
  425. package/dist/esm/RunCatalogRead.d.ts +17 -0
  426. package/dist/esm/RunCatalogRead.d.ts.map +1 -0
  427. package/dist/esm/RunCatalogRead.js +17 -0
  428. package/dist/esm/RunCatalogRead.js.map +1 -0
  429. package/dist/esm/RunChangeFeed.d.ts +75 -0
  430. package/dist/esm/RunChangeFeed.d.ts.map +1 -0
  431. package/dist/esm/RunChangeFeed.js +81 -0
  432. package/dist/esm/RunChangeFeed.js.map +1 -0
  433. package/dist/esm/RunState.d.ts +116 -0
  434. package/dist/esm/RunState.d.ts.map +1 -0
  435. package/dist/esm/RunState.js +109 -0
  436. package/dist/esm/RunState.js.map +1 -0
  437. package/dist/esm/Selection.d.ts +495 -0
  438. package/dist/esm/Selection.d.ts.map +1 -0
  439. package/dist/esm/Selection.js +482 -0
  440. package/dist/esm/Selection.js.map +1 -0
  441. package/dist/esm/SelectionStore.d.ts +141 -0
  442. package/dist/esm/SelectionStore.d.ts.map +1 -0
  443. package/dist/esm/SelectionStore.js +215 -0
  444. package/dist/esm/SelectionStore.js.map +1 -0
  445. package/dist/esm/StepBoundary.d.ts +501 -0
  446. package/dist/esm/StepBoundary.d.ts.map +1 -0
  447. package/dist/esm/StepBoundary.js +919 -0
  448. package/dist/esm/StepBoundary.js.map +1 -0
  449. package/dist/esm/StepCacheFold.d.ts +148 -0
  450. package/dist/esm/StepCacheFold.d.ts.map +1 -0
  451. package/dist/esm/StepCacheFold.js +201 -0
  452. package/dist/esm/StepCacheFold.js.map +1 -0
  453. package/dist/esm/StepSandbox.d.ts +78 -0
  454. package/dist/esm/StepSandbox.d.ts.map +1 -0
  455. package/dist/esm/StepSandbox.js +70 -0
  456. package/dist/esm/StepSandbox.js.map +1 -0
  457. package/dist/esm/WakeBus.d.ts +116 -0
  458. package/dist/esm/WakeBus.d.ts.map +1 -0
  459. package/dist/esm/WakeBus.js +121 -0
  460. package/dist/esm/WakeBus.js.map +1 -0
  461. package/dist/esm/WorkspaceSandbox.d.ts +619 -0
  462. package/dist/esm/WorkspaceSandbox.d.ts.map +1 -0
  463. package/dist/esm/WorkspaceSandbox.js +985 -0
  464. package/dist/esm/WorkspaceSandbox.js.map +1 -0
  465. package/dist/esm/index.d.ts +157 -0
  466. package/dist/esm/index.d.ts.map +1 -0
  467. package/dist/esm/index.js +157 -0
  468. package/dist/esm/index.js.map +1 -0
  469. package/dist/esm/internal/ActionPersistence.d.ts +276 -0
  470. package/dist/esm/internal/ActionPersistence.d.ts.map +1 -0
  471. package/dist/esm/internal/ActionPersistence.js +2306 -0
  472. package/dist/esm/internal/ActionPersistence.js.map +1 -0
  473. package/dist/esm/internal/ArtifactRoots.d.ts +38 -0
  474. package/dist/esm/internal/ArtifactRoots.d.ts.map +1 -0
  475. package/dist/esm/internal/ArtifactRoots.js +76 -0
  476. package/dist/esm/internal/ArtifactRoots.js.map +1 -0
  477. package/dist/esm/internal/AttemptAdmission.d.ts +53 -0
  478. package/dist/esm/internal/AttemptAdmission.d.ts.map +1 -0
  479. package/dist/esm/internal/AttemptAdmission.js +52 -0
  480. package/dist/esm/internal/AttemptAdmission.js.map +1 -0
  481. package/dist/esm/internal/AttemptLifecycle.d.ts +245 -0
  482. package/dist/esm/internal/AttemptLifecycle.d.ts.map +1 -0
  483. package/dist/esm/internal/AttemptLifecycle.js +104 -0
  484. package/dist/esm/internal/AttemptLifecycle.js.map +1 -0
  485. package/dist/esm/internal/AttemptProbe.d.ts +53 -0
  486. package/dist/esm/internal/AttemptProbe.d.ts.map +1 -0
  487. package/dist/esm/internal/AttemptProbe.js +83 -0
  488. package/dist/esm/internal/AttemptProbe.js.map +1 -0
  489. package/dist/esm/internal/CacheAdmission.d.ts +79 -0
  490. package/dist/esm/internal/CacheAdmission.d.ts.map +1 -0
  491. package/dist/esm/internal/CacheAdmission.js +72 -0
  492. package/dist/esm/internal/CacheAdmission.js.map +1 -0
  493. package/dist/esm/internal/CacheAgeHistory.d.ts +27 -0
  494. package/dist/esm/internal/CacheAgeHistory.d.ts.map +1 -0
  495. package/dist/esm/internal/CacheAgeHistory.js +49 -0
  496. package/dist/esm/internal/CacheAgeHistory.js.map +1 -0
  497. package/dist/esm/internal/CacheAgeVerdicts.d.ts +15 -0
  498. package/dist/esm/internal/CacheAgeVerdicts.d.ts.map +1 -0
  499. package/dist/esm/internal/CacheAgeVerdicts.js +54 -0
  500. package/dist/esm/internal/CacheAgeVerdicts.js.map +1 -0
  501. package/dist/esm/internal/CacheOutputPolicy.d.ts +24 -0
  502. package/dist/esm/internal/CacheOutputPolicy.d.ts.map +1 -0
  503. package/dist/esm/internal/CacheOutputPolicy.js +73 -0
  504. package/dist/esm/internal/CacheOutputPolicy.js.map +1 -0
  505. package/dist/esm/internal/CachePublication.d.ts +97 -0
  506. package/dist/esm/internal/CachePublication.d.ts.map +1 -0
  507. package/dist/esm/internal/CachePublication.js +116 -0
  508. package/dist/esm/internal/CachePublication.js.map +1 -0
  509. package/dist/esm/internal/CallFacts.d.ts +15 -0
  510. package/dist/esm/internal/CallFacts.d.ts.map +1 -0
  511. package/dist/esm/internal/CallFacts.js +83 -0
  512. package/dist/esm/internal/CallFacts.js.map +1 -0
  513. package/dist/esm/internal/CopiedRecord.d.ts +61 -0
  514. package/dist/esm/internal/CopiedRecord.d.ts.map +1 -0
  515. package/dist/esm/internal/CopiedRecord.js +165 -0
  516. package/dist/esm/internal/CopiedRecord.js.map +1 -0
  517. package/dist/esm/internal/DeferredPersistence.d.ts +108 -0
  518. package/dist/esm/internal/DeferredPersistence.d.ts.map +1 -0
  519. package/dist/esm/internal/DeferredPersistence.js +240 -0
  520. package/dist/esm/internal/DeferredPersistence.js.map +1 -0
  521. package/dist/esm/internal/EffectRecords.d.ts +92 -0
  522. package/dist/esm/internal/EffectRecords.d.ts.map +1 -0
  523. package/dist/esm/internal/EffectRecords.js +94 -0
  524. package/dist/esm/internal/EffectRecords.js.map +1 -0
  525. package/dist/esm/internal/EngineJj.d.ts +30 -0
  526. package/dist/esm/internal/EngineJj.d.ts.map +1 -0
  527. package/dist/esm/internal/EngineJj.js +29 -0
  528. package/dist/esm/internal/EngineJj.js.map +1 -0
  529. package/dist/esm/internal/EngineStateSchema.d.ts +68 -0
  530. package/dist/esm/internal/EngineStateSchema.d.ts.map +1 -0
  531. package/dist/esm/internal/EngineStateSchema.js +53 -0
  532. package/dist/esm/internal/EngineStateSchema.js.map +1 -0
  533. package/dist/esm/internal/ExecutionSnapshotRead.d.ts +162 -0
  534. package/dist/esm/internal/ExecutionSnapshotRead.d.ts.map +1 -0
  535. package/dist/esm/internal/ExecutionSnapshotRead.js +218 -0
  536. package/dist/esm/internal/ExecutionSnapshotRead.js.map +1 -0
  537. package/dist/esm/internal/ExecutionSnapshotRelations.d.ts +39 -0
  538. package/dist/esm/internal/ExecutionSnapshotRelations.d.ts.map +1 -0
  539. package/dist/esm/internal/ExecutionSnapshotRelations.js +81 -0
  540. package/dist/esm/internal/ExecutionSnapshotRelations.js.map +1 -0
  541. package/dist/esm/internal/ExitEncoding.d.ts +180 -0
  542. package/dist/esm/internal/ExitEncoding.d.ts.map +1 -0
  543. package/dist/esm/internal/ExitEncoding.js +361 -0
  544. package/dist/esm/internal/ExitEncoding.js.map +1 -0
  545. package/dist/esm/internal/FileBoundarySnapshot.d.ts +14 -0
  546. package/dist/esm/internal/FileBoundarySnapshot.d.ts.map +1 -0
  547. package/dist/esm/internal/FileBoundarySnapshot.js +29 -0
  548. package/dist/esm/internal/FileBoundarySnapshot.js.map +1 -0
  549. package/dist/esm/internal/FileEnumeration.d.ts +127 -0
  550. package/dist/esm/internal/FileEnumeration.d.ts.map +1 -0
  551. package/dist/esm/internal/FileEnumeration.js +236 -0
  552. package/dist/esm/internal/FileEnumeration.js.map +1 -0
  553. package/dist/esm/internal/HostReflection.d.ts +80 -0
  554. package/dist/esm/internal/HostReflection.d.ts.map +1 -0
  555. package/dist/esm/internal/HostReflection.js +98 -0
  556. package/dist/esm/internal/HostReflection.js.map +1 -0
  557. package/dist/esm/internal/JournalRecords.d.ts +325 -0
  558. package/dist/esm/internal/JournalRecords.d.ts.map +1 -0
  559. package/dist/esm/internal/JournalRecords.js +306 -0
  560. package/dist/esm/internal/JournalRecords.js.map +1 -0
  561. package/dist/esm/internal/NodeJournal.d.ts +157 -0
  562. package/dist/esm/internal/NodeJournal.d.ts.map +1 -0
  563. package/dist/esm/internal/NodeJournal.js +298 -0
  564. package/dist/esm/internal/NodeJournal.js.map +1 -0
  565. package/dist/esm/internal/Ordering.d.ts +14 -0
  566. package/dist/esm/internal/Ordering.d.ts.map +1 -0
  567. package/dist/esm/internal/Ordering.js +14 -0
  568. package/dist/esm/internal/Ordering.js.map +1 -0
  569. package/dist/esm/internal/PlanInputs.d.ts +14 -0
  570. package/dist/esm/internal/PlanInputs.d.ts.map +1 -0
  571. package/dist/esm/internal/PlanInputs.js +57 -0
  572. package/dist/esm/internal/PlanInputs.js.map +1 -0
  573. package/dist/esm/internal/PlanMerges.d.ts +178 -0
  574. package/dist/esm/internal/PlanMerges.d.ts.map +1 -0
  575. package/dist/esm/internal/PlanMerges.js +113 -0
  576. package/dist/esm/internal/PlanMerges.js.map +1 -0
  577. package/dist/esm/internal/ProvenanceSlot.d.ts +30 -0
  578. package/dist/esm/internal/ProvenanceSlot.d.ts.map +1 -0
  579. package/dist/esm/internal/ProvenanceSlot.js +39 -0
  580. package/dist/esm/internal/ProvenanceSlot.js.map +1 -0
  581. package/dist/esm/internal/ResultEnvelope.d.ts +88 -0
  582. package/dist/esm/internal/ResultEnvelope.d.ts.map +1 -0
  583. package/dist/esm/internal/ResultEnvelope.js +83 -0
  584. package/dist/esm/internal/ResultEnvelope.js.map +1 -0
  585. package/dist/esm/internal/RetentionOps.d.ts +414 -0
  586. package/dist/esm/internal/RetentionOps.d.ts.map +1 -0
  587. package/dist/esm/internal/RetentionOps.js +576 -0
  588. package/dist/esm/internal/RetentionOps.js.map +1 -0
  589. package/dist/esm/internal/RunCatalogOps.d.ts +118 -0
  590. package/dist/esm/internal/RunCatalogOps.d.ts.map +1 -0
  591. package/dist/esm/internal/RunCatalogOps.js +120 -0
  592. package/dist/esm/internal/RunCatalogOps.js.map +1 -0
  593. package/dist/esm/internal/RunCoordinator.d.ts +78 -0
  594. package/dist/esm/internal/RunCoordinator.d.ts.map +1 -0
  595. package/dist/esm/internal/RunCoordinator.js +115 -0
  596. package/dist/esm/internal/RunCoordinator.js.map +1 -0
  597. package/dist/esm/internal/RunDriver.d.ts +192 -0
  598. package/dist/esm/internal/RunDriver.d.ts.map +1 -0
  599. package/dist/esm/internal/RunDriver.js +2334 -0
  600. package/dist/esm/internal/RunDriver.js.map +1 -0
  601. package/dist/esm/internal/RunLifecycle.d.ts +22 -0
  602. package/dist/esm/internal/RunLifecycle.d.ts.map +1 -0
  603. package/dist/esm/internal/RunLifecycle.js +49 -0
  604. package/dist/esm/internal/RunLifecycle.js.map +1 -0
  605. package/dist/esm/internal/RunListing.d.ts +78 -0
  606. package/dist/esm/internal/RunListing.d.ts.map +1 -0
  607. package/dist/esm/internal/RunListing.js +146 -0
  608. package/dist/esm/internal/RunListing.js.map +1 -0
  609. package/dist/esm/internal/RunListingError.d.ts +35 -0
  610. package/dist/esm/internal/RunListingError.d.ts.map +1 -0
  611. package/dist/esm/internal/RunListingError.js +27 -0
  612. package/dist/esm/internal/RunListingError.js.map +1 -0
  613. package/dist/esm/internal/RuntimeGraph.d.ts +73 -0
  614. package/dist/esm/internal/RuntimeGraph.d.ts.map +1 -0
  615. package/dist/esm/internal/RuntimeGraph.js +182 -0
  616. package/dist/esm/internal/RuntimeGraph.js.map +1 -0
  617. package/dist/esm/internal/SandboxedExecution.d.ts +80 -0
  618. package/dist/esm/internal/SandboxedExecution.d.ts.map +1 -0
  619. package/dist/esm/internal/SandboxedExecution.js +107 -0
  620. package/dist/esm/internal/SandboxedExecution.js.map +1 -0
  621. package/dist/esm/internal/StateTransaction.d.ts +44 -0
  622. package/dist/esm/internal/StateTransaction.d.ts.map +1 -0
  623. package/dist/esm/internal/StateTransaction.js +54 -0
  624. package/dist/esm/internal/StateTransaction.js.map +1 -0
  625. package/dist/esm/internal/StepFacts.d.ts +14 -0
  626. package/dist/esm/internal/StepFacts.d.ts.map +1 -0
  627. package/dist/esm/internal/StepFacts.js +35 -0
  628. package/dist/esm/internal/StepFacts.js.map +1 -0
  629. package/dist/esm/internal/TypedEvents.d.ts +14 -0
  630. package/dist/esm/internal/TypedEvents.d.ts.map +1 -0
  631. package/dist/esm/internal/TypedEvents.js +14 -0
  632. package/dist/esm/internal/TypedEvents.js.map +1 -0
  633. package/dist/esm/migrations/0001_initial.d.ts +17 -0
  634. package/dist/esm/migrations/0001_initial.d.ts.map +1 -0
  635. package/dist/esm/migrations/0001_initial.js +41 -0
  636. package/dist/esm/migrations/0001_initial.js.map +1 -0
  637. package/dist/esm/migrations/0002_selection_store.d.ts +15 -0
  638. package/dist/esm/migrations/0002_selection_store.d.ts.map +1 -0
  639. package/dist/esm/migrations/0002_selection_store.js +34 -0
  640. package/dist/esm/migrations/0002_selection_store.js.map +1 -0
  641. package/dist/esm/migrations/0003_plan_inputs.d.ts +13 -0
  642. package/dist/esm/migrations/0003_plan_inputs.d.ts.map +1 -0
  643. package/dist/esm/migrations/0003_plan_inputs.js +70 -0
  644. package/dist/esm/migrations/0003_plan_inputs.js.map +1 -0
  645. package/dist/esm/migrations/0004_plan_environment.d.ts +14 -0
  646. package/dist/esm/migrations/0004_plan_environment.d.ts.map +1 -0
  647. package/dist/esm/migrations/0004_plan_environment.js +33 -0
  648. package/dist/esm/migrations/0004_plan_environment.js.map +1 -0
  649. package/dist/esm/migrations/0005_plan_merges.d.ts +14 -0
  650. package/dist/esm/migrations/0005_plan_merges.d.ts.map +1 -0
  651. package/dist/esm/migrations/0005_plan_merges.js +59 -0
  652. package/dist/esm/migrations/0005_plan_merges.js.map +1 -0
  653. package/dist/esm/migrations/0006_execution_listing.d.ts +15 -0
  654. package/dist/esm/migrations/0006_execution_listing.d.ts.map +1 -0
  655. package/dist/esm/migrations/0006_execution_listing.js +81 -0
  656. package/dist/esm/migrations/0006_execution_listing.js.map +1 -0
  657. package/dist/esm/migrations/0007_run_parent_sequence.d.ts +15 -0
  658. package/dist/esm/migrations/0007_run_parent_sequence.d.ts.map +1 -0
  659. package/dist/esm/migrations/0007_run_parent_sequence.js +18 -0
  660. package/dist/esm/migrations/0007_run_parent_sequence.js.map +1 -0
  661. package/dist/esm/migrations/0008_deferred_consumption.d.ts +16 -0
  662. package/dist/esm/migrations/0008_deferred_consumption.d.ts.map +1 -0
  663. package/dist/esm/migrations/0008_deferred_consumption.js +24 -0
  664. package/dist/esm/migrations/0008_deferred_consumption.js.map +1 -0
  665. package/dist/esm/migrations/0009_deferred_clock_facts.d.ts +24 -0
  666. package/dist/esm/migrations/0009_deferred_clock_facts.d.ts.map +1 -0
  667. package/dist/esm/migrations/0009_deferred_clock_facts.js +127 -0
  668. package/dist/esm/migrations/0009_deferred_clock_facts.js.map +1 -0
  669. package/dist/esm/migrations/0010_pending_cancellation.d.ts +15 -0
  670. package/dist/esm/migrations/0010_pending_cancellation.d.ts.map +1 -0
  671. package/dist/esm/migrations/0010_pending_cancellation.js +19 -0
  672. package/dist/esm/migrations/0010_pending_cancellation.js.map +1 -0
  673. package/dist/esm/test/TestStores.d.ts +89 -0
  674. package/dist/esm/test/TestStores.d.ts.map +1 -0
  675. package/dist/esm/test/TestStores.js +103 -0
  676. package/dist/esm/test/TestStores.js.map +1 -0
  677. package/docs/README.md +113 -0
  678. package/docs/api.md +1494 -0
  679. package/docs/concepts/attempts-and-replay.md +149 -0
  680. package/docs/concepts/cache-admission.md +265 -0
  681. package/docs/concepts/call-facts.md +86 -0
  682. package/docs/concepts/durable-waits.md +175 -0
  683. package/docs/concepts/execution-facts.md +90 -0
  684. package/docs/concepts/ownership-and-fencing.md +128 -0
  685. package/docs/concepts/step-boundaries.md +148 -0
  686. package/docs/concepts/workspace-transactions.md +199 -0
  687. package/docs/event-types.md +14 -0
  688. package/docs/guides/back-up-and-restore.md +164 -0
  689. package/docs/guides/collect-unreferenced-artifacts.md +128 -0
  690. package/docs/guides/compose-a-durable-engine.md +146 -0
  691. package/docs/guides/coordinate-two-processes.md +120 -0
  692. package/docs/guides/defer-work-with-selection.md +171 -0
  693. package/docs/guides/delete-old-run-history.md +154 -0
  694. package/docs/guides/drive-a-plan.md +314 -0
  695. package/docs/guides/observe-engine-metrics.md +98 -0
  696. package/docs/guides/observe-executions.md +187 -0
  697. package/docs/guides/reclaim-runs-from-a-dead-host.md +133 -0
  698. package/docs/guides/share-a-cache-across-machines.md +134 -0
  699. package/docs/guides/testing.md +123 -0
  700. package/docs/installation.md +102 -0
  701. package/docs/quickstart.md +215 -0
  702. package/docs/troubleshooting.md +347 -0
  703. package/package.json +438 -3
  704. package/src/ArtifactGc.ts +408 -0
  705. package/src/ArtifactSync.ts +278 -0
  706. package/src/CacheSync.ts +131 -0
  707. package/src/DeferredClockFold.ts +586 -0
  708. package/src/DisasterRecovery.ts +888 -0
  709. package/src/DurableEngineState.ts +2656 -0
  710. package/src/EngineStore.ts +656 -0
  711. package/src/EngineStoreMetrics.ts +331 -0
  712. package/src/Errors.ts +28 -0
  713. package/src/EventTypes.ts +27 -0
  714. package/src/ExecutionFacts.ts +125 -0
  715. package/src/ExecutionSnapshot.ts +186 -0
  716. package/src/Inconsistency.ts +253 -0
  717. package/src/Migrations.ts +95 -0
  718. package/src/OwnerIdentity.ts +125 -0
  719. package/src/PlanInputStore.ts +292 -0
  720. package/src/PlanMergeStore.ts +330 -0
  721. package/src/PlanScheduler.ts +1806 -0
  722. package/src/Reconciliation.ts +224 -0
  723. package/src/ReplayOnly.ts +95 -0
  724. package/src/Retention.ts +214 -0
  725. package/src/RunCatalogRead.ts +27 -0
  726. package/src/RunChangeFeed.ts +125 -0
  727. package/src/RunState.ts +137 -0
  728. package/src/Selection.ts +683 -0
  729. package/src/SelectionStore.ts +353 -0
  730. package/src/StepBoundary.ts +1165 -0
  731. package/src/StepCacheFold.ts +244 -0
  732. package/src/StepSandbox.ts +110 -0
  733. package/src/WakeBus.ts +167 -0
  734. package/src/WorkspaceSandbox.ts +1604 -0
  735. package/src/index.ts +185 -0
  736. package/src/internal/ActionPersistence.ts +2687 -0
  737. package/src/internal/ArtifactRoots.ts +92 -0
  738. package/src/internal/AttemptAdmission.ts +76 -0
  739. package/src/internal/AttemptLifecycle.ts +163 -0
  740. package/src/internal/AttemptProbe.ts +90 -0
  741. package/src/internal/CacheAdmission.ts +133 -0
  742. package/src/internal/CacheAgeHistory.ts +58 -0
  743. package/src/internal/CacheAgeVerdicts.ts +61 -0
  744. package/src/internal/CacheOutputPolicy.ts +82 -0
  745. package/src/internal/CachePublication.ts +153 -0
  746. package/src/internal/CallFacts.ts +87 -0
  747. package/src/internal/CopiedRecord.ts +201 -0
  748. package/src/internal/DeferredPersistence.ts +459 -0
  749. package/src/internal/EffectRecords.ts +136 -0
  750. package/src/internal/EngineJj.ts +30 -0
  751. package/src/internal/EngineStateSchema.ts +92 -0
  752. package/src/internal/ExecutionSnapshotRead.ts +298 -0
  753. package/src/internal/ExecutionSnapshotRelations.ts +121 -0
  754. package/src/internal/ExitEncoding.ts +453 -0
  755. package/src/internal/FileBoundarySnapshot.ts +39 -0
  756. package/src/internal/FileEnumeration.ts +334 -0
  757. package/src/internal/HostReflection.ts +128 -0
  758. package/src/internal/JournalRecords.ts +396 -0
  759. package/src/internal/NodeJournal.ts +340 -0
  760. package/src/internal/Ordering.ts +14 -0
  761. package/src/internal/PlanInputs.ts +62 -0
  762. package/src/internal/PlanMerges.ts +123 -0
  763. package/src/internal/ProvenanceSlot.ts +52 -0
  764. package/src/internal/ResultEnvelope.ts +118 -0
  765. package/src/internal/RetentionOps.ts +865 -0
  766. package/src/internal/RunCatalogOps.ts +174 -0
  767. package/src/internal/RunCoordinator.ts +215 -0
  768. package/src/internal/RunDriver.ts +3152 -0
  769. package/src/internal/RunLifecycle.ts +53 -0
  770. package/src/internal/RunListing.ts +210 -0
  771. package/src/internal/RunListingError.ts +37 -0
  772. package/src/internal/RuntimeGraph.ts +253 -0
  773. package/src/internal/SandboxedExecution.ts +165 -0
  774. package/src/internal/StateTransaction.ts +71 -0
  775. package/src/internal/StepFacts.ts +36 -0
  776. package/src/internal/TypedEvents.ts +29 -0
  777. package/src/migrations/0001_initial.ts +51 -0
  778. package/src/migrations/0002_selection_store.ts +38 -0
  779. package/src/migrations/0003_plan_inputs.ts +75 -0
  780. package/src/migrations/0004_plan_environment.ts +34 -0
  781. package/src/migrations/0005_plan_merges.ts +60 -0
  782. package/src/migrations/0006_execution_listing.ts +86 -0
  783. package/src/migrations/0007_run_parent_sequence.ts +19 -0
  784. package/src/migrations/0008_deferred_consumption.ts +27 -0
  785. package/src/migrations/0009_deferred_clock_facts.ts +163 -0
  786. package/src/migrations/0010_pending_cancellation.ts +20 -0
  787. package/src/test/TestStores.ts +145 -0
package/docs/api.md ADDED
@@ -0,0 +1,1494 @@
1
+ ---
2
+ title: "API reference"
3
+ description: "Every public export of @smthrs/engine-store, grouped by namespace: services, layers, constructors, options, schemas, constants, and the stable error codes."
4
+ ---
5
+
6
+ The durable `FlowEngine`. It claims a run before driving it, fences every write
7
+ against the current owner, and persists attempts, waits, and terminal results
8
+ through [`@smthrs/journal`](/api/journal),
9
+ [`@smthrs/run-store`](/api/run-store), and
10
+ [`@smthrs/step-cache`](/api/step-cache). It owns the durable deferred and clock
11
+ tables and composes every package's migration set.
12
+
13
+ ```ts
14
+ import { EngineStore, StepBoundary } from "@smthrs/engine-store"
15
+
16
+ const engine = EngineStore.layer({
17
+ owner: { hostId: "worker-a" },
18
+ journalSource: "worker-a"
19
+ })
20
+ ```
21
+
22
+ ## Entry point
23
+
24
+ | Import | Source | Platform |
25
+ | ---------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------- |
26
+ | `@smthrs/engine-store` | [src/index.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/index.ts) | Node and browser |
27
+
28
+ Every namespace below is also importable from `@smthrs/engine-store/<Module>`.
29
+ `@smthrs/engine-store/internal/*`, `@smthrs/engine-store/migrations/*`, and
30
+ `@smthrs/engine-store/*/index` are blocked in the export map.
31
+
32
+ Shared versioned event schemas are public at `@smthrs/journal/EngineEvent`; see
33
+ [state and event authority](https://journal.smithers.sh/concepts/state-event-authority/).
34
+ Engine adapters `TypedEvents`, `AttemptLifecycle`, and `ResultEnvelope` remain
35
+ internal. They are additive contracts: current writers retain their bytes, and
36
+ the disclosed attempt projection does not replace executable recovery stores.
37
+
38
+ ### Bundling is not running
39
+
40
+ This entry point bundles for a browser. The two host reads it once made
41
+ directly, `process.pid` and `randomUUID` from `node:crypto`, enter through the
42
+ injectable [`OwnerIdentity`](#owneridentity) service, and everything it
43
+ composes, `@smthrs/crypto`, `@smthrs/flow`, `@smthrs/journal`,
44
+ `@smthrs/run-store`, `@smthrs/step-cache`, `@smthrs/database`,
45
+ `@smthrs/kernel`, and `@smthrs/engine`, is browser-bundleable too. A release
46
+ that broke the bundle would fail the build before it shipped.
47
+
48
+ The durable stores accept an injected SQL client and `DurableWriter`. Native
49
+ Node.js and Bun compositions use SQLite or the shipped PostgreSQL adapter;
50
+ `NodeDatabase.layer` selects PostgreSQL for a PostgreSQL URL, and
51
+ `@smthrs/database/postgres/PostgresDatabase` supports direct injection. Browser
52
+ bundling does not supply a durable browser driver or qualify browser execution.
53
+ PostgreSQL storage alone does not qualify a canonical backend deployment:
54
+ artifacts, workspaces, and native process state still need durable host storage.
55
+ See [database configuration](https://database.smithers.sh/concepts/sqlite-only/)
56
+ and [platform support](/docs/reference/api/#platform-support).
57
+
58
+ ## EngineStore
59
+
60
+ [src/EngineStore.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/EngineStore.ts)
61
+
62
+ The production durable composition.
63
+
64
+ `flow.start`, `flow.ensure`, and `execute` with `discard: true` durably admit
65
+ an execution and schedule its drive before returning its id. They do not wait
66
+ for the child's action, durable wait, or settlement, including when launched
67
+ from inside another action. The driver owns the scheduled drive in its engine
68
+ scope; ending the caller's action or round does not interrupt it. A discarded
69
+ child records `onParentExit: "detach"`, so normal parent completion leaves it
70
+ running. Explicit parent cancellation still cascades to linked children.
71
+
72
+ Observe progress with `poll(id)`, or await the result with
73
+ `execute(payload, { executionId: id })`. Callers that need a durable waiting
74
+ row or attempt receipt must await that evidence explicitly. Closing the engine
75
+ scope releases ownership and retains durable admission and progress for
76
+ recovery by a replacement host. The heartbeat sweep recovers pending admissions
77
+ through the same coordinator and fenced claim/activate path;
78
+ unregistered flows wait for a host that registers them. Pending recovery scans
79
+ at most 64 rows per sweep and rotates registered flows. Each scan cycle has a
80
+ fixed creation-time/id upper bound, so new admissions cannot postpone retrying
81
+ refused work indefinitely. Recovery only selects admissions older than the stale
82
+ heartbeat interval, giving a live admitting host time to claim its own work. Storage
83
+ failures remain visible and are retried by the heartbeat sweep.
84
+
85
+ Cancellation is logical-run scoped: `Flow.interrupt(id)` accepts any round ID
86
+ and records intent across its trampoline lineage and linked child lineages in
87
+ one transaction. Children attached to an earlier parent round remain included;
88
+ time-travel fork ancestry alone is not child ownership. Handoff admission checks
89
+ cancellation in that same transaction domain, so a successor cannot escape a
90
+ request by racing its creation.
91
+
92
+ The request commits before local interrupt delivery. Returning from `interrupt`
93
+ acknowledges intent, not finished user cleanup or a remote owner's settlement.
94
+ Owners on other connections observe durable intent through their cancellation
95
+ polls. Completed predecessor history remains unchanged. On normal parent exit,
96
+ `onParentExit` belongs to the child's creating round and is retained through its
97
+ handoffs; explicit cancellation still cascades to linked children.
98
+
99
+ | Export | Signature | Meaning |
100
+ | ----------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
101
+ | `Options` | interface | Construction options. See below. |
102
+ | `make` | `(options: Options) => Effect<FlowRuntime["Service"], never, Requirements>` | Builds the `FlowRuntime` service the port in [`@smthrs/flow`](/api/flow) declares. |
103
+ | `layer` | `(options: Options) => Layer<SnapshotBoundary \| FlowRuntime, never, Requirements>` | Provides both, using the ambient `Jj` for action bodies and engine bookkeeping. |
104
+ | `layerWithPrivilegedJj` | `(options: Options, privilegedJj: Layer<Jj, E, R>) => Layer<SnapshotBoundary \| FlowRuntime, E, Requirements \| R>` | The same, with a private repository for engine bookkeeping while ambient `Jj` stays for action bodies. |
105
+
106
+ ### EngineStore.Options
107
+
108
+ | Field | Type | Meaning |
109
+ | ---------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
110
+ | `owner.hostId` | `string` | This engine's stable host identity. Which host a store speaks for is a composition decision, not a host fact. |
111
+ | `journalSource` | `string` | The source id every record this engine writes carries. |
112
+ | `isAlive` | `Ownership.LivenessCheck` (optional) | Liveness arbitration consulted before stealing a run whose lease expired. Answering `true` refuses the takeover. Defaults to `Ownership.leaseLiveness(Ownership.heartbeatStaleAfter)`. |
113
+ | `canExecute` | `(row: RunStore.RunRow) => Effect<boolean>` (optional) | Host admission before claiming, including automatic wakes. |
114
+ | `canActivate` | `(row: RunStore.RunRow) => Effect<boolean>` (optional) | Read-only admission fence rechecked inside the native activation transaction. Use the same consent and ownership policy as preflight; keep module loading and external I/O in `canExecute`. A refusal abandons the claim without dispatching the body. |
115
+ | `clockFireRetryPolicy` | `Schedule<unknown, unknown>` (optional) | Redispatch policy for a durable clock whose fire failed. Defaults to exponential from 100ms capped at 30s, forever, the same option shape as the engine's `suspendedRetryPolicy`. |
116
+ | `requestResume` | `(executionId, reason) => Effect<void>` (optional) | Called for every wake this engine initiates against a PARKED execution: `"deferred"` (a durable deferred completed), `"clock"` (a durable clock fired), `"parent"` (a child settled under a parent parked on it). An operator's own resume is not reported. A host that refuses to re-enter a parked run nobody asked for reads it to tell an engine wake from its own heartbeat sweep. |
117
+
118
+ ### Required services
119
+
120
+ `Journal`, `DurableWriter`, `RunStore`, `AttemptStore`, `CacheStore`, Effect's `Crypto`,
121
+ `DurableEngineState`, kernel `Jj`, `StepBoundary`, `OwnerIdentity`, and a
122
+ `Scope`. A composition failure is an unmet `Requirements` type at compile time,
123
+ so there is no run-time composition error to handle.
124
+
125
+ [`WorkspaceSandbox`](#workspacesandbox) and its `EffectDispatcher` are optional
126
+ and are resolved at construction, because `actionExecute` runs on the engine's
127
+ own fiber, which does not carry the store's layer context. `StepSandbox`,
128
+ `WakeBus`, `ArtifactSync`, `CacheSync`, `Inconsistency`, `Reconciliation`,
129
+ [`ReplayOnly`](#replayonly), and `Selection` are optional in the same way.
130
+
131
+ ### Behavior
132
+
133
+ The engine stores a versioned state envelope in each run row, fences run and
134
+ attempt ownership, replays encoded exits, and writes engine decisions to the
135
+ journal. Cache addresses are the injected `Sha256` transformation of the step
136
+ key, not the raw `key1_...` value.
137
+
138
+ An action's `CachePolicy.ttlMs` records one age-admission decision per run,
139
+ step key, and cached provenance. Resuming that decision preserves its verdict
140
+ even when the clock crosses the bound in either direction. A conflicting
141
+ journal record proves the opposite verdict only when an exact retry of that
142
+ opposite record returns `Duplicate`. An incompatible TTL or copied history
143
+ with different lineage metadata instead fails with `JournalError` code
144
+ `idempotency_conflict`, before output replay, cache eviction, or body dispatch.
145
+ Changing TTL before a decision exists remains allowed. Omitting `ttlMs` is
146
+ unbounded only before a durable age verdict exists for this run and step.
147
+ Removing `ttlMs` after a recorded verdict fails with `idempotency_conflict`,
148
+ even if the cache head was evicted or replaced. Recovery must retain the
149
+ original TTL and history identity, or use a new action or run identity as
150
+ appropriate. No persisted keys or journal producer identities are rewritten.
151
+
152
+ Durable cancellation is observed, not just recorded: while a run executes, the
153
+ driver polls `cancel_requested_at_ms` on the heartbeat cadence and cancels the
154
+ run when another process has called `RunStore.requestCancel`. Terminal
155
+ transitions are additionally guarded with `{ cancelRequested: "absent" }` inside
156
+ the ownership compare-and-swap.
157
+
158
+ The driver's periodic sweep re-drives durable shapes on the heartbeat
159
+ cadence: pending admissions, parked runs whose cancellation was durably requested,
160
+ runs parked with reason `released`, and stale `running` rows left by a hard-killed
161
+ owner. Each
162
+ re-enters the ordinary claim, steal, and activate path. A wake for a flow the
163
+ sweeping process has not registered logs a once-per-run structured warning and
164
+ leaves the durable waiting row parked.
165
+
166
+ Every lifecycle journal write, run decisions, attempt started and finished, hard
167
+ violations, snapshot identity, cache provenance, deferred completions, clock
168
+ schedules, interruption records, and the `Inconsistency` cache-conflict record,
169
+ takes the journal's durable channel (`emitDurable`), so a saturated lossy queue
170
+ can never drop one. Attempt lifecycle writes additionally pass the owner: a
171
+ reclaimed owner fails with `fence_lost` and self-interrupts instead of
172
+ appending.
173
+
174
+ Full model: [Ownership and fencing](./concepts/ownership-and-fencing.md) and
175
+ [Attempts and replay](./concepts/attempts-and-replay.md).
176
+
177
+ ## DurableEngineState
178
+
179
+ `PendingRunCursor` contains `{ createdAtMs: number; runId: string }`. Pending
180
+ queries return rows after `after` and at or before `through`, ordered by those
181
+ fields. An optional `eligibleBeforeMs` limits results to older admissions.
182
+ `pendingRunTail` captures the upper bound of a recovery scan cycle.
183
+ `pendingCancellationRuns` and `pendingCancellationTail` use the same cursors
184
+ for explicitly requested cancellations, independent of registered handlers.
185
+ Their partial index excludes settled and unrequested admissions; cleanup has
186
+ no admission grace and still requires workspace admission and ownership fencing.
187
+ `limit` must be zero or a positive safe integer; other values defect with `RangeError`.
188
+
189
+ [src/DurableEngineState.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/DurableEngineState.ts)
190
+
191
+ Durable deferreds, clocks, waiting rows, and the run parent DAG. This package
192
+ owns deferred and clock state for 1.0. A successful mutation means the row is
193
+ durable, so callers may journal and schedule a wake only after the mutation
194
+ returns.
195
+
196
+ Work that needs both this state and the journal opens `transaction` OUTSIDE
197
+ `Journal.transact`, never the other way around. The SQL implementation shares
198
+ the journal's writer and cannot tell the difference, but `makeMemory` has a
199
+ permit of its own, and taking the journal's writer first while waiting for that
200
+ permit deadlocks against a fiber doing the opposite.
201
+
202
+ | Export | Signature | Meaning |
203
+ | -------------------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------- |
204
+ | `DurableEngineState` | `Context.Service<Service>` | Service tag. |
205
+ | `Service` | interface | The operations below. |
206
+ | `make` | `Effect<Service, never, DurableWriter \| SqlClient>` | The SQL implementation. |
207
+ | `layer` | `Layer<DurableEngineState, never, DurableWriter \| SqlClient>` | Provides it. |
208
+ | `makeMemory` | `(options?: MemoryOptions) => Service` | Deterministic in-memory implementation. |
209
+ | `layerMemory` | `Layer<DurableEngineState>` | Provides it. |
210
+ | `MemoryOptions`, `MemoryRunView` | interfaces | Optional `runs` lookup so the memory twin enforces the same ownership fences. |
211
+
212
+ ### Service members
213
+
214
+ | Member | Signature |
215
+ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
216
+ | `deferred` | `(address: DeferredAddress) => Effect<Option<DeferredRow>>` |
217
+ | `consumeDeferred` | `(address: DeferredAddress, consumedAtMs: number) => Effect<void>` |
218
+ | `completeDeferred` | `(row: DeferredRow) => Effect<CompleteDeferredOutcome>` |
219
+ | `clock` | `(address: ClockAddress) => Effect<Option<ClockRow>>` |
220
+ | `scheduleClock` | `(row: ClockRow, owner: OwnerId) => Effect<ScheduleClockOutcome>` |
221
+ | `completeClock` | `(address: ClockAddress, completedAtMs: number) => Effect<CompleteClockOutcome>` |
222
+ | `dueClocks` | `(nowMs: number) => Effect<ReadonlyArray<ClockRow>>` |
223
+ | `completeRunClocks` | `(executionId: string, completedAtMs: number) => Effect<void>` |
224
+ | `pendingClocks` | `(scope: { executionId?: string; flowName?: string }) => Effect<ReadonlyArray<ClockRow>>` |
225
+ | `completedDeferreds` | `(flowName: string) => Effect<ReadonlyArray<DeferredAddress>>` |
226
+ | `park` | `(runId: string, waiting: Waiting, owner: OwnerId) => Effect<ParkOutcome>` |
227
+ | `wake` | `(runId: string) => Effect<WakeOutcome>` |
228
+ | `waiting` | `(runId: string) => Effect<Option<WaitingRow>>` |
229
+ | `waitingRuns` | `(filter?: WaitingRunsFilter) => Effect<ReadonlyArray<WaitingRow>>` |
230
+ | `waitingTree` | `(runId: string, options?: WaitingTreeOptions) => Effect<ReadonlyArray<WaitingRow>>` |
231
+ | `pendingRuns` | `(flowName: string, limit?: number, after?: PendingRunCursor, through?: PendingRunCursor, eligibleBeforeMs?: number) => Effect<ReadonlyArray<PendingRunCursor>>` |
232
+ | `pendingRunTail` | `(flowName: string, eligibleBeforeMs?: number) => Effect<Option<PendingRunCursor>>` |
233
+ | `pendingCancellationRuns` | `(limit: number, after?: PendingRunCursor, through?: PendingRunCursor) => Effect<ReadonlyArray<PendingRunCursor>>` |
234
+ | `pendingCancellationTail` | `() => Effect<Option<PendingRunCursor>>` |
235
+ | `staleRunningRuns` | `(staleBeforeMs: number, limit?: number) => Effect<ReadonlyArray<StaleRunningRow>>` |
236
+ | `attemptSurvivors` | `((runId: string, stepKeyDigest: string) => Effect<Option<AttemptSurvivors>>)` (optional) |
237
+ | `recordRunParent` | `(childId: string, parentId: string) => Effect<RecordRunParentOutcome, RunParentCycleError>` |
238
+ | `removeRunParentsForRun` | `(runId: string) => Effect<void>` |
239
+ | `runParents` | `(childId: string) => Effect<ReadonlyArray<RunParentEdge>>` |
240
+ | `runChildren` | `(parentId: string) => Effect<ReadonlyArray<RunParentEdge>>` |
241
+ | `transaction` | `<A, E, R>(effect: Effect<A, E, R>) => Effect<A, E, R>` |
242
+
243
+ `scheduleClock` requires the execution's ownership token. Creation succeeds
244
+ only while the run is running under that owner. An existing clock wins unchanged,
245
+ even after ownership is lost. If no clock exists and the ownership fence fails,
246
+ the effect self-interrupts.
247
+
248
+ `recordRunParent` allocates `MAX(seq) + 1` in the serialized write transaction.
249
+ Migration 0007 indexes `seq` so allocation does not scan retained parent history.
250
+
251
+ `completeRunClocks` closes every uncompleted clock row of one run in a single
252
+ statement, which a terminal transition does in its own transaction.
253
+ `pendingClocks` and `completedDeferreds` never list a row whose run has settled,
254
+ so a registration sweep re-arms timers and replays completions for runs that can
255
+ still make progress and for no others. `completedDeferreds` also excludes
256
+ completions marked observed by `consumeDeferred`. The engine marks a completion
257
+ before `deferredResult` serves it; `deferred` remains a read-only lookup and keeps
258
+ returning the original result for replay. Duplicate completion writes do not
259
+ clear the marker. Migration 0008 leaves existing completions unconsumed until
260
+ the upgraded engine first serves them.
261
+
262
+ `attemptSurvivors` is optional because
263
+ only storage that can range-scan `flows_attempts` implements it; when absent the
264
+ engine falls back to per-attempt point reads against `AttemptStore`.
265
+
266
+ Every list read (`dueClocks`, `pendingClocks`, `completedDeferreds`,
267
+ `waitingRuns`, `runParents`, and `runChildren`) skips a row that will not decode
268
+ and logs a storage-integrity warning naming its primary key, so one corrupt row
269
+ costs its own row and nothing else. The point reads `deferred`, `clock`, and
270
+ `waiting` still die on such a row: reporting "no row" for a completion or
271
+ deadline that is durably recorded but unreadable would re-run work whose side
272
+ effects already ran.
273
+
274
+ `recordRunParent` performs its cycle check inside the same write transaction as
275
+ the insert, so a rejected edge leaves no durable trace and, of two concurrent
276
+ writers whose edges jointly close a cycle, exactly one fails. `transaction`
277
+ makes several store operations atomic; nested store writes become savepoints.
278
+ Serialized write transactions are a documented requirement of the
279
+ `DurableWriter.write` contract, not a SQLite artifact. The shipped PostgreSQL
280
+ adapter uses READ COMMITTED transactions with a transaction-scoped advisory lock
281
+ keyed by schema, acquired before domain reads to serialize writes across pools
282
+ and processes; nested writes use savepoints. A bare PostgreSQL READ COMMITTED
283
+ client without equivalent serialization is insufficient. The in-memory twin
284
+ serializes every store operation behind one permit, snapshots its state on
285
+ entry, rolls back to that snapshot when the effect fails or dies, and treats a
286
+ nested call on the same fiber as a savepoint. It is not durable: a process crash loses the whole
287
+ in-memory state, not only the uncommitted part.
288
+
289
+ When engine state and the journal participate together, `StateTransaction`
290
+ takes the engine-state boundary first and the journal writer inside it. Native
291
+ lifecycle admission, direct cancellation, deferred completion and clock
292
+ scheduling share this order. A refused park or owner transition rolls both
293
+ stores back, including a preexisting memory waiting marker. The memory commit
294
+ callback releases its gate at SQL commit, before post-commit subscribers or
295
+ compaction capture can read it. Failure after publication starts cannot undo
296
+ committed state.
297
+
298
+ `ExecutionFacts` captures the semantic native lifecycle inside the same write.
299
+ Its additive `treeVersion: 1` metadata includes parent attachment policy and a
300
+ redacted waiting question plus its named point. Opaque wake tokens remain in
301
+ the operational waiting row; the fact carries only their digest. The native
302
+ fact fold derives attached descendant human waits and compares them with a
303
+ coherent executor observation. Old v1 facts without the tree extension retain
304
+ legacy tree-wait provenance. Raw waiting request JSON is available through the
305
+ protected execution snapshot reader, independently of its redacted event view.
306
+
307
+ ### Addresses, rows, and outcomes
308
+
309
+ | Export | Shape |
310
+ | ------------------------- | ---------------------------------------------------------------------------------------------------- |
311
+ | `DeferredAddress` | `{ flowName, executionId, deferredName }` |
312
+ | `DeferredRow` | the address plus `exit: unknown` and optional `metadata` |
313
+ | `ClockAddress` | `{ flowName, executionId, clockName }` |
314
+ | `ClockRow` | the address plus `deferredName`, an absolute due time, and `completedAtMs: number \| null` |
315
+ | `Waiting` | `{ reason, wakeAt?, token?, request?: string }` |
316
+ | `WaitingRow` | `{ runId, reason, wakeAt: number \| null, token: string \| null, request?: Json }` |
317
+ | `StaleRunningRow` | `{ runId, heartbeatAtMs }`: a stale `running` row and the lease heartbeat it froze on |
318
+ | `WaitingReason` | a non-empty string; the open taxonomy the driver writes (`timer`, `event`, `released`, `quarantine`) |
319
+ | `WaitingRunsFilter` | `{ reason?, dueBeforeMs?, cancelRequested? }` |
320
+ | `RunParentEdge` | `{ childId, parentId, seq }`, where `seq` is ordering only |
321
+ | `AttemptSurvivors` | `{ earliestAttempt, earliestStartedAtMs, latest }` |
322
+ | `CompleteDeferredOutcome` | `Completed` or `Existing` |
323
+ | `ScheduleClockOutcome` | `Scheduled` or `Existing` |
324
+ | `CompleteClockOutcome` | `Completed`, `AlreadyCompleted`, or `NotFound` |
325
+ | `ParkOutcome` | `Parked` or `NotFound` |
326
+ | `WakeOutcome` | `Woken`, `NotWaiting`, or `NotFound` |
327
+ | `RecordRunParentOutcome` | `Recorded` or `Existing` |
328
+ | `RunParentCycleError` | tagged error carrying `path`, the execution ids from the child back to itself |
329
+ | `EngineStateFault` | defect for a broken invariant: `reason` names it, `field` names an unwritable or unreadable column |
330
+
331
+ Both implementations answer one behavior contract, so a test written against
332
+ the memory twin holds for the SQL one. See
333
+ [Test against a durable store](./guides/testing.md).
334
+
335
+ Full model: [Durable waits](./concepts/durable-waits.md).
336
+
337
+ ### EngineStateFault
338
+
339
+ `DurableEngineState.EngineStateFault` is a tagged defect with optional `field`
340
+ and `cause`. JSON encoding and decoding failures use `value_not_serializable`
341
+ and `value_not_decodable`; `field` identifies the value or column.
342
+ `deferred_completion_missing` and `run_parent_edge_missing` identify missing
343
+ first-writer transaction rows. The tag is
344
+ `@smthrs/engine-store/EngineStateFault`; these remain defects, not recoverable
345
+ failures in the service error channel.
346
+
347
+ ## StepBoundary
348
+
349
+ [src/StepBoundary.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/StepBoundary.ts)
350
+
351
+ The declared read and write sets of a step, measured before and after it runs.
352
+ The declaration itself, `FileBoundary` with `readSet`, `writeSet`, `removes`,
353
+ and `boundaryMode` of `hard` or `expected`, lives in
354
+ [`@smthrs/flow`](/api/flow)'s `Action` namespace.
355
+
356
+ ```ts
357
+ interface Service {
358
+ readonly prepare: (descriptor: FileBoundary) => Effect<PreparedBoundary, UnsupportedBoundary, Crypto>
359
+ readonly settle: (prepared: PreparedBoundary) => Effect<
360
+ BoundaryEvidence,
361
+ UndeclaredWrite | MissingDeclaredOutput | SurvivingDeclaredRemoval | UnsupportedBoundary | BoundaryCorruption,
362
+ Crypto
363
+ >
364
+ readonly replayOutputs: (evidence: BoundaryEvidence) => Effect<
365
+ void,
366
+ UnsupportedBoundary | BoundaryCorruption | MissingArtifact,
367
+ Crypto
368
+ >
369
+ }
370
+ ```
371
+
372
+ | Export | Signature | Meaning |
373
+ | ------------------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
374
+ | `StepBoundary` | `Context.Service<Service>` | Service tag. |
375
+ | `make` | `(service: Service) => Service` | Brands an implementation, so a wrong shape is reported where it is written. |
376
+ | `makeFileSystem` | `(fs: FileSystem, path: Path, artifacts: ArtifactStore.Service, options?: FileSystemOptions) => Service` | The production boundary. |
377
+ | `layer` | `Layer<Service, never, FileSystem \| Path \| ArtifactStore>` | Provides it, confining replay to the kernel `Workspace` root when one is in context. Resolves that root with the host `Path`. |
378
+ | `layerTest` | `(options?: TestOptions) => Layer<Service>` | Deterministic in-memory boundary. |
379
+ | `exactReads` | `(descriptor: FileBoundary) => ReadonlyArray<FileInput>` | Exact read inputs, ignoring declarations that still need expansion. |
380
+ | `readSetMatches` | `(prepared: PreparedBoundary) => boolean` | Whether the measured snapshot still matches the declaration. |
381
+ | `referencedDigests` | `(evidence: BoundaryEvidence) => ReadonlyArray<ArtifactStore.Digest>` | The digests the evidence references rather than inlines. Evidence from a foreign implementation yields the empty list. |
382
+
383
+ ### Schemas
384
+
385
+ | Export | Shape |
386
+ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
387
+ | `PreparedBoundary` | `{ descriptor, readSnapshot }`. The snapshot is what the host actually measured, and is the evidence the declared digests still describe reality. |
388
+ | `BoundaryEvidence` | `{ declaredOutputs, diffIdentity, wholeTreeWritesVerified?, hermeticReadsVerified?, deviation? }` |
389
+ | `ExpectedSetDeviation` | `{ paths, diffIdentity }`, writes outside the declared write set |
390
+ | `MissingOutputDeviation` | `{ paths, diffIdentity }`, declared writes never produced |
391
+ | `SurvivingRemovalDeviation` | `{ paths, diffIdentity }`, declared removals left in place |
392
+ | `BoundaryDeviation` | the union of the three |
393
+
394
+ ### FileSystemOptions
395
+
396
+ | Field | Default | Meaning |
397
+ | --------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------- |
398
+ | `maxInlineBytes` | 1 MiB | The largest single output inlined into the evidence. Anything larger is stored by digest reference. |
399
+ | `maxTotalInlineBytes` | 8 MiB | The largest aggregate inline payload one settle may fold in. Past it, an output is spilled even though it individually fits. |
400
+ | `root` | cwd | The root replay confines writes and removals to. A filesystem already confined to a root keeps its own. |
401
+
402
+ `replayOutputs` writes and deletes what the evidence names, so it confines its
403
+ own mutations instead of trusting the composition. Every write, removal, probe,
404
+ and tree prune goes through `@smthrs/kernel/FileSystem`'s `confined` view:
405
+ one descriptor-relative, no-follow request per call against the pinned root. A
406
+ symlink on a replayed path (a parent, the final component, or a member of a
407
+ replayed tree) refuses with `UnsupportedBoundary`, and so does a host with no
408
+ descriptor-relative executor or isolation attestation, before any host call.
409
+ `prepare` and `settle` only read and keep the caller's filesystem.
410
+
411
+ ### TestOptions
412
+
413
+ `failure`, `deviation`, `readSnapshot`,
414
+ `declaredOutputs`, `diffIdentity`, `supported`, `wholeTreeWriteDetection`,
415
+ `hermeticReadDetection`, and `onReplay`. Defaults describe a well-behaved,
416
+ fully-supported host. Failures and deviations are returned verbatim; use the real
417
+ filesystem layer to test classification. `wholeTreeWriteDetection` defaults to `true`, which is a
418
+ fixture claim rather than a proof: the real whole-tree observation comes from
419
+ [`WorkspaceSandbox`](#workspacesandbox).
420
+
421
+ ### Errors
422
+
423
+ | Error | `code` | Fields |
424
+ | -------------------------- | ---------------------------- | ------------------------------------------ |
425
+ | `UndeclaredWrite` | `undeclared_write` | `paths`, `diffIdentity` |
426
+ | `MissingDeclaredOutput` | `missing_declared_output` | `paths`, `diffIdentity` |
427
+ | `SurvivingDeclaredRemoval` | `surviving_declared_removal` | `paths`, `diffIdentity` |
428
+ | `UnsupportedBoundary` | `unsupported_boundary` | `message`, optional `cause` carried whole |
429
+ | `BoundaryCorruption` | `boundary_corruption` | `path`, `recordedDigest`, `measuredDigest` |
430
+ | `MissingArtifact` | `missing_artifact` | `path`, `digest` |
431
+
432
+ Full model: [Step boundaries](./concepts/step-boundaries.md).
433
+
434
+ ## StepSandbox
435
+
436
+ [src/StepSandbox.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/StepSandbox.ts)
437
+
438
+ Scope-safe acquisition of one isolated workspace per step.
439
+
440
+ | Export | Signature | Meaning |
441
+ | ---------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
442
+ | `StepSandbox` | `Context.Service<Service>` | Service tag. |
443
+ | `Service` | `{ open: Effect<WorkspaceSandbox.Service, UnsupportedBoundary> }` | Acquires the workspace. |
444
+ | `make` | `(workspace: WorkspaceSandbox.Service) => Service` | Wraps a transaction backend. |
445
+ | `layer` | `Layer<Service, WorkspaceError, FileSystem \| Path \| ArtifactStore \| Workspace>` | The filesystem-backed sandbox. Refuses a path-based host at build. |
446
+ | `layerTest` | `(initialFiles?: InitialFiles) => Layer<Service, WorkspaceError, Crypto>` | Deterministic in-memory sandbox. |
447
+ | `layerNoop` | `Layer<Service>` | Fails closed with `UnsupportedBoundary`, for a host that cannot sandbox. |
448
+ | `UndeclaredRead` | tagged error, `code: "undeclared_read"`, fields `paths` and `diffIdentity` | A hermetic body read outside its declared read set. |
449
+
450
+ ## WorkspaceSandbox
451
+
452
+ [src/WorkspaceSandbox.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/WorkspaceSandbox.ts)
453
+
454
+ The functional workspace transaction: a sealed action's body runs in an isolated
455
+ workspace and returns its writes rather than performing them.
456
+
457
+ ```ts
458
+ interface Service {
459
+ readonly execute: <Output, Error>(
460
+ execution: Execution<Output, Error>
461
+ ) => Effect<ExecutionResult<Output>, Error | WorkspaceError, Crypto>
462
+ readonly materialize: <Output>(
463
+ accepted: Accepted<Output>
464
+ ) => Effect<void, MaterializationConflict | WorkspaceError, Crypto>
465
+ }
466
+ ```
467
+
468
+ `materialize` checks digests and retained bytes before changing files. Every
469
+ copy-back host call is one descriptor-relative, no-follow request against the
470
+ root pinned for that commit (`@smthrs/kernel/FileSystem`'s `confined`), so a
471
+ symlink on a change's path, including one swapped in mid-commit, fails with
472
+ `path_escapes_workspace` and is never followed. The host must carry the
473
+ kernel's atomic executor (`@smthrs/platform-node`'s `AtomicFileSystem`), an
474
+ isolation attestation, or be the kernel-guarded filesystem for the same root. The filesystem host serializes cooperating commits through preflight,
475
+ apply, and rollback, using a workspace-root semaphore and the
476
+ `.smithers-workspace-lock` lease file (`@smthrs/artifacts/FileLease`: heartbeat
477
+ every 10 seconds, stale after 60 seconds, acquisition deadline 2 minutes). The
478
+ lock and its children are reserved, as are the `.flows` engine state directory
479
+ and every `reservedPaths` entry, under any write set or boundary mode. A change
480
+ that targets or lies beneath a reserved path fails with `host_unavailable`.
481
+ Reserved names match after Unicode NFKC normalization and case folding, so
482
+ `.FLOWS` or `.flows`, which open `.flows` on default APFS and NTFS volumes, are
483
+ refused on every volume. An NTFS 8.3 short-name shape, such as `FLOWS~1`, is
484
+ refused wherever a reserved segment stands, because an NTFS volume with short
485
+ names on opens the long name through it, including from WSL or SMB.
486
+ Hosts must support exclusive `wx` file creation, `stat` with an mtime,
487
+ `utimes`, `rename`, and `remove`; writers that ignore the lock are outside this
488
+ guarantee.
489
+
490
+ Rollback uses in-memory file pre-images. Copy-back is not crash-atomic, and
491
+ rollback can fail. A compound cause preserves the apply failure plus a
492
+ `WorkspaceError` (`host_unavailable`) carrying the rollback cause. The caller
493
+ must reconcile host files after a crash or failed rollback before resuming.
494
+ A crashed holder's lock is reclaimed once its heartbeat is 60 seconds old. A
495
+ commit that cannot take the lock within 2 minutes fails with
496
+ `commit_lock_timeout` and changes nothing. Lock waits are interruptible.
497
+
498
+ | Export | Signature | Meaning |
499
+ | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
500
+ | `WorkspaceSandbox` | `Context.Service<Service>` | Service tag. |
501
+ | `make` | `(service: Service) => Service` | Brands an implementation. |
502
+ | `layer` | `(service: Service) => Layer<Service>` | Provides one. |
503
+ | `makeHosted` | `(host: Host) => Service` | The transaction itself, over a `Host`. |
504
+ | `makeMemory` | `(initialFiles?: InitialFiles) => Effect<MemorySandbox, WorkspaceError, Crypto>` | Deterministic, browser-safe, and the conformance implementation. Seeds the whole tree, so an undeclared read is observable. |
505
+ | `makeFileSystem` | `(fs: FileSystem, path: Path, artifacts: ArtifactStore.Service, workspaceRoot: string, options?: FileSystemOptions) => Service` | The production host. |
506
+ | `layerFileSystem` | `(options?: FileSystemOptions) => Layer<Service, WorkspaceError, FileSystem \| Path \| ArtifactStore \| Workspace>` | Provides it, taking the root from the kernel `Workspace` and resolving it with the host `Path`. Fails with `host_unavailable` over a path-based host. |
507
+ | `Workspace` | `Context.Service<Workspace>` | The in-transaction filesystem and effect outbox, available only inside `execute`. |
508
+ | `EffectDispatcher` | `Context.Service<Dispatcher>` | The post-copy-back dispatch stage. Optional. |
509
+ | `layerDispatcher` | `(dispatcher: Dispatcher) => Layer<Dispatcher>` | Provides one. |
510
+ | `violations` | `(descriptor: FileBoundary, base: ReadonlyMap<string, Uint8Array>, provenance: Provenance) => ReadonlyArray<DeclarationViolation>` | Everything the declaration failed to predict, deduplicated. |
511
+ | `isMaterializationConflict` | `(error: unknown) => boolean` | Recognizes both the live class and the persisted schema form. |
512
+
513
+ ### Models
514
+
515
+ | Export | Shape |
516
+ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
517
+ | `Resource` | `{ kind, id }`. This implementation records `kind: "file"`. |
518
+ | `InputObservation` | `{ resource, digest }` |
519
+ | `OutputObservation` | `{ resource, operation: "write" \| "remove", digest }` |
520
+ | `Provenance` | `{ baseRevision, inputs, outputs }` |
521
+ | `FileChange` | `{ path, beforeDigest, afterDigest, after? }`. `beforeDigest` is a materialization precondition, not a hint. |
522
+ | `QueuedEffect` | `{ protocol, idempotencyKey, payload }` |
523
+ | `WorkflowResult<Output>` | `{ output, files, provenance, effects }` |
524
+ | `Execution<Output, Error>` | `{ descriptor, cacheKey?, workflow }` |
525
+ | `DeclarationViolation` | `{ kind: "undeclared-read" \| "undeclared-write", resource }` |
526
+ | `CacheOutcome` | `disabled`, `miss`, or `hit`. A run-local memo, not the cross-run cache. |
527
+ | `Accepted<Output>` | `{ _tag: "Accepted", result, cache, violations }` |
528
+ | `Invalidated` | `{ _tag: "Invalidated", provenance, violations }`. No accessor for the candidate output, files, or queued effects. |
529
+ | `ExecutionResult<Output>` | `Accepted<Output> \| Invalidated` |
530
+ | `Host` | `{ snapshot, baseline, retain, commit, root }` |
531
+ | `MemorySandbox` | `{ service, files }`, where `files` observes host state, changed only by `materialize` |
532
+ | `HostFile` | `{ path, content }` |
533
+ | `InitialFiles` | `Readonly<Record<string, string \| Uint8Array>>` |
534
+ | `FileSystemOptions` | `{ maxInlineBytes?, reservedPaths? }`. `maxInlineBytes` defaults to 1 MiB, matching `StepBoundary`'s evidence bound. `reservedPaths` lists root-relative engine state paths copy-back refuses, beyond `.smithers-workspace-lock` and `.flows`. |
535
+
536
+ ### Errors
537
+
538
+ | Error | Fields |
539
+ | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
540
+ | `WorkspaceError` | `code` of `invalid_path`, `not_found`, `host_unavailable`, `path_escapes_workspace`, or `commit_lock_timeout`; `message`; optional `cause` carried whole |
541
+ | `MaterializationConflict` | `paths` (at most 1,024, each at most 4,096 characters) and `message` |
542
+
543
+ It is a deterministic transaction model, not a security boundary. A body
544
+ reaching the host through a service the transaction does not seed is outside it;
545
+ denying that ambient access is the VM and `SandboxProvider` story in
546
+ [`@smthrs/sandbox`](/api/sandbox). The human diff-review gate is not implemented
547
+ and a settled bundle is applied without it, a known limitation of this release,
548
+ and the transaction's `FileSystem` surface is deliberately partial.
549
+
550
+ Full model: [Workspace transactions](./concepts/workspace-transactions.md).
551
+
552
+ ## PlanScheduler
553
+
554
+ Every declared effect tier is schedulable. Sealed dispatches retain their
555
+ content-derived keys and cache-admission requirements. Compensable and
556
+ irreversible dispatches use run-local plan/node/declaration scopes, retain
557
+ their tier in attempt metadata, and never publish shared-cache results. A
558
+ `clean` settlement means no executor ran: it includes both same-run durable
559
+ replay and eligible shared-cache hits. Compensable retries restore the supplied
560
+ snapshot; the generic executor has no irreversible idempotency contract and
561
+ therefore refuses uncertain recovery or retry of those effects. Irreversible
562
+ conflicts fail without automatic rebase or merge elaboration.
563
+
564
+ [src/PlanScheduler.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/PlanScheduler.ts)
565
+
566
+ Drives a persisted [`@smthrs/plan`](/api/plan) plan to completion.
567
+
568
+ ```ts
569
+ interface Service {
570
+ readonly record: (plan: Plan) => Effect<PlanStore.RecordResult, SchedulerError, PlanStore | Journal | Crypto>
571
+ readonly append: (plan: Plan) => Effect<void, SchedulerError, PlanStore | Journal | Crypto>
572
+ readonly run: (plan: Plan) => Effect<Report, SchedulerError, Requirements>
573
+ }
574
+ ```
575
+
576
+ | Export | Signature | Meaning |
577
+ | --------------- | ---------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
578
+ | `PlanScheduler` | `Context.Service<Service>` | Service tag. |
579
+ | `make` | `(options: Options) => Service` | Builds a scheduler bound to one run. |
580
+ | `layer` | `(options: Options) => Layer<PlanScheduler>` | Provides it. |
581
+ | `NodeExecutor` | `Context.Service<Executor>` | The DI seam that turns a node into work. |
582
+ | `layerExecutor` | `(executor: Executor) => Layer<NodeExecutor>` | Provides one. |
583
+ | `recertify` | `(input: { plan, deferringRunId, options }) => Effect<RecertifyResult, ...>` | Re-drives a plan guess-free under a fresh run, then reports remaining debt. |
584
+ | `Requirements` | type | `AttemptStore`, `CacheStore`, `Crypto`, `Jj`, `Journal`, `NodeExecutor`, `PlanStore`, `PlanInputStore`, `PlanMergeStore`, `RunStore`, and `StepBoundary.Service`. |
585
+
586
+ ### Options
587
+
588
+ | Field | Meaning |
589
+ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
590
+ | `runId` | The run this scheduler drives. |
591
+ | `owner` | The `OwnerId` its writes are fenced with. |
592
+ | `sourceId` | The journal source id. |
593
+ | `environment` | Runtime identity copied at construction and bound durably before dispatch; changing it requires a new run. Omission preserves action keys but is a distinct environment binding. |
594
+ | `concurrency.steps` | Caps leaf execution. Defaults to unbounded; zero is refused. |
595
+ | `concurrency.agents` | Caps the agent subset within it. Same defaults. |
596
+ | `rebaseLimit` | How many times a `delay-rebase` node may re-measure and re-key before reconciliation is asked. |
597
+ | `selection.changed` | Changed paths the belief edges are matched against. |
598
+ | `selection.beliefs` | The `BeliefSnapshot` pinned before planning. |
599
+ | `selection.policy` | Deferral policy; `deferBelow` defaults to zero, which defers nothing. |
600
+ | `selection.full` | Treat every verdict as `Admit`, journaled. |
601
+
602
+ Both concurrency caps must be positive safe integers and `rebaseLimit` a
603
+ non-negative one; invalid bounds are rejected at construction.
604
+
605
+ ### Models
606
+
607
+ | Export | Shape |
608
+ | ----------------- | ------------------------------------------------------------------------------------------------------------- |
609
+ | `Outcome` | `built`, `clean`, `failed`, `skipped`, or `deferred` |
610
+ | `ResolvedInput` | `{ from, path, value }`, the settled output of `from` projected along `path` |
611
+ | `NodeInput` | `{ node, attempt, boundary, inputs }` |
612
+ | `Executor` | `{ execute: (input: NodeInput) => Effect<unknown, unknown> }` |
613
+ | `Settlement` | `{ nodeId, planKey, dispatchKey, outcome, attempts, rebases }` |
614
+ | `Report` | `{ planId, digest, settlements, results, verdicts, appended }` |
615
+ | `RecertifyResult` | `{ runId, report, remaining }` |
616
+ | `SchedulerError` | `code` of `invalid_plan`, `boundary_unavailable`, `key_uncomputable`, `elaboration_failed`, or `store_failed` |
617
+
618
+ Ready nodes dispatch through the same persistence path every action uses, so
619
+ the shared step cache,
620
+ [`WorkspaceSandbox`](#workspacesandbox)'s execute-then-materialize transaction,
621
+ attempt rows, and the fenced journal all apply unchanged. A sealed dispatch key
622
+ folds the node's own declaration, measured file digests and projected material
623
+ inputs. It does not fold upstream plan keys, so unchanged consumed content can
624
+ reuse a result even when an upstream declaration changed.
625
+
626
+ Skyframe's `AbstractParallelEvaluator` is the prior art. A private, rebuildable
627
+ `RuntimeGraph` maintains forward/reverse adjacency, dependency counts and ready
628
+ frontiers. Reverse indexes propagate settled outcomes and readiness only;
629
+ content addressing still governs reuse, with no cache-invalidation visitor.
630
+ The coordinator reconciles each completion before admitting dependents, while
631
+ unrelated work can remain in flight. Retry/rebase attempts are not additional
632
+ node settlements. Appended indexes become visible after durable admission.
633
+
634
+ The existing scheduling policy ranks the current ready frontier by priority
635
+ plus capacity-constrained admission passes waited, with exact arithmetic and
636
+ compiled plan order for ties. It retains independent step and agent caps.
637
+ Readiness no longer scans the entire plan after each settlement; admission
638
+ still considers and re-ranks all ready candidates to preserve aging.
639
+
640
+ Read versions are relative to each reader's predecessors. A path with no
641
+ preceding writer is a source input, even when that reader or a later node writes
642
+ it. Source paths and source-glob membership are pinned before the first dispatch
643
+ (new generations are observed at append time); preceding producers' outputs are
644
+ measured after settlement. Later writers do not widen a read glob's membership.
645
+ A rebase re-observes preceding outputs, not source inputs.
646
+
647
+ `PlanInputStore` records those observations before dispatch and restores them on
648
+ reopen, without re-enumerating source globs or measuring source files again.
649
+ Each run binds one plan ID and approved base digest; a different approved
650
+ graph or plan ID needs a new run. New runs observe the current world independently and may
651
+ reuse eligible shared-cache results. These rules do not freeze external state
652
+ or replace boundary enforcement when an unfinished action actually executes.
653
+
654
+ `Options.environment` is copied at scheduler construction and bound durably
655
+ before source observation or dispatch. Recovery requires the same normalized
656
+ identity for all compiled effect tiers. Layer order and duplicates matter;
657
+ capability-pattern order and duplicates do not. Omission, declared-empty, and
658
+ undeclared/run-scoped identities are distinct. A changed environment returns
659
+ `store_failed` with a typed input/merge-store cause of `incompatible_state`, without
660
+ executing or replacing the old binding. Recover with the original environment,
661
+ or explicitly reconcile unfinished effects before starting a new run. This
662
+ checks supplied identities, not undeclared changes in implementation behavior.
663
+
664
+ Ready work is ordered by declared
665
+ `priority` plus one point per round waited, so priority changes latency without
666
+ permitting starvation.
667
+
668
+ Full guide: [Drive a plan to completion](./guides/drive-a-plan.md).
669
+
670
+ `stop-merge` records its stopped-attempt decision in `PlanMergeStore`. Recovery
671
+ preserves `skipped` without repeating that attempt, and commits each generated
672
+ merge with its plan extension, source observations, and durable append event.
673
+ Generated IDs avoid occupied user names. `skipped` does not mean no executor
674
+ ever ran: stopped attempts retain their attempt count. `Report.appended` lists
675
+ new appends by this invocation, not merges recovered from prior invocations.
676
+
677
+ ## PlanMergeStore
678
+
679
+ Authoritative scheduler decisions, separate from action failure evidence and
680
+ redacted journal projections. Compose `layer` over the same `SqlClient` and
681
+ `DurableWriter` as `PlanInputStore`, `PlanStore`, and `Journal`, with `Crypto`;
682
+ run migrations first. `TestStores.layer` and `layerAt` include it.
683
+
684
+ | Export | Contract |
685
+ | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
686
+ | `Identity` | `{ runId, planId, baseDigest, environmentDigest }`. |
687
+ | `Intent` | Version 1; stopped node/key, dispatch key, attempts/rebases, and exact eligible peers. |
688
+ | `Completion` | Version 1; appended generation, parent/result digests, merge ID/key, and winning peers. |
689
+ | `Decision` | Intent and optional committed completion. |
690
+ | `list(identity, owner)` | Committed decisions; refuses enclosing SQL transactions. |
691
+ | `intend(identity, intent, owner)` | First writer wins; joins an outer transaction when provided. Await its commit before exposing the stopped decision. |
692
+ | `complete(identity, nodeId, completion, owner)` | Requires the caller's plan/input append transaction. Repeated identical completion converges; a different completion is refused. |
693
+ | `make`, `layer`, `PlanMergeStore` | SQL constructor, layer, and service tag. |
694
+ | `maximumDecisionCharacters` | 16 Mi JavaScript string code units per encoded decision. |
695
+
696
+ All operations check current ownership, cancellation, and the admitted plan and
697
+ environment. Rows are versioned, checksummed, immutable, and retained until run
698
+ collection; checksums detect corruption, not malicious database writes. The
699
+ scheduler additionally reconstructs approved generation digests and validates
700
+ stopped-node policy before dispatch. It can recover recorded merge-only
701
+ extensions from the original base, but requires supplied approved intervening
702
+ manual generations rather than inventing missing work.
703
+
704
+ `PlanMergeError.code` distinguishes `invalid_input`, `corrupt_state`,
705
+ `incompatible_state`, `fence_lost`, `transaction_open`, `transaction_required`,
706
+ and `persistence_failed`. The scheduler interrupts on fence loss and otherwise
707
+ reports `SchedulerError` with `store_failed` and the typed cause. Migration
708
+ `3005` leaves existing observation heads' merge-state version unknown and
709
+ refuses recovery under this runtime. Finish on the prior runtime or reconcile
710
+ unfinished effects before starting a new run; never infer authority from
711
+ merge-like names/bodies or backfill an unknown version by guessing.
712
+
713
+ ## PlanInputStore
714
+
715
+ Authoritative, append-only source observations for compiled plan execution.
716
+ Compose `PlanInputStore.layer` over the **same** `SqlClient` and `DurableWriter`
717
+ as the run, attempt, plan, and journal stores, with `Crypto`. The layer does not
718
+ run migrations. `TestStores.layer` and `layerAt` include it.
719
+
720
+ | Export | Contract |
721
+ | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
722
+ | `Address` | `{ runId, planId, baseDigest, environmentDigest, generation }`; derive the environment digest with `StepKey.environmentIdentity(environment)`. |
723
+ | `Snapshot` | Version 1; generation; node IDs/keys and each read declaration's frozen source paths; newly pinned `{ path, digest }` entries. |
724
+ | `get(address, owner)` | Returns the recorded snapshot or `None` for the next generation. Refuses enclosing SQL transactions so execution cannot consume speculative state. |
725
+ | `record(address, snapshot, owner)` | First-writer-wins; returns the winning snapshot. Consecutive generations only. Can join a transaction, whose outer commit the caller must await before dispatch. |
726
+ | `make`, `layer`, `PlanInputStore` | SQL constructor, layer, and service tag. No memory/cache fallback. |
727
+ | `maximumSnapshotCharacters` | 16 Mi JavaScript string code units per encoded generation, checked before persisted JSON is decoded. |
728
+
729
+ Reads and writes validate ownership and absent cancellation within the owning
730
+ write transaction. Snapshot rows are checksummed, versioned, schema-validated,
731
+ and immutable; the scheduler additionally checks node declarations, file-version
732
+ selection, and pin consistency before using them. Checksums detect corruption,
733
+ not unauthorized database modification. Rows are retained until their owning
734
+ run is collected; they are not subject to cache eviction or journal redaction.
735
+
736
+ `PlanInputError.code` distinguishes `invalid_input`, `corrupt_state`,
737
+ `incompatible_state`, `fence_lost`, `transaction_open`, and `persistence_failed`.
738
+ The scheduler self-interrupts on fence loss and otherwise exposes the typed
739
+ cause through `SchedulerError` with `store_failed`.
740
+
741
+ Migration `engine-store/0003_plan_inputs` marks runs that already had attempts
742
+ before durable observations existed. Such runs cannot safely enter the new
743
+ compiled scheduler: their original sources may have been overwritten. Finish
744
+ them on the previous runtime before upgrading, or make an explicit operator
745
+ recovery decision and start new work under a new run ID. Do not delete the
746
+ legacy marker or retry an uncertain irreversible effect blindly.
747
+
748
+ Migration `engine-store/0004_plan_environment` adds the environment binding.
749
+ Existing observation heads keep an unknown (`NULL`) environment and are refused;
750
+ the migration never guesses from the current process. New heads require a
751
+ non-empty, immutable fingerprint. Earlier snapshots and attempts remain intact.
752
+
753
+ ## Reconciliation
754
+
755
+ [src/Reconciliation.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/Reconciliation.ts)
756
+
757
+ The pluggable seam for when the world disagrees with the declaration. It is the
758
+ first consumer `flows.engine.expected-set-deviation` has had.
759
+
760
+ ```ts
761
+ interface Service {
762
+ readonly onDeviation: (deviation: Deviation) => Effect<Verdict>
763
+ readonly onConflict: (conflict: Conflict) => Effect<Verdict>
764
+ }
765
+ ```
766
+
767
+ | Export | Signature | Meaning |
768
+ | ----------------------- | --------------------------------------------- | ----------------------------------- |
769
+ | `Reconciliation` | `Context.Service<Service>` | Service tag. |
770
+ | `make` | `(service: Service) => Service` | Names an implementation. |
771
+ | `layer` | `(service: Service) => Layer<Reconciliation>` | Installs one. |
772
+ | `makeDefault` | `() => Service` | The deterministic verdict function. |
773
+ | `layerDefault` | `Layer<Reconciliation>` | Installs it. |
774
+ | `Deviation`, `Conflict` | schemas | What the scheduler reports. |
775
+ | `Verdict` | schema | `Fail`, `Reorder`, or `FactorOut`. |
776
+
777
+ `layerDefault` answers in one order of preference: `Reorder` when every
778
+ undeclared path is one another plan node declares it writes, `FactorOut` when
779
+ another node in the same run deviated on exactly the same paths, and `Fail`
780
+ otherwise. A conflict the runtime strategy could not absorb always fails, because
781
+ choosing a winner between two landings is a semantic judgement this default does
782
+ not have the material to make.
783
+
784
+ The scheduler attributes every deviation on a journal page before judging any of
785
+ it, so two steps that produced the same undeclared paths both see each other.
786
+ Pluggability is dependency injection at the owning seam; there is no hook
787
+ kernel. A model-backed reconciler is a different `Layer` and lives in the agent
788
+ packages: this package has no model dependency and must not grow one.
789
+
790
+ ## Selection
791
+
792
+ [src/Selection.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/Selection.ts)
793
+
794
+ The advisory scheduler seam. It may return `Admit`, `Defer`, or `Propose`
795
+ verdicts for sink candidates and missing flows, and never changes a step key, a
796
+ cache row, or a correctness decision.
797
+
798
+ | Export | Signature | Meaning |
799
+ | ---------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------- |
800
+ | `Selection` | `Context.Service<Service>` | Service tag. |
801
+ | `Service` | `{ select: (input: Input) => Effect<ReadonlyArray<Selected>> }` | One verdict per candidate. |
802
+ | `make` | `(service: Service) => Service` | Names an implementation. |
803
+ | `layer` | `(service: Service) => Layer<Selection>` | Installs one. |
804
+ | `makeNoop` / `layerNoop` | | Admits everything. The behavioral default. |
805
+ | `makeHeuristic` / `layerHeuristic` | | Pure glob matching over live edges. |
806
+ | `debt` | `(runId: string, options?: DebtOptions) => Effect<ReadonlyArray<DebtEntry>, ..., Journal>` | Folds the journal for unpaid deferrals. |
807
+ | `risk` | `(input: { changed, beliefs }) => Risk` | A pure annotation, never a gate. |
808
+ | `card` | `(input: CardInput) => ReadonlyArray<string>` | Renders the plan card, one string per line. |
809
+ | `proposeReadSet` | `(input: { beliefs, flow, paths }) => ReadonlyArray<string>` | The `boundaryMode: "expected"` feeder. |
810
+
811
+ ### Schemas and models
812
+
813
+ | Export | Shape |
814
+ | -------------------- | ----------------------------------------------------------------------------------------- |
815
+ | `SuspectedEdge` | `{ scope, affects, confidence, validFromMs, evidence }` |
816
+ | `BeliefSnapshot` | `{ pinnedAtMs, edges }` |
817
+ | `Verdict` | `Admit`, `Defer { edge, likelihood }`, or `Propose { flow, edge, confidence }` |
818
+ | `Policy` | `{ deferBelow }`. Zero defers nothing; a likelihood exactly at the threshold is admitted. |
819
+ | `Candidate` | `{ nodeId, planKey, stats? }` |
820
+ | `Input` | `{ changed, sinks, present, beliefs, policy }` |
821
+ | `Selected` | `{ nodeId, verdict }` |
822
+ | `DebtEntry` | `{ planId, nodeId, planKey, edge, likelihood, seq }` |
823
+ | `DebtOptions` | `{ repaidBy? }` |
824
+ | `Risk` | `{ level: "low" \| "medium" \| "high", reasons }` |
825
+ | `CardInput` | `{ settlements, deferrals, proposals, cadence, risk? }` |
826
+ | `NonNegativeSafeInt` | the epoch and counter schema both public schemas and SQLite accept |
827
+
828
+ `layerHeuristic` matches live edges (`validFromMs <= pinnedAtMs`): a matching
829
+ edge supplies the likelihood, a sink can defer only when a live edge names it,
830
+ and a `Candidate.stats` failure ratio raises the likelihood so flaky sinks stay
831
+ inline. Stats alone never defer. A model-backed layer is out of scope, because
832
+ `engine-store` must not depend on a model.
833
+
834
+ `risk` returns `high` at confidence at or above 0.7, `medium` at or above 0.4,
835
+ otherwise `low`, with each reason named `<scope> -> <affects> (<confidence>)`.
836
+ `card` row strings are stable: `clean` renders as `cached` and `built` as
837
+ `run`.
838
+
839
+ Out of scope here: CLI verbs, approval routing, auto-appending proposals, and
840
+ the recertification cadence, which is a product concern rather than a store
841
+ primitive.
842
+
843
+ Full guide: [Defer work with selection beliefs](./guides/defer-work-with-selection.md).
844
+
845
+ ## SelectionStore
846
+
847
+ [src/SelectionStore.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/SelectionStore.ts)
848
+
849
+ The durable suspected-edge store, tagged `@smthrs/engine-store/SelectionStore`.
850
+
851
+ | Export | Signature | Meaning |
852
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------- |
853
+ | `SelectionStore` | `Context.Service<Service>` | Service tag. |
854
+ | `make` | `Effect<Service, never, DurableWriter \| SqlClient>` | Builds it through this package's migration set. |
855
+ | `layer` | `Layer<SelectionStore, never, DurableWriter \| SqlClient>` | Provides it. |
856
+ | `maxEvidenceEntries` | `128` | Newest evidence entries retained per edge. |
857
+ | `TrainingOutcome` | `"hit" \| "miss"` | |
858
+ | `TrainingObservation` | `{ scope, affects, outcome }` | |
859
+ | `SelectionStoreError` | `code` of `invalid_input`, `decode_failed`, or `persistence_failed`, plus optional `scope`, `affects`, and `cause` | |
860
+
861
+ `upsert(edges)` inserts or replaces by `(scope, affects)`. `list()` returns
862
+ every edge. `snapshot()` pins the injected clock's current time, never
863
+ `Date.now()`. `train(observations)` updates only matching edges in one
864
+ transaction, ignores unknown pairs, appends every observation to evidence, and
865
+ applies the asymmetric rule: a hit becomes `confidence + 0.05 * (1 -
866
+ confidence)`, a miss becomes `confidence * 0.5`. Training never creates edges
867
+ and never writes journal records.
868
+
869
+ ## ArtifactSync
870
+
871
+ [src/ArtifactSync.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/ArtifactSync.ts)
872
+
873
+ The two-tier artifact protocol, and the seam a shared-cache composition injects
874
+ into.
875
+
876
+ | Export | Signature | Meaning |
877
+ | --------------------------- | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
878
+ | `ArtifactSync` | `Context.Service<Service>` | Service tag. |
879
+ | `makeLocal` | `() => Service` | Publish is a no-op; hydrate reports nothing arrived. The default when the tag is absent. |
880
+ | `layerLocal` | `Layer<ArtifactSync>` | Provides it. |
881
+ | `make` | `(options: { local, remote, downloadPolicy? }) => Service` | The two-tier protocol. |
882
+ | `layer` | `(remote: Effect<ArtifactStore.Service, E, R>, options?) => Layer<ArtifactSync, E, ArtifactStore \| R>` | Takes the local tier from the `ArtifactStore` tag and the shared tier from the effect. |
883
+ | `DownloadPolicy` | `RemoteArtifacts.DownloadPolicy` | `all`, `toplevel`, or `minimal`. |
884
+ | `ArtifactPublicationFailed` | `code: "artifact_publication_failed"`, fields `digests`, `message`, optional `cause` | |
885
+
886
+ `publish(digests)` runs `findMissing` on the shared tier, uploads what is
887
+ missing, and re-probes to confirm. The engine calls it immediately before the
888
+ transaction that records the cache entry, and never inside it: this
889
+ is Bazel's REAPI ordering constraint, because a result accessed before its blobs
890
+ are present cannot be validated. A publication that cannot make the artifacts
891
+ durable fails and the shared entry is withheld.
892
+
893
+ `hydrate(digests)` establishes that this host can resolve every referenced
894
+ artifact and reports whether the replay is now worth retrying. It never fails a
895
+ run: a shared tier that is down must not stop work that can simply be done.
896
+
897
+ The two tiers cannot both be layers, because they inhabit the same tag and
898
+ composing them would shadow one with the other.
899
+
900
+ ### DownloadPolicy
901
+
902
+ Declared on the shared tier as `RemoteArtifacts.Options.downloadPolicy` and read
903
+ from the store `make` was handed, so one deployment setting reaches both seams.
904
+ An explicit `downloadPolicy` on `make` or `layer` overrides it.
905
+
906
+ | Policy | `hydrate` behavior |
907
+ | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
908
+ | `all` (default) | Downloads every referenced artifact into this host's store while admitting the replay. Every later read is local, and a shared tier that goes down afterwards costs nothing. |
909
+ | `toplevel` | Downloads nothing. One batched `findMissing` establishes that the shared tier can serve what is missing, and `CombinedArtifacts.get` fetches and writes back the blobs a reader actually reads. |
910
+ | `minimal` | The same probe and the same zero downloads; `CombinedArtifacts.get` then serves without writing back, so this host never accumulates other machines' artifacts. |
911
+
912
+ The two lazy policies are sound only when the store the replay reads through can
913
+ reach the shared tier, which means `CombinedArtifacts` with the same remote
914
+ tier. A tier that refuses the probe is indistinguishable from one that holds
915
+ nothing, so the replay is refused either way and the step executes.
916
+
917
+ ## CacheSync
918
+
919
+ [src/CacheSync.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/CacheSync.ts)
920
+
921
+ The second half of the ordering constraint: the shared step-result tier's `put`,
922
+ run after the transaction that made the local row durable.
923
+
924
+ | Export | Signature | Meaning |
925
+ | ------------ | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
926
+ | `CacheSync` | `Context.Service<Service>` | Service tag. |
927
+ | `Service` | `{ publishEntry: (entry: CacheStore.CacheEntry) => Effect<Option<CacheStore.CacheStoreError>> }` | `none` means shared, `some(error)` means not, and why. |
928
+ | `makeLocal` | `() => Service` | The single-tier implementation. The default when the tag is absent. |
929
+ | `layerLocal` | `Layer<CacheSync>` | Provides it. |
930
+ | `make` | `(options: { remote: CacheStore.Service }) => Service` | Publishes to a shared store, typically `RemoteCacheStore`. |
931
+ | `layer` | `(remote: Effect<CacheStore.Service, E, R>) => Layer<CacheSync, E, R>` | Provides it. |
932
+
933
+ It is a separate seam from the `CacheStore` tag because of where the local row
934
+ is written. The engine commits the cache row and the journal record explaining
935
+ it in one `DurableWriter` transaction, and nothing that is not
936
+ storage work may be held across one: a `CacheStore` whose `put` also wrote a
937
+ shared HTTP tier would put a network round trip inside that transaction,
938
+ blocking every other writer for its duration and rolling the local row back
939
+ whenever a shared cache was unreachable. Compose it with `CombinedCacheStore` in
940
+ `"deferred"` publication mode; lookups stay read-through either way.
941
+
942
+ A `Conflict` from the shared tier is not reported: it means another machine
943
+ recorded the key first, which is the first-writer-wins outcome the shared tier
944
+ exists to arbitrate.
945
+
946
+ Neither publication step can fail a run. Both run after `attempts.finish`, so
947
+ the result is already durably recorded on this host. A refusal withholds the
948
+ shared copy, never the local row, and journals a `cache-provenance` record with
949
+ `action: "unpublished"` carrying the stage (`artifacts` or `entry`) and the
950
+ reason.
951
+
952
+ ## ArtifactGc
953
+
954
+ [src/ArtifactGc.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/ArtifactGc.ts)
955
+
956
+ Explicit mark and sweep collection of unreferenced blobs. Collection never runs
957
+ automatically; [`smthrs gc`](/cli/gc) runs it after retention.
958
+
959
+ | Export | Signature | Meaning |
960
+ | ------------------ | --------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
961
+ | `ArtifactGc` | `Context.Service<Service>` | Service tag. |
962
+ | `Service` | `{ gc: (options?: GcOptions) => Effect<GcReport, ArtifactGcError> }` | Marks the live set from the durable roots, then sweeps. |
963
+ | `make` | `(options?: MakeOptions) => Effect<Service, never, SqlClient \| ArtifactSweep>` | Builds the collector. |
964
+ | `layer` | `(options?: MakeOptions) => Layer<ArtifactGc, never, SqlClient \| ArtifactSweep>` | Provides it. |
965
+ | `layerFileSystem` | `(options?: MakeOptions & SweepOptions) => Layer<ArtifactGc, never, SqlClient \| FileSystem>` | Provides it over a filesystem objects directory. |
966
+ | `ArtifactGcPolicy` | `Context.Service<Policy>` | The opt-in collection policy. |
967
+ | `layerPolicy` | `(policy: Policy) => Layer<ArtifactGcPolicy>` | Installs it. |
968
+ | `defaultGraceMs` | 14 days | Git's `gc.pruneExpire` default. |
969
+ | `ArtifactGcError` | `code` of `invalid_options`, `mark_failed`, or `sweep_failed` | |
970
+
971
+ | Type | Fields |
972
+ | ------------- | ------------------------------------------------------------------------------------------------------------------ |
973
+ | `MakeOptions` | `pageSize`, rows per mark-phase page. Defaults to 500. |
974
+ | `Policy` | `graceMs?`, and `pins?` as an `Effect<ReadonlyArray<string>>` resolved fresh on every collection. |
975
+ | `GcOptions` | `graceMs?`, `pins?`, `dryRun?`. Explicit options override the installed policy; the policy overrides the defaults. |
976
+ | `GcReport` | `scannedBlobs`, `liveDigests`, `sweptDigests`, `reclaimedBytes`, `keptByGrace`, `dryRun` |
977
+
978
+ The mark is fail-safe: a root row carrying boundary evidence this build cannot
979
+ decode aborts the collection rather than contributing nothing. Attempt
980
+ checkpoints are also live roots, with digest-shaped strings retained
981
+ conservatively. The live set is computed before the inventory, so a root
982
+ recorded during the sweep can only be missed, never half seen, and the blob such
983
+ a root references is protected by the mtime fence anyway.
984
+
985
+ Full guide: [Collect unreferenced artifacts](./guides/collect-unreferenced-artifacts.md).
986
+
987
+ ## StepCacheFold
988
+
989
+ [src/StepCacheFold.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/StepCacheFold.ts)
990
+
991
+ `flows_step_cache` heads as a fold of the journal. Drop the heads and
992
+ `rebuild` writes them back from the retained `cache-provenance` entries.
993
+
994
+ | Export | Signature | Meaning |
995
+ | ----------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
996
+ | `rebuild` | `() => Effect<Rebuilt, JournalError \| CacheStoreError \| SqlError, Journal \| SqlClient \| DurableWriter>` | Folds every run's retained entries and replaces the heads. |
997
+ | `reduce` | `(state: State, entry: JournalEvent.Entry) => State` | Folds one entry. |
998
+ | `initial` | `State` | The empty fold. |
999
+ | `projection` | `Projection<State>` | The same fold for `Journal.project` over one run. |
1000
+ | `candidates` | `(state: State) => ReadonlyArray<CacheStore.RecordedRef>` | The head each key may be rebuilt with. |
1001
+ | `refId` | `(ref: CacheStore.RecordedRef) => string` | A recorded row's stable identity. |
1002
+ | `eventType` | `"flows.engine.cache-provenance"` | The entries the fold reads. |
1003
+ | `retiringActions` | `["expired", "stale_read_set", "replay_failed"]` | Provenance actions that retire the row they name. |
1004
+
1005
+ | Type | Fields |
1006
+ | --------- | ------------------------------------------------------------------- |
1007
+ | `State` | `admitted` and `retired`: the rows `put` inserted, the ones evicted |
1008
+ | `Rebuilt` | `runs`, `compacted`, `rewound`, `admitted`, `retired`, `heads` |
1009
+
1010
+ A `put` that inserts a head journals an `admitted` entry naming its row in the
1011
+ same transaction. A duplicate or a losing conflict writes a ledger row but no
1012
+ `admitted` entry. These entries retire the row they name:
1013
+
1014
+ | Entry | Why the row cannot serve |
1015
+ | --------------------------- | -------------------------------------------------- |
1016
+ | `expired`, `stale_read_set` | The engine evicted it. |
1017
+ | `replay_failed` | The engine may have quarantined it for corruption. |
1018
+
1019
+ A producer slot keeps the first `replay_failed` reason it journalled, so a
1020
+ corruption can hide behind an earlier host failure; the fold retires the row on
1021
+ any reason, and a row whose replay failed only on the host is a miss.
1022
+
1023
+ A key with one admitted row that no entry retired gets that row back as its
1024
+ head. A key with several gets no head: one of them left without a journal
1025
+ entry, such as by `sweepExpired`, and the journal cannot say which one the
1026
+ store held. The journal holds provenance, not results: the result stays in the
1027
+ ledger row the entry addresses, because the journal is redacted and replayed
1028
+ to sync subscribers.
1029
+
1030
+ A rebuild writes a subset of the live heads. It drops heads with no local
1031
+ entry, such as shared-tier write-backs. A store with a compacted run, or one where
1032
+ any run was ever rewound, gets no heads, because compaction and rewind may have
1033
+ deleted the eviction that retired a row. Retention is not yet covered: it
1034
+ deletes a run's entries and compaction floor, so a rebuild after retention can
1035
+ restore a row a deleted run evicted. A single admitted row that `sweepExpired`
1036
+ or an operator `evict` removed also returns; every restored hit still passes
1037
+ the engine's age, read-set, and digest checks. Run it on a
1038
+ quiescent store: a write between the journal read and the rewrite is missed.
1039
+
1040
+ ## Retention
1041
+
1042
+ [src/Retention.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/Retention.ts)
1043
+
1044
+ Explicit deletion of finished run state. Nothing schedules any of it.
1045
+
1046
+ | Export | Signature | Meaning |
1047
+ | ------------------ | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
1048
+ | `Retention` | `Context.Service<Service>` | Service tag. |
1049
+ | `Service` | `{ retain: (options: RetainOptions) => Effect<RetainReport, RetentionError \| JournalError> }` | One bounded pass inside one `journal.transact`. |
1050
+ | `make` | `Effect<Service, never, SqlClient \| Journal>` | Builds it. |
1051
+ | `layer` | `Layer<Retention, never, SqlClient \| Journal>` | Provides it. |
1052
+ | `collect` | `(options: Options) => Effect<Report, SqlError \| RetentionError, SqlClient>` | The host-facing pass, over one database file. |
1053
+ | `eligible` | `(olderThanMs: number, limit?: number) => Effect<ReadonlyArray<string>, SqlError, SqlClient>` | The candidate run ids, oldest first. |
1054
+ | `defaultLimit` | `1000` | Runs deleted by one pass when the caller names no bound. |
1055
+ | `terminalStatuses` | `["completed", "failed", "cancelled"]` | The statuses a run can never leave. |
1056
+ | `runScopedTables` | `ReadonlyArray<RunScopedTable>` | Every table a deleted run leaves rows in, and the column naming the run. |
1057
+ | `RetentionError` | `code` of `scan_failed` or `delete_failed` | |
1058
+
1059
+ | Type | Fields |
1060
+ | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1061
+ | `RetainOptions` | `olderThanMs` (a duration: how long a run must have been finished), `limit?`, `dryRun?`. A negative `olderThanMs` is read as zero; a `limit` that is not a non-negative safe integer is read as zero. |
1062
+ | `RetainReport` | `cutoffMs`, `runIds`, `retainedForLiveDescendants`, `retainedForLiveAncestors`, `runs`, `attempts`, `clockDeadlines`, `deferredCompletions`, `journalEntries`, `journalCheckpoints`, `journalIdentities`, `archiveEntries`, `timeTravelReceipts`, `dryRun` |
1063
+ | `Options` (for `collect`) | `olderThanMs` (an absolute epoch millisecond threshold), `dryRun?`, `database?`, `limit?`, `pins?` |
1064
+ | `Report` (from `collect`) | `database`, `olderThanMs`, `runs`, `deleted` (empty under a dry run), `dryRun` |
1065
+
1066
+ A run is a candidate only when its status is terminal and it finished before the
1067
+ cutoff, and it is retained whenever a live run stands above or below it in the
1068
+ lineage, over both the `flows_run_parents` edge a spawned child records and the
1069
+ `parent_run_id` column a trampoline lineage is chained through. `collect` runs
1070
+ the same deletion and the same guard, and drops the edge-table half of the walk
1071
+ for a database that does not carry it, such as the control plane's.
1072
+
1073
+ Both passes select children before parents, so a trampoline lineage longer
1074
+ than `limit` still loses at least one run every pass.
1075
+
1076
+ `collect` is the pass [`smthrs gc`](/cli/gc) runs over one database file.
1077
+
1078
+ Full guide: [Delete old run history](./guides/delete-old-run-history.md).
1079
+
1080
+ The host-facing `collect` also accepts `pins`, a list of run IDs required by
1081
+ live ancestry in another store. Pinned runs and their continuation ancestors
1082
+ are excluded before the bounded candidate window, so protected history cannot
1083
+ starve collection of unrelated terminal runs.
1084
+
1085
+ ## ExecutionSnapshot
1086
+
1087
+ Execution snapshot reads validate the batch source and safe non-negative revisions,
1088
+ return exactly one row per requested ID in request order (including duplicates),
1089
+ and require every row to share the batch source and have a revision no greater
1090
+ than the batch watermark. Incoherent batches fail with `RunStoreError` and
1091
+ `persistence_failed`; malformed stored fields retain `decode_failed`.
1092
+
1093
+ The engine-owned read port, exported from the root and
1094
+ `@smthrs/engine-store/ExecutionSnapshot`. Its `make()` and `layer` require
1095
+ `SqlClient` with the engine migrations applied.
1096
+
1097
+ | Export | Contract |
1098
+ | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1099
+ | `ExecutionSnapshot`, `Service` | Service tag and its `read` and `related` operations. |
1100
+ | `Service.read(runIds)` | Coherent `Batch` for up to `maximumBatchSize` (200) IDs, preserving request order and duplicates. |
1101
+ | `withReadTransaction(sql, effect)` | Reserves a read transaction without writer admission: deferred on SQLite and repeatable-read, read-only on PostgreSQL. An existing transaction retains its caller-selected isolation. |
1102
+ | `Service.related(options)` | Bounded `RelatedPage` of direct durable children or lineage rounds, with the requested anchor. |
1103
+ | `Position` | Durable database `source` and monotonic `revision`. |
1104
+ | `Snapshot`, `Observed`, `Missing` | Explicit observed execution or absence, including deletion evidence. |
1105
+ | `Waiting` | Timer, signal, approval, quota, human, or other reason, with wake time and SHA-256 `tokenDigest`. |
1106
+ | `Batch`, `RelatedOptions`, `RelatedPage` | Source watermark, scoped results, relation selector, and optional continuation. |
1107
+ | `isNewer(incoming, stored)` | True only for the same source with a greater revision. |
1108
+
1109
+ The requested run's lifecycle remains round scoped. Intent and the first owner's
1110
+ cancellation acknowledgement are separate fields. Observation failures use
1111
+ `RunStoreError` with causes preserved. `withReadTransaction` also preserves SQL
1112
+ transaction admission errors; interruption releases the read transaction.
1113
+
1114
+ ## RunChangeFeed
1115
+
1116
+ Exported from the root and `@smthrs/engine-store/RunChangeFeed`. `make()` and
1117
+ `layer` require a migrated `SqlClient`; `RunChangeFeed` is the service tag.
1118
+
1119
+ `Service.current` reads a `Position`.
1120
+ `Service.changesSince({ source, revision, limit })` returns a `Page` containing
1121
+ `Change` entries, the observed source watermark, `nextRevision`, and `hasMore`.
1122
+ The allowed limit is 1 through `maximumPageSize` (1,000). Changes are coalesced
1123
+ per run ID and ordered by revision. Tombstones persist indefinitely, including
1124
+ after ordinary run retention, so an offline consumer can resume its checkpoint.
1125
+ Source replacement or an ahead-of-source checkpoint fails with `invalid_run`.
1126
+
1127
+ ## RunCatalogRead
1128
+
1129
+ [src/RunCatalogRead.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/RunCatalogRead.ts)
1130
+
1131
+ Bounded execution pages and the preserved polling run set for a
1132
+ [`@smthrs/sync`](/api/smithers-sync) `RunCatalog`.
1133
+
1134
+ | Export | Signature | Meaning |
1135
+ | ---------------------------- | --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
1136
+ | `RunCatalogRead` | `Context.Service<Service>` | Service tag. |
1137
+ | `Service` | `listRunIds(options?)`, `listRuns(options?)` | Polling IDs or a coherent filtered execution page. |
1138
+ | `make` | `() => Effect<Service, never, SqlClient>` | Builds it over `flows_runs`. |
1139
+ | `layer` | `Layer<RunCatalogRead, never, SqlClient>` | Provides it. |
1140
+ | `ListOptions` | `{ limit? }` | Defaults to `defaultLimit`. |
1141
+ | `defaultLimit` | `10000` | |
1142
+ | `Filters` | Schema and type for status, flow, effective parent, lineage/root, waiting reason, and inclusive creation range. | All predicates run in SQL before pagination. |
1143
+ | `ListRunsOptions`, `RunPage` | `{ filters?, cursor?, limit? }`, page results and source watermark | Versioned source-bound keyset continuation. |
1144
+ | `maximumPageSize` | `200` | `listRuns` defaults to 100, without a total count. |
1145
+ | `RunCatalogError` | `invalid_options`, `invalid_cursor`, `source_changed`, `list_failed` | Typed failures preserve causes. |
1146
+
1147
+ `listRunIds` reads a set rather than a cursor tail, so retention of a run removes it from
1148
+ a follower's view. Rows come back newest first by rowid and are returned oldest
1149
+ first. Nothing here polls: the interval belongs to `RunCatalog.makePolling`.
1150
+
1151
+ `listRuns` orders by immutable creation time plus run ID. It decodes only the
1152
+ selected page plus one lookahead, with indexed ancillary reads scoped to those
1153
+ rows. Numeric offsets are rejected. Successive pages use live keyset semantics;
1154
+ each response is coherent at its own engine revision. Control-only admissions
1155
+ and the control projection are a separate integration.
1156
+
1157
+ Full observation, listing, lag, retention, and cursor contract:
1158
+ [Observe executions and page runs](./guides/observe-executions.md).
1159
+
1160
+ ## DisasterRecovery
1161
+
1162
+ [src/DisasterRecovery.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/DisasterRecovery.ts)
1163
+
1164
+ Hot backup, verification, restore, and restore-time fencing.
1165
+
1166
+ | Export | Signature |
1167
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------- |
1168
+ | `backup` | `(options: BackupOptions<R, E>) => Effect<BackupManifest, DisasterRecoveryError \| E, SqlClient \| FileSystem \| Crypto \| R>` |
1169
+ | `verify` | `(backupDirectory: string, options?: FileSizeOptions) => Effect<BackupManifest, DisasterRecoveryError, FileSystem \| Crypto>` |
1170
+ | `restore` | `(options: RestoreOptions) => Effect<RestoredStore, DisasterRecoveryError, FileSystem \| Crypto>` |
1171
+ | `fence` | `(manifest: BackupManifest) => Effect<FenceSummary, DisasterRecoveryError, SqlClient \| DurableWriter>` |
1172
+ | `restoreAndFence` | `(options: RestoreAndFenceOptions<R, E>) => Effect<FencedRestoredStore, DisasterRecoveryError \| E, FileSystem \| Crypto \| R>` |
1173
+
1174
+ | Constant | Value |
1175
+ | ------------------------- | ---------------------------------------------------------------------- |
1176
+ | `databaseFileName` | `store.sqlite3` |
1177
+ | `manifestFileName` | `manifest.json`, written last, so its presence marks a complete backup |
1178
+ | `objectsDirectoryName` | `objects` |
1179
+ | `restoredMarkerFileName` | `restored.json` |
1180
+ | `defaultMaxFileSizeBytes` | 512 MiB |
1181
+
1182
+ | Type | Fields |
1183
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1184
+ | `FileSizeOptions` | `maxFileSizeBytes?`, a finite non-negative safe integer |
1185
+ | `BackupOptions<R, E>` | `directory`, `objectsDirectory?`, `snapshotDatabaseLayer`, plus `FileSizeOptions` |
1186
+ | `RestoreOptions` | `backupDirectory`, `targetDirectory`, plus `FileSizeOptions` |
1187
+ | `RestoreAndFenceOptions<R, E>` | `RestoreOptions` plus `databaseLayer` |
1188
+ | `RestoredStore` | `{ databaseFile, objectsDirectory, manifest }` |
1189
+ | `FencedRestoredStore` | `RestoredStore` plus `fence: FenceSummary` |
1190
+ | `FenceSummary` | `{ clearedClaims, suspendedRuns }` |
1191
+ | `BackupManifest` | `{ formatVersion: 1, createdAtMs, database: { file, sha256, sizeBytes, migrations }, artifacts }` |
1192
+ | `AppliedMigration` | `{ migrationId, name }` |
1193
+ | `ArtifactEntry` | `{ digest, sizeBytes }` |
1194
+ | `DisasterRecoveryError` | `code` of `invalid_options`, `not_empty`, `invalid_manifest`, `missing_file`, `digest_mismatch`, `artifact_corruption`, `snapshot_incomplete`, `schema_mismatch`, `io`, or `sql`, plus the `method` that raised it |
1195
+
1196
+ The database is snapshotted with `VACUUM INTO`, a read transaction under WAL, so
1197
+ live writers are never blocked. The artifact walk runs after it, because results
1198
+ reference artifacts only after publication. With an `objectsDirectory` the whole
1199
+ capture holds the cross-process artifact backup lease; without one no lease is
1200
+ taken, and a frozen snapshot that references any artifact digest fails with
1201
+ `snapshot_incomplete` instead of reporting success.
1202
+
1203
+ Host access arrives through Effect's `FileSystem` and `SqlClient` tags and
1204
+ hashing through the injected `Crypto` service, so the module carries no platform
1205
+ binding. The SQL dialect is SQLite; a non-SQLite backend fails with the `sql`
1206
+ code rather than pretending to snapshot.
1207
+
1208
+ Full guide: [Back up and restore the store](./guides/back-up-and-restore.md).
1209
+
1210
+ ## Inconsistency
1211
+
1212
+ [src/Inconsistency.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/Inconsistency.ts)
1213
+
1214
+ The receiver for cache conflicts and corrupt evidence.
1215
+
1216
+ ```ts
1217
+ interface Service {
1218
+ readonly note: (event: CacheConflict) => Effect<InconsistencyVerdict, JournalError>
1219
+ readonly noteCorruption: (event: BlobCorruption) => Effect<InconsistencyVerdict, JournalError>
1220
+ }
1221
+ ```
1222
+
1223
+ | Export | Signature | Meaning |
1224
+ | --------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
1225
+ | `Inconsistency` | `Context.Service<Service>` | Service tag. |
1226
+ | `make` | `(options: MakeOptions) => Service` | Journals every conflict under the run that attempted the write and returns a fixed verdict. |
1227
+ | `makeNoop` | `(overrides?: Partial<Service>) => Service` | Notes nothing and tolerates. |
1228
+ | `layerNoop` | `(overrides?: Partial<Service>) => Layer<Inconsistency>` | Provides it. |
1229
+ | `layerStrict` | `(owner: Ownership.OwnerId) => Layer<Inconsistency, never, Journal>` | Journals and fails. The default for engine wiring. |
1230
+ | `layerTolerant` | `(owner: Ownership.OwnerId) => Layer<Inconsistency, never, Journal>` | Journals and continues, preserving the first-recorded row. |
1231
+
1232
+ | Type | Fields |
1233
+ | ---------------------- | ------------------------------------------------------------------------------------------------------- |
1234
+ | `InconsistencyVerdict` | `"fail"` or `"tolerate"` |
1235
+ | `MakeOptions` | `{ journal, verdict, owner }`. The owner is required: every composer of this receiver is a run's owner. |
1236
+ | `CacheConflict` | `{ key, existing, attempted }` |
1237
+ | `BlobCorruption` | `{ runId, keyDigest, path, recordedDigest, measuredDigest, recordedRunId?, recordedEventSeq? }` |
1238
+
1239
+ The record goes through the journal's durable channel, so a `tolerate` verdict
1240
+ cannot silently drop its only record. For `noteCorruption`, `"fail"` fails the
1241
+ dispatch and `"tolerate"` lets it fall back to a real execution, which
1242
+ re-captures and heals the corrupt address.
1243
+
1244
+ ## ReplayOnly
1245
+
1246
+ [src/ReplayOnly.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/ReplayOnly.ts)
1247
+
1248
+ An engine composed with this service replays recorded work and executes none.
1249
+ `smthrs runs verify` drives a copy of a run's store with it to report which
1250
+ recorded steps the current code would replay and which step it would execute
1251
+ again.
1252
+
1253
+ ```ts
1254
+ interface Service {
1255
+ readonly observe: (dispatch: Dispatch) => Effect<void>
1256
+ }
1257
+ ```
1258
+
1259
+ | Export | Signature | Meaning |
1260
+ | -------------- | ---------------------------------------------------------- | ------------------------------------------------------------ |
1261
+ | `ReplayOnly` | `Context.Service<Service>` | Service tag, resolved when the engine is composed. |
1262
+ | `layer` | `(observe: Service["observe"]) => Layer<ReplayOnly>` | Provides it. |
1263
+ | `WouldExecute` | `TaggedError<{ runId, stepKeyDigest, attempt, action }>` | The defect a dispatch dies with instead of running a body. |
1264
+ | `Dispatch` | `{ runId, stepKeyDigest, attempt, action, tier, outcome }` | `outcome` is `"replayed"`, `"resumes"` or `"would-execute"`. |
1265
+
1266
+ A dispatch served from a durable record, a recorded failure included, reports
1267
+ `replayed`. The first dispatch that would run a body dies before its attempt
1268
+ row, snapshot, boundary, or body: it reports `resumes` when it would re-enter a
1269
+ recorded attempt that never finished, such as a step parked inside its body,
1270
+ and `would-execute` when no record matches its key. The defect is never
1271
+ retried, so the run settles `failed` instead of spinning in its retry policy.
1272
+ Replays still write the journal rows a resume converges on, so drive a copy of
1273
+ the store, never the original.
1274
+
1275
+ ## OwnerIdentity
1276
+
1277
+ [src/OwnerIdentity.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/OwnerIdentity.ts)
1278
+
1279
+ Mints the `OwnerId` an incarnation fences its writes with.
1280
+
1281
+ | Export | Signature | Meaning |
1282
+ | ----------------- | ------------------------------------------------------- | ------------------------------------------------------------------- |
1283
+ | `OwnerIdentity` | `Context.Service<Service>` | Service tag. |
1284
+ | `Service` | `{ ownerId: (hostId: string) => Effect<OwnerId> }` | The host supplies the incarnation; the caller supplies the host id. |
1285
+ | `make` | `(service: Service) => Service` | Brands an implementation. |
1286
+ | `makeIncarnation` | `(pid: number \| undefined, crypto: Crypto) => Service` | The standard source over an explicitly supplied process id. |
1287
+ | `layer` | `Layer<OwnerIdentity, never, Crypto>` | The platform default. |
1288
+ | `layerConstant` | `(owner: OwnerId) => Layer<OwnerIdentity>` | Pins the whole token. |
1289
+
1290
+ The process id is read off `globalThis` rather than through a bare `process`
1291
+ reference, so the module carries no Node binding: a browser bundle sees
1292
+ `undefined` and draws an incarnation number from `Random` instead. The read
1293
+ happens at layer construction, so importing the module touches nothing. The
1294
+ nonce is a UUIDv4 from the injected `Crypto` service.
1295
+
1296
+ ## WakeBus
1297
+
1298
+ [src/WakeBus.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/WakeBus.ts)
1299
+
1300
+ Edge-triggered in-process wakes, with durable polling as the miss-tolerant
1301
+ fallback.
1302
+
1303
+ | Export | Signature | Meaning |
1304
+ | ------------ | -------------------------------------------------- | ------------------------------------------- |
1305
+ | `WakeBus` | `Context.Service<Service>` | Service tag. |
1306
+ | `Service` | `{ wake, awaitWake, waiters }` | See below. |
1307
+ | `makeUnsafe` | `() => Service` | Constructs a bus. Nothing is durable. |
1308
+ | `make` | `Effect<Service>` | The same, as an effect. |
1309
+ | `layer` | `Layer<WakeBus>` | Provides a fresh bus. |
1310
+ | `makeNoop` | `(overrides?: Partial<Service>) => Service` | Wakes are dropped and waiters park forever. |
1311
+ | `layerNoop` | `(overrides?: Partial<Service>) => Layer<WakeBus>` | Provides it. |
1312
+
1313
+ `wake(executionId)` resumes every waiter parked on that execution; with no
1314
+ waiters the wake is dropped. `awaitWake(executionId)` parks until the next one,
1315
+ and registration is removed when the waiting fiber is interrupted, so an
1316
+ abandoned wait leaks nothing. The wait is keyed by execution id alone, because
1317
+ execution ids are unique across flows. `waiters(executionId)` is observability
1318
+ for tests and diagnostics, not a coordination primitive.
1319
+
1320
+ An engine composition resolves the bus optionally, so providing `layer` is how a
1321
+ host shares one bus between the engine and its own wake sources. Cross-process
1322
+ delivery stays store-driven.
1323
+
1324
+ ## EngineStoreMetrics
1325
+
1326
+ [src/EngineStoreMetrics.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/EngineStoreMetrics.ts)
1327
+
1328
+ Metric handles and observation combinators for the engine hot paths. Exporters
1329
+ remain host-owned.
1330
+
1331
+ | Export | Kind |
1332
+ | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
1333
+ | `ExitTag` | `"Success" \| "Failure" \| "Interrupt"` |
1334
+ | `exitTag` | `<A, E>(exit: Exit<A, E>) => ExitTag` |
1335
+ | `observe` | `(instruments: { timer, counter }) => <A, E, R>(effect: Effect<A, E, R>) => Effect<A, E, R>` |
1336
+ | `dispatches`, `dispatchDuration`, `dispatch` | counter, timer, and views keyed by `ExitTag` |
1337
+ | `schedulerAdmissions`, `schedulerDispatchDuration` | counter and timer |
1338
+ | `schedulerNodes`, `node` | counter and views keyed by `PlanScheduler.Outcome` |
1339
+ | `sandboxExecutions`, `sandboxExecutionDuration`, `sandboxExecution` | counter, timer, and views keyed by `ExitTag` |
1340
+ | `sandboxMaterializations`, `materializationDuration`, `materialization` | counter, timer, and views keyed by `ExitTag` |
1341
+ | `materializationConflicts` | counter |
1342
+ | `boundarySettlements`, `boundarySettlement` | counter and views keyed by `Clean`, `Deviation`, `Violation`, `Refused` |
1343
+ | `stepCacheDecisions`, `stepCacheDecision` | counter and views keyed by `VerifiedHit`, `Miss`, `UnverifiableEvidence`, `Unmeasurable`, `StaleReadSet`, `ReplayFailed` |
1344
+ | `claims`, `claim` | counter and views keyed by `Activated`, `Terminal`, `HeartbeatFresh`, `StealRefusedOwnerAlive`, `ClaimLost`, `ActivationLost` |
1345
+
1346
+ Outcome tags are rewritten as snake case attribute values, so `HeartbeatFresh`
1347
+ is recorded as `heartbeat_fresh`. `observe` composes `Effect.trackDuration` with
1348
+ an exit counter update and a span annotation, and propagates the instrumented
1349
+ effect's exit byte-identically.
1350
+
1351
+ Full guide: [Observe engine metrics](./guides/observe-engine-metrics.md).
1352
+
1353
+ ## Migrations
1354
+
1355
+ [src/Migrations.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/Migrations.ts)
1356
+
1357
+ | Export | Signature | Meaning |
1358
+ | ------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
1359
+ | `set` | `MigrationSet` | This package's own set, namespace `engine-store`, migration id block `3000`. |
1360
+ | `sets` | `ReadonlyArray<MigrationSet>` | The complete durable engine schema in dependency order: journal, run store, step cache, this package, then the plan store. |
1361
+ | `run` | the migration effect | |
1362
+ | `layer` | `Layer` | Installs the complete schema before exposing the database to any durable service. |
1363
+
1364
+ This package's own set creates deferred/clock state, selection beliefs, and the
1365
+ `flows_plan_input_heads`, `flows_plan_input_generations`, and
1366
+ `flows_plan_input_legacy_runs` recovery tables. The plan set's block (`4000`)
1367
+ comes last. The database loader supports forward additions to an already
1368
+ installed lower block, so migrations `3003` and `3004` also run on existing installations
1369
+ whose global cursor reached `4003`; earlier holes remain refusals. See
1370
+ [`@smthrs/database`](/api/database) for how namespaced sets compose without
1371
+ colliding.
1372
+
1373
+ ## RunState
1374
+
1375
+ [src/RunState.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/RunState.ts)
1376
+
1377
+ The versioned state envelope stored in each run row.
1378
+
1379
+ | Export | Shape |
1380
+ | -------------- | ---------------------------------------------------------------------------------------------------------- |
1381
+ | `RunState` | `{ version: 1, flowName, payload, parentExecutionId?, onParentExit?, maxRounds?, result?, cancellation? }` |
1382
+ | `OnParentExit` | `"cancel"` or `"detach"` |
1383
+
1384
+ `ReleaseCause` is why a driver released a run it still owned, recorded as the
1385
+ optional `cause` of its `interrupt-released` run decision:
1386
+ `{ kind: "lease-lapsed", unconfirmedMs }` when the host went that long without
1387
+ confirming its run lease, or `{ kind: "interrupted" }` for any other
1388
+ non-cancel interruption, usually a host shutdown. `releaseCauseOf(decision)`
1389
+ reads it and answers `undefined` for decisions recorded before the field
1390
+ existed.
1391
+
1392
+ `parentExecutionId` is present only on a child run. `onParentExit` is recorded
1393
+ at first admission, including independent runs that a later caller may join as
1394
+ a child: the parent's terminal transition reads it to decide whether the child
1395
+ ends with it. The policy is recorded on the child rather than on the edge,
1396
+ because it is a property of how the child was started and because a child with
1397
+ two parents must answer the question once. Missing policies on legacy rows
1398
+ default to `"cancel"`. A later caller awaiting or ensuring the run does not
1399
+ rewrite its recorded policy.
1400
+
1401
+ ## Errors
1402
+
1403
+ [src/Errors.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/Errors.ts)
1404
+
1405
+ The stable error contract. Every `code` literal here is public API: consumers
1406
+ may switch on `code` or `_tag`, and the strings will not change without a major
1407
+ version.
1408
+
1409
+ | Export | `code` | Fields |
1410
+ | ----------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------ |
1411
+ | `AttemptSuspended` | `attempt_suspended` | `runId`, `keyDigest`, `attempt` |
1412
+ | `AttemptAdmissionRejected` | `attempt_admission_rejected` | `keyDigest`, `outcome` |
1413
+ | `AttemptEvidenceQuarantined` | `attempt_evidence_quarantined` | `keyDigest`, `attempt`, `path`, `recordedDigest`, `measuredDigest` |
1414
+ | `CacheConflictDetected` | `cache_conflict_detected` | `keyDigest`, `recordedRunId` |
1415
+ | `CacheCorruptionDetected` | `cache_corruption_detected` | `keyDigest`, `path`, `recordedDigest`, `measuredDigest` |
1416
+ | `RetentionError`, `RetentionErrorCode` | `scan_failed`, `delete_failed` | |
1417
+ | `RunCatalogError`, `RunCatalogErrorCode` | `invalid_options`, `invalid_cursor`, `source_changed`, `list_failed` | `cause` when a decode or store operation failed. |
1418
+ | `IrreversibleRetryRequiresIdempotencyKey` | re-exported from [`@smthrs/flow`](/api/flow)'s `Action` | |
1419
+ | `FlowCycleDetected` | re-exported from [`@smthrs/flow`](/api/flow)'s `FlowRuntime` | |
1420
+
1421
+ Each failure, with its cause and its fix, is in
1422
+ [Troubleshooting](./troubleshooting.md).
1423
+
1424
+ ## test/TestStores
1425
+
1426
+ [src/test/TestStores.ts](https://github.com/smithersai/smithers/blob/main/packages/smithers/flows/engine-store/src/test/TestStores.ts)
1427
+
1428
+ Every durable engine service over one database, migrated.
1429
+
1430
+ | Export | Signature | Meaning |
1431
+ | ------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
1432
+ | `layer` | `(options?: TestStoresOptions) => Layer<...>` | The private in-memory bundle: journal, run, attempt, cache, plan, and plan-input stores plus `OwnerIdentity.layer`, keeping `SqlClient` to itself. |
1433
+ | `layerAt` | `(filename: string, options?: TestStoresOptions) => Layer<...>` | The same over a named database, with the connection and `DurableEngineState` re-exported. |
1434
+ | `database` | `Layer` | The migrated in-memory database alone, as `SqlClient` and `DurableWriter`. |
1435
+ | `databaseAt` | `(filename: string) => Layer` | The same over a named file. |
1436
+ | `TestStoresOptions` | `{ capacity?, overflow?, batchSize? }` | Forwarded to the journal. |
1437
+
1438
+ Use `layerAt` with a real file to point two independently constructed bundles at
1439
+ one database: two connections, two engines, no shared object graph, which is
1440
+ what a second process actually has. `:memory:` gives each connection its own
1441
+ private database, so it cannot prove anything durable across compositions.
1442
+
1443
+ Full guide: [Test against a durable store](./guides/testing.md).
1444
+
1445
+ ## Cache admission
1446
+
1447
+ The engine admits a cache record only when the action is sealed, the boundary is
1448
+ hard, no deviation occurred, and the evidence explicitly carries
1449
+ `wholeTreeWritesVerified: true`. Older evidence and boundaries that observe
1450
+ declared paths only are conservatively refused. Only a content-key record has an
1451
+ address another run can reproduce; an ordinal-key record remains run-local.
1452
+
1453
+ A cache hit is verified before it is served: the store calls `prepare` and
1454
+ compares the descriptor's declared `readSet` against the `readSnapshot` the host
1455
+ measured. Reuse happens only when every declared read still matches. Reads the
1456
+ host reports but the declaration never claimed are ignored, while a declared
1457
+ path that is missing or has a different digest refuses the hit, journals a
1458
+ `cache-provenance` record with `action: "stale_read_set"`, and falls through to a
1459
+ real execution. That is Skyframe's dirty-check invariant: the key alone detects a
1460
+ changed declaration, not a stale one.
1461
+
1462
+ A verified hit calls `replayOutputs` before returning the stored result. When
1463
+ that refuses with `MissingArtifact`, the dispatch hydrates from the shared tier
1464
+ and retries the replay exactly once before falling through to a real execution.
1465
+ A replay refused for confinement (a symlink on a replayed path, or a host that
1466
+ cannot be confined) journals `replay_failed` and executes the step for real;
1467
+ it never writes through the link.
1468
+
1469
+ Replaying a succeeded attempt row also converges the cache: if a crash landed
1470
+ between `attempts.finish` and `cache.put`, the restarted executor re-records the
1471
+ sealed completion with fresh cache provenance. A divergent first-recorded row
1472
+ surfaces through the [`Inconsistency`](#inconsistency) receiver, strict by
1473
+ default.
1474
+
1475
+ A persisted `failed` attempt row replays by rethrowing the persisted domain
1476
+ failure, never by readmission, so `AttemptAdmissionRejected` marks only
1477
+ genuinely mid-flight rows. The `Fail` errors were schema-encoded before
1478
+ persistence, so their `_tag` survives the JSON round trip and `RetryPolicy`
1479
+ non-retryable matching applies on replay. The composition also implements the
1480
+ engine's `actionLatestAttempt` and degrades `actionRetryOrigin` to the earliest
1481
+ surviving attempt row when a retention job pruned attempt 1.
1482
+
1483
+ Full model: [Cache admission](./concepts/cache-admission.md). See also
1484
+ [Run durably over SQLite](/docs/tutorials/first-flow/#6-run-durably-over-sqlite)
1485
+ and [Content addressing](/docs/concepts/content-addressing/).
1486
+
1487
+ ## Durable failure warnings
1488
+
1489
+ If an unsuccessful irreversible action cannot append its `unknown` boundary
1490
+ record, the engine logs at Warning with the append cause, `runId`, and the
1491
+ action key as `step`. The action's original failure or interruption remains
1492
+ the primary outcome. Reading a completed trampoline lineage whose terminal
1493
+ flow is unregistered dies with `FlowEngine.FlowNotRegistered`, carrying the
1494
+ missing `flowName`, so callers can classify the registration defect.