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
@@ -0,0 +1,47 @@
1
+ /**
2
+ * attempt/standalone.ts — `attempt(fn, policy?, options?)`: the attempt runner with no scope and no run (design §3.6,
3
+ * packet P2).
4
+ *
5
+ * The same loop, the same record (law 1) for code that is not a stage — a provider decorator, a client wrapper, a
6
+ * script. There is no run, so there is no execution tree and no hook: every record goes to `options.onAttempt`, the
7
+ * caller's own, as each attempt ends. There is no redaction rule either: the record holds the error's named fields
8
+ * (never the thrown value), and the caller's callback decides what to keep.
9
+ *
10
+ * Time and cancellation are the caller's: `deadline` caps every attempt by the time left (and a wait that would
11
+ * outlast it is never started — `no-time-left`); `signal` cancels. A deadline already past, or a signal already
12
+ * aborted, starts no attempt and records nothing.
13
+ *
14
+ * ```typescript
15
+ * const res = await attempt((t) => fetch(url, { signal: t.signal }), { attempts: 3, timeoutMs: 5_000 }, {
16
+ * target: 'inventory.lookup',
17
+ * deadline: Date.now() + 20_000,
18
+ * onAttempt: (record) => log.info(record),
19
+ * });
20
+ * ```
21
+ */
22
+ import type { AttemptContext, AttemptRecord, RetryPolicy } from './types.js';
23
+ /** How a standalone attempt series is named, timed and reported. */
24
+ export interface AttemptOptions {
25
+ /** The outside target — a name from code (1–128 characters, no control character), stamped on every record. */
26
+ readonly target?: string;
27
+ /**
28
+ * The series every record names — the caller's name for this one operation (an order id, a request id), so two
29
+ * operations can be told apart. Default: the target, else `'attempt'`.
30
+ */
31
+ readonly series?: string;
32
+ /** The deadline, epoch milliseconds: every attempt is capped by the time left before it. */
33
+ readonly deadline?: number;
34
+ /** Cancels the series: the attempt in flight is cut (`aborted`), a wait ends, and no attempt follows. */
35
+ readonly signal?: AbortSignal;
36
+ /**
37
+ * Every attempt, at its end — the only place a standalone record goes. A throw from it is isolated: it never
38
+ * changes the call's outcome (dev mode warns).
39
+ */
40
+ readonly onAttempt?: (record: AttemptRecord) => void;
41
+ }
42
+ /**
43
+ * Run `fn` under `policy` (none = one attempt, still recorded) and resolve with its answer, or reject with the LAST
44
+ * attempt's own error. `fn` gets the attempt's `AttemptContext`: pass `signal` to the work, read `timeLeftMs()`,
45
+ * and report an SDK's own retries with `observed()`.
46
+ */
47
+ export declare function attempt<T>(fn: (attempt: AttemptContext) => Promise<T> | T, policy?: RetryPolicy, options?: AttemptOptions): Promise<T>;
@@ -0,0 +1,126 @@
1
+ /**
2
+ * attempt/standalone.ts — `attempt(fn, policy?, options?)`: the attempt runner with no scope and no run (design §3.6,
3
+ * packet P2).
4
+ *
5
+ * The same loop, the same record (law 1) for code that is not a stage — a provider decorator, a client wrapper, a
6
+ * script. There is no run, so there is no execution tree and no hook: every record goes to `options.onAttempt`, the
7
+ * caller's own, as each attempt ends. There is no redaction rule either: the record holds the error's named fields
8
+ * (never the thrown value), and the caller's callback decides what to keep.
9
+ *
10
+ * Time and cancellation are the caller's: `deadline` caps every attempt by the time left (and a wait that would
11
+ * outlast it is never started — `no-time-left`); `signal` cancels. A deadline already past, or a signal already
12
+ * aborted, starts no attempt and records nothing.
13
+ *
14
+ * ```typescript
15
+ * const res = await attempt((t) => fetch(url, { signal: t.signal }), { attempts: 3, timeoutMs: 5_000 }, {
16
+ * target: 'inventory.lookup',
17
+ * deadline: Date.now() + 20_000,
18
+ * onAttempt: (record) => log.info(record),
19
+ * });
20
+ * ```
21
+ */
22
+ import { isDevMode } from '../devMode.js';
23
+ import { extractErrorInfo } from '../errors/errorInfo.js';
24
+ import { armDeadline, isAbortSignal } from './deadline.js';
25
+ import { admitAttemptName } from './name.js';
26
+ import { observedRecord, ObservedSeriesBook, readObservedReport } from './observed.js';
27
+ import { admitCallPolicy } from './policy.js';
28
+ import { runAttempts } from './runner.js';
29
+ const WHERE = 'attempt()';
30
+ /**
31
+ * Run `fn` under `policy` (none = one attempt, still recorded) and resolve with its answer, or reject with the LAST
32
+ * attempt's own error. `fn` gets the attempt's `AttemptContext`: pass `signal` to the work, read `timeLeftMs()`,
33
+ * and report an SDK's own retries with `observed()`.
34
+ */
35
+ export function attempt(fn, policy, options = {}) {
36
+ if (typeof fn !== 'function')
37
+ throw new TypeError(`${WHERE}: fn must be a function`);
38
+ const admitted = admitCallPolicy(WHERE, policy);
39
+ const read = readOptions(options);
40
+ const armed = armDeadline(read.signal, read.deadline, `${WHERE} passed its deadline (${String(read.deadline)} epoch ms)`);
41
+ if (armed.signal?.aborted) {
42
+ armed.dispose();
43
+ return Promise.reject(armed.signal.reason);
44
+ }
45
+ const deliver = (record) => {
46
+ if (read.onAttempt === undefined)
47
+ return;
48
+ try {
49
+ read.onAttempt(record);
50
+ }
51
+ catch (error) {
52
+ if (isDevMode()) {
53
+ // eslint-disable-next-line no-console
54
+ console.warn(`[footprint] ${WHERE}: onAttempt threw; the record was still made`, error);
55
+ }
56
+ }
57
+ };
58
+ const observing = new ObservedOwner(read.series, deliver);
59
+ return runAttempts((_attempt, context) => fn(context), admitted, {
60
+ series: read.series,
61
+ kind: 'call',
62
+ ...(read.target !== undefined && { target: read.target }),
63
+ ...(armed.signal !== undefined && { signal: armed.signal }),
64
+ ...(read.deadline !== undefined && { deadline: read.deadline }),
65
+ onAttempt: (record) => deliver(record),
66
+ observe: (report, at) => observing.observe(report, at),
67
+ }).finally(() => armed.dispose());
68
+ }
69
+ /** The options as read: each once, validated (a `TypeError` naming the field). */
70
+ function readOptions(options) {
71
+ if (options === null || typeof options !== 'object')
72
+ throw new TypeError(`${WHERE}: options must be an object`);
73
+ const { target, series, deadline, signal, onAttempt } = options;
74
+ const name = target === undefined ? undefined : admitAttemptName(WHERE, 'target', target);
75
+ const named = series === undefined ? name ?? 'attempt' : admitAttemptName(WHERE, 'series', series);
76
+ if (deadline !== undefined && (typeof deadline !== 'number' || Number.isNaN(deadline))) {
77
+ throw new TypeError(`${WHERE}: deadline must be a number (epoch ms)`);
78
+ }
79
+ if (signal !== undefined && !isAbortSignal(signal))
80
+ throw new TypeError(`${WHERE}: signal must be an AbortSignal`);
81
+ if (onAttempt !== undefined && typeof onAttempt !== 'function') {
82
+ throw new TypeError(`${WHERE}: onAttempt must be a function`);
83
+ }
84
+ // `-Infinity` is a deadline long past (no attempt starts); `Infinity` is none.
85
+ const at = deadline === -Infinity ? 0 : deadline;
86
+ return {
87
+ ...(name !== undefined && { target: name }),
88
+ series: named,
89
+ ...(at !== undefined && Number.isFinite(at) && { deadline: at }),
90
+ ...(signal !== undefined && { signal }),
91
+ ...(onAttempt !== undefined && { onAttempt }),
92
+ };
93
+ }
94
+ /**
95
+ * The observed reports of a standalone series: each attempt `m` opens its own call level, `<series>@<m>.<k>` — the
96
+ * shape a stage attempt's calls have, rooted at the caller's series. A report after its attempt ended is dropped.
97
+ */
98
+ class ObservedOwner {
99
+ series;
100
+ deliver;
101
+ current;
102
+ constructor(series, deliver) {
103
+ this.series = series;
104
+ this.deliver = deliver;
105
+ }
106
+ observe(report, at) {
107
+ const read = readObservedReport(report);
108
+ // After its attempt ended: dropped, never thrown — an SDK's own callback may fire late, and an observed attempt
109
+ // never changes control flow.
110
+ if (at.ended)
111
+ return;
112
+ if (this.current?.attempt !== at.attempt) {
113
+ let ordinal = 0;
114
+ const prefix = `${this.series}@${at.attempt}`;
115
+ this.current = { attempt: at.attempt, book: new ObservedSeriesBook(() => `${prefix}.${++ordinal}`) };
116
+ }
117
+ const { record } = observedRecord(read, {
118
+ series: this.current.book.seriesFor(read),
119
+ now: Date.now,
120
+ // No run, no rule: the error's structured info (the record keeps its named fields only).
121
+ serve: extractErrorInfo,
122
+ });
123
+ this.deliver(record);
124
+ }
125
+ }
126
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhbmRhbG9uZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvYXR0ZW1wdC9zdGFuZGFsb25lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUVILE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDMUMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDMUQsT0FBTyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0QsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzdDLE9BQU8sRUFBRSxjQUFjLEVBQUUsa0JBQWtCLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDdkYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM5QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBRzFDLE1BQU0sS0FBSyxHQUFHLFdBQVcsQ0FBQztBQXNCMUI7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxPQUFPLENBQ3JCLEVBQStDLEVBQy9DLE1BQW9CLEVBQ3BCLFVBQTBCLEVBQUU7SUFFNUIsSUFBSSxPQUFPLEVBQUUsS0FBSyxVQUFVO1FBQUUsTUFBTSxJQUFJLFNBQVMsQ0FBQyxHQUFHLEtBQUsseUJBQXlCLENBQUMsQ0FBQztJQUNyRixNQUFNLFFBQVEsR0FBRyxlQUFlLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2hELE1BQU0sSUFBSSxHQUFHLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNsQyxNQUFNLEtBQUssR0FBRyxXQUFXLENBQ3ZCLElBQUksQ0FBQyxNQUFNLEVBQ1gsSUFBSSxDQUFDLFFBQVEsRUFDYixHQUFHLEtBQUsseUJBQXlCLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFlB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LENBQUMsTUFBTSxDQUFDLENBQUM7UUFDeEMsZ0hBQWdIO1FBQ2hILDhCQUE4QjtRQUM5QixJQUFJLEVBQUUsQ0FBQyxLQUFLO1lBQUUsT0FBTztRQUNyQixJQUFJLElBQUksQ0FBQyxPQUFPLEVBQUUsT0FBTyxLQUFLLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN6QyxJQUFJLE9BQU8sR0FBRyxDQUFDLENBQUM7WUFDaEIsTUFBTSxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUM5QyxJQUFJLENBQUMsT0FBTyxHQUFHLEVBQUUsT0FBTyxFQUFFLEVBQUUsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLElBQUksa0JBQWtCLENBQUMsR0FBRyxFQUFFLENBQUMsR0FBRyxNQUFNLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDdkcsQ0FBQztRQUNELE1BQU0sRUFBRSxNQUFNLEVBQUUsR0FBRyxjQUFjLENBQUMsSUFBSSxFQUFFO1lBQ3RDLE1BQU0sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDO1lBQ3pDLEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRztZQUNiLHlGQUF5RjtZQUN6RixLQUFLLEVBQUUsZ0JBQWdCO1NBQ3hCLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDdkIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBhdHRlbXB0L3N0YW5kYWxvbmUudHMg4oCUIGBhdHRlbXB0KGZuLCBwb2xpY3k/LCBvcHRpb25zPylgOiB0aGUgYXR0ZW1wdCBydW5uZXIgd2l0aCBubyBzY29wZSBhbmQgbm8gcnVuIChkZXNpZ24gwqczLjYsXG4gKiBwYWNrZXQgUDIpLlxuICpcbiAqIFRoZSBzYW1lIGxvb3AsIHRoZSBzYW1lIHJlY29yZCAobGF3IDEpIGZvciBjb2RlIHRoYXQgaXMgbm90IGEgc3RhZ2Ug4oCUIGEgcHJvdmlkZXIgZGVjb3JhdG9yLCBhIGNsaWVudCB3cmFwcGVyLCBhXG4gKiBzY3JpcHQuIFRoZXJlIGlzIG5vIHJ1biwgc28gdGhlcmUgaXMgbm8gZXhlY3V0aW9uIHRyZWUgYW5kIG5vIGhvb2s6IGV2ZXJ5IHJlY29yZCBnb2VzIHRvIGBvcHRpb25zLm9uQXR0ZW1wdGAsIHRoZVxuICogY2FsbGVyJ3Mgb3duLCBhcyBlYWNoIGF0dGVtcHQgZW5kcy4gVGhlcmUgaXMgbm8gcmVkYWN0aW9uIHJ1bGUgZWl0aGVyOiB0aGUgcmVjb3JkIGhvbGRzIHRoZSBlcnJvcidzIG5hbWVkIGZpZWxkc1xuICogKG5ldmVyIHRoZSB0aHJvd24gdmFsdWUpLCBhbmQgdGhlIGNhbGxlcidzIGNhbGxiYWNrIGRlY2lkZXMgd2hhdCB0byBrZWVwLlxuICpcbiAqIFRpbWUgYW5kIGNhbmNlbGxhdGlvbiBhcmUgdGhlIGNhbGxlcidzOiBgZGVhZGxpbmVgIGNhcHMgZXZlcnkgYXR0ZW1wdCBieSB0aGUgdGltZSBsZWZ0IChhbmQgYSB3YWl0IHRoYXQgd291bGRcbiAqIG91dGxhc3QgaXQgaXMgbmV2ZXIgc3RhcnRlZCDigJQgYG5vLXRpbWUtbGVmdGApOyBgc2lnbmFsYCBjYW5jZWxzLiBBIGRlYWRsaW5lIGFscmVhZHkgcGFzdCwgb3IgYSBzaWduYWwgYWxyZWFkeVxuICogYWJvcnRlZCwgc3RhcnRzIG5vIGF0dGVtcHQgYW5kIHJlY29yZHMgbm90aGluZy5cbiAqXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBjb25zdCByZXMgPSBhd2FpdCBhdHRlbXB0KCh0KSA9PiBmZXRjaCh1cmwsIHsgc2lnbmFsOiB0LnNpZ25hbCB9KSwgeyBhdHRlbXB0czogMywgdGltZW91dE1zOiA1XzAwMCB9LCB7XG4gKiAgIHRhcmdldDogJ2ludmVudG9yeS5sb29rdXAnLFxuICogICBkZWFkbGluZTogRGF0ZS5ub3coKSArIDIwXzAwMCxcbiAqICAgb25BdHRlbXB0OiAocmVjb3JkKSA9PiBsb2cuaW5mbyhyZWNvcmQpLFxuICogfSk7XG4gKiBgYGBcbiAqL1xuXG5pbXBvcnQgeyBpc0Rldk1vZGUgfSBmcm9tICcuLi9kZXZNb2RlLmpzJztcbmltcG9ydCB7IGV4dHJhY3RFcnJvckluZm8gfSBmcm9tICcuLi9lcnJvcnMvZXJyb3JJbmZvLmpzJztcbmltcG9ydCB7IGFybURlYWRsaW5lLCBpc0Fib3J0U2lnbmFsIH0gZnJvbSAnLi9kZWFkbGluZS5qcyc7XG5pbXBvcnQgeyBhZG1pdEF0dGVtcHROYW1lIH0gZnJvbSAnLi9uYW1lLmpzJztcbmltcG9ydCB7IG9ic2VydmVkUmVjb3JkLCBPYnNlcnZlZFNlcmllc0Jvb2ssIHJlYWRPYnNlcnZlZFJlcG9ydCB9IGZyb20gJy4vb2JzZXJ2ZWQuanMnO1xuaW1wb3J0IHsgYWRtaXRDYWxsUG9saWN5IH0gZnJvbSAnLi9wb2xpY3kuanMnO1xuaW1wb3J0IHsgcnVuQXR0ZW1wdHMgfSBmcm9tICcuL3J1bm5lci5qcyc7XG5pbXBvcnQgdHlwZSB7IEF0dGVtcHRDb250ZXh0LCBBdHRlbXB0UmVjb3JkLCBPYnNlcnZlZEF0dGVtcHQsIFJldHJ5UG9saWN5IH0gZnJvbSAnLi90eXBlcy5qcyc7XG5cbmNvbnN0IFdIRVJFID0gJ2F0dGVtcHQoKSc7XG5cbi8qKiBIb3cgYSBzdGFuZGFsb25lIGF0dGVtcHQgc2VyaWVzIGlzIG5hbWVkLCB0aW1lZCBhbmQgcmVwb3J0ZWQuICovXG5leHBvcnQgaW50ZXJmYWNlIEF0dGVtcHRPcHRpb25zIHtcbiAgLyoqIFRoZSBvdXRzaWRlIHRhcmdldCDigJQgYSBuYW1lIGZyb20gY29kZSAoMeKAkzEyOCBjaGFyYWN0ZXJzLCBubyBjb250cm9sIGNoYXJhY3RlciksIHN0YW1wZWQgb24gZXZlcnkgcmVjb3JkLiAqL1xuICByZWFkb25seSB0YXJnZXQ/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgc2VyaWVzIGV2ZXJ5IHJlY29yZCBuYW1lcyDigJQgdGhlIGNhbGxlcidzIG5hbWUgZm9yIHRoaXMgb25lIG9wZXJhdGlvbiAoYW4gb3JkZXIgaWQsIGEgcmVxdWVzdCBpZCksIHNvIHR3b1xuICAgKiBvcGVyYXRpb25zIGNhbiBiZSB0b2xkIGFwYXJ0LiBEZWZhdWx0OiB0aGUgdGFyZ2V0LCBlbHNlIGAnYXR0ZW1wdCdgLlxuICAgKi9cbiAgcmVhZG9ubHkgc2VyaWVzPzogc3RyaW5nO1xuICAvKiogVGhlIGRlYWRsaW5lLCBlcG9jaCBtaWxsaXNlY29uZHM6IGV2ZXJ5IGF0dGVtcHQgaXMgY2FwcGVkIGJ5IHRoZSB0aW1lIGxlZnQgYmVmb3JlIGl0LiAqL1xuICByZWFkb25seSBkZWFkbGluZT86IG51bWJlcjtcbiAgLyoqIENhbmNlbHMgdGhlIHNlcmllczogdGhlIGF0dGVtcHQgaW4gZmxpZ2h0IGlzIGN1dCAoYGFib3J0ZWRgKSwgYSB3YWl0IGVuZHMsIGFuZCBubyBhdHRlbXB0IGZvbGxvd3MuICovXG4gIHJlYWRvbmx5IHNpZ25hbD86IEFib3J0U2lnbmFsO1xuICAvKipcbiAgICogRXZlcnkgYXR0ZW1wdCwgYXQgaXRzIGVuZCDigJQgdGhlIG9ubHkgcGxhY2UgYSBzdGFuZGFsb25lIHJlY29yZCBnb2VzLiBBIHRocm93IGZyb20gaXQgaXMgaXNvbGF0ZWQ6IGl0IG5ldmVyXG4gICAqIGNoYW5nZXMgdGhlIGNhbGwncyBvdXRjb21lIChkZXYgbW9kZSB3YXJucykuXG4gICAqL1xuICByZWFkb25seSBvbkF0dGVtcHQ/OiAocmVjb3JkOiBBdHRlbXB0UmVjb3JkKSA9PiB2b2lkO1xufVxuXG4vKipcbiAqIFJ1biBgZm5gIHVuZGVyIGBwb2xpY3lgIChub25lID0gb25lIGF0dGVtcHQsIHN0aWxsIHJlY29yZGVkKSBhbmQgcmVzb2x2ZSB3aXRoIGl0cyBhbnN3ZXIsIG9yIHJlamVjdCB3aXRoIHRoZSBMQVNUXG4gKiBhdHRlbXB0J3Mgb3duIGVycm9yLiBgZm5gIGdldHMgdGhlIGF0dGVtcHQncyBgQXR0ZW1wdENvbnRleHRgOiBwYXNzIGBzaWduYWxgIHRvIHRoZSB3b3JrLCByZWFkIGB0aW1lTGVmdE1zKClgLFxuICogYW5kIHJlcG9ydCBhbiBTREsncyBvd24gcmV0cmllcyB3aXRoIGBvYnNlcnZlZCgpYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGF0dGVtcHQ8VD4oXG4gIGZuOiAoYXR0ZW1wdDogQXR0ZW1wdENvbnRleHQpID0+IFByb21pc2U8VD4gfCBULFxuICBwb2xpY3k/OiBSZXRyeVBvbGljeSxcbiAgb3B0aW9uczogQXR0ZW1wdE9wdGlvbnMgPSB7fSxcbik6IFByb21pc2U8VD4ge1xuICBpZiAodHlwZW9mIGZuICE9PSAnZnVuY3Rpb24nKSB0aHJvdyBuZXcgVHlwZUVycm9yKGAke1dIRVJFfTogZm4gbXVzdCBiZSBhIGZ1bmN0aW9uYCk7XG4gIGNvbnN0IGFkbWl0dGVkID0gYWRtaXRDYWxsUG9saWN5KFdIRVJFLCBwb2xpY3kpO1xuICBjb25zdCByZWFkID0gcmVhZE9wdGlvbnMob3B0aW9ucyk7XG4gIGNvbnN0IGFybWVkID0gYXJtRGVhZGxpbmUoXG4gICAgcmVhZC5zaWduYWwsXG4gICAgcmVhZC5kZWFkbGluZSxcbiAgICBgJHtXSEVSRX0gcGFzc2VkIGl0cyBkZWFkbGluZSAoJHtTdHJpbmcocmVhZC5kZWFkbGluZSl9IGVwb2NoIG1zKWAsXG4gICk7XG4gIGlmIChhcm1lZC5zaWduYWw/LmFib3J0ZWQpIHtcbiAgICBhcm1lZC5kaXNwb3NlKCk7XG4gICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGFybWVkLnNpZ25hbC5yZWFzb24pO1xuICB9XG4gIGNvbnN0IGRlbGl2ZXIgPSAocmVjb3JkOiBBdHRlbXB0UmVjb3JkKSA9PiB7XG4gICAgaWYgKHJlYWQub25BdHRlbXB0ID09PSB1bmRlZmluZWQpIHJldHVybjtcbiAgICB0cnkge1xuICAgICAgcmVhZC5vbkF0dGVtcHQocmVjb3JkKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGlzRGV2TW9kZSgpKSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlXG4gICAgICAgIGNvbnNvbGUud2FybihgW2Zvb3RwcmludF0gJHtXSEVSRX06IG9uQXR0ZW1wdCB0aHJldzsgdGhlIHJlY29yZCB3YXMgc3RpbGwgbWFkZWAsIGVycm9yKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG4gIGNvbnN0IG9ic2VydmluZyA9IG5ldyBPYnNlcnZlZE93bmVyKHJlYWQuc2VyaWVzLCBkZWxpdmVyKTtcbiAgcmV0dXJuIHJ1bkF0dGVtcHRzPFQ+KChfYXR0ZW1wdCwgY29udGV4dCkgPT4gZm4oY29udGV4dCksIGFkbWl0dGVkLCB7XG4gICAgc2VyaWVzOiByZWFkLnNlcmllcyxcbiAgICBraW5kOiAnY2FsbCcsXG4gICAgLi4uKHJlYWQudGFyZ2V0ICE9PSB1bmRlZmluZWQgJiYgeyB0YXJnZXQ6IHJlYWQudGFyZ2V0IH0pLFxuICAgIC4uLihhcm1lZC5zaWduYWwgIT09IHVuZGVmaW5lZCAmJiB7IHNpZ25hbDogYXJtZWQuc2lnbmFsIH0pLFxuICAgIC4uLihyZWFkLmRlYWRsaW5lICE9PSB1bmRlZmluZWQgJiYgeyBkZWFkbGluZTogcmVhZC5kZWFkbGluZSB9KSxcbiAgICBvbkF0dGVtcHQ6IChyZWNvcmQpID0+IGRlbGl2ZXIocmVjb3JkKSxcbiAgICBvYnNlcnZlOiAocmVwb3J0LCBhdCkgPT4gb2JzZXJ2aW5nLm9ic2VydmUocmVwb3J0LCBhdCksXG4gIH0pLmZpbmFsbHkoKCkgPT4gYXJtZWQuZGlzcG9zZSgpKTtcbn1cblxuLyoqIFRoZSBvcHRpb25zIGFzIHJlYWQ6IGVhY2ggb25jZSwgdmFsaWRhdGVkIChhIGBUeXBlRXJyb3JgIG5hbWluZyB0aGUgZmllbGQpLiAqL1xuZnVuY3Rpb24gcmVhZE9wdGlvbnMob3B0aW9uczogQXR0ZW1wdE9wdGlvbnMpOiB7XG4gIHRhcmdldD86IHN0cmluZztcbiAgc2VyaWVzOiBzdHJpbmc7XG4gIGRlYWRsaW5lPzogbnVtYmVyO1xuICBzaWduYWw/OiBBYm9ydFNpZ25hbDtcbiAgb25BdHRlbXB0PzogKHJlY29yZDogQXR0ZW1wdFJlY29yZCkgPT4gdm9pZDtcbn0ge1xuICBpZiAob3B0aW9ucyA9PT0gbnVsbCB8fCB0eXBlb2Ygb3B0aW9ucyAhPT0gJ29iamVjdCcpIHRocm93IG5ldyBUeXBlRXJyb3IoYCR7V0hFUkV9OiBvcHRpb25zIG11c3QgYmUgYW4gb2JqZWN0YCk7XG4gIGNvbnN0IHsgdGFyZ2V0LCBzZXJpZXMsIGRlYWRsaW5lLCBzaWduYWwsIG9uQXR0ZW1wdCB9ID0gb3B0aW9ucztcbiAgY29uc3QgbmFtZSA9IHRhcmdldCA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogYWRtaXRBdHRlbXB0TmFtZShXSEVSRSwgJ3RhcmdldCcsIHRhcmdldCk7XG4gIGNvbnN0IG5hbWVkID0gc2VyaWVzID09PSB1bmRlZmluZWQgPyBuYW1lID8/ICdhdHRlbXB0JyA6IGFkbWl0QXR0ZW1wdE5hbWUoV0hFUkUsICdzZXJpZXMnLCBzZXJpZXMpO1xuICBpZiAoZGVhZGxpbmUgIT09IHVuZGVmaW5lZCAmJiAodHlwZW9mIGRlYWRsaW5lICE9PSAnbnVtYmVyJyB8fCBOdW1iZXIuaXNOYU4oZGVhZGxpbmUpKSkge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoYCR7V0hFUkV9OiBkZWFkbGluZSBtdXN0IGJlIGEgbnVtYmVyIChlcG9jaCBtcylgKTtcbiAgfVxuICBpZiAoc2lnbmFsICE9PSB1bmRlZmluZWQgJiYgIWlzQWJvcnRTaWduYWwoc2lnbmFsKSkgdGhyb3cgbmV3IFR5cGVFcnJvcihgJHtXSEVSRX06IHNpZ25hbCBtdXN0IGJlIGFuIEFib3J0U2lnbmFsYCk7XG4gIGlmIChvbkF0dGVtcHQgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb25BdHRlbXB0ICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgJHtXSEVSRX06IG9uQXR0ZW1wdCBtdXN0IGJlIGEgZnVuY3Rpb25gKTtcbiAgfVxuICAvLyBgLUluZmluaXR5YCBpcyBhIGRlYWRsaW5lIGxvbmcgcGFzdCAobm8gYXR0ZW1wdCBzdGFydHMpOyBgSW5maW5pdHlgIGlzIG5vbmUuXG4gIGNvbnN0IGF0ID0gZGVhZGxpbmUgPT09IC1JbmZpbml0eSA/IDAgOiBkZWFkbGluZTtcbiAgcmV0dXJuIHtcbiAgICAuLi4obmFtZSAhPT0gdW5kZWZpbmVkICYmIHsgdGFyZ2V0OiBuYW1lIH0pLFxuICAgIHNlcmllczogbmFtZWQsXG4gICAgLi4uKGF0ICE9PSB1bmRlZmluZWQgJiYgTnVtYmVyLmlzRmluaXRlKGF0KSAmJiB7IGRlYWRsaW5lOiBhdCB9KSxcbiAgICAuLi4oc2lnbmFsICE9PSB1bmRlZmluZWQgJiYgeyBzaWduYWwgfSksXG4gICAgLi4uKG9uQXR0ZW1wdCAhPT0gdW5kZWZpbmVkICYmIHsgb25BdHRlbXB0IH0pLFxuICB9O1xufVxuXG4vKipcbiAqIFRoZSBvYnNlcnZlZCByZXBvcnRzIG9mIGEgc3RhbmRhbG9uZSBzZXJpZXM6IGVhY2ggYXR0ZW1wdCBgbWAgb3BlbnMgaXRzIG93biBjYWxsIGxldmVsLCBgPHNlcmllcz5APG0+LjxrPmAg4oCUIHRoZVxuICogc2hhcGUgYSBzdGFnZSBhdHRlbXB0J3MgY2FsbHMgaGF2ZSwgcm9vdGVkIGF0IHRoZSBjYWxsZXIncyBzZXJpZXMuIEEgcmVwb3J0IGFmdGVyIGl0cyBhdHRlbXB0IGVuZGVkIGlzIGRyb3BwZWQuXG4gKi9cbmNsYXNzIE9ic2VydmVkT3duZXIge1xuICBwcml2YXRlIGN1cnJlbnQ/OiB7IHJlYWRvbmx5IGF0dGVtcHQ6IG51bWJlcjsgcmVhZG9ubHkgYm9vazogT2JzZXJ2ZWRTZXJpZXNCb29rIH07XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBzZXJpZXM6IHN0cmluZywgcHJpdmF0ZSByZWFkb25seSBkZWxpdmVyOiAocmVjb3JkOiBBdHRlbXB0UmVjb3JkKSA9PiB2b2lkKSB7fVxuXG4gIG9ic2VydmUocmVwb3J0OiBPYnNlcnZlZEF0dGVtcHQsIGF0OiB7IHJlYWRvbmx5IGF0dGVtcHQ6IG51bWJlcjsgcmVhZG9ubHkgZW5kZWQ6IGJvb2xlYW4gfSk6IHZvaWQge1xuICAgIGNvbnN0IHJlYWQgPSByZWFkT2JzZXJ2ZWRSZXBvcnQocmVwb3J0KTtcbiAgICAvLyBBZnRlciBpdHMgYXR0ZW1wdCBlbmRlZDogZHJvcHBlZCwgbmV2ZXIgdGhyb3duIOKAlCBhbiBTREsncyBvd24gY2FsbGJhY2sgbWF5IGZpcmUgbGF0ZSwgYW5kIGFuIG9ic2VydmVkIGF0dGVtcHRcbiAgICAvLyBuZXZlciBjaGFuZ2VzIGNvbnRyb2wgZmxvdy5cbiAgICBpZiAoYXQuZW5kZWQpIHJldHVybjtcbiAgICBpZiAodGhpcy5jdXJyZW50Py5hdHRlbXB0ICE9PSBhdC5hdHRlbXB0KSB7XG4gICAgICBsZXQgb3JkaW5hbCA9IDA7XG4gICAgICBjb25zdCBwcmVmaXggPSBgJHt0aGlzLnNlcmllc31AJHthdC5hdHRlbXB0fWA7XG4gICAgICB0aGlzLmN1cnJlbnQgPSB7IGF0dGVtcHQ6IGF0LmF0dGVtcHQsIGJvb2s6IG5ldyBPYnNlcnZlZFNlcmllc0Jvb2soKCkgPT4gYCR7cHJlZml4fS4keysrb3JkaW5hbH1gKSB9O1xuICAgIH1cbiAgICBjb25zdCB7IHJlY29yZCB9ID0gb2JzZXJ2ZWRSZWNvcmQocmVhZCwge1xuICAgICAgc2VyaWVzOiB0aGlzLmN1cnJlbnQuYm9vay5zZXJpZXNGb3IocmVhZCksXG4gICAgICBub3c6IERhdGUubm93LFxuICAgICAgLy8gTm8gcnVuLCBubyBydWxlOiB0aGUgZXJyb3IncyBzdHJ1Y3R1cmVkIGluZm8gKHRoZSByZWNvcmQga2VlcHMgaXRzIG5hbWVkIGZpZWxkcyBvbmx5KS5cbiAgICAgIHNlcnZlOiBleHRyYWN0RXJyb3JJbmZvLFxuICAgIH0pO1xuICAgIHRoaXMuZGVsaXZlcihyZWNvcmQpO1xuICB9XG59XG4iXX0=
@@ -0,0 +1,453 @@
1
+ /**
2
+ * attempt/types.ts — the attempt vocabulary: ONE record shape for every try the library runs.
3
+ *
4
+ * A retry is a loop, and every pass of it is an `AttemptRecord`: when it started, how long it took, how it
5
+ * ended, its failure category, and the retry-or-stop decision that followed it — a `DecisionEvidence`, the
6
+ * shape `decide()` produces, so a reader walks a retry exactly as it walks a decider (design
7
+ * docs/design/2026-10-time-and-failure-evidence.md, §3.1, §3.8, §4).
8
+ *
9
+ * WHERE it lives: on the execution tree (`StageSnapshot.attempts` / `attemptSummary`), on the `onAttempt`
10
+ * hook, and in recorders' stores — never on the commit bundle, so every log stays byte-identical (Q1).
11
+ *
12
+ * A LEAF (L0, scripts/layering.config.cjs): the frame's snapshot type (`memory/frameTypes.ts`, L4) names
13
+ * `AttemptRecord`, so this file imports only other leaves' types.
14
+ */
15
+ import type { DecisionEvidence } from '../decide/types.js';
16
+ import type { StructuredErrorInfo } from '../errors/errorInfo.js';
17
+ import type { RetryLoopCall } from './retryLoopTypes.js';
18
+ /**
19
+ * Declarative per-stage retry policy — the policy the attempt runner runs (`AttemptPolicy` in the design is
20
+ * this one type, under this one name).
21
+ *
22
+ * WHY this exists: a retry hand-rolled inside a stage function is invisible to
23
+ * the trace. The stage shows one execution, the commit log shows one bundle,
24
+ * and the two failed calls that preceded the successful one left no mark
25
+ * anywhere — an unexplained behaviour in a library whose whole thesis is that
26
+ * nothing invisible happens. Declared here instead, every attempt is part of
27
+ * the record: each attempt fires `FlowRecorder.onAttempt` with its
28
+ * {@link AttemptRecord}, each failed attempt that is retried also fires
29
+ * `FlowRecorder.onStageRetry`, and the stage's execution-tree node carries
30
+ * `attempts` and `attemptSummary`.
31
+ *
32
+ * A POLICY, not a stage kind — `retry` sits on a normal stage the way
33
+ * `isPausable` / `isStreaming` do. The serialized node `type` is unchanged and
34
+ * every existing consumer keeps rendering the stage exactly as before.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * flowChart<State>('Fetch user', fetchFn, 'fetch-user')
39
+ * .retry({ attempts: 3, backoffMs: (n) => 100 * 2 ** (n - 1) })
40
+ * ```
41
+ */
42
+ export interface RetryPolicy {
43
+ /**
44
+ * How many times the stage function may run in total, INCLUDING the first
45
+ * run. Must be an integer >= 1; `1` means "no retry" (a declared no-op,
46
+ * accepted so a policy can be switched off without deleting it — such a
47
+ * stage runs once and records no attempts).
48
+ */
49
+ attempts: number;
50
+ /**
51
+ * How long to wait before the NEXT attempt. Either a fixed number of
52
+ * milliseconds, or a function of the attempt that just FAILED (1-based) and
53
+ * its error, returning milliseconds — `(n) => 100 * 2 ** (n - 1)` is
54
+ * exponential backoff; `(n, error) => statedWaitMs(error) ?? 100 * n` honours
55
+ * a wait the outside system stated (a `Retry-After`) without the engine
56
+ * parsing anything. A one-argument function is unchanged. Omitted (or a
57
+ * non-finite / negative result, or a throw) means no wait.
58
+ *
59
+ * The wait is a plain awaited timer that is CANCELLED by the run's
60
+ * `AbortSignal`. It is not a pause: a chart cannot be checkpointed in the
61
+ * middle of a backoff. Under a run deadline, a wait that would outlast it is
62
+ * never started: the series stops `no-time-left`.
63
+ */
64
+ backoffMs?: number | ((attempt: number, error: unknown) => number);
65
+ /**
66
+ * The most one wait may last, in milliseconds — a finite number >= 0. The
67
+ * runner ENFORCES it: every wait is `min(backoffMs's answer, maxBackoffMs)`,
68
+ * whatever the error stated, so the declaration cannot lie.
69
+ *
70
+ * It is what makes a FUNCTION backoff countable before the run. A function
71
+ * may read the error (a stated `Retry-After`), and no error exists at build,
72
+ * so the static budget check never asks it: with `maxBackoffMs` it counts
73
+ * each wait at the ceiling; without, the stage is unbounded (`'backoff'`).
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * .retry({ attempts: 4, timeoutMs: 10_000, backoffMs: (n, error) => statedWaitMs(error) ?? 500 * n, maxBackoffMs: 5_000 })
78
+ * ```
79
+ */
80
+ maxBackoffMs?: number;
81
+ /**
82
+ * The cap on ONE attempt, in milliseconds — a finite number > 0. The attempt
83
+ * runs under `min(timeoutMs, time left before the run's deadline)`; when the
84
+ * cap runs out, the attempt's signal (`scope.$attempt().signal`) aborts with
85
+ * an `AttemptTimeoutError`, the engine stops waiting for it, and the attempt
86
+ * is recorded `timeout` (then retried like any failure, if the policy allows).
87
+ *
88
+ * What the engine stops is the WAITING. The function's own work stops only if
89
+ * it passes the signal on (`fetch(url, { signal: scope.$attempt().signal })`);
90
+ * whatever it writes after its attempt ended is dropped and recorded on the
91
+ * stage (`StageSnapshot.lateWrites`).
92
+ *
93
+ * Declared with `attempts: 1`, it is a timeout with no retry — the stage
94
+ * still records its one attempt.
95
+ */
96
+ timeoutMs?: number;
97
+ /**
98
+ * Is THIS error worth another attempt? Defaults to retrying every error.
99
+ * Returning `false` ends the stage immediately on the normal error path, with
100
+ * no retry event; the attempt's record says why it stopped (`reason:
101
+ * 'declined'`).
102
+ *
103
+ * A throw from this predicate is treated as `false` — a broken predicate
104
+ * must not turn a failing stage into an infinite retry loop. The record
105
+ * tells the two apart: a throw stops the series `declined` with
106
+ * `retryOnThrew: true`.
107
+ */
108
+ retryOn?: (error: unknown) => boolean;
109
+ }
110
+ /**
111
+ * Who ran the attempt: the engine, for a stage's own policy (`'stage'`); the attempt runner, for a call a stage made
112
+ * through `scope.$call` or for the standalone `attempt()` (`'call'`); an outside system on its own — an SDK's
113
+ * internal retry — reported through `AttemptContext.observed` (`'observed'`, P2).
114
+ */
115
+ export type AttemptKind = 'stage' | 'call' | 'observed';
116
+ /**
117
+ * How one attempt ended. `'timeout'` is the attempt's OWN timer (never the outside system failing — law 4);
118
+ * `'paused'` is a pause (control flow, never retried). `'aborted'` is the run's signal ending the attempt: the
119
+ * attempt threw the abort's own reason. An attempt that threw its own error is `'failed'`, with its category,
120
+ * even when the run aborted around it — the abort is then the series' stop reason (`reason: 'aborted'`), never a
121
+ * rewrite of what the attempt did.
122
+ */
123
+ export type AttemptOutcome = 'ok' | 'failed' | 'timeout' | 'aborted' | 'paused';
124
+ /**
125
+ * The failure category of an attempt that did not succeed — ONE fixed set of seven, classified by
126
+ * `errorCategory` (`attempt/category.ts`), so every recorder breaks failures down the same way (§3.9).
127
+ * Evidence, never policy: the default `retryOn` retries every category.
128
+ */
129
+ export type AttemptCategory = 'timeout' | 'rate-limited' | 'server' | 'network' | 'auth' | 'permanent' | 'unknown';
130
+ /** What follows an attempt: another one, the value (`'done'`), or the attempt's own error (`'stop'`). */
131
+ export type AttemptNext = 'retry' | 'done' | 'stop';
132
+ /**
133
+ * Why the series went on or ended — the matched rule's label in `retryRules` (`attempt/decision.ts`), or the
134
+ * default's (`'retryable'`).
135
+ */
136
+ export type AttemptReason = 'succeeded' | 'paused' | 'aborted' | 'exhausted' | 'declined' | 'no-time-left' | 'retryable';
137
+ /**
138
+ * What an attempt did to the outside system a touching target names (design §3.3, P3) — present only on the records
139
+ * of a target that declared `touches`:
140
+ * - `'applied'` — the attempt answered (`ok`);
141
+ * - `'none'` — it failed, and its error itself declares `effect: 'none'` (the adapter's word: nothing was sent);
142
+ * - `'unknown'` — anything else: a timeout, a cancellation, a pause, or a failure the adapter did not declare
143
+ * harmless. Nobody knows whether the effect happened, so the series never reports it as failed or ok: a last
144
+ * attempt of unknown effect fails with `UnknownEffectError` — reconcile, do not retry blindly.
145
+ */
146
+ export type AttemptEffect = 'applied' | 'none' | 'unknown';
147
+ /** What a stage's idempotency-key rule is handed — once per EXECUTION, before attempt 1 (`StageTouches`). */
148
+ export interface IdempotencyKeyContext {
149
+ /**
150
+ * The run's (or the subflow's) input, frozen. On the root of a resumed leg the run's input is gone (it does not
151
+ * cross a resume), so reading it there THROWS rather than hand the rule nothing — the stage fails before anything
152
+ * is sent. A paused stage itself resumes under the key its checkpoint carries; the rule is not asked again.
153
+ */
154
+ readonly args: unknown;
155
+ /** This run's id. Regenerated per run and per resume — never a key on its own (see `StageTouches`). */
156
+ readonly runId: string;
157
+ /** The execution the key is for (`charge#4`). */
158
+ readonly runtimeStageId: string;
159
+ /**
160
+ * A committed state value, read without tracking — the key is not a write. Use it for a key the chart keeps in
161
+ * state; it survives a resume, where `args` does not (reading `args` on a resumed leg's root throws). A selected
162
+ * value read here makes the recorded key the redaction placeholder. Read-only: a frozen copy, never the committed
163
+ * value itself.
164
+ */
165
+ getState(key: string): unknown;
166
+ }
167
+ /**
168
+ * A stage that changes something outside the run — a charge, an email, a write to another service (design §3.3,
169
+ * P3). Declared with `.touches(system, { idempotencyKey })` or a `touches` option; a POLICY-like field on the node,
170
+ * like `retry` and `tags`. The built spec carries `system` only.
171
+ *
172
+ * `system` is a NAME from code (`'stripe'`) — never a value. `idempotencyKey` is the RULE that makes the key, run
173
+ * ONCE per execution (not per attempt) and handed to every attempt as `scope.$attempt().idempotencyKey`. It must
174
+ * name the OPERATION, so that every retry — and a resume's re-run, and a caller's whole-run retry — sends the same
175
+ * key: derive it from the input (`order-${args.orderId}`) or from state (`getState('orderId')`), never from `runId`
176
+ * alone (it changes on a resume) and never from what a model wrote. The builder refuses a touching stage that may retry with no rule, and the engine refuses an
177
+ * `interrupt()` in a keyless touching stage (a resume re-runs it). Under a redaction rule, a key derived from an
178
+ * input that holds a selected value is served as the placeholder (records, hook, `UnknownEffectError`) — the
179
+ * caller recomputes it from the input it gave to reconcile.
180
+ */
181
+ export interface StageTouches {
182
+ /** The outside system — a name, 1–128 characters, no control, format or line-separator character. */
183
+ readonly system: string;
184
+ /**
185
+ * The key rule — a function, so the key belongs to the execution (a constant would make every run one operation).
186
+ * Its answer must be 1–255 printable ASCII characters with no space (it travels in a request header); anything
187
+ * else fails the stage with a `TypeError` that never echoes it.
188
+ */
189
+ readonly idempotencyKey?: (context: IdempotencyKeyContext) => string;
190
+ }
191
+ /**
192
+ * What `scope.$call(target, fn, policy, options)` declares beyond its policy (P3): the outside system the call
193
+ * touches, and the key it is made under. A call that touches a system and may retry must carry a key; the key is a
194
+ * VALUE the stage computed from its input or its state — never from model output — and is checked like a stage's.
195
+ */
196
+ export interface CallOptions {
197
+ /** The outside system the call changes — a name like `target`. */
198
+ readonly touches?: string;
199
+ /**
200
+ * The key every attempt of the call is made under — only with `touches`. When the stage can `interrupt()`, derive it
201
+ * from state or from `scope.$attempt().idempotencyKey`, never from `$getArgs()`: the input does not cross a resume,
202
+ * so an args-derived key would differ on the re-run.
203
+ */
204
+ readonly idempotencyKey?: string;
205
+ }
206
+ /**
207
+ * An attempt's error as the run SERVES it — `StructuredErrorInfo` under the run's redaction rule
208
+ * (`RedactionRule.retainStageError`), without `raw`: a record must survive `structuredClone` and must never
209
+ * hand out the thrown value itself.
210
+ */
211
+ export type AttemptError = Omit<StructuredErrorInfo, 'raw'>;
212
+ /**
213
+ * What a retry-or-stop decision reads — the inputs `retryRules` evaluates, first match wins (§3.1). The runner
214
+ * computes each one only when a rule reaches it, so `retryOn` and `backoffMs` run exactly when a retry needs
215
+ * them.
216
+ *
217
+ * `category` and `keyPresent` are inputs no default rule reads; a chart's own rules over the same inputs may.
218
+ * `timeLeftMs` is `Infinity` without a deadline, and so is `timeLeftAfterWaitMs` (= `timeLeftMs − delayMs`):
219
+ * the no-time-left rule compares one input with a constant, as every `decide()` filter does.
220
+ */
221
+ export interface AttemptInputs {
222
+ readonly outcome: AttemptOutcome;
223
+ readonly category?: AttemptCategory;
224
+ /**
225
+ * The run's signal has aborted — read when rule 3 is reached, so an abort raised inside `retryOn` is seen by
226
+ * the decision taken again after it. Always `true` for an `'aborted'` outcome.
227
+ */
228
+ readonly aborted: boolean;
229
+ /** This attempt, 1-based. */
230
+ readonly attempt: number;
231
+ /** The attempts the policy allows in total. */
232
+ readonly of: number;
233
+ readonly timeLeftMs: number;
234
+ /** The wait before the next attempt, from `backoffMs` (`0` when it is absent, invalid or throws). */
235
+ readonly delayMs: number;
236
+ readonly timeLeftAfterWaitMs: number;
237
+ /**
238
+ * The policy's `retryOn` verdict on this attempt's error (`true` when absent; a throw is `false`, and the
239
+ * record says it threw: `AttemptRecord.retryOnThrew`).
240
+ */
241
+ readonly retryOn: boolean;
242
+ /** Whether the target declared an idempotency key — never its value. */
243
+ readonly keyPresent: boolean;
244
+ }
245
+ /**
246
+ * One attempt — the unit of time and failure evidence. Frozen; survives `structuredClone`.
247
+ *
248
+ * Identity: `series` (the stage execution's `runtimeStageId` for a stage attempt) plus `attempt`.
249
+ */
250
+ export interface AttemptRecord {
251
+ /** Logical workflow/pass link, stamped by an explicit retry helper; physical series/attempt stay unchanged. */
252
+ readonly retryLoop?: RetryLoopCall;
253
+ /**
254
+ * The series the attempt belongs to. A stage attempt: its execution's `runtimeStageId`. A call — `$call`, or an
255
+ * observed SDK call — made during stage attempt `n`: `<runtimeStageId>@<n>.<k>`, the `k`-th call of that attempt,
256
+ * so `<series>@<attempt>` is the attempt id of foottrace's grammar (design §3.4). A standalone `attempt()`: the
257
+ * caller's name for the operation.
258
+ */
259
+ readonly series: string;
260
+ readonly kind: AttemptKind;
261
+ /**
262
+ * The outside target of a `'call'` or `'observed'` attempt — a NAME from code (`'stripe.quotes.create'`), never
263
+ * a value. Absent on a stage attempt: its stage names it.
264
+ */
265
+ readonly target?: string;
266
+ /** Who ran an `'observed'` attempt — the report's `source` (`'sdk'` unless it said otherwise). Absent otherwise. */
267
+ readonly source?: string;
268
+ /** 1-based within the series. */
269
+ readonly attempt: number;
270
+ /** The attempts the policy allows in total. */
271
+ readonly of?: number;
272
+ /** Epoch milliseconds when the attempt started. */
273
+ readonly startedAt: number;
274
+ readonly durationMs: number;
275
+ /** How the attempt itself ended — never rewritten by what the series did next (see {@link AttemptOutcome}). */
276
+ readonly outcome: AttemptOutcome;
277
+ /**
278
+ * Present when the attempt failed, timed out or was aborted; absent for `'ok'` and `'paused'`. Read off the
279
+ * error as it stood when the decision was made (after `retryOn` ran), like `error`.
280
+ */
281
+ readonly category?: AttemptCategory;
282
+ /** The retry-or-stop decision — the evidence `decide()` would record for `retryRules(policy)`. */
283
+ readonly decision: DecisionEvidence;
284
+ /** `decision.chosen` — the compact projection a badge reads. */
285
+ readonly next: AttemptNext;
286
+ readonly reason: AttemptReason;
287
+ /**
288
+ * `true` when the policy's `retryOn` THREW on this attempt's error (absent otherwise). A throw is "do not
289
+ * retry", so the reason is `'declined'`; this flag keeps a broken predicate apart from a real `false`.
290
+ */
291
+ readonly retryOnThrew?: true;
292
+ /**
293
+ * The wait before the next attempt — present when the decision computed it: a retry, or (under a deadline) a
294
+ * `no-time-left` stop, whose wait would have outlasted the time left.
295
+ */
296
+ readonly delayMs?: number;
297
+ /**
298
+ * The cap this attempt ran under, in milliseconds — `min(RetryPolicy.timeoutMs, time left before the deadline)`
299
+ * at its start. Absent when neither was set (the attempt ran uncapped).
300
+ */
301
+ readonly timeoutMs?: number;
302
+ /** The time left before the run's deadline when the decision was made (negative once past). Absent without one. */
303
+ readonly timeLeftMs?: number;
304
+ /** The served error of an attempt that failed, timed out or was aborted. */
305
+ readonly error?: AttemptError;
306
+ /** The outside system a touching target names (P3). Absent for a target that touches nothing. */
307
+ readonly system?: string;
308
+ /**
309
+ * The key the attempt was made under, as the run SERVES it — retained under the diagnostic rule as
310
+ * `{ idempotencyKey }`, so a redaction rule of that name (or `policy.diagnostics`) scrubs it. Absent without a key.
311
+ */
312
+ readonly idempotencyKey?: string;
313
+ /** What the attempt did to the outside system (see {@link AttemptEffect}). Present only on a touching target. */
314
+ readonly effect?: AttemptEffect;
315
+ }
316
+ /**
317
+ * The attempt a function is running in — a stage's (`scope.$attempt()`, design §3.1), or a call's (the argument
318
+ * `scope.$call` and `attempt()` hand their function, P2). Never serialised: it holds a live signal.
319
+ *
320
+ * A stage with no retry policy and no deadline is attempt 1 of 1, with the run's signal (or one that never
321
+ * aborts) and `Infinity` left.
322
+ */
323
+ export interface AttemptContext {
324
+ /** The series its record names (see {@link AttemptRecord.series}). */
325
+ readonly series: string;
326
+ /** This attempt, 1-based. */
327
+ readonly attempt: number;
328
+ /** The attempts the policy allows in total. */
329
+ readonly of: number;
330
+ /**
331
+ * Aborts when this attempt must stop: at its cap (`AttemptTimeoutError`), at the run's deadline, or when the run
332
+ * is cancelled. Pass it to `fetch` and SDK calls — the engine stops waiting at the cap either way, but only the
333
+ * function can stop its own work.
334
+ */
335
+ readonly signal: AbortSignal;
336
+ /** The run's deadline, epoch milliseconds — absent without one. */
337
+ readonly deadline?: number;
338
+ /** The cap this attempt runs under (see {@link AttemptRecord.timeoutMs}) — absent when uncapped. */
339
+ readonly timeoutMs?: number;
340
+ /** The outside system this attempt touches (P3) — absent when it touches none. */
341
+ readonly system?: string;
342
+ /**
343
+ * The key this attempt must be made under — the REAL key, computed once per execution from the declared rule (or
344
+ * the `$call`'s option). Pass it to the system (`{ idempotencyKey }`), so a retry, a resume and a caller's retry
345
+ * all name one operation. Absent without a key. Records carry its served form.
346
+ */
347
+ readonly idempotencyKey?: string;
348
+ /**
349
+ * Milliseconds before the run's deadline — `Infinity` without one. Read through the scope, it marks the stage's
350
+ * commit `untrackedSources: ['env']` when a deadline exists: time is an input the record cannot replay.
351
+ */
352
+ timeLeftMs(): number;
353
+ /**
354
+ * Report an attempt an outside system ran ON ITS OWN — an SDK's internal retry (design §3.6, P2). It becomes an
355
+ * `AttemptRecord` of kind `'observed'` beside this attempt's evidence, and fires `onAttempt`; it never changes
356
+ * control flow — in either direction: a report that comes after this attempt ended (an SDK's callback firing
357
+ * late) is dropped and recorded by name (`lateWrites`), never thrown. Only the report's named fields are read; its
358
+ * error is served under the run's redaction rule, and no hook is handed the error object itself. A malformed
359
+ * report is the adapter's bug: a `TypeError` naming the field. Prefer one loop: turn the SDK's own retries off and
360
+ * run the call under `scope.$call`.
361
+ */
362
+ observed(report: ObservedAttempt): void;
363
+ }
364
+ /**
365
+ * An attempt an outside system ran on its own, as an adapter reports it (`AttemptContext.observed`). Only these
366
+ * fields are read — each once; anything else on the object is dropped.
367
+ *
368
+ * A report with `of` stands for one attempt of the SDK's series; a report without one stands for the SDK's WHOLE
369
+ * call, its count unknown — "the SDK ran this" rather than a pretended count.
370
+ */
371
+ export interface ObservedAttempt {
372
+ /** The outside target — a name from code: 1–128 characters, no control, format or line-separator character. */
373
+ readonly target: string;
374
+ /** Which attempt of the SDK's own series, 1-based. Default `1`. */
375
+ readonly attempt?: number;
376
+ /** The attempts the SDK allows in total, when it says (≥ `attempt`). */
377
+ readonly of?: number;
378
+ /** How the SDK's attempt ended. An SDK cannot pause a flowchart, so `'paused'` is refused. */
379
+ readonly outcome: Exclude<AttemptOutcome, 'paused'>;
380
+ /** How long it took, milliseconds — finite and ≥ 0. */
381
+ readonly durationMs: number;
382
+ /** When it started, epoch milliseconds. Default: the report's arrival minus `durationMs`. */
383
+ readonly startedAt?: number;
384
+ /** Who ran it — a name like `target`. Default `'sdk'`. */
385
+ readonly source?: string;
386
+ /** The error of an attempt that did not succeed — served under the run's redaction rule, never kept as thrown. */
387
+ readonly error?: unknown;
388
+ }
389
+ /**
390
+ * A write, emit, diagnostic, detach or call an attempt tried AFTER it had ended — timed out, aborted or failed —
391
+ * dropped at the scope and recorded on its stage (`StageSnapshot.lateWrites`, the first 100 —
392
+ * `StageContext · MAX_LATE_WRITES`). A name, never the value.
393
+ */
394
+ export interface LateWrite {
395
+ /** The attempt that wrote late, 1-based. */
396
+ readonly attempt: number;
397
+ /**
398
+ * The state key (a dotted path for a nested write), the emitted event's name (a diagnostic's emit name —
399
+ * `log.debug.<key>`, `metric.<name>` — for `$debug` / `$metric` / …), `detach:<child root id>`, or — on the
400
+ * `'attempt'` channel (P2) — `call:<target>` (a `$call` started, or a call's record arriving, after its attempt
401
+ * ended) or `observed:<target>` (an observed report after it).
402
+ */
403
+ readonly key: string;
404
+ readonly channel: 'state' | 'emit' | 'detach' | 'attempt';
405
+ }
406
+ /**
407
+ * A series at a glance — stamped once, when the series ends (the Lens badge, §3.10). `last` is how it ended:
408
+ * the last record's `next` / `reason` (and `category`, `retryOnThrew`), or `stop` / `aborted` when the run's
409
+ * signal cut a wait (no attempt followed, so none is recorded).
410
+ *
411
+ * The SERIES' outcome, not the STAGE's. `last.next: 'done'` says the stage function returned; the stage can
412
+ * still fail after that — its commit can fail (a value nothing can clone), and a StageNode it returned can be
413
+ * refused at the run-time door (R5) — and then its `onError` fires with this summary unchanged. Whether the
414
+ * stage failed is the execution's own fact (its error), never read off this summary.
415
+ */
416
+ export interface AttemptSummary {
417
+ readonly count: number;
418
+ readonly ok: number;
419
+ readonly failed: number;
420
+ readonly timeout: number;
421
+ readonly aborted: number;
422
+ readonly paused: number;
423
+ readonly last: {
424
+ readonly next: Exclude<AttemptNext, 'retry'>;
425
+ readonly reason: AttemptReason;
426
+ readonly category?: AttemptCategory;
427
+ readonly retryOnThrew?: true;
428
+ /** The series' effect — `unknown` once any attempt left it unknown, unless the series ended with an answer. Touching targets only. */
429
+ readonly effect?: AttemptEffect;
430
+ };
431
+ }
432
+ /**
433
+ * The run's correlation — which outside trace and unit of work this run belongs to (design §3.4). Resolved ONCE
434
+ * per leg (`run()`, and each `resume()`) from the env by `attempt/correlation.ts · resolveCorrelation`, frozen, and
435
+ * handed by reference to `RuntimeSnapshot.correlation`, every flow event's `TraversalContext.correlation`, and
436
+ * every scope and emit event's `correlation`. Absent — no key anywhere — when the env gives none.
437
+ *
438
+ * Correlation only: a NAME the record carries so a run can be found from a trace. Never identity, never
439
+ * authorisation — a `traceparent` comes from whoever sent the request.
440
+ */
441
+ export interface RunCorrelation {
442
+ /** `env.traceId`, else the trace id of `env.traceparent` (32 lowercase hex). */
443
+ readonly traceId: string;
444
+ /** `env.operationId`, else the header's parent-id (only while the trace is the header's): the caller's unit of work. */
445
+ readonly operationId?: string;
446
+ /** The header's sampled flag (bit 0 of trace-flags) — present only while the trace is the header's. A hint. */
447
+ readonly sampled?: boolean;
448
+ /**
449
+ * The canonical header of the EFFECTIVE ids (`formatTraceparent`) — for propagating the trace onward. Present
450
+ * only while the trace is the header's and the operation is a W3C parent-id; never the received bytes.
451
+ */
452
+ readonly traceparent?: string;
453
+ }