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.
- package/AGENTS.md +2 -1
- package/CLAUDE.md +61 -7
- package/README.md +136 -312
- package/dist/esm/index.d.ts +62 -2
- package/dist/esm/index.js +13 -6
- package/dist/esm/lib/attempt/anySignal.d.ts +19 -0
- package/dist/esm/lib/attempt/anySignal.js +39 -0
- package/dist/esm/lib/attempt/call.d.ts +88 -0
- package/dist/esm/lib/attempt/call.js +129 -0
- package/dist/esm/lib/attempt/category.d.ts +37 -0
- package/dist/esm/lib/attempt/category.js +131 -0
- package/dist/esm/lib/attempt/correlation.d.ts +95 -0
- package/dist/esm/lib/attempt/correlation.js +178 -0
- package/dist/esm/lib/attempt/deadline.d.ts +44 -0
- package/dist/esm/lib/attempt/deadline.js +101 -0
- package/dist/esm/lib/attempt/decision.d.ts +52 -0
- package/dist/esm/lib/attempt/decision.js +134 -0
- package/dist/esm/lib/attempt/effect.d.ts +76 -0
- package/dist/esm/lib/attempt/effect.js +160 -0
- package/dist/esm/lib/attempt/errors.d.ts +41 -0
- package/dist/esm/lib/attempt/errors.js +44 -0
- package/dist/esm/lib/attempt/index.d.ts +18 -0
- package/dist/esm/lib/attempt/index.js +15 -0
- package/dist/esm/lib/attempt/name.d.ts +21 -0
- package/dist/esm/lib/attempt/name.js +43 -0
- package/dist/esm/lib/attempt/observed.d.ts +66 -0
- package/dist/esm/lib/attempt/observed.js +171 -0
- package/dist/esm/lib/attempt/policy.d.ts +45 -0
- package/dist/esm/lib/attempt/policy.js +83 -0
- package/dist/esm/lib/attempt/record.d.ts +11 -0
- package/dist/esm/lib/attempt/record.js +24 -0
- package/dist/esm/lib/attempt/retryLoopContext.d.ts +18 -0
- package/dist/esm/lib/attempt/retryLoopContext.js +24 -0
- package/dist/esm/lib/attempt/retryLoopTypes.d.ts +18 -0
- package/dist/esm/lib/attempt/retryLoopTypes.js +2 -0
- package/dist/esm/lib/attempt/runner.d.ts +157 -0
- package/dist/esm/lib/attempt/runner.js +523 -0
- package/dist/esm/lib/attempt/standalone.d.ts +47 -0
- package/dist/esm/lib/attempt/standalone.js +126 -0
- package/dist/esm/lib/attempt/types.d.ts +453 -0
- package/dist/esm/lib/attempt/types.js +16 -0
- package/dist/esm/lib/budget/index.d.ts +9 -0
- package/dist/esm/lib/budget/index.js +9 -0
- package/dist/esm/lib/budget/timeBudget.d.ts +136 -0
- package/dist/esm/lib/budget/timeBudget.js +666 -0
- package/dist/esm/lib/builder/FlowChartBuilder.d.ts +88 -3
- package/dist/esm/lib/builder/FlowChartBuilder.js +199 -9
- package/dist/esm/lib/builder/retryLoop.d.ts +56 -0
- package/dist/esm/lib/builder/retryLoop.js +283 -0
- package/dist/esm/lib/builder/types.d.ts +35 -1
- package/dist/esm/lib/builder/types.js +1 -1
- package/dist/esm/lib/decide/decide.js +2 -2
- package/dist/esm/lib/decide/index.d.ts +1 -1
- package/dist/esm/lib/decide/index.js +2 -2
- package/dist/esm/lib/decide/types.d.ts +3 -0
- package/dist/esm/lib/decide/types.js +1 -8
- package/dist/esm/lib/engine/graph/StageNode.d.ts +11 -1
- package/dist/esm/lib/engine/graph/StageNode.js +1 -1
- package/dist/esm/lib/engine/graph/prefixNodeTree.js +5 -1
- package/dist/esm/lib/engine/handlers/ChildrenExecutor.js +36 -6
- package/dist/esm/lib/engine/handlers/DeciderHandler.js +9 -5
- package/dist/esm/lib/engine/handlers/ResumeEntry.js +3 -1
- package/dist/esm/lib/engine/handlers/SelectorHandler.js +6 -5
- package/dist/esm/lib/engine/handlers/StageRunner.d.ts +8 -1
- package/dist/esm/lib/engine/handlers/StageRunner.js +36 -9
- package/dist/esm/lib/engine/handlers/SubflowExecutor.js +24 -5
- package/dist/esm/lib/engine/handlers/commitStage.d.ts +7 -0
- package/dist/esm/lib/engine/handlers/commitStage.js +22 -4
- package/dist/esm/lib/engine/handlers/stageError.d.ts +9 -0
- package/dist/esm/lib/engine/handlers/stageError.js +23 -1
- package/dist/esm/lib/engine/index.d.ts +2 -2
- package/dist/esm/lib/engine/index.js +1 -1
- package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +27 -13
- package/dist/esm/lib/engine/narrative/CombinedNarrativeRecorder.js +68 -40
- package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -1
- package/dist/esm/lib/engine/narrative/FlowRecorderDispatcher.js +19 -2
- package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.d.ts +22 -3
- package/dist/esm/lib/engine/narrative/NarrativeFlowRecorder.js +61 -9
- package/dist/esm/lib/engine/narrative/NullControlFlowNarrativeGenerator.d.ts +1 -0
- package/dist/esm/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
- package/dist/esm/lib/engine/narrative/formatting/sentences.d.ts +23 -0
- package/dist/esm/lib/engine/narrative/formatting/sentences.js +127 -1
- package/dist/esm/lib/engine/narrative/index.d.ts +2 -2
- package/dist/esm/lib/engine/narrative/index.js +1 -1
- package/dist/esm/lib/engine/narrative/narrativeTypes.d.ts +27 -21
- package/dist/esm/lib/engine/narrative/narrativeTypes.js +1 -1
- package/dist/esm/lib/engine/narrative/recorders/ManifestFlowRecorder.d.ts +45 -2
- package/dist/esm/lib/engine/narrative/recorders/ManifestFlowRecorder.js +55 -2
- package/dist/esm/lib/engine/narrative/recorders/index.d.ts +1 -1
- package/dist/esm/lib/engine/narrative/recorders/index.js +1 -1
- package/dist/esm/lib/engine/narrative/types.d.ts +74 -5
- package/dist/esm/lib/engine/narrative/types.js +1 -1
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.d.ts +59 -19
- package/dist/esm/lib/engine/traversal/FlowchartTraverser.js +194 -118
- package/dist/esm/lib/engine/traversalContext.d.ts +7 -2
- package/dist/esm/lib/engine/traversalContext.js +6 -3
- package/dist/esm/lib/engine/types.d.ts +52 -57
- package/dist/esm/lib/engine/types.js +1 -1
- package/dist/esm/lib/errors/terminalFailure.d.ts +29 -0
- package/dist/esm/lib/errors/terminalFailure.js +60 -0
- package/dist/esm/lib/{decide → filter}/evaluator.d.ts +7 -2
- package/dist/esm/lib/filter/evaluator.js +135 -0
- package/dist/esm/lib/ids/idempotencyKey.d.ts +14 -0
- package/dist/esm/lib/ids/idempotencyKey.js +24 -0
- package/dist/esm/lib/memory/StageContext.d.ts +123 -3
- package/dist/esm/lib/memory/StageContext.js +245 -4
- package/dist/esm/lib/memory/attention.d.ts +26 -0
- package/dist/esm/lib/memory/attention.js +171 -0
- package/dist/esm/lib/memory/borrowedMutation.d.ts +8 -0
- package/dist/esm/lib/memory/borrowedMutation.js +14 -1
- package/dist/esm/lib/memory/frameTypes.d.ts +38 -0
- package/dist/esm/lib/memory/frameTypes.js +3 -1
- package/dist/esm/lib/memory/redaction.d.ts +12 -0
- package/dist/esm/lib/memory/redaction.js +54 -5
- package/dist/esm/lib/pause/record.js +10 -1
- package/dist/esm/lib/pause/types.d.ts +19 -0
- package/dist/esm/lib/pause/types.js +17 -1
- package/dist/esm/lib/reactive/createTypedScope.js +3 -1
- package/dist/esm/lib/reactive/types.d.ts +36 -4
- package/dist/esm/lib/reactive/types.js +3 -1
- package/dist/esm/lib/recorder/AttemptRecorder.d.ts +141 -0
- package/dist/esm/lib/recorder/AttemptRecorder.js +412 -0
- package/dist/esm/lib/recorder/ControlDepRecorder.d.ts +36 -2
- package/dist/esm/lib/recorder/ControlDepRecorder.js +50 -2
- package/dist/esm/lib/recorder/EmitRecorder.d.ts +3 -0
- package/dist/esm/lib/recorder/EmitRecorder.js +1 -1
- package/dist/esm/lib/recorder/InOutRecorder.d.ts +37 -1
- package/dist/esm/lib/recorder/InOutRecorder.js +75 -6
- package/dist/esm/lib/recorder/QualityRecorder.d.ts +32 -5
- package/dist/esm/lib/recorder/QualityRecorder.js +87 -29
- package/dist/esm/lib/recorder/TopologyRecorder.d.ts +35 -5
- package/dist/esm/lib/recorder/TopologyRecorder.js +76 -2
- package/dist/esm/lib/recorder/attemptMetricRows.d.ts +11 -0
- package/dist/esm/lib/recorder/attemptMetricRows.js +202 -0
- package/dist/esm/lib/recorder/attemptMetrics.d.ts +7 -0
- package/dist/esm/lib/recorder/attemptMetrics.js +165 -0
- package/dist/esm/lib/recorder/attemptMetricsTypes.d.ts +114 -0
- package/dist/esm/lib/recorder/attemptMetricsTypes.js +2 -0
- package/dist/esm/lib/recorder/attemptOTel.d.ts +78 -0
- package/dist/esm/lib/recorder/attemptOTel.js +107 -0
- package/dist/esm/lib/recorder/attemptSeries.d.ts +81 -0
- package/dist/esm/lib/recorder/attemptSeries.js +103 -0
- package/dist/esm/lib/recorder/hooks.d.ts +9 -0
- package/dist/esm/lib/recorder/hooks.js +4 -1
- package/dist/esm/lib/runner/DeferredObserverTier.js +13 -1
- package/dist/esm/lib/runner/ExecutionRuntime.d.ts +54 -6
- package/dist/esm/lib/runner/ExecutionRuntime.js +57 -5
- package/dist/esm/lib/runner/FlowChartExecutor.d.ts +46 -2
- package/dist/esm/lib/runner/FlowChartExecutor.js +330 -101
- package/dist/esm/lib/runner/RunnableChart.d.ts +6 -0
- package/dist/esm/lib/runner/RunnableChart.js +5 -1
- package/dist/esm/lib/runner/attach.d.ts +2 -1
- package/dist/esm/lib/runner/attach.js +8 -2
- package/dist/esm/lib/runner/checkpoint.js +3 -1
- package/dist/esm/lib/runner/deadline.d.ts +42 -0
- package/dist/esm/lib/runner/deadline.js +90 -0
- package/dist/esm/lib/runner/index.d.ts +3 -1
- package/dist/esm/lib/runner/index.js +2 -1
- package/dist/esm/lib/runner/options.d.ts +17 -0
- package/dist/esm/lib/runner/options.js +3 -1
- package/dist/esm/lib/runner/recordSink.d.ts +128 -0
- package/dist/esm/lib/runner/recordSink.js +296 -0
- package/dist/esm/lib/runner/resume.d.ts +3 -0
- package/dist/esm/lib/runner/resume.js +22 -2
- package/dist/esm/lib/runner/snapshot.d.ts +2 -2
- package/dist/esm/lib/runner/snapshot.js +6 -2
- package/dist/esm/lib/scope/ScopeFacade.d.ts +118 -4
- package/dist/esm/lib/scope/ScopeFacade.js +304 -7
- package/dist/esm/lib/scope/recorders/DebugRecorder.d.ts +17 -3
- package/dist/esm/lib/scope/recorders/DebugRecorder.js +79 -13
- package/dist/esm/lib/scope/recorders/MetricRecorder.d.ts +10 -0
- package/dist/esm/lib/scope/recorders/MetricRecorder.js +15 -2
- package/dist/esm/lib/scope/runtime.d.ts +3 -0
- package/dist/esm/lib/scope/runtime.js +1 -1
- package/dist/esm/lib/scope/types.d.ts +6 -0
- package/dist/esm/lib/scope/types.js +1 -1
- package/dist/esm/lib/sinks/fileSink.d.ts +135 -0
- package/dist/esm/lib/sinks/fileSink.js +387 -0
- package/dist/esm/recorders.d.ts +8 -2
- package/dist/esm/recorders.js +7 -1
- package/dist/esm/sinks.d.ts +23 -0
- package/dist/esm/sinks.js +23 -0
- package/dist/esm/trace.d.ts +2 -2
- package/dist/esm/trace.js +1 -1
- package/dist/index.js +77 -60
- package/dist/lib/attempt/anySignal.js +43 -0
- package/dist/lib/attempt/call.js +134 -0
- package/dist/lib/attempt/category.js +136 -0
- package/dist/lib/attempt/correlation.js +186 -0
- package/dist/lib/attempt/deadline.js +112 -0
- package/dist/lib/attempt/decision.js +139 -0
- package/dist/lib/attempt/effect.js +174 -0
- package/dist/lib/attempt/errors.js +49 -0
- package/dist/lib/attempt/index.js +26 -0
- package/dist/lib/attempt/name.js +48 -0
- package/dist/lib/attempt/observed.js +177 -0
- package/dist/lib/attempt/policy.js +92 -0
- package/dist/lib/attempt/record.js +29 -0
- package/dist/lib/attempt/retryLoopContext.js +31 -0
- package/dist/lib/attempt/retryLoopTypes.js +3 -0
- package/dist/lib/attempt/runner.js +530 -0
- package/dist/lib/attempt/standalone.js +130 -0
- package/dist/lib/attempt/types.js +17 -0
- package/dist/lib/budget/index.js +17 -0
- package/dist/lib/budget/timeBudget.js +674 -0
- package/dist/lib/builder/FlowChartBuilder.js +199 -9
- package/dist/lib/builder/retryLoop.js +287 -0
- package/dist/lib/builder/types.js +1 -1
- package/dist/lib/decide/decide.js +2 -2
- package/dist/lib/decide/index.js +2 -2
- package/dist/lib/decide/types.js +1 -8
- package/dist/lib/engine/graph/StageNode.js +1 -1
- package/dist/lib/engine/graph/prefixNodeTree.js +5 -1
- package/dist/lib/engine/handlers/ChildrenExecutor.js +36 -6
- package/dist/lib/engine/handlers/DeciderHandler.js +7 -3
- package/dist/lib/engine/handlers/ResumeEntry.js +3 -1
- package/dist/lib/engine/handlers/SelectorHandler.js +4 -3
- package/dist/lib/engine/handlers/StageRunner.js +36 -9
- package/dist/lib/engine/handlers/SubflowExecutor.js +24 -5
- package/dist/lib/engine/handlers/commitStage.js +24 -5
- package/dist/lib/engine/handlers/stageError.js +26 -2
- package/dist/lib/engine/index.js +1 -1
- package/dist/lib/engine/narrative/CombinedNarrativeRecorder.js +67 -39
- package/dist/lib/engine/narrative/FlowRecorderDispatcher.js +19 -2
- package/dist/lib/engine/narrative/NarrativeFlowRecorder.js +60 -8
- package/dist/lib/engine/narrative/NullControlFlowNarrativeGenerator.js +2 -1
- package/dist/lib/engine/narrative/formatting/sentences.js +131 -2
- package/dist/lib/engine/narrative/index.js +1 -1
- package/dist/lib/engine/narrative/narrativeTypes.js +1 -1
- package/dist/lib/engine/narrative/recorders/ManifestFlowRecorder.js +55 -2
- package/dist/lib/engine/narrative/recorders/index.js +1 -1
- package/dist/lib/engine/narrative/types.js +1 -1
- package/dist/lib/engine/traversal/FlowchartTraverser.js +192 -116
- package/dist/lib/engine/traversalContext.js +6 -3
- package/dist/lib/engine/types.js +1 -1
- package/dist/lib/errors/terminalFailure.js +64 -0
- package/dist/lib/filter/evaluator.js +139 -0
- package/dist/lib/ids/idempotencyKey.js +28 -0
- package/dist/lib/memory/StageContext.js +246 -5
- package/dist/lib/memory/attention.js +175 -0
- package/dist/lib/memory/borrowedMutation.js +16 -2
- package/dist/lib/memory/frameTypes.js +3 -1
- package/dist/lib/memory/redaction.js +54 -5
- package/dist/lib/pause/record.js +10 -1
- package/dist/lib/pause/types.js +17 -1
- package/dist/lib/reactive/createTypedScope.js +3 -1
- package/dist/lib/reactive/types.js +3 -1
- package/dist/lib/recorder/AttemptRecorder.js +417 -0
- package/dist/lib/recorder/ControlDepRecorder.js +50 -2
- package/dist/lib/recorder/EmitRecorder.js +1 -1
- package/dist/lib/recorder/InOutRecorder.js +75 -6
- package/dist/lib/recorder/QualityRecorder.js +87 -29
- package/dist/lib/recorder/TopologyRecorder.js +76 -2
- package/dist/lib/recorder/attemptMetricRows.js +209 -0
- package/dist/lib/recorder/attemptMetrics.js +174 -0
- package/dist/lib/recorder/attemptMetricsTypes.js +3 -0
- package/dist/lib/recorder/attemptOTel.js +111 -0
- package/dist/lib/recorder/attemptSeries.js +113 -0
- package/dist/lib/recorder/hooks.js +4 -1
- package/dist/lib/runner/DeferredObserverTier.js +13 -1
- package/dist/lib/runner/ExecutionRuntime.js +57 -5
- package/dist/lib/runner/FlowChartExecutor.js +330 -101
- package/dist/lib/runner/RunnableChart.js +5 -1
- package/dist/lib/runner/attach.js +8 -2
- package/dist/lib/runner/checkpoint.js +3 -1
- package/dist/lib/runner/deadline.js +94 -0
- package/dist/lib/runner/index.js +4 -2
- package/dist/lib/runner/options.js +3 -1
- package/dist/lib/runner/recordSink.js +302 -0
- package/dist/lib/runner/resume.js +22 -2
- package/dist/lib/runner/snapshot.js +6 -2
- package/dist/lib/scope/ScopeFacade.js +303 -6
- package/dist/lib/scope/recorders/DebugRecorder.js +79 -13
- package/dist/lib/scope/recorders/MetricRecorder.js +15 -2
- package/dist/lib/scope/runtime.js +1 -1
- package/dist/lib/scope/types.js +1 -1
- package/dist/lib/sinks/fileSink.js +392 -0
- package/dist/recorders.js +10 -2
- package/dist/sinks.js +32 -0
- package/dist/trace.js +1 -1
- package/dist/types/index.d.ts +62 -2
- package/dist/types/lib/attempt/anySignal.d.ts +19 -0
- package/dist/types/lib/attempt/call.d.ts +88 -0
- package/dist/types/lib/attempt/category.d.ts +37 -0
- package/dist/types/lib/attempt/correlation.d.ts +95 -0
- package/dist/types/lib/attempt/deadline.d.ts +44 -0
- package/dist/types/lib/attempt/decision.d.ts +52 -0
- package/dist/types/lib/attempt/effect.d.ts +76 -0
- package/dist/types/lib/attempt/errors.d.ts +41 -0
- package/dist/types/lib/attempt/index.d.ts +18 -0
- package/dist/types/lib/attempt/name.d.ts +21 -0
- package/dist/types/lib/attempt/observed.d.ts +66 -0
- package/dist/types/lib/attempt/policy.d.ts +45 -0
- package/dist/types/lib/attempt/record.d.ts +11 -0
- package/dist/types/lib/attempt/retryLoopContext.d.ts +18 -0
- package/dist/types/lib/attempt/retryLoopTypes.d.ts +18 -0
- package/dist/types/lib/attempt/runner.d.ts +157 -0
- package/dist/types/lib/attempt/standalone.d.ts +47 -0
- package/dist/types/lib/attempt/types.d.ts +453 -0
- package/dist/types/lib/budget/index.d.ts +9 -0
- package/dist/types/lib/budget/timeBudget.d.ts +136 -0
- package/dist/types/lib/builder/FlowChartBuilder.d.ts +88 -3
- package/dist/types/lib/builder/retryLoop.d.ts +56 -0
- package/dist/types/lib/builder/types.d.ts +35 -1
- package/dist/types/lib/decide/index.d.ts +1 -1
- package/dist/types/lib/decide/types.d.ts +3 -0
- package/dist/types/lib/engine/graph/StageNode.d.ts +11 -1
- package/dist/types/lib/engine/handlers/StageRunner.d.ts +8 -1
- package/dist/types/lib/engine/handlers/commitStage.d.ts +7 -0
- package/dist/types/lib/engine/handlers/stageError.d.ts +9 -0
- package/dist/types/lib/engine/index.d.ts +2 -2
- package/dist/types/lib/engine/narrative/CombinedNarrativeRecorder.d.ts +27 -13
- package/dist/types/lib/engine/narrative/FlowRecorderDispatcher.d.ts +4 -1
- package/dist/types/lib/engine/narrative/NarrativeFlowRecorder.d.ts +22 -3
- package/dist/types/lib/engine/narrative/NullControlFlowNarrativeGenerator.d.ts +1 -0
- package/dist/types/lib/engine/narrative/formatting/sentences.d.ts +23 -0
- package/dist/types/lib/engine/narrative/index.d.ts +2 -2
- package/dist/types/lib/engine/narrative/narrativeTypes.d.ts +27 -21
- package/dist/types/lib/engine/narrative/recorders/ManifestFlowRecorder.d.ts +45 -2
- package/dist/types/lib/engine/narrative/recorders/index.d.ts +1 -1
- package/dist/types/lib/engine/narrative/types.d.ts +74 -5
- package/dist/types/lib/engine/traversal/FlowchartTraverser.d.ts +59 -19
- package/dist/types/lib/engine/traversalContext.d.ts +7 -2
- package/dist/types/lib/engine/types.d.ts +52 -57
- package/dist/types/lib/errors/terminalFailure.d.ts +29 -0
- package/dist/types/lib/{decide → filter}/evaluator.d.ts +7 -2
- package/dist/types/lib/ids/idempotencyKey.d.ts +14 -0
- package/dist/types/lib/memory/StageContext.d.ts +123 -3
- package/dist/types/lib/memory/attention.d.ts +26 -0
- package/dist/types/lib/memory/borrowedMutation.d.ts +8 -0
- package/dist/types/lib/memory/frameTypes.d.ts +38 -0
- package/dist/types/lib/memory/redaction.d.ts +12 -0
- package/dist/types/lib/pause/types.d.ts +19 -0
- package/dist/types/lib/reactive/types.d.ts +36 -4
- package/dist/types/lib/recorder/AttemptRecorder.d.ts +141 -0
- package/dist/types/lib/recorder/ControlDepRecorder.d.ts +36 -2
- package/dist/types/lib/recorder/EmitRecorder.d.ts +3 -0
- package/dist/types/lib/recorder/InOutRecorder.d.ts +37 -1
- package/dist/types/lib/recorder/QualityRecorder.d.ts +32 -5
- package/dist/types/lib/recorder/TopologyRecorder.d.ts +35 -5
- package/dist/types/lib/recorder/attemptMetricRows.d.ts +11 -0
- package/dist/types/lib/recorder/attemptMetrics.d.ts +7 -0
- package/dist/types/lib/recorder/attemptMetricsTypes.d.ts +114 -0
- package/dist/types/lib/recorder/attemptOTel.d.ts +78 -0
- package/dist/types/lib/recorder/attemptSeries.d.ts +81 -0
- package/dist/types/lib/recorder/hooks.d.ts +9 -0
- package/dist/types/lib/runner/ExecutionRuntime.d.ts +54 -6
- package/dist/types/lib/runner/FlowChartExecutor.d.ts +46 -2
- package/dist/types/lib/runner/RunnableChart.d.ts +6 -0
- package/dist/types/lib/runner/attach.d.ts +2 -1
- package/dist/types/lib/runner/deadline.d.ts +42 -0
- package/dist/types/lib/runner/index.d.ts +3 -1
- package/dist/types/lib/runner/options.d.ts +17 -0
- package/dist/types/lib/runner/recordSink.d.ts +128 -0
- package/dist/types/lib/runner/resume.d.ts +3 -0
- package/dist/types/lib/runner/snapshot.d.ts +2 -2
- package/dist/types/lib/scope/ScopeFacade.d.ts +118 -4
- package/dist/types/lib/scope/recorders/DebugRecorder.d.ts +17 -3
- package/dist/types/lib/scope/recorders/MetricRecorder.d.ts +10 -0
- package/dist/types/lib/scope/runtime.d.ts +3 -0
- package/dist/types/lib/scope/types.d.ts +6 -0
- package/dist/types/lib/sinks/fileSink.d.ts +135 -0
- package/dist/types/recorders.d.ts +8 -2
- package/dist/types/sinks.d.ts +23 -0
- package/dist/types/trace.d.ts +2 -2
- package/package.json +20 -6
- package/dist/esm/lib/decide/evaluator.js +0 -130
- package/dist/lib/decide/evaluator.js +0 -134
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* filter/evaluator -- Prisma-style filter evaluator for decision rules.
|
|
3
3
|
*
|
|
4
4
|
* Pure function. Takes a WhereFilter, a value getter, and a redaction checker.
|
|
5
5
|
* Evaluates each condition, records the result, returns matched/conditions.
|
|
6
6
|
*
|
|
7
7
|
* All keys in the filter are ANDed (all must match for the rule to match).
|
|
8
8
|
* Decoupled from ScopeFacade — receives callbacks, not scope.
|
|
9
|
+
*
|
|
10
|
+
* A LEAF module of its own (P2, 10.1): `decide()` (decide/) and the attempt rule table (attempt/decision.ts) share
|
|
11
|
+
* this one law, and neither may reach the other's dependencies through it. In decide/ it made `attempt/` reach
|
|
12
|
+
* `scope/` (decide.ts imports the scope runtime), so a `scope → attempt` edge — `scope.$call` — closed a module
|
|
13
|
+
* cycle.
|
|
9
14
|
*/
|
|
10
|
-
import type { FilterCondition, WhereFilter } from '
|
|
15
|
+
import type { FilterCondition, WhereFilter } from '../decide/types.js';
|
|
11
16
|
/**
|
|
12
17
|
* Evaluates a Prisma-style filter against scope values.
|
|
13
18
|
*
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ids/idempotencyKey.ts — the ONE format rule for an idempotency key (design §3.3, packet P3). A leaf: the attempt
|
|
3
|
+
* law (`attempt/effect.ts · admitIdempotencyKey`, a key a stage's rule or a `$call` gives) and the checkpoint decoder
|
|
4
|
+
* (`pause/record.ts`, a key a paused execution carries to its resume) both ask it, so a key a stored checkpoint
|
|
5
|
+
* smuggles in is held to the same rule as one the code made.
|
|
6
|
+
*
|
|
7
|
+
* 1–255 printable ASCII characters (`\x21`–`\x7e`), no space: a key travels in a request header
|
|
8
|
+
* (`Idempotency-Key`), so a CR/LF could forge one, and 255 is Stripe's limit, inside every header limit. The
|
|
9
|
+
* problem names the rule, never the value.
|
|
10
|
+
*/
|
|
11
|
+
/** The longest idempotency key. */
|
|
12
|
+
export declare const MAX_IDEMPOTENCY_KEY_LENGTH = 255;
|
|
13
|
+
/** Why `value` is not an idempotency key, or `undefined` when it is one. */
|
|
14
|
+
export declare function idempotencyKeyProblem(value: unknown): string | undefined;
|
|
@@ -13,12 +13,28 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import type { CommitPhase, EmitSourcePosition, UntrackedSource } from 'foottrace';
|
|
15
15
|
import type { EventLog, SharedMemory } from 'foottrace/write';
|
|
16
|
+
import type { AttemptContext, AttemptRecord, AttemptSummary, LateWrite } from '../attempt/types.js';
|
|
17
|
+
import type { StructuredErrorInfo } from '../errors/errorInfo.js';
|
|
18
|
+
import { type TerminalFailureContext, NativeFailureState } from '../errors/terminalFailure.js';
|
|
16
19
|
import { type DiagnosticChannel, DiagnosticCollector } from './DiagnosticCollector.js';
|
|
17
20
|
import type { FlowControlType, StageSnapshot } from './frameTypes.js';
|
|
18
21
|
import type { RedactionVerdict } from './redaction.js';
|
|
19
22
|
import { RedactionRule } from './redaction.js';
|
|
20
23
|
import type { RunPolicy } from './runPolicy.js';
|
|
24
|
+
/**
|
|
25
|
+
* How many call and observed attempt records one stage execution keeps (P2) — a stage that calls in a loop must
|
|
26
|
+
* not grow the execution tree without bound. The rest are counted (`StageSnapshot.attemptsDropped`) and still
|
|
27
|
+
* fired on `onAttempt`. A stage's OWN attempt records are never displaced: its policy's ceiling bounds them.
|
|
28
|
+
*/
|
|
29
|
+
export declare const MAX_CALL_RECORDS = 1000;
|
|
21
30
|
export declare class StageContext {
|
|
31
|
+
#private;
|
|
32
|
+
/** @internal Ownership of an escaping failure. Shared only by sequential frames, never serialized. */
|
|
33
|
+
failureState: NativeFailureState;
|
|
34
|
+
/** @internal The native frame stamp, independent of mutable recorder event context. */
|
|
35
|
+
get failureIdentity(): NonNullable<TerminalFailureContext['stage']> | undefined;
|
|
36
|
+
/** @internal Stamped before observers; never inherited by another frame or persisted. */
|
|
37
|
+
bindFailureIdentity(runId: string, runtimeStageId: string): void;
|
|
22
38
|
/**
|
|
23
39
|
* The record half of this frame (`RecordFrame.ts`, L3, C3): the heap and,
|
|
24
40
|
* when the run keeps them, the redacted mirror and the log; the address;
|
|
@@ -138,6 +154,41 @@ export declare class StageContext {
|
|
|
138
154
|
* stages that never touch an untracked path pay nothing.
|
|
139
155
|
*/
|
|
140
156
|
private _untrackedSources?;
|
|
157
|
+
/**
|
|
158
|
+
* The attempts of this frame's execution (10.1) — its own under the attempt runner, appended as each attempt ends
|
|
159
|
+
* (`FlowchartTraverser · executeStage`), and those of the calls it made (P2, {@link reportCallAttempt}) — read
|
|
160
|
+
* by {@link snapshotSelf}. Append-only
|
|
161
|
+
* evidence like `debug`: NOT cleared by {@link discardStaged} (the earlier attempts are the point) and never
|
|
162
|
+
* part of a commit bundle. Lazily allocated: a stage without a policy pays nothing.
|
|
163
|
+
*/
|
|
164
|
+
private _attempts?;
|
|
165
|
+
/** The attempt series at a glance, stamped once when it ends. */
|
|
166
|
+
private _attemptSummary?;
|
|
167
|
+
/** Facts collected for this execution only; retry discards deliberately keep them. */
|
|
168
|
+
private _attention?;
|
|
169
|
+
/**
|
|
170
|
+
* The attempt now running (P1b) — set by `StageRunner` before the scope is built, so the facade can hand it out
|
|
171
|
+
* (`scope.$attempt()`) and fence its own attempt. Absent for a stage the attempt runner does not run.
|
|
172
|
+
*/
|
|
173
|
+
private _attempt?;
|
|
174
|
+
/** The run's signal, for the attempt a stage outside the runner reports (attempt 1 of 1). */
|
|
175
|
+
private _runSignal?;
|
|
176
|
+
/** Every attempt up to this number has ENDED without an answer — its scope is fenced (0 = none). */
|
|
177
|
+
private _endedThrough;
|
|
178
|
+
/** Writes an attempt tried after it ended — dropped at the scope, kept here as names. Lazily allocated. */
|
|
179
|
+
private _lateWrites?;
|
|
180
|
+
/**
|
|
181
|
+
* Where a call's attempt records are reported (P2) — the engine's `onAttempt` for this stage execution, set by
|
|
182
|
+
* `FlowchartTraverser · executeStage` with the stage's own traversal context (and its correlation).
|
|
183
|
+
*/
|
|
184
|
+
private _attemptReporter?;
|
|
185
|
+
/** Calls made so far, per stage attempt — the `k` of a call's series. Lazily allocated. */
|
|
186
|
+
private _callOrdinals?;
|
|
187
|
+
/** Per stage attempt, the signal its calls stop by (`callsEndedSignal`). Lazily allocated. */
|
|
188
|
+
private _callsEnded?;
|
|
189
|
+
/** Call and observed records kept on the frame, and those past {@link MAX_CALL_RECORDS}. */
|
|
190
|
+
private _callRecords;
|
|
191
|
+
private _attemptsDropped;
|
|
141
192
|
/** Observer called after commit() — used by ScopeFacade to fire ScopeRecorder.onCommit. */
|
|
142
193
|
private _commitObserver?;
|
|
143
194
|
constructor(runId: string, name: string, stageId: string, sharedMemory: SharedMemory, branchId?: string, eventLog?: EventLog, isDecider?: boolean);
|
|
@@ -404,6 +455,8 @@ export declare class StageContext {
|
|
|
404
455
|
* reads them post-run for the execution-tree snapshot.
|
|
405
456
|
*/
|
|
406
457
|
commit(phase?: CommitPhase): void;
|
|
458
|
+
/** Whether this frame has committed — a call's record arriving after it is late (P2, `ScopeFacade · call`). */
|
|
459
|
+
get committed(): boolean;
|
|
407
460
|
/**
|
|
408
461
|
* Throw away everything this stage has STAGED, without committing any of it.
|
|
409
462
|
*
|
|
@@ -429,14 +482,81 @@ export declare class StageContext {
|
|
|
429
482
|
* holds bare references — dropping it un-clones nothing);
|
|
430
483
|
* - `_untrackedSources` — the D2 honesty markers, released with the rest.
|
|
431
484
|
*
|
|
432
|
-
* What is deliberately KEPT: `debug` (logs, metrics, errors, flow messages)
|
|
433
|
-
*
|
|
434
|
-
* retry feature's whole point is that the earlier
|
|
485
|
+
* What is deliberately KEPT: `debug` (logs, metrics, errors, flow messages)
|
|
486
|
+
* and the attempt records (10.1). Both are the append-only record of what
|
|
487
|
+
* every attempt did, and the retry feature's whole point is that the earlier
|
|
488
|
+
* attempts stay visible.
|
|
435
489
|
*
|
|
436
490
|
* No commit is recorded and no observer fires — a discarded attempt is not a
|
|
437
491
|
* cursor stop, because from shared state's point of view it never happened.
|
|
438
492
|
*/
|
|
439
493
|
discardStaged(): void;
|
|
494
|
+
/** Append one attempt's record — the attempt runner calls this as each attempt ends. */
|
|
495
|
+
recordAttempt(record: AttemptRecord): void;
|
|
496
|
+
/** Stamp the series' summary — once, when the runner ends the series. */
|
|
497
|
+
endAttempts(summary: AttemptSummary): void;
|
|
498
|
+
/** Reset only at the node's execution stamp, never between attempts. */
|
|
499
|
+
beginAttention(): void;
|
|
500
|
+
/** Delegate the explicit retained-error fact; attention owns validation of its proof. */
|
|
501
|
+
markStageFailure(): void;
|
|
502
|
+
/**
|
|
503
|
+
* The crash-safe record (10.1, P6): an attempt that ended is noted in the run's sink AT ONCE, beside this frame's
|
|
504
|
+
* log — so a process killed before the stage commits (mid-retry) still leaves every attempt that ended. The
|
|
505
|
+
* record is the one the tree keeps: frozen, `structuredClone`-safe, its error the SERVED form (no `raw`), so the
|
|
506
|
+
* note needs no second redaction pass. Without a sink the log does nothing (`EventLog · note`).
|
|
507
|
+
*/
|
|
508
|
+
private noteAttempt;
|
|
509
|
+
/** The attempts of this execution so far, in order — its own and its calls'; `undefined` when there are none. */
|
|
510
|
+
get attempts(): readonly AttemptRecord[] | undefined;
|
|
511
|
+
/** The ended series' summary; `undefined` while it runs and without a policy. */
|
|
512
|
+
get attemptSummary(): AttemptSummary | undefined;
|
|
513
|
+
/** The attempt about to run (and the run's signal) — `StageRunner` sets both before it builds the scope. */
|
|
514
|
+
useAttempt(attempt: AttemptContext | undefined, runSignal: AbortSignal | undefined): void;
|
|
515
|
+
/** The attempt now running; `undefined` for a stage the attempt runner does not run. */
|
|
516
|
+
get attempt(): AttemptContext | undefined;
|
|
517
|
+
/** The run's signal, as `StageRunner` last saw it. */
|
|
518
|
+
get runSignal(): AbortSignal | undefined;
|
|
519
|
+
/**
|
|
520
|
+
* Attempt `attempt` ended without an answer: from now on its scope is fenced — a write, an emit or a read
|
|
521
|
+
* through it is refused (`ScopeFacade`). The runner calls this the moment the attempt's signal aborts.
|
|
522
|
+
*/
|
|
523
|
+
endAttempt(attempt: number): void;
|
|
524
|
+
/** Whether attempt `attempt` has ended — its scope may no longer touch the stage. */
|
|
525
|
+
hasAttemptEnded(attempt: number): boolean;
|
|
526
|
+
/** Record a write an ended attempt tried — a name, never the value. Append-only evidence like the attempts. */
|
|
527
|
+
recordLateWrite(write: LateWrite): void;
|
|
528
|
+
/** This execution's own idempotency key may be made of a selected value (or was carried by a checkpoint). */
|
|
529
|
+
private _effectKeyTainted;
|
|
530
|
+
/** A touching `$call` with NO key started in this execution — the stage may not be re-run by a resume. */
|
|
531
|
+
private _keylessEffect;
|
|
532
|
+
/**
|
|
533
|
+
* Start an execution's side-effect bookkeeping (`FlowchartTraverser · executeStage`, before attempt 1) — reset,
|
|
534
|
+
* because a frame can be re-used by a later execution. `keyTainted`: the stage's own key may be made of a selected
|
|
535
|
+
* value, so a key a `$call` passes on (`$attempt().idempotencyKey`) is served the same way.
|
|
536
|
+
*/
|
|
537
|
+
beginEffects(keyTainted: boolean): void;
|
|
538
|
+
get effectKeyTainted(): boolean;
|
|
539
|
+
/** A keyless touching `$call` started: an `interrupt()` after it would re-send it on resume (`StageRunner`). */
|
|
540
|
+
markKeylessEffect(): void;
|
|
541
|
+
get hasKeylessEffect(): boolean;
|
|
542
|
+
/** Where this execution's call records are reported — the engine sets it before the stage runs. */
|
|
543
|
+
useAttemptReporter(report: ((record: AttemptRecord, structuredError: StructuredErrorInfo | undefined) => void) | undefined): void;
|
|
544
|
+
/**
|
|
545
|
+
* The signal the calls of stage attempt `stageAttempt` run under besides its own (P2): aborted when that attempt is
|
|
546
|
+
* over — however it ended — and when the frame commits, so no call outlives the attempt that made it (no
|
|
547
|
+
* background retry, no wait, no listener left on the run's signal). Already aborted after the commit.
|
|
548
|
+
*/
|
|
549
|
+
callsEndedSignal(stageAttempt: number): AbortSignal;
|
|
550
|
+
/** End the calls of `stageAttempt` (every attempt's when `undefined`) — `reason` when the attempt's signal gave one. */
|
|
551
|
+
private endCalls;
|
|
552
|
+
/** The next call's ordinal within stage attempt `stageAttempt`, 1-based (`attempt/call.ts · callSeries`). */
|
|
553
|
+
nextCallOrdinal(stageAttempt: number): number;
|
|
554
|
+
/**
|
|
555
|
+
* A call's (or an observed) attempt record: kept beside the stage's own attempts — the first
|
|
556
|
+
* {@link MAX_CALL_RECORDS}, the rest counted — and reported to the run's `onAttempt` either way. Like the stage's
|
|
557
|
+
* records, NOT cleared by {@link discardStaged}: a failed attempt's calls are evidence too.
|
|
558
|
+
*/
|
|
559
|
+
reportCallAttempt(record: AttemptRecord, structuredError: StructuredErrorInfo | undefined): void;
|
|
440
560
|
/**
|
|
441
561
|
* Create (or return) this context's linked successor.
|
|
442
562
|
*
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Engine-owned attention is collected with retained facts; snapshots only copy this bounded projection. */
|
|
2
|
+
import type { Attention } from 'foottrace';
|
|
3
|
+
import type { AttemptRecord, AttemptSummary } from '../attempt/types.js';
|
|
4
|
+
/** One execution's ownership, pending summary, marks and omission accounting stay in this helper. */
|
|
5
|
+
export declare class StageAttention {
|
|
6
|
+
private marks?;
|
|
7
|
+
private omitted;
|
|
8
|
+
private retryPossible;
|
|
9
|
+
private summary?;
|
|
10
|
+
private terminal?;
|
|
11
|
+
/** A new execution starts fresh; an attempt discard never calls this. No collection is reconstructed. */
|
|
12
|
+
begin(): void;
|
|
13
|
+
/** Called only after the frame retained this attempt. Raw error, target and decision payloads are never read. */
|
|
14
|
+
recordAttempt(record: AttemptRecord, owner: string): void;
|
|
15
|
+
recordSummary(summary: AttemptSummary): void;
|
|
16
|
+
/** A summary-only cut wait has no phantom final attempt; use its actual retained summary. */
|
|
17
|
+
private projectSummary;
|
|
18
|
+
/** Only the explicit retained stage-error path calls this; a diagnostic value never classifies itself. */
|
|
19
|
+
stageFailed(errors: unknown): void;
|
|
20
|
+
attemptDropped(): void;
|
|
21
|
+
/** Keep only bounded exact references; one slot is reserved to disclose omissions. */
|
|
22
|
+
append(attention: Attention): void;
|
|
23
|
+
missing(): void;
|
|
24
|
+
/** Copy already collected bounded marks, never an attempt array, diagnostic bag or execution tree. */
|
|
25
|
+
snapshot(): readonly Attention[];
|
|
26
|
+
}
|
|
@@ -47,6 +47,14 @@ export declare function firstDifferingPath(before: unknown, after: unknown, pref
|
|
|
47
47
|
* path names it); this text names the stage the handle came from.
|
|
48
48
|
*/
|
|
49
49
|
export declare function deadFrameMessage(stageName: string, runtimeStageId: string | undefined, key: string): string;
|
|
50
|
+
/**
|
|
51
|
+
* The refusal raised in an attempt that has ENDED (P1b) — timed out, aborted or
|
|
52
|
+
* failed — when the function behind it touches its scope anyway. The engine
|
|
53
|
+
* stopped waiting for it; whatever it does now would land beside a later
|
|
54
|
+
* attempt (or after the stage's commit), so it is refused. A write or emit is
|
|
55
|
+
* recorded on the stage (`StageSnapshot.lateWrites`) before this is thrown.
|
|
56
|
+
*/
|
|
57
|
+
export declare function lateAttemptMessage(stageName: string, series: string, attempt: number, key: string): string;
|
|
50
58
|
/**
|
|
51
59
|
* The warning text for a key the stage WROTE after changing, in place, the
|
|
52
60
|
* committed value it had read before its first write (copy-on-write, 9.29.0).
|
|
@@ -7,9 +7,13 @@
|
|
|
7
7
|
* in the record's `types.ts` until C6; the record names nothing outside itself now
|
|
8
8
|
* (`RECORD_FILES`, scripts/layering.config.cjs), so they sit beside the frame that writes them.
|
|
9
9
|
*
|
|
10
|
+
* A retried stage's node also carries its attempts (`attempts`, `attemptSummary` — the attempt leaf's types, L0).
|
|
11
|
+
*
|
|
10
12
|
* A `StageSnapshot` is an `ExecutionTree` (`types.ts`), the shape the record's readers walk:
|
|
11
13
|
* `commitStops`, `tagStops` and `keysReadFromExecutionTree` take one.
|
|
12
14
|
*/
|
|
15
|
+
import type { Attention } from 'foottrace';
|
|
16
|
+
import type { AttemptRecord, AttemptSummary, LateWrite } from '../attempt/types.js';
|
|
13
17
|
import type { RetentionPolicy } from '../capture/policies.js';
|
|
14
18
|
/** Types of control flow decisions captured by the execution engine. */
|
|
15
19
|
export type FlowControlType = 'next' | 'branch' | 'children' | 'selected' | 'subflow' | 'loop';
|
|
@@ -93,6 +97,40 @@ export type StageSnapshot = {
|
|
|
93
97
|
metrics: Record<string, unknown>;
|
|
94
98
|
evals: Record<string, unknown>;
|
|
95
99
|
flowMessages?: FlowMessage[];
|
|
100
|
+
/**
|
|
101
|
+
* Every attempt of this execution, in order — when it started, how long it took, how it ended, and the
|
|
102
|
+
* retry-or-stop decision that followed (`AttemptRecord`): the stage's own under its retry policy, a `timeoutMs`
|
|
103
|
+
* or a run deadline (10.1, `kind: 'stage'`), and those of the calls it made through `scope.$call` and the
|
|
104
|
+
* outside attempts it reported through `observed()` (P2, `kind: 'call'` / `'observed'`, the first 1000 —
|
|
105
|
+
* `StageContext · MAX_CALL_RECORDS`). Absent when there are none. The commit log never carries attempts: a
|
|
106
|
+
* retried stage is still ONE bundle.
|
|
107
|
+
*/
|
|
108
|
+
attempts?: readonly AttemptRecord[];
|
|
109
|
+
/**
|
|
110
|
+
* Call and observed attempt records this execution made past the first 1000 — counted, not kept (each still
|
|
111
|
+
* fired `onAttempt`). Absent when none were dropped.
|
|
112
|
+
*/
|
|
113
|
+
attemptsDropped?: number;
|
|
114
|
+
/**
|
|
115
|
+
* The series at a glance — counts per outcome, and how it ended. Stamped when the series ends: absent while it
|
|
116
|
+
* is still running (a snapshot taken mid-stage) and without a policy.
|
|
117
|
+
*/
|
|
118
|
+
attemptSummary?: AttemptSummary;
|
|
119
|
+
/**
|
|
120
|
+
* Writes (and emits) an attempt tried AFTER it had ended — timed out, aborted or failed — in the order they came
|
|
121
|
+
* (P1b). Each was dropped at the scope, so none reached the stage's buffer, its commit or a recorder; this is
|
|
122
|
+
* the record that they were tried — the first 100 (`MAX_LATE_WRITES`). An abandoned function can keep running
|
|
123
|
+
* after the run ended, so the list can grow after a snapshot was taken. Names only, never values. Absent when
|
|
124
|
+
* there were none.
|
|
125
|
+
*/
|
|
126
|
+
lateWrites?: readonly LateWrite[];
|
|
127
|
+
/**
|
|
128
|
+
* Fixed-reason marks collected as this execution runs. Absent when no fact needs attention.
|
|
129
|
+
* Attempt evidence uses canonical Foottrace attempt IDs. Summary-only and stage-error proof resolves within THIS node
|
|
130
|
+
* through attemptSummary, errors:stageExecutionError or attemptsDropped. Quality marks are read-time recorder work.
|
|
131
|
+
* Marks retain no error text, values, targets or idempotency keys; omitted proof is disclosed as not-collected.
|
|
132
|
+
*/
|
|
133
|
+
attention?: readonly Attention[];
|
|
96
134
|
next?: StageSnapshot;
|
|
97
135
|
children?: StageSnapshot[];
|
|
98
136
|
};
|
|
@@ -224,6 +224,18 @@ export declare class RedactionRule {
|
|
|
224
224
|
* channel) applies on top. Clear values keep their identity.
|
|
225
225
|
*/
|
|
226
226
|
retainDiagnostic(address: readonly string[], value: unknown): unknown;
|
|
227
|
+
/**
|
|
228
|
+
* An idempotency key as records serve it (P3, design §6). The key is a VALUE, and the documented way to make one
|
|
229
|
+
* is from the input or the state (`order-${args.orderId}`) — so it is selected by its NAME (the diagnostic entry
|
|
230
|
+
* `{ idempotencyKey }`: a state rule of that name, or `policy.diagnostics` at `logs.idempotencyKey`) AND by its
|
|
231
|
+
* SOURCES, conservatively, the subflow-mapper taint law's way: when the input it may be derived from holds a
|
|
232
|
+
* selected key at any depth, or the stage read a selected value before making it (`selectedReads`), it is served
|
|
233
|
+
* whole as the placeholder. Never value equality. An inert rule never reads it.
|
|
234
|
+
*/
|
|
235
|
+
retainIdempotencyKey(key: string, sources: {
|
|
236
|
+
readonly input?: unknown;
|
|
237
|
+
readonly selectedReads?: number;
|
|
238
|
+
}): string;
|
|
227
239
|
/**
|
|
228
240
|
* Retain flow-message text (`flowMessages.description` / `.rationale`): text
|
|
229
241
|
* the engine composes has no name of its own, so no state selector reaches
|
|
@@ -114,6 +114,8 @@ export declare class PauseSignal extends Error {
|
|
|
114
114
|
* (`completeExecution`), or both carried over for a queued sibling.
|
|
115
115
|
*/
|
|
116
116
|
private _pausedExecution?;
|
|
117
|
+
/** The paused execution's idempotency key (P3) — a touching stage's, stamped once at the stage boundary. */
|
|
118
|
+
private _idempotencyKey?;
|
|
117
119
|
constructor(data: unknown, stageId: string, pausedBy?: 'interrupt');
|
|
118
120
|
get subflowPath(): readonly string[];
|
|
119
121
|
/** The paused execution (its run and `[path/]stageId#N`), once both are known. */
|
|
@@ -125,6 +127,13 @@ export declare class PauseSignal extends Error {
|
|
|
125
127
|
* carries both (it paused in an EARLIER run).
|
|
126
128
|
*/
|
|
127
129
|
stampExecution(runtimeStageId: string, runId?: string): void;
|
|
130
|
+
/**
|
|
131
|
+
* The idempotency key the paused execution ran under (P3) — a touching stage's. It rides the checkpoint so the
|
|
132
|
+
* resume re-runs the stage (or its `resumeFn`) under the SAME key: the input its rule read does not cross a
|
|
133
|
+
* resume. First stamp wins.
|
|
134
|
+
*/
|
|
135
|
+
get idempotencyKey(): string | undefined;
|
|
136
|
+
stampIdempotencyKey(key: string | undefined): void;
|
|
128
137
|
/**
|
|
129
138
|
* Name the run for every pause on this signal that paused in it — this one
|
|
130
139
|
* and its queued siblings that do not already carry a run (a sibling raised
|
|
@@ -213,6 +222,8 @@ export interface PendingPause {
|
|
|
213
222
|
readonly pausedBy?: 'interrupt';
|
|
214
223
|
/** Which execution the sibling paused in (as `pausedExecution`, 9.37.0) — kept so its own resume links to it. */
|
|
215
224
|
readonly pausedExecution?: PausedExecution;
|
|
225
|
+
/** The idempotency key the sibling's execution ran under (as `idempotencyKey`, 10.1). */
|
|
226
|
+
readonly idempotencyKey?: string;
|
|
216
227
|
}
|
|
217
228
|
/**
|
|
218
229
|
* Returned by a pausable stage's execute/resume function to signal pause.
|
|
@@ -277,6 +288,14 @@ export interface FlowchartCheckpoint {
|
|
|
277
288
|
* which then resumes without a link.
|
|
278
289
|
*/
|
|
279
290
|
readonly pausedExecution?: PausedExecution;
|
|
291
|
+
/**
|
|
292
|
+
* The idempotency key the paused execution ran under (10.1) — present only when the paused stage `touches` an
|
|
293
|
+
* outside system with a key rule. `resume()` re-runs the stage (or runs its `resumeFn`) under THIS key, never a
|
|
294
|
+
* recomputed one: the input the rule read does not cross a resume, and a different key on the re-run would make
|
|
295
|
+
* the outside system apply the effect twice. A real value, like `sharedState` — no redaction policy touches the
|
|
296
|
+
* checkpoint. A malformed one is refused at `resume()`.
|
|
297
|
+
*/
|
|
298
|
+
readonly idempotencyKey?: string;
|
|
280
299
|
/** Path through subflows to the paused stage (e.g., ['sf-payment', 'sf-validation']).
|
|
281
300
|
* Empty array when paused at the top level. */
|
|
282
301
|
readonly subflowPath: readonly string[];
|
|
@@ -7,6 +7,9 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Dependency: type-only imports from engine/ and scope/ (zero runtime cost).
|
|
9
9
|
*/
|
|
10
|
+
import type { AttemptContext, CallOptions, RetryPolicy } from '../attempt/types.js';
|
|
11
|
+
import type { FlowChart } from '../builder/types.js';
|
|
12
|
+
import type { DetachDriver, DetachHandle } from '../detach/types.js';
|
|
10
13
|
import type { ExecutionEnv } from '../engine/types.js';
|
|
11
14
|
import type { ScopeRecorder } from '../scope/types.js';
|
|
12
15
|
export interface ReactiveTarget {
|
|
@@ -27,6 +30,10 @@ export interface ReactiveTarget {
|
|
|
27
30
|
getValueSilent?(key?: string): unknown;
|
|
28
31
|
getArgs<T = Record<string, unknown>>(): T;
|
|
29
32
|
getEnv(): Readonly<ExecutionEnv>;
|
|
33
|
+
/** The attempt the stage function runs in — its signal, its cap and the time left (P1b). */
|
|
34
|
+
getAttempt(): AttemptContext;
|
|
35
|
+
/** A call to an outside system on the attempt runner, recorded under this stage (P2). */
|
|
36
|
+
call<R>(target: string, fn: (attempt: AttemptContext) => Promise<R> | R, policy?: RetryPolicy, options?: CallOptions): Promise<R>;
|
|
30
37
|
attachScopeRecorder(recorder: ScopeRecorder): void;
|
|
31
38
|
detachScopeRecorder(recorderId: string): void;
|
|
32
39
|
getScopeRecorders(): ScopeRecorder[];
|
|
@@ -36,8 +43,8 @@ export interface ReactiveTarget {
|
|
|
36
43
|
addMetric(name: string, value: unknown): void;
|
|
37
44
|
addEval(name: string, value: unknown): void;
|
|
38
45
|
emitEvent(name: string, payload?: unknown): void;
|
|
39
|
-
detachAndJoinLater(driver:
|
|
40
|
-
detachAndForget(driver:
|
|
46
|
+
detachAndJoinLater(driver: DetachDriver, child: FlowChart, input?: unknown): DetachHandle;
|
|
47
|
+
detachAndForget(driver: DetachDriver, child: FlowChart, input?: unknown): void;
|
|
41
48
|
}
|
|
42
49
|
export interface ScopeMethods {
|
|
43
50
|
$getValue(key: string): unknown;
|
|
@@ -48,6 +55,31 @@ export interface ScopeMethods {
|
|
|
48
55
|
$read(dotPath: string): unknown;
|
|
49
56
|
$getArgs<T = Record<string, unknown>>(): T;
|
|
50
57
|
$getEnv(): Readonly<ExecutionEnv>;
|
|
58
|
+
/**
|
|
59
|
+
* The attempt this stage function runs in (P1b): `attempt` / `of`, the `signal` to pass to `fetch` and SDK
|
|
60
|
+
* calls (it aborts at the attempt's cap, the run's deadline, or a cancellation), and `timeLeftMs()` — the
|
|
61
|
+
* milliseconds before the run's deadline (`Infinity` without one; reading it with a deadline marks the stage's
|
|
62
|
+
* commit `untrackedSources: ['env']`). A stage with no retry policy and no deadline is attempt 1 of 1.
|
|
63
|
+
*/
|
|
64
|
+
$attempt(): AttemptContext;
|
|
65
|
+
/**
|
|
66
|
+
* A call to an outside system, made inside this stage (P2): `fn` runs on the attempt runner under `policy`
|
|
67
|
+
* (none = ONE attempt — still recorded), and every attempt is an `AttemptRecord` of kind `'call'` on this
|
|
68
|
+
* stage's node and on `onAttempt`, with its timing, outcome, category and decision. It runs under this stage
|
|
69
|
+
* attempt's time and signal — pass `t.signal` on. `target` is a NAME from code (1–128 characters, no control
|
|
70
|
+
* character), never a value. A malformed call (target, `fn`, policy) or one from an attempt that already ended
|
|
71
|
+
* THROWS at the call, synchronously, like every scope refusal — it is the stage's code breaking its contract; a
|
|
72
|
+
* call that runs and fails REJECTS with its last attempt's own error. A call that changes an outside system
|
|
73
|
+
* declares it in `options` (`{ touches, idempotencyKey }`, P3): a touching call that may retry needs a key, every
|
|
74
|
+
* record carries its `effect`, and a call that ends without an answer after any attempt of unknown effect rejects
|
|
75
|
+
* with `UnknownEffectError`.
|
|
76
|
+
*
|
|
77
|
+
* ```typescript
|
|
78
|
+
* const quote = await scope.$call('stripe.quotes.create', (t) => stripe.quotes.create(body, { signal: t.signal }),
|
|
79
|
+
* { attempts: 3, timeoutMs: 10_000 });
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
$call<R>(target: string, fn: (attempt: AttemptContext) => Promise<R> | R, policy?: RetryPolicy, options?: CallOptions): Promise<R>;
|
|
51
83
|
$debug(key: string, value: unknown): void;
|
|
52
84
|
$log(value: unknown): void;
|
|
53
85
|
$error(key: string, value: unknown): void;
|
|
@@ -129,8 +161,8 @@ export interface ScopeMethods {
|
|
|
129
161
|
* ```
|
|
130
162
|
*/
|
|
131
163
|
$emit(name: string, payload?: unknown): void;
|
|
132
|
-
$detachAndJoinLater(driver:
|
|
133
|
-
$detachAndForget(driver:
|
|
164
|
+
$detachAndJoinLater(driver: DetachDriver, child: FlowChart, input?: unknown): DetachHandle;
|
|
165
|
+
$detachAndForget(driver: DetachDriver, child: FlowChart, input?: unknown): void;
|
|
134
166
|
/**
|
|
135
167
|
* Stop the current execution context.
|
|
136
168
|
*
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { FlowAttemptEvent, FlowDecisionEvent, FlowPauseEvent, FlowRecorder, FlowRunEvent, FlowRunFailedEvent } from '../engine/narrative/types.js';
|
|
2
|
+
import type { AttemptAggregate, AttemptDecisionRow, AttemptQuery, AttemptRecorderOptions, AttemptStorageStats, AttemptStore, PhysicalAttemptRow } from './attemptMetricsTypes.js';
|
|
3
|
+
export declare class AttemptRecorder implements FlowRecorder {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
private readonly rows;
|
|
6
|
+
private readonly logical;
|
|
7
|
+
private readonly starts;
|
|
8
|
+
private reads;
|
|
9
|
+
private readonly pending;
|
|
10
|
+
private readonly exemplars;
|
|
11
|
+
private readonly maxRows;
|
|
12
|
+
private readonly maxPending;
|
|
13
|
+
private readonly timeoutMs;
|
|
14
|
+
private readonly store?;
|
|
15
|
+
private failed;
|
|
16
|
+
private dropped;
|
|
17
|
+
private omittedRows;
|
|
18
|
+
constructor(options?: AttemptRecorderOptions);
|
|
19
|
+
onRunStart(event: FlowRunEvent): void;
|
|
20
|
+
onRunEnd(event: FlowRunEvent): void;
|
|
21
|
+
onPause(event: FlowPauseEvent): void;
|
|
22
|
+
onRunFailed(event: FlowRunFailedEvent): void;
|
|
23
|
+
private end;
|
|
24
|
+
onAttempt(event: FlowAttemptEvent): void;
|
|
25
|
+
onDecision(event: FlowDecisionEvent): void;
|
|
26
|
+
private collect;
|
|
27
|
+
storage(): AttemptStorageStats;
|
|
28
|
+
flush(): Promise<AttemptStorageStats>;
|
|
29
|
+
byTarget(): AttemptAggregate['byTarget'];
|
|
30
|
+
byRun(): AttemptAggregate['byRun'];
|
|
31
|
+
slowest(target: string, limit?: number): import("./attemptMetricsTypes.js").AttemptMetricRef[];
|
|
32
|
+
series(series: string, runId?: string): {
|
|
33
|
+
attempts: PhysicalAttemptRow[];
|
|
34
|
+
decisions: AttemptDecisionRow[];
|
|
35
|
+
};
|
|
36
|
+
aggregate(supplied?: AttemptQuery): Promise<AttemptAggregate>;
|
|
37
|
+
private readStored;
|
|
38
|
+
toSnapshot(): {
|
|
39
|
+
name: string;
|
|
40
|
+
data: {
|
|
41
|
+
byTarget: Map<string, import("./attemptMetricsTypes.js").AttemptStats>;
|
|
42
|
+
byRun: Map<string, import("./attemptMetricsTypes.js").AttemptRunStats>;
|
|
43
|
+
};
|
|
44
|
+
meta: {
|
|
45
|
+
projection: string;
|
|
46
|
+
exemplars: number;
|
|
47
|
+
rows: number;
|
|
48
|
+
maxRows: number;
|
|
49
|
+
storage: AttemptStorageStats;
|
|
50
|
+
workTime: string;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
toOTel(): {
|
|
54
|
+
resourceMetrics: {
|
|
55
|
+
resource: {
|
|
56
|
+
attributes: never[];
|
|
57
|
+
};
|
|
58
|
+
scopeMetrics: {
|
|
59
|
+
scope: {
|
|
60
|
+
name: string;
|
|
61
|
+
};
|
|
62
|
+
metrics: ({
|
|
63
|
+
name: string;
|
|
64
|
+
unit: string;
|
|
65
|
+
description: string;
|
|
66
|
+
histogram: {
|
|
67
|
+
aggregationTemporality: number;
|
|
68
|
+
dataPoints: {
|
|
69
|
+
attributes: {
|
|
70
|
+
key: string;
|
|
71
|
+
value: {
|
|
72
|
+
stringValue: string;
|
|
73
|
+
};
|
|
74
|
+
}[];
|
|
75
|
+
startTimeUnixNano: string;
|
|
76
|
+
timeUnixNano: string;
|
|
77
|
+
count: string;
|
|
78
|
+
sum: number;
|
|
79
|
+
explicitBounds: number[];
|
|
80
|
+
bucketCounts: string[];
|
|
81
|
+
exemplars: {
|
|
82
|
+
traceId?: string | undefined;
|
|
83
|
+
asDouble: number;
|
|
84
|
+
timeUnixNano: string;
|
|
85
|
+
filteredAttributes: {
|
|
86
|
+
key: string;
|
|
87
|
+
value: {
|
|
88
|
+
stringValue: string;
|
|
89
|
+
};
|
|
90
|
+
}[];
|
|
91
|
+
}[];
|
|
92
|
+
}[];
|
|
93
|
+
};
|
|
94
|
+
sum?: undefined;
|
|
95
|
+
} | {
|
|
96
|
+
name: string;
|
|
97
|
+
unit: string;
|
|
98
|
+
sum: {
|
|
99
|
+
aggregationTemporality: number;
|
|
100
|
+
isMonotonic: boolean;
|
|
101
|
+
dataPoints: {
|
|
102
|
+
attributes: {
|
|
103
|
+
key: string;
|
|
104
|
+
value: {
|
|
105
|
+
stringValue: string;
|
|
106
|
+
};
|
|
107
|
+
}[];
|
|
108
|
+
startTimeUnixNano: string;
|
|
109
|
+
timeUnixNano: string;
|
|
110
|
+
asDouble: number;
|
|
111
|
+
exemplars: {
|
|
112
|
+
asDouble: number;
|
|
113
|
+
traceId?: string | undefined;
|
|
114
|
+
timeUnixNano: string;
|
|
115
|
+
filteredAttributes: {
|
|
116
|
+
key: string;
|
|
117
|
+
value: {
|
|
118
|
+
stringValue: string;
|
|
119
|
+
};
|
|
120
|
+
}[];
|
|
121
|
+
}[];
|
|
122
|
+
}[];
|
|
123
|
+
};
|
|
124
|
+
description?: undefined;
|
|
125
|
+
histogram?: undefined;
|
|
126
|
+
})[];
|
|
127
|
+
}[];
|
|
128
|
+
}[];
|
|
129
|
+
};
|
|
130
|
+
/** Clear completed local projections; active/paused evidence and bounded ownership survive executor auto-clear. */
|
|
131
|
+
clear(): void;
|
|
132
|
+
}
|
|
133
|
+
/** Bounded reference adapter for tests/local use; apps supply their own database adapter. */
|
|
134
|
+
export declare function memoryStore(options?: {
|
|
135
|
+
readonly maxRows?: number;
|
|
136
|
+
}): AttemptStore & {
|
|
137
|
+
stats(): {
|
|
138
|
+
rows: number;
|
|
139
|
+
omittedRows: number;
|
|
140
|
+
};
|
|
141
|
+
};
|
|
@@ -27,6 +27,17 @@
|
|
|
27
27
|
* completing consumes its slot via `onError`, so the post-fan-out
|
|
28
28
|
* convergence stage is never misattributed as a branch entry.
|
|
29
29
|
*
|
|
30
|
+
* 3. attempt stops (10.1) — `onAttempt`: a stage whose retry series STOPPED
|
|
31
|
+
* (it gave up, or a later attempt paused or was aborted; the shared
|
|
32
|
+
* predicate `recorder/attemptSeries.ts · isRetryEvidence`) made a decision of its
|
|
33
|
+
* own — the retry-or-stop decision, in the shape `decide()` produces. It
|
|
34
|
+
* is recorded beside the deciders as `kind: 'attempt-stop'`
|
|
35
|
+
* (`getDecisions()`, `getAttemptStop(id)`), `chosen: 'stop'`, the stop
|
|
36
|
+
* reason as its `ruleLabel`. It is NOT a branch entry: a control edge in
|
|
37
|
+
* `causalChain` links a stage to ANOTHER execution that governed it, and
|
|
38
|
+
* the stop governs the stage itself — so `lookup` is unchanged, and a
|
|
39
|
+
* reader walking a failed stage reads the stop off its decision record.
|
|
40
|
+
*
|
|
30
41
|
* `lookup(runtimeStageId)` then walks the ancestor chain from the stage
|
|
31
42
|
* upward; the first ancestor (or the stage itself) registered as a
|
|
32
43
|
* branch entry yields its governing decider — the NEAREST decision.
|
|
@@ -55,9 +66,15 @@ import { causalChain } from 'foottrace';
|
|
|
55
66
|
*/
|
|
56
67
|
import type { ControlDependency, ControlDepLookup } from 'foottrace';
|
|
57
68
|
import type { DecisionEvidence, SelectionEvidence } from '../decide/types.js';
|
|
58
|
-
import type { FlowDecisionEvent, FlowErrorEvent, FlowRecorder, FlowSelectedEvent, FlowStageEvent } from '../engine/narrative/types.js';
|
|
69
|
+
import type { FlowAttemptEvent, FlowDecisionEvent, FlowErrorEvent, FlowRecorder, FlowSelectedEvent, FlowStageEvent } from '../engine/narrative/types.js';
|
|
59
70
|
/** One recorded decision/selection event (RFC-003 D5). */
|
|
60
71
|
export interface ControlDecisionRecord {
|
|
72
|
+
/**
|
|
73
|
+
* `'attempt-stop'` for a stage's own retry-or-stop decision that STOPPED its series (10.1) — then
|
|
74
|
+
* `deciderRuntimeStageId` is the stage's execution, `chosen` is `'stop'`, `evidence` the attempt's decision and
|
|
75
|
+
* `ruleLabel` the stop reason. Absent for a decider / selector.
|
|
76
|
+
*/
|
|
77
|
+
kind?: 'attempt-stop';
|
|
61
78
|
/** runtimeStageId of the decider/selector execution step. */
|
|
62
79
|
deciderRuntimeStageId: string;
|
|
63
80
|
/** Chosen branch display name (decider) or selected names (selector). */
|
|
@@ -100,6 +117,7 @@ export declare class ControlDepRecorder implements FlowRecorder {
|
|
|
100
117
|
private lastRunId?;
|
|
101
118
|
constructor(options?: ControlDepRecorderOptions);
|
|
102
119
|
onDecision(event: FlowDecisionEvent): void;
|
|
120
|
+
onAttempt(event: FlowAttemptEvent): void;
|
|
103
121
|
onSelected(event: FlowSelectedEvent): void;
|
|
104
122
|
onStageExecuted(event: FlowStageEvent): void;
|
|
105
123
|
/**
|
|
@@ -118,8 +136,24 @@ export declare class ControlDepRecorder implements FlowRecorder {
|
|
|
118
136
|
lookup(runtimeStageId: string): ControlDependency | undefined;
|
|
119
137
|
/** The lookup as a bare function — plug into `causalChain(..., { controlDeps })`. */
|
|
120
138
|
asLookup(): ControlDepLookup;
|
|
121
|
-
/**
|
|
139
|
+
/** The attempt-stop decision of a stage execution whose retry series stopped, if it did. */
|
|
140
|
+
getAttemptStop(runtimeStageId: string): ControlDecisionRecord | undefined;
|
|
141
|
+
/** All decisions recorded for the current run, in event order — deciders, selectors and attempt stops. */
|
|
122
142
|
getDecisions(): ControlDecisionRecord[];
|
|
143
|
+
/**
|
|
144
|
+
* Current-run control evidence for the native snapshot. Project only the
|
|
145
|
+
* stage identities collected during traversal; never walk the execution tree.
|
|
146
|
+
* Parentless roots cannot have a governing control edge.
|
|
147
|
+
*/
|
|
148
|
+
toSnapshot(): {
|
|
149
|
+
name: string;
|
|
150
|
+
data: {
|
|
151
|
+
decisions: ControlDecisionRecord[];
|
|
152
|
+
controlDeps: {
|
|
153
|
+
[k: string]: ControlDependency;
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
};
|
|
123
157
|
/** Reset all state (also happens automatically on runId change). */
|
|
124
158
|
clear(): void;
|
|
125
159
|
/** Convention 4: a new runId means a new run — reset transient state. */
|