@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
@@ -0,0 +1,1165 @@
1
+ /**
2
+ * Hermetic step boundary contracts, the filesystem-backed production
3
+ * implementation, and the deterministic test implementation.
4
+ *
5
+ * @since 0.1.0
6
+ */
7
+
8
+ import * as ArtifactStore from "@smthrs/artifacts/ArtifactStore"
9
+ import { Sha256 } from "@smthrs/crypto"
10
+ import { FileBoundary } from "@smthrs/flow/FileBoundary"
11
+ import { FileInput } from "@smthrs/flow/FileInput"
12
+ import * as KernelFileSystem from "@smthrs/kernel/FileSystem"
13
+ import { Workspace as KernelWorkspace } from "@smthrs/kernel/Workspace"
14
+ import { DerivedKey } from "@smthrs/keys"
15
+ import * as FileSet from "@smthrs/plan/FileSet"
16
+ import * as Context from "effect/Context"
17
+ import type * as Crypto from "effect/Crypto"
18
+ import * as Effect from "effect/Effect"
19
+ import * as Encoding from "effect/Encoding"
20
+ import * as FileSystem from "effect/FileSystem"
21
+ import * as Layer from "effect/Layer"
22
+ import * as Path from "effect/Path"
23
+ import * as Result from "effect/Result"
24
+ import * as Schema from "effect/Schema"
25
+ import * as FileBoundarySnapshot from "./internal/FileBoundarySnapshot.ts"
26
+ import * as FileEnumeration from "./internal/FileEnumeration.ts"
27
+ import { compareText } from "./internal/Ordering.ts"
28
+
29
+ /**
30
+ * A file boundary that has been measured but not yet run: the caller's
31
+ * declaration, paired with what the host actually found on disk for it.
32
+ *
33
+ * `prepare` produces one of these before a step executes and `settle` consumes
34
+ * it afterwards, which is what lets the boundary say whether the world moved
35
+ * underneath the declaration. Check it with {@link readSetMatches}.
36
+ *
37
+ * @since 0.1.0
38
+ * @category schemas
39
+ */
40
+ export const PreparedBoundary = Schema.Struct({
41
+ descriptor: FileBoundary,
42
+ /**
43
+ * What the host actually measured for the declared read set at prepare
44
+ * time. The declared digests are caller metadata folded into the step key;
45
+ * this is the evidence that they still describe reality, and a sealed
46
+ * cache hit is refused when the two disagree (issue #90).
47
+ */
48
+ readSnapshot: Schema.Array(FileInput)
49
+ })
50
+
51
+ /**
52
+ * The value form of {@link PreparedBoundary}.
53
+ *
54
+ * @since 0.1.0
55
+ * @category models
56
+ */
57
+ export type PreparedBoundary = typeof PreparedBoundary.Type
58
+
59
+ /**
60
+ * Exact read inputs from a boundary after ignoring declarations that still need expansion.
61
+ *
62
+ * @category accessors
63
+ * @since 0.1.0
64
+ */
65
+ export const exactReads = (descriptor: FileBoundary): ReadonlyArray<FileInput> =>
66
+ descriptor.readSet.filter((entry): entry is FileInput => !FileSet.isGlob(entry))
67
+
68
+ /**
69
+ * Whether every declared read still matches what the host measured.
70
+ *
71
+ * Reads the host reports but the declaration never claimed are ignored: the
72
+ * declaration is the dependency edge set, and an incidental extra read is not
73
+ * one of its edges. A declared path missing from the measurement counts as a
74
+ * mismatch — its value is unknown, so reuse cannot be justified.
75
+ *
76
+ * @since 0.1.0
77
+ * @category predicates
78
+ */
79
+ export const readSetMatches = (prepared: PreparedBoundary): boolean => {
80
+ const digestsByPath = new Map<string, Set<string>>()
81
+ for (const measured of prepared.readSnapshot) {
82
+ const digests = digestsByPath.get(measured.path)
83
+ if (digests === undefined) digestsByPath.set(measured.path, new Set([measured.digest]))
84
+ else digests.add(measured.digest)
85
+ }
86
+ return prepared.descriptor.readSet.every((entry) =>
87
+ !FileSet.isGlob(entry) &&
88
+ digestsByPath.get(entry.path)?.has(entry.digest) === true
89
+ )
90
+ }
91
+
92
+ /**
93
+ * The paths a step wrote that its `expected` write set did not name, together
94
+ * with the diff identity they were observed under.
95
+ *
96
+ * An expected-mode boundary reports these rather than failing: the declaration
97
+ * is a prediction, and a wrong prediction is evidence to journal, not an
98
+ * error. A hard-mode boundary raises {@link UndeclaredWrite} for the same
99
+ * observation.
100
+ *
101
+ * @since 0.1.0
102
+ * @category schemas
103
+ */
104
+ export const ExpectedSetDeviation = Schema.TaggedStruct("ExpectedSetDeviation", {
105
+ paths: Schema.Array(Schema.String),
106
+ diffIdentity: Schema.NonEmptyString
107
+ })
108
+
109
+ /**
110
+ * Declared writes an expected-mode step did not produce, and did not declare
111
+ * as removals.
112
+ *
113
+ * The absence itself is the defect: recording it as valid evidence caches the
114
+ * claim "this file should not exist", which `replayOutputs` then acts on by
115
+ * deleting the path on a workspace that never ran the step. A hard-mode
116
+ * boundary raises {@link MissingDeclaredOutput} for the same observation.
117
+ *
118
+ * Expected mode records it rather than failing because the declaration there is
119
+ * a prediction — and because a deviation of any variant already bars the
120
+ * evidence from the shared cache (`ActionPersistence` gates `recordCache` on
121
+ * `deviation === undefined`), so an unexplained absence never reaches another
122
+ * host either way.
123
+ *
124
+ * @since 0.1.0
125
+ * @category schemas
126
+ */
127
+ export const MissingOutputDeviation = Schema.TaggedStruct("MissingDeclaredOutput", {
128
+ paths: Schema.Array(Schema.String),
129
+ diffIdentity: Schema.NonEmptyString
130
+ })
131
+
132
+ /**
133
+ * Declared removals an expected-mode step left in place.
134
+ *
135
+ * The dual of {@link MissingOutputDeviation}: a removal is a promise about the
136
+ * post-state exactly as a write is. A path that was promised absent but is
137
+ * still present — possibly mutated — must not settle as valid evidence, or
138
+ * the mutation is cached under a declaration that disclaimed it and replay
139
+ * materializes it everywhere. A hard-mode boundary raises
140
+ * {@link SurvivingDeclaredRemoval} for the same observation.
141
+ *
142
+ * @since 0.1.0
143
+ * @category schemas
144
+ */
145
+ export const SurvivingRemovalDeviation = Schema.TaggedStruct("SurvivingDeclaredRemoval", {
146
+ paths: Schema.Array(Schema.String),
147
+ diffIdentity: Schema.NonEmptyString
148
+ })
149
+
150
+ /**
151
+ * What a settled boundary observed that its declaration did not predict.
152
+ *
153
+ * @since 0.1.0
154
+ * @category schemas
155
+ */
156
+ export const BoundaryDeviation = Schema.Union([ExpectedSetDeviation, MissingOutputDeviation, SurvivingRemovalDeviation])
157
+
158
+ /**
159
+ * The value form of {@link BoundaryDeviation}.
160
+ *
161
+ * @since 0.1.0
162
+ * @category models
163
+ */
164
+ export type BoundaryDeviation = typeof BoundaryDeviation.Type
165
+
166
+ /**
167
+ * What a settled boundary proved about a step's writes — the record the
168
+ * journal keeps and a later cache hit is justified against.
169
+ *
170
+ * `diffIdentity` names the post-state the step produced; `declaredOutputs`
171
+ * carries whatever the implementation needs to reproduce it on a workspace
172
+ * that never ran the step. The two optional fields are the honest gaps:
173
+ * `wholeTreeWritesVerified` is present only when the boundary could observe
174
+ * the entire execution tree, and `deviation` only when it saw writes the
175
+ * declaration did not predict.
176
+ *
177
+ * @since 0.1.0
178
+ * @category schemas
179
+ */
180
+ export const BoundaryEvidence = Schema.Struct({
181
+ declaredOutputs: Schema.Unknown,
182
+ diffIdentity: Schema.NonEmptyString,
183
+ /**
184
+ * The boundary observed the whole execution tree and proved that every
185
+ * write was covered by the descriptor's write set. Only evidence carrying
186
+ * this explicit proof may enter the cross-run cache. Older evidence and
187
+ * boundaries that can inspect declared paths only omit it.
188
+ */
189
+ wholeTreeWritesVerified: Schema.optional(Schema.Literal(true)),
190
+ /** The body could observe only declared filesystem inputs. */
191
+ hermeticReadsVerified: Schema.optional(Schema.Literal(true)),
192
+ deviation: Schema.optional(BoundaryDeviation)
193
+ })
194
+
195
+ /**
196
+ * The value form of {@link BoundaryEvidence}.
197
+ *
198
+ * @since 0.1.0
199
+ * @category models
200
+ */
201
+ export type BoundaryEvidence = typeof BoundaryEvidence.Type
202
+
203
+ /**
204
+ * A hard-mode step wrote outside its declared write set.
205
+ *
206
+ * Hard mode treats the declaration as a contract, so this is a refusal, not a
207
+ * report: the step's evidence is never journaled and never becomes a cache
208
+ * entry. An expected-mode boundary records the same observation as a
209
+ * {@link BoundaryDeviation} instead.
210
+ *
211
+ * @since 0.1.0
212
+ * @category errors
213
+ */
214
+ export class UndeclaredWrite extends Schema.TaggedError<UndeclaredWrite>()(
215
+ "@smthrs/engine-store/UndeclaredWrite",
216
+ {
217
+ code: Schema.Literal("undeclared_write"),
218
+ paths: Schema.Array(Schema.String),
219
+ diffIdentity: Schema.NonEmptyString
220
+ }
221
+ ) {}
222
+
223
+ /**
224
+ * A step finished without producing a path its write set declared, and did not
225
+ * declare that path as a removal.
226
+ *
227
+ * Bazel hard-fails the same observation — `SkyframeActionExecutor.checkOutputs`
228
+ * reports "output was not created" — and for the same reason: the alternative
229
+ * is to record `digest: null` as valid evidence, which caches the claim "this
230
+ * file should not exist" and makes every later replay delete the path. A step
231
+ * that crashed after declaring its writes would poison the cache with an
232
+ * eraser.
233
+ *
234
+ * Declaring the path in {@link FileBoundary}'s `removes` is how a deliberate
235
+ * deletion says so, and it is the only thing that makes the absence legitimate.
236
+ *
237
+ * @since 0.1.0
238
+ * @category errors
239
+ */
240
+ export class MissingDeclaredOutput extends Schema.TaggedError<MissingDeclaredOutput>()(
241
+ "@smthrs/engine-store/MissingDeclaredOutput",
242
+ {
243
+ code: Schema.Literal("missing_declared_output"),
244
+ paths: Schema.Array(Schema.String),
245
+ diffIdentity: Schema.NonEmptyString
246
+ }
247
+ ) {}
248
+
249
+ /**
250
+ * A hard-mode step left a declared removal in place.
251
+ *
252
+ * The dual of {@link MissingDeclaredOutput}: `removes` promises the path is
253
+ * absent afterwards, and a path that survived — or was quietly rewritten —
254
+ * is a post-state the declaration disclaimed. Settling it as evidence would
255
+ * cache the surviving bytes under a removal and hand them to every replay.
256
+ *
257
+ * @since 0.1.0
258
+ * @category errors
259
+ */
260
+ export class SurvivingDeclaredRemoval extends Schema.TaggedError<SurvivingDeclaredRemoval>()(
261
+ "@smthrs/engine-store/SurvivingDeclaredRemoval",
262
+ {
263
+ code: Schema.Literal("surviving_declared_removal"),
264
+ paths: Schema.Array(Schema.String),
265
+ diffIdentity: Schema.NonEmptyString
266
+ }
267
+ ) {}
268
+
269
+ /**
270
+ * The host could not honour the boundary at all — a filesystem that cannot be
271
+ * measured, a path that cannot be read, a transient I/O failure.
272
+ *
273
+ * It is the catch-all host refusal, deliberately kept distinct from the two
274
+ * refusals a caller can act on: {@link BoundaryCorruption} (the bytes changed
275
+ * under a recorded digest) and {@link MissingArtifact} (the bytes might be
276
+ * fetchable from a shared tier).
277
+ *
278
+ * @since 0.1.0
279
+ * @category errors
280
+ */
281
+ export class UnsupportedBoundary extends Schema.TaggedError<UnsupportedBoundary>()(
282
+ "@smthrs/engine-store/UnsupportedBoundary",
283
+ {
284
+ code: Schema.Literal("unsupported_boundary"),
285
+ message: Schema.String,
286
+ /**
287
+ * The refusing host or artifact-store failure, carried whole rather than
288
+ * flattened into the message (`PlatformError`'s own convention), so the
289
+ * journal record and a live debugger both see the original error.
290
+ */
291
+ cause: Schema.optional(Schema.Defect())
292
+ }
293
+ ) {}
294
+
295
+ /**
296
+ * Recorded boundary evidence whose bytes no longer match their recorded
297
+ * digest — an integrity violation of the store's strongest invariant, as
298
+ * opposed to a transient host failure (issue #150). The two classes were
299
+ * previously conflated under one `UnsupportedBoundary` tag, so a failing
300
+ * disk corrupting many blobs journalled identically to a one-off EIO.
301
+ *
302
+ * @since 0.1.0
303
+ * @category errors
304
+ */
305
+ export class BoundaryCorruption extends Schema.TaggedError<BoundaryCorruption>()(
306
+ "@smthrs/engine-store/BoundaryCorruption",
307
+ {
308
+ code: Schema.Literal("boundary_corruption"),
309
+ path: Schema.String,
310
+ recordedDigest: Schema.String,
311
+ measuredDigest: Schema.String
312
+ }
313
+ ) {}
314
+
315
+ /**
316
+ * Recorded evidence references an artifact this host's store does not hold
317
+ * (issue #172). Distinct from {@link UnsupportedBoundary} because it is the one
318
+ * replay refusal a *shared artifact tier* can repair: the caller fetches the
319
+ * blob from the remote store, writes it back locally, and retries the replay
320
+ * once before falling through to a real execution. Every other host refusal
321
+ * says nothing about where the bytes might be.
322
+ *
323
+ * @since 0.1.0
324
+ * @category errors
325
+ */
326
+ export class MissingArtifact extends Schema.TaggedError<MissingArtifact>()(
327
+ "@smthrs/engine-store/MissingArtifact",
328
+ {
329
+ code: Schema.Literal("missing_artifact"),
330
+ path: Schema.String,
331
+ digest: Schema.String
332
+ }
333
+ ) {}
334
+
335
+ /**
336
+ * The three-call lifecycle of a hermetic step boundary.
337
+ *
338
+ * `prepare` measures the declared read set before the step runs; `settle`
339
+ * measures the writes afterwards and turns them into {@link BoundaryEvidence};
340
+ * `replayOutputs` reproduces a previous step's outputs from that evidence, so
341
+ * a cache hit can materialize results on a workspace that never executed
342
+ * anything.
343
+ *
344
+ * @since 0.1.0
345
+ * @category services
346
+ */
347
+ export interface Service {
348
+ readonly prepare: (
349
+ descriptor: FileBoundary
350
+ ) => Effect.Effect<PreparedBoundary, UnsupportedBoundary, Crypto.Crypto>
351
+ readonly settle: (
352
+ prepared: PreparedBoundary
353
+ ) => Effect.Effect<
354
+ BoundaryEvidence,
355
+ UndeclaredWrite | MissingDeclaredOutput | SurvivingDeclaredRemoval | UnsupportedBoundary | BoundaryCorruption,
356
+ Crypto.Crypto
357
+ >
358
+ readonly replayOutputs: (
359
+ evidence: BoundaryEvidence
360
+ ) => Effect.Effect<void, UnsupportedBoundary | BoundaryCorruption | MissingArtifact, Crypto.Crypto>
361
+ }
362
+
363
+ /**
364
+ * The service key for a {@link Service}. Provide it with `layer` for
365
+ * a real workspace or `layerTest` for a deterministic in-memory one.
366
+ *
367
+ * @since 0.1.0
368
+ * @category services
369
+ */
370
+ export const StepBoundary: Context.Service<Service, Service> = Context.Service<Service>(
371
+ "@smthrs/engine-store/StepBoundary"
372
+ )
373
+
374
+ /**
375
+ * Brands a {@link Service} implementation as a `StepBoundary`, so a new
376
+ * boundary backend is type-checked where it is written rather than where it is
377
+ * provided.
378
+ *
379
+ * @since 0.1.0
380
+ * @category constructors
381
+ */
382
+ export const make = (service: Service): Service => StepBoundary.of(service)
383
+
384
+ /**
385
+ * The digest a measurement reports for a declared path that does not exist.
386
+ * Declared digests are hex SHA-256 strings, so the sentinel can never
387
+ * collide with a real measurement — a declaration naming a vanished file
388
+ * always mismatches and the cache hit is refused.
389
+ */
390
+ const absentDigest = "absent"
391
+
392
+ /**
393
+ * The persisted shape of the production layer's `declaredOutputs`: the
394
+ * declared write set's materialized post-state, so a cache-hit replay can
395
+ * reproduce the outputs on a workspace that never ran the step.
396
+ *
397
+ * Outputs are recorded by content digest, never inlined unbounded
398
+ * (issue #113): a `null` digest records that the path did not exist at
399
+ * settle time; `content` (base64) is present only when the payload fits the
400
+ * configured inline bound, otherwise the bytes live in the host's
401
+ * content-addressed object directory under the digest and the row carries
402
+ * only the reference. Temporal's blob-size limits are the prior art — the
403
+ * evidence is persisted into every attempt row and cache entry.
404
+ *
405
+ * The digest is decoded against the store's strict address schema
406
+ * (`ArtifactStore.Digest`), so a persisted row carrying a malformed address
407
+ * fails the decode here instead of reaching the store or the sync RPCs.
408
+ */
409
+ const DigestReferencedOutput = Schema.Struct({
410
+ path: Schema.String,
411
+ digest: Schema.NullOr(ArtifactStore.Digest),
412
+ sizeBytes: Schema.optional(Schema.Number),
413
+ content: Schema.optional(Schema.String)
414
+ })
415
+
416
+ const MaterializedOutputs = Schema.Struct({
417
+ outputs: Schema.Array(DigestReferencedOutput),
418
+ trees: Schema.optional(Schema.Array(Schema.Struct({
419
+ path: Schema.String,
420
+ identity: Schema.String
421
+ })))
422
+ })
423
+
424
+ /**
425
+ * The directory portion of a slash-separated path, or `undefined` for a
426
+ * bare filename (nothing to create). Boundary paths are workspace-relative
427
+ * and slash-separated — the same normalization the kernel `FileSystem`
428
+ * layer applies.
429
+ */
430
+ const parentDirectory = (path: string): string | undefined => {
431
+ const index = path.lastIndexOf("/")
432
+ return index <= 0 ? undefined : path.slice(0, index)
433
+ }
434
+
435
+ const hostFailure = (cause: unknown): UnsupportedBoundary =>
436
+ new UnsupportedBoundary({
437
+ code: "unsupported_boundary",
438
+ message: "the host filesystem could not enforce the step boundary",
439
+ cause
440
+ })
441
+
442
+ /**
443
+ * An artifact store that refused the operation outright — a failing disk, an
444
+ * unreachable shared tier, an address that is not a content address. Unlike a
445
+ * miss or a corruption it says nothing about the artifact, so it stays the
446
+ * ordinary retryable host refusal the issue-#107 call sites already handle.
447
+ */
448
+ const artifactFailure = (cause: ArtifactStore.ArtifactStoreError): UnsupportedBoundary =>
449
+ new UnsupportedBoundary({
450
+ code: "unsupported_boundary",
451
+ message: `the artifact store could not serve the step boundary: ${cause.message}`,
452
+ cause
453
+ })
454
+
455
+ /**
456
+ * Corruption of an *inline* evidence payload (issue #159): the recorded
457
+ * base64 no longer decodes, so there are no bytes to measure a digest of —
458
+ * the `invalid_base64` sentinel records that the measurement itself was
459
+ * impossible, which is still cache-origin corruption and never a transient
460
+ * host refusal.
461
+ */
462
+ const inlineCorruption = (path: string, recordedDigest: string): BoundaryCorruption =>
463
+ new BoundaryCorruption({
464
+ code: "boundary_corruption",
465
+ path,
466
+ recordedDigest,
467
+ measuredDigest: "invalid_base64"
468
+ })
469
+
470
+ /**
471
+ * The two size bounds that decide when a settled output is inlined into
472
+ * boundary evidence and when it is spilled to the `ArtifactStore` by digest.
473
+ *
474
+ * Both default to values that keep an evidence row small enough to journal;
475
+ * raise them only when the workspace's outputs are known to be small and the
476
+ * extra artifact round-trip is measurably costing something.
477
+ *
478
+ * @since 0.1.0
479
+ * @category models
480
+ */
481
+ export interface FileSystemOptions {
482
+ /**
483
+ * The largest output (in bytes) inlined into the boundary evidence
484
+ * itself. Anything larger is handed to the `ArtifactStore` and recorded by
485
+ * digest reference only (issue #113). Defaults to 1 MiB.
486
+ */
487
+ readonly maxInlineBytes?: number | undefined
488
+ /**
489
+ * The largest *aggregate* inline payload (in bytes) a single settle may
490
+ * fold into its boundary evidence (issue #122). A per-output bound alone
491
+ * still let a wide write set multiply many individually-small payloads
492
+ * into an unbounded evidence row; once an output would push the running
493
+ * total past this bound it is spilled to the `ArtifactStore` and
494
+ * recorded by digest reference only, even though it individually fits
495
+ * {@link maxInlineBytes}. Defaults to 8 MiB.
496
+ */
497
+ readonly maxTotalInlineBytes?: number | undefined
498
+ /**
499
+ * The workspace root cache replay confines its writes, removals, and prune
500
+ * walk to. A filesystem already confined to a root (the kernel-guarded
501
+ * layer's service, or a `confined` view) keeps its own root and ignores
502
+ * this. Otherwise it defaults to the process working directory, the root a
503
+ * path-based host resolves `prepare` and `settle` against. {@link layer}
504
+ * passes the kernel `Workspace` root when one is in context.
505
+ */
506
+ readonly root?: string | undefined
507
+ }
508
+
509
+ const defaultMaxInlineBytes = 1024 * 1024
510
+ const defaultMaxTotalInlineBytes = 8 * 1024 * 1024
511
+ interface MeasuredDigest {
512
+ readonly digest: ArtifactStore.Digest
513
+ readonly bytes: Uint8Array
514
+ }
515
+
516
+ interface BatchedDigest {
517
+ readonly digest: ArtifactStore.Digest
518
+ readonly sizeBytes: number
519
+ readonly bytes?: Uint8Array
520
+ }
521
+
522
+ type MaterializedOutput = typeof DigestReferencedOutput.Type
523
+
524
+ /**
525
+ * The digests this evidence references rather than inlines — the set that must
526
+ * be durable in a shared artifact tier before the evidence's cache entry
527
+ * becomes observable there, and the set a replay on a fresh host has to fetch.
528
+ *
529
+ * Evidence recorded by a foreign boundary implementation references nothing
530
+ * this store can name, so it yields the empty list rather than failing: the
531
+ * caller's replay path already refuses such evidence with
532
+ * {@link UnsupportedBoundary}.
533
+ *
534
+ * @since 0.1.0
535
+ * @category accessors
536
+ */
537
+ export const referencedDigests = (evidence: BoundaryEvidence): ReadonlyArray<ArtifactStore.Digest> => {
538
+ const decoded = Schema.decodeUnknownResult(MaterializedOutputs)(evidence.declaredOutputs)
539
+ if (decoded._tag === "Failure") return []
540
+ const digests: Array<ArtifactStore.Digest> = []
541
+ for (const output of decoded.success.outputs) {
542
+ if (output.digest === null || output.content !== undefined) continue
543
+ digests.push(output.digest)
544
+ }
545
+ return digests
546
+ }
547
+
548
+ /**
549
+ * Builds the filesystem-backed boundary service.
550
+ *
551
+ * The blob mechanics — content addressing, atomic publication, digest
552
+ * verification, dedupe — belong to `artifacts` and were extracted into
553
+ * `@smthrs/artifacts` (`packages/smithers/flows/artifacts/docs/api.md`). What stays here
554
+ * is the *policy* that decides which outputs become blobs at all: the
555
+ * inline-versus-spill budgets are a property of how large an evidence row may
556
+ * get, not of how bytes are stored.
557
+ *
558
+ * @since 0.1.0
559
+ * @category constructors
560
+ */
561
+ export const makeFileSystem = (
562
+ fs: FileSystem.FileSystem,
563
+ platformPath: Path.Path,
564
+ artifacts: ArtifactStore.Service,
565
+ options: FileSystemOptions = {}
566
+ ): Service => {
567
+ const maxInlineBytes = options.maxInlineBytes ?? defaultMaxInlineBytes
568
+ const maxTotalInlineBytes = options.maxTotalInlineBytes ?? defaultMaxTotalInlineBytes
569
+ // Stat tuples are not content identities: a same-size rewrite can preserve
570
+ // mtime, device, and inode on every supported filesystem.
571
+ const readDigestFrom = Effect.fn("StepBoundary.readDigest")(function*(host: FileSystem.FileSystem, path: string) {
572
+ const bytes = yield* host.readFile(path)
573
+ const digest = yield* Schema.decodeUnknownEffect(Sha256)(bytes).pipe(Effect.orDie)
574
+ return { digest, bytes } satisfies MeasuredDigest
575
+ })
576
+ const readDigest = (path: string) => readDigestFrom(fs, path)
577
+ const batch = KernelFileSystem.batch(fs)
578
+ const measurements = Effect.fn("StepBoundary.measurements")(
579
+ function*(paths: ReadonlyArray<string>, content: boolean) {
580
+ if (batch === undefined) {
581
+ return yield* Effect.forEach(paths, (path) =>
582
+ readDigest(path).pipe(
583
+ Effect.map((value): BatchedDigest => ({
584
+ digest: value.digest,
585
+ sizeBytes: value.bytes.length,
586
+ ...(content ? { bytes: value.bytes } : {})
587
+ })),
588
+ Effect.catchReason("PlatformError", "NotFound", () => Effect.succeed(undefined)),
589
+ Effect.mapError(hostFailure)
590
+ ), { concurrency: KernelFileSystem.fallbackConcurrency })
591
+ }
592
+ const values: Array<BatchedDigest | undefined> = []
593
+ for (let offset = 0; offset < paths.length; offset += batch.maxSize) {
594
+ const response = yield* batch.execute(
595
+ paths.slice(offset, offset + batch.maxSize).map((path) => ({
596
+ operation: "digest",
597
+ path,
598
+ content
599
+ }))
600
+ ).pipe(Effect.mapError(hostFailure))
601
+ for (const entry of [...response.entries].sort((a, b) => a.index - b.index)) {
602
+ const measured = yield* Effect.fromResult(entry.result).pipe(
603
+ Effect.catchReason("PlatformError", "NotFound", () => Effect.succeed(undefined)),
604
+ Effect.mapError(hostFailure)
605
+ )
606
+ if (measured === undefined) values.push(undefined)
607
+ else if (measured.operation !== "digest") {
608
+ return yield* Effect.fail(hostFailure(new Error("host returned a non-digest batch result")))
609
+ } else values.push({ ...measured, digest: measured.digest as ArtifactStore.Digest })
610
+ }
611
+ }
612
+ return values
613
+ }
614
+ )
615
+ /**
616
+ * One host call, never two. An `exists` probe ahead of the read asked
617
+ * exactly what the read itself answers — a path that is not there refuses
618
+ * with `NotFound` — and every declared read was therefore measured twice.
619
+ * On the confined host that is two CPython forks per path
620
+ * (`@smthrs/platform-node/AtomicFileSystem` spawns one interpreter per
621
+ * operation, ~130 ms each), so the probe doubled the cost of every
622
+ * `prepare`, every post-body change check, and every materialization.
623
+ */
624
+ const measure = (
625
+ path: string,
626
+ host: FileSystem.FileSystem = fs
627
+ ): Effect.Effect<string, UnsupportedBoundary, Crypto.Crypto> =>
628
+ readDigestFrom(host, path).pipe(
629
+ Effect.map((measured) => measured.digest),
630
+ Effect.catchReason("PlatformError", "NotFound", () => Effect.succeed(absentDigest)),
631
+ Effect.mapError(hostFailure)
632
+ )
633
+ // Both expansions enumerate through `FileEnumeration`, never the host
634
+ // `glob`: host results are absolute under the kernel FileSystem and skip
635
+ // dotfiles under Node's matcher, so trusting them silently emptied every
636
+ // workspace-relative expansion and let a tree replay delete dotfiles the
637
+ // producer wrote.
638
+ const expandGlob = Effect.fn("StepBoundary.expandGlob")(function*(glob: FileSet.Glob) {
639
+ return yield* FileEnumeration.expandGlob(fs, glob).pipe(Effect.mapError(hostFailure))
640
+ })
641
+ const treeEntries = Effect.fn("StepBoundary.treeEntries")(function*(host: FileSystem.FileSystem, path: string) {
642
+ return yield* FileEnumeration.entriesUnder(host, path).pipe(Effect.mapError(hostFailure))
643
+ })
644
+ // Replay writes and deletes what evidence names, so the lexical check alone
645
+ // is not a boundary: a symlink planted on a lexically valid path would carry
646
+ // the mutation outside the workspace. Every replay mutation, its probes, and
647
+ // its prune walk go through a view pinned to the root, where each call is
648
+ // one descriptor-relative, no-follow request and a symlink anywhere on the
649
+ // path is refused rather than followed. `prepare` and `settle` only read,
650
+ // and keep the caller's filesystem.
651
+ const replayRoot = KernelFileSystem.confinedRoot(fs) ?? options.root ?? "."
652
+ const replayHost: Effect.Effect<FileSystem.FileSystem, UnsupportedBoundary> = KernelFileSystem.isConfinable(fs)
653
+ ? KernelFileSystem.confined(fs, replayRoot).pipe(
654
+ Effect.provideService(Path.Path, platformPath),
655
+ Effect.mapError(hostFailure)
656
+ )
657
+ : Effect.fail(
658
+ new UnsupportedBoundary({
659
+ code: "unsupported_boundary",
660
+ message:
661
+ "cache replay needs a confined host filesystem; the host carries no descriptor-relative executor or isolation attestation"
662
+ })
663
+ )
664
+ const capture = Effect.fn("StepBoundary.capture")(
665
+ function*(path: string, inlineBudget: number, measured: BatchedDigest | undefined) {
666
+ yield* Effect.annotateCurrentSpan({ path })
667
+ // As in `measure`: the read reports absence itself, so the output is
668
+ // captured in one host call rather than an `exists` probe plus a read.
669
+ if (measured === undefined) {
670
+ return { output: { path, digest: null } satisfies MaterializedOutput, inlinedBytes: 0 }
671
+ }
672
+ const bytes = measured.bytes
673
+ if (bytes === undefined) return yield* Effect.fail(hostFailure(new Error("host omitted requested batch content")))
674
+ const digest = measured.digest
675
+ // Inline only while both bounds hold (issue #122): the per-output bound
676
+ // and the settle-wide aggregate budget the caller threads through.
677
+ if (bytes.length <= maxInlineBytes && bytes.length <= inlineBudget) {
678
+ return {
679
+ output: {
680
+ path,
681
+ digest,
682
+ sizeBytes: bytes.length,
683
+ content: Encoding.encodeBase64(bytes)
684
+ } satisfies MaterializedOutput,
685
+ inlinedBytes: bytes.length
686
+ }
687
+ }
688
+ // Over the inline bound: the payload goes to the content-addressed
689
+ // artifact store and the persisted row carries only the reference. Every
690
+ // property that used to live here — atomic publication, verify-once
691
+ // dedupe, healing rewrite of a corrupt address — is now the store's, and
692
+ // is tested there (`@smthrs/artifacts`).
693
+ const stored = yield* artifacts.put(bytes).pipe(Effect.mapError(artifactFailure))
694
+ if (stored !== digest) {
695
+ return yield* Effect.fail(
696
+ new BoundaryCorruption({
697
+ code: "boundary_corruption",
698
+ path,
699
+ recordedDigest: `${stored}`,
700
+ measuredDigest: digest
701
+ })
702
+ )
703
+ }
704
+ return { output: { path, digest, sizeBytes: bytes.length } satisfies MaterializedOutput, inlinedBytes: 0 }
705
+ }
706
+ )
707
+ const materialize = Effect.fn("StepBoundary.materialize")(function*(
708
+ host: FileSystem.FileSystem,
709
+ output: MaterializedOutput
710
+ ) {
711
+ yield* Effect.annotateCurrentSpan({ path: output.path })
712
+ // The filesystem is the cheapest source of truth for a warm workspace.
713
+ // Probe before decoding inline bytes or consulting the artifact store; a
714
+ // transient probe refusal merely forfeits the optimization and the
715
+ // ordinary materialization path retains its existing typed failures.
716
+ const current = yield* measure(output.path, host).pipe(
717
+ Effect.map((digest) => digest !== absentDigest && digest === output.digest),
718
+ Effect.catch(() => Effect.succeed(false))
719
+ )
720
+ if (current) return
721
+ let bytes: Uint8Array
722
+ if (output.content !== undefined) {
723
+ const decoded = Encoding.decodeBase64(output.content)
724
+ if (Result.isFailure(decoded)) {
725
+ // Inline content is cache-origin bytes: an undecodable payload is a
726
+ // tampered durable row, classified exactly like a digest mismatch so
727
+ // the caller routes it to the Inconsistency receiver instead of
728
+ // retrying it as a transient host refusal (issue #159).
729
+ return yield* Effect.fail(inlineCorruption(output.path, `${output.digest}`))
730
+ }
731
+ bytes = decoded.success
732
+ // Inline evidence is verified here because nothing else can: the bytes
733
+ // travel inside the row rather than at a content address. A referenced
734
+ // artifact is verified by the store on the way out, so the check below
735
+ // would be a second read+hash of the same bytes.
736
+ const measured = yield* Schema.decodeUnknownEffect(Sha256)(bytes).pipe(Effect.orDie)
737
+ if (measured !== output.digest) {
738
+ return yield* Effect.fail(
739
+ new BoundaryCorruption({
740
+ code: "boundary_corruption",
741
+ path: output.path,
742
+ recordedDigest: `${output.digest}`,
743
+ measuredDigest: measured
744
+ })
745
+ )
746
+ }
747
+ } else {
748
+ bytes = yield* artifacts.get(`${output.digest}`).pipe(
749
+ Effect.catchTags({
750
+ // A reference this host cannot resolve is not a host refusal: a
751
+ // shared artifact tier may still hold it, so the caller gets a
752
+ // typed, repairable failure and fetches before falling back to a
753
+ // real execution (issue #172).
754
+ "@smthrs/artifacts/ArtifactMissing": (missing) =>
755
+ Effect.fail(
756
+ new MissingArtifact({ code: "missing_artifact", path: output.path, digest: missing.digest })
757
+ ),
758
+ // Corruption is a distinct typed failure from a transient host
759
+ // error (issue #150): the caller routes it to the Inconsistency
760
+ // receiver instead of treating it as an ordinary retryable refusal.
761
+ "@smthrs/artifacts/ArtifactCorruption": (corrupt) =>
762
+ Effect.fail(
763
+ new BoundaryCorruption({
764
+ code: "boundary_corruption",
765
+ path: output.path,
766
+ recordedDigest: corrupt.recordedDigest,
767
+ measuredDigest: corrupt.measuredDigest
768
+ })
769
+ ),
770
+ "@smthrs/artifacts/ArtifactStoreError": (failure) => Effect.fail(artifactFailure(failure))
771
+ })
772
+ )
773
+ }
774
+ // The original body may have created the output's directory itself; a
775
+ // fresh workspace replaying the evidence has no such directory and
776
+ // `writeFile` does not create parents (issue #107).
777
+ const parent = parentDirectory(output.path)
778
+ if (parent !== undefined) {
779
+ yield* host.makeDirectory(parent, { recursive: true }).pipe(Effect.mapError(hostFailure))
780
+ }
781
+ yield* host.writeFile(output.path, bytes).pipe(Effect.mapError(hostFailure))
782
+ })
783
+ return make({
784
+ prepare: Effect.fn("StepBoundary.prepare")(function*(descriptor) {
785
+ const boundary = FileBoundarySnapshot.make(descriptor)
786
+ yield* Effect.annotateCurrentSpan({
787
+ reads: boundary.readSet.length,
788
+ boundaryMode: boundary.boundaryMode
789
+ })
790
+ // The dirty check's evidence (issue #90): what the host actually
791
+ // measured for every declared read, never the declaration itself —
792
+ // defaulting the snapshot to the declaration made `readSetMatches`
793
+ // compare the declaration against itself and pass unconditionally
794
+ // (issue #104).
795
+ const readSnapshot: Array<FileInput> = []
796
+ const paths: Array<string> = []
797
+ for (const entry of boundary.readSet) {
798
+ if (FileSet.isGlob(entry)) {
799
+ paths.push(...yield* expandGlob(entry))
800
+ } else paths.push(entry.path)
801
+ }
802
+ const measured = yield* measurements(paths, false)
803
+ for (const [index, path] of paths.entries()) {
804
+ readSnapshot.push({ path, digest: measured[index]?.digest ?? absentDigest })
805
+ }
806
+ readSnapshot.sort((left, right) => compareText(left.path, right.path))
807
+ return Object.freeze({
808
+ descriptor: boundary,
809
+ readSnapshot: Object.freeze(readSnapshot.map((entry) => Object.freeze({ ...entry })))
810
+ })
811
+ }),
812
+ settle: Effect.fn("StepBoundary.settle")(function*(prepared) {
813
+ yield* Effect.annotateCurrentSpan({
814
+ writes: prepared.descriptor.writeSet.length,
815
+ boundaryMode: prepared.descriptor.boundaryMode
816
+ })
817
+ // Undeclared-write detection is scoped to the declared read set: a
818
+ // declared read whose content moved during the body and is not also a
819
+ // declared write was mutated outside the contract. Whole-tree change
820
+ // detection needs the jj diff surface and stays a documented
821
+ // limitation of this layer rather than a silent pass — the read set
822
+ // is exactly the material cacheability rests on.
823
+ const removes = prepared.descriptor.removes ?? []
824
+ const declaredWrites = [...prepared.descriptor.writeSet, ...removes]
825
+ const declaredCovers = (path: string) =>
826
+ declaredWrites.some((entry) =>
827
+ typeof entry === "string"
828
+ ? entry === path
829
+ : entry._tag === "TreeArtifact"
830
+ ? path === entry.path || path.startsWith(`${entry.path}/`)
831
+ : FileSet.matchesGlob(entry, path)
832
+ )
833
+ const undeclared: Array<string> = []
834
+ const checkedReads = prepared.readSnapshot.filter((entry) => !declaredCovers(entry.path))
835
+ const currentReads = yield* measurements(checkedReads.map((entry) => entry.path), false)
836
+ for (const [index, entry] of checkedReads.entries()) {
837
+ if ((currentReads[index]?.digest ?? absentDigest) !== entry.digest) undeclared.push(entry.path)
838
+ }
839
+ const outputs: Array<MaterializedOutput> = []
840
+ // Declared removals are captured on the same path and under the same
841
+ // `digest: null` semantics they have always had — the difference is that
842
+ // here the absence was declared, so it is evidence rather than a defect.
843
+ const missing: Array<string> = []
844
+ const surviving: Array<string> = []
845
+ let inlinedBytes = 0
846
+ const outputPaths: Array<string> = []
847
+ const treeMembers: Array<{ readonly path: string; readonly files: ReadonlyArray<string> }> = []
848
+ for (const entry of prepared.descriptor.writeSet) {
849
+ if (typeof entry === "string") outputPaths.push(entry)
850
+ else if (entry._tag === "Glob") outputPaths.push(...yield* expandGlob(entry))
851
+ else {
852
+ const files = (yield* treeEntries(fs, entry.path)).files
853
+ outputPaths.push(...files)
854
+ treeMembers.push({ path: entry.path, files })
855
+ }
856
+ }
857
+ outputPaths.push(...removes)
858
+ const captured = new Map<string, MaterializedOutput>()
859
+ const sortedPaths = [...new Set(outputPaths)].sort(compareText)
860
+ // Digest-only preflight bounds content batches by bytes as well as path
861
+ // count. Both measurements share the guarded host's pinned root identity;
862
+ // a rewrite between them is a refusal, never mismatched cached content.
863
+ const sizes = batch === undefined ? undefined : yield* measurements(sortedPaths, false)
864
+ for (let offset = 0; offset < sortedPaths.length;) {
865
+ let end = offset
866
+ let responseBytes = 256
867
+ const size = batch?.maxSize ?? KernelFileSystem.fallbackConcurrency
868
+ while (end < sortedPaths.length && end - offset < size) {
869
+ const estimate = 4096 + new TextEncoder().encode(sortedPaths[end]).length * 6 +
870
+ Math.ceil((sizes?.[end]?.sizeBytes ?? 0) / 3) * 4
871
+ if (end > offset && batch !== undefined && responseBytes + estimate > batch.maxResponseBytes) break
872
+ responseBytes += estimate
873
+ end++
874
+ }
875
+ const group = sortedPaths.slice(offset, end)
876
+ const contents = yield* measurements(group, true)
877
+ for (const [index, path] of group.entries()) {
878
+ const measured = contents[index]
879
+ if (sizes !== undefined && measured?.digest !== sizes[offset + index]?.digest) {
880
+ return yield* Effect.fail(hostFailure(new Error(`output changed during measurement: ${path}`)))
881
+ }
882
+ const output = yield* capture(path, maxTotalInlineBytes - inlinedBytes, measured)
883
+ // `capture` reports the bytes it actually inlined (zero for a
884
+ // digest-only reference), so the aggregate budget never has to
885
+ // re-derive them from the row it just built.
886
+ inlinedBytes += output.inlinedBytes
887
+ outputs.push(output.output)
888
+ captured.set(path, output.output)
889
+ if (
890
+ output.output.digest === null &&
891
+ !removes.includes(path) &&
892
+ prepared.descriptor.writeSet.some((entry) => typeof entry === "string" && entry === path)
893
+ ) missing.push(path)
894
+ // The dual check: a removal promised the path absent, and it is still
895
+ // here — possibly rewritten. Settling it would cache the surviving
896
+ // bytes under a declaration that disclaimed them.
897
+ if (output.output.digest !== null && removes.includes(path)) surviving.push(path)
898
+ }
899
+ offset = end
900
+ }
901
+ // A tree member is already one of the captured outputs, so its identity
902
+ // is folded from the digest that capture measured rather than from a
903
+ // second read of the same bytes. `capture` spells an absent member
904
+ // `null` where `measure` spells it `absentDigest`; the identity keeps
905
+ // the `measure` spelling, so a tree recorded before this and one
906
+ // recorded after hash identically.
907
+ const trees: Array<{ readonly path: string; readonly identity: string }> = []
908
+ for (const tree of treeMembers) {
909
+ const pairs = tree.files.map((path) =>
910
+ [path.slice(tree.path.length + 1), captured.get(path)!.digest ?? absentDigest] as const
911
+ )
912
+ trees.push({
913
+ path: tree.path,
914
+ identity: yield* Schema.decodeUnknownEffect(DerivedKey)({ kind: "tree-artifact", files: pairs }).pipe(
915
+ Effect.orDie
916
+ )
917
+ })
918
+ }
919
+ // Through `DerivedKey` — the repo's one hashing chokepoint — so the identity is
920
+ // a digest of the RFC 8785 canonical form rather than of whatever
921
+ // `JSON.stringify` happened to emit for this shape.
922
+ const diffIdentity = yield* Schema.decodeUnknownEffect(DerivedKey)({
923
+ kind: "diff-identity",
924
+ outputs: outputs.map((output) => [output.path, output.digest]),
925
+ trees
926
+ }).pipe(Effect.orDie)
927
+ yield* Effect.annotateCurrentSpan({ diffIdentity })
928
+ if (prepared.descriptor.boundaryMode === "hard") {
929
+ if (undeclared.length > 0) {
930
+ return yield* Effect.fail(
931
+ new UndeclaredWrite({ code: "undeclared_write", paths: undeclared, diffIdentity })
932
+ )
933
+ }
934
+ // A declared output that was never produced is a defect, not evidence
935
+ // (Bazel's `checkOutputs`). Recording it would cache `digest: null`,
936
+ // which every later `replayOutputs` reads as "delete this path".
937
+ if (missing.length > 0) {
938
+ return yield* Effect.fail(
939
+ new MissingDeclaredOutput({ code: "missing_declared_output", paths: missing, diffIdentity })
940
+ )
941
+ }
942
+ if (surviving.length > 0) {
943
+ return yield* Effect.fail(
944
+ new SurvivingDeclaredRemoval({ code: "surviving_declared_removal", paths: surviving, diffIdentity })
945
+ )
946
+ }
947
+ }
948
+ return {
949
+ declaredOutputs: { outputs, ...(trees.length === 0 ? {} : { trees }) },
950
+ diffIdentity,
951
+ // This filesystem-only boundary cannot observe writes elsewhere in
952
+ // the tree. Omission is deliberate: ActionPersistence treats the
953
+ // result as run-local and will not publish it to the shared cache.
954
+ //
955
+ // An undeclared write is reported ahead of a missing output, and a
956
+ // missing output ahead of a surviving removal: each is the stronger
957
+ // claim about the same execution, and every variant bars the evidence
958
+ // from the shared cache identically.
959
+ ...(undeclared.length > 0
960
+ ? { deviation: { _tag: "ExpectedSetDeviation" as const, paths: undeclared, diffIdentity } }
961
+ : missing.length > 0
962
+ ? { deviation: { _tag: "MissingDeclaredOutput" as const, paths: missing, diffIdentity } }
963
+ : surviving.length > 0
964
+ ? { deviation: { _tag: "SurvivingDeclaredRemoval" as const, paths: surviving, diffIdentity } }
965
+ : {})
966
+ }
967
+ }),
968
+ replayOutputs: Effect.fn("StepBoundary.replayOutputs")(function*(evidence) {
969
+ yield* Effect.annotateCurrentSpan({ diffIdentity: evidence.diffIdentity })
970
+ const decoded = Schema.decodeUnknownResult(MaterializedOutputs)(evidence.declaredOutputs)
971
+ if (decoded._tag === "Failure") {
972
+ // Evidence recorded by a different boundary implementation carries
973
+ // no materializable outputs; refusing is honest — the caller's
974
+ // dispatch path falls back to a real execution or fails visibly.
975
+ return yield* Effect.fail(
976
+ new UnsupportedBoundary({
977
+ code: "unsupported_boundary",
978
+ message: "the recorded boundary evidence carries no materializable outputs"
979
+ })
980
+ )
981
+ }
982
+ // Replay writes and DELETES whatever the evidence names, so a path is
983
+ // honored only in the coordinate system declarations are written in.
984
+ // Evidence can arrive from a foreign producer through cache sync; an
985
+ // absolute or upward spelling is an eraser aimed outside the workspace,
986
+ // and refusing it here is what keeps that a refusal instead of a wipe.
987
+ const foreign = [
988
+ ...(decoded.success.trees ?? []).map((tree) => tree.path),
989
+ ...decoded.success.outputs.map((output) => output.path)
990
+ ].filter((path) => !FileSet.workspaceRelative(path))
991
+ if (foreign.length > 0) {
992
+ return yield* Effect.fail(
993
+ new UnsupportedBoundary({
994
+ code: "unsupported_boundary",
995
+ message: `the recorded boundary evidence names paths outside the workspace: ${foreign.join(", ")}`
996
+ })
997
+ )
998
+ }
999
+ // Before any mutation: a host that cannot be confined refuses the whole
1000
+ // replay, and the caller falls back to a real execution.
1001
+ const host = yield* replayHost
1002
+ const emptyDirectoryCandidates = new Set<string>()
1003
+ for (const tree of decoded.success.trees ?? []) {
1004
+ const prefix = `${tree.path}/`.replace(/\/{2,}$/g, "/")
1005
+ const recorded = new Set(
1006
+ decoded.success.outputs
1007
+ .map((output) => output.path)
1008
+ .filter((path) => path.startsWith(prefix))
1009
+ )
1010
+ const entries = yield* treeEntries(host, tree.path)
1011
+ for (const path of entries.files) {
1012
+ if (!recorded.has(path)) yield* host.remove(path).pipe(Effect.mapError(hostFailure))
1013
+ }
1014
+ for (const directory of entries.directories) emptyDirectoryCandidates.add(directory)
1015
+ }
1016
+ for (const output of decoded.success.outputs) {
1017
+ if (output.digest === null) {
1018
+ // `force` IS the probe: the evidence says this path must not exist,
1019
+ // and a removal that finds it already gone has done its job. The
1020
+ // `exists` call that used to precede it was a second host call — a
1021
+ // second process on the confined host — for the same answer.
1022
+ yield* host.remove(output.path, { force: true }).pipe(Effect.mapError(hostFailure))
1023
+ } else {
1024
+ yield* materialize(host, output)
1025
+ }
1026
+ }
1027
+ // Remove only directories proven empty after pruning and
1028
+ // materialization. Deepest-first preserves every directory that still
1029
+ // contains a recorded child while clearing stale empty scaffolding.
1030
+ const directories = [...emptyDirectoryCandidates].sort((left, right) =>
1031
+ right.length - left.length || compareText(left, right)
1032
+ )
1033
+ for (const directory of directories) {
1034
+ const entries = yield* host.readDirectory(directory).pipe(Effect.mapError(hostFailure))
1035
+ if (entries.length === 0) yield* host.remove(directory).pipe(Effect.mapError(hostFailure))
1036
+ }
1037
+ })
1038
+ })
1039
+ }
1040
+
1041
+ /**
1042
+ * Provides the filesystem-backed production boundary: `prepare` measures the
1043
+ * declared read set for real, `settle` detects reads mutated outside the
1044
+ * declared write set and captures the write set's post-state, and
1045
+ * `replayOutputs` re-materializes those outputs on cache-hit replay.
1046
+ *
1047
+ * Host access arrives through Effect's `FileSystem` tag, which the capability
1048
+ * kernel decorates in place — the same seam every host implementation (node,
1049
+ * bun, browser, sandbox) already provides. Blob storage arrives through
1050
+ * `@smthrs/artifacts`, so the same boundary runs over a purely local store or
1051
+ * over a local-plus-shared composition without knowing which it got.
1052
+ *
1053
+ * Replay confines its own mutations rather than trusting the composition:
1054
+ * they run through `@smthrs/kernel/FileSystem`'s `confined` view, rooted at
1055
+ * the kernel `Workspace` when one is in context. A symlink on a replayed path
1056
+ * (a parent, the final component, or a member of a replayed tree) and a host
1057
+ * with no descriptor-relative executor or isolation attestation both refuse
1058
+ * with {@link UnsupportedBoundary}, which the caller journals as
1059
+ * `replay_failed` before executing the step for real.
1060
+ *
1061
+ * @since 0.1.0
1062
+ * @category layers
1063
+ */
1064
+ export const layer: Layer.Layer<
1065
+ Service,
1066
+ never,
1067
+ FileSystem.FileSystem | Path.Path | ArtifactStore.ArtifactStore
1068
+ > = Layer.effect(
1069
+ StepBoundary,
1070
+ Effect.gen(function*() {
1071
+ const fs = yield* FileSystem.FileSystem
1072
+ const platformPath = yield* Path.Path
1073
+ const artifacts = yield* ArtifactStore.ArtifactStore
1074
+ const workspace = yield* Effect.serviceOption(KernelWorkspace)
1075
+ return makeFileSystem(fs, platformPath, artifacts, workspace._tag === "Some" ? { root: workspace.value.root } : {})
1076
+ })
1077
+ )
1078
+
1079
+ /**
1080
+ * What the deterministic test boundary should pretend the host observed.
1081
+ *
1082
+ * Every field is a fixture, not a classification rule: a test supplies settlement
1083
+ * evidence or failure, the read snapshot, and whether the host claims
1084
+ * to support the boundary at all — then asserts on the resulting evidence or
1085
+ * refusal. Defaults describe a well-behaved, fully-supported host.
1086
+ *
1087
+ * @since 0.1.0
1088
+ * @category models
1089
+ */
1090
+ export interface TestOptions {
1091
+ /** A settlement failure supplied verbatim by an integration fixture. */
1092
+ readonly failure?: UndeclaredWrite | MissingDeclaredOutput | SurvivingDeclaredRemoval | undefined
1093
+ /** Settlement evidence supplied verbatim; classification belongs to the real layer. */
1094
+ readonly deviation?: BoundaryDeviation | undefined
1095
+ /**
1096
+ * What `prepare` reports as measured for the declared read set. Defaults
1097
+ * to the declaration itself; a test supplies a different snapshot to stand
1098
+ * for a file whose content moved out from under a stale declaration
1099
+ * (issue #90).
1100
+ */
1101
+ readonly readSnapshot?: ReadonlyArray<FileInput> | undefined
1102
+ /** The opaque replay payload recorded in the evidence. */
1103
+ readonly declaredOutputs?: unknown
1104
+ /** The post-state identity the evidence names. Defaults to a fixed string. */
1105
+ readonly diffIdentity?: string | undefined
1106
+ /** When false, every call fails with {@link UnsupportedBoundary}. Defaults to true. */
1107
+ readonly supported?: boolean | undefined
1108
+ /** Whether the fixture attests a whole-tree observation. Defaults to true. */
1109
+ readonly wholeTreeWriteDetection?: boolean | undefined
1110
+ /** Whether the fixture models an isolated read surface. Defaults to true. */
1111
+ readonly hermeticReadDetection?: boolean | undefined
1112
+ /** Observes each `replayOutputs` call, so a test can assert replay happened. */
1113
+ readonly onReplay?: (evidence: BoundaryEvidence) => void
1114
+ }
1115
+
1116
+ const unsupported = (): UnsupportedBoundary =>
1117
+ new UnsupportedBoundary({
1118
+ code: "unsupported_boundary",
1119
+ message: "the host cannot enforce the declared step boundary"
1120
+ })
1121
+
1122
+ /**
1123
+ * Deterministic in-memory boundary suitable only for tests. Production
1124
+ * wiring uses {@link layer}, the filesystem-backed implementation.
1125
+ *
1126
+ * Whole-tree change detection is supplied by sandboxed settlement, not by any
1127
+ * boundary layer: an isolated execution's transaction IS the tree, so
1128
+ * `ActionPersistence` compares its diff against the declared sets and sets
1129
+ * `wholeTreeWritesVerified` structurally (the retired piece-6 limitation).
1130
+ * {@link layer} still detects mutations within the declared read set only,
1131
+ * which is why unsandboxed evidence stays run-local.
1132
+ *
1133
+ * @since 0.1.0
1134
+ * @category layers
1135
+ */
1136
+ export const layerTest = (options: TestOptions = {}): Layer.Layer<Service> => {
1137
+ const diffIdentity = options.diffIdentity ?? "test-diff"
1138
+ const service = make({
1139
+ prepare: Effect.fn("StepBoundary.prepare")(function*(descriptor) {
1140
+ if (options.supported === false) return yield* Effect.fail(unsupported())
1141
+ return {
1142
+ descriptor,
1143
+ readSnapshot: options.readSnapshot ?? exactReads(descriptor)
1144
+ }
1145
+ }),
1146
+ settle: Effect.fn("StepBoundary.settle")(function*(prepared) {
1147
+ if (options.supported === false) return yield* Effect.fail(unsupported())
1148
+ if (options.failure !== undefined) return yield* Effect.fail(options.failure)
1149
+ return {
1150
+ declaredOutputs: options.declaredOutputs ?? { paths: prepared.descriptor.writeSet },
1151
+ diffIdentity,
1152
+ ...(options.wholeTreeWriteDetection === false ? {} : { wholeTreeWritesVerified: true as const }),
1153
+ ...(options.hermeticReadDetection === false ? {} : { hermeticReadsVerified: true as const }),
1154
+ ...(options.deviation === undefined ? {} : { deviation: options.deviation })
1155
+ }
1156
+ }),
1157
+ replayOutputs: Effect.fn("StepBoundary.replayOutputs")(function*(evidence) {
1158
+ if (options.supported === false) return yield* Effect.fail(unsupported())
1159
+ yield* Effect.sync(() => {
1160
+ options.onReplay?.(evidence)
1161
+ })
1162
+ })
1163
+ })
1164
+ return Layer.succeed(StepBoundary, service)
1165
+ }