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
@@ -11,10 +11,11 @@
11
11
  * The execute() convenience method is intentionally omitted —
12
12
  * it belongs in the runner layer (Phase 5).
13
13
  */
14
- import type { ParallelForEachConfig, RetryPolicy, ScopeFactory } from '../engine/types.js';
14
+ import type { ParallelForEachConfig, RetryPolicy, ScopeFactory, StageTouches } from '../engine/types.js';
15
15
  import type { PausableHandler } from '../pause/types.js';
16
16
  import type { TypedScope } from '../reactive/types.js';
17
17
  import { type RunnableFlowChart } from '../runner/RunnableChart.js';
18
+ import type { RetryLoopOptions } from './retryLoop.js';
18
19
  import type { StructureEdgeKind, StructureRecorder } from './structure/StructureRecorder.js';
19
20
  import { StructureRecorderDispatcher } from './structure/StructureRecorderDispatcher.js';
20
21
  import { type TypedStageFunction } from './typedFlowChart.js';
@@ -35,6 +36,7 @@ export declare class DeciderList<TOut = any, TScope = any> {
35
36
  options?: {
36
37
  readonly loopTo?: string;
37
38
  readonly retry?: RetryPolicy;
39
+ readonly touches?: StageTouches;
38
40
  readonly tags?: readonly string[];
39
41
  }): DeciderList<TOut, TScope>;
40
42
  /**
@@ -54,6 +56,7 @@ export declare class DeciderList<TOut = any, TScope = any> {
54
56
  options?: {
55
57
  readonly loopTo?: string;
56
58
  readonly retry?: RetryPolicy;
59
+ readonly touches?: StageTouches;
57
60
  readonly tags?: readonly string[];
58
61
  }): DeciderList<TOut, TScope>;
59
62
  addSubFlowChartBranch(id: string, subflow: FlowChart<any, any>, mountName?: string, options?: SubflowMountOptions): DeciderList<TOut, TScope>;
@@ -107,6 +110,7 @@ export declare class SelectorFnList<TOut = any, TScope = any> {
107
110
  * `{ tags }` puts declared tags on it (see `FlowChartBuilder.tag`). */
108
111
  options?: {
109
112
  readonly retry?: RetryPolicy;
113
+ readonly touches?: StageTouches;
110
114
  readonly tags?: readonly string[];
111
115
  }): SelectorFnList<TOut, TScope>;
112
116
  /**
@@ -122,6 +126,7 @@ export declare class SelectorFnList<TOut = any, TScope = any> {
122
126
  * contract); `{ tags }` puts declared tags on it. */
123
127
  options?: {
124
128
  readonly retry?: RetryPolicy;
129
+ readonly touches?: StageTouches;
125
130
  readonly tags?: readonly string[];
126
131
  }): SelectorFnList<TOut, TScope>;
127
132
  addSubFlowChartBranch(id: string, subflow: FlowChart<any, any>, mountName?: string, options?: SubflowMountOptions): SelectorFnList<TOut, TScope>;
@@ -286,6 +291,7 @@ export declare class FlowChartBuilder<TOut = any, TScope = any> {
286
291
  }): this;
287
292
  start(name: string, fn: StageFunction<TOut, TScope> | PausableHandler<TScope>, id: string, description?: string, options?: {
288
293
  retry?: RetryPolicy;
294
+ touches?: StageTouches;
289
295
  tags?: readonly string[];
290
296
  }): this;
291
297
  /**
@@ -303,9 +309,12 @@ export declare class FlowChartBuilder<TOut = any, TScope = any> {
303
309
  startSelector(name: string, fn: StageFunction<any, TScope>, id: string, description?: string, options?: {
304
310
  failFast?: boolean;
305
311
  retry?: RetryPolicy;
312
+ touches?: StageTouches;
306
313
  tags?: readonly string[];
307
314
  }): SelectorFnList<TOut, TScope>;
308
315
  addFunction(name: string, fn: StageFunction<TOut, TScope>, id: string, description?: string): this;
316
+ /** Compose a keyed outside operation, reconciliation, shared retry decision and wait as ordinary chart nodes. */
317
+ addRetryLoop<TValue = unknown>(id: string, options: RetryLoopOptions<TScope, TValue>): this;
309
318
  addStreamingFunction(name: string, fn: StageFunction<TOut, TScope>, id: string, streamId?: string, description?: string): this;
310
319
  /**
311
320
  * Add a pausable stage — can pause execution and resume later with input.
@@ -417,6 +426,7 @@ export declare class FlowChartBuilder<TOut = any, TScope = any> {
417
426
  * `{ tags }` likewise. */
418
427
  options?: {
419
428
  retry?: RetryPolicy;
429
+ touches?: StageTouches;
420
430
  tags?: readonly string[];
421
431
  }): DeciderList<TOut, TScope>;
