footprint-explainable-ui 0.20.0 → 0.22.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 (149) hide show
  1. package/README.md +1 -0
  2. package/dist/flowchart.cjs +1366 -343
  3. package/dist/flowchart.cjs.map +1 -1
  4. package/dist/flowchart.d.cts +513 -6
  5. package/dist/flowchart.d.ts +513 -6
  6. package/dist/flowchart.js +1257 -262
  7. package/dist/flowchart.js.map +1 -1
  8. package/dist/index.cjs +941 -436
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +6 -0
  11. package/dist/index.d.ts +6 -0
  12. package/dist/index.js +852 -352
  13. package/dist/index.js.map +1 -1
  14. package/package.json +10 -3
  15. package/dist/adapters/fromRuntimeSnapshot.d.ts +0 -81
  16. package/dist/adapters/fromRuntimeSnapshot.d.ts.map +0 -1
  17. package/dist/adapters/fromRuntimeSnapshot.js +0 -226
  18. package/dist/adapters/fromRuntimeSnapshot.js.map +0 -1
  19. package/dist/components/ExplainableShell/ExplainableShell.d.ts +0 -169
  20. package/dist/components/ExplainableShell/ExplainableShell.d.ts.map +0 -1
  21. package/dist/components/ExplainableShell/ExplainableShell.js +0 -702
  22. package/dist/components/ExplainableShell/ExplainableShell.js.map +0 -1
  23. package/dist/components/ExplainableShell/index.d.ts +0 -3
  24. package/dist/components/ExplainableShell/index.d.ts.map +0 -1
  25. package/dist/components/ExplainableShell/index.js +0 -2
  26. package/dist/components/ExplainableShell/index.js.map +0 -1
  27. package/dist/components/FlowchartView/SubflowBreadcrumb.d.ts +0 -11
  28. package/dist/components/FlowchartView/SubflowBreadcrumb.d.ts.map +0 -1
  29. package/dist/components/FlowchartView/SubflowBreadcrumb.js +0 -49
  30. package/dist/components/FlowchartView/SubflowBreadcrumb.js.map +0 -1
  31. package/dist/components/FlowchartView/SubflowTree.d.ts +0 -29
  32. package/dist/components/FlowchartView/SubflowTree.d.ts.map +0 -1
  33. package/dist/components/FlowchartView/SubflowTree.js +0 -153
  34. package/dist/components/FlowchartView/SubflowTree.js.map +0 -1
  35. package/dist/components/FlowchartView/index.d.ts +0 -39
  36. package/dist/components/FlowchartView/index.d.ts.map +0 -1
  37. package/dist/components/FlowchartView/index.js +0 -26
  38. package/dist/components/FlowchartView/index.js.map +0 -1
  39. package/dist/components/FlowchartView/useSubflowNavigation.d.ts +0 -60
  40. package/dist/components/FlowchartView/useSubflowNavigation.d.ts.map +0 -1
  41. package/dist/components/FlowchartView/useSubflowNavigation.js +0 -99
  42. package/dist/components/FlowchartView/useSubflowNavigation.js.map +0 -1
  43. package/dist/components/GanttTimeline/GanttTimeline.d.ts +0 -18
  44. package/dist/components/GanttTimeline/GanttTimeline.d.ts.map +0 -1
  45. package/dist/components/GanttTimeline/GanttTimeline.js +0 -123
  46. package/dist/components/GanttTimeline/GanttTimeline.js.map +0 -1
  47. package/dist/components/GanttTimeline/index.d.ts +0 -3
  48. package/dist/components/GanttTimeline/index.d.ts.map +0 -1
  49. package/dist/components/GanttTimeline/index.js +0 -2
  50. package/dist/components/GanttTimeline/index.js.map +0 -1
  51. package/dist/components/MemoryInspector/MemoryInspector.d.ts +0 -19
  52. package/dist/components/MemoryInspector/MemoryInspector.d.ts.map +0 -1
  53. package/dist/components/MemoryInspector/MemoryInspector.js +0 -118
  54. package/dist/components/MemoryInspector/MemoryInspector.js.map +0 -1
  55. package/dist/components/MemoryInspector/index.d.ts +0 -3
  56. package/dist/components/MemoryInspector/index.d.ts.map +0 -1
  57. package/dist/components/MemoryInspector/index.js +0 -2
  58. package/dist/components/MemoryInspector/index.js.map +0 -1
  59. package/dist/components/NarrativeLog/NarrativeLog.d.ts +0 -15
  60. package/dist/components/NarrativeLog/NarrativeLog.d.ts.map +0 -1
  61. package/dist/components/NarrativeLog/NarrativeLog.js +0 -65
  62. package/dist/components/NarrativeLog/NarrativeLog.js.map +0 -1
  63. package/dist/components/NarrativeLog/index.d.ts +0 -3
  64. package/dist/components/NarrativeLog/index.d.ts.map +0 -1
  65. package/dist/components/NarrativeLog/index.js +0 -2
  66. package/dist/components/NarrativeLog/index.js.map +0 -1
  67. package/dist/components/NarrativeTrace/NarrativeTrace.d.ts +0 -13
  68. package/dist/components/NarrativeTrace/NarrativeTrace.d.ts.map +0 -1
  69. package/dist/components/NarrativeTrace/NarrativeTrace.js +0 -134
  70. package/dist/components/NarrativeTrace/NarrativeTrace.js.map +0 -1
  71. package/dist/components/NarrativeTrace/index.d.ts +0 -3
  72. package/dist/components/NarrativeTrace/index.d.ts.map +0 -1
  73. package/dist/components/NarrativeTrace/index.js +0 -2
  74. package/dist/components/NarrativeTrace/index.js.map +0 -1
  75. package/dist/components/ResultPanel/ResultPanel.d.ts +0 -11
  76. package/dist/components/ResultPanel/ResultPanel.d.ts.map +0 -1
  77. package/dist/components/ResultPanel/ResultPanel.js +0 -54
  78. package/dist/components/ResultPanel/ResultPanel.js.map +0 -1
  79. package/dist/components/ResultPanel/index.d.ts +0 -3
  80. package/dist/components/ResultPanel/index.d.ts.map +0 -1
  81. package/dist/components/ResultPanel/index.js +0 -2
  82. package/dist/components/ResultPanel/index.js.map +0 -1
  83. package/dist/components/ScopeDiff/ScopeDiff.d.ts +0 -17
  84. package/dist/components/ScopeDiff/ScopeDiff.d.ts.map +0 -1
  85. package/dist/components/ScopeDiff/ScopeDiff.js +0 -87
  86. package/dist/components/ScopeDiff/ScopeDiff.js.map +0 -1
  87. package/dist/components/ScopeDiff/index.d.ts +0 -3
  88. package/dist/components/ScopeDiff/index.d.ts.map +0 -1
  89. package/dist/components/ScopeDiff/index.js +0 -2
  90. package/dist/components/ScopeDiff/index.js.map +0 -1
  91. package/dist/components/SnapshotPanel/SnapshotPanel.d.ts +0 -17
  92. package/dist/components/SnapshotPanel/SnapshotPanel.d.ts.map +0 -1
  93. package/dist/components/SnapshotPanel/SnapshotPanel.js +0 -85
  94. package/dist/components/SnapshotPanel/SnapshotPanel.js.map +0 -1
  95. package/dist/components/SnapshotPanel/index.d.ts +0 -3
  96. package/dist/components/SnapshotPanel/index.d.ts.map +0 -1
  97. package/dist/components/SnapshotPanel/index.js +0 -2
  98. package/dist/components/SnapshotPanel/index.js.map +0 -1
  99. package/dist/components/StageNode/StageNode.d.ts +0 -52
  100. package/dist/components/StageNode/StageNode.d.ts.map +0 -1
  101. package/dist/components/StageNode/StageNode.js +0 -314
  102. package/dist/components/StageNode/StageNode.js.map +0 -1
  103. package/dist/components/StageNode/index.d.ts +0 -3
  104. package/dist/components/StageNode/index.d.ts.map +0 -1
  105. package/dist/components/StageNode/index.js +0 -2
  106. package/dist/components/StageNode/index.js.map +0 -1
  107. package/dist/components/TimeTravelControls/TimeTravelControls.d.ts +0 -13
  108. package/dist/components/TimeTravelControls/TimeTravelControls.d.ts.map +0 -1
  109. package/dist/components/TimeTravelControls/TimeTravelControls.js +0 -120
  110. package/dist/components/TimeTravelControls/TimeTravelControls.js.map +0 -1
  111. package/dist/components/TimeTravelControls/index.d.ts +0 -3
  112. package/dist/components/TimeTravelControls/index.d.ts.map +0 -1
  113. package/dist/components/TimeTravelControls/index.js +0 -2
  114. package/dist/components/TimeTravelControls/index.js.map +0 -1
  115. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.d.ts +0 -33
  116. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.d.ts.map +0 -1
  117. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.js +0 -119
  118. package/dist/components/TimeTravelDebugger/TimeTravelDebugger.js.map +0 -1
  119. package/dist/components/TimeTravelDebugger/index.d.ts +0 -3
  120. package/dist/components/TimeTravelDebugger/index.d.ts.map +0 -1
  121. package/dist/components/TimeTravelDebugger/index.js +0 -2
  122. package/dist/components/TimeTravelDebugger/index.js.map +0 -1
  123. package/dist/flowchart.d.ts.map +0 -1
  124. package/dist/index.d.ts.map +0 -1
  125. package/dist/theme/ThemeProvider.d.ts +0 -27
  126. package/dist/theme/ThemeProvider.d.ts.map +0 -1
  127. package/dist/theme/ThemeProvider.js +0 -30
  128. package/dist/theme/ThemeProvider.js.map +0 -1
  129. package/dist/theme/index.d.ts +0 -9
  130. package/dist/theme/index.d.ts.map +0 -1
  131. package/dist/theme/index.js +0 -6
  132. package/dist/theme/index.js.map +0 -1
  133. package/dist/theme/presets.d.ts +0 -18
  134. package/dist/theme/presets.d.ts.map +0 -1
  135. package/dist/theme/presets.js +0 -92
  136. package/dist/theme/presets.js.map +0 -1
  137. package/dist/theme/styles.d.ts +0 -32
  138. package/dist/theme/styles.d.ts.map +0 -1
  139. package/dist/theme/styles.js +0 -37
  140. package/dist/theme/styles.js.map +0 -1
  141. package/dist/theme/tokens.d.ts +0 -49
  142. package/dist/theme/tokens.d.ts.map +0 -1
  143. package/dist/theme/tokens.js +0 -79
  144. package/dist/theme/tokens.js.map +0 -1
  145. package/dist/tsconfig.tsbuildinfo +0 -1
  146. package/dist/types.d.ts +0 -60
  147. package/dist/types.d.ts.map +0 -1
  148. package/dist/types.js +0 -2
  149. package/dist/types.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/flowchart.ts","../src/components/StageNode/StageNode.tsx","../src/theme/ThemeProvider.tsx","../src/theme/tokens.ts","../src/theme/styles.ts","../src/theme/useDarkModeTokens.ts","../src/components/TimeTravelDebugger/TimeTravelDebugger.tsx","../src/components/MemoryInspector/MemoryInspector.tsx","../src/components/NarrativeLog/NarrativeLog.tsx","../src/components/GanttTimeline/GanttTimeline.tsx","../src/components/FlowchartView/TraceFlow.tsx","../src/components/FlowchartView/TracedFlow.tsx","../src/components/FlowchartView/_internal/devWarn.ts","../src/components/FlowchartView/_internal/notifyChange.ts","../src/components/FlowchartView/createTraceRuntimeOverlay.ts","../src/components/FlowchartView/_internal/subflowDrill.ts","../src/components/FlowchartView/_internal/overlayProjection.ts","../src/components/FlowchartView/_internal/useSubflowDrill.ts","../src/components/FlowchartView/_internal/useChartAutoRefit.ts","../src/components/FlowchartView/SubflowBreadcrumbBar.tsx","../src/components/FlowchartView/SubflowBreadcrumb.tsx","../src/components/FlowchartView/useSubflowNavigation.ts","../src/components/FlowchartView/SubflowTree.tsx","../src/components/FlowchartView/_internal/keys.ts","../src/components/FlowchartView/_internal/walkSubflowSpecInto.ts","../src/components/FlowchartView/traceStructureRecorder.ts","../src/components/FlowchartView/createNodeViewRecorder.ts","../src/components/FlowchartView/createCommitFlowRecorder.ts","../src/components/FlowchartView/createTraceBundle.ts","../src/components/FlowchartView/_internal/useTranslator.ts","../src/components/FlowchartView/walkHelpers.ts","../src/components/FlowchartView/NodeInspector.tsx","../src/components/FlowchartView/CommitInspector.tsx","../src/components/FlowchartView/buildCommitChainTree.ts","../src/components/FlowchartView/CommitChainView.tsx","../src/components/FlowchartView/TraceExplorerShell.tsx","../src/components/FlowchartView/RunSlider.tsx"],"sourcesContent":["// Flowchart components (require @xyflow/react peer dependency)\n// Import from \"footprint-explainable-ui/flowchart\"\n//\n// v6+: recorder-driven only. The legacy spec-walk path was deleted.\n// Drive the chart via `createTraceStructureRecorder` →\n// `<TraceFlow graph={...} />` (build-time) or\n// `<TracedFlow graph={...} overlay={...} scrubIndex={...} />`\n// (build + runtime).\n\nexport { StageNode } from \"./components/StageNode\";\nexport type { StageNodeData } from \"./components/StageNode\";\n\nexport { TimeTravelDebugger } from \"./components/TimeTravelDebugger\";\nexport type { TimeTravelDebuggerProps } from \"./components/TimeTravelDebugger\";\n\n// Subflow drill-down navigation (recorder-driven)\nexport { SubflowBreadcrumb } from \"./components/FlowchartView\";\nexport type { SubflowBreadcrumbProps } from \"./components/FlowchartView\";\nexport { useSubflowNavigation } from \"./components/FlowchartView\";\nexport type { SubflowNavigation, BreadcrumbEntry } from \"./components/FlowchartView\";\n\n// Subflow manifest tree (no ReactFlow dependency — pure React)\nexport { SubflowTree } from \"./components/FlowchartView\";\nexport type { SubflowTreeProps, SubflowTreeEntry } from \"./components/FlowchartView\";\n\n// v6.0+ — event-driven trace recorder + xyflow renderer (StructureRecorder\n// consumer pattern, no spec-tree post-walk required).\nexport { createTraceStructureRecorder } from \"./components/FlowchartView\";\nexport type {\n MinimalStructureRecorder,\n TraceNode,\n TraceEdge,\n TraceNodeData,\n TraceEdgeData,\n TraceGraph,\n TraceStructureRecorderHandle,\n CreateTraceStructureRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport { TraceFlow, defaultTraceFlowLayout } from \"./components/FlowchartView\";\nexport type {\n TraceFlowProps,\n TraceFlowLayout,\n TraceFlowEdgeColors,\n} from \"./components/FlowchartView\";\n\n// v7.0 — runtime overlay recorder + traced (build+runtime) component.\n// Pair with createTraceStructureRecorder for the full time-travel\n// trace UI without spec-tree post-walks.\nexport { createTraceRuntimeOverlay, sliceOverlay } from \"./components/FlowchartView\";\nexport type {\n MinimalFlowRecorder,\n RuntimeExecutionStep,\n RuntimeOverlay,\n RuntimeOverlaySlice,\n TraceRuntimeOverlayHandle,\n CreateTraceRuntimeOverlayOptions,\n} from \"./components/FlowchartView\";\n\nexport { TracedFlow } from \"./components/FlowchartView\";\nexport type { TracedFlowProps, TracedFlowColors } from \"./components/FlowchartView\";\n\n// L8.0 — landing strip exports.\nexport { createTraceBundle } from \"./components/FlowchartView\";\nexport type {\n TraceBundle,\n CreateTraceBundleOptions,\n} from \"./components/FlowchartView\";\n\nexport { useTranslator } from \"./components/FlowchartView\";\nexport type { TranslatorHandleLike } from \"./components/FlowchartView\";\n\nexport { asStageId, asRuntimeStageId } from \"./components/FlowchartView\";\nexport type { StageId, RuntimeStageId } from \"./components/FlowchartView\";\n\n// L8.1 — NodeView translator + traversal helpers + inspector renderer\nexport { createNodeViewRecorder } from \"./components/FlowchartView\";\nexport type {\n MinimalNodeViewRecorder,\n NodeView,\n NodeViewIndex,\n ExecutionRecord,\n NodeViewRecorderHandle,\n CreateNodeViewRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport {\n walkForward,\n walkBackward,\n backtraceStructural,\n forwardtraceStructural,\n} from \"./components/FlowchartView\";\nexport type { WalkOptions } from \"./components/FlowchartView\";\n\nexport { NodeInspector } from \"./components/FlowchartView\";\nexport type { NodeInspectorProps } from \"./components/FlowchartView\";\n\n// L8.2 — CommitFlow translator + data-lineage backtrace + inspector\nexport {\n createCommitFlowRecorder,\n backtraceDataFlow,\n} from \"./components/FlowchartView\";\nexport type {\n MinimalCommitFlowRecorder,\n CommitView,\n CommitFlowIndex,\n DataDependency,\n CommitFlowRecorderHandle,\n CreateCommitFlowRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport { CommitInspector } from \"./components/FlowchartView\";\nexport type { CommitInspectorProps } from \"./components/FlowchartView\";\n\n// L8.3 — series-parallel chain tree builders + git-log swim-lane renderer\nexport {\n structureAsChainTree,\n buildCommitChainTree,\n} from \"./components/FlowchartView\";\nexport type {\n StructureChain,\n StructureChainLeaf,\n CommitChain,\n CommitChainLeaf,\n ChainTreeOptions,\n} from \"./components/FlowchartView\";\n\nexport { CommitChainView } from \"./components/FlowchartView\";\nexport type { CommitChainViewProps } from \"./components/FlowchartView\";\n\n// L8.4 — composed shell wiring the full L8 stack into a master/detail UI\nexport { TraceExplorerShell } from \"./components/FlowchartView\";\nexport type {\n TraceExplorerShellProps,\n TraceExplorerSlots,\n ChainSlotProps,\n CommitInspectorSlotProps,\n NodeInspectorSlotProps,\n SliderSlotProps,\n} from \"./components/FlowchartView\";\n\n// L8.5 — time-travel cursor slider (ONE-CURSOR model)\nexport { RunSlider } from \"./components/FlowchartView\";\nexport type { RunSliderProps } from \"./components/FlowchartView\";\n","import { memo, useEffect, useRef } from \"react\";\nimport { Handle, Position } from \"@xyflow/react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport { theme } from \"../../theme\";\n\nconst KEYFRAMES_ID = \"fp-stage-node-keyframes\";\nconst KEYFRAMES_CSS = `\n@media (prefers-reduced-motion: no-preference) {\n @keyframes fp-pulse {\n 0%, 100% { opacity: 0.4; transform: scale(1); }\n 50% { opacity: 0.15; transform: scale(1.06); }\n }\n @keyframes fp-blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n}\n@media (prefers-reduced-motion: reduce) {\n @keyframes fp-pulse { 0%, 100% { opacity: 0.3; } }\n @keyframes fp-blink { 0%, 100% { opacity: 1; } }\n}\n`;\n\nexport interface StageNodeData {\n label: string;\n active?: boolean;\n done?: boolean;\n error?: boolean;\n linked?: boolean;\n /** Semantic icon hint (e.g., \"llm\", \"tool\", \"rag\", \"start\", \"parse\", \"agent\", \"guard\") */\n icon?: string;\n /** Step numbers in execution order (shown as badges — multiple when revisited via loops) */\n stepNumbers?: number[];\n /** Node was not executed (dim it) */\n dimmed?: boolean;\n /** Node is a subflow root (show nested indicator) */\n isSubflow?: boolean;\n /** Node uses lazy resolution (dashed border + cloud icon when unresolved) */\n isLazy?: boolean;\n /** Node is a decider (renders as diamond shape per flowchart convention) */\n isDecider?: boolean;\n /** Node is a fork (parallel fan-out) */\n isFork?: boolean;\n /** Human-readable description of what this stage does */\n description?: string;\n /** Subflow identifier — set when this node belongs to a subflow */\n subflowId?: string;\n /**\n * Stable stage identifier from the spec (`SpecNode.id`). Renderable as a\n * small monospace caption under the label when `showStageId` is true —\n * useful for teaching the runtimeStageId convention and for debugging\n * which node a recorder event belongs to.\n */\n stageId?: string;\n /**\n * When true, render the `stageId` as a small monospace caption beneath\n * the label. Default false. Drives the \"Show IDs\" toggle in\n * ExplainableShell.\n */\n showStageId?: boolean;\n [key: string]: unknown;\n}\n\n// ── Stage icon SVGs ───────────────────────────────────────────────────────\n// Inline SVGs for crisp rendering at any size. Consumers pass a string key\n// via SpecNode.icon; StageNode renders the matching mini-icon.\n\nconst ICON_SIZE = 16;\n\nfunction StageIcon({ type, color }: { type: string; color: string }) {\n const s = ICON_SIZE;\n const props = { width: s, height: s, viewBox: `0 0 ${s} ${s}`, fill: \"none\", style: { flexShrink: 0 } as const };\n\n switch (type) {\n // LLM / AI call — brain/sparkle\n case \"llm\":\n case \"ai\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"8\" r=\"6\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M5.5 8C5.5 6.5 6.5 5 8 5S10.5 6.5 10.5 8\" stroke={color} strokeWidth=\"1.2\" strokeLinecap=\"round\" />\n <circle cx=\"8\" cy=\"9.5\" r=\"1\" fill={color} />\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"3.5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"12.5\" y1=\"4\" x2=\"11.2\" y2=\"5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"3.5\" y1=\"4\" x2=\"4.8\" y2=\"5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Tool / function call — gear\n case \"tool\":\n case \"function\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"8\" r=\"3\" stroke={color} strokeWidth=\"1.5\" />\n {[0, 45, 90, 135, 180, 225, 270, 315].map((angle) => {\n const rad = (angle * Math.PI) / 180;\n const x1 = 8 + Math.cos(rad) * 4.5;\n const y1 = 8 + Math.sin(rad) * 4.5;\n const x2 = 8 + Math.cos(rad) * 6;\n const y2 = 8 + Math.sin(rad) * 6;\n return <line key={angle} x1={x1} y1={y1} x2={x2} y2={y2} stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />;\n })}\n </svg>\n );\n\n // RAG / retrieval — magnifying glass + doc\n case \"rag\":\n case \"search\":\n case \"retrieval\":\n return (\n <svg {...props}>\n <circle cx=\"7\" cy=\"7\" r=\"4\" stroke={color} strokeWidth=\"1.5\" />\n <line x1=\"10\" y1=\"10\" x2=\"13.5\" y2=\"13.5\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"6\" x2=\"8.5\" y2=\"6\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"8\" x2=\"7.5\" y2=\"8\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Parse / process — diamond with arrows\n case \"parse\":\n case \"process\":\n case \"transform\":\n return (\n <svg {...props}>\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" stroke={color} strokeWidth=\"1.5\" transform=\"rotate(45 8 8)\" />\n </svg>\n );\n\n // Start / seed — play triangle\n case \"start\":\n case \"seed\":\n case \"init\":\n return (\n <svg {...props}>\n <path d=\"M5 3.5L12.5 8L5 12.5V3.5Z\" fill={color} opacity=\"0.8\" />\n </svg>\n );\n\n // End / finalize — stop square\n case \"end\":\n case \"finalize\":\n case \"output\":\n return (\n <svg {...props}>\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" fill={color} opacity=\"0.8\" />\n </svg>\n );\n\n // Agent — person silhouette\n case \"agent\":\n case \"orchestrator\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"5\" r=\"2.5\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M3.5 14C3.5 11 5.5 9 8 9S12.5 11 12.5 14\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Swarm — multi-agent\n case \"swarm\":\n case \"multi-agent\":\n return (\n <svg {...props}>\n <circle cx=\"5\" cy=\"5\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <circle cx=\"11\" cy=\"5\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <circle cx=\"8\" cy=\"11\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <line x1=\"5\" y1=\"7\" x2=\"8\" y2=\"9\" stroke={color} strokeWidth=\"1\" opacity=\"0.5\" />\n <line x1=\"11\" y1=\"7\" x2=\"8\" y2=\"9\" stroke={color} strokeWidth=\"1\" opacity=\"0.5\" />\n </svg>\n );\n\n // Guard / guardrail — shield\n case \"guard\":\n case \"guardrail\":\n case \"validate\":\n return (\n <svg {...props}>\n <path d=\"M8 2L3 5V9C3 11.5 5 13.5 8 14.5C11 13.5 13 11.5 13 9V5L8 2Z\" stroke={color} strokeWidth=\"1.5\" strokeLinejoin=\"round\" />\n <path d=\"M6 8L7.5 9.5L10 6.5\" stroke={color} strokeWidth=\"1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n\n // Stream — wave\n case \"stream\":\n case \"streaming\":\n return (\n <svg {...props}>\n <path d=\"M2 8C4 5 6 11 8 8S12 5 14 8\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" fill=\"none\" />\n <path d=\"M2 11C4 8 6 14 8 11S12 8 14 11\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" fill=\"none\" opacity=\"0.5\" />\n </svg>\n );\n\n // Memory / state — database cylinder\n case \"memory\":\n case \"state\":\n case \"db\":\n return (\n <svg {...props}>\n <ellipse cx=\"8\" cy=\"4.5\" rx=\"5\" ry=\"2\" stroke={color} strokeWidth=\"1.3\" />\n <line x1=\"3\" y1=\"4.5\" x2=\"3\" y2=\"11.5\" stroke={color} strokeWidth=\"1.3\" />\n <line x1=\"13\" y1=\"4.5\" x2=\"13\" y2=\"11.5\" stroke={color} strokeWidth=\"1.3\" />\n <ellipse cx=\"8\" cy=\"11.5\" rx=\"5\" ry=\"2\" stroke={color} strokeWidth=\"1.3\" />\n </svg>\n );\n\n // Loop — circular arrow\n case \"loop\":\n case \"retry\":\n return (\n <svg {...props}>\n <path d=\"M12 8A4 4 0 1 1 8 4\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" fill=\"none\" />\n <path d=\"M8 1.5L10.5 4L8 6.5\" stroke={color} strokeWidth=\"1.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" fill=\"none\" />\n </svg>\n );\n\n // Lazy / service — cloud (deferred resolution, loaded on demand)\n case \"lazy\":\n case \"service\":\n case \"cloud\":\n return (\n <svg {...props}>\n <path\n d=\"M4.5 12C2.8 12 1.5 10.7 1.5 9C1.5 7.5 2.5 6.3 3.8 6C4 4 5.8 2.5 8 2.5C9.8 2.5 11.3 3.5 11.9 5C13.9 5.2 15.5 6.8 15.5 8.8C15.5 10.8 13.9 12.5 11.8 12.5H4.5\"\n stroke={color}\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n fill=\"none\"\n />\n </svg>\n );\n\n // Decision — diamond (already handled by isDecider shape)\n case \"decision\":\n case \"router\":\n return (\n <svg {...props}>\n <path d=\"M8 2L14 8L8 14L2 8Z\" stroke={color} strokeWidth=\"1.5\" fill=\"none\" />\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill={color} />\n </svg>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * Custom ReactFlow node for pipeline stages.\n * All colors and fonts come from `--fp-*` CSS variables (via theme).\n * Shows execution state via color, icon, step badge, and pulse animation.\n */\nexport const StageNode = memo(function StageNode({\n data,\n}: NodeProps & { data: StageNodeData }) {\n const { label, active, done, error, linked, icon, stepNumbers, dimmed, isSubflow, isLazy, isDecider, isFork, description, stageId, showStageId } = data;\n\n // Lazy nodes show cloud icon by default (unless another icon is specified)\n const effectiveIcon = icon || (isLazy ? \"lazy\" : undefined);\n // Lazy + unresolved = dashed border\n const isLazyUnresolved = isLazy && !done && !active;\n\n // Inject keyframes once into document head\n const injectedRef = useRef(false);\n useEffect(() => {\n if (injectedRef.current) return;\n if (typeof document !== \"undefined\" && !document.getElementById(KEYFRAMES_ID)) {\n const styleEl = document.createElement(\"style\");\n styleEl.id = KEYFRAMES_ID;\n styleEl.textContent = KEYFRAMES_CSS;\n document.head.appendChild(styleEl);\n }\n injectedRef.current = true;\n }, []);\n\n const isOnPath = active || done;\n\n const bg = active\n ? theme.primary\n : done\n ? theme.success\n : error\n ? theme.error\n : theme.bgSecondary;\n\n const borderColor = active\n ? theme.primary\n : done\n ? theme.success\n : error\n ? theme.error\n : theme.border;\n\n const shadow = active\n ? `0 0 16px color-mix(in srgb, ${theme.primary} 40%, transparent)`\n : done\n ? `0 0 8px color-mix(in srgb, ${theme.success} 20%, transparent)`\n : error\n ? `0 0 12px color-mix(in srgb, ${theme.error} 30%, transparent)`\n : `0 2px 8px rgba(0,0,0,0.15)`;\n\n // Colored states use white for contrast; default uses consumer's text color.\n const textColor =\n active || done || error ? \"#fff\" : theme.textPrimary;\n\n return (\n <>\n <Handle type=\"target\" position={Position.Top} style={{ opacity: 0 }} />\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n }}\n >\n {/* Step number badges — multiple when revisited via loops */}\n {stepNumbers && stepNumbers.length > 0 && isOnPath && (\n <div\n style={{\n position: \"absolute\",\n top: -10,\n left: -10,\n display: \"flex\",\n gap: 3,\n zIndex: 10,\n }}\n >\n {stepNumbers.map((num, i) => {\n const isLatest = i === stepNumbers.length - 1;\n const badgeBg = isLatest && active ? theme.primary : theme.success;\n const glow = isLatest && active\n ? `color-mix(in srgb, ${theme.primary} 50%, transparent)`\n : `color-mix(in srgb, ${theme.success} 40%, transparent)`;\n return (\n <div\n key={num}\n style={{\n width: 22,\n height: 22,\n borderRadius: \"50%\",\n background: badgeBg,\n color: \"#fff\",\n fontSize: 11,\n fontWeight: 700,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: `0 0 8px ${glow}`,\n }}\n >\n {num}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Linked pulse ring */}\n {linked && (\n <div\n style={{\n position: \"absolute\",\n inset: -6,\n borderRadius: isDecider ? 0 : `calc(${theme.radius} + 4px)`,\n clipPath: isDecider ? \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\" : undefined,\n border: `2px solid ${theme.primary}`,\n opacity: 0.4,\n animation: \"fp-pulse 2s ease-in-out infinite\",\n }}\n />\n )}\n\n {/* Active node pulse ring */}\n {active && (\n <div\n style={{\n position: \"absolute\",\n inset: -6,\n borderRadius: isDecider ? 0 : `calc(${theme.radius} + 4px)`,\n clipPath: isDecider ? \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\" : undefined,\n border: `2px solid ${theme.primary}`,\n opacity: 0.3,\n animation: \"fp-pulse 1.5s ease-out infinite\",\n }}\n />\n )}\n\n {/* Diamond for decider nodes — proper diamond via clip-path */}\n {isDecider ? (\n <div style={{ position: \"relative\", width: 120, height: 72 }}>\n {/* Diamond shape layer */}\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: bg,\n clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\",\n border: \"none\",\n boxShadow: shadow,\n transition: \"all 0.3s ease\",\n }}\n />\n {/* Border layer — slightly larger diamond behind */}\n <div\n style={{\n position: \"absolute\",\n inset: -2,\n clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\",\n background: borderColor,\n zIndex: -1,\n ...(isLazyUnresolved ? {\n background: \"transparent\",\n // Dashed border via SVG for clip-path (CSS border doesn't work with clip-path)\n } : {}),\n }}\n />\n {/* Content — centered on top of diamond */}\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 1,\n fontFamily: theme.fontSans,\n zIndex: 1,\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 4 }}>\n {effectiveIcon && <StageIcon type={effectiveIcon} color={textColor} />}\n {!effectiveIcon && (\n <span style={{ fontSize: 9, color: textColor }}>&#x25C7;</span>\n )}\n <span\n style={{\n fontSize: 11,\n fontWeight: 600,\n color: textColor,\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n </span>\n </div>\n {description && (\n <span\n style={{\n fontSize: 8,\n fontWeight: 400,\n color: textColor,\n opacity: 0.7,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 100,\n }}\n >\n {description}\n </span>\n )}\n {showStageId && stageId && (\n <span\n style={{\n fontSize: 8,\n fontFamily: \"ui-monospace, monospace\",\n color: textColor,\n opacity: 0.55,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 100,\n }}\n title={`stageId: ${stageId}`}\n >\n {stageId}\n </span>\n )}\n </div>\n </div>\n ) : (\n /* Standard rectangular node */\n <div\n style={{\n background: bg,\n border: `2px ${isLazyUnresolved ? \"dashed\" : \"solid\"} ${borderColor}`,\n borderRadius: theme.radius,\n padding: description ? \"8px 16px\" : \"10px 20px\",\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: description ? 2 : 0,\n boxShadow: shadow,\n transition: \"all 0.3s ease\",\n fontFamily: theme.fontSans,\n minWidth: 100,\n justifyContent: \"center\",\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n {/* Semantic icon (lazy nodes default to cloud icon) */}\n {effectiveIcon && <StageIcon type={effectiveIcon} color={textColor} />}\n\n {/* State icon */}\n {done && !effectiveIcon && (\n <span style={{ fontSize: 10, color: textColor }}>&#x2713;</span>\n )}\n {active && !effectiveIcon && (\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: \"#fff\",\n animation: \"fp-blink 1s ease-in-out infinite\",\n flexShrink: 0,\n }}\n />\n )}\n {error && !effectiveIcon && (\n <span style={{ fontSize: 10, color: textColor }}>&#x2717;</span>\n )}\n\n <span\n style={{\n fontSize: 13,\n fontWeight: 500,\n color: textColor,\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n </span>\n {/* Subflow indicator — nested boxes icon */}\n {isSubflow && (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 16,\n height: 16,\n borderRadius: 3,\n border: `1.5px solid ${textColor}`,\n position: \"relative\",\n opacity: 0.7,\n flexShrink: 0,\n }}\n >\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: 2,\n border: `1px solid ${textColor}`,\n }}\n />\n </span>\n )}\n </div>\n {/* Description subtitle */}\n {description && (\n <span\n style={{\n fontSize: 10,\n fontWeight: 400,\n color: textColor,\n opacity: 0.7,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 160,\n }}\n >\n {description}\n </span>\n )}\n {/* Stage ID caption — toggled by `showStageId`. Teaches the\n runtimeStageId convention; recorders key their data by\n this ID so consumers can render any recorder's per-stage\n output by lookup. */}\n {showStageId && stageId && (\n <span\n style={{\n fontSize: 9,\n fontFamily: \"ui-monospace, monospace\",\n color: textColor,\n opacity: 0.55,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 160,\n }}\n title={`stageId: ${stageId}`}\n >\n {stageId}\n </span>\n )}\n </div>\n )}\n </div>\n <Handle type=\"source\" position={Position.Bottom} style={{ opacity: 0 }} />\n {/* Loop handles: source exits bottom-right, target enters from right.\n Creates a clockwise arc: down → right → up → back into right side. */}\n <Handle\n id=\"loop-source\"\n type=\"source\"\n position={Position.Bottom}\n style={{ background: \"transparent\", border: \"none\", width: 6, height: 6, left: \"75%\" }}\n />\n <Handle\n id=\"loop-target\"\n type=\"target\"\n position={Position.Right}\n style={{ background: \"transparent\", border: \"none\", width: 6, height: 6 }}\n />\n </>\n );\n});\n","import { createContext, useContext } from \"react\";\nimport type { ThemeTokens } from \"./tokens\";\nimport { tokensToCSSVars } from \"./tokens\";\n\nconst ThemeContext = createContext<ThemeTokens>({});\n\nexport function useFootprintTheme(): ThemeTokens {\n return useContext(ThemeContext);\n}\n\ninterface FootprintThemeProps {\n tokens?: ThemeTokens;\n children: React.ReactNode;\n}\n\n/**\n * Optional theme provider — wraps children with CSS custom properties.\n * Consumers can also just set --fp-* CSS variables directly.\n *\n * Wrapper div uses `display: contents` so it's invisible to the\n * parent's layout (flex / grid / block). This matters because themed\n * children often need to fill a parent (flex:1 / height:100% /\n * grid cells), and a regular block `<div>` here would break that\n * chain — descendants would resolve to 0 height when the parent is\n * flex-column or a grid cell with minmax(0, 1fr). `display: contents`\n * removes the box from the render tree while keeping the DOM intact,\n * so CSS custom property inheritance (which follows the DOM) still\n * flows to children.\n *\n * Trade-off: `display: contents` elements are removed from the\n * accessibility tree in some older browser versions. Our wrapper has\n * no semantic role, so this is fine.\n */\nexport function FootprintTheme({ tokens = {}, children }: FootprintThemeProps) {\n const cssVars = tokensToCSSVars(tokens);\n\n return (\n <ThemeContext.Provider value={tokens}>\n <div\n style={{ ...(cssVars as React.CSSProperties), display: \"contents\" }}\n className=\"fp-theme-root\"\n >\n {children}\n </div>\n </ThemeContext.Provider>\n );\n}\n","/** Default theme tokens — consumers override via CSS variables or ThemeProvider. */\nexport interface ThemeTokens {\n colors?: {\n primary?: string;\n success?: string;\n error?: string;\n warning?: string;\n bgPrimary?: string;\n bgSecondary?: string;\n bgTertiary?: string;\n textPrimary?: string;\n textSecondary?: string;\n textMuted?: string;\n border?: string;\n };\n radius?: string;\n fontFamily?: {\n sans?: string;\n mono?: string;\n };\n}\n\n/** Maps ThemeTokens to CSS custom property assignments. */\nexport function tokensToCSSVars(tokens: ThemeTokens): Record<string, string> {\n const vars: Record<string, string> = {};\n if (tokens.colors) {\n const c = tokens.colors;\n if (c.primary) vars[\"--fp-color-primary\"] = c.primary;\n if (c.success) vars[\"--fp-color-success\"] = c.success;\n if (c.error) vars[\"--fp-color-error\"] = c.error;\n if (c.warning) vars[\"--fp-color-warning\"] = c.warning;\n if (c.bgPrimary) vars[\"--fp-bg-primary\"] = c.bgPrimary;\n if (c.bgSecondary) vars[\"--fp-bg-secondary\"] = c.bgSecondary;\n if (c.bgTertiary) vars[\"--fp-bg-tertiary\"] = c.bgTertiary;\n if (c.textPrimary) vars[\"--fp-text-primary\"] = c.textPrimary;\n if (c.textSecondary) vars[\"--fp-text-secondary\"] = c.textSecondary;\n if (c.textMuted) vars[\"--fp-text-muted\"] = c.textMuted;\n if (c.border) vars[\"--fp-border\"] = c.border;\n }\n if (tokens.radius) vars[\"--fp-radius\"] = tokens.radius;\n if (tokens.fontFamily?.sans) vars[\"--fp-font-sans\"] = tokens.fontFamily.sans;\n if (tokens.fontFamily?.mono) vars[\"--fp-font-mono\"] = tokens.fontFamily.mono;\n return vars;\n}\n\n/** Raw fallback values — used by tokensToCSSVars() and anywhere a real color is needed. */\nexport const rawDefaults = {\n colors: {\n primary: \"#6366f1\",\n success: \"#22c55e\",\n error: \"#ef4444\",\n warning: \"#f59e0b\",\n bgPrimary: \"#0f172a\",\n bgSecondary: \"#1e293b\",\n bgTertiary: \"#334155\",\n textPrimary: \"#f8fafc\",\n textSecondary: \"#94a3b8\",\n textMuted: \"#64748b\",\n border: \"#334155\",\n },\n radius: \"8px\",\n fontFamily: {\n sans: \"Inter, system-ui, -apple-system, sans-serif\",\n mono: \"'JetBrains Mono', 'Fira Code', monospace\",\n },\n} as const;\n\n/** Default dark theme values with CSS variable references (consumers can override via CSS). */\nexport const defaultTokens: Required<{\n [K in keyof ThemeTokens]-?: Required<ThemeTokens[K]>;\n}> = {\n colors: {\n primary: `var(--fp-color-primary, ${rawDefaults.colors.primary})`,\n success: `var(--fp-color-success, ${rawDefaults.colors.success})`,\n error: `var(--fp-color-error, ${rawDefaults.colors.error})`,\n warning: `var(--fp-color-warning, ${rawDefaults.colors.warning})`,\n bgPrimary: `var(--fp-bg-primary, ${rawDefaults.colors.bgPrimary})`,\n bgSecondary: `var(--fp-bg-secondary, ${rawDefaults.colors.bgSecondary})`,\n bgTertiary: `var(--fp-bg-tertiary, ${rawDefaults.colors.bgTertiary})`,\n textPrimary: `var(--fp-text-primary, ${rawDefaults.colors.textPrimary})`,\n textSecondary: `var(--fp-text-secondary, ${rawDefaults.colors.textSecondary})`,\n textMuted: `var(--fp-text-muted, ${rawDefaults.colors.textMuted})`,\n border: `var(--fp-border, ${rawDefaults.colors.border})`,\n },\n radius: `var(--fp-radius, ${rawDefaults.radius})`,\n fontFamily: {\n sans: `var(--fp-font-sans, ${rawDefaults.fontFamily.sans})`,\n mono: `var(--fp-font-mono, ${rawDefaults.fontFamily.mono})`,\n },\n};\n","import type { Size } from \"../types\";\n\n/**\n * Helper to resolve a CSS variable with a fallback.\n * Usage: v(\"--fp-color-primary\", \"#6366f1\")\n */\nexport function v(varName: string, fallback: string): string {\n return `var(${varName}, ${fallback})`;\n}\n\n/** Shorthand for common theme variables */\nexport const theme = {\n primary: v(\"--fp-color-primary\", \"#6366f1\"),\n success: v(\"--fp-color-success\", \"#22c55e\"),\n error: v(\"--fp-color-error\", \"#ef4444\"),\n warning: v(\"--fp-color-warning\", \"#f59e0b\"),\n bgPrimary: v(\"--fp-bg-primary\", \"#0f172a\"),\n bgSecondary: v(\"--fp-bg-secondary\", \"#1e293b\"),\n bgTertiary: v(\"--fp-bg-tertiary\", \"#334155\"),\n textPrimary: v(\"--fp-text-primary\", \"#f8fafc\"),\n textSecondary: v(\"--fp-text-secondary\", \"#94a3b8\"),\n textMuted: v(\"--fp-text-muted\", \"#64748b\"),\n border: v(\"--fp-border\", \"#334155\"),\n radius: v(\"--fp-radius\", \"8px\"),\n fontSans: v(\"--fp-font-sans\", \"Inter, system-ui, -apple-system, sans-serif\"),\n fontMono: v(\"--fp-font-mono\", \"'JetBrains Mono', 'Fira Code', monospace\"),\n} as const;\n\n/** Font sizes per size variant */\nexport const fontSize: Record<Size, { label: number; body: number; small: number }> = {\n compact: { label: 10, body: 11, small: 9 },\n default: { label: 11, body: 12, small: 10 },\n detailed: { label: 12, body: 13, small: 11 },\n};\n\n/** Padding per size variant */\nexport const padding: Record<Size, number> = {\n compact: 8,\n default: 12,\n detailed: 16,\n};\n","/**\n * useDarkModeTokens — Auto-bridge between CSS class-based dark mode and FootprintTheme.\n *\n * Watches for a `.dark` class on <html> (Tailwind convention) and returns\n * the appropriate ThemeTokens preset. Pairs with FootprintTheme:\n *\n * import { FootprintTheme, useDarkModeTokens } from 'footprint-explainable-ui';\n *\n * function MyApp() {\n * const tokens = useDarkModeTokens();\n * return (\n * <FootprintTheme tokens={tokens}>\n * <NarrativeTrace ... />\n * </FootprintTheme>\n * );\n * }\n *\n * Consumers can override the light/dark presets:\n *\n * const tokens = useDarkModeTokens({ light: warmLight, dark: warmDark });\n */\n\nimport { useState, useEffect } from \"react\";\nimport type { ThemeTokens } from \"./tokens\";\nimport { coolDark } from \"./presets\";\nimport { coolLight } from \"./presets\";\n\nexport interface DarkModeTokensOptions {\n /** Tokens to use in light mode. Defaults to coolLight. */\n light?: ThemeTokens;\n /** Tokens to use in dark mode. Defaults to coolDark. */\n dark?: ThemeTokens;\n /** CSS selector to watch for dark mode. Defaults to checking .dark on documentElement. */\n selector?: string;\n}\n\nexport function useDarkModeTokens(options?: DarkModeTokensOptions): ThemeTokens {\n const lightTokens = options?.light ?? coolLight;\n const darkTokens = options?.dark ?? coolDark;\n\n const [isDark, setIsDark] = useState(\n () => document.documentElement.classList.contains(options?.selector ?? \"dark\"),\n );\n\n useEffect(() => {\n const cls = options?.selector ?? \"dark\";\n const obs = new MutationObserver(() => {\n setIsDark(document.documentElement.classList.contains(cls));\n });\n obs.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n return () => obs.disconnect();\n }, [options?.selector]);\n\n return isDark ? darkTokens : lightTokens;\n}\n","import { useState } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\nimport { MemoryInspector } from \"../MemoryInspector\";\nimport { NarrativeLog } from \"../NarrativeLog\";\nimport { GanttTimeline } from \"../GanttTimeline\";\nimport { TraceFlow } from \"../FlowchartView/TraceFlow\";\nimport { TracedFlow } from \"../FlowchartView/TracedFlow\";\nimport type { TraceGraph } from \"../FlowchartView/traceStructureRecorder\";\nimport type { RuntimeOverlay } from \"../FlowchartView/createTraceRuntimeOverlay\";\n\nexport interface TimeTravelDebuggerProps extends BaseComponentProps {\n /** Stage snapshots */\n snapshots: StageSnapshot[];\n /** Recorder-captured build-time graph (from\n * `createTraceStructureRecorder().getGraph()`). Required for the\n * chart rendering — replaces the legacy `nodes` / `edges` props. */\n graph: TraceGraph;\n /** Optional runtime overlay (from\n * `createTraceRuntimeOverlay().getOverlay()`). When provided, the\n * chart renders via `<TracedFlow>` with per-step coloring synced to\n * the scrubber; otherwise renders via `<TraceFlow>` (build-time only). */\n runtimeOverlay?: RuntimeOverlay;\n /** Show Gantt timeline */\n showGantt?: boolean;\n /** Layout direction */\n layout?: \"horizontal\" | \"vertical\";\n /** Title */\n title?: string;\n}\n\n/**\n * Full time-travel debugger: scrubber + recorder-driven flowchart +\n * memory + narrative + gantt. This is the \"batteries included\"\n * component for pipeline debugging.\n *\n * v6+: chart rendering is recorder-driven. Pass `graph` (always) and\n * optionally `runtimeOverlay` for per-step coloring tied to the\n * scrubber.\n */\nexport function TimeTravelDebugger({\n snapshots,\n graph,\n runtimeOverlay,\n showGantt = true,\n layout = \"horizontal\",\n title = \"Time-Travel Debugger\",\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: TimeTravelDebuggerProps) {\n const [selectedIndex, setSelectedIndex] = useState(0);\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (snapshots.length === 0) {\n return (\n <div\n className={className}\n style={{\n padding: pad * 2,\n textAlign: \"center\",\n color: theme.textMuted,\n ...style,\n }}\n >\n No snapshots to debug\n </div>\n );\n }\n\n const isHorizontal = layout === \"horizontal\";\n\n // Click → jump scrubber to whichever snapshot maps to the clicked\n // stage. Matches the legacy `onNodeClick(index)` semantics: callers\n // receive a stage id, we translate to a snapshot index.\n const handleNodeClick = (stageId: string) => {\n const idx = snapshots.findIndex(\n (s) => s.stageName === stageId || s.stageLabel === stageId,\n );\n if (idx >= 0) setSelectedIndex(idx);\n };\n\n const chart = runtimeOverlay ? (\n <TracedFlow\n graph={graph}\n overlay={runtimeOverlay}\n scrubIndex={selectedIndex}\n onNodeClick={handleNodeClick}\n />\n ) : (\n <TraceFlow graph={graph} onNodeClick={handleNodeClick} />\n );\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"time-travel-debugger\">\n <h3>{title}</h3>\n <input\n type=\"range\"\n min={0}\n max={snapshots.length - 1}\n value={selectedIndex}\n onChange={(e) => setSelectedIndex(parseInt(e.target.value))}\n />\n {chart}\n <MemoryInspector\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n unstyled\n />\n <NarrativeLog\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n unstyled\n />\n {showGantt && (\n <GanttTimeline\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onSelect={setSelectedIndex}\n unstyled\n />\n )}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n background: theme.bgPrimary,\n fontFamily: theme.fontSans,\n overflow: \"hidden\",\n ...style,\n }}\n data-fp=\"time-travel-debugger\"\n >\n {/* Scrubber header */}\n <div\n style={{\n padding: `${pad}px ${pad + 4}px`,\n borderBottom: `1px solid ${theme.border}`,\n background: theme.bgSecondary,\n flexShrink: 0,\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n marginBottom: 8,\n }}\n >\n <span\n style={{\n fontSize: fs.body + 2,\n fontWeight: 600,\n color: theme.textPrimary,\n }}\n >\n {title}\n </span>\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n }}\n >\n Scrub to replay execution\n </span>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <ScrubButton\n label=\"◀\"\n disabled={selectedIndex === 0}\n onClick={() => setSelectedIndex((i) => Math.max(0, i - 1))}\n />\n <input\n type=\"range\"\n min={0}\n max={snapshots.length - 1}\n value={selectedIndex}\n onChange={(e) => setSelectedIndex(parseInt(e.target.value))}\n style={{\n flex: 1,\n height: 4,\n accentColor: theme.primary,\n cursor: \"pointer\",\n }}\n />\n <ScrubButton\n label=\"▶\"\n disabled={selectedIndex === snapshots.length - 1}\n onClick={() =>\n setSelectedIndex((i) => Math.min(snapshots.length - 1, i + 1))\n }\n />\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n flexShrink: 0,\n fontFamily: theme.fontMono,\n }}\n >\n {selectedIndex + 1}/{snapshots.length}\n </span>\n </div>\n </div>\n\n {/* Main content: flowchart + data panels */}\n <div\n style={{\n flex: 1,\n display: \"flex\",\n flexDirection: isHorizontal ? \"row\" : \"column\",\n overflow: \"hidden\",\n }}\n >\n {/* Flowchart */}\n <div\n style={{\n flex: 1,\n overflow: \"hidden\",\n borderRight: isHorizontal\n ? `1px solid ${theme.border}`\n : \"none\",\n borderBottom: !isHorizontal\n ? `1px solid ${theme.border}`\n : \"none\",\n }}\n >\n {chart}\n </div>\n\n {/* Data panel */}\n <div style={{ flex: 1, overflow: \"auto\" }}>\n <MemoryInspector\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n size={size}\n />\n <div\n style={{\n height: 1,\n background: theme.border,\n margin: `0 ${pad}px`,\n }}\n />\n <NarrativeLog\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n size={size}\n />\n </div>\n </div>\n\n {/* Gantt footer */}\n {showGantt && (\n <div\n style={{\n borderTop: `1px solid ${theme.border}`,\n background: theme.bgSecondary,\n flexShrink: 0,\n }}\n >\n <GanttTimeline\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onSelect={setSelectedIndex}\n size={size}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction ScrubButton({\n label,\n disabled,\n onClick,\n}: {\n label: string;\n disabled: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n onClick={onClick}\n disabled={disabled}\n style={{\n background: theme.bgTertiary,\n border: `1px solid ${theme.border}`,\n color: disabled ? theme.textMuted : theme.textPrimary,\n borderRadius: 6,\n width: 28,\n height: 28,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: disabled ? \"not-allowed\" : \"pointer\",\n opacity: disabled ? 0.5 : 1,\n fontSize: 12,\n flexShrink: 0,\n }}\n >\n {label}\n </button>\n );\n}\n","import { useMemo, useRef } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface MemoryInspectorProps extends BaseComponentProps {\n /** Single memory object or snapshots (will accumulate up to selectedIndex) */\n data?: Record<string, unknown>;\n /** When using snapshots mode, pass these instead of data */\n snapshots?: StageSnapshot[];\n /** Index to accumulate up to (for time-travel) */\n selectedIndex?: number;\n /** Show data types alongside values */\n showTypes?: boolean;\n /** Highlight keys that are new at this step */\n highlightNew?: boolean;\n}\n\n/** Cache for incremental memory accumulation — avoids O(n) rebuild on every slider scrub. */\ninterface MemoryCache {\n snapshots: StageSnapshot[];\n index: number;\n accumulated: Record<string, unknown>;\n}\n\n/**\n * Displays pipeline memory state as formatted JSON.\n * Supports both static (data prop) and time-travel (snapshots + selectedIndex) modes.\n */\nexport function MemoryInspector({\n data,\n snapshots,\n selectedIndex = 0,\n showTypes = false,\n highlightNew = true,\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: MemoryInspectorProps) {\n // Incremental cache: accumulate forward from last known index instead of rebuilding from 0\n const cacheRef = useRef<MemoryCache | null>(null);\n\n const { memory, newKeys } = useMemo(() => {\n if (data) {\n return { memory: data, newKeys: new Set<string>() };\n }\n if (!snapshots || snapshots.length === 0) {\n return { memory: {}, newKeys: new Set<string>() };\n }\n\n const safeIdx = Math.min(selectedIndex, snapshots.length - 1);\n let merged: Record<string, unknown>;\n const cache = cacheRef.current;\n\n if (cache && cache.snapshots === snapshots && cache.index <= safeIdx) {\n // Forward scrub: extend from cached state\n merged = { ...cache.accumulated };\n for (let i = cache.index + 1; i <= safeIdx; i++) {\n Object.assign(merged, snapshots[i]?.memory);\n }\n } else {\n // Backward scrub or new snapshots: rebuild from scratch\n merged = {};\n for (let i = 0; i <= safeIdx; i++) {\n Object.assign(merged, snapshots[i]?.memory);\n }\n }\n\n // Update cache\n cacheRef.current = { snapshots, index: safeIdx, accumulated: merged };\n\n const nk = new Set<string>();\n if (highlightNew && safeIdx > 0) {\n // Previous state is cache at safeIdx-1, or rebuild if needed\n let prev: Record<string, unknown>;\n if (cache && cache.snapshots === snapshots && cache.index === safeIdx - 1) {\n prev = cache.accumulated;\n } else {\n prev = {};\n for (let i = 0; i < safeIdx; i++) {\n Object.assign(prev, snapshots[i]?.memory);\n }\n }\n const current = snapshots[safeIdx]?.memory ?? {};\n for (const k of Object.keys(current)) {\n if (!(k in prev)) nk.add(k);\n }\n } else if (highlightNew && safeIdx === 0 && snapshots[0]) {\n for (const k of Object.keys(snapshots[0].memory)) nk.add(k);\n }\n\n return { memory: merged, newKeys: nk };\n }, [data, snapshots, selectedIndex, highlightNew]);\n\n const entries = Object.entries(memory);\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"memory-inspector\" role=\"region\" aria-label=\"Memory state\">\n <div data-fp=\"memory-label\">Memory State</div>\n <pre data-fp=\"memory-json\">\n <code>{JSON.stringify(memory, null, 2)}</code>\n </pre>\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: pad,\n fontFamily: theme.fontSans,\n ...style,\n }}\n data-fp=\"memory-inspector\"\n role=\"region\"\n aria-label=\"Memory state\"\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n Memory State\n </span>\n <div\n style={{\n marginTop: 8,\n background: theme.bgSecondary,\n border: `1px solid ${theme.border}`,\n borderRadius: theme.radius,\n padding: `${pad}px ${pad + 4}px`,\n fontFamily: theme.fontMono,\n fontSize: fs.body,\n lineHeight: 1.8,\n }}\n >\n <span style={{ color: theme.textMuted }}>{\"{\"}</span>\n {entries.length === 0 && (\n <div\n style={{\n paddingLeft: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n }}\n >\n {\"// empty\"}\n </div>\n )}\n {entries.map(([key, value], i) => {\n const isNew = newKeys.has(key);\n const isLast = i === entries.length - 1;\n return (\n <div\n key={key}\n style={{\n paddingLeft: 16,\n background: isNew\n ? `color-mix(in srgb, ${theme.success} 10%, transparent)`\n : \"transparent\",\n borderRadius: 4,\n marginLeft: -4,\n marginRight: -4,\n paddingRight: 4,\n }}\n >\n <span style={{ color: theme.primary }}>&quot;{key}&quot;</span>\n <span style={{ color: theme.textMuted }}>: </span>\n <span style={{ color: theme.success }}>\n {formatValue(value)}\n </span>\n {showTypes && (\n <span\n style={{\n color: theme.textMuted,\n fontSize: fs.small,\n marginLeft: 8,\n opacity: 0.6,\n }}\n >\n ({typeof value})\n </span>\n )}\n {!isLast && <span style={{ color: theme.textMuted }}>,</span>}\n </div>\n );\n })}\n <span style={{ color: theme.textMuted }}>{\"}\"}</span>\n </div>\n </div>\n );\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") return `\"${value}\"`;\n if (typeof value === \"object\" && value !== null) return JSON.stringify(value);\n return String(value);\n}\n","import { useMemo } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface NarrativeLogProps extends BaseComponentProps {\n /** Snapshots to display narratives from */\n snapshots: StageSnapshot[];\n /** Show narratives up to this index (for time-travel sync) */\n selectedIndex?: number;\n /** Show a single narrative string (simple mode) */\n narrative?: string;\n}\n\n/**\n * Timeline-style execution log showing what happened at each stage.\n * Supports both full snapshots mode and single-narrative mode.\n */\nexport function NarrativeLog({\n snapshots,\n selectedIndex,\n narrative,\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: NarrativeLogProps) {\n const entries = useMemo(() => {\n if (narrative) {\n return [{ label: \"Output\", text: narrative, isCurrent: true }];\n }\n const idx = selectedIndex ?? snapshots.length - 1;\n return snapshots.slice(0, idx + 1).map((s, i) => ({\n label: s.stageLabel,\n text: s.narrative,\n isCurrent: i === idx,\n }));\n }, [snapshots, selectedIndex, narrative]);\n\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"narrative-log\">\n {entries.map((entry, i) => (\n <div key={i} data-fp=\"narrative-entry\" data-current={entry.isCurrent}>\n <strong>{entry.label}</strong>\n <p>{entry.text}</p>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{ padding: pad, fontFamily: theme.fontSans, ...style }}\n data-fp=\"narrative-log\"\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n Execution Log\n </span>\n <div style={{ marginTop: 8, display: \"flex\", flexDirection: \"column\" }}>\n {entries.map((entry, i) => (\n <div\n key={i}\n style={{\n display: \"flex\",\n gap: 10,\n padding: `${pad}px 0`,\n borderBottom:\n i < entries.length - 1 ? `1px solid ${theme.border}` : \"none\",\n }}\n >\n {/* Timeline dot + line */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n width: 12,\n flexShrink: 0,\n paddingTop: 5,\n }}\n >\n <div\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: entry.isCurrent ? theme.primary : theme.success,\n flexShrink: 0,\n }}\n />\n {i < entries.length - 1 && (\n <div\n style={{\n width: 1,\n flex: 1,\n background: theme.border,\n marginTop: 4,\n }}\n />\n )}\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, minWidth: 0 }}>\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: entry.isCurrent ? theme.primary : theme.textMuted,\n }}\n >\n {entry.label}\n </span>\n <div\n style={{\n fontSize: fs.body,\n lineHeight: 1.5,\n color: entry.isCurrent ? theme.textPrimary : theme.textSecondary,\n marginTop: 2,\n }}\n >\n {entry.text}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n","import { useState, useMemo, useRef, useEffect } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface GanttTimelineProps extends BaseComponentProps {\n /** Stage snapshots with timing info */\n snapshots: StageSnapshot[];\n /** Currently selected stage index */\n selectedIndex?: number;\n /** Callback when a stage bar is clicked */\n onSelect?: (index: number) => void;\n /** Max visible rows before collapsing (0 = no collapse). Default: 5 */\n maxVisibleRows?: number;\n}\n\n/**\n * Horizontal Gantt-style timeline showing stage durations and overlap.\n * Collapses to `maxVisibleRows` with expand/collapse toggle.\n * Auto-scrolls to keep the active stage visible when collapsed.\n */\nexport function GanttTimeline({\n snapshots,\n selectedIndex = 0,\n onSelect,\n size = \"default\",\n unstyled = false,\n className,\n style,\n maxVisibleRows = 5,\n}: GanttTimelineProps) {\n const [expanded, setExpanded] = useState(false);\n const activeRowRef = useRef<HTMLDivElement | null>(null);\n const scrollContainerRef = useRef<HTMLDivElement | null>(null);\n\n const totalWallTime = useMemo(\n () => Math.max(...snapshots.map((s) => s.startMs + s.durationMs), 1),\n [snapshots]\n );\n\n const fs = fontSize[size];\n const pad = padding[size];\n const labelWidth = size === \"compact\" ? 50 : size === \"detailed\" ? 100 : 80;\n const msWidth = size === \"compact\" ? 28 : 36;\n const rowHeight = size === \"compact\" ? 18 : 22;\n\n const collapsible = maxVisibleRows > 0 && snapshots.length > maxVisibleRows;\n const showAll = expanded || !collapsible;\n\n // Auto-scroll to active row when collapsed\n useEffect(() => {\n if (!showAll && activeRowRef.current && scrollContainerRef.current) {\n activeRowRef.current.scrollIntoView({\n block: \"nearest\",\n behavior: \"smooth\",\n });\n }\n }, [selectedIndex, showAll]);\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"gantt-timeline\" role=\"listbox\" aria-label=\"Execution timeline\">\n {snapshots.map((snap, idx) => (\n <div\n key={`${snap.stageName}-${idx}`}\n data-fp=\"gantt-bar\"\n data-selected={idx === selectedIndex}\n data-visible={idx <= selectedIndex}\n role=\"option\"\n aria-selected={idx === selectedIndex}\n aria-label={`${snap.stageLabel}, ${snap.durationMs}ms`}\n onClick={() => onSelect?.(idx)}\n >\n <span data-fp=\"gantt-label\">{snap.stageLabel}</span>\n <span data-fp=\"gantt-duration\">{snap.durationMs}ms</span>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{ padding: pad, fontFamily: theme.fontSans, ...style }}\n data-fp=\"gantt-timeline\"\n >\n {/* Header with collapse toggle */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n {size === \"compact\" ? \"Timeline\" : \"Execution Timeline\"}\n </span>\n {collapsible && (\n <button\n onClick={() => setExpanded((e) => !e)}\n style={{\n background: \"none\",\n border: `1px solid ${theme.border}`,\n borderRadius: 4,\n color: theme.textSecondary,\n fontSize: fs.small,\n padding: \"2px 8px\",\n cursor: \"pointer\",\n fontFamily: theme.fontSans,\n }}\n >\n {expanded\n ? \"Collapse\"\n : `${snapshots.length - maxVisibleRows} more...`}\n </button>\n )}\n </div>\n\n {/* Scrollable rows container */}\n <div\n ref={scrollContainerRef}\n role=\"listbox\"\n aria-label=\"Execution timeline\"\n style={{\n marginTop: 8,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 4,\n ...(showAll\n ? {}\n : {\n maxHeight: maxVisibleRows * (rowHeight + 4),\n overflowY: \"auto\",\n scrollbarWidth: \"thin\",\n }),\n }}\n >\n {snapshots.map((snap, idx) => {\n const leftPct = (snap.startMs / totalWallTime) * 100;\n const widthPct = Math.max((snap.durationMs / totalWallTime) * 100, 1);\n const isSelected = idx === selectedIndex;\n const isVisible = idx <= selectedIndex;\n\n return (\n <div\n key={`${snap.stageName}-${idx}`}\n ref={isSelected ? activeRowRef : undefined}\n role=\"option\"\n aria-selected={isSelected}\n aria-label={`${snap.stageLabel}, ${snap.durationMs}ms`}\n onClick={() => onSelect?.(idx)}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: size === \"compact\" ? 4 : 8,\n cursor: onSelect ? \"pointer\" : \"default\",\n opacity: isVisible ? 1 : 0.3,\n transition: \"opacity 0.3s ease\",\n height: rowHeight,\n flexShrink: 0,\n }}\n >\n <span\n title={snap.stageLabel}\n style={{\n width: labelWidth,\n fontSize: fs.small,\n color: isSelected ? theme.primary : theme.textMuted,\n fontWeight: isSelected ? 600 : 400,\n textAlign: \"right\",\n flexShrink: 0,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {snap.stageLabel}\n </span>\n <div\n style={{\n flex: 1,\n height: size === \"compact\" ? 6 : 8,\n position: \"relative\",\n background: theme.bgTertiary,\n borderRadius: 3,\n }}\n >\n {isVisible && (\n <div\n style={{\n position: \"absolute\",\n left: `${leftPct}%`,\n top: 0,\n width: `${widthPct}%`,\n height: \"100%\",\n borderRadius: 3,\n background: isSelected ? theme.primary : theme.success,\n transition: \"width 0.3s ease\",\n }}\n />\n )}\n </div>\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n fontFamily: theme.fontMono,\n width: msWidth,\n flexShrink: 0,\n }}\n >\n {snap.durationMs}ms\n </span>\n </div>\n );\n })}\n </div>\n\n {/* Time axis */}\n <div\n style={{\n marginTop: 4,\n marginLeft: labelWidth + (size === \"compact\" ? 4 : 8),\n marginRight: msWidth + (size === \"compact\" ? 4 : 8),\n display: \"flex\",\n justifyContent: \"space-between\",\n fontSize: fs.small - 1,\n color: theme.textMuted,\n fontFamily: theme.fontMono,\n }}\n >\n <span>0ms</span>\n {size !== \"compact\" && (\n <span>{(totalWallTime / 2).toFixed(1)}ms</span>\n )}\n <span>{totalWallTime.toFixed(1)}ms</span>\n </div>\n </div>\n );\n}\n","/**\n * TraceFlow — ReactFlow renderer driven by `createTraceStructureRecorder`.\n *\n * Two input modes (mutually exclusive):\n *\n * 1. **Live mode**: pass `recorder={traceHandle}`. The component\n * subscribes via `useSyncExternalStore` to the recorder's\n * pub-sub `subscribe()` API and re-renders as the builder runs.\n * Ideal for incremental visualisation (Lens-style live chart\n * construction).\n *\n * 2. **Static mode**: pass `graph={{ nodes, edges }}`. The component\n * treats the graph as final and renders once. Ideal for post-build\n * snapshots (Trace tab, docs site).\n *\n * Layout is pluggable:\n *\n * - Pass a `layout` function `(graph) => positioned graph`. Default is\n * a simple BFS tree walk (Y_STEP=100, X_SPREAD=200).\n * - Pass the literal `\"passthrough\"` to skip layout when nodes are\n * already pre-positioned by the caller.\n *\n * @example\n * ```tsx\n * import { createTraceStructureRecorder, TraceFlow } from 'footprint-explainable-ui/flowchart';\n * import { flowChart } from 'footprintjs';\n *\n * function MyTraceUI() {\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * useEffect(() => {\n * flowChart('seed', fn, 'seed', {\n * structureRecorders: [trace.recorder],\n * }).addFunction('a', fnA, 'a').build();\n * }, [trace]);\n * return <TraceFlow recorder={trace} />;\n * }\n * ```\n */\n\nimport type * as React from \"react\";\nimport { useMemo, useCallback, useSyncExternalStore } from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n MarkerType,\n} from \"@xyflow/react\";\nimport type { Node, Edge, NodeTypes, EdgeTypes } from \"@xyflow/react\";\nimport type {\n TraceGraph,\n TraceNode,\n TraceEdge,\n TraceStructureRecorderHandle,\n} from \"./traceStructureRecorder\";\nimport { StageNode } from \"../StageNode\";\nimport type { StageNodeData } from \"../StageNode\";\nimport { rawDefaults } from \"../../theme/tokens\";\nimport type { BaseComponentProps } from \"../../types\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Layout\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst Y_STEP = 100;\nconst X_SPREAD = 200;\n\n/** Layout function shape — takes a graph, returns a graph with positions set. */\nexport type TraceFlowLayout = (graph: TraceGraph) => TraceGraph;\n\n/**\n * Default tree-walk layout.\n *\n * Edge-kind semantics (critical for parity)\n * ─────────────────────────────────────────\n * `fork-branch` + `decision-branch` edges are SIBLINGS at depth+1\n * (centered under the parent). A `next` edge from a node that ALSO\n * has branch edges is the \"after convergence\" target — its rank is\n * `max(deepest branch subtree) + 1`, so it sits BELOW the fan-out,\n * matching the legacy diamond layout.\n *\n * LoadOrder (fork)\n * ├── fork-branch → CheckInventory (sibling, y+1)\n * ├── fork-branch → RunFraudCheck (sibling, y+1)\n * └── next → FinalizeOrder (after convergence,\n * below deepest sibling)\n *\n * A `next` edge from a node with NO branch edges is a plain linear\n * chain — target at depth+1.\n *\n * `loop` back-edges DO NOT shape layout (they're scrub-time visual\n * markers only).\n *\n * Limitations (documented; not bugs)\n * ──────────────────────────────────\n * - Multi-root graphs render with the first-seen node as the visual\n * root; orphans stack below.\n * - Convergence where multiple branches join into a single node:\n * the node is placed under its FIRST traversed branch (first-wins).\n * For deep DAGs swap in a graph-layout library (dagre, elk).\n * - Sibling x-positions are local to each parent's subtree; no\n * global x-overlap detection across deep nested structures.\n */\nexport const defaultTraceFlowLayout: TraceFlowLayout = (graph) => {\n if (graph.nodes.length === 0) return { nodes: [], edges: graph.edges };\n\n // Split outgoing edges into two semantic groups per node:\n // - branches: fork-branch + decision-branch (siblings at y+1)\n // - linearNext: 'next' edges (after-convergence, deeper rank)\n // Loop back-edges (kind: 'loop') do NOT shape layout.\n const branchChildrenOf = new Map<string, string[]>();\n const nextChildrenOf = new Map<string, string[]>();\n const hasIncomingForward = new Set<string>();\n for (const e of graph.edges) {\n const kind = e.data?.kind;\n if (kind === \"loop\") continue;\n hasIncomingForward.add(e.target);\n if (kind === \"fork-branch\" || kind === \"decision-branch\") {\n const arr = branchChildrenOf.get(e.source) ?? [];\n arr.push(e.target);\n branchChildrenOf.set(e.source, arr);\n } else {\n // 'next' (default) — linear continuation. Treat undefined kind\n // as 'next' so forward edges without explicit kind still flow.\n const arr = nextChildrenOf.get(e.source) ?? [];\n arr.push(e.target);\n nextChildrenOf.set(e.source, arr);\n }\n }\n\n // Seed: first node (insertion order) with no incoming non-loop edge.\n const seed = graph.nodes.find((n) => !hasIncomingForward.has(n.id)) ?? graph.nodes[0]!;\n\n const positions = new Map<string, { x: number; y: number }>();\n\n /**\n * Recursive tree-walk. Returns the bottom-most y reached in this\n * subtree so the parent can position its `next` continuation BELOW\n * the deepest descendant (post-convergence semantics).\n */\n function layoutSubtree(nodeId: string, x: number, y: number): number {\n if (positions.has(nodeId)) {\n // Convergence: this node was already placed by an earlier branch.\n // Keep the original position (first-wins) and report its current\n // bottom so the caller's `next` target lands below us correctly.\n return positions.get(nodeId)!.y;\n }\n positions.set(nodeId, { x, y });\n\n // Place fork/decision branches first — they're siblings at y+1.\n let deepestBranchY = y;\n const branches = branchChildrenOf.get(nodeId) ?? [];\n if (branches.length > 0) {\n const childY = y + Y_STEP;\n const totalWidth = (branches.length - 1) * X_SPREAD;\n const startX = x - totalWidth / 2;\n for (let i = 0; i < branches.length; i++) {\n const childId = branches[i]!;\n const childX = startX + i * X_SPREAD;\n const subtreeBottom = layoutSubtree(childId, childX, childY);\n if (subtreeBottom > deepestBranchY) deepestBranchY = subtreeBottom;\n }\n }\n\n // Then place `next` continuations. If branches exist, `next` lands\n // BELOW the deepest branch (post-convergence). If no branches, it's\n // a plain linear chain — y+1.\n const nextChildren = nextChildrenOf.get(nodeId) ?? [];\n if (nextChildren.length > 0) {\n const nextY = branches.length > 0 ? deepestBranchY + Y_STEP : y + Y_STEP;\n // Multiple `next` from one node is rare (linear chains have one);\n // when it happens, distribute horizontally like branches.\n const totalWidth = (nextChildren.length - 1) * X_SPREAD;\n const startX = x - totalWidth / 2;\n let deepestNextY = nextY;\n for (let i = 0; i < nextChildren.length; i++) {\n const childId = nextChildren[i]!;\n const childX = startX + i * X_SPREAD;\n const subtreeBottom = layoutSubtree(childId, childX, nextY);\n if (subtreeBottom > deepestNextY) deepestNextY = subtreeBottom;\n }\n return deepestNextY;\n }\n\n return deepestBranchY;\n }\n\n layoutSubtree(seed.id, 0, 0);\n\n // Unreached nodes (multi-root or cycles outside the seed's tree)\n // stack below. Use a loop (not `Math.max(...spread)`) — spread\n // blows the call stack at ~10k+ args.\n let maxY = 0;\n for (const p of positions.values()) {\n if (p.y > maxY) maxY = p.y;\n }\n let orphanY = maxY + Y_STEP;\n for (const n of graph.nodes) {\n if (!positions.has(n.id)) {\n positions.set(n.id, { x: 0, y: orphanY });\n orphanY += Y_STEP;\n }\n }\n\n return {\n nodes: graph.nodes.map((n) => ({\n ...n,\n position: positions.get(n.id) ?? n.position,\n })),\n edges: graph.edges,\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Edge styling\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceFlowEdgeColors {\n next: string;\n forkBranch: string;\n decisionBranch: string;\n loop: string;\n}\n\nconst DEFAULT_EDGE_COLORS: TraceFlowEdgeColors = {\n next: rawDefaults.colors.textMuted,\n forkBranch: rawDefaults.colors.textMuted,\n decisionBranch: rawDefaults.colors.primary,\n loop: rawDefaults.colors.warning,\n};\n\nfunction styleEdge(edge: TraceEdge, colors: TraceFlowEdgeColors): Edge {\n const kind = edge.data?.kind ?? \"next\";\n const color =\n kind === \"loop\"\n ? colors.loop\n : kind === \"fork-branch\"\n ? colors.forkBranch\n : kind === \"decision-branch\"\n ? colors.decisionBranch\n : colors.next;\n const styled: Edge = {\n ...edge,\n type: kind === \"loop\" ? \"step\" : \"smoothstep\",\n animated: false,\n style: { stroke: color, strokeWidth: 1.5 },\n markerEnd: { type: MarkerType.ArrowClosed, color, width: 16, height: 16 },\n };\n if (kind === \"loop\") {\n styled.style = { ...styled.style, strokeDasharray: \"4 3\" };\n }\n return styled;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype TraceFlowSource =\n | { recorder: TraceStructureRecorderHandle; graph?: never }\n | { graph: TraceGraph; recorder?: never };\n\nexport type TraceFlowProps = BaseComponentProps &\n TraceFlowSource & {\n /** Layout function. Default: BFS tree walk. Pass the literal\n * `\"passthrough\"` to skip layout when nodes already carry positions. */\n layout?: TraceFlowLayout | \"passthrough\";\n /** Per-kind edge color overrides. */\n edgeColors?: Partial<TraceFlowEdgeColors>;\n /** Node click handler — receives the node id. */\n onNodeClick?: (id: string) => void;\n /**\n * Consumer-supplied xyflow node types. Merged with the built-in\n * `{ stageNode: StageNode }` registry — keys you supply OVERRIDE\n * the default for that node type. Pass `{ stageNode: MyNode }` to\n * replace the default stage renderer entirely, or add new keys\n * for nodes you build yourself (any nodes you push into the\n * graph with `type: 'customKey'` will use your component).\n */\n nodeTypes?: NodeTypes;\n /**\n * Consumer-supplied xyflow edge types. Merged with no built-in\n * defaults — pass `{ myEdge: MyEdge }` to register custom edge\n * components for nodes/edges you build with `type: 'myEdge'`.\n */\n edgeTypes?: EdgeTypes;\n /**\n * Children rendered INSIDE the `<ReactFlow>` element, after the\n * built-in `<Background>`. Use this slot to mount xyflow\n * accessory components like `<Controls />`, `<MiniMap />`, or a\n * custom legend. If unset, only the default Background is rendered.\n *\n * @example\n * ```tsx\n * import { Controls, MiniMap } from '@xyflow/react';\n * <TraceFlow recorder={r}>\n * <Controls />\n * <MiniMap />\n * </TraceFlow>\n * ```\n */\n children?: React.ReactNode;\n };\n\nconst DEFAULT_NODE_TYPES: NodeTypes = { stageNode: StageNode };\n\n/**\n * Convert a `TraceNode` (with `TraceNodeData`) to the `StageNode`-typed\n * node shape so the built-in `<StageNode>` renderer works.\n *\n * Pass-through contract: if the consumer pushed a node with a custom\n * `type` (anything OTHER than the recorder's default `'stage'`), this\n * function returns the node UNCHANGED so xyflow's `nodeTypes` lookup\n * sees the consumer's chosen key. This is what makes the `nodeTypes`\n * extension point useful — without it every node would be force-typed\n * to `'stageNode'` and consumer registrations would never route.\n */\nfunction toStageNode(node: TraceNode): Node {\n // Consumer-supplied custom type — pass through unchanged.\n // Recorders produce nodes with `type: 'stage'` (the recorder's\n // default); anything else is consumer-authored and must be respected.\n if (node.type !== undefined && node.type !== \"stage\") {\n return node as Node;\n }\n\n const data = node.data;\n const stageData: StageNodeData = {\n label: data.label,\n isDecider: data.isDecider,\n isFork: data.isFork,\n isSubflow: data.isSubflow,\n active: false,\n done: false,\n error: false,\n ...(data.description !== undefined && { description: data.description }),\n ...(data.icon !== undefined && { icon: data.icon }),\n ...(data.subflowId !== undefined && { subflowId: data.subflowId }),\n ...(data.isLazy === true && { isLazy: true }),\n };\n return {\n ...node,\n type: \"stageNode\",\n data: stageData as unknown as Record<string, unknown>,\n };\n}\n\n// Empty-graph sentinel returned by static-mode getSnapshot when no\n// graph or recorder is present. Module-scoped so React's identity check\n// sees a stable reference across renders.\nconst EMPTY_GRAPH: TraceGraph = { nodes: [], edges: [] };\n\n// ── Subscription helpers (defined at module scope so useSyncExternalStore\n// sees stable function references when the recorder doesn't change) ─\n\nfunction subscribeToRecorder(recorder: TraceStructureRecorderHandle | undefined) {\n return (listener: () => void): (() => void) => {\n if (!recorder) return () => {};\n return recorder.subscribe(listener);\n };\n}\n\nfunction getRecorderVersion(recorder: TraceStructureRecorderHandle | undefined) {\n return (): number => {\n if (!recorder) return 0;\n return recorder.version();\n };\n}\n\nexport function TraceFlow(props: TraceFlowProps) {\n // Dev-mode contract check — TypeScript enforces the discriminated union\n // at compile time, but JS consumers (or `as any` casts) can hit this.\n const proc = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n const isDev = proc?.env?.NODE_ENV !== \"production\";\n if (isDev && !props.recorder && !props.graph) {\n // eslint-disable-next-line no-console\n console.warn(\n \"[TraceFlow] neither `recorder` nor `graph` prop was provided — rendering an empty chart. Pass one of: <TraceFlow recorder={handle} /> OR <TraceFlow graph={{nodes, edges}} />.\",\n );\n }\n\n const layout = props.layout ?? defaultTraceFlowLayout;\n const edgeColors = useMemo<TraceFlowEdgeColors>(\n () => ({ ...DEFAULT_EDGE_COLORS, ...(props.edgeColors ?? {}) }),\n [props.edgeColors],\n );\n\n // Subscribe to the version counter (live mode) — equality-by-number\n // means React only re-renders when the recorder actually mutated.\n // Memoize the subscribe + getSnapshot closures by the recorder\n // identity so useSyncExternalStore doesn't re-subscribe each render.\n const subscribe = useMemo(\n () => subscribeToRecorder(props.recorder),\n [props.recorder],\n );\n const getVersion = useMemo(\n () => getRecorderVersion(props.recorder),\n [props.recorder],\n );\n const version = useSyncExternalStore(subscribe, getVersion, getVersion);\n\n // Resolve graph: live (recorder) vs static (prop). The version\n // dependency drives re-evaluation in live mode; static mode falls\n // through to the prop's identity on each render.\n const { recorder, graph: graphProp } = props;\n const graph: TraceGraph = useMemo<TraceGraph>(() => {\n if (recorder) return recorder.getGraph();\n if (graphProp) return graphProp;\n return EMPTY_GRAPH;\n }, [recorder, graphProp, version]);\n\n const positioned = useMemo<TraceGraph>(() => {\n if (layout === \"passthrough\") return graph;\n return layout(graph);\n }, [graph, layout]);\n\n const reactFlowNodes = useMemo<Node[]>(\n () => positioned.nodes.map(toStageNode),\n [positioned.nodes],\n );\n const reactFlowEdges = useMemo<Edge[]>(\n () => positioned.edges.map((e) => styleEdge(e, edgeColors)),\n [positioned.edges, edgeColors],\n );\n\n const onNodeClickRef = props.onNodeClick;\n const handleNodeClick = useCallback(\n (_: unknown, node: Node) => {\n onNodeClickRef?.(node.id);\n },\n [onNodeClickRef],\n );\n\n const { nodeTypes: userNodeTypes, edgeTypes: userEdgeTypes } = props;\n const mergedNodeTypes = useMemo<NodeTypes>(\n () => (userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES),\n [userNodeTypes],\n );\n\n return (\n <div\n className={props.className}\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 300,\n ...props.style,\n }}\n >\n <ReactFlow\n nodes={reactFlowNodes}\n edges={reactFlowEdges}\n nodeTypes={mergedNodeTypes}\n {...(userEdgeTypes && { edgeTypes: userEdgeTypes })}\n onNodeClick={handleNodeClick}\n fitView\n proOptions={{ hideAttribution: true }}\n >\n <Background variant={BackgroundVariant.Dots} gap={20} size={1} />\n {props.children}\n </ReactFlow>\n </div>\n );\n}\n","/**\n * TracedFlow — runtime-overlay variant of `<TraceFlow>`.\n *\n * Pairs a build-time `TraceGraph` (from `createTraceStructureRecorder`)\n * with a runtime `RuntimeOverlay` (from `createTraceRuntimeOverlay`)\n * and a scrub index → renders an xyflow chart with per-node coloring\n * (done / active / error), per-edge highlighting (executed paths),\n * loop-edge side-routing, and subflow drill-down.\n *\n * The component is orchestration only. Each responsibility lives in\n * an extracted helper / hook (see `_internal/`):\n *\n * - drill state .................. useSubflowDrill\n * - container resize → fitView ... useChartAutoRefit\n * - graph filtering by drill ..... filterGraphForDrill\n * - breadcrumb path .............. buildSubflowBreadcrumb\n * - slice id normalization ....... normalizeSliceLeafIds\n * - mount status aggregation ..... aggregateMountStatus\n * - node / edge styling .......... toStageNodeWithOverlay + styleEdgeWithOverlay\n * - breadcrumb UI ................ <SubflowBreadcrumbBar>\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const runtime = useMemo(() => createTraceRuntimeOverlay(), []);\n * // ... attach both to executor, run the chart ...\n * <TracedFlow\n * graph={trace.getGraph()}\n * overlay={runtime.getOverlay()}\n * scrubIndex={sliderValue}\n * onNodeClick={(stageId) => focusStage(stageId)}\n * onSubflowChange={(mountId) => syncShellDrill(mountId)}\n * />\n * ```\n */\n\nimport type * as React from \"react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n MarkerType,\n} from \"@xyflow/react\";\nimport type { Node, Edge, NodeTypes, EdgeTypes, ReactFlowInstance } from \"@xyflow/react\";\nimport type { TraceGraph, TraceNode, TraceEdge } from \"./traceStructureRecorder\";\nimport type { TraceFlowLayout } from \"./TraceFlow\";\nimport { defaultTraceFlowLayout } from \"./TraceFlow\";\nimport type { RuntimeOverlay } from \"./createTraceRuntimeOverlay\";\nimport { sliceOverlay } from \"./createTraceRuntimeOverlay\";\nimport { StageNode } from \"../StageNode\";\nimport type { StageNodeData } from \"../StageNode\";\nimport { rawDefaults } from \"../../theme/tokens\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { filterGraphForDrill, buildSubflowBreadcrumb } from \"./_internal/subflowDrill\";\nimport { normalizeSliceLeafIds, aggregateMountStatus } from \"./_internal/overlayProjection\";\nimport { useSubflowDrill } from \"./_internal/useSubflowDrill\";\nimport { useChartAutoRefit } from \"./_internal/useChartAutoRefit\";\nimport { SubflowBreadcrumbBar } from \"./SubflowBreadcrumbBar\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Theming\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TracedFlowColors {\n /** Default (un-executed) node text + edge stroke. */\n default: string;\n /** Done — visually de-emphasised (lighter). */\n done: string;\n /** Active — current scrub position. */\n active: string;\n /** Error — node with recorded onError. */\n error: string;\n /** Loop back-edge color. */\n loop: string;\n}\n\nconst DEFAULT_COLORS: TracedFlowColors = {\n default: rawDefaults.colors.textMuted,\n done: rawDefaults.colors.success,\n active: rawDefaults.colors.primary,\n error: rawDefaults.colors.error,\n loop: rawDefaults.colors.warning,\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Per-node / per-edge styling (pure)\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction toStageNodeWithOverlay(\n node: TraceNode,\n doneStageIds: ReadonlySet<string>,\n activeStageId: string | null,\n errorMessage: string | undefined,\n executedOrderIds: readonly string[],\n): Node {\n // Pass-through contract — see TraceFlow.toStageNode for rationale.\n // If consumer pushed a node with a non-default `type`, return it\n // unchanged so xyflow's nodeTypes registry routes to the consumer's\n // component instead of the built-in StageNode. The runtime overlay\n // (done/active/error) is intentionally NOT applied to consumer\n // custom nodes — the consumer's component owns its visual state.\n if (node.type !== undefined && node.type !== \"stage\") {\n return node as Node;\n }\n\n const isDone = doneStageIds.has(node.id);\n const isActive = activeStageId === node.id;\n const wasExecuted = isDone || isActive;\n const hasError = !!errorMessage;\n const dimmed = !wasExecuted && executedOrderIds.length > 0;\n\n // Per-stage step number(s) — a loop may visit the same node multiple times.\n let stepNumbers: number[] | undefined;\n if (executedOrderIds.length > 0) {\n const nums: number[] = [];\n for (let i = 0; i < executedOrderIds.length; i++) {\n if (executedOrderIds[i] === node.id) nums.push(i + 1);\n }\n if (nums.length > 0) stepNumbers = nums;\n }\n\n const stageData: StageNodeData = {\n label: node.data.label,\n isDecider: node.data.isDecider,\n isFork: node.data.isFork,\n isSubflow: node.data.isSubflow,\n active: isActive,\n done: isDone,\n error: hasError,\n ...(node.data.description !== undefined && { description: node.data.description }),\n ...(node.data.icon !== undefined && { icon: node.data.icon }),\n ...(node.data.subflowId !== undefined && { subflowId: node.data.subflowId }),\n ...(node.data.isLazy === true && { isLazy: true }),\n ...(dimmed && { dimmed: true }),\n ...(stepNumbers && { stepNumbers }),\n ...(errorMessage && { errorMessage }),\n } as StageNodeData;\n\n return {\n ...node,\n type: \"stageNode\",\n data: stageData as unknown as Record<string, unknown>,\n ...(dimmed && { style: { opacity: 0.35 } }),\n };\n}\n\nfunction styleEdgeWithOverlay(\n edge: TraceEdge,\n doneStageIds: ReadonlySet<string>,\n activeStageId: string | null,\n colors: TracedFlowColors,\n): Edge {\n const kind = edge.data?.kind ?? \"next\";\n const sourceExecuted = doneStageIds.has(edge.source) || activeStageId === edge.source;\n const targetExecuted = doneStageIds.has(edge.target) || activeStageId === edge.target;\n const traversed = sourceExecuted && targetExecuted;\n const isLeadingEdge = activeStageId === edge.source && !doneStageIds.has(edge.target);\n\n let color: string = colors.default;\n if (kind === \"loop\") color = colors.loop;\n else if (isLeadingEdge) color = colors.active;\n else if (traversed) color = colors.done;\n\n const styled: Edge = {\n ...edge,\n type: \"smoothstep\",\n animated: isLeadingEdge,\n style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },\n markerEnd: { type: MarkerType.ArrowClosed, color, width: 16, height: 16 },\n };\n if (kind === \"loop\") {\n // Route loop-back edges AROUND the chart via the StageNode's\n // dedicated loop-source / loop-target handles + offset path.\n styled.style = { ...styled.style, strokeDasharray: \"4 3\" };\n (styled.data as any) = {\n ...(styled.data ?? {}),\n pathOptions: { borderRadius: 14, offset: 36 },\n };\n styled.sourceHandle = \"loop-source\";\n styled.targetHandle = \"loop-target\";\n }\n return styled;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TracedFlowProps extends BaseComponentProps {\n /** Build-time graph from `createTraceStructureRecorder().getGraph()`. */\n graph: TraceGraph;\n /** Runtime overlay from `createTraceRuntimeOverlay().getOverlay()`. */\n overlay?: RuntimeOverlay;\n /** Time-travel scrub index. Defaults to the last step (latest state). */\n scrubIndex?: number;\n /** Layout function. Default: BFS tree walk over the recorder graph. */\n layout?: TraceFlowLayout | \"passthrough\";\n /** Color overrides. */\n colors?: Partial<TracedFlowColors>;\n /** Node click handler — receives stage id. */\n onNodeClick?: (stageId: string) => void;\n /**\n * Fires when the chart drills into or out of a subflow (explicit\n * user click on a mount node). Receives the mount stage id (drill\n * in) or `null` (pop back). Container shells use this to keep\n * their data panels in lock-step with the chart's drill state.\n */\n onSubflowChange?: (mountStageId: string | null) => void;\n /**\n * Consumer-supplied xyflow node types. Merged with the built-in\n * `{ stageNode: StageNode }` registry — keys you supply OVERRIDE\n * the default for that node type. Pass `{ stageNode: MyNode }` to\n * replace the default stage renderer entirely, or add new keys\n * for custom node components you push into the graph.\n */\n nodeTypes?: NodeTypes;\n /**\n * Consumer-supplied xyflow edge types. Merged with no built-in\n * defaults — pass `{ myEdge: MyEdge }` to register custom edge\n * components for edges you push into the graph with `type: 'myEdge'`.\n */\n edgeTypes?: EdgeTypes;\n /**\n * Children rendered INSIDE the `<ReactFlow>` element, after the\n * built-in `<Background>`. Use this slot to mount xyflow\n * accessory components like `<Controls />`, `<MiniMap />`, or a\n * custom legend. If unset, only the default Background is rendered.\n */\n children?: React.ReactNode;\n}\n\nconst DEFAULT_NODE_TYPES: NodeTypes = { stageNode: StageNode };\n\nexport function TracedFlow({\n graph,\n overlay,\n scrubIndex,\n layout: layoutProp,\n colors: colorOverrides,\n onNodeClick,\n onSubflowChange,\n nodeTypes: userNodeTypes,\n edgeTypes: userEdgeTypes,\n children,\n className,\n style,\n}: TracedFlowProps) {\n const layout = layoutProp ?? defaultTraceFlowLayout;\n const colors = useMemo<TracedFlowColors>(\n () => ({ ...DEFAULT_COLORS, ...(colorOverrides ?? {}) }),\n [colorOverrides],\n );\n const mergedNodeTypes = useMemo<NodeTypes>(\n () => (userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES),\n [userNodeTypes],\n );\n\n // ── Drill state + visibility derivations ──────────────────────────\n const drill = useSubflowDrill(graph, onSubflowChange);\n const filteredGraph = useMemo(\n () => filterGraphForDrill(graph, drill.currentSubflowId),\n [graph, drill.currentSubflowId],\n );\n const breadcrumb = useMemo(\n () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),\n [graph, drill.currentSubflowId],\n );\n const positioned = useMemo<TraceGraph>(\n () => (layout === \"passthrough\" ? filteredGraph : layout(filteredGraph)),\n [filteredGraph, layout],\n );\n\n // ── Runtime overlay slice → leaf-normalize + mount aggregation ────\n const slice = useMemo(() => {\n const empty = {\n doneStageIds: new Set<string>(),\n activeStageId: null as string | null,\n executedStageIds: new Set<string>(),\n executedOrderIds: [] as string[],\n errors: new Map<string, string>(),\n };\n if (!overlay) return empty;\n const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);\n const normalized = normalizeSliceLeafIds(sliceOverlay(overlay, idx));\n return aggregateMountStatus(normalized, graph, drill.currentSubflowId);\n }, [overlay, scrubIndex, graph, drill.currentSubflowId]);\n\n // ── xyflow nodes + edges (re-run per scrub tick) ──────────────────\n const reactFlowNodes = useMemo<Node[]>(\n () =>\n positioned.nodes.map((n) =>\n toStageNodeWithOverlay(\n n,\n slice.doneStageIds,\n slice.activeStageId,\n slice.errors.get(n.id),\n slice.executedOrderIds,\n ),\n ),\n [positioned.nodes, slice],\n );\n const reactFlowEdges = useMemo<Edge[]>(\n () =>\n positioned.edges.map((e) =>\n styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors),\n ),\n [positioned.edges, slice, colors],\n );\n\n // ── Click handling: drill on subflow mount click, propagate click ─\n const handleNodeClick = useCallback(\n (_: unknown, node: Node) => {\n const data = (node.data ?? {}) as StageNodeData;\n if (data.isSubflow && data.subflowId) {\n drill.drillInto(data.subflowId);\n }\n onNodeClick?.(node.id);\n },\n [drill, onNodeClick],\n );\n\n // ── Container auto-refit (xyflow's fitView is mount-only) ─────────\n const wrapperRef = useRef<HTMLDivElement>(null);\n const [rfInstance, setRfInstance] = useState<ReactFlowInstance | null>(null);\n useChartAutoRefit(wrapperRef, rfInstance);\n\n return (\n <div\n ref={wrapperRef}\n className={className}\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 300,\n display: \"flex\",\n flexDirection: \"column\",\n ...style,\n }}\n >\n {breadcrumb.length > 1 && (\n <SubflowBreadcrumbBar\n entries={breadcrumb}\n onNavigate={drill.setCurrentSubflowId}\n />\n )}\n <div style={{ flex: 1, minHeight: 0 }}>\n <ReactFlow\n nodes={reactFlowNodes}\n edges={reactFlowEdges}\n nodeTypes={mergedNodeTypes}\n {...(userEdgeTypes && { edgeTypes: userEdgeTypes })}\n onNodeClick={handleNodeClick}\n onInit={setRfInstance}\n fitView\n proOptions={{ hideAttribution: true }}\n >\n <Background variant={BackgroundVariant.Dots} gap={20} size={1} />\n {children}\n </ReactFlow>\n </div>\n </div>\n );\n}\n","/**\n * Dev-mode detection without depending on `@types/node`.\n *\n * Returns `true` when running outside an explicitly production env.\n * Browser builds (no `process` global) treat as dev — acceptable for\n * a debugging library: a user-visible warning in a browser is a\n * debugging signal anyway.\n *\n * Shared by every translator's notify path + orphan-event warnings.\n */\nexport function isDevModeEnv(): boolean {\n const proc = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n return proc?.env?.NODE_ENV !== \"production\";\n}\n\n/**\n * Dev-mode `console.warn` shim. No-op in production. Lazy message\n * construction (`messageFn`) — avoids string-concat cost when prod.\n */\nexport function devWarn(messageFn: () => string, ...extras: unknown[]): void {\n if (!isDevModeEnv()) return;\n // eslint-disable-next-line no-console\n console.warn(messageFn(), ...extras);\n}\n","/**\n * `createNotifier` — shared pub-sub + monotonic version + microtask\n * batching, extracted from `traceStructureRecorder` and\n * `createTraceRuntimeOverlay` (which duplicated this pattern).\n *\n * Every translator needs the same shape to integrate with React's\n * `useSyncExternalStore`:\n * - `subscribe(listener)` returns unsubscribe\n * - `version()` returns monotonic int (snapshot identity)\n * - `notify()` bumps version + fires listeners (error-isolated)\n *\n * Microtask batching\n * ──────────────────\n * A single stage execution fires multiple recorder events (Structure\n * `onStageAdded` + `onEdgeAdded` for each edge; Flow `onStageExecuted`;\n * Scope `onCommit`). With 3+ translators subscribed, that's 6+ React\n * re-renders per stage. The batcher coalesces all `notify()` calls\n * within one microtask into a SINGLE listener fire — version still\n * bumps per event (so consumers that poll `version()` from outside\n * React see every change), but listener invocations are deduplicated.\n *\n * Trade-off: listeners observe the FINAL state after a microtask\n * batch, not every intermediate state. Acceptable for UI consumers\n * (React renders the final state anyway). Non-React consumers that\n * need every event should call `getSnapshot()` from inside event\n * handlers, not rely on the listener for granularity.\n *\n * Error isolation\n * ───────────────\n * A throwing listener is caught + warned in dev. Other listeners\n * still fire. Mirrors footprintjs's recorder dispatcher pattern.\n */\n\nimport { devWarn } from \"./devWarn\";\n\nexport interface Notifier {\n /** Subscribe a listener; returns unsubscribe. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps once per `notify()` call. */\n version(): number;\n /** Bump version + schedule a listener flush (coalesced via microtask). */\n notify(): void;\n /** Force-flush any pending coalesced notification immediately. Used\n * by tests that need synchronous observation. */\n flushPending(): void;\n /** Reset the notifier — clears listeners is NOT done (consumers\n * manage their own subscriptions). Only the pending-flush flag\n * and version stay as-is (no consumer should observe a version\n * rollback). */\n // (intentionally no reset for version — monotonicity is load-bearing\n // for useSyncExternalStore snapshot equality)\n}\n\nexport function createNotifier(label = \"notifier\"): Notifier {\n const listeners = new Set<() => void>();\n let v = 0;\n let pending = false;\n\n function flush(): void {\n if (!pending) return;\n pending = false;\n // Snapshot listeners into an array BEFORE iteration. A listener\n // that synchronously subscribes/unsubscribes another listener\n // would otherwise leave Set-iteration semantics implementation-\n // defined. Array snapshot guarantees: every listener registered\n // AT THIS FLUSH-START fires exactly once; listeners added during\n // a callback wait for the next notify cycle.\n const snapshot = Array.from(listeners);\n for (const l of snapshot) {\n try {\n l();\n } catch (err) {\n devWarn(\n () =>\n `[${label}] subscribe() listener threw — isolated; other subscribers continue.`,\n err,\n );\n }\n }\n }\n\n return {\n subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n version(): number {\n return v;\n },\n notify(): void {\n v += 1;\n if (pending) return;\n pending = true;\n // Coalesce within a single microtask. `queueMicrotask` is\n // available in every supported runtime (Node 11+, all browsers).\n queueMicrotask(flush);\n },\n flushPending(): void {\n flush();\n },\n };\n}\n","/**\n * createTraceRuntimeOverlay — event-driven runtime overlay for `<TracedFlow>`.\n *\n * The runtime twin of `createTraceStructureRecorder` (L7.7). Where the\n * structure recorder accumulates the build-time graph SHAPE from\n * `StructureRecorder` events, this recorder accumulates the runtime\n * EXECUTION STATE (which nodes ran, current active, errors) from\n * `FlowRecorder` events. The two compose into the full time-travel\n * trace UI:\n *\n * StructureRecorder events → TraceGraph (nodes + edges, id-keyed)\n * FlowRecorder events → RuntimeOverlay (per-node state, id-keyed)\n * │\n * ▼\n * <TracedFlow graph={...} overlay={...} scrubIndex={i} />\n *\n * **Universal key**: `runtimeStageId = [subflowPath/]stageId#executionIndex`.\n * Loops re-execute the same stageId with bumping executionIndex — the\n * overlay records each execution as a distinct step in `executionOrder`\n * but updates the SAME node-by-id in `doneStageIds` (because the build-\n * time graph has one node per spec — loops re-visit it).\n *\n * Per L7.7 panel guidance: the consumer pattern mirrors recorder error\n * isolation, exposes a pub-sub `subscribe(listener)` + monotonic\n * `version()` for `useSyncExternalStore` integration, and accumulates\n * pure data with zero React coupling.\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local type aliases mirroring footprintjs FlowRecorder\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Same rationale as traceStructureRecorder.ts: explainable-ui has no\n// `footprintjs` dep declared (consumer wires it). We mirror the\n// subset of `FlowRecorder` we consume. If footprintjs changes the\n// interface, this module's types update in lockstep.\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface RuntimeStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n /** Discriminator for which kind of stage completed. footprintjs v6+\n * fires this event uniformly for every stage kind (proposal #003);\n * consumers route by `stageType` without a chart-spec lookup. */\n readonly stageType: 'linear' | 'decider' | 'fork' | 'selector' | 'subflow-mount';\n readonly traversalContext: TraversalContext;\n}\n\ninterface RuntimeErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface RuntimeRunStartEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface RuntimeRunEndEvent {\n readonly traversalContext?: TraversalContext;\n}\n\n/** Minimal FlowRecorder interface mirror — see top-of-file rationale.\n *\n * As of footprintjs v6 (proposal #003), `onStageExecuted` fires\n * uniformly for ALL stage kinds — linear / decider / fork / selector\n * / subflow-mount. The event payload carries a `stageType` field for\n * consumers that need to route by kind. We no longer need separate\n * `onDecision` / `onFork` / `onSelected` handlers to track \"did this\n * stage run\" — a single `onStageExecuted` handler suffices. */\nexport interface MinimalFlowRecorder {\n readonly id: string;\n onStageExecuted?(event: RuntimeStageExecutedEvent): void;\n onError?(event: RuntimeErrorEvent): void;\n onRunStart?(event: RuntimeRunStartEvent): void;\n onRunEnd?(event: RuntimeRunEndEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Runtime overlay shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * One entry in the execution timeline. `<TracedFlow>` keys time-travel\n * scrubbing on the index into this array — at index `i`, all entries\n * `0..i-1` are \"done\", entry `i` is \"active\".\n */\nexport interface RuntimeExecutionStep {\n /** `[subflowPath/]stageId#executionIndex` — universal key. */\n readonly runtimeStageId: string;\n /** Base stage id (without `#N`) — matches the `TraceGraph` node id. */\n readonly stageId: string;\n /** Human-readable label (from event.stageName). */\n readonly stageName: string;\n /** When this step recorded, in ms since recorder start. */\n readonly timestampMs: number;\n}\n\nexport interface RuntimeOverlay {\n /** Ordered execution history — drives time-travel scrubbing. */\n readonly executionOrder: readonly RuntimeExecutionStep[];\n /** Per-base-stageId error message (most-recent wins). */\n readonly errors: ReadonlyMap<string, string>;\n /** True after `onRunStart` until `onRunEnd` — useful for \"still running\" indicators. */\n readonly running: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceRuntimeOverlayHandle {\n /** The recorder to attach via `executor.attachFlowRecorder(handle.recorder)`. */\n recorder: MinimalFlowRecorder;\n /** Returns a defensive copy of the current overlay state. */\n getOverlay(): RuntimeOverlay;\n /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps once per overlay-mutating event. */\n version(): number;\n /** Reset for reuse across runs. Does NOT bump version or notify (matches\n * traceStructureRecorder's reset contract). */\n reset(): void;\n}\n\nexport interface CreateTraceRuntimeOverlayOptions {\n id?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport { createNotifier } from \"./_internal/notifyChange\";\n\n/**\n * Strip `#executionIndex` suffix to get the base stage id.\n *\n * **WARNING (invariant I3)**: use ONLY for DISPLAY. NEVER for matching\n * commitLog stageIds — those use the full path-prefixed id (e.g.,\n * `'sf-a/sf-b/inner'`) as emitted by the engine. Parsing back to the\n * unqualified inner name loses uniqueness across subflow instances.\n */\nfunction parseStageIdFromRuntimeStageId(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createTraceRuntimeOverlay(\n options: CreateTraceRuntimeOverlayOptions = {},\n): TraceRuntimeOverlayHandle {\n const id = options.id ?? \"trace-runtime-overlay\";\n const startTime = performance.now();\n\n let executionOrder: RuntimeExecutionStep[] = [];\n // Defensive dedupe by runtimeStageId — should be moot post-#003\n // since the engine fires `onStageExecuted` exactly once per stage\n // execution, but a future change or a misbehaving recorder upstream\n // could still produce duplicates; keep the set as belt-and-suspenders.\n const recordedRuntimeStageIds = new Set<string>();\n const errors = new Map<string, string>();\n let running = false;\n const notifier = createNotifier(\"traceRuntimeOverlay\");\n const notifyChange = notifier.notify;\n\n function pushStep(runtimeStageId: string, stageId: string, stageName: string): void {\n if (recordedRuntimeStageIds.has(runtimeStageId)) return;\n recordedRuntimeStageIds.add(runtimeStageId);\n executionOrder.push({\n runtimeStageId,\n stageId,\n stageName,\n timestampMs: performance.now() - startTime,\n });\n notifyChange();\n }\n\n const recorder: MinimalFlowRecorder = {\n id,\n onRunStart() {\n running = true;\n notifyChange();\n },\n onRunEnd() {\n running = false;\n notifyChange();\n },\n onStageExecuted(event) {\n // footprintjs v6 (#003) fires this for EVERY stage kind —\n // linear / decider / fork / selector / subflow-mount — so\n // we no longer need separate handlers for the branching events.\n const runtimeStageId = event.traversalContext.runtimeStageId;\n const baseStageId = parseStageIdFromRuntimeStageId(runtimeStageId);\n pushStep(runtimeStageId, baseStageId, event.stageName);\n },\n onError(event) {\n const fallbackId =\n event.stageId ??\n (event.traversalContext\n ? parseStageIdFromRuntimeStageId(event.traversalContext.runtimeStageId)\n : event.stageName);\n errors.set(fallbackId, event.message ?? \"error\");\n notifyChange();\n },\n };\n\n return {\n recorder,\n getOverlay(): RuntimeOverlay {\n return {\n executionOrder: executionOrder.map((s) => ({ ...s })),\n errors: new Map(errors),\n running,\n };\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n executionOrder = [];\n recordedRuntimeStageIds.clear();\n errors.clear();\n running = false;\n // Note: reset does NOT bump version or notify (matches\n // traceStructureRecorder contract — see its `reset()` JSDoc\n // for the consumer-facing recipe).\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Overlay slicing for time-travel\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Snapshot of overlay state AT a specific scrub index. Drives node\n * coloring in `<TracedFlow>`.\n */\nexport interface RuntimeOverlaySlice {\n /** Base stage ids that completed before the active scrub position. */\n readonly doneStageIds: ReadonlySet<string>;\n /** The currently-active stage id (or `null` when scrub is at 0 with no exec yet). */\n readonly activeStageId: string | null;\n /** Union of done + active — convenient for \"executed at all\" checks. */\n readonly executedStageIds: ReadonlySet<string>;\n /** The full ordered list of base stage ids up through the active position —\n * used by renderers that want to number stages by occurrence (e.g.,\n * show \"3rd loop iteration\" badges). */\n readonly executedOrderIds: readonly string[];\n /** Pass-through errors map for the renderer. */\n readonly errors: ReadonlyMap<string, string>;\n}\n\n/**\n * Slice `overlay.executionOrder` at the given index:\n *\n * - `executionOrder[0..index-1]` → \"done\"\n * - `executionOrder[index]` → \"active\"\n * - `index >= executionOrder.length` → all done, no active\n *\n * Returns an empty slice when overlay has no execution history.\n */\nexport function sliceOverlay(\n overlay: RuntimeOverlay,\n index: number,\n): RuntimeOverlaySlice {\n const order = overlay.executionOrder;\n if (order.length === 0) {\n return {\n doneStageIds: new Set(),\n activeStageId: null,\n executedStageIds: new Set(),\n executedOrderIds: [],\n errors: overlay.errors,\n };\n }\n const clampedIndex = Math.max(0, Math.min(index, order.length - 1));\n const doneStageIds = new Set<string>();\n for (let i = 0; i < clampedIndex; i++) {\n doneStageIds.add(order[i]!.stageId);\n }\n const activeStep = order[clampedIndex];\n const activeStageId = activeStep ? activeStep.stageId : null;\n const executedStageIds = new Set(doneStageIds);\n if (activeStageId) executedStageIds.add(activeStageId);\n const executedOrderIds = order.slice(0, clampedIndex + 1).map((s) => s.stageId);\n return {\n doneStageIds,\n activeStageId,\n executedStageIds,\n executedOrderIds,\n errors: overlay.errors,\n };\n}\n","/**\n * Pure helpers for subflow drill-down on a `TraceGraph`.\n *\n * Filtering and breadcrumb computation are derived from the\n * `TraceNodeData.subflowOf` field that the structure recorder sets\n * at `onSubflowMounted` time. Both functions are pure (no I/O, no\n * React) so they can be unit-tested in isolation and reused by any\n * renderer.\n */\n\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\n/**\n * Filter the trace graph by drill-down scope.\n *\n * - `currentSubflowId === null` → show top-level (nodes with no\n * `subflowOf`). Subflow internals are hidden; their mount node\n * stays visible as a single clickable card.\n * - `currentSubflowId === 'X'` → show only nodes where\n * `subflowOf === 'X'` (the drilled-in subflow's internals).\n *\n * Edges follow the same filter — only edges where both endpoints\n * are in the visible set survive. When nothing would be filtered\n * out, returns the original graph reference (preserves upstream\n * memoization).\n */\nexport function filterGraphForDrill(\n graph: TraceGraph,\n currentSubflowId: string | null,\n): TraceGraph {\n if (graph.nodes.length === 0) return graph;\n const matchesScope = (subflowOf: string | undefined): boolean =>\n currentSubflowId === null ? subflowOf === undefined : subflowOf === currentSubflowId;\n const visibleIds = new Set<string>();\n for (const n of graph.nodes) {\n if (matchesScope(n.data?.subflowOf)) visibleIds.add(n.id);\n }\n if (visibleIds.size === graph.nodes.length) return graph;\n return {\n nodes: graph.nodes.filter((n) => visibleIds.has(n.id)),\n edges: graph.edges.filter((e) => visibleIds.has(e.source) && visibleIds.has(e.target)),\n };\n}\n\n/** Entry in the breadcrumb path. `subflowId === null` is the root. */\nexport interface BreadcrumbEntry {\n subflowId: string | null;\n label: string;\n}\n\n/**\n * Build the breadcrumb path for the current drill level.\n *\n * Always starts with the root `{ subflowId: null, label: 'Chart' }`.\n * When drilled into a subflow, appends one entry with the mount\n * node's display label (falling back to the subflow id). Multi-level\n * drill chains are NOT supported by the current chart UX (drill is\n * always from root or sibling — clicking a deeper subflow's mount\n * replaces the current scope), so the path has at most 2 entries.\n */\nexport function buildSubflowBreadcrumb(\n graph: TraceGraph,\n currentSubflowId: string | null,\n): BreadcrumbEntry[] {\n const out: BreadcrumbEntry[] = [{ subflowId: null, label: \"Chart\" }];\n if (currentSubflowId !== null) {\n const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);\n out.push({\n subflowId: currentSubflowId,\n label: mount?.data?.label ?? currentSubflowId,\n });\n }\n return out;\n}\n","/**\n * Pure helpers for projecting a raw `RuntimeOverlaySlice` into the\n * shape `<TracedFlow>` needs for per-node coloring:\n *\n * 1. `normalizeSliceLeafIds` — strips subflow path prefixes from\n * stage ids so they match `TraceNode.id` (graph stores LEAF ids\n * like `charge-card`; overlay records path-prefixed ids like\n * `payment/charge-card`).\n * 2. `aggregateMountStatus` — when execution is INSIDE a subflow,\n * light up the mount node in the parent view as\n * done/active based on its internals' statuses.\n *\n * Both are pure (no I/O, no React). Composed in TracedFlow as\n * `aggregate(normalize(raw))`.\n */\n\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\nexport interface OverlaySlice {\n doneStageIds: ReadonlySet<string>;\n activeStageId: string | null;\n executedStageIds: ReadonlySet<string>;\n executedOrderIds: readonly string[];\n errors: ReadonlyMap<string, string>;\n}\n\n/** Strip everything before the last `/` — `'payment/charge-card'` → `'charge-card'`. */\nfunction leafId(id: string): string {\n const i = id.lastIndexOf(\"/\");\n return i >= 0 ? id.slice(i + 1) : id;\n}\n\n/**\n * Normalize all stage ids in a slice to LEAF ids so they line up\n * with `TraceNode.id` keys for coloring lookups.\n */\nexport function normalizeSliceLeafIds(slice: OverlaySlice): OverlaySlice {\n return {\n doneStageIds: new Set(Array.from(slice.doneStageIds).map(leafId)),\n activeStageId: slice.activeStageId ? leafId(slice.activeStageId) : null,\n executedStageIds: new Set(Array.from(slice.executedStageIds).map(leafId)),\n executedOrderIds: slice.executedOrderIds.map(leafId),\n errors: new Map(Array.from(slice.errors).map(([k, v]) => [leafId(k), v])),\n };\n}\n\n/**\n * Aggregate subflow internals' status onto their mount nodes.\n *\n * - Mount is DONE when EVERY internal stage is done.\n * - Mount is ACTIVE when ANY internal is active or done — but only\n * when we're viewing the TOP-LEVEL chart (`currentSubflowId ===\n * null`). When drilled INTO a subflow, the active highlight goes\n * on the actual subflow stage, not on the parent's mount.\n *\n * Pre-condition: slice has already been leaf-normalized so its\n * stage ids match `graph.nodes[].id`.\n */\nexport function aggregateMountStatus(\n slice: OverlaySlice,\n graph: TraceGraph,\n currentSubflowId: string | null,\n): OverlaySlice {\n if (graph.nodes.length === 0) return slice;\n const mounts = graph.nodes.filter((n) => n.data?.isSubflow && n.data?.subflowId);\n if (mounts.length === 0) return slice;\n const doneIds = new Set(slice.doneStageIds);\n let activeId = slice.activeStageId;\n for (const mount of mounts) {\n const sfId = mount.data!.subflowId as string;\n const members = graph.nodes.filter((n) => n.data?.subflowOf === sfId);\n if (members.length === 0) continue;\n const anyActive = members.some((m) => m.id === slice.activeStageId);\n const anyDone = members.some((m) => slice.doneStageIds.has(m.id));\n const allDone = members.every((m) => slice.doneStageIds.has(m.id));\n if (allDone) doneIds.add(mount.id);\n else if ((anyActive || anyDone) && currentSubflowId === null) {\n activeId = mount.id;\n }\n }\n return { ...slice, doneStageIds: doneIds, activeStageId: activeId };\n}\n","/**\n * useSubflowDrill — drill state for the chart's view scope.\n *\n * - Owns `currentSubflowId: string | null` (null = top-level)\n * - Exposes `drillInto(subflowId)` and `drillUp()` for navigation\n * - Notifies the host via `onSubflowChange(mountStageId | null)`\n * whenever the drill state changes — host wires this to its own\n * drill-stack so data panels follow\n *\n * Drill changes are EXPLICIT — there's no auto-drill on scrub. The\n * mount node's status reflects \"execution is inside\" via\n * `aggregateMountStatus` (see overlayProjection.ts).\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\nexport interface SubflowDrillHandle {\n /** Current drill scope. `null` = top-level. */\n currentSubflowId: string | null;\n /** Navigate INTO the given subflow (by `subflowId`). */\n drillInto: (subflowId: string) => void;\n /** Pop back up to the parent / top-level. */\n drillUp: () => void;\n /** Direct setter for breadcrumb navigation (any target including `null`). */\n setCurrentSubflowId: (id: string | null) => void;\n}\n\nexport function useSubflowDrill(\n graph: TraceGraph,\n onSubflowChange?: (mountStageId: string | null) => void,\n): SubflowDrillHandle {\n const [currentSubflowId, setCurrentSubflowId] = useState<string | null>(null);\n\n // Reset drill state when the graph IDENTITY changes (e.g., the\n // user switched to a different sample in the playground sidebar).\n // Without this, the drill state from sample A persists into\n // sample B's rendering — `currentSubflowId='payment'` survives the\n // chart swap, but sample B has no 'payment' subflow, so the filter\n // returns no visible nodes (blank chart).\n //\n // Also reset when the currently-drilled subflow no longer exists\n // in the new graph (defensive — graph mutations could remove a\n // subflow without changing the wrapper reference).\n const lastGraphRef = useRef<TraceGraph | null>(null);\n if (lastGraphRef.current !== graph) {\n lastGraphRef.current = graph;\n if (\n currentSubflowId !== null &&\n !graph.nodes.some((n) => n.data?.subflowId === currentSubflowId)\n ) {\n // Schedule reset for next render (can't setState during render).\n queueMicrotask(() => setCurrentSubflowId(null));\n }\n }\n\n // Notify the host when drill changes. Resolve the mount stage id\n // from the graph (the parent-chart node whose `subflowId` matches).\n const lastNotifiedRef = useRef<string | null | undefined>(undefined);\n useEffect(() => {\n if (lastNotifiedRef.current === currentSubflowId) return;\n lastNotifiedRef.current = currentSubflowId;\n if (currentSubflowId === null) {\n onSubflowChange?.(null);\n } else {\n const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);\n if (mount) onSubflowChange?.(mount.id);\n }\n }, [currentSubflowId, graph, onSubflowChange]);\n\n const drillInto = useCallback((subflowId: string) => {\n setCurrentSubflowId(subflowId);\n }, []);\n const drillUp = useCallback(() => {\n setCurrentSubflowId(null);\n }, []);\n\n return { currentSubflowId, drillInto, drillUp, setCurrentSubflowId };\n}\n","/**\n * useChartAutoRefit — keep an xyflow chart fitted to its container.\n *\n * xyflow's `fitView` prop only runs on mount; it does NOT re-fit\n * when the container resizes. This hook closes that gap by:\n *\n * 1. Observing the wrapper element via `ResizeObserver` →\n * `instance.fitView({ duration, padding })` on the next animation\n * frame (so the new container size is measured first).\n * 2. Also listening to `window resize` events — `ExplainableShell`\n * dispatches synthetic resize events when its detail panels\n * toggle (those size changes may be animated and not yet\n * measurable by ResizeObserver on the first tick).\n *\n * Without this hook the chart shrinks once on Details-open and\n * never grows back when Details closes.\n */\n\nimport { useEffect } from \"react\";\nimport type { RefObject } from \"react\";\nimport type { ReactFlowInstance } from \"@xyflow/react\";\n\nexport function useChartAutoRefit(\n wrapperRef: RefObject<HTMLElement | null>,\n rfInstance: ReactFlowInstance | null,\n options: { duration?: number; padding?: number } = {},\n): void {\n const duration = options.duration ?? 200;\n const padding = options.padding ?? 0.1;\n\n useEffect(() => {\n const el = wrapperRef.current;\n if (!el || !rfInstance) return;\n let raf = 0;\n const refit = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() => {\n rfInstance.fitView({ duration, padding });\n });\n };\n const ro = new ResizeObserver(refit);\n ro.observe(el);\n window.addEventListener(\"resize\", refit);\n return () => {\n ro.disconnect();\n window.removeEventListener(\"resize\", refit);\n cancelAnimationFrame(raf);\n };\n }, [rfInstance, wrapperRef, duration, padding]);\n}\n","/**\n * SubflowBreadcrumbBar — clickable trail of subflow drill levels.\n *\n * Chart › Outer Subflow › Inner Subflow\n *\n * The last entry renders disabled (you're already here). Earlier\n * entries are clickable — fire `onNavigate(subflowId)` (null = root).\n *\n * Pure presentation: takes the precomputed `entries` array (built by\n * `buildSubflowBreadcrumb` in `_internal/subflowDrill.ts`). No drill\n * state lives here.\n */\n\nimport type { BreadcrumbEntry } from \"./_internal/subflowDrill\";\nimport { rawDefaults } from \"../../theme/tokens\";\n\nexport interface SubflowBreadcrumbBarProps {\n entries: BreadcrumbEntry[];\n onNavigate: (subflowId: string | null) => void;\n}\n\nexport function SubflowBreadcrumbBar({ entries, onNavigate }: SubflowBreadcrumbBarProps) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"6px 12px\",\n fontSize: 11,\n background: rawDefaults.colors.bgSecondary,\n borderBottom: `1px solid ${rawDefaults.colors.border}`,\n flexShrink: 0,\n }}\n aria-label=\"Subflow breadcrumb\"\n >\n {entries.map((entry, i) => {\n const isLast = i === entries.length - 1;\n return (\n <span\n key={entry.subflowId ?? \"__top__\"}\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n >\n <button\n type=\"button\"\n onClick={() => onNavigate(entry.subflowId)}\n disabled={isLast}\n style={{\n background: \"transparent\",\n border: \"none\",\n padding: 0,\n fontSize: 11,\n fontWeight: isLast ? 600 : 500,\n color: isLast ? rawDefaults.colors.textPrimary : rawDefaults.colors.primary,\n cursor: isLast ? \"default\" : \"pointer\",\n textDecoration: isLast ? \"none\" : \"underline\",\n fontFamily: \"inherit\",\n }}\n >\n {entry.label}\n </button>\n {!isLast && <span style={{ color: rawDefaults.colors.textMuted }}>›</span>}\n </span>\n );\n })}\n </div>\n );\n}\n","import { memo } from \"react\";\nimport { theme } from \"../../theme\";\nimport type { BreadcrumbEntry } from \"./useSubflowNavigation\";\n\nexport interface SubflowBreadcrumbProps {\n breadcrumbs: BreadcrumbEntry[];\n onNavigate: (level: number) => void;\n}\n\n/**\n * Breadcrumb bar for subflow drill-down navigation.\n * Shows: Root > SubflowA > SubflowB — clicking any crumb navigates back.\n */\nexport const SubflowBreadcrumb = memo(function SubflowBreadcrumb({\n breadcrumbs,\n onNavigate,\n}: SubflowBreadcrumbProps) {\n if (breadcrumbs.length <= 1) return null;\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n padding: \"6px 12px\",\n background: theme.bgSecondary,\n borderBottom: `1px solid ${theme.border}`,\n fontSize: 12,\n fontFamily: theme.fontSans,\n flexShrink: 0,\n overflowX: \"auto\",\n }}\n >\n {breadcrumbs.map((crumb, i) => {\n const isLast = i === breadcrumbs.length - 1;\n return (\n <span key={`${crumb.label}-${i}`} style={{ display: \"flex\", alignItems: \"center\", gap: 4 }}>\n {i > 0 && (\n <span style={{ color: theme.textMuted, fontSize: 10 }}>\n ›\n </span>\n )}\n {isLast ? (\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <span\n style={{\n color: theme.primary,\n fontWeight: 600,\n }}\n >\n {crumb.label}\n </span>\n {crumb.description && (\n <span\n style={{\n color: theme.textMuted,\n fontWeight: 400,\n fontSize: 11,\n }}\n >\n — {crumb.description}\n </span>\n )}\n </span>\n ) : (\n <button\n onClick={() => onNavigate(i)}\n style={{\n background: \"none\",\n border: \"none\",\n color: theme.textSecondary,\n cursor: \"pointer\",\n padding: \"2px 4px\",\n borderRadius: 4,\n fontSize: 12,\n fontFamily: \"inherit\",\n fontWeight: 500,\n transition: \"color 0.15s\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.color = `${theme.primary}`;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.color = `${theme.textSecondary}`;\n }}\n >\n {crumb.label}\n </button>\n )}\n </span>\n );\n })}\n </div>\n );\n});\n","/**\n * useSubflowNavigation — drill-down breadcrumb tracker for recorder-driven charts.\n *\n * Recorder-driven (v6+): replaces the legacy SpecNode-walk path. Accepts\n * a `TraceGraph` (from `createTraceStructureRecorder`) and tracks WHICH\n * subflow the user has drilled into.\n *\n * Limitation (intentional — recorder graph is flat / mount-only):\n * The StructureRecorder records the MOUNT of each subflow in the\n * parent chart, not the inner structure of each child chart. So\n * \"drill into a subflow\" today returns the SAME graph with the\n * `currentSubflowId` marker advanced — there is no separate\n * child-graph to swap in. Filtering nodes by\n * `data.subflowId === <selected>` would only surface mount nodes,\n * not the child chart's stages.\n *\n * TODO(recorder-driven-nesting): when child charts attach their own\n * `traceStructureRecorder` and surface those graphs via a registry,\n * accept `Map<subflowId, TraceGraph>` and swap `currentGraph` to the\n * child's graph on drill-down. Consumers can then render\n * `<TraceFlow graph={currentGraph} />` per level.\n */\n\nimport { useState, useCallback, useMemo } from \"react\";\nimport type { TraceGraph } from \"./traceStructureRecorder\";\n\nexport interface BreadcrumbEntry {\n /** Display name for this level */\n label: string;\n /** The subflow id that was drilled into to reach this level\n * (undefined for root). */\n subflowId?: string;\n /** Human-readable description of this subflow */\n description?: string;\n}\n\nexport interface SubflowNavigation {\n /** Current breadcrumb path (root → ... → current) */\n breadcrumbs: BreadcrumbEntry[];\n /** Current graph — today identical to the root graph (see file-level\n * TODO). Consumers should still treat this as the source of truth so\n * they remain forward-compatible once per-subflow graphs are wired in. */\n currentGraph: TraceGraph;\n /** Subflow id of the level the user is currently inside (null at root). */\n currentSubflowId: string | null;\n /** Display name of the subflow node we drilled into (null at root). */\n currentSubflowNodeName: string | null;\n /** Call when a node is clicked — drills in if it's a subflow.\n * Returns true when the click pushed a new level. */\n handleNodeClick: (nodeId: string) => boolean;\n /** Navigate to a specific breadcrumb level (0 = root) */\n navigateTo: (level: number) => void;\n /** Whether we're currently inside a subflow (not at root) */\n isInSubflow: boolean;\n}\n\nconst EMPTY_GRAPH: TraceGraph = { nodes: [], edges: [] };\n\n/**\n * Hook that tracks subflow drill-down state for a recorder-driven chart.\n *\n * Maintains a breadcrumb stack. When a subflow node is clicked the\n * stack pushes a new entry; breadcrumb clicks pop back to that level.\n * See file-level docs for the deferred per-subflow graph swap.\n */\nexport function useSubflowNavigation(\n rootGraph: TraceGraph | null,\n): SubflowNavigation {\n const [stack, setStack] = useState<BreadcrumbEntry[]>([]);\n\n const safeRootGraph = rootGraph ?? EMPTY_GRAPH;\n\n // Lookup: subflow id → mount node display name. Populated from the\n // recorder graph so click handlers can resolve the node-id the\n // consumer passes.\n const subflowMounts = useMemo(() => {\n const map = new Map<\n string,\n { subflowId: string; label: string; description?: string }\n >();\n for (const node of safeRootGraph.nodes) {\n if (!node.data?.isSubflow) continue;\n const subflowId =\n typeof node.data.subflowId === \"string\" ? node.data.subflowId : node.id;\n const label =\n typeof node.data.label === \"string\" ? node.data.label : node.id;\n const entry: { subflowId: string; label: string; description?: string } = {\n subflowId,\n label,\n };\n if (typeof node.data.description === \"string\") {\n entry.description = node.data.description;\n }\n // Key by stable id AND by the node id callers usually pass.\n map.set(node.id, entry);\n map.set(subflowId, entry);\n }\n return map;\n }, [safeRootGraph]);\n\n const breadcrumbs: BreadcrumbEntry[] = useMemo(() => {\n const rootLabel = \"Flowchart\";\n const root: BreadcrumbEntry = { label: rootLabel };\n return [root, ...stack];\n }, [stack]);\n\n const handleNodeClick = useCallback(\n (nodeId: string): boolean => {\n const mount = subflowMounts.get(nodeId);\n if (!mount) return false;\n setStack((prev) => {\n const entry: BreadcrumbEntry = {\n label: mount.label,\n subflowId: mount.subflowId,\n };\n if (mount.description !== undefined) entry.description = mount.description;\n return [...prev, entry];\n });\n return true;\n },\n [subflowMounts],\n );\n\n const navigateTo = useCallback((level: number) => {\n if (level === 0) {\n setStack([]);\n } else {\n setStack((prev) => prev.slice(0, level));\n }\n }, []);\n\n const top = stack[stack.length - 1];\n return {\n breadcrumbs,\n // TODO(recorder-driven-nesting): swap to per-subflow graph when\n // child charts attach their own recorders.\n currentGraph: safeRootGraph,\n currentSubflowId: top?.subflowId ?? null,\n currentSubflowNodeName: top?.label ?? null,\n handleNodeClick,\n navigateTo,\n isInSubflow: stack.length > 0,\n };\n}\n","/**\n * SubflowTree — collapsible sidebar listing mounted subflows.\n *\n * Recorder-driven (v6+): derives the tree from a `TraceGraph` produced\n * by `createTraceStructureRecorder`. Filters nodes by\n * `data.isSubflow === true` and lists them as `SubflowTreeEntry[]`\n * keyed by `subflowId`.\n *\n * Limitation (intentional — recorder graph is flat / mount-only):\n * Subflow-within-subflow nesting is NOT represented. The\n * StructureRecorder records the MOUNT of each subflow in the parent\n * chart, not the inner structure of each child chart. Rendering the\n * nested tree requires a separate recorder attached to each child\n * chart instance (deferred — see TODO below).\n *\n * Shared navigation layer — humans click through the tree just like\n * LLMs call getSubflowManifest() / getSubflowSpec().\n *\n * TODO(recorder-driven-nesting): when child charts attach their own\n * `traceStructureRecorder` and surface those graphs via a parent\n * registry, accept `Map<subflowId, TraceGraph>` and recurse to\n * restore the nested rendering the legacy SpecNode-walk supported.\n *\n * All colors come from `--fp-*` CSS variables set by the consumer.\n */\nimport { memo, useState, useCallback, useMemo } from \"react\";\nimport { theme } from \"../../theme\";\nimport type { TraceGraph } from \"./traceStructureRecorder\";\nimport type { BaseComponentProps } from \"../../types\";\n\nexport interface SubflowTreeEntry {\n /** Node name / identifier */\n name: string;\n /** Human-readable description */\n description?: string;\n /** Subflow ID (when this node represents a subflow) */\n subflowId?: string;\n /** Whether this node is a subflow root (has nested structure) */\n isSubflow?: boolean;\n /** Nested children (subflow stages) — always undefined in the\n * current recorder-driven implementation; see file-level TODO. */\n children?: SubflowTreeEntry[];\n}\n\nexport interface SubflowTreeProps extends BaseComponentProps {\n /** Recorder-captured graph from `createTraceStructureRecorder().getGraph()`. */\n graph: TraceGraph;\n /** Currently active stage name (highlights in tree) */\n activeStage?: string | null;\n /** Set of completed stage names */\n doneStages?: Set<string>;\n /** Called when a tree node is clicked */\n onNodeSelect?: (name: string, isSubflow: boolean) => void;\n}\n\n/** Extracts subflow entries from a recorder graph. Insertion-order preserving. */\nexport function graphToSubflowEntries(graph: TraceGraph): SubflowTreeEntry[] {\n if (!graph?.nodes?.length) return [];\n const entries: SubflowTreeEntry[] = [];\n for (const node of graph.nodes) {\n if (!node.data?.isSubflow) continue;\n const entry: SubflowTreeEntry = {\n name: typeof node.data.label === \"string\" ? node.data.label : node.id,\n isSubflow: true,\n };\n if (typeof node.data.description === \"string\") entry.description = node.data.description;\n if (typeof node.data.subflowId === \"string\") entry.subflowId = node.data.subflowId;\n entries.push(entry);\n }\n return entries;\n}\n\n/** Single tree node row */\nconst TreeNode = memo(function TreeNode({\n entry,\n depth,\n activeStage,\n doneStages,\n onNodeSelect,\n}: {\n entry: SubflowTreeEntry;\n depth: number;\n activeStage?: string | null;\n doneStages?: Set<string>;\n onNodeSelect?: (name: string, isSubflow: boolean) => void;\n}) {\n const [expanded, setExpanded] = useState(true);\n const hasChildren = entry.children && entry.children.length > 0;\n const isActive = activeStage === entry.name;\n const isDone = doneStages?.has(entry.name);\n\n const handleClick = useCallback(() => {\n if (hasChildren) {\n setExpanded((prev) => !prev);\n }\n onNodeSelect?.(entry.name, !!entry.isSubflow);\n }, [hasChildren, onNodeSelect, entry.name, entry.isSubflow]);\n\n return (\n <>\n <button\n onClick={handleClick}\n data-fp=\"subflow-tree-node\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n width: \"100%\",\n border: \"none\",\n background: isActive\n ? `color-mix(in srgb, ${theme.primary} 15%, transparent)`\n : \"transparent\",\n cursor: \"pointer\",\n padding: `4px 8px 4px ${8 + depth * 16}px`,\n fontFamily: theme.fontSans,\n fontSize: 12,\n textAlign: \"left\",\n borderRadius: 4,\n transition: \"background 0.15s\",\n }}\n onMouseEnter={(e) => {\n if (!isActive) {\n e.currentTarget.style.background = `color-mix(in srgb, ${theme.textMuted} 10%, transparent)`;\n }\n }}\n onMouseLeave={(e) => {\n if (!isActive) {\n e.currentTarget.style.background = \"transparent\";\n }\n }}\n >\n {/* Expand/collapse chevron for subflows */}\n {hasChildren ? (\n <span\n style={{\n fontSize: 10,\n color: theme.textMuted,\n width: 12,\n textAlign: \"center\",\n flexShrink: 0,\n transition: \"transform 0.15s\",\n transform: expanded ? \"rotate(90deg)\" : \"rotate(0deg)\",\n display: \"inline-block\",\n }}\n >\n ▶\n </span>\n ) : (\n <span style={{ width: 12, flexShrink: 0 }} />\n )}\n\n {/* Status dot */}\n <span\n style={{\n width: 6,\n height: 6,\n borderRadius: \"50%\",\n flexShrink: 0,\n background: isActive\n ? theme.primary\n : isDone\n ? theme.success\n : theme.border,\n }}\n />\n\n {/* Label + description */}\n <span style={{ display: \"flex\", flexDirection: \"column\", minWidth: 0 }}>\n <span\n style={{\n color: isActive\n ? theme.primary\n : isDone\n ? theme.textPrimary\n : theme.textSecondary,\n fontWeight: isActive ? 600 : entry.isSubflow ? 500 : 400,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {entry.name}\n {entry.isSubflow && (\n <span style={{ opacity: 0.5, marginLeft: 4, fontSize: 10 }}>⊞</span>\n )}\n </span>\n {entry.description && (\n <span\n style={{\n color: theme.textMuted,\n fontSize: 10,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {entry.description}\n </span>\n )}\n </span>\n </button>\n\n {/* Children */}\n {hasChildren && expanded && (\n <div>\n {entry.children!.map((child, i) => (\n <TreeNode\n key={child.subflowId ?? `${child.name}-${i}`}\n entry={child}\n depth={depth + 1}\n activeStage={activeStage}\n doneStages={doneStages}\n onNodeSelect={onNodeSelect}\n />\n ))}\n </div>\n )}\n </>\n );\n});\n\n/** Section label used for \"Flowchart\" and \"Subflows\" headings. */\nconst SectionLabel = memo(function SectionLabel({ children }: { children: string }) {\n return (\n <div\n style={{\n padding: \"4px 12px 8px\",\n fontSize: 10,\n fontWeight: 600,\n textTransform: \"uppercase\",\n letterSpacing: \"0.05em\",\n color: theme.textMuted,\n }}\n >\n {children}\n </div>\n );\n});\n\nexport const SubflowTree = memo(function SubflowTree({\n graph,\n activeStage,\n doneStages,\n onNodeSelect,\n unstyled = false,\n className,\n style,\n}: SubflowTreeProps) {\n const subflowStages = useMemo(() => graphToSubflowEntries(graph), [graph]);\n\n // Don't render anything if there are no subflows\n if (subflowStages.length === 0) return null;\n\n return (\n <div\n className={className}\n data-fp=\"subflow-tree\"\n style={{\n ...(unstyled\n ? {}\n : {\n fontFamily: theme.fontSans,\n fontSize: 12,\n background: theme.bgPrimary,\n borderRight: `1px solid ${theme.border}`,\n overflowY: \"auto\",\n overflowX: \"hidden\",\n padding: \"8px 0\",\n }),\n ...style,\n }}\n >\n {!unstyled && <SectionLabel>Subflows</SectionLabel>}\n {subflowStages.map((entry, i) => (\n <TreeNode\n key={entry.subflowId ?? `${entry.name}-${i}`}\n entry={entry}\n depth={0}\n activeStage={activeStage}\n doneStages={doneStages}\n onNodeSelect={onNodeSelect}\n />\n ))}\n </div>\n );\n});\n","/**\n * Branded types for translator key discipline.\n *\n * The footprintjs/trace contract uses two distinct identity strings:\n *\n * - **StageId**: the stable identifier the user picks at build time\n * (e.g. `'load-order'`, `'check-inventory'`). Identity per chart spec.\n *\n * - **RuntimeStageId**: `[subflowPath/]stageId#executionIndex` — the\n * per-execution identity. A loop visiting the same stage 3 times\n * produces 3 distinct RuntimeStageIds with the same StageId base.\n *\n * Translator outputs index per-stage data by StageId (`Map<StageId, ...>`)\n * AND per-execution data by RuntimeStageId (`Map<RuntimeStageId, ...>`).\n * Both are `string` at runtime — TypeScript can't distinguish them\n * without help. Branded types make `byStageId.get(runtimeStageId)` a\n * **compile-time error** instead of a silent `undefined` at runtime.\n *\n * Why branded types over wrapper classes\n * ──────────────────────────────────────\n * - Zero runtime cost (the brand exists only at the type level)\n * - JSON-serializable as-is (no `toJSON` glue needed)\n * - Interop with consumer code that uses raw `string` is one cast\n * (`stageId as StageId`) when the consumer is sure of the source.\n *\n * Usage pattern\n * ─────────────\n * ```ts\n * import type { StageId, RuntimeStageId } from './_internal/keys';\n *\n * // In a translator, when accepting input from a footprintjs event:\n * const sid = event.stageId as StageId;\n * const rsid = event.traversalContext.runtimeStageId as RuntimeStageId;\n *\n * // In a consumer reading from the index:\n * const node = index.byStageId.get(stageId); // typechecks\n * const node = index.byStageId.get(runtimeStageId); // TS ERROR ✓\n * ```\n *\n * Helper to derive a StageId from a RuntimeStageId — strips `#N` suffix\n * and optional subflow path. **Use only for DISPLAY**, NEVER for matching\n * commitLog stageIds (see invariant I3 in `traceStructureRecorder.ts`).\n */\n\n// String-literal brands (NOT `unique symbol`) — survive `.d.ts` emit\n// across module boundaries. Unique-symbol brands get serialized as\n// new local symbols when consumers compile their own .d.ts, causing\n// \"missing property [unique symbol]\" errors. String literals stay\n// nominal because the literal value is identical across builds.\n\n/** Stable per-spec identifier (e.g. `'load-order'`). */\nexport type StageId = string & { readonly __brand: \"StageId\" };\n\n/** Per-execution identifier (e.g. `'load-order#0'` or `'sf-foo/inner#3'`). */\nexport type RuntimeStageId = string & { readonly __brand: \"RuntimeStageId\" };\n\n/**\n * Tag a raw string as a `StageId`. Use at translator boundaries when\n * ingesting from a footprintjs event payload (the source guarantees\n * the string IS a stage id). Zero runtime cost.\n */\nexport function asStageId(s: string): StageId {\n return s as StageId;\n}\n\n/**\n * Tag a raw string as a `RuntimeStageId`. Use at translator boundaries\n * when ingesting from a `traversalContext.runtimeStageId`. Zero\n * runtime cost.\n */\nexport function asRuntimeStageId(s: string): RuntimeStageId {\n return s as RuntimeStageId;\n}\n","/**\n * walkSubflowSpecInto — walks a footprintjs v6.0+ `subflowSpec` payload\n * from `StructureSubflowMountedEvent` and emits nodes + edges into the\n * trace recorder's existing upsert helpers.\n *\n * This is the local mirror of `walkSubflowSpec` from `footprintjs/trace`\n * — kept local to preserve explainable-ui's zero-`footprintjs`-dep\n * boundary (see traceStructureRecorder.ts top-of-file rationale).\n *\n * Stage IDs come pre-prefixed from footprintjs's `_prefixNodeTree`\n * (e.g. `'sf-tools/execute-tool-calls'`), so we use them as-is for\n * node ids. The `subflowPath` is set on `data.subflowOf` to mark which\n * subflow each inner stage belongs to.\n */\n\nimport type { Node, Edge } from \"@xyflow/react\";\nimport { asStageId } from \"./keys\";\nimport type { TraceEdgeData, TraceNodeData } from \"../traceStructureRecorder\";\n\n/** Minimal duck-typed spec shape — mirrors the slice of\n * `SerializedPipelineStructure` we need. */\ninterface SpecNode {\n readonly id: string;\n readonly name: string;\n readonly type?: \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n readonly icon?: string;\n readonly description?: string;\n readonly children?: readonly SpecNode[];\n readonly next?: SpecNode;\n readonly loopTarget?: string;\n readonly isLoopReference?: boolean;\n readonly isSubflowRoot?: boolean;\n readonly subflowId?: string;\n readonly subflowName?: string;\n readonly subflowStructure?: SpecNode;\n readonly isPausable?: boolean;\n readonly isLazy?: boolean;\n}\n\ninterface WalkSink {\n upsertNode(node: Node<TraceNodeData>): void;\n pushEdge(edge: Edge<TraceEdgeData>): void;\n}\n\nexport function walkSubflowSpecInto(\n spec: SpecNode,\n subflowPath: string,\n sink: WalkSink,\n): void {\n walkNode(spec, subflowPath, sink, new Set<string>());\n}\n\nfunction walkNode(\n node: SpecNode,\n subflowPath: string,\n sink: WalkSink,\n visited: Set<string>,\n): void {\n if (visited.has(node.id)) return;\n visited.add(node.id);\n if (node.isLoopReference) return;\n\n // Nested subflow mount — recurse into its structure with composed path.\n if (node.isSubflowRoot && node.subflowId !== undefined && node.subflowStructure) {\n const nestedPath = `${subflowPath}/${node.subflowId}`;\n walkNode(node.subflowStructure, nestedPath, sink, visited);\n // Fall through so the mount node itself is emitted in the parent\n // subflow's scope below.\n }\n\n // Emit the stage node, tagged with subflowOf.\n const type = node.type ?? \"stage\";\n const isDecider = type === \"decider\" || type === \"selector\";\n const isFork = type === \"fork\";\n const isStreaming = type === \"streaming\";\n const isSubflow = !!node.isSubflowRoot;\n\n const stageId = asStageId(node.id);\n const data: TraceNodeData = {\n label: node.name,\n isDecider,\n isFork,\n isStreaming,\n isSubflow,\n subflowOf: subflowPath,\n prevIds: [],\n nextIds: [],\n };\n if (node.description !== undefined) data.description = node.description;\n if (node.icon !== undefined) data.icon = node.icon;\n if (node.subflowId !== undefined) data.subflowId = node.subflowId;\n if (node.isLazy === true) data.isLazy = true;\n if (node.isPausable === true) data.isPausable = true;\n\n sink.upsertNode({\n id: node.id,\n type: \"stage\",\n position: { x: 0, y: 0 },\n data,\n });\n\n // Children (decider/selector/fork branches).\n if (node.children && node.children.length > 0) {\n const edgeKind: \"fork-branch\" | \"decision-branch\" = type === \"fork\" ? \"fork-branch\" : \"decision-branch\";\n for (const child of node.children) {\n const edgeId = `${node.id}->${child.id}:${edgeKind}${edgeKind === \"decision-branch\" ? `:${child.id}` : \"\"}`;\n const edgeData: TraceEdgeData = { kind: edgeKind };\n if (edgeKind === \"decision-branch\") edgeData.label = child.id;\n const edge: Edge<TraceEdgeData> = {\n id: edgeId,\n source: node.id,\n target: child.id,\n data: edgeData,\n };\n if (edgeKind === \"decision-branch\") edge.label = child.id;\n sink.pushEdge(edge);\n walkNode(child, subflowPath, sink, visited);\n }\n }\n\n // Linear next or loop back-edge.\n if (node.next) {\n if (node.next.isLoopReference && node.loopTarget) {\n sink.pushEdge({\n id: `${node.id}->${node.loopTarget}:loop`,\n source: node.id,\n target: node.loopTarget,\n data: { kind: \"loop\" },\n });\n } else {\n const edgeId = `${node.id}->${node.next.id}:next`;\n sink.pushEdge({\n id: edgeId,\n source: node.id,\n target: node.next.id,\n data: { kind: \"next\" },\n });\n walkNode(node.next, subflowPath, sink, visited);\n }\n }\n // Suppress unused-binding warning for stageId (kept for parity with\n // recorder upsertNode signature; xyflow node `id` is the string form).\n void stageId;\n}\n","/**\n * traceStructureRecorder — event-driven xyflow Node[] + Edge[] collector.\n *\n * Implements footprintjs v6.0+ `StructureRecorder` interface. Accumulates\n * an unpositioned graph (xyflow node + edge shape) as the chart is being\n * built — no spec tree walk required.\n *\n * Why event-driven\n * ────────────────\n * The recorder fires SYNCHRONOUSLY at every spec-mutation moment during\n * construction. By the time `.build()` returns, the recorder's\n * `getGraph()` returns the complete graph — zero extra walking\n * (the \"collect during traversal, never post-process\" rule footprintjs\n * documents in its core principle).\n *\n * Bonus: the same recorder shape can drive incremental UI updates if\n * the builder is constructed asynchronously (e.g., a UI builder where\n * each \"add stage\" click re-renders the live graph).\n *\n * Layout is a separate concern\n * ────────────────────────────\n * This module produces UNPOSITIONED nodes (no `position` field set;\n * xyflow defaults to `{x: 0, y: 0}`). Apply a layout algorithm\n * downstream — either:\n *\n * - a graph algorithm (dagre / elk / d3-force)\n * - manual positioning via your own walk over `recorder.getGraph()`\n *\n * The `<TraceFlow>` component wires a default BFS layout.\n *\n * @example\n * ```ts\n * import { flowChart } from 'footprintjs';\n * import { createTraceStructureRecorder } from 'footprint-explainable-ui/flowchart';\n *\n * const trace = createTraceStructureRecorder();\n * const chart = flowChart('seed', fn, 'seed', {\n * structureRecorders: [trace.recorder],\n * })\n * .addFunction('a', fnA, 'a')\n * .build();\n *\n * const { nodes, edges } = trace.getGraph();\n * // → nodes: [{ id: 'seed', data: { label: 'seed', ... } }, { id: 'a', ... }]\n * // → edges: [{ id: 'seed->a', source: 'seed', target: 'a', data: { kind: 'next' } }]\n *\n * <ReactFlow nodes={layout(nodes)} edges={edges} />\n * ```\n */\n\nimport type { Node, Edge } from \"@xyflow/react\";\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport type { StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { walkSubflowSpecInto } from \"./_internal/walkSubflowSpecInto\";\n\nexport type { StageId, RuntimeStageId } from \"./_internal/keys\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local type aliases mirroring footprintjs/StructureRecorder\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Rationale for redefining these here instead of `import type` from\n// 'footprintjs': footprint-explainable-ui has no `footprintjs` dependency\n// declared in package.json (intentional — consumers wire it). So we mirror\n// the public interface shape. If footprintjs changes the StructureRecorder\n// interface, this module's types must update in lockstep — tracked by the\n// type-conformance test in `test/unit/traceStructureRecorder.test.ts`.\n\ntype StructureNodeType = \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n\ninterface StructureSpecRef {\n readonly id: string;\n readonly name: string;\n readonly type?: StructureNodeType;\n readonly description?: string;\n readonly icon?: string;\n readonly isSubflowRoot?: boolean;\n readonly subflowId?: string;\n readonly isLazy?: boolean;\n readonly [key: string]: unknown;\n}\n\ninterface StageAddedEvent {\n readonly stageId: string;\n readonly name: string;\n readonly type: StructureNodeType;\n readonly isPausable?: boolean;\n readonly spec: StructureSpecRef;\n}\n\ntype EdgeKind = \"next\" | \"fork-branch\" | \"decision-branch\";\n\ninterface EdgeAddedEvent {\n readonly from: string;\n readonly to: string;\n readonly kind: EdgeKind;\n readonly label?: string;\n}\n\ninterface LoopEdgeAddedEvent {\n readonly from: string;\n readonly to: string;\n}\n\ninterface DeciderCompleteEvent {\n readonly decider: string;\n readonly type: \"decider\" | \"selector\";\n readonly branchIds: readonly string[];\n readonly defaultBranch?: string;\n}\n\ninterface SubflowMountedEvent {\n readonly subflowId: string;\n readonly subflowName: string;\n readonly rootStageId: string;\n readonly isLazy?: boolean;\n /**\n * The mounted subflow's complete spec — added in footprintjs v6.0\n * (proposal #001). Present for eager mounts, UNDEFINED for lazy\n * mounts (the subflow isn't resolved yet at mount-event-fire-time).\n * When present, the consumer walks it to materialize inner nodes +\n * edges directly with `subflowOf` set — no retroactive tagging\n * needed.\n *\n * Typed as `unknown` because the upstream `SerializedPipelineStructure`\n * shape has no index signature and we want to stay loosely-coupled\n * (see top-of-file rationale for the no-`footprintjs`-dep boundary).\n * `walkSubflowSpecInto` accepts the duck-typed shape it actually\n * walks.\n */\n readonly subflowSpec?: unknown;\n /**\n * Local mount id within the parent (matches `subflowId` for top-level\n * mounts; composed `'parent/child'` for nested). Tagged onto every\n * inner stage's `data.subflowOf` during the walk.\n */\n readonly subflowPath?: string;\n}\n\n/**\n * Minimal StructureRecorder interface — mirrors footprintjs v6.0+.\n *\n * Named with the `Minimal` prefix to make the local-mirror nature\n * explicit at consumer call sites — a consumer importing both this\n * type and the upstream `StructureRecorder` from `footprintjs` won't\n * collide, and code reviewers see at a glance which boundary the type\n * crosses.\n *\n * The upstream `footprintjs.StructureRecorder` is structurally\n * compatible (this type's shape is a subset of upstream's), so passing\n * an instance of this to `flowChart(..., { structureRecorders: [...] })`\n * typechecks cleanly.\n */\nexport interface MinimalStructureRecorder {\n readonly id: string;\n onStageAdded?(event: StageAddedEvent): void;\n onEdgeAdded?(event: EdgeAddedEvent): void;\n onLoopEdgeAdded?(event: LoopEdgeAddedEvent): void;\n onDeciderComplete?(event: DeciderCompleteEvent): void;\n onSubflowMounted?(event: SubflowMountedEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// xyflow node + edge data shapes\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Per-node data attached to the xyflow `Node`. The built-in `StageNode`\n * renderer reads the named fields below.\n *\n * Consumer extension: this type EXTENDS `Record<string, unknown>` so\n * you can attach custom fields without TypeScript fighting you. Pair\n * this with `<TraceFlow nodeTypes={{ stageNode: MyNode }} />` (or push\n * nodes with `type: 'myCustomKind'`) to render those custom fields\n * however you want. The built-in `StageNode` ignores fields it doesn't\n * recognize, so adding consumer fields is non-breaking even if you\n * keep the default renderer.\n */\nexport interface TraceNodeData extends Record<string, unknown> {\n label: string;\n isDecider: boolean;\n isFork: boolean;\n isSubflow: boolean;\n /** True when the event carried `type: 'streaming'` (the spec was added\n * via `addStreamingFunction`). Renderers that style streaming stages\n * distinctly key on this flag. */\n isStreaming: boolean;\n description?: string;\n icon?: string;\n subflowId?: string;\n isLazy?: boolean;\n isPausable?: boolean;\n /** Set later by `onDeciderComplete` when the decider's branch list is\n * sealed. Useful for renderers that want to render decider with a\n * branch-count badge. */\n branchIds?: readonly string[];\n defaultBranch?: string;\n /**\n * The subflow this node belongs to, OR `undefined` for top-level\n * parent-chart stages. Tracked via a stack-based heuristic during\n * event ingestion:\n *\n * - Push on `onSubflowMounted({subflowId, rootStageId})` →\n * top-of-stack = `{subflowId, mountStageId}`\n * - `onStageAdded` tags new nodes with the top-of-stack `subflowId`\n * (the mount node itself stays UNtagged — it's part of the parent\n * chain)\n * - Pop on `onEdgeAdded` where `from === mount.id` (a mount's\n * outgoing edge to a sibling means the parent chain has resumed);\n * the wrongly-tagged target node is re-tagged to the parent scope\n *\n * Mount nodes (where `isSubflow=true`) have `subflowOf` reflecting\n * their OWN parent context, NOT the subflow they mount. So a parent's\n * mount node has `subflowOf=undefined` (top-level parent), and the\n * subflow's INTERNAL stages have `subflowOf=<mount.subflowId>`.\n *\n * Renderers use this to filter the chart by drill-down level: show\n * only nodes where `subflowOf === currentDrillSubflowId` (undefined\n * for top-level view, mount.subflowId after drilling in).\n */\n subflowOf?: string;\n /**\n * **L8.0 — STRUCTURAL prev/next**: stage ids that lead into / out of\n * this node, derived live from incoming/outgoing edges. Excludes\n * `loop` back-edges (visual only — per invariant I1).\n *\n * Convergence-correct: a fork-join node carries an ENTRY per branch\n * child (e.g., `FinalizeOrder.prevIds = ['CheckInventory', 'RunFraudCheck']`).\n *\n * \"Structural\" qualifier: this is the chart-SHAPE prev/next, not\n * runtime execution order. For runtime ancestry use `CommitView`\n * fields on `CommitFlowIndex` (L8.2).\n */\n prevIds: StageId[];\n nextIds: StageId[];\n}\n\n/**\n * Per-edge data attached to the xyflow `Edge`. The default edge\n * renderer reads `kind` (and `label`).\n *\n * Consumer extension: same pattern as `TraceNodeData` — extra fields\n * pass through unchanged. Pair with `<TraceFlow edgeTypes={...} />`\n * to render custom edges (e.g., a \"retried\" edge with a count badge).\n */\nexport interface TraceEdgeData extends Record<string, unknown> {\n kind: EdgeKind | \"loop\";\n label?: string;\n}\n\nexport type TraceNode = Node<TraceNodeData>;\nexport type TraceEdge = Edge<TraceEdgeData>;\n\nexport interface TraceGraph {\n nodes: TraceNode[];\n edges: TraceEdge[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceStructureRecorderHandle {\n /** The recorder to register via `flowChart(..., { structureRecorders: [handle.recorder] })`\n * or `.attachStructureRecorder(handle.recorder)`. */\n recorder: MinimalStructureRecorder;\n /** Returns a defensive copy of the current graph state. Safe to call\n * multiple times; safe to mutate the returned arrays without affecting\n * the recorder's internal state. */\n getGraph(): TraceGraph;\n /** Direct read-only access for hot-path consumers (Lens slider scrubbing).\n * Returns the LIVE internal arrays — do NOT mutate. Prefer `getGraph()`\n * unless you measure a performance cost. */\n getGraphRef(): Readonly<TraceGraph>;\n /**\n * Subscribe to graph-change notifications. Pub-sub model — multiple\n * listeners can subscribe; each fires after every event that mutates\n * the graph (per-event, NOT batched). Returns an unsubscribe function.\n * Designed for React's `useSyncExternalStore` consumption.\n *\n * Listeners are NOT invoked during `reset()`. **Consumer guidance**:\n * if you need to clear a live `<TraceFlow recorder={handle} />`\n * mid-mount, either (a) unmount the component before calling\n * `reset()` and re-mount after, OR (b) drive a fresh recorder\n * instance via state. See `reset()` JSDoc for the rationale.\n */\n subscribe(listener: () => void): () => void;\n /**\n * Monotonically-increasing version counter — bumps once per\n * graph-mutating event. Pair with `getGraph()` in\n * `useSyncExternalStore` snapshot equality:\n * ```ts\n * const version = useSyncExternalStore(handle.subscribe, () => handle.version());\n * const graph = useMemo(() => handle.getGraph(), [version]);\n * ```\n * Avoids defensive-copy allocation on every render while keeping\n * React's identity-check happy.\n */\n version(): number;\n /** Reset the recorder for reuse across multiple builds. After this,\n * the recorder behaves like a freshly-constructed instance. */\n reset(): void;\n}\n\nexport interface CreateTraceStructureRecorderOptions {\n /** Recorder id — surfaces in `StructureBuildError.recorderId` when\n * the recorder throws. Defaults to `'trace-structure'`. Use distinct\n * ids if you attach multiple instances. */\n id?: string;\n /** Optional callback fired after each event mutates the graph. Useful\n * for incremental-render UIs (Lens) that want to re-render between\n * builder operations. NOT invoked during the initial `attachStructureRecorder`\n * seed replay; consumers can call `getGraph()` directly after attach. */\n onChange?: (graph: Readonly<TraceGraph>) => void;\n}\n\nexport function createTraceStructureRecorder(\n options: CreateTraceStructureRecorderOptions = {},\n): TraceStructureRecorderHandle {\n const id = options.id ?? \"trace-structure\";\n const onChange = options.onChange;\n\n let nodes: TraceNode[] = [];\n let edges: TraceEdge[] = [];\n // Indexes — O(1) lookup for decider-completion + subflow-mounted updates.\n const nodeIndex = new Map<string, number>();\n const seenEdgeIds = new Set<string>();\n // L8.0 — per-node prev/next indexes maintained as edges arrive. The\n // arrays land on `TraceNode.data.prevIds` / `data.nextIds` so basic\n // TraceGraph consumers get convergence-correct neighbor info \"for\n // free\" (no separate NodeView translator needed for chart rendering).\n const prevIdsOf = new Map<string, StageId[]>();\n const nextIdsOf = new Map<string, StageId[]>();\n // Pub-sub + version via shared infra (microtask-batched listener fan-out).\n const notifier = createNotifier(\"traceStructureRecorder\");\n\n function notifyChange(): void {\n if (onChange) {\n try {\n onChange({ nodes, edges });\n } catch (err) {\n devWarn(\n () => \"[traceStructureRecorder] onChange callback threw — isolated.\",\n err,\n );\n }\n }\n notifier.notify();\n }\n\n function upsertNode(node: TraceNode): void {\n const existing = nodeIndex.get(node.id);\n if (existing !== undefined) {\n // Merge: later events may carry richer data (e.g., onDeciderComplete\n // → branchIds). Preserve any fields the new event didn't set.\n nodes[existing] = {\n ...nodes[existing],\n ...node,\n data: { ...nodes[existing]!.data, ...node.data },\n };\n } else {\n nodeIndex.set(node.id, nodes.length);\n nodes.push(node);\n }\n }\n\n function pushEdge(edge: TraceEdge): void {\n // Dedupe by id — the seed replay path could otherwise double-add\n // if a consumer attaches the same recorder twice (allowed by design,\n // but the graph should still be sane).\n if (seenEdgeIds.has(edge.id)) return;\n seenEdgeIds.add(edge.id);\n edges.push(edge);\n\n // L8.0 — maintain prev/next indexes. Loop back-edges do NOT\n // contribute (invariant I1: loops are visual annotations only).\n const kind = edge.data?.kind;\n if (kind === \"loop\") return;\n const source = asStageId(edge.source);\n const target = asStageId(edge.target);\n const nextArr = nextIdsOf.get(source) ?? [];\n nextArr.push(target);\n nextIdsOf.set(source, nextArr);\n const prevArr = prevIdsOf.get(target) ?? [];\n prevArr.push(source);\n prevIdsOf.set(target, prevArr);\n\n // Sync the index changes onto the LIVE node-data arrays so\n // consumers reading `node.data.prevIds`/`nextIds` see fresh values\n // after each edge event. We mutate in place rather than re-cloning\n // the node — `getGraph()` returns defensive copies anyway.\n syncNeighborsOnto(source);\n syncNeighborsOnto(target);\n }\n\n function syncNeighborsOnto(stageId: StageId): void {\n const idx = nodeIndex.get(stageId);\n if (idx === undefined) return; // node not yet announced — will sync at onStageAdded\n const node = nodes[idx]!;\n // L8.0 panel must-fix: ATOMIC REPLACE — copy the arrays from the\n // index, don't share the map's array refs. A consumer using\n // `getGraphRef()` who caches `node.data.prevIds` would otherwise\n // see their cached array silently grow when a new edge fires.\n // The slice() cost is one allocation per edge per touched node —\n // negligible vs. the consumer-safety win.\n const prevs = prevIdsOf.get(stageId);\n const nexts = nextIdsOf.get(stageId);\n node.data.prevIds = prevs ? prevs.slice() : [];\n node.data.nextIds = nexts ? nexts.slice() : [];\n }\n\n const recorder: MinimalStructureRecorder = {\n id,\n onStageAdded(event) {\n const spec = event.spec;\n const type = event.type;\n const isDecider = type === \"decider\" || type === \"selector\";\n const isFork = type === \"fork\";\n const isStreaming = type === \"streaming\";\n const isSubflow = !!spec.isSubflowRoot;\n\n const stageId = asStageId(event.stageId);\n const data: TraceNodeData = {\n label: event.name,\n isDecider,\n isFork,\n isStreaming,\n isSubflow,\n // L8.0 — seed prev/next from any edges that already fired\n // pointing AT this node. Convergence case: a fork-branch edge\n // from LoadOrder fires BEFORE the child's onStageAdded; this\n // line ensures the child's prevIds picks up the back-pointer.\n // Atomic copy (not shared ref) — see `syncNeighborsOnto` for\n // the panel-flagged consumer-safety rationale.\n prevIds: (prevIdsOf.get(stageId) ?? []).slice(),\n nextIds: (nextIdsOf.get(stageId) ?? []).slice(),\n };\n if (spec.description !== undefined) data.description = spec.description;\n if (spec.icon !== undefined) data.icon = spec.icon;\n if (spec.subflowId !== undefined) data.subflowId = spec.subflowId;\n if (spec.isLazy === true) data.isLazy = true;\n if (event.isPausable === true) data.isPausable = true;\n // subflowOf gets set RETROACTIVELY in onSubflowMounted (the\n // builder fires inner-stage events BEFORE the mount event, so\n // we can't tag at stage-add time — we tag at mount time by\n // identifying untagged disconnected subgraphs).\n\n upsertNode({\n id: event.stageId,\n type: \"stage\",\n // No layout here — downstream consumer applies positions.\n position: { x: 0, y: 0 },\n data,\n });\n notifyChange();\n },\n\n onEdgeAdded(event) {\n const edgeId = `${event.from}->${event.to}:${event.kind}${event.label ? `:${event.label}` : \"\"}`;\n const data: TraceEdgeData = { kind: event.kind };\n if (event.label !== undefined) data.label = event.label;\n const edge: TraceEdge = {\n id: edgeId,\n source: event.from,\n target: event.to,\n data,\n };\n if (event.label !== undefined) edge.label = event.label;\n pushEdge(edge);\n notifyChange();\n },\n\n onLoopEdgeAdded(event) {\n const edgeId = `${event.from}->${event.to}:loop`;\n pushEdge({\n id: edgeId,\n source: event.from,\n target: event.to,\n data: { kind: \"loop\" },\n });\n notifyChange();\n },\n\n onDeciderComplete(event) {\n // Patch the already-added decider node with its sealed branch info.\n const existing = nodeIndex.get(event.decider);\n if (existing === undefined) {\n // The decider node SHOULD have been added via onStageAdded\n // before its branches were declared. If this fires for an\n // unknown id, the upstream builder reordered events —\n // visualisation will silently degrade. Warn in dev so the bug\n // is visible at its source.\n devWarn(\n () =>\n `[traceStructureRecorder] onDeciderComplete fired for unknown stageId \"${event.decider}\" — branch metadata dropped. Did the upstream fire onStageAdded for this id first?`,\n );\n return;\n }\n const node = nodes[existing]!;\n const data: TraceNodeData = {\n ...node.data,\n branchIds: event.branchIds,\n };\n if (event.defaultBranch !== undefined) data.defaultBranch = event.defaultBranch;\n nodes[existing] = { ...node, data };\n notifyChange();\n },\n\n onSubflowMounted(event) {\n // The mount node was already announced via `onStageAdded`; here\n // we patch in the subflow-specific data fields, then materialize\n // the subflow's inner structure.\n const existing = nodeIndex.get(event.rootStageId);\n if (existing === undefined) {\n devWarn(\n () =>\n `[traceStructureRecorder] onSubflowMounted fired for unknown rootStageId \"${event.rootStageId}\" (subflowId=\"${event.subflowId}\") — subflow metadata dropped. Did the upstream fire onStageAdded for the mount node first?`,\n );\n return;\n }\n const node = nodes[existing]!;\n const data: TraceNodeData = {\n ...node.data,\n isSubflow: true,\n subflowId: event.subflowId,\n };\n if (event.isLazy === true) data.isLazy = true;\n nodes[existing] = { ...node, data };\n\n // Eager mounts (footprintjs v6.0+): walk the full subflow spec\n // delivered on the event to emit inner nodes + edges with\n // `subflowOf` set directly. Lazy mounts arrive with no spec —\n // their internal structure isn't known until the resolver runs\n // at runtime; the mount node alone is rendered (consumer apps\n // can subscribe to runtime events to fill in detail if desired).\n const subflowPath = event.subflowPath ?? event.subflowId;\n if (event.subflowSpec) {\n // Cast: type is `unknown` at the event boundary (see\n // SubflowMountedEvent JSDoc); walkSubflowSpecInto accepts\n // the duck-typed structural shape it actually traverses.\n walkSubflowSpecInto(event.subflowSpec as Parameters<typeof walkSubflowSpecInto>[0], subflowPath, {\n upsertNode,\n pushEdge,\n });\n }\n notifyChange();\n },\n };\n\n return {\n recorder,\n getGraph(): TraceGraph {\n return {\n nodes: nodes.map((n) => ({ ...n, data: { ...n.data } })),\n edges: edges.map((e) => ({ ...e, data: e.data ? { ...e.data } : undefined })),\n };\n },\n getGraphRef(): Readonly<TraceGraph> {\n return { nodes, edges };\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n nodes = [];\n edges = [];\n nodeIndex.clear();\n seenEdgeIds.clear();\n prevIdsOf.clear();\n nextIdsOf.clear();\n // Why `reset()` does NOT bump version or notify listeners:\n // a notify here would cause `<TraceFlow recorder={handle} />`\n // to re-render with an empty graph for one frame, then re-render\n // again when the next builder event fires — visible flicker for\n // users who reset between builds. The recommended pattern is to\n // recycle the recorder OUTSIDE the React tree (e.g., via a\n // factory hook keyed on a \"build epoch\" so React unmounts and\n // re-mounts <TraceFlow> across builds). See `subscribe()` JSDoc\n // for the consumer-facing recipe.\n },\n };\n}\n","/**\n * createNodeViewRecorder — per-stage summary translator.\n *\n * Implements footprintjs v6.0+ `CombinedRecorder` (Flow + Scope) and\n * produces a `NodeViewIndex` — per-stage data keyed by both `StageId`\n * (chart-shape lookup) and `RuntimeStageId` (per-execution lookup).\n *\n * Composition (panel guidance, L8.0 review)\n * ─────────────────────────────────────────\n * NodeView does NOT duplicate the structural prev/next index — it\n * READS those fields from the structure translator's\n * `node.data.prevIds`/`nextIds`. The structure translator already\n * maintains convergence-correct, loop-excluded neighbors. Duplicating\n * the index here would re-introduce edge-ordering bugs we just\n * solved.\n *\n * The NodeView translator owns ONLY runtime-derived per-stage state:\n * - `executions[]` — every FlowRecorder.onStageExecuted event for\n * this stage (loop-friendly: N executions of one stage produce\n * N entries, each with its own runtimeStageId).\n * - `commitRuntimeStageIds[]` — refs to commits made by this stage\n * (the canonical CommitView lives in CommitFlowIndex from L8.2;\n * NodeView stores only the join key).\n *\n * Plus derived convenience fields: `visitedInRun`, `executionCount`,\n * `firstExecutedAt`, `lastExecutedAt`, `totalDurationMs`, `errorCount`.\n *\n * Version bumping\n * ───────────────\n * NodeView bumps its own version on EITHER:\n * (a) a Flow/Scope event arrives (own state mutates), OR\n * (b) the structure translator's version bumps (structural data\n * the index projects from changed).\n *\n * So `useTranslator(nodeView, ...)` re-renders when EITHER changes —\n * one subscription, full reactive coverage.\n *\n * @example\n * ```tsx\n * import { createTraceStructureRecorder, createNodeViewRecorder, useTranslator } from 'footprint-explainable-ui/flowchart';\n *\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const nodeView = useMemo(() => createNodeViewRecorder({ structure: trace }), [trace]);\n *\n * useEffect(() => {\n * executor.attachFlowRecorder(nodeView.recorder);\n * executor.attachScopeRecorder(nodeView.recorder);\n * }, [nodeView]);\n *\n * const index = useTranslator(nodeView, () => nodeView.getIndex());\n * const finalize = index.byStageId.get(asStageId('FinalizeOrder'));\n * // finalize.prevIds → ['CheckInventory', 'RunFraudCheck'] (from structure)\n * // finalize.executions → [{ runtimeStageId, iteration, startMs, endMs, ... }]\n * // finalize.visitedInRun → true\n * // finalize.commitRuntimeStageIds → ['finalize-order#3', ...]\n * ```\n */\n\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport { asStageId, asRuntimeStageId } from \"./_internal/keys\";\nimport type { StageId, RuntimeStageId } from \"./_internal/keys\";\nimport type { TraceStructureRecorderHandle, TraceNode } from \"./traceStructureRecorder\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local mirrors of footprintjs runtime recorder interfaces\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Same rationale as other translators: explainable-ui has no\n// `footprintjs` dep — we mirror the subset we consume. Structural\n// compatibility means our `recorder` passes through to\n// `executor.attachFlowRecorder()` / `attachScopeRecorder()` cleanly.\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface FlowStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly traversalContext: TraversalContext;\n readonly startTime?: number;\n readonly endTime?: number;\n}\n\ninterface FlowErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface FlowRunLifecycleEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface ScopeCommitEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly updates?: Record<string, unknown>;\n readonly reads?: readonly string[];\n}\n\n/**\n * Minimal CombinedRecorder interface mirror — subset of footprintjs's\n * Flow + Scope recorder interfaces NodeView consumes. Implements both\n * channels in one object; consumer attaches via\n * `executor.attachFlowRecorder()` AND `executor.attachScopeRecorder()`\n * (or `executor.attachCombinedRecorder()` if available).\n */\nexport interface MinimalNodeViewRecorder {\n readonly id: string;\n // Flow channel\n onStageExecuted?(event: FlowStageExecutedEvent): void;\n onError?(event: FlowErrorEvent): void;\n onRunStart?(event: FlowRunLifecycleEvent): void;\n onRunEnd?(event: FlowRunLifecycleEvent): void;\n // Scope channel\n onCommit?(event: ScopeCommitEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** One execution of a stage. A stage that runs N times in a loop\n * produces N `ExecutionRecord` entries on the NodeView.executions[]. */\nexport interface ExecutionRecord {\n /** `[subflowPath/]stageId#executionIndex` — universal join key. */\n readonly runtimeStageId: RuntimeStageId;\n /** Loop iteration (0-indexed). undefined when the engine didn't\n * populate it (rare). */\n readonly iteration?: number;\n /** ms since executor start. */\n readonly startMs?: number;\n /** ms since executor start. */\n readonly endMs?: number;\n /** Set when `onError` fired for this execution. */\n readonly errorMessage?: string;\n}\n\n/**\n * Per-stage summary. Joins STRUCTURAL data (from the structure\n * translator's TraceNode.data) with RUNTIME data (executions + commit\n * refs accumulated by this translator).\n */\nexport interface NodeView {\n // ── Identity ────────────────────────────────────────────────────\n readonly stageId: StageId;\n readonly label: string;\n\n // ── Structural (read-through from structure translator) ─────────\n readonly type: \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n readonly isDecider: boolean;\n readonly isFork: boolean;\n readonly isSubflow: boolean;\n readonly isStreaming: boolean;\n readonly isPausable: boolean;\n readonly description?: string;\n readonly icon?: string;\n readonly subflowId?: string;\n readonly branchIds?: readonly string[];\n readonly defaultBranch?: string;\n /** From the structure translator (loop-excluded, convergence-correct). */\n readonly prevIds: StageId[];\n readonly nextIds: StageId[];\n\n // ── Visit data (runtime) ────────────────────────────────────────\n readonly executions: ExecutionRecord[];\n /** Derived: `executions.length > 0`. */\n readonly visitedInRun: boolean;\n /** Derived: `executions.length` (loop iteration count). */\n readonly executionCount: number;\n /** Derived: first execution `startMs`, or `null` if not yet executed. */\n readonly firstExecutedAt: number | null;\n /** Derived: last execution `endMs`, or `null`. */\n readonly lastExecutedAt: number | null;\n /** Derived: sum of `endMs - startMs` across executions. */\n readonly totalDurationMs: number;\n /** Derived: count of executions with an errorMessage. */\n readonly errorCount: number;\n\n // ── Commit refs (join key into CommitFlowIndex from L8.2) ───────\n /** Run-time stage ids of commits made by this stage. Look up the\n * canonical CommitView via `commitFlow.byRuntimeStageId.get(id)`. */\n readonly commitRuntimeStageIds: RuntimeStageId[];\n}\n\n/** Index of NodeView keyed by both StageId and RuntimeStageId. The\n * branded types prevent `byStageId.get(runtimeStageId)` silent-undefined. */\nexport interface NodeViewIndex {\n readonly byStageId: ReadonlyMap<StageId, NodeView>;\n readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, NodeView>;\n /** All NodeViews — insertion order matches structure translator. */\n readonly all: readonly NodeView[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface NodeViewRecorderHandle {\n /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`\n * AND `executor.attachScopeRecorder()` (footprintjs routes by\n * method-shape detection). */\n recorder: MinimalNodeViewRecorder;\n /** Returns a defensive copy of the current index state. */\n getIndex(): NodeViewIndex;\n /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps on Flow/Scope event OR when\n * the structure translator's version bumps (since NodeView projects\n * from its data). */\n version(): number;\n /** Reset runtime state. Does NOT bump version or notify (consistent\n * with traceStructureRecorder + createTraceRuntimeOverlay). */\n reset(): void;\n}\n\nexport interface CreateNodeViewRecorderOptions {\n /** Recorder id (surfaces in error attribution). */\n id?: string;\n /** REQUIRED — the structure translator handle. NodeView projects\n * structural fields (`prevIds`, `nextIds`, `label`, etc.) from\n * this on every `getIndex()` call. */\n structure: TraceStructureRecorderHandle;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Strip `#executionIndex` from runtimeStageId to recover the base\n * stageId. **Use only for in-translator matching where both sides\n * use full-path-prefixed stageIds consistently** (invariant I3 — do\n * NOT use this to match commitLog stageIds across subflow boundaries). */\nfunction baseStageIdOf(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createNodeViewRecorder(\n options: CreateNodeViewRecorderOptions,\n): NodeViewRecorderHandle {\n const id = options.id ?? \"node-view\";\n const structure = options.structure;\n if (!structure) {\n throw new Error(\n \"[createNodeViewRecorder] `structure` option is required. \" +\n \"Pass the handle returned by `createTraceStructureRecorder()`.\",\n );\n }\n\n // Per-stage execution + commit-ref state. Keyed by base stageId.\n // Loops produce multiple entries with the same stageId / different\n // runtimeStageIds.\n let executionsOf: Map<StageId, ExecutionRecord[]> = new Map();\n let commitRefsOf: Map<StageId, RuntimeStageId[]> = new Map();\n // Reverse lookup: runtimeStageId → its base stageId. Lets\n // `byRuntimeStageId` map directly to a NodeView without\n // re-parsing.\n let stageIdOfRuntimeStageId: Map<RuntimeStageId, StageId> = new Map();\n\n const notifier = createNotifier(\"node-view\");\n\n // Subscribe to structure translator — when its graph changes\n // (e.g., new stage announced during incremental build), bump our\n // version so consumers re-derive the projection.\n const unsubStructure = structure.subscribe(() => notifier.notify());\n\n function recordExecution(event: FlowStageExecutedEvent): void {\n // L8.1 Panel 2 must-fix: guard against malformed event payloads\n // (asymmetric with recordError's existing guard). Upstream MAY\n // fire with traversalContext absent if the engine's runtime\n // observer chain is reorganised — fail soft, not hard.\n const rsid = event.traversalContext?.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onStageExecuted event without traversalContext.runtimeStageId — execution attribution dropped (stage=${event.stageName}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const runtimeStageId = asRuntimeStageId(rsid);\n const execList = executionsOf.get(stageId) ?? [];\n const record: ExecutionRecord = {\n runtimeStageId,\n ...(event.traversalContext.iteration !== undefined && {\n iteration: event.traversalContext.iteration,\n }),\n ...(event.startTime !== undefined && { startMs: event.startTime }),\n ...(event.endTime !== undefined && { endMs: event.endTime }),\n };\n execList.push(record);\n executionsOf.set(stageId, execList);\n stageIdOfRuntimeStageId.set(runtimeStageId, stageId);\n notifier.notify();\n }\n\n function recordError(event: FlowErrorEvent): void {\n const rsid = event.traversalContext?.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onError event without traversalContext.runtimeStageId — error attribution dropped (stage=${event.stageName}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const runtimeStageId = asRuntimeStageId(rsid);\n const execList = executionsOf.get(stageId);\n // L8.1 Panel 1 must-fix: match by runtimeStageId equality (NOT\n // array position). With interleaved-stage events under footprintjs's\n // FlowRecorder dispatcher, \"most-recent execution by array index\"\n // can attach an error to the wrong execution. Looking up by\n // runtimeStageId is the correct join key.\n const matchIdx = execList\n ? execList.findIndex((e) => e.runtimeStageId === runtimeStageId)\n : -1;\n if (!execList || matchIdx === -1) {\n // Error before onStageExecuted? Synthesize a minimal execution\n // record so consumers see the error.\n const synth: ExecutionRecord = {\n runtimeStageId,\n errorMessage: event.message ?? \"error\",\n };\n if (execList) {\n execList.push(synth);\n } else {\n executionsOf.set(stageId, [synth]);\n }\n } else {\n const match = execList[matchIdx]!;\n execList[matchIdx] = { ...match, errorMessage: event.message ?? \"error\" };\n }\n stageIdOfRuntimeStageId.set(runtimeStageId, stageId);\n notifier.notify();\n }\n\n function recordCommit(event: ScopeCommitEvent): void {\n // Read runtimeStageId directly from the onCommit payload\n // (panel L8.0 ordering invariant: Scope.onCommit fires BEFORE\n // Flow.onStageExecuted; don't rely on Flow event arriving first).\n const rsid = event.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onCommit event without runtimeStageId — commit attribution dropped (stage=${event.stage ?? event.stageId ?? \"?\"}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const refs = commitRefsOf.get(stageId) ?? [];\n refs.push(asRuntimeStageId(rsid));\n commitRefsOf.set(stageId, refs);\n stageIdOfRuntimeStageId.set(asRuntimeStageId(rsid), stageId);\n notifier.notify();\n }\n\n const recorder: MinimalNodeViewRecorder = {\n id,\n onStageExecuted: recordExecution,\n onError: recordError,\n onCommit: recordCommit,\n // onRunStart / onRunEnd — no-op for now (state stays alive across\n // runs; consumers call .reset() between runs if they want fresh\n // state). Listed for shape conformance with FlowRecorder.\n onRunStart() {\n /* no-op */\n },\n onRunEnd() {\n /* no-op */\n },\n };\n\n function buildView(structNode: TraceNode): NodeView {\n const stageId = asStageId(structNode.id);\n const execs = executionsOf.get(stageId) ?? [];\n const commitRefs = commitRefsOf.get(stageId) ?? [];\n\n // Derived visit-data fields\n const visitedInRun = execs.length > 0;\n const executionCount = execs.length;\n const firstExecutedAt = execs.length > 0 && execs[0]!.startMs !== undefined\n ? execs[0]!.startMs!\n : null;\n const lastExecutedAt = execs.length > 0 && execs[execs.length - 1]!.endMs !== undefined\n ? execs[execs.length - 1]!.endMs!\n : null;\n let totalDurationMs = 0;\n let errorCount = 0;\n for (const e of execs) {\n if (e.startMs !== undefined && e.endMs !== undefined) {\n totalDurationMs += e.endMs - e.startMs;\n }\n if (e.errorMessage) errorCount++;\n }\n\n const d = structNode.data;\n return {\n stageId,\n label: d.label,\n type: (structNode.type as NodeView[\"type\"]) ?? \"stage\",\n isDecider: d.isDecider,\n isFork: d.isFork,\n isSubflow: d.isSubflow,\n isStreaming: d.isStreaming,\n isPausable: d.isPausable === true,\n ...(d.description !== undefined && { description: d.description }),\n ...(d.icon !== undefined && { icon: d.icon }),\n ...(d.subflowId !== undefined && { subflowId: d.subflowId }),\n // L8.1 Panel 2 must-fix: branchIds is a live ref from the\n // structure translator's internal graph — defensive copy via\n // slice() prevents consumer mutation from corrupting it.\n ...(d.branchIds !== undefined && { branchIds: d.branchIds.slice() }),\n ...(d.defaultBranch !== undefined && { defaultBranch: d.defaultBranch }),\n // Note: structure translator always sets prevIds/nextIds (never\n // undefined). The slice() copies defend against consumer mutation.\n prevIds: d.prevIds.slice(),\n nextIds: d.nextIds.slice(),\n executions: execs.map((e) => ({ ...e })),\n visitedInRun,\n executionCount,\n firstExecutedAt,\n lastExecutedAt,\n totalDurationMs,\n errorCount,\n commitRuntimeStageIds: commitRefs.slice(),\n };\n }\n\n // L8.1 Panel 5 optimization: version-keyed cache. `getIndex()` is\n // called per React render that observes a version bump; with N\n // translators subscribed + StrictMode double-invoke, a single\n // stage event can produce 6+ full rebuilds. Cache the last index\n // keyed on `(ownVersion, structureVersion)` — return the cached\n // index when neither has changed since the previous build.\n let cachedIndex: NodeViewIndex | null = null;\n let cachedOwnVersion = -1;\n let cachedStructureVersion = -1;\n\n return {\n recorder,\n getIndex(): NodeViewIndex {\n const own = notifier.version();\n const struct = structure.version();\n if (\n cachedIndex !== null &&\n cachedOwnVersion === own &&\n cachedStructureVersion === struct\n ) {\n return cachedIndex;\n }\n // Read structure live — we project from its current graph each\n // call. Defensive-copy via getGraph() would over-allocate; we\n // use getGraphRef() and tolerate the read-only contract (we\n // don't mutate structure data).\n const graphRef = structure.getGraphRef();\n const byStageId = new Map<StageId, NodeView>();\n const byRuntimeStageId = new Map<RuntimeStageId, NodeView>();\n const all: NodeView[] = [];\n for (const structNode of graphRef.nodes) {\n const view = buildView(structNode);\n byStageId.set(view.stageId, view);\n all.push(view);\n // Reverse map: every execution's runtimeStageId → this view.\n for (const exec of view.executions) {\n byRuntimeStageId.set(exec.runtimeStageId, view);\n }\n // Commit refs also point back to this view (a stage's\n // runtimeStageId for its execution is the same key its\n // commit carries).\n for (const rsid of view.commitRuntimeStageIds) {\n byRuntimeStageId.set(rsid, view);\n }\n }\n cachedIndex = { byStageId, byRuntimeStageId, all };\n cachedOwnVersion = own;\n cachedStructureVersion = struct;\n return cachedIndex;\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n executionsOf = new Map();\n commitRefsOf = new Map();\n stageIdOfRuntimeStageId = new Map();\n // L8.1 — invalidate the version-keyed cache. We do NOT bump\n // version (matches the other translators' reset contract — see\n // traceStructureRecorder's `reset()` JSDoc for the consumer\n // recipe), but the cache MUST be cleared so the next\n // `getIndex()` rebuilds from the freshly-empty state instead\n // of returning a stale snapshot.\n cachedIndex = null;\n cachedOwnVersion = -1;\n cachedStructureVersion = -1;\n // We intentionally do NOT unsubscribe from structure here; the\n // handle is still alive across resets.\n void unsubStructure;\n },\n };\n}\n","/**\n * createCommitFlowRecorder — per-commit summary translator.\n *\n * Owns the canonical `CommitView[]` — captured from Scope `onCommit`\n * events as the chart runs. Each CommitView joins:\n *\n * - **Identity**: runtimeStageId, stageId, commitIdx\n * - **Structural**: prev/next stage ids (read from structure\n * translator's `TraceNode.data.prevIds`/`nextIds`)\n * - **Runtime prev/next**: derived via \"most-recent-per-structural-\n * prev\" rule over the commitLog (loop-safe, convergence-aware)\n * - **Data dependencies**: per-read-key lineage via\n * `findLastWriter` over the commitLog\n * - **Payload**: updates + reads\n *\n * Composition (panel guidance, L8.1 review)\n * ─────────────────────────────────────────\n * Per Panel 1 rule \"translators MUST subscribe to structure\n * directly, never to peer translators\", CommitFlow subscribes to\n * the structure handle (NOT to NodeView). Linear dependency tree\n * keeps notify cascades O(depth) instead of O(N²).\n *\n * NodeView (L8.1) stores `commitRuntimeStageIds[]` — refs only —\n * pointing into CommitFlow's `byRuntimeStageId`. The canonical\n * payload lives HERE; NodeView is the per-stage projection.\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const commitFlow = useMemo(\n * () => createCommitFlowRecorder({ structure: trace }),\n * [trace],\n * );\n * useEffect(() => {\n * executor.attachFlowRecorder(commitFlow.recorder);\n * executor.attachScopeRecorder(commitFlow.recorder);\n * }, [commitFlow]);\n *\n * const index = useTranslator(commitFlow, () => commitFlow.getIndex());\n * const c = index.byRuntimeStageId.get(asRuntimeStageId('finalize-order#3'));\n * c.structuralPrevIds // ['CheckInventory', 'RunFraudCheck']\n * c.runtimePrevIds // ['check-inventory#1', 'run-fraud-check#2']\n * c.dataDependencies // [{ key:'inStock', sourceRuntimeStageId:'check-inventory#1', sourceCommitIdx:1 }, ...]\n *\n * const lineage = backtraceDataFlow(index, asRuntimeStageId('finalize-order#3'));\n * // → ancestry chain of commits whose writes contributed to this commit's reads\n * ```\n */\n\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport { asStageId, asRuntimeStageId } from \"./_internal/keys\";\nimport type { StageId, RuntimeStageId } from \"./_internal/keys\";\nimport type { TraceStructureRecorderHandle } from \"./traceStructureRecorder\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local mirrors of footprintjs runtime recorder interfaces\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface FlowStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly traversalContext: TraversalContext;\n}\n\ninterface FlowErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface FlowRunLifecycleEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface ScopeReadEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly key?: string;\n}\n\ninterface ScopeCommitEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly updates?: Record<string, unknown>;\n readonly reads?: readonly string[];\n}\n\n/**\n * Minimal CombinedRecorder mirror — subset of footprintjs's Flow +\n * Scope channels CommitFlow consumes.\n */\nexport interface MinimalCommitFlowRecorder {\n readonly id: string;\n // Flow channel — for runtimeStageId enrichment + error attribution\n onStageExecuted?(event: FlowStageExecutedEvent): void;\n onError?(event: FlowErrorEvent): void;\n onRunStart?(event: FlowRunLifecycleEvent): void;\n onRunEnd?(event: FlowRunLifecycleEvent): void;\n // Scope channel — the canonical commit + read data source\n onRead?(event: ScopeReadEvent): void;\n onCommit?(event: ScopeCommitEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * One data-dependency edge — a read key in this commit AND the commit\n * whose `updates` last wrote that key before this commit's index.\n *\n * `sourceRuntimeStageId` and `sourceCommitIdx` are BOTH `null` when no\n * prior commit wrote the key (panel-flagged: NEVER `undefined` — forces\n * consumers to handle absence as load-bearing).\n */\nexport interface DataDependency {\n readonly key: string;\n readonly sourceRuntimeStageId: RuntimeStageId | null;\n readonly sourceCommitIdx: number | null;\n}\n\n/**\n * Per-commit summary. Joins structural data (from the structure\n * translator) with runtime data (commitLog timeline) into a single\n * consumer-friendly shape.\n *\n * Three \"prev\" views — pick the right one for your UI:\n * ─────────────────────────────────────────────────────\n * | Field | Answers |\n * |----------------------|--------------------------------------------|\n * | `structuralPrevIds` | \"what COULD flow in\" (chart shape) |\n * | `runtimePrevIds` | \"what DID flow in by stage\" (execution |\n * | | timeline; loop-aware) |\n * | `dataDependencies` | \"which commit wrote the bytes I read\" |\n * | | (causal data lineage; per-key) |\n *\n * The three answers usually align on simple charts (linear; single\n * fork-merge). They DIVERGE in interesting ways under loops (runtime\n * differs by iteration; data-deps may skip uninvolved stages) and\n * conditional branches (structural sees all options; runtime + data\n * see only the chosen path).\n */\nexport interface CommitView {\n // ── Identity ────────────────────────────────────────────────────\n readonly runtimeStageId: RuntimeStageId;\n readonly stageId: StageId;\n /** Position in the chronologically-ordered commitLog. */\n readonly commitIdx: number;\n\n // ── Structural (from structure translator) ──────────────────────\n /** Stage ids that lead into this stage in the chart (loop-excluded). */\n readonly structuralPrevIds: StageId[];\n readonly structuralNextIds: StageId[];\n\n // ── Runtime (derived: structural prev ∩ commitLog up-to-here) ──\n /**\n * For each structural prev stage that EXECUTED IN THIS RUN before\n * this commit, the most-recent runtimeStageId of that prev's commit.\n * Loop-safe: in iteration 2, runtime prev points at iteration 2's\n * commits (not iteration 1's).\n */\n readonly runtimePrevIds: RuntimeStageId[];\n /**\n * For each structural next stage that EXECUTED IN THIS RUN after\n * this commit, the soonest runtimeStageId. Symmetric to prev.\n */\n readonly runtimeNextIds: RuntimeStageId[];\n\n // ── Data flow (per-key lineage via findLastWriter) ──────────────\n /**\n * One entry per key in `reads`. `sourceRuntimeStageId` points at the\n * commit whose `updates` last set this key BEFORE this commit's\n * index; `null` when no prior writer (typically: read of a key\n * declared as default but never written by another stage).\n */\n readonly dataDependencies: DataDependency[];\n\n // ── Payload ─────────────────────────────────────────────────────\n /**\n * The commit's writes. **Shallow-copied** at intake — top-level\n * keys are owned, but nested object values are SHARED references\n * to whatever the upstream `onCommit` payload carried. Consumers\n * MUST NOT mutate nested values; doing so corrupts the recorder's\n * internal state and propagates through `findLastWriter` to every\n * subsequent `getIndex()` call.\n */\n readonly updates: Record<string, unknown>;\n readonly reads: string[];\n}\n\n/** Indexed CommitView access. */\nexport interface CommitFlowIndex {\n /** Ordered list — index === commitIdx. */\n readonly commits: readonly CommitView[];\n /** Lookup by runtimeStageId (the universal join key). */\n readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, CommitView>;\n /**\n * Data-dependency edges — `from` and `to` are commitIdx ints; `key`\n * is the data key that flowed from one commit to the other. Same\n * data as walking each CommitView's `dataDependencies` — exposed as\n * a flat edge list for graph algorithms and rendering.\n *\n * **When to use which**:\n * - `view.dataDependencies` — render ONE commit's inputs in a\n * detail panel (e.g., `<CommitInspector>`).\n * - `index.dataEdges` — draw the FULL data-flow DAG (React Flow\n * edges, GraphViz, dependency matrix, etc.). One pass over the\n * flat list = the whole graph.\n *\n * Edges are `Object.freeze()`d at construction — type `readonly` is\n * compile-time; freeze is the runtime enforcement.\n */\n readonly dataEdges: readonly { readonly from: number; readonly to: number; readonly key: string }[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CommitFlowRecorderHandle {\n /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`\n * AND `executor.attachScopeRecorder()`. */\n recorder: MinimalCommitFlowRecorder;\n /** Returns a defensive copy of the current index state. */\n getIndex(): CommitFlowIndex;\n /** Pub-sub: returns unsubscribe. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps on Scope/Flow event OR when\n * the structure translator's version bumps. */\n version(): number;\n /** Reset runtime state. Does NOT bump version or notify (consistent\n * with other translators' reset contracts). */\n reset(): void;\n}\n\nexport interface CreateCommitFlowRecorderOptions {\n /** Recorder id (surfaces in error attribution). */\n id?: string;\n /** REQUIRED — structure translator handle for structural prev/next\n * projection. CommitFlow subscribes to its version. */\n structure: TraceStructureRecorderHandle;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Strip `#executionIndex` from a runtimeStageId to recover the base\n * stageId. **Invariant I3**: matches commitLog stageIds when the\n * runtimeStageId already carries the full subflow path prefix the\n * engine emits. Do NOT manually re-parse subflow paths. */\nfunction baseStageIdOf(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createCommitFlowRecorder(\n options: CreateCommitFlowRecorderOptions,\n): CommitFlowRecorderHandle {\n const id = options.id ?? \"commit-flow\";\n const structure = options.structure;\n if (!structure) {\n throw new Error(\n \"[createCommitFlowRecorder] `structure` option is required. \" +\n \"Pass the handle returned by `createTraceStructureRecorder()`.\",\n );\n }\n\n // Internal raw commit storage — `RawCommit` is the un-projected\n // version (no structural/runtime joins yet). The full `CommitView`\n // gets computed on `getIndex()` (cached by version key).\n interface RawCommit {\n runtimeStageId: RuntimeStageId;\n stageId: StageId;\n commitIdx: number;\n updates: Record<string, unknown>;\n reads: string[];\n }\n let rawCommits: RawCommit[] = [];\n\n const notifier = createNotifier(\"commit-flow\");\n const unsubStructure = structure.subscribe(() => notifier.notify());\n\n function recordCommit(event: ScopeCommitEvent): void {\n // L8.0 ordering invariant — Scope.onCommit fires BEFORE Flow's\n // onStageExecuted. We read runtimeStageId directly from the\n // onCommit payload, NEVER waiting for a Flow event to enrich.\n const rsid = event.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createCommitFlowRecorder] onCommit without runtimeStageId — commit dropped (stage=${event.stage ?? event.stageId ?? \"?\"}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n rawCommits.push({\n runtimeStageId: asRuntimeStageId(rsid),\n stageId,\n commitIdx: rawCommits.length,\n updates: event.updates ? { ...event.updates } : {},\n reads: event.reads ? [...event.reads] : [],\n });\n notifier.notify();\n }\n\n // Flow channel handlers — no-ops for the canonical commit-data\n // capture (Scope.onCommit already carries runtimeStageId). Listed\n // so the recorder shape matches FlowRecorder and `attachTo()` can\n // attach via attachFlowRecorder for parity with other translators.\n // onError doesn't influence CommitView state today — errors belong\n // to NodeView's per-stage projection.\n const recorder: MinimalCommitFlowRecorder = {\n id,\n onCommit: recordCommit,\n onStageExecuted() {\n /* no-op — CommitFlow is commit-centric, not execution-centric */\n },\n onError() {\n /* no-op */\n },\n onRunStart() {\n /* no-op */\n },\n onRunEnd() {\n /* no-op */\n },\n };\n\n function buildIndex(): CommitFlowIndex {\n // Snapshot structure once — `getGraphRef()` returns live refs;\n // we only read from `node.data.prevIds`/`nextIds` (read-only).\n const graphRef = structure.getGraphRef();\n const nodeByStageId = new Map<string, (typeof graphRef.nodes)[number]>();\n for (const n of graphRef.nodes) nodeByStageId.set(n.id, n);\n\n // Precompute per-key writer index for findLastWriter (linear-time\n // build, O(1) lookup per read in the per-commit loop below).\n // Maps key → ordered list of {commitIdx, runtimeStageId} for\n // commits that wrote this key.\n interface KeyWriter {\n commitIdx: number;\n runtimeStageId: RuntimeStageId;\n }\n const writersOf = new Map<string, KeyWriter[]>();\n for (const rc of rawCommits) {\n for (const k of Object.keys(rc.updates)) {\n const list = writersOf.get(k) ?? [];\n list.push({ commitIdx: rc.commitIdx, runtimeStageId: rc.runtimeStageId });\n writersOf.set(k, list);\n }\n }\n\n // Precompute per-stage commit-index lists for runtimePrev/Next\n // derivation. Each stageId → ordered list of commitIdx where that\n // stage committed.\n const commitsOfStage = new Map<string, number[]>();\n for (const rc of rawCommits) {\n const list = commitsOfStage.get(rc.stageId) ?? [];\n list.push(rc.commitIdx);\n commitsOfStage.set(rc.stageId, list);\n }\n\n const commits: CommitView[] = [];\n const byRuntimeStageId = new Map<RuntimeStageId, CommitView>();\n const dataEdges: { from: number; to: number; key: string }[] = [];\n\n for (const rc of rawCommits) {\n const structNode = nodeByStageId.get(rc.stageId);\n const structuralPrevIds = (structNode?.data.prevIds ?? []).slice();\n const structuralNextIds = (structNode?.data.nextIds ?? []).slice();\n\n // runtimePrevIds — for each structural prev, the most-recent\n // commit with that stageId BEFORE rc.commitIdx.\n const runtimePrevIds: RuntimeStageId[] = [];\n for (const pStageId of structuralPrevIds) {\n const list = commitsOfStage.get(pStageId);\n if (!list) continue;\n // Walk backwards to find the highest commitIdx strictly less\n // than rc.commitIdx (invariant I2: strict `<`, not `<=`).\n let chosenIdx: number | null = null;\n for (let i = list.length - 1; i >= 0; i--) {\n if (list[i]! < rc.commitIdx) {\n chosenIdx = list[i]!;\n break;\n }\n }\n if (chosenIdx !== null) {\n runtimePrevIds.push(rawCommits[chosenIdx]!.runtimeStageId);\n }\n }\n\n // runtimeNextIds — for each structural next, the soonest commit\n // with that stageId AFTER rc.commitIdx.\n const runtimeNextIds: RuntimeStageId[] = [];\n for (const nStageId of structuralNextIds) {\n const list = commitsOfStage.get(nStageId);\n if (!list) continue;\n let chosenIdx: number | null = null;\n for (let i = 0; i < list.length; i++) {\n if (list[i]! > rc.commitIdx) {\n chosenIdx = list[i]!;\n break;\n }\n }\n if (chosenIdx !== null) {\n runtimeNextIds.push(rawCommits[chosenIdx]!.runtimeStageId);\n }\n }\n\n // Data dependencies — per-read-key findLastWriter.\n const dataDependencies: DataDependency[] = [];\n for (const key of rc.reads) {\n const writers = writersOf.get(key);\n let source: KeyWriter | null = null;\n if (writers) {\n for (let i = writers.length - 1; i >= 0; i--) {\n if (writers[i]!.commitIdx < rc.commitIdx) {\n source = writers[i]!;\n break;\n }\n }\n }\n if (source) {\n dataDependencies.push({\n key,\n sourceRuntimeStageId: source.runtimeStageId,\n sourceCommitIdx: source.commitIdx,\n });\n // L8.2 Panel 2 must-fix: freeze each edge so consumers can't\n // mutate the exposed objects. `readonly` is type-only; this\n // is the runtime enforcement.\n dataEdges.push(\n Object.freeze({ from: source.commitIdx, to: rc.commitIdx, key }),\n );\n } else {\n // Panel must-fix: use `null` (not `undefined`) for missing\n // source — forces consumers to handle absence load-bearingly.\n dataDependencies.push({\n key,\n sourceRuntimeStageId: null,\n sourceCommitIdx: null,\n });\n }\n }\n\n const view: CommitView = {\n runtimeStageId: rc.runtimeStageId,\n stageId: rc.stageId,\n commitIdx: rc.commitIdx,\n structuralPrevIds,\n structuralNextIds,\n runtimePrevIds,\n runtimeNextIds,\n dataDependencies,\n updates: { ...rc.updates },\n reads: rc.reads.slice(),\n };\n commits.push(view);\n byRuntimeStageId.set(view.runtimeStageId, view);\n }\n\n return { commits, byRuntimeStageId, dataEdges };\n }\n\n // L8.1 Panel 5 optimization: version-keyed cache. Same pattern as\n // NodeView — rebuild on (ownVersion, structureVersion) change.\n let cachedIndex: CommitFlowIndex | null = null;\n let cachedOwnVersion = -1;\n let cachedStructureVersion = -1;\n\n return {\n recorder,\n getIndex(): CommitFlowIndex {\n const own = notifier.version();\n const struct = structure.version();\n if (\n cachedIndex !== null &&\n cachedOwnVersion === own &&\n cachedStructureVersion === struct\n ) {\n return cachedIndex;\n }\n cachedIndex = buildIndex();\n cachedOwnVersion = own;\n cachedStructureVersion = struct;\n return cachedIndex;\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n rawCommits = [];\n // Cache invalidation — version doesn't bump (panel reset contract),\n // but next getIndex() must rebuild from the freshly-empty state.\n cachedIndex = null;\n cachedOwnVersion = -1;\n cachedStructureVersion = -1;\n // Subscription to structure is INTENTIONALLY kept across resets\n // (matches NodeView's reset contract). The handle is alive for\n // the recorder's full lifetime; consumer that wants full\n // disposal should drop the handle reference + let GC reclaim.\n // Referenced here purely to keep the closure alive for the\n // unsub's lexical scope.\n void unsubStructure;\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Data-flow backtrace helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Walk data-dependency edges BACKWARD from a starting commit. Returns\n * the lineage chain — every ancestor commit whose writes transitively\n * contributed to the starting commit's reads.\n *\n * BFS order, commitIdx-ascending (oldest first). Includes the starting\n * commit at the END of the returned array.\n *\n * Cycle defense: visited set + recursion cap at `index.commits.length`\n * (per L8 panel must-fix — defends against future malformed graphs).\n *\n * @example\n * ```ts\n * const lineage = backtraceDataFlow(commitIndex, asRuntimeStageId('finalize-order#3'));\n * // → [load-order#0, check-inventory#1, run-fraud-check#2, finalize-order#3]\n * // (the commits whose updates fed FinalizeOrder's reads)\n * ```\n */\nexport function backtraceDataFlow(\n index: CommitFlowIndex,\n startRuntimeStageId: RuntimeStageId,\n): CommitView[] {\n const start = index.byRuntimeStageId.get(startRuntimeStageId);\n if (!start) return [];\n // L8.2 Panel 1 must-fix: dropped the `hops < cap` counter. The\n // visited-set IS the real cycle defense — it guarantees each\n // commitIdx is dequeued AT MOST ONCE, so the loop body executes\n // ≤ `index.commits.length` times by construction. The old `hops`\n // counter could short-circuit BEFORE the visited-set saturated in\n // dense-data graphs (every commit reads from every prior), dropping\n // legitimate work. Visited-set + head-index queue is sufficient and\n // correct.\n const visitedIdx = new Set<number>([start.commitIdx]);\n const queue: number[] = [start.commitIdx];\n const collectedIdxs = new Set<number>([start.commitIdx]);\n let head = 0;\n while (head < queue.length) {\n const cur = index.commits[queue[head++]!];\n if (!cur) continue;\n for (const dep of cur.dataDependencies) {\n if (dep.sourceCommitIdx === null) continue;\n if (visitedIdx.has(dep.sourceCommitIdx)) continue;\n visitedIdx.add(dep.sourceCommitIdx);\n collectedIdxs.add(dep.sourceCommitIdx);\n queue.push(dep.sourceCommitIdx);\n }\n }\n // Return commits ordered by commitIdx ascending (chronological).\n return Array.from(collectedIdxs)\n .sort((a, b) => a - b)\n .map((idx) => index.commits[idx]!)\n .filter((c): c is CommitView => c !== undefined);\n}\n","/**\n * `createTraceBundle` — one factory wires every shipped translator\n * + provides a single `attachTo(executor)` call that registers all\n * runtime recorders.\n *\n * Bundle shape (as of L8.2)\n * ─────────────────────────\n * - `structure` — build-time `TraceGraph` (StructureRecorder).\n * - `runtimeOverlay` — execution overlay for time-travel (FlowRecorder).\n * - `nodeView` — per-stage summary index, CombinedRecorder\n * (FlowRecorder + ScopeRecorder).\n * - `commitFlow` — per-commit summary + data-lineage,\n * CombinedRecorder (ScopeRecorder + FlowRecorder).\n *\n * Goal: collapse the 5-line \"create + attach + subscribe\" boilerplate\n * into one call for the common case. Consumers that want à-la-carte\n * setup can still construct each translator directly (the underlying\n * factories are unchanged).\n *\n * Independence: each translator subscribes ONLY to `structure` (per\n * L8.1 Panel 1 rule — translators must never subscribe to peers).\n * Linear dependency tree keeps notify cascades O(depth), not O(N²).\n *\n * @example\n * ```tsx\n * import { createTraceBundle } from 'footprint-explainable-ui/flowchart';\n *\n * function MyTraceUI() {\n * const bundle = useMemo(() => createTraceBundle(), []);\n * useEffect(() => {\n * const chart = flowChart('seed', fn, 'seed', {\n * structureRecorders: [bundle.structure.recorder],\n * }).addFunction('a', fnA, 'a').build();\n * const executor = new FlowChartExecutor(chart);\n * bundle.attachTo(executor);\n * executor.run({ input });\n * }, [bundle]);\n *\n * return <TracedFlow recorder={bundle.structure} overlay={bundle.runtimeOverlay} />;\n * }\n * ```\n *\n * **Recorder-attach lifecycle**: `attachTo(executor)` attaches THREE\n * FlowRecorders (`runtimeOverlay`, `nodeView`, `commitFlow`) and TWO\n * ScopeRecorders (`nodeView`, `commitFlow`). Each translator has a\n * distinct `recorder.id`, so footprintjs's id-idempotency rule\n * doesn't collide. The build-time `structure.recorder` is NOT\n * auto-attached — it must be passed to `flowChart(..., {\n * structureRecorders: [...] })` because builder recorders register\n * BEFORE `executor` exists. Consumers wire that one explicitly (see\n * example above). This matches footprintjs's two-phase recorder\n * model (build vs runtime).\n */\n\nimport { devWarn } from \"./_internal/devWarn\";\nimport {\n createTraceStructureRecorder,\n type TraceStructureRecorderHandle,\n type CreateTraceStructureRecorderOptions,\n} from \"./traceStructureRecorder\";\nimport {\n createTraceRuntimeOverlay,\n type TraceRuntimeOverlayHandle,\n type CreateTraceRuntimeOverlayOptions,\n} from \"./createTraceRuntimeOverlay\";\nimport {\n createNodeViewRecorder,\n type NodeViewRecorderHandle,\n type CreateNodeViewRecorderOptions,\n} from \"./createNodeViewRecorder\";\nimport {\n createCommitFlowRecorder,\n type CommitFlowRecorderHandle,\n type CreateCommitFlowRecorderOptions,\n} from \"./createCommitFlowRecorder\";\n\n/** Minimal executor surface — mirrors the bits of footprintjs's\n * `FlowChartExecutor` the bundle calls into. Local to keep\n * explainable-ui dep-free from footprintjs. */\ninterface MinimalExecutor {\n attachFlowRecorder(recorder: unknown): void;\n attachScopeRecorder?(recorder: unknown): void;\n}\n\nexport interface TraceBundle {\n structure: TraceStructureRecorderHandle;\n runtimeOverlay: TraceRuntimeOverlayHandle;\n /** L8.1 — per-stage summary translator. Reads `prevIds`/`nextIds`\n * from `structure` (no duplication), accumulates `executions[]`\n * + commit refs from Flow + Scope events. */\n nodeView: NodeViewRecorderHandle;\n /** L8.2 — per-commit summary translator. Owns canonical CommitView[].\n * Derives structural prev/next from `structure`, runtimePrev/Next\n * from \"most-recent-per-prev\" over commitLog, and dataDependencies\n * via findLastWriter per read key. */\n commitFlow: CommitFlowRecorderHandle;\n /**\n * Attach RUNTIME recorders (FlowRecorder, ScopeRecorder) to a\n * footprintjs executor. The build-time `structure.recorder` is NOT\n * covered — pass it to `flowChart(..., { structureRecorders: [...] })`\n * at construction time instead (see file header example).\n */\n attachTo(executor: MinimalExecutor): void;\n}\n\nexport interface CreateTraceBundleOptions {\n /** Per-translator options. All optional. */\n structure?: CreateTraceStructureRecorderOptions;\n runtimeOverlay?: CreateTraceRuntimeOverlayOptions;\n nodeView?: Omit<CreateNodeViewRecorderOptions, \"structure\">;\n commitFlow?: Omit<CreateCommitFlowRecorderOptions, \"structure\">;\n}\n\nexport function createTraceBundle(\n options: CreateTraceBundleOptions = {},\n): TraceBundle {\n const structure = createTraceStructureRecorder(options.structure);\n const runtimeOverlay = createTraceRuntimeOverlay(options.runtimeOverlay);\n // NodeView needs the structure handle — wired internally so the\n // consumer doesn't have to pass it. The bundle is the consumer-\n // ergonomics layer; à-la-carte consumers can construct\n // createNodeViewRecorder directly with their own structure handle.\n const nodeView = createNodeViewRecorder({\n ...(options.nodeView ?? {}),\n structure,\n });\n const commitFlow = createCommitFlowRecorder({\n ...(options.commitFlow ?? {}),\n structure,\n });\n\n return {\n structure,\n runtimeOverlay,\n nodeView,\n commitFlow,\n attachTo(executor: MinimalExecutor): void {\n // All three runtime translators attach as FlowRecorders (each\n // has its own distinct `recorder.id`, so the dispatcher's\n // id-idempotency rule doesn't collide). NodeView + CommitFlow\n // ALSO implement ScopeRecorder (onCommit) — attached via\n // attachScopeRecorder when the executor exposes it.\n //\n // Footprintjs v6.0+ exposes both methods; older executors\n // gracefully degrade (commit-side data drops with a dev-warn).\n executor.attachFlowRecorder(runtimeOverlay.recorder);\n executor.attachFlowRecorder(nodeView.recorder);\n executor.attachFlowRecorder(commitFlow.recorder);\n if (typeof executor.attachScopeRecorder === \"function\") {\n executor.attachScopeRecorder(nodeView.recorder);\n executor.attachScopeRecorder(commitFlow.recorder);\n } else {\n // Old/partial executor without ScopeRecorder support. NodeView\n // + CommitFlow will silently miss commit events — surface this\n // to consumers debugging \"why are commitRuntimeStageIds empty?\".\n devWarn(\n () =>\n \"[createTraceBundle] executor.attachScopeRecorder is missing — NodeView.commitRuntimeStageIds[] AND CommitFlow.commits[] will be empty. Upgrade to footprintjs v6.0+.\",\n );\n }\n },\n };\n}\n","/**\n * `useTranslator(handle, getSnapshot)` — React adapter for any translator\n * exposing the standard `subscribe()` + `version()` shape.\n *\n * Wraps `useSyncExternalStore` so consumers don't repeat the boilerplate\n * for every translator. The `version` is the snapshot identity — when it\n * changes, React re-renders; `getSnapshot` then returns the consumer-\n * chosen view (full graph, slice, etc.).\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const graph = useTranslator(trace, () => trace.getGraph());\n * return <TraceFlow graph={graph} />;\n * ```\n *\n * **Why a hook (vs each component wiring `useSyncExternalStore` itself)**:\n * three reasons. (1) Reduces 4 lines of `useSyncExternalStore + useMemo`\n * boilerplate to one line. (2) Standardises the snapshot-identity\n * convention (version int) — consumers can't accidentally pass a getter\n * whose return identity changes every call (which would re-render\n * forever). (3) Stable subscribe/getVersion refs via memoization on the\n * handle identity — no re-subscribe on parent re-renders.\n */\n\nimport { useMemo, useSyncExternalStore } from \"react\";\n\nexport interface TranslatorHandleLike {\n subscribe(listener: () => void): () => void;\n version(): number;\n}\n\n/**\n * Subscribe to a translator + return a typed snapshot computed by the\n * caller. The snapshot recomputes whenever `version()` changes.\n *\n * `getSnapshot` is called inside a `useMemo` keyed on the version\n * integer — so consumers can return fresh objects from `getSnapshot`\n * (e.g., `handle.getGraph()` returns a defensive copy) without\n * triggering infinite re-renders.\n */\nexport function useTranslator<T>(\n handle: TranslatorHandleLike,\n getSnapshot: () => T,\n): T {\n const subscribe = useMemo(() => handle.subscribe.bind(handle), [handle]);\n const getVersion = useMemo(() => handle.version.bind(handle), [handle]);\n const version = useSyncExternalStore(subscribe, getVersion, getVersion);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => getSnapshot(), [version, getSnapshot]);\n}\n","/**\n * Graph traversal helpers — pure functions over a `NodeViewIndex`.\n *\n * Bi-directional structural walks (`walkForward` / `walkBackward`) plus\n * convenience wrappers (`backtraceStructural` / `forwardtraceStructural`).\n *\n * Cycle defense (panel L8 must-fix)\n * ──────────────────────────────────\n * Every traversal carries a `visited: Set<StageId>` and caps recursion\n * at `index.all.length` (the total node count). Defends against:\n * - Future bugs where a malformed graph includes a non-loop cycle\n * - Manual edge injection bypassing the structure-recorder fix\n * - Duplicate edges that survive dedupe due to source/target\n * collisions\n * Loop back-edges (`data.kind === 'loop'`) already excluded at the\n * structure-recorder layer (invariant I1), so they never enter\n * `prevIds`/`nextIds` — no extra filtering here.\n *\n * BFS order\n * ─────────\n * Walks return nodes in BFS order — root first, then immediate\n * neighbors, then their neighbors. Matches breadcrumb-friendly\n * \"closest-first\" display order.\n *\n * Always-arrays returns\n * ─────────────────────\n * All helpers return `NodeView[]`. Empty array (NOT null/undefined)\n * means \"no path\" or \"node not found\". Consumers `.map()` /\n * `.length`-check without null-handling boilerplate.\n */\n\nimport type { NodeView, NodeViewIndex } from \"./createNodeViewRecorder\";\nimport type { StageId } from \"./_internal/keys\";\n\nexport interface WalkOptions {\n /** Hard cap on hops. Default: `index.all.length` (one full traversal). */\n maxDepth?: number;\n /** When true, only return nodes that have `visitedInRun === true`.\n * Useful for \"in THIS run, what fed me?\" queries (runtime-aware walk). */\n onlyVisited?: boolean;\n /** When true, INCLUDE the start node in the returned array. Default:\n * false (caller already has the start node; the walk returns its\n * ancestors/descendants). */\n includeStart?: boolean;\n}\n\n/**\n * Walk forward (`nextIds`) from `startId`. BFS order. Cycle-safe.\n * Returns `[]` if `startId` is unknown.\n *\n * Convergence semantics: a node reachable via multiple paths appears\n * ONCE in the result (visited-set dedupes).\n */\nexport function walkForward(\n index: NodeViewIndex,\n startId: StageId,\n options: WalkOptions = {},\n): NodeView[] {\n return bfsWalk(index, startId, (n) => n.nextIds, options);\n}\n\n/**\n * Walk backward (`prevIds`) from `startId`. BFS order. Cycle-safe.\n * Returns `[]` if `startId` is unknown.\n *\n * Convergence semantics: a fork-join's `walkBackward` returns BOTH\n * branch parents (and their ancestors), each once.\n */\nexport function walkBackward(\n index: NodeViewIndex,\n startId: StageId,\n options: WalkOptions = {},\n): NodeView[] {\n return bfsWalk(index, startId, (n) => n.prevIds, options);\n}\n\n/**\n * Backtrace from `stageId` to a structural root (no prev) OR a split\n * point (multiple prevs). Returns the chain from `stageId` BACK to\n * the root, root-first. Includes `stageId` at the END.\n *\n * Defines \"split\" as `prevIds.length > 1 OR prevIds.length === 0`\n * (per L8 panel recommendation) — stops at convergence points AND at\n * the seed. Useful for breadcrumb display where \"innermost serial\n * run\" is the meaningful path.\n */\nexport function backtraceStructural(\n index: NodeViewIndex,\n stageId: StageId,\n options: Pick<WalkOptions, \"maxDepth\" | \"onlyVisited\"> = {},\n): NodeView[] {\n const start = index.byStageId.get(stageId);\n if (!start) return [];\n const chain: NodeView[] = [start];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>([stageId]);\n let cur: NodeView | undefined = start;\n let hops = 0;\n while (cur && hops < cap) {\n if (cur.prevIds.length === 0 || cur.prevIds.length > 1) {\n // Reached seed (no prevs) or split (multi-prev convergence).\n break;\n }\n const nextId = cur.prevIds[0]!;\n if (visited.has(nextId)) break; // cycle guard\n visited.add(nextId);\n const next: NodeView | undefined = index.byStageId.get(nextId);\n if (!next) break;\n if (options.onlyVisited && !next.visitedInRun) break;\n chain.unshift(next);\n cur = next;\n hops++;\n }\n return chain;\n}\n\n/**\n * Forward-trace from `stageId` to a structural leaf (no next) OR a\n * fork point (multiple nexts). Returns the chain from `stageId`\n * FORWARD to the leaf/fork, with `stageId` at the START.\n */\nexport function forwardtraceStructural(\n index: NodeViewIndex,\n stageId: StageId,\n options: Pick<WalkOptions, \"maxDepth\" | \"onlyVisited\"> = {},\n): NodeView[] {\n const start = index.byStageId.get(stageId);\n if (!start) return [];\n const chain: NodeView[] = [start];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>([stageId]);\n let cur: NodeView | undefined = start;\n let hops = 0;\n while (cur && hops < cap) {\n if (cur.nextIds.length === 0 || cur.nextIds.length > 1) break;\n const nextId = cur.nextIds[0]!;\n if (visited.has(nextId)) break;\n visited.add(nextId);\n const next: NodeView | undefined = index.byStageId.get(nextId);\n if (!next) break;\n if (options.onlyVisited && !next.visitedInRun) break;\n chain.push(next);\n cur = next;\n hops++;\n }\n return chain;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction bfsWalk(\n index: NodeViewIndex,\n startId: StageId,\n neighborsOf: (n: NodeView) => StageId[],\n options: WalkOptions,\n): NodeView[] {\n const start = index.byStageId.get(startId);\n if (!start) return [];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>();\n visited.add(startId);\n const out: NodeView[] = [];\n if (options.includeStart) out.push(start);\n // Queue holds [node, depthFromStart]. depthFromStart = 0 for the\n // start node; neighbors are depth 1; etc. We bail when depth > cap.\n //\n // L8.1 Panel 5 optimization: use a head-index pointer instead of\n // `queue.shift()`. shift() is O(n) (re-indexes the array on every\n // pop) → BFS over 50+ nodes degrades to O(n²). The head-index\n // pattern is O(1) per pop, O(n) total — standard interview answer.\n const queue: Array<[NodeView, number]> = [[start, 0]];\n let head = 0;\n while (head < queue.length) {\n const [node, depth] = queue[head++]!;\n if (depth >= cap) continue;\n for (const neighborId of neighborsOf(node)) {\n if (visited.has(neighborId)) continue;\n visited.add(neighborId);\n const neighbor = index.byStageId.get(neighborId);\n if (!neighbor) continue;\n if (options.onlyVisited && !neighbor.visitedInRun) continue;\n out.push(neighbor);\n queue.push([neighbor, depth + 1]);\n }\n }\n return out;\n}\n","/**\n * NodeInspector — debug/teaching panel for a single stage's\n * per-node summary from a `NodeViewIndex`.\n *\n * Demonstrates the canonical L8.1 consumer pattern:\n * 1. Read the `NodeView` for `selectedId` from the index\n * 2. Use `backtraceStructural` / `forwardtraceStructural` for the\n * prev/next chains\n * 3. Render: identity, structural neighbors (clickable to navigate),\n * visit data (count + duration + error state), commit refs.\n *\n * Composable: this is a small demo renderer. Real consumers wire\n * their own layout — the data shape is the contract.\n */\n\nimport { useMemo } from \"react\";\nimport type { NodeViewIndex, NodeView } from \"./createNodeViewRecorder\";\nimport type { StageId } from \"./_internal/keys\";\nimport { backtraceStructural, forwardtraceStructural } from \"./walkHelpers\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface NodeInspectorProps extends BaseComponentProps {\n /** The NodeView index (from `nodeView.getIndex()` or `useTranslator`).\n *\n * **Pure data prop** (NOT the recorder handle) — by design. Lets\n * consumers wrap in `useTranslator(nodeView, () => nodeView.getIndex())`\n * at the parent, or pass a static index from tests / Storybook /\n * SSR. Mirrors `<CommitInspector index={...}>` for consistency. */\n index: NodeViewIndex;\n /** Which stage to inspect. When `null`, renders the placeholder. */\n selectedId: StageId | null;\n /** Click handler — receives a stageId for breadcrumb navigation. */\n onNavigate?: (stageId: StageId) => void;\n /** When true, the prev/next chains include only `visitedInRun` nodes\n * (runtime-filtered view). */\n onlyVisited?: boolean;\n}\n\nexport function NodeInspector({\n index,\n selectedId,\n onNavigate,\n onlyVisited = false,\n className,\n style,\n}: NodeInspectorProps) {\n const view = selectedId ? index.byStageId.get(selectedId) ?? null : null;\n\n // Backtrace (root-first chain ending at this stage) — recomputes\n // when index version OR selectedId OR onlyVisited changes.\n const prevChain = useMemo(\n () => (view ? backtraceStructural(index, view.stageId, { onlyVisited }) : []),\n [index, view, onlyVisited],\n );\n // Forward-trace (this stage → leaf or fork).\n const nextChain = useMemo(\n () => (view ? forwardtraceStructural(index, view.stageId, { onlyVisited }) : []),\n [index, view, onlyVisited],\n );\n\n if (!view) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n Select a stage to inspect.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 14,\n color: theme.textPrimary,\n fontSize: 13,\n overflow: \"auto\",\n ...style,\n }}\n >\n {/* ── Identity ──────────────────────────────────────────── */}\n <div style={{ marginBottom: 16 }}>\n <div style={{ fontSize: 16, fontWeight: 700, color: theme.textPrimary }}>\n {view.label}\n </div>\n <div style={{ fontSize: 11, fontFamily: \"monospace\", color: theme.textMuted, marginTop: 2 }}>\n {view.stageId} · {view.type}\n {view.isDecider && \" · decider\"}\n {view.isFork && \" · fork\"}\n {view.isSubflow && \" · subflow\"}\n {view.isStreaming && \" · streaming\"}\n {view.isPausable && \" · pausable\"}\n </div>\n {view.description && (\n <div style={{ fontSize: 12, color: theme.textSecondary, marginTop: 6 }}>\n {view.description}\n </div>\n )}\n </div>\n\n {/* ── Visit data ────────────────────────────────────────── */}\n <Section title=\"Runtime\">\n <Row label=\"Visited\" value={view.visitedInRun ? \"yes\" : \"no\"} />\n {view.visitedInRun && (\n <>\n <Row label=\"Executions\" value={String(view.executionCount)} />\n {view.firstExecutedAt !== null && (\n <Row label=\"First at\" value={`${view.firstExecutedAt.toFixed(1)}ms`} />\n )}\n {view.lastExecutedAt !== null && (\n <Row label=\"Last at\" value={`${view.lastExecutedAt.toFixed(1)}ms`} />\n )}\n {view.totalDurationMs > 0 && (\n <Row label=\"Total\" value={`${view.totalDurationMs.toFixed(1)}ms`} />\n )}\n {view.errorCount > 0 && (\n <Row label=\"Errors\" value={String(view.errorCount)} valueColor={theme.error} />\n )}\n </>\n )}\n </Section>\n\n {/* ── Structural prev chain (clickable breadcrumb) ──────── */}\n {prevChain.length > 1 && (\n <Section title={`Prev chain (${prevChain.length - 1} hops)`}>\n <Crumbs nodes={prevChain.slice(0, -1)} onClick={onNavigate} />\n </Section>\n )}\n {view.prevIds.length > 1 && (\n <Section title=\"Multiple prev (convergence)\">\n <Crumbs\n nodes={view.prevIds\n .map((id) => index.byStageId.get(id))\n .filter((n): n is NodeView => n !== undefined)}\n onClick={onNavigate}\n />\n </Section>\n )}\n\n {/* ── Structural next chain ─────────────────────────────── */}\n {nextChain.length > 1 && (\n <Section title={`Next chain (${nextChain.length - 1} hops)`}>\n <Crumbs nodes={nextChain.slice(1)} onClick={onNavigate} />\n </Section>\n )}\n {view.nextIds.length > 1 && (\n <Section title=\"Multiple next (fork/decider)\">\n <Crumbs\n nodes={view.nextIds\n .map((id) => index.byStageId.get(id))\n .filter((n): n is NodeView => n !== undefined)}\n onClick={onNavigate}\n />\n </Section>\n )}\n\n {/* ── Commit refs (join key into CommitFlowIndex from L8.2) ── */}\n {view.commitRuntimeStageIds.length > 0 && (\n <Section title={`Commits (${view.commitRuntimeStageIds.length})`}>\n <div style={{ fontFamily: \"monospace\", fontSize: 11, color: theme.textSecondary }}>\n {view.commitRuntimeStageIds.map((rsid) => (\n <div key={rsid}>{rsid}</div>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n\n// ── Sub-components ─────────────────────────────────────────────────\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div style={{ marginBottom: 14 }}>\n <div\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n marginBottom: 6,\n }}\n >\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nfunction Row({ label, value, valueColor }: { label: string; value: string; valueColor?: string }) {\n return (\n <div style={{ display: \"flex\", justifyContent: \"space-between\", fontSize: 12, padding: \"2px 0\" }}>\n <span style={{ color: theme.textMuted }}>{label}</span>\n <span style={{ color: valueColor ?? theme.textSecondary, fontFamily: \"monospace\" }}>{value}</span>\n </div>\n );\n}\n\nfunction Crumbs({ nodes, onClick }: { nodes: NodeView[]; onClick?: (id: StageId) => void }) {\n if (nodes.length === 0) return null;\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {nodes.map((n, i) => (\n <span key={n.stageId} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n <button\n onClick={onClick ? () => onClick(n.stageId) : undefined}\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"3px 8px\",\n borderRadius: 4,\n border: `1px solid ${theme.border}`,\n background: \"transparent\",\n color: n.visitedInRun ? theme.success : theme.textSecondary,\n cursor: onClick ? \"pointer\" : \"default\",\n }}\n >\n {n.label}\n </button>\n {i < nodes.length - 1 && <span style={{ color: theme.textMuted, fontSize: 10 }}>›</span>}\n </span>\n ))}\n </div>\n );\n}\n","/**\n * CommitInspector — demo renderer for a single CommitView from a\n * `CommitFlowIndex`. Mirrors `<NodeInspector>` but commit-centric:\n *\n * - Identity: runtimeStageId + stageId + commitIdx\n * - Structural: prev/next stage ids (the chart-shape neighbors)\n * - Runtime: runtimePrev/Next commit refs (the actual prev/next\n * executions in this run — useful for time-travel breadcrumbs)\n * - Data lineage: `dataDependencies[]` per read key + a one-click\n * `backtraceDataFlow` walk showing the full ancestry chain\n * - Payload: updates + reads\n */\n\nimport { useMemo } from \"react\";\nimport type {\n CommitFlowIndex,\n CommitView,\n} from \"./createCommitFlowRecorder\";\nimport { backtraceDataFlow } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface CommitInspectorProps extends BaseComponentProps {\n /** The CommitFlow index (from `commitFlow.getIndex()` or `useTranslator`).\n *\n * **Pure data prop** (NOT the recorder handle) — by design. Lets\n * consumers wrap in `useTranslator(commitFlow, () => commitFlow.getIndex())`\n * at the parent, or pass a static index from tests / Storybook /\n * SSR. Mirrors `<NodeInspector index={...}>` for consistency. */\n index: CommitFlowIndex;\n /** Which commit to inspect (by runtimeStageId). null → placeholder. */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Click handler — receives a runtimeStageId for time-travel\n * navigation. Used by all clickable references (runtime prev/next,\n * data-dep sources, lineage chain). */\n onNavigate?: (runtimeStageId: RuntimeStageId) => void;\n}\n\nexport function CommitInspector({\n index,\n selectedRuntimeStageId,\n onNavigate,\n className,\n style,\n}: CommitInspectorProps) {\n const view = selectedRuntimeStageId\n ? index.byRuntimeStageId.get(selectedRuntimeStageId) ?? null\n : null;\n\n // Backtrace ancestry chain — recomputes when index version OR\n // selectedRuntimeStageId changes.\n const lineage = useMemo(\n () =>\n view ? backtraceDataFlow(index, view.runtimeStageId) : [],\n [index, view],\n );\n\n if (!view) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n Select a commit to inspect.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 14,\n color: theme.textPrimary,\n fontSize: 13,\n overflow: \"auto\",\n ...style,\n }}\n >\n {/* ── Identity ──────────────────────────────────────────── */}\n <div style={{ marginBottom: 16 }}>\n <div style={{ fontSize: 16, fontWeight: 700, color: theme.textPrimary }}>\n {view.stageId}\n </div>\n <div\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n color: theme.textMuted,\n marginTop: 2,\n }}\n >\n {view.runtimeStageId} · commitIdx {view.commitIdx}\n </div>\n </div>\n\n {/* ── Structural neighbors ──────────────────────────────── */}\n {view.structuralPrevIds.length > 0 && (\n <Section title=\"Structural prev (chart shape)\">\n <PlainTags labels={view.structuralPrevIds} />\n </Section>\n )}\n {view.structuralNextIds.length > 0 && (\n <Section title=\"Structural next (chart shape)\">\n <PlainTags labels={view.structuralNextIds} />\n </Section>\n )}\n\n {/* ── Runtime neighbors (clickable for time-travel) ─────── */}\n {view.runtimePrevIds.length > 0 && (\n <Section title=\"Runtime prev (this execution)\">\n <RuntimeRefs refs={view.runtimePrevIds} onClick={onNavigate} />\n </Section>\n )}\n {view.runtimeNextIds.length > 0 && (\n <Section title=\"Runtime next (this execution)\">\n <RuntimeRefs refs={view.runtimeNextIds} onClick={onNavigate} />\n </Section>\n )}\n\n {/* ── Payload ───────────────────────────────────────────── */}\n {Object.keys(view.updates).length > 0 && (\n <Section title={`Updates (${Object.keys(view.updates).length})`}>\n <KeyValueGrid entries={Object.entries(view.updates)} />\n </Section>\n )}\n {view.reads.length > 0 && (\n <Section title={`Reads (${view.reads.length})`}>\n <PlainTags labels={view.reads} />\n </Section>\n )}\n\n {/* ── Data dependencies (per-key lineage) ───────────────── */}\n {view.dataDependencies.length > 0 && (\n <Section title={`Data dependencies (${view.dataDependencies.length})`}>\n <table style={{ fontSize: 11, fontFamily: \"monospace\", width: \"100%\", borderCollapse: \"collapse\" }}>\n <tbody>\n {view.dataDependencies.map((dep) => (\n <tr key={dep.key}>\n <td style={{ color: theme.textSecondary, padding: \"2px 8px 2px 0\" }}>\n {dep.key}\n </td>\n <td style={{ color: dep.sourceRuntimeStageId ? theme.textPrimary : theme.textMuted }}>\n {dep.sourceRuntimeStageId ? (\n <button\n onClick={onNavigate ? () => onNavigate(dep.sourceRuntimeStageId!) : undefined}\n style={crumbButtonStyle(onNavigate !== undefined)}\n >\n ← {dep.sourceRuntimeStageId}\n </button>\n ) : (\n <em>(no prior writer — default or external)</em>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </Section>\n )}\n\n {/* ── Lineage chain (full data-flow backtrace) ──────────── */}\n {lineage.length > 1 && (\n <Section title={`Lineage chain (${lineage.length - 1} ancestor commits)`}>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {lineage.slice(0, -1).map((c, i) => (\n <span key={c.runtimeStageId} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n <button\n onClick={onNavigate ? () => onNavigate(c.runtimeStageId) : undefined}\n style={crumbButtonStyle(onNavigate !== undefined)}\n >\n {c.runtimeStageId}\n </button>\n {i < lineage.length - 2 && (\n <span style={{ color: theme.textMuted, fontSize: 10 }}>→</span>\n )}\n </span>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n\n// ── Sub-components ─────────────────────────────────────────────────\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div style={{ marginBottom: 14 }}>\n <div\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n marginBottom: 6,\n }}\n >\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nfunction PlainTags({ labels }: { labels: readonly string[] }) {\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 4 }}>\n {labels.map((l) => (\n <span\n key={l}\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"2px 6px\",\n borderRadius: 3,\n background: \"var(--fp-bg-secondary, transparent)\",\n color: theme.textSecondary,\n }}\n >\n {l}\n </span>\n ))}\n </div>\n );\n}\n\nfunction RuntimeRefs({\n refs,\n onClick,\n}: {\n refs: readonly RuntimeStageId[];\n onClick?: (rsid: RuntimeStageId) => void;\n}) {\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {refs.map((r) => (\n <button\n key={r}\n onClick={onClick ? () => onClick(r) : undefined}\n style={crumbButtonStyle(onClick !== undefined)}\n >\n {r}\n </button>\n ))}\n </div>\n );\n}\n\nfunction KeyValueGrid({ entries }: { entries: ReadonlyArray<[string, unknown]> }) {\n return (\n <table style={{ fontSize: 11, fontFamily: \"monospace\", width: \"100%\", borderCollapse: \"collapse\" }}>\n <tbody>\n {entries.map(([k, v]) => (\n <tr key={k}>\n <td style={{ color: theme.textSecondary, padding: \"2px 8px 2px 0\", verticalAlign: \"top\" }}>\n {k}\n </td>\n <td style={{ color: theme.textPrimary, wordBreak: \"break-word\" }}>\n {typeof v === \"object\" ? JSON.stringify(v) : String(v)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n\nfunction crumbButtonStyle(clickable: boolean): React.CSSProperties {\n return {\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"3px 8px\",\n borderRadius: 4,\n border: `1px solid ${theme.border}`,\n background: \"transparent\",\n color: theme.textSecondary,\n cursor: clickable ? \"pointer\" : \"default\",\n };\n}\n","/**\n * Series-parallel chain tree builders — pure functions over `TraceGraph`\n * (structural) + `CommitFlowIndex` (runtime).\n *\n * When to reach for this vs. flat commitLog\n * ─────────────────────────────────────────\n * Use `commitLog` when you want chronological replay / slider scrubbing\n * (\"what happened in order\"). Use the chain tree when you want to\n * render parallel structure visually or answer \"which branch ran?\"\n * questions — flat `commitLog[idx-1]` loses the fork shape.\n *\n * Pairs with `<CommitInspector>` for git-log-style master/detail —\n * `<CommitChainView>` picks, `<CommitInspector>` inspects.\n * Complements the per-stage view from `createNodeViewRecorder`.\n *\n * Why a chain tree\n * ────────────────\n * Footprintjs charts are **series-parallel DAGs by construction** —\n * the builder primitives compose serially (`addFunction`) or in\n * parallel (`addListOfFunction` / `addDeciderFunction`). Series-\n * parallel DAGs are provably representable as expression trees,\n * so we can decompose any footprintjs chart into a nested\n * `(serial | parallel | leaf)` shape that renders cleanly as\n * swim lanes.\n *\n * Two builders, one tree shape\n * ────────────────────────────\n * - `structureAsChainTree(graph, options?)` — STRUCTURAL view.\n * No commitLog. Decomposes the chart shape into S-P primitives.\n * Renders the full chart (all branches of a decider, etc.) even\n * before running.\n *\n * - `buildCommitChainTree(graph, commitFlow, options?)` — RUNTIME\n * view. Each leaf carries the commits[] that fired for that stage\n * in this run. Loops produce a leaf with N commits. Branches that\n * never executed in this run appear as empty `commits[]` leaves\n * (consumer can filter).\n *\n * Algorithm scope (correctness contract)\n * ──────────────────────────────────────\n * These builders are tuned for **series-parallel charts** — every\n * fork in footprintjs's builder has a matching merge point. For\n * non-S-P or malformed graphs the tree is still finite and stable\n * (cycle defense guarantees termination), but the shape may not\n * reflect a clean S-P decomposition.\n *\n * - Forks with **no common descendant** drop the outer-walk tail at\n * the fork node. Real footprintjs charts always re-merge.\n * - Edges with `data.kind === undefined` are treated as `'next'`.\n * Multiple linear-next edges from a single source follow only the\n * first (deterministic by insertion order); a dev-mode warning\n * fires when this is observed (`isDevMode()` from footprintjs).\n *\n * Cycle defense (L8 panel must-fix carried forward)\n * ─────────────────────────────────────────────────\n * Every recursive walk carries a `visited: Set<StageId>` to defend\n * against malformed graphs (manual edge injection, future builder\n * bugs). Loop edges (`kind === 'loop'`) are excluded at the\n * structure-recorder layer per invariant I1, so they never enter\n * prev/next — no extra filtering needed here. Convergence detection\n * uses BFS bounded by `graph.nodes.length`.\n *\n * @example\n * ```ts\n * const trace = createTraceStructureRecorder();\n * // ... build a fork chart ...\n *\n * const sChain = structureAsChainTree(trace.getGraph());\n * // → { kind: 'serial', items: [\n * // { kind: 'leaf', stageId: 'LoadOrder' },\n * // { kind: 'parallel', branches: [\n * // { kind: 'leaf', stageId: 'CheckInventory' },\n * // { kind: 'leaf', stageId: 'RunFraudCheck' },\n * // ]},\n * // { kind: 'leaf', stageId: 'FinalizeOrder' },\n * // ]}\n *\n * const commitFlow = createCommitFlowRecorder({ structure: trace });\n * // ... run chart ...\n * const cChain = buildCommitChainTree(trace.getGraph(), commitFlow.getIndex());\n * // → same shape, but each leaf carries `commits: CommitView[]`\n * ```\n */\n\nimport type { TraceGraph } from \"./traceStructureRecorder\";\nimport type { CommitFlowIndex, CommitView } from \"./createCommitFlowRecorder\";\nimport type { StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { devWarn } from \"./_internal/devWarn\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Structural chain tree leaf (no commits). */\nexport interface StructureChainLeaf {\n readonly kind: \"leaf\";\n readonly stageId: StageId;\n}\n\n/** Structural chain tree node — recursive S-P composition over stage ids. */\nexport type StructureChain =\n | StructureChainLeaf\n | { readonly kind: \"serial\"; readonly items: readonly StructureChain[] }\n | { readonly kind: \"parallel\"; readonly branches: readonly StructureChain[] };\n\n/** Commit chain tree leaf — carries all commits for the stage (loop-aware). */\nexport interface CommitChainLeaf {\n readonly kind: \"leaf\";\n readonly stageId: StageId;\n /** All commits that fired for this stage in this run, in commitIdx\n * ascending order. Loop iteration N has commits[N]. Empty array\n * when the stage never executed in this run.\n *\n * **Ownership**: references are shared with\n * `CommitFlowIndex.commits` (no deep copy). The same shallow-copy /\n * nested-shared-value contract documented on `CommitView.updates`\n * applies. Do not mutate. */\n readonly commits: readonly CommitView[];\n}\n\n/** Commit chain tree — recursive S-P composition with commit leaves. */\nexport type CommitChain =\n | CommitChainLeaf\n | { readonly kind: \"serial\"; readonly items: readonly CommitChain[] }\n | { readonly kind: \"parallel\"; readonly branches: readonly CommitChain[] };\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Per-stage indexes computed once per build call. */\ninterface GraphIndex {\n byStageId: Map<StageId, { branchChildren: StageId[]; linearNext: StageId[] }>;\n allNodeIds: StageId[];\n}\n\nfunction indexGraph(graph: TraceGraph): GraphIndex {\n const byStageId = new Map<\n StageId,\n { branchChildren: StageId[]; linearNext: StageId[] }\n >();\n const allNodeIds: StageId[] = [];\n\n for (const node of graph.nodes) {\n const stageId = asStageId(node.id);\n allNodeIds.push(stageId);\n // node.data already carries prevIds/nextIds (L8.0 enrichment), but\n // we split outgoing into branch vs linear based on edge kind below.\n byStageId.set(stageId, { branchChildren: [], linearNext: [] });\n }\n\n for (const edge of graph.edges) {\n const kind = edge.data?.kind;\n if (kind === \"loop\") continue;\n const sourceEntry = byStageId.get(asStageId(edge.source));\n if (!sourceEntry) continue;\n // Skip edges whose target is not in the node set (malformed graph\n // defense — walker would bail on entry === undefined anyway, but\n // pruning here keeps branchChildren/linearNext clean for the\n // ambiguity warning below).\n const target = asStageId(edge.target);\n if (!byStageId.has(target)) continue;\n if (kind === \"fork-branch\" || kind === \"decision-branch\") {\n sourceEntry.branchChildren.push(target);\n } else {\n // 'next' or any unspecified kind treated as linear.\n sourceEntry.linearNext.push(target);\n }\n }\n\n return { byStageId, allNodeIds };\n}\n\n/** Find the seed: first node with no incoming non-loop edge. Falls back\n * to the first node in insertion order. */\nfunction findSeed(graph: TraceGraph, fromStageId?: StageId): StageId | null {\n if (fromStageId) {\n const n = graph.nodes.find((n) => n.id === fromStageId);\n return n ? asStageId(n.id) : null;\n }\n const hasIncoming = new Set<string>();\n for (const e of graph.edges) {\n if (e.data?.kind !== \"loop\") hasIncoming.add(e.target);\n }\n const seed = graph.nodes.find((n) => !hasIncoming.has(n.id)) ?? graph.nodes[0];\n return seed ? asStageId(seed.id) : null;\n}\n\n/**\n * BFS forward from `startId`. Returns ordered visit list (BFS order)\n * + reachable set. Skips `loop`-kind edges per invariant I1.\n */\nfunction bfsReachable(\n startId: StageId,\n index: GraphIndex,\n): { order: StageId[]; reachable: Set<StageId> } {\n const reachable = new Set<StageId>([startId]);\n const order: StageId[] = [startId];\n const queue: StageId[] = [startId];\n let head = 0;\n while (head < queue.length) {\n const cur = queue[head++]!;\n const entry = index.byStageId.get(cur);\n if (!entry) continue;\n for (const next of [...entry.branchChildren, ...entry.linearNext]) {\n if (reachable.has(next)) continue;\n reachable.add(next);\n order.push(next);\n queue.push(next);\n }\n }\n return { order, reachable };\n}\n\n/**\n * Find the convergence point of a fork — the FIRST node (BFS order\n * from branch[0]) reachable from EVERY branch. Returns `null` if no\n * common descendant (branches diverge without re-merging — does not\n * happen in series-parallel footprintjs charts).\n *\n * For strict S-P charts, the first node in branch[0]'s BFS order that\n * sits in every reachable set IS the true convergence (dominator).\n * For non-S-P graphs this is a best-effort approximation.\n */\nfunction findConvergence(\n branches: readonly StageId[],\n index: GraphIndex,\n): StageId | null {\n if (branches.length < 2) return null;\n // Compute reachable + order for branch[0] once; reuse the same walk\n // for both ordering AND the first reachable set (panel 5 must-fix).\n const firstWalk = bfsReachable(branches[0]!, index);\n const reachableSets: Set<StageId>[] = [firstWalk.reachable];\n for (let i = 1; i < branches.length; i++) {\n reachableSets.push(bfsReachable(branches[i]!, index).reachable);\n }\n // Exclude the branch starting points themselves — they're not the\n // convergence of their own subtree.\n const startSet = new Set(branches);\n for (const candidate of firstWalk.order) {\n if (startSet.has(candidate)) continue;\n if (reachableSets.every((s) => s.has(candidate))) {\n return candidate;\n }\n }\n return null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Recursive walker — produces a StructureChain\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Walk forward from `startId`, stopping at `untilId` (exclusive). Returns\n * the chain for the [startId, untilId) segment. `untilId === null` means\n * walk to the end (terminal nodes).\n *\n * Cycle defense: passes a `visited: Set<StageId>` through recursion. A\n * node already in `visited` is skipped (returns null), so the same\n * StageId appears at most once in the resulting tree.\n */\nfunction walkChain(\n startId: StageId,\n untilId: StageId | null,\n index: GraphIndex,\n visited: Set<StageId>,\n): StructureChain | null {\n const items: StructureChain[] = [];\n let cur: StageId | null = startId;\n while (cur !== null && cur !== untilId) {\n if (visited.has(cur)) break;\n visited.add(cur);\n const entry = index.byStageId.get(cur);\n if (!entry) break;\n\n const branches = entry.branchChildren;\n const linearNexts = entry.linearNext;\n\n // Always emit the current node as a leaf — its OWN position in the\n // chain. Parallel/serial wrappers follow if applicable.\n items.push({ kind: \"leaf\", stageId: cur });\n\n if (branches.length >= 2) {\n // Fork — find convergence + recurse into each branch.\n const convergence = findConvergence(branches, index);\n const branchChains: StructureChain[] = [];\n for (const b of branches) {\n // Each branch walks with a per-branch clone of `visited` for\n // traversal isolation. After the branch returns, its markers\n // are unioned into the outer scope so the post-convergence\n // walk doesn't re-emit nodes that any branch already covered.\n // This is correct dedup for S-P graphs (branches don't share\n // pre-convergence nodes) and is what keeps the recursion\n // bounded for malformed graphs (cycle defense).\n const branchVisited = new Set(visited);\n const sub = walkChain(b, convergence, index, branchVisited);\n if (sub !== null) branchChains.push(sub);\n for (const v of branchVisited) visited.add(v);\n }\n if (branchChains.length > 0) {\n items.push({ kind: \"parallel\", branches: branchChains });\n }\n cur = convergence;\n } else if (branches.length === 1 && linearNexts.length === 0) {\n // Single branch — treat as linear continuation.\n cur = branches[0]!;\n } else if (linearNexts.length >= 1) {\n // Linear continuation. Multiple linearNexts is ambiguous for S-P\n // decomposition; we follow the first (deterministic per-recorder\n // insertion order) and warn in dev mode so consumers building\n // unusual graph shapes are alerted.\n if (linearNexts.length > 1) {\n devWarn(\n () =>\n `[buildCommitChainTree] stage '${cur}' has ${linearNexts.length} linear-next edges; chain decomposition follows only the first ('${linearNexts[0]}'). Use 'fork-branch' or 'decision-branch' edge kinds to express parallel/conditional splits.`,\n );\n }\n cur = linearNexts[0]!;\n } else {\n // Terminal node.\n cur = null;\n }\n }\n\n if (items.length === 0) return null;\n if (items.length === 1) return items[0]!;\n return { kind: \"serial\", items };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API: structureAsChainTree\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ChainTreeOptions {\n /** Stage id to start the walk from. Defaults to the chart's seed\n * (first node with no incoming non-loop edge). */\n rootStageId?: StageId;\n}\n\n/**\n * Build a structural chain tree for a chart. Pure function over\n * `TraceGraph` — no runtime data required. Useful for rendering the\n * chart shape before any execution (static documentation, etc.).\n */\nexport function structureAsChainTree(\n graph: TraceGraph,\n options: ChainTreeOptions = {},\n): StructureChain | null {\n if (graph.nodes.length === 0) return null;\n const index = indexGraph(graph);\n const seed = findSeed(graph, options.rootStageId);\n if (!seed) return null;\n const visited = new Set<StageId>();\n return walkChain(seed, null, index, visited);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API: buildCommitChainTree\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a commit-decorated chain tree. Same S-P shape as\n * `structureAsChainTree`, but each leaf carries the commits[] that\n * fired for that stage in this run (in commitIdx ascending order).\n *\n * Loop semantics: a stage that ran N times has a leaf with\n * `commits.length === N`. The consumer's renderer decides whether to\n * display them as a single \"ran 3×\" badge or unroll into N visible\n * boxes — both views are supported by the same data.\n *\n * Branches that never executed in this run appear with empty\n * `commits[]`. Consumers wanting \"runtime-only\" view can filter them\n * out.\n */\nexport function buildCommitChainTree(\n graph: TraceGraph,\n commitFlow: CommitFlowIndex,\n options: ChainTreeOptions = {},\n): CommitChain | null {\n const structural = structureAsChainTree(graph, options);\n if (!structural) return null;\n // Index commits by stageId for O(1) leaf decoration.\n const commitsByStageId = new Map<StageId, CommitView[]>();\n for (const c of commitFlow.commits) {\n const list = commitsByStageId.get(c.stageId) ?? [];\n list.push(c);\n commitsByStageId.set(c.stageId, list);\n }\n return decorate(structural, commitsByStageId);\n}\n\nfunction decorate(\n node: StructureChain,\n commitsByStageId: ReadonlyMap<StageId, readonly CommitView[]>,\n): CommitChain {\n if (node.kind === \"leaf\") {\n return {\n kind: \"leaf\",\n stageId: node.stageId,\n commits: commitsByStageId.get(node.stageId) ?? [],\n };\n }\n if (node.kind === \"serial\") {\n return {\n kind: \"serial\",\n items: node.items.map((n) => decorate(n, commitsByStageId)),\n };\n }\n return {\n kind: \"parallel\",\n branches: node.branches.map((b) => decorate(b, commitsByStageId)),\n };\n}\n","/**\n * CommitChainView — git-log-style swim-lane renderer for a\n * `CommitChain` or `StructureChain` (from `buildCommitChainTree` or\n * `structureAsChainTree`).\n *\n * Pair with `<CommitInspector>` for master/detail — this picks,\n * that inspects.\n *\n * Time-travel dimming (L8.5)\n * ──────────────────────────\n * Pass `revealedThroughCommitIdx={N}` (typically driven by\n * `<RunSlider>` via the ONE-CURSOR model) to dim commits with\n * `commitIdx > N`. Dimmed commits stay in the DOM (stable layout)\n * and stay CLICKABLE (clicking jumps the cursor forward to that\n * commit). Use `null` (default) to reveal all, `-1` to reveal none\n * (e.g., stale-cursor sentinel from `<TraceExplorerShell>`).\n *\n * Layout rules\n * ────────────\n * serial → vertical stack of children; subtle connector between them\n * parallel → horizontal row of branch columns (swim lanes), each\n * column is its own chain\n * leaf → one box per commit (loop unrolls into N boxes); empty\n * commits[] (or `StructureChain` leaf) renders a dashed\n * \"not executed in this run\" box\n *\n * Pure data prop: pass `chain` directly. For live updates, wrap with\n * `useTranslator(commitFlow, () => buildCommitChainTree(graph, commitFlow.getIndex()))`\n * at the parent. Mirrors the consumer pattern used by `<NodeInspector>`\n * and `<CommitInspector>`.\n *\n * Pre-execution rendering: pass a `StructureChain` directly (from\n * `structureAsChainTree(graph)`) — every leaf renders as the\n * \"not executed yet\" placeholder. No need to manufacture an empty\n * `CommitFlowIndex`.\n *\n * Selection: `selectedRuntimeStageId` highlights one commit box;\n * `onSelectCommit` fires when any commit box is clicked.\n *\n * Future extension: the recursive renderer is factored as\n * `<ChainShell renderLeaf={...}>` so a future `<StructureChainView>`\n * can reuse the same layout primitives with a different leaf renderer.\n *\n * @example\n * ```tsx\n * const chain = useTranslator(commitFlow, () =>\n * buildCommitChainTree(trace.getGraph(), commitFlow.getIndex()),\n * );\n * const [selected, setSelected] = useState<RuntimeStageId | null>(null);\n * return (\n * <div style={{ display: 'flex' }}>\n * <CommitChainView\n * chain={chain}\n * selectedRuntimeStageId={selected}\n * onSelectCommit={setSelected}\n * />\n * <CommitInspector index={commitFlow.getIndex()} selectedRuntimeStageId={selected} />\n * </div>\n * );\n * ```\n */\n\nimport type {\n CommitChain,\n CommitChainLeaf,\n StructureChain,\n StructureChainLeaf,\n} from \"./buildCommitChainTree\";\nimport type { CommitView } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId, StageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface CommitChainViewProps extends BaseComponentProps {\n /** The chain tree. Accepts BOTH `CommitChain` (from\n * `buildCommitChainTree`) and `StructureChain` (from\n * `structureAsChainTree` — pre-execution view). null → placeholder. */\n chain: CommitChain | StructureChain | null;\n /** Highlighted commit (by runtimeStageId). Only meaningful for\n * `CommitChain` input (StructureChain has no commits to select). */\n selectedRuntimeStageId?: RuntimeStageId | null;\n /** Fires when a commit box is clicked — pass to `<CommitInspector>`\n * for master/detail wiring. Not fired for \"not executed\" leaves. */\n onSelectCommit?: (runtimeStageId: RuntimeStageId) => void;\n /** Optional label resolver — default uses the bare stageId. Consumers\n * can map id → friendly name (e.g., from a NodeViewIndex). */\n resolveLabel?: (stageId: StageId) => string;\n /** Time-travel cursor: commits with `commitIdx > revealedThroughCommitIdx`\n * render dimmed (still visible — keeps layout stable). Pairs with\n * `<RunSlider>` in the ONE-CURSOR model.\n *\n * Semantics:\n * - `null` (default) — reveal ALL commits (no time-travel applied).\n * - `N >= 0` — reveal commits 0..N inclusive; dim commits with\n * `commitIdx > N`.\n * - `N < 0` (e.g., `-1`) — reveal NONE; all commits dim. Use this\n * sentinel for \"cursor is stale / unresolved\" so the chain doesn't\n * accidentally fall back to fully-revealed when the consumer wants\n * no-reveal. */\n revealedThroughCommitIdx?: number | null;\n}\n\nexport function CommitChainView({\n chain,\n selectedRuntimeStageId = null,\n onSelectCommit,\n resolveLabel,\n revealedThroughCommitIdx = null,\n className,\n style,\n}: CommitChainViewProps) {\n if (!chain) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n No chain to display.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 12,\n color: theme.textPrimary,\n fontSize: 12,\n overflow: \"auto\",\n ...style,\n }}\n >\n <ChainShell\n node={chain}\n renderLeaf={(leaf) => (\n <Leaf\n leaf={leaf}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={onSelectCommit}\n resolveLabel={resolveLabel}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n )}\n />\n </div>\n );\n}\n\n// ── Recursive layout shell (reusable by future StructureChainView) ──\n\ntype AnyChain = CommitChain | StructureChain;\ntype AnyLeaf = CommitChainLeaf | StructureChainLeaf;\n\ninterface ChainShellProps {\n node: AnyChain;\n renderLeaf: (leaf: AnyLeaf) => React.ReactNode;\n}\n\nfunction ChainShell({ node, renderLeaf }: ChainShellProps): React.ReactElement {\n if (node.kind === \"leaf\") {\n return <>{renderLeaf(node)}</>;\n }\n\n if (node.kind === \"serial\") {\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 0,\n }}\n >\n {node.items.map((child, i) => (\n <div\n key={chainKey(child, i)}\n style={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\" }}\n >\n <ChainShell node={child} renderLeaf={renderLeaf} />\n {i < node.items.length - 1 && <Connector orientation=\"vertical\" />}\n </div>\n ))}\n </div>\n );\n }\n\n // parallel → swim lanes\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 0,\n }}\n >\n <ForkMarker />\n <div\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n gap: 18,\n padding: \"4px 0\",\n borderLeft: `1px dashed ${theme.border}`,\n borderRight: `1px dashed ${theme.border}`,\n paddingLeft: 12,\n paddingRight: 12,\n }}\n >\n {node.branches.map((branch, i) => (\n <div\n key={chainKey(branch, i)}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n minWidth: 120,\n }}\n >\n <ChainShell node={branch} renderLeaf={renderLeaf} />\n </div>\n ))}\n </div>\n <ForkMarker />\n </div>\n );\n}\n\n/**\n * Stable React key for serial/parallel children — derived from the\n * subtree shape so a rerender with shifted branches doesn't mis-pair\n * subtree state. Falls back to `index` only when the leaf can't be\n * located (defensive — shouldn't happen).\n */\nfunction chainKey(node: AnyChain, fallbackIndex: number): string {\n const leaf = firstLeafOf(node);\n return leaf ? `${node.kind}:${leaf.stageId}` : `${node.kind}:idx${fallbackIndex}`;\n}\n\nfunction firstLeafOf(node: AnyChain): AnyLeaf | null {\n if (node.kind === \"leaf\") return node;\n if (node.kind === \"serial\") {\n for (const item of node.items) {\n const l = firstLeafOf(item);\n if (l) return l;\n }\n return null;\n }\n for (const branch of node.branches) {\n const l = firstLeafOf(branch);\n if (l) return l;\n }\n return null;\n}\n\n// ── Leaf (one or N commit boxes for loop iterations) ────────────────\n\nfunction Leaf({\n leaf,\n selectedRuntimeStageId,\n onSelectCommit,\n resolveLabel,\n revealedThroughCommitIdx,\n}: {\n leaf: AnyLeaf;\n selectedRuntimeStageId: RuntimeStageId | null;\n onSelectCommit?: (rsid: RuntimeStageId) => void;\n resolveLabel?: (stageId: StageId) => string;\n revealedThroughCommitIdx: number | null;\n}) {\n const label = resolveLabel ? resolveLabel(leaf.stageId) : leaf.stageId;\n const commits: readonly CommitView[] =\n \"commits\" in leaf ? leaf.commits : [];\n\n if (commits.length === 0) {\n return (\n <div\n style={{\n ...boxBaseStyle,\n borderStyle: \"dashed\",\n color: theme.textMuted,\n background: \"transparent\",\n }}\n title={`${leaf.stageId} — not executed in this run`}\n >\n <div style={{ fontWeight: 600 }}>{label}</div>\n <div style={{ fontSize: 10, fontStyle: \"italic\" }}>not executed</div>\n </div>\n );\n }\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\", gap: 4 }}>\n {commits.map((c, i) => {\n const isSelected = c.runtimeStageId === selectedRuntimeStageId;\n const clickable = onSelectCommit !== undefined;\n // Time-travel dimming: when revealedThroughCommitIdx is set,\n // commits BEYOND the cursor render dimmed (still in the DOM\n // so layout stays stable as the cursor slides). Commits are\n // STILL clickable (clicking jumps the time cursor forward).\n // We use aria-disabled (not aria-hidden) so screen-readers\n // perceive the element + state, per WAI-ARIA's \"MUST NOT use\n // aria-hidden on focusable elements\" rule.\n const isRevealed =\n revealedThroughCommitIdx === null ||\n c.commitIdx <= revealedThroughCommitIdx;\n return (\n <button\n key={c.commitIdx}\n type=\"button\"\n onClick={clickable ? () => onSelectCommit(c.runtimeStageId) : undefined}\n style={{\n ...boxBaseStyle,\n cursor: clickable ? \"pointer\" : \"default\",\n borderColor: isSelected ? theme.success : theme.border,\n borderWidth: isSelected ? 2 : 1,\n background: isSelected ? \"rgba(34,197,94,0.08)\" : \"transparent\",\n color: theme.textPrimary,\n textAlign: \"left\",\n fontFamily: \"inherit\",\n padding: \"6px 10px\",\n opacity: isRevealed ? 1 : 0.35,\n }}\n aria-disabled={!isRevealed}\n aria-current={isSelected ? \"true\" : undefined}\n title={c.runtimeStageId}\n >\n <div style={{ fontWeight: 600 }}>\n {label}\n {commits.length > 1 && (\n <span style={{ color: theme.textMuted, fontWeight: 400, marginLeft: 6 }}>\n iter {i + 1}/{commits.length}\n </span>\n )}\n </div>\n <div\n style={{\n fontSize: 10,\n fontFamily: \"monospace\",\n color: theme.textMuted,\n marginTop: 2,\n }}\n >\n #{c.commitIdx} · {c.runtimeStageId}\n </div>\n </button>\n );\n })}\n </div>\n );\n}\n\n// ── Decorations ─────────────────────────────────────────────────────\n\nfunction Connector({ orientation }: { orientation: \"vertical\" | \"horizontal\" }) {\n return orientation === \"vertical\" ? (\n <div\n aria-hidden\n style={{\n width: 1,\n height: 12,\n background: theme.border,\n }}\n />\n ) : (\n <div\n aria-hidden\n style={{\n height: 1,\n width: 12,\n background: theme.border,\n }}\n />\n );\n}\n\nfunction ForkMarker() {\n return (\n <div\n aria-hidden\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: theme.border,\n margin: \"2px 0\",\n }}\n />\n );\n}\n\nconst boxBaseStyle: React.CSSProperties = {\n display: \"inline-block\",\n minWidth: 110,\n padding: \"6px 10px\",\n border: `1px solid ${theme.border}`,\n borderRadius: 4,\n fontSize: 12,\n color: theme.textPrimary,\n background: \"transparent\",\n};\n","/**\n * TraceExplorerShell — composed master/detail layout that wires the\n * full L8 translator stack into a single drop-in component.\n *\n * **Composes**: [`<CommitChainView>`](./CommitChainView.tsx),\n * [`<CommitInspector>`](./CommitInspector.tsx),\n * [`<NodeInspector>`](./NodeInspector.tsx) over a [`TraceBundle`](./createTraceBundle.ts).\n *\n * The L8 stack is intentionally factored as independent pieces\n * (structure / runtimeOverlay / nodeView / commitFlow / chain\n * builder / inspectors). Consumers can wire à-la-carte for custom\n * layouts. `<TraceExplorerShell>` is the \"I want the canonical\n * trace-explorer UI without writing 50 lines of `useTranslator`\n * plumbing\" entry point — pass a `bundle`, get a master/detail UI.\n *\n * **Prerequisite**: call `bundle.attachTo(executor)` (see\n * `createTraceBundle` for the recorder-attach lifecycle) BEFORE\n * rendering this component. The shell only consumes events; it does\n * not trigger them. Without the attach step, every pane will show its\n * placeholder.\n *\n * Layout\n * ──────\n * ┌─────────────────────────────────────────────────┐\n * │ RunSlider (time-travel cursor) │\n * ├──────────────────────────┬──────────────────────┤\n * │ CommitChainView │ CommitInspector │\n * │ (master, click a box) │ (detail, selected) │\n * │ │ │\n * ├──────────────────────────┴──────────────────────┤\n * │ NodeInspector (resolved from selected stageId) │\n * └─────────────────────────────────────────────────┘\n *\n * The slider is the **ONE-CURSOR** affordance: dragging it moves\n * the same cursor that clicking a commit moves. Commits past the\n * cursor render dimmed in the chain view (`revealedThroughCommitIdx`\n * threaded through automatically). Pass `slots: { slider: null }`\n * to hide the slider (e.g., for static post-run views).\n *\n * Selection model\n * ───────────────\n * ONE cursor (`selectedRuntimeStageId`) drives both detail panes.\n * Clicking a commit in the chain view updates the cursor; the\n * `<CommitInspector>` shows that commit; the `<NodeInspector>`\n * shows the stage that commit belongs to (derived by stripping the\n * `#executionIndex` suffix from the runtimeStageId).\n *\n * Controlled mode: pass `selectedRuntimeStageId` + `onSelectionChange`\n * to drive selection from outside (URL hash, parent state, etc.).\n * Uncontrolled mode: omit both — the shell owns the cursor.\n * `onSelectionChange` also fires in uncontrolled mode for\n * observability (logging, analytics).\n *\n * Composition rule (L8 architecture, carried forward)\n * ───────────────────────────────────────────────────\n * This shell consumes ONLY the bundle's translator handles via\n * `useTranslator`. It NEVER subscribes to peer translators directly\n * (would violate the linear-dep-tree rule). It builds the chain\n * tree fresh on each commitFlow version bump — cheap, cache-friendly\n * (every input index is version-keyed-cached upstream, and\n * `commitFlow` transitively re-notifies on `structure` changes per\n * the L8.2 contract, so structure-only events also propagate).\n *\n * Customization\n * ─────────────\n * The default layout is a CSS grid. Override via `slots` to swap any\n * panel for a custom renderer. Slot props mirror the sibling-\n * inspector pattern — they receive PURE DATA (the typed index/chain),\n * NOT the bundle. This keeps slots usable from tests / Storybook /\n * SSR and means slot authors do not have to re-subscribe to\n * translators (the shell does that once).\n *\n * Stability note: `slots` should be stable across renders (define at\n * module scope or wrap with `useMemo`). The shell memoizes the\n * resolved component refs to defend against accidental remounts.\n *\n * @example Minimal\n * ```tsx\n * const bundle = useMemo(() => createTraceBundle(), []);\n * useEffect(() => {\n * const chart = flowChart('seed', fn, 'seed', undefined, undefined, {\n * structureRecorders: [bundle.structure.recorder],\n * }).build();\n * const executor = new FlowChartExecutor(chart);\n * bundle.attachTo(executor); // Prerequisite — see createTraceBundle.\n * executor.run({ input });\n * }, [bundle]);\n *\n * return <TraceExplorerShell bundle={bundle} />;\n * ```\n *\n * @example Controlled selection (sync to URL hash)\n * ```tsx\n * const [sel, setSel] = useState<RuntimeStageId | null>(null);\n * return (\n * <TraceExplorerShell\n * bundle={bundle}\n * selectedRuntimeStageId={sel}\n * onSelectionChange={setSel}\n * />\n * );\n * ```\n *\n * @example Custom chain pane (typed data slot)\n * ```tsx\n * const slots = useMemo(() => ({\n * chain: ({ chain, selectedRuntimeStageId, onSelectCommit }) => (\n * <MyCustomTimeline chain={chain} cursor={selectedRuntimeStageId} onPick={onSelectCommit} />\n * ),\n * }), []);\n * return <TraceExplorerShell bundle={bundle} slots={slots} />;\n * ```\n */\n\nimport { useMemo, useState, useCallback } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport type { TraceBundle } from \"./createTraceBundle\";\nimport type { RuntimeStageId, StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { useTranslator } from \"./_internal/useTranslator\";\nimport { buildCommitChainTree, type CommitChain } from \"./buildCommitChainTree\";\nimport { CommitChainView } from \"./CommitChainView\";\nimport { CommitInspector } from \"./CommitInspector\";\nimport { NodeInspector } from \"./NodeInspector\";\nimport { RunSlider } from \"./RunSlider\";\nimport type { CommitFlowIndex } from \"./createCommitFlowRecorder\";\nimport type { NodeViewIndex } from \"./createNodeViewRecorder\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\n/**\n * Slot prop bags — slots receive PURE DATA (chain/index), NOT the\n * bundle. Mirrors the sibling-inspector convention so slot bodies are\n * usable from tests / Storybook / SSR and avoid re-subscribing to\n * translators. Each callback is wired by the shell to the shared\n * selection cursor.\n */\nexport interface ChainSlotProps {\n /** Live chain tree, derived from the bundle. `null` before any\n * commits arrive. */\n chain: CommitChain | null;\n /** Currently selected commit (shared cursor). */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor. */\n onSelectCommit: (rsid: RuntimeStageId) => void;\n /** Time-travel reveal cursor (derived from selectedRuntimeStageId\n * via ONE-CURSOR model). Commits with commitIdx > this value\n * render dimmed. `null` reveals all, `-1` reveals none, `N >= 0`\n * reveals up to commit N. **Optional in custom slots** — slot\n * authors that don't implement time-travel dimming can ignore it\n * (matches the standalone `<CommitChainView>` prop optionality). */\n revealedThroughCommitIdx?: number | null;\n}\nexport interface CommitInspectorSlotProps {\n /** Live commitFlow index. */\n index: CommitFlowIndex;\n /** Currently selected commit (shared cursor). */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor (e.g., for clickable\n * data-dep / lineage breadcrumbs). */\n onNavigate: (rsid: RuntimeStageId) => void;\n}\nexport interface NodeInspectorSlotProps {\n /** Live nodeView index. */\n index: NodeViewIndex;\n /** StageId derived from `selectedRuntimeStageId`. */\n selectedStageId: StageId | null;\n /** Wire to the shared selection cursor (e.g., for prev/next chain\n * breadcrumbs). Resolves the stage to its first commit. */\n onNavigate: (stageId: StageId) => void;\n}\nexport interface SliderSlotProps {\n /** Live commitFlow index. */\n index: CommitFlowIndex;\n /** Currently selected commit — same cursor as the chain selection\n * per the ONE-CURSOR model. */\n cursorRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor. */\n onCursorChange: (rsid: RuntimeStageId | null) => void;\n}\n\nexport interface TraceExplorerSlots {\n /** Override the chain (master) pane. Use to swap the swim-lane\n * renderer for a timeline/Gantt/custom layout while keeping the\n * same selection contract. */\n chain?: React.ComponentType<ChainSlotProps>;\n /** Override the commit (detail) pane. Use to add custom commit-\n * detail formatting (e.g., domain-specific updates rendering). */\n commitInspector?: React.ComponentType<CommitInspectorSlotProps>;\n /** Override the node (stage-summary) pane. Use to surface per-stage\n * custom KPIs / annotations alongside the default execution data. */\n nodeInspector?: React.ComponentType<NodeInspectorSlotProps>;\n /** Override the slider (top time-travel bar). Pass `null` to HIDE\n * the slider entirely (e.g., for static post-run views with no\n * scrub affordance). */\n slider?: React.ComponentType<SliderSlotProps> | null;\n}\n\nexport interface TraceExplorerShellProps extends BaseComponentProps {\n /** The translator bundle from `createTraceBundle()`. MUST have had\n * `bundle.attachTo(executor)` called before any commits arrive,\n * otherwise every pane shows its placeholder. */\n bundle: TraceBundle;\n /** Controlled selection (omit for uncontrolled). `null` clears. */\n selectedRuntimeStageId?: RuntimeStageId | null;\n /** Fires on selection changes. In controlled mode, required for\n * selection to take effect. In uncontrolled mode, fires as an\n * observation hook (logging/analytics) — the shell still owns the\n * state.\n *\n * Memoize via `useCallback` to avoid downstream re-renders. */\n onSelectionChange?: (rsid: RuntimeStageId | null) => void;\n /** Optional slot overrides. Should be stable across renders\n * (define at module scope or `useMemo`). */\n slots?: TraceExplorerSlots;\n}\n\nexport function TraceExplorerShell({\n bundle,\n selectedRuntimeStageId: controlledSel,\n onSelectionChange,\n slots,\n className,\n style,\n}: TraceExplorerShellProps) {\n // Controlled vs uncontrolled selection. Standard React idiom.\n const [internalSel, setInternalSel] = useState<RuntimeStageId | null>(null);\n const isControlled = controlledSel !== undefined;\n const selectedRuntimeStageId = isControlled ? controlledSel : internalSel;\n\n const handleSelect = useCallback(\n (rsid: RuntimeStageId | null) => {\n if (!isControlled) setInternalSel(rsid);\n // Fire in both modes — controlled mode requires it for parent\n // sync; uncontrolled mode fires for observability (logging,\n // analytics, URL sync without taking control).\n onSelectionChange?.(rsid);\n },\n [isControlled, onSelectionChange],\n );\n const handleSelectCommit = useCallback(\n (rsid: RuntimeStageId) => handleSelect(rsid),\n [handleSelect],\n );\n\n // Derive selected stageId from selectedRuntimeStageId by stripping\n // the '#executionIndex' suffix. Mirrors footprintjs/trace\n // `parseRuntimeStageId` invariant — kept inline because\n // explainable-ui is dep-free from footprintjs (subflow prefix is\n // preserved; nodeView keys subflow stages by the full path-prefixed\n // form per footprintjs convention).\n const selectedStageId = useMemo<StageId | null>(() => {\n if (!selectedRuntimeStageId) return null;\n const hashIdx = selectedRuntimeStageId.lastIndexOf(\"#\");\n // hashIdx === 0 → empty stageId (malformed input) → no selection.\n if (hashIdx <= 0) return null;\n return asStageId(selectedRuntimeStageId.slice(0, hashIdx));\n }, [selectedRuntimeStageId]);\n\n // Resolve slot components ONCE per slots-identity change — defends\n // against consumer footgun of passing inline `slots={{...}}` every\n // render which would otherwise remount default panes.\n const ChainPane = useMemo(\n () => slots?.chain ?? DefaultChainPane,\n [slots?.chain],\n );\n const CommitPane = useMemo(\n () => slots?.commitInspector ?? DefaultCommitPane,\n [slots?.commitInspector],\n );\n const NodePane = useMemo(\n () => slots?.nodeInspector ?? DefaultNodePane,\n [slots?.nodeInspector],\n );\n // Slider has tri-state semantics: undefined = use default; null =\n // hide; ComponentType = override. `slots?.slider === null` is the\n // \"hide\" signal; absent key = default.\n const SliderPane = useMemo<React.ComponentType<SliderSlotProps> | null>(() => {\n if (slots && \"slider\" in slots) {\n return slots.slider ?? null;\n }\n return DefaultSliderPane;\n }, [slots]);\n\n // Subscribe ONCE here to the three translators; pass the resolved\n // data down to slots (whether default or custom). Slots NEVER need\n // to subscribe themselves.\n const chain = useTranslator(bundle.commitFlow, () =>\n buildCommitChainTree(bundle.structure.getGraph(), bundle.commitFlow.getIndex()),\n );\n const commitIndex = useTranslator(bundle.commitFlow, () =>\n bundle.commitFlow.getIndex(),\n );\n const nodeIndex = useTranslator(bundle.nodeView, () => bundle.nodeView.getIndex());\n\n // Stage-click → resolve first commit and select it. One-shot lookup\n // outside useTranslator (no subscription) is intentional — this\n // fires on click, not in a render path. Picking commits[0] is the\n // documented semantic; loops resolve to iteration 1.\n const handleStageNavigate = useCallback(\n (stageId: StageId) => {\n const candidates = commitIndex.commits.filter((c) => c.stageId === stageId);\n const first = candidates[0];\n handleSelect(first ? first.runtimeStageId : null);\n },\n [commitIndex, handleSelect],\n );\n\n // Cursor → commitIdx for chain dimming. ONE-CURSOR model: the same\n // cursor that drives selection also drives time-travel reveal.\n //\n // Three states (distinguished — Panel 1 must-fix L8.5):\n // - no cursor (`null`) → `null` (reveal ALL)\n // - cursor resolves to a commit → that commit's commitIdx\n // - cursor is STALE (rsid unknown to index, e.g. removed by reset)\n // → `-1` (reveal NONE), NOT `null` — prevents incoherent \"stale\n // cursor falls back to fully-revealed\" state.\n const revealedThroughCommitIdx = useMemo<number | null>(() => {\n if (!selectedRuntimeStageId) return null;\n const view = commitIndex.byRuntimeStageId.get(selectedRuntimeStageId);\n return view ? view.commitIdx : -1;\n }, [selectedRuntimeStageId, commitIndex]);\n\n // Layout: when the slider is hidden (`slots.slider === null`),\n // collapse the slider row so the grid doesn't reserve empty space.\n const layoutStyle = useMemo<CSSProperties>(\n () => (SliderPane ? SHELL_STYLE_WITH_SLIDER : SHELL_STYLE_NO_SLIDER),\n [SliderPane],\n );\n\n return (\n <div className={className} style={{ ...layoutStyle, ...style }}>\n {SliderPane && (\n <Pane area=\"slider\">\n <SliderPane\n index={commitIndex}\n cursorRuntimeStageId={selectedRuntimeStageId}\n onCursorChange={handleSelect}\n />\n </Pane>\n )}\n <Pane area=\"chain\">\n <ChainPane\n chain={chain}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={handleSelectCommit}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n </Pane>\n <Pane area=\"commit\">\n <CommitPane\n index={commitIndex}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onNavigate={handleSelectCommit}\n />\n </Pane>\n <Pane area=\"node\">\n <NodePane\n index={nodeIndex}\n selectedStageId={selectedStageId}\n onNavigate={handleStageNavigate}\n />\n </Pane>\n </div>\n );\n}\n\n// ── Default panes (pure data props, no internal subscriptions) ──────\n\nfunction DefaultChainPane({\n chain,\n selectedRuntimeStageId,\n onSelectCommit,\n revealedThroughCommitIdx,\n}: ChainSlotProps) {\n return (\n <CommitChainView\n chain={chain}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={onSelectCommit}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n );\n}\n\nfunction DefaultCommitPane({\n index,\n selectedRuntimeStageId,\n onNavigate,\n}: CommitInspectorSlotProps) {\n return (\n <CommitInspector\n index={index}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onNavigate={onNavigate}\n />\n );\n}\n\nfunction DefaultNodePane({ index, selectedStageId, onNavigate }: NodeInspectorSlotProps) {\n return (\n <NodeInspector index={index} selectedId={selectedStageId} onNavigate={onNavigate} />\n );\n}\n\nfunction DefaultSliderPane({\n index,\n cursorRuntimeStageId,\n onCursorChange,\n}: SliderSlotProps) {\n return (\n <RunSlider\n index={index}\n cursorRuntimeStageId={cursorRuntimeStageId}\n onCursorChange={onCursorChange}\n />\n );\n}\n\n// ── Layout helpers ──────────────────────────────────────────────────\n\nconst SHELL_STYLE_WITH_SLIDER: CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: \"minmax(280px, 1fr) minmax(320px, 1fr)\",\n gridTemplateRows: \"auto 1fr auto\",\n gridTemplateAreas: '\"slider slider\" \"chain commit\" \"node node\"',\n gap: 12,\n padding: 12,\n background: theme.bgPrimary,\n color: theme.textPrimary,\n};\n\nconst SHELL_STYLE_NO_SLIDER: CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: \"minmax(280px, 1fr) minmax(320px, 1fr)\",\n gridTemplateRows: \"1fr auto\",\n gridTemplateAreas: '\"chain commit\" \"node node\"',\n gap: 12,\n padding: 12,\n background: theme.bgPrimary,\n color: theme.textPrimary,\n};\n\nconst PANE_BASE_STYLE: CSSProperties = {\n border: `1px solid ${theme.border}`,\n borderRadius: 6,\n background: theme.bgSecondary,\n overflow: \"auto\",\n minHeight: 0, // permit shrinking inside grid\n};\n\nfunction Pane({ area, children }: { area: string; children: React.ReactNode }) {\n // Wrap each pane as an accessibility landmark so screen readers can\n // jump between panels.\n return (\n <div role=\"region\" aria-label={area} style={{ ...PANE_BASE_STYLE, gridArea: area }}>\n {children}\n </div>\n );\n}\n","/**\n * RunSlider — time-travel cursor over the commit timeline.\n *\n * Implements the **ONE-CURSOR** model from the Lens architecture: the\n * slider position IS the same `runtimeStageId` cursor that selection\n * uses everywhere else (chain view, inspectors). Moving the slider\n * advances the cursor; clicking a commit in the chain view moves the\n * slider. Same underlying state, two affordances.\n *\n * Internal mapping\n * ────────────────\n * Slider value is a `commitIdx` integer in `[0, commits.length - 1]`.\n * - slider value N ↔ `commits[N].runtimeStageId` (the cursor)\n * - cursor === null ↔ slider at value 0 (initial/empty state)\n *\n * When `commits[]` grows mid-run the slider's max bound expands\n * automatically (`index.commits.length` re-evaluates on every\n * render via the consumer's `useTranslator` subscription). The\n * cursor does NOT auto-advance — consumers that want \"follow latest\n * commit\" behavior wire a `useEffect` on `index.commits.length`.\n *\n * @example\n * ```tsx\n * const [cursor, setCursor] = useState<RuntimeStageId | null>(null);\n * const index = useTranslator(commitFlow, () => commitFlow.getIndex());\n * return (\n * <RunSlider\n * index={index}\n * cursorRuntimeStageId={cursor}\n * onCursorChange={setCursor}\n * />\n * );\n * ```\n *\n * @example Follow-latest behavior (consumer-owned)\n * ```tsx\n * useEffect(() => {\n * const last = index.commits[index.commits.length - 1];\n * if (last) setCursor(last.runtimeStageId);\n * }, [index.commits.length]);\n * ```\n *\n * Pairs with `<CommitChainView>` (via shared `revealedThroughCommitIdx`\n * to dim future commits) and `<TraceExplorerShell>` (which wires the\n * slider as a top bar driving the same cursor as the chain selection).\n */\n\nimport { useCallback, useMemo } from \"react\";\nimport type { CommitFlowIndex, CommitView } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface RunSliderProps extends BaseComponentProps {\n /** Live commit flow index (pure data prop — pass via\n * `useTranslator(commitFlow, () => commitFlow.getIndex())`).\n * Source: `createCommitFlowRecorder` — see `<CommitInspector>` for\n * the canonical consumer pattern. */\n index: CommitFlowIndex;\n /** The shared time cursor. `null` = no commit yet selected (slider\n * sits at value 0). */\n cursorRuntimeStageId: RuntimeStageId | null;\n /** Fires when the slider moves. */\n onCursorChange: (rsid: RuntimeStageId | null) => void;\n /** Optional label callback. Default renders `\"#commitIdx · stageId\"`.\n * Receives the full resolved `commit` + the `index` for richer\n * labels (step name, duration from a sibling translator, etc.). */\n renderLabel?: (info: {\n commitIdx: number;\n total: number;\n runtimeStageId: RuntimeStageId | null;\n /** Resolved commit at the cursor, or `null` when index is empty. */\n commit: CommitView | null;\n /** Full index — for cross-lookups (e.g., finding the previous\n * commit's stage label). */\n index: CommitFlowIndex;\n }) => React.ReactNode;\n}\n\nexport function RunSlider({\n index,\n cursorRuntimeStageId,\n onCursorChange,\n renderLabel,\n className,\n style,\n}: RunSliderProps) {\n const total = index.commits.length;\n\n // Map cursor → slider value. If cursor is null OR unknown to the\n // index, value 0 (placeholder).\n const cursorCommitIdx = useMemo<number>(() => {\n if (!cursorRuntimeStageId) return 0;\n const view = index.byRuntimeStageId.get(cursorRuntimeStageId);\n return view ? view.commitIdx : 0;\n }, [index, cursorRuntimeStageId]);\n\n const handleSliderChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = Number(e.target.value);\n const view = index.commits[value];\n onCursorChange(view ? view.runtimeStageId : null);\n },\n [index, onCursorChange],\n );\n\n const label = useMemo(() => {\n const commit = index.commits[cursorCommitIdx] ?? null;\n const rsid = cursorRuntimeStageId ?? commit?.runtimeStageId ?? null;\n if (renderLabel)\n return renderLabel({\n commitIdx: cursorCommitIdx,\n total,\n runtimeStageId: rsid,\n commit,\n index,\n });\n if (total === 0) return <span style={{ color: theme.textMuted }}>No commits yet</span>;\n return (\n <span style={{ fontFamily: \"monospace\", fontSize: 11, color: theme.textSecondary }}>\n #{cursorCommitIdx + 1} / {total} · {commit?.runtimeStageId ?? \"—\"}\n </span>\n );\n }, [renderLabel, cursorCommitIdx, total, index, cursorRuntimeStageId]);\n\n // Disabled state — slider is non-interactive when there are 0 or 1\n // commits (sliding has no effect).\n const disabled = total < 2;\n\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 12,\n padding: \"8px 12px\",\n background: theme.bgSecondary,\n border: `1px solid ${theme.border}`,\n borderRadius: 6,\n ...style,\n }}\n >\n <span\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n }}\n >\n Time\n </span>\n <input\n type=\"range\"\n min={0}\n max={Math.max(0, total - 1)}\n step={1}\n value={Math.min(cursorCommitIdx, Math.max(0, total - 1))}\n onChange={handleSliderChange}\n disabled={disabled}\n aria-label=\"Commit time cursor\"\n aria-valuemin={0}\n aria-valuemax={Math.max(0, total - 1)}\n aria-valuenow={cursorCommitIdx}\n aria-valuetext={\n total === 0 ? \"no commits\" : `commit ${cursorCommitIdx + 1} of ${total}`\n }\n style={{ flex: 1, accentColor: theme.success }}\n />\n <div style={{ minWidth: 200, textAlign: \"right\" }}>{label}</div>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","StageNode","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","v","v","import_react","import_react","padding","import_jsx_runtime","import_jsx_runtime","DEFAULT_NODE_TYPES","import_jsx_runtime","import_react","import_jsx_runtime","SubflowBreadcrumb","import_react","EMPTY_GRAPH","import_react","import_jsx_runtime","TreeNode","SectionLabel","SubflowTree","baseStageIdOf","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","Section","v","n","v","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/flowchart.ts","../src/components/StageNode/StageNode.tsx","../src/theme/ThemeProvider.tsx","../src/theme/tokens.ts","../src/theme/styles.ts","../src/theme/useDarkModeTokens.ts","../src/components/TimeTravelDebugger/TimeTravelDebugger.tsx","../src/components/MemoryInspector/MemoryInspector.tsx","../src/components/NarrativeLog/NarrativeLog.tsx","../src/components/GanttTimeline/GanttTimeline.tsx","../src/components/FlowchartView/TraceFlow.tsx","../src/components/LoopBackEdge/LoopBackEdge.tsx","../src/components/FlowchartView/_internal/loopRouting.ts","../src/components/FlowchartView/_internal/groupLayout.ts","../src/components/SmartStepEdge/SmartStepEdge.tsx","../src/components/FlowchartView/_internal/stepRouting.ts","../src/components/FlowchartView/_internal/dagreTraceLayout.ts","../src/components/FlowchartView/TracedFlow.tsx","../src/components/FlowchartView/_internal/devWarn.ts","../src/components/FlowchartView/_internal/notifyChange.ts","../src/components/FlowchartView/createTraceRuntimeOverlay.ts","../src/components/FlowchartView/_internal/subflowDrill.ts","../src/components/FlowchartView/_internal/overlayProjection.ts","../src/components/FlowchartView/_internal/useSubflowDrill.ts","../src/components/FlowchartView/_internal/useChartAutoRefit.ts","../src/components/FlowchartView/SubflowBreadcrumbBar.tsx","../src/components/GroupContainerNode/GroupContainerNode.tsx","../src/components/FlowchartView/SubflowBreadcrumb.tsx","../src/components/FlowchartView/useSubflowNavigation.ts","../src/components/FlowchartView/SubflowTree.tsx","../src/components/FlowchartView/_internal/keys.ts","../src/components/FlowchartView/_internal/walkSubflowSpecInto.ts","../src/components/FlowchartView/traceStructureRecorder.ts","../src/components/SlotPillNode/SlotPillNode.tsx","../src/components/FlowchartView/_internal/snapLinearSuccessors.ts","../src/components/FlowchartView/_internal/traceGroupLayout.ts","../src/components/FlowchartView/createNodeViewRecorder.ts","../src/components/FlowchartView/createCommitFlowRecorder.ts","../src/components/FlowchartView/createTraceBundle.ts","../src/components/FlowchartView/_internal/useTranslator.ts","../src/components/FlowchartView/walkHelpers.ts","../src/components/FlowchartView/NodeInspector.tsx","../src/components/FlowchartView/CommitInspector.tsx","../src/components/FlowchartView/buildCommitChainTree.ts","../src/components/FlowchartView/CommitChainView.tsx","../src/components/FlowchartView/TraceExplorerShell.tsx","../src/components/FlowchartView/RunSlider.tsx"],"sourcesContent":["// Flowchart components (require @xyflow/react peer dependency)\n// Import from \"footprint-explainable-ui/flowchart\"\n//\n// v6+: recorder-driven only. The legacy spec-walk path was deleted.\n// Drive the chart via `createTraceStructureRecorder` →\n// `<TraceFlow graph={...} />` (build-time) or\n// `<TracedFlow graph={...} overlay={...} scrubIndex={...} />`\n// (build + runtime).\n\nexport { StageNode } from \"./components/StageNode\";\nexport type { StageNodeData } from \"./components/StageNode\";\n\nexport { TimeTravelDebugger } from \"./components/TimeTravelDebugger\";\nexport type { TimeTravelDebuggerProps } from \"./components/TimeTravelDebugger\";\n\n// Subflow drill-down navigation (recorder-driven)\nexport { SubflowBreadcrumb } from \"./components/FlowchartView\";\nexport type { SubflowBreadcrumbProps } from \"./components/FlowchartView\";\nexport { useSubflowNavigation } from \"./components/FlowchartView\";\nexport type { SubflowNavigation, BreadcrumbEntry } from \"./components/FlowchartView\";\n\n// Drill-scope graph filter (top-level view = subflows as single cards).\nexport { filterGraphForDrill, buildSubflowBreadcrumb } from \"./components/FlowchartView\";\n\n// Subflow manifest tree (no ReactFlow dependency — pure React)\nexport { SubflowTree } from \"./components/FlowchartView\";\nexport type { SubflowTreeProps, SubflowTreeEntry } from \"./components/FlowchartView\";\n\n// v6.0+ — event-driven trace recorder + xyflow renderer (StructureRecorder\n// consumer pattern, no spec-tree post-walk required).\nexport { createTraceStructureRecorder } from \"./components/FlowchartView\";\nexport type {\n MinimalStructureRecorder,\n TraceNode,\n TraceEdge,\n TraceNodeData,\n TraceEdgeData,\n TraceGraph,\n TraceStructureRecorderHandle,\n CreateTraceStructureRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport { TraceFlow, defaultTraceFlowLayout } from \"./components/FlowchartView\";\nexport type {\n TraceFlowProps,\n TraceFlowLayout,\n TraceFlowEdgeColors,\n} from \"./components/FlowchartView\";\n\n// v7.0 — runtime overlay recorder + traced (build+runtime) component.\n// Pair with createTraceStructureRecorder for the full time-travel\n// trace UI without spec-tree post-walks.\nexport { createTraceRuntimeOverlay, sliceOverlay } from \"./components/FlowchartView\";\nexport type {\n MinimalFlowRecorder,\n RuntimeExecutionStep,\n RuntimeOverlay,\n RuntimeOverlaySlice,\n TraceRuntimeOverlayHandle,\n CreateTraceRuntimeOverlayOptions,\n} from \"./components/FlowchartView\";\n\nexport { TracedFlow } from \"./components/FlowchartView\";\nexport type { TracedFlowProps, TracedFlowColors } from \"./components/FlowchartView\";\n\n// Loop-back edge — curves `loopTo` edges along the right margin. Built-in in\n// TraceFlow/TracedFlow; exported for consumers that fully replace `edgeTypes`.\nexport { LoopBackEdge } from \"./components/FlowchartView\";\n// Smart step edge — routes rank-skipping (staggered) edges around skipped nodes.\n// Built-in `smartStep`; exported for consumers that fully replace `edgeTypes`.\nexport { SmartStepEdge } from \"./components/FlowchartView\";\n\n// Group containers (subflow-as-box, xyflow native nesting via parentId).\nexport {\n GroupContainerNode,\n SlotPillNode,\n applyGroupLayout,\n createGroupedLayout,\n wrapInMainChartBox,\n createMainChartBoxLayout,\n GROUP_CONTAINER_NODE_TYPE,\n MAIN_CHART_BOX_ID,\n} from \"./components/FlowchartView\";\nexport type {\n GroupContainerNodeData,\n SlotPillNodeData,\n GroupLayoutOptions,\n MainChartBoxOptions,\n} from \"./components/FlowchartView\";\n\n// Dagre layout — structure-derived spacing; the professor-grade default.\nexport { dagreTraceLayout, createDagreTraceLayout } from \"./components/FlowchartView\";\nexport type {\n DagreTraceLayoutOptions,\n NodeFootprint,\n NodeSizeResolver,\n EdgeWeightResolver,\n EdgeMinLenResolver,\n SiblingOrderResolver,\n} from \"./components/FlowchartView\";\n\n// Post-dagre spine alignment — snaps pure linear successors onto their single\n// predecessor's center-x (fixes balanced-mode drift). Opt-in via compose.\nexport { snapLinearSuccessors, createSnappedDagreLayout } from \"./components/FlowchartView\";\nexport type { SnapLinearSuccessorsOptions } from \"./components/FlowchartView\";\n\n// Group-based layout — longest-path rank bands + span-centered merges, for\n// structured flowcharts with staggered merges. Composes with the snap pass.\nexport { traceGroupLayout, createTraceGroupLayout } from \"./components/FlowchartView\";\nexport type { TraceGroupLayoutOptions } from \"./components/FlowchartView\";\n\n// L8.0 — landing strip exports.\nexport { createTraceBundle } from \"./components/FlowchartView\";\nexport type {\n TraceBundle,\n CreateTraceBundleOptions,\n} from \"./components/FlowchartView\";\n\nexport { useTranslator } from \"./components/FlowchartView\";\nexport type { TranslatorHandleLike } from \"./components/FlowchartView\";\n\nexport { asStageId, asRuntimeStageId } from \"./components/FlowchartView\";\nexport type { StageId, RuntimeStageId } from \"./components/FlowchartView\";\n\n// L8.1 — NodeView translator + traversal helpers + inspector renderer\nexport { createNodeViewRecorder } from \"./components/FlowchartView\";\nexport type {\n MinimalNodeViewRecorder,\n NodeView,\n NodeViewIndex,\n ExecutionRecord,\n NodeViewRecorderHandle,\n CreateNodeViewRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport {\n walkForward,\n walkBackward,\n backtraceStructural,\n forwardtraceStructural,\n} from \"./components/FlowchartView\";\nexport type { WalkOptions } from \"./components/FlowchartView\";\n\nexport { NodeInspector } from \"./components/FlowchartView\";\nexport type { NodeInspectorProps } from \"./components/FlowchartView\";\n\n// L8.2 — CommitFlow translator + data-lineage backtrace + inspector\nexport {\n createCommitFlowRecorder,\n backtraceDataFlow,\n} from \"./components/FlowchartView\";\nexport type {\n MinimalCommitFlowRecorder,\n CommitView,\n CommitFlowIndex,\n DataDependency,\n CommitFlowRecorderHandle,\n CreateCommitFlowRecorderOptions,\n} from \"./components/FlowchartView\";\n\nexport { CommitInspector } from \"./components/FlowchartView\";\nexport type { CommitInspectorProps } from \"./components/FlowchartView\";\n\n// L8.3 — series-parallel chain tree builders + git-log swim-lane renderer\nexport {\n structureAsChainTree,\n buildCommitChainTree,\n} from \"./components/FlowchartView\";\nexport type {\n StructureChain,\n StructureChainLeaf,\n CommitChain,\n CommitChainLeaf,\n ChainTreeOptions,\n} from \"./components/FlowchartView\";\n\nexport { CommitChainView } from \"./components/FlowchartView\";\nexport type { CommitChainViewProps } from \"./components/FlowchartView\";\n\n// L8.4 — composed shell wiring the full L8 stack into a master/detail UI\nexport { TraceExplorerShell } from \"./components/FlowchartView\";\nexport type {\n TraceExplorerShellProps,\n TraceExplorerSlots,\n ChainSlotProps,\n CommitInspectorSlotProps,\n NodeInspectorSlotProps,\n SliderSlotProps,\n} from \"./components/FlowchartView\";\n\n// L8.5 — time-travel cursor slider (ONE-CURSOR model)\nexport { RunSlider } from \"./components/FlowchartView\";\nexport type { RunSliderProps } from \"./components/FlowchartView\";\n","import { memo, useEffect, useRef } from \"react\";\nimport { Handle, Position } from \"@xyflow/react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport { theme } from \"../../theme\";\n\nconst KEYFRAMES_ID = \"fp-stage-node-keyframes\";\nconst KEYFRAMES_CSS = `\n@media (prefers-reduced-motion: no-preference) {\n @keyframes fp-pulse {\n 0%, 100% { opacity: 0.4; transform: scale(1); }\n 50% { opacity: 0.15; transform: scale(1.06); }\n }\n @keyframes fp-blink {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n}\n@media (prefers-reduced-motion: reduce) {\n @keyframes fp-pulse { 0%, 100% { opacity: 0.3; } }\n @keyframes fp-blink { 0%, 100% { opacity: 1; } }\n}\n`;\n\nexport interface StageNodeData {\n label: string;\n active?: boolean;\n done?: boolean;\n error?: boolean;\n linked?: boolean;\n /** Semantic icon hint (e.g., \"llm\", \"tool\", \"rag\", \"start\", \"parse\", \"agent\", \"guard\") */\n icon?: string;\n /** Step numbers in execution order (shown as badges — multiple when revisited via loops) */\n stepNumbers?: number[];\n /** Node was not executed (dim it) */\n dimmed?: boolean;\n /** Node is a subflow root (show nested indicator) */\n isSubflow?: boolean;\n /** Node uses lazy resolution (dashed border + cloud icon when unresolved) */\n isLazy?: boolean;\n /** Node is a decider (renders as diamond shape per flowchart convention) */\n isDecider?: boolean;\n /** Node is a fork (parallel fan-out) */\n isFork?: boolean;\n /** Human-readable description of what this stage does */\n description?: string;\n /** Subflow identifier — set when this node belongs to a subflow */\n subflowId?: string;\n /**\n * Stable stage identifier from the spec (`SpecNode.id`). Renderable as a\n * small monospace caption under the label when `showStageId` is true —\n * useful for teaching the runtimeStageId convention and for debugging\n * which node a recorder event belongs to.\n */\n stageId?: string;\n /**\n * When true, render the `stageId` as a small monospace caption beneath\n * the label. Default false. Drives the \"Show IDs\" toggle in\n * ExplainableShell.\n */\n showStageId?: boolean;\n /**\n * Visual emphasis hint — generic, so the renderer stays domain-agnostic.\n * `hero` = a stage the viewer cares about (accent border + tint + bold);\n * `muted` = mechanism/plumbing (recedes — faded + thin border). The\n * consumer's graph builder sets this from its own semantics (e.g. the\n * agentfootprint lens maps `stageRole` → emphasis). Layers UNDER run status:\n * active/done/error colours still override during a run.\n */\n emphasis?: \"hero\" | \"muted\";\n /**\n * Size tier — scales the card's text + padding to match the footprint the\n * layout allocated (the layout's node-size resolver must scale in lockstep,\n * else the card and its laid-out box disagree). `lg` = a focal stage,\n * `sm` = a minor/plumbing stage, default `md`. Generic — no domain meaning.\n */\n size?: \"sm\" | \"md\" | \"lg\";\n [key: string]: unknown;\n}\n\n// ── Stage icon SVGs ───────────────────────────────────────────────────────\n// Inline SVGs for crisp rendering at any size. Consumers pass a string key\n// via SpecNode.icon; StageNode renders the matching mini-icon.\n\nconst ICON_SIZE = 16;\n\nfunction StageIcon({ type, color }: { type: string; color: string }) {\n const s = ICON_SIZE;\n const props = { width: s, height: s, viewBox: `0 0 ${s} ${s}`, fill: \"none\", style: { flexShrink: 0 } as const };\n\n switch (type) {\n // LLM / AI call — brain/sparkle\n case \"llm\":\n case \"ai\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"8\" r=\"6\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M5.5 8C5.5 6.5 6.5 5 8 5S10.5 6.5 10.5 8\" stroke={color} strokeWidth=\"1.2\" strokeLinecap=\"round\" />\n <circle cx=\"8\" cy=\"9.5\" r=\"1\" fill={color} />\n <line x1=\"8\" y1=\"2\" x2=\"8\" y2=\"3.5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"12.5\" y1=\"4\" x2=\"11.2\" y2=\"5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"3.5\" y1=\"4\" x2=\"4.8\" y2=\"5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Tool / function call — gear\n case \"tool\":\n case \"function\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"8\" r=\"3\" stroke={color} strokeWidth=\"1.5\" />\n {[0, 45, 90, 135, 180, 225, 270, 315].map((angle) => {\n const rad = (angle * Math.PI) / 180;\n const x1 = 8 + Math.cos(rad) * 4.5;\n const y1 = 8 + Math.sin(rad) * 4.5;\n const x2 = 8 + Math.cos(rad) * 6;\n const y2 = 8 + Math.sin(rad) * 6;\n return <line key={angle} x1={x1} y1={y1} x2={x2} y2={y2} stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />;\n })}\n </svg>\n );\n\n // RAG / retrieval — magnifying glass + doc\n case \"rag\":\n case \"search\":\n case \"retrieval\":\n return (\n <svg {...props}>\n <circle cx=\"7\" cy=\"7\" r=\"4\" stroke={color} strokeWidth=\"1.5\" />\n <line x1=\"10\" y1=\"10\" x2=\"13.5\" y2=\"13.5\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"6\" x2=\"8.5\" y2=\"6\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"8\" x2=\"7.5\" y2=\"8\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Parse / process — diamond with arrows\n case \"parse\":\n case \"process\":\n case \"transform\":\n return (\n <svg {...props}>\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" stroke={color} strokeWidth=\"1.5\" transform=\"rotate(45 8 8)\" />\n </svg>\n );\n\n // Start / seed — play triangle\n case \"start\":\n case \"seed\":\n case \"init\":\n return (\n <svg {...props}>\n <path d=\"M5 3.5L12.5 8L5 12.5V3.5Z\" fill={color} opacity=\"0.8\" />\n </svg>\n );\n\n // End / finalize — stop square\n case \"end\":\n case \"finalize\":\n case \"output\":\n return (\n <svg {...props}>\n <rect x=\"4\" y=\"4\" width=\"8\" height=\"8\" rx=\"1.5\" fill={color} opacity=\"0.8\" />\n </svg>\n );\n\n // Agent — person silhouette\n case \"agent\":\n case \"orchestrator\":\n return (\n <svg {...props}>\n <circle cx=\"8\" cy=\"5\" r=\"2.5\" stroke={color} strokeWidth=\"1.5\" />\n <path d=\"M3.5 14C3.5 11 5.5 9 8 9S12.5 11 12.5 14\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Swarm — multi-agent\n case \"swarm\":\n case \"multi-agent\":\n return (\n <svg {...props}>\n <circle cx=\"5\" cy=\"5\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <circle cx=\"11\" cy=\"5\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <circle cx=\"8\" cy=\"11\" r=\"2\" stroke={color} strokeWidth=\"1.2\" />\n <line x1=\"5\" y1=\"7\" x2=\"8\" y2=\"9\" stroke={color} strokeWidth=\"1\" opacity=\"0.5\" />\n <line x1=\"11\" y1=\"7\" x2=\"8\" y2=\"9\" stroke={color} strokeWidth=\"1\" opacity=\"0.5\" />\n </svg>\n );\n\n // Guard / guardrail — shield\n case \"guard\":\n case \"guardrail\":\n case \"validate\":\n return (\n <svg {...props}>\n <path d=\"M8 2L3 5V9C3 11.5 5 13.5 8 14.5C11 13.5 13 11.5 13 9V5L8 2Z\" stroke={color} strokeWidth=\"1.5\" strokeLinejoin=\"round\" />\n <path d=\"M6 8L7.5 9.5L10 6.5\" stroke={color} strokeWidth=\"1.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n\n // Stream — wave\n case \"stream\":\n case \"streaming\":\n return (\n <svg {...props}>\n <path d=\"M2 8C4 5 6 11 8 8S12 5 14 8\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" fill=\"none\" />\n <path d=\"M2 11C4 8 6 14 8 11S12 8 14 11\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" fill=\"none\" opacity=\"0.5\" />\n </svg>\n );\n\n // Memory / state — database cylinder\n case \"memory\":\n case \"state\":\n case \"db\":\n return (\n <svg {...props}>\n <ellipse cx=\"8\" cy=\"4.5\" rx=\"5\" ry=\"2\" stroke={color} strokeWidth=\"1.3\" />\n <line x1=\"3\" y1=\"4.5\" x2=\"3\" y2=\"11.5\" stroke={color} strokeWidth=\"1.3\" />\n <line x1=\"13\" y1=\"4.5\" x2=\"13\" y2=\"11.5\" stroke={color} strokeWidth=\"1.3\" />\n <ellipse cx=\"8\" cy=\"11.5\" rx=\"5\" ry=\"2\" stroke={color} strokeWidth=\"1.3\" />\n </svg>\n );\n\n // System prompt — document with lines\n case \"system-prompt\":\n case \"prompt\":\n case \"instructions\":\n case \"document\":\n return (\n <svg {...props}>\n <rect x=\"3.5\" y=\"2\" width=\"9\" height=\"12\" rx=\"1.5\" stroke={color} strokeWidth=\"1.3\" fill=\"none\" />\n <line x1=\"5.5\" y1=\"5\" x2=\"10.5\" y2=\"5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"7.5\" x2=\"10.5\" y2=\"7.5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"5.5\" y1=\"10\" x2=\"8.5\" y2=\"10\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Messages / conversation — chat bubble\n case \"messages\":\n case \"chat\":\n case \"conversation\":\n return (\n <svg {...props}>\n <rect x=\"2.5\" y=\"3\" width=\"11\" height=\"8\" rx=\"2\" stroke={color} strokeWidth=\"1.3\" fill=\"none\" />\n <path d=\"M5.5 11L5.5 13.5L8.5 11\" stroke={color} strokeWidth=\"1.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" fill=\"none\" />\n <line x1=\"5\" y1=\"6\" x2=\"11\" y2=\"6\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n <line x1=\"5\" y1=\"8.5\" x2=\"9\" y2=\"8.5\" stroke={color} strokeWidth=\"1\" strokeLinecap=\"round\" />\n </svg>\n );\n\n // Loop — circular arrow\n case \"loop\":\n case \"retry\":\n return (\n <svg {...props}>\n <path d=\"M12 8A4 4 0 1 1 8 4\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" fill=\"none\" />\n <path d=\"M8 1.5L10.5 4L8 6.5\" stroke={color} strokeWidth=\"1.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\" fill=\"none\" />\n </svg>\n );\n\n // Lazy / service — cloud (deferred resolution, loaded on demand)\n case \"lazy\":\n case \"service\":\n case \"cloud\":\n return (\n <svg {...props}>\n <path\n d=\"M4.5 12C2.8 12 1.5 10.7 1.5 9C1.5 7.5 2.5 6.3 3.8 6C4 4 5.8 2.5 8 2.5C9.8 2.5 11.3 3.5 11.9 5C13.9 5.2 15.5 6.8 15.5 8.8C15.5 10.8 13.9 12.5 11.8 12.5H4.5\"\n stroke={color}\n strokeWidth=\"1.3\"\n strokeLinecap=\"round\"\n fill=\"none\"\n />\n </svg>\n );\n\n // Decision — diamond (already handled by isDecider shape)\n case \"decision\":\n case \"router\":\n return (\n <svg {...props}>\n <path d=\"M8 2L14 8L8 14L2 8Z\" stroke={color} strokeWidth=\"1.5\" fill=\"none\" />\n <circle cx=\"8\" cy=\"8\" r=\"1.5\" fill={color} />\n </svg>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * Custom ReactFlow node for pipeline stages.\n * All colors and fonts come from `--fp-*` CSS variables (via theme).\n * Shows execution state via color, icon, step badge, and pulse animation.\n */\nexport const StageNode = memo(function StageNode({\n data,\n}: NodeProps & { data: StageNodeData }) {\n const { label, active, done, error, linked, icon, stepNumbers, dimmed, isSubflow, isLazy, isDecider, isFork, description, stageId, showStageId } = data;\n\n // Lazy nodes show cloud icon by default (unless another icon is specified)\n const effectiveIcon = icon || (isLazy ? \"lazy\" : undefined);\n // Lazy + unresolved = dashed border\n const isLazyUnresolved = isLazy && !done && !active;\n\n // Inject keyframes once into document head\n const injectedRef = useRef(false);\n useEffect(() => {\n if (injectedRef.current) return;\n if (typeof document !== \"undefined\" && !document.getElementById(KEYFRAMES_ID)) {\n const styleEl = document.createElement(\"style\");\n styleEl.id = KEYFRAMES_ID;\n styleEl.textContent = KEYFRAMES_CSS;\n document.head.appendChild(styleEl);\n }\n injectedRef.current = true;\n }, []);\n\n const isOnPath = active || done;\n\n // Emphasis (importance hierarchy). Generic flags — no domain knowledge.\n const isHero = data.emphasis === \"hero\";\n const isMuted = data.emphasis === \"muted\";\n // Card text/padding scale — kept in step with the layout's footprint resolver.\n const sizeScale = data.size === \"lg\" ? 1.3 : data.size === \"sm\" ? 0.85 : 1;\n\n // RESTING (not-yet-run) appearance carries the importance hierarchy: heroes\n // get an accent border + faint accent tint + accent glow. Run status\n // (active/done/error) overrides these during execution.\n const restingBg = isHero\n ? `color-mix(in srgb, ${theme.primary} 12%, ${theme.bgSecondary})`\n : theme.bgSecondary;\n const restingBorder = isHero ? theme.primary : theme.border;\n const restingShadow = isHero\n ? `0 0 10px color-mix(in srgb, ${theme.primary} 22%, transparent)`\n : `0 2px 8px rgba(0,0,0,0.15)`;\n\n const bg = active\n ? theme.primary\n : done\n ? theme.success\n : error\n ? theme.error\n : restingBg;\n\n const borderColor = active\n ? theme.primary\n : done\n ? theme.success\n : error\n ? theme.error\n : restingBorder;\n\n const shadow = active\n ? `0 0 22px color-mix(in srgb, ${theme.primary} 55%, transparent)`\n : done\n ? `0 0 8px color-mix(in srgb, ${theme.success} 20%, transparent)`\n : error\n ? `0 0 12px color-mix(in srgb, ${theme.error} 30%, transparent)`\n : restingShadow;\n\n // Colored states use white for contrast; default uses consumer's text color.\n const textColor =\n active || done || error ? \"#fff\" : theme.textPrimary;\n\n return (\n <>\n <Handle type=\"target\" position={Position.Top} style={{ opacity: 0 }} />\n {/* Centering wrapper. React Flow sizes the node WRAPPER to the layout's\n allocated width (which may be WIDER than the card — e.g. uniform-width\n columns, or a NodeSizeResolver footprint stamped by the layout). The\n card below is content-sized; without this wrapper it sits at the\n wrapper's LEFT edge, so its visual center drifts left of the box\n center the layout placed it at (the wider the box, the worse the\n drift). `width:100%` + center-justify makes the card's visual center\n coincide with the node-box center, so layout centering == paint\n centering. Mirrors SlotPillNode / GroupContainerNode, which already\n fill their wrapper width. */}\n <div style={{ width: \"100%\", display: \"flex\", justifyContent: \"center\" }}>\n <div\n style={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n // Plumbing recedes. Layers with the run-overlay `dimmed` (not-yet-run)\n // — a muted AND not-run node is faintest, which is correct.\n opacity: isMuted ? 0.5 : undefined,\n }}\n >\n {/* Step number badges — multiple when revisited via loops */}\n {stepNumbers && stepNumbers.length > 0 && isOnPath && (\n <div\n style={{\n position: \"absolute\",\n top: -10,\n left: -10,\n display: \"flex\",\n gap: 3,\n zIndex: 10,\n }}\n >\n {stepNumbers.map((num, i) => {\n const isLatest = i === stepNumbers.length - 1;\n const badgeBg = isLatest && active ? theme.primary : theme.success;\n const glow = isLatest && active\n ? `color-mix(in srgb, ${theme.primary} 50%, transparent)`\n : `color-mix(in srgb, ${theme.success} 40%, transparent)`;\n return (\n <div\n key={num}\n style={{\n width: 22,\n height: 22,\n borderRadius: \"50%\",\n background: badgeBg,\n color: \"#fff\",\n fontSize: 11,\n fontWeight: 700,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: `0 0 8px ${glow}`,\n }}\n >\n {num}\n </div>\n );\n })}\n </div>\n )}\n\n {/* Linked pulse ring */}\n {linked && (\n <div\n style={{\n position: \"absolute\",\n inset: -6,\n borderRadius: isDecider ? 0 : `calc(${theme.radius} + 4px)`,\n clipPath: isDecider ? \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\" : undefined,\n border: `2px solid ${theme.primary}`,\n opacity: 0.4,\n animation: \"fp-pulse 2s ease-in-out infinite\",\n }}\n />\n )}\n\n {/* Active node pulse ring */}\n {active && (\n <div\n style={{\n position: \"absolute\",\n inset: -6,\n borderRadius: isDecider ? 0 : `calc(${theme.radius} + 4px)`,\n clipPath: isDecider ? \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\" : undefined,\n border: `2px solid ${theme.primary}`,\n opacity: 0.3,\n animation: \"fp-pulse 1.5s ease-out infinite\",\n }}\n />\n )}\n\n {/* \"NOW\" badge — marks the step the cursor is on (the live step),\n mirroring the monitor mockup. Sits top-right so it never collides\n with the top-left step-number badge. */}\n {active && (\n <div\n style={{\n position: \"absolute\",\n top: -9,\n right: -8,\n zIndex: 11,\n background: theme.warning,\n color: \"#1a1a1a\",\n fontSize: 9,\n fontWeight: 800,\n letterSpacing: 0.6,\n padding: \"2px 6px\",\n borderRadius: 10,\n boxShadow: `0 0 10px color-mix(in srgb, ${theme.warning} 60%, transparent)`,\n }}\n >\n NOW\n </div>\n )}\n\n {/* Diamond for decider nodes — proper diamond via clip-path */}\n {isDecider ? (\n <div style={{ position: \"relative\", width: 120, height: 72 }}>\n {/* Diamond shape layer */}\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n background: bg,\n clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\",\n border: \"none\",\n boxShadow: shadow,\n transition: \"all 0.3s ease\",\n }}\n />\n {/* Border layer — slightly larger diamond behind */}\n <div\n style={{\n position: \"absolute\",\n inset: -2,\n clipPath: \"polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)\",\n background: borderColor,\n zIndex: -1,\n ...(isLazyUnresolved ? {\n background: \"transparent\",\n // Dashed border via SVG for clip-path (CSS border doesn't work with clip-path)\n } : {}),\n }}\n />\n {/* Content — centered on top of diamond */}\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 1,\n fontFamily: theme.fontSans,\n zIndex: 1,\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 4 }}>\n {effectiveIcon && <StageIcon type={effectiveIcon} color={textColor} />}\n {!effectiveIcon && (\n <span style={{ fontSize: 9, color: textColor }}>&#x25C7;</span>\n )}\n <span\n style={{\n fontSize: 11,\n fontWeight: 600,\n color: textColor,\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n </span>\n </div>\n {description && (\n <span\n style={{\n fontSize: 8,\n fontWeight: 400,\n color: textColor,\n opacity: 0.7,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 100,\n }}\n >\n {description}\n </span>\n )}\n {showStageId && stageId && (\n <span\n style={{\n fontSize: 8,\n fontFamily: \"ui-monospace, monospace\",\n color: textColor,\n opacity: 0.55,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 100,\n }}\n title={`stageId: ${stageId}`}\n >\n {stageId}\n </span>\n )}\n </div>\n </div>\n ) : (\n /* Standard rectangular node */\n <div\n style={{\n background: bg,\n border: `${isHero ? \"2.5px\" : isMuted ? \"1px\" : \"2px\"} ${isLazyUnresolved ? \"dashed\" : \"solid\"} ${borderColor}`,\n borderRadius: theme.radius,\n padding: description\n ? `${Math.round(8 * sizeScale)}px ${Math.round(16 * sizeScale)}px`\n : `${Math.round(10 * sizeScale)}px ${Math.round(20 * sizeScale)}px`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: description ? 2 : 0,\n boxShadow: shadow,\n transition: \"all 0.3s ease\",\n fontFamily: theme.fontSans,\n minWidth: 100,\n justifyContent: \"center\",\n }}\n >\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n {/* Semantic icon (lazy nodes default to cloud icon) */}\n {effectiveIcon && <StageIcon type={effectiveIcon} color={textColor} />}\n\n {/* State icon */}\n {done && !effectiveIcon && (\n <span style={{ fontSize: 10, color: textColor }}>&#x2713;</span>\n )}\n {active && !effectiveIcon && (\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: \"#fff\",\n animation: \"fp-blink 1s ease-in-out infinite\",\n flexShrink: 0,\n }}\n />\n )}\n {error && !effectiveIcon && (\n <span style={{ fontSize: 10, color: textColor }}>&#x2717;</span>\n )}\n\n <span\n style={{\n fontSize: Math.round(13 * sizeScale),\n fontWeight: isHero ? 700 : 500,\n color: textColor,\n whiteSpace: \"nowrap\",\n }}\n >\n {label}\n </span>\n {/* Subflow indicator — nested boxes icon */}\n {isSubflow && (\n <span\n style={{\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: 16,\n height: 16,\n borderRadius: 3,\n border: `1.5px solid ${textColor}`,\n position: \"relative\",\n opacity: 0.7,\n flexShrink: 0,\n }}\n >\n <span\n style={{\n width: 8,\n height: 8,\n borderRadius: 2,\n border: `1px solid ${textColor}`,\n }}\n />\n </span>\n )}\n </div>\n {/* Description subtitle */}\n {description && (\n <span\n style={{\n fontSize: 10,\n fontWeight: 400,\n color: textColor,\n opacity: 0.7,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 160,\n }}\n >\n {description}\n </span>\n )}\n {/* Stage ID caption — toggled by `showStageId`. Teaches the\n runtimeStageId convention; recorders key their data by\n this ID so consumers can render any recorder's per-stage\n output by lookup. */}\n {showStageId && stageId && (\n <span\n style={{\n fontSize: 9,\n fontFamily: \"ui-monospace, monospace\",\n color: textColor,\n opacity: 0.55,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n maxWidth: 160,\n }}\n title={`stageId: ${stageId}`}\n >\n {stageId}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n <Handle type=\"source\" position={Position.Bottom} style={{ opacity: 0 }} />\n </>\n );\n});\n","import { createContext, useContext } from \"react\";\nimport type { ThemeTokens } from \"./tokens\";\nimport { tokensToCSSVars } from \"./tokens\";\n\nconst ThemeContext = createContext<ThemeTokens>({});\n\nexport function useFootprintTheme(): ThemeTokens {\n return useContext(ThemeContext);\n}\n\ninterface FootprintThemeProps {\n tokens?: ThemeTokens;\n children: React.ReactNode;\n}\n\n/**\n * Optional theme provider — wraps children with CSS custom properties.\n * Consumers can also just set --fp-* CSS variables directly.\n *\n * Wrapper div uses `display: contents` so it's invisible to the\n * parent's layout (flex / grid / block). This matters because themed\n * children often need to fill a parent (flex:1 / height:100% /\n * grid cells), and a regular block `<div>` here would break that\n * chain — descendants would resolve to 0 height when the parent is\n * flex-column or a grid cell with minmax(0, 1fr). `display: contents`\n * removes the box from the render tree while keeping the DOM intact,\n * so CSS custom property inheritance (which follows the DOM) still\n * flows to children.\n *\n * Trade-off: `display: contents` elements are removed from the\n * accessibility tree in some older browser versions. Our wrapper has\n * no semantic role, so this is fine.\n */\nexport function FootprintTheme({ tokens = {}, children }: FootprintThemeProps) {\n const cssVars = tokensToCSSVars(tokens);\n\n return (\n <ThemeContext.Provider value={tokens}>\n <div\n style={{ ...(cssVars as React.CSSProperties), display: \"contents\" }}\n className=\"fp-theme-root\"\n >\n {children}\n </div>\n </ThemeContext.Provider>\n );\n}\n","/** Default theme tokens — consumers override via CSS variables or ThemeProvider. */\nexport interface ThemeTokens {\n colors?: {\n primary?: string;\n success?: string;\n error?: string;\n warning?: string;\n bgPrimary?: string;\n bgSecondary?: string;\n bgTertiary?: string;\n textPrimary?: string;\n textSecondary?: string;\n textMuted?: string;\n border?: string;\n };\n radius?: string;\n fontFamily?: {\n sans?: string;\n mono?: string;\n };\n}\n\n/** Maps ThemeTokens to CSS custom property assignments. */\nexport function tokensToCSSVars(tokens: ThemeTokens): Record<string, string> {\n const vars: Record<string, string> = {};\n if (tokens.colors) {\n const c = tokens.colors;\n if (c.primary) vars[\"--fp-color-primary\"] = c.primary;\n if (c.success) vars[\"--fp-color-success\"] = c.success;\n if (c.error) vars[\"--fp-color-error\"] = c.error;\n if (c.warning) vars[\"--fp-color-warning\"] = c.warning;\n if (c.bgPrimary) vars[\"--fp-bg-primary\"] = c.bgPrimary;\n if (c.bgSecondary) vars[\"--fp-bg-secondary\"] = c.bgSecondary;\n if (c.bgTertiary) vars[\"--fp-bg-tertiary\"] = c.bgTertiary;\n if (c.textPrimary) vars[\"--fp-text-primary\"] = c.textPrimary;\n if (c.textSecondary) vars[\"--fp-text-secondary\"] = c.textSecondary;\n if (c.textMuted) vars[\"--fp-text-muted\"] = c.textMuted;\n if (c.border) vars[\"--fp-border\"] = c.border;\n }\n if (tokens.radius) vars[\"--fp-radius\"] = tokens.radius;\n if (tokens.fontFamily?.sans) vars[\"--fp-font-sans\"] = tokens.fontFamily.sans;\n if (tokens.fontFamily?.mono) vars[\"--fp-font-mono\"] = tokens.fontFamily.mono;\n return vars;\n}\n\n/** Raw fallback values — used by tokensToCSSVars() and anywhere a real color is needed. */\nexport const rawDefaults = {\n colors: {\n primary: \"#6366f1\",\n success: \"#22c55e\",\n error: \"#ef4444\",\n warning: \"#f59e0b\",\n bgPrimary: \"#0f172a\",\n bgSecondary: \"#1e293b\",\n bgTertiary: \"#334155\",\n textPrimary: \"#f8fafc\",\n textSecondary: \"#94a3b8\",\n textMuted: \"#64748b\",\n border: \"#334155\",\n },\n radius: \"8px\",\n fontFamily: {\n sans: \"Inter, system-ui, -apple-system, sans-serif\",\n mono: \"'JetBrains Mono', 'Fira Code', monospace\",\n },\n} as const;\n\n/** Default dark theme values with CSS variable references (consumers can override via CSS). */\nexport const defaultTokens: Required<{\n [K in keyof ThemeTokens]-?: Required<ThemeTokens[K]>;\n}> = {\n colors: {\n primary: `var(--fp-color-primary, ${rawDefaults.colors.primary})`,\n success: `var(--fp-color-success, ${rawDefaults.colors.success})`,\n error: `var(--fp-color-error, ${rawDefaults.colors.error})`,\n warning: `var(--fp-color-warning, ${rawDefaults.colors.warning})`,\n bgPrimary: `var(--fp-bg-primary, ${rawDefaults.colors.bgPrimary})`,\n bgSecondary: `var(--fp-bg-secondary, ${rawDefaults.colors.bgSecondary})`,\n bgTertiary: `var(--fp-bg-tertiary, ${rawDefaults.colors.bgTertiary})`,\n textPrimary: `var(--fp-text-primary, ${rawDefaults.colors.textPrimary})`,\n textSecondary: `var(--fp-text-secondary, ${rawDefaults.colors.textSecondary})`,\n textMuted: `var(--fp-text-muted, ${rawDefaults.colors.textMuted})`,\n border: `var(--fp-border, ${rawDefaults.colors.border})`,\n },\n radius: `var(--fp-radius, ${rawDefaults.radius})`,\n fontFamily: {\n sans: `var(--fp-font-sans, ${rawDefaults.fontFamily.sans})`,\n mono: `var(--fp-font-mono, ${rawDefaults.fontFamily.mono})`,\n },\n};\n","import type { Size } from \"../types\";\n\n/**\n * Helper to resolve a CSS variable with a fallback.\n * Usage: v(\"--fp-color-primary\", \"#6366f1\")\n */\nexport function v(varName: string, fallback: string): string {\n return `var(${varName}, ${fallback})`;\n}\n\n/** Shorthand for common theme variables */\nexport const theme = {\n primary: v(\"--fp-color-primary\", \"#6366f1\"),\n success: v(\"--fp-color-success\", \"#22c55e\"),\n error: v(\"--fp-color-error\", \"#ef4444\"),\n warning: v(\"--fp-color-warning\", \"#f59e0b\"),\n bgPrimary: v(\"--fp-bg-primary\", \"#0f172a\"),\n bgSecondary: v(\"--fp-bg-secondary\", \"#1e293b\"),\n bgTertiary: v(\"--fp-bg-tertiary\", \"#334155\"),\n textPrimary: v(\"--fp-text-primary\", \"#f8fafc\"),\n textSecondary: v(\"--fp-text-secondary\", \"#94a3b8\"),\n textMuted: v(\"--fp-text-muted\", \"#64748b\"),\n border: v(\"--fp-border\", \"#334155\"),\n radius: v(\"--fp-radius\", \"8px\"),\n fontSans: v(\"--fp-font-sans\", \"Inter, system-ui, -apple-system, sans-serif\"),\n fontMono: v(\"--fp-font-mono\", \"'JetBrains Mono', 'Fira Code', monospace\"),\n} as const;\n\n/** Font sizes per size variant */\nexport const fontSize: Record<Size, { label: number; body: number; small: number }> = {\n compact: { label: 10, body: 11, small: 9 },\n default: { label: 11, body: 12, small: 10 },\n detailed: { label: 12, body: 13, small: 11 },\n};\n\n/** Padding per size variant */\nexport const padding: Record<Size, number> = {\n compact: 8,\n default: 12,\n detailed: 16,\n};\n","/**\n * useDarkModeTokens — Auto-bridge between CSS class-based dark mode and FootprintTheme.\n *\n * Watches for a `.dark` class on <html> (Tailwind convention) and returns\n * the appropriate ThemeTokens preset. Pairs with FootprintTheme:\n *\n * import { FootprintTheme, useDarkModeTokens } from 'footprint-explainable-ui';\n *\n * function MyApp() {\n * const tokens = useDarkModeTokens();\n * return (\n * <FootprintTheme tokens={tokens}>\n * <NarrativeTrace ... />\n * </FootprintTheme>\n * );\n * }\n *\n * Consumers can override the light/dark presets:\n *\n * const tokens = useDarkModeTokens({ light: warmLight, dark: warmDark });\n */\n\nimport { useState, useEffect } from \"react\";\nimport type { ThemeTokens } from \"./tokens\";\nimport { coolDark } from \"./presets\";\nimport { coolLight } from \"./presets\";\n\nexport interface DarkModeTokensOptions {\n /** Tokens to use in light mode. Defaults to coolLight. */\n light?: ThemeTokens;\n /** Tokens to use in dark mode. Defaults to coolDark. */\n dark?: ThemeTokens;\n /** CSS selector to watch for dark mode. Defaults to checking .dark on documentElement. */\n selector?: string;\n}\n\nexport function useDarkModeTokens(options?: DarkModeTokensOptions): ThemeTokens {\n const lightTokens = options?.light ?? coolLight;\n const darkTokens = options?.dark ?? coolDark;\n\n const [isDark, setIsDark] = useState(\n () => document.documentElement.classList.contains(options?.selector ?? \"dark\"),\n );\n\n useEffect(() => {\n const cls = options?.selector ?? \"dark\";\n const obs = new MutationObserver(() => {\n setIsDark(document.documentElement.classList.contains(cls));\n });\n obs.observe(document.documentElement, {\n attributes: true,\n attributeFilter: [\"class\"],\n });\n return () => obs.disconnect();\n }, [options?.selector]);\n\n return isDark ? darkTokens : lightTokens;\n}\n","import { useState } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\nimport { MemoryInspector } from \"../MemoryInspector\";\nimport { NarrativeLog } from \"../NarrativeLog\";\nimport { GanttTimeline } from \"../GanttTimeline\";\nimport { TraceFlow } from \"../FlowchartView/TraceFlow\";\nimport { TracedFlow } from \"../FlowchartView/TracedFlow\";\nimport type { TraceGraph } from \"../FlowchartView/traceStructureRecorder\";\nimport type { RuntimeOverlay } from \"../FlowchartView/createTraceRuntimeOverlay\";\n\nexport interface TimeTravelDebuggerProps extends BaseComponentProps {\n /** Stage snapshots */\n snapshots: StageSnapshot[];\n /** Recorder-captured build-time graph (from\n * `createTraceStructureRecorder().getGraph()`). Required for the\n * chart rendering — replaces the legacy `nodes` / `edges` props. */\n graph: TraceGraph;\n /** Optional runtime overlay (from\n * `createTraceRuntimeOverlay().getOverlay()`). When provided, the\n * chart renders via `<TracedFlow>` with per-step coloring synced to\n * the scrubber; otherwise renders via `<TraceFlow>` (build-time only). */\n runtimeOverlay?: RuntimeOverlay;\n /** Show Gantt timeline */\n showGantt?: boolean;\n /** Layout direction */\n layout?: \"horizontal\" | \"vertical\";\n /** Title */\n title?: string;\n}\n\n/**\n * Full time-travel debugger: scrubber + recorder-driven flowchart +\n * memory + narrative + gantt. This is the \"batteries included\"\n * component for pipeline debugging.\n *\n * v6+: chart rendering is recorder-driven. Pass `graph` (always) and\n * optionally `runtimeOverlay` for per-step coloring tied to the\n * scrubber.\n */\nexport function TimeTravelDebugger({\n snapshots,\n graph,\n runtimeOverlay,\n showGantt = true,\n layout = \"horizontal\",\n title = \"Time-Travel Debugger\",\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: TimeTravelDebuggerProps) {\n const [selectedIndex, setSelectedIndex] = useState(0);\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (snapshots.length === 0) {\n return (\n <div\n className={className}\n style={{\n padding: pad * 2,\n textAlign: \"center\",\n color: theme.textMuted,\n ...style,\n }}\n >\n No snapshots to debug\n </div>\n );\n }\n\n const isHorizontal = layout === \"horizontal\";\n\n // Click → jump scrubber to whichever snapshot maps to the clicked\n // stage. Matches the legacy `onNodeClick(index)` semantics: callers\n // receive a stage id, we translate to a snapshot index.\n const handleNodeClick = (stageId: string) => {\n const idx = snapshots.findIndex(\n (s) => s.stageName === stageId || s.stageLabel === stageId,\n );\n if (idx >= 0) setSelectedIndex(idx);\n };\n\n const chart = runtimeOverlay ? (\n <TracedFlow\n graph={graph}\n overlay={runtimeOverlay}\n scrubIndex={selectedIndex}\n onNodeClick={handleNodeClick}\n />\n ) : (\n <TraceFlow graph={graph} onNodeClick={handleNodeClick} />\n );\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"time-travel-debugger\">\n <h3>{title}</h3>\n <input\n type=\"range\"\n min={0}\n max={snapshots.length - 1}\n value={selectedIndex}\n onChange={(e) => setSelectedIndex(parseInt(e.target.value))}\n />\n {chart}\n <MemoryInspector\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n unstyled\n />\n <NarrativeLog\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n unstyled\n />\n {showGantt && (\n <GanttTimeline\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onSelect={setSelectedIndex}\n unstyled\n />\n )}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n height: \"100%\",\n background: theme.bgPrimary,\n fontFamily: theme.fontSans,\n overflow: \"hidden\",\n ...style,\n }}\n data-fp=\"time-travel-debugger\"\n >\n {/* Scrubber header */}\n <div\n style={{\n padding: `${pad}px ${pad + 4}px`,\n borderBottom: `1px solid ${theme.border}`,\n background: theme.bgSecondary,\n flexShrink: 0,\n }}\n >\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n marginBottom: 8,\n }}\n >\n <span\n style={{\n fontSize: fs.body + 2,\n fontWeight: 600,\n color: theme.textPrimary,\n }}\n >\n {title}\n </span>\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n }}\n >\n Scrub to replay execution\n </span>\n </div>\n <div style={{ display: \"flex\", alignItems: \"center\", gap: 8 }}>\n <ScrubButton\n label=\"◀\"\n disabled={selectedIndex === 0}\n onClick={() => setSelectedIndex((i) => Math.max(0, i - 1))}\n />\n <input\n type=\"range\"\n min={0}\n max={snapshots.length - 1}\n value={selectedIndex}\n onChange={(e) => setSelectedIndex(parseInt(e.target.value))}\n style={{\n flex: 1,\n height: 4,\n accentColor: theme.primary,\n cursor: \"pointer\",\n }}\n />\n <ScrubButton\n label=\"▶\"\n disabled={selectedIndex === snapshots.length - 1}\n onClick={() =>\n setSelectedIndex((i) => Math.min(snapshots.length - 1, i + 1))\n }\n />\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n flexShrink: 0,\n fontFamily: theme.fontMono,\n }}\n >\n {selectedIndex + 1}/{snapshots.length}\n </span>\n </div>\n </div>\n\n {/* Main content: flowchart + data panels */}\n <div\n style={{\n flex: 1,\n display: \"flex\",\n flexDirection: isHorizontal ? \"row\" : \"column\",\n overflow: \"hidden\",\n }}\n >\n {/* Flowchart */}\n <div\n style={{\n flex: 1,\n overflow: \"hidden\",\n borderRight: isHorizontal\n ? `1px solid ${theme.border}`\n : \"none\",\n borderBottom: !isHorizontal\n ? `1px solid ${theme.border}`\n : \"none\",\n }}\n >\n {chart}\n </div>\n\n {/* Data panel */}\n <div style={{ flex: 1, overflow: \"auto\" }}>\n <MemoryInspector\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n size={size}\n />\n <div\n style={{\n height: 1,\n background: theme.border,\n margin: `0 ${pad}px`,\n }}\n />\n <NarrativeLog\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n size={size}\n />\n </div>\n </div>\n\n {/* Gantt footer */}\n {showGantt && (\n <div\n style={{\n borderTop: `1px solid ${theme.border}`,\n background: theme.bgSecondary,\n flexShrink: 0,\n }}\n >\n <GanttTimeline\n snapshots={snapshots}\n selectedIndex={selectedIndex}\n onSelect={setSelectedIndex}\n size={size}\n />\n </div>\n )}\n </div>\n );\n}\n\nfunction ScrubButton({\n label,\n disabled,\n onClick,\n}: {\n label: string;\n disabled: boolean;\n onClick: () => void;\n}) {\n return (\n <button\n onClick={onClick}\n disabled={disabled}\n style={{\n background: theme.bgTertiary,\n border: `1px solid ${theme.border}`,\n color: disabled ? theme.textMuted : theme.textPrimary,\n borderRadius: 6,\n width: 28,\n height: 28,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n cursor: disabled ? \"not-allowed\" : \"pointer\",\n opacity: disabled ? 0.5 : 1,\n fontSize: 12,\n flexShrink: 0,\n }}\n >\n {label}\n </button>\n );\n}\n","import { useMemo, useRef } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface MemoryInspectorProps extends BaseComponentProps {\n /** Single memory object or snapshots (will accumulate up to selectedIndex) */\n data?: Record<string, unknown>;\n /** When using snapshots mode, pass these instead of data */\n snapshots?: StageSnapshot[];\n /** Index to accumulate up to (for time-travel) */\n selectedIndex?: number;\n /** Show data types alongside values */\n showTypes?: boolean;\n /** Highlight keys that are new at this step */\n highlightNew?: boolean;\n}\n\n/** Cache for incremental memory accumulation — avoids O(n) rebuild on every slider scrub. */\ninterface MemoryCache {\n snapshots: StageSnapshot[];\n index: number;\n accumulated: Record<string, unknown>;\n}\n\n/**\n * Displays pipeline memory state as formatted JSON.\n * Supports both static (data prop) and time-travel (snapshots + selectedIndex) modes.\n */\nexport function MemoryInspector({\n data,\n snapshots,\n selectedIndex = 0,\n showTypes = false,\n highlightNew = true,\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: MemoryInspectorProps) {\n // Incremental cache: accumulate forward from last known index instead of rebuilding from 0\n const cacheRef = useRef<MemoryCache | null>(null);\n\n const { memory, newKeys } = useMemo(() => {\n if (data) {\n return { memory: data, newKeys: new Set<string>() };\n }\n if (!snapshots || snapshots.length === 0) {\n return { memory: {}, newKeys: new Set<string>() };\n }\n\n const safeIdx = Math.min(selectedIndex, snapshots.length - 1);\n let merged: Record<string, unknown>;\n const cache = cacheRef.current;\n\n if (cache && cache.snapshots === snapshots && cache.index <= safeIdx) {\n // Forward scrub: extend from cached state\n merged = { ...cache.accumulated };\n for (let i = cache.index + 1; i <= safeIdx; i++) {\n Object.assign(merged, snapshots[i]?.memory);\n }\n } else {\n // Backward scrub or new snapshots: rebuild from scratch\n merged = {};\n for (let i = 0; i <= safeIdx; i++) {\n Object.assign(merged, snapshots[i]?.memory);\n }\n }\n\n // Update cache\n cacheRef.current = { snapshots, index: safeIdx, accumulated: merged };\n\n const nk = new Set<string>();\n if (highlightNew && safeIdx > 0) {\n // Previous state is cache at safeIdx-1, or rebuild if needed\n let prev: Record<string, unknown>;\n if (cache && cache.snapshots === snapshots && cache.index === safeIdx - 1) {\n prev = cache.accumulated;\n } else {\n prev = {};\n for (let i = 0; i < safeIdx; i++) {\n Object.assign(prev, snapshots[i]?.memory);\n }\n }\n const current = snapshots[safeIdx]?.memory ?? {};\n for (const k of Object.keys(current)) {\n if (!(k in prev)) nk.add(k);\n }\n } else if (highlightNew && safeIdx === 0 && snapshots[0]) {\n for (const k of Object.keys(snapshots[0].memory)) nk.add(k);\n }\n\n return { memory: merged, newKeys: nk };\n }, [data, snapshots, selectedIndex, highlightNew]);\n\n const entries = Object.entries(memory);\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"memory-inspector\" role=\"region\" aria-label=\"Memory state\">\n <div data-fp=\"memory-label\">Memory State</div>\n <pre data-fp=\"memory-json\">\n <code>{JSON.stringify(memory, null, 2)}</code>\n </pre>\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: pad,\n fontFamily: theme.fontSans,\n ...style,\n }}\n data-fp=\"memory-inspector\"\n role=\"region\"\n aria-label=\"Memory state\"\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n Memory State\n </span>\n <div\n style={{\n marginTop: 8,\n background: theme.bgSecondary,\n border: `1px solid ${theme.border}`,\n borderRadius: theme.radius,\n padding: `${pad}px ${pad + 4}px`,\n fontFamily: theme.fontMono,\n fontSize: fs.body,\n lineHeight: 1.8,\n }}\n >\n <span style={{ color: theme.textMuted }}>{\"{\"}</span>\n {entries.length === 0 && (\n <div\n style={{\n paddingLeft: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n }}\n >\n {\"// empty\"}\n </div>\n )}\n {entries.map(([key, value], i) => {\n const isNew = newKeys.has(key);\n const isLast = i === entries.length - 1;\n return (\n <div\n key={key}\n style={{\n paddingLeft: 16,\n background: isNew\n ? `color-mix(in srgb, ${theme.success} 10%, transparent)`\n : \"transparent\",\n borderRadius: 4,\n marginLeft: -4,\n marginRight: -4,\n paddingRight: 4,\n }}\n >\n <span style={{ color: theme.primary }}>&quot;{key}&quot;</span>\n <span style={{ color: theme.textMuted }}>: </span>\n <span style={{ color: theme.success }}>\n {formatValue(value)}\n </span>\n {showTypes && (\n <span\n style={{\n color: theme.textMuted,\n fontSize: fs.small,\n marginLeft: 8,\n opacity: 0.6,\n }}\n >\n ({typeof value})\n </span>\n )}\n {!isLast && <span style={{ color: theme.textMuted }}>,</span>}\n </div>\n );\n })}\n <span style={{ color: theme.textMuted }}>{\"}\"}</span>\n </div>\n </div>\n );\n}\n\nfunction formatValue(value: unknown): string {\n if (typeof value === \"string\") return `\"${value}\"`;\n if (typeof value === \"object\" && value !== null) return JSON.stringify(value);\n return String(value);\n}\n","import { useMemo } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface NarrativeLogProps extends BaseComponentProps {\n /** Snapshots to display narratives from */\n snapshots: StageSnapshot[];\n /** Show narratives up to this index (for time-travel sync) */\n selectedIndex?: number;\n /** Show a single narrative string (simple mode) */\n narrative?: string;\n}\n\n/**\n * Timeline-style execution log showing what happened at each stage.\n * Supports both full snapshots mode and single-narrative mode.\n */\nexport function NarrativeLog({\n snapshots,\n selectedIndex,\n narrative,\n size = \"default\",\n unstyled = false,\n className,\n style,\n}: NarrativeLogProps) {\n const entries = useMemo(() => {\n if (narrative) {\n return [{ label: \"Output\", text: narrative, isCurrent: true }];\n }\n const idx = selectedIndex ?? snapshots.length - 1;\n return snapshots.slice(0, idx + 1).map((s, i) => ({\n label: s.stageLabel,\n text: s.narrative,\n isCurrent: i === idx,\n }));\n }, [snapshots, selectedIndex, narrative]);\n\n const fs = fontSize[size];\n const pad = padding[size];\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"narrative-log\">\n {entries.map((entry, i) => (\n <div key={i} data-fp=\"narrative-entry\" data-current={entry.isCurrent}>\n <strong>{entry.label}</strong>\n <p>{entry.text}</p>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{ padding: pad, fontFamily: theme.fontSans, ...style }}\n data-fp=\"narrative-log\"\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n Execution Log\n </span>\n <div style={{ marginTop: 8, display: \"flex\", flexDirection: \"column\" }}>\n {entries.map((entry, i) => (\n <div\n key={i}\n style={{\n display: \"flex\",\n gap: 10,\n padding: `${pad}px 0`,\n borderBottom:\n i < entries.length - 1 ? `1px solid ${theme.border}` : \"none\",\n }}\n >\n {/* Timeline dot + line */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n width: 12,\n flexShrink: 0,\n paddingTop: 5,\n }}\n >\n <div\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: entry.isCurrent ? theme.primary : theme.success,\n flexShrink: 0,\n }}\n />\n {i < entries.length - 1 && (\n <div\n style={{\n width: 1,\n flex: 1,\n background: theme.border,\n marginTop: 4,\n }}\n />\n )}\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, minWidth: 0 }}>\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: entry.isCurrent ? theme.primary : theme.textMuted,\n }}\n >\n {entry.label}\n </span>\n <div\n style={{\n fontSize: fs.body,\n lineHeight: 1.5,\n color: entry.isCurrent ? theme.textPrimary : theme.textSecondary,\n marginTop: 2,\n }}\n >\n {entry.text}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n","import { useState, useMemo, useRef, useEffect } from \"react\";\nimport type { StageSnapshot, BaseComponentProps } from \"../../types\";\nimport { theme, fontSize, padding } from \"../../theme\";\n\nexport interface GanttTimelineProps extends BaseComponentProps {\n /** Stage snapshots with timing info */\n snapshots: StageSnapshot[];\n /** Currently selected stage index */\n selectedIndex?: number;\n /** Callback when a stage bar is clicked */\n onSelect?: (index: number) => void;\n /** Max visible rows before collapsing (0 = no collapse). Default: 5 */\n maxVisibleRows?: number;\n}\n\n/**\n * Horizontal Gantt-style timeline showing stage durations and overlap.\n * Collapses to `maxVisibleRows` with expand/collapse toggle.\n * Auto-scrolls to keep the active stage visible when collapsed.\n */\nexport function GanttTimeline({\n snapshots,\n selectedIndex = 0,\n onSelect,\n size = \"default\",\n unstyled = false,\n className,\n style,\n maxVisibleRows = 5,\n}: GanttTimelineProps) {\n const [expanded, setExpanded] = useState(false);\n const activeRowRef = useRef<HTMLDivElement | null>(null);\n const scrollContainerRef = useRef<HTMLDivElement | null>(null);\n\n const totalWallTime = useMemo(\n () => Math.max(...snapshots.map((s) => s.startMs + s.durationMs), 1),\n [snapshots]\n );\n\n const fs = fontSize[size];\n const pad = padding[size];\n const labelWidth = size === \"compact\" ? 50 : size === \"detailed\" ? 100 : 80;\n const msWidth = size === \"compact\" ? 28 : 36;\n const rowHeight = size === \"compact\" ? 18 : 22;\n\n const collapsible = maxVisibleRows > 0 && snapshots.length > maxVisibleRows;\n const showAll = expanded || !collapsible;\n\n // Auto-scroll to active row when collapsed\n useEffect(() => {\n if (!showAll && activeRowRef.current && scrollContainerRef.current) {\n activeRowRef.current.scrollIntoView({\n block: \"nearest\",\n behavior: \"smooth\",\n });\n }\n }, [selectedIndex, showAll]);\n\n if (unstyled) {\n return (\n <div className={className} style={style} data-fp=\"gantt-timeline\" role=\"listbox\" aria-label=\"Execution timeline\">\n {snapshots.map((snap, idx) => (\n <div\n key={`${snap.stageName}-${idx}`}\n data-fp=\"gantt-bar\"\n data-selected={idx === selectedIndex}\n data-visible={idx <= selectedIndex}\n role=\"option\"\n aria-selected={idx === selectedIndex}\n aria-label={`${snap.stageLabel}, ${snap.durationMs}ms`}\n onClick={() => onSelect?.(idx)}\n >\n <span data-fp=\"gantt-label\">{snap.stageLabel}</span>\n <span data-fp=\"gantt-duration\">{snap.durationMs}ms</span>\n </div>\n ))}\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{ padding: pad, fontFamily: theme.fontSans, ...style }}\n data-fp=\"gantt-timeline\"\n >\n {/* Header with collapse toggle */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <span\n style={{\n fontSize: fs.label,\n fontWeight: 600,\n color: theme.textMuted,\n textTransform: \"uppercase\",\n letterSpacing: \"0.08em\",\n }}\n >\n {size === \"compact\" ? \"Timeline\" : \"Execution Timeline\"}\n </span>\n {collapsible && (\n <button\n onClick={() => setExpanded((e) => !e)}\n style={{\n background: \"none\",\n border: `1px solid ${theme.border}`,\n borderRadius: 4,\n color: theme.textSecondary,\n fontSize: fs.small,\n padding: \"2px 8px\",\n cursor: \"pointer\",\n fontFamily: theme.fontSans,\n }}\n >\n {expanded\n ? \"Collapse\"\n : `${snapshots.length - maxVisibleRows} more...`}\n </button>\n )}\n </div>\n\n {/* Scrollable rows container */}\n <div\n ref={scrollContainerRef}\n role=\"listbox\"\n aria-label=\"Execution timeline\"\n style={{\n marginTop: 8,\n display: \"flex\",\n flexDirection: \"column\",\n gap: 4,\n ...(showAll\n ? {}\n : {\n maxHeight: maxVisibleRows * (rowHeight + 4),\n overflowY: \"auto\",\n scrollbarWidth: \"thin\",\n }),\n }}\n >\n {snapshots.map((snap, idx) => {\n const leftPct = (snap.startMs / totalWallTime) * 100;\n const widthPct = Math.max((snap.durationMs / totalWallTime) * 100, 1);\n const isSelected = idx === selectedIndex;\n const isVisible = idx <= selectedIndex;\n\n return (\n <div\n key={`${snap.stageName}-${idx}`}\n ref={isSelected ? activeRowRef : undefined}\n role=\"option\"\n aria-selected={isSelected}\n aria-label={`${snap.stageLabel}, ${snap.durationMs}ms`}\n onClick={() => onSelect?.(idx)}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: size === \"compact\" ? 4 : 8,\n cursor: onSelect ? \"pointer\" : \"default\",\n opacity: isVisible ? 1 : 0.3,\n transition: \"opacity 0.3s ease\",\n height: rowHeight,\n flexShrink: 0,\n }}\n >\n <span\n title={snap.stageLabel}\n style={{\n width: labelWidth,\n fontSize: fs.small,\n color: isSelected ? theme.primary : theme.textMuted,\n fontWeight: isSelected ? 600 : 400,\n textAlign: \"right\",\n flexShrink: 0,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {snap.stageLabel}\n </span>\n <div\n style={{\n flex: 1,\n height: size === \"compact\" ? 6 : 8,\n position: \"relative\",\n background: theme.bgTertiary,\n borderRadius: 3,\n }}\n >\n {isVisible && (\n <div\n style={{\n position: \"absolute\",\n left: `${leftPct}%`,\n top: 0,\n width: `${widthPct}%`,\n height: \"100%\",\n borderRadius: 3,\n background: isSelected ? theme.primary : theme.success,\n transition: \"width 0.3s ease\",\n }}\n />\n )}\n </div>\n <span\n style={{\n fontSize: fs.small,\n color: theme.textMuted,\n fontFamily: theme.fontMono,\n width: msWidth,\n flexShrink: 0,\n }}\n >\n {snap.durationMs}ms\n </span>\n </div>\n );\n })}\n </div>\n\n {/* Time axis */}\n <div\n style={{\n marginTop: 4,\n marginLeft: labelWidth + (size === \"compact\" ? 4 : 8),\n marginRight: msWidth + (size === \"compact\" ? 4 : 8),\n display: \"flex\",\n justifyContent: \"space-between\",\n fontSize: fs.small - 1,\n color: theme.textMuted,\n fontFamily: theme.fontMono,\n }}\n >\n <span>0ms</span>\n {size !== \"compact\" && (\n <span>{(totalWallTime / 2).toFixed(1)}ms</span>\n )}\n <span>{totalWallTime.toFixed(1)}ms</span>\n </div>\n </div>\n );\n}\n","/**\n * TraceFlow — ReactFlow renderer driven by `createTraceStructureRecorder`.\n *\n * Two input modes (mutually exclusive):\n *\n * 1. **Live mode**: pass `recorder={traceHandle}`. The component\n * subscribes via `useSyncExternalStore` to the recorder's\n * pub-sub `subscribe()` API and re-renders as the builder runs.\n * Ideal for incremental visualisation (Lens-style live chart\n * construction).\n *\n * 2. **Static mode**: pass `graph={{ nodes, edges }}`. The component\n * treats the graph as final and renders once. Ideal for post-build\n * snapshots (Trace tab, docs site).\n *\n * Layout is pluggable:\n *\n * - Pass a `layout` function `(graph) => positioned graph`. Default is\n * a simple BFS tree walk (Y_STEP=100, X_SPREAD=200).\n * - Pass the literal `\"passthrough\"` to skip layout when nodes are\n * already pre-positioned by the caller.\n *\n * @example\n * ```tsx\n * import { createTraceStructureRecorder, TraceFlow } from 'footprint-explainable-ui/flowchart';\n * import { flowChart } from 'footprintjs';\n *\n * function MyTraceUI() {\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * useEffect(() => {\n * flowChart('seed', fn, 'seed', {\n * structureRecorders: [trace.recorder],\n * }).addFunction('a', fnA, 'a').build();\n * }, [trace]);\n * return <TraceFlow recorder={trace} />;\n * }\n * ```\n */\n\nimport type * as React from \"react\";\nimport { useMemo, useCallback, useSyncExternalStore } from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n MarkerType,\n} from \"@xyflow/react\";\nimport type { Node, Edge, NodeTypes, EdgeTypes } from \"@xyflow/react\";\nimport type {\n TraceGraph,\n TraceNode,\n TraceEdge,\n TraceStructureRecorderHandle,\n} from \"./traceStructureRecorder\";\nimport { StageNode } from \"../StageNode\";\nimport type { StageNodeData } from \"../StageNode\";\nimport { LoopBackEdge } from \"../LoopBackEdge\";\nimport { SmartStepEdge } from \"../SmartStepEdge\";\nimport { rawDefaults } from \"../../theme/tokens\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { dagreTraceLayout } from \"./_internal/dagreTraceLayout\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Layout\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst Y_STEP = 100;\nconst X_SPREAD = 200;\n\n/** Layout function shape — takes a graph, returns a graph with positions set. */\nexport type TraceFlowLayout = (graph: TraceGraph) => TraceGraph;\n\n/**\n * Default tree-walk layout.\n *\n * Edge-kind semantics (critical for parity)\n * ─────────────────────────────────────────\n * `fork-branch` + `decision-branch` edges are SIBLINGS at depth+1\n * (centered under the parent). A `next` edge from a node that ALSO\n * has branch edges is the \"after convergence\" target — its rank is\n * `max(deepest branch subtree) + 1`, so it sits BELOW the fan-out,\n * matching the legacy diamond layout.\n *\n * LoadOrder (fork)\n * ├── fork-branch → CheckInventory (sibling, y+1)\n * ├── fork-branch → RunFraudCheck (sibling, y+1)\n * └── next → FinalizeOrder (after convergence,\n * below deepest sibling)\n *\n * A `next` edge from a node with NO branch edges is a plain linear\n * chain — target at depth+1.\n *\n * `loop` back-edges DO NOT shape layout (they're scrub-time visual\n * markers only).\n *\n * Limitations (documented; not bugs)\n * ──────────────────────────────────\n * - Multi-root graphs render with the first-seen node as the visual\n * root; orphans stack below.\n * - Convergence where multiple branches join into a single node:\n * the node is placed under its FIRST traversed branch (first-wins).\n * For deep DAGs swap in a graph-layout library (dagre, elk).\n * - Sibling x-positions are local to each parent's subtree; no\n * global x-overlap detection across deep nested structures.\n */\nexport const defaultTraceFlowLayout: TraceFlowLayout = (graph) => {\n if (graph.nodes.length === 0) return { nodes: [], edges: graph.edges };\n\n // Split outgoing edges into two semantic groups per node:\n // - branches: fork-branch + decision-branch (siblings at y+1)\n // - linearNext: 'next' edges (after-convergence, deeper rank)\n // Loop back-edges (kind: 'loop') do NOT shape layout.\n const branchChildrenOf = new Map<string, string[]>();\n const nextChildrenOf = new Map<string, string[]>();\n const hasIncomingForward = new Set<string>();\n for (const e of graph.edges) {\n const kind = e.data?.kind;\n if (kind === \"loop\") continue;\n hasIncomingForward.add(e.target);\n if (kind === \"fork-branch\" || kind === \"decision-branch\") {\n const arr = branchChildrenOf.get(e.source) ?? [];\n arr.push(e.target);\n branchChildrenOf.set(e.source, arr);\n } else {\n // 'next' (default) — linear continuation. Treat undefined kind\n // as 'next' so forward edges without explicit kind still flow.\n const arr = nextChildrenOf.get(e.source) ?? [];\n arr.push(e.target);\n nextChildrenOf.set(e.source, arr);\n }\n }\n\n // Seed: first node (insertion order) with no incoming non-loop edge.\n const seed = graph.nodes.find((n) => !hasIncomingForward.has(n.id)) ?? graph.nodes[0]!;\n\n const positions = new Map<string, { x: number; y: number }>();\n\n /**\n * Recursive tree-walk. Returns the bottom-most y reached in this\n * subtree so the parent can position its `next` continuation BELOW\n * the deepest descendant (post-convergence semantics).\n */\n function layoutSubtree(nodeId: string, x: number, y: number): number {\n if (positions.has(nodeId)) {\n // Convergence: this node was already placed by an earlier branch.\n // Keep the original position (first-wins) and report its current\n // bottom so the caller's `next` target lands below us correctly.\n return positions.get(nodeId)!.y;\n }\n positions.set(nodeId, { x, y });\n\n // Place fork/decision branches first — they're siblings at y+1.\n let deepestBranchY = y;\n const branches = branchChildrenOf.get(nodeId) ?? [];\n if (branches.length > 0) {\n const childY = y + Y_STEP;\n const totalWidth = (branches.length - 1) * X_SPREAD;\n const startX = x - totalWidth / 2;\n for (let i = 0; i < branches.length; i++) {\n const childId = branches[i]!;\n const childX = startX + i * X_SPREAD;\n const subtreeBottom = layoutSubtree(childId, childX, childY);\n if (subtreeBottom > deepestBranchY) deepestBranchY = subtreeBottom;\n }\n }\n\n // Then place `next` continuations. If branches exist, `next` lands\n // BELOW the deepest branch (post-convergence). If no branches, it's\n // a plain linear chain — y+1.\n const nextChildren = nextChildrenOf.get(nodeId) ?? [];\n if (nextChildren.length > 0) {\n const nextY = branches.length > 0 ? deepestBranchY + Y_STEP : y + Y_STEP;\n // Multiple `next` from one node is rare (linear chains have one);\n // when it happens, distribute horizontally like branches.\n const totalWidth = (nextChildren.length - 1) * X_SPREAD;\n const startX = x - totalWidth / 2;\n let deepestNextY = nextY;\n for (let i = 0; i < nextChildren.length; i++) {\n const childId = nextChildren[i]!;\n const childX = startX + i * X_SPREAD;\n const subtreeBottom = layoutSubtree(childId, childX, nextY);\n if (subtreeBottom > deepestNextY) deepestNextY = subtreeBottom;\n }\n return deepestNextY;\n }\n\n return deepestBranchY;\n }\n\n layoutSubtree(seed.id, 0, 0);\n\n // Unreached nodes (multi-root or cycles outside the seed's tree)\n // stack below. Use a loop (not `Math.max(...spread)`) — spread\n // blows the call stack at ~10k+ args.\n let maxY = 0;\n for (const p of positions.values()) {\n if (p.y > maxY) maxY = p.y;\n }\n let orphanY = maxY + Y_STEP;\n for (const n of graph.nodes) {\n if (!positions.has(n.id)) {\n positions.set(n.id, { x: 0, y: orphanY });\n orphanY += Y_STEP;\n }\n }\n\n return {\n nodes: graph.nodes.map((n) => ({\n ...n,\n position: positions.get(n.id) ?? n.position,\n })),\n edges: graph.edges,\n };\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Edge styling\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceFlowEdgeColors {\n next: string;\n forkBranch: string;\n decisionBranch: string;\n loop: string;\n}\n\nconst DEFAULT_EDGE_COLORS: TraceFlowEdgeColors = {\n next: rawDefaults.colors.textMuted,\n forkBranch: rawDefaults.colors.textMuted,\n decisionBranch: rawDefaults.colors.primary,\n loop: rawDefaults.colors.warning,\n};\n\nfunction styleEdge(edge: TraceEdge, colors: TraceFlowEdgeColors): Edge {\n const kind = edge.data?.kind ?? \"next\";\n const color =\n kind === \"loop\"\n ? colors.loop\n : kind === \"fork-branch\"\n ? colors.forkBranch\n : kind === \"decision-branch\"\n ? colors.decisionBranch\n : colors.next;\n const styled: Edge = {\n ...edge,\n // Loop back-edges use the custom `loopBack` edge — a curve routed along the\n // right margin (clear of the spine) instead of a straight/step center line.\n // Every other edge uses `smartStep`: a smoothstep superset that routes a\n // RANK-SKIPPING edge around the node it skips (else identical to smoothstep).\n type: kind === \"loop\" ? \"loopBack\" : \"smartStep\",\n animated: false,\n style: { stroke: color, strokeWidth: 1.5 },\n markerEnd: { type: MarkerType.ArrowClosed, color, width: 16, height: 16 },\n };\n if (kind === \"loop\") {\n styled.style = { ...styled.style, strokeDasharray: \"4 3\" };\n }\n return styled;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\ntype TraceFlowSource =\n | { recorder: TraceStructureRecorderHandle; graph?: never }\n | { graph: TraceGraph; recorder?: never };\n\nexport type TraceFlowProps = BaseComponentProps &\n TraceFlowSource & {\n /** Layout function. Default: BFS tree walk. Pass the literal\n * `\"passthrough\"` to skip layout when nodes already carry positions. */\n layout?: TraceFlowLayout | \"passthrough\";\n /** Per-kind edge color overrides. */\n edgeColors?: Partial<TraceFlowEdgeColors>;\n /** Node click handler — receives the node id. */\n onNodeClick?: (id: string) => void;\n /**\n * Consumer-supplied xyflow node types. Merged with the built-in\n * `{ stageNode: StageNode }` registry — keys you supply OVERRIDE\n * the default for that node type. Pass `{ stageNode: MyNode }` to\n * replace the default stage renderer entirely, or add new keys\n * for nodes you build yourself (any nodes you push into the\n * graph with `type: 'customKey'` will use your component).\n */\n nodeTypes?: NodeTypes;\n /**\n * Consumer-supplied xyflow edge types. Merged with no built-in\n * defaults — pass `{ myEdge: MyEdge }` to register custom edge\n * components for nodes/edges you build with `type: 'myEdge'`.\n */\n edgeTypes?: EdgeTypes;\n /**\n * Children rendered INSIDE the `<ReactFlow>` element, after the\n * built-in `<Background>`. Use this slot to mount xyflow\n * accessory components like `<Controls />`, `<MiniMap />`, or a\n * custom legend. If unset, only the default Background is rendered.\n *\n * @example\n * ```tsx\n * import { Controls, MiniMap } from '@xyflow/react';\n * <TraceFlow recorder={r}>\n * <Controls />\n * <MiniMap />\n * </TraceFlow>\n * ```\n */\n children?: React.ReactNode;\n };\n\nconst DEFAULT_NODE_TYPES: NodeTypes = { stageNode: StageNode };\n\n// Built-in edge types. `loopBack` curves loop-back edges along the right margin\n// (see LoopBackEdge). Always registered so every consumer gets the curve;\n// merged UNDER any consumer-supplied `edgeTypes` (consumer keys win).\nconst DEFAULT_EDGE_TYPES: EdgeTypes = { loopBack: LoopBackEdge, smartStep: SmartStepEdge };\n\n/**\n * Convert a `TraceNode` (with `TraceNodeData`) to the `StageNode`-typed\n * node shape so the built-in `<StageNode>` renderer works.\n *\n * Pass-through contract: if the consumer pushed a node with a custom\n * `type` (anything OTHER than the recorder's default `'stage'`), this\n * function returns the node UNCHANGED so xyflow's `nodeTypes` lookup\n * sees the consumer's chosen key. This is what makes the `nodeTypes`\n * extension point useful — without it every node would be force-typed\n * to `'stageNode'` and consumer registrations would never route.\n */\nfunction toStageNode(node: TraceNode): Node {\n // Consumer-supplied custom type — pass through unchanged.\n // Recorders produce nodes with `type: 'stage'` (the recorder's\n // default); anything else is consumer-authored and must be respected.\n if (node.type !== undefined && node.type !== \"stage\") {\n return node as Node;\n }\n\n const data = node.data;\n const stageData: StageNodeData = {\n label: data.label,\n isDecider: data.isDecider,\n isFork: data.isFork,\n isSubflow: data.isSubflow,\n active: false,\n done: false,\n error: false,\n ...(data.description !== undefined && { description: data.description }),\n ...(data.icon !== undefined && { icon: data.icon }),\n ...(data.subflowId !== undefined && { subflowId: data.subflowId }),\n ...(data.isLazy === true && { isLazy: true }),\n ...(data.emphasis !== undefined && { emphasis: data.emphasis }),\n ...(data.size !== undefined && { size: data.size }),\n };\n return {\n ...node,\n type: \"stageNode\",\n data: stageData as unknown as Record<string, unknown>,\n };\n}\n\n// Empty-graph sentinel returned by static-mode getSnapshot when no\n// graph or recorder is present. Module-scoped so React's identity check\n// sees a stable reference across renders.\nconst EMPTY_GRAPH: TraceGraph = { nodes: [], edges: [] };\n\n// ── Subscription helpers (defined at module scope so useSyncExternalStore\n// sees stable function references when the recorder doesn't change) ─\n\nfunction subscribeToRecorder(recorder: TraceStructureRecorderHandle | undefined) {\n return (listener: () => void): (() => void) => {\n if (!recorder) return () => {};\n return recorder.subscribe(listener);\n };\n}\n\nfunction getRecorderVersion(recorder: TraceStructureRecorderHandle | undefined) {\n return (): number => {\n if (!recorder) return 0;\n return recorder.version();\n };\n}\n\nexport function TraceFlow(props: TraceFlowProps) {\n // Dev-mode contract check — TypeScript enforces the discriminated union\n // at compile time, but JS consumers (or `as any` casts) can hit this.\n const proc = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n const isDev = proc?.env?.NODE_ENV !== \"production\";\n if (isDev && !props.recorder && !props.graph) {\n // eslint-disable-next-line no-console\n console.warn(\n \"[TraceFlow] neither `recorder` nor `graph` prop was provided — rendering an empty chart. Pass one of: <TraceFlow recorder={handle} /> OR <TraceFlow graph={{nodes, edges}} />.\",\n );\n }\n\n // Dagre is the default — structure-derived spacing (fork fan-out by subtree\n // width, rank-depth ranking, centered merges). Pass `layout` to override\n // (e.g. the legacy `defaultTraceFlowLayout` BFS, or `\"passthrough\"`).\n const layout = props.layout ?? dagreTraceLayout;\n const edgeColors = useMemo<TraceFlowEdgeColors>(\n () => ({ ...DEFAULT_EDGE_COLORS, ...(props.edgeColors ?? {}) }),\n [props.edgeColors],\n );\n\n // Subscribe to the version counter (live mode) — equality-by-number\n // means React only re-renders when the recorder actually mutated.\n // Memoize the subscribe + getSnapshot closures by the recorder\n // identity so useSyncExternalStore doesn't re-subscribe each render.\n const subscribe = useMemo(\n () => subscribeToRecorder(props.recorder),\n [props.recorder],\n );\n const getVersion = useMemo(\n () => getRecorderVersion(props.recorder),\n [props.recorder],\n );\n const version = useSyncExternalStore(subscribe, getVersion, getVersion);\n\n // Resolve graph: live (recorder) vs static (prop). The version\n // dependency drives re-evaluation in live mode; static mode falls\n // through to the prop's identity on each render.\n const { recorder, graph: graphProp } = props;\n const graph: TraceGraph = useMemo<TraceGraph>(() => {\n if (recorder) return recorder.getGraph();\n if (graphProp) return graphProp;\n return EMPTY_GRAPH;\n }, [recorder, graphProp, version]);\n\n const positioned = useMemo<TraceGraph>(() => {\n if (layout === \"passthrough\") return graph;\n return layout(graph);\n }, [graph, layout]);\n\n const reactFlowNodes = useMemo<Node[]>(\n () => positioned.nodes.map(toStageNode),\n [positioned.nodes],\n );\n const reactFlowEdges = useMemo<Edge[]>(\n () => positioned.edges.map((e) => styleEdge(e, edgeColors)),\n [positioned.edges, edgeColors],\n );\n\n const onNodeClickRef = props.onNodeClick;\n const handleNodeClick = useCallback(\n (_: unknown, node: Node) => {\n onNodeClickRef?.(node.id);\n },\n [onNodeClickRef],\n );\n\n const { nodeTypes: userNodeTypes, edgeTypes: userEdgeTypes } = props;\n const mergedNodeTypes = useMemo<NodeTypes>(\n () => (userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES),\n [userNodeTypes],\n );\n const mergedEdgeTypes = useMemo<EdgeTypes>(\n () => (userEdgeTypes ? { ...DEFAULT_EDGE_TYPES, ...userEdgeTypes } : DEFAULT_EDGE_TYPES),\n [userEdgeTypes],\n );\n\n return (\n <div\n className={props.className}\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 300,\n ...props.style,\n }}\n >\n <ReactFlow\n nodes={reactFlowNodes}\n edges={reactFlowEdges}\n nodeTypes={mergedNodeTypes}\n edgeTypes={mergedEdgeTypes}\n onNodeClick={handleNodeClick}\n fitView\n proOptions={{ hideAttribution: true }}\n >\n <Background variant={BackgroundVariant.Dots} gap={20} size={1} />\n {props.children}\n </ReactFlow>\n </div>\n );\n}\n","/**\n * LoopBackEdge — xyflow custom edge for `loopTo` back-edges, routed as a\n * CURVE along the chart's right margin instead of straight down the spine.\n *\n * WHY a custom edge (not handle-based side-routing): the prior approach asked\n * every node type to declare dedicated `loop-source` / `loop-target` handles;\n * any node missing them (custom consumer nodes, group boxes, slot pills)\n * silently fell back to the default top/bottom handles and the loop collapsed\n * back onto the spine. This component sidesteps handles entirely: it reads the\n * source/target node bounds straight from the xyflow store, anchors on their\n * RIGHT edges, and bows out to a shared lane clear of every content node. It\n * therefore works for ANY node type with zero per-node wiring — register it\n * once and every loop curves.\n *\n * The math lives in `_internal/loopRouting` (pure, unit-tested); this is the\n * thin React adapter. `style` (stroke color + dash) and `markerEnd` (arrow)\n * flow through from the renderer's edge styler unchanged.\n */\n\nimport { BaseEdge, useStore } from \"@xyflow/react\";\nimport type { CSSProperties } from \"react\";\nimport type { EdgeProps, InternalNode, ReactFlowState } from \"@xyflow/react\";\nimport { LOOP_LANE_GAP, loopBackPath, loopLaneX } from \"../FlowchartView/_internal/loopRouting\";\nimport { GROUP_CONTAINER_NODE_TYPE } from \"../FlowchartView/_internal/groupLayout\";\n\n/** A loop-back spans the whole chart height down the right margin, so a SOLID\n * line at full weight reads as a wall. We soften it — dashed + slightly muted —\n * so it registers as a \"control returns to the top\" path, not a hard edge.\n * The renderer's color/state still flows through `style`; we only ADD the dash\n * and CAP the opacity (never brighter than `softCap`, but free to dim further\n * when the edge is out of the current scrub scope). */\nconst LOOP_DASH = \"5 5\";\nconst LOOP_STROKE_OPACITY_CAP = 0.55; // muted — the long return shouldn't dominate\nconst LOOP_STROKE_WIDTH = 1.5; // thinner than a spine edge (default ~2)\nexport function softenLoopStyle(style: CSSProperties | undefined): CSSProperties {\n // Use SVG-native stroke props (strokeOpacity / strokeWidth) — they render on\n // the <path> reliably, unlike `opacity` which react-flow's BaseEdge does not\n // forward to the stroke. strokeOpacity is CAPPED (never bolder than the cap)\n // but may go lower when the renderer dims an out-of-scope edge.\n const passedStrokeOpacity =\n typeof style?.strokeOpacity === \"number\" ? style.strokeOpacity : 1;\n return {\n ...style,\n strokeDasharray: style?.strokeDasharray ?? LOOP_DASH,\n strokeOpacity: Math.min(passedStrokeOpacity, LOOP_STROKE_OPACITY_CAP),\n strokeWidth: LOOP_STROKE_WIDTH,\n };\n}\n\n/** Slightly larger corner radius than a normal step edge — a gentler, rounder\n * arc reinforces the \"soft return\" read. */\nconst LOOP_CORNER_RADIUS = 28;\n\n/** Absolute x of a node's right edge. */\nfunction rightEdge(node: InternalNode): number {\n return node.internals.positionAbsolute.x + (node.measured.width ?? 0);\n}\n\n/** Absolute y of a node's vertical center. */\nfunction centerY(node: InternalNode): number {\n return node.internals.positionAbsolute.y + (node.measured.height ?? 0) / 2;\n}\n\nexport function LoopBackEdge({ id, source, target, markerEnd, style }: EdgeProps) {\n // Derive the full SVG path inside the store selector and return it as a\n // STRING — primitive equality means the edge only re-renders when its\n // geometry actually changes (no per-tick churn, no render loop).\n const path = useStore((s: ReactFlowState) => {\n const src = s.nodeLookup.get(source);\n const tgt = s.nodeLookup.get(target);\n if (!src || !tgt) return \"\";\n\n // Lane sits right of every CONTENT node. Group containers (the frame box\n // itself) are excluded — the box spans the whole chart, so counting it\n // would always push the lane outside its own border.\n const contentRights: number[] = [];\n for (const n of s.nodeLookup.values()) {\n if (n.type === GROUP_CONTAINER_NODE_TYPE) continue;\n contentRights.push(rightEdge(n));\n }\n // Add the endpoints explicitly: when source or target IS a group container\n // (a loop into/out of a box), the loop above skipped it, so include its\n // right edge here so the lane still clears the endpoint. For ordinary\n // (content) endpoints this is a harmless duplicate — loopLaneX takes a max.\n const laneX = loopLaneX([...contentRights, rightEdge(src), rightEdge(tgt)], LOOP_LANE_GAP);\n\n return loopBackPath(\n { right: rightEdge(src), centerY: centerY(src) },\n { right: rightEdge(tgt), centerY: centerY(tgt) },\n laneX,\n LOOP_CORNER_RADIUS,\n );\n });\n\n if (!path) return null;\n return (\n <BaseEdge\n id={id}\n path={path}\n markerEnd={markerEnd}\n style={softenLoopStyle(style)}\n aria-label=\"Loop back\"\n />\n );\n}\n","/**\n * loopRouting — pure geometry for the right-margin loop-back curve.\n *\n * A `loopTo` back-edge (e.g. ReAct's `Route → Context`) must NOT be drawn\n * straight down the chart spine — it overlaps every node it passes. Instead\n * it is routed as a CURVE that exits the source node's RIGHT edge, bows out to\n * a vertical \"lane\" clear of every content node, and re-enters the target\n * node's RIGHT edge. The lane is shared by all loops so they stack tidily on\n * the right margin.\n *\n * This module is the pure core (no React, no DOM): the `LoopBackEdge`\n * component gathers node bounds from the xyflow store and calls these; the\n * `wrapInMainChartBox` layout reserves `LOOP_LANE_GAP` of right-margin width\n * so the curve renders INSIDE the chart's frame. Keeping the math here makes\n * it unit-testable and keeps the edge component a thin adapter.\n */\n\n/**\n * Horizontal gap (px) between the rightmost content node and the loop lane —\n * how far right of everything the curve bows. Shared by `LoopBackEdge` (which\n * draws to the lane) and `wrapInMainChartBox` (which reserves room for it), so\n * the curve always lands inside the frame.\n */\nexport const LOOP_LANE_GAP = 56;\n\n/** A loop endpoint: a node's right edge x and vertical center y (flow coords). */\nexport interface LoopEndpoint {\n /** Absolute x of the node's RIGHT edge (position.x + width). */\n readonly right: number;\n /** Absolute y of the node's vertical center. */\n readonly centerY: number;\n}\n\n/**\n * The x of the vertical lane the loop curve bows out to: just right of the\n * widest content node, so the curve clears every node it arcs past. Pass the\n * right-edge x of every content node (the box container itself is excluded by\n * the caller — it would otherwise always be the widest and push the lane\n * outside its own frame). Empty input → `gap` (degenerate but safe).\n */\nexport function loopLaneX(contentRights: readonly number[], gap: number = LOOP_LANE_GAP): number {\n // Empty-input fallback: `max` stays -Infinity until the loop assigns it, so\n // `!Number.isFinite` catches the no-nodes case and degrades the lane to `gap`.\n let max = -Infinity;\n for (const r of contentRights) if (r > max) max = r;\n if (!Number.isFinite(max)) max = 0;\n return max + gap;\n}\n\n/**\n * SVG path for one right-margin loop-back curve. A cubic bezier whose BOTH\n * route HUGS the lane: it leaves the source heading right, runs straight UP (or\n * down) the lane — which sits right of EVERY node — and only turns in toward the\n * target at the target's own row (the target is the chart's first node, alone at\n * the top, so the turn-in clears everything). Corners are rounded for a curved\n * feel. A pure inward-bowing bezier was abandoned because it cuts back toward\n * the target's x BEFORE the top, slicing across whatever node is rightmost in\n * the rows it passes (e.g. the tools slot).\n *\n * `radius` is the corner rounding (clamped to fit the available run/rise).\n */\nexport function loopBackPath(\n source: LoopEndpoint,\n target: LoopEndpoint,\n laneX: number,\n radius = 22,\n): string {\n const { right: sx, centerY: sy } = source;\n const { right: tx, centerY: ty } = target;\n // Corner radius can't exceed half the vertical run, nor the horizontal gap to\n // the lane on either side.\n const r = Math.max(\n 0,\n Math.min(radius, Math.abs(sy - ty) / 2, laneX - sx, laneX - tx),\n );\n const up = ty <= sy; // target above source (the normal ReAct loop)\n const vy1 = up ? sy - r : sy + r; // first corner's far-y (leaving source row)\n const vy2 = up ? ty + r : ty - r; // second corner's near-y (entering target row)\n // out to the lane → round → straight up/down the lane → round → in to target.\n return [\n `M ${sx},${sy}`,\n `L ${laneX - r},${sy}`,\n `Q ${laneX},${sy} ${laneX},${vy1}`,\n `L ${laneX},${vy2}`,\n `Q ${laneX},${ty} ${laneX - r},${ty}`,\n `L ${tx},${ty}`,\n ].join(\" \");\n}\n","/**\n * groupLayout — xyflow NATIVE container boxes for the trace chart.\n *\n * Two box mechanisms live here, plus the existing drill (elsewhere):\n *\n * - **Drill** (`subflowDrill.ts` + `useSubflowDrill`): a subflow shows as\n * ONE mount card; clicking it zooms in. The DEFAULT for every subflow.\n * - **Main-chart box** (`wrapInMainChartBox`): wrap the WHOLE chart in ONE\n * container box. This is the Lens model — the primitive you're viewing\n * (LLMCall / Agent) is always one box; every subflow inside it stays a\n * drill card. A `nodeTypes` registry then styles each inner card\n * (system-prompt / messages / tools / LLM). USE THIS for Lens.\n * - **Per-subflow group** (`applyGroupLayout`): box individual subflows\n * (mount → container, members nested inside). A more granular tool kept\n * for consumers that want specific subflows inlined as boxes rather than\n * drilled. NOT what the Lens main-chart model uses.\n *\n * All are pure `(graph, opts) => graph` (no React, no I/O) and compose with\n * `<TracedFlow>` before nodes reach `<ReactFlow>`. explainable-ui stays\n * policy-free: it offers the mechanisms; the consumer (Lens) picks.\n *\n * Pure: `(graph, opts) => graph`. No React, no I/O. Composed by `<TracedFlow>`\n * before the nodes reach `<ReactFlow>`.\n *\n * What it does, given `groupedSubflowIds`:\n * 1. For each grouped subflow that is actually present (a mount node whose\n * `subflowId` is listed AND has ≥1 member where `subflowOf === id`):\n * - lay the OUTER graph out with `baseLayout` (members excluded; the\n * mount stays as the box anchor);\n * - lay the subflow's MEMBERS out with `baseLayout` in isolation, then\n * normalise them to the box's local coordinate space;\n * - size the container box to fit the members (+ header + padding);\n * - convert the mount node to `type: 'groupContainer'` with a `style`\n * width/height, and nest each member via `parentId` + `extent`.\n * 2. Subflows NOT listed are left untouched (they continue to drill).\n *\n * Node ORDER invariant (xyflow requirement): a parent node MUST appear\n * before its children in the array. We emit all outer nodes (containers\n * included) first, then all nested members — so every container precedes\n * its members.\n */\n\nimport type { TraceGraph, TraceNode } from \"../traceStructureRecorder\";\nimport type { TraceFlowLayout } from \"../TraceFlow\";\nimport { LOOP_LANE_GAP } from \"./loopRouting\";\n\n/** xyflow node type used for the container box. Consumers register a\n * renderer for this key (explainable-ui ships a default `GroupContainerNode`). */\nexport const GROUP_CONTAINER_NODE_TYPE = \"groupContainer\";\n\nexport interface GroupLayoutOptions {\n /** Subflow ids (the mount's `subflowId`) to render as group boxes. */\n readonly groupedSubflowIds: readonly string[];\n /** Layout for both the outer graph and each subflow's interior. */\n readonly baseLayout: TraceFlowLayout;\n /** Inner padding inside the container box, in px. Default 16. */\n readonly padding?: number;\n /** Header strip height (room for the box title), in px. Default 44. */\n readonly headerHeight?: number;\n /** Assumed node footprint for box sizing (the layout sets positions, not\n * sizes). Defaults match the bundled `StageNode` footprint. */\n readonly nodeWidth?: number;\n readonly nodeHeight?: number;\n}\n\nconst DEFAULT_PADDING = 16;\nconst DEFAULT_HEADER = 44;\nconst DEFAULT_NODE_W = 200;\nconst DEFAULT_NODE_H = 80;\n\n/**\n * Resolve a node's rendered FOOTPRINT for box-sizing math.\n *\n * A node's true extent is `position + footprint`, not its top-left corner.\n * For a `groupContainer` produced by a prior pass the footprint lives on\n * `style.width/height` (e.g. a boxed subflow ~1756px wide); for a plain\n * stage card it is the configured default. Composing nested boxes therefore\n * REQUIRES reading this — otherwise a wide container is measured as a point\n * and the outer box is sized far too small to contain it.\n *\n * Mirrors `dagreTraceLayout.sizeOf` (`style.width/height` → default) so the\n * box transforms and the dagre layout agree on every node's footprint.\n */\nfunction footprintOf(\n node: TraceNode,\n fallbackW: number,\n fallbackH: number,\n): { width: number; height: number } {\n const style = (node.style ?? {}) as { width?: unknown; height?: unknown };\n const w = typeof style.width === \"number\" ? style.width : fallbackW;\n const h = typeof style.height === \"number\" ? style.height : fallbackH;\n return { width: w, height: h };\n}\n\n/**\n * Apply group-container nesting to a positioned-or-unpositioned graph.\n * Returns a NEW graph (input is not mutated). Edges pass through unchanged\n * — xyflow resolves them by node id regardless of nesting, so an edge that\n * pointed at a now-container mount still connects to the box, and\n * member↔member edges render inside it.\n */\nexport function applyGroupLayout(graph: TraceGraph, opts: GroupLayoutOptions): TraceGraph {\n const padding = opts.padding ?? DEFAULT_PADDING;\n const headerHeight = opts.headerHeight ?? DEFAULT_HEADER;\n const nodeW = opts.nodeWidth ?? DEFAULT_NODE_W;\n const nodeH = opts.nodeHeight ?? DEFAULT_NODE_H;\n const baseLayout = opts.baseLayout;\n\n // Which requested subflows are genuinely groupable: a mount node carrying\n // that subflowId AND at least one member tagged subflowOf === id.\n const requested = new Set(opts.groupedSubflowIds);\n const membersBySubflow = new Map<string, TraceNode[]>();\n for (const n of graph.nodes) {\n const of = n.data?.subflowOf;\n if (of !== undefined && requested.has(of)) {\n const arr = membersBySubflow.get(of) ?? [];\n arr.push(n);\n membersBySubflow.set(of, arr);\n }\n }\n const mountBySubflow = new Map<string, TraceNode>();\n for (const n of graph.nodes) {\n const sfId = n.data?.subflowId;\n if (n.data?.isSubflow && sfId !== undefined && requested.has(sfId) && membersBySubflow.has(sfId)) {\n mountBySubflow.set(sfId, n);\n }\n }\n // Only group subflows that have BOTH a mount and members.\n const activeGroups = new Set<string>();\n for (const sfId of mountBySubflow.keys()) activeGroups.add(sfId);\n\n // Nothing to do — return input unchanged (preserves upstream memoization).\n if (activeGroups.size === 0) {\n return graph;\n }\n\n // Member ids across all active groups (excluded from the outer layout).\n const memberIds = new Set<string>();\n for (const sfId of activeGroups) {\n for (const m of membersBySubflow.get(sfId) ?? []) memberIds.add(m.id);\n }\n\n // ── PASS 1 — lay out each group's MEMBERS and size its box FIRST. We must\n // know each container's true footprint BEFORE the outer layout runs, or\n // dagre would place the outer siblings (Route, ToolCalls, …) around the\n // mount's default 200px point and they'd collide once the box balloons.\n // (Inside-out reflow: size the inner box, then place the outer graph\n // around it at its real size.) ──\n const containerNodes: TraceNode[] = [];\n const nestedMembers: TraceNode[] = [];\n /** Per-group: box size + the normalisation origin needed when nesting. */\n const groupBox = new Map<\n string,\n { width: number; height: number; minX: number; minY: number; members: TraceNode[] }\n >();\n\n for (const sfId of activeGroups) {\n const members = membersBySubflow.get(sfId)!;\n const innerOnlyEdges = graph.edges.filter((e) => {\n const s = members.some((m) => m.id === e.source);\n const t = members.some((m) => m.id === e.target);\n return s && t;\n });\n const innerPositioned = baseLayout({ nodes: members, edges: innerOnlyEdges });\n\n // Normalise member positions to the box's local space (min → 0). Measure\n // each member's full FOOTPRINT (position + width/height), not just its\n // top-left corner — a member may itself be a sized container (nested\n // composition), and corner-only math would undersize this box around it.\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const m of innerPositioned.nodes) {\n const p = m.position;\n const { width, height } = footprintOf(m, nodeW, nodeH);\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x + width > maxX) maxX = p.x + width;\n if (p.y + height > maxY) maxY = p.y + height;\n }\n if (!Number.isFinite(minX)) {\n minX = 0;\n minY = 0;\n maxX = 0;\n maxY = 0;\n }\n\n // maxX/maxY already include each member's footprint, so the inner extent\n // is just the spanned distance (no extra nodeW/nodeH to add).\n const boxWidth = maxX - minX + padding * 2;\n const boxHeight = maxY - minY + headerHeight + padding * 2;\n groupBox.set(sfId, { width: boxWidth, height: boxHeight, minX, minY, members: innerPositioned.nodes });\n }\n\n // ── PASS 2 — lay out the OUTER graph with each mount STAMPED at its real\n // box size, so dagre reserves the correct footprint and outer siblings\n // are placed clear of the box (no overlap). ──\n const outerNodes = graph.nodes\n .filter((n) => !memberIds.has(n.id))\n .map((n) => {\n const box = n.data?.subflowId ? groupBox.get(n.data.subflowId) : undefined;\n // Stamp the box's footprint onto the mount so the dagre baseLayout\n // (which reads style.width/height via sizeOf) places siblings around it.\n // ALSO flag `data.isGroupContainer` so `sizeOf` treats this stamped\n // footprint as AUTHORITATIVE — i.e. style WINS over any consumer\n // `nodeSize` resolver. Without the flag, a resolver that sizes by\n // recorder semantics (e.g. \"any subflow → a 38px slim bar\") out-ranks\n // the stamp: dagre reserves 38px while the box renders ~794px, so the\n // post-container siblings (route / tool-calls / final) rank inside the\n // box and overlap it. The flag makes dagre reserve the box's TRUE height.\n return box\n ? {\n ...n,\n style: { ...(n.style ?? {}), width: box.width, height: box.height },\n data: { ...n.data, isGroupContainer: true },\n }\n : n;\n });\n const outerEdges = graph.edges.filter(\n (e) => !memberIds.has(e.source) && !memberIds.has(e.target),\n );\n const outerPositioned = baseLayout({ nodes: outerNodes, edges: outerEdges });\n const outerPosById = new Map(outerPositioned.nodes.map((n) => [n.id, n.position]));\n\n // ── Emit containers (at their outer position) + nest their members. ──\n for (const sfId of activeGroups) {\n const mount = mountBySubflow.get(sfId)!;\n const box = groupBox.get(sfId)!;\n const { width: boxWidth, height: boxHeight, minX, minY } = box;\n\n // Container = the mount node, retyped + sized, keeping its outer position.\n const mountPos = outerPosById.get(mount.id) ?? mount.position ?? { x: 0, y: 0 };\n containerNodes.push({\n ...mount,\n type: GROUP_CONTAINER_NODE_TYPE,\n position: mountPos,\n style: { ...(mount.style ?? {}), width: boxWidth, height: boxHeight },\n data: { ...mount.data, isGroupContainer: true },\n });\n\n // Members nested under the container, positioned in local space below\n // the header strip.\n for (const m of box.members) {\n const relX = m.position.x - minX + padding;\n const relY = m.position.y - minY + headerHeight + padding;\n nestedMembers.push({\n ...(m as TraceNode),\n parentId: mount.id,\n extent: \"parent\",\n position: { x: relX, y: relY },\n });\n }\n }\n\n // ── Reassemble: outer nodes (with containers swapped in) FIRST, then\n // nested members — guarantees every parent precedes its children. ──\n const containerById = new Map(containerNodes.map((c) => [c.id, c]));\n const outerOut: TraceNode[] = outerPositioned.nodes.map(\n (n) => containerById.get(n.id) ?? n,\n );\n\n return {\n nodes: [...outerOut, ...nestedMembers],\n edges: graph.edges,\n };\n}\n\n/**\n * Convenience: wrap a base layout into a `TraceFlowLayout` that applies\n * group containers. Pass to `<TraceFlow layout={...}>` / `<TracedFlow>`.\n */\nexport function createGroupedLayout(opts: GroupLayoutOptions): TraceFlowLayout {\n return (graph: TraceGraph) => applyGroupLayout(graph, opts);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Main-chart box — wrap the ENTIRE (drill-filtered) chart in ONE container\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// The Lens model: the chart you're looking at (an LLMCall / Agent primitive)\n// is ALWAYS one box; every subflow INSIDE it is a drill card (click → zoom).\n// This is distinct from `applyGroupLayout` (which boxes individual subflows).\n// Here there's no per-subflow mount — the whole graph is the box's contents,\n// so we synthesise ONE container node and nest every top-level node under it.\n//\n// Composition contract: feed this the ALREADY drill-filtered graph (top-level\n// nodes only; subflow internals hidden behind their drill cards). Nodes that\n// already carry a `parentId` are left parented as-is (only parentId-less\n// top-level nodes get re-parented to the main box), so this composes safely\n// even if some upstream nesting exists.\n\n/** Default id for the synthesised main-chart container node. */\nexport const MAIN_CHART_BOX_ID = \"__main_chart__\";\n\nexport interface MainChartBoxOptions {\n /** Layout applied to the chart's contents before wrapping. */\n readonly baseLayout: TraceFlowLayout;\n /** Container node id. Default `__main_chart__`. */\n readonly id?: string;\n /** Box title (rendered in the container header). */\n readonly label?: string;\n /** Optional taxonomy hint surfaced on `data` (e.g. 'LLMCall' | 'Agent'). */\n readonly kind?: string;\n readonly padding?: number;\n readonly headerHeight?: number;\n readonly nodeWidth?: number;\n readonly nodeHeight?: number;\n}\n\n/**\n * Wrap an entire graph in a single main-chart container box. Pure\n * `(graph, opts) => graph`; input not mutated. Empty graph → returned\n * unchanged (nothing to wrap).\n */\nexport function wrapInMainChartBox(graph: TraceGraph, opts: MainChartBoxOptions): TraceGraph {\n if (graph.nodes.length === 0) return graph;\n\n const padding = opts.padding ?? DEFAULT_PADDING;\n const headerHeight = opts.headerHeight ?? DEFAULT_HEADER;\n const nodeW = opts.nodeWidth ?? DEFAULT_NODE_W;\n const nodeH = opts.nodeHeight ?? DEFAULT_NODE_H;\n const mainId = opts.id ?? MAIN_CHART_BOX_ID;\n\n const positioned = opts.baseLayout(graph);\n\n // Only top-level nodes (no existing parentId) get re-parented to the box;\n // already-nested nodes keep their parent (their relative position is\n // unaffected by re-parenting their ancestor — xyflow positions are\n // parent-relative).\n const topLevel = positioned.nodes.filter((n) => n.parentId === undefined);\n\n // Bounding box of the top-level nodes → container size. We measure each\n // node's full FOOTPRINT (position + width/height), not just its top-left\n // corner — a top-level node may itself be a wide group container (from a\n // prior `applyGroupLayout` pass) carrying a large `style.width`. Reading\n // only the corner would size the box as if that container were a 200px\n // node, so it would overflow the outer box (the nesting bug).\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const n of topLevel) {\n const p = n.position;\n const { width, height } = footprintOf(n, nodeW, nodeH);\n if (p.x < minX) minX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.x + width > maxX) maxX = p.x + width;\n if (p.y + height > maxY) maxY = p.y + height;\n }\n if (!Number.isFinite(minX)) {\n minX = 0;\n minY = 0;\n maxX = 0;\n maxY = 0;\n }\n\n // maxX/maxY already include the widest/tallest node's footprint, so the\n // box size is just the spanned extent + padding (+ header for the title).\n // When the chart has a loop-back edge, `LoopBackEdge` bows out to a lane\n // `LOOP_LANE_GAP` right of the widest content node — reserve that width so\n // the curve renders INSIDE the frame instead of spilling past its right border.\n const hasLoopEdge = graph.edges.some((e) => e.data?.kind === \"loop\");\n const loopReserve = hasLoopEdge ? LOOP_LANE_GAP : 0;\n const boxWidth = maxX - minX + padding * 2 + loopReserve;\n const boxHeight = maxY - minY + headerHeight + padding * 2;\n\n const container: TraceNode = {\n id: mainId,\n type: GROUP_CONTAINER_NODE_TYPE,\n position: { x: 0, y: 0 },\n style: { width: boxWidth, height: boxHeight },\n data: {\n label: opts.label ?? \"Chart\",\n isDecider: false,\n isFork: false,\n isStreaming: false,\n isSubflow: false,\n isGroupContainer: true,\n isMainChart: true,\n ...(opts.kind !== undefined && { kind: opts.kind }),\n prevIds: [],\n nextIds: [],\n },\n } as TraceNode;\n\n const topLevelIds = new Set(topLevel.map((n) => n.id));\n const reparented: TraceNode[] = positioned.nodes.map((n) => {\n if (!topLevelIds.has(n.id)) return n; // already nested — leave as-is\n return {\n ...n,\n parentId: mainId,\n extent: \"parent\",\n position: {\n x: n.position.x - minX + padding,\n y: n.position.y - minY + headerHeight + padding,\n },\n };\n });\n\n // Container FIRST (xyflow parent-before-child invariant).\n return { nodes: [container, ...reparented], edges: graph.edges };\n}\n\n/**\n * Convenience: a `TraceFlowLayout` that wraps the whole chart in one\n * main-chart box. Pass to `<TraceFlow layout={...}>` / `<TracedFlow>`.\n */\nexport function createMainChartBoxLayout(opts: MainChartBoxOptions): TraceFlowLayout {\n return (graph: TraceGraph) => wrapInMainChartBox(graph, opts);\n}\n","/**\n * SmartStepEdge — a smooth-step edge that routes a RANK-SKIPPING (staggered)\n * edge AROUND the node(s) it skips, instead of bending through them.\n *\n * It is a drop-in superset of the built-in `smoothstep` edge: for an ordinary\n * adjacent edge it produces the IDENTICAL path (default midpoint bend); only\n * when the edge skips a rank — a node sits vertically between its endpoints —\n * does it move the bend into the gap below that node (see `stepRouting`).\n *\n * WHY a custom edge (not a layout tweak): which edges skip a rank depends on the\n * final laid-out geometry, which only the renderer knows. Like `LoopBackEdge`,\n * this reads node bounds straight from the xyflow store, so it works for ANY\n * staggered merge in ANY chart with zero per-node or per-chart wiring — register\n * it once as the default step edge and every staggered edge routes cleanly.\n *\n * The decision math lives in `_internal/stepRouting` (pure, unit-tested); this\n * is the thin React adapter. `style` + `markerEnd` flow through unchanged.\n */\n\nimport { BaseEdge, getSmoothStepPath, useStore } from \"@xyflow/react\";\nimport type { EdgeProps, ReactFlowState } from \"@xyflow/react\";\nimport { Position } from \"@xyflow/react\";\nimport { staggeredBendY, type VerticalBounds } from \"../FlowchartView/_internal/stepRouting\";\nimport { GROUP_CONTAINER_NODE_TYPE } from \"../FlowchartView/_internal/groupLayout\";\n\nexport function SmartStepEdge({\n id,\n source,\n target,\n sourceX,\n sourceY,\n targetX,\n targetY,\n sourcePosition,\n targetPosition,\n markerEnd,\n style,\n}: EdgeProps) {\n // The bend y for a staggered edge, or null for an ordinary adjacent edge.\n // Derived in the store selector and returned as a NUMBER/null — primitive\n // equality means the edge only re-renders when its routing actually changes.\n const bendY = useStore((s: ReactFlowState) => {\n const src = s.nodeLookup.get(source);\n const tgt = s.nodeLookup.get(target);\n if (!src || !tgt) return null;\n const sourceBottom = src.internals.positionAbsolute.y + (src.measured.height ?? 0);\n const targetTop = tgt.internals.positionAbsolute.y;\n const others: VerticalBounds[] = [];\n for (const n of s.nodeLookup.values()) {\n if (n.id === source || n.id === target) continue;\n if (n.type === GROUP_CONTAINER_NODE_TYPE) continue; // the frame box spans everything\n const top = n.internals.positionAbsolute.y;\n others.push({ top, bottom: top + (n.measured.height ?? 0) });\n }\n return staggeredBendY(sourceBottom, targetTop, others);\n });\n\n const [path] = getSmoothStepPath({\n sourceX,\n sourceY,\n sourcePosition: sourcePosition ?? Position.Bottom,\n targetX,\n targetY,\n targetPosition: targetPosition ?? Position.Top,\n // Override the bend only for a staggered edge; otherwise let getSmoothStepPath\n // use its default centerY (== the built-in `smoothstep` path, byte-for-byte).\n ...(bendY !== null ? { centerY: bendY } : {}),\n });\n\n return <BaseEdge id={id} path={path} markerEnd={markerEnd} style={style} />;\n}\n","/**\n * stepRouting — pure geometry for the \"smart\" step edge that routes a\n * RANK-SKIPPING (staggered) edge AROUND the node(s) it skips.\n *\n * The problem: a normal smooth-step edge bends at the vertical MIDPOINT between\n * its endpoints. When an edge skips a rank (e.g. the agent merge-tree's\n * `tools → call-llm`, which bypasses `message-api`), that midpoint falls right\n * on the skipped node's row, so the horizontal segment cuts straight through it\n * — it reads as if the edge connects to the skipped node.\n *\n * The fix: place the bend in the GAP just below the lowest skipped node and\n * above the target, so the horizontal run clears every skipped node. Because the\n * bend sits below ALL skipped nodes, vertical clearance alone guarantees the\n * horizontal run never overlaps them. (The vertical run stays at the source's x;\n * for fork-join staggered merges the skipped input is laterally offset from the\n * trunk, so that run is already clear — the case this targets.)\n *\n * This module is the pure core (no React/DOM); `SmartStepEdge` is the thin\n * adapter that reads node bounds from the xyflow store and calls this. Keeping\n * the math here makes it unit-testable, mirroring `loopRouting`.\n */\n\n/** A node's vertical extent in flow coordinates (top edge .. bottom edge). */\nexport interface VerticalBounds {\n readonly top: number;\n readonly bottom: number;\n}\n\n/**\n * The y at which a step edge should bend to clear every rank it SKIPS, or `null`\n * when it skips nothing (caller then uses the default midpoint bend == ordinary\n * smooth-step).\n *\n * A node counts as \"skipped\" when its vertical CENTER lies strictly between the\n * source's bottom and the target's top. The bend is placed midway between the\n * lowest skipped node's bottom and the target's top, clamped to stay\n * `minGapFromTarget` above the target so a rounded corner still fits.\n */\nexport function staggeredBendY(\n sourceBottom: number,\n targetTop: number,\n others: readonly VerticalBounds[],\n minGapFromTarget = 8,\n): number | null {\n let lowestSkippedBottom = -Infinity;\n for (const n of others) {\n const cy = (n.top + n.bottom) / 2;\n if (cy > sourceBottom && cy < targetTop && n.bottom > lowestSkippedBottom) {\n lowestSkippedBottom = n.bottom;\n }\n }\n if (lowestSkippedBottom === -Infinity) return null; // nothing skipped → default bend\n return Math.min((lowestSkippedBottom + targetTop) / 2, targetTop - minGapFromTarget);\n}\n","/**\n * dagreTraceLayout — professor-grade `TraceFlowLayout` backed by dagre.\n *\n * Replaces the hand-rolled BFS `defaultTraceFlowLayout` (which used FIXED\n * spacing constants — Y_STEP / X_SPREAD — and documented \"first-wins\"\n * convergence + no overlap detection). Dagre instead derives every\n * position from the STRUCTURE RELATIONS:\n *\n * - **next** (sequential): y-delta = rank depth (longest path), so a\n * convergence node lands at `max(incoming ranks) + 1` — not\n * \"deepest-branch-so-far\".\n * - **fork / selector** (N branches): x-delta = the measured SUBTREE\n * WIDTH of each branch (a wide branch pushes its siblings further; a\n * thin one barely shifts them) — scales cleanly for any N, no collisions.\n * - **merge** (join): centered under the average of its real parents.\n *\n * Compound nesting: dagre is given `parentId` as a compound-parent link,\n * so group-container children (from `applyGroupLayout` / `wrapInMainChartBox`)\n * stay inside their box. Coordinates are returned parent-RELATIVE (xyflow\n * convention), matching what the box transforms expect.\n *\n * Ported from agentfootprint-lens's proven `dagreLayout` (same dagre core),\n * re-shaped to the `TraceFlowLayout` contract: `(TraceGraph) => TraceGraph`.\n * Pure — same graph in, same positions out; no React, no I/O.\n */\n\nimport dagre from \"dagre\";\nimport type { Edge } from \"@xyflow/react\";\nimport type { TraceGraph, TraceNode, TraceEdgeData } from \"../traceStructureRecorder\";\nimport type { TraceFlowLayout } from \"../TraceFlow\";\n\n/** Explicit node footprint (px). */\nexport interface NodeFootprint {\n readonly width: number;\n readonly height: number;\n}\n\n/**\n * Consumer-supplied per-node size resolver. Receives the WHOLE node (all\n * recorder semantics: `data.isSubflow`, `data.icon`, `data.subflowId`,\n * `id`, …) and returns a footprint, or `undefined` to leave the node alone\n * (→ falls back to `style.width/height`, then the default footprint).\n *\n * The library imposes NO sizing rules — the consumer decides per node by\n * whatever criteria THEY choose. E.g. make one specific slot a slim bar\n * while another stays a full card; make the LLM-call node large; etc.\n */\nexport type NodeSizeResolver = (node: TraceNode) => NodeFootprint | undefined;\n\n/** Consumer-supplied per-edge layout-weight resolver. Higher weight pulls\n * the two endpoints into a tighter, straighter column (dagre `weight`).\n * Return `undefined` for the default (1). */\nexport type EdgeWeightResolver = (edge: Edge<TraceEdgeData>) => number | undefined;\n\n/** Consumer-supplied per-edge minimum rank-span resolver. `>1` STRETCHES an\n * edge (pushes its target that many ranks down). Note dagre cannot make an\n * edge SHORTER than one rank — `minlen` only increases. Return `undefined`\n * for the default (1). */\nexport type EdgeMinLenResolver = (edge: Edge<TraceEdgeData>) => number | undefined;\n\n/**\n * Consumer-supplied left-to-right ORDER for a node's fork/decider children.\n * Receives the source node id + its child target ids (in spec/edge-insertion\n * order); returns the SAME ids reordered left-to-right (index 0 = leftmost).\n * Ids omitted from the result keep their original relative order after the\n * listed ones. Return the input unchanged (or `undefined` from the resolver)\n * to leave a node alone.\n *\n * Use to place a specific branch on a chosen side — e.g. the looping branch on\n * the right margin where the loop-back curve lives, so the \"iterate\" path reads\n * as one side of the fork. This is a pure VISUAL/LAYOUT decision (it changes\n * which side a branch draws on, never the chart's behavior), so it belongs in\n * the renderer, not the chart spec.\n *\n * Mechanism: dagre seeds its sibling order from edge-insertion order and keeps\n * it as the tie-break for equal-barycenter siblings. We insert each source's\n * edges in the resolved order, so for the common symmetric N-branch decider the\n * result is deterministic. (For graphs where one ordering strictly reduces edge\n * crossings, dagre's crossing-minimizer may still override — best-effort, as\n * documented for any dagre ordering hint.)\n */\nexport type SiblingOrderResolver = (\n sourceId: string,\n childIds: readonly string[],\n) => readonly string[];\n\nexport interface DagreTraceLayoutOptions {\n /** Layout direction. `'TB'` (top-to-bottom) is the default — matches the\n * \"Seed → … → answer\" reading order. */\n readonly direction?: \"TB\" | \"BT\" | \"LR\" | \"RL\";\n /** Vertical spacing between rank layers (px). Surfaced as a knob — the\n * rank-gap delta. Default 80. */\n readonly rankSep?: number;\n /** Horizontal spacing between siblings within a rank (px). The\n * sibling-gap delta dagre adds ON TOP of measured subtree widths.\n * Default 60. */\n readonly nodeSep?: number;\n /** Spacing between edges (px). Default 20. */\n readonly edgeSep?: number;\n /** Fallback node footprint when a node carries no explicit size. dagre\n * needs real dimensions or arrows collapse to a point. */\n readonly nodeWidth?: number;\n readonly nodeHeight?: number;\n /** Per-node size resolver — consumer decides each node's footprint. See\n * `NodeSizeResolver`. Resolution order: resolver → `node.style` → default. */\n readonly nodeSize?: NodeSizeResolver;\n /** Per-edge pull (dagre `weight`). See `EdgeWeightResolver`. */\n readonly edgeWeight?: EdgeWeightResolver;\n /** Per-edge stretch (dagre `minlen`). See `EdgeMinLenResolver`. */\n readonly edgeMinLen?: EdgeMinLenResolver;\n /** Per-node fork/decider child ordering. See `SiblingOrderResolver`. */\n readonly siblingOrder?: SiblingOrderResolver;\n}\n\nexport const DEFAULT_NODE_W = 200;\nexport const DEFAULT_NODE_H = 80;\n\n/**\n * Resolve a node's render size. Order: consumer `nodeSize` resolver (if it\n * returns a footprint) → explicit `style.width/height` (set by the\n * group/main-box transforms) → configured fallback footprint.\n *\n * GROUP-CONTAINER EXCEPTION — style WINS over the resolver. A node flagged\n * `data.isGroupContainer` has been STAMPED with its true box footprint on\n * `style.width/height` by `applyGroupLayout` PASS 2 (or `wrapInMainChartBox`).\n * That footprint is authoritative: it is the size the box actually RENDERS at,\n * so dagre must reserve exactly it or post-container siblings rank inside the\n * box and overlap it. A consumer `nodeSize` resolver that sizes by recorder\n * semantics (e.g. \"any subflow → a 38px slim bar\") would otherwise out-rank\n * the stamp — dagre would be told 38px while the box paints ~794px, and the\n * `route`/`tool-calls`/`final` siblings would land on top of it. So for a\n * group container the resolution order flips to: `style` → resolver → default.\n *\n * Exported so the post-layout `snapLinearSuccessors` pass reconstructs each\n * node's center from the IDENTICAL width dagre placed it at, keeping snapped\n * centers geometry-exact.\n */\nexport function sizeOf(\n node: TraceNode,\n fallbackW: number,\n fallbackH: number,\n resolver?: NodeSizeResolver,\n): { width: number; height: number } {\n const style = (node.style ?? {}) as { width?: unknown; height?: unknown };\n const styleW = typeof style.width === \"number\" ? style.width : undefined;\n const styleH = typeof style.height === \"number\" ? style.height : undefined;\n\n // A stamped group container's footprint is authoritative — style beats the\n // resolver so dagre reserves the box's REAL rendered height (no sibling\n // overlap). Both dimensions must be present to use the stamp; otherwise fall\n // through to the normal order.\n if (node.data?.isGroupContainer && styleW !== undefined && styleH !== undefined) {\n return { width: styleW, height: styleH };\n }\n\n const resolved = resolver?.(node);\n if (resolved) return { width: resolved.width, height: resolved.height };\n return {\n width: styleW ?? fallbackW,\n height: styleH ?? fallbackH,\n };\n}\n\n/**\n * Reorder edges so each source node's forward (non-loop) children are fed to\n * dagre in `siblingOrder`'s left-to-right order. dagre seeds sibling order from\n * edge-insertion order (and keeps it as the equal-barycenter tie-break), so\n * inserting in the resolved order biases each fork's left-to-right layout.\n *\n * Pure. Loop edges are dropped (they never shape layout — the caller skips them\n * anyway). Sources keep first-seen order; within a source, children follow the\n * resolver, and any children the resolver omits keep their original order after\n * the listed ones. Single-child sources are returned untouched.\n */\nfunction reorderSiblingEdges<E extends { source: string; target: string; data?: { kind?: string } }>(\n edges: readonly E[],\n siblingOrder: SiblingOrderResolver,\n): E[] {\n const bySource = new Map<string, E[]>();\n for (const e of edges) {\n if (e.data?.kind === \"loop\") continue;\n const arr = bySource.get(e.source);\n if (arr) arr.push(e);\n else bySource.set(e.source, [e]);\n }\n const out: E[] = [];\n for (const [src, group] of bySource) {\n if (group.length < 2) {\n out.push(...group);\n continue;\n }\n const ordered = siblingOrder(src, group.map((e) => e.target));\n const byTarget = new Map(group.map((e) => [e.target, e]));\n const used = new Set<string>();\n for (const t of ordered) {\n const e = byTarget.get(t);\n if (e && !used.has(t)) {\n out.push(e);\n used.add(t);\n }\n }\n for (const e of group) if (!used.has(e.target)) out.push(e); // resolver omissions\n }\n return out;\n}\n\n/**\n * Lay out a `TraceGraph` with dagre. Returns a NEW graph with each node's\n * `position` set (top-left, parent-relative for nested nodes). Edges pass\n * through unchanged — xyflow routes them once nodes are placed.\n *\n * Loop back-edges (`kind: 'loop'`) are EXCLUDED from the dagre graph: they\n * are visual annotations only (invariant I1) and would otherwise create\n * cycles that distort ranking.\n */\nexport function dagreTraceLayout(\n graph: TraceGraph,\n options: DagreTraceLayoutOptions = {},\n): TraceGraph {\n if (graph.nodes.length === 0) return graph;\n\n const direction = options.direction ?? \"TB\";\n const rankSep = options.rankSep ?? 80;\n const nodeSep = options.nodeSep ?? 60;\n const edgeSep = options.edgeSep ?? 20;\n const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W;\n const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H;\n\n const g = new dagre.graphlib.Graph({ compound: true });\n g.setGraph({ rankdir: direction, ranksep: rankSep, nodesep: nodeSep, edgesep: edgeSep });\n g.setDefaultEdgeLabel(() => ({}));\n\n const sizes = new Map<string, { width: number; height: number }>();\n // Sizes the consumer resolver supplied — applied to the node's `style` so\n // xyflow RENDERS at the same footprint dagre laid out for (layout/paint\n // parity). Style-derived + default sizes are layout-only (the node already\n // renders at them), so we don't override their style.\n const resolvedStyleSizes = new Map<string, NodeFootprint>();\n for (const node of graph.nodes) {\n const resolved = options.nodeSize?.(node);\n const size = sizeOf(node, fallbackW, fallbackH, options.nodeSize);\n sizes.set(node.id, size);\n // Only re-stamp the node's `style` from the resolver when `sizeOf` actually\n // USED the resolver — i.e. the dagre size equals the resolved footprint. A\n // stamped group container ignores the resolver (style wins, see sizeOf), so\n // we must NOT overwrite its authoritative box footprint with the resolver's\n // value (that would shrink the rendered box back to e.g. a 38px slim bar).\n if (resolved && resolved.width === size.width && resolved.height === size.height) {\n resolvedStyleSizes.set(node.id, resolved);\n }\n g.setNode(node.id, { width: size.width, height: size.height });\n if (node.parentId) {\n g.setParent(node.id, node.parentId);\n }\n }\n\n // When a sibling order is requested, feed each fork's child edges to dagre in\n // that order (opt-in; the default path keeps edges byte-identical to before).\n // `reorderSiblingEdges` returns FORWARD edges only (loop edges are dropped —\n // they never shape layout, and the `kind === \"loop\"` skip below is the no-op\n // for that case). The graph's edges are returned UNCHANGED from this function\n // (see the final `return` — loop edges still reach the renderer intact).\n const layoutEdges = options.siblingOrder\n ? reorderSiblingEdges(graph.edges, options.siblingOrder)\n : graph.edges;\n for (const e of layoutEdges) {\n if (e.data?.kind === \"loop\") continue; // visual-only — never shapes layout\n if (g.hasNode(e.source) && g.hasNode(e.target)) {\n // Per-edge pull (weight) + stretch (minlen) — consumer-controlled.\n const label: { weight?: number; minlen?: number } = {};\n const weight = options.edgeWeight?.(e);\n const minlen = options.edgeMinLen?.(e);\n if (typeof weight === \"number\") label.weight = weight;\n if (typeof minlen === \"number\") label.minlen = minlen;\n g.setEdge(e.source, e.target, label);\n }\n }\n\n dagre.layout(g);\n\n // dagre returns CENTER coords; xyflow wants TOP-LEFT. Nested children get\n // coords RELATIVE to their parent's top-left (xyflow convention).\n const positioned: TraceNode[] = graph.nodes.map((node) => {\n const laidOut = g.node(node.id);\n if (!laidOut) return node; // unreached (orphan) — keep original position\n const size = sizes.get(node.id)!;\n let x = laidOut.x - size.width / 2;\n let y = laidOut.y - size.height / 2;\n if (node.parentId) {\n const parent = g.node(node.parentId);\n const parentSize = sizes.get(node.parentId);\n if (parent && parentSize) {\n x -= parent.x - parentSize.width / 2;\n y -= parent.y - parentSize.height / 2;\n }\n }\n // Apply consumer-resolved size to `style` so xyflow RENDERS at the same\n // footprint dagre placed (paint matches layout). Only for resolver-set\n // sizes — style/default-sized nodes already render correctly.\n const styleSize = resolvedStyleSizes.get(node.id);\n if (styleSize) {\n return {\n ...node,\n position: { x, y },\n style: { ...(node.style ?? {}), width: styleSize.width, height: styleSize.height },\n };\n }\n return { ...node, position: { x, y } };\n });\n\n return { nodes: positioned, edges: graph.edges };\n}\n\n/**\n * Build a `TraceFlowLayout` from dagre options. Pass to\n * `<TraceFlow layout={...}>` / `<TracedFlow layout={...}>`, or use it as a\n * `baseLayout` for the group/main-box transforms.\n */\nexport function createDagreTraceLayout(\n options: DagreTraceLayoutOptions = {},\n): TraceFlowLayout {\n return (graph: TraceGraph) => dagreTraceLayout(graph, options);\n}\n","/**\n * TracedFlow — runtime-overlay variant of `<TraceFlow>`.\n *\n * Pairs a build-time `TraceGraph` (from `createTraceStructureRecorder`)\n * with a runtime `RuntimeOverlay` (from `createTraceRuntimeOverlay`)\n * and a scrub index → renders an xyflow chart with per-node coloring\n * (done / active / error), per-edge highlighting (executed paths),\n * loop-edge side-routing, and subflow drill-down.\n *\n * The component is orchestration only. Each responsibility lives in\n * an extracted helper / hook (see `_internal/`):\n *\n * - drill state .................. useSubflowDrill\n * - container resize → fitView ... useChartAutoRefit\n * - graph filtering by drill ..... filterGraphForDrill\n * - breadcrumb path .............. buildSubflowBreadcrumb\n * - slice id normalization ....... normalizeSliceLeafIds\n * - mount status aggregation ..... aggregateMountStatus\n * - node / edge styling .......... toStageNodeWithOverlay + styleEdgeWithOverlay\n * - breadcrumb UI ................ <SubflowBreadcrumbBar>\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const runtime = useMemo(() => createTraceRuntimeOverlay(), []);\n * // ... attach both to executor, run the chart ...\n * <TracedFlow\n * graph={trace.getGraph()}\n * overlay={runtime.getOverlay()}\n * scrubIndex={sliderValue}\n * onNodeClick={(stageId) => focusStage(stageId)}\n * onSubflowChange={(mountId) => syncShellDrill(mountId)}\n * />\n * ```\n */\n\nimport type * as React from \"react\";\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport {\n ReactFlow,\n Background,\n BackgroundVariant,\n MarkerType,\n} from \"@xyflow/react\";\nimport type { Node, Edge, NodeTypes, EdgeTypes, ReactFlowInstance } from \"@xyflow/react\";\nimport type { TraceGraph, TraceNode, TraceEdge } from \"./traceStructureRecorder\";\nimport type { TraceFlowLayout } from \"./TraceFlow\";\nimport { defaultTraceFlowLayout } from \"./TraceFlow\";\nimport { dagreTraceLayout } from \"./_internal/dagreTraceLayout\";\nimport type { RuntimeOverlay } from \"./createTraceRuntimeOverlay\";\nimport { sliceOverlay } from \"./createTraceRuntimeOverlay\";\nimport { StageNode } from \"../StageNode\";\nimport type { StageNodeData } from \"../StageNode\";\nimport { rawDefaults } from \"../../theme/tokens\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { filterGraphForDrill, buildSubflowBreadcrumb } from \"./_internal/subflowDrill\";\nimport { aggregateMountStatus } from \"./_internal/overlayProjection\";\nimport { useSubflowDrill } from \"./_internal/useSubflowDrill\";\nimport { useChartAutoRefit } from \"./_internal/useChartAutoRefit\";\nimport { SubflowBreadcrumbBar } from \"./SubflowBreadcrumbBar\";\nimport { GroupContainerNode } from \"../GroupContainerNode\";\nimport { LoopBackEdge } from \"../LoopBackEdge\";\nimport { SmartStepEdge } from \"../SmartStepEdge\";\nimport { applyGroupLayout, wrapInMainChartBox } from \"./_internal/groupLayout\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Theming\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TracedFlowColors {\n /** Default (un-executed) node text + edge stroke. */\n default: string;\n /** Done — visually de-emphasised (lighter). */\n done: string;\n /** Active — current scrub position. */\n active: string;\n /** Error — node with recorded onError. */\n error: string;\n /** Loop back-edge color. */\n loop: string;\n}\n\nconst DEFAULT_COLORS: TracedFlowColors = {\n default: rawDefaults.colors.textMuted,\n done: rawDefaults.colors.success,\n active: rawDefaults.colors.primary,\n error: rawDefaults.colors.error,\n loop: rawDefaults.colors.warning,\n};\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Per-node / per-edge styling (pure)\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Derive overlay state fields for a single node from the current\n * scrub slice. Shared between the default `stageNode` path and the\n * custom-node pass-through path so custom renderers receive the same\n * `active`/`done`/`error`/`dimmed`/`stepNumbers` shape the bundled\n * `<StageNode>` consumes.\n */\n/** Stable empty set so the nodes useMemo doesn't re-run when no co-active set is passed. */\nconst EMPTY_SET: ReadonlySet<string> = new Set<string>();\n\nfunction deriveOverlayFields(\n node: TraceNode,\n doneStageIds: ReadonlySet<string>,\n activeStageId: string | null,\n errorMessage: string | undefined,\n executedOrderIds: readonly string[],\n coActiveStageIds: ReadonlySet<string>,\n): {\n active: boolean;\n done: boolean;\n error: boolean;\n dimmed: boolean;\n errorMessage?: string;\n stepNumbers?: number[];\n} {\n const isDone = doneStageIds.has(node.id);\n // `active` is the SINGLE cursor node OR any node in the co-active set — the\n // latter lets a consumer light a whole parallel cohort (e.g. the lens lighting\n // all branches of a fork) at one cursor. Applies to BOTH stage and custom\n // nodes (custom nodes also OR consumer `data.active` below).\n const isActive = activeStageId === node.id || coActiveStageIds.has(node.id);\n const wasExecuted = isDone || isActive;\n const hasError = !!errorMessage;\n const dimmed = !wasExecuted && executedOrderIds.length > 0;\n\n // Per-stage step number(s) — a loop may visit the same node multiple times.\n let stepNumbers: number[] | undefined;\n if (executedOrderIds.length > 0) {\n const nums: number[] = [];\n for (let i = 0; i < executedOrderIds.length; i++) {\n if (executedOrderIds[i] === node.id) nums.push(i + 1);\n }\n if (nums.length > 0) stepNumbers = nums;\n }\n\n return {\n active: isActive,\n done: isDone,\n error: hasError,\n dimmed,\n ...(errorMessage && { errorMessage }),\n ...(stepNumbers && { stepNumbers }),\n };\n}\n\nfunction toStageNodeWithOverlay(\n node: TraceNode,\n doneStageIds: ReadonlySet<string>,\n activeStageId: string | null,\n errorMessage: string | undefined,\n executedOrderIds: readonly string[],\n coActiveStageIds: ReadonlySet<string>,\n): Node {\n const overlayFields = deriveOverlayFields(\n node,\n doneStageIds,\n activeStageId,\n errorMessage,\n executedOrderIds,\n coActiveStageIds,\n );\n const { dimmed } = overlayFields;\n\n // Custom-node pass-through with overlay enrichment.\n //\n // Behaviour (v0.20+): when a consumer pushes a node with a non-default\n // `type`, we return it with overlay state MERGED INTO `data`\n // (`active`, `done`, `error`, `errorMessage`, `dimmed`, `stepNumbers`).\n // The consumer's custom renderer can read those fields to style itself\n // the same way the bundled `<StageNode>` does, without re-implementing\n // the scrub-slice derivation.\n //\n // Merge semantics: OR-union with consumer `data`. The consumer may\n // ALSO want to mark a node active/done (e.g., agentfootprint-lens marks\n // its User pill active at root cursors — the User pill isn't a real\n // stage so the overlay can't compute it). When EITHER source flags a\n // node active/done/error, the renderer sees it. This composes cleanly:\n // - Pure overlay flow (no consumer override) → overlay values pass through\n // - Consumer override (lens User pill case) → consumer flag wins\n // - Both set → OR (lit either way)\n //\n // `dimmed` is mutually exclusive with `active`/`done` — when a node is\n // active or done at the current cursor it can't simultaneously be\n // \"faded because others have executed.\" We zero dimmed when active or\n // done is true regardless of source.\n if (node.type !== undefined && node.type !== \"stage\") {\n const consumerData = (node.data ?? {}) as Record<string, unknown>;\n const consumerActive = consumerData.active === true;\n const consumerDone = consumerData.done === true;\n const consumerError = consumerData.error === true;\n const finalActive = consumerActive || overlayFields.active;\n const finalDone = consumerDone || overlayFields.done;\n const finalError = consumerError || overlayFields.error;\n const finalDimmed = !finalActive && !finalDone && dimmed;\n return {\n ...node,\n data: {\n ...node.data,\n active: finalActive,\n done: finalDone,\n error: finalError,\n ...(overlayFields.errorMessage !== undefined &&\n consumerData.errorMessage === undefined && {\n errorMessage: overlayFields.errorMessage,\n }),\n ...(finalDimmed && { dimmed: true }),\n ...(overlayFields.stepNumbers && { stepNumbers: overlayFields.stepNumbers }),\n },\n ...(finalDimmed && { style: { ...(node.style ?? {}), opacity: 0.35 } }),\n } as Node;\n }\n\n const stageData: StageNodeData = {\n label: node.data.label,\n isDecider: node.data.isDecider,\n isFork: node.data.isFork,\n isSubflow: node.data.isSubflow,\n ...overlayFields,\n ...(node.data.description !== undefined && { description: node.data.description }),\n ...(node.data.icon !== undefined && { icon: node.data.icon }),\n ...(node.data.subflowId !== undefined && { subflowId: node.data.subflowId }),\n ...(node.data.isLazy === true && { isLazy: true }),\n ...(node.data.emphasis !== undefined && { emphasis: node.data.emphasis }),\n ...(node.data.size !== undefined && { size: node.data.size }),\n } as StageNodeData;\n\n return {\n ...node,\n type: \"stageNode\",\n data: stageData as unknown as Record<string, unknown>,\n ...(dimmed && { style: { opacity: 0.35 } }),\n };\n}\n\nfunction styleEdgeWithOverlay(\n edge: TraceEdge,\n doneStageIds: ReadonlySet<string>,\n activeStageId: string | null,\n colors: TracedFlowColors,\n): Edge {\n const kind = edge.data?.kind ?? \"next\";\n const sourceExecuted = doneStageIds.has(edge.source) || activeStageId === edge.source;\n const targetExecuted = doneStageIds.has(edge.target) || activeStageId === edge.target;\n const traversed = sourceExecuted && targetExecuted;\n const isLeadingEdge = activeStageId === edge.source && !doneStageIds.has(edge.target);\n\n let color: string = colors.default;\n if (kind === \"loop\") color = colors.loop;\n else if (isLeadingEdge) color = colors.active;\n else if (traversed) color = colors.done;\n\n const styled: Edge = {\n ...edge,\n // Loop back-edges use the custom `loopBack` edge — a curve routed along the\n // right margin (clear of the spine). It reads node bounds from the store\n // and anchors on right edges itself, so it needs NO dedicated loop handles\n // on the node (the old approach broke for any node missing them).\n // Every other edge uses `smartStep`: a smoothstep superset that routes a\n // RANK-SKIPPING edge around the node it skips (else identical to smoothstep).\n type: kind === \"loop\" ? \"loopBack\" : \"smartStep\",\n animated: isLeadingEdge,\n style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },\n markerEnd: { type: MarkerType.ArrowClosed, color, width: 16, height: 16 },\n };\n if (kind === \"loop\") {\n styled.style = { ...styled.style, strokeDasharray: \"4 3\" };\n }\n return styled;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Component\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TracedFlowProps extends BaseComponentProps {\n /** Build-time graph from `createTraceStructureRecorder().getGraph()`. */\n graph: TraceGraph;\n /** Runtime overlay from `createTraceRuntimeOverlay().getOverlay()`. */\n overlay?: RuntimeOverlay;\n /** Time-travel scrub index. Defaults to the last step (latest state). */\n scrubIndex?: number;\n /** Layout function. Default: BFS tree walk over the recorder graph. */\n layout?: TraceFlowLayout | \"passthrough\";\n /** Color overrides. */\n colors?: Partial<TracedFlowColors>;\n /** Node click handler — receives stage id. */\n onNodeClick?: (stageId: string) => void;\n /**\n * Fires when the chart drills into or out of a subflow (explicit\n * user click on a mount node). Receives the mount stage id (drill\n * in) or `null` (pop back). Container shells use this to keep\n * their data panels in lock-step with the chart's drill state.\n */\n onSubflowChange?: (mountStageId: string | null) => void;\n /**\n * Consumer-supplied xyflow node types. Merged with the built-in\n * `{ stageNode: StageNode }` registry — keys you supply OVERRIDE\n * the default for that node type. Pass `{ stageNode: MyNode }` to\n * replace the default stage renderer entirely, or add new keys\n * for custom node components you push into the graph.\n *\n * v0.20+ — overlay state is injected into custom nodes' `data`\n * fields too (`active`, `done`, `error`, `errorMessage`, `dimmed`,\n * `stepNumbers`), so consumer renderers can style themselves with\n * the same scrub-driven done/active/error semantics the bundled\n * `<StageNode>` uses — without re-implementing the overlay slice\n * derivation. Consumer `data` fields pass through untouched alongside.\n */\n nodeTypes?: NodeTypes;\n /**\n * Consumer-supplied xyflow edge types. Merged with no built-in\n * defaults — pass `{ myEdge: MyEdge }` to register custom edge\n * components for edges you push into the graph with `type: 'myEdge'`.\n */\n edgeTypes?: EdgeTypes;\n /**\n * Extra chart node ids to mark `active` SIMULTANEOUSLY at the current scrub\n * position, on top of the overlay's single active node. Lets a consumer light\n * a whole parallel cohort at one cursor (e.g. the lens lighting every branch\n * of a fork together). Works for BOTH stage and custom nodes. Defaults to\n * none — single-active behaviour is unchanged.\n */\n coActiveStageIds?: ReadonlySet<string>;\n /**\n * Subflow ids to render as GROUP CONTAINER boxes — the subflow's member\n * stages render NESTED inside the box (xyflow `parentId` + `extent`),\n * instead of behind a click-to-zoom DRILL card. Per-subflow choice: any\n * subflow id NOT listed keeps drilling. Default (unset): all drill —\n * existing behavior, nothing changes.\n */\n groupedSubflows?: readonly string[];\n /**\n * Wrap the ENTIRE chart in ONE main-chart container box (the Lens model:\n * the primitive you're viewing is always one box; subflows inside stay\n * drill cards). Pass a config object to enable + label it; omit for no\n * outer box. Composes AFTER drill-filtering, so when you drill into a\n * subflow the box reframes to that subflow's contents.\n */\n mainChartBox?: { label?: string; kind?: string };\n /**\n * Children rendered INSIDE the `<ReactFlow>` element, after the\n * built-in `<Background>`. Use this slot to mount xyflow\n * accessory components like `<Controls />`, `<MiniMap />`, or a\n * custom legend. If unset, only the default Background is rendered.\n */\n children?: React.ReactNode;\n}\n\nconst DEFAULT_NODE_TYPES: NodeTypes = {\n stageNode: StageNode,\n groupContainer: GroupContainerNode,\n};\n\n// Built-in edge types. `loopBack` curves loop-back edges along the right margin\n// (see LoopBackEdge); `smartStep` routes rank-skipping edges around the node\n// they skip (see SmartStepEdge). Always registered; merged UNDER consumer\n// `edgeTypes` (consumer keys win).\nconst DEFAULT_EDGE_TYPES: EdgeTypes = { loopBack: LoopBackEdge, smartStep: SmartStepEdge };\n\nexport function TracedFlow({\n graph,\n overlay,\n scrubIndex,\n layout: layoutProp,\n colors: colorOverrides,\n onNodeClick,\n onSubflowChange,\n groupedSubflows,\n mainChartBox,\n nodeTypes: userNodeTypes,\n edgeTypes: userEdgeTypes,\n coActiveStageIds,\n children,\n className,\n style,\n}: TracedFlowProps) {\n // Dagre is the default (structure-derived spacing); override via `layout`.\n const layout = layoutProp ?? dagreTraceLayout;\n const colors = useMemo<TracedFlowColors>(\n () => ({ ...DEFAULT_COLORS, ...(colorOverrides ?? {}) }),\n [colorOverrides],\n );\n const mergedNodeTypes = useMemo<NodeTypes>(\n () => (userNodeTypes ? { ...DEFAULT_NODE_TYPES, ...userNodeTypes } : DEFAULT_NODE_TYPES),\n [userNodeTypes],\n );\n const mergedEdgeTypes = useMemo<EdgeTypes>(\n () => (userEdgeTypes ? { ...DEFAULT_EDGE_TYPES, ...userEdgeTypes } : DEFAULT_EDGE_TYPES),\n [userEdgeTypes],\n );\n\n // ── Drill state + visibility derivations ──────────────────────────\n const drill = useSubflowDrill(graph, onSubflowChange);\n const groupedSet = useMemo(() => new Set(groupedSubflows ?? []), [groupedSubflows]);\n // Drill-filter the graph, but KEEP members of grouped subflows visible:\n // a grouped subflow renders its members nested in a container box rather\n // than hidden behind a drill card, so it opts out of drill hiding.\n const filteredGraph = useMemo(() => {\n const base = filterGraphForDrill(graph, drill.currentSubflowId);\n if (groupedSet.size === 0) return base;\n const baseIds = new Set(base.nodes.map((n) => n.id));\n const extraNodes = graph.nodes.filter(\n (n) =>\n n.data?.subflowOf !== undefined &&\n groupedSet.has(n.data.subflowOf) &&\n !baseIds.has(n.id),\n );\n if (extraNodes.length === 0) return base;\n const allIds = new Set([...baseIds, ...extraNodes.map((n) => n.id)]);\n const baseEdgeIds = new Set(base.edges.map((e) => e.id));\n const extraEdges = graph.edges.filter(\n (e) => !baseEdgeIds.has(e.id) && allIds.has(e.source) && allIds.has(e.target),\n );\n return { nodes: [...base.nodes, ...extraNodes], edges: [...base.edges, ...extraEdges] };\n }, [graph, drill.currentSubflowId, groupedSet]);\n const breadcrumb = useMemo(\n () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),\n [graph, drill.currentSubflowId],\n );\n const positioned = useMemo<TraceGraph>(() => {\n const realBase: TraceFlowLayout =\n layout === \"passthrough\" ? (g: TraceGraph) => g : layout;\n\n // Per-subflow group boxes (granular; not the main-chart model).\n if (groupedSet.size > 0) {\n const grouped = applyGroupLayout(filteredGraph, {\n groupedSubflowIds: [...groupedSet],\n baseLayout: realBase,\n });\n // Main box can still wrap the grouped result if both are requested.\n return mainChartBox\n ? wrapInMainChartBox(grouped, { baseLayout: (g) => g, ...mainChartBox })\n : grouped;\n }\n\n // Main-chart box: wrap the whole (drill-filtered) chart in ONE box.\n // The base layout positions the contents; the box frames them.\n if (mainChartBox) {\n return wrapInMainChartBox(filteredGraph, { baseLayout: realBase, ...mainChartBox });\n }\n\n return layout === \"passthrough\" ? filteredGraph : layout(filteredGraph);\n }, [filteredGraph, layout, groupedSet, mainChartBox]);\n\n // ── Runtime overlay slice → mount aggregation ────\n // Overlay stage ids are path-qualified (`subflowPath/stageId`, parsed\n // from runtimeStageId) and structure node ids are ALSO path-qualified\n // now (walkSubflowSpecInto), so they match directly — no leaf-stripping.\n // (The former `normalizeSliceLeafIds` step only existed because\n // structure ids used to be bare; it would now MISMATCH by stripping a\n // qualified id down to its leaf.)\n const slice = useMemo(() => {\n const empty = {\n doneStageIds: new Set<string>(),\n activeStageId: null as string | null,\n executedStageIds: new Set<string>(),\n executedOrderIds: [] as string[],\n errors: new Map<string, string>(),\n };\n if (!overlay) return empty;\n const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);\n return aggregateMountStatus(sliceOverlay(overlay, idx), graph, drill.currentSubflowId);\n }, [overlay, scrubIndex, graph, drill.currentSubflowId]);\n\n // ── xyflow nodes + edges (re-run per scrub tick) ──────────────────\n const reactFlowNodes = useMemo<Node[]>(\n () =>\n positioned.nodes.map((n) =>\n toStageNodeWithOverlay(\n n,\n slice.doneStageIds,\n slice.activeStageId,\n slice.errors.get(n.id),\n slice.executedOrderIds,\n coActiveStageIds ?? EMPTY_SET,\n ),\n ),\n [positioned.nodes, slice, coActiveStageIds],\n );\n const reactFlowEdges = useMemo<Edge[]>(\n () =>\n positioned.edges.map((e) =>\n styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors),\n ),\n [positioned.edges, slice, colors],\n );\n\n // ── Click handling: drill on subflow mount click, propagate click ─\n const handleNodeClick = useCallback(\n (_: unknown, node: Node) => {\n const data = (node.data ?? {}) as StageNodeData;\n // Grouped subflows render inline (no drill) — only drill the ones\n // still in card mode.\n if (data.isSubflow && data.subflowId && !groupedSet.has(data.subflowId)) {\n drill.drillInto(data.subflowId);\n }\n onNodeClick?.(node.id);\n },\n [drill, onNodeClick, groupedSet],\n );\n\n // ── Container auto-refit (xyflow's fitView is mount-only) ─────────\n const wrapperRef = useRef<HTMLDivElement>(null);\n const [rfInstance, setRfInstance] = useState<ReactFlowInstance | null>(null);\n // refitKey = the drill id: drilling in/out swaps the visible subgraph, so the\n // chart must recenter + rezoom to the new content (otherwise the smaller\n // drilled graph keeps the parent's pan/zoom and sits cramped in a corner).\n useChartAutoRefit(wrapperRef, rfInstance, { refitKey: drill.currentSubflowId });\n\n return (\n <div\n ref={wrapperRef}\n className={className}\n style={{\n width: \"100%\",\n height: \"100%\",\n minHeight: 300,\n display: \"flex\",\n flexDirection: \"column\",\n ...style,\n }}\n >\n {breadcrumb.length > 1 && (\n <SubflowBreadcrumbBar\n entries={breadcrumb}\n onNavigate={drill.setCurrentSubflowId}\n />\n )}\n <div style={{ flex: 1, minHeight: 0 }}>\n <ReactFlow\n nodes={reactFlowNodes}\n edges={reactFlowEdges}\n nodeTypes={mergedNodeTypes}\n edgeTypes={mergedEdgeTypes}\n onNodeClick={handleNodeClick}\n onInit={setRfInstance}\n fitView\n proOptions={{ hideAttribution: true }}\n >\n <Background variant={BackgroundVariant.Dots} gap={20} size={1} />\n {children}\n </ReactFlow>\n </div>\n </div>\n );\n}\n","/**\n * Dev-mode detection without depending on `@types/node`.\n *\n * Returns `true` when running outside an explicitly production env.\n * Browser builds (no `process` global) treat as dev — acceptable for\n * a debugging library: a user-visible warning in a browser is a\n * debugging signal anyway.\n *\n * Shared by every translator's notify path + orphan-event warnings.\n */\nexport function isDevModeEnv(): boolean {\n const proc = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process;\n return proc?.env?.NODE_ENV !== \"production\";\n}\n\n/**\n * Dev-mode `console.warn` shim. No-op in production. Lazy message\n * construction (`messageFn`) — avoids string-concat cost when prod.\n */\nexport function devWarn(messageFn: () => string, ...extras: unknown[]): void {\n if (!isDevModeEnv()) return;\n // eslint-disable-next-line no-console\n console.warn(messageFn(), ...extras);\n}\n","/**\n * `createNotifier` — shared pub-sub + monotonic version + microtask\n * batching, extracted from `traceStructureRecorder` and\n * `createTraceRuntimeOverlay` (which duplicated this pattern).\n *\n * Every translator needs the same shape to integrate with React's\n * `useSyncExternalStore`:\n * - `subscribe(listener)` returns unsubscribe\n * - `version()` returns monotonic int (snapshot identity)\n * - `notify()` bumps version + fires listeners (error-isolated)\n *\n * Microtask batching\n * ──────────────────\n * A single stage execution fires multiple recorder events (Structure\n * `onStageAdded` + `onEdgeAdded` for each edge; Flow `onStageExecuted`;\n * Scope `onCommit`). With 3+ translators subscribed, that's 6+ React\n * re-renders per stage. The batcher coalesces all `notify()` calls\n * within one microtask into a SINGLE listener fire — version still\n * bumps per event (so consumers that poll `version()` from outside\n * React see every change), but listener invocations are deduplicated.\n *\n * Trade-off: listeners observe the FINAL state after a microtask\n * batch, not every intermediate state. Acceptable for UI consumers\n * (React renders the final state anyway). Non-React consumers that\n * need every event should call `getSnapshot()` from inside event\n * handlers, not rely on the listener for granularity.\n *\n * Error isolation\n * ───────────────\n * A throwing listener is caught + warned in dev. Other listeners\n * still fire. Mirrors footprintjs's recorder dispatcher pattern.\n */\n\nimport { devWarn } from \"./devWarn\";\n\nexport interface Notifier {\n /** Subscribe a listener; returns unsubscribe. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps once per `notify()` call. */\n version(): number;\n /** Bump version + schedule a listener flush (coalesced via microtask). */\n notify(): void;\n /** Force-flush any pending coalesced notification immediately. Used\n * by tests that need synchronous observation. */\n flushPending(): void;\n /** Reset the notifier — clears listeners is NOT done (consumers\n * manage their own subscriptions). Only the pending-flush flag\n * and version stay as-is (no consumer should observe a version\n * rollback). */\n // (intentionally no reset for version — monotonicity is load-bearing\n // for useSyncExternalStore snapshot equality)\n}\n\nexport function createNotifier(label = \"notifier\"): Notifier {\n const listeners = new Set<() => void>();\n let v = 0;\n let pending = false;\n\n function flush(): void {\n if (!pending) return;\n pending = false;\n // Snapshot listeners into an array BEFORE iteration. A listener\n // that synchronously subscribes/unsubscribes another listener\n // would otherwise leave Set-iteration semantics implementation-\n // defined. Array snapshot guarantees: every listener registered\n // AT THIS FLUSH-START fires exactly once; listeners added during\n // a callback wait for the next notify cycle.\n const snapshot = Array.from(listeners);\n for (const l of snapshot) {\n try {\n l();\n } catch (err) {\n devWarn(\n () =>\n `[${label}] subscribe() listener threw — isolated; other subscribers continue.`,\n err,\n );\n }\n }\n }\n\n return {\n subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n version(): number {\n return v;\n },\n notify(): void {\n v += 1;\n if (pending) return;\n pending = true;\n // Coalesce within a single microtask. `queueMicrotask` is\n // available in every supported runtime (Node 11+, all browsers).\n queueMicrotask(flush);\n },\n flushPending(): void {\n flush();\n },\n };\n}\n","/**\n * createTraceRuntimeOverlay — event-driven runtime overlay for `<TracedFlow>`.\n *\n * The runtime twin of `createTraceStructureRecorder` (L7.7). Where the\n * structure recorder accumulates the build-time graph SHAPE from\n * `StructureRecorder` events, this recorder accumulates the runtime\n * EXECUTION STATE (which nodes ran, current active, errors) from\n * `FlowRecorder` events. The two compose into the full time-travel\n * trace UI:\n *\n * StructureRecorder events → TraceGraph (nodes + edges, id-keyed)\n * FlowRecorder events → RuntimeOverlay (per-node state, id-keyed)\n * │\n * ▼\n * <TracedFlow graph={...} overlay={...} scrubIndex={i} />\n *\n * **Universal key**: `runtimeStageId = [subflowPath/]stageId#executionIndex`.\n * Loops re-execute the same stageId with bumping executionIndex — the\n * overlay records each execution as a distinct step in `executionOrder`\n * but updates the SAME node-by-id in `doneStageIds` (because the build-\n * time graph has one node per spec — loops re-visit it).\n *\n * Per L7.7 panel guidance: the consumer pattern mirrors recorder error\n * isolation, exposes a pub-sub `subscribe(listener)` + monotonic\n * `version()` for `useSyncExternalStore` integration, and accumulates\n * pure data with zero React coupling.\n */\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local type aliases mirroring footprintjs FlowRecorder\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Same rationale as traceStructureRecorder.ts: explainable-ui has no\n// `footprintjs` dep declared (consumer wires it). We mirror the\n// subset of `FlowRecorder` we consume. If footprintjs changes the\n// interface, this module's types update in lockstep.\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface RuntimeStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n /** Discriminator for which kind of stage completed. footprintjs v6+\n * fires this event uniformly for every stage kind (proposal #003);\n * consumers route by `stageType` without a chart-spec lookup. */\n readonly stageType: 'linear' | 'decider' | 'fork' | 'selector' | 'subflow-mount';\n readonly traversalContext: TraversalContext;\n}\n\ninterface RuntimeErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface RuntimeRunStartEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface RuntimeRunEndEvent {\n readonly traversalContext?: TraversalContext;\n}\n\n/** Minimal FlowRecorder interface mirror — see top-of-file rationale.\n *\n * As of footprintjs v6 (proposal #003), `onStageExecuted` fires\n * uniformly for ALL stage kinds — linear / decider / fork / selector\n * / subflow-mount. The event payload carries a `stageType` field for\n * consumers that need to route by kind. We no longer need separate\n * `onDecision` / `onFork` / `onSelected` handlers to track \"did this\n * stage run\" — a single `onStageExecuted` handler suffices. */\nexport interface MinimalFlowRecorder {\n readonly id: string;\n onStageExecuted?(event: RuntimeStageExecutedEvent): void;\n onError?(event: RuntimeErrorEvent): void;\n onRunStart?(event: RuntimeRunStartEvent): void;\n onRunEnd?(event: RuntimeRunEndEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Runtime overlay shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * One entry in the execution timeline. `<TracedFlow>` keys time-travel\n * scrubbing on the index into this array — at index `i`, all entries\n * `0..i-1` are \"done\", entry `i` is \"active\".\n */\nexport interface RuntimeExecutionStep {\n /** `[subflowPath/]stageId#executionIndex` — universal key. */\n readonly runtimeStageId: string;\n /** Base stage id (without `#N`) — matches the `TraceGraph` node id. */\n readonly stageId: string;\n /** Human-readable label (from event.stageName). */\n readonly stageName: string;\n /** When this step recorded, in ms since recorder start. */\n readonly timestampMs: number;\n}\n\nexport interface RuntimeOverlay {\n /** Ordered execution history — drives time-travel scrubbing. */\n readonly executionOrder: readonly RuntimeExecutionStep[];\n /** Per-base-stageId error message (most-recent wins). */\n readonly errors: ReadonlyMap<string, string>;\n /** True after `onRunStart` until `onRunEnd` — useful for \"still running\" indicators. */\n readonly running: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceRuntimeOverlayHandle {\n /** The recorder to attach via `executor.attachFlowRecorder(handle.recorder)`. */\n recorder: MinimalFlowRecorder;\n /** Returns a defensive copy of the current overlay state. */\n getOverlay(): RuntimeOverlay;\n /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps once per overlay-mutating event. */\n version(): number;\n /** Reset for reuse across runs. Does NOT bump version or notify (matches\n * traceStructureRecorder's reset contract). */\n reset(): void;\n}\n\nexport interface CreateTraceRuntimeOverlayOptions {\n id?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nimport { createNotifier } from \"./_internal/notifyChange\";\n\n/**\n * Strip `#executionIndex` suffix to get the base stage id.\n *\n * **WARNING (invariant I3)**: use ONLY for DISPLAY. NEVER for matching\n * commitLog stageIds — those use the full path-prefixed id (e.g.,\n * `'sf-a/sf-b/inner'`) as emitted by the engine. Parsing back to the\n * unqualified inner name loses uniqueness across subflow instances.\n */\nfunction parseStageIdFromRuntimeStageId(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createTraceRuntimeOverlay(\n options: CreateTraceRuntimeOverlayOptions = {},\n): TraceRuntimeOverlayHandle {\n const id = options.id ?? \"trace-runtime-overlay\";\n const startTime = performance.now();\n\n let executionOrder: RuntimeExecutionStep[] = [];\n // Defensive dedupe by runtimeStageId — should be moot post-#003\n // since the engine fires `onStageExecuted` exactly once per stage\n // execution, but a future change or a misbehaving recorder upstream\n // could still produce duplicates; keep the set as belt-and-suspenders.\n const recordedRuntimeStageIds = new Set<string>();\n const errors = new Map<string, string>();\n let running = false;\n const notifier = createNotifier(\"traceRuntimeOverlay\");\n const notifyChange = notifier.notify;\n\n function pushStep(runtimeStageId: string, stageId: string, stageName: string): void {\n if (recordedRuntimeStageIds.has(runtimeStageId)) return;\n recordedRuntimeStageIds.add(runtimeStageId);\n executionOrder.push({\n runtimeStageId,\n stageId,\n stageName,\n timestampMs: performance.now() - startTime,\n });\n notifyChange();\n }\n\n const recorder: MinimalFlowRecorder = {\n id,\n onRunStart() {\n running = true;\n notifyChange();\n },\n onRunEnd() {\n running = false;\n notifyChange();\n },\n onStageExecuted(event) {\n // footprintjs v6 (#003) fires this for EVERY stage kind —\n // linear / decider / fork / selector / subflow-mount — so\n // we no longer need separate handlers for the branching events.\n const runtimeStageId = event.traversalContext.runtimeStageId;\n const baseStageId = parseStageIdFromRuntimeStageId(runtimeStageId);\n pushStep(runtimeStageId, baseStageId, event.stageName);\n },\n onError(event) {\n const fallbackId =\n event.stageId ??\n (event.traversalContext\n ? parseStageIdFromRuntimeStageId(event.traversalContext.runtimeStageId)\n : event.stageName);\n errors.set(fallbackId, event.message ?? \"error\");\n notifyChange();\n },\n };\n\n return {\n recorder,\n getOverlay(): RuntimeOverlay {\n return {\n executionOrder: executionOrder.map((s) => ({ ...s })),\n errors: new Map(errors),\n running,\n };\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n executionOrder = [];\n recordedRuntimeStageIds.clear();\n errors.clear();\n running = false;\n // Note: reset does NOT bump version or notify (matches\n // traceStructureRecorder contract — see its `reset()` JSDoc\n // for the consumer-facing recipe).\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Overlay slicing for time-travel\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Snapshot of overlay state AT a specific scrub index. Drives node\n * coloring in `<TracedFlow>`.\n */\nexport interface RuntimeOverlaySlice {\n /** Base stage ids that completed before the active scrub position. */\n readonly doneStageIds: ReadonlySet<string>;\n /** The currently-active stage id (or `null` when scrub is at 0 with no exec yet). */\n readonly activeStageId: string | null;\n /** Union of done + active — convenient for \"executed at all\" checks. */\n readonly executedStageIds: ReadonlySet<string>;\n /** The full ordered list of base stage ids up through the active position —\n * used by renderers that want to number stages by occurrence (e.g.,\n * show \"3rd loop iteration\" badges). */\n readonly executedOrderIds: readonly string[];\n /** Pass-through errors map for the renderer. */\n readonly errors: ReadonlyMap<string, string>;\n}\n\n/**\n * Slice `overlay.executionOrder` at the given index:\n *\n * - `executionOrder[0..index-1]` → \"done\"\n * - `executionOrder[index]` → \"active\"\n * - `index >= executionOrder.length` → all done, no active\n *\n * Returns an empty slice when overlay has no execution history.\n */\nexport function sliceOverlay(\n overlay: RuntimeOverlay,\n index: number,\n): RuntimeOverlaySlice {\n const order = overlay.executionOrder;\n if (order.length === 0) {\n return {\n doneStageIds: new Set(),\n activeStageId: null,\n executedStageIds: new Set(),\n executedOrderIds: [],\n errors: overlay.errors,\n };\n }\n const clampedIndex = Math.max(0, Math.min(index, order.length - 1));\n const doneStageIds = new Set<string>();\n for (let i = 0; i < clampedIndex; i++) {\n doneStageIds.add(order[i]!.stageId);\n }\n const activeStep = order[clampedIndex];\n const activeStageId = activeStep ? activeStep.stageId : null;\n const executedStageIds = new Set(doneStageIds);\n if (activeStageId) executedStageIds.add(activeStageId);\n const executedOrderIds = order.slice(0, clampedIndex + 1).map((s) => s.stageId);\n return {\n doneStageIds,\n activeStageId,\n executedStageIds,\n executedOrderIds,\n errors: overlay.errors,\n };\n}\n","/**\n * Pure helpers for subflow drill-down on a `TraceGraph`.\n *\n * Filtering and breadcrumb computation are derived from the\n * `TraceNodeData.subflowOf` field that the structure recorder sets\n * at `onSubflowMounted` time. Both functions are pure (no I/O, no\n * React) so they can be unit-tested in isolation and reused by any\n * renderer.\n */\n\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\n/**\n * Filter the trace graph by drill-down scope.\n *\n * - `currentSubflowId === null` → show top-level (nodes with no\n * `subflowOf`). Subflow internals are hidden; their mount node\n * stays visible as a single clickable card.\n * - `currentSubflowId === 'X'` → show only nodes where\n * `subflowOf === 'X'` (the drilled-in subflow's internals).\n *\n * Edges follow the same filter — only edges where both endpoints\n * are in the visible set survive. When nothing would be filtered\n * out, returns the original graph reference (preserves upstream\n * memoization).\n */\nexport function filterGraphForDrill(\n graph: TraceGraph,\n currentSubflowId: string | null,\n): TraceGraph {\n if (graph.nodes.length === 0) return graph;\n const matchesScope = (subflowOf: string | undefined): boolean =>\n currentSubflowId === null ? subflowOf === undefined : subflowOf === currentSubflowId;\n const visibleIds = new Set<string>();\n for (const n of graph.nodes) {\n if (matchesScope(n.data?.subflowOf)) visibleIds.add(n.id);\n }\n if (visibleIds.size === graph.nodes.length) return graph;\n return {\n nodes: graph.nodes.filter((n) => visibleIds.has(n.id)),\n edges: graph.edges.filter((e) => visibleIds.has(e.source) && visibleIds.has(e.target)),\n };\n}\n\n/** Entry in the breadcrumb path. `subflowId === null` is the root. */\nexport interface BreadcrumbEntry {\n subflowId: string | null;\n label: string;\n}\n\n/**\n * Build the breadcrumb path for the current drill level.\n *\n * Always starts with the root `{ subflowId: null, label: 'Chart' }`.\n * When drilled into a subflow, appends one entry with the mount\n * node's display label (falling back to the subflow id). Multi-level\n * drill chains are NOT supported by the current chart UX (drill is\n * always from root or sibling — clicking a deeper subflow's mount\n * replaces the current scope), so the path has at most 2 entries.\n */\nexport function buildSubflowBreadcrumb(\n graph: TraceGraph,\n currentSubflowId: string | null,\n): BreadcrumbEntry[] {\n const out: BreadcrumbEntry[] = [{ subflowId: null, label: \"Chart\" }];\n if (currentSubflowId !== null) {\n const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);\n out.push({\n subflowId: currentSubflowId,\n label: mount?.data?.label ?? currentSubflowId,\n });\n }\n return out;\n}\n","/**\n * Pure helper for projecting a raw `RuntimeOverlaySlice` into the\n * shape `<TracedFlow>` needs for per-node coloring:\n *\n * `aggregateMountStatus` — when execution is INSIDE a subflow, light\n * up the mount node in the parent view as done/active based on its\n * internals' statuses.\n *\n * Pure (no I/O, no React).\n *\n * Note: there is NO id-normalization step. Both the overlay slice and\n * the structure graph use path-QUALIFIED stage ids (`subflowPath/stageId`,\n * mirroring runtimeStageId), so they match directly. (A former\n * `normalizeSliceLeafIds` step existed only while structure ids were\n * bare; once `walkSubflowSpecInto` started qualifying inner ids, leaf-\n * stripping became a mismatch and was removed.)\n */\n\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\nexport interface OverlaySlice {\n doneStageIds: ReadonlySet<string>;\n activeStageId: string | null;\n executedStageIds: ReadonlySet<string>;\n executedOrderIds: readonly string[];\n errors: ReadonlyMap<string, string>;\n}\n\n/**\n * Aggregate subflow internals' status onto their mount nodes.\n *\n * - Mount is DONE when EVERY internal stage is done.\n * - Mount is ACTIVE only when an internal stage is CURRENTLY active\n * (not merely past-done), and only when viewing the TOP-LEVEL chart\n * (`currentSubflowId === null`). When drilled INTO a subflow, the\n * active highlight stays on the actual subflow stage, not the mount.\n * (Promoting on past-done internals let a looping subflow steal\n * \"active\" from the real live top-level node — see the inline note.)\n *\n * Pre-condition: slice has already been leaf-normalized so its\n * stage ids match `graph.nodes[].id`.\n */\nexport function aggregateMountStatus(\n slice: OverlaySlice,\n graph: TraceGraph,\n currentSubflowId: string | null,\n): OverlaySlice {\n if (graph.nodes.length === 0) return slice;\n const mounts = graph.nodes.filter((n) => n.data?.isSubflow && n.data?.subflowId);\n if (mounts.length === 0) return slice;\n const doneIds = new Set(slice.doneStageIds);\n let activeId = slice.activeStageId;\n for (const mount of mounts) {\n const sfId = mount.data!.subflowId as string;\n const members = graph.nodes.filter((n) => n.data?.subflowOf === sfId);\n if (members.length === 0) continue;\n const anyActive = members.some((m) => m.id === slice.activeStageId);\n const allDone = members.every((m) => slice.doneStageIds.has(m.id));\n if (allDone) doneIds.add(mount.id);\n // Promote \"active\" to the mount ONLY when the live node is genuinely INSIDE\n // this subflow (anyActive). Previously a mount with merely PAST-done members\n // (`anyDone`) also stole active — and once subflow internals are materialised\n // (for drill), a looping subflow's earlier-iteration done members made the\n // mount steal \"active\" from the real top-level live node (e.g. the tool\n // call), so that node's NOW highlight disappeared. The mount's own done-ness\n // still comes from its own commit + the allDone branch above.\n else if (anyActive && currentSubflowId === null) {\n activeId = mount.id;\n }\n }\n return { ...slice, doneStageIds: doneIds, activeStageId: activeId };\n}\n","/**\n * useSubflowDrill — drill state for the chart's view scope.\n *\n * - Owns `currentSubflowId: string | null` (null = top-level)\n * - Exposes `drillInto(subflowId)` and `drillUp()` for navigation\n * - Notifies the host via `onSubflowChange(mountStageId | null)`\n * whenever the drill state changes — host wires this to its own\n * drill-stack so data panels follow\n *\n * Drill changes are EXPLICIT — there's no auto-drill on scrub. The\n * mount node's status reflects \"execution is inside\" via\n * `aggregateMountStatus` (see overlayProjection.ts).\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport type { TraceGraph } from \"../traceStructureRecorder\";\n\nexport interface SubflowDrillHandle {\n /** Current drill scope. `null` = top-level. */\n currentSubflowId: string | null;\n /** Navigate INTO the given subflow (by `subflowId`). */\n drillInto: (subflowId: string) => void;\n /** Pop back up to the parent / top-level. */\n drillUp: () => void;\n /** Direct setter for breadcrumb navigation (any target including `null`). */\n setCurrentSubflowId: (id: string | null) => void;\n}\n\nexport function useSubflowDrill(\n graph: TraceGraph,\n onSubflowChange?: (mountStageId: string | null) => void,\n): SubflowDrillHandle {\n const [currentSubflowId, setCurrentSubflowId] = useState<string | null>(null);\n\n // Reset drill state when the graph IDENTITY changes (e.g., the\n // user switched to a different sample in the playground sidebar).\n // Without this, the drill state from sample A persists into\n // sample B's rendering — `currentSubflowId='payment'` survives the\n // chart swap, but sample B has no 'payment' subflow, so the filter\n // returns no visible nodes (blank chart).\n //\n // Also reset when the currently-drilled subflow no longer exists\n // in the new graph (defensive — graph mutations could remove a\n // subflow without changing the wrapper reference).\n const lastGraphRef = useRef<TraceGraph | null>(null);\n if (lastGraphRef.current !== graph) {\n lastGraphRef.current = graph;\n if (\n currentSubflowId !== null &&\n !graph.nodes.some((n) => n.data?.subflowId === currentSubflowId)\n ) {\n // Schedule reset for next render (can't setState during render).\n queueMicrotask(() => setCurrentSubflowId(null));\n }\n }\n\n // Notify the host when drill changes. Resolve the mount stage id\n // from the graph (the parent-chart node whose `subflowId` matches).\n const lastNotifiedRef = useRef<string | null | undefined>(undefined);\n useEffect(() => {\n if (lastNotifiedRef.current === currentSubflowId) return;\n lastNotifiedRef.current = currentSubflowId;\n if (currentSubflowId === null) {\n onSubflowChange?.(null);\n } else {\n const mount = graph.nodes.find((n) => n.data?.subflowId === currentSubflowId);\n if (mount) onSubflowChange?.(mount.id);\n }\n }, [currentSubflowId, graph, onSubflowChange]);\n\n const drillInto = useCallback((subflowId: string) => {\n setCurrentSubflowId(subflowId);\n }, []);\n const drillUp = useCallback(() => {\n setCurrentSubflowId(null);\n }, []);\n\n return { currentSubflowId, drillInto, drillUp, setCurrentSubflowId };\n}\n","/**\n * useChartAutoRefit — keep an xyflow chart fitted to its container.\n *\n * xyflow's `fitView` prop only runs on mount; it does NOT re-fit\n * when the container resizes. This hook closes that gap by:\n *\n * 1. Observing the wrapper element via `ResizeObserver` →\n * `instance.fitView({ duration, padding })` on the next animation\n * frame (so the new container size is measured first).\n * 2. Also listening to `window resize` events — `ExplainableShell`\n * dispatches synthetic resize events when its detail panels\n * toggle (those size changes may be animated and not yet\n * measurable by ResizeObserver on the first tick).\n *\n * Without this hook the chart shrinks once on Details-open and\n * never grows back when Details closes.\n *\n * It ALSO re-fits when the VISIBLE GRAPH changes (e.g. drilling into /\n * out of a subflow). xyflow only auto-fits on mount, so after a drill the\n * new, smaller subgraph keeps the parent chart's pan/zoom — leaving it\n * cramped in one corner with empty space around it. Pass a `refitKey`\n * (the drill id) so the chart recenters + rezooms to the drilled content.\n */\n\nimport { useEffect } from \"react\";\nimport type { RefObject } from \"react\";\nimport type { ReactFlowInstance } from \"@xyflow/react\";\n\nexport function useChartAutoRefit(\n wrapperRef: RefObject<HTMLElement | null>,\n rfInstance: ReactFlowInstance | null,\n options: { duration?: number; padding?: number; refitKey?: unknown } = {},\n): void {\n const duration = options.duration ?? 200;\n const padding = options.padding ?? 0.1;\n const refitKey = options.refitKey;\n\n useEffect(() => {\n const el = wrapperRef.current;\n if (!el || !rfInstance) return;\n let raf = 0;\n const refit = () => {\n cancelAnimationFrame(raf);\n raf = requestAnimationFrame(() => {\n rfInstance.fitView({ duration, padding });\n });\n };\n const ro = new ResizeObserver(refit);\n ro.observe(el);\n window.addEventListener(\"resize\", refit);\n return () => {\n ro.disconnect();\n window.removeEventListener(\"resize\", refit);\n cancelAnimationFrame(raf);\n };\n }, [rfInstance, wrapperRef, duration, padding]);\n\n // Re-fit when the visible graph changes (drill in/out). Two rAFs: the first\n // lets React commit the new node set, the second lets xyflow measure the new\n // nodes' dimensions before fitView reads them — otherwise fitView centers on\n // stale/zero-size bounds and the drilled chart still lands off-center.\n useEffect(() => {\n if (!rfInstance) return;\n let raf2 = 0;\n const raf1 = requestAnimationFrame(() => {\n raf2 = requestAnimationFrame(() => {\n rfInstance.fitView({ duration, padding });\n });\n });\n return () => {\n cancelAnimationFrame(raf1);\n cancelAnimationFrame(raf2);\n };\n }, [rfInstance, refitKey, duration, padding]);\n}\n","/**\n * SubflowBreadcrumbBar — clickable trail of subflow drill levels.\n *\n * Chart › Outer Subflow › Inner Subflow\n *\n * The last entry renders disabled (you're already here). Earlier\n * entries are clickable — fire `onNavigate(subflowId)` (null = root).\n *\n * Pure presentation: takes the precomputed `entries` array (built by\n * `buildSubflowBreadcrumb` in `_internal/subflowDrill.ts`). No drill\n * state lives here.\n */\n\nimport type { BreadcrumbEntry } from \"./_internal/subflowDrill\";\nimport { rawDefaults } from \"../../theme/tokens\";\n\nexport interface SubflowBreadcrumbBarProps {\n entries: BreadcrumbEntry[];\n onNavigate: (subflowId: string | null) => void;\n}\n\nexport function SubflowBreadcrumbBar({ entries, onNavigate }: SubflowBreadcrumbBarProps) {\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"6px 12px\",\n fontSize: 11,\n background: rawDefaults.colors.bgSecondary,\n borderBottom: `1px solid ${rawDefaults.colors.border}`,\n flexShrink: 0,\n }}\n aria-label=\"Subflow breadcrumb\"\n >\n {entries.map((entry, i) => {\n const isLast = i === entries.length - 1;\n return (\n <span\n key={entry.subflowId ?? \"__top__\"}\n style={{ display: \"inline-flex\", alignItems: \"center\", gap: 6 }}\n >\n <button\n type=\"button\"\n onClick={() => onNavigate(entry.subflowId)}\n disabled={isLast}\n style={{\n background: \"transparent\",\n border: \"none\",\n padding: 0,\n fontSize: 11,\n fontWeight: isLast ? 600 : 500,\n color: isLast ? rawDefaults.colors.textPrimary : rawDefaults.colors.primary,\n cursor: isLast ? \"default\" : \"pointer\",\n textDecoration: isLast ? \"none\" : \"underline\",\n fontFamily: \"inherit\",\n }}\n >\n {entry.label}\n </button>\n {!isLast && <span style={{ color: rawDefaults.colors.textMuted }}>›</span>}\n </span>\n );\n })}\n </div>\n );\n}\n","/**\n * GroupContainerNode — xyflow renderer for a subflow rendered as a GROUP\n * box (the `parentId` + `extent:'parent'` sub-flow pattern). Produced by\n * `applyGroupLayout` (it retypes a subflow mount to `groupContainer` and\n * sizes it via `style.width/height`); the subflow's member stages render\n * NESTED inside, as their own xyflow nodes positioned over this box.\n *\n * This box is therefore mostly chrome: a titled, bordered frame the member\n * nodes sit inside. It carries top/bottom handles so the parent-chain edges\n * (e.g. `context → this`, `this → message-api`) still connect to it.\n *\n * Overlay-aware: when the subflow's internals are active/done (aggregated\n * onto the mount by `aggregateMountStatus`), the frame highlights — same\n * done/active semantics the bundled `StageNode` uses.\n */\n\nimport { Handle, Position } from \"@xyflow/react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport { rawDefaults } from \"../../theme/tokens\";\n\nconst C = rawDefaults.colors;\n\nexport interface GroupContainerNodeData {\n label: string;\n isGroupContainer?: boolean;\n active?: boolean;\n done?: boolean;\n error?: boolean;\n dimmed?: boolean;\n description?: string;\n icon?: string;\n [key: string]: unknown;\n}\n\nexport function GroupContainerNode({ data }: NodeProps) {\n const d = data as GroupContainerNodeData;\n const borderColor = d.error\n ? C.error\n : d.active\n ? C.primary\n : d.done\n ? C.success\n : C.border;\n\n return (\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n boxSizing: \"border-box\",\n border: `1.5px ${d.active || d.done || d.error ? \"solid\" : \"dashed\"} ${borderColor}`,\n borderRadius: 12,\n // Translucent so the dotted background + nested children read clearly.\n background: \"rgba(148, 163, 184, 0.06)\",\n opacity: d.dimmed ? 0.4 : 1,\n position: \"relative\",\n }}\n >\n {/* Title header strip. */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n padding: \"8px 12px\",\n fontSize: 12,\n fontWeight: 600,\n color: C.textMuted,\n letterSpacing: 0.2,\n }}\n >\n {d.icon ? <span aria-hidden>{d.icon}</span> : null}\n <span>{d.label}</span>\n </div>\n\n {/* Edge handles — top target, bottom source (top→bottom flow). */}\n <Handle type=\"target\" position={Position.Top} style={{ opacity: 0 }} />\n <Handle type=\"source\" position={Position.Bottom} style={{ opacity: 0 }} />\n </div>\n );\n}\n","import { memo } from \"react\";\nimport { theme } from \"../../theme\";\nimport type { BreadcrumbEntry } from \"./useSubflowNavigation\";\n\nexport interface SubflowBreadcrumbProps {\n breadcrumbs: BreadcrumbEntry[];\n onNavigate: (level: number) => void;\n}\n\n/**\n * Breadcrumb bar for subflow drill-down navigation.\n * Shows: Root > SubflowA > SubflowB — clicking any crumb navigates back.\n */\nexport const SubflowBreadcrumb = memo(function SubflowBreadcrumb({\n breadcrumbs,\n onNavigate,\n}: SubflowBreadcrumbProps) {\n if (breadcrumbs.length <= 1) return null;\n\n return (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 4,\n padding: \"6px 12px\",\n background: theme.bgSecondary,\n borderBottom: `1px solid ${theme.border}`,\n fontSize: 12,\n fontFamily: theme.fontSans,\n flexShrink: 0,\n overflowX: \"auto\",\n }}\n >\n {breadcrumbs.map((crumb, i) => {\n const isLast = i === breadcrumbs.length - 1;\n return (\n <span key={`${crumb.label}-${i}`} style={{ display: \"flex\", alignItems: \"center\", gap: 4 }}>\n {i > 0 && (\n <span style={{ color: theme.textMuted, fontSize: 10 }}>\n ›\n </span>\n )}\n {isLast ? (\n <span style={{ display: \"flex\", alignItems: \"center\", gap: 6 }}>\n <span\n style={{\n color: theme.primary,\n fontWeight: 600,\n }}\n >\n {crumb.label}\n </span>\n {crumb.description && (\n <span\n style={{\n color: theme.textMuted,\n fontWeight: 400,\n fontSize: 11,\n }}\n >\n — {crumb.description}\n </span>\n )}\n </span>\n ) : (\n <button\n onClick={() => onNavigate(i)}\n style={{\n background: \"none\",\n border: \"none\",\n color: theme.textSecondary,\n cursor: \"pointer\",\n padding: \"2px 4px\",\n borderRadius: 4,\n fontSize: 12,\n fontFamily: \"inherit\",\n fontWeight: 500,\n transition: \"color 0.15s\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.color = `${theme.primary}`;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.color = `${theme.textSecondary}`;\n }}\n >\n {crumb.label}\n </button>\n )}\n </span>\n );\n })}\n </div>\n );\n});\n","/**\n * useSubflowNavigation — drill-down breadcrumb tracker for recorder-driven charts.\n *\n * Recorder-driven (v6+): replaces the legacy SpecNode-walk path. Accepts\n * a `TraceGraph` (from `createTraceStructureRecorder`) and tracks WHICH\n * subflow the user has drilled into.\n *\n * Limitation (intentional — recorder graph is flat / mount-only):\n * The StructureRecorder records the MOUNT of each subflow in the\n * parent chart, not the inner structure of each child chart. So\n * \"drill into a subflow\" today returns the SAME graph with the\n * `currentSubflowId` marker advanced — there is no separate\n * child-graph to swap in. Filtering nodes by\n * `data.subflowId === <selected>` would only surface mount nodes,\n * not the child chart's stages.\n *\n * TODO(recorder-driven-nesting): when child charts attach their own\n * `traceStructureRecorder` and surface those graphs via a registry,\n * accept `Map<subflowId, TraceGraph>` and swap `currentGraph` to the\n * child's graph on drill-down. Consumers can then render\n * `<TraceFlow graph={currentGraph} />` per level.\n */\n\nimport { useState, useCallback, useMemo } from \"react\";\nimport type { TraceGraph } from \"./traceStructureRecorder\";\n\nexport interface BreadcrumbEntry {\n /** Display name for this level */\n label: string;\n /** The subflow id that was drilled into to reach this level\n * (undefined for root). */\n subflowId?: string;\n /** Human-readable description of this subflow */\n description?: string;\n}\n\nexport interface SubflowNavigation {\n /** Current breadcrumb path (root → ... → current) */\n breadcrumbs: BreadcrumbEntry[];\n /** Current graph — today identical to the root graph (see file-level\n * TODO). Consumers should still treat this as the source of truth so\n * they remain forward-compatible once per-subflow graphs are wired in. */\n currentGraph: TraceGraph;\n /** Subflow id of the level the user is currently inside (null at root). */\n currentSubflowId: string | null;\n /** Display name of the subflow node we drilled into (null at root). */\n currentSubflowNodeName: string | null;\n /** Call when a node is clicked — drills in if it's a subflow.\n * Returns true when the click pushed a new level. */\n handleNodeClick: (nodeId: string) => boolean;\n /** Navigate to a specific breadcrumb level (0 = root) */\n navigateTo: (level: number) => void;\n /** Whether we're currently inside a subflow (not at root) */\n isInSubflow: boolean;\n}\n\nconst EMPTY_GRAPH: TraceGraph = { nodes: [], edges: [] };\n\n/**\n * Hook that tracks subflow drill-down state for a recorder-driven chart.\n *\n * Maintains a breadcrumb stack. When a subflow node is clicked the\n * stack pushes a new entry; breadcrumb clicks pop back to that level.\n * See file-level docs for the deferred per-subflow graph swap.\n */\nexport function useSubflowNavigation(\n rootGraph: TraceGraph | null,\n): SubflowNavigation {\n const [stack, setStack] = useState<BreadcrumbEntry[]>([]);\n\n const safeRootGraph = rootGraph ?? EMPTY_GRAPH;\n\n // Lookup: subflow id → mount node display name. Populated from the\n // recorder graph so click handlers can resolve the node-id the\n // consumer passes.\n const subflowMounts = useMemo(() => {\n const map = new Map<\n string,\n { subflowId: string; label: string; description?: string }\n >();\n for (const node of safeRootGraph.nodes) {\n if (!node.data?.isSubflow) continue;\n const subflowId =\n typeof node.data.subflowId === \"string\" ? node.data.subflowId : node.id;\n const label =\n typeof node.data.label === \"string\" ? node.data.label : node.id;\n const entry: { subflowId: string; label: string; description?: string } = {\n subflowId,\n label,\n };\n if (typeof node.data.description === \"string\") {\n entry.description = node.data.description;\n }\n // Key by stable id AND by the node id callers usually pass.\n map.set(node.id, entry);\n map.set(subflowId, entry);\n }\n return map;\n }, [safeRootGraph]);\n\n const breadcrumbs: BreadcrumbEntry[] = useMemo(() => {\n const rootLabel = \"Flowchart\";\n const root: BreadcrumbEntry = { label: rootLabel };\n return [root, ...stack];\n }, [stack]);\n\n const handleNodeClick = useCallback(\n (nodeId: string): boolean => {\n const mount = subflowMounts.get(nodeId);\n if (!mount) return false;\n setStack((prev) => {\n const entry: BreadcrumbEntry = {\n label: mount.label,\n subflowId: mount.subflowId,\n };\n if (mount.description !== undefined) entry.description = mount.description;\n return [...prev, entry];\n });\n return true;\n },\n [subflowMounts],\n );\n\n const navigateTo = useCallback((level: number) => {\n if (level === 0) {\n setStack([]);\n } else {\n setStack((prev) => prev.slice(0, level));\n }\n }, []);\n\n const top = stack[stack.length - 1];\n return {\n breadcrumbs,\n // TODO(recorder-driven-nesting): swap to per-subflow graph when\n // child charts attach their own recorders.\n currentGraph: safeRootGraph,\n currentSubflowId: top?.subflowId ?? null,\n currentSubflowNodeName: top?.label ?? null,\n handleNodeClick,\n navigateTo,\n isInSubflow: stack.length > 0,\n };\n}\n","/**\n * SubflowTree — collapsible sidebar listing mounted subflows.\n *\n * Recorder-driven (v6+): derives the tree from a `TraceGraph` produced\n * by `createTraceStructureRecorder`. Filters nodes by\n * `data.isSubflow === true` and lists them as `SubflowTreeEntry[]`\n * keyed by `subflowId`.\n *\n * Limitation (intentional — recorder graph is flat / mount-only):\n * Subflow-within-subflow nesting is NOT represented. The\n * StructureRecorder records the MOUNT of each subflow in the parent\n * chart, not the inner structure of each child chart. Rendering the\n * nested tree requires a separate recorder attached to each child\n * chart instance (deferred — see TODO below).\n *\n * Shared navigation layer — humans click through the tree just like\n * LLMs call getSubflowManifest() / getSubflowSpec().\n *\n * TODO(recorder-driven-nesting): when child charts attach their own\n * `traceStructureRecorder` and surface those graphs via a parent\n * registry, accept `Map<subflowId, TraceGraph>` and recurse to\n * restore the nested rendering the legacy SpecNode-walk supported.\n *\n * All colors come from `--fp-*` CSS variables set by the consumer.\n */\nimport { memo, useState, useCallback, useMemo } from \"react\";\nimport { theme } from \"../../theme\";\nimport type { TraceGraph } from \"./traceStructureRecorder\";\nimport type { BaseComponentProps } from \"../../types\";\n\nexport interface SubflowTreeEntry {\n /** Node name / identifier */\n name: string;\n /** Human-readable description */\n description?: string;\n /** Subflow ID (when this node represents a subflow) */\n subflowId?: string;\n /** Whether this node is a subflow root (has nested structure) */\n isSubflow?: boolean;\n /** Nested children (subflow stages) — always undefined in the\n * current recorder-driven implementation; see file-level TODO. */\n children?: SubflowTreeEntry[];\n}\n\nexport interface SubflowTreeProps extends BaseComponentProps {\n /** Recorder-captured graph from `createTraceStructureRecorder().getGraph()`. */\n graph: TraceGraph;\n /** Currently active stage name (highlights in tree) */\n activeStage?: string | null;\n /** Set of completed stage names */\n doneStages?: Set<string>;\n /** Called when a tree node is clicked */\n onNodeSelect?: (name: string, isSubflow: boolean) => void;\n}\n\n/** Extracts subflow entries from a recorder graph. Insertion-order preserving. */\nexport function graphToSubflowEntries(graph: TraceGraph): SubflowTreeEntry[] {\n if (!graph?.nodes?.length) return [];\n const entries: SubflowTreeEntry[] = [];\n for (const node of graph.nodes) {\n if (!node.data?.isSubflow) continue;\n const entry: SubflowTreeEntry = {\n name: typeof node.data.label === \"string\" ? node.data.label : node.id,\n isSubflow: true,\n };\n if (typeof node.data.description === \"string\") entry.description = node.data.description;\n if (typeof node.data.subflowId === \"string\") entry.subflowId = node.data.subflowId;\n entries.push(entry);\n }\n return entries;\n}\n\n/** Single tree node row */\nconst TreeNode = memo(function TreeNode({\n entry,\n depth,\n activeStage,\n doneStages,\n onNodeSelect,\n}: {\n entry: SubflowTreeEntry;\n depth: number;\n activeStage?: string | null;\n doneStages?: Set<string>;\n onNodeSelect?: (name: string, isSubflow: boolean) => void;\n}) {\n const [expanded, setExpanded] = useState(true);\n const hasChildren = entry.children && entry.children.length > 0;\n const isActive = activeStage === entry.name;\n const isDone = doneStages?.has(entry.name);\n\n const handleClick = useCallback(() => {\n if (hasChildren) {\n setExpanded((prev) => !prev);\n }\n onNodeSelect?.(entry.name, !!entry.isSubflow);\n }, [hasChildren, onNodeSelect, entry.name, entry.isSubflow]);\n\n return (\n <>\n <button\n onClick={handleClick}\n data-fp=\"subflow-tree-node\"\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n width: \"100%\",\n border: \"none\",\n background: isActive\n ? `color-mix(in srgb, ${theme.primary} 15%, transparent)`\n : \"transparent\",\n cursor: \"pointer\",\n padding: `4px 8px 4px ${8 + depth * 16}px`,\n fontFamily: theme.fontSans,\n fontSize: 12,\n textAlign: \"left\",\n borderRadius: 4,\n transition: \"background 0.15s\",\n }}\n onMouseEnter={(e) => {\n if (!isActive) {\n e.currentTarget.style.background = `color-mix(in srgb, ${theme.textMuted} 10%, transparent)`;\n }\n }}\n onMouseLeave={(e) => {\n if (!isActive) {\n e.currentTarget.style.background = \"transparent\";\n }\n }}\n >\n {/* Expand/collapse chevron for subflows */}\n {hasChildren ? (\n <span\n style={{\n fontSize: 10,\n color: theme.textMuted,\n width: 12,\n textAlign: \"center\",\n flexShrink: 0,\n transition: \"transform 0.15s\",\n transform: expanded ? \"rotate(90deg)\" : \"rotate(0deg)\",\n display: \"inline-block\",\n }}\n >\n ▶\n </span>\n ) : (\n <span style={{ width: 12, flexShrink: 0 }} />\n )}\n\n {/* Status dot */}\n <span\n style={{\n width: 6,\n height: 6,\n borderRadius: \"50%\",\n flexShrink: 0,\n background: isActive\n ? theme.primary\n : isDone\n ? theme.success\n : theme.border,\n }}\n />\n\n {/* Label + description */}\n <span style={{ display: \"flex\", flexDirection: \"column\", minWidth: 0 }}>\n <span\n style={{\n color: isActive\n ? theme.primary\n : isDone\n ? theme.textPrimary\n : theme.textSecondary,\n fontWeight: isActive ? 600 : entry.isSubflow ? 500 : 400,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {entry.name}\n {entry.isSubflow && (\n <span style={{ opacity: 0.5, marginLeft: 4, fontSize: 10 }}>⊞</span>\n )}\n </span>\n {entry.description && (\n <span\n style={{\n color: theme.textMuted,\n fontSize: 10,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }}\n >\n {entry.description}\n </span>\n )}\n </span>\n </button>\n\n {/* Children */}\n {hasChildren && expanded && (\n <div>\n {entry.children!.map((child, i) => (\n <TreeNode\n key={child.subflowId ?? `${child.name}-${i}`}\n entry={child}\n depth={depth + 1}\n activeStage={activeStage}\n doneStages={doneStages}\n onNodeSelect={onNodeSelect}\n />\n ))}\n </div>\n )}\n </>\n );\n});\n\n/** Section label used for \"Flowchart\" and \"Subflows\" headings. */\nconst SectionLabel = memo(function SectionLabel({ children }: { children: string }) {\n return (\n <div\n style={{\n padding: \"4px 12px 8px\",\n fontSize: 10,\n fontWeight: 600,\n textTransform: \"uppercase\",\n letterSpacing: \"0.05em\",\n color: theme.textMuted,\n }}\n >\n {children}\n </div>\n );\n});\n\nexport const SubflowTree = memo(function SubflowTree({\n graph,\n activeStage,\n doneStages,\n onNodeSelect,\n unstyled = false,\n className,\n style,\n}: SubflowTreeProps) {\n const subflowStages = useMemo(() => graphToSubflowEntries(graph), [graph]);\n\n // Don't render anything if there are no subflows\n if (subflowStages.length === 0) return null;\n\n return (\n <div\n className={className}\n data-fp=\"subflow-tree\"\n style={{\n ...(unstyled\n ? {}\n : {\n fontFamily: theme.fontSans,\n fontSize: 12,\n background: theme.bgPrimary,\n borderRight: `1px solid ${theme.border}`,\n overflowY: \"auto\",\n overflowX: \"hidden\",\n padding: \"8px 0\",\n }),\n ...style,\n }}\n >\n {!unstyled && <SectionLabel>Subflows</SectionLabel>}\n {subflowStages.map((entry, i) => (\n <TreeNode\n key={entry.subflowId ?? `${entry.name}-${i}`}\n entry={entry}\n depth={0}\n activeStage={activeStage}\n doneStages={doneStages}\n onNodeSelect={onNodeSelect}\n />\n ))}\n </div>\n );\n});\n","/**\n * Branded types for translator key discipline.\n *\n * The footprintjs/trace contract uses two distinct identity strings:\n *\n * - **StageId**: the stable identifier the user picks at build time\n * (e.g. `'load-order'`, `'check-inventory'`). Identity per chart spec.\n *\n * - **RuntimeStageId**: `[subflowPath/]stageId#executionIndex` — the\n * per-execution identity. A loop visiting the same stage 3 times\n * produces 3 distinct RuntimeStageIds with the same StageId base.\n *\n * Translator outputs index per-stage data by StageId (`Map<StageId, ...>`)\n * AND per-execution data by RuntimeStageId (`Map<RuntimeStageId, ...>`).\n * Both are `string` at runtime — TypeScript can't distinguish them\n * without help. Branded types make `byStageId.get(runtimeStageId)` a\n * **compile-time error** instead of a silent `undefined` at runtime.\n *\n * Why branded types over wrapper classes\n * ──────────────────────────────────────\n * - Zero runtime cost (the brand exists only at the type level)\n * - JSON-serializable as-is (no `toJSON` glue needed)\n * - Interop with consumer code that uses raw `string` is one cast\n * (`stageId as StageId`) when the consumer is sure of the source.\n *\n * Usage pattern\n * ─────────────\n * ```ts\n * import type { StageId, RuntimeStageId } from './_internal/keys';\n *\n * // In a translator, when accepting input from a footprintjs event:\n * const sid = event.stageId as StageId;\n * const rsid = event.traversalContext.runtimeStageId as RuntimeStageId;\n *\n * // In a consumer reading from the index:\n * const node = index.byStageId.get(stageId); // typechecks\n * const node = index.byStageId.get(runtimeStageId); // TS ERROR ✓\n * ```\n *\n * Helper to derive a StageId from a RuntimeStageId — strips `#N` suffix\n * and optional subflow path. **Use only for DISPLAY**, NEVER for matching\n * commitLog stageIds (see invariant I3 in `traceStructureRecorder.ts`).\n */\n\n// String-literal brands (NOT `unique symbol`) — survive `.d.ts` emit\n// across module boundaries. Unique-symbol brands get serialized as\n// new local symbols when consumers compile their own .d.ts, causing\n// \"missing property [unique symbol]\" errors. String literals stay\n// nominal because the literal value is identical across builds.\n\n/** Stable per-spec identifier (e.g. `'load-order'`). */\nexport type StageId = string & { readonly __brand: \"StageId\" };\n\n/** Per-execution identifier (e.g. `'load-order#0'` or `'sf-foo/inner#3'`). */\nexport type RuntimeStageId = string & { readonly __brand: \"RuntimeStageId\" };\n\n/**\n * Tag a raw string as a `StageId`. Use at translator boundaries when\n * ingesting from a footprintjs event payload (the source guarantees\n * the string IS a stage id). Zero runtime cost.\n */\nexport function asStageId(s: string): StageId {\n return s as StageId;\n}\n\n/**\n * Tag a raw string as a `RuntimeStageId`. Use at translator boundaries\n * when ingesting from a `traversalContext.runtimeStageId`. Zero\n * runtime cost.\n */\nexport function asRuntimeStageId(s: string): RuntimeStageId {\n return s as RuntimeStageId;\n}\n","/**\n * walkSubflowSpecInto — walks a footprintjs v6.0+ `subflowSpec` payload\n * from `StructureSubflowMountedEvent` and emits nodes + edges into the\n * trace recorder's existing upsert helpers.\n *\n * This is the local mirror of `walkSubflowSpec` from `footprintjs/trace`\n * — kept local to preserve explainable-ui's zero-`footprintjs`-dep\n * boundary (see traceStructureRecorder.ts top-of-file rationale).\n *\n * Node-id qualification (why inner ids get the subflow-path prefix)\n * ────────────────────────────────────────────────────────────────\n * The `subflowStructure` payload on a mount event carries the child\n * chart's OWN build-time ids, which are LOCAL and unprefixed (e.g. two\n * sibling slot subflows can each contain a stage literally named\n * `compose`). xyflow requires globally-unique node ids, and the\n * recorder dedupes by id — so two siblings sharing `compose` would\n * collapse into one node (last-write-wins), orphaning the other.\n *\n * To prevent that we qualify every emitted node id with the composed\n * `subflowPath`: `compose` under `sf-system-prompt` becomes\n * `sf-system-prompt/compose`. This MIRRORS footprintjs's runtime\n * `runtimeStageId` format (`subflowPath/stageId#index`) exactly, so the\n * runtime overlay matches a node by comparing its id against the\n * runtimeStageId minus the `#index` suffix (see overlayProjection.ts).\n * `data.subflowOf` still carries the path alone; `data.subflowId` still\n * carries the LOCAL id for mount nodes — only the xyflow node `id` and\n * edge endpoints are path-qualified.\n */\n\nimport type { Node, Edge } from \"@xyflow/react\";\nimport { asStageId } from \"./keys\";\nimport type { TraceEdgeData, TraceNodeData } from \"../traceStructureRecorder\";\n\n/** Minimal duck-typed spec shape — mirrors the slice of\n * `SerializedPipelineStructure` we need. */\ninterface SpecNode {\n readonly id: string;\n readonly name: string;\n readonly type?: \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n readonly icon?: string;\n readonly description?: string;\n readonly children?: readonly SpecNode[];\n readonly next?: SpecNode;\n readonly loopTarget?: string;\n readonly isLoopReference?: boolean;\n readonly isSubflowRoot?: boolean;\n readonly subflowId?: string;\n readonly subflowName?: string;\n readonly subflowStructure?: SpecNode;\n readonly isPausable?: boolean;\n readonly isLazy?: boolean;\n}\n\ninterface WalkSink {\n upsertNode(node: Node<TraceNodeData>): void;\n pushEdge(edge: Edge<TraceEdgeData>): void;\n}\n\nexport function walkSubflowSpecInto(\n spec: SpecNode,\n subflowPath: string,\n sink: WalkSink,\n): void {\n walkNode(spec, subflowPath, sink, new Set<string>());\n}\n\n/**\n * Qualify a LOCAL node id with its subflow path, mirroring footprintjs's\n * runtimeStageId format (`subflowPath/stageId`). All ids that share a\n * `subflowPath` are siblings, so edge endpoints inside one walkNode call\n * use the same path. `loopTarget` is a local id in the same subflow.\n */\nfunction qid(subflowPath: string, localId: string): string {\n return `${subflowPath}/${localId}`;\n}\n\nfunction walkNode(\n node: SpecNode,\n subflowPath: string,\n sink: WalkSink,\n visited: Set<string>,\n): void {\n // Cycle guard keyed on the QUALIFIED id — two different subflows can\n // share a local id (e.g. both have `compose`); keying on the bare id\n // would wrongly skip the second.\n const fullId = qid(subflowPath, node.id);\n if (visited.has(fullId)) return;\n visited.add(fullId);\n if (node.isLoopReference) return;\n\n // Nested subflow mount — recurse into its structure with composed path.\n if (node.isSubflowRoot && node.subflowId !== undefined && node.subflowStructure) {\n const nestedPath = `${subflowPath}/${node.subflowId}`;\n walkNode(node.subflowStructure, nestedPath, sink, visited);\n // Fall through so the mount node itself is emitted in the parent\n // subflow's scope below.\n }\n\n // Emit the stage node, tagged with subflowOf.\n const type = node.type ?? \"stage\";\n const isDecider = type === \"decider\" || type === \"selector\";\n const isFork = type === \"fork\";\n const isStreaming = type === \"streaming\";\n const isSubflow = !!node.isSubflowRoot;\n\n const data: TraceNodeData = {\n label: node.name,\n isDecider,\n isFork,\n isStreaming,\n isSubflow,\n subflowOf: subflowPath,\n prevIds: [],\n nextIds: [],\n };\n if (node.description !== undefined) data.description = node.description;\n if (node.icon !== undefined) data.icon = node.icon;\n // `subflowId` stays the LOCAL id (mount nodes use it to match runtime\n // events + drill scope); only the xyflow node `id` is path-qualified.\n if (node.subflowId !== undefined) data.subflowId = node.subflowId;\n if (node.isLazy === true) data.isLazy = true;\n if (node.isPausable === true) data.isPausable = true;\n\n sink.upsertNode({\n id: asStageId(fullId),\n type: \"stage\",\n position: { x: 0, y: 0 },\n data,\n });\n\n // Children (decider/selector/fork branches) — siblings at the same path.\n if (node.children && node.children.length > 0) {\n const edgeKind: \"fork-branch\" | \"decision-branch\" = type === \"fork\" ? \"fork-branch\" : \"decision-branch\";\n for (const child of node.children) {\n const childFullId = qid(subflowPath, child.id);\n const edgeId = `${fullId}->${childFullId}:${edgeKind}${edgeKind === \"decision-branch\" ? `:${child.id}` : \"\"}`;\n const edgeData: TraceEdgeData = { kind: edgeKind };\n if (edgeKind === \"decision-branch\") edgeData.label = child.id;\n const edge: Edge<TraceEdgeData> = {\n id: edgeId,\n source: fullId,\n target: childFullId,\n data: edgeData,\n };\n if (edgeKind === \"decision-branch\") edge.label = child.id;\n sink.pushEdge(edge);\n walkNode(child, subflowPath, sink, visited);\n }\n }\n\n // Linear next or loop back-edge — also same-path siblings.\n if (node.next) {\n if (node.next.isLoopReference && node.loopTarget) {\n const loopFullId = qid(subflowPath, node.loopTarget);\n sink.pushEdge({\n id: `${fullId}->${loopFullId}:loop`,\n source: fullId,\n target: loopFullId,\n data: { kind: \"loop\" },\n });\n } else {\n const nextFullId = qid(subflowPath, node.next.id);\n const edgeId = `${fullId}->${nextFullId}:next`;\n sink.pushEdge({\n id: edgeId,\n source: fullId,\n target: nextFullId,\n data: { kind: \"next\" },\n });\n walkNode(node.next, subflowPath, sink, visited);\n }\n }\n}\n","/**\n * traceStructureRecorder — event-driven xyflow Node[] + Edge[] collector.\n *\n * Implements footprintjs v6.0+ `StructureRecorder` interface. Accumulates\n * an unpositioned graph (xyflow node + edge shape) as the chart is being\n * built — no spec tree walk required.\n *\n * Why event-driven\n * ────────────────\n * The recorder fires SYNCHRONOUSLY at every spec-mutation moment during\n * construction. By the time `.build()` returns, the recorder's\n * `getGraph()` returns the complete graph — zero extra walking\n * (the \"collect during traversal, never post-process\" rule footprintjs\n * documents in its core principle).\n *\n * Bonus: the same recorder shape can drive incremental UI updates if\n * the builder is constructed asynchronously (e.g., a UI builder where\n * each \"add stage\" click re-renders the live graph).\n *\n * Layout is a separate concern\n * ────────────────────────────\n * This module produces UNPOSITIONED nodes (no `position` field set;\n * xyflow defaults to `{x: 0, y: 0}`). Apply a layout algorithm\n * downstream — either:\n *\n * - a graph algorithm (dagre / elk / d3-force)\n * - manual positioning via your own walk over `recorder.getGraph()`\n *\n * The `<TraceFlow>` component wires a default BFS layout.\n *\n * @example\n * ```ts\n * import { flowChart } from 'footprintjs';\n * import { createTraceStructureRecorder } from 'footprint-explainable-ui/flowchart';\n *\n * const trace = createTraceStructureRecorder();\n * const chart = flowChart('seed', fn, 'seed', {\n * structureRecorders: [trace.recorder],\n * })\n * .addFunction('a', fnA, 'a')\n * .build();\n *\n * const { nodes, edges } = trace.getGraph();\n * // → nodes: [{ id: 'seed', data: { label: 'seed', ... } }, { id: 'a', ... }]\n * // → edges: [{ id: 'seed->a', source: 'seed', target: 'a', data: { kind: 'next' } }]\n *\n * <ReactFlow nodes={layout(nodes)} edges={edges} />\n * ```\n */\n\nimport type { Node, Edge } from \"@xyflow/react\";\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport type { StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { walkSubflowSpecInto } from \"./_internal/walkSubflowSpecInto\";\n\nexport type { StageId, RuntimeStageId } from \"./_internal/keys\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local type aliases mirroring footprintjs/StructureRecorder\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Rationale for redefining these here instead of `import type` from\n// 'footprintjs': footprint-explainable-ui has no `footprintjs` dependency\n// declared in package.json (intentional — consumers wire it). So we mirror\n// the public interface shape. If footprintjs changes the StructureRecorder\n// interface, this module's types must update in lockstep — tracked by the\n// type-conformance test in `test/unit/traceStructureRecorder.test.ts`.\n\ntype StructureNodeType = \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n\ninterface StructureSpecRef {\n readonly id: string;\n readonly name: string;\n readonly type?: StructureNodeType;\n readonly description?: string;\n readonly icon?: string;\n readonly isSubflowRoot?: boolean;\n readonly subflowId?: string;\n readonly isLazy?: boolean;\n readonly [key: string]: unknown;\n}\n\ninterface StageAddedEvent {\n readonly stageId: string;\n readonly name: string;\n readonly type: StructureNodeType;\n readonly isPausable?: boolean;\n readonly spec: StructureSpecRef;\n}\n\ntype EdgeKind = \"next\" | \"fork-branch\" | \"decision-branch\";\n\ninterface EdgeAddedEvent {\n readonly from: string;\n readonly to: string;\n readonly kind: EdgeKind;\n readonly label?: string;\n}\n\ninterface LoopEdgeAddedEvent {\n readonly from: string;\n readonly to: string;\n}\n\ninterface DeciderCompleteEvent {\n readonly decider: string;\n readonly type: \"decider\" | \"selector\";\n readonly branchIds: readonly string[];\n readonly defaultBranch?: string;\n}\n\ninterface SubflowMountedEvent {\n readonly subflowId: string;\n readonly subflowName: string;\n readonly rootStageId: string;\n readonly isLazy?: boolean;\n /**\n * The mounted subflow's complete spec — added in footprintjs v6.0\n * (proposal #001). Present for eager mounts, UNDEFINED for lazy\n * mounts (the subflow isn't resolved yet at mount-event-fire-time).\n * When present, the consumer walks it to materialize inner nodes +\n * edges directly with `subflowOf` set — no retroactive tagging\n * needed.\n *\n * Typed as `unknown` because the upstream `SerializedPipelineStructure`\n * shape has no index signature and we want to stay loosely-coupled\n * (see top-of-file rationale for the no-`footprintjs`-dep boundary).\n * `walkSubflowSpecInto` accepts the duck-typed shape it actually\n * walks.\n */\n readonly subflowSpec?: unknown;\n /**\n * Local mount id within the parent (matches `subflowId` for top-level\n * mounts; composed `'parent/child'` for nested). Tagged onto every\n * inner stage's `data.subflowOf` during the walk.\n */\n readonly subflowPath?: string;\n}\n\n/**\n * Minimal StructureRecorder interface — mirrors footprintjs v6.0+.\n *\n * Named with the `Minimal` prefix to make the local-mirror nature\n * explicit at consumer call sites — a consumer importing both this\n * type and the upstream `StructureRecorder` from `footprintjs` won't\n * collide, and code reviewers see at a glance which boundary the type\n * crosses.\n *\n * The upstream `footprintjs.StructureRecorder` is structurally\n * compatible (this type's shape is a subset of upstream's), so passing\n * an instance of this to `flowChart(..., { structureRecorders: [...] })`\n * typechecks cleanly.\n */\nexport interface MinimalStructureRecorder {\n readonly id: string;\n onStageAdded?(event: StageAddedEvent): void;\n onEdgeAdded?(event: EdgeAddedEvent): void;\n onLoopEdgeAdded?(event: LoopEdgeAddedEvent): void;\n onDeciderComplete?(event: DeciderCompleteEvent): void;\n onSubflowMounted?(event: SubflowMountedEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// xyflow node + edge data shapes\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Per-node data attached to the xyflow `Node`. The built-in `StageNode`\n * renderer reads the named fields below.\n *\n * Consumer extension: this type EXTENDS `Record<string, unknown>` so\n * you can attach custom fields without TypeScript fighting you. Pair\n * this with `<TraceFlow nodeTypes={{ stageNode: MyNode }} />` (or push\n * nodes with `type: 'myCustomKind'`) to render those custom fields\n * however you want. The built-in `StageNode` ignores fields it doesn't\n * recognize, so adding consumer fields is non-breaking even if you\n * keep the default renderer.\n */\nexport interface TraceNodeData extends Record<string, unknown> {\n label: string;\n isDecider: boolean;\n isFork: boolean;\n isSubflow: boolean;\n /** True when the event carried `type: 'streaming'` (the spec was added\n * via `addStreamingFunction`). Renderers that style streaming stages\n * distinctly key on this flag. */\n isStreaming: boolean;\n description?: string;\n icon?: string;\n subflowId?: string;\n isLazy?: boolean;\n isPausable?: boolean;\n /** Visual emphasis hint — `hero` (prominent) / `muted` (recedes). Set by\n * the consumer's graph builder from its own semantics; the renderer styles\n * off it without any domain knowledge. */\n emphasis?: \"hero\" | \"muted\";\n /** Size tier — scales the card; must match the layout's node-size resolver. */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Set later by `onDeciderComplete` when the decider's branch list is\n * sealed. Useful for renderers that want to render decider with a\n * branch-count badge. */\n branchIds?: readonly string[];\n defaultBranch?: string;\n /**\n * The subflow this node belongs to, OR `undefined` for top-level\n * parent-chart stages. Tracked via a stack-based heuristic during\n * event ingestion:\n *\n * - Push on `onSubflowMounted({subflowId, rootStageId})` →\n * top-of-stack = `{subflowId, mountStageId}`\n * - `onStageAdded` tags new nodes with the top-of-stack `subflowId`\n * (the mount node itself stays UNtagged — it's part of the parent\n * chain)\n * - Pop on `onEdgeAdded` where `from === mount.id` (a mount's\n * outgoing edge to a sibling means the parent chain has resumed);\n * the wrongly-tagged target node is re-tagged to the parent scope\n *\n * Mount nodes (where `isSubflow=true`) have `subflowOf` reflecting\n * their OWN parent context, NOT the subflow they mount. So a parent's\n * mount node has `subflowOf=undefined` (top-level parent), and the\n * subflow's INTERNAL stages have `subflowOf=<mount.subflowId>`.\n *\n * Renderers use this to filter the chart by drill-down level: show\n * only nodes where `subflowOf === currentDrillSubflowId` (undefined\n * for top-level view, mount.subflowId after drilling in).\n */\n subflowOf?: string;\n /**\n * **L8.0 — STRUCTURAL prev/next**: stage ids that lead into / out of\n * this node, derived live from incoming/outgoing edges. Excludes\n * `loop` back-edges (visual only — per invariant I1).\n *\n * Convergence-correct: a fork-join node carries an ENTRY per branch\n * child (e.g., `FinalizeOrder.prevIds = ['CheckInventory', 'RunFraudCheck']`).\n *\n * \"Structural\" qualifier: this is the chart-SHAPE prev/next, not\n * runtime execution order. For runtime ancestry use `CommitView`\n * fields on `CommitFlowIndex` (L8.2).\n */\n prevIds: StageId[];\n nextIds: StageId[];\n}\n\n/**\n * Per-edge data attached to the xyflow `Edge`. The default edge\n * renderer reads `kind` (and `label`).\n *\n * Consumer extension: same pattern as `TraceNodeData` — extra fields\n * pass through unchanged. Pair with `<TraceFlow edgeTypes={...} />`\n * to render custom edges (e.g., a \"retried\" edge with a count badge).\n */\nexport interface TraceEdgeData extends Record<string, unknown> {\n kind: EdgeKind | \"loop\";\n label?: string;\n}\n\nexport type TraceNode = Node<TraceNodeData>;\nexport type TraceEdge = Edge<TraceEdgeData>;\n\nexport interface TraceGraph {\n nodes: TraceNode[];\n edges: TraceEdge[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface TraceStructureRecorderHandle {\n /** The recorder to register via `flowChart(..., { structureRecorders: [handle.recorder] })`\n * or `.attachStructureRecorder(handle.recorder)`. */\n recorder: MinimalStructureRecorder;\n /** Returns a defensive copy of the current graph state. Safe to call\n * multiple times; safe to mutate the returned arrays without affecting\n * the recorder's internal state. */\n getGraph(): TraceGraph;\n /** Direct read-only access for hot-path consumers (Lens slider scrubbing).\n * Returns the LIVE internal arrays — do NOT mutate. Prefer `getGraph()`\n * unless you measure a performance cost. */\n getGraphRef(): Readonly<TraceGraph>;\n /**\n * Subscribe to graph-change notifications. Pub-sub model — multiple\n * listeners can subscribe; each fires after every event that mutates\n * the graph (per-event, NOT batched). Returns an unsubscribe function.\n * Designed for React's `useSyncExternalStore` consumption.\n *\n * Listeners are NOT invoked during `reset()`. **Consumer guidance**:\n * if you need to clear a live `<TraceFlow recorder={handle} />`\n * mid-mount, either (a) unmount the component before calling\n * `reset()` and re-mount after, OR (b) drive a fresh recorder\n * instance via state. See `reset()` JSDoc for the rationale.\n */\n subscribe(listener: () => void): () => void;\n /**\n * Monotonically-increasing version counter — bumps once per\n * graph-mutating event. Pair with `getGraph()` in\n * `useSyncExternalStore` snapshot equality:\n * ```ts\n * const version = useSyncExternalStore(handle.subscribe, () => handle.version());\n * const graph = useMemo(() => handle.getGraph(), [version]);\n * ```\n * Avoids defensive-copy allocation on every render while keeping\n * React's identity-check happy.\n */\n version(): number;\n /** Reset the recorder for reuse across multiple builds. After this,\n * the recorder behaves like a freshly-constructed instance. */\n reset(): void;\n}\n\nexport interface CreateTraceStructureRecorderOptions {\n /** Recorder id — surfaces in `StructureBuildError.recorderId` when\n * the recorder throws. Defaults to `'trace-structure'`. Use distinct\n * ids if you attach multiple instances. */\n id?: string;\n /** Optional callback fired after each event mutates the graph. Useful\n * for incremental-render UIs (Lens) that want to re-render between\n * builder operations. NOT invoked during the initial `attachStructureRecorder`\n * seed replay; consumers can call `getGraph()` directly after attach. */\n onChange?: (graph: Readonly<TraceGraph>) => void;\n}\n\nexport function createTraceStructureRecorder(\n options: CreateTraceStructureRecorderOptions = {},\n): TraceStructureRecorderHandle {\n const id = options.id ?? \"trace-structure\";\n const onChange = options.onChange;\n\n let nodes: TraceNode[] = [];\n let edges: TraceEdge[] = [];\n // Indexes — O(1) lookup for decider-completion + subflow-mounted updates.\n const nodeIndex = new Map<string, number>();\n const seenEdgeIds = new Set<string>();\n // L8.0 — per-node prev/next indexes maintained as edges arrive. The\n // arrays land on `TraceNode.data.prevIds` / `data.nextIds` so basic\n // TraceGraph consumers get convergence-correct neighbor info \"for\n // free\" (no separate NodeView translator needed for chart rendering).\n const prevIdsOf = new Map<string, StageId[]>();\n const nextIdsOf = new Map<string, StageId[]>();\n // Pub-sub + version via shared infra (microtask-batched listener fan-out).\n const notifier = createNotifier(\"traceStructureRecorder\");\n\n function notifyChange(): void {\n if (onChange) {\n try {\n onChange({ nodes, edges });\n } catch (err) {\n devWarn(\n () => \"[traceStructureRecorder] onChange callback threw — isolated.\",\n err,\n );\n }\n }\n notifier.notify();\n }\n\n function upsertNode(node: TraceNode): void {\n const existing = nodeIndex.get(node.id);\n if (existing !== undefined) {\n // Merge: later events may carry richer data (e.g., onDeciderComplete\n // → branchIds). Preserve any fields the new event didn't set.\n nodes[existing] = {\n ...nodes[existing],\n ...node,\n data: { ...nodes[existing]!.data, ...node.data },\n };\n } else {\n nodeIndex.set(node.id, nodes.length);\n nodes.push(node);\n }\n }\n\n function pushEdge(edge: TraceEdge): void {\n // Dedupe by id — the seed replay path could otherwise double-add\n // if a consumer attaches the same recorder twice (allowed by design,\n // but the graph should still be sane).\n if (seenEdgeIds.has(edge.id)) return;\n seenEdgeIds.add(edge.id);\n edges.push(edge);\n\n // L8.0 — maintain prev/next indexes. Loop back-edges do NOT\n // contribute (invariant I1: loops are visual annotations only).\n const kind = edge.data?.kind;\n if (kind === \"loop\") return;\n const source = asStageId(edge.source);\n const target = asStageId(edge.target);\n const nextArr = nextIdsOf.get(source) ?? [];\n nextArr.push(target);\n nextIdsOf.set(source, nextArr);\n const prevArr = prevIdsOf.get(target) ?? [];\n prevArr.push(source);\n prevIdsOf.set(target, prevArr);\n\n // Sync the index changes onto the LIVE node-data arrays so\n // consumers reading `node.data.prevIds`/`nextIds` see fresh values\n // after each edge event. We mutate in place rather than re-cloning\n // the node — `getGraph()` returns defensive copies anyway.\n syncNeighborsOnto(source);\n syncNeighborsOnto(target);\n }\n\n function syncNeighborsOnto(stageId: StageId): void {\n const idx = nodeIndex.get(stageId);\n if (idx === undefined) return; // node not yet announced — will sync at onStageAdded\n const node = nodes[idx]!;\n // L8.0 panel must-fix: ATOMIC REPLACE — copy the arrays from the\n // index, don't share the map's array refs. A consumer using\n // `getGraphRef()` who caches `node.data.prevIds` would otherwise\n // see their cached array silently grow when a new edge fires.\n // The slice() cost is one allocation per edge per touched node —\n // negligible vs. the consumer-safety win.\n const prevs = prevIdsOf.get(stageId);\n const nexts = nextIdsOf.get(stageId);\n node.data.prevIds = prevs ? prevs.slice() : [];\n node.data.nextIds = nexts ? nexts.slice() : [];\n }\n\n const recorder: MinimalStructureRecorder = {\n id,\n onStageAdded(event) {\n const spec = event.spec;\n const type = event.type;\n const isDecider = type === \"decider\" || type === \"selector\";\n const isFork = type === \"fork\";\n const isStreaming = type === \"streaming\";\n const isSubflow = !!spec.isSubflowRoot;\n\n const stageId = asStageId(event.stageId);\n const data: TraceNodeData = {\n label: event.name,\n isDecider,\n isFork,\n isStreaming,\n isSubflow,\n // L8.0 — seed prev/next from any edges that already fired\n // pointing AT this node. Convergence case: a fork-branch edge\n // from LoadOrder fires BEFORE the child's onStageAdded; this\n // line ensures the child's prevIds picks up the back-pointer.\n // Atomic copy (not shared ref) — see `syncNeighborsOnto` for\n // the panel-flagged consumer-safety rationale.\n prevIds: (prevIdsOf.get(stageId) ?? []).slice(),\n nextIds: (nextIdsOf.get(stageId) ?? []).slice(),\n };\n if (spec.description !== undefined) data.description = spec.description;\n if (spec.icon !== undefined) data.icon = spec.icon;\n if (spec.subflowId !== undefined) data.subflowId = spec.subflowId;\n if (spec.isLazy === true) data.isLazy = true;\n if (event.isPausable === true) data.isPausable = true;\n // subflowOf gets set RETROACTIVELY in onSubflowMounted (the\n // builder fires inner-stage events BEFORE the mount event, so\n // we can't tag at stage-add time — we tag at mount time by\n // identifying untagged disconnected subgraphs).\n\n upsertNode({\n id: event.stageId,\n type: \"stage\",\n // No layout here — downstream consumer applies positions.\n position: { x: 0, y: 0 },\n data,\n });\n notifyChange();\n },\n\n onEdgeAdded(event) {\n const edgeId = `${event.from}->${event.to}:${event.kind}${event.label ? `:${event.label}` : \"\"}`;\n const data: TraceEdgeData = { kind: event.kind };\n if (event.label !== undefined) data.label = event.label;\n const edge: TraceEdge = {\n id: edgeId,\n source: event.from,\n target: event.to,\n data,\n };\n if (event.label !== undefined) edge.label = event.label;\n pushEdge(edge);\n notifyChange();\n },\n\n onLoopEdgeAdded(event) {\n const edgeId = `${event.from}->${event.to}:loop`;\n pushEdge({\n id: edgeId,\n source: event.from,\n target: event.to,\n data: { kind: \"loop\" },\n });\n notifyChange();\n },\n\n onDeciderComplete(event) {\n // Patch the already-added decider node with its sealed branch info.\n const existing = nodeIndex.get(event.decider);\n if (existing === undefined) {\n // The decider node SHOULD have been added via onStageAdded\n // before its branches were declared. If this fires for an\n // unknown id, the upstream builder reordered events —\n // visualisation will silently degrade. Warn in dev so the bug\n // is visible at its source.\n devWarn(\n () =>\n `[traceStructureRecorder] onDeciderComplete fired for unknown stageId \"${event.decider}\" — branch metadata dropped. Did the upstream fire onStageAdded for this id first?`,\n );\n return;\n }\n const node = nodes[existing]!;\n const data: TraceNodeData = {\n ...node.data,\n branchIds: event.branchIds,\n };\n if (event.defaultBranch !== undefined) data.defaultBranch = event.defaultBranch;\n nodes[existing] = { ...node, data };\n notifyChange();\n },\n\n onSubflowMounted(event) {\n // The mount node was already announced via `onStageAdded`; here\n // we patch in the subflow-specific data fields, then materialize\n // the subflow's inner structure.\n const existing = nodeIndex.get(event.rootStageId);\n if (existing === undefined) {\n devWarn(\n () =>\n `[traceStructureRecorder] onSubflowMounted fired for unknown rootStageId \"${event.rootStageId}\" (subflowId=\"${event.subflowId}\") — subflow metadata dropped. Did the upstream fire onStageAdded for the mount node first?`,\n );\n return;\n }\n const node = nodes[existing]!;\n const data: TraceNodeData = {\n ...node.data,\n isSubflow: true,\n subflowId: event.subflowId,\n };\n if (event.isLazy === true) data.isLazy = true;\n nodes[existing] = { ...node, data };\n\n // Eager mounts (footprintjs v6.0+): walk the full subflow spec\n // delivered on the event to emit inner nodes + edges with\n // `subflowOf` set directly. Lazy mounts arrive with no spec —\n // their internal structure isn't known until the resolver runs\n // at runtime; the mount node alone is rendered (consumer apps\n // can subscribe to runtime events to fill in detail if desired).\n const subflowPath = event.subflowPath ?? event.subflowId;\n if (event.subflowSpec) {\n // Cast: type is `unknown` at the event boundary (see\n // SubflowMountedEvent JSDoc); walkSubflowSpecInto accepts\n // the duck-typed structural shape it actually traverses.\n walkSubflowSpecInto(event.subflowSpec as Parameters<typeof walkSubflowSpecInto>[0], subflowPath, {\n upsertNode,\n pushEdge,\n });\n }\n notifyChange();\n },\n };\n\n return {\n recorder,\n getGraph(): TraceGraph {\n return {\n nodes: nodes.map((n) => ({ ...n, data: { ...n.data } })),\n edges: edges.map((e) => ({ ...e, data: e.data ? { ...e.data } : undefined })),\n };\n },\n getGraphRef(): Readonly<TraceGraph> {\n return { nodes, edges };\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n nodes = [];\n edges = [];\n nodeIndex.clear();\n seenEdgeIds.clear();\n prevIdsOf.clear();\n nextIdsOf.clear();\n // Why `reset()` does NOT bump version or notify listeners:\n // a notify here would cause `<TraceFlow recorder={handle} />`\n // to re-render with an empty graph for one frame, then re-render\n // again when the next builder event fires — visible flicker for\n // users who reset between builds. The recommended pattern is to\n // recycle the recorder OUTSIDE the React tree (e.g., via a\n // factory hook keyed on a \"build epoch\" so React unmounts and\n // re-mounts <TraceFlow> across builds). See `subscribe()` JSDoc\n // for the consumer-facing recipe.\n },\n };\n}\n","/**\n * SlotPillNode — a slim, pill-shaped node renderer for context \"slots\"\n * (system-prompt / messages / tools) inside an LLM-call / Agent chart.\n *\n * Why a dedicated renderer (not a resized StageNode): `StageNode` sizes to\n * its OWN content (padding + label + description) and ignores the wrapper\n * size, so it can't render genuinely slim. `SlotPillNode` is intrinsically a\n * thin bar that fills its wrapper — so a consumer's `nodeSize` resolver\n * (e.g. 210×38) produces a real pill.\n *\n * Lit / selected state (the context-selector highlight): a slot is part of a\n * `select()` decision — the Context selector PICKS which slots to engineer\n * each turn. When the runtime overlay (or the consumer) marks a slot\n * `active`/`selected`, the pill LIGHTS UP; unlit = \"this slot wasn't engineered\n * this turn\". That lit/unlit signal is the whole point of the slot view.\n *\n * Consumer-supplied via `nodeTypes={{ slotPill: SlotPillNode }}`. The trace\n * components inject overlay state (`active`/`done`/`dimmed`) into custom node\n * `data`, so this reads the same fields the bundled StageNode does.\n */\n\nimport { Handle, Position } from \"@xyflow/react\";\nimport type { NodeProps } from \"@xyflow/react\";\nimport { rawDefaults } from \"../../theme/tokens\";\n\nconst C = rawDefaults.colors;\n\nexport interface SlotPillNodeData {\n label: string;\n /** Lit when the selector PICKED this slot this turn (overlay or consumer). */\n active?: boolean;\n selected?: boolean;\n done?: boolean;\n /** Faded when other slots ran but this one didn't (the \"unlit\" signal). */\n dimmed?: boolean;\n /** Semantic kind hint for the dot color (e.g. 'system-prompt'|'messages'|'tools'). */\n slotKind?: string;\n icon?: string;\n [key: string]: unknown;\n}\n\nexport function SlotPillNode({ data }: NodeProps) {\n const d = data as SlotPillNodeData;\n const lit = !!(d.active || d.selected);\n\n // Lit → primary glow; done → success tint; otherwise muted. Dimmed fades.\n const accent = lit ? C.primary : d.done ? C.success : C.textMuted;\n const opacity = d.dimmed && !lit ? 0.45 : 1;\n\n return (\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n boxSizing: \"border-box\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n padding: \"0 12px\",\n borderRadius: 999, // full pill\n border: `1.5px solid ${lit ? C.primary : C.border}`,\n background: lit ? \"rgba(99, 102, 241, 0.14)\" : \"rgba(148, 163, 184, 0.06)\",\n boxShadow: lit ? `0 0 0 2px rgba(99,102,241,0.25)` : \"none\",\n opacity,\n fontSize: 12,\n fontWeight: 600,\n color: lit ? C.textPrimary : C.textSecondary,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n transition: \"opacity 120ms, box-shadow 120ms, border-color 120ms\",\n }}\n title={d.label}\n >\n {/* Status dot — lit/done/muted. */}\n <span\n aria-hidden\n style={{\n flexShrink: 0,\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: accent,\n }}\n />\n {d.icon ? <span aria-hidden style={{ flexShrink: 0 }}>{d.icon}</span> : null}\n <span style={{ overflow: \"hidden\", textOverflow: \"ellipsis\" }}>{d.label}</span>\n\n {/* Edge handles — top in, bottom out (top→bottom flow). */}\n <Handle type=\"target\" position={Position.Top} style={{ opacity: 0 }} />\n <Handle type=\"source\" position={Position.Bottom} style={{ opacity: 0 }} />\n </div>\n );\n}\n","/**\n * snapLinearSuccessors — pure post-dagre alignment pass for the chart SPINE.\n *\n * THE PROBLEM IT FIXES\n * --------------------\n * On a chart like `Context(selector) → [slot, slot] → messageAPI(merge) →\n * callLLM(linear)`, dagre's default balanced x-assignment (Brandes–Köpf\n * `balance()` = median of 4 extreme alignments) drifts a pure linear\n * successor a few px off the spine on an ASYMMETRIC graph (a wide callLLM\n * node + the fork above unbalance the alignment passes). Measured centers:\n * context 915, messageAPI 917, callLLM 921 — callLLM is ~6px off even though\n * it is a single-in / single-out continuation of messageAPI.\n *\n * THE FIX\n * -------\n * A pure `(graph) => graph` pass applied AFTER `dagreTraceLayout`. A node with\n * EXACTLY ONE forward (non-loop) predecessor, whose predecessor has EXACTLY\n * ONE forward (non-loop) successor, and which shares the same `parentId`\n * coordinate space, snaps its CENTER-x onto that predecessor's center-x. The\n * top-left `position.x` is recomputed from the new center using the node's OWN\n * width. `y` is never touched.\n *\n * WHAT IT NEVER MOVES (by construction of the predicate)\n * ------------------------------------------------------\n * - the ROOT — 0 predecessors → predicate (1) fails\n * - a MERGE (messageAPI) — >1 predecessor → predicate (1) fails\n * - FORK / DECISION children — predecessor out-deg>1 → predicate (2) fails\n * - cross-compound hops — differing parentId → predicate (3) fails\n * A fork/merge NODE itself is still snapped onto ITS upstream predecessor when\n * that predecessor is a pure linear hop — correct, it is a continuation of\n * whatever feeds it. Only its CHILDREN are protected.\n *\n * PROPERTIES\n * ----------\n * - PURE: never mutates the input graph; returns a new nodes array (edges by\n * reference, mirroring dagre's own pass-through).\n * - IDEMPOTENT: re-running finds centers already equal → zero-delta writes.\n * - CHAIN-PROPAGATING: nodes are processed in rank (y-asc) order, so a\n * snapped predecessor's corrected x flows down a `a→b→c` chain in one pass.\n * - GEOMETRY-EXACT: widths come from the SAME resolver→style→default order\n * dagre used (`sizeOf`), so reconstructed centers match dagre's placement.\n *\n * Compose it with dagre via `createSnappedDagreLayout`, or call it directly on\n * a `dagreTraceLayout(...)` result. Kept SEPARATE from `dagreTraceLayout` so\n * the base layout's output stays byte-identical for consumers that don't opt\n * in.\n */\n\nimport type { Edge } from \"@xyflow/react\";\nimport type { TraceGraph, TraceNode, TraceEdgeData } from \"../traceStructureRecorder\";\nimport type { TraceFlowLayout } from \"../TraceFlow\";\nimport {\n DEFAULT_NODE_H,\n DEFAULT_NODE_W,\n sizeOf,\n type NodeSizeResolver,\n} from \"./dagreTraceLayout\";\n\n/**\n * Options for the snap pass. These MUST mirror the size-relevant options\n * passed to the `dagreTraceLayout` run that produced the graph, so the pass\n * reconstructs each node's center from the identical width.\n */\nexport interface SnapLinearSuccessorsOptions {\n /** Per-node size resolver — same one passed to dagre. Resolution order:\n * resolver → `node.style` → default. */\n readonly nodeSize?: NodeSizeResolver;\n /** Fallback width when a node carries no resolver/style size. Must match\n * the dagre run's `nodeWidth`. Default 200. */\n readonly nodeWidth?: number;\n /** Fallback height. Must match the dagre run's `nodeHeight`. Default 80.\n * (Height is unused for x-snapping but kept so `sizeOf` resolves the same\n * footprint the resolver may key on.) */\n readonly nodeHeight?: number;\n}\n\n/**\n * Snap pure single-in/single-out linear successors onto their predecessor's\n * center-x. See the file header for the full contract. Pure + idempotent.\n */\nexport function snapLinearSuccessors(\n graph: TraceGraph,\n options: SnapLinearSuccessorsOptions = {},\n): TraceGraph {\n // Empty guard — preserve memo identity, mirror dagre's empty guard.\n if (graph.nodes.length === 0) return graph;\n\n const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W;\n const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H;\n\n // ── id → node map, and a width per node (identical resolution to dagre). ──\n const byId = new Map<string, TraceNode>();\n const width = new Map<string, number>();\n for (const n of graph.nodes) {\n byId.set(n.id, n);\n width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);\n }\n\n // ── forward adjacency from edges, EXCLUDING loop back-edges (invariant I1, ──\n // matching dagre's own loop exclusion). Dedupe (source,target) so a doubled\n // edge can't fake a fork; only count edges whose BOTH endpoints are nodes.\n const preds = new Map<string, string[]>();\n const outDegree = new Map<string, number>();\n const seenEdge = new Set<string>();\n for (const e of graph.edges as Edge<TraceEdgeData>[]) {\n if (e.data?.kind === \"loop\") continue;\n if (!byId.has(e.source) || !byId.has(e.target)) continue;\n const key = `${e.source}\u0000${e.target}`;\n if (seenEdge.has(key)) continue;\n seenEdge.add(key);\n const list = preds.get(e.target);\n if (list) list.push(e.source);\n else preds.set(e.target, [e.source]);\n outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);\n }\n\n // ── mutable working x per node (clone — never mutate input). Centers read ──\n // these so a chain `a→b→c` propagates in one pass.\n const workingX = new Map<string, number>();\n for (const n of graph.nodes) workingX.set(n.id, n.position.x);\n const centerX = (id: string) => workingX.get(id)! + width.get(id)! / 2;\n\n // ── rank order = y ascending (TB rank is monotonic in y), ties by current ──\n // x then id → fully deterministic, predecessor finalized before successor.\n const order = [...graph.nodes].sort(\n (a, b) =>\n a.position.y - b.position.y ||\n a.position.x - b.position.x ||\n (a.id < b.id ? -1 : a.id > b.id ? 1 : 0),\n );\n\n for (const n of order) {\n const p = preds.get(n.id);\n if (!p || p.length !== 1) continue; // (1) ROOT (0) or MERGE (>1) → skip\n const pid = p[0]!;\n if ((outDegree.get(pid) ?? 0) !== 1) continue; // (2) pred is FORK/branch → skip\n const P = byId.get(pid)!;\n // (3) same coordinate space — treat both `undefined` as the shared top level.\n if ((n.parentId ?? undefined) !== (P.parentId ?? undefined)) continue;\n // SNAP: center-x of n := center-x of p (p may already be snapped this pass).\n workingX.set(n.id, centerX(pid) - width.get(n.id)! / 2);\n }\n\n // ── emit a new graph; only rebuild nodes whose x actually changed (cheap, ──\n // preserves identity for untouched nodes). Order is preserved (xyflow's\n // parent-before-child invariant). Edges pass through by reference.\n const nodes = graph.nodes.map((n) => {\n const nx = workingX.get(n.id)!;\n return nx === n.position.x ? n : { ...n, position: { x: nx, y: n.position.y } };\n });\n return { nodes, edges: graph.edges };\n}\n\n/**\n * Convenience: run a base `TraceFlowLayout` (typically `createDagreTraceLayout`)\n * then the snap pass, as one composed layout.\n *\n * @example\n * const layout = createSnappedDagreLayout(\n * createDagreTraceLayout({ nodeSize }),\n * { nodeSize }, // SAME size opts so widths match\n * );\n */\nexport function createSnappedDagreLayout(\n base: TraceFlowLayout,\n options: SnapLinearSuccessorsOptions = {},\n): TraceFlowLayout {\n return (graph: TraceGraph) => snapLinearSuccessors(base(graph), options);\n}\n","/**\n * traceGroupLayout — a group-based layout for footprint trace charts, designed\n * the way a layout engineer reasons about structured flowcharts: NOT by tuning\n * a generic Sugiyama/dagre pass, but by ranking nodes into bands and centering\n * each MERGE under the SPAN of its inputs, so the layout's correctness falls out\n * BY CONSTRUCTION.\n *\n * The mental model (groups):\n * - A SEQUENCE is a single-in/single-out chain → stacked vertically, each node\n * inheriting its predecessor's x (a straight spine; the downstream\n * `snapLinearSuccessors` pass keeps it pixel-exact).\n * - A FORK (a node with ≥2 branch children) → its children spread across the\n * next band; the children ARE the parallel group.\n * - A MERGE (a node with ≥2 incoming edges) → centered under the combined\n * visual SPAN of its inputs. This handles STAGGERED merges with zero\n * special-casing: longest-path ranking puts a merge one band below its\n * deepest input, and span-centering places it symmetrically under inputs\n * that may sit at different bands and have very different widths.\n *\n * For the agent merge-tree this yields: messageAPI centered under\n * {system-prompt, messages}; call-llm centered under the span of\n * {messageAPI, tools} (tools bypasses messageAPI's band — a staggered merge);\n * route + its branches symmetric below; the loop excluded from layout (drawn as\n * a right-margin back-edge by `LoopBackEdge`).\n *\n * Contract: pure `(TraceGraph) => TraceGraph`, sets `position` (top-left) on\n * every node, parent-relative for `parentId` nodes — same as `dagreTraceLayout`.\n * Reuses `sizeOf` / `NodeSizeResolver` / size defaults from `dagreTraceLayout`\n * (so the group-container \"style-wins\" exception + any consumer sizing behave\n * identically), and composes with the existing `createSnappedDagreLayout` +\n * `wrapInMainChartBox` passes — no duplication.\n */\n\nimport type { TraceGraph, TraceNode } from \"../traceStructureRecorder\";\nimport type { TraceFlowLayout } from \"../TraceFlow\";\nimport {\n sizeOf,\n DEFAULT_NODE_W,\n DEFAULT_NODE_H,\n type NodeSizeResolver,\n type SiblingOrderResolver,\n} from \"./dagreTraceLayout\";\n\nexport interface TraceGroupLayoutOptions {\n /** Vertical gap between rank bands (px). Default 80. */\n readonly rankSep?: number;\n /** Horizontal gap between siblings within a band (px). Default 60. */\n readonly nodeSep?: number;\n /** Fallback node footprint when a node carries no explicit size. */\n readonly nodeWidth?: number;\n readonly nodeHeight?: number;\n /** Per-node size resolver (see `NodeSizeResolver`). Resolution order matches\n * `dagreTraceLayout.sizeOf`. */\n readonly nodeSize?: NodeSizeResolver;\n /** Left-to-right order for a fork's children within their band (see\n * `SiblingOrderResolver`). Default = edge-insertion order. */\n readonly siblingOrder?: SiblingOrderResolver;\n /** Bottom-up merge re-centering pass. Default true; off = pass-1 only (debug). */\n readonly enableMergeCentering?: boolean;\n /**\n * How a MERGE (join) node is horizontally placed relative to its inputs:\n * - `\"span\"` (default) — centered under the combined visual SPAN of its\n * inputs. Faithful \"this node's data comes from those boxes\", but when a\n * join's inputs are the splayed children of a fork, the join lands under\n * the splay (off the trunk) and the main path ZIG-ZAGS.\n * - `\"fork-origin\"` — aligned with the FORK the inputs re-converge from\n * (their lowest common ancestor). A join returns to its fork's axis, so\n * the trunk (root → joins → tail) renders as ONE STRAIGHT centered column\n * with the branches splaying symmetrically around it. Nested forks return\n * to their INNER fork. Use for \"read it as a sequence with side-inputs\"\n * charts.\n * Default `\"span\"` (unchanged behavior for existing consumers).\n */\n readonly mergeAlign?: \"span\" | \"fork-origin\";\n}\n\ninterface Adjacency {\n readonly preds: Map<string, string[]>;\n readonly branchSuccs: Map<string, string[]>;\n readonly width: Map<string, number>;\n readonly height: Map<string, number>;\n /** Nodes whose footprint came from the consumer `nodeSize` resolver — their\n * resolved size is stamped onto `style` at emit so the node RENDERS at the\n * same footprint it was LAID OUT for (paint matches layout). Mirrors\n * `dagreTraceLayout`'s `resolvedStyleSizes`. */\n readonly resolvedStyle: Map<string, { width: number; height: number }>;\n}\n\n/**\n * Build forward adjacency from the graph. Loop edges are excluded (visual-only\n * back-edges), duplicate (source,target) pairs are deduped (a doubled edge must\n * not fake a fork/merge), and edges to missing nodes are dropped.\n */\nfunction buildAdjacency(\n graph: TraceGraph,\n fallbackW: number,\n fallbackH: number,\n nodeSize?: NodeSizeResolver,\n): Adjacency {\n const preds = new Map<string, string[]>();\n const branchSuccs = new Map<string, string[]>();\n const width = new Map<string, number>();\n const height = new Map<string, number>();\n const resolvedStyle = new Map<string, { width: number; height: number }>();\n const ids = new Set<string>();\n\n for (const n of graph.nodes) {\n ids.add(n.id);\n const s = sizeOf(n, fallbackW, fallbackH, nodeSize);\n width.set(n.id, s.width);\n height.set(n.id, s.height);\n // Stamp only when sizeOf actually USED the resolver (resolved == final), so\n // a group container's authoritative `style` footprint is NOT overwritten\n // (mirrors dagreTraceLayout). Default/style-sized nodes already render right.\n const resolved = nodeSize?.(n);\n if (resolved && resolved.width === s.width && resolved.height === s.height) {\n resolvedStyle.set(n.id, resolved);\n }\n preds.set(n.id, []);\n branchSuccs.set(n.id, []);\n }\n\n const seen = new Set<string>();\n for (const e of graph.edges) {\n if (e.data?.kind === \"loop\") continue; // visual back-edge — never shapes layout\n if (!ids.has(e.source) || !ids.has(e.target)) continue;\n const key = `${e.source}\u0000${e.target}`;\n if (seen.has(key)) continue; // dedupe — a doubled edge can't fake a fork/merge\n seen.add(key);\n preds.get(e.target)!.push(e.source);\n if (e.data?.kind === \"fork-branch\" || e.data?.kind === \"decision-branch\") {\n branchSuccs.get(e.source)!.push(e.target);\n }\n }\n return { preds, branchSuccs, width, height, resolvedStyle };\n}\n\n/**\n * Longest-path rank for every node (memoized DFS). A merge lands at\n * `max(input ranks) + 1`, so it is ALWAYS below every input regardless of how\n * many bands an input skips — the staggered-merge guarantee. Sources are rank 0.\n * A non-loop cycle (malformed input) is broken at the in-progress node (treated\n * as a rank-0 contribution) rather than recursing forever.\n */\nfunction assignRanks(preds: Map<string, string[]>, ids: readonly string[]): Map<string, number> {\n const rank = new Map<string, number>();\n const inProgress = new Set<string>();\n const visit = (id: string): number => {\n const memo = rank.get(id);\n if (memo !== undefined) return memo;\n if (inProgress.has(id)) return 0; // cycle guard (DAG once loops excluded)\n inProgress.add(id);\n const ps = preds.get(id) ?? [];\n let r = 0;\n for (const p of ps) {\n const pr = visit(p);\n if (pr + 1 > r) r = pr + 1;\n }\n inProgress.delete(id);\n rank.set(id, r);\n return r;\n };\n for (const id of ids) visit(id);\n return rank;\n}\n\n/** Center-x under the combined visual SPAN of the given nodes (min left edge ..\n * max right edge). For equal widths this equals the plain center-average; for\n * asymmetric widths it centers under the span (no drift toward the narrow side). */\nfunction spanCenter(ids: readonly string[], center: Map<string, number>, width: Map<string, number>): number {\n let left = Infinity;\n let right = -Infinity;\n for (const id of ids) {\n const c = center.get(id);\n if (c === undefined) continue;\n const w = width.get(id) ?? 0;\n if (c - w / 2 < left) left = c - w / 2;\n if (c + w / 2 > right) right = c + w / 2;\n }\n if (!Number.isFinite(left)) return 0;\n return (left + right) / 2;\n}\n\n/** All ancestors of `start` (INCLUDING itself), walking `preds` up. Cycle-safe\n * via a visited set; loop edges are already excluded from `preds`. */\nfunction ancestorsOf(start: string, preds: Map<string, string[]>): Set<string> {\n const seen = new Set<string>();\n const stack = [start];\n while (stack.length) {\n const n = stack.pop()!;\n if (seen.has(n)) continue;\n seen.add(n);\n for (const p of preds.get(n) ?? []) if (!seen.has(p)) stack.push(p);\n }\n return seen;\n}\n\n/**\n * The LOWEST COMMON ANCESTOR of a merge's inputs — the fork those inputs\n * re-converge from. Computed as the deepest (highest-rank) node present in EVERY\n * input's ancestor set. Used by `mergeAlign: \"fork-origin\"` so a join aligns\n * with its fork (the trunk returns to one axis) instead of centering under the\n * splayed branches. For nested forks this returns the INNER fork (not the outer\n * root), keeping each sub-trunk straight. Returns `undefined` when the inputs\n * share no common ancestor (disjoint sources) → caller falls back to span.\n */\nfunction lowestCommonAncestor(\n inputs: readonly string[],\n preds: Map<string, string[]>,\n rank: Map<string, number>,\n): string | undefined {\n if (inputs.length === 0) return undefined;\n let common = ancestorsOf(inputs[0]!, preds);\n for (let i = 1; i < inputs.length && common.size > 0; i++) {\n const a = ancestorsOf(inputs[i]!, preds);\n common = new Set([...common].filter((x) => a.has(x)));\n }\n let best: string | undefined;\n let bestRank = -Infinity;\n for (const id of common) {\n const r = rank.get(id) ?? -Infinity;\n if (r > bestRank) (bestRank = r), (best = id);\n }\n return best;\n}\n\n/**\n * Order the ids within one band left-to-right. When they all share a single\n * fork parent and a `siblingOrder` is supplied, honor it; otherwise sort by the\n * primary predecessor's center-x (so children stay under their parents), then\n * by original insertion order.\n */\nfunction orderBand(\n ids: readonly string[],\n preds: Map<string, string[]>,\n center: Map<string, number>,\n insertionIndex: Map<string, number>,\n siblingOrder?: SiblingOrderResolver,\n): string[] {\n if (siblingOrder && ids.length > 1) {\n const parents = new Set(ids.map((id) => preds.get(id)?.[0]));\n if (parents.size === 1) {\n const parent = [...parents][0];\n if (parent !== undefined) {\n const ordered = siblingOrder(parent, ids);\n const used = new Set<string>();\n const out: string[] = [];\n for (const id of ordered) if (ids.includes(id) && !used.has(id)) (out.push(id), used.add(id));\n for (const id of ids) if (!used.has(id)) out.push(id);\n return out;\n }\n }\n }\n return [...ids].sort((a, b) => {\n const pa = preds.get(a)?.[0];\n const pb = preds.get(b)?.[0];\n const ca = pa !== undefined ? center.get(pa) : undefined;\n const cb = pb !== undefined ? center.get(pb) : undefined;\n if (ca !== undefined && cb !== undefined && ca !== cb) return ca - cb;\n return (insertionIndex.get(a) ?? 0) - (insertionIndex.get(b) ?? 0);\n });\n}\n\n/**\n * Lay out a `TraceGraph` by rank bands + span-centered merges. Returns a NEW\n * graph with each node's `position` set. Edges pass through by reference.\n */\nexport function traceGroupLayout(graph: TraceGraph, options: TraceGroupLayoutOptions = {}): TraceGraph {\n if (graph.nodes.length === 0) return { nodes: graph.nodes, edges: graph.edges };\n if (graph.nodes.length === 1) {\n const only = graph.nodes[0]!;\n return { nodes: [{ ...only, position: { x: 0, y: 0 } }], edges: graph.edges };\n }\n\n const rankSep = options.rankSep ?? 80;\n const nodeSep = options.nodeSep ?? 60;\n const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W;\n const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H;\n const mergeCentering = options.enableMergeCentering ?? true;\n const mergeAlign = options.mergeAlign ?? \"span\";\n\n const ids = graph.nodes.map((n) => n.id);\n const insertionIndex = new Map(ids.map((id, i) => [id, i]));\n const { preds, branchSuccs, width, height, resolvedStyle } = buildAdjacency(\n graph,\n fallbackW,\n fallbackH,\n options.nodeSize,\n );\n const rank = assignRanks(preds, ids);\n\n // Orphans (no rank — only possible via the cycle guard) stack below.\n let maxRank = 0;\n for (const r of rank.values()) if (r > maxRank) maxRank = r;\n for (const id of ids) if (!rank.has(id)) rank.set(id, maxRank + 1);\n maxRank = 0;\n for (const r of rank.values()) if (r > maxRank) maxRank = r;\n\n // Band → ids; band → top-y (cumulative by tallest node per band + rankSep).\n const byRank = new Map<number, string[]>();\n const bandMaxH = new Map<number, number>();\n for (const id of ids) {\n const r = rank.get(id)!;\n (byRank.get(r) ?? byRank.set(r, []).get(r)!).push(id);\n bandMaxH.set(r, Math.max(bandMaxH.get(r) ?? 0, height.get(id)!));\n }\n const bandTop = new Map<number, number>();\n let yAcc = 0;\n for (let r = 0; r <= maxRank; r++) {\n bandTop.set(r, yAcc);\n yAcc += (bandMaxH.get(r) ?? fallbackH) + rankSep;\n }\n\n // ── PASS 1 — top-down placement. Every node's positioning dependency lives\n // in a HIGHER band (already placed): a sequence inherits its predecessor's\n // x; a merge centers under its inputs' span; a fork's children are placed\n // as a GROUP centered under the fork parent (symmetric spread). A cursor\n // prevents overlap with the prior node/group in the band. ──\n const center = new Map<string, number>();\n // A merge's center: under its inputs' SPAN (default), or — in \"fork-origin\"\n // mode — on the axis of the fork the inputs re-converge from (their lowest\n // common ancestor), which keeps the trunk straight. The LCA is strictly\n // higher-rank than the merge, so it is already placed when read (top-down\n // PASS 1 and bottom-up PASS 2 both satisfy this). Falls back to span when the\n // inputs share no common ancestor.\n const mergeCenterX = (ps: readonly string[]): number => {\n if (mergeAlign === \"fork-origin\") {\n const lca = lowestCommonAncestor(ps, preds, rank);\n const lcaC = lca !== undefined ? center.get(lca) : undefined;\n if (lcaC !== undefined) return lcaC;\n }\n return spanCenter(ps, center, width);\n };\n for (let r = 0; r <= maxRank; r++) {\n const band = orderBand(byRank.get(r) ?? [], preds, center, insertionIndex, options.siblingOrder);\n let cursor = -Infinity; // left edge available for the next node/group\n let i = 0;\n while (i < band.length) {\n const id = band[i]!;\n const ps = preds.get(id) ?? [];\n const parent = ps.length === 1 ? ps[0]! : undefined;\n const parentBranches = parent !== undefined ? branchSuccs.get(parent) ?? [] : [];\n // Only a real BRANCH child (fork-branch/decision-branch edge) is centered\n // as part of the fork group — a plain `next` child of a fork parent is a\n // sequence node, not a parallel branch, so it must NOT be swept in.\n const isForkChild = parent !== undefined && parentBranches.length >= 2 && parentBranches.includes(id);\n\n if (isForkChild) {\n // Contiguous run of BRANCH siblings sharing this fork parent → center it.\n const run: string[] = [];\n let j = i;\n while (j < band.length) {\n const cand = band[j]!;\n const cps = preds.get(cand) ?? [];\n if (cps.length === 1 && cps[0] === parent && parentBranches.includes(cand)) run.push(cand), j++;\n else break;\n }\n const totalW = run.reduce((s, rid) => s + width.get(rid)!, 0) + (run.length - 1) * nodeSep;\n let left = (center.get(parent) ?? 0) - totalW / 2;\n if (cursor !== -Infinity && left < cursor) left = cursor; // no overlap with prior\n let x = left;\n for (const rid of run) {\n const w = width.get(rid)!;\n center.set(rid, x + w / 2);\n x += w + nodeSep;\n }\n cursor = x;\n i = j;\n } else {\n const w = width.get(id)!;\n let desired: number;\n if (ps.length === 0) desired = (cursor === -Infinity ? 0 : cursor) + w / 2;\n else if (ps.length === 1) desired = center.get(ps[0]!) ?? 0; // sequence: inherit pred x\n else desired = mergeCenterX(ps); // merge: span- or fork-origin-aligned\n const cursorCenter = cursor === -Infinity ? -Infinity : cursor + w / 2;\n const c = Math.max(cursorCenter, desired); // never overlap the left sibling\n center.set(id, c);\n cursor = c + w / 2 + nodeSep;\n i++;\n }\n }\n }\n\n // ── PASS 2 — bottom-up exact merge centering. Walk high→low rank so every\n // merge reads finalized (strictly-higher-rank) inputs. Inputs are NOT\n // shifted; merges sit alone in their band here, so no collision. ──\n if (mergeCentering) {\n for (let r = maxRank; r >= 1; r--) {\n for (const id of byRank.get(r) ?? []) {\n const ps = preds.get(id) ?? [];\n if (ps.length > 1) center.set(id, mergeCenterX(ps));\n }\n }\n }\n\n // ── EMIT — top-left positions; vertically center each node in its band;\n // parent-relative for `parentId` nodes (mirrors dagreTraceLayout). ──\n const centerById = center;\n const positioned: TraceNode[] = graph.nodes.map((n) => {\n const r = rank.get(n.id)!;\n const w = width.get(n.id)!;\n const h = height.get(n.id)!;\n let x = (centerById.get(n.id) ?? 0) - w / 2;\n let y = (bandTop.get(r) ?? 0) + ((bandMaxH.get(r) ?? h) - h) / 2;\n if (n.parentId) {\n const pr = rank.get(n.parentId);\n const pw = width.get(n.parentId);\n const ph = height.get(n.parentId);\n if (pr !== undefined && pw !== undefined && ph !== undefined) {\n const parentX = (centerById.get(n.parentId) ?? 0) - pw / 2;\n const parentY = (bandTop.get(pr) ?? 0) + ((bandMaxH.get(pr) ?? ph) - ph) / 2;\n x -= parentX;\n y -= parentY;\n }\n }\n // Stamp the resolver footprint onto `style` so the node RENDERS at the same\n // size it was laid out for (paint matches layout) — otherwise a funnel-sized\n // merge would render at its intrinsic width and its visual center would drift.\n const styleSize = resolvedStyle.get(n.id);\n if (styleSize) {\n return { ...n, position: { x, y }, style: { ...(n.style ?? {}), width: styleSize.width, height: styleSize.height } };\n }\n return { ...n, position: { x, y } };\n });\n\n return { nodes: positioned, edges: graph.edges };\n}\n\n/**\n * Build a `TraceFlowLayout` from group-layout options. Pass to\n * `<TraceFlow layout={...}>` / `<TracedFlow layout={...}>`, or wrap with the\n * existing `createSnappedDagreLayout(base, opts)` (it is layout-engine-agnostic)\n * and/or `wrapInMainChartBox`.\n */\nexport function createTraceGroupLayout(options: TraceGroupLayoutOptions = {}): TraceFlowLayout {\n return (graph: TraceGraph) => traceGroupLayout(graph, options);\n}\n","/**\n * createNodeViewRecorder — per-stage summary translator.\n *\n * Implements footprintjs v6.0+ `CombinedRecorder` (Flow + Scope) and\n * produces a `NodeViewIndex` — per-stage data keyed by both `StageId`\n * (chart-shape lookup) and `RuntimeStageId` (per-execution lookup).\n *\n * Composition (panel guidance, L8.0 review)\n * ─────────────────────────────────────────\n * NodeView does NOT duplicate the structural prev/next index — it\n * READS those fields from the structure translator's\n * `node.data.prevIds`/`nextIds`. The structure translator already\n * maintains convergence-correct, loop-excluded neighbors. Duplicating\n * the index here would re-introduce edge-ordering bugs we just\n * solved.\n *\n * The NodeView translator owns ONLY runtime-derived per-stage state:\n * - `executions[]` — every FlowRecorder.onStageExecuted event for\n * this stage (loop-friendly: N executions of one stage produce\n * N entries, each with its own runtimeStageId).\n * - `commitRuntimeStageIds[]` — refs to commits made by this stage\n * (the canonical CommitView lives in CommitFlowIndex from L8.2;\n * NodeView stores only the join key).\n *\n * Plus derived convenience fields: `visitedInRun`, `executionCount`,\n * `firstExecutedAt`, `lastExecutedAt`, `totalDurationMs`, `errorCount`.\n *\n * Version bumping\n * ───────────────\n * NodeView bumps its own version on EITHER:\n * (a) a Flow/Scope event arrives (own state mutates), OR\n * (b) the structure translator's version bumps (structural data\n * the index projects from changed).\n *\n * So `useTranslator(nodeView, ...)` re-renders when EITHER changes —\n * one subscription, full reactive coverage.\n *\n * @example\n * ```tsx\n * import { createTraceStructureRecorder, createNodeViewRecorder, useTranslator } from 'footprint-explainable-ui/flowchart';\n *\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const nodeView = useMemo(() => createNodeViewRecorder({ structure: trace }), [trace]);\n *\n * useEffect(() => {\n * executor.attachFlowRecorder(nodeView.recorder);\n * executor.attachScopeRecorder(nodeView.recorder);\n * }, [nodeView]);\n *\n * const index = useTranslator(nodeView, () => nodeView.getIndex());\n * const finalize = index.byStageId.get(asStageId('FinalizeOrder'));\n * // finalize.prevIds → ['CheckInventory', 'RunFraudCheck'] (from structure)\n * // finalize.executions → [{ runtimeStageId, iteration, startMs, endMs, ... }]\n * // finalize.visitedInRun → true\n * // finalize.commitRuntimeStageIds → ['finalize-order#3', ...]\n * ```\n */\n\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport { asStageId, asRuntimeStageId } from \"./_internal/keys\";\nimport type { StageId, RuntimeStageId } from \"./_internal/keys\";\nimport type { TraceStructureRecorderHandle, TraceNode } from \"./traceStructureRecorder\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local mirrors of footprintjs runtime recorder interfaces\n// ─────────────────────────────────────────────────────────────────────────────\n//\n// Same rationale as other translators: explainable-ui has no\n// `footprintjs` dep — we mirror the subset we consume. Structural\n// compatibility means our `recorder` passes through to\n// `executor.attachFlowRecorder()` / `attachScopeRecorder()` cleanly.\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface FlowStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly traversalContext: TraversalContext;\n readonly startTime?: number;\n readonly endTime?: number;\n}\n\ninterface FlowErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface FlowRunLifecycleEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface ScopeCommitEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly updates?: Record<string, unknown>;\n readonly reads?: readonly string[];\n}\n\n/**\n * Minimal CombinedRecorder interface mirror — subset of footprintjs's\n * Flow + Scope recorder interfaces NodeView consumes. Implements both\n * channels in one object; consumer attaches via\n * `executor.attachFlowRecorder()` AND `executor.attachScopeRecorder()`\n * (or `executor.attachCombinedRecorder()` if available).\n */\nexport interface MinimalNodeViewRecorder {\n readonly id: string;\n // Flow channel\n onStageExecuted?(event: FlowStageExecutedEvent): void;\n onError?(event: FlowErrorEvent): void;\n onRunStart?(event: FlowRunLifecycleEvent): void;\n onRunEnd?(event: FlowRunLifecycleEvent): void;\n // Scope channel\n onCommit?(event: ScopeCommitEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** One execution of a stage. A stage that runs N times in a loop\n * produces N `ExecutionRecord` entries on the NodeView.executions[]. */\nexport interface ExecutionRecord {\n /** `[subflowPath/]stageId#executionIndex` — universal join key. */\n readonly runtimeStageId: RuntimeStageId;\n /** Loop iteration (0-indexed). undefined when the engine didn't\n * populate it (rare). */\n readonly iteration?: number;\n /** ms since executor start. */\n readonly startMs?: number;\n /** ms since executor start. */\n readonly endMs?: number;\n /** Set when `onError` fired for this execution. */\n readonly errorMessage?: string;\n}\n\n/**\n * Per-stage summary. Joins STRUCTURAL data (from the structure\n * translator's TraceNode.data) with RUNTIME data (executions + commit\n * refs accumulated by this translator).\n */\nexport interface NodeView {\n // ── Identity ────────────────────────────────────────────────────\n readonly stageId: StageId;\n readonly label: string;\n\n // ── Structural (read-through from structure translator) ─────────\n readonly type: \"stage\" | \"decider\" | \"selector\" | \"fork\" | \"streaming\" | \"subflow\" | \"loop\";\n readonly isDecider: boolean;\n readonly isFork: boolean;\n readonly isSubflow: boolean;\n readonly isStreaming: boolean;\n readonly isPausable: boolean;\n readonly description?: string;\n readonly icon?: string;\n readonly subflowId?: string;\n readonly branchIds?: readonly string[];\n readonly defaultBranch?: string;\n /** From the structure translator (loop-excluded, convergence-correct). */\n readonly prevIds: StageId[];\n readonly nextIds: StageId[];\n\n // ── Visit data (runtime) ────────────────────────────────────────\n readonly executions: ExecutionRecord[];\n /** Derived: `executions.length > 0`. */\n readonly visitedInRun: boolean;\n /** Derived: `executions.length` (loop iteration count). */\n readonly executionCount: number;\n /** Derived: first execution `startMs`, or `null` if not yet executed. */\n readonly firstExecutedAt: number | null;\n /** Derived: last execution `endMs`, or `null`. */\n readonly lastExecutedAt: number | null;\n /** Derived: sum of `endMs - startMs` across executions. */\n readonly totalDurationMs: number;\n /** Derived: count of executions with an errorMessage. */\n readonly errorCount: number;\n\n // ── Commit refs (join key into CommitFlowIndex from L8.2) ───────\n /** Run-time stage ids of commits made by this stage. Look up the\n * canonical CommitView via `commitFlow.byRuntimeStageId.get(id)`. */\n readonly commitRuntimeStageIds: RuntimeStageId[];\n}\n\n/** Index of NodeView keyed by both StageId and RuntimeStageId. The\n * branded types prevent `byStageId.get(runtimeStageId)` silent-undefined. */\nexport interface NodeViewIndex {\n readonly byStageId: ReadonlyMap<StageId, NodeView>;\n readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, NodeView>;\n /** All NodeViews — insertion order matches structure translator. */\n readonly all: readonly NodeView[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface NodeViewRecorderHandle {\n /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`\n * AND `executor.attachScopeRecorder()` (footprintjs routes by\n * method-shape detection). */\n recorder: MinimalNodeViewRecorder;\n /** Returns a defensive copy of the current index state. */\n getIndex(): NodeViewIndex;\n /** Pub-sub: returns unsubscribe. Designed for `useSyncExternalStore`. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps on Flow/Scope event OR when\n * the structure translator's version bumps (since NodeView projects\n * from its data). */\n version(): number;\n /** Reset runtime state. Does NOT bump version or notify (consistent\n * with traceStructureRecorder + createTraceRuntimeOverlay). */\n reset(): void;\n}\n\nexport interface CreateNodeViewRecorderOptions {\n /** Recorder id (surfaces in error attribution). */\n id?: string;\n /** REQUIRED — the structure translator handle. NodeView projects\n * structural fields (`prevIds`, `nextIds`, `label`, etc.) from\n * this on every `getIndex()` call. */\n structure: TraceStructureRecorderHandle;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Strip `#executionIndex` from runtimeStageId to recover the base\n * stageId. **Use only for in-translator matching where both sides\n * use full-path-prefixed stageIds consistently** (invariant I3 — do\n * NOT use this to match commitLog stageIds across subflow boundaries). */\nfunction baseStageIdOf(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createNodeViewRecorder(\n options: CreateNodeViewRecorderOptions,\n): NodeViewRecorderHandle {\n const id = options.id ?? \"node-view\";\n const structure = options.structure;\n if (!structure) {\n throw new Error(\n \"[createNodeViewRecorder] `structure` option is required. \" +\n \"Pass the handle returned by `createTraceStructureRecorder()`.\",\n );\n }\n\n // Per-stage execution + commit-ref state. Keyed by base stageId.\n // Loops produce multiple entries with the same stageId / different\n // runtimeStageIds.\n let executionsOf: Map<StageId, ExecutionRecord[]> = new Map();\n let commitRefsOf: Map<StageId, RuntimeStageId[]> = new Map();\n // Reverse lookup: runtimeStageId → its base stageId. Lets\n // `byRuntimeStageId` map directly to a NodeView without\n // re-parsing.\n let stageIdOfRuntimeStageId: Map<RuntimeStageId, StageId> = new Map();\n\n const notifier = createNotifier(\"node-view\");\n\n // Subscribe to structure translator — when its graph changes\n // (e.g., new stage announced during incremental build), bump our\n // version so consumers re-derive the projection.\n const unsubStructure = structure.subscribe(() => notifier.notify());\n\n function recordExecution(event: FlowStageExecutedEvent): void {\n // L8.1 Panel 2 must-fix: guard against malformed event payloads\n // (asymmetric with recordError's existing guard). Upstream MAY\n // fire with traversalContext absent if the engine's runtime\n // observer chain is reorganised — fail soft, not hard.\n const rsid = event.traversalContext?.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onStageExecuted event without traversalContext.runtimeStageId — execution attribution dropped (stage=${event.stageName}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const runtimeStageId = asRuntimeStageId(rsid);\n const execList = executionsOf.get(stageId) ?? [];\n const record: ExecutionRecord = {\n runtimeStageId,\n ...(event.traversalContext.iteration !== undefined && {\n iteration: event.traversalContext.iteration,\n }),\n ...(event.startTime !== undefined && { startMs: event.startTime }),\n ...(event.endTime !== undefined && { endMs: event.endTime }),\n };\n execList.push(record);\n executionsOf.set(stageId, execList);\n stageIdOfRuntimeStageId.set(runtimeStageId, stageId);\n notifier.notify();\n }\n\n function recordError(event: FlowErrorEvent): void {\n const rsid = event.traversalContext?.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onError event without traversalContext.runtimeStageId — error attribution dropped (stage=${event.stageName}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const runtimeStageId = asRuntimeStageId(rsid);\n const execList = executionsOf.get(stageId);\n // L8.1 Panel 1 must-fix: match by runtimeStageId equality (NOT\n // array position). With interleaved-stage events under footprintjs's\n // FlowRecorder dispatcher, \"most-recent execution by array index\"\n // can attach an error to the wrong execution. Looking up by\n // runtimeStageId is the correct join key.\n const matchIdx = execList\n ? execList.findIndex((e) => e.runtimeStageId === runtimeStageId)\n : -1;\n if (!execList || matchIdx === -1) {\n // Error before onStageExecuted? Synthesize a minimal execution\n // record so consumers see the error.\n const synth: ExecutionRecord = {\n runtimeStageId,\n errorMessage: event.message ?? \"error\",\n };\n if (execList) {\n execList.push(synth);\n } else {\n executionsOf.set(stageId, [synth]);\n }\n } else {\n const match = execList[matchIdx]!;\n execList[matchIdx] = { ...match, errorMessage: event.message ?? \"error\" };\n }\n stageIdOfRuntimeStageId.set(runtimeStageId, stageId);\n notifier.notify();\n }\n\n function recordCommit(event: ScopeCommitEvent): void {\n // Read runtimeStageId directly from the onCommit payload\n // (panel L8.0 ordering invariant: Scope.onCommit fires BEFORE\n // Flow.onStageExecuted; don't rely on Flow event arriving first).\n const rsid = event.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createNodeViewRecorder] onCommit event without runtimeStageId — commit attribution dropped (stage=${event.stage ?? event.stageId ?? \"?\"}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n const refs = commitRefsOf.get(stageId) ?? [];\n refs.push(asRuntimeStageId(rsid));\n commitRefsOf.set(stageId, refs);\n stageIdOfRuntimeStageId.set(asRuntimeStageId(rsid), stageId);\n notifier.notify();\n }\n\n const recorder: MinimalNodeViewRecorder = {\n id,\n onStageExecuted: recordExecution,\n onError: recordError,\n onCommit: recordCommit,\n // onRunStart / onRunEnd — no-op for now (state stays alive across\n // runs; consumers call .reset() between runs if they want fresh\n // state). Listed for shape conformance with FlowRecorder.\n onRunStart() {\n /* no-op */\n },\n onRunEnd() {\n /* no-op */\n },\n };\n\n function buildView(structNode: TraceNode): NodeView {\n const stageId = asStageId(structNode.id);\n const execs = executionsOf.get(stageId) ?? [];\n const commitRefs = commitRefsOf.get(stageId) ?? [];\n\n // Derived visit-data fields\n const visitedInRun = execs.length > 0;\n const executionCount = execs.length;\n const firstExecutedAt = execs.length > 0 && execs[0]!.startMs !== undefined\n ? execs[0]!.startMs!\n : null;\n const lastExecutedAt = execs.length > 0 && execs[execs.length - 1]!.endMs !== undefined\n ? execs[execs.length - 1]!.endMs!\n : null;\n let totalDurationMs = 0;\n let errorCount = 0;\n for (const e of execs) {\n if (e.startMs !== undefined && e.endMs !== undefined) {\n totalDurationMs += e.endMs - e.startMs;\n }\n if (e.errorMessage) errorCount++;\n }\n\n const d = structNode.data;\n return {\n stageId,\n label: d.label,\n type: (structNode.type as NodeView[\"type\"]) ?? \"stage\",\n isDecider: d.isDecider,\n isFork: d.isFork,\n isSubflow: d.isSubflow,\n isStreaming: d.isStreaming,\n isPausable: d.isPausable === true,\n ...(d.description !== undefined && { description: d.description }),\n ...(d.icon !== undefined && { icon: d.icon }),\n ...(d.subflowId !== undefined && { subflowId: d.subflowId }),\n // L8.1 Panel 2 must-fix: branchIds is a live ref from the\n // structure translator's internal graph — defensive copy via\n // slice() prevents consumer mutation from corrupting it.\n ...(d.branchIds !== undefined && { branchIds: d.branchIds.slice() }),\n ...(d.defaultBranch !== undefined && { defaultBranch: d.defaultBranch }),\n // Note: structure translator always sets prevIds/nextIds (never\n // undefined). The slice() copies defend against consumer mutation.\n prevIds: d.prevIds.slice(),\n nextIds: d.nextIds.slice(),\n executions: execs.map((e) => ({ ...e })),\n visitedInRun,\n executionCount,\n firstExecutedAt,\n lastExecutedAt,\n totalDurationMs,\n errorCount,\n commitRuntimeStageIds: commitRefs.slice(),\n };\n }\n\n // L8.1 Panel 5 optimization: version-keyed cache. `getIndex()` is\n // called per React render that observes a version bump; with N\n // translators subscribed + StrictMode double-invoke, a single\n // stage event can produce 6+ full rebuilds. Cache the last index\n // keyed on `(ownVersion, structureVersion)` — return the cached\n // index when neither has changed since the previous build.\n let cachedIndex: NodeViewIndex | null = null;\n let cachedOwnVersion = -1;\n let cachedStructureVersion = -1;\n\n return {\n recorder,\n getIndex(): NodeViewIndex {\n const own = notifier.version();\n const struct = structure.version();\n if (\n cachedIndex !== null &&\n cachedOwnVersion === own &&\n cachedStructureVersion === struct\n ) {\n return cachedIndex;\n }\n // Read structure live — we project from its current graph each\n // call. Defensive-copy via getGraph() would over-allocate; we\n // use getGraphRef() and tolerate the read-only contract (we\n // don't mutate structure data).\n const graphRef = structure.getGraphRef();\n const byStageId = new Map<StageId, NodeView>();\n const byRuntimeStageId = new Map<RuntimeStageId, NodeView>();\n const all: NodeView[] = [];\n for (const structNode of graphRef.nodes) {\n const view = buildView(structNode);\n byStageId.set(view.stageId, view);\n all.push(view);\n // Reverse map: every execution's runtimeStageId → this view.\n for (const exec of view.executions) {\n byRuntimeStageId.set(exec.runtimeStageId, view);\n }\n // Commit refs also point back to this view (a stage's\n // runtimeStageId for its execution is the same key its\n // commit carries).\n for (const rsid of view.commitRuntimeStageIds) {\n byRuntimeStageId.set(rsid, view);\n }\n }\n cachedIndex = { byStageId, byRuntimeStageId, all };\n cachedOwnVersion = own;\n cachedStructureVersion = struct;\n return cachedIndex;\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n executionsOf = new Map();\n commitRefsOf = new Map();\n stageIdOfRuntimeStageId = new Map();\n // L8.1 — invalidate the version-keyed cache. We do NOT bump\n // version (matches the other translators' reset contract — see\n // traceStructureRecorder's `reset()` JSDoc for the consumer\n // recipe), but the cache MUST be cleared so the next\n // `getIndex()` rebuilds from the freshly-empty state instead\n // of returning a stale snapshot.\n cachedIndex = null;\n cachedOwnVersion = -1;\n cachedStructureVersion = -1;\n // We intentionally do NOT unsubscribe from structure here; the\n // handle is still alive across resets.\n void unsubStructure;\n },\n };\n}\n","/**\n * createCommitFlowRecorder — per-commit summary translator.\n *\n * Owns the canonical `CommitView[]` — captured from Scope `onCommit`\n * events as the chart runs. Each CommitView joins:\n *\n * - **Identity**: runtimeStageId, stageId, commitIdx\n * - **Structural**: prev/next stage ids (read from structure\n * translator's `TraceNode.data.prevIds`/`nextIds`)\n * - **Runtime prev/next**: derived via \"most-recent-per-structural-\n * prev\" rule over the commitLog (loop-safe, convergence-aware)\n * - **Data dependencies**: per-read-key lineage via\n * `findLastWriter` over the commitLog\n * - **Payload**: updates + reads\n *\n * Composition (panel guidance, L8.1 review)\n * ─────────────────────────────────────────\n * Per Panel 1 rule \"translators MUST subscribe to structure\n * directly, never to peer translators\", CommitFlow subscribes to\n * the structure handle (NOT to NodeView). Linear dependency tree\n * keeps notify cascades O(depth) instead of O(N²).\n *\n * NodeView (L8.1) stores `commitRuntimeStageIds[]` — refs only —\n * pointing into CommitFlow's `byRuntimeStageId`. The canonical\n * payload lives HERE; NodeView is the per-stage projection.\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const commitFlow = useMemo(\n * () => createCommitFlowRecorder({ structure: trace }),\n * [trace],\n * );\n * useEffect(() => {\n * executor.attachFlowRecorder(commitFlow.recorder);\n * executor.attachScopeRecorder(commitFlow.recorder);\n * }, [commitFlow]);\n *\n * const index = useTranslator(commitFlow, () => commitFlow.getIndex());\n * const c = index.byRuntimeStageId.get(asRuntimeStageId('finalize-order#3'));\n * c.structuralPrevIds // ['CheckInventory', 'RunFraudCheck']\n * c.runtimePrevIds // ['check-inventory#1', 'run-fraud-check#2']\n * c.dataDependencies // [{ key:'inStock', sourceRuntimeStageId:'check-inventory#1', sourceCommitIdx:1 }, ...]\n *\n * const lineage = backtraceDataFlow(index, asRuntimeStageId('finalize-order#3'));\n * // → ancestry chain of commits whose writes contributed to this commit's reads\n * ```\n */\n\nimport { createNotifier } from \"./_internal/notifyChange\";\nimport { devWarn } from \"./_internal/devWarn\";\nimport { asStageId, asRuntimeStageId } from \"./_internal/keys\";\nimport type { StageId, RuntimeStageId } from \"./_internal/keys\";\nimport type { TraceStructureRecorderHandle } from \"./traceStructureRecorder\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Local mirrors of footprintjs runtime recorder interfaces\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface TraversalContext {\n readonly runtimeStageId: string;\n readonly iteration?: number;\n readonly runId?: string;\n}\n\ninterface FlowStageExecutedEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly traversalContext: TraversalContext;\n}\n\ninterface FlowErrorEvent {\n readonly stageName: string;\n readonly stageId?: string;\n readonly message?: string;\n readonly traversalContext?: TraversalContext;\n}\n\ninterface FlowRunLifecycleEvent {\n readonly traversalContext?: TraversalContext;\n}\n\ninterface ScopeReadEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly key?: string;\n}\n\ninterface ScopeCommitEvent {\n readonly stage?: string;\n readonly stageId?: string;\n readonly runtimeStageId?: string;\n readonly updates?: Record<string, unknown>;\n readonly reads?: readonly string[];\n}\n\n/**\n * Minimal CombinedRecorder mirror — subset of footprintjs's Flow +\n * Scope channels CommitFlow consumes.\n */\nexport interface MinimalCommitFlowRecorder {\n readonly id: string;\n // Flow channel — for runtimeStageId enrichment + error attribution\n onStageExecuted?(event: FlowStageExecutedEvent): void;\n onError?(event: FlowErrorEvent): void;\n onRunStart?(event: FlowRunLifecycleEvent): void;\n onRunEnd?(event: FlowRunLifecycleEvent): void;\n // Scope channel — the canonical commit + read data source\n onRead?(event: ScopeReadEvent): void;\n onCommit?(event: ScopeCommitEvent): void;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output shape\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * One data-dependency edge — a read key in this commit AND the commit\n * whose `updates` last wrote that key before this commit's index.\n *\n * `sourceRuntimeStageId` and `sourceCommitIdx` are BOTH `null` when no\n * prior commit wrote the key (panel-flagged: NEVER `undefined` — forces\n * consumers to handle absence as load-bearing).\n */\nexport interface DataDependency {\n readonly key: string;\n readonly sourceRuntimeStageId: RuntimeStageId | null;\n readonly sourceCommitIdx: number | null;\n}\n\n/**\n * Per-commit summary. Joins structural data (from the structure\n * translator) with runtime data (commitLog timeline) into a single\n * consumer-friendly shape.\n *\n * Three \"prev\" views — pick the right one for your UI:\n * ─────────────────────────────────────────────────────\n * | Field | Answers |\n * |----------------------|--------------------------------------------|\n * | `structuralPrevIds` | \"what COULD flow in\" (chart shape) |\n * | `runtimePrevIds` | \"what DID flow in by stage\" (execution |\n * | | timeline; loop-aware) |\n * | `dataDependencies` | \"which commit wrote the bytes I read\" |\n * | | (causal data lineage; per-key) |\n *\n * The three answers usually align on simple charts (linear; single\n * fork-merge). They DIVERGE in interesting ways under loops (runtime\n * differs by iteration; data-deps may skip uninvolved stages) and\n * conditional branches (structural sees all options; runtime + data\n * see only the chosen path).\n */\nexport interface CommitView {\n // ── Identity ────────────────────────────────────────────────────\n readonly runtimeStageId: RuntimeStageId;\n readonly stageId: StageId;\n /** Position in the chronologically-ordered commitLog. */\n readonly commitIdx: number;\n\n // ── Structural (from structure translator) ──────────────────────\n /** Stage ids that lead into this stage in the chart (loop-excluded). */\n readonly structuralPrevIds: StageId[];\n readonly structuralNextIds: StageId[];\n\n // ── Runtime (derived: structural prev ∩ commitLog up-to-here) ──\n /**\n * For each structural prev stage that EXECUTED IN THIS RUN before\n * this commit, the most-recent runtimeStageId of that prev's commit.\n * Loop-safe: in iteration 2, runtime prev points at iteration 2's\n * commits (not iteration 1's).\n */\n readonly runtimePrevIds: RuntimeStageId[];\n /**\n * For each structural next stage that EXECUTED IN THIS RUN after\n * this commit, the soonest runtimeStageId. Symmetric to prev.\n */\n readonly runtimeNextIds: RuntimeStageId[];\n\n // ── Data flow (per-key lineage via findLastWriter) ──────────────\n /**\n * One entry per key in `reads`. `sourceRuntimeStageId` points at the\n * commit whose `updates` last set this key BEFORE this commit's\n * index; `null` when no prior writer (typically: read of a key\n * declared as default but never written by another stage).\n */\n readonly dataDependencies: DataDependency[];\n\n // ── Payload ─────────────────────────────────────────────────────\n /**\n * The commit's writes. **Shallow-copied** at intake — top-level\n * keys are owned, but nested object values are SHARED references\n * to whatever the upstream `onCommit` payload carried. Consumers\n * MUST NOT mutate nested values; doing so corrupts the recorder's\n * internal state and propagates through `findLastWriter` to every\n * subsequent `getIndex()` call.\n */\n readonly updates: Record<string, unknown>;\n readonly reads: string[];\n}\n\n/** Indexed CommitView access. */\nexport interface CommitFlowIndex {\n /** Ordered list — index === commitIdx. */\n readonly commits: readonly CommitView[];\n /** Lookup by runtimeStageId (the universal join key). */\n readonly byRuntimeStageId: ReadonlyMap<RuntimeStageId, CommitView>;\n /**\n * Data-dependency edges — `from` and `to` are commitIdx ints; `key`\n * is the data key that flowed from one commit to the other. Same\n * data as walking each CommitView's `dataDependencies` — exposed as\n * a flat edge list for graph algorithms and rendering.\n *\n * **When to use which**:\n * - `view.dataDependencies` — render ONE commit's inputs in a\n * detail panel (e.g., `<CommitInspector>`).\n * - `index.dataEdges` — draw the FULL data-flow DAG (React Flow\n * edges, GraphViz, dependency matrix, etc.). One pass over the\n * flat list = the whole graph.\n *\n * Edges are `Object.freeze()`d at construction — type `readonly` is\n * compile-time; freeze is the runtime enforcement.\n */\n readonly dataEdges: readonly { readonly from: number; readonly to: number; readonly key: string }[];\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Handle\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface CommitFlowRecorderHandle {\n /** CombinedRecorder — attach via BOTH `executor.attachFlowRecorder()`\n * AND `executor.attachScopeRecorder()`. */\n recorder: MinimalCommitFlowRecorder;\n /** Returns a defensive copy of the current index state. */\n getIndex(): CommitFlowIndex;\n /** Pub-sub: returns unsubscribe. */\n subscribe(listener: () => void): () => void;\n /** Monotonic version counter — bumps on Scope/Flow event OR when\n * the structure translator's version bumps. */\n version(): number;\n /** Reset runtime state. Does NOT bump version or notify (consistent\n * with other translators' reset contracts). */\n reset(): void;\n}\n\nexport interface CreateCommitFlowRecorderOptions {\n /** Recorder id (surfaces in error attribution). */\n id?: string;\n /** REQUIRED — structure translator handle for structural prev/next\n * projection. CommitFlow subscribes to its version. */\n structure: TraceStructureRecorderHandle;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Strip `#executionIndex` from a runtimeStageId to recover the base\n * stageId. **Invariant I3**: matches commitLog stageIds when the\n * runtimeStageId already carries the full subflow path prefix the\n * engine emits. Do NOT manually re-parse subflow paths. */\nfunction baseStageIdOf(runtimeStageId: string): string {\n const hashIdx = runtimeStageId.indexOf(\"#\");\n return hashIdx >= 0 ? runtimeStageId.slice(0, hashIdx) : runtimeStageId;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Factory\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport function createCommitFlowRecorder(\n options: CreateCommitFlowRecorderOptions,\n): CommitFlowRecorderHandle {\n const id = options.id ?? \"commit-flow\";\n const structure = options.structure;\n if (!structure) {\n throw new Error(\n \"[createCommitFlowRecorder] `structure` option is required. \" +\n \"Pass the handle returned by `createTraceStructureRecorder()`.\",\n );\n }\n\n // Internal raw commit storage — `RawCommit` is the un-projected\n // version (no structural/runtime joins yet). The full `CommitView`\n // gets computed on `getIndex()` (cached by version key).\n interface RawCommit {\n runtimeStageId: RuntimeStageId;\n stageId: StageId;\n commitIdx: number;\n updates: Record<string, unknown>;\n reads: string[];\n }\n let rawCommits: RawCommit[] = [];\n\n const notifier = createNotifier(\"commit-flow\");\n const unsubStructure = structure.subscribe(() => notifier.notify());\n\n function recordCommit(event: ScopeCommitEvent): void {\n // L8.0 ordering invariant — Scope.onCommit fires BEFORE Flow's\n // onStageExecuted. We read runtimeStageId directly from the\n // onCommit payload, NEVER waiting for a Flow event to enrich.\n const rsid = event.runtimeStageId;\n if (!rsid) {\n devWarn(\n () =>\n `[createCommitFlowRecorder] onCommit without runtimeStageId — commit dropped (stage=${event.stage ?? event.stageId ?? \"?\"}).`,\n );\n return;\n }\n const stageId = asStageId(baseStageIdOf(rsid));\n rawCommits.push({\n runtimeStageId: asRuntimeStageId(rsid),\n stageId,\n commitIdx: rawCommits.length,\n updates: event.updates ? { ...event.updates } : {},\n reads: event.reads ? [...event.reads] : [],\n });\n notifier.notify();\n }\n\n // Flow channel handlers — no-ops for the canonical commit-data\n // capture (Scope.onCommit already carries runtimeStageId). Listed\n // so the recorder shape matches FlowRecorder and `attachTo()` can\n // attach via attachFlowRecorder for parity with other translators.\n // onError doesn't influence CommitView state today — errors belong\n // to NodeView's per-stage projection.\n const recorder: MinimalCommitFlowRecorder = {\n id,\n onCommit: recordCommit,\n onStageExecuted() {\n /* no-op — CommitFlow is commit-centric, not execution-centric */\n },\n onError() {\n /* no-op */\n },\n onRunStart() {\n /* no-op */\n },\n onRunEnd() {\n /* no-op */\n },\n };\n\n function buildIndex(): CommitFlowIndex {\n // Snapshot structure once — `getGraphRef()` returns live refs;\n // we only read from `node.data.prevIds`/`nextIds` (read-only).\n const graphRef = structure.getGraphRef();\n const nodeByStageId = new Map<string, (typeof graphRef.nodes)[number]>();\n for (const n of graphRef.nodes) nodeByStageId.set(n.id, n);\n\n // Precompute per-key writer index for findLastWriter (linear-time\n // build, O(1) lookup per read in the per-commit loop below).\n // Maps key → ordered list of {commitIdx, runtimeStageId} for\n // commits that wrote this key.\n interface KeyWriter {\n commitIdx: number;\n runtimeStageId: RuntimeStageId;\n }\n const writersOf = new Map<string, KeyWriter[]>();\n for (const rc of rawCommits) {\n for (const k of Object.keys(rc.updates)) {\n const list = writersOf.get(k) ?? [];\n list.push({ commitIdx: rc.commitIdx, runtimeStageId: rc.runtimeStageId });\n writersOf.set(k, list);\n }\n }\n\n // Precompute per-stage commit-index lists for runtimePrev/Next\n // derivation. Each stageId → ordered list of commitIdx where that\n // stage committed.\n const commitsOfStage = new Map<string, number[]>();\n for (const rc of rawCommits) {\n const list = commitsOfStage.get(rc.stageId) ?? [];\n list.push(rc.commitIdx);\n commitsOfStage.set(rc.stageId, list);\n }\n\n const commits: CommitView[] = [];\n const byRuntimeStageId = new Map<RuntimeStageId, CommitView>();\n const dataEdges: { from: number; to: number; key: string }[] = [];\n\n for (const rc of rawCommits) {\n const structNode = nodeByStageId.get(rc.stageId);\n const structuralPrevIds = (structNode?.data.prevIds ?? []).slice();\n const structuralNextIds = (structNode?.data.nextIds ?? []).slice();\n\n // runtimePrevIds — for each structural prev, the most-recent\n // commit with that stageId BEFORE rc.commitIdx.\n const runtimePrevIds: RuntimeStageId[] = [];\n for (const pStageId of structuralPrevIds) {\n const list = commitsOfStage.get(pStageId);\n if (!list) continue;\n // Walk backwards to find the highest commitIdx strictly less\n // than rc.commitIdx (invariant I2: strict `<`, not `<=`).\n let chosenIdx: number | null = null;\n for (let i = list.length - 1; i >= 0; i--) {\n if (list[i]! < rc.commitIdx) {\n chosenIdx = list[i]!;\n break;\n }\n }\n if (chosenIdx !== null) {\n runtimePrevIds.push(rawCommits[chosenIdx]!.runtimeStageId);\n }\n }\n\n // runtimeNextIds — for each structural next, the soonest commit\n // with that stageId AFTER rc.commitIdx.\n const runtimeNextIds: RuntimeStageId[] = [];\n for (const nStageId of structuralNextIds) {\n const list = commitsOfStage.get(nStageId);\n if (!list) continue;\n let chosenIdx: number | null = null;\n for (let i = 0; i < list.length; i++) {\n if (list[i]! > rc.commitIdx) {\n chosenIdx = list[i]!;\n break;\n }\n }\n if (chosenIdx !== null) {\n runtimeNextIds.push(rawCommits[chosenIdx]!.runtimeStageId);\n }\n }\n\n // Data dependencies — per-read-key findLastWriter.\n const dataDependencies: DataDependency[] = [];\n for (const key of rc.reads) {\n const writers = writersOf.get(key);\n let source: KeyWriter | null = null;\n if (writers) {\n for (let i = writers.length - 1; i >= 0; i--) {\n if (writers[i]!.commitIdx < rc.commitIdx) {\n source = writers[i]!;\n break;\n }\n }\n }\n if (source) {\n dataDependencies.push({\n key,\n sourceRuntimeStageId: source.runtimeStageId,\n sourceCommitIdx: source.commitIdx,\n });\n // L8.2 Panel 2 must-fix: freeze each edge so consumers can't\n // mutate the exposed objects. `readonly` is type-only; this\n // is the runtime enforcement.\n dataEdges.push(\n Object.freeze({ from: source.commitIdx, to: rc.commitIdx, key }),\n );\n } else {\n // Panel must-fix: use `null` (not `undefined`) for missing\n // source — forces consumers to handle absence load-bearingly.\n dataDependencies.push({\n key,\n sourceRuntimeStageId: null,\n sourceCommitIdx: null,\n });\n }\n }\n\n const view: CommitView = {\n runtimeStageId: rc.runtimeStageId,\n stageId: rc.stageId,\n commitIdx: rc.commitIdx,\n structuralPrevIds,\n structuralNextIds,\n runtimePrevIds,\n runtimeNextIds,\n dataDependencies,\n updates: { ...rc.updates },\n reads: rc.reads.slice(),\n };\n commits.push(view);\n byRuntimeStageId.set(view.runtimeStageId, view);\n }\n\n return { commits, byRuntimeStageId, dataEdges };\n }\n\n // L8.1 Panel 5 optimization: version-keyed cache. Same pattern as\n // NodeView — rebuild on (ownVersion, structureVersion) change.\n let cachedIndex: CommitFlowIndex | null = null;\n let cachedOwnVersion = -1;\n let cachedStructureVersion = -1;\n\n return {\n recorder,\n getIndex(): CommitFlowIndex {\n const own = notifier.version();\n const struct = structure.version();\n if (\n cachedIndex !== null &&\n cachedOwnVersion === own &&\n cachedStructureVersion === struct\n ) {\n return cachedIndex;\n }\n cachedIndex = buildIndex();\n cachedOwnVersion = own;\n cachedStructureVersion = struct;\n return cachedIndex;\n },\n subscribe: notifier.subscribe,\n version: notifier.version,\n reset(): void {\n rawCommits = [];\n // Cache invalidation — version doesn't bump (panel reset contract),\n // but next getIndex() must rebuild from the freshly-empty state.\n cachedIndex = null;\n cachedOwnVersion = -1;\n cachedStructureVersion = -1;\n // Subscription to structure is INTENTIONALLY kept across resets\n // (matches NodeView's reset contract). The handle is alive for\n // the recorder's full lifetime; consumer that wants full\n // disposal should drop the handle reference + let GC reclaim.\n // Referenced here purely to keep the closure alive for the\n // unsub's lexical scope.\n void unsubStructure;\n },\n };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Data-flow backtrace helper\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Walk data-dependency edges BACKWARD from a starting commit. Returns\n * the lineage chain — every ancestor commit whose writes transitively\n * contributed to the starting commit's reads.\n *\n * BFS order, commitIdx-ascending (oldest first). Includes the starting\n * commit at the END of the returned array.\n *\n * Cycle defense: visited set + recursion cap at `index.commits.length`\n * (per L8 panel must-fix — defends against future malformed graphs).\n *\n * @example\n * ```ts\n * const lineage = backtraceDataFlow(commitIndex, asRuntimeStageId('finalize-order#3'));\n * // → [load-order#0, check-inventory#1, run-fraud-check#2, finalize-order#3]\n * // (the commits whose updates fed FinalizeOrder's reads)\n * ```\n */\nexport function backtraceDataFlow(\n index: CommitFlowIndex,\n startRuntimeStageId: RuntimeStageId,\n): CommitView[] {\n const start = index.byRuntimeStageId.get(startRuntimeStageId);\n if (!start) return [];\n // L8.2 Panel 1 must-fix: dropped the `hops < cap` counter. The\n // visited-set IS the real cycle defense — it guarantees each\n // commitIdx is dequeued AT MOST ONCE, so the loop body executes\n // ≤ `index.commits.length` times by construction. The old `hops`\n // counter could short-circuit BEFORE the visited-set saturated in\n // dense-data graphs (every commit reads from every prior), dropping\n // legitimate work. Visited-set + head-index queue is sufficient and\n // correct.\n const visitedIdx = new Set<number>([start.commitIdx]);\n const queue: number[] = [start.commitIdx];\n const collectedIdxs = new Set<number>([start.commitIdx]);\n let head = 0;\n while (head < queue.length) {\n const cur = index.commits[queue[head++]!];\n if (!cur) continue;\n for (const dep of cur.dataDependencies) {\n if (dep.sourceCommitIdx === null) continue;\n if (visitedIdx.has(dep.sourceCommitIdx)) continue;\n visitedIdx.add(dep.sourceCommitIdx);\n collectedIdxs.add(dep.sourceCommitIdx);\n queue.push(dep.sourceCommitIdx);\n }\n }\n // Return commits ordered by commitIdx ascending (chronological).\n return Array.from(collectedIdxs)\n .sort((a, b) => a - b)\n .map((idx) => index.commits[idx]!)\n .filter((c): c is CommitView => c !== undefined);\n}\n","/**\n * `createTraceBundle` — one factory wires every shipped translator\n * + provides a single `attachTo(executor)` call that registers all\n * runtime recorders.\n *\n * Bundle shape (as of L8.2)\n * ─────────────────────────\n * - `structure` — build-time `TraceGraph` (StructureRecorder).\n * - `runtimeOverlay` — execution overlay for time-travel (FlowRecorder).\n * - `nodeView` — per-stage summary index, CombinedRecorder\n * (FlowRecorder + ScopeRecorder).\n * - `commitFlow` — per-commit summary + data-lineage,\n * CombinedRecorder (ScopeRecorder + FlowRecorder).\n *\n * Goal: collapse the 5-line \"create + attach + subscribe\" boilerplate\n * into one call for the common case. Consumers that want à-la-carte\n * setup can still construct each translator directly (the underlying\n * factories are unchanged).\n *\n * Independence: each translator subscribes ONLY to `structure` (per\n * L8.1 Panel 1 rule — translators must never subscribe to peers).\n * Linear dependency tree keeps notify cascades O(depth), not O(N²).\n *\n * @example\n * ```tsx\n * import { createTraceBundle } from 'footprint-explainable-ui/flowchart';\n *\n * function MyTraceUI() {\n * const bundle = useMemo(() => createTraceBundle(), []);\n * useEffect(() => {\n * const chart = flowChart('seed', fn, 'seed', {\n * structureRecorders: [bundle.structure.recorder],\n * }).addFunction('a', fnA, 'a').build();\n * const executor = new FlowChartExecutor(chart);\n * bundle.attachTo(executor);\n * executor.run({ input });\n * }, [bundle]);\n *\n * return <TracedFlow recorder={bundle.structure} overlay={bundle.runtimeOverlay} />;\n * }\n * ```\n *\n * **Recorder-attach lifecycle**: `attachTo(executor)` attaches THREE\n * FlowRecorders (`runtimeOverlay`, `nodeView`, `commitFlow`) and TWO\n * ScopeRecorders (`nodeView`, `commitFlow`). Each translator has a\n * distinct `recorder.id`, so footprintjs's id-idempotency rule\n * doesn't collide. The build-time `structure.recorder` is NOT\n * auto-attached — it must be passed to `flowChart(..., {\n * structureRecorders: [...] })` because builder recorders register\n * BEFORE `executor` exists. Consumers wire that one explicitly (see\n * example above). This matches footprintjs's two-phase recorder\n * model (build vs runtime).\n */\n\nimport { devWarn } from \"./_internal/devWarn\";\nimport {\n createTraceStructureRecorder,\n type TraceStructureRecorderHandle,\n type CreateTraceStructureRecorderOptions,\n} from \"./traceStructureRecorder\";\nimport {\n createTraceRuntimeOverlay,\n type TraceRuntimeOverlayHandle,\n type CreateTraceRuntimeOverlayOptions,\n} from \"./createTraceRuntimeOverlay\";\nimport {\n createNodeViewRecorder,\n type NodeViewRecorderHandle,\n type CreateNodeViewRecorderOptions,\n} from \"./createNodeViewRecorder\";\nimport {\n createCommitFlowRecorder,\n type CommitFlowRecorderHandle,\n type CreateCommitFlowRecorderOptions,\n} from \"./createCommitFlowRecorder\";\n\n/** Minimal executor surface — mirrors the bits of footprintjs's\n * `FlowChartExecutor` the bundle calls into. Local to keep\n * explainable-ui dep-free from footprintjs. */\ninterface MinimalExecutor {\n attachFlowRecorder(recorder: unknown): void;\n attachScopeRecorder?(recorder: unknown): void;\n}\n\nexport interface TraceBundle {\n structure: TraceStructureRecorderHandle;\n runtimeOverlay: TraceRuntimeOverlayHandle;\n /** L8.1 — per-stage summary translator. Reads `prevIds`/`nextIds`\n * from `structure` (no duplication), accumulates `executions[]`\n * + commit refs from Flow + Scope events. */\n nodeView: NodeViewRecorderHandle;\n /** L8.2 — per-commit summary translator. Owns canonical CommitView[].\n * Derives structural prev/next from `structure`, runtimePrev/Next\n * from \"most-recent-per-prev\" over commitLog, and dataDependencies\n * via findLastWriter per read key. */\n commitFlow: CommitFlowRecorderHandle;\n /**\n * Attach RUNTIME recorders (FlowRecorder, ScopeRecorder) to a\n * footprintjs executor. The build-time `structure.recorder` is NOT\n * covered — pass it to `flowChart(..., { structureRecorders: [...] })`\n * at construction time instead (see file header example).\n */\n attachTo(executor: MinimalExecutor): void;\n}\n\nexport interface CreateTraceBundleOptions {\n /** Per-translator options. All optional. */\n structure?: CreateTraceStructureRecorderOptions;\n runtimeOverlay?: CreateTraceRuntimeOverlayOptions;\n nodeView?: Omit<CreateNodeViewRecorderOptions, \"structure\">;\n commitFlow?: Omit<CreateCommitFlowRecorderOptions, \"structure\">;\n}\n\nexport function createTraceBundle(\n options: CreateTraceBundleOptions = {},\n): TraceBundle {\n const structure = createTraceStructureRecorder(options.structure);\n const runtimeOverlay = createTraceRuntimeOverlay(options.runtimeOverlay);\n // NodeView needs the structure handle — wired internally so the\n // consumer doesn't have to pass it. The bundle is the consumer-\n // ergonomics layer; à-la-carte consumers can construct\n // createNodeViewRecorder directly with their own structure handle.\n const nodeView = createNodeViewRecorder({\n ...(options.nodeView ?? {}),\n structure,\n });\n const commitFlow = createCommitFlowRecorder({\n ...(options.commitFlow ?? {}),\n structure,\n });\n\n return {\n structure,\n runtimeOverlay,\n nodeView,\n commitFlow,\n attachTo(executor: MinimalExecutor): void {\n // All three runtime translators attach as FlowRecorders (each\n // has its own distinct `recorder.id`, so the dispatcher's\n // id-idempotency rule doesn't collide). NodeView + CommitFlow\n // ALSO implement ScopeRecorder (onCommit) — attached via\n // attachScopeRecorder when the executor exposes it.\n //\n // Footprintjs v6.0+ exposes both methods; older executors\n // gracefully degrade (commit-side data drops with a dev-warn).\n executor.attachFlowRecorder(runtimeOverlay.recorder);\n executor.attachFlowRecorder(nodeView.recorder);\n executor.attachFlowRecorder(commitFlow.recorder);\n if (typeof executor.attachScopeRecorder === \"function\") {\n executor.attachScopeRecorder(nodeView.recorder);\n executor.attachScopeRecorder(commitFlow.recorder);\n } else {\n // Old/partial executor without ScopeRecorder support. NodeView\n // + CommitFlow will silently miss commit events — surface this\n // to consumers debugging \"why are commitRuntimeStageIds empty?\".\n devWarn(\n () =>\n \"[createTraceBundle] executor.attachScopeRecorder is missing — NodeView.commitRuntimeStageIds[] AND CommitFlow.commits[] will be empty. Upgrade to footprintjs v6.0+.\",\n );\n }\n },\n };\n}\n","/**\n * `useTranslator(handle, getSnapshot)` — React adapter for any translator\n * exposing the standard `subscribe()` + `version()` shape.\n *\n * Wraps `useSyncExternalStore` so consumers don't repeat the boilerplate\n * for every translator. The `version` is the snapshot identity — when it\n * changes, React re-renders; `getSnapshot` then returns the consumer-\n * chosen view (full graph, slice, etc.).\n *\n * @example\n * ```tsx\n * const trace = useMemo(() => createTraceStructureRecorder(), []);\n * const graph = useTranslator(trace, () => trace.getGraph());\n * return <TraceFlow graph={graph} />;\n * ```\n *\n * **Why a hook (vs each component wiring `useSyncExternalStore` itself)**:\n * three reasons. (1) Reduces 4 lines of `useSyncExternalStore + useMemo`\n * boilerplate to one line. (2) Standardises the snapshot-identity\n * convention (version int) — consumers can't accidentally pass a getter\n * whose return identity changes every call (which would re-render\n * forever). (3) Stable subscribe/getVersion refs via memoization on the\n * handle identity — no re-subscribe on parent re-renders.\n */\n\nimport { useMemo, useSyncExternalStore } from \"react\";\n\nexport interface TranslatorHandleLike {\n subscribe(listener: () => void): () => void;\n version(): number;\n}\n\n/**\n * Subscribe to a translator + return a typed snapshot computed by the\n * caller. The snapshot recomputes whenever `version()` changes.\n *\n * `getSnapshot` is called inside a `useMemo` keyed on the version\n * integer — so consumers can return fresh objects from `getSnapshot`\n * (e.g., `handle.getGraph()` returns a defensive copy) without\n * triggering infinite re-renders.\n */\nexport function useTranslator<T>(\n handle: TranslatorHandleLike,\n getSnapshot: () => T,\n): T {\n const subscribe = useMemo(() => handle.subscribe.bind(handle), [handle]);\n const getVersion = useMemo(() => handle.version.bind(handle), [handle]);\n const version = useSyncExternalStore(subscribe, getVersion, getVersion);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n return useMemo(() => getSnapshot(), [version, getSnapshot]);\n}\n","/**\n * Graph traversal helpers — pure functions over a `NodeViewIndex`.\n *\n * Bi-directional structural walks (`walkForward` / `walkBackward`) plus\n * convenience wrappers (`backtraceStructural` / `forwardtraceStructural`).\n *\n * Cycle defense (panel L8 must-fix)\n * ──────────────────────────────────\n * Every traversal carries a `visited: Set<StageId>` and caps recursion\n * at `index.all.length` (the total node count). Defends against:\n * - Future bugs where a malformed graph includes a non-loop cycle\n * - Manual edge injection bypassing the structure-recorder fix\n * - Duplicate edges that survive dedupe due to source/target\n * collisions\n * Loop back-edges (`data.kind === 'loop'`) already excluded at the\n * structure-recorder layer (invariant I1), so they never enter\n * `prevIds`/`nextIds` — no extra filtering here.\n *\n * BFS order\n * ─────────\n * Walks return nodes in BFS order — root first, then immediate\n * neighbors, then their neighbors. Matches breadcrumb-friendly\n * \"closest-first\" display order.\n *\n * Always-arrays returns\n * ─────────────────────\n * All helpers return `NodeView[]`. Empty array (NOT null/undefined)\n * means \"no path\" or \"node not found\". Consumers `.map()` /\n * `.length`-check without null-handling boilerplate.\n */\n\nimport type { NodeView, NodeViewIndex } from \"./createNodeViewRecorder\";\nimport type { StageId } from \"./_internal/keys\";\n\nexport interface WalkOptions {\n /** Hard cap on hops. Default: `index.all.length` (one full traversal). */\n maxDepth?: number;\n /** When true, only return nodes that have `visitedInRun === true`.\n * Useful for \"in THIS run, what fed me?\" queries (runtime-aware walk). */\n onlyVisited?: boolean;\n /** When true, INCLUDE the start node in the returned array. Default:\n * false (caller already has the start node; the walk returns its\n * ancestors/descendants). */\n includeStart?: boolean;\n}\n\n/**\n * Walk forward (`nextIds`) from `startId`. BFS order. Cycle-safe.\n * Returns `[]` if `startId` is unknown.\n *\n * Convergence semantics: a node reachable via multiple paths appears\n * ONCE in the result (visited-set dedupes).\n */\nexport function walkForward(\n index: NodeViewIndex,\n startId: StageId,\n options: WalkOptions = {},\n): NodeView[] {\n return bfsWalk(index, startId, (n) => n.nextIds, options);\n}\n\n/**\n * Walk backward (`prevIds`) from `startId`. BFS order. Cycle-safe.\n * Returns `[]` if `startId` is unknown.\n *\n * Convergence semantics: a fork-join's `walkBackward` returns BOTH\n * branch parents (and their ancestors), each once.\n */\nexport function walkBackward(\n index: NodeViewIndex,\n startId: StageId,\n options: WalkOptions = {},\n): NodeView[] {\n return bfsWalk(index, startId, (n) => n.prevIds, options);\n}\n\n/**\n * Backtrace from `stageId` to a structural root (no prev) OR a split\n * point (multiple prevs). Returns the chain from `stageId` BACK to\n * the root, root-first. Includes `stageId` at the END.\n *\n * Defines \"split\" as `prevIds.length > 1 OR prevIds.length === 0`\n * (per L8 panel recommendation) — stops at convergence points AND at\n * the seed. Useful for breadcrumb display where \"innermost serial\n * run\" is the meaningful path.\n */\nexport function backtraceStructural(\n index: NodeViewIndex,\n stageId: StageId,\n options: Pick<WalkOptions, \"maxDepth\" | \"onlyVisited\"> = {},\n): NodeView[] {\n const start = index.byStageId.get(stageId);\n if (!start) return [];\n const chain: NodeView[] = [start];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>([stageId]);\n let cur: NodeView | undefined = start;\n let hops = 0;\n while (cur && hops < cap) {\n if (cur.prevIds.length === 0 || cur.prevIds.length > 1) {\n // Reached seed (no prevs) or split (multi-prev convergence).\n break;\n }\n const nextId = cur.prevIds[0]!;\n if (visited.has(nextId)) break; // cycle guard\n visited.add(nextId);\n const next: NodeView | undefined = index.byStageId.get(nextId);\n if (!next) break;\n if (options.onlyVisited && !next.visitedInRun) break;\n chain.unshift(next);\n cur = next;\n hops++;\n }\n return chain;\n}\n\n/**\n * Forward-trace from `stageId` to a structural leaf (no next) OR a\n * fork point (multiple nexts). Returns the chain from `stageId`\n * FORWARD to the leaf/fork, with `stageId` at the START.\n */\nexport function forwardtraceStructural(\n index: NodeViewIndex,\n stageId: StageId,\n options: Pick<WalkOptions, \"maxDepth\" | \"onlyVisited\"> = {},\n): NodeView[] {\n const start = index.byStageId.get(stageId);\n if (!start) return [];\n const chain: NodeView[] = [start];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>([stageId]);\n let cur: NodeView | undefined = start;\n let hops = 0;\n while (cur && hops < cap) {\n if (cur.nextIds.length === 0 || cur.nextIds.length > 1) break;\n const nextId = cur.nextIds[0]!;\n if (visited.has(nextId)) break;\n visited.add(nextId);\n const next: NodeView | undefined = index.byStageId.get(nextId);\n if (!next) break;\n if (options.onlyVisited && !next.visitedInRun) break;\n chain.push(next);\n cur = next;\n hops++;\n }\n return chain;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction bfsWalk(\n index: NodeViewIndex,\n startId: StageId,\n neighborsOf: (n: NodeView) => StageId[],\n options: WalkOptions,\n): NodeView[] {\n const start = index.byStageId.get(startId);\n if (!start) return [];\n const cap = options.maxDepth ?? index.all.length;\n const visited = new Set<StageId>();\n visited.add(startId);\n const out: NodeView[] = [];\n if (options.includeStart) out.push(start);\n // Queue holds [node, depthFromStart]. depthFromStart = 0 for the\n // start node; neighbors are depth 1; etc. We bail when depth > cap.\n //\n // L8.1 Panel 5 optimization: use a head-index pointer instead of\n // `queue.shift()`. shift() is O(n) (re-indexes the array on every\n // pop) → BFS over 50+ nodes degrades to O(n²). The head-index\n // pattern is O(1) per pop, O(n) total — standard interview answer.\n const queue: Array<[NodeView, number]> = [[start, 0]];\n let head = 0;\n while (head < queue.length) {\n const [node, depth] = queue[head++]!;\n if (depth >= cap) continue;\n for (const neighborId of neighborsOf(node)) {\n if (visited.has(neighborId)) continue;\n visited.add(neighborId);\n const neighbor = index.byStageId.get(neighborId);\n if (!neighbor) continue;\n if (options.onlyVisited && !neighbor.visitedInRun) continue;\n out.push(neighbor);\n queue.push([neighbor, depth + 1]);\n }\n }\n return out;\n}\n","/**\n * NodeInspector — debug/teaching panel for a single stage's\n * per-node summary from a `NodeViewIndex`.\n *\n * Demonstrates the canonical L8.1 consumer pattern:\n * 1. Read the `NodeView` for `selectedId` from the index\n * 2. Use `backtraceStructural` / `forwardtraceStructural` for the\n * prev/next chains\n * 3. Render: identity, structural neighbors (clickable to navigate),\n * visit data (count + duration + error state), commit refs.\n *\n * Composable: this is a small demo renderer. Real consumers wire\n * their own layout — the data shape is the contract.\n */\n\nimport { useMemo } from \"react\";\nimport type { NodeViewIndex, NodeView } from \"./createNodeViewRecorder\";\nimport type { StageId } from \"./_internal/keys\";\nimport { backtraceStructural, forwardtraceStructural } from \"./walkHelpers\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface NodeInspectorProps extends BaseComponentProps {\n /** The NodeView index (from `nodeView.getIndex()` or `useTranslator`).\n *\n * **Pure data prop** (NOT the recorder handle) — by design. Lets\n * consumers wrap in `useTranslator(nodeView, () => nodeView.getIndex())`\n * at the parent, or pass a static index from tests / Storybook /\n * SSR. Mirrors `<CommitInspector index={...}>` for consistency. */\n index: NodeViewIndex;\n /** Which stage to inspect. When `null`, renders the placeholder. */\n selectedId: StageId | null;\n /** Click handler — receives a stageId for breadcrumb navigation. */\n onNavigate?: (stageId: StageId) => void;\n /** When true, the prev/next chains include only `visitedInRun` nodes\n * (runtime-filtered view). */\n onlyVisited?: boolean;\n}\n\nexport function NodeInspector({\n index,\n selectedId,\n onNavigate,\n onlyVisited = false,\n className,\n style,\n}: NodeInspectorProps) {\n const view = selectedId ? index.byStageId.get(selectedId) ?? null : null;\n\n // Backtrace (root-first chain ending at this stage) — recomputes\n // when index version OR selectedId OR onlyVisited changes.\n const prevChain = useMemo(\n () => (view ? backtraceStructural(index, view.stageId, { onlyVisited }) : []),\n [index, view, onlyVisited],\n );\n // Forward-trace (this stage → leaf or fork).\n const nextChain = useMemo(\n () => (view ? forwardtraceStructural(index, view.stageId, { onlyVisited }) : []),\n [index, view, onlyVisited],\n );\n\n if (!view) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n Select a stage to inspect.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 14,\n color: theme.textPrimary,\n fontSize: 13,\n overflow: \"auto\",\n ...style,\n }}\n >\n {/* ── Identity ──────────────────────────────────────────── */}\n <div style={{ marginBottom: 16 }}>\n <div style={{ fontSize: 16, fontWeight: 700, color: theme.textPrimary }}>\n {view.label}\n </div>\n <div style={{ fontSize: 11, fontFamily: \"monospace\", color: theme.textMuted, marginTop: 2 }}>\n {view.stageId} · {view.type}\n {view.isDecider && \" · decider\"}\n {view.isFork && \" · fork\"}\n {view.isSubflow && \" · subflow\"}\n {view.isStreaming && \" · streaming\"}\n {view.isPausable && \" · pausable\"}\n </div>\n {view.description && (\n <div style={{ fontSize: 12, color: theme.textSecondary, marginTop: 6 }}>\n {view.description}\n </div>\n )}\n </div>\n\n {/* ── Visit data ────────────────────────────────────────── */}\n <Section title=\"Runtime\">\n <Row label=\"Visited\" value={view.visitedInRun ? \"yes\" : \"no\"} />\n {view.visitedInRun && (\n <>\n <Row label=\"Executions\" value={String(view.executionCount)} />\n {view.firstExecutedAt !== null && (\n <Row label=\"First at\" value={`${view.firstExecutedAt.toFixed(1)}ms`} />\n )}\n {view.lastExecutedAt !== null && (\n <Row label=\"Last at\" value={`${view.lastExecutedAt.toFixed(1)}ms`} />\n )}\n {view.totalDurationMs > 0 && (\n <Row label=\"Total\" value={`${view.totalDurationMs.toFixed(1)}ms`} />\n )}\n {view.errorCount > 0 && (\n <Row label=\"Errors\" value={String(view.errorCount)} valueColor={theme.error} />\n )}\n </>\n )}\n </Section>\n\n {/* ── Structural prev chain (clickable breadcrumb) ──────── */}\n {prevChain.length > 1 && (\n <Section title={`Prev chain (${prevChain.length - 1} hops)`}>\n <Crumbs nodes={prevChain.slice(0, -1)} onClick={onNavigate} />\n </Section>\n )}\n {view.prevIds.length > 1 && (\n <Section title=\"Multiple prev (convergence)\">\n <Crumbs\n nodes={view.prevIds\n .map((id) => index.byStageId.get(id))\n .filter((n): n is NodeView => n !== undefined)}\n onClick={onNavigate}\n />\n </Section>\n )}\n\n {/* ── Structural next chain ─────────────────────────────── */}\n {nextChain.length > 1 && (\n <Section title={`Next chain (${nextChain.length - 1} hops)`}>\n <Crumbs nodes={nextChain.slice(1)} onClick={onNavigate} />\n </Section>\n )}\n {view.nextIds.length > 1 && (\n <Section title=\"Multiple next (fork/decider)\">\n <Crumbs\n nodes={view.nextIds\n .map((id) => index.byStageId.get(id))\n .filter((n): n is NodeView => n !== undefined)}\n onClick={onNavigate}\n />\n </Section>\n )}\n\n {/* ── Commit refs (join key into CommitFlowIndex from L8.2) ── */}\n {view.commitRuntimeStageIds.length > 0 && (\n <Section title={`Commits (${view.commitRuntimeStageIds.length})`}>\n <div style={{ fontFamily: \"monospace\", fontSize: 11, color: theme.textSecondary }}>\n {view.commitRuntimeStageIds.map((rsid) => (\n <div key={rsid}>{rsid}</div>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n\n// ── Sub-components ─────────────────────────────────────────────────\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div style={{ marginBottom: 14 }}>\n <div\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n marginBottom: 6,\n }}\n >\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nfunction Row({ label, value, valueColor }: { label: string; value: string; valueColor?: string }) {\n return (\n <div style={{ display: \"flex\", justifyContent: \"space-between\", fontSize: 12, padding: \"2px 0\" }}>\n <span style={{ color: theme.textMuted }}>{label}</span>\n <span style={{ color: valueColor ?? theme.textSecondary, fontFamily: \"monospace\" }}>{value}</span>\n </div>\n );\n}\n\nfunction Crumbs({ nodes, onClick }: { nodes: NodeView[]; onClick?: (id: StageId) => void }) {\n if (nodes.length === 0) return null;\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {nodes.map((n, i) => (\n <span key={n.stageId} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n <button\n onClick={onClick ? () => onClick(n.stageId) : undefined}\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"3px 8px\",\n borderRadius: 4,\n border: `1px solid ${theme.border}`,\n background: \"transparent\",\n color: n.visitedInRun ? theme.success : theme.textSecondary,\n cursor: onClick ? \"pointer\" : \"default\",\n }}\n >\n {n.label}\n </button>\n {i < nodes.length - 1 && <span style={{ color: theme.textMuted, fontSize: 10 }}>›</span>}\n </span>\n ))}\n </div>\n );\n}\n","/**\n * CommitInspector — demo renderer for a single CommitView from a\n * `CommitFlowIndex`. Mirrors `<NodeInspector>` but commit-centric:\n *\n * - Identity: runtimeStageId + stageId + commitIdx\n * - Structural: prev/next stage ids (the chart-shape neighbors)\n * - Runtime: runtimePrev/Next commit refs (the actual prev/next\n * executions in this run — useful for time-travel breadcrumbs)\n * - Data lineage: `dataDependencies[]` per read key + a one-click\n * `backtraceDataFlow` walk showing the full ancestry chain\n * - Payload: updates + reads\n */\n\nimport { useMemo } from \"react\";\nimport type {\n CommitFlowIndex,\n CommitView,\n} from \"./createCommitFlowRecorder\";\nimport { backtraceDataFlow } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface CommitInspectorProps extends BaseComponentProps {\n /** The CommitFlow index (from `commitFlow.getIndex()` or `useTranslator`).\n *\n * **Pure data prop** (NOT the recorder handle) — by design. Lets\n * consumers wrap in `useTranslator(commitFlow, () => commitFlow.getIndex())`\n * at the parent, or pass a static index from tests / Storybook /\n * SSR. Mirrors `<NodeInspector index={...}>` for consistency. */\n index: CommitFlowIndex;\n /** Which commit to inspect (by runtimeStageId). null → placeholder. */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Click handler — receives a runtimeStageId for time-travel\n * navigation. Used by all clickable references (runtime prev/next,\n * data-dep sources, lineage chain). */\n onNavigate?: (runtimeStageId: RuntimeStageId) => void;\n}\n\nexport function CommitInspector({\n index,\n selectedRuntimeStageId,\n onNavigate,\n className,\n style,\n}: CommitInspectorProps) {\n const view = selectedRuntimeStageId\n ? index.byRuntimeStageId.get(selectedRuntimeStageId) ?? null\n : null;\n\n // Backtrace ancestry chain — recomputes when index version OR\n // selectedRuntimeStageId changes.\n const lineage = useMemo(\n () =>\n view ? backtraceDataFlow(index, view.runtimeStageId) : [],\n [index, view],\n );\n\n if (!view) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n Select a commit to inspect.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 14,\n color: theme.textPrimary,\n fontSize: 13,\n overflow: \"auto\",\n ...style,\n }}\n >\n {/* ── Identity ──────────────────────────────────────────── */}\n <div style={{ marginBottom: 16 }}>\n <div style={{ fontSize: 16, fontWeight: 700, color: theme.textPrimary }}>\n {view.stageId}\n </div>\n <div\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n color: theme.textMuted,\n marginTop: 2,\n }}\n >\n {view.runtimeStageId} · commitIdx {view.commitIdx}\n </div>\n </div>\n\n {/* ── Structural neighbors ──────────────────────────────── */}\n {view.structuralPrevIds.length > 0 && (\n <Section title=\"Structural prev (chart shape)\">\n <PlainTags labels={view.structuralPrevIds} />\n </Section>\n )}\n {view.structuralNextIds.length > 0 && (\n <Section title=\"Structural next (chart shape)\">\n <PlainTags labels={view.structuralNextIds} />\n </Section>\n )}\n\n {/* ── Runtime neighbors (clickable for time-travel) ─────── */}\n {view.runtimePrevIds.length > 0 && (\n <Section title=\"Runtime prev (this execution)\">\n <RuntimeRefs refs={view.runtimePrevIds} onClick={onNavigate} />\n </Section>\n )}\n {view.runtimeNextIds.length > 0 && (\n <Section title=\"Runtime next (this execution)\">\n <RuntimeRefs refs={view.runtimeNextIds} onClick={onNavigate} />\n </Section>\n )}\n\n {/* ── Payload ───────────────────────────────────────────── */}\n {Object.keys(view.updates).length > 0 && (\n <Section title={`Updates (${Object.keys(view.updates).length})`}>\n <KeyValueGrid entries={Object.entries(view.updates)} />\n </Section>\n )}\n {view.reads.length > 0 && (\n <Section title={`Reads (${view.reads.length})`}>\n <PlainTags labels={view.reads} />\n </Section>\n )}\n\n {/* ── Data dependencies (per-key lineage) ───────────────── */}\n {view.dataDependencies.length > 0 && (\n <Section title={`Data dependencies (${view.dataDependencies.length})`}>\n <table style={{ fontSize: 11, fontFamily: \"monospace\", width: \"100%\", borderCollapse: \"collapse\" }}>\n <tbody>\n {view.dataDependencies.map((dep) => (\n <tr key={dep.key}>\n <td style={{ color: theme.textSecondary, padding: \"2px 8px 2px 0\" }}>\n {dep.key}\n </td>\n <td style={{ color: dep.sourceRuntimeStageId ? theme.textPrimary : theme.textMuted }}>\n {dep.sourceRuntimeStageId ? (\n <button\n onClick={onNavigate ? () => onNavigate(dep.sourceRuntimeStageId!) : undefined}\n style={crumbButtonStyle(onNavigate !== undefined)}\n >\n ← {dep.sourceRuntimeStageId}\n </button>\n ) : (\n <em>(no prior writer — default or external)</em>\n )}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </Section>\n )}\n\n {/* ── Lineage chain (full data-flow backtrace) ──────────── */}\n {lineage.length > 1 && (\n <Section title={`Lineage chain (${lineage.length - 1} ancestor commits)`}>\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {lineage.slice(0, -1).map((c, i) => (\n <span key={c.runtimeStageId} style={{ display: \"inline-flex\", alignItems: \"center\", gap: 4 }}>\n <button\n onClick={onNavigate ? () => onNavigate(c.runtimeStageId) : undefined}\n style={crumbButtonStyle(onNavigate !== undefined)}\n >\n {c.runtimeStageId}\n </button>\n {i < lineage.length - 2 && (\n <span style={{ color: theme.textMuted, fontSize: 10 }}>→</span>\n )}\n </span>\n ))}\n </div>\n </Section>\n )}\n </div>\n );\n}\n\n// ── Sub-components ─────────────────────────────────────────────────\n\nfunction Section({ title, children }: { title: string; children: React.ReactNode }) {\n return (\n <div style={{ marginBottom: 14 }}>\n <div\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n marginBottom: 6,\n }}\n >\n {title}\n </div>\n {children}\n </div>\n );\n}\n\nfunction PlainTags({ labels }: { labels: readonly string[] }) {\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 4 }}>\n {labels.map((l) => (\n <span\n key={l}\n style={{\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"2px 6px\",\n borderRadius: 3,\n background: \"var(--fp-bg-secondary, transparent)\",\n color: theme.textSecondary,\n }}\n >\n {l}\n </span>\n ))}\n </div>\n );\n}\n\nfunction RuntimeRefs({\n refs,\n onClick,\n}: {\n refs: readonly RuntimeStageId[];\n onClick?: (rsid: RuntimeStageId) => void;\n}) {\n return (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: 6 }}>\n {refs.map((r) => (\n <button\n key={r}\n onClick={onClick ? () => onClick(r) : undefined}\n style={crumbButtonStyle(onClick !== undefined)}\n >\n {r}\n </button>\n ))}\n </div>\n );\n}\n\nfunction KeyValueGrid({ entries }: { entries: ReadonlyArray<[string, unknown]> }) {\n return (\n <table style={{ fontSize: 11, fontFamily: \"monospace\", width: \"100%\", borderCollapse: \"collapse\" }}>\n <tbody>\n {entries.map(([k, v]) => (\n <tr key={k}>\n <td style={{ color: theme.textSecondary, padding: \"2px 8px 2px 0\", verticalAlign: \"top\" }}>\n {k}\n </td>\n <td style={{ color: theme.textPrimary, wordBreak: \"break-word\" }}>\n {typeof v === \"object\" ? JSON.stringify(v) : String(v)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n}\n\nfunction crumbButtonStyle(clickable: boolean): React.CSSProperties {\n return {\n fontSize: 11,\n fontFamily: \"monospace\",\n padding: \"3px 8px\",\n borderRadius: 4,\n border: `1px solid ${theme.border}`,\n background: \"transparent\",\n color: theme.textSecondary,\n cursor: clickable ? \"pointer\" : \"default\",\n };\n}\n","/**\n * Series-parallel chain tree builders — pure functions over `TraceGraph`\n * (structural) + `CommitFlowIndex` (runtime).\n *\n * When to reach for this vs. flat commitLog\n * ─────────────────────────────────────────\n * Use `commitLog` when you want chronological replay / slider scrubbing\n * (\"what happened in order\"). Use the chain tree when you want to\n * render parallel structure visually or answer \"which branch ran?\"\n * questions — flat `commitLog[idx-1]` loses the fork shape.\n *\n * Pairs with `<CommitInspector>` for git-log-style master/detail —\n * `<CommitChainView>` picks, `<CommitInspector>` inspects.\n * Complements the per-stage view from `createNodeViewRecorder`.\n *\n * Why a chain tree\n * ────────────────\n * Footprintjs charts are **series-parallel DAGs by construction** —\n * the builder primitives compose serially (`addFunction`) or in\n * parallel (`addListOfFunction` / `addDeciderFunction`). Series-\n * parallel DAGs are provably representable as expression trees,\n * so we can decompose any footprintjs chart into a nested\n * `(serial | parallel | leaf)` shape that renders cleanly as\n * swim lanes.\n *\n * Two builders, one tree shape\n * ────────────────────────────\n * - `structureAsChainTree(graph, options?)` — STRUCTURAL view.\n * No commitLog. Decomposes the chart shape into S-P primitives.\n * Renders the full chart (all branches of a decider, etc.) even\n * before running.\n *\n * - `buildCommitChainTree(graph, commitFlow, options?)` — RUNTIME\n * view. Each leaf carries the commits[] that fired for that stage\n * in this run. Loops produce a leaf with N commits. Branches that\n * never executed in this run appear as empty `commits[]` leaves\n * (consumer can filter).\n *\n * Algorithm scope (correctness contract)\n * ──────────────────────────────────────\n * These builders are tuned for **series-parallel charts** — every\n * fork in footprintjs's builder has a matching merge point. For\n * non-S-P or malformed graphs the tree is still finite and stable\n * (cycle defense guarantees termination), but the shape may not\n * reflect a clean S-P decomposition.\n *\n * - Forks with **no common descendant** drop the outer-walk tail at\n * the fork node. Real footprintjs charts always re-merge.\n * - Edges with `data.kind === undefined` are treated as `'next'`.\n * Multiple linear-next edges from a single source follow only the\n * first (deterministic by insertion order); a dev-mode warning\n * fires when this is observed (`isDevMode()` from footprintjs).\n *\n * Cycle defense (L8 panel must-fix carried forward)\n * ─────────────────────────────────────────────────\n * Every recursive walk carries a `visited: Set<StageId>` to defend\n * against malformed graphs (manual edge injection, future builder\n * bugs). Loop edges (`kind === 'loop'`) are excluded at the\n * structure-recorder layer per invariant I1, so they never enter\n * prev/next — no extra filtering needed here. Convergence detection\n * uses BFS bounded by `graph.nodes.length`.\n *\n * @example\n * ```ts\n * const trace = createTraceStructureRecorder();\n * // ... build a fork chart ...\n *\n * const sChain = structureAsChainTree(trace.getGraph());\n * // → { kind: 'serial', items: [\n * // { kind: 'leaf', stageId: 'LoadOrder' },\n * // { kind: 'parallel', branches: [\n * // { kind: 'leaf', stageId: 'CheckInventory' },\n * // { kind: 'leaf', stageId: 'RunFraudCheck' },\n * // ]},\n * // { kind: 'leaf', stageId: 'FinalizeOrder' },\n * // ]}\n *\n * const commitFlow = createCommitFlowRecorder({ structure: trace });\n * // ... run chart ...\n * const cChain = buildCommitChainTree(trace.getGraph(), commitFlow.getIndex());\n * // → same shape, but each leaf carries `commits: CommitView[]`\n * ```\n */\n\nimport type { TraceGraph } from \"./traceStructureRecorder\";\nimport type { CommitFlowIndex, CommitView } from \"./createCommitFlowRecorder\";\nimport type { StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { devWarn } from \"./_internal/devWarn\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Output types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Structural chain tree leaf (no commits). */\nexport interface StructureChainLeaf {\n readonly kind: \"leaf\";\n readonly stageId: StageId;\n}\n\n/** Structural chain tree node — recursive S-P composition over stage ids. */\nexport type StructureChain =\n | StructureChainLeaf\n | { readonly kind: \"serial\"; readonly items: readonly StructureChain[] }\n | { readonly kind: \"parallel\"; readonly branches: readonly StructureChain[] };\n\n/** Commit chain tree leaf — carries all commits for the stage (loop-aware). */\nexport interface CommitChainLeaf {\n readonly kind: \"leaf\";\n readonly stageId: StageId;\n /** All commits that fired for this stage in this run, in commitIdx\n * ascending order. Loop iteration N has commits[N]. Empty array\n * when the stage never executed in this run.\n *\n * **Ownership**: references are shared with\n * `CommitFlowIndex.commits` (no deep copy). The same shallow-copy /\n * nested-shared-value contract documented on `CommitView.updates`\n * applies. Do not mutate. */\n readonly commits: readonly CommitView[];\n}\n\n/** Commit chain tree — recursive S-P composition with commit leaves. */\nexport type CommitChain =\n | CommitChainLeaf\n | { readonly kind: \"serial\"; readonly items: readonly CommitChain[] }\n | { readonly kind: \"parallel\"; readonly branches: readonly CommitChain[] };\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Internal helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Per-stage indexes computed once per build call. */\ninterface GraphIndex {\n byStageId: Map<StageId, { branchChildren: StageId[]; linearNext: StageId[] }>;\n allNodeIds: StageId[];\n}\n\nfunction indexGraph(graph: TraceGraph): GraphIndex {\n const byStageId = new Map<\n StageId,\n { branchChildren: StageId[]; linearNext: StageId[] }\n >();\n const allNodeIds: StageId[] = [];\n\n for (const node of graph.nodes) {\n const stageId = asStageId(node.id);\n allNodeIds.push(stageId);\n // node.data already carries prevIds/nextIds (L8.0 enrichment), but\n // we split outgoing into branch vs linear based on edge kind below.\n byStageId.set(stageId, { branchChildren: [], linearNext: [] });\n }\n\n for (const edge of graph.edges) {\n const kind = edge.data?.kind;\n if (kind === \"loop\") continue;\n const sourceEntry = byStageId.get(asStageId(edge.source));\n if (!sourceEntry) continue;\n // Skip edges whose target is not in the node set (malformed graph\n // defense — walker would bail on entry === undefined anyway, but\n // pruning here keeps branchChildren/linearNext clean for the\n // ambiguity warning below).\n const target = asStageId(edge.target);\n if (!byStageId.has(target)) continue;\n if (kind === \"fork-branch\" || kind === \"decision-branch\") {\n sourceEntry.branchChildren.push(target);\n } else {\n // 'next' or any unspecified kind treated as linear.\n sourceEntry.linearNext.push(target);\n }\n }\n\n return { byStageId, allNodeIds };\n}\n\n/** Find the seed: first node with no incoming non-loop edge. Falls back\n * to the first node in insertion order. */\nfunction findSeed(graph: TraceGraph, fromStageId?: StageId): StageId | null {\n if (fromStageId) {\n const n = graph.nodes.find((n) => n.id === fromStageId);\n return n ? asStageId(n.id) : null;\n }\n const hasIncoming = new Set<string>();\n for (const e of graph.edges) {\n if (e.data?.kind !== \"loop\") hasIncoming.add(e.target);\n }\n const seed = graph.nodes.find((n) => !hasIncoming.has(n.id)) ?? graph.nodes[0];\n return seed ? asStageId(seed.id) : null;\n}\n\n/**\n * BFS forward from `startId`. Returns ordered visit list (BFS order)\n * + reachable set. Skips `loop`-kind edges per invariant I1.\n */\nfunction bfsReachable(\n startId: StageId,\n index: GraphIndex,\n): { order: StageId[]; reachable: Set<StageId> } {\n const reachable = new Set<StageId>([startId]);\n const order: StageId[] = [startId];\n const queue: StageId[] = [startId];\n let head = 0;\n while (head < queue.length) {\n const cur = queue[head++]!;\n const entry = index.byStageId.get(cur);\n if (!entry) continue;\n for (const next of [...entry.branchChildren, ...entry.linearNext]) {\n if (reachable.has(next)) continue;\n reachable.add(next);\n order.push(next);\n queue.push(next);\n }\n }\n return { order, reachable };\n}\n\n/**\n * Find the convergence point of a fork — the FIRST node (BFS order\n * from branch[0]) reachable from EVERY branch. Returns `null` if no\n * common descendant (branches diverge without re-merging — does not\n * happen in series-parallel footprintjs charts).\n *\n * For strict S-P charts, the first node in branch[0]'s BFS order that\n * sits in every reachable set IS the true convergence (dominator).\n * For non-S-P graphs this is a best-effort approximation.\n */\nfunction findConvergence(\n branches: readonly StageId[],\n index: GraphIndex,\n): StageId | null {\n if (branches.length < 2) return null;\n // Compute reachable + order for branch[0] once; reuse the same walk\n // for both ordering AND the first reachable set (panel 5 must-fix).\n const firstWalk = bfsReachable(branches[0]!, index);\n const reachableSets: Set<StageId>[] = [firstWalk.reachable];\n for (let i = 1; i < branches.length; i++) {\n reachableSets.push(bfsReachable(branches[i]!, index).reachable);\n }\n // Exclude the branch starting points themselves — they're not the\n // convergence of their own subtree.\n const startSet = new Set(branches);\n for (const candidate of firstWalk.order) {\n if (startSet.has(candidate)) continue;\n if (reachableSets.every((s) => s.has(candidate))) {\n return candidate;\n }\n }\n return null;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Recursive walker — produces a StructureChain\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Walk forward from `startId`, stopping at `untilId` (exclusive). Returns\n * the chain for the [startId, untilId) segment. `untilId === null` means\n * walk to the end (terminal nodes).\n *\n * Cycle defense: passes a `visited: Set<StageId>` through recursion. A\n * node already in `visited` is skipped (returns null), so the same\n * StageId appears at most once in the resulting tree.\n */\nfunction walkChain(\n startId: StageId,\n untilId: StageId | null,\n index: GraphIndex,\n visited: Set<StageId>,\n): StructureChain | null {\n const items: StructureChain[] = [];\n let cur: StageId | null = startId;\n while (cur !== null && cur !== untilId) {\n if (visited.has(cur)) break;\n visited.add(cur);\n const entry = index.byStageId.get(cur);\n if (!entry) break;\n\n const branches = entry.branchChildren;\n const linearNexts = entry.linearNext;\n\n // Always emit the current node as a leaf — its OWN position in the\n // chain. Parallel/serial wrappers follow if applicable.\n items.push({ kind: \"leaf\", stageId: cur });\n\n if (branches.length >= 2) {\n // Fork — find convergence + recurse into each branch.\n const convergence = findConvergence(branches, index);\n const branchChains: StructureChain[] = [];\n for (const b of branches) {\n // Each branch walks with a per-branch clone of `visited` for\n // traversal isolation. After the branch returns, its markers\n // are unioned into the outer scope so the post-convergence\n // walk doesn't re-emit nodes that any branch already covered.\n // This is correct dedup for S-P graphs (branches don't share\n // pre-convergence nodes) and is what keeps the recursion\n // bounded for malformed graphs (cycle defense).\n const branchVisited = new Set(visited);\n const sub = walkChain(b, convergence, index, branchVisited);\n if (sub !== null) branchChains.push(sub);\n for (const v of branchVisited) visited.add(v);\n }\n if (branchChains.length > 0) {\n items.push({ kind: \"parallel\", branches: branchChains });\n }\n cur = convergence;\n } else if (branches.length === 1 && linearNexts.length === 0) {\n // Single branch — treat as linear continuation.\n cur = branches[0]!;\n } else if (linearNexts.length >= 1) {\n // Linear continuation. Multiple linearNexts is ambiguous for S-P\n // decomposition; we follow the first (deterministic per-recorder\n // insertion order) and warn in dev mode so consumers building\n // unusual graph shapes are alerted.\n if (linearNexts.length > 1) {\n devWarn(\n () =>\n `[buildCommitChainTree] stage '${cur}' has ${linearNexts.length} linear-next edges; chain decomposition follows only the first ('${linearNexts[0]}'). Use 'fork-branch' or 'decision-branch' edge kinds to express parallel/conditional splits.`,\n );\n }\n cur = linearNexts[0]!;\n } else {\n // Terminal node.\n cur = null;\n }\n }\n\n if (items.length === 0) return null;\n if (items.length === 1) return items[0]!;\n return { kind: \"serial\", items };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API: structureAsChainTree\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport interface ChainTreeOptions {\n /** Stage id to start the walk from. Defaults to the chart's seed\n * (first node with no incoming non-loop edge). */\n rootStageId?: StageId;\n}\n\n/**\n * Build a structural chain tree for a chart. Pure function over\n * `TraceGraph` — no runtime data required. Useful for rendering the\n * chart shape before any execution (static documentation, etc.).\n */\nexport function structureAsChainTree(\n graph: TraceGraph,\n options: ChainTreeOptions = {},\n): StructureChain | null {\n if (graph.nodes.length === 0) return null;\n const index = indexGraph(graph);\n const seed = findSeed(graph, options.rootStageId);\n if (!seed) return null;\n const visited = new Set<StageId>();\n return walkChain(seed, null, index, visited);\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Public API: buildCommitChainTree\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Build a commit-decorated chain tree. Same S-P shape as\n * `structureAsChainTree`, but each leaf carries the commits[] that\n * fired for that stage in this run (in commitIdx ascending order).\n *\n * Loop semantics: a stage that ran N times has a leaf with\n * `commits.length === N`. The consumer's renderer decides whether to\n * display them as a single \"ran 3×\" badge or unroll into N visible\n * boxes — both views are supported by the same data.\n *\n * Branches that never executed in this run appear with empty\n * `commits[]`. Consumers wanting \"runtime-only\" view can filter them\n * out.\n */\nexport function buildCommitChainTree(\n graph: TraceGraph,\n commitFlow: CommitFlowIndex,\n options: ChainTreeOptions = {},\n): CommitChain | null {\n const structural = structureAsChainTree(graph, options);\n if (!structural) return null;\n // Index commits by stageId for O(1) leaf decoration.\n const commitsByStageId = new Map<StageId, CommitView[]>();\n for (const c of commitFlow.commits) {\n const list = commitsByStageId.get(c.stageId) ?? [];\n list.push(c);\n commitsByStageId.set(c.stageId, list);\n }\n return decorate(structural, commitsByStageId);\n}\n\nfunction decorate(\n node: StructureChain,\n commitsByStageId: ReadonlyMap<StageId, readonly CommitView[]>,\n): CommitChain {\n if (node.kind === \"leaf\") {\n return {\n kind: \"leaf\",\n stageId: node.stageId,\n commits: commitsByStageId.get(node.stageId) ?? [],\n };\n }\n if (node.kind === \"serial\") {\n return {\n kind: \"serial\",\n items: node.items.map((n) => decorate(n, commitsByStageId)),\n };\n }\n return {\n kind: \"parallel\",\n branches: node.branches.map((b) => decorate(b, commitsByStageId)),\n };\n}\n","/**\n * CommitChainView — git-log-style swim-lane renderer for a\n * `CommitChain` or `StructureChain` (from `buildCommitChainTree` or\n * `structureAsChainTree`).\n *\n * Pair with `<CommitInspector>` for master/detail — this picks,\n * that inspects.\n *\n * Time-travel dimming (L8.5)\n * ──────────────────────────\n * Pass `revealedThroughCommitIdx={N}` (typically driven by\n * `<RunSlider>` via the ONE-CURSOR model) to dim commits with\n * `commitIdx > N`. Dimmed commits stay in the DOM (stable layout)\n * and stay CLICKABLE (clicking jumps the cursor forward to that\n * commit). Use `null` (default) to reveal all, `-1` to reveal none\n * (e.g., stale-cursor sentinel from `<TraceExplorerShell>`).\n *\n * Layout rules\n * ────────────\n * serial → vertical stack of children; subtle connector between them\n * parallel → horizontal row of branch columns (swim lanes), each\n * column is its own chain\n * leaf → one box per commit (loop unrolls into N boxes); empty\n * commits[] (or `StructureChain` leaf) renders a dashed\n * \"not executed in this run\" box\n *\n * Pure data prop: pass `chain` directly. For live updates, wrap with\n * `useTranslator(commitFlow, () => buildCommitChainTree(graph, commitFlow.getIndex()))`\n * at the parent. Mirrors the consumer pattern used by `<NodeInspector>`\n * and `<CommitInspector>`.\n *\n * Pre-execution rendering: pass a `StructureChain` directly (from\n * `structureAsChainTree(graph)`) — every leaf renders as the\n * \"not executed yet\" placeholder. No need to manufacture an empty\n * `CommitFlowIndex`.\n *\n * Selection: `selectedRuntimeStageId` highlights one commit box;\n * `onSelectCommit` fires when any commit box is clicked.\n *\n * Future extension: the recursive renderer is factored as\n * `<ChainShell renderLeaf={...}>` so a future `<StructureChainView>`\n * can reuse the same layout primitives with a different leaf renderer.\n *\n * @example\n * ```tsx\n * const chain = useTranslator(commitFlow, () =>\n * buildCommitChainTree(trace.getGraph(), commitFlow.getIndex()),\n * );\n * const [selected, setSelected] = useState<RuntimeStageId | null>(null);\n * return (\n * <div style={{ display: 'flex' }}>\n * <CommitChainView\n * chain={chain}\n * selectedRuntimeStageId={selected}\n * onSelectCommit={setSelected}\n * />\n * <CommitInspector index={commitFlow.getIndex()} selectedRuntimeStageId={selected} />\n * </div>\n * );\n * ```\n */\n\nimport type {\n CommitChain,\n CommitChainLeaf,\n StructureChain,\n StructureChainLeaf,\n} from \"./buildCommitChainTree\";\nimport type { CommitView } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId, StageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface CommitChainViewProps extends BaseComponentProps {\n /** The chain tree. Accepts BOTH `CommitChain` (from\n * `buildCommitChainTree`) and `StructureChain` (from\n * `structureAsChainTree` — pre-execution view). null → placeholder. */\n chain: CommitChain | StructureChain | null;\n /** Highlighted commit (by runtimeStageId). Only meaningful for\n * `CommitChain` input (StructureChain has no commits to select). */\n selectedRuntimeStageId?: RuntimeStageId | null;\n /** Fires when a commit box is clicked — pass to `<CommitInspector>`\n * for master/detail wiring. Not fired for \"not executed\" leaves. */\n onSelectCommit?: (runtimeStageId: RuntimeStageId) => void;\n /** Optional label resolver — default uses the bare stageId. Consumers\n * can map id → friendly name (e.g., from a NodeViewIndex). */\n resolveLabel?: (stageId: StageId) => string;\n /** Time-travel cursor: commits with `commitIdx > revealedThroughCommitIdx`\n * render dimmed (still visible — keeps layout stable). Pairs with\n * `<RunSlider>` in the ONE-CURSOR model.\n *\n * Semantics:\n * - `null` (default) — reveal ALL commits (no time-travel applied).\n * - `N >= 0` — reveal commits 0..N inclusive; dim commits with\n * `commitIdx > N`.\n * - `N < 0` (e.g., `-1`) — reveal NONE; all commits dim. Use this\n * sentinel for \"cursor is stale / unresolved\" so the chain doesn't\n * accidentally fall back to fully-revealed when the consumer wants\n * no-reveal. */\n revealedThroughCommitIdx?: number | null;\n}\n\nexport function CommitChainView({\n chain,\n selectedRuntimeStageId = null,\n onSelectCommit,\n resolveLabel,\n revealedThroughCommitIdx = null,\n className,\n style,\n}: CommitChainViewProps) {\n if (!chain) {\n return (\n <div\n className={className}\n style={{\n padding: 16,\n color: theme.textMuted,\n fontStyle: \"italic\",\n ...style,\n }}\n >\n No chain to display.\n </div>\n );\n }\n\n return (\n <div\n className={className}\n style={{\n padding: 12,\n color: theme.textPrimary,\n fontSize: 12,\n overflow: \"auto\",\n ...style,\n }}\n >\n <ChainShell\n node={chain}\n renderLeaf={(leaf) => (\n <Leaf\n leaf={leaf}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={onSelectCommit}\n resolveLabel={resolveLabel}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n )}\n />\n </div>\n );\n}\n\n// ── Recursive layout shell (reusable by future StructureChainView) ──\n\ntype AnyChain = CommitChain | StructureChain;\ntype AnyLeaf = CommitChainLeaf | StructureChainLeaf;\n\ninterface ChainShellProps {\n node: AnyChain;\n renderLeaf: (leaf: AnyLeaf) => React.ReactNode;\n}\n\nfunction ChainShell({ node, renderLeaf }: ChainShellProps): React.ReactElement {\n if (node.kind === \"leaf\") {\n return <>{renderLeaf(node)}</>;\n }\n\n if (node.kind === \"serial\") {\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 0,\n }}\n >\n {node.items.map((child, i) => (\n <div\n key={chainKey(child, i)}\n style={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\" }}\n >\n <ChainShell node={child} renderLeaf={renderLeaf} />\n {i < node.items.length - 1 && <Connector orientation=\"vertical\" />}\n </div>\n ))}\n </div>\n );\n }\n\n // parallel → swim lanes\n return (\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 0,\n }}\n >\n <ForkMarker />\n <div\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"flex-start\",\n gap: 18,\n padding: \"4px 0\",\n borderLeft: `1px dashed ${theme.border}`,\n borderRight: `1px dashed ${theme.border}`,\n paddingLeft: 12,\n paddingRight: 12,\n }}\n >\n {node.branches.map((branch, i) => (\n <div\n key={chainKey(branch, i)}\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n minWidth: 120,\n }}\n >\n <ChainShell node={branch} renderLeaf={renderLeaf} />\n </div>\n ))}\n </div>\n <ForkMarker />\n </div>\n );\n}\n\n/**\n * Stable React key for serial/parallel children — derived from the\n * subtree shape so a rerender with shifted branches doesn't mis-pair\n * subtree state. Falls back to `index` only when the leaf can't be\n * located (defensive — shouldn't happen).\n */\nfunction chainKey(node: AnyChain, fallbackIndex: number): string {\n const leaf = firstLeafOf(node);\n return leaf ? `${node.kind}:${leaf.stageId}` : `${node.kind}:idx${fallbackIndex}`;\n}\n\nfunction firstLeafOf(node: AnyChain): AnyLeaf | null {\n if (node.kind === \"leaf\") return node;\n if (node.kind === \"serial\") {\n for (const item of node.items) {\n const l = firstLeafOf(item);\n if (l) return l;\n }\n return null;\n }\n for (const branch of node.branches) {\n const l = firstLeafOf(branch);\n if (l) return l;\n }\n return null;\n}\n\n// ── Leaf (one or N commit boxes for loop iterations) ────────────────\n\nfunction Leaf({\n leaf,\n selectedRuntimeStageId,\n onSelectCommit,\n resolveLabel,\n revealedThroughCommitIdx,\n}: {\n leaf: AnyLeaf;\n selectedRuntimeStageId: RuntimeStageId | null;\n onSelectCommit?: (rsid: RuntimeStageId) => void;\n resolveLabel?: (stageId: StageId) => string;\n revealedThroughCommitIdx: number | null;\n}) {\n const label = resolveLabel ? resolveLabel(leaf.stageId) : leaf.stageId;\n const commits: readonly CommitView[] =\n \"commits\" in leaf ? leaf.commits : [];\n\n if (commits.length === 0) {\n return (\n <div\n style={{\n ...boxBaseStyle,\n borderStyle: \"dashed\",\n color: theme.textMuted,\n background: \"transparent\",\n }}\n title={`${leaf.stageId} — not executed in this run`}\n >\n <div style={{ fontWeight: 600 }}>{label}</div>\n <div style={{ fontSize: 10, fontStyle: \"italic\" }}>not executed</div>\n </div>\n );\n }\n\n return (\n <div style={{ display: \"flex\", flexDirection: \"column\", alignItems: \"center\", gap: 4 }}>\n {commits.map((c, i) => {\n const isSelected = c.runtimeStageId === selectedRuntimeStageId;\n const clickable = onSelectCommit !== undefined;\n // Time-travel dimming: when revealedThroughCommitIdx is set,\n // commits BEYOND the cursor render dimmed (still in the DOM\n // so layout stays stable as the cursor slides). Commits are\n // STILL clickable (clicking jumps the time cursor forward).\n // We use aria-disabled (not aria-hidden) so screen-readers\n // perceive the element + state, per WAI-ARIA's \"MUST NOT use\n // aria-hidden on focusable elements\" rule.\n const isRevealed =\n revealedThroughCommitIdx === null ||\n c.commitIdx <= revealedThroughCommitIdx;\n return (\n <button\n key={c.commitIdx}\n type=\"button\"\n onClick={clickable ? () => onSelectCommit(c.runtimeStageId) : undefined}\n style={{\n ...boxBaseStyle,\n cursor: clickable ? \"pointer\" : \"default\",\n borderColor: isSelected ? theme.success : theme.border,\n borderWidth: isSelected ? 2 : 1,\n background: isSelected ? \"rgba(34,197,94,0.08)\" : \"transparent\",\n color: theme.textPrimary,\n textAlign: \"left\",\n fontFamily: \"inherit\",\n padding: \"6px 10px\",\n opacity: isRevealed ? 1 : 0.35,\n }}\n aria-disabled={!isRevealed}\n aria-current={isSelected ? \"true\" : undefined}\n title={c.runtimeStageId}\n >\n <div style={{ fontWeight: 600 }}>\n {label}\n {commits.length > 1 && (\n <span style={{ color: theme.textMuted, fontWeight: 400, marginLeft: 6 }}>\n iter {i + 1}/{commits.length}\n </span>\n )}\n </div>\n <div\n style={{\n fontSize: 10,\n fontFamily: \"monospace\",\n color: theme.textMuted,\n marginTop: 2,\n }}\n >\n #{c.commitIdx} · {c.runtimeStageId}\n </div>\n </button>\n );\n })}\n </div>\n );\n}\n\n// ── Decorations ─────────────────────────────────────────────────────\n\nfunction Connector({ orientation }: { orientation: \"vertical\" | \"horizontal\" }) {\n return orientation === \"vertical\" ? (\n <div\n aria-hidden\n style={{\n width: 1,\n height: 12,\n background: theme.border,\n }}\n />\n ) : (\n <div\n aria-hidden\n style={{\n height: 1,\n width: 12,\n background: theme.border,\n }}\n />\n );\n}\n\nfunction ForkMarker() {\n return (\n <div\n aria-hidden\n style={{\n width: 8,\n height: 8,\n borderRadius: \"50%\",\n background: theme.border,\n margin: \"2px 0\",\n }}\n />\n );\n}\n\nconst boxBaseStyle: React.CSSProperties = {\n display: \"inline-block\",\n minWidth: 110,\n padding: \"6px 10px\",\n border: `1px solid ${theme.border}`,\n borderRadius: 4,\n fontSize: 12,\n color: theme.textPrimary,\n background: \"transparent\",\n};\n","/**\n * TraceExplorerShell — composed master/detail layout that wires the\n * full L8 translator stack into a single drop-in component.\n *\n * **Composes**: [`<CommitChainView>`](./CommitChainView.tsx),\n * [`<CommitInspector>`](./CommitInspector.tsx),\n * [`<NodeInspector>`](./NodeInspector.tsx) over a [`TraceBundle`](./createTraceBundle.ts).\n *\n * The L8 stack is intentionally factored as independent pieces\n * (structure / runtimeOverlay / nodeView / commitFlow / chain\n * builder / inspectors). Consumers can wire à-la-carte for custom\n * layouts. `<TraceExplorerShell>` is the \"I want the canonical\n * trace-explorer UI without writing 50 lines of `useTranslator`\n * plumbing\" entry point — pass a `bundle`, get a master/detail UI.\n *\n * **Prerequisite**: call `bundle.attachTo(executor)` (see\n * `createTraceBundle` for the recorder-attach lifecycle) BEFORE\n * rendering this component. The shell only consumes events; it does\n * not trigger them. Without the attach step, every pane will show its\n * placeholder.\n *\n * Layout\n * ──────\n * ┌─────────────────────────────────────────────────┐\n * │ RunSlider (time-travel cursor) │\n * ├──────────────────────────┬──────────────────────┤\n * │ CommitChainView │ CommitInspector │\n * │ (master, click a box) │ (detail, selected) │\n * │ │ │\n * ├──────────────────────────┴──────────────────────┤\n * │ NodeInspector (resolved from selected stageId) │\n * └─────────────────────────────────────────────────┘\n *\n * The slider is the **ONE-CURSOR** affordance: dragging it moves\n * the same cursor that clicking a commit moves. Commits past the\n * cursor render dimmed in the chain view (`revealedThroughCommitIdx`\n * threaded through automatically). Pass `slots: { slider: null }`\n * to hide the slider (e.g., for static post-run views).\n *\n * Selection model\n * ───────────────\n * ONE cursor (`selectedRuntimeStageId`) drives both detail panes.\n * Clicking a commit in the chain view updates the cursor; the\n * `<CommitInspector>` shows that commit; the `<NodeInspector>`\n * shows the stage that commit belongs to (derived by stripping the\n * `#executionIndex` suffix from the runtimeStageId).\n *\n * Controlled mode: pass `selectedRuntimeStageId` + `onSelectionChange`\n * to drive selection from outside (URL hash, parent state, etc.).\n * Uncontrolled mode: omit both — the shell owns the cursor.\n * `onSelectionChange` also fires in uncontrolled mode for\n * observability (logging, analytics).\n *\n * Composition rule (L8 architecture, carried forward)\n * ───────────────────────────────────────────────────\n * This shell consumes ONLY the bundle's translator handles via\n * `useTranslator`. It NEVER subscribes to peer translators directly\n * (would violate the linear-dep-tree rule). It builds the chain\n * tree fresh on each commitFlow version bump — cheap, cache-friendly\n * (every input index is version-keyed-cached upstream, and\n * `commitFlow` transitively re-notifies on `structure` changes per\n * the L8.2 contract, so structure-only events also propagate).\n *\n * Customization\n * ─────────────\n * The default layout is a CSS grid. Override via `slots` to swap any\n * panel for a custom renderer. Slot props mirror the sibling-\n * inspector pattern — they receive PURE DATA (the typed index/chain),\n * NOT the bundle. This keeps slots usable from tests / Storybook /\n * SSR and means slot authors do not have to re-subscribe to\n * translators (the shell does that once).\n *\n * Stability note: `slots` should be stable across renders (define at\n * module scope or wrap with `useMemo`). The shell memoizes the\n * resolved component refs to defend against accidental remounts.\n *\n * @example Minimal\n * ```tsx\n * const bundle = useMemo(() => createTraceBundle(), []);\n * useEffect(() => {\n * const chart = flowChart('seed', fn, 'seed', undefined, undefined, {\n * structureRecorders: [bundle.structure.recorder],\n * }).build();\n * const executor = new FlowChartExecutor(chart);\n * bundle.attachTo(executor); // Prerequisite — see createTraceBundle.\n * executor.run({ input });\n * }, [bundle]);\n *\n * return <TraceExplorerShell bundle={bundle} />;\n * ```\n *\n * @example Controlled selection (sync to URL hash)\n * ```tsx\n * const [sel, setSel] = useState<RuntimeStageId | null>(null);\n * return (\n * <TraceExplorerShell\n * bundle={bundle}\n * selectedRuntimeStageId={sel}\n * onSelectionChange={setSel}\n * />\n * );\n * ```\n *\n * @example Custom chain pane (typed data slot)\n * ```tsx\n * const slots = useMemo(() => ({\n * chain: ({ chain, selectedRuntimeStageId, onSelectCommit }) => (\n * <MyCustomTimeline chain={chain} cursor={selectedRuntimeStageId} onPick={onSelectCommit} />\n * ),\n * }), []);\n * return <TraceExplorerShell bundle={bundle} slots={slots} />;\n * ```\n */\n\nimport { useMemo, useState, useCallback } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport type { TraceBundle } from \"./createTraceBundle\";\nimport type { RuntimeStageId, StageId } from \"./_internal/keys\";\nimport { asStageId } from \"./_internal/keys\";\nimport { useTranslator } from \"./_internal/useTranslator\";\nimport { buildCommitChainTree, type CommitChain } from \"./buildCommitChainTree\";\nimport { CommitChainView } from \"./CommitChainView\";\nimport { CommitInspector } from \"./CommitInspector\";\nimport { NodeInspector } from \"./NodeInspector\";\nimport { RunSlider } from \"./RunSlider\";\nimport type { CommitFlowIndex } from \"./createCommitFlowRecorder\";\nimport type { NodeViewIndex } from \"./createNodeViewRecorder\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\n/**\n * Slot prop bags — slots receive PURE DATA (chain/index), NOT the\n * bundle. Mirrors the sibling-inspector convention so slot bodies are\n * usable from tests / Storybook / SSR and avoid re-subscribing to\n * translators. Each callback is wired by the shell to the shared\n * selection cursor.\n */\nexport interface ChainSlotProps {\n /** Live chain tree, derived from the bundle. `null` before any\n * commits arrive. */\n chain: CommitChain | null;\n /** Currently selected commit (shared cursor). */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor. */\n onSelectCommit: (rsid: RuntimeStageId) => void;\n /** Time-travel reveal cursor (derived from selectedRuntimeStageId\n * via ONE-CURSOR model). Commits with commitIdx > this value\n * render dimmed. `null` reveals all, `-1` reveals none, `N >= 0`\n * reveals up to commit N. **Optional in custom slots** — slot\n * authors that don't implement time-travel dimming can ignore it\n * (matches the standalone `<CommitChainView>` prop optionality). */\n revealedThroughCommitIdx?: number | null;\n}\nexport interface CommitInspectorSlotProps {\n /** Live commitFlow index. */\n index: CommitFlowIndex;\n /** Currently selected commit (shared cursor). */\n selectedRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor (e.g., for clickable\n * data-dep / lineage breadcrumbs). */\n onNavigate: (rsid: RuntimeStageId) => void;\n}\nexport interface NodeInspectorSlotProps {\n /** Live nodeView index. */\n index: NodeViewIndex;\n /** StageId derived from `selectedRuntimeStageId`. */\n selectedStageId: StageId | null;\n /** Wire to the shared selection cursor (e.g., for prev/next chain\n * breadcrumbs). Resolves the stage to its first commit. */\n onNavigate: (stageId: StageId) => void;\n}\nexport interface SliderSlotProps {\n /** Live commitFlow index. */\n index: CommitFlowIndex;\n /** Currently selected commit — same cursor as the chain selection\n * per the ONE-CURSOR model. */\n cursorRuntimeStageId: RuntimeStageId | null;\n /** Wire to the shared selection cursor. */\n onCursorChange: (rsid: RuntimeStageId | null) => void;\n}\n\nexport interface TraceExplorerSlots {\n /** Override the chain (master) pane. Use to swap the swim-lane\n * renderer for a timeline/Gantt/custom layout while keeping the\n * same selection contract. */\n chain?: React.ComponentType<ChainSlotProps>;\n /** Override the commit (detail) pane. Use to add custom commit-\n * detail formatting (e.g., domain-specific updates rendering). */\n commitInspector?: React.ComponentType<CommitInspectorSlotProps>;\n /** Override the node (stage-summary) pane. Use to surface per-stage\n * custom KPIs / annotations alongside the default execution data. */\n nodeInspector?: React.ComponentType<NodeInspectorSlotProps>;\n /** Override the slider (top time-travel bar). Pass `null` to HIDE\n * the slider entirely (e.g., for static post-run views with no\n * scrub affordance). */\n slider?: React.ComponentType<SliderSlotProps> | null;\n}\n\nexport interface TraceExplorerShellProps extends BaseComponentProps {\n /** The translator bundle from `createTraceBundle()`. MUST have had\n * `bundle.attachTo(executor)` called before any commits arrive,\n * otherwise every pane shows its placeholder. */\n bundle: TraceBundle;\n /** Controlled selection (omit for uncontrolled). `null` clears. */\n selectedRuntimeStageId?: RuntimeStageId | null;\n /** Fires on selection changes. In controlled mode, required for\n * selection to take effect. In uncontrolled mode, fires as an\n * observation hook (logging/analytics) — the shell still owns the\n * state.\n *\n * Memoize via `useCallback` to avoid downstream re-renders. */\n onSelectionChange?: (rsid: RuntimeStageId | null) => void;\n /** Optional slot overrides. Should be stable across renders\n * (define at module scope or `useMemo`). */\n slots?: TraceExplorerSlots;\n}\n\nexport function TraceExplorerShell({\n bundle,\n selectedRuntimeStageId: controlledSel,\n onSelectionChange,\n slots,\n className,\n style,\n}: TraceExplorerShellProps) {\n // Controlled vs uncontrolled selection. Standard React idiom.\n const [internalSel, setInternalSel] = useState<RuntimeStageId | null>(null);\n const isControlled = controlledSel !== undefined;\n const selectedRuntimeStageId = isControlled ? controlledSel : internalSel;\n\n const handleSelect = useCallback(\n (rsid: RuntimeStageId | null) => {\n if (!isControlled) setInternalSel(rsid);\n // Fire in both modes — controlled mode requires it for parent\n // sync; uncontrolled mode fires for observability (logging,\n // analytics, URL sync without taking control).\n onSelectionChange?.(rsid);\n },\n [isControlled, onSelectionChange],\n );\n const handleSelectCommit = useCallback(\n (rsid: RuntimeStageId) => handleSelect(rsid),\n [handleSelect],\n );\n\n // Derive selected stageId from selectedRuntimeStageId by stripping\n // the '#executionIndex' suffix. Mirrors footprintjs/trace\n // `parseRuntimeStageId` invariant — kept inline because\n // explainable-ui is dep-free from footprintjs (subflow prefix is\n // preserved; nodeView keys subflow stages by the full path-prefixed\n // form per footprintjs convention).\n const selectedStageId = useMemo<StageId | null>(() => {\n if (!selectedRuntimeStageId) return null;\n const hashIdx = selectedRuntimeStageId.lastIndexOf(\"#\");\n // hashIdx === 0 → empty stageId (malformed input) → no selection.\n if (hashIdx <= 0) return null;\n return asStageId(selectedRuntimeStageId.slice(0, hashIdx));\n }, [selectedRuntimeStageId]);\n\n // Resolve slot components ONCE per slots-identity change — defends\n // against consumer footgun of passing inline `slots={{...}}` every\n // render which would otherwise remount default panes.\n const ChainPane = useMemo(\n () => slots?.chain ?? DefaultChainPane,\n [slots?.chain],\n );\n const CommitPane = useMemo(\n () => slots?.commitInspector ?? DefaultCommitPane,\n [slots?.commitInspector],\n );\n const NodePane = useMemo(\n () => slots?.nodeInspector ?? DefaultNodePane,\n [slots?.nodeInspector],\n );\n // Slider has tri-state semantics: undefined = use default; null =\n // hide; ComponentType = override. `slots?.slider === null` is the\n // \"hide\" signal; absent key = default.\n const SliderPane = useMemo<React.ComponentType<SliderSlotProps> | null>(() => {\n if (slots && \"slider\" in slots) {\n return slots.slider ?? null;\n }\n return DefaultSliderPane;\n }, [slots]);\n\n // Subscribe ONCE here to the three translators; pass the resolved\n // data down to slots (whether default or custom). Slots NEVER need\n // to subscribe themselves.\n const chain = useTranslator(bundle.commitFlow, () =>\n buildCommitChainTree(bundle.structure.getGraph(), bundle.commitFlow.getIndex()),\n );\n const commitIndex = useTranslator(bundle.commitFlow, () =>\n bundle.commitFlow.getIndex(),\n );\n const nodeIndex = useTranslator(bundle.nodeView, () => bundle.nodeView.getIndex());\n\n // Stage-click → resolve first commit and select it. One-shot lookup\n // outside useTranslator (no subscription) is intentional — this\n // fires on click, not in a render path. Picking commits[0] is the\n // documented semantic; loops resolve to iteration 1.\n const handleStageNavigate = useCallback(\n (stageId: StageId) => {\n const candidates = commitIndex.commits.filter((c) => c.stageId === stageId);\n const first = candidates[0];\n handleSelect(first ? first.runtimeStageId : null);\n },\n [commitIndex, handleSelect],\n );\n\n // Cursor → commitIdx for chain dimming. ONE-CURSOR model: the same\n // cursor that drives selection also drives time-travel reveal.\n //\n // Three states (distinguished — Panel 1 must-fix L8.5):\n // - no cursor (`null`) → `null` (reveal ALL)\n // - cursor resolves to a commit → that commit's commitIdx\n // - cursor is STALE (rsid unknown to index, e.g. removed by reset)\n // → `-1` (reveal NONE), NOT `null` — prevents incoherent \"stale\n // cursor falls back to fully-revealed\" state.\n const revealedThroughCommitIdx = useMemo<number | null>(() => {\n if (!selectedRuntimeStageId) return null;\n const view = commitIndex.byRuntimeStageId.get(selectedRuntimeStageId);\n return view ? view.commitIdx : -1;\n }, [selectedRuntimeStageId, commitIndex]);\n\n // Layout: when the slider is hidden (`slots.slider === null`),\n // collapse the slider row so the grid doesn't reserve empty space.\n const layoutStyle = useMemo<CSSProperties>(\n () => (SliderPane ? SHELL_STYLE_WITH_SLIDER : SHELL_STYLE_NO_SLIDER),\n [SliderPane],\n );\n\n return (\n <div className={className} style={{ ...layoutStyle, ...style }}>\n {SliderPane && (\n <Pane area=\"slider\">\n <SliderPane\n index={commitIndex}\n cursorRuntimeStageId={selectedRuntimeStageId}\n onCursorChange={handleSelect}\n />\n </Pane>\n )}\n <Pane area=\"chain\">\n <ChainPane\n chain={chain}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={handleSelectCommit}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n </Pane>\n <Pane area=\"commit\">\n <CommitPane\n index={commitIndex}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onNavigate={handleSelectCommit}\n />\n </Pane>\n <Pane area=\"node\">\n <NodePane\n index={nodeIndex}\n selectedStageId={selectedStageId}\n onNavigate={handleStageNavigate}\n />\n </Pane>\n </div>\n );\n}\n\n// ── Default panes (pure data props, no internal subscriptions) ──────\n\nfunction DefaultChainPane({\n chain,\n selectedRuntimeStageId,\n onSelectCommit,\n revealedThroughCommitIdx,\n}: ChainSlotProps) {\n return (\n <CommitChainView\n chain={chain}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onSelectCommit={onSelectCommit}\n revealedThroughCommitIdx={revealedThroughCommitIdx}\n />\n );\n}\n\nfunction DefaultCommitPane({\n index,\n selectedRuntimeStageId,\n onNavigate,\n}: CommitInspectorSlotProps) {\n return (\n <CommitInspector\n index={index}\n selectedRuntimeStageId={selectedRuntimeStageId}\n onNavigate={onNavigate}\n />\n );\n}\n\nfunction DefaultNodePane({ index, selectedStageId, onNavigate }: NodeInspectorSlotProps) {\n return (\n <NodeInspector index={index} selectedId={selectedStageId} onNavigate={onNavigate} />\n );\n}\n\nfunction DefaultSliderPane({\n index,\n cursorRuntimeStageId,\n onCursorChange,\n}: SliderSlotProps) {\n return (\n <RunSlider\n index={index}\n cursorRuntimeStageId={cursorRuntimeStageId}\n onCursorChange={onCursorChange}\n />\n );\n}\n\n// ── Layout helpers ──────────────────────────────────────────────────\n\nconst SHELL_STYLE_WITH_SLIDER: CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: \"minmax(280px, 1fr) minmax(320px, 1fr)\",\n gridTemplateRows: \"auto 1fr auto\",\n gridTemplateAreas: '\"slider slider\" \"chain commit\" \"node node\"',\n gap: 12,\n padding: 12,\n background: theme.bgPrimary,\n color: theme.textPrimary,\n};\n\nconst SHELL_STYLE_NO_SLIDER: CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: \"minmax(280px, 1fr) minmax(320px, 1fr)\",\n gridTemplateRows: \"1fr auto\",\n gridTemplateAreas: '\"chain commit\" \"node node\"',\n gap: 12,\n padding: 12,\n background: theme.bgPrimary,\n color: theme.textPrimary,\n};\n\nconst PANE_BASE_STYLE: CSSProperties = {\n border: `1px solid ${theme.border}`,\n borderRadius: 6,\n background: theme.bgSecondary,\n overflow: \"auto\",\n minHeight: 0, // permit shrinking inside grid\n};\n\nfunction Pane({ area, children }: { area: string; children: React.ReactNode }) {\n // Wrap each pane as an accessibility landmark so screen readers can\n // jump between panels.\n return (\n <div role=\"region\" aria-label={area} style={{ ...PANE_BASE_STYLE, gridArea: area }}>\n {children}\n </div>\n );\n}\n","/**\n * RunSlider — time-travel cursor over the commit timeline.\n *\n * Implements the **ONE-CURSOR** model from the Lens architecture: the\n * slider position IS the same `runtimeStageId` cursor that selection\n * uses everywhere else (chain view, inspectors). Moving the slider\n * advances the cursor; clicking a commit in the chain view moves the\n * slider. Same underlying state, two affordances.\n *\n * Internal mapping\n * ────────────────\n * Slider value is a `commitIdx` integer in `[0, commits.length - 1]`.\n * - slider value N ↔ `commits[N].runtimeStageId` (the cursor)\n * - cursor === null ↔ slider at value 0 (initial/empty state)\n *\n * When `commits[]` grows mid-run the slider's max bound expands\n * automatically (`index.commits.length` re-evaluates on every\n * render via the consumer's `useTranslator` subscription). The\n * cursor does NOT auto-advance — consumers that want \"follow latest\n * commit\" behavior wire a `useEffect` on `index.commits.length`.\n *\n * @example\n * ```tsx\n * const [cursor, setCursor] = useState<RuntimeStageId | null>(null);\n * const index = useTranslator(commitFlow, () => commitFlow.getIndex());\n * return (\n * <RunSlider\n * index={index}\n * cursorRuntimeStageId={cursor}\n * onCursorChange={setCursor}\n * />\n * );\n * ```\n *\n * @example Follow-latest behavior (consumer-owned)\n * ```tsx\n * useEffect(() => {\n * const last = index.commits[index.commits.length - 1];\n * if (last) setCursor(last.runtimeStageId);\n * }, [index.commits.length]);\n * ```\n *\n * Pairs with `<CommitChainView>` (via shared `revealedThroughCommitIdx`\n * to dim future commits) and `<TraceExplorerShell>` (which wires the\n * slider as a top bar driving the same cursor as the chain selection).\n */\n\nimport { useCallback, useMemo } from \"react\";\nimport type { CommitFlowIndex, CommitView } from \"./createCommitFlowRecorder\";\nimport type { RuntimeStageId } from \"./_internal/keys\";\nimport type { BaseComponentProps } from \"../../types\";\nimport { theme } from \"../../theme\";\n\nexport interface RunSliderProps extends BaseComponentProps {\n /** Live commit flow index (pure data prop — pass via\n * `useTranslator(commitFlow, () => commitFlow.getIndex())`).\n * Source: `createCommitFlowRecorder` — see `<CommitInspector>` for\n * the canonical consumer pattern. */\n index: CommitFlowIndex;\n /** The shared time cursor. `null` = no commit yet selected (slider\n * sits at value 0). */\n cursorRuntimeStageId: RuntimeStageId | null;\n /** Fires when the slider moves. */\n onCursorChange: (rsid: RuntimeStageId | null) => void;\n /** Optional label callback. Default renders `\"#commitIdx · stageId\"`.\n * Receives the full resolved `commit` + the `index` for richer\n * labels (step name, duration from a sibling translator, etc.). */\n renderLabel?: (info: {\n commitIdx: number;\n total: number;\n runtimeStageId: RuntimeStageId | null;\n /** Resolved commit at the cursor, or `null` when index is empty. */\n commit: CommitView | null;\n /** Full index — for cross-lookups (e.g., finding the previous\n * commit's stage label). */\n index: CommitFlowIndex;\n }) => React.ReactNode;\n}\n\nexport function RunSlider({\n index,\n cursorRuntimeStageId,\n onCursorChange,\n renderLabel,\n className,\n style,\n}: RunSliderProps) {\n const total = index.commits.length;\n\n // Map cursor → slider value. If cursor is null OR unknown to the\n // index, value 0 (placeholder).\n const cursorCommitIdx = useMemo<number>(() => {\n if (!cursorRuntimeStageId) return 0;\n const view = index.byRuntimeStageId.get(cursorRuntimeStageId);\n return view ? view.commitIdx : 0;\n }, [index, cursorRuntimeStageId]);\n\n const handleSliderChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = Number(e.target.value);\n const view = index.commits[value];\n onCursorChange(view ? view.runtimeStageId : null);\n },\n [index, onCursorChange],\n );\n\n const label = useMemo(() => {\n const commit = index.commits[cursorCommitIdx] ?? null;\n const rsid = cursorRuntimeStageId ?? commit?.runtimeStageId ?? null;\n if (renderLabel)\n return renderLabel({\n commitIdx: cursorCommitIdx,\n total,\n runtimeStageId: rsid,\n commit,\n index,\n });\n if (total === 0) return <span style={{ color: theme.textMuted }}>No commits yet</span>;\n return (\n <span style={{ fontFamily: \"monospace\", fontSize: 11, color: theme.textSecondary }}>\n #{cursorCommitIdx + 1} / {total} · {commit?.runtimeStageId ?? \"—\"}\n </span>\n );\n }, [renderLabel, cursorCommitIdx, total, index, cursorRuntimeStageId]);\n\n // Disabled state — slider is non-interactive when there are 0 or 1\n // commits (sliding has no effect).\n const disabled = total < 2;\n\n return (\n <div\n className={className}\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 12,\n padding: \"8px 12px\",\n background: theme.bgSecondary,\n border: `1px solid ${theme.border}`,\n borderRadius: 6,\n ...style,\n }}\n >\n <span\n style={{\n fontSize: 10,\n fontWeight: 700,\n letterSpacing: 0.4,\n textTransform: \"uppercase\",\n color: theme.textMuted,\n }}\n >\n Time\n </span>\n <input\n type=\"range\"\n min={0}\n max={Math.max(0, total - 1)}\n step={1}\n value={Math.min(cursorCommitIdx, Math.max(0, total - 1))}\n onChange={handleSliderChange}\n disabled={disabled}\n aria-label=\"Commit time cursor\"\n aria-valuemin={0}\n aria-valuemax={Math.max(0, total - 1)}\n aria-valuenow={cursorCommitIdx}\n aria-valuetext={\n total === 0 ? \"no commits\" : `commit ${cursorCommitIdx + 1} of ${total}`\n }\n style={{ flex: 1, accentColor: theme.success }}\n />\n <div style={{ minWidth: 200, textAlign: \"right\" }}>{label}</div>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","StageNode","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_react","padding","import_jsx_runtime","import_react","import_jsx_runtime","DEFAULT_NODE_W","DEFAULT_NODE_H","dagre","import_jsx_runtime","import_react","v","import_react","import_react","padding","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","DEFAULT_NODE_TYPES","DEFAULT_EDGE_TYPES","import_jsx_runtime","import_react","import_jsx_runtime","SubflowBreadcrumb","import_react","EMPTY_GRAPH","import_react","import_jsx_runtime","TreeNode","SectionLabel","SubflowTree","import_react","import_jsx_runtime","C","DEFAULT_NODE_W","DEFAULT_NODE_H","memo","DEFAULT_NODE_W","DEFAULT_NODE_H","baseStageIdOf","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","Section","v","n","v","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime"]}