footprintjs 10.0.1 → 10.2.0

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 (368) hide show
  1. package/AGENTS.md +2 -1
  2. package/CLAUDE.md +61 -7
  3. package/README.md +136 -312
  4. package/dist/esm/index.d.ts +62 -2
  5. package/dist/esm/index.js +13 -6
  6. package/dist/esm/lib/attempt/anySignal.d.ts +19 -0
  7. package/dist/esm/lib/attempt/anySignal.js +39 -0
  8. package/dist/esm/lib/attempt/call.d.ts +88 -0
  9. package/dist/esm/lib/attempt/call.js +129 -0
  10. package/dist/esm/lib/attempt/category.d.ts +37 -0
  11. package/dist/esm/lib/attempt/category.js +131 -0
  12. package/dist/esm/lib/attempt/correlation.d.ts +95 -0
  13. package/dist/esm/lib/attempt/correlation.js +178 -0
  14. package/dist/esm/lib/attempt/deadline.d.ts +44 -0
  15. package/dist/esm/lib/attempt/deadline.js +101 -0
  16. package/dist/esm/lib/attempt/decision.d.ts +52 -0
  17. package/dist/esm/lib/attempt/decision.js +134 -0
  18. package/dist/esm/lib/attempt/effect.d.ts +76 -0
  19. package/dist/esm/lib/attempt/effect.js +160 -0
  20. package/dist/esm/lib/attempt/errors.d.ts +41 -0
  21. package/dist/esm/lib/attempt/errors.js +44 -0
  22. package/dist/esm/lib/attempt/index.d.ts +18 -0
  23. package/dist/esm/lib/attempt/index.js +15 -0
  24. package/dist/esm/lib/attempt/name.d.ts +21 -0
  25. package/dist/esm/lib/attempt/name.js +43 -0
  26. package/dist/esm/lib/attempt/observed.d.ts +66 -0
  27. package/dist/esm/lib/attempt/observed.js +171 -0
  28. package/dist/esm/lib/attempt/policy.d.ts +45 -0
  29. package/dist/esm/lib/attempt/policy.js +83 -0
  30. package/dist/esm/lib/attempt/record.d.ts +11 -0
  31. package/dist/esm/lib/attempt/record.js +24 -0
  32. package/dist/esm/lib/attempt/retryLoopContext.d.ts +18 -0
  33. package/dist/esm/lib/attempt/retryLoopContext.js +24 -0
  34. package/dist/esm/lib/attempt/retryLoopTypes.d.ts +18 -0
  35. package/dist/esm/lib/attempt/retryLoopTypes.js +2 -0
  36. package/dist/esm/lib/attempt/runner.d.ts +157 -0
  37. package/dist/esm/lib/attempt/runner.js +523 -0
  38. package/dist/esm/lib/attempt/standalone.d.ts +47 -0
  39. package/dist/esm/lib/attempt/standalone.js +126 -0
  40. package/dist/esm/lib/attempt/types.d.ts +453 -0
  41. package/dist/esm/lib/attempt/types.js +16 -0
  42. package/dist/esm/lib/budget/index.d.ts +9 -0
  43. package/dist/esm/lib/budget/index.js +9 -0
  44. package/dist/esm/lib/budget/timeBudget.d.ts +136 -0
  45. package/dist/esm/lib/budget/timeBudget.js +666 -0
  46. package/dist/esm/lib/builder/FlowChartBuilder.d.ts +88 -3
  47. package/dist/esm/lib/builder/FlowChartBuilder.js +199 -9
  48. package/dist/esm/lib/builder/retryLoop.d.ts +56 -0
  49. package/dist/esm/lib/builder/retryLoop.js +283 -0
  50. package/dist/esm/lib/builder/types.d.ts +35 -1
  51. package/dist/esm/lib/builder/types.js +1 -1
  52. package/dist/esm/lib/decide/decide.js +2 -2
  53. package/dist/esm/lib/decide/index.d.ts +1 -1
  54. package/dist/esm/lib/decide/index.js +2 -2
  55. package/dist/esm/lib/decide/types.d.ts +3 -0
  56. package/dist/esm/lib/decide/types.js +1 -8
  57. package/dist/esm/lib/engine/graph/StageNode.d.ts +11 -1
  58. package/dist/esm/lib/engine/graph/StageNode.js +1 -1
  59. package/dist/esm/lib/engine/graph/prefixNodeTree.js +5 -1
  60. package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +36 -6
  61. package/dist/esm/lib/engine/handlers/DeciderHandler.js +9 -5
  62. package/dist/esm/lib/engine/handlers/ResumeEntry.js +3 -1
  63. package/dist/esm/lib/engine/handlers/SelectorHandler.js +6 -5
  64. package/dist/esm/lib/engine/handlers/StageRunner.d.ts +8 -1
  65. package/dist/esm/lib/engine/handlers/StageRunner.js +36 -9
  66. package/dist/esm/lib/engine/handlers/SubflowExecutor.js +24 -5
  67. package/dist/esm/lib/engine/handlers/commitStage.d.ts +7 -0
  68. package/dist/esm/lib/engine/handlers/commitStage.js +22 -4
  69. package/dist/esm/lib/engine/handlers/stageError.d.ts +9 -0
  70. package/dist/esm/lib/engine/handlers/stageError.js +23 -1
  71. package/dist/esm/lib/engine/index.d.ts +2 -2
  72. package/dist/esm/lib/engine/index.js +1 -1
  73. package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +27 -13
  74. package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +68 -40
  75. package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -1
  76. package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.js +19 -2
  77. package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.d.ts +22 -3
  78. package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.js +61 -9
  79. package/dist/esm/lib/engine/narrative/NullControlFlowNarrativeGenerator.d.ts +1 -0
  80. package/dist/esm/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
  81. package/dist/esm/lib/engine/narrative/formatting/sentences.d.ts +23 -0
  82. package/dist/esm/lib/engine/narrative/formatting/sentences.js +127 -1
  83. package/dist/esm/lib/engine/narrative/index.d.ts +2 -2
  84. package/dist/esm/lib/engine/narrative/index.js +1 -1
  85. package/dist/esm/lib/engine/narrative/narrativeTypes.d.ts +27 -21
  86. package/dist/esm/lib/engine/narrative/narrativeTypes.js +1 -1
  87. package/dist/esm/lib/engine/narrative/recorders/ManifestFlowRecorder.d.ts +45 -2
  88. package/dist/esm/lib/engine/narrative/recorders/ManifestFlowRecorder.js +55 -2
  89. package/dist/esm/lib/engine/narrative/recorders/index.d.ts +1 -1
  90. package/dist/esm/lib/engine/narrative/recorders/index.js +1 -1
  91. package/dist/esm/lib/engine/narrative/types.d.ts +74 -5
  92. package/dist/esm/lib/engine/narrative/types.js +1 -1
  93. package/dist/esm/lib/engine/traversal/FlowchartTraverser.d.ts +59 -19
  94. package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +194 -118
  95. package/dist/esm/lib/engine/traversalContext.d.ts +7 -2
  96. package/dist/esm/lib/engine/traversalContext.js +6 -3
  97. package/dist/esm/lib/engine/types.d.ts +52 -57
  98. package/dist/esm/lib/engine/types.js +1 -1
  99. package/dist/esm/lib/errors/terminalFailure.d.ts +29 -0
  100. package/dist/esm/lib/errors/terminalFailure.js +60 -0
  101. package/dist/esm/lib/{decide → filter}/evaluator.d.ts +7 -2
  102. package/dist/esm/lib/filter/evaluator.js +135 -0
  103. package/dist/esm/lib/ids/idempotencyKey.d.ts +14 -0
  104. package/dist/esm/lib/ids/idempotencyKey.js +24 -0
  105. package/dist/esm/lib/memory/StageContext.d.ts +123 -3
  106. package/dist/esm/lib/memory/StageContext.js +245 -4
  107. package/dist/esm/lib/memory/attention.d.ts +26 -0
  108. package/dist/esm/lib/memory/attention.js +171 -0
  109. package/dist/esm/lib/memory/borrowedMutation.d.ts +8 -0
  110. package/dist/esm/lib/memory/borrowedMutation.js +14 -1
  111. package/dist/esm/lib/memory/frameTypes.d.ts +38 -0
  112. package/dist/esm/lib/memory/frameTypes.js +3 -1
  113. package/dist/esm/lib/memory/redaction.d.ts +12 -0
  114. package/dist/esm/lib/memory/redaction.js +54 -5
  115. package/dist/esm/lib/pause/record.js +10 -1
  116. package/dist/esm/lib/pause/types.d.ts +19 -0
  117. package/dist/esm/lib/pause/types.js +17 -1
  118. package/dist/esm/lib/reactive/createTypedScope.js +3 -1
  119. package/dist/esm/lib/reactive/types.d.ts +36 -4
  120. package/dist/esm/lib/reactive/types.js +3 -1
  121. package/dist/esm/lib/recorder/AttemptRecorder.d.ts +141 -0
  122. package/dist/esm/lib/recorder/AttemptRecorder.js +412 -0
  123. package/dist/esm/lib/recorder/ControlDepRecorder.d.ts +36 -2
  124. package/dist/esm/lib/recorder/ControlDepRecorder.js +50 -2
  125. package/dist/esm/lib/recorder/EmitRecorder.d.ts +3 -0
  126. package/dist/esm/lib/recorder/EmitRecorder.js +1 -1
  127. package/dist/esm/lib/recorder/InOutRecorder.d.ts +37 -1
  128. package/dist/esm/lib/recorder/InOutRecorder.js +75 -6
  129. package/dist/esm/lib/recorder/QualityRecorder.d.ts +32 -5
  130. package/dist/esm/lib/recorder/QualityRecorder.js +87 -29
  131. package/dist/esm/lib/recorder/TopologyRecorder.d.ts +35 -5
  132. package/dist/esm/lib/recorder/TopologyRecorder.js +76 -2
  133. package/dist/esm/lib/recorder/attemptMetricRows.d.ts +11 -0
  134. package/dist/esm/lib/recorder/attemptMetricRows.js +202 -0
  135. package/dist/esm/lib/recorder/attemptMetrics.d.ts +7 -0
  136. package/dist/esm/lib/recorder/attemptMetrics.js +165 -0
  137. package/dist/esm/lib/recorder/attemptMetricsTypes.d.ts +114 -0
  138. package/dist/esm/lib/recorder/attemptMetricsTypes.js +2 -0
  139. package/dist/esm/lib/recorder/attemptOTel.d.ts +78 -0
  140. package/dist/esm/lib/recorder/attemptOTel.js +107 -0
  141. package/dist/esm/lib/recorder/attemptSeries.d.ts +81 -0
  142. package/dist/esm/lib/recorder/attemptSeries.js +103 -0
  143. package/dist/esm/lib/recorder/hooks.d.ts +9 -0
  144. package/dist/esm/lib/recorder/hooks.js +4 -1
  145. package/dist/esm/lib/runner/DeferredObserverTier.js +13 -1
  146. package/dist/esm/lib/runner/ExecutionRuntime.d.ts +54 -6
  147. package/dist/esm/lib/runner/ExecutionRuntime.js +57 -5
  148. package/dist/esm/lib/runner/FlowChartExecutor.d.ts +46 -2
  149. package/dist/esm/lib/runner/FlowChartExecutor.js +330 -101
  150. package/dist/esm/lib/runner/RunnableChart.d.ts +6 -0
  151. package/dist/esm/lib/runner/RunnableChart.js +5 -1
  152. package/dist/esm/lib/runner/attach.d.ts +2 -1
  153. package/dist/esm/lib/runner/attach.js +8 -2
  154. package/dist/esm/lib/runner/checkpoint.js +3 -1
  155. package/dist/esm/lib/runner/deadline.d.ts +42 -0
  156. package/dist/esm/lib/runner/deadline.js +90 -0
  157. package/dist/esm/lib/runner/index.d.ts +3 -1
  158. package/dist/esm/lib/runner/index.js +2 -1
  159. package/dist/esm/lib/runner/options.d.ts +17 -0
  160. package/dist/esm/lib/runner/options.js +3 -1
  161. package/dist/esm/lib/runner/recordSink.d.ts +128 -0
  162. package/dist/esm/lib/runner/recordSink.js +296 -0
  163. package/dist/esm/lib/runner/resume.d.ts +3 -0
  164. package/dist/esm/lib/runner/resume.js +22 -2
  165. package/dist/esm/lib/runner/snapshot.d.ts +2 -2
  166. package/dist/esm/lib/runner/snapshot.js +6 -2
  167. package/dist/esm/lib/scope/ScopeFacade.d.ts +118 -4
  168. package/dist/esm/lib/scope/ScopeFacade.js +304 -7
  169. package/dist/esm/lib/scope/recorders/DebugRecorder.d.ts +17 -3
  170. package/dist/esm/lib/scope/recorders/DebugRecorder.js +79 -13
  171. package/dist/esm/lib/scope/recorders/MetricRecorder.d.ts +10 -0
  172. package/dist/esm/lib/scope/recorders/MetricRecorder.js +15 -2
  173. package/dist/esm/lib/scope/runtime.d.ts +3 -0
  174. package/dist/esm/lib/scope/runtime.js +1 -1
  175. package/dist/esm/lib/scope/types.d.ts +6 -0
  176. package/dist/esm/lib/scope/types.js +1 -1
  177. package/dist/esm/lib/sinks/fileSink.d.ts +135 -0
  178. package/dist/esm/lib/sinks/fileSink.js +387 -0
  179. package/dist/esm/recorders.d.ts +8 -2
  180. package/dist/esm/recorders.js +7 -1
  181. package/dist/esm/sinks.d.ts +23 -0
  182. package/dist/esm/sinks.js +23 -0
  183. package/dist/esm/trace.d.ts +2 -2
  184. package/dist/esm/trace.js +1 -1
  185. package/dist/index.js +77 -60
  186. package/dist/lib/attempt/anySignal.js +43 -0
  187. package/dist/lib/attempt/call.js +134 -0
  188. package/dist/lib/attempt/category.js +136 -0
  189. package/dist/lib/attempt/correlation.js +186 -0
  190. package/dist/lib/attempt/deadline.js +112 -0
  191. package/dist/lib/attempt/decision.js +139 -0
  192. package/dist/lib/attempt/effect.js +174 -0
  193. package/dist/lib/attempt/errors.js +49 -0
  194. package/dist/lib/attempt/index.js +26 -0
  195. package/dist/lib/attempt/name.js +48 -0
  196. package/dist/lib/attempt/observed.js +177 -0
  197. package/dist/lib/attempt/policy.js +92 -0
  198. package/dist/lib/attempt/record.js +29 -0
  199. package/dist/lib/attempt/retryLoopContext.js +31 -0
  200. package/dist/lib/attempt/retryLoopTypes.js +3 -0
  201. package/dist/lib/attempt/runner.js +530 -0
  202. package/dist/lib/attempt/standalone.js +130 -0
  203. package/dist/lib/attempt/types.js +17 -0
  204. package/dist/lib/budget/index.js +17 -0
  205. package/dist/lib/budget/timeBudget.js +674 -0
  206. package/dist/lib/builder/FlowChartBuilder.js +199 -9
  207. package/dist/lib/builder/retryLoop.js +287 -0
  208. package/dist/lib/builder/types.js +1 -1
  209. package/dist/lib/decide/decide.js +2 -2
  210. package/dist/lib/decide/index.js +2 -2
  211. package/dist/lib/decide/types.js +1 -8
  212. package/dist/lib/engine/graph/StageNode.js +1 -1
  213. package/dist/lib/engine/graph/prefixNodeTree.js +5 -1
  214. package/dist/lib/engine/handlers/ChildrenExecutor.js +36 -6
  215. package/dist/lib/engine/handlers/DeciderHandler.js +7 -3
  216. package/dist/lib/engine/handlers/ResumeEntry.js +3 -1
  217. package/dist/lib/engine/handlers/SelectorHandler.js +4 -3
  218. package/dist/lib/engine/handlers/StageRunner.js +36 -9
  219. package/dist/lib/engine/handlers/SubflowExecutor.js +24 -5
  220. package/dist/lib/engine/handlers/commitStage.js +24 -5
  221. package/dist/lib/engine/handlers/stageError.js +26 -2
  222. package/dist/lib/engine/index.js +1 -1
  223. package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +67 -39
  224. package/dist/lib/engine/narrative/FlowRecorderDispatcher.js +19 -2
  225. package/dist/lib/engine/narrative/NarrativeFlowRecorder.js +60 -8
  226. package/dist/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
  227. package/dist/lib/engine/narrative/formatting/sentences.js +131 -2
  228. package/dist/lib/engine/narrative/index.js +1 -1
  229. package/dist/lib/engine/narrative/narrativeTypes.js +1 -1
  230. package/dist/lib/engine/narrative/recorders/ManifestFlowRecorder.js +55 -2
  231. package/dist/lib/engine/narrative/recorders/index.js +1 -1
  232. package/dist/lib/engine/narrative/types.js +1 -1
  233. package/dist/lib/engine/traversal/FlowchartTraverser.js +192 -116
  234. package/dist/lib/engine/traversalContext.js +6 -3
  235. package/dist/lib/engine/types.js +1 -1
  236. package/dist/lib/errors/terminalFailure.js +64 -0
  237. package/dist/lib/filter/evaluator.js +139 -0
  238. package/dist/lib/ids/idempotencyKey.js +28 -0
  239. package/dist/lib/memory/StageContext.js +246 -5
  240. package/dist/lib/memory/attention.js +175 -0
  241. package/dist/lib/memory/borrowedMutation.js +16 -2
  242. package/dist/lib/memory/frameTypes.js +3 -1
  243. package/dist/lib/memory/redaction.js +54 -5
  244. package/dist/lib/pause/record.js +10 -1
  245. package/dist/lib/pause/types.js +17 -1
  246. package/dist/lib/reactive/createTypedScope.js +3 -1
  247. package/dist/lib/reactive/types.js +3 -1
  248. package/dist/lib/recorder/AttemptRecorder.js +417 -0
  249. package/dist/lib/recorder/ControlDepRecorder.js +50 -2
  250. package/dist/lib/recorder/EmitRecorder.js +1 -1
  251. package/dist/lib/recorder/InOutRecorder.js +75 -6
  252. package/dist/lib/recorder/QualityRecorder.js +87 -29
  253. package/dist/lib/recorder/TopologyRecorder.js +76 -2
  254. package/dist/lib/recorder/attemptMetricRows.js +209 -0
  255. package/dist/lib/recorder/attemptMetrics.js +174 -0
  256. package/dist/lib/recorder/attemptMetricsTypes.js +3 -0
  257. package/dist/lib/recorder/attemptOTel.js +111 -0
  258. package/dist/lib/recorder/attemptSeries.js +113 -0
  259. package/dist/lib/recorder/hooks.js +4 -1
  260. package/dist/lib/runner/DeferredObserverTier.js +13 -1
  261. package/dist/lib/runner/ExecutionRuntime.js +57 -5
  262. package/dist/lib/runner/FlowChartExecutor.js +330 -101
  263. package/dist/lib/runner/RunnableChart.js +5 -1
  264. package/dist/lib/runner/attach.js +8 -2
  265. package/dist/lib/runner/checkpoint.js +3 -1
  266. package/dist/lib/runner/deadline.js +94 -0
  267. package/dist/lib/runner/index.js +4 -2
  268. package/dist/lib/runner/options.js +3 -1
  269. package/dist/lib/runner/recordSink.js +302 -0
  270. package/dist/lib/runner/resume.js +22 -2
  271. package/dist/lib/runner/snapshot.js +6 -2
  272. package/dist/lib/scope/ScopeFacade.js +303 -6
  273. package/dist/lib/scope/recorders/DebugRecorder.js +79 -13
  274. package/dist/lib/scope/recorders/MetricRecorder.js +15 -2
  275. package/dist/lib/scope/runtime.js +1 -1
  276. package/dist/lib/scope/types.js +1 -1
  277. package/dist/lib/sinks/fileSink.js +392 -0
  278. package/dist/recorders.js +10 -2
  279. package/dist/sinks.js +32 -0
  280. package/dist/trace.js +1 -1
  281. package/dist/types/index.d.ts +62 -2
  282. package/dist/types/lib/attempt/anySignal.d.ts +19 -0
  283. package/dist/types/lib/attempt/call.d.ts +88 -0
  284. package/dist/types/lib/attempt/category.d.ts +37 -0
  285. package/dist/types/lib/attempt/correlation.d.ts +95 -0
  286. package/dist/types/lib/attempt/deadline.d.ts +44 -0
  287. package/dist/types/lib/attempt/decision.d.ts +52 -0
  288. package/dist/types/lib/attempt/effect.d.ts +76 -0
  289. package/dist/types/lib/attempt/errors.d.ts +41 -0
  290. package/dist/types/lib/attempt/index.d.ts +18 -0
  291. package/dist/types/lib/attempt/name.d.ts +21 -0
  292. package/dist/types/lib/attempt/observed.d.ts +66 -0
  293. package/dist/types/lib/attempt/policy.d.ts +45 -0
  294. package/dist/types/lib/attempt/record.d.ts +11 -0
  295. package/dist/types/lib/attempt/retryLoopContext.d.ts +18 -0
  296. package/dist/types/lib/attempt/retryLoopTypes.d.ts +18 -0
  297. package/dist/types/lib/attempt/runner.d.ts +157 -0
  298. package/dist/types/lib/attempt/standalone.d.ts +47 -0
  299. package/dist/types/lib/attempt/types.d.ts +453 -0
  300. package/dist/types/lib/budget/index.d.ts +9 -0
  301. package/dist/types/lib/budget/timeBudget.d.ts +136 -0
  302. package/dist/types/lib/builder/FlowChartBuilder.d.ts +88 -3
  303. package/dist/types/lib/builder/retryLoop.d.ts +56 -0
  304. package/dist/types/lib/builder/types.d.ts +35 -1
  305. package/dist/types/lib/decide/index.d.ts +1 -1
  306. package/dist/types/lib/decide/types.d.ts +3 -0
  307. package/dist/types/lib/engine/graph/StageNode.d.ts +11 -1
  308. package/dist/types/lib/engine/handlers/StageRunner.d.ts +8 -1
  309. package/dist/types/lib/engine/handlers/commitStage.d.ts +7 -0
  310. package/dist/types/lib/engine/handlers/stageError.d.ts +9 -0
  311. package/dist/types/lib/engine/index.d.ts +2 -2
  312. package/dist/types/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +27 -13
  313. package/dist/types/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -1
  314. package/dist/types/lib/engine/narrative/NarrativeFlowRecorder.d.ts +22 -3
  315. package/dist/types/lib/engine/narrative/NullControlFlowNarrativeGenerator.d.ts +1 -0
  316. package/dist/types/lib/engine/narrative/formatting/sentences.d.ts +23 -0
  317. package/dist/types/lib/engine/narrative/index.d.ts +2 -2
  318. package/dist/types/lib/engine/narrative/narrativeTypes.d.ts +27 -21
  319. package/dist/types/lib/engine/narrative/recorders/ManifestFlowRecorder.d.ts +45 -2
  320. package/dist/types/lib/engine/narrative/recorders/index.d.ts +1 -1
  321. package/dist/types/lib/engine/narrative/types.d.ts +74 -5
  322. package/dist/types/lib/engine/traversal/FlowchartTraverser.d.ts +59 -19
  323. package/dist/types/lib/engine/traversalContext.d.ts +7 -2
  324. package/dist/types/lib/engine/types.d.ts +52 -57
  325. package/dist/types/lib/errors/terminalFailure.d.ts +29 -0
  326. package/dist/types/lib/{decide → filter}/evaluator.d.ts +7 -2
  327. package/dist/types/lib/ids/idempotencyKey.d.ts +14 -0
  328. package/dist/types/lib/memory/StageContext.d.ts +123 -3
  329. package/dist/types/lib/memory/attention.d.ts +26 -0
  330. package/dist/types/lib/memory/borrowedMutation.d.ts +8 -0
  331. package/dist/types/lib/memory/frameTypes.d.ts +38 -0
  332. package/dist/types/lib/memory/redaction.d.ts +12 -0
  333. package/dist/types/lib/pause/types.d.ts +19 -0
  334. package/dist/types/lib/reactive/types.d.ts +36 -4
  335. package/dist/types/lib/recorder/AttemptRecorder.d.ts +141 -0
  336. package/dist/types/lib/recorder/ControlDepRecorder.d.ts +36 -2
  337. package/dist/types/lib/recorder/EmitRecorder.d.ts +3 -0
  338. package/dist/types/lib/recorder/InOutRecorder.d.ts +37 -1
  339. package/dist/types/lib/recorder/QualityRecorder.d.ts +32 -5
  340. package/dist/types/lib/recorder/TopologyRecorder.d.ts +35 -5
  341. package/dist/types/lib/recorder/attemptMetricRows.d.ts +11 -0
  342. package/dist/types/lib/recorder/attemptMetrics.d.ts +7 -0
  343. package/dist/types/lib/recorder/attemptMetricsTypes.d.ts +114 -0
  344. package/dist/types/lib/recorder/attemptOTel.d.ts +78 -0
  345. package/dist/types/lib/recorder/attemptSeries.d.ts +81 -0
  346. package/dist/types/lib/recorder/hooks.d.ts +9 -0
  347. package/dist/types/lib/runner/ExecutionRuntime.d.ts +54 -6
  348. package/dist/types/lib/runner/FlowChartExecutor.d.ts +46 -2
  349. package/dist/types/lib/runner/RunnableChart.d.ts +6 -0
  350. package/dist/types/lib/runner/attach.d.ts +2 -1
  351. package/dist/types/lib/runner/deadline.d.ts +42 -0
  352. package/dist/types/lib/runner/index.d.ts +3 -1
  353. package/dist/types/lib/runner/options.d.ts +17 -0
  354. package/dist/types/lib/runner/recordSink.d.ts +128 -0
  355. package/dist/types/lib/runner/resume.d.ts +3 -0
  356. package/dist/types/lib/runner/snapshot.d.ts +2 -2
  357. package/dist/types/lib/scope/ScopeFacade.d.ts +118 -4
  358. package/dist/types/lib/scope/recorders/DebugRecorder.d.ts +17 -3
  359. package/dist/types/lib/scope/recorders/MetricRecorder.d.ts +10 -0
  360. package/dist/types/lib/scope/runtime.d.ts +3 -0
  361. package/dist/types/lib/scope/types.d.ts +6 -0
  362. package/dist/types/lib/sinks/fileSink.d.ts +135 -0
  363. package/dist/types/recorders.d.ts +8 -2
  364. package/dist/types/sinks.d.ts +23 -0
  365. package/dist/types/trace.d.ts +2 -2
  366. package/package.json +20 -6
  367. package/dist/esm/lib/decide/evaluator.js +0 -130
  368. package/dist/lib/decide/evaluator.js +0 -134