422
432
  addSelectorFunction(name: string, fn: StageFunction<any, TScope>, id: string, description?: string,
@@ -426,6 +436,7 @@ export declare class FlowChartBuilder<TOut = any, TScope = any> {
426
436
  options?: {
427
437
  failFast?: boolean;
428
438
  retry?: RetryPolicy;
439
+ touches?: StageTouches;
429
440
  tags?: readonly string[];
430
441
  }): SelectorFnList<TOut, TScope>;
431
442
  addListOfFunction(children: SimplifiedParallelSpec<TOut, TScope>[], options?: {
@@ -489,8 +500,13 @@ export declare class FlowChartBuilder<TOut = any, TScope = any> {
489
500
  * failed calls that came before the successful one left no mark anywhere —
490
501
  * an unexplained behaviour in a library whose whole point is that nothing
491
502
  * invisible happens. Declared here, every attempt is part of the record: each
492
- * failed attempt fires `FlowRecorder.onStageRetry` and appears in the
493
- * narrative, in order, between the attempts' own reads and writes.
503
+ * attempt fires `FlowRecorder.onAttempt` with its `AttemptRecord` (outcome,
504
+ * duration, failure category, the retry-or-stop decision), which is what
505
+ * feeds the narrative — one line per attempt, in order, between the
506
+ * attempts' own reads and writes. The stage's execution-tree node keeps the
507
+ * records (`attempts`, `attemptSummary`). A failed attempt that is retried
508
+ * also fires `FlowRecorder.onStageRetry`, which the narrative does not tell
509
+ * twice.
494
510
  *
495
511
  * ## What an attempt is
496
512
  *
@@ -518,6 +534,46 @@ export declare class FlowChartBuilder<TOut = any, TScope = any> {
518
534
  * `retry` option instead.
519
535
  */
520
536
  retry(policy: RetryPolicy): this;
537
+ /**
538
+ * Declare that the stage you JUST added changes an outside system — a charge, an email, a write to another
539
+ * service (10.1, design §3.3) — and give the rule for its idempotency key.
540
+ *
541
+ * ## Why declare it
542
+ *
543
+ * A retry is safe for a read. For a charge it is safe only when the outside system can tell a retry from a new
544
+ * request — by an idempotency key. So the builder refuses a touching stage that may retry (`.retry({ attempts >
545
+ * 1 })`, in either order) without a key rule: a double charge must be impossible to write by accident. A default
546
+ * key made by the library was rejected — the run id changes across a resume and a caller's whole-run retry, the
547
+ * two places a double charge actually happens. The key must name the OPERATION: derive it from the input the rule
548
+ * is handed, never from model output (`({ getState }) => …` reads it from state). A
549
+ * keyless touching stage may not `interrupt()`: a resume re-runs it from its top. In a chart that pauses, derive
550
+ * keys from state (`({ getState }) => …`): the run's input does not cross a resume.
551
+ *
552
+ * ## What it changes at run time
553
+ *
554
+ * The stage always runs on the attempt runner. The key rule runs ONCE per execution, before attempt 1, and every
555
+ * attempt gets the key as `scope.$attempt().idempotencyKey` — pass it to the system. Every attempt record says
556
+ * what it did there (`effect`: `'applied'`, `'none'` when the error itself declares `effect: 'none'`, else
557
+ * `'unknown'`). When ANY attempt left the effect unknown — it timed out, was cut, or failed without the adapter
558
+ * saying nothing was sent — the stage fails with `UnknownEffectError`: reconcile with the system by the key, do
559
+ * not retry blindly. The spec carries the system's name (`touches`).
560
+ *
561
+ * @example
562
+ * ```ts
563
+ * flowChart<Order>('Load order', loadFn, 'load')
564
+ * .addFunction('Charge card', chargeFn, 'charge')
565
+ * .touches('stripe', { idempotencyKey: ({ args }) => `order-${(args as { orderId: string }).orderId}` })
566
+ * .retry({ attempts: 3, timeoutMs: 20_000 })
567
+ * ```
568
+ *
569
+ * Applies to the CURRENT cursor, like `.retry()`; where the cursor would be ambiguous (a decider, selector,
570
+ * branch, or fork child), declare it in that method's own `touches` option. Refused: on a subflow mount, a
571
+ * parallel-for-each stage or a loop reference (no function of their own), after a mount or a fork (the cursor did
572
+ * not move), twice, with a system that is not a name, and with a key that is not a function.
573
+ */
574
+ touches(system: string, options?: {
575
+ readonly idempotencyKey?: StageTouches['idempotencyKey'];
576
+ }): this;
521
577
  /**
522
578
  * Put NAMES on the stage you JUST added. The first commit bundle of each
523
579
  * execution of that stage carries them (`CommitBundle.tags` — the bundle
@@ -574,11 +630,40 @@ export declare class FlowChartBuilder<TOut = any, TScope = any> {
574
630
  * second declaration on the same stage.
575
631
  */
576
632
  tag(...names: readonly string[]): this;
633
+ /**
634
+ * Declare the chart's time budget: the most milliseconds a caller gives one run (design §3.2).
635
+ *
636
+ * WHY: the incident behind it — a stage retried an SDK call four times, 40 s each, past a caller's 120 s, and the
637
+ * record said "one stage, one error". Both numbers were declared: the policy on the stage, the budget of the
638
+ * caller. So `build()` checks one against the other: it REFUSES the chart when its declared policies already allow
639
+ * longer (`attempts × timeoutMs` plus the waits, summed along the slowest path — see `timeBudget`), and in dev mode
640
+ * names every stage it cannot bound (no `timeoutMs`, a function backoff with no `maxBackoffMs`, a loop, a lazy
641
+ * subflow, a `parallelForEach`). The spec root carries it (`budgetMs`); at run start, a deadline shorter than it is
642
+ * a dev-mode warning.
643
+ *
644
+ * Chart-level, so it may be declared anywhere before `build()`, once.
645
+ *
646
+ * @example
647
+ * ```ts
648
+ * flowChart<State>('Read', readFn, 'read', { retry: { attempts: 1, timeoutMs: 5_000 } })
649
+ * .addFunction('Charge', chargeFn, 'charge')
650
+ * .retry({ attempts: 4, timeoutMs: 40_000, backoffMs: 1_000 })
651
+ * .budget(120_000)
652
+ * .build(); // throws: its declared policies allow 168000 ms, over its budget by 48000 ms
653
+ * ```
654
+ */
655
+ budget(ms: number): this;
577
656
  loopTo(stageId: string): this;
578
657
  onStream(handler: StreamTokenHandler): this;
579
658
  onStreamStart(handler: StreamLifecycleHandler): this;
580
659
  onStreamEnd(handler: StreamLifecycleHandler): this;
581
660
  build(): RunnableFlowChart<TOut, TScope>;
661
+ /**
662
+ * The declared budget, checked (owner ruling Q2): refused when the chart's bounded part alone allows longer — a
663
+ * time its declared policies allow a run to take, so the budget cannot be promised; every stage it cannot bound is
664
+ * a dev-mode warning.
665
+ */
666
+ private _checkBudget;
582
667
  /** Override the scope factory. Rarely needed — auto-embeds TypedScope by default. */
583
668
  setScopeFactory(factory: ScopeFactory<TScope>): this;
584
669
  toSpec<TResult = SerializedPipelineStructure>(): TResult;
@@ -0,0 +1,56 @@
1
+ import type { RetryLoopBudget } from '../attempt/retryLoopContext.js';
2
+ import type { RetryLoopCall } from '../attempt/retryLoopTypes.js';
3
+ import type { AttemptContext, AttemptEffect, AttemptError, AttemptRecord, IdempotencyKeyContext, RetryPolicy } from '../attempt/types.js';
4
+ import type { DecisionEvidence } from '../decide/types.js';
5
+ export interface RetryLoopContext extends AttemptContext {
6
+ readonly retryLoop: RetryLoopCall;
7
+ }
8
+ export interface RetryLoopOptions<TScope = any, TValue = unknown> {
9
+ readonly touches: string;
10
+ readonly idempotencyKey: (context: IdempotencyKeyContext) => string;
11
+ readonly retry: RetryPolicy;
12
+ readonly attempt: (scope: TScope, context: RetryLoopContext) => TValue | Promise<TValue>;
13
+ /** 'none' must authoritatively establish that the operation was not applied; an empty search is not enough. */
14
+ readonly reconcile: (scope: TScope, context: RetryLoopContext) => AttemptEffect | Promise<AttemptEffect>;
15
+ readonly into?: string;
16
+ readonly onStop?: 'throw' | 'continue';
17
+ readonly wait?: 'sleep' | 'pause';
18
+ }
19
+ /** Operational state stays real; normal state retention scrubs selected keys and every error is already served. */
20
+ export interface RetryLoopState<TValue = unknown> {
21
+ readonly id: string;
22
+ readonly series: string;
23
+ readonly attempt: number;
24
+ readonly of: number;
25
+ readonly idempotencyKey: string;
26
+ readonly effect: AttemptEffect;
27
+ readonly reconciled: boolean;
28
+ readonly outcome?: AttemptRecord['outcome'];
29
+ readonly category?: AttemptRecord['category'];
30
+ readonly error?: AttemptError;
31
+ readonly value?: TValue;
32
+ readonly delayMs: number;
33
+ readonly retryOn: boolean;
34
+ readonly retryOnThrew?: true;
35
+ readonly decision?: DecisionEvidence;
36
+ readonly terminal: boolean;
37
+ readonly resumeAt?: number;
38
+ }
39
+ /** Builder-only composition interface; no runtime engine kind or new scope method. */
40
+ interface Builder {
41
+ addFunction(name: string, fn: (scope: any) => any, id: string): this;
42
+ addPausableFunction(name: string, handler: {
43
+ execute(scope: any): any;
44
+ resume(scope: any, input: unknown): any;
45
+ }, id: string): this;
46
+ addDeciderFunction(name: string, fn: (scope: any) => any, id: string): {
47
+ addFunctionBranch(branch: string, name: string, fn: (scope: any) => any, id?: string, options?: any): any;
48
+ end(): Builder;
49
+ };
50
+ touches(system: string, options: {
51
+ idempotencyKey: (context: IdempotencyKeyContext) => string;
52
+ }): this;
53
+ tag(...names: string[]): this;
54
+ }
55
+ export declare function appendRetryLoop<TScope>(builder: Builder, id: string, supplied: RetryLoopOptions<TScope>, stamp: (budget: RetryLoopBudget, branch?: string) => void): void;
56
+ export {};
@@ -9,7 +9,7 @@
9
9
  * The builder remains standalone at runtime.
10
10
  */
11
11
  import type { StageNode } from '../engine/graph/StageNode.js';
12
- import type { ILogger, RetryPolicy, ScopeFactory, StageFunction } from '../engine/types.js';
12
+ import type { ILogger, RetryPolicy, ScopeFactory, StageFunction, StageTouches } from '../engine/types.js';
13
13
  import type { ScopeProtectionMode } from '../scope/protection/types.js';
14
14
  import type { StructureRecorder } from './structure/StructureRecorder.js';
15
15
  export type { ResumeFn, StageNode } from '../engine/graph/StageNode.js';
@@ -71,6 +71,26 @@ export interface SerializedPipelineStructure {
71
71
  * be `undefined` at fire time for exactly the stages that have a policy.
72
72
  */
73
73
  retryAttempts?: number;
74
+ /**
75
+ * The cap on ONE attempt of this stage, from its declared {@link RetryPolicy}
76
+ * (`timeoutMs`). Present only when declared. With `retryAttempts` it is what
77
+ * bounds the stage in time: at most `retryAttempts × timeoutMs` plus the
78
+ * waits between attempts (`timeBudget`). Same read-it-from-the-built-spec
79
+ * caveat as `retryAttempts`.
80
+ */
81
+ timeoutMs?: number;
82
+ /**
83
+ * The chart's declared time budget (`.budget(ms)`), on the ROOT spec only —
84
+ * the most milliseconds a caller gives one run. `build()` refused the chart
85
+ * if its declared policies could already take longer. Absent when undeclared.
86
+ */
87
+ budgetMs?: number;
88
+ /**
89
+ * The outside system this stage changes (`.touches(system, …)`, 10.1) — the
90
+ * NAME only; the key rule is a function and stays on the node. Present only
91
+ * when declared. Same read-it-from-the-built-spec caveat as `retryAttempts`.
92
+ */
93
+ touches?: string;
74
94
  /**
75
95
  * Declared tags (9.21.0) — the NAMES the author put on this stage at build
76
96
  * time, copied as-is (JSON-safe, free strings; footprintjs owns no
@@ -118,6 +138,12 @@ export interface FlowChartSpec {
118
138
  /** Total attempts allowed by this stage's declared retry policy — the count
119
139
  * only (see `SerializedPipelineStructure.retryAttempts`). */
120
140
  retryAttempts?: number;
141
+ /** The cap on one attempt (see `SerializedPipelineStructure.timeoutMs`). */
142
+ timeoutMs?: number;
143
+ /** The chart's declared time budget, on the root only (see `SerializedPipelineStructure.budgetMs`). */
144
+ budgetMs?: number;
145
+ /** The outside system this stage changes, by name (see `SerializedPipelineStructure.touches`). */
146
+ touches?: string;
121
147
  /** Declared tags on this stage, as-is (see `SerializedPipelineStructure.tags`). */
122
148
  tags?: readonly string[];
123
149
  }
@@ -154,6 +180,12 @@ export interface FlowChartOptions {
154
180
  * at their own declaration site. See {@link RetryPolicy}.
155
181
  */
156
182
  retry?: RetryPolicy;
183
+ /**
184
+ * The outside system the chart's FIRST stage changes, and its idempotency-key
185
+ * rule (10.1). Later stages use the `.touches()` modifier, or the `touches`
186
+ * option at their own declaration site. See {@link StageTouches}.
187
+ */
188
+ touches?: StageTouches;
157
189
  /**
158
190
  * Declared tags for the chart's FIRST stage. Later stages use the `.tag()`
159
191
  * modifier, or the `tags` option at their own declaration site. A tag is a
@@ -190,6 +222,8 @@ export type SimplifiedParallelSpec<TOut = any, TScope = any> = {
190
222
  /** Declarative retry policy for this fork child. Fork branches are where
191
223
  * flaky I/O usually lives, so each child declares its own. */
192
224
  retry?: RetryPolicy;
225
+ /** The outside system this fork child changes, and its key rule (10.1). */
226
+ touches?: StageTouches;
193
227
  /** Declared tags for this fork child — each child's bundle carries its own. */
194
228
  tags?: readonly string[];
195
229
  };
@@ -8,5 +8,5 @@
8
8
  export type { DecideRule, DecisionEvidence, DecisionResult, DefaultBranch, FilterCondition, FilterOps, FilterRuleEvidence, FunctionRuleEvidence, ReadInput, RuleEvidence, SelectionEvidence, SelectionResult, WhenClause, WhereFilter, } from './types.js';
9
9
  export { DECISION_RESULT } from './types.js';
10
10
  export { decide, select } from './decide.js';
11
- export { evaluateFilter } from './evaluator.js';
11
+ export { evaluateFilter } from '../filter/evaluator.js';
12
12
  export { EvidenceCollector } from './evidence.js';
@@ -1,3 +1,4 @@
1
+ import type { RetryLoopDecision } from '../attempt/retryLoopTypes.js';
1
2
  /**
2
3
  * decide/types -- Type definitions for the decide()/select() decision reasoning system.
3
4
  *
@@ -126,6 +127,8 @@ export interface FilterCondition {
126
127
  redacted: boolean;
127
128
  }
128
129
  export interface DecisionEvidence {
130
+ /** Explicit logical-loop link recorded by addRetryLoop; no key, raw error or provider payload. */
131
+ retryLoop?: RetryLoopDecision;
129
132
  rules: RuleEvidence[];
130
133
  /** The branch selected. Equals `default` when no rule matched. */
131
134
  chosen: string;
@@ -8,7 +8,7 @@
8
8
  * - Back-edges via dynamic next (loop)
9
9
  * - Isolated sub-traversals via `isSubflowRoot` (subflow)
10
10
  */
11
- import type { ParallelForEachConfig, RetryPolicy, StageFunction, SubflowMountOptions } from '../types.js';
11
+ import type { ParallelForEachConfig, RetryPolicy, StageFunction, StageTouches, SubflowMountOptions } from '../types.js';
12
12
  /**
13
13
  * Resume function for pausable stages.
14
14
  * Unlike StageFunction, the 2nd argument is the resume input (not breakFn).
@@ -84,6 +84,16 @@ export type StageNode<TOut = any, TScope = any> = {
84
84
  * See {@link RetryPolicy}.
85
85
  */
86
86
  retry?: RetryPolicy;
87
+ /**
88
+ * The outside system this stage changes, and the rule for its idempotency key (10.1, design §3.3). A POLICY-like
89
+ * field, the `retry` / `tags` precedent: no node kind, no `computeNodeType` edit, and the prefixer's
90
+ * `{ ...node }` spread carries it through subflow prefixing. Lands only through
91
+ * `FlowChartBuilder · applyTouches`; a touching stage that may retry without a key rule is refused there, at the
92
+ * run-time door for a returned node, and at the stage. Honoured by `FlowchartTraverser · executeStage`: the key
93
+ * is computed once per execution, every attempt records its `effect`, and a series that ends without an answer after any attempt of unknown effect fails
94
+ * the stage with `UnknownEffectError`. See {@link StageTouches}.
95
+ */
96
+ touches?: StageTouches;
87
97
  /**
88
98
  * Declared tags (9.21.0) — the NAMES the author put on this stage at build
89
99
  * time. A POLICY-like field, not a kind: no `computeNodeType` edit, no
@@ -7,11 +7,18 @@
7
7
  * - Handle streaming stages (onStart, onToken, onEnd lifecycle)
8
8
  * - Sync+async safety: only await real Promises (instanceof check)
9
9
  */
10
+ import type { AttemptContext } from '../../attempt/types.js';
10
11
  import type { StageContext } from '../../memory/StageContext.js';
11
12
  import type { StageNode } from '../graph/StageNode.js';
12
13
  import type { HandlerDeps, StageFunction } from '../types.js';
13
14
  export declare class StageRunner<TOut = any, TScope = any> {
14
15
  private readonly deps;
15
16
  constructor(deps: HandlerDeps<TOut, TScope>);
16
- run(node: StageNode<TOut, TScope>, stageFunc: StageFunction<TOut, TScope>, context: StageContext, breakFn: () => void): Promise<TOut>;
17
+ /**
18
+ * Run one stage function. `attempt` is the attempt runner's (P1b) — present when the stage runs under a retry
19
+ * policy, a `timeoutMs` or a run deadline: the scope hands it out (`$attempt()`) and is fenced to it, and the
20
+ * race below is against ITS signal (the run's, composed with the attempt's cap). Without one, the race is
21
+ * against the run's signal, as it always was.
22
+ */
23
+ run(node: StageNode<TOut, TScope>, stageFunc: StageFunction<TOut, TScope>, context: StageContext, breakFn: () => void, attempt?: AttemptContext): Promise<TOut>;
17
24
  }
@@ -8,6 +8,13 @@
8
8
  * outright); it is a stage failure like any other, so `onError` fires for the
9
9
  * stage before the error propagates.
10
10
  */
11
+ import type { CommitPhase } from 'foottrace';
11
12
  import type { StageContext } from '../../memory/StageContext.js';
12
13
  import type { IControlFlowNarrative, TraversalContext } from '../narrative/types.js';
14
+ /**
15
+ * All native stage commits own their exact escaping commit error, including
16
+ * commits while another error or pause was bubbling. Capture safe ownership
17
+ * only; existing diagnostic/event behavior stays with the caller.
18
+ */
19
+ export declare function commitStageWrites(context: StageContext, phase?: CommitPhase): void;
13
20
  export declare function commitStage(context: StageContext, narrative: IControlFlowNarrative, stageName: string, traversalContext?: TraversalContext): void;
@@ -14,7 +14,16 @@ export declare function recordStageError(context: StageContext, error: unknown):
14
14
  message: string;
15
15
  structuredError: StructuredErrorInfo;
16
16
  };
17
+ /** Capture before commit observers or diagnostic serving can change the raw value. */
18
+ export declare function captureStageFailure(context: StageContext, error: unknown): void;
17
19
  /** The served form of a thrown value at any other report of a stage failure (retry, throttle). */
18
20
  export declare function servedStageError(context: StageContext, error: unknown): StructuredErrorInfo;
19
21
  /** What the logger is handed: the thrown value, or its masked form when the policy masked its text. */
20
22
  export declare function loggableStageError(context: StageContext, error: unknown): unknown;
23
+ /**
24
+ * A touching stage's idempotency key as records carry it (P3, design §6) — `RedactionRule · retainIdempotencyKey`:
25
+ * selected by its name, and served whole when the input its rule was handed holds a selected key or the rule read
26
+ * a selected state value. The stage itself
27
+ * keeps the real key.
28
+ */
29
+ export declare function servedIdempotencyKey(context: StageContext, key: string, input: unknown, readSelected?: boolean): string;
@@ -14,11 +14,11 @@ export { NullControlFlowNarrativeGenerator } from './narrative/NullControlFlowNa
14
14
  export type { IControlFlowNarrative } from './narrative/types.js';
15
15
  export { FlowRecorderDispatcher } from './narrative/FlowRecorderDispatcher.js';
16
16
  export { NarrativeFlowRecorder } from './narrative/NarrativeFlowRecorder.js';
17
- export type { FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowNextEvent, FlowRecorder, FlowRunEvent, FlowRunFailedEvent, FlowSelectedEvent, FlowStageEvent, FlowStageRetryEvent, FlowSubflowEvent, FlowSubflowRegisteredEvent, FlowThrottledEvent, ResumeLink, TraversalContext, } from './narrative/types.js';
17
+ export type { FlowAttemptEvent, FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowNextEvent, FlowRecorder, FlowRunEvent, FlowRunFailedEvent, FlowSelectedEvent, FlowStageEvent, FlowStageRetryEvent, FlowSubflowEvent, FlowSubflowRegisteredEvent, FlowThrottledEvent, ResumeLink, TraversalContext, } from './narrative/types.js';
18
18
  export type { StructuredErrorInfo } from '../errors/errorInfo.js';
19
19
  export { extractErrorInfo, formatErrorInfo } from '../errors/errorInfo.js';
20
20
  export { AdaptiveNarrativeFlowRecorder } from './narrative/recorders/AdaptiveNarrativeFlowRecorder.js';
21
- export type { ManifestEntry } from './narrative/recorders/ManifestFlowRecorder.js';
21
+ export type { ManifestAttemptRow, ManifestEntry } from './narrative/recorders/ManifestFlowRecorder.js';
22
22
  export { ManifestFlowRecorder } from './narrative/recorders/ManifestFlowRecorder.js';
23
23
  export { MilestoneNarrativeFlowRecorder } from './narrative/recorders/MilestoneNarrativeFlowRecorder.js';
24
24
  export { ProgressiveNarrativeFlowRecorder } from './narrative/recorders/ProgressiveNarrativeFlowRecorder.js';
@@ -18,7 +18,7 @@ import type { CombinedRecorder } from '../../recorder/CombinedRecorder.js';
18
18
  import type { EmitEvent } from '../../recorder/EmitRecorder.js';
19
19
  import type { ErrorEvent, PauseEvent, ReadEvent, ResumeEvent, WriteEvent } from '../../scope/types.js';
20
20
  import type { CombinedNarrativeEntry, NarrativeFormatter } from './narrativeTypes.js';
21
- import type { FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowPauseEvent, FlowResumeEvent, FlowSelectedEvent, FlowStageEvent, FlowStageRetryEvent, FlowSubflowEvent } from './types.js';
21
+ import type { FlowAttemptEvent, FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowPauseEvent, FlowResumeEvent, FlowSelectedEvent, FlowStageEvent, FlowSubflowEvent } from './types.js';
22
22
  export interface CombinedNarrativeRecorderOptions {
23
23
  includeStepNumbers?: boolean;
24
24
  includeValues?: boolean;
@@ -82,21 +82,36 @@ export declare class CombinedNarrativeRecorder implements CombinedRecorder {
82
82
  onLoop(event: FlowLoopEvent): void;
83
83
  onBreak(event: FlowBreakEvent): void;
84
84
  /**
85
- * A failed attempt that was retried. BUFFERED, not pushed: this is the only
86
- * flow event that fires DURING a stage, so pushing it straight to the store
87
- * would place the line before its own stage header. Buffered alongside the
88
- * reads and writes, it flushes in true execution order:
85
+ * One attempt of a retried stage (10.1). BUFFERED, not pushed: attempt
86
+ * events fire DURING a stage, so pushing one straight to the store would
87
+ * place the line before its own stage header. Buffered alongside the reads
88
+ * and writes, it flushes in true execution order:
89
89
  *
90
- * Step 3: Fetch user
91
- * ↳ read userId = "u1"
92
- * ↳ [Retry]: attempt 1 of 3 failed … retrying
93
- * ↳ read userId = "u1"
94
- * ↳ wrote user = { … }
90
+ * Stage 3: Fetch user
91
+ * Step 1: Read userId = "u1"
92
+ * Attempt 1 of 3 at Fetch user failed in 12ms (…), retrying in 100ms.
93
+ * Step 3: Read userId = "u1"
94
+ * Step 4: Write user = { … }
95
+ * Attempt 2 of 3 at Fetch user succeeded in 9ms.
96
+ *
97
+ * This line replaces the 9.15 `[Retry]` line: it already says "retrying",
98
+ * so `onStageRetry` is not narrated (two lines for one fact).
95
99
  */
96
- onStageRetry(event: FlowStageRetryEvent): void;
100
+ onAttempt(event: FlowAttemptEvent): void;
97
101
  onPause(event: PauseEvent | FlowPauseEvent): void;
98
102
  onResume(event: ResumeEvent | FlowResumeEvent): void;
99
103
  onError(event: ErrorEvent | FlowErrorEvent): void;
104
+ /**
105
+ * A failed stage has no header (its `[Error]` line stands for it) and its
106
+ * buffered reads and writes are not narrated — the narrative's law since
107
+ * before retry existed, kept. Its ATTEMPT lines are the exception (10.1):
108
+ * the stop reason is the point, so they follow the error line, in order,
109
+ * as its depth-1 sub-items. A stage with no retry policy buffers no attempt
110
+ * lines, so its failure narrates exactly as before.
111
+ */
112
+ private flushAttempts;
113
+ /** One attempt line — the consumer's `renderAttempt` first; `null` drops it, `undefined` falls back. */
114
+ private pushAttempt;
100
115
  /**
101
116
  * Receive a consumer-emitted event from `scope.$emit(name, payload)`.
102
117
  *
@@ -158,7 +173,7 @@ export declare class CombinedNarrativeRecorder implements CombinedRecorder {
158
173
  description: string;
159
174
  preferredOperation: "translate";
160
175
  data: {
161
- type: "subflow" | "loop" | "error" | "pause" | "emit" | "fork" | "selector" | "stage" | "step" | "condition" | "break" | "resume" | "retry";
176
+ type: "attempt" | "retry" | "error" | "stage" | "emit" | "subflow" | "loop" | "pause" | "fork" | "selector" | "step" | "condition" | "break" | "resume";
162
177
  text: string;
163
178
  depth: number;
164
179
  stageName?: string | undefined;
@@ -186,6 +201,5 @@ export declare class CombinedNarrativeRecorder implements CombinedRecorder {
186
201
  private defaultRenderSubflow;
187
202
  private defaultRenderLoop;
188
203
  private defaultRenderBreak;
189
- private defaultRenderRetry;
190
204
  private defaultRenderError;
191
205
  }
@@ -10,8 +10,10 @@
10
10
  *
11
11
  * When no recorders are attached, every method is a fast no-op (empty array check).
12
12
  */
13
+ import type { AttemptRecord } from '../../attempt/types.js';
13
14
  import type { DecisionEvidence, SelectionEvidence } from '../../decide/types.js';
14
15
  import type { StructuredErrorInfo } from '../../errors/errorInfo.js';
16
+ import type { TerminalFailureContext } from '../../errors/terminalFailure.js';
15
17
  import type { FlowRecorder, IControlFlowNarrative, StageType, TraversalContext } from './types.js';
16
18
  export declare class FlowRecorderDispatcher implements IControlFlowNarrative {
17
19
  private recorders;
@@ -34,13 +36,14 @@ export declare class FlowRecorderDispatcher implements IControlFlowNarrative {
34
36
  onLoop(targetStage: string, iteration: number, description?: string, traversalContext?: TraversalContext): void;
35
37
  onBreak(stageName: string, traversalContext?: TraversalContext, reason?: string, propagatedFromSubflow?: string): void;
36
38
  onError(stageName: string, errorMessage: string, structuredError: StructuredErrorInfo, traversalContext?: TraversalContext): void;
39
+ onAttempt(stageName: string, stageId: string, record: AttemptRecord, structuredError: StructuredErrorInfo | undefined, traversalContext?: TraversalContext): void;
37
40
  onStageRetry(stageName: string, stageId: string, attempt: number, maxAttempts: number, delayMs: number, structuredError: StructuredErrorInfo, traversalContext?: TraversalContext): void;
38
41
  onThrottled(stageName: string, stageId: string, structuredError: StructuredErrorInfo, traversalContext?: TraversalContext): void;
39
42
  onPause(stageName: string, stageId: string, pauseData: unknown, subflowPath: readonly string[], traversalContext?: TraversalContext): void;
40
43
  onResume(stageName: string, stageId: string, hasInput: boolean, traversalContext?: TraversalContext): void;
41
44
  onRunStart(input: unknown, traversalContext?: TraversalContext): void;
42
45
  onRunEnd(output: unknown, traversalContext?: TraversalContext): void;
43
- onRunFailed(error: StructuredErrorInfo, traversalContext?: TraversalContext): void;
46
+ onRunFailed(error: StructuredErrorInfo, traversalContext?: TraversalContext, failure?: TerminalFailureContext): void;
44
47
  /**
45
48
  * Returns sentences from an attached NarrativeFlowRecorder (looked up by ID).
46
49
  * Callers that need sentences should attach a NarrativeFlowRecorder with id 'narrative'
@@ -8,7 +8,7 @@
8
8
  * Consumers who want different narrative behavior (windowed loops, adaptive
9
9
  * summarization, etc.) can replace this with a different FlowRecorder.
10
10
  */
11
- import type { FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowNextEvent, FlowPauseEvent, FlowRecorder, FlowResumeEvent, FlowSelectedEvent, FlowStageEvent, FlowStageRetryEvent, FlowSubflowEvent } from './types.js';
11
+ import type { FlowAttemptEvent, FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowNextEvent, FlowPauseEvent, FlowRecorder, FlowResumeEvent, FlowSelectedEvent, FlowStageEvent, FlowSubflowEvent } from './types.js';
12
12
  export declare class NarrativeFlowRecorder implements FlowRecorder {
13
13
  readonly id: string;
14
14
  private sentences;
@@ -20,6 +20,14 @@ export declare class NarrativeFlowRecorder implements FlowRecorder {
20
20
  * `onStageExecuted` for that stage stays silent — an arrival is told ONCE.
21
21
  */
22
22
  private announcedArrival;
23
+ /**
24
+ * A retried stage's attempt sentences, by `runtimeStageId`, held until the stage's own outcome is known. A
25
+ * stage that FAILED tells its attempts beneath its error sentence — where the combined narrative puts them
26
+ * (`CombinedNarrativeRecorder · flushAttempts`), so the two built-in narratives tell a failure in one order,
27
+ * the stop reason last. A stage that completed (or paused) tells them where they always stood: before the
28
+ * sentence its completion adds.
29
+ */
30
+ private readonly heldAttempts;
23
31
  constructor(id?: string);
24
32
  onStageExecuted(event: FlowStageEvent): void;
25
33
  onNext(_event: FlowNextEvent): void;
@@ -31,11 +39,22 @@ export declare class NarrativeFlowRecorder implements FlowRecorder {
31
39
  onLoop(event: FlowLoopEvent): void;
32
40
  onBreak(event: FlowBreakEvent): void;
33
41
  onError(event: FlowErrorEvent): void;
34
- onStageRetry(event: FlowStageRetryEvent): void;
42
+ /**
43
+ * One sentence per attempt of a retried stage (10.1) — its outcome, duration, cause and decision. It replaces
44
+ * the 9.15 retry sentence (`onStageRetry` is no longer narrated here): the attempt line already says
45
+ * "retrying", and says it for the attempt that stopped the series too. Held until the stage's outcome is
46
+ * known ({@link heldAttempts}); an event with no `runtimeStageId` has nothing to hold it by, so it is told now.
47
+ */
48
+ onAttempt(event: FlowAttemptEvent): void;
35
49
  onPause(event: FlowPauseEvent): void;
36
50
  onResume(event: FlowResumeEvent): void;
37
- /** Returns a defensive copy of accumulated sentences. */
51
+ /**
52
+ * Returns a defensive copy of accumulated sentences. Attempt sentences still held — read mid-stage, before the
53
+ * stage's outcome — come last, so nothing the run did is ever missing from the copy.
54
+ */
38
55
  getSentences(): string[];
39
56
  /** Clears accumulated sentences. Useful for reuse across runs. */
40
57
  clear(): void;
58
+ /** Tell the held attempt sentences of `runtimeStageId`, in order, and stop holding them. */
59
+ private releaseAttempts;
41
60
  }
@@ -18,6 +18,7 @@ export declare class NullControlFlowNarrativeGenerator implements IControlFlowNa
18
18
  onLoop(): void;
19
19
  onBreak(): void;
20
20
  onError(): void;
21
+ onAttempt(): void;
21
22
  onStageRetry(): void;
22
23
  onPause(): void;
23
24
  onResume(): void;
@@ -1,4 +1,5 @@
1
1
  /** Shared English sentence bodies, with no event capture or recorder state. */
2
+ import type { AttemptRecord } from '../../../attempt/types.js';
2
3
  import type { ValidationIssue } from '../../../schema/errors.js';
3
4
  import type { BreakRenderContext, DecisionRenderContext, ErrorRenderContext, ForkRenderContext, LoopRenderContext, StageRenderContext } from '../narrativeTypes.js';
4
5
  import type { FlowResumeEvent } from '../types.js';
@@ -14,3 +15,25 @@ export declare function validationDetails(issues: readonly ValidationIssue[]): s
14
15
  export declare function errorSentence(ctx: Pick<ErrorRenderContext, 'stageName' | 'message'>): string;
15
16
  /** Callers retain their distinct rules for whether to display empty details. */
16
17
  export declare function validationSentence(details: string): string;
18
+ /**
19
+ * Whether the narrative tells an attempt (P1b). A STAGE series of ONE attempt — a stage run on the attempt runner
20
+ * only because of a `timeoutMs` or the run's deadline — that succeeded or paused says nothing the stage's own line
21
+ * does not, so it is not told (its record is still on the tree and the hook). Every other attempt is — every call
22
+ * and every observed attempt too (P2): the stage's own line never mentions them.
23
+ */
24
+ export declare function isAttemptTold(record: AttemptRecord): boolean;
25
+ /**
26
+ * One attempt of a retried stage, as one sentence (10.1): its outcome and duration, the cause of a failure
27
+ * (`category: message`, the category left out when it is `unknown`), and the decision — the wait before a retry,
28
+ * or why the series stopped. The error is the record's SERVED message, so a redacted error reads redacted here.
29
+ * Under a run deadline the decision also says the time left (P1b).
30
+ *
31
+ * Attempt 1 of 3 at Fetch rate failed in 812ms (rate-limited: 429), retrying in 4s.
32
+ * Attempt 3 of 3 at Fetch rate succeeded in 31ms.
33
+ * Attempt 1 of 4 at Charge card failed in 120ms (permanent: card declined); stopped: retryOn declined.
34
+ * Attempt 2 of 3 at Fetch rate timed out after 40s, retrying in 2s (70s left).
35
+ * Attempt 2 of 4 at Charge card timed out after 20s; stopped: no time left (300ms left, next wait 2s).
36
+ */
37
+ export declare function attemptSentence(stageName: string, record: AttemptRecord): string;
38
+ /** A duration as the narrative says it: whole milliseconds under a second, seconds (one decimal at most) above. */
39
+ export declare function formatDuration(ms: number): string;
@@ -1,11 +1,11 @@
1
1
  export type { CombinedNarrativeRecorderOptions } from './CombinedNarrativeRecorder.js';
2
2
  export { CombinedNarrativeRecorder } from './CombinedNarrativeRecorder.js';
3
- export type { BreakRenderContext, CombinedNarrativeEntry, CombinedNarrativeOptions, DecisionRenderContext, EmitRenderContext, ErrorRenderContext, ForkRenderContext, LoopRenderContext, NarrativeFormatter, OpRenderContext, SelectedRenderContext, StageRenderContext, SubflowRenderContext, } from './narrativeTypes.js';
3
+ export type { AttemptRenderContext, BreakRenderContext, CombinedNarrativeEntry, CombinedNarrativeOptions, DecisionRenderContext, EmitRenderContext, ErrorRenderContext, ForkRenderContext, LoopRenderContext, NarrativeFormatter, OpRenderContext, SelectedRenderContext, StageRenderContext, SubflowRenderContext, } from './narrativeTypes.js';
4
4
  export { NullControlFlowNarrativeGenerator } from './NullControlFlowNarrativeGenerator.js';
5
5
  export type { IControlFlowNarrative } from './types.js';
6
6
  export { FlowRecorderDispatcher } from './FlowRecorderDispatcher.js';
7
7
  export { NarrativeFlowRecorder } from './NarrativeFlowRecorder.js';
8
- export type { FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowNextEvent, FlowRecorder, FlowRunEvent, FlowRunFailedEvent, FlowSelectedEvent, FlowStageEvent, FlowSubflowEvent, } from './types.js';
8
+ export type { FlowAttemptEvent, FlowBreakEvent, FlowDecisionEvent, FlowErrorEvent, FlowForkEvent, FlowLoopEvent, FlowNextEvent, FlowRecorder, FlowRunEvent, FlowRunFailedEvent, FlowSelectedEvent, FlowStageEvent, FlowSubflowEvent, } from './types.js';
9
9
  export { AdaptiveNarrativeFlowRecorder } from './recorders/AdaptiveNarrativeFlowRecorder.js';
10
10
  export { MilestoneNarrativeFlowRecorder } from './recorders/MilestoneNarrativeFlowRecorder.js';
11
11
  export { ProgressiveNarrativeFlowRecorder } from './recorders/ProgressiveNarrativeFlowRecorder.js';