footprint-explainable-ui 0.18.0 → 0.19.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 (90) hide show
  1. package/dist/adapters/fromRuntimeSnapshot.d.ts +33 -4
  2. package/dist/adapters/fromRuntimeSnapshot.d.ts.map +1 -1
  3. package/dist/adapters/fromRuntimeSnapshot.js +162 -33
  4. package/dist/adapters/fromRuntimeSnapshot.js.map +1 -1
  5. package/dist/components/ExplainableShell/ExplainableShell.d.ts +157 -14
  6. package/dist/components/ExplainableShell/ExplainableShell.d.ts.map +1 -1
  7. package/dist/components/ExplainableShell/ExplainableShell.js +676 -68
  8. package/dist/components/ExplainableShell/ExplainableShell.js.map +1 -1
  9. package/dist/components/ExplainableShell/index.d.ts +1 -1
  10. package/dist/components/ExplainableShell/index.d.ts.map +1 -1
  11. package/dist/components/FlowchartView/SubflowTree.d.ts +7 -14
  12. package/dist/components/FlowchartView/SubflowTree.d.ts.map +1 -1
  13. package/dist/components/FlowchartView/SubflowTree.js +56 -46
  14. package/dist/components/FlowchartView/SubflowTree.js.map +1 -1
  15. package/dist/components/FlowchartView/index.d.ts +32 -4
  16. package/dist/components/FlowchartView/index.d.ts.map +1 -1
  17. package/dist/components/FlowchartView/index.js +22 -2
  18. package/dist/components/FlowchartView/index.js.map +1 -1
  19. package/dist/components/FlowchartView/useSubflowNavigation.d.ts +41 -16
  20. package/dist/components/FlowchartView/useSubflowNavigation.d.ts.map +1 -1
  21. package/dist/components/FlowchartView/useSubflowNavigation.js +69 -50
  22. package/dist/components/FlowchartView/useSubflowNavigation.js.map +1 -1
  23. package/dist/components/GanttTimeline/GanttTimeline.d.ts.map +1 -1
  24. package/dist/components/GanttTimeline/GanttTimeline.js +5 -5
  25. package/dist/components/GanttTimeline/GanttTimeline.js.map +1 -1
  26. package/dist/components/MemoryInspector/MemoryInspector.d.ts.map +1 -1
  27. package/dist/components/MemoryInspector/MemoryInspector.js +36 -13
  28. package/dist/components/MemoryInspector/MemoryInspector.js.map +1 -1
  29. package/dist/components/NarrativeTrace/NarrativeTrace.d.ts.map +1 -1
  30. package/dist/components/NarrativeTrace/NarrativeTrace.js +24 -17
  31. package/dist/components/NarrativeTrace/NarrativeTrace.js.map +1 -1
  32. package/dist/components/ScopeDiff/ScopeDiff.js +3 -3
  33. package/dist/components/ScopeDiff/ScopeDiff.js.map +1 -1
  34. package/dist/components/StageNode/StageNode.d.ts +21 -0
  35. package/dist/components/StageNode/StageNode.d.ts.map +1 -1
  36. package/dist/components/StageNode/StageNode.js +189 -9
  37. package/dist/components/StageNode/StageNode.js.map +1 -1
  38. package/dist/components/TimeTravelControls/TimeTravelControls.d.ts.map +1 -1
  39. package/dist/components/TimeTravelControls/TimeTravelControls.js +19 -3
  40. package/dist/components/TimeTravelControls/TimeTravelControls.js.map +1 -1
  41. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.d.ts +19 -8
  42. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.d.ts.map +1 -1
  43. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.js +23 -8
  44. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.js.map +1 -1
  45. package/dist/flowchart.cjs +3485 -1340
  46. package/dist/flowchart.cjs.map +1 -1
  47. package/dist/flowchart.d.cts +1616 -177
  48. package/dist/flowchart.d.ts +1616 -177
  49. package/dist/flowchart.d.ts.map +1 -1
  50. package/dist/flowchart.js +3507 -1384
  51. package/dist/flowchart.js.map +1 -1
  52. package/dist/index.cjs +749 -557
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.d.cts +276 -29
  55. package/dist/index.d.ts +276 -29
  56. package/dist/index.d.ts.map +1 -1
  57. package/dist/index.js +742 -547
  58. package/dist/index.js.map +1 -1
  59. package/dist/theme/ThemeProvider.d.ts +14 -0
  60. package/dist/theme/ThemeProvider.d.ts.map +1 -1
  61. package/dist/theme/ThemeProvider.js +15 -1
  62. package/dist/theme/ThemeProvider.js.map +1 -1
  63. package/dist/theme/index.d.ts +4 -2
  64. package/dist/theme/index.d.ts.map +1 -1
  65. package/dist/theme/index.js +3 -2
  66. package/dist/theme/index.js.map +1 -1
  67. package/dist/theme/presets.d.ts +3 -0
  68. package/dist/theme/presets.d.ts.map +1 -1
  69. package/dist/theme/presets.js +22 -0
  70. package/dist/theme/presets.js.map +1 -1
  71. package/dist/theme/tokens.d.ts +22 -1
  72. package/dist/theme/tokens.d.ts.map +1 -1
  73. package/dist/theme/tokens.js +23 -2
  74. package/dist/theme/tokens.js.map +1 -1
  75. package/dist/tsconfig.tsbuildinfo +1 -1
  76. package/dist/types.d.ts +25 -0
  77. package/dist/types.d.ts.map +1 -1
  78. package/package.json +4 -4
  79. package/dist/components/FlowchartView/FlowchartView.d.ts +0 -20
  80. package/dist/components/FlowchartView/FlowchartView.d.ts.map +0 -1
  81. package/dist/components/FlowchartView/FlowchartView.js +0 -80
  82. package/dist/components/FlowchartView/FlowchartView.js.map +0 -1
  83. package/dist/components/FlowchartView/TracedFlowchartView.d.ts +0 -20
  84. package/dist/components/FlowchartView/TracedFlowchartView.d.ts.map +0 -1
  85. package/dist/components/FlowchartView/TracedFlowchartView.js +0 -101
  86. package/dist/components/FlowchartView/TracedFlowchartView.js.map +0 -1
  87. package/dist/components/FlowchartView/specToReactFlow.d.ts +0 -56
  88. package/dist/components/FlowchartView/specToReactFlow.d.ts.map +0 -1
  89. package/dist/components/FlowchartView/specToReactFlow.js +0 -202
  90. package/dist/components/FlowchartView/specToReactFlow.js.map +0 -1
@@ -1,7 +1,59 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import * as _xyflow_react from '@xyflow/react';
3
- import { Node, Edge, NodeTypes } from '@xyflow/react';
4
1
  import * as react from 'react';
2
+ import * as _xyflow_react from '@xyflow/react';
3
+ import { Node, Edge } from '@xyflow/react';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+
6
+ interface StageNodeData {
7
+ label: string;
8
+ active?: boolean;
9
+ done?: boolean;
10
+ error?: boolean;
11
+ linked?: boolean;
12
+ /** Semantic icon hint (e.g., "llm", "tool", "rag", "start", "parse", "agent", "guard") */
13
+ icon?: string;
14
+ /** Step numbers in execution order (shown as badges — multiple when revisited via loops) */
15
+ stepNumbers?: number[];
16
+ /** Node was not executed (dim it) */
17
+ dimmed?: boolean;
18
+ /** Node is a subflow root (show nested indicator) */
19
+ isSubflow?: boolean;
20
+ /** Node uses lazy resolution (dashed border + cloud icon when unresolved) */
21
+ isLazy?: boolean;
22
+ /** Node is a decider (renders as diamond shape per flowchart convention) */
23
+ isDecider?: boolean;
24
+ /** Node is a fork (parallel fan-out) */
25
+ isFork?: boolean;
26
+ /** Human-readable description of what this stage does */
27
+ description?: string;
28
+ /** Subflow identifier — set when this node belongs to a subflow */
29
+ subflowId?: string;
30
+ /**
31
+ * Stable stage identifier from the spec (`SpecNode.id`). Renderable as a
32
+ * small monospace caption under the label when `showStageId` is true —
33
+ * useful for teaching the runtimeStageId convention and for debugging
34
+ * which node a recorder event belongs to.
35
+ */
36
+ stageId?: string;
37
+ /**
38
+ * When true, render the `stageId` as a small monospace caption beneath
39
+ * the label. Default false. Drives the "Show IDs" toggle in
40
+ * ExplainableShell.
41
+ */
42
+ showStageId?: boolean;
43
+ [key: string]: unknown;
44
+ }
45
+ /**
46
+ * Custom ReactFlow node for pipeline stages.
47
+ * All colors and fonts come from `--fp-*` CSS variables (via theme).
48
+ * Shows execution state via color, icon, step badge, and pulse animation.
49
+ */
50
+ declare const StageNode: react.NamedExoticComponent<Pick<_xyflow_react.Node<Record<string, unknown>, string | undefined>, "id" | "data" | "width" | "height" | "sourcePosition" | "targetPosition" | "dragHandle" | "parentId"> & Required<Pick<_xyflow_react.Node<Record<string, unknown>, string | undefined>, "type" | "dragging" | "zIndex" | "selectable" | "deletable" | "selected" | "draggable">> & {
51
+ isConnectable: boolean;
52
+ positionAbsoluteX: number;
53
+ positionAbsoluteY: number;
54
+ } & {
55
+ data: StageNodeData;
56
+ }>;
5
57
 
6
58
  /** Snapshot of a single pipeline stage — the core data shape for all components. */
7
59
  interface StageSnapshot {
@@ -42,164 +94,558 @@ interface BaseComponentProps {
42
94
  style?: React.CSSProperties;
43
95
  }
44
96
 
45
- interface FlowchartViewProps extends BaseComponentProps {
46
- /** ReactFlow nodes */
47
- nodes: Node[];
48
- /** ReactFlow edges */
49
- edges: Edge[];
50
- /** Optional snapshots for state-aware rendering (done/active coloring) */
51
- snapshots?: StageSnapshot[];
52
- /** Currently selected snapshot index (for state coloring) */
53
- selectedIndex?: number;
54
- /** Callback when a node is clicked */
55
- onNodeClick?: (index: number) => void;
56
- }
57
- /**
58
- * Pipeline flowchart visualization using ReactFlow.
59
- * When snapshots are provided, nodes are colored by execution state.
60
- */
61
- declare function FlowchartView({ nodes: rawNodes, edges: rawEdges, snapshots, selectedIndex, onNodeClick, unstyled, className, style, }: FlowchartViewProps): react_jsx_runtime.JSX.Element;
97
+ /**
98
+ * Branded types for translator key discipline.
99
+ *
100
+ * The footprintjs/trace contract uses two distinct identity strings:
101
+ *
102
+ * - **StageId**: the stable identifier the user picks at build time
103
+ * (e.g. `'load-order'`, `'check-inventory'`). Identity per chart spec.
104
+ *
105
+ * - **RuntimeStageId**: `[subflowPath/]stageId#executionIndex` — the
106
+ * per-execution identity. A loop visiting the same stage 3 times
107
+ * produces 3 distinct RuntimeStageIds with the same StageId base.
108
+ *
109
+ * Translator outputs index per-stage data by StageId (`Map<StageId, ...>`)
110
+ * AND per-execution data by RuntimeStageId (`Map<RuntimeStageId, ...>`).
111
+ * Both are `string` at runtime TypeScript can't distinguish them
112
+ * without help. Branded types make `byStageId.get(runtimeStageId)` a
113
+ * **compile-time error** instead of a silent `undefined` at runtime.
114
+ *
115
+ * Why branded types over wrapper classes
116
+ * ──────────────────────────────────────
117
+ * - Zero runtime cost (the brand exists only at the type level)
118
+ * - JSON-serializable as-is (no `toJSON` glue needed)
119
+ * - Interop with consumer code that uses raw `string` is one cast
120
+ * (`stageId as StageId`) when the consumer is sure of the source.
121
+ *
122
+ * Usage pattern
123
+ * ─────────────
124
+ * ```ts
125
+ * import type { StageId, RuntimeStageId } from './_internal/keys';
126
+ *
127
+ * // In a translator, when accepting input from a footprintjs event:
128
+ * const sid = event.stageId as StageId;
129
+ * const rsid = event.traversalContext.runtimeStageId as RuntimeStageId;
130
+ *
131
+ * // In a consumer reading from the index:
132
+ * const node = index.byStageId.get(stageId); // typechecks
133
+ * const node = index.byStageId.get(runtimeStageId); // TS ERROR ✓
134
+ * ```
135
+ *
136
+ * Helper to derive a StageId from a RuntimeStageId — strips `#N` suffix
137
+ * and optional subflow path. **Use only for DISPLAY**, NEVER for matching
138
+ * commitLog stageIds (see invariant I3 in `traceStructureRecorder.ts`).
139
+ */
140
+ /** Stable per-spec identifier (e.g. `'load-order'`). */
141
+ type StageId = string & {
142
+ readonly __brand: "StageId";
143
+ };
144
+ /** Per-execution identifier (e.g. `'load-order#0'` or `'sf-foo/inner#3'`). */
145
+ type RuntimeStageId = string & {
146
+ readonly __brand: "RuntimeStageId";
147
+ };
148
+ /**
149
+ * Tag a raw string as a `StageId`. Use at translator boundaries when
150
+ * ingesting from a footprintjs event payload (the source guarantees
151
+ * the string IS a stage id). Zero runtime cost.
152
+ */
153
+ declare function asStageId(s: string): StageId;
154
+ /**
155
+ * Tag a raw string as a `RuntimeStageId`. Use at translator boundaries
156
+ * when ingesting from a `traversalContext.runtimeStageId`. Zero
157
+ * runtime cost.
158
+ */
159
+ declare function asRuntimeStageId(s: string): RuntimeStageId;
62
160
 
63
- interface SpecNode {
64
- name: string;
65
- id?: string;
66
- type?: "stage" | "decider" | "selector" | "fork" | "streaming";
67
- /** Semantic icon hint rendered by StageNode. Common values:
68
- * "llm", "tool", "rag", "search", "parse", "start", "end", "loop",
69
- * "agent", "swarm", "guard", "stream", "memory" */
70
- icon?: string;
71
- description?: string;
72
- children?: SpecNode[];
73
- next?: SpecNode;
74
- branchIds?: string[];
75
- hasDecider?: boolean;
76
- hasSelector?: boolean;
77
- loopTarget?: string;
78
- isSubflowRoot?: boolean;
79
- subflowId?: string;
80
- subflowName?: string;
81
- subflowStructure?: SpecNode;
82
- /** True when this subflow uses lazy resolution (deferred until execution). */
83
- isLazy?: boolean;
161
+ /**
162
+ * traceStructureRecorder — event-driven xyflow Node[] + Edge[] collector.
163
+ *
164
+ * Implements footprintjs v6.0+ `StructureRecorder` interface. Accumulates
165
+ * an unpositioned graph (xyflow node + edge shape) as the chart is being
166
+ * built no spec tree walk required.
167
+ *
168
+ * Why event-driven
169
+ * ────────────────
170
+ * The recorder fires SYNCHRONOUSLY at every spec-mutation moment during
171
+ * construction. By the time `.build()` returns, the recorder's
172
+ * `getGraph()` returns the complete graph — zero extra walking
173
+ * (the "collect during traversal, never post-process" rule footprintjs
174
+ * documents in its core principle).
175
+ *
176
+ * Bonus: the same recorder shape can drive incremental UI updates if
177
+ * the builder is constructed asynchronously (e.g., a UI builder where
178
+ * each "add stage" click re-renders the live graph).
179
+ *
180
+ * Layout is a separate concern
181
+ * ────────────────────────────
182
+ * This module produces UNPOSITIONED nodes (no `position` field set;
183
+ * xyflow defaults to `{x: 0, y: 0}`). Apply a layout algorithm
184
+ * downstream — either:
185
+ *
186
+ * - a graph algorithm (dagre / elk / d3-force)
187
+ * - manual positioning via your own walk over `recorder.getGraph()`
188
+ *
189
+ * The `<TraceFlow>` component wires a default BFS layout.
190
+ *
191
+ * @example
192
+ * ```ts
193
+ * import { flowChart } from 'footprintjs';
194
+ * import { createTraceStructureRecorder } from 'footprint-explainable-ui/flowchart';
195
+ *
196
+ * const trace = createTraceStructureRecorder();
197
+ * const chart = flowChart('seed', fn, 'seed', {
198
+ * structureRecorders: [trace.recorder],
199
+ * })
200
+ * .addFunction('a', fnA, 'a')
201
+ * .build();
202
+ *
203
+ * const { nodes, edges } = trace.getGraph();
204
+ * // → nodes: [{ id: 'seed', data: { label: 'seed', ... } }, { id: 'a', ... }]
205
+ * // → edges: [{ id: 'seed->a', source: 'seed', target: 'a', data: { kind: 'next' } }]
206
+ *
207
+ * <ReactFlow nodes={layout(nodes)} edges={edges} />
208
+ * ```
209
+ */
210
+
211
+ type StructureNodeType = "stage" | "decider" | "selector" | "fork" | "streaming" | "subflow" | "loop";
212
+ interface StructureSpecRef {
213
+ readonly id: string;
214
+ readonly name: string;
215
+ readonly type?: StructureNodeType;
216
+ readonly description?: string;
217
+ readonly icon?: string;
218
+ readonly isSubflowRoot?: boolean;
219
+ readonly subflowId?: string;
220
+ readonly isLazy?: boolean;
221
+ readonly [key: string]: unknown;
222
+ }
223
+ interface StageAddedEvent {
224
+ readonly stageId: string;
225
+ readonly name: string;
226
+ readonly type: StructureNodeType;
227
+ readonly isPausable?: boolean;
228
+ readonly spec: StructureSpecRef;
229
+ }
230
+ type EdgeKind = "next" | "fork-branch" | "decision-branch";
231
+ interface EdgeAddedEvent {
232
+ readonly from: string;
233
+ readonly to: string;
234
+ readonly kind: EdgeKind;
235
+ readonly label?: string;
236
+ }
237
+ interface LoopEdgeAddedEvent {
238
+ readonly from: string;
239
+ readonly to: string;
240
+ }
241
+ interface DeciderCompleteEvent {
242
+ readonly decider: string;
243
+ readonly type: "decider" | "selector";
244
+ readonly branchIds: readonly string[];
245
+ readonly defaultBranch?: string;
246
+ }
247
+ interface SubflowMountedEvent {
248
+ readonly subflowId: string;
249
+ readonly subflowName: string;
250
+ readonly rootStageId: string;
251
+ readonly isLazy?: boolean;
252
+ /**
253
+ * The mounted subflow's complete spec — added in footprintjs v6.0
254
+ * (proposal #001). Present for eager mounts, UNDEFINED for lazy
255
+ * mounts (the subflow isn't resolved yet at mount-event-fire-time).
256
+ * When present, the consumer walks it to materialize inner nodes +
257
+ * edges directly with `subflowOf` set — no retroactive tagging
258
+ * needed.
259
+ *
260
+ * Typed as `unknown` because the upstream `SerializedPipelineStructure`
261
+ * shape has no index signature and we want to stay loosely-coupled
262
+ * (see top-of-file rationale for the no-`footprintjs`-dep boundary).
263
+ * `walkSubflowSpecInto` accepts the duck-typed shape it actually
264
+ * walks.
265
+ */
266
+ readonly subflowSpec?: unknown;
267
+ /**
268
+ * Local mount id within the parent (matches `subflowId` for top-level
269
+ * mounts; composed `'parent/child'` for nested). Tagged onto every
270
+ * inner stage's `data.subflowOf` during the walk.
271
+ */
272
+ readonly subflowPath?: string;
273
+ }
274
+ /**
275
+ * Minimal StructureRecorder interface — mirrors footprintjs v6.0+.
276
+ *
277
+ * Named with the `Minimal` prefix to make the local-mirror nature
278
+ * explicit at consumer call sites — a consumer importing both this
279
+ * type and the upstream `StructureRecorder` from `footprintjs` won't
280
+ * collide, and code reviewers see at a glance which boundary the type
281
+ * crosses.
282
+ *
283
+ * The upstream `footprintjs.StructureRecorder` is structurally
284
+ * compatible (this type's shape is a subset of upstream's), so passing
285
+ * an instance of this to `flowChart(..., { structureRecorders: [...] })`
286
+ * typechecks cleanly.
287
+ */
288
+ interface MinimalStructureRecorder {
289
+ readonly id: string;
290
+ onStageAdded?(event: StageAddedEvent): void;
291
+ onEdgeAdded?(event: EdgeAddedEvent): void;
292
+ onLoopEdgeAdded?(event: LoopEdgeAddedEvent): void;
293
+ onDeciderComplete?(event: DeciderCompleteEvent): void;
294
+ onSubflowMounted?(event: SubflowMountedEvent): void;
84
295
  }
85
- interface ExecutionOverlay {
86
- /** Names of stages that have completed (before the active one) */
87
- doneStages: Set<string>;
88
- /** Name of the currently active stage */
89
- activeStage: string | null;
90
- /** Names of all stages that were executed (done + active) */
91
- executedStages: Set<string>;
92
- /** Ordered list of executed stage names (for step numbering) */
93
- executionOrder?: string[];
94
- }
95
- /** Colors for the flowchart — consumer provides these to match their theme */
96
- interface FlowchartColors {
97
- edgeDefault: string;
98
- edgeExecuted: string;
99
- edgeActive: string;
100
- edgeLoop: string;
101
- labelDefault: string;
102
- labelExecuted: string;
103
- labelLoop: string;
104
- pathGlow: string;
105
- }
106
- /** A positioned node with all static info, before overlay is applied. */
107
- interface LayoutNode {
108
- id: string;
109
- x: number;
110
- y: number;
296
+ /**
297
+ * Per-node data attached to the xyflow `Node`. Consumed by the
298
+ * `StageNode` renderer (shape mirrors what the renderer expects).
299
+ */
300
+ interface TraceNodeData extends Record<string, unknown> {
111
301
  label: string;
112
302
  isDecider: boolean;
113
303
  isFork: boolean;
304
+ isSubflow: boolean;
305
+ /** True when the event carried `type: 'streaming'` (the spec was added
306
+ * via `addStreamingFunction`). Renderers that style streaming stages
307
+ * distinctly key on this flag. */
308
+ isStreaming: boolean;
114
309
  description?: string;
115
310
  icon?: string;
116
311
  subflowId?: string;
117
- isSubflow: boolean;
118
312
  isLazy?: boolean;
313
+ isPausable?: boolean;
314
+ /** Set later by `onDeciderComplete` when the decider's branch list is
315
+ * sealed. Useful for renderers that want to render decider with a
316
+ * branch-count badge. */
317
+ branchIds?: readonly string[];
318
+ defaultBranch?: string;
319
+ /**
320
+ * The subflow this node belongs to, OR `undefined` for top-level
321
+ * parent-chart stages. Tracked via a stack-based heuristic during
322
+ * event ingestion:
323
+ *
324
+ * - Push on `onSubflowMounted({subflowId, rootStageId})` →
325
+ * top-of-stack = `{subflowId, mountStageId}`
326
+ * - `onStageAdded` tags new nodes with the top-of-stack `subflowId`
327
+ * (the mount node itself stays UNtagged — it's part of the parent
328
+ * chain)
329
+ * - Pop on `onEdgeAdded` where `from === mount.id` (a mount's
330
+ * outgoing edge to a sibling means the parent chain has resumed);
331
+ * the wrongly-tagged target node is re-tagged to the parent scope
332
+ *
333
+ * Mount nodes (where `isSubflow=true`) have `subflowOf` reflecting
334
+ * their OWN parent context, NOT the subflow they mount. So a parent's
335
+ * mount node has `subflowOf=undefined` (top-level parent), and the
336
+ * subflow's INTERNAL stages have `subflowOf=<mount.subflowId>`.
337
+ *
338
+ * Renderers use this to filter the chart by drill-down level: show
339
+ * only nodes where `subflowOf === currentDrillSubflowId` (undefined
340
+ * for top-level view, mount.subflowId after drilling in).
341
+ */
342
+ subflowOf?: string;
343
+ /**
344
+ * **L8.0 — STRUCTURAL prev/next**: stage ids that lead into / out of
345
+ * this node, derived live from incoming/outgoing edges. Excludes
346
+ * `loop` back-edges (visual only — per invariant I1).
347
+ *
348
+ * Convergence-correct: a fork-join node carries an ENTRY per branch
349
+ * child (e.g., `FinalizeOrder.prevIds = ['CheckInventory', 'RunFraudCheck']`).
350
+ *
351
+ * "Structural" qualifier: this is the chart-SHAPE prev/next, not
352
+ * runtime execution order. For runtime ancestry use `CommitView`
353
+ * fields on `CommitFlowIndex` (L8.2).
354
+ */
355
+ prevIds: StageId[];
356
+ nextIds: StageId[];
119
357
  }
120
- /** A positioned edge with source/target info. */
121
- interface LayoutEdge {
122
- id: string;
123
- source: string;
124
- target: string;
358
+ /** Per-edge data attached to the xyflow `Edge`. */
359
+ interface TraceEdgeData extends Record<string, unknown> {
360
+ kind: EdgeKind | "loop";
125
361
  label?: string;
126
- isLoop: boolean;
127
362
  }
128
- /** Static layout output — positions + structure, no execution state. */
129
- interface SpecLayout {
130
- nodes: LayoutNode[];
131
- edges: LayoutEdge[];
132
- /** Maps stage ID → node id for resolving loopTarget references. */
133
- idToName: Map<string, string>;
363
+ type TraceNode = Node<TraceNodeData>;
364
+ type TraceEdge = Edge<TraceEdgeData>;
365
+ interface TraceGraph {
366
+ nodes: TraceNode[];
367
+ edges: TraceEdge[];
134
368
  }
369
+ interface TraceStructureRecorderHandle {
370
+ /** The recorder to register via `flowChart(..., { structureRecorders: [handle.recorder] })`
371
+ * or `.attachStructureRecorder(handle.recorder)`. */
372
+ recorder: MinimalStructureRecorder;
373
+ /** Returns a defensive copy of the current graph state. Safe to call
374
+ * multiple times; safe to mutate the returned arrays without affecting
375
+ * the recorder's internal state. */
376
+ getGraph(): TraceGraph;
377
+ /** Direct read-only access for hot-path consumers (Lens slider scrubbing).
378
+ * Returns the LIVE internal arrays — do NOT mutate. Prefer `getGraph()`
379
+ * unless you measure a performance cost. */
380
+ getGraphRef(): Readonly<TraceGraph>;
381
+ /**
382
+ * Subscribe to graph-change notifications. Pub-sub model — multiple
383
+ * listeners can subscribe; each fires after every event that mutates
384
+ * the graph (per-event, NOT batched). Returns an unsubscribe function.
385
+ * Designed for React's `useSyncExternalStore` consumption.
386
+ *
387
+ * Listeners are NOT invoked during `reset()`. **Consumer guidance**:
388
+ * if you need to clear a live `<TraceFlow recorder={handle} />`
389
+ * mid-mount, either (a) unmount the component before calling
390
+ * `reset()` and re-mount after, OR (b) drive a fresh recorder
391
+ * instance via state. See `reset()` JSDoc for the rationale.
392
+ */
393
+ subscribe(listener: () => void): () => void;
394
+ /**
395
+ * Monotonically-increasing version counter — bumps once per
396
+ * graph-mutating event. Pair with `getGraph()` in
397
+ * `useSyncExternalStore` snapshot equality:
398
+ * ```ts
399
+ * const version = useSyncExternalStore(handle.subscribe, () => handle.version());
400
+ * const graph = useMemo(() => handle.getGraph(), [version]);
401
+ * ```
402
+ * Avoids defensive-copy allocation on every render while keeping
403
+ * React's identity-check happy.
404
+ */
405
+ version(): number;
406
+ /** Reset the recorder for reuse across multiple builds. After this,
407
+ * the recorder behaves like a freshly-constructed instance. */
408
+ reset(): void;
409
+ }
410
+ interface CreateTraceStructureRecorderOptions {
411
+ /** Recorder id — surfaces in `StructureBuildError.recorderId` when
412
+ * the recorder throws. Defaults to `'trace-structure'`. Use distinct
413
+ * ids if you attach multiple instances. */
414
+ id?: string;
415
+ /** Optional callback fired after each event mutates the graph. Useful
416
+ * for incremental-render UIs (Lens) that want to re-render between
417
+ * builder operations. NOT invoked during the initial `attachStructureRecorder`
418
+ * seed replay; consumers can call `getGraph()` directly after attach. */
419
+ onChange?: (graph: Readonly<TraceGraph>) => void;
420
+ }
421
+ declare function createTraceStructureRecorder(options?: CreateTraceStructureRecorderOptions): TraceStructureRecorderHandle;
422
+
135
423
  /**
136
- * Phase 1: Compute static layout from spec. Cached on spec reference — only
137
- * recomputes when the pipeline structure changes, not on every slider tick.
424
+ * createTraceRuntimeOverlay event-driven runtime overlay for `<TracedFlow>`.
425
+ *
426
+ * The runtime twin of `createTraceStructureRecorder` (L7.7). Where the
427
+ * structure recorder accumulates the build-time graph SHAPE from
428
+ * `StructureRecorder` events, this recorder accumulates the runtime
429
+ * EXECUTION STATE (which nodes ran, current active, errors) from
430
+ * `FlowRecorder` events. The two compose into the full time-travel
431
+ * trace UI:
432
+ *
433
+ * StructureRecorder events → TraceGraph (nodes + edges, id-keyed)
434
+ * FlowRecorder events → RuntimeOverlay (per-node state, id-keyed)
435
+ * │
436
+ * ▼
437
+ * <TracedFlow graph={...} overlay={...} scrubIndex={i} />
438
+ *
439
+ * **Universal key**: `runtimeStageId = [subflowPath/]stageId#executionIndex`.
440
+ * Loops re-execute the same stageId with bumping executionIndex — the
441
+ * overlay records each execution as a distinct step in `executionOrder`
442
+ * but updates the SAME node-by-id in `doneStageIds` (because the build-
443
+ * time graph has one node per spec — loops re-visit it).
444
+ *
445
+ * Per L7.7 panel guidance: the consumer pattern mirrors recorder error
446
+ * isolation, exposes a pub-sub `subscribe(listener)` + monotonic
447
+ * `version()` for `useSyncExternalStore` integration, and accumulates
448
+ * pure data with zero React coupling.
138
449
  */
139
- declare function specToLayout(spec: SpecNode): SpecLayout;
450
+ interface TraversalContext$2 {
451
+ readonly runtimeStageId: string;
452
+ readonly iteration?: number;
453
+ readonly runId?: string;
454
+ }
455
+ interface RuntimeStageExecutedEvent {
456
+ readonly stageName: string;
457
+ readonly stageId?: string;
458
+ /** Discriminator for which kind of stage completed. footprintjs v6+
459
+ * fires this event uniformly for every stage kind (proposal #003);
460
+ * consumers route by `stageType` without a chart-spec lookup. */
461
+ readonly stageType: 'linear' | 'decider' | 'fork' | 'selector' | 'subflow-mount';
462
+ readonly traversalContext: TraversalContext$2;
463
+ }
464
+ interface RuntimeErrorEvent {
465
+ readonly stageName: string;
466
+ readonly stageId?: string;
467
+ readonly message?: string;
468
+ readonly traversalContext?: TraversalContext$2;
469
+ }
470
+ interface RuntimeRunStartEvent {
471
+ readonly traversalContext?: TraversalContext$2;
472
+ }
473
+ interface RuntimeRunEndEvent {
474
+ readonly traversalContext?: TraversalContext$2;
475
+ }
476
+ /** Minimal FlowRecorder interface mirror — see top-of-file rationale.
477
+ *
478
+ * As of footprintjs v6 (proposal #003), `onStageExecuted` fires
479
+ * uniformly for ALL stage kinds — linear / decider / fork / selector
480
+ * / subflow-mount. The event payload carries a `stageType` field for
481
+ * consumers that need to route by kind. We no longer need separate
482
+ * `onDecision` / `onFork` / `onSelected` handlers to track "did this
483
+ * stage run" — a single `onStageExecuted` handler suffices. */
484
+ interface MinimalFlowRecorder {
485
+ readonly id: string;
486
+ onStageExecuted?(event: RuntimeStageExecutedEvent): void;
487
+ onError?(event: RuntimeErrorEvent): void;
488
+ onRunStart?(event: RuntimeRunStartEvent): void;
489
+ onRunEnd?(event: RuntimeRunEndEvent): void;
490
+ }
140
491
  /**
141
- * Phase 2: Apply execution overlay to static layout.
142
- * Produces ReactFlow nodes/edges with correct colors, step numbers, and glow.
492
+ * One entry in the execution timeline. `<TracedFlow>` keys time-travel
493
+ * scrubbing on the index into this array at index `i`, all entries
494
+ * `0..i-1` are "done", entry `i` is "active".
143
495
  */
144
- declare function applyOverlay(layout: SpecLayout, overlay?: ExecutionOverlay, colors?: Partial<FlowchartColors>): {
145
- nodes: Node[];
146
- edges: Edge[];
147
- };
496
+ interface RuntimeExecutionStep {
497
+ /** `[subflowPath/]stageId#executionIndex` — universal key. */
498
+ readonly runtimeStageId: string;
499
+ /** Base stage id (without `#N`) — matches the `TraceGraph` node id. */
500
+ readonly stageId: string;
501
+ /** Human-readable label (from event.stageName). */
502
+ readonly stageName: string;
503
+ /** When this step recorded, in ms since recorder start. */
504
+ readonly timestampMs: number;
505
+ }
506
+ interface RuntimeOverlay {
507
+ /** Ordered execution history — drives time-travel scrubbing. */
508
+ readonly executionOrder: readonly RuntimeExecutionStep[];
509
+ /** Per-base-stageId error message (most-recent wins). */
510
+ readonly errors: ReadonlyMap<string, string>;
511
+ /** True after `onRunStart` until `onRunEnd` — useful for "still running" indicators. */
512
+ readonly running: boolean;
513
+ }
514
+ interface TraceRuntimeOverlayHandle {
515
+ /** The recorder to attach via `executor.attachFlowRecorder(handle.recorder)`. */
516
+ recorder: MinimalFlowRecorder;
517
+ /** Returns a defensive copy of the current overlay state. */
518
+ getOverlay(): RuntimeOverlay;
519
+ /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */
520
+ subscribe(listener: () => void): () => void;
521
+ /** Monotonic version counter — bumps once per overlay-mutating event. */
522
+ version(): number;
523
+ /** Reset for reuse across runs. Does NOT bump version or notify (matches
524
+ * traceStructureRecorder's reset contract). */
525
+ reset(): void;
526
+ }
527
+ interface CreateTraceRuntimeOverlayOptions {
528
+ id?: string;
529
+ }
530
+ declare function createTraceRuntimeOverlay(options?: CreateTraceRuntimeOverlayOptions): TraceRuntimeOverlayHandle;
148
531
  /**
149
- * Convert a pipeline spec to ReactFlow graph.
150
- * Pass `overlay` to color nodes/edges by execution state.
532
+ * Snapshot of overlay state AT a specific scrub index. Drives node
533
+ * coloring in `<TracedFlow>`.
151
534
  */
152
- declare function specToReactFlow(spec: SpecNode, overlay?: ExecutionOverlay, colors?: Partial<FlowchartColors>): {
153
- nodes: Node[];
154
- edges: Edge[];
155
- };
535
+ interface RuntimeOverlaySlice {
536
+ /** Base stage ids that completed before the active scrub position. */
537
+ readonly doneStageIds: ReadonlySet<string>;
538
+ /** The currently-active stage id (or `null` when scrub is at 0 with no exec yet). */
539
+ readonly activeStageId: string | null;
540
+ /** Union of done + active — convenient for "executed at all" checks. */
541
+ readonly executedStageIds: ReadonlySet<string>;
542
+ /** The full ordered list of base stage ids up through the active position —
543
+ * used by renderers that want to number stages by occurrence (e.g.,
544
+ * show "3rd loop iteration" badges). */
545
+ readonly executedOrderIds: readonly string[];
546
+ /** Pass-through errors map for the renderer. */
547
+ readonly errors: ReadonlyMap<string, string>;
548
+ }
549
+ /**
550
+ * Slice `overlay.executionOrder` at the given index:
551
+ *
552
+ * - `executionOrder[0..index-1]` → "done"
553
+ * - `executionOrder[index]` → "active"
554
+ * - `index >= executionOrder.length` → all done, no active
555
+ *
556
+ * Returns an empty slice when overlay has no execution history.
557
+ */
558
+ declare function sliceOverlay(overlay: RuntimeOverlay, index: number): RuntimeOverlaySlice;
156
559
 
157
- interface TracedFlowchartViewProps extends BaseComponentProps {
158
- /** Pipeline spec from builder.toSpec() — for the current level */
159
- spec: SpecNode;
160
- /** Visualization snapshots (enables trace overlay when provided) */
161
- snapshots?: StageSnapshot[];
162
- /** Current time-travel position */
163
- snapshotIndex?: number;
164
- /** Callback when a node is clicked (receives snapshot index, or node id if no snapshots) */
165
- onNodeClick?: (indexOrId: number | string) => void;
166
- /** Override default node types */
167
- nodeTypes?: NodeTypes;
168
- }
169
- declare function TracedFlowchartView({ spec, snapshots, snapshotIndex, onNodeClick, nodeTypes: customNodeTypes, unstyled, className, style, }: TracedFlowchartViewProps): react_jsx_runtime.JSX.Element;
560
+ interface TimeTravelDebuggerProps extends BaseComponentProps {
561
+ /** Stage snapshots */
562
+ snapshots: StageSnapshot[];
563
+ /** Recorder-captured build-time graph (from
564
+ * `createTraceStructureRecorder().getGraph()`). Required for the
565
+ * chart rendering replaces the legacy `nodes` / `edges` props. */
566
+ graph: TraceGraph;
567
+ /** Optional runtime overlay (from
568
+ * `createTraceRuntimeOverlay().getOverlay()`). When provided, the
569
+ * chart renders via `<TracedFlow>` with per-step coloring synced to
570
+ * the scrubber; otherwise renders via `<TraceFlow>` (build-time only). */
571
+ runtimeOverlay?: RuntimeOverlay;
572
+ /** Show Gantt timeline */
573
+ showGantt?: boolean;
574
+ /** Layout direction */
575
+ layout?: "horizontal" | "vertical";
576
+ /** Title */
577
+ title?: string;
578
+ }
579
+ /**
580
+ * Full time-travel debugger: scrubber + recorder-driven flowchart +
581
+ * memory + narrative + gantt. This is the "batteries included"
582
+ * component for pipeline debugging.
583
+ *
584
+ * v6+: chart rendering is recorder-driven. Pass `graph` (always) and
585
+ * optionally `runtimeOverlay` for per-step coloring tied to the
586
+ * scrubber.
587
+ */
588
+ declare function TimeTravelDebugger({ snapshots, graph, runtimeOverlay, showGantt, layout, title, size, unstyled, className, style, }: TimeTravelDebuggerProps): react_jsx_runtime.JSX.Element;
589
+
590
+ /**
591
+ * useSubflowNavigation — drill-down breadcrumb tracker for recorder-driven charts.
592
+ *
593
+ * Recorder-driven (v6+): replaces the legacy SpecNode-walk path. Accepts
594
+ * a `TraceGraph` (from `createTraceStructureRecorder`) and tracks WHICH
595
+ * subflow the user has drilled into.
596
+ *
597
+ * Limitation (intentional — recorder graph is flat / mount-only):
598
+ * The StructureRecorder records the MOUNT of each subflow in the
599
+ * parent chart, not the inner structure of each child chart. So
600
+ * "drill into a subflow" today returns the SAME graph with the
601
+ * `currentSubflowId` marker advanced — there is no separate
602
+ * child-graph to swap in. Filtering nodes by
603
+ * `data.subflowId === <selected>` would only surface mount nodes,
604
+ * not the child chart's stages.
605
+ *
606
+ * TODO(recorder-driven-nesting): when child charts attach their own
607
+ * `traceStructureRecorder` and surface those graphs via a registry,
608
+ * accept `Map<subflowId, TraceGraph>` and swap `currentGraph` to the
609
+ * child's graph on drill-down. Consumers can then render
610
+ * `<TraceFlow graph={currentGraph} />` per level.
611
+ */
170
612
 
171
613
  interface BreadcrumbEntry {
172
614
  /** Display name for this level */
173
615
  label: string;
174
- /** The spec node tree at this level */
175
- spec: SpecNode;
616
+ /** The subflow id that was drilled into to reach this level
617
+ * (undefined for root). */
618
+ subflowId?: string;
176
619
  /** Human-readable description of this subflow */
177
620
  description?: string;
178
621
  }
179
622
  interface SubflowNavigation {
180
623
  /** Current breadcrumb path (root → ... → current) */
181
624
  breadcrumbs: BreadcrumbEntry[];
182
- /** Current level's ReactFlow nodes */
183
- nodes: Node[];
184
- /** Current level's ReactFlow edges */
185
- edges: Edge[];
186
- /** Call when a node is clicked drills in if it's a subflow */
625
+ /** Current graph today identical to the root graph (see file-level
626
+ * TODO). Consumers should still treat this as the source of truth so
627
+ * they remain forward-compatible once per-subflow graphs are wired in. */
628
+ currentGraph: TraceGraph;
629
+ /** Subflow id of the level the user is currently inside (null at root). */
630
+ currentSubflowId: string | null;
631
+ /** Display name of the subflow node we drilled into (null at root). */
632
+ currentSubflowNodeName: string | null;
633
+ /** Call when a node is clicked — drills in if it's a subflow.
634
+ * Returns true when the click pushed a new level. */
187
635
  handleNodeClick: (nodeId: string) => boolean;
188
636
  /** Navigate to a specific breadcrumb level (0 = root) */
189
637
  navigateTo: (level: number) => void;
190
638
  /** Whether we're currently inside a subflow (not at root) */
191
639
  isInSubflow: boolean;
192
- /** Name of the subflow node we drilled into (for finding execution data) */
193
- currentSubflowNodeName: string | null;
194
640
  }
195
641
  /**
196
- * Hook that manages subflow drill-down navigation for a flowchart spec.
642
+ * Hook that tracks subflow drill-down state for a recorder-driven chart.
197
643
  *
198
- * Maintains a breadcrumb stack. When a subflow node is clicked, pushes its
199
- * nested spec onto the stack and re-derives nodes/edges. Breadcrumb clicks
200
- * pop back to that level.
644
+ * Maintains a breadcrumb stack. When a subflow node is clicked the
645
+ * stack pushes a new entry; breadcrumb clicks pop back to that level.
646
+ * See file-level docs for the deferred per-subflow graph swap.
201
647
  */
202
- declare function useSubflowNavigation(rootSpec: SpecNode | null, overlay?: ExecutionOverlay, colors?: Partial<FlowchartColors>): SubflowNavigation;
648
+ declare function useSubflowNavigation(rootGraph: TraceGraph | null): SubflowNavigation;
203
649
 
204
650
  interface SubflowBreadcrumbProps {
205
651
  breadcrumbs: BreadcrumbEntry[];
@@ -220,12 +666,13 @@ interface SubflowTreeEntry {
220
666
  subflowId?: string;
221
667
  /** Whether this node is a subflow root (has nested structure) */
222
668
  isSubflow?: boolean;
223
- /** Nested children (subflow stages) */
669
+ /** Nested children (subflow stages) — always undefined in the
670
+ * current recorder-driven implementation; see file-level TODO. */
224
671
  children?: SubflowTreeEntry[];
225
672
  }
226
673
  interface SubflowTreeProps extends BaseComponentProps {
227
- /** Pipeline spec to derive the tree from */
228
- spec: SpecNode;
674
+ /** Recorder-captured graph from `createTraceStructureRecorder().getGraph()`. */
675
+ graph: TraceGraph;
229
676
  /** Currently active stage name (highlights in tree) */
230
677
  activeStage?: string | null;
231
678
  /** Set of completed stage names */
@@ -235,63 +682,1055 @@ interface SubflowTreeProps extends BaseComponentProps {
235
682
  }
236
683
  declare const SubflowTree: react.NamedExoticComponent<SubflowTreeProps>;
237
684
 
238
- interface StageNodeData {
239
- label: string;
240
- active?: boolean;
241
- done?: boolean;
242
- error?: boolean;
243
- linked?: boolean;
244
- /** Semantic icon hint (e.g., "llm", "tool", "rag", "start", "parse", "agent", "guard") */
245
- icon?: string;
246
- /** Step numbers in execution order (shown as badges multiple when revisited via loops) */
247
- stepNumbers?: number[];
248
- /** Node was not executed (dim it) */
249
- dimmed?: boolean;
250
- /** Node is a subflow root (show nested indicator) */
251
- isSubflow?: boolean;
252
- /** Node uses lazy resolution (dashed border + cloud icon when unresolved) */
253
- isLazy?: boolean;
254
- /** Node is a decider (renders as diamond shape per flowchart convention) */
255
- isDecider?: boolean;
256
- /** Node is a fork (parallel fan-out) */
257
- isFork?: boolean;
258
- /** Human-readable description of what this stage does */
259
- description?: string;
260
- /** Subflow identifier set when this node belongs to a subflow */
261
- subflowId?: string;
262
- [key: string]: unknown;
685
+ /** Layout function shape — takes a graph, returns a graph with positions set. */
686
+ type TraceFlowLayout = (graph: TraceGraph) => TraceGraph;
687
+ /**
688
+ * Default tree-walk layout.
689
+ *
690
+ * Edge-kind semantics (critical for parity)
691
+ * ─────────────────────────────────────────
692
+ * `fork-branch` + `decision-branch` edges are SIBLINGS at depth+1
693
+ * (centered under the parent). A `next` edge from a node that ALSO
694
+ * has branch edges is the "after convergence" target — its rank is
695
+ * `max(deepest branch subtree) + 1`, so it sits BELOW the fan-out,
696
+ * matching the legacy diamond layout.
697
+ *
698
+ * LoadOrder (fork)
699
+ * ├── fork-branch CheckInventory (sibling, y+1)
700
+ * ├── fork-branch → RunFraudCheck (sibling, y+1)
701
+ * └── next → FinalizeOrder (after convergence,
702
+ * below deepest sibling)
703
+ *
704
+ * A `next` edge from a node with NO branch edges is a plain linear
705
+ * chain target at depth+1.
706
+ *
707
+ * `loop` back-edges DO NOT shape layout (they're scrub-time visual
708
+ * markers only).
709
+ *
710
+ * Limitations (documented; not bugs)
711
+ * ──────────────────────────────────
712
+ * - Multi-root graphs render with the first-seen node as the visual
713
+ * root; orphans stack below.
714
+ * - Convergence where multiple branches join into a single node:
715
+ * the node is placed under its FIRST traversed branch (first-wins).
716
+ * For deep DAGs swap in a graph-layout library (dagre, elk).
717
+ * - Sibling x-positions are local to each parent's subtree; no
718
+ * global x-overlap detection across deep nested structures.
719
+ */
720
+ declare const defaultTraceFlowLayout: TraceFlowLayout;
721
+ interface TraceFlowEdgeColors {
722
+ next: string;
723
+ forkBranch: string;
724
+ decisionBranch: string;
725
+ loop: string;
263
726
  }
727
+ type TraceFlowSource = {
728
+ recorder: TraceStructureRecorderHandle;
729
+ graph?: never;
730
+ } | {
731
+ graph: TraceGraph;
732
+ recorder?: never;
733
+ };
734
+ type TraceFlowProps = BaseComponentProps & TraceFlowSource & {
735
+ /** Layout function. Default: BFS tree walk. Pass the literal
736
+ * `"passthrough"` to skip layout when nodes already carry positions. */
737
+ layout?: TraceFlowLayout | "passthrough";
738
+ /** Per-kind edge color overrides. */
739
+ edgeColors?: Partial<TraceFlowEdgeColors>;
740
+ /** Node click handler — receives the node id. */
741
+ onNodeClick?: (id: string) => void;
742
+ };
743
+ declare function TraceFlow(props: TraceFlowProps): react_jsx_runtime.JSX.Element;
744
+
745
+ interface TracedFlowColors {
746
+ /** Default (un-executed) node text + edge stroke. */
747
+ default: string;
748
+ /** Done — visually de-emphasised (lighter). */
749
+ done: string;
750
+ /** Active — current scrub position. */
751
+ active: string;
752
+ /** Error — node with recorded onError. */
753
+ error: string;
754
+ /** Loop back-edge color. */
755
+ loop: string;
756
+ }
757
+ interface TracedFlowProps extends BaseComponentProps {
758
+ /** Build-time graph from `createTraceStructureRecorder().getGraph()`. */
759
+ graph: TraceGraph;
760
+ /** Runtime overlay from `createTraceRuntimeOverlay().getOverlay()`. */
761
+ overlay?: RuntimeOverlay;
762
+ /** Time-travel scrub index. Defaults to the last step (latest state). */
763
+ scrubIndex?: number;
764
+ /** Layout function. Default: BFS tree walk over the recorder graph. */
765
+ layout?: TraceFlowLayout | "passthrough";
766
+ /** Color overrides. */
767
+ colors?: Partial<TracedFlowColors>;
768
+ /** Node click handler — receives stage id. */
769
+ onNodeClick?: (stageId: string) => void;
770
+ /**
771
+ * Fires when the chart drills into or out of a subflow (explicit
772
+ * user click on a mount node). Receives the mount stage id (drill
773
+ * in) or `null` (pop back). Container shells use this to keep
774
+ * their data panels in lock-step with the chart's drill state.
775
+ */
776
+ onSubflowChange?: (mountStageId: string | null) => void;
777
+ }
778
+ declare function TracedFlow({ graph, overlay, scrubIndex, layout: layoutProp, colors: colorOverrides, onNodeClick, onSubflowChange, className, style, }: TracedFlowProps): react_jsx_runtime.JSX.Element;
779
+
264
780
  /**
265
- * Custom ReactFlow node for pipeline stages.
266
- * All colors and fonts come from `--fp-*` CSS variables (via theme).
267
- * Shows execution state via color, icon, step badge, and pulse animation.
781
+ * createNodeViewRecorder per-stage summary translator.
782
+ *
783
+ * Implements footprintjs v6.0+ `CombinedRecorder` (Flow + Scope) and
784
+ * produces a `NodeViewIndex` — per-stage data keyed by both `StageId`
785
+ * (chart-shape lookup) and `RuntimeStageId` (per-execution lookup).
786
+ *
787
+ * Composition (panel guidance, L8.0 review)
788
+ * ─────────────────────────────────────────
789
+ * NodeView does NOT duplicate the structural prev/next index — it
790
+ * READS those fields from the structure translator's
791
+ * `node.data.prevIds`/`nextIds`. The structure translator already
792
+ * maintains convergence-correct, loop-excluded neighbors. Duplicating
793
+ * the index here would re-introduce edge-ordering bugs we just
794
+ * solved.
795
+ *
796
+ * The NodeView translator owns ONLY runtime-derived per-stage state:
797
+ * - `executions[]` — every FlowRecorder.onStageExecuted event for
798
+ * this stage (loop-friendly: N executions of one stage produce
799
+ * N entries, each with its own runtimeStageId).
800
+ * - `commitRuntimeStageIds[]` — refs to commits made by this stage
801
+ * (the canonical CommitView lives in CommitFlowIndex from L8.2;
802
+ * NodeView stores only the join key).
803
+ *
804
+ * Plus derived convenience fields: `visitedInRun`, `executionCount`,
805
+ * `firstExecutedAt`, `lastExecutedAt`, `totalDurationMs`, `errorCount`.
806
+ *
807
+ * Version bumping
808
+ * ───────────────
809
+ * NodeView bumps its own version on EITHER:
810
+ * (a) a Flow/Scope event arrives (own state mutates), OR
811
+ * (b) the structure translator's version bumps (structural data
812
+ * the index projects from changed).
813
+ *
814
+ * So `useTranslator(nodeView, ...)` re-renders when EITHER changes —
815
+ * one subscription, full reactive coverage.
816
+ *
817
+ * @example
818
+ * ```tsx
819
+ * import { createTraceStructureRecorder, createNodeViewRecorder, useTranslator } from 'footprint-explainable-ui/flowchart';
820
+ *
821
+ * const trace = useMemo(() => createTraceStructureRecorder(), []);
822
+ * const nodeView = useMemo(() => createNodeViewRecorder({ structure: trace }), [trace]);
823
+ *
824
+ * useEffect(() => {
825
+ * executor.attachFlowRecorder(nodeView.recorder);
826
+ * executor.attachScopeRecorder(nodeView.recorder);
827
+ * }, [nodeView]);
828
+ *
829
+ * const index = useTranslator(nodeView, () => nodeView.getIndex());
830
+ * const finalize = index.byStageId.get(asStageId('FinalizeOrder'));
831
+ * // finalize.prevIds → ['CheckInventory', 'RunFraudCheck'] (from structure)
832
+ * // finalize.executions → [{ runtimeStageId, iteration, startMs, endMs, ... }]
833
+ * // finalize.visitedInRun → true
834
+ * // finalize.commitRuntimeStageIds → ['finalize-order#3', ...]
835
+ * ```
268
836
  */
269
- declare const StageNode: react.NamedExoticComponent<Pick<_xyflow_react.Node<Record<string, unknown>, string | undefined>, "id" | "data" | "width" | "height" | "sourcePosition" | "targetPosition" | "dragHandle" | "parentId"> & Required<Pick<_xyflow_react.Node<Record<string, unknown>, string | undefined>, "type" | "dragging" | "zIndex" | "selectable" | "deletable" | "selected" | "draggable">> & {
270
- isConnectable: boolean;
271
- positionAbsoluteX: number;
272
- positionAbsoluteY: number;
273
- } & {
274
- data: StageNodeData;
275
- }>;
276
837
 
277
- interface TimeTravelDebuggerProps extends BaseComponentProps {
278
- /** Stage snapshots */
279
- snapshots: StageSnapshot[];
280
- /** ReactFlow nodes (required for flowchart) */
281
- nodes: Node[];
282
- /** ReactFlow edges (required for flowchart) */
283
- edges: Edge[];
284
- /** Show Gantt timeline */
285
- showGantt?: boolean;
286
- /** Layout direction */
287
- layout?: "horizontal" | "vertical";
288
- /** Title */
289
- title?: string;
838
+ interface TraversalContext$1 {
839
+ readonly runtimeStageId: string;
840
+ readonly iteration?: number;
841
+ readonly runId?: string;
842
+ }
843
+ interface FlowStageExecutedEvent$1 {
844
+ readonly stageName: string;
845
+ readonly stageId?: string;
846
+ readonly traversalContext: TraversalContext$1;
847
+ readonly startTime?: number;
848
+ readonly endTime?: number;
849
+ }
850
+ interface FlowErrorEvent$1 {
851
+ readonly stageName: string;
852
+ readonly stageId?: string;
853
+ readonly message?: string;
854
+ readonly traversalContext?: TraversalContext$1;
855
+ }
856
+ interface FlowRunLifecycleEvent$1 {
857
+ readonly traversalContext?: TraversalContext$1;
858
+ }
859
+ interface ScopeCommitEvent$1 {
860
+ readonly stage?: string;
861
+ readonly stageId?: string;
862
+ readonly runtimeStageId?: string;
863
+ readonly updates?: Record<string, unknown>;
864
+ readonly reads?: readonly string[];
290
865
  }
291
866
  /**
292
- * Full time-travel debugger: scrubber + flowchart + memory + narrative + gantt.
293
- * This is the "batteries included" component for pipeline debugging.
867
+ * Minimal CombinedRecorder interface mirror subset of footprintjs's
868
+ * Flow + Scope recorder interfaces NodeView consumes. Implements both
869
+ * channels in one object; consumer attaches via
870
+ * `executor.attachFlowRecorder()` AND `executor.attachScopeRecorder()`
871
+ * (or `executor.attachCombinedRecorder()` if available).
294
872
  */
295
- declare function TimeTravelDebugger({ snapshots, nodes, edges, showGantt, layout, title, size, unstyled, className, style, }: TimeTravelDebuggerProps): react_jsx_runtime.JSX.Element;
873
+ interface MinimalNodeViewRecorder {
874
+ readonly id: string;
875
+ onStageExecuted?(event: FlowStageExecutedEvent$1): void;
876
+ onError?(event: FlowErrorEvent$1): void;
877
+ onRunStart?(event: FlowRunLifecycleEvent$1): void;
878
+ onRunEnd?(event: FlowRunLifecycleEvent$1): void;
879
+ onCommit?(event: ScopeCommitEvent$1): void;
880
+ }
881
+ /** One execution of a stage. A stage that runs N times in a loop
882
+ * produces N `ExecutionRecord` entries on the NodeView.executions[]. */
883
+ interface ExecutionRecord {
884
+ /** `[subflowPath/]stageId#executionIndex` — universal join key. */
885
+ readonly runtimeStageId: RuntimeStageId;
886
+ /** Loop iteration (0-indexed). undefined when the engine didn't
887
+ * populate it (rare). */
888
+ readonly iteration?: number;
889
+ /** ms since executor start. */
890
+ readonly startMs?: number;
891
+ /** ms since executor start. */
892
+ readonly endMs?: number;
893
+ /** Set when `onError` fired for this execution. */
894
+ readonly errorMessage?: string;
895
+ }
896
+ /**
897
+ * Per-stage summary. Joins STRUCTURAL data (from the structure
898
+ * translator's TraceNode.data) with RUNTIME data (executions + commit
899
+ * refs accumulated by this translator).
900
+ */
901
+ interface NodeView {
902
+ readonly stageId: StageId;
903
+ readonly label: string;
904
+ readonly type: "stage" | "decider" | "selector" | "fork" | "streaming" | "subflow" | "loop";
905
+ readonly isDecider: boolean;
906
+ readonly isFork: boolean;
907
+ readonly isSubflow: boolean;
908
+ readonly isStreaming: boolean;
909
+ readonly isPausable: boolean;
910
+ readonly description?: string;
911
+ readonly icon?: string;
912
+ readonly subflowId?: string;
913
+ readonly branchIds?: readonly string[];
914
+ readonly defaultBranch?: string;
915
+ /** From the structure translator (loop-excluded, convergence-correct). */
916
+ readonly prevIds: StageId[];
917
+ readonly nextIds: StageId[];
918
+ readonly executions: ExecutionRecord[];
919
+ /** Derived: `executions.length > 0`. */
920
+ readonly visitedInRun: boolean;
921
+ /** Derived: `executions.length` (loop iteration count). */
922
+ readonly executionCount: number;
923
+ /** Derived: first execution `startMs`, or `null` if not yet executed. */
924
+ readonly firstExecutedAt: number | null;
925
+ /** Derived: last execution `endMs`, or `null`. */
926
+ readonly lastExecutedAt: number | null;
927
+ /** Derived: sum of `endMs - startMs` across executions. */
928
+ readonly totalDurationMs: number;
929
+ /** Derived: count of executions with an errorMessage. */
930
+ readonly errorCount: number;
931
+ /** Run-time stage ids of commits made by this stage. Look up the
932
+ * canonical CommitView via `commitFlow.byRuntimeStageId.get(id)`. */
933
+ readonly commitRuntimeStageIds: RuntimeStageId[];
934
+ }
935
+ /** Index of NodeView keyed by both StageId and RuntimeStageId. The
936
+ * branded types prevent `byStageId.get(runtimeStageId)` silent-undefined. */
937
+ interface NodeViewIndex {
938
+ readonly byStageId: ReadonlyMap<StageId, NodeView>;
939
+ readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, NodeView>;
940
+ /** All NodeViews — insertion order matches structure translator. */
941
+ readonly all: readonly NodeView[];
942
+ }
943
+ interface NodeViewRecorderHandle {
944
+ /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`
945
+ * AND `executor.attachScopeRecorder()` (footprintjs routes by
946
+ * method-shape detection). */
947
+ recorder: MinimalNodeViewRecorder;
948
+ /** Returns a defensive copy of the current index state. */
949
+ getIndex(): NodeViewIndex;
950
+ /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */
951
+ subscribe(listener: () => void): () => void;
952
+ /** Monotonic version counter — bumps on Flow/Scope event OR when
953
+ * the structure translator's version bumps (since NodeView projects
954
+ * from its data). */
955
+ version(): number;
956
+ /** Reset runtime state. Does NOT bump version or notify (consistent
957
+ * with traceStructureRecorder + createTraceRuntimeOverlay). */
958
+ reset(): void;
959
+ }
960
+ interface CreateNodeViewRecorderOptions {
961
+ /** Recorder id (surfaces in error attribution). */
962
+ id?: string;
963
+ /** REQUIRED — the structure translator handle. NodeView projects
964
+ * structural fields (`prevIds`, `nextIds`, `label`, etc.) from
965
+ * this on every `getIndex()` call. */
966
+ structure: TraceStructureRecorderHandle;
967
+ }
968
+ declare function createNodeViewRecorder(options: CreateNodeViewRecorderOptions): NodeViewRecorderHandle;
969
+
970
+ /**
971
+ * createCommitFlowRecorder — per-commit summary translator.
972
+ *
973
+ * Owns the canonical `CommitView[]` — captured from Scope `onCommit`
974
+ * events as the chart runs. Each CommitView joins:
975
+ *
976
+ * - **Identity**: runtimeStageId, stageId, commitIdx
977
+ * - **Structural**: prev/next stage ids (read from structure
978
+ * translator's `TraceNode.data.prevIds`/`nextIds`)
979
+ * - **Runtime prev/next**: derived via "most-recent-per-structural-
980
+ * prev" rule over the commitLog (loop-safe, convergence-aware)
981
+ * - **Data dependencies**: per-read-key lineage via
982
+ * `findLastWriter` over the commitLog
983
+ * - **Payload**: updates + reads
984
+ *
985
+ * Composition (panel guidance, L8.1 review)
986
+ * ─────────────────────────────────────────
987
+ * Per Panel 1 rule "translators MUST subscribe to structure
988
+ * directly, never to peer translators", CommitFlow subscribes to
989
+ * the structure handle (NOT to NodeView). Linear dependency tree
990
+ * keeps notify cascades O(depth) instead of O(N²).
991
+ *
992
+ * NodeView (L8.1) stores `commitRuntimeStageIds[]` — refs only —
993
+ * pointing into CommitFlow's `byRuntimeStageId`. The canonical
994
+ * payload lives HERE; NodeView is the per-stage projection.
995
+ *
996
+ * @example
997
+ * ```tsx
998
+ * const trace = useMemo(() => createTraceStructureRecorder(), []);
999
+ * const commitFlow = useMemo(
1000
+ * () => createCommitFlowRecorder({ structure: trace }),
1001
+ * [trace],
1002
+ * );
1003
+ * useEffect(() => {
1004
+ * executor.attachFlowRecorder(commitFlow.recorder);
1005
+ * executor.attachScopeRecorder(commitFlow.recorder);
1006
+ * }, [commitFlow]);
1007
+ *
1008
+ * const index = useTranslator(commitFlow, () => commitFlow.getIndex());
1009
+ * const c = index.byRuntimeStageId.get(asRuntimeStageId('finalize-order#3'));
1010
+ * c.structuralPrevIds // ['CheckInventory', 'RunFraudCheck']
1011
+ * c.runtimePrevIds // ['check-inventory#1', 'run-fraud-check#2']
1012
+ * c.dataDependencies // [{ key:'inStock', sourceRuntimeStageId:'check-inventory#1', sourceCommitIdx:1 }, ...]
1013
+ *
1014
+ * const lineage = backtraceDataFlow(index, asRuntimeStageId('finalize-order#3'));
1015
+ * // → ancestry chain of commits whose writes contributed to this commit's reads
1016
+ * ```
1017
+ */
1018
+
1019
+ interface TraversalContext {
1020
+ readonly runtimeStageId: string;
1021
+ readonly iteration?: number;
1022
+ readonly runId?: string;
1023
+ }
1024
+ interface FlowStageExecutedEvent {
1025
+ readonly stageName: string;
1026
+ readonly stageId?: string;
1027
+ readonly traversalContext: TraversalContext;
1028
+ }
1029
+ interface FlowErrorEvent {
1030
+ readonly stageName: string;
1031
+ readonly stageId?: string;
1032
+ readonly message?: string;
1033
+ readonly traversalContext?: TraversalContext;
1034
+ }
1035
+ interface FlowRunLifecycleEvent {
1036
+ readonly traversalContext?: TraversalContext;
1037
+ }
1038
+ interface ScopeReadEvent {
1039
+ readonly stage?: string;
1040
+ readonly stageId?: string;
1041
+ readonly runtimeStageId?: string;
1042
+ readonly key?: string;
1043
+ }
1044
+ interface ScopeCommitEvent {
1045
+ readonly stage?: string;
1046
+ readonly stageId?: string;
1047
+ readonly runtimeStageId?: string;
1048
+ readonly updates?: Record<string, unknown>;
1049
+ readonly reads?: readonly string[];
1050
+ }
1051
+ /**
1052
+ * Minimal CombinedRecorder mirror — subset of footprintjs's Flow +
1053
+ * Scope channels CommitFlow consumes.
1054
+ */
1055
+ interface MinimalCommitFlowRecorder {
1056
+ readonly id: string;
1057
+ onStageExecuted?(event: FlowStageExecutedEvent): void;
1058
+ onError?(event: FlowErrorEvent): void;
1059
+ onRunStart?(event: FlowRunLifecycleEvent): void;
1060
+ onRunEnd?(event: FlowRunLifecycleEvent): void;
1061
+ onRead?(event: ScopeReadEvent): void;
1062
+ onCommit?(event: ScopeCommitEvent): void;
1063
+ }
1064
+ /**
1065
+ * One data-dependency edge — a read key in this commit AND the commit
1066
+ * whose `updates` last wrote that key before this commit's index.
1067
+ *
1068
+ * `sourceRuntimeStageId` and `sourceCommitIdx` are BOTH `null` when no
1069
+ * prior commit wrote the key (panel-flagged: NEVER `undefined` — forces
1070
+ * consumers to handle absence as load-bearing).
1071
+ */
1072
+ interface DataDependency {
1073
+ readonly key: string;
1074
+ readonly sourceRuntimeStageId: RuntimeStageId | null;
1075
+ readonly sourceCommitIdx: number | null;
1076
+ }
1077
+ /**
1078
+ * Per-commit summary. Joins structural data (from the structure
1079
+ * translator) with runtime data (commitLog timeline) into a single
1080
+ * consumer-friendly shape.
1081
+ *
1082
+ * Three "prev" views — pick the right one for your UI:
1083
+ * ─────────────────────────────────────────────────────
1084
+ * | Field | Answers |
1085
+ * |----------------------|--------------------------------------------|
1086
+ * | `structuralPrevIds` | "what COULD flow in" (chart shape) |
1087
+ * | `runtimePrevIds` | "what DID flow in by stage" (execution |
1088
+ * | | timeline; loop-aware) |
1089
+ * | `dataDependencies` | "which commit wrote the bytes I read" |
1090
+ * | | (causal data lineage; per-key) |
1091
+ *
1092
+ * The three answers usually align on simple charts (linear; single
1093
+ * fork-merge). They DIVERGE in interesting ways under loops (runtime
1094
+ * differs by iteration; data-deps may skip uninvolved stages) and
1095
+ * conditional branches (structural sees all options; runtime + data
1096
+ * see only the chosen path).
1097
+ */
1098
+ interface CommitView {
1099
+ readonly runtimeStageId: RuntimeStageId;
1100
+ readonly stageId: StageId;
1101
+ /** Position in the chronologically-ordered commitLog. */
1102
+ readonly commitIdx: number;
1103
+ /** Stage ids that lead into this stage in the chart (loop-excluded). */
1104
+ readonly structuralPrevIds: StageId[];
1105
+ readonly structuralNextIds: StageId[];
1106
+ /**
1107
+ * For each structural prev stage that EXECUTED IN THIS RUN before
1108
+ * this commit, the most-recent runtimeStageId of that prev's commit.
1109
+ * Loop-safe: in iteration 2, runtime prev points at iteration 2's
1110
+ * commits (not iteration 1's).
1111
+ */
1112
+ readonly runtimePrevIds: RuntimeStageId[];
1113
+ /**
1114
+ * For each structural next stage that EXECUTED IN THIS RUN after
1115
+ * this commit, the soonest runtimeStageId. Symmetric to prev.
1116
+ */
1117
+ readonly runtimeNextIds: RuntimeStageId[];
1118
+ /**
1119
+ * One entry per key in `reads`. `sourceRuntimeStageId` points at the
1120
+ * commit whose `updates` last set this key BEFORE this commit's
1121
+ * index; `null` when no prior writer (typically: read of a key
1122
+ * declared as default but never written by another stage).
1123
+ */
1124
+ readonly dataDependencies: DataDependency[];
1125
+ /**
1126
+ * The commit's writes. **Shallow-copied** at intake — top-level
1127
+ * keys are owned, but nested object values are SHARED references
1128
+ * to whatever the upstream `onCommit` payload carried. Consumers
1129
+ * MUST NOT mutate nested values; doing so corrupts the recorder's
1130
+ * internal state and propagates through `findLastWriter` to every
1131
+ * subsequent `getIndex()` call.
1132
+ */
1133
+ readonly updates: Record<string, unknown>;
1134
+ readonly reads: string[];
1135
+ }
1136
+ /** Indexed CommitView access. */
1137
+ interface CommitFlowIndex {
1138
+ /** Ordered list — index === commitIdx. */
1139
+ readonly commits: readonly CommitView[];
1140
+ /** Lookup by runtimeStageId (the universal join key). */
1141
+ readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, CommitView>;
1142
+ /**
1143
+ * Data-dependency edges — `from` and `to` are commitIdx ints; `key`
1144
+ * is the data key that flowed from one commit to the other. Same
1145
+ * data as walking each CommitView's `dataDependencies` — exposed as
1146
+ * a flat edge list for graph algorithms and rendering.
1147
+ *
1148
+ * **When to use which**:
1149
+ * - `view.dataDependencies` — render ONE commit's inputs in a
1150
+ * detail panel (e.g., `<CommitInspector>`).
1151
+ * - `index.dataEdges` — draw the FULL data-flow DAG (React Flow
1152
+ * edges, GraphViz, dependency matrix, etc.). One pass over the
1153
+ * flat list = the whole graph.
1154
+ *
1155
+ * Edges are `Object.freeze()`d at construction — type `readonly` is
1156
+ * compile-time; freeze is the runtime enforcement.
1157
+ */
1158
+ readonly dataEdges: readonly {
1159
+ readonly from: number;
1160
+ readonly to: number;
1161
+ readonly key: string;
1162
+ }[];
1163
+ }
1164
+ interface CommitFlowRecorderHandle {
1165
+ /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`
1166
+ * AND `executor.attachScopeRecorder()`. */
1167
+ recorder: MinimalCommitFlowRecorder;
1168
+ /** Returns a defensive copy of the current index state. */
1169
+ getIndex(): CommitFlowIndex;
1170
+ /** Pub-sub: returns unsubscribe. */
1171
+ subscribe(listener: () => void): () => void;
1172
+ /** Monotonic version counter — bumps on Scope/Flow event OR when
1173
+ * the structure translator's version bumps. */
1174
+ version(): number;
1175
+ /** Reset runtime state. Does NOT bump version or notify (consistent
1176
+ * with other translators' reset contracts). */
1177
+ reset(): void;
1178
+ }
1179
+ interface CreateCommitFlowRecorderOptions {
1180
+ /** Recorder id (surfaces in error attribution). */
1181
+ id?: string;
1182
+ /** REQUIRED — structure translator handle for structural prev/next
1183
+ * projection. CommitFlow subscribes to its version. */
1184
+ structure: TraceStructureRecorderHandle;
1185
+ }
1186
+ declare function createCommitFlowRecorder(options: CreateCommitFlowRecorderOptions): CommitFlowRecorderHandle;
1187
+ /**
1188
+ * Walk data-dependency edges BACKWARD from a starting commit. Returns
1189
+ * the lineage chain — every ancestor commit whose writes transitively
1190
+ * contributed to the starting commit's reads.
1191
+ *
1192
+ * BFS order, commitIdx-ascending (oldest first). Includes the starting
1193
+ * commit at the END of the returned array.
1194
+ *
1195
+ * Cycle defense: visited set + recursion cap at `index.commits.length`
1196
+ * (per L8 panel must-fix — defends against future malformed graphs).
1197
+ *
1198
+ * @example
1199
+ * ```ts
1200
+ * const lineage = backtraceDataFlow(commitIndex, asRuntimeStageId('finalize-order#3'));
1201
+ * // → [load-order#0, check-inventory#1, run-fraud-check#2, finalize-order#3]
1202
+ * // (the commits whose updates fed FinalizeOrder's reads)
1203
+ * ```
1204
+ */
1205
+ declare function backtraceDataFlow(index: CommitFlowIndex, startRuntimeStageId: RuntimeStageId): CommitView[];
1206
+
1207
+ /**
1208
+ * `createTraceBundle` — one factory wires every shipped translator
1209
+ * + provides a single `attachTo(executor)` call that registers all
1210
+ * runtime recorders.
1211
+ *
1212
+ * Bundle shape (as of L8.2)
1213
+ * ─────────────────────────
1214
+ * - `structure` — build-time `TraceGraph` (StructureRecorder).
1215
+ * - `runtimeOverlay` — execution overlay for time-travel (FlowRecorder).
1216
+ * - `nodeView` — per-stage summary index, CombinedRecorder
1217
+ * (FlowRecorder + ScopeRecorder).
1218
+ * - `commitFlow` — per-commit summary + data-lineage,
1219
+ * CombinedRecorder (ScopeRecorder + FlowRecorder).
1220
+ *
1221
+ * Goal: collapse the 5-line "create + attach + subscribe" boilerplate
1222
+ * into one call for the common case. Consumers that want à-la-carte
1223
+ * setup can still construct each translator directly (the underlying
1224
+ * factories are unchanged).
1225
+ *
1226
+ * Independence: each translator subscribes ONLY to `structure` (per
1227
+ * L8.1 Panel 1 rule — translators must never subscribe to peers).
1228
+ * Linear dependency tree keeps notify cascades O(depth), not O(N²).
1229
+ *
1230
+ * @example
1231
+ * ```tsx
1232
+ * import { createTraceBundle } from 'footprint-explainable-ui/flowchart';
1233
+ *
1234
+ * function MyTraceUI() {
1235
+ * const bundle = useMemo(() => createTraceBundle(), []);
1236
+ * useEffect(() => {
1237
+ * const chart = flowChart('seed', fn, 'seed', {
1238
+ * structureRecorders: [bundle.structure.recorder],
1239
+ * }).addFunction('a', fnA, 'a').build();
1240
+ * const executor = new FlowChartExecutor(chart);
1241
+ * bundle.attachTo(executor);
1242
+ * executor.run({ input });
1243
+ * }, [bundle]);
1244
+ *
1245
+ * return <TracedFlow recorder={bundle.structure} overlay={bundle.runtimeOverlay} />;
1246
+ * }
1247
+ * ```
1248
+ *
1249
+ * **Recorder-attach lifecycle**: `attachTo(executor)` attaches THREE
1250
+ * FlowRecorders (`runtimeOverlay`, `nodeView`, `commitFlow`) and TWO
1251
+ * ScopeRecorders (`nodeView`, `commitFlow`). Each translator has a
1252
+ * distinct `recorder.id`, so footprintjs's id-idempotency rule
1253
+ * doesn't collide. The build-time `structure.recorder` is NOT
1254
+ * auto-attached — it must be passed to `flowChart(..., {
1255
+ * structureRecorders: [...] })` because builder recorders register
1256
+ * BEFORE `executor` exists. Consumers wire that one explicitly (see
1257
+ * example above). This matches footprintjs's two-phase recorder
1258
+ * model (build vs runtime).
1259
+ */
1260
+
1261
+ /** Minimal executor surface — mirrors the bits of footprintjs's
1262
+ * `FlowChartExecutor` the bundle calls into. Local to keep
1263
+ * explainable-ui dep-free from footprintjs. */
1264
+ interface MinimalExecutor {
1265
+ attachFlowRecorder(recorder: unknown): void;
1266
+ attachScopeRecorder?(recorder: unknown): void;
1267
+ }
1268
+ interface TraceBundle {
1269
+ structure: TraceStructureRecorderHandle;
1270
+ runtimeOverlay: TraceRuntimeOverlayHandle;
1271
+ /** L8.1 — per-stage summary translator. Reads `prevIds`/`nextIds`
1272
+ * from `structure` (no duplication), accumulates `executions[]`
1273
+ * + commit refs from Flow + Scope events. */
1274
+ nodeView: NodeViewRecorderHandle;
1275
+ /** L8.2 — per-commit summary translator. Owns canonical CommitView[].
1276
+ * Derives structural prev/next from `structure`, runtimePrev/Next
1277
+ * from "most-recent-per-prev" over commitLog, and dataDependencies
1278
+ * via findLastWriter per read key. */
1279
+ commitFlow: CommitFlowRecorderHandle;
1280
+ /**
1281
+ * Attach RUNTIME recorders (FlowRecorder, ScopeRecorder) to a
1282
+ * footprintjs executor. The build-time `structure.recorder` is NOT
1283
+ * covered — pass it to `flowChart(..., { structureRecorders: [...] })`
1284
+ * at construction time instead (see file header example).
1285
+ */
1286
+ attachTo(executor: MinimalExecutor): void;
1287
+ }
1288
+ interface CreateTraceBundleOptions {
1289
+ /** Per-translator options. All optional. */
1290
+ structure?: CreateTraceStructureRecorderOptions;
1291
+ runtimeOverlay?: CreateTraceRuntimeOverlayOptions;
1292
+ nodeView?: Omit<CreateNodeViewRecorderOptions, "structure">;
1293
+ commitFlow?: Omit<CreateCommitFlowRecorderOptions, "structure">;
1294
+ }
1295
+ declare function createTraceBundle(options?: CreateTraceBundleOptions): TraceBundle;
1296
+
1297
+ /**
1298
+ * `useTranslator(handle, getSnapshot)` — React adapter for any translator
1299
+ * exposing the standard `subscribe()` + `version()` shape.
1300
+ *
1301
+ * Wraps `useSyncExternalStore` so consumers don't repeat the boilerplate
1302
+ * for every translator. The `version` is the snapshot identity — when it
1303
+ * changes, React re-renders; `getSnapshot` then returns the consumer-
1304
+ * chosen view (full graph, slice, etc.).
1305
+ *
1306
+ * @example
1307
+ * ```tsx
1308
+ * const trace = useMemo(() => createTraceStructureRecorder(), []);
1309
+ * const graph = useTranslator(trace, () => trace.getGraph());
1310
+ * return <TraceFlow graph={graph} />;
1311
+ * ```
1312
+ *
1313
+ * **Why a hook (vs each component wiring `useSyncExternalStore` itself)**:
1314
+ * three reasons. (1) Reduces 4 lines of `useSyncExternalStore + useMemo`
1315
+ * boilerplate to one line. (2) Standardises the snapshot-identity
1316
+ * convention (version int) — consumers can't accidentally pass a getter
1317
+ * whose return identity changes every call (which would re-render
1318
+ * forever). (3) Stable subscribe/getVersion refs via memoization on the
1319
+ * handle identity — no re-subscribe on parent re-renders.
1320
+ */
1321
+ interface TranslatorHandleLike {
1322
+ subscribe(listener: () => void): () => void;
1323
+ version(): number;
1324
+ }
1325
+ /**
1326
+ * Subscribe to a translator + return a typed snapshot computed by the
1327
+ * caller. The snapshot recomputes whenever `version()` changes.
1328
+ *
1329
+ * `getSnapshot` is called inside a `useMemo` keyed on the version
1330
+ * integer — so consumers can return fresh objects from `getSnapshot`
1331
+ * (e.g., `handle.getGraph()` returns a defensive copy) without
1332
+ * triggering infinite re-renders.
1333
+ */
1334
+ declare function useTranslator<T>(handle: TranslatorHandleLike, getSnapshot: () => T): T;
1335
+
1336
+ /**
1337
+ * Graph traversal helpers — pure functions over a `NodeViewIndex`.
1338
+ *
1339
+ * Bi-directional structural walks (`walkForward` / `walkBackward`) plus
1340
+ * convenience wrappers (`backtraceStructural` / `forwardtraceStructural`).
1341
+ *
1342
+ * Cycle defense (panel L8 must-fix)
1343
+ * ──────────────────────────────────
1344
+ * Every traversal carries a `visited: Set<StageId>` and caps recursion
1345
+ * at `index.all.length` (the total node count). Defends against:
1346
+ * - Future bugs where a malformed graph includes a non-loop cycle
1347
+ * - Manual edge injection bypassing the structure-recorder fix
1348
+ * - Duplicate edges that survive dedupe due to source/target
1349
+ * collisions
1350
+ * Loop back-edges (`data.kind === 'loop'`) already excluded at the
1351
+ * structure-recorder layer (invariant I1), so they never enter
1352
+ * `prevIds`/`nextIds` — no extra filtering here.
1353
+ *
1354
+ * BFS order
1355
+ * ─────────
1356
+ * Walks return nodes in BFS order — root first, then immediate
1357
+ * neighbors, then their neighbors. Matches breadcrumb-friendly
1358
+ * "closest-first" display order.
1359
+ *
1360
+ * Always-arrays returns
1361
+ * ─────────────────────
1362
+ * All helpers return `NodeView[]`. Empty array (NOT null/undefined)
1363
+ * means "no path" or "node not found". Consumers `.map()` /
1364
+ * `.length`-check without null-handling boilerplate.
1365
+ */
1366
+
1367
+ interface WalkOptions {
1368
+ /** Hard cap on hops. Default: `index.all.length` (one full traversal). */
1369
+ maxDepth?: number;
1370
+ /** When true, only return nodes that have `visitedInRun === true`.
1371
+ * Useful for "in THIS run, what fed me?" queries (runtime-aware walk). */
1372
+ onlyVisited?: boolean;
1373
+ /** When true, INCLUDE the start node in the returned array. Default:
1374
+ * false (caller already has the start node; the walk returns its
1375
+ * ancestors/descendants). */
1376
+ includeStart?: boolean;
1377
+ }
1378
+ /**
1379
+ * Walk forward (`nextIds`) from `startId`. BFS order. Cycle-safe.
1380
+ * Returns `[]` if `startId` is unknown.
1381
+ *
1382
+ * Convergence semantics: a node reachable via multiple paths appears
1383
+ * ONCE in the result (visited-set dedupes).
1384
+ */
1385
+ declare function walkForward(index: NodeViewIndex, startId: StageId, options?: WalkOptions): NodeView[];
1386
+ /**
1387
+ * Walk backward (`prevIds`) from `startId`. BFS order. Cycle-safe.
1388
+ * Returns `[]` if `startId` is unknown.
1389
+ *
1390
+ * Convergence semantics: a fork-join's `walkBackward` returns BOTH
1391
+ * branch parents (and their ancestors), each once.
1392
+ */
1393
+ declare function walkBackward(index: NodeViewIndex, startId: StageId, options?: WalkOptions): NodeView[];
1394
+ /**
1395
+ * Backtrace from `stageId` to a structural root (no prev) OR a split
1396
+ * point (multiple prevs). Returns the chain from `stageId` BACK to
1397
+ * the root, root-first. Includes `stageId` at the END.
1398
+ *
1399
+ * Defines "split" as `prevIds.length > 1 OR prevIds.length === 0`
1400
+ * (per L8 panel recommendation) — stops at convergence points AND at
1401
+ * the seed. Useful for breadcrumb display where "innermost serial
1402
+ * run" is the meaningful path.
1403
+ */
1404
+ declare function backtraceStructural(index: NodeViewIndex, stageId: StageId, options?: Pick<WalkOptions, "maxDepth" | "onlyVisited">): NodeView[];
1405
+ /**
1406
+ * Forward-trace from `stageId` to a structural leaf (no next) OR a
1407
+ * fork point (multiple nexts). Returns the chain from `stageId`
1408
+ * FORWARD to the leaf/fork, with `stageId` at the START.
1409
+ */
1410
+ declare function forwardtraceStructural(index: NodeViewIndex, stageId: StageId, options?: Pick<WalkOptions, "maxDepth" | "onlyVisited">): NodeView[];
1411
+
1412
+ interface NodeInspectorProps extends BaseComponentProps {
1413
+ /** The NodeView index (from `nodeView.getIndex()` or `useTranslator`).
1414
+ *
1415
+ * **Pure data prop** (NOT the recorder handle) — by design. Lets
1416
+ * consumers wrap in `useTranslator(nodeView, () => nodeView.getIndex())`
1417
+ * at the parent, or pass a static index from tests / Storybook /
1418
+ * SSR. Mirrors `<CommitInspector index={...}>` for consistency. */
1419
+ index: NodeViewIndex;
1420
+ /** Which stage to inspect. When `null`, renders the placeholder. */
1421
+ selectedId: StageId | null;
1422
+ /** Click handler — receives a stageId for breadcrumb navigation. */
1423
+ onNavigate?: (stageId: StageId) => void;
1424
+ /** When true, the prev/next chains include only `visitedInRun` nodes
1425
+ * (runtime-filtered view). */
1426
+ onlyVisited?: boolean;
1427
+ }
1428
+ declare function NodeInspector({ index, selectedId, onNavigate, onlyVisited, className, style, }: NodeInspectorProps): react_jsx_runtime.JSX.Element;
1429
+
1430
+ interface CommitInspectorProps extends BaseComponentProps {
1431
+ /** The CommitFlow index (from `commitFlow.getIndex()` or `useTranslator`).
1432
+ *
1433
+ * **Pure data prop** (NOT the recorder handle) — by design. Lets
1434
+ * consumers wrap in `useTranslator(commitFlow, () => commitFlow.getIndex())`
1435
+ * at the parent, or pass a static index from tests / Storybook /
1436
+ * SSR. Mirrors `<NodeInspector index={...}>` for consistency. */
1437
+ index: CommitFlowIndex;
1438
+ /** Which commit to inspect (by runtimeStageId). null → placeholder. */
1439
+ selectedRuntimeStageId: RuntimeStageId | null;
1440
+ /** Click handler — receives a runtimeStageId for time-travel
1441
+ * navigation. Used by all clickable references (runtime prev/next,
1442
+ * data-dep sources, lineage chain). */
1443
+ onNavigate?: (runtimeStageId: RuntimeStageId) => void;
1444
+ }
1445
+ declare function CommitInspector({ index, selectedRuntimeStageId, onNavigate, className, style, }: CommitInspectorProps): react_jsx_runtime.JSX.Element;
1446
+
1447
+ /**
1448
+ * Series-parallel chain tree builders — pure functions over `TraceGraph`
1449
+ * (structural) + `CommitFlowIndex` (runtime).
1450
+ *
1451
+ * When to reach for this vs. flat commitLog
1452
+ * ─────────────────────────────────────────
1453
+ * Use `commitLog` when you want chronological replay / slider scrubbing
1454
+ * ("what happened in order"). Use the chain tree when you want to
1455
+ * render parallel structure visually or answer "which branch ran?"
1456
+ * questions — flat `commitLog[idx-1]` loses the fork shape.
1457
+ *
1458
+ * Pairs with `<CommitInspector>` for git-log-style master/detail —
1459
+ * `<CommitChainView>` picks, `<CommitInspector>` inspects.
1460
+ * Complements the per-stage view from `createNodeViewRecorder`.
1461
+ *
1462
+ * Why a chain tree
1463
+ * ────────────────
1464
+ * Footprintjs charts are **series-parallel DAGs by construction** —
1465
+ * the builder primitives compose serially (`addFunction`) or in
1466
+ * parallel (`addListOfFunction` / `addDeciderFunction`). Series-
1467
+ * parallel DAGs are provably representable as expression trees,
1468
+ * so we can decompose any footprintjs chart into a nested
1469
+ * `(serial | parallel | leaf)` shape that renders cleanly as
1470
+ * swim lanes.
1471
+ *
1472
+ * Two builders, one tree shape
1473
+ * ────────────────────────────
1474
+ * - `structureAsChainTree(graph, options?)` — STRUCTURAL view.
1475
+ * No commitLog. Decomposes the chart shape into S-P primitives.
1476
+ * Renders the full chart (all branches of a decider, etc.) even
1477
+ * before running.
1478
+ *
1479
+ * - `buildCommitChainTree(graph, commitFlow, options?)` — RUNTIME
1480
+ * view. Each leaf carries the commits[] that fired for that stage
1481
+ * in this run. Loops produce a leaf with N commits. Branches that
1482
+ * never executed in this run appear as empty `commits[]` leaves
1483
+ * (consumer can filter).
1484
+ *
1485
+ * Algorithm scope (correctness contract)
1486
+ * ──────────────────────────────────────
1487
+ * These builders are tuned for **series-parallel charts** — every
1488
+ * fork in footprintjs's builder has a matching merge point. For
1489
+ * non-S-P or malformed graphs the tree is still finite and stable
1490
+ * (cycle defense guarantees termination), but the shape may not
1491
+ * reflect a clean S-P decomposition.
1492
+ *
1493
+ * - Forks with **no common descendant** drop the outer-walk tail at
1494
+ * the fork node. Real footprintjs charts always re-merge.
1495
+ * - Edges with `data.kind === undefined` are treated as `'next'`.
1496
+ * Multiple linear-next edges from a single source follow only the
1497
+ * first (deterministic by insertion order); a dev-mode warning
1498
+ * fires when this is observed (`isDevMode()` from footprintjs).
1499
+ *
1500
+ * Cycle defense (L8 panel must-fix carried forward)
1501
+ * ─────────────────────────────────────────────────
1502
+ * Every recursive walk carries a `visited: Set<StageId>` to defend
1503
+ * against malformed graphs (manual edge injection, future builder
1504
+ * bugs). Loop edges (`kind === 'loop'`) are excluded at the
1505
+ * structure-recorder layer per invariant I1, so they never enter
1506
+ * prev/next — no extra filtering needed here. Convergence detection
1507
+ * uses BFS bounded by `graph.nodes.length`.
1508
+ *
1509
+ * @example
1510
+ * ```ts
1511
+ * const trace = createTraceStructureRecorder();
1512
+ * // ... build a fork chart ...
1513
+ *
1514
+ * const sChain = structureAsChainTree(trace.getGraph());
1515
+ * // → { kind: 'serial', items: [
1516
+ * // { kind: 'leaf', stageId: 'LoadOrder' },
1517
+ * // { kind: 'parallel', branches: [
1518
+ * // { kind: 'leaf', stageId: 'CheckInventory' },
1519
+ * // { kind: 'leaf', stageId: 'RunFraudCheck' },
1520
+ * // ]},
1521
+ * // { kind: 'leaf', stageId: 'FinalizeOrder' },
1522
+ * // ]}
1523
+ *
1524
+ * const commitFlow = createCommitFlowRecorder({ structure: trace });
1525
+ * // ... run chart ...
1526
+ * const cChain = buildCommitChainTree(trace.getGraph(), commitFlow.getIndex());
1527
+ * // → same shape, but each leaf carries `commits: CommitView[]`
1528
+ * ```
1529
+ */
1530
+
1531
+ /** Structural chain tree leaf (no commits). */
1532
+ interface StructureChainLeaf {
1533
+ readonly kind: "leaf";
1534
+ readonly stageId: StageId;
1535
+ }
1536
+ /** Structural chain tree node — recursive S-P composition over stage ids. */
1537
+ type StructureChain = StructureChainLeaf | {
1538
+ readonly kind: "serial";
1539
+ readonly items: readonly StructureChain[];
1540
+ } | {
1541
+ readonly kind: "parallel";
1542
+ readonly branches: readonly StructureChain[];
1543
+ };
1544
+ /** Commit chain tree leaf — carries all commits for the stage (loop-aware). */
1545
+ interface CommitChainLeaf {
1546
+ readonly kind: "leaf";
1547
+ readonly stageId: StageId;
1548
+ /** All commits that fired for this stage in this run, in commitIdx
1549
+ * ascending order. Loop iteration N has commits[N]. Empty array
1550
+ * when the stage never executed in this run.
1551
+ *
1552
+ * **Ownership**: references are shared with
1553
+ * `CommitFlowIndex.commits` (no deep copy). The same shallow-copy /
1554
+ * nested-shared-value contract documented on `CommitView.updates`
1555
+ * applies. Do not mutate. */
1556
+ readonly commits: readonly CommitView[];
1557
+ }
1558
+ /** Commit chain tree — recursive S-P composition with commit leaves. */
1559
+ type CommitChain = CommitChainLeaf | {
1560
+ readonly kind: "serial";
1561
+ readonly items: readonly CommitChain[];
1562
+ } | {
1563
+ readonly kind: "parallel";
1564
+ readonly branches: readonly CommitChain[];
1565
+ };
1566
+ interface ChainTreeOptions {
1567
+ /** Stage id to start the walk from. Defaults to the chart's seed
1568
+ * (first node with no incoming non-loop edge). */
1569
+ rootStageId?: StageId;
1570
+ }
1571
+ /**
1572
+ * Build a structural chain tree for a chart. Pure function over
1573
+ * `TraceGraph` — no runtime data required. Useful for rendering the
1574
+ * chart shape before any execution (static documentation, etc.).
1575
+ */
1576
+ declare function structureAsChainTree(graph: TraceGraph, options?: ChainTreeOptions): StructureChain | null;
1577
+ /**
1578
+ * Build a commit-decorated chain tree. Same S-P shape as
1579
+ * `structureAsChainTree`, but each leaf carries the commits[] that
1580
+ * fired for that stage in this run (in commitIdx ascending order).
1581
+ *
1582
+ * Loop semantics: a stage that ran N times has a leaf with
1583
+ * `commits.length === N`. The consumer's renderer decides whether to
1584
+ * display them as a single "ran 3×" badge or unroll into N visible
1585
+ * boxes — both views are supported by the same data.
1586
+ *
1587
+ * Branches that never executed in this run appear with empty
1588
+ * `commits[]`. Consumers wanting "runtime-only" view can filter them
1589
+ * out.
1590
+ */
1591
+ declare function buildCommitChainTree(graph: TraceGraph, commitFlow: CommitFlowIndex, options?: ChainTreeOptions): CommitChain | null;
1592
+
1593
+ interface CommitChainViewProps extends BaseComponentProps {
1594
+ /** The chain tree. Accepts BOTH `CommitChain` (from
1595
+ * `buildCommitChainTree`) and `StructureChain` (from
1596
+ * `structureAsChainTree` — pre-execution view). null → placeholder. */
1597
+ chain: CommitChain | StructureChain | null;
1598
+ /** Highlighted commit (by runtimeStageId). Only meaningful for
1599
+ * `CommitChain` input (StructureChain has no commits to select). */
1600
+ selectedRuntimeStageId?: RuntimeStageId | null;
1601
+ /** Fires when a commit box is clicked — pass to `<CommitInspector>`
1602
+ * for master/detail wiring. Not fired for "not executed" leaves. */
1603
+ onSelectCommit?: (runtimeStageId: RuntimeStageId) => void;
1604
+ /** Optional label resolver — default uses the bare stageId. Consumers
1605
+ * can map id → friendly name (e.g., from a NodeViewIndex). */
1606
+ resolveLabel?: (stageId: StageId) => string;
1607
+ /** Time-travel cursor: commits with `commitIdx > revealedThroughCommitIdx`
1608
+ * render dimmed (still visible — keeps layout stable). Pairs with
1609
+ * `<RunSlider>` in the ONE-CURSOR model.
1610
+ *
1611
+ * Semantics:
1612
+ * - `null` (default) — reveal ALL commits (no time-travel applied).
1613
+ * - `N >= 0` — reveal commits 0..N inclusive; dim commits with
1614
+ * `commitIdx > N`.
1615
+ * - `N < 0` (e.g., `-1`) — reveal NONE; all commits dim. Use this
1616
+ * sentinel for "cursor is stale / unresolved" so the chain doesn't
1617
+ * accidentally fall back to fully-revealed when the consumer wants
1618
+ * no-reveal. */
1619
+ revealedThroughCommitIdx?: number | null;
1620
+ }
1621
+ declare function CommitChainView({ chain, selectedRuntimeStageId, onSelectCommit, resolveLabel, revealedThroughCommitIdx, className, style, }: CommitChainViewProps): react_jsx_runtime.JSX.Element;
1622
+
1623
+ /**
1624
+ * Slot prop bags — slots receive PURE DATA (chain/index), NOT the
1625
+ * bundle. Mirrors the sibling-inspector convention so slot bodies are
1626
+ * usable from tests / Storybook / SSR and avoid re-subscribing to
1627
+ * translators. Each callback is wired by the shell to the shared
1628
+ * selection cursor.
1629
+ */
1630
+ interface ChainSlotProps {
1631
+ /** Live chain tree, derived from the bundle. `null` before any
1632
+ * commits arrive. */
1633
+ chain: CommitChain | null;
1634
+ /** Currently selected commit (shared cursor). */
1635
+ selectedRuntimeStageId: RuntimeStageId | null;
1636
+ /** Wire to the shared selection cursor. */
1637
+ onSelectCommit: (rsid: RuntimeStageId) => void;
1638
+ /** Time-travel reveal cursor (derived from selectedRuntimeStageId
1639
+ * via ONE-CURSOR model). Commits with commitIdx > this value
1640
+ * render dimmed. `null` reveals all, `-1` reveals none, `N >= 0`
1641
+ * reveals up to commit N. **Optional in custom slots** — slot
1642
+ * authors that don't implement time-travel dimming can ignore it
1643
+ * (matches the standalone `<CommitChainView>` prop optionality). */
1644
+ revealedThroughCommitIdx?: number | null;
1645
+ }
1646
+ interface CommitInspectorSlotProps {
1647
+ /** Live commitFlow index. */
1648
+ index: CommitFlowIndex;
1649
+ /** Currently selected commit (shared cursor). */
1650
+ selectedRuntimeStageId: RuntimeStageId | null;
1651
+ /** Wire to the shared selection cursor (e.g., for clickable
1652
+ * data-dep / lineage breadcrumbs). */
1653
+ onNavigate: (rsid: RuntimeStageId) => void;
1654
+ }
1655
+ interface NodeInspectorSlotProps {
1656
+ /** Live nodeView index. */
1657
+ index: NodeViewIndex;
1658
+ /** StageId derived from `selectedRuntimeStageId`. */
1659
+ selectedStageId: StageId | null;
1660
+ /** Wire to the shared selection cursor (e.g., for prev/next chain
1661
+ * breadcrumbs). Resolves the stage to its first commit. */
1662
+ onNavigate: (stageId: StageId) => void;
1663
+ }
1664
+ interface SliderSlotProps {
1665
+ /** Live commitFlow index. */
1666
+ index: CommitFlowIndex;
1667
+ /** Currently selected commit — same cursor as the chain selection
1668
+ * per the ONE-CURSOR model. */
1669
+ cursorRuntimeStageId: RuntimeStageId | null;
1670
+ /** Wire to the shared selection cursor. */
1671
+ onCursorChange: (rsid: RuntimeStageId | null) => void;
1672
+ }
1673
+ interface TraceExplorerSlots {
1674
+ /** Override the chain (master) pane. Use to swap the swim-lane
1675
+ * renderer for a timeline/Gantt/custom layout while keeping the
1676
+ * same selection contract. */
1677
+ chain?: React.ComponentType<ChainSlotProps>;
1678
+ /** Override the commit (detail) pane. Use to add custom commit-
1679
+ * detail formatting (e.g., domain-specific updates rendering). */
1680
+ commitInspector?: React.ComponentType<CommitInspectorSlotProps>;
1681
+ /** Override the node (stage-summary) pane. Use to surface per-stage
1682
+ * custom KPIs / annotations alongside the default execution data. */
1683
+ nodeInspector?: React.ComponentType<NodeInspectorSlotProps>;
1684
+ /** Override the slider (top time-travel bar). Pass `null` to HIDE
1685
+ * the slider entirely (e.g., for static post-run views with no
1686
+ * scrub affordance). */
1687
+ slider?: React.ComponentType<SliderSlotProps> | null;
1688
+ }
1689
+ interface TraceExplorerShellProps extends BaseComponentProps {
1690
+ /** The translator bundle from `createTraceBundle()`. MUST have had
1691
+ * `bundle.attachTo(executor)` called before any commits arrive,
1692
+ * otherwise every pane shows its placeholder. */
1693
+ bundle: TraceBundle;
1694
+ /** Controlled selection (omit for uncontrolled). `null` clears. */
1695
+ selectedRuntimeStageId?: RuntimeStageId | null;
1696
+ /** Fires on selection changes. In controlled mode, required for
1697
+ * selection to take effect. In uncontrolled mode, fires as an
1698
+ * observation hook (logging/analytics) — the shell still owns the
1699
+ * state.
1700
+ *
1701
+ * Memoize via `useCallback` to avoid downstream re-renders. */
1702
+ onSelectionChange?: (rsid: RuntimeStageId | null) => void;
1703
+ /** Optional slot overrides. Should be stable across renders
1704
+ * (define at module scope or `useMemo`). */
1705
+ slots?: TraceExplorerSlots;
1706
+ }
1707
+ declare function TraceExplorerShell({ bundle, selectedRuntimeStageId: controlledSel, onSelectionChange, slots, className, style, }: TraceExplorerShellProps): react_jsx_runtime.JSX.Element;
1708
+
1709
+ interface RunSliderProps extends BaseComponentProps {
1710
+ /** Live commit flow index (pure data prop — pass via
1711
+ * `useTranslator(commitFlow, () => commitFlow.getIndex())`).
1712
+ * Source: `createCommitFlowRecorder` — see `<CommitInspector>` for
1713
+ * the canonical consumer pattern. */
1714
+ index: CommitFlowIndex;
1715
+ /** The shared time cursor. `null` = no commit yet selected (slider
1716
+ * sits at value 0). */
1717
+ cursorRuntimeStageId: RuntimeStageId | null;
1718
+ /** Fires when the slider moves. */
1719
+ onCursorChange: (rsid: RuntimeStageId | null) => void;
1720
+ /** Optional label callback. Default renders `"#commitIdx · stageId"`.
1721
+ * Receives the full resolved `commit` + the `index` for richer
1722
+ * labels (step name, duration from a sibling translator, etc.). */
1723
+ renderLabel?: (info: {
1724
+ commitIdx: number;
1725
+ total: number;
1726
+ runtimeStageId: RuntimeStageId | null;
1727
+ /** Resolved commit at the cursor, or `null` when index is empty. */
1728
+ commit: CommitView | null;
1729
+ /** Full index — for cross-lookups (e.g., finding the previous
1730
+ * commit's stage label). */
1731
+ index: CommitFlowIndex;
1732
+ }) => React.ReactNode;
1733
+ }
1734
+ declare function RunSlider({ index, cursorRuntimeStageId, onCursorChange, renderLabel, className, style, }: RunSliderProps): react_jsx_runtime.JSX.Element;
296
1735
 
297
- export { type BreadcrumbEntry, type ExecutionOverlay, type FlowchartColors, FlowchartView, type FlowchartViewProps, type LayoutEdge, type LayoutNode, type SpecLayout, type SpecNode, StageNode, type StageNodeData, SubflowBreadcrumb, type SubflowBreadcrumbProps, type SubflowNavigation, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, TimeTravelDebugger, type TimeTravelDebuggerProps, TracedFlowchartView, type TracedFlowchartViewProps, applyOverlay, specToLayout, specToReactFlow, useSubflowNavigation };
1736
+ export { type BreadcrumbEntry, type ChainSlotProps, type ChainTreeOptions, type CommitChain, type CommitChainLeaf, CommitChainView, type CommitChainViewProps, type CommitFlowIndex, type CommitFlowRecorderHandle, CommitInspector, type CommitInspectorProps, type CommitInspectorSlotProps, type CommitView, type CreateCommitFlowRecorderOptions, type CreateNodeViewRecorderOptions, type CreateTraceBundleOptions, type CreateTraceRuntimeOverlayOptions, type CreateTraceStructureRecorderOptions, type DataDependency, type ExecutionRecord, type MinimalCommitFlowRecorder, type MinimalFlowRecorder, type MinimalNodeViewRecorder, type MinimalStructureRecorder, NodeInspector, type NodeInspectorProps, type NodeInspectorSlotProps, type NodeView, type NodeViewIndex, type NodeViewRecorderHandle, RunSlider, type RunSliderProps, type RuntimeExecutionStep, type RuntimeOverlay, type RuntimeOverlaySlice, type RuntimeStageId, type SliderSlotProps, type StageId, StageNode, type StageNodeData, type StructureChain, type StructureChainLeaf, SubflowBreadcrumb, type SubflowBreadcrumbProps, type SubflowNavigation, SubflowTree, type SubflowTreeEntry, type SubflowTreeProps, TimeTravelDebugger, type TimeTravelDebuggerProps, type TraceBundle, type TraceEdge, type TraceEdgeData, TraceExplorerShell, type TraceExplorerShellProps, type TraceExplorerSlots, TraceFlow, type TraceFlowEdgeColors, type TraceFlowLayout, type TraceFlowProps, type TraceGraph, type TraceNode, type TraceNodeData, type TraceRuntimeOverlayHandle, type TraceStructureRecorderHandle, TracedFlow, type TracedFlowColors, type TracedFlowProps, type TranslatorHandleLike, type WalkOptions, asRuntimeStageId, asStageId, backtraceDataFlow, backtraceStructural, buildCommitChainTree, createCommitFlowRecorder, createNodeViewRecorder, createTraceBundle, createTraceRuntimeOverlay, createTraceStructureRecorder, defaultTraceFlowLayout, forwardtraceStructural, sliceOverlay, structureAsChainTree, useSubflowNavigation, useTranslator, walkBackward, walkForward };