@@ -9,9 +9,10 @@
9
9
  * The engine (FlowchartTraverser) receives this as its runtime parameter.
10
10
  * After execution, consumers query it for the full execution state.
11
11
  */
12
- import type { CommitBundle, CommitValuesMode, LogAddress } from 'foottrace';
13
- import type { WriteProvenanceMode } from 'foottrace/write';
12
+ import type { CommitBundle, CommitValuesMode, LogAddress, LogOutcome, Meta } from 'foottrace';
13
+ import type { RecordSink, WriteProvenanceMode } from 'foottrace/write';
14
14
  import { EventLog, SharedMemory } from 'foottrace/write';
15
+ import type { RunCorrelation } from '../attempt/types.js';
15
16
  import type { StageSnapshot } from '../memory/frameTypes.js';
16
17
  import type { RunPolicy } from '../memory/runPolicy.js';
17
18
  import { StageContext } from '../memory/StageContext.js';
@@ -56,6 +57,13 @@ export type RuntimeSnapshot = {
56
57
  * snapshot carries a DIFFERENT runId than the paused run's snapshot.
57
58
  */
58
59
  readonly runId: string;
60
+ /**
61
+ * The run's correlation (10.1) — `env.traceparent`, or `env.traceId` + `env.operationId`, resolved once per
62
+ * leg; the same frozen object every event of the leg carries (`TraversalContext.correlation`, a scope event's
63
+ * `correlation`). Like `runId`, per leg: a resume carries ITS env's, never the paused leg's. Absent — no
64
+ * key — when none was given.
65
+ */
66
+ readonly correlation?: RunCorrelation;
59
67
  sharedState: Record<string, unknown>;
60
68
  executionTree: StageSnapshot;
61
69
  /**
@@ -124,7 +132,34 @@ export type RuntimeSnapshot = {
124
132
  * with `{ delivery: 'deferred' }` on this executor (zero-cost discipline).
125
133
  */
126
134
  observerStats?: ObserverStats;
135
+ /**
136
+ * The crash-safe record's accounting (10.1, P6) — how many entries the run handed its sink and how many the sink
137
+ * did not take. ABSENT unless the executor was built with a `sink` and a run started.
138
+ */
139
+ sink?: RecordSinkStats;
127
140
  };
141
+ /** `getSnapshot().sink` — what the run handed its sink, and what the sink did not take (10.1, P6). */
142
+ export interface RecordSinkStats {
143
+ /** Entries handed to the adapter (each `opened`, `commit`, `note`, `closed` call). */
144
+ readonly entries: number;
145
+ /**
146
+ * Losses — a method that threw or rejected, an entry the log refused to send, a `meta` the log could not copy
147
+ * (that entry was still stored, without it), and failed or timed-out flushes. A rejection that settles after the
148
+ * run finished is counted when it settles.
149
+ */
150
+ readonly failed: number;
151
+ /** The last loss's error, as text. Absent while nothing was lost. */
152
+ readonly lastError?: string;
153
+ }
154
+ /**
155
+ * Where a runtime's log writes as it lands (10.1, P6): the run's sink, the log's address and what the writer puts on
156
+ * its `opened` entry. Absent → the log is the plain one-argument `EventLog`, byte-identical to 10.0.
157
+ */
158
+ export interface RuntimeRecord {
159
+ readonly sink: RecordSink;
160
+ readonly address: LogAddress;
161
+ readonly meta?: Meta;
162
+ }
128
163
  export declare class ExecutionRuntime {
129
164
  globalStore: SharedMemory;
130
165
  /**
@@ -139,6 +174,8 @@ export declare class ExecutionRuntime {
139
174
  redactedStore?: SharedMemory;
140
175
  rootStageContext: StageContext;
141
176
  executionHistory: EventLog;
177
+ /** The run's sink, when this runtime's log writes to one — handed on to every mount (`recordFor`). */
178
+ private recordSink?;
142
179
  /** Original root for getSnapshot() — set before resume changes rootStageContext. */
143
180
  private _snapshotRoot?;
144
181
  private _initialState;
@@ -155,7 +192,7 @@ export declare class ExecutionRuntime {
155
192
  * every frame after inherits the same reference. Default: every dial at
156
193
  * its default, no rule, no mirror.
157
194
  */
158
- constructor(rootName: string, rootId: string, defaultValues?: unknown, initialState?: unknown, policy?: RunPolicy);
195
+ constructor(rootName: string, rootId: string, defaultValues?: unknown, initialState?: unknown, policy?: RunPolicy, record?: RuntimeRecord);
159
196
  /**
160
197
  * A fresh root frame for this runtime — `globalStore`, `executionHistory`,
161
198
  * the run's policy and (when kept) the mirror. Also how `SubflowExecutor`
@@ -193,6 +230,16 @@ export declare class ExecutionRuntime {
193
230
  * 9.44.2).
194
231
  */
195
232
  private getFoldBase;
233
+ /**
234
+ * Where a mount's log writes (10.1, P6): the same sink, at this log's address plus the mount's `runtimeStageId`
235
+ * (`drillPath: [...parent, mount]`, the address law `RuntimeSnapshot.logAddress` states). Absent when this log
236
+ * writes to no sink — a mount of a plain log is plain too.
237
+ */
238
+ recordFor(mountRuntimeStageId: string, meta?: Meta): RuntimeRecord | undefined;
239
+ /** Tell the sink this runtime's log ended. Nothing happens without a sink; never throws. */
240
+ closeRecord(outcome: LogOutcome, meta?: Meta): void;
241
+ /** Note something beside this runtime's log, in its sink (a resumed leg). Nothing without a sink; never throws. */
242
+ noteRecord(kind: string, data: Meta): void;
196
243
  getPipelines(): string[];
197
244
  setRootObject(path: string[], key: string, value: unknown): void;
198
245
  /**
@@ -222,14 +269,15 @@ export declare class ExecutionRuntime {
222
269
  * `stateAt`, which is the honest signal that the base did not travel with
223
270
  * this log — a partial answer that says it is partial, never a silent one.
224
271
  *
225
- * Returns `Omit<RuntimeSnapshot, 'runId'>`: the runtime is the memory
272
+ * Returns `Omit<RuntimeSnapshot, 'runId' | 'correlation'>`: the runtime is the memory
226
273
  * container and doesn't know which run it serves — `runId` is per-run
227
274
  * executor state, stamped by `FlowchartTraverser.getSnapshot()` (which
228
275
  * owns the run's id and already stamps it on every event). Subflows'
229
276
  * nested runtimes deliberately have NO runId of their own (a subflow is
230
- * part of the parent's logical run).
277
+ * part of the parent's logical run). `correlation` is the traverser's for
278
+ * the same reason.
231
279
  */
232
280
  getSnapshot(options?: {
233
281
  redact?: boolean;
234
- }): Omit<RuntimeSnapshot, 'runId'>;
282
+ }): Omit<RuntimeSnapshot, 'runId' | 'correlation'>;
235
283
  }
@@ -28,6 +28,7 @@ import type { CombinedNarrativeEntry } from '../engine/narrative/narrativeTypes.
28
28
  import type { ManifestEntry } from '../engine/narrative/recorders/ManifestFlowRecorder.js';
29
29
  import type { FlowRecorder } from '../engine/narrative/types.js';
30
30
  import { type ExecutorResult, type RunOptions, type ScopeFactory, type SerializedPipelineStructure, type StageNode, type SubflowResult } from '../engine/types.js';
31
+ import { type TerminalFailureContext } from '../errors/terminalFailure.js';
31
32
  import type { ReadTrackingMode, WriteTrackingMode } from '../memory/frameTypes.js';
32
33
  import type { FlowchartCheckpoint } from '../pause/types.js';
33
34
  import type { CombinedRecorder } from '../recorder/CombinedRecorder.js';
@@ -36,6 +37,7 @@ import type { RedactionPolicy, RedactionReport, ScopeRecorder } from '../scope/t
36
37
  import type { AttachRecorderOptions, ObserverDrainResult } from './DeferredObserverTier.js';
37
38
  import { type RuntimeSnapshot } from './ExecutionRuntime.js';
38
39
  import { type FlowChartExecutorOptions } from './options.js';
40
+ import { type RecordFlushResult } from './recordSink.js';
39
41
  export declare class FlowChartExecutor<TOut = any, TScope = any> {
40
42
  private traverser;
41
43
  /** Shared execution counter and per-stage visit counts (loopIteration) — shared BY
@@ -63,7 +65,16 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
63
65
  * See docs/guides/execution-model.md.
64
66
  */
65
67
  private _isExecuting;
68
+ private failureState;
69
+ /** Safe native context for the latest rejected leg; undefined before, during, after success or pause. */
70
+ getFailureContext(): TerminalFailureContext | undefined;
66
71
  private readonly flowChartArgs;
72
+ /**
73
+ * The crash-safe record of the current run (10.1, P6) — the sink every log of the run writes to, its
74
+ * accounting and its failure mode. Fresh per `run()` and per fresh-executor resume; a same-executor resume keeps
75
+ * it, as it keeps the root log. Absent without a `sink` option.
76
+ */
77
+ private record;
67
78
  /**
68
79
  * Create a FlowChartExecutor.
69
80
  *
@@ -159,7 +170,7 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
159
170
  * const result = await executor.resume(restored, { approved: true });
160
171
  * ```
161
172
  */
162
- resume(checkpoint: FlowchartCheckpoint, resumeInput?: unknown, options?: Pick<RunOptions, 'signal' | 'env' | 'maxDepth' | 'maxIterations'>): Promise<ExecutorResult>;
173
+ resume(checkpoint: FlowchartCheckpoint, resumeInput?: unknown, options?: Pick<RunOptions, 'signal' | 'env' | 'maxDepth' | 'maxIterations' | 'deadline' | 'timeoutMs'>): Promise<ExecutorResult>;
163
174
  /**
164
175
  * The settle of a leg that threw: flush the deferred tier (the OUTERMOST
165
176
  * handler — a pause re-throws through subflow traversers without exit
@@ -168,6 +179,22 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
168
179
  * is rethrown.
169
180
  */
170
181
  private pausedOrThrow;
182
+ /**
183
+ * The settle of a leg that writes its record (10.1, P6) — the 10.0 settle (`run()` / `resume()`), then the root
184
+ * log's closing entry with how the leg ended, then (`flush: 'auto'`) the adapter's flush, all before the leg
185
+ * counts as finished. A leg without a sink never comes here: its settle has no extra await.
186
+ *
187
+ * The leg's own error always wins. A run that finished but lost an entry under `onFailure: 'fail'` rejects with
188
+ * the `RecordSinkError`.
189
+ */
190
+ private settleRecorded;
191
+ /**
192
+ * What a new root log opens with: names and numbers the run already serves — the run, the chart, the correlation,
193
+ * the deadline, the declared budget, and the run a fresh-executor resume continues. Served by the record.
194
+ */
195
+ private openingMeta;
196
+ /** The closing entry's error: the run's SERVED form of it, its name, message and code only (never `raw`). */
197
+ private closingError;
171
198
  /** The re-entrancy guard: one executor = one in-flight execution. */
172
199
  private assertIdle;
173
200
  /**
@@ -273,7 +300,8 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
273
300
  *
274
301
  * @param options `{ input, env }` — `input` is the frozen business input
275
302
  * (read in a stage via `scope.$getArgs()`); `env` is infrastructure context
276
- * like `{ signal, timeoutMs, traceId }` (read via `scope.$getEnv()`).
303
+ * like `{ signal, timeoutMs, traceId }` (read via `scope.$getEnv()`); `deadline` / `timeoutMs` give the run
304
+ * its deadline (`env.deadline`, `scope.$attempt().timeLeftMs()`).
277
305
  *
278
306
  * After it resolves, read results off the executor:
279
307
  * - `getSnapshot()` — full state, commit log, execution tree.
@@ -294,6 +322,22 @@ export declare class FlowChartExecutor<TOut = any, TScope = any> {
294
322
  drainObservers(opts?: {
295
323
  timeoutMs?: number;
296
324
  }): Promise<ObserverDrainResult>;
325
+ /**
326
+ * Flush the record sink (10.1, P6): await the adapter's `flush()` — for an executor built with
327
+ * `sink: { adapter, flush: 'manual' }`, or before a serverless process freezes. `timeoutMs` bounds the wait; a
328
+ * flush still running then is `pending` (and keeps running). A failed flush is counted on `getSnapshot().sink`.
329
+ * Done at once without a sink, or with an adapter that has no `flush`.
330
+ *
331
+ * @example
332
+ * ```typescript
333
+ * const executor = new FlowChartExecutor(chart, { sink: { adapter: fileSink(path), flush: 'manual' } });
334
+ * await executor.run();
335
+ * await executor.flushRecord({ timeoutMs: 2_000 });
336
+ * ```
337
+ */
338
+ flushRecord(opts?: {
339
+ timeoutMs?: number;
340
+ }): Promise<RecordFlushResult>;
297
341
  /**
298
342
  * Returns the runtime snapshot.
299
343
  *
@@ -5,6 +5,7 @@
5
5
  * Called by FlowChartBuilder.build() to enrich the compiled chart with
6
6
  * d3-style chainable run methods and self-describing outputs.
7
7
  */
8
+ import { type TimeBudgetOptions, type TimeBudgetReport } from '../budget/index.js';
8
9
  import type { FlowChart } from '../builder/types.js';
9
10
  import type { JsonSchema } from '../contract/types.js';
10
11
  import type { FlowRecorder } from '../engine/narrative/types.js';
@@ -49,6 +50,11 @@ export interface RunnableFlowChart<TOut = any, TScope = any> extends FlowChart<T
49
50
  toMCPTool(): MCPToolDescription;
50
51
  /** Generate a Mermaid flowchart diagram string from the chart's node graph. */
51
52
  toMermaid(): string;
53
+ /**
54
+ * The slowest this chart can take, from its declared retry policies — `timeBudget(chart, options)`. Checks
55
+ * against the chart's declared `.budget(ms)` unless `options.budgetMs` is given.
56
+ */
57
+ timeBudget(options?: TimeBudgetOptions): TimeBudgetReport;
52
58
  }
53
59
  /**
54
60
  * Enrich a FlowChart with run + describe methods.
@@ -15,6 +15,7 @@
15
15
  * from the same per-stage list as `onRead`/`onWrite`);
16
16
  * - a flow attach turns the narrative on (the flow channel needs it).
17
17
  */
18
+ import type { RunCorrelation } from '../attempt/types.js';
18
19
  import type { CombinedNarrativeRecorderOptions } from '../engine/narrative/CombinedNarrativeRecorder.js';
19
20
  import { CombinedNarrativeRecorder } from '../engine/narrative/CombinedNarrativeRecorder.js';
20
21
  import type { FlowRecorder } from '../engine/narrative/types.js';
@@ -77,7 +78,7 @@ export declare class RunObservers {
77
78
  * The marked-keys set is ALWAYS wired (a stage can call
78
79
  * `setValue(key, val, true)` for per-call redaction without any policy).
79
80
  */
80
- composeScopeFactory<TScope>(baseFactory: ScopeFactory<TScope>, redactionPolicy: RedactionPolicy | undefined, sharedRedactedKeys: Set<string>): ScopeFactory<TScope>;
81
+ composeScopeFactory<TScope>(baseFactory: ScopeFactory<TScope>, redactionPolicy: RedactionPolicy | undefined, sharedRedactedKeys: Set<string>, correlation?: RunCorrelation): ScopeFactory<TScope>;
81
82
  /**
82
83
  * The leg's flow recorders: the narrative recorder (when on), the user's
83
84
  * flow recorders, then the deferred tier's flow tap (RFC-001 Block 7) —
@@ -0,0 +1,42 @@
1
+ /**
2
+ * runner/deadline.ts — `armRun`: the run's ONE effective signal and its deadline (design §3.1, P1b).
3
+ *
4
+ * A run has three ways to be told to stop — `RunOptions.signal`, `env.signal`, and a deadline (`RunOptions.deadline`,
5
+ * `now + RunOptions.timeoutMs`, or `env.deadline`; the earliest wins). Before 10.1 they did not compose: `timeoutMs`
6
+ * was ignored beside a `signal`, and `env.signal` was readable but never raced. `armRun` composes all of them into
7
+ * one signal the traverser races (and hands every subflow), and stamps the env a stage reads:
8
+ *
9
+ * env.deadline = the deadline (epoch ms) env.signal = the one composed signal
10
+ *
11
+ * — but only when there is something to stamp AND somewhere it was already going: a deadline always gives the run
12
+ * an env; a signal is stamped onto an env the caller gave. A run with no deadline and no env keeps no env, so a
13
+ * stage's `$getEnv()` stays `{}` and its commit carries no `'env'` mark — byte-identical to 10.0.
14
+ *
15
+ * At the deadline the signal aborts with a BRANDED reason (`attempt/deadline.ts`) carrying the message a run with
16
+ * `timeoutMs` always rejected with, so the attempt runner reads it as "out of time" (`timeout` / `no-time-left`),
17
+ * never as a cancellation.
18
+ */
19
+ import type { ExecutionEnv } from '../engine/types.js';
20
+ /** What `armRun` reads — the run's own options. */
21
+ export interface RunTiming {
22
+ readonly signal?: AbortSignal;
23
+ readonly timeoutMs?: number;
24
+ readonly deadline?: number;
25
+ readonly env?: ExecutionEnv;
26
+ /**
27
+ * The executor's own stop (10.1, P6): a record sink with `onFailure: 'fail'` aborts it at the first lost entry,
28
+ * with the `RecordSinkError` as its reason. Composed like the others; absent for every other run.
29
+ */
30
+ readonly stop?: AbortSignal;
31
+ }
32
+ /** The armed run: the signal the traverser races, the env stages read, and the one call that releases both. */
33
+ export interface ArmedRun {
34
+ readonly signal: AbortSignal | undefined;
35
+ readonly env: ExecutionEnv | undefined;
36
+ /** The run's deadline, epoch ms — absent without one. */
37
+ readonly deadline: number | undefined;
38
+ /** Clear the deadline timer and remove every listener composition added. Idempotent. */
39
+ dispose(): void;
40
+ }
41
+ /** Compose the run's signal and deadline from its options; `now` is the clock (epoch ms). */
42
+ export declare function armRun(timing: RunTiming, now?: () => number): ArmedRun;
@@ -1,11 +1,13 @@
1
1
  export type { ComposableRunner } from './ComposableRunner.js';
2
2
  export type { AttachRecorderOptions, ObserverDelivery, ObserverDrainResult, ObserverStats, } from './DeferredObserverTier.js';
3
- export type { RecorderSnapshot, RuntimeSnapshot } from './ExecutionRuntime.js';
3
+ export type { RecorderSnapshot, RecordSinkStats, RuntimeSnapshot } from './ExecutionRuntime.js';
4
4
  export { ExecutionRuntime } from './ExecutionRuntime.js';
5
5
  export { FlowChartExecutor } from './FlowChartExecutor.js';
6
6
  export type { SubtreeSnapshot } from './getSubtreeSnapshot.js';
7
7
  export { getSubtreeSnapshot, listSubflowPaths } from './getSubtreeSnapshot.js';
8
8
  export type { FlowChartExecutorOptions } from './options.js';
9
+ export type { RecordFlushResult, RecordSinkFailureMode, RecordSinkFlushMode, RecordSinkOption, RecordSinkOptions, } from './recordSink.js';
10
+ export { RecordSinkError } from './recordSink.js';
9
11
  export type { RunResult } from './RunContext.js';
10
12
  export { RunContext } from './RunContext.js';
11
13
  export type { RunnableFlowChart } from './RunnableChart.js';
@@ -9,6 +9,7 @@ import type { FlowChart } from '../builder/types.js';
9
9
  import type { ScopeFactory, StreamHandlers } from '../engine/types.js';
10
10
  import type { RunDials } from '../memory/runPolicy.js';
11
11
  import type { ScopeProtectionMode } from '../scope/protection/types.js';
12
+ import { type RecordSinkOption, type ResolvedRecordSink } from './recordSink.js';
12
13
  /**
13
14
  * Options object for `FlowChartExecutor` — preferred over positional params.
14
15
  *
@@ -44,6 +45,20 @@ export interface FlowChartExecutorOptions<TScope = any> extends RunDials {
44
45
  initialContext?: unknown;
45
46
  /** Read-only input accessible via `scope.getArgs()` — never tracked or written. */
46
47
  readOnlyContext?: unknown;
48
+ /**
49
+ * Where the run's record goes AS IT LANDS, so a run that never finishes still leaves it: every log of the run
50
+ * (the root and each subflow mount) hands the sink its `opened` base, each commit, a note per attempt that ended,
51
+ * and its `closed` outcome. `fileSink(path)` (`footprintjs/sinks`, Node) or `memorySink()` (`foottrace/write`);
52
+ * read it back with `readStoredRecord` (`foottrace`). The redaction policy applies before any entry is written.
53
+ * A failing sink never stops the run (`onFailure: 'report'`, the default) — `getSnapshot().sink` counts what was
54
+ * lost. See the guide's "A crash-safe record".
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * const executor = new FlowChartExecutor(chart, { sink: fileSink('/var/footprint/run.jsonl') });
59
+ * ```
60
+ */
61
+ sink?: RecordSinkOption;
47
62
  /**
48
63
  * Custom error classifier for throttling detection. Return `true` if a fork
49
64
  * child's error represents a rate-limit or backpressure condition; the
@@ -70,6 +85,8 @@ export interface ExecutorArgs<TOut, TScope> {
70
85
  scopeProtectionMode?: ScopeProtectionMode;
71
86
  /** The dials as given (absent = default) — the run's policy is built from them per leg. */
72
87
  dials: RunDials;
88
+ /** The record sink, resolved and checked at construction (10.1, P6). */
89
+ sink?: ResolvedRecordSink;
73
90
  }
74
91
  /**
75
92
  * Resolve either constructor form. The 2-param form is the options form with
@@ -0,0 +1,128 @@
1
+ /**
2
+ * runner/recordSink.ts — the run's side of the crash-safe record (design §3.5, packet P6).
3
+ *
4
+ * foottrace owns the port (`RecordSink`, `foottrace/write`): a log built with a sink hands it every entry AS IT
5
+ * LANDS — `opened`, `commit`, `note`, `closed` — and counts what the sink did not take. This file is what the
6
+ * EXECUTOR adds around an app's adapter, one {@link RunRecord} per run:
7
+ *
8
+ * - THE ONE LAW, before any byte leaves: the `opened` base is the run's served form of it (the redaction rule's
9
+ * `retainState`, the mirror's seed — so a policy key seeded by `initialContext` or a checkpoint never reaches
10
+ * the sink), and the `opened` / `closed` meta are boundary records (`retainBoundary`). A commit is the log's own
11
+ * bundle, already scrubbed at commit; an attempt note carries the served `AttemptRecord` (no `raw`).
12
+ * - ACCOUNTING: every entry handed to the adapter is counted, every loss too (`getSnapshot().sink`), with a
13
+ * dev-mode warning on the first loss of a run. The adapter's own `onFailure` hears a dispatched entry's loss
14
+ * with that same served entry and a served error, isolated. A refusal before dispatch is counted without
15
+ * forwarding Foottrace's unserved entry.
16
+ * - THE FAILURE MODE (owner ruling Q3): `'report'` (default) — the run goes on; `'fail'` — the first lost entry
17
+ * aborts the run's signal with a {@link RecordSinkError}, and a run that finished with a loss rejects with it.
18
+ * - FLUSH: `'auto'` (default) — `run()` / `resume()` await the adapter's `flush()` after the closing entry;
19
+ * `'manual'` — the app calls `executor.flushRecord()`.
20
+ *
21
+ * Every adapter method is called synchronously from the log; whatever the adapter throws or rejects with is the
22
+ * log's to count (`EventLog · sinkFailures`), never the run's — so nothing here throws to the engine.
23
+ */
24
+ import type { Meta } from 'foottrace';
25
+ import type { RecordSink } from 'foottrace/write';
26
+ import type { RedactionRule } from '../memory/redaction.js';
27
+ import type { RecordSinkStats } from './ExecutionRuntime.js';
28
+ /** What a lost entry does to the run: `'report'` counts it and goes on; `'fail'` fails the run. */
29
+ export type RecordSinkFailureMode = 'report' | 'fail';
30
+ /** When the adapter's `flush()` runs: after each run's closing entry (`'auto'`), or when the app asks. */
31
+ export type RecordSinkFlushMode = 'auto' | 'manual';
32
+ /**
33
+ * The executor's `sink` option in its long form. The short form is the adapter itself.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * new FlowChartExecutor(chart, { sink: { adapter: fileSink('/var/footprint/run.jsonl'), onFailure: 'fail' } });
38
+ * ```
39
+ */
40
+ export interface RecordSinkOptions {
41
+ /** Where the entries go — `fileSink(path)` (`footprintjs/sinks`), `memorySink()` (`foottrace/write`), or yours. */
42
+ readonly adapter: RecordSink;
43
+ /** `'report'` (default): a lost entry is counted and the run goes on. `'fail'`: the first one fails the run. */
44
+ readonly onFailure?: RecordSinkFailureMode;
45
+ /** `'auto'` (default): `run()` awaits the adapter's `flush()` after the closing entry. `'manual'`: `flushRecord()`. */
46
+ readonly flush?: RecordSinkFlushMode;
47
+ }
48
+ /** The executor's `sink` option: an adapter, or {@link RecordSinkOptions}. */
49
+ export type RecordSinkOption = RecordSink | RecordSinkOptions;
50
+ /** What `executor.flushRecord()` resolves with — the `drainObservers` shape. */
51
+ export interface RecordFlushResult {
52
+ /** The adapter's flush finished (or there was nothing to flush). */
53
+ readonly done: boolean;
54
+ /** The adapter's flush threw or rejected — counted on `getSnapshot().sink`. */
55
+ readonly failed: boolean;
56
+ /** The flush had not settled when `timeoutMs` ran out. */
57
+ readonly pending: boolean;
58
+ }
59
+ /**
60
+ * A run with `sink: { onFailure: 'fail' }` lost an entry: the record the app asked to be kept is not whole.
61
+ * `cause` is the adapter's own error.
62
+ */
63
+ export declare class RecordSinkError extends Error {
64
+ readonly cause: unknown;
65
+ readonly name = "RecordSinkError";
66
+ constructor(message: string, cause: unknown);
67
+ }
68
+ /** The option resolved once, at construction. */
69
+ export interface ResolvedRecordSink {
70
+ readonly adapter: RecordSink;
71
+ readonly onFailure: RecordSinkFailureMode;
72
+ readonly flush: RecordSinkFlushMode;
73
+ }
74
+ /**
75
+ * Resolve the executor's `sink` option, or refuse it with a `TypeError` naming what is wrong — a wiring mistake
76
+ * the app makes once, so it fails at construction, never mid-run.
77
+ */
78
+ export declare function resolveRecordSink(option: unknown): ResolvedRecordSink | undefined;
79
+ /**
80
+ * One run's record sink: the sink every log of the run writes to (root and mounts), its accounting and its
81
+ * failure mode. A same-executor resume keeps it (the root log goes on); a fresh run makes a new one.
82
+ */
83
+ export declare class RunRecord {
84
+ private readonly resolved;
85
+ /** Hand this to every `EventLog` of the run. */
86
+ readonly sink: RecordSink;
87
+ private entries;
88
+ private failed;
89
+ private lastError?;
90
+ private warned;
91
+ private rule?;
92
+ /** Aborted at the first loss under `'fail'` — composed into the leg's signal; fresh per leg ({@link beginLeg}). */
93
+ private stopper?;
94
+ private failure?;
95
+ /** Opaque error identities only: no raw entry or adapter error is enumerable on the transport error. */
96
+ private readonly invocationFailures;
97
+ constructor(resolved: ResolvedRecordSink);
98
+ /** Capture the served entry now; an asynchronous failure keeps this leg's rule, not a later resume's rule. */
99
+ private invoke;
100
+ /** A sink error is the diagnostic errors.recordSinkError; raw causes belong only to the caller's exception. */
101
+ private errorView;
102
+ /**
103
+ * A same-executor resume starts a new leg on the same record: the counts go on (one log, one record), but the
104
+ * failure mode is the LEG's — a loss in an earlier leg (which already failed that leg) does not stop this one —
105
+ * and the dev-mode warning may fire again.
106
+ */
107
+ beginLeg(): void;
108
+ /** The leg's redaction rule — a resume builds a new one; the next `opened` / `closed` is served under it. */
109
+ useRule(rule: RedactionRule | undefined): void;
110
+ /** Aborts at the first loss under `onFailure: 'fail'`; absent otherwise. */
111
+ get stopSignal(): AbortSignal | undefined;
112
+ get flushMode(): RecordSinkFlushMode;
113
+ /** The loss that fails the run under `'fail'`; absent while nothing was lost (and always under `'report'`). */
114
+ get fatal(): RecordSinkError | undefined;
115
+ stats(): RecordSinkStats;
116
+ /**
117
+ * Await the adapter's `flush()`, at most `timeoutMs` when given. A flush that throws or rejects is a loss
118
+ * (counted, and fatal under `'fail'`); one still running at the deadline is `pending` and keeps running — and,
119
+ * with `pendingIsLoss` (the run's own flush), counted as a loss too, so a flush that never settles cannot hold a
120
+ * run open, and cannot pass for one that landed. Nothing here throws: a hostile adapter (a throwing `flush`
121
+ * getter, a promise with its own `then`) is a loss, never the run's error.
122
+ */
123
+ flush(timeoutMs?: number, pendingIsLoss?: boolean): Promise<RecordFlushResult>;
124
+ /** The meta as served: a boundary record, scrubbed by key name at every depth (an inert rule copies nothing). */
125
+ serve(meta: Meta): Meta;
126
+ /** One loss: counted, warned once per run, told with a safe dispatched entry when available, fatal under 'fail'. */
127
+ private lost;
128
+ }
@@ -17,6 +17,7 @@
17
17
  * The executor owns the per-run state between the steps (the runId, the
18
18
  * runtime, the traverser); this module never holds any.
19
19
  */
20
+ import type { RunCorrelation } from '../attempt/types.js';
20
21
  import type { FlowChart } from '../builder/types.js';
21
22
  import { ResumeEntry } from '../engine/handlers/ResumeEntry.js';
22
23
  import type { StageNode } from '../engine/types.js';
@@ -70,4 +71,6 @@ export declare function announceResume<TOut, TScope>(plan: ResumePlan<TOut, TSco
70
71
  readonly runId: string;
71
72
  readonly executionCount: number;
72
73
  readonly observers: RunObservers;
74
+ /** The RESUMED leg's correlation (from `resume()`'s env) — on both events, like every event of the leg. */
75
+ readonly correlation?: RunCorrelation;
73
76
  }): void;
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import type { FlowchartTraverser } from '../engine/traversal/FlowchartTraverser.js';
9
9
  import type { RunObservers } from './attach.js';
10
- import type { RecorderSnapshot, RuntimeSnapshot } from './ExecutionRuntime.js';
10
+ import type { RecorderSnapshot, RecordSinkStats, RuntimeSnapshot } from './ExecutionRuntime.js';
11
11
  /**
12
12
  * The served snapshot. `sharedState` is the LIVE view in production (zero
13
13
  * copy); in dev mode it is a deep-frozen CLONE, so a consumer mutation throws
@@ -15,7 +15,7 @@ import type { RecorderSnapshot, RuntimeSnapshot } from './ExecutionRuntime.js';
15
15
  */
16
16
  export declare function servedSnapshot(traverser: FlowchartTraverser<any, any>, observers: RunObservers, options?: {
17
17
  redact?: boolean;
18
- }): RuntimeSnapshot;
18
+ }, sink?: RecordSinkStats): RuntimeSnapshot;
19
19
  /**
20
20
  * Collect `toSnapshot()` bundles from every attached recorder — ONE entry
21
21
  * per recorder id, across all channels and both delivery tiers.