@pipelex/mthds-ui 0.28.0 → 0.29.1

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.
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/graph/validateGraphSpec.ts","../src/graph/graphAnalysis.ts","../src/graph/pipeCardPayload.ts","../src/graph/graphBuilders.ts","../src/graph/graphFolds.ts","../src/graph/graphValidation.ts","../src/graph/stuffLookup.ts","../src/graph/elkGraphBuilder.ts","../src/graph/graphLayout.ts","../src/graph/graphControllers.ts"],"sourcesContent":["/**\n * Single boundary validator for GraphSpec JSON.\n *\n * `validateGraphSpec()` runs once when a spec is loaded from an untyped source\n * (embedded JSON, library consumer input). After it returns, internal code\n * trusts the data and uses the strict types in `types.ts` — no inline\n * defensive checks scattered across modules.\n *\n * The pipelex runtime guarantees specific fields are always present and\n * non-null. This validator enforces those guarantees and fails loudly when\n * they are violated, instead of hiding upstream bugs behind fabricated values.\n *\n * Note: `validateGraphSpec` normalizes the input **in place** — see its doc\n * comment.\n */\nimport type {\n GraphSpec,\n GraphSpecEdgeKind,\n GraphSpecMode,\n GraphSpecNode,\n PipeCallNode,\n PipeStatus,\n} from \"./types\";\nimport { KNOWN_PIPE_TYPES } from \"./types\";\n\n/**\n * Thrown by `validateGraphSpec` when a spec violates a pipelex runtime\n * guarantee. `path` points at the offending location (e.g.\n * `nodes[3].io.inputs[0].name`) and `name` is the stable, greppable\n * `\"GraphSpecValidationError\"`.\n */\nexport class GraphSpecValidationError extends Error {\n readonly path: string;\n\n constructor(path: string, detail: string) {\n const location = path === \"\" ? \"<root>\" : path;\n super(`GraphSpec validation failed at ${location}: ${detail}`);\n this.name = \"GraphSpecValidationError\";\n this.path = path;\n }\n}\n\nconst PIPE_STATUSES: ReadonlySet<string> = new Set<PipeStatus>([\n \"succeeded\",\n \"failed\",\n \"running\",\n \"scheduled\",\n \"skipped\",\n \"canceled\",\n]);\n\nconst GRAPH_SPEC_MODES: ReadonlySet<string> = new Set<GraphSpecMode>([\"dry\", \"live\", \"static\"]);\n\nconst EDGE_KINDS: ReadonlySet<string> = new Set<GraphSpecEdgeKind>([\n \"contains\",\n \"data\",\n \"control\",\n \"selected_outcome\",\n \"batch_item\",\n \"batch_aggregate\",\n \"parallel_combine\",\n]);\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction describe(value: unknown): string {\n if (value === null) return \"null\";\n if (value === undefined) return \"undefined\";\n if (Array.isArray(value)) return \"an array\";\n return `a ${typeof value}`;\n}\n\nfunction fail(path: string, detail: string): never {\n throw new GraphSpecValidationError(path, detail);\n}\n\nfunction requireNonEmptyString(value: unknown, path: string): string {\n if (typeof value !== \"string\" || value.length === 0) {\n fail(path, `expected a non-empty string, got ${describe(value)}`);\n }\n return value;\n}\n\nfunction validateIoItem(item: unknown, path: string): void {\n if (!isPlainObject(item)) {\n fail(path, `expected an object, got ${describe(item)}`);\n }\n // `name` is guaranteed by pipelex; `concept` and `digest` stay tolerant.\n requireNonEmptyString(item.name, `${path}.name`);\n // `multiplicity` may be absent (a producer predating it, or a single value),\n // but a present one must be the registry's encoding: a malformed marker would\n // otherwise read as single without a word, which is the drop it exists to end.\n const multiplicity = item.multiplicity;\n if (\n multiplicity !== undefined &&\n multiplicity !== null &&\n typeof multiplicity !== \"boolean\" &&\n !(Number.isInteger(multiplicity) && (multiplicity as number) >= 1)\n ) {\n const got = typeof multiplicity === \"number\" ? String(multiplicity) : describe(multiplicity);\n fail(`${path}.multiplicity`, `expected a boolean, a positive integer or null, got ${got}`);\n }\n}\n\nfunction requireNumber(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n fail(path, `expected a finite number, got ${describe(value)}`);\n }\n return value;\n}\n\n/**\n * A cost, which may arrive absent where its producer wrote `null`, normalized to `null`\n * when — and only when — the rated-call count says `null` is what it was.\n *\n * Some hosts drop `null` values from the JSON they relay (ChatGPT does, on the way to\n * an MCP App view), so every unrated cost reaches the renderer as a missing key. Absence\n * alone is ambiguous: a dropped `null`, or a cost the producer failed to write. Invariant\n * 2 on `GraphSpecNodeUsage` settles it: `cost` is `null` exactly when no call was rated.\n * With no rated call the value can only have been `null`. With one, a missing cost is a\n * real gap, and reading it as unrated would understate what the run spent, so it fails.\n */\nfunction normalizeCost(value: unknown, ratedCalls: number, path: string): number | null {\n if (value === null) return null;\n if (value === undefined) {\n if (ratedCalls === 0) return null;\n fail(path, `expected a finite number for ${ratedCalls} rated call(s), got undefined`);\n }\n return requireNumber(value, path);\n}\n\n/**\n * A nullable number that may also be absent, normalized to `null`.\n *\n * For fields added after specs were already being produced. The validator's job is\n * to reject malformed data, not to insist the producer is the latest version: an\n * absent key is unambiguous (the producer predates the field), while a wrong-typed\n * one is not and still fails.\n */\nfunction normalizeNullableNumber(value: unknown, path: string): number | null {\n if (value === undefined || value === null) return null;\n return requireNumber(value, path);\n}\n\nfunction requireNumberRecord(value: unknown, path: string): void {\n if (!isPlainObject(value)) {\n fail(path, `expected an object, got ${describe(value)}`);\n }\n for (const [key, entry] of Object.entries(value)) {\n requireNumber(entry, `${path}.${key}`);\n }\n}\n\n/**\n * Validate a usage object (node-level or graph-level).\n *\n * This is the whole point of the boundary: types alone are a compile-time\n * fiction, so a malformed `usage` from a stale or hostile spec would otherwise\n * flow through as trusted data and be rendered as a dollar figure. In\n * particular `cost` MUST come out as `number | null` and nothing else — a string\n * cost, or an absent one on calls that were rated, silently becoming \"unrated\"\n * would understate what a run spent. The counts stay required: an absent count\n * is not a relayed `null`, since the producer never writes one.\n */\nfunction validateUsage(usage: unknown, path: string): void {\n if (!isPlainObject(usage)) {\n fail(path, `expected an object, got ${describe(usage)}`);\n }\n requireNumber(usage.inference_calls, `${path}.inference_calls`);\n const ratedCalls = requireNumber(usage.rated_inference_calls, `${path}.rated_inference_calls`);\n requireNumberRecord(usage.nb_tokens_by_category, `${path}.nb_tokens_by_category`);\n requireNumber(usage.total_tokens, `${path}.total_tokens`);\n usage.cost = normalizeCost(usage.cost, ratedCalls, `${path}.cost`);\n usage.cost_input = normalizeNullableNumber(usage.cost_input, `${path}.cost_input`);\n usage.cost_output = normalizeNullableNumber(usage.cost_output, `${path}.cost_output`);\n requireNumber(usage.subtree_inference_calls, `${path}.subtree_inference_calls`);\n const subtreeRatedCalls = requireNumber(\n usage.subtree_rated_inference_calls,\n `${path}.subtree_rated_inference_calls`,\n );\n requireNumberRecord(usage.subtree_nb_tokens_by_category, `${path}.subtree_nb_tokens_by_category`);\n requireNumber(usage.subtree_total_tokens, `${path}.subtree_total_tokens`);\n usage.subtree_cost = normalizeCost(usage.subtree_cost, subtreeRatedCalls, `${path}.subtree_cost`);\n usage.subtree_cost_input = normalizeNullableNumber(\n usage.subtree_cost_input,\n `${path}.subtree_cost_input`,\n );\n usage.subtree_cost_output = normalizeNullableNumber(\n usage.subtree_cost_output,\n `${path}.subtree_cost_output`,\n );\n // Absent is tolerated and normalized to `[]` (mirroring the `io` treatment\n // below): a spec produced before per-model attribution existed is legitimately\n // missing it, and an absent list is unambiguous — no per-model data — unlike a\n // malformed one, which is still rejected.\n usage.by_model = normalizeModelUsageList(usage.by_model, `${path}.by_model`);\n usage.subtree_by_model = normalizeModelUsageList(\n usage.subtree_by_model,\n `${path}.subtree_by_model`,\n );\n}\n\n/**\n * Validate a per-model usage list, normalizing an absent one to `[]`.\n *\n * The model names here are displayed as fact (\"this is what ran\"), so a malformed\n * entry must fail loudly rather than render as an empty or partial attribution.\n * Absence is not malformation, though: specs generated before per-model\n * attribution existed simply have no such key.\n */\nfunction normalizeModelUsageList(value: unknown, path: string): unknown[] {\n if (value === undefined) return [];\n if (!Array.isArray(value)) {\n fail(path, `expected an array when present, got ${describe(value)}`);\n }\n value.forEach((entry, index) => {\n const entryPath = `${path}[${index}]`;\n if (!isPlainObject(entry)) {\n fail(entryPath, `expected an object, got ${describe(entry)}`);\n }\n requireNonEmptyString(entry.inference_model_name, `${entryPath}.inference_model_name`);\n requireNonEmptyString(entry.inference_model_id, `${entryPath}.inference_model_id`);\n // Absent on specs predating the field. Normalized to a value that is not \"llm\",\n // so token counts stay hidden rather than being shown on unverified grounds.\n if (entry.model_type === undefined) {\n entry.model_type = \"unknown\";\n } else {\n requireNonEmptyString(entry.model_type, `${entryPath}.model_type`);\n }\n requireNumber(entry.inference_calls, `${entryPath}.inference_calls`);\n const ratedCalls = requireNumber(\n entry.rated_inference_calls,\n `${entryPath}.rated_inference_calls`,\n );\n entry.cost = normalizeCost(entry.cost, ratedCalls, `${entryPath}.cost`);\n });\n return value;\n}\n\nfunction validateNode(node: unknown, path: string): void {\n if (!isPlainObject(node)) {\n fail(path, `expected an object, got ${describe(node)}`);\n }\n\n requireNonEmptyString(node.id, `${path}.id`);\n\n // Every node a real pipelex run serializes is a pipe-call node\n // (`kind` is \"controller\" or \"operator\"). The other `NodeKind` values exist\n // in the enum only for the mermaid renderer and never reach a graphspec.json\n // — a spec carrying one is malformed or wrong-version, so reject it.\n if (node.kind !== \"controller\" && node.kind !== \"operator\") {\n fail(\n `${path}.kind`,\n `expected \"controller\" or \"operator\" — a real pipelex run emits only ` +\n `pipe-call nodes, got ${JSON.stringify(node.kind)}`,\n );\n }\n\n if (typeof node.status !== \"string\" || !PIPE_STATUSES.has(node.status)) {\n fail(\n `${path}.status`,\n `expected one of ${[...PIPE_STATUSES].join(\", \")}, got ${JSON.stringify(node.status)}`,\n );\n }\n\n requireNonEmptyString(node.pipe_code, `${path}.pipe_code`);\n const pipeType = requireNonEmptyString(node.pipe_type, `${path}.pipe_type`);\n if (!KNOWN_PIPE_TYPES.has(pipeType)) {\n fail(\n `${path}.pipe_type`,\n `unrecognized pipe class \"${pipeType}\" — add it to PipeOperatorType ` +\n `or PipeControllerType in types.ts`,\n );\n }\n requireNonEmptyString(node.description, `${path}.description`);\n requireNonEmptyString(node.domain_code, `${path}.domain_code`);\n\n // `io` is always emitted by pipelex; tolerate an absent key (the pipelex\n // model defaults it) by normalizing to an empty shape.\n let io = node.io;\n if (io === undefined) {\n io = { inputs: [], outputs: [] };\n node.io = io;\n }\n if (!isPlainObject(io)) {\n fail(`${path}.io`, `expected an object, got ${describe(io)}`);\n }\n if (io.inputs === undefined) {\n io.inputs = [];\n } else if (!Array.isArray(io.inputs)) {\n fail(`${path}.io.inputs`, `expected an array, got ${describe(io.inputs)}`);\n }\n if (io.outputs === undefined) {\n io.outputs = [];\n } else if (!Array.isArray(io.outputs)) {\n fail(`${path}.io.outputs`, `expected an array, got ${describe(io.outputs)}`);\n }\n (io.inputs as unknown[]).forEach((item, j) => validateIoItem(item, `${path}.io.inputs[${j}]`));\n (io.outputs as unknown[]).forEach((item, j) => validateIoItem(item, `${path}.io.outputs[${j}]`));\n\n // `usage` is legitimately ABSENT OR NULL: pydantic serializes `usage=None` as an\n // explicit `\"usage\": null` rather than omitting the key, and that is the normal\n // shape for a run that collected no usage. Both mean the same thing, so null is\n // normalized away here and downstream code only ever sees an object or undefined.\n if (node.usage === null) {\n delete node.usage;\n } else if (node.usage !== undefined) {\n validateUsage(node.usage, `${path}.usage`);\n }\n}\n\nfunction validateEdge(edge: unknown, path: string): void {\n if (!isPlainObject(edge)) {\n fail(path, `expected an object, got ${describe(edge)}`);\n }\n requireNonEmptyString(edge.id, `${path}.id`);\n requireNonEmptyString(edge.source, `${path}.source`);\n requireNonEmptyString(edge.target, `${path}.target`);\n if (typeof edge.kind !== \"string\" || !EDGE_KINDS.has(edge.kind)) {\n fail(\n `${path}.kind`,\n `expected one of ${[...EDGE_KINDS].join(\", \")}, got ${JSON.stringify(edge.kind)}`,\n );\n }\n}\n\n/**\n * Validate a raw, untyped value as a `GraphSpec`. Throws\n * `GraphSpecValidationError` on the first violation.\n *\n * **Mutates the input in place:** on success it returns the *same* object\n * (typed as `GraphSpec`), with its normalizations written directly onto the\n * passed-in object: where a node has no `io` key it writes\n * `io = { inputs: [], outputs: [] }` (and fills absent `io.inputs` /\n * `io.outputs` arrays), and an absent unrated cost is written as `null`, so\n * code downstream never meets `undefined` where the types promise `null`. Pass a fresh\n * parse result (e.g. straight from `JSON.parse`) — do not pass a frozen or\n * externally shared object.\n */\nexport function validateGraphSpec(raw: unknown): GraphSpec {\n if (!isPlainObject(raw)) {\n fail(\"\", `expected a GraphSpec object, got ${describe(raw)}`);\n }\n\n if (!Array.isArray(raw.nodes)) {\n fail(\"nodes\", `expected an array, got ${describe(raw.nodes)}`);\n }\n if (!Array.isArray(raw.edges)) {\n fail(\"edges\", `expected an array, got ${describe(raw.edges)}`);\n }\n\n if (!isPlainObject(raw.meta)) {\n fail(\"meta\", `expected an object, got ${describe(raw.meta)}`);\n }\n if (raw.meta.format !== \"mthds\") {\n fail(\n \"meta.format\",\n `expected \"mthds\" (this does not look like pipelex GraphSpec JSON), ` +\n `got ${JSON.stringify(raw.meta.format)}`,\n );\n }\n if (\n raw.meta.mode !== undefined &&\n (typeof raw.meta.mode !== \"string\" || !GRAPH_SPEC_MODES.has(raw.meta.mode))\n ) {\n fail(\n \"meta.mode\",\n `expected one of ${[...GRAPH_SPEC_MODES].join(\", \")} when present, ` +\n `got ${JSON.stringify(raw.meta.mode)}`,\n );\n }\n\n // `pipe_registry` / `concept_registry` are gated by the pipelex\n // `data_inclusion` flag — legitimately absent, and minimally `{}`.\n if (raw.pipe_registry !== undefined && !isPlainObject(raw.pipe_registry)) {\n fail(\"pipe_registry\", `expected an object when present, got ${describe(raw.pipe_registry)}`);\n }\n if (raw.concept_registry !== undefined && !isPlainObject(raw.concept_registry)) {\n fail(\n \"concept_registry\",\n `expected an object when present, got ${describe(raw.concept_registry)}`,\n );\n }\n\n // Same all-or-nothing rule as the node field, and the same null-vs-absent point:\n // pydantic emits `\"usage\": null` for a run that collected none.\n if (raw.usage === null) {\n delete raw.usage;\n } else if (raw.usage !== undefined) {\n if (!isPlainObject(raw.usage)) {\n fail(\"usage\", `expected an object when present, got ${describe(raw.usage)}`);\n }\n validateUsage(raw.usage.total, \"usage.total\");\n validateUsage(raw.usage.unattributed, \"usage.unattributed\");\n }\n\n raw.nodes.forEach((node, i) => validateNode(node, `nodes[${i}]`));\n raw.edges.forEach((edge, i) => validateEdge(edge, `edges[${i}]`));\n\n return raw as unknown as GraphSpec;\n}\n\n/**\n * Narrow a `GraphSpecNode` to a `PipeCallNode` at an internal trust boundary,\n * throwing `GraphSpecValidationError` when the node is not a well-formed\n * pipe-call node.\n *\n * Graph-topology analysis (`buildGraph` and friends) identifies a node as a\n * pipe by its edges, not by re-checking `kind`/`pipe_code`. When the spec has\n * been through `validateGraphSpec` this always holds — but library consumers\n * may call `buildGraph` directly. This guard turns that gap into a loud,\n * greppable failure instead of a bare `TypeError` on a missing `pipe_code`.\n */\nexport function asPipeCallNode(node: GraphSpecNode, path = \"node\"): PipeCallNode {\n if (node.kind !== \"controller\" && node.kind !== \"operator\") {\n fail(\n `${path}.kind`,\n `expected a pipe-call node (\"controller\" or \"operator\"), ` +\n `got ${JSON.stringify(node.kind)}`,\n );\n }\n requireNonEmptyString(node.pipe_code, `${path}.pipe_code`);\n return node as PipeCallNode;\n}\n","import type {\n GraphSpec,\n DataflowAnalysis,\n PipeBlueprintUnion,\n ConceptInfo,\n StuffRegistryEntry,\n} from \"./types\";\n\nexport function buildDataflowAnalysis(graphspec: GraphSpec | null): DataflowAnalysis | null {\n if (!graphspec) return null;\n\n const stuffRegistry: Record<string, StuffRegistryEntry> = {};\n const stuffProducers: Record<string, string> = {};\n const stuffConsumers: Record<string, string[]> = {};\n const containmentTree: Record<string, string[]> = {};\n const childNodeIds = new Set<string>();\n\n // Build containment tree from edges\n for (const edge of graphspec.edges) {\n if (edge.kind === \"contains\") {\n if (!containmentTree[edge.source]) containmentTree[edge.source] = [];\n containmentTree[edge.source].push(edge.target);\n childNodeIds.add(edge.target);\n }\n }\n\n // Controller IDs are nodes that have children\n const controllerNodeIds = new Set<string>(Object.keys(containmentTree));\n\n // Register stuffs from all nodes; track producers/consumers from operators only\n for (const node of graphspec.nodes) {\n const nodeIo = node.io;\n const isController = controllerNodeIds.has(node.id);\n\n // Register outputs\n for (const output of nodeIo.outputs) {\n if (output.digest && !stuffRegistry[output.digest]) {\n stuffRegistry[output.digest] = {\n name: output.name,\n concept: output.concept,\n multiplicity: output.multiplicity,\n contentType: output.content_type,\n };\n }\n if (output.digest && !isController) {\n stuffProducers[output.digest] = node.id;\n }\n }\n\n // Register inputs\n for (const input of nodeIo.inputs) {\n if (input.digest && !stuffRegistry[input.digest]) {\n stuffRegistry[input.digest] = {\n name: input.name,\n concept: input.concept,\n multiplicity: input.multiplicity,\n contentType: input.content_type,\n };\n }\n if (input.digest && !isController) {\n if (!stuffConsumers[input.digest]) stuffConsumers[input.digest] = [];\n stuffConsumers[input.digest].push(node.id);\n }\n }\n }\n\n return {\n stuffRegistry,\n stuffProducers,\n stuffConsumers,\n controllerNodeIds,\n childNodeIds,\n containmentTree,\n };\n}\n\n/**\n * Build a map from node id -> controller id for all nodes that belong to a controller.\n * Includes both direct children (operators) and stuff nodes assigned to controllers.\n *\n * Stuff nodes are placed at the lowest controller level where they connect producers\n * to consumers. A stuff node produced inside controller C is promoted to C's parent\n * if none of its consumers are inside C (output flows outward).\n */\nexport function buildChildToControllerMap(\n graphspec: GraphSpec,\n analysis: DataflowAnalysis,\n): Record<string, string> {\n const childToController: Record<string, string> = {};\n\n // Direct children from containment tree\n for (const [ctrlId, children] of Object.entries(analysis.containmentTree)) {\n for (const childId of children) {\n childToController[childId] = ctrlId;\n }\n }\n\n // Stuff nodes produced by operators inside controllers\n for (const [digest, producerId] of Object.entries(analysis.stuffProducers)) {\n const stuffId = \"stuff_\" + digest;\n const ctrlId = childToController[producerId];\n if (ctrlId) {\n childToController[stuffId] = ctrlId;\n }\n }\n\n // Stuff produced by controllers themselves -> assign to parent controller\n for (const node of graphspec.nodes) {\n if (!analysis.controllerNodeIds.has(node.id)) continue;\n const parentCtrlId = childToController[node.id];\n if (!parentCtrlId) continue;\n for (const output of node.io.outputs) {\n if (!output.digest) continue;\n const stuffId = \"stuff_\" + output.digest;\n if (!childToController[stuffId]) {\n childToController[stuffId] = parentCtrlId;\n }\n }\n }\n\n // Batch item stuff (fan-out) -> assign to the PipeBatch controller\n for (const edge of graphspec.edges) {\n if (edge.kind === \"batch_item\" && edge.target_stuff_digest) {\n const stuffId = \"stuff_\" + edge.target_stuff_digest;\n // edge.source is the PipeBatch controller node\n if (analysis.controllerNodeIds.has(edge.source)) {\n childToController[stuffId] = edge.source;\n }\n }\n }\n\n // ─── Promote stuff nodes whose consumers are all outside their controller ──\n // Stuff involved in stuff-to-stuff edges (batch/parallel) should not be promoted\n // when they have no operator consumers — they're intermediate batch/parallel data.\n const stuffInStuffEdges = new Set<string>();\n for (const edge of graphspec.edges) {\n if (\n edge.kind === \"batch_item\" ||\n edge.kind === \"batch_aggregate\" ||\n edge.kind === \"parallel_combine\"\n ) {\n if (edge.source_stuff_digest) stuffInStuffEdges.add(edge.source_stuff_digest);\n if (edge.target_stuff_digest) stuffInStuffEdges.add(edge.target_stuff_digest);\n }\n }\n\n const stuffPrefix = \"stuff_\";\n const stuffEntries = Object.keys(childToController).filter((id) => id.startsWith(stuffPrefix));\n\n for (const stuffId of stuffEntries) {\n const digest = stuffId.slice(stuffPrefix.length);\n let assignedCtrl: string | undefined = childToController[stuffId];\n if (!assignedCtrl) continue;\n\n const consumers = analysis.stuffConsumers[digest] || [];\n\n if (consumers.length === 0) {\n // No operator consumers — promote to root only if this is a pure final output\n // (not involved in batch/parallel stuff-to-stuff edges)\n if (!stuffInStuffEdges.has(digest)) {\n delete childToController[stuffId];\n }\n continue;\n }\n\n // Has consumers — promote until we find a level where at least one consumer is inside\n while (assignedCtrl) {\n const ctrl = assignedCtrl;\n const hasConsumerInside = consumers.some((consumerId) =>\n isDescendantOf(consumerId, ctrl, childToController),\n );\n if (hasConsumerInside) break;\n\n const parentCtrl: string | undefined = childToController[assignedCtrl];\n if (parentCtrl) {\n childToController[stuffId] = parentCtrl;\n assignedCtrl = parentCtrl;\n } else {\n delete childToController[stuffId];\n assignedCtrl = undefined;\n }\n }\n }\n\n return childToController;\n}\n\n/** Check if nodeId is a descendant of ancestorCtrlId in the containment hierarchy. */\nfunction isDescendantOf(\n nodeId: string,\n ancestorCtrlId: string,\n childToController: Record<string, string>,\n): boolean {\n let current = childToController[nodeId];\n while (current) {\n if (current === ancestorCtrlId) return true;\n current = childToController[current];\n }\n return false;\n}\n\n// ─── Registry lookup helpers ───────────────────────────────────────────────\n\nexport function getPipeBlueprint(spec: GraphSpec, pipeRef: string): PipeBlueprintUnion | undefined {\n return spec.pipe_registry?.[pipeRef];\n}\n\nexport function getConceptInfo(spec: GraphSpec, conceptRef: string): ConceptInfo | undefined {\n return spec.concept_registry?.[conceptRef];\n}\n\nexport function resolveConceptRef(spec: GraphSpec, codeOrRef: string): ConceptInfo | undefined {\n if (!spec.concept_registry) return undefined;\n // Direct lookup first (e.g., \"test_domain.Summary\")\n const direct = spec.concept_registry[codeOrRef];\n if (direct) return direct;\n // Search by code (e.g., \"Summary\" matches \"test_domain.Summary\")\n for (const info of Object.values(spec.concept_registry)) {\n if (info.code === codeOrRef) return info;\n }\n return undefined;\n}\n","import type { GraphSpecMode, GraphSpecNodeIoItem, PipeCallNode, PipeCardPayload } from \"./types\";\nimport { multiplicitySuffix } from \"./types\";\n\n/** An io item as a card pill: its name, and its concept with the multiplicity marker (`Document[]`). */\nfunction ioPill(item: GraphSpecNodeIoItem): { name: string; concept: string } {\n return {\n name: item.name,\n concept: item.concept ? item.concept + multiplicitySuffix(item.multiplicity) : \"\",\n };\n}\n\n/**\n * Build a PipeCardPayload from a pipe-call node.\n *\n * `validateGraphSpec` guarantees the pipe-call node's `pipe_code`, `pipe_type`,\n * `description`, `status`, and `io` are present and well-formed, so this\n * function reads them directly with no fallback synthesis.\n */\nexport function buildPipeCardPayload(\n node: PipeCallNode,\n graphMode?: GraphSpecMode,\n): PipeCardPayload {\n const payload: PipeCardPayload = {\n pipeCode: node.pipe_code,\n pipeType: node.pipe_type,\n description: node.description,\n status: node.status,\n inputs: node.io.inputs.map(ioPill),\n outputs: node.io.outputs.map(ioPill),\n };\n if (graphMode !== undefined) payload.graphMode = graphMode;\n if (node.tags !== undefined) payload.tags = node.tags;\n return payload;\n}\n","import type { GraphSpec, DataflowAnalysis, GraphNode, GraphEdge, GraphData } from \"./types\";\nimport {\n ARROW_CLOSED_MARKER,\n NODE_TYPE_PIPE_CARD,\n NODE_TYPE_STUFF,\n graphSpecMode,\n multiplicitySuffix,\n stuffNodeId,\n} from \"./types\";\nimport { buildDataflowAnalysis, buildChildToControllerMap } from \"./graphAnalysis\";\nimport { asPipeCallNode } from \"./validateGraphSpec\";\nimport { buildPipeCardPayload } from \"./pipeCardPayload\";\n\nconst STUFF_CHAR_WIDTH_PX = 7;\nconst STUFF_LABEL_PADDING = 48;\nconst MIN_STUFF_WIDTH = 140;\n\n/**\n * Build dataflow graph from GraphSpec. Creates pipe nodes + stuff (data) nodes +\n * producer/consumer edges. Returns label descriptors (not React elements).\n */\nexport function buildDataflowGraph(\n graphspec: GraphSpec,\n analysis: DataflowAnalysis,\n edgeType: string,\n): GraphData {\n const nodes: GraphNode[] = [];\n const edges: GraphEdge[] = [];\n const graphMode = graphSpecMode(graphspec);\n const combinedStuffDigests = new Set<string>();\n for (const edge of graphspec.edges) {\n if (edge.kind === \"parallel_combine\" && edge.target_stuff_digest) {\n combinedStuffDigests.add(edge.target_stuff_digest);\n }\n }\n\n // Find participating pipes (those that produce or consume data)\n const participatingPipes = new Set<string>();\n for (const producer of Object.values(analysis.stuffProducers)) {\n participatingPipes.add(producer);\n }\n for (const consumers of Object.values(analysis.stuffConsumers)) {\n for (const consumer of consumers) {\n participatingPipes.add(consumer);\n }\n }\n\n // Create pipe nodes (only those that participate in data flow)\n for (const node of graphspec.nodes) {\n if (!participatingPipes.has(node.id)) continue;\n // A participating pipe is always a pipe-call node; this guard turns a\n // malformed spec into a loud, greppable error rather than a bare TypeError.\n const pipeNode = asPipeCallNode(node, `nodes[${node.id}]`);\n\n const isFailed = pipeNode.status === \"failed\";\n const label = pipeNode.pipe_code;\n const pipeCardData = buildPipeCardPayload(pipeNode, graphMode);\n\n nodes.push({\n id: pipeNode.id,\n type: NODE_TYPE_PIPE_CARD,\n data: {\n labelDescriptor: { kind: \"pipe\", label, isFailed },\n nodeData: pipeNode,\n isPipe: true,\n isStuff: false,\n labelText: label,\n pipeCode: pipeCardData.pipeCode,\n pipeType: pipeNode.pipe_type,\n graphMode,\n pipeCardData,\n },\n position: { x: 0, y: 0 },\n });\n }\n\n // Create stuff (data) nodes\n for (const [digest, stuffInfo] of Object.entries(analysis.stuffRegistry)) {\n const stuffId = stuffNodeId(digest);\n const label = stuffInfo.name;\n // The marked ref (`Document[]`), so a list reads as a list on the canvas.\n const concept = stuffInfo.concept\n ? stuffInfo.concept + multiplicitySuffix(stuffInfo.multiplicity)\n : \"\";\n const textWidth =\n Math.max(label.length, concept.length) * STUFF_CHAR_WIDTH_PX + STUFF_LABEL_PADDING;\n const stuffWidth = Math.max(MIN_STUFF_WIDTH, textWidth);\n\n // Classify: input (no producer), output (no consumer), or intermediate\n const isCombined = combinedStuffDigests.has(digest);\n const isInput = !analysis.stuffProducers[digest] && !isCombined;\n const isOutput = !isInput && !isCombined && !analysis.stuffConsumers[digest]?.length;\n const stuffRole = isCombined\n ? (\"combined\" as const)\n : isInput\n ? (\"input\" as const)\n : isOutput\n ? (\"output\" as const)\n : undefined;\n\n const borderColor = isInput\n ? \"var(--color-stuff-input-border, #50FA7B)\"\n : isOutput\n ? \"var(--color-stuff-output-border, #a78bfa)\"\n : isCombined\n ? \"var(--color-parallel-combine)\"\n : \"var(--color-stuff-border)\";\n\n nodes.push({\n id: stuffId,\n type: NODE_TYPE_STUFF,\n data: {\n labelDescriptor: { kind: \"stuff\", label, concept },\n isStuff: true,\n isPipe: false,\n labelText: label,\n stuffRole,\n stuffDigest: digest,\n },\n position: { x: 0, y: 0 },\n style: {\n background: \"var(--color-stuff-bg)\",\n border: `2px solid ${borderColor}`,\n borderRadius: \"999px\",\n padding: \"0\",\n width: stuffWidth + \"px\",\n boxShadow: \"var(--shadow-md)\",\n },\n });\n }\n\n // Create edges: producer -> stuff\n let edgeId = 0;\n for (const [digest, producerNodeId] of Object.entries(analysis.stuffProducers)) {\n const stuffId = stuffNodeId(digest);\n edges.push({\n id: \"edge_\" + edgeId++,\n source: producerNodeId,\n target: stuffId,\n type: edgeType,\n animated: false,\n style: { stroke: \"var(--color-edge)\", strokeWidth: 2 },\n markerEnd: {\n type: ARROW_CLOSED_MARKER,\n color: \"var(--color-edge)\",\n },\n });\n }\n\n // Create edges: stuff -> consumer\n for (const [digest, consumers] of Object.entries(analysis.stuffConsumers)) {\n const stuffId = stuffNodeId(digest);\n for (const consumerNodeId of consumers) {\n edges.push({\n id: \"edge_\" + edgeId++,\n source: stuffId,\n target: consumerNodeId,\n type: edgeType,\n animated: false,\n style: { stroke: \"var(--color-edge)\", strokeWidth: 2 },\n markerEnd: {\n type: ARROW_CLOSED_MARKER,\n color: \"var(--color-edge)\",\n },\n });\n }\n }\n\n // Create PARALLEL_COMBINE edges from GraphSpec\n for (const edge of graphspec.edges) {\n if (edge.kind !== \"parallel_combine\") continue;\n if (!edge.source_stuff_digest || !edge.target_stuff_digest) continue;\n if (\n !analysis.stuffRegistry[edge.source_stuff_digest] ||\n !analysis.stuffRegistry[edge.target_stuff_digest]\n )\n continue;\n const sourceId = stuffNodeId(edge.source_stuff_digest);\n const targetId = stuffNodeId(edge.target_stuff_digest);\n\n edges.push({\n id: edge.id,\n source: sourceId,\n target: targetId,\n type: \"smoothstep\",\n animated: false,\n style: {\n stroke: \"var(--color-parallel-combine)\",\n strokeWidth: 2,\n strokeDasharray: \"5,5\",\n },\n markerEnd: {\n type: ARROW_CLOSED_MARKER,\n color: \"var(--color-parallel-combine)\",\n },\n });\n }\n\n // Create BATCH_ITEM and BATCH_AGGREGATE edges (data-centric mode: stuff -> stuff)\n for (const edge of graphspec.edges) {\n if (edge.kind !== \"batch_item\" && edge.kind !== \"batch_aggregate\") continue;\n\n if (!edge.source_stuff_digest || !edge.target_stuff_digest) continue;\n if (\n !analysis.stuffRegistry[edge.source_stuff_digest] ||\n !analysis.stuffRegistry[edge.target_stuff_digest]\n )\n continue;\n const sourceId = stuffNodeId(edge.source_stuff_digest);\n const targetId = stuffNodeId(edge.target_stuff_digest);\n const isBatchItem = edge.kind === \"batch_item\";\n\n edges.push({\n id: edge.id,\n source: sourceId,\n target: targetId,\n type: edgeType,\n animated: false,\n _batchEdge: true,\n label: edge.label || \"\",\n labelStyle: {\n fontSize: \"10px\",\n fontFamily: \"var(--font-mono)\",\n fill: isBatchItem ? \"var(--color-batch-item)\" : \"var(--color-batch-aggregate)\",\n },\n labelBgStyle: { fill: \"var(--color-bg)\", fillOpacity: 0.9 },\n style: {\n stroke: isBatchItem ? \"var(--color-batch-item)\" : \"var(--color-batch-aggregate)\",\n strokeWidth: 2,\n strokeDasharray: \"5,5\",\n },\n markerEnd: {\n type: ARROW_CLOSED_MARKER,\n color: isBatchItem ? \"var(--color-batch-item)\" : \"var(--color-batch-aggregate)\",\n },\n });\n }\n\n // Mark edges that cross between different sibling controller groups\n const childToCtrl = buildChildToControllerMap(graphspec, analysis);\n // and assign per-class edge types for better routing\n for (const edge of edges) {\n const srcCtrl = childToCtrl[edge.source] || null;\n const tgtCtrl = childToCtrl[edge.target] || null;\n if (srcCtrl && tgtCtrl && srcCtrl !== tgtCtrl) {\n edge._crossGroup = true;\n // Keep bezier for long-distance cross-group edges (natural curves look better)\n // but visually de-emphasize to reduce spaghetti effect\n edge.style = {\n ...edge.style,\n strokeWidth: 1.5,\n opacity: 0.65,\n };\n }\n }\n\n // Batch edges: keep bezier but visually differentiate\n for (const edge of edges) {\n if (edge._batchEdge) {\n edge.style = {\n ...edge.style,\n opacity: 0.7,\n };\n }\n }\n\n return { nodes, edges };\n}\n\n/**\n * Build graph from GraphSpec using dataflow mode.\n * Returns the built graph data and analysis.\n */\nexport function buildGraph(\n graphspec: GraphSpec | null,\n edgeType: string,\n): { graphData: GraphData; analysis: DataflowAnalysis | null } {\n if (graphspec) {\n const analysis = buildDataflowAnalysis(graphspec);\n if (\n analysis &&\n (Object.keys(analysis.stuffProducers).length > 0 ||\n Object.keys(analysis.stuffConsumers).length > 0)\n ) {\n return { graphData: buildDataflowGraph(graphspec, analysis, edgeType), analysis };\n }\n }\n return { graphData: { nodes: [], edges: [] }, analysis: null };\n}\n","import type {\n DataflowAnalysis,\n FoldToggleOptions,\n GraphData,\n GraphEdge,\n GraphNode,\n GraphSpec,\n GraphSpecNode,\n} from \"./types\";\nimport {\n ARROW_CLOSED_MARKER,\n NODE_TYPE_PIPE_CARD,\n graphSpecMode,\n isStuffNodeId,\n stuffDigestFromId,\n} from \"./types\";\nimport { buildChildToControllerMap } from \"./graphAnalysis\";\nimport { asPipeCallNode } from \"./validateGraphSpec\";\nimport { buildPipeCardPayload } from \"./pipeCardPayload\";\n\n/**\n * Find every controller that shares the same `pipe_code` as `controllerId` —\n * the \"cousins\" of the clicked controller (other instances of the same pipe,\n * possibly living in different branches of the graph).\n *\n * The result always includes `controllerId` itself. If the controller has no\n * `pipe_code` or no cousins exist, returns a singleton set.\n *\n * Used by GraphViewer to mirror fold/expand actions across all instances of a\n * pipe — the default behavior — while alt/option-click bypasses cousin lookup\n * and toggles only the clicked controller.\n */\nexport function findCousinControllers(\n controllerId: string,\n graphspec: GraphSpec,\n controllerNodeIds: ReadonlySet<string>,\n): Set<string> {\n const result = new Set<string>([controllerId]);\n const clicked = graphspec.nodes.find((n) => n.id === controllerId);\n const pipeCode = clicked?.pipe_code;\n if (!pipeCode) return result;\n for (const node of graphspec.nodes) {\n if (node.pipe_code !== pipeCode) continue;\n if (!controllerNodeIds.has(node.id)) continue;\n result.add(node.id);\n }\n return result;\n}\n\n/**\n * Walk the containment chain from `nodeId` upward, returning the ordered list of\n * ancestor controller IDs from immediate parent → root.\n */\nexport function buildContainmentChain(\n nodeId: string,\n childToCtrl: Readonly<Record<string, string>>,\n): string[] {\n const chain: string[] = [];\n let current: string | undefined = childToCtrl[nodeId];\n const seen = new Set<string>();\n while (current && !seen.has(current)) {\n chain.push(current);\n seen.add(current);\n current = childToCtrl[current];\n }\n return chain;\n}\n\n/**\n * Find the **outermost** (closest to root) ancestor of `nodeId` whose ID is in\n * `foldedSet`. Returns `null` if no ancestor is folded.\n */\nexport function outermostFoldedAncestor(\n nodeId: string,\n childToCtrl: Readonly<Record<string, string>>,\n foldedSet: ReadonlySet<string>,\n): string | null {\n const chain = buildContainmentChain(nodeId, childToCtrl);\n let outermost: string | null = null;\n for (const ancestorId of chain) {\n if (foldedSet.has(ancestorId)) outermost = ancestorId;\n }\n return outermost;\n}\n\n/**\n * Effective ID after folding: returns the outermost folded ancestor if one\n * exists; otherwise the node itself.\n */\nfunction effectiveId(\n nodeId: string,\n childToCtrl: Readonly<Record<string, string>>,\n foldedSet: ReadonlySet<string>,\n): string {\n return outermostFoldedAncestor(nodeId, childToCtrl, foldedSet) ?? nodeId;\n}\n\nfunction findSpecNode(graphspec: GraphSpec, id: string): GraphSpecNode | undefined {\n return graphspec.nodes.find((n) => n.id === id);\n}\n\n/**\n * Apply the fold transformation to a dataflow graph.\n *\n * For each controller in `foldedSet` that is not itself inside another folded\n * controller (outermost-wins): emit a single `pipe-card` node carrying the\n * controller's payload, and rewrite/dedup edges so the controller card replaces\n * its hidden descendants.\n *\n * The function is pure — inputs are not mutated; a fresh `{ nodes, edges,\n * analysis }` is returned.\n */\nexport function applyFolds(\n graphData: GraphData,\n analysis: DataflowAnalysis,\n graphspec: GraphSpec,\n foldedSet: ReadonlySet<string>,\n onToggleFold?: (controllerId: string, options?: FoldToggleOptions) => void,\n): { nodes: GraphNode[]; edges: GraphEdge[]; analysis: DataflowAnalysis } {\n if (foldedSet.size === 0) {\n return { nodes: graphData.nodes, edges: graphData.edges, analysis };\n }\n\n const childToCtrl = buildChildToControllerMap(graphspec, analysis);\n const graphMode = graphSpecMode(graphspec);\n\n // ─── Promote declared-output stuffs out of folded controllers ───────────\n // A folded controller's pipe-card represents the controller as a whole, and\n // its declared outputs are external data flowing out of it. If a stuff node\n // currently lives inside a folded controller that declares it as an output,\n // moving the stuff outside lets the folded card connect to it just like\n // before the fold. Without this, the stuff would be hidden alongside the\n // controller's internals, and the output edge would collapse to a self-loop.\n const outputDeclarers: Map<string, Set<string>> = new Map();\n for (const controllerId of foldedSet) {\n const ctrlNode = findSpecNode(graphspec, controllerId);\n const outputs = ctrlNode?.io?.outputs;\n if (!outputs) continue;\n for (const output of outputs) {\n if (!output.digest) continue;\n let set = outputDeclarers.get(output.digest);\n if (!set) {\n set = new Set();\n outputDeclarers.set(output.digest, set);\n }\n set.add(controllerId);\n }\n }\n\n if (outputDeclarers.size > 0) {\n for (const node of graphData.nodes) {\n if (!isStuffNodeId(node.id)) continue;\n const declarers = outputDeclarers.get(stuffDigestFromId(node.id));\n if (!declarers) continue;\n\n // Walk the chain to find the outermost folded ancestor that declares this\n // stuff as one of its outputs. Reparenting to that ancestor's parent\n // (which may itself be folded or root) ensures the stuff escapes the fold.\n let current: string | undefined = childToCtrl[node.id];\n let outermostDeclarer: string | null = null;\n const seen = new Set<string>();\n while (current && !seen.has(current)) {\n seen.add(current);\n if (declarers.has(current)) outermostDeclarer = current;\n current = childToCtrl[current];\n }\n if (!outermostDeclarer) continue;\n\n const newParent = childToCtrl[outermostDeclarer];\n if (newParent) {\n childToCtrl[node.id] = newParent;\n } else {\n delete childToCtrl[node.id];\n }\n }\n }\n\n // ─── Filter visible nodes ───────────────────────────────────────────────\n // Drop any node whose outermost folded ancestor is non-null (it's hidden\n // inside a folded controller).\n const visibleNodes: GraphNode[] = [];\n for (const node of graphData.nodes) {\n if (outermostFoldedAncestor(node.id, childToCtrl, foldedSet)) continue;\n visibleNodes.push(node);\n }\n\n // ─── Emit pipe-card nodes for outermost-folded controllers ──────────────\n for (const folded of foldedSet) {\n // Skip if this folded controller is itself inside another folded ancestor.\n if (outermostFoldedAncestor(folded, childToCtrl, foldedSet)) continue;\n const specNode = findSpecNode(graphspec, folded);\n if (!specNode) continue; // unknown ID — silently ignore\n\n // A folded controller is a pipe-call node; guard the narrowing so a\n // malformed spec fails loudly instead of producing an undefined pipeCode.\n const payload = buildPipeCardPayload(asPipeCallNode(specNode, folded), graphMode);\n if (onToggleFold) {\n payload.onExpand = (options?: FoldToggleOptions) => onToggleFold(folded, options);\n }\n\n const cardNode: GraphNode = {\n id: folded,\n type: NODE_TYPE_PIPE_CARD,\n data: {\n labelDescriptor: {\n kind: \"pipe\",\n label: payload.pipeCode,\n isFailed: payload.status === \"failed\",\n },\n nodeData: specNode,\n isPipe: false,\n isStuff: false,\n isController: true,\n labelText: payload.pipeCode,\n pipeCode: payload.pipeCode,\n pipeType: specNode.pipe_type,\n graphMode,\n pipeCardData: payload,\n },\n position: { x: 0, y: 0 },\n };\n visibleNodes.push(cardNode);\n }\n\n // ─── Build updated analysis ─────────────────────────────────────────────\n // Drop folded controllers and any controller that lives inside a folded\n // outermost ancestor.\n const updatedControllerIds = new Set<string>();\n for (const ctrlId of analysis.controllerNodeIds) {\n if (foldedSet.has(ctrlId)) continue;\n if (outermostFoldedAncestor(ctrlId, childToCtrl, foldedSet)) continue;\n updatedControllerIds.add(ctrlId);\n }\n\n // containmentTree: only keep entries for surviving controllers; filter their\n // children to drop hidden ones (children whose outermost folded ancestor is\n // a different controller). Children that are the folded controllers themselves\n // should remain as children (they now render as pipe-card leaves).\n const updatedContainmentTree: Record<string, string[]> = {};\n for (const ctrlId of updatedControllerIds) {\n const originalChildren = analysis.containmentTree[ctrlId] ?? [];\n const survivors: string[] = [];\n for (const childId of originalChildren) {\n const outer = outermostFoldedAncestor(childId, childToCtrl, foldedSet);\n // If the child has a folded outermost ancestor that is NOT itself, drop.\n // If the child IS the folded outermost (childId is in foldedSet), keep —\n // it will appear as a pipe-card child of this controller.\n if (outer && outer !== childId) continue;\n survivors.push(childId);\n }\n updatedContainmentTree[ctrlId] = survivors;\n }\n\n // childNodeIds: rebuild from the updated containment tree.\n const updatedChildNodeIds = new Set<string>();\n for (const children of Object.values(updatedContainmentTree)) {\n for (const child of children) updatedChildNodeIds.add(child);\n }\n\n // Rewrite stuffProducers/stuffConsumers so any reference to an operator hidden\n // by a fold is replaced with its outermost folded ancestor — mirroring the\n // edge-endpoint rewrite below. Without this, buildChildToControllerMap's\n // promotion loop loses the consumer/producer trail and stuff nodes get\n // ejected to the root level when their parent controller's sibling is folded.\n const updatedStuffProducers: Record<string, string> = {};\n for (const [digest, producerId] of Object.entries(analysis.stuffProducers)) {\n updatedStuffProducers[digest] = effectiveId(producerId, childToCtrl, foldedSet);\n }\n\n const updatedStuffConsumers: Record<string, string[]> = {};\n for (const [digest, consumers] of Object.entries(analysis.stuffConsumers)) {\n const seen = new Set<string>();\n for (const consumerId of consumers) {\n seen.add(effectiveId(consumerId, childToCtrl, foldedSet));\n }\n updatedStuffConsumers[digest] = [...seen];\n }\n\n const updatedAnalysis: DataflowAnalysis = {\n stuffRegistry: analysis.stuffRegistry,\n stuffProducers: updatedStuffProducers,\n stuffConsumers: updatedStuffConsumers,\n controllerNodeIds: updatedControllerIds,\n childNodeIds: updatedChildNodeIds,\n containmentTree: updatedContainmentTree,\n };\n\n // ─── Rewrite edges ──────────────────────────────────────────────────────\n // Each surviving endpoint is replaced by its effective (outermost-folded)\n // ancestor or itself. Drop self-loops. Dedup by (newSrc, newDst, bucket).\n const dedupMap = new Map<string, GraphEdge>();\n for (const edge of graphData.edges) {\n const newSrc = effectiveId(edge.source, childToCtrl, foldedSet);\n const newDst = effectiveId(edge.target, childToCtrl, foldedSet);\n if (newSrc === newDst) continue;\n const bucket = edge._batchEdge ? \"batch\" : \"data\";\n const key = `${newSrc}->${newDst}|${bucket}`;\n if (dedupMap.has(key)) continue;\n // Clone the edge with rewritten endpoints; drop the stale _crossGroup flag\n // (recomputed below against folded containment).\n const cloned: GraphEdge = {\n ...edge,\n source: newSrc,\n target: newDst,\n id: edge.id,\n };\n // Batch edges carry per-item indices like \"[0]\", \"[1]\" in their labels.\n // Once a fold collapses many of these into a single edge (or hides the\n // per-item target), the surviving index is misleading — generalize to \"[N]\".\n if (edge._batchEdge && (newSrc !== edge.source || newDst !== edge.target)) {\n cloned.label = \"[N]\";\n }\n delete cloned._crossGroup;\n dedupMap.set(key, cloned);\n }\n\n // Recompute _crossGroup against the folded containment. Build a fresh\n // childToCtrl from the updated analysis so the classification reflects the\n // post-fold node graph (folded controllers no longer have children).\n const foldedChildToCtrl = buildChildToControllerMap(\n {\n ...graphspec,\n // Mask out the contains edges for folded outermost controllers — they no\n // longer logically contain anything after folding.\n edges: graphspec.edges.filter((e) => {\n if (e.kind !== \"contains\") return true;\n return updatedControllerIds.has(e.source);\n }),\n },\n updatedAnalysis,\n );\n\n const rewrittenEdges: GraphEdge[] = [];\n for (const edge of dedupMap.values()) {\n const srcCtrl = foldedChildToCtrl[edge.source] || null;\n const tgtCtrl = foldedChildToCtrl[edge.target] || null;\n if (srcCtrl && tgtCtrl && srcCtrl !== tgtCtrl) {\n edge._crossGroup = true;\n edge.style = {\n ...edge.style,\n strokeWidth: 1.5,\n opacity: 0.65,\n };\n } else if (edge.style && (edge.style.opacity === 0.65 || edge.style.strokeWidth === 1.5)) {\n // Edge no longer crosses sibling groups — reset the de-emphasized style.\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { opacity: _opacity, strokeWidth: _strokeWidth, ...rest } = edge.style;\n edge.style = { ...rest, strokeWidth: 2 };\n if (!edge.markerEnd) {\n edge.markerEnd = { type: ARROW_CLOSED_MARKER, color: \"var(--color-edge)\" };\n }\n }\n rewrittenEdges.push(edge);\n }\n\n return { nodes: visibleNodes, edges: rewrittenEdges, analysis: updatedAnalysis };\n}\n","// Validation decorations — project targeted ValidationIssues onto rendered nodes.\n//\n// Pure module (no React): GraphViewer derives a per-node decoration map from\n// the same `validationIssues` prop that feeds the validation panel, then stamps\n// it onto node data. Node components render the ring + badge from that stamp.\n\nimport type { GraphNodeData, GraphSpec, NodeValidationSummary, ValidationIssue } from \"./types\";\nimport { outermostFoldedAncestor } from \"./graphFolds\";\nimport { makePipeRef } from \"./pipeRefs\";\n\n/**\n * Resolve which GraphSpec node ids an issue targets:\n * - `nodeId` → that precise invocation (wins over `pipeRef` when both are set);\n * - `pipeRef` → every spec node invoking that exact `domain_code.pipe_code`\n * pipe (a pipe can appear in several places in the graph). The match is on\n * the qualified ref — never on the bare code — so two domains declaring the\n * same pipe code can never cross-decorate. A node missing either identity\n * field cannot be qualified and is never matched;\n * - neither → no targets (the issue stays panel-only).\n */\nfunction issueTargetIds(issue: ValidationIssue, graphspec: GraphSpec): string[] {\n if (issue.nodeId) return [issue.nodeId];\n if (issue.pipeRef) {\n return graphspec.nodes\n .filter(\n (n) =>\n n.domain_code !== undefined &&\n n.pipe_code !== undefined &&\n makePipeRef(n.domain_code, n.pipe_code) === issue.pipeRef,\n )\n .map((n) => n.id);\n }\n return [];\n}\n\n/**\n * Build the per-node decoration map for the current fold state.\n *\n * Each issue's target ids are remapped through the fold containment\n * (`outermostFoldedAncestor`): an issue on a node hidden inside a folded\n * controller decorates the folded controller's card instead, so folding never\n * hides an error. Targets that don't resolve to a rendered node (e.g. a\n * diagnostic about a pipe that was skipped during the static walk) simply\n * produce no decoration — those issues stay panel-only.\n *\n * Counts are per issue × target invocation: a folded controller containing two\n * invocations of a broken pipe shows 2, matching the sum of the badges that\n * become visible when it is expanded.\n */\nexport function buildValidationDecorations(\n issues: readonly ValidationIssue[] | undefined,\n graphspec: GraphSpec | null,\n childToCtrl: Readonly<Record<string, string>>,\n foldedSet: ReadonlySet<string>,\n): Map<string, NodeValidationSummary> {\n const decorations = new Map<string, NodeValidationSummary>();\n if (!issues || issues.length === 0 || !graphspec) return decorations;\n\n for (const issue of issues) {\n for (const targetId of issueTargetIds(issue, graphspec)) {\n const visibleId = outermostFoldedAncestor(targetId, childToCtrl, foldedSet) ?? targetId;\n const existing = decorations.get(visibleId);\n const lines = [issue.message, ...(issue.suggestedFix ? [`Fix: ${issue.suggestedFix}`] : [])];\n if (existing) {\n if (issue.severity === \"error\") existing.severity = \"error\";\n existing.count += 1;\n existing.lines.push(...lines);\n } else {\n decorations.set(visibleId, { severity: issue.severity, count: 1, lines });\n }\n }\n }\n return decorations;\n}\n\n/**\n * Resolve the rendered node a panel row should navigate to: the issue's first\n * target, remapped through the fold containment, and only if that id is\n * actually rendered. `null` for panel-only issues (no target, or the target\n * never became a node).\n */\nexport function resolveIssueTargetNodeId(\n issue: ValidationIssue,\n graphspec: GraphSpec | null,\n childToCtrl: Readonly<Record<string, string>>,\n foldedSet: ReadonlySet<string>,\n renderedNodeIds: ReadonlySet<string>,\n): string | null {\n if (!graphspec) return null;\n for (const targetId of issueTargetIds(issue, graphspec)) {\n const visibleId = outermostFoldedAncestor(targetId, childToCtrl, foldedSet) ?? targetId;\n if (renderedNodeIds.has(visibleId)) return visibleId;\n }\n return null;\n}\n\n/**\n * Stamp the decoration map onto rendered nodes (and their pipe-card payloads).\n * Nodes whose decoration is unchanged are returned as-is; a node whose issues\n * disappeared gets its stamp cleared, so verdict flips are fully reactive.\n * `onBadgeClick` (when provided) rides along on decorated nodes only — the\n * badge renders as a button that opens the validation panel.\n */\nexport function applyValidationDecorations<T extends { id: string; data: GraphNodeData }>(\n nodes: T[],\n decorations: ReadonlyMap<string, NodeValidationSummary>,\n onBadgeClick?: () => void,\n): T[] {\n return nodes.map((node) => {\n const decoration = decorations.get(node.id);\n if (!decoration && !node.data.validation && !node.data.pipeCardData?.validation) return node;\n const badgeClick = decoration ? onBadgeClick : undefined;\n return {\n ...node,\n data: {\n ...node.data,\n validation: decoration,\n onValidationBadgeClick: badgeClick,\n pipeCardData: node.data.pipeCardData\n ? {\n ...node.data.pipeCardData,\n validation: decoration,\n onValidationBadgeClick: badgeClick,\n }\n : node.data.pipeCardData,\n },\n };\n });\n}\n","import { makePipeRef } from \"./pipeRefs\";\nimport type { GraphSpec, GraphSpecNode, GraphSpecNodeIoItem } from \"./types\";\n\n/**\n * Where a data item lives in a `GraphSpec`, and which pipe put it there.\n *\n * The producing pipe is the half that is not obvious and the half that matters:\n * a stuff carries a concept, but the artifacts that describe how to RENDER it —\n * `output_form` and the output half of `pipe_io_contracts` — are keyed by\n * `pipe_ref`, not by concept. So a panel that wants to show a result as the\n * standard describes it has to walk from the data back to the pipe that\n * resolved to it, and this is that walk, done once at the boundary rather than\n * re-derived by every consumer.\n */\nexport interface StuffLocation {\n /** The item as the spec holds it, richest copy first (see below). */\n item: GraphSpecNodeIoItem;\n /**\n * `domain.code` of the pipe whose OUTPUT this is, when the spec names one.\n *\n * Absent for a pipeline-level input, which no pipe produced, and for a node\n * missing either half of the ref. A consumer must treat it as optional: a\n * method's own inputs are stuff too, and they are the common case at the top\n * of every graph.\n */\n producerPipeRef?: string;\n /**\n * The first pipe that CONSUMES it, and the slot it arrives in.\n *\n * The fallback identity for a method's own inputs, which no pipe produced and\n * which therefore no `output_form` describes. What does describe them is the\n * consuming pipe's `input_form` entry for that slot — the same field, seen\n * from the other side — so a renderer that holds the input artifacts can show\n * a method input as something better than a JSON dump.\n *\n * First rather than all, deliberately: several pipes may read the same stuff,\n * and every one of them describes it identically, because they are describing\n * the concept it carries. A list here would be a list of the same answer.\n */\n consumer?: { pipeRef: string; slotName: string };\n}\n\n/**\n * `domain.code`, or nothing when the node does not carry both halves.\n *\n * Assembled with `makePipeRef` rather than a template literal so every consumer\n * agrees with the runtime on what a ref is — the domain path may be\n * multi-segment, and this repo has exactly one place that spelling lives.\n */\nexport function pipeRefOf(node: GraphSpecNode): string | undefined {\n if (!node.pipe_code || !node.domain_code) return undefined;\n return makePipeRef(node.domain_code, node.pipe_code);\n}\n\n/**\n * Find a data item by digest, preferring the pipe that PRODUCED it.\n *\n * Two passes, and the order is the point rather than an optimization. The same\n * digest appears on the producer's `outputs` and again on every consumer's\n * `inputs`, and only the producer's copy is guaranteed to carry the payload —\n * a consumer's may be a reference with `data` elided. Taking the first match in\n * spec order would therefore hand back an emptier copy of the same stuff\n * depending on how the nodes happened to be sorted.\n *\n * The second pass exists for the items no pipe produced: a method's declared\n * inputs appear only as some pipe's `inputs`, so a digest-first walk that\n * searched outputs alone would report the top of every graph as missing.\n */\nexport function findStuffByDigest(spec: GraphSpec, digest: string): StuffLocation | null {\n const consumer = findConsumer(spec, digest);\n for (const node of spec.nodes) {\n for (const output of node.io?.outputs ?? []) {\n if (output.digest === digest) {\n const producerPipeRef = pipeRefOf(node);\n return {\n item: output,\n ...(producerPipeRef ? { producerPipeRef } : {}),\n ...(consumer ? { consumer } : {}),\n };\n }\n }\n }\n for (const node of spec.nodes) {\n for (const input of node.io?.inputs ?? []) {\n if (input.digest === digest) return { item: input, ...(consumer ? { consumer } : {}) };\n }\n }\n return null;\n}\n\n/** The first pipe reading this digest, and the slot name it reads it as. */\nfunction findConsumer(\n spec: GraphSpec,\n digest: string,\n): { pipeRef: string; slotName: string } | undefined {\n for (const node of spec.nodes) {\n const pipeRef = pipeRefOf(node);\n if (!pipeRef) continue;\n for (const input of node.io?.inputs ?? []) {\n if (input.digest === digest) return { pipeRef, slotName: input.name };\n }\n }\n return undefined;\n}\n","import type { ElkNode, ElkPort, ElkExtendedEdge, LayoutOptions } from \"elkjs/lib/elk-api\";\nimport type {\n GraphNode,\n GraphEdge,\n GraphSpec,\n DataflowAnalysis,\n LayoutConfig,\n GraphDirection,\n} from \"./types\";\nimport {\n NODE_TYPE_PIPE_CARD,\n CONTROLLER_PADDING_X,\n CONTROLLER_PADDING_TOP,\n CONTROLLER_PADDING_BOTTOM,\n} from \"./types\";\nimport { buildChildToControllerMap } from \"./graphAnalysis\";\n\n// ─── Direction mapping ──────────────────────────────────────────────────────\n\nfunction elkDirection(direction: GraphDirection): string {\n switch (direction) {\n case \"LR\":\n return \"RIGHT\";\n case \"RL\":\n return \"LEFT\";\n case \"BT\":\n return \"UP\";\n default:\n return \"DOWN\"; // TB\n }\n}\n\n// ─── Port helpers ───────────────────────────────────────────────────────────\n\nconst INPUT_PORT_SUFFIX = \"_in\";\nconst OUTPUT_PORT_SUFFIX = \"_out\";\n\nexport function inputPortId(nodeId: string): string {\n return nodeId + INPUT_PORT_SUFFIX;\n}\n\nexport function outputPortId(nodeId: string): string {\n return nodeId + OUTPUT_PORT_SUFFIX;\n}\n\nfunction makePorts(nodeId: string, dims: NodeDimensions, direction: GraphDirection): ElkPort[] {\n // Port sides must match the flow direction so ELK computes edge attachment\n // on the same side that ReactFlow renders handles.\n // LR: input=WEST, output=EAST | RL: input=EAST, output=WEST\n // TB: input=NORTH, output=SOUTH | BT: input=SOUTH, output=NORTH\n const portSides: Record<GraphDirection, { inSide: string; outSide: string }> = {\n LR: { inSide: \"WEST\", outSide: \"EAST\" },\n RL: { inSide: \"EAST\", outSide: \"WEST\" },\n TB: { inSide: \"NORTH\", outSide: \"SOUTH\" },\n BT: { inSide: \"SOUTH\", outSide: \"NORTH\" },\n };\n const { inSide, outSide } = portSides[direction];\n\n const isHorizontal = direction === \"LR\" || direction === \"RL\";\n // Pin ports at the exact center of each side so ELK computes layout\n // with the same edge attachment point that ReactFlow will render.\n const inX = isHorizontal ? (direction === \"LR\" ? 0 : dims.width) : dims.width / 2;\n const inY = isHorizontal ? dims.height / 2 : direction === \"TB\" ? 0 : dims.height;\n const outX = isHorizontal ? (direction === \"LR\" ? dims.width : 0) : dims.width / 2;\n const outY = isHorizontal ? dims.height / 2 : direction === \"TB\" ? dims.height : 0;\n\n return [\n {\n id: inputPortId(nodeId),\n x: inX,\n y: inY,\n width: 1,\n height: 1,\n layoutOptions: { \"elk.port.side\": inSide },\n },\n {\n id: outputPortId(nodeId),\n x: outX,\n y: outY,\n width: 1,\n height: 1,\n layoutOptions: { \"elk.port.side\": outSide },\n },\n ];\n}\n\n// ─── Node dimension estimation ──────────────────────────────────────────────\n// ELK needs dimensions upfront to compute layout.\n\ninterface NodeDimensions {\n width: number;\n height: number;\n}\n\n// ─── Pipe card layout constants (keep in sync with graph-core.css) ──────────\n// If you change these, update the matching rules in graph-core.css.\nconst PIPE_CARD_HEIGHT_CAP = 320;\n\n// Horizontal padding (12 + 12 = 24) + vertical padding (12 + 12 = 24)\nconst PIPE_CARD_PADDING_X = 28; // padding-left + padding-right (14 + 14)\nconst PIPE_CARD_PADDING_Y = 24; // padding-top + padding-bottom (12 + 12)\nconst PIPE_CARD_GAP = 8; // gap between flex children (header / description / io sections)\n\n// Header:\n// - TB: single row with badge + code + status (~22px)\n// - LR: badge/status row + pipe code on its own line below + flex gap (~50px)\nconst PIPE_CARD_HEADER_HEIGHT_TB = 22;\nconst PIPE_CARD_HEADER_HEIGHT_LR = 50;\n\n// Description: 11.5px font × 1.4 line-height ≈ 16.1px per line\nconst PIPE_CARD_DESC_LINE_HEIGHT = 16;\nconst PIPE_CARD_DESC_MAX_LINES_LR = 3;\n\n// I/O section heights (label + first row of pills)\nconst PIPE_CARD_IO_SECTION_HEIGHT_LR = 38; // stacked: label on top, pills below\nconst PIPE_CARD_IO_SECTION_HEIGHT_TB = 30; // inline: label on left, pills on right\nconst PIPE_CARD_IO_EXTRA_ROW_HEIGHT = 22; // each additional wrapping row of pills\n\n// Pill dimension caps (keep in sync with .pipe-card--tb .pipe-card-io-pill-name/concept max-width)\nconst PIPE_CARD_PILL_NAME_MAX_WIDTH = 140;\nconst PIPE_CARD_PILL_CONCEPT_MAX_WIDTH = 100;\nconst PIPE_CARD_PILL_CHROME_WIDTH = 17; // pill padding (10) + name/concept gap (3) + inter-pill gap (4)\nconst PIPE_CARD_IO_LABEL_WIDTH_TB = 58; // min-width 52 + gap 6\n\n// Character width estimates for Inter font\nconst CHAR_WIDTH_DESC = 5.5; // 11.5px font\nconst CHAR_WIDTH_PILL_NAME = 5.0; // 10px font (pill-name)\nconst CHAR_WIDTH_PILL_CONCEPT = 4.5; // 9px font (pill-concept)\n\nconst MAX_VISIBLE_INPUTS = 4;\n\n/** Estimate how many lines the description will wrap to, given direction + text length. */\nfunction estimateDescriptionLines(\n description: string,\n isHorizontal: boolean,\n cardWidth: number,\n): number {\n if (!description) return 0;\n if (!isHorizontal) return 1; // TB always clamps to 1 line (CSS handles ellipsis)\n const textWidth = cardWidth - PIPE_CARD_PADDING_X;\n const charsPerLine = Math.max(1, Math.floor(textWidth / CHAR_WIDTH_DESC));\n const neededLines = Math.ceil(description.length / charsPerLine);\n return Math.min(PIPE_CARD_DESC_MAX_LINES_LR, Math.max(1, neededLines));\n}\n\n/** Estimate the rendered width of a single pill in TB mode. */\nfunction estimateTbPillWidth(name: string, concept: string): number {\n const nameWidth = Math.min(\n PIPE_CARD_PILL_NAME_MAX_WIDTH,\n Math.ceil(name.length * CHAR_WIDTH_PILL_NAME),\n );\n const conceptWidth = Math.min(\n PIPE_CARD_PILL_CONCEPT_MAX_WIDTH,\n Math.ceil(concept.length * CHAR_WIDTH_PILL_CONCEPT),\n );\n return nameWidth + conceptWidth + PIPE_CARD_PILL_CHROME_WIDTH;\n}\n\n/** Count how many wrapping rows a set of pills will occupy in TB mode.\n * Uses a simple first-fit bin-packing against the available pill area width.\n */\nfunction countTbPillRows(\n pills: readonly { name: string; concept: string }[],\n cardWidth: number,\n): number {\n if (pills.length === 0) return 0;\n const availableWidth = cardWidth - PIPE_CARD_PADDING_X - PIPE_CARD_IO_LABEL_WIDTH_TB;\n let rows = 1;\n let currentRowWidth = 0;\n for (const pill of pills) {\n const pillWidth = estimateTbPillWidth(pill.name, pill.concept);\n if (currentRowWidth === 0) {\n currentRowWidth = pillWidth;\n continue;\n }\n if (currentRowWidth + pillWidth <= availableWidth) {\n currentRowWidth += pillWidth;\n } else {\n rows += 1;\n currentRowWidth = pillWidth;\n }\n }\n return rows;\n}\n\nexport function estimateNodeDimensions(node: GraphNode, isHorizontal: boolean): NodeDimensions {\n const nodeData = node.data || {};\n const isStuff = nodeData.isStuff;\n const labelText = nodeData.labelText || \"\";\n const isPipeCard = node.type === NODE_TYPE_PIPE_CARD;\n\n const pipeCardMinWidth = isHorizontal ? 180 : 280;\n const pipeCardMaxWidth = isHorizontal ? 240 : 400;\n // Stuff nodes are visually aligned with pipe cards — they must never be wider\n // than the pipe card max for the current direction, otherwise the graph looks\n // lopsided (a 400px stuff node next to a 240px pipe card in LR mode).\n const estimatedWidth = Math.max(180, Math.min(pipeCardMaxWidth, labelText.length * 8 + 60));\n\n let width: number;\n if (isStuff) {\n width = Math.max(180, estimatedWidth);\n } else if (isPipeCard && nodeData.pipeCardData) {\n width = pipeCardMaxWidth;\n } else {\n width = Math.max(isPipeCard ? pipeCardMinWidth : 200, estimatedWidth);\n }\n\n let height: number;\n if (isStuff) {\n height = 60;\n } else if (isPipeCard && nodeData.pipeCardData) {\n const pcd = nodeData.pipeCardData;\n const inputs = pcd.inputs ?? [];\n const outputs = pcd.outputs ?? [];\n const description = pcd.description || nodeData.nodeData?.description || \"\";\n\n // Header\n let total =\n PIPE_CARD_PADDING_Y +\n (isHorizontal ? PIPE_CARD_HEADER_HEIGHT_LR : PIPE_CARD_HEADER_HEIGHT_TB);\n\n // Description: actual lines needed\n const descLines = estimateDescriptionLines(description, isHorizontal, width);\n if (descLines > 0) {\n total += PIPE_CARD_GAP + descLines * PIPE_CARD_DESC_LINE_HEIGHT;\n }\n\n // Inputs — cap visible to MAX_VISIBLE_INPUTS (rest collapses behind \"+N more\")\n const visibleInputs = inputs.slice(0, MAX_VISIBLE_INPUTS);\n if (visibleInputs.length > 0) {\n total += PIPE_CARD_GAP;\n if (isHorizontal) {\n // LR: one pill per row, always stacked\n total +=\n PIPE_CARD_IO_SECTION_HEIGHT_LR +\n (visibleInputs.length - 1) * PIPE_CARD_IO_EXTRA_ROW_HEIGHT;\n } else {\n // TB: bin-pack pills horizontally, each extra row adds height\n const rows = countTbPillRows(visibleInputs, width);\n total += PIPE_CARD_IO_SECTION_HEIGHT_TB + (rows - 1) * PIPE_CARD_IO_EXTRA_ROW_HEIGHT;\n }\n }\n\n // Outputs — same logic as inputs\n if (outputs.length > 0) {\n total += PIPE_CARD_GAP;\n if (isHorizontal) {\n total +=\n PIPE_CARD_IO_SECTION_HEIGHT_LR + (outputs.length - 1) * PIPE_CARD_IO_EXTRA_ROW_HEIGHT;\n } else {\n const rows = countTbPillRows(outputs, width);\n total += PIPE_CARD_IO_SECTION_HEIGHT_TB + (rows - 1) * PIPE_CARD_IO_EXTRA_ROW_HEIGHT;\n }\n }\n\n height = Math.min(PIPE_CARD_HEIGHT_CAP, total);\n } else {\n height = isPipeCard ? 120 : 70;\n }\n\n return { width, height };\n}\n\n// ─── Controller nesting depth ───────────────────────────────────────────────\n\nfunction computeDepths(\n controllerNodeIds: ReadonlySet<string>,\n containmentTree: Readonly<Record<string, readonly string[]>>,\n): Record<string, number> {\n const depthCache: Record<string, number> = {};\n const visiting = new Set<string>();\n\n function getDepth(ctrlId: string): number {\n if (depthCache[ctrlId] !== undefined) return depthCache[ctrlId];\n if (visiting.has(ctrlId)) return 0;\n visiting.add(ctrlId);\n const children = containmentTree[ctrlId] || [];\n let maxChildDepth = -1;\n for (const childId of children) {\n if (controllerNodeIds.has(childId)) {\n maxChildDepth = Math.max(maxChildDepth, getDepth(childId));\n }\n }\n visiting.delete(ctrlId);\n depthCache[ctrlId] = maxChildDepth + 1;\n return depthCache[ctrlId];\n }\n\n for (const id of controllerNodeIds) getDepth(id);\n return depthCache;\n}\n\n// ─── Leaf node builder ──────────────────────────────────────────────────────\n\nfunction makeLeafNode(nodeId: string, dims: NodeDimensions, direction: GraphDirection): ElkNode {\n return {\n id: nodeId,\n width: dims.width,\n height: dims.height,\n ports: makePorts(nodeId, dims, direction),\n layoutOptions: {\n \"elk.portConstraints\": \"FIXED_POS\",\n },\n };\n}\n\n// ─── Build ELK graph ────────────────────────────────────────────────────────\n\nexport function buildElkGraph(\n nodes: GraphNode[],\n edges: GraphEdge[],\n graphspec: GraphSpec | null,\n analysis: DataflowAnalysis | null,\n direction: GraphDirection,\n layoutConfig?: LayoutConfig,\n): { elkGraph: ElkNode; dimensionMap: Record<string, NodeDimensions> } {\n const isHorizontal = direction === \"LR\" || direction === \"RL\";\n const nodesep = layoutConfig?.nodesep ?? 80;\n const ranksep = layoutConfig?.ranksep ?? 70;\n const elkDir = elkDirection(direction);\n\n const edgeNodeSpacing = \"30\";\n\n const rootLayoutOptions: LayoutOptions = {\n \"elk.algorithm\": \"layered\",\n \"elk.direction\": elkDir,\n \"elk.hierarchyHandling\": \"INCLUDE_CHILDREN\",\n \"elk.spacing.nodeNode\": String(nodesep),\n \"elk.layered.spacing.nodeNodeBetweenLayers\": String(ranksep),\n \"elk.spacing.edgeNode\": edgeNodeSpacing,\n \"elk.spacing.edgeEdge\": \"20\",\n \"elk.layered.spacing.edgeNodeBetweenLayers\": edgeNodeSpacing,\n \"elk.layered.spacing.edgeEdgeBetweenLayers\": \"15\",\n \"elk.layered.nodePlacement.favorStraightEdges\": \"true\",\n };\n\n // Fast path: no hierarchy info → flat layout\n if (!graphspec || !analysis || analysis.controllerNodeIds.size === 0) {\n const dimensionMap: Record<string, NodeDimensions> = {};\n const elkChildren: ElkNode[] = nodes.map((node) => {\n const dims = estimateNodeDimensions(node, isHorizontal);\n dimensionMap[node.id] = dims;\n return makeLeafNode(node.id, dims, direction);\n });\n\n const elkEdges: ElkExtendedEdge[] = edges.map((edge) => ({\n id: edge.id,\n sources: [outputPortId(edge.source)],\n targets: [inputPortId(edge.target)],\n }));\n\n return {\n elkGraph: {\n id: \"root\",\n layoutOptions: rootLayoutOptions,\n children: elkChildren,\n edges: elkEdges,\n },\n dimensionMap,\n };\n }\n\n // Hierarchical layout: build tree from containment analysis\n const childToCtrl = buildChildToControllerMap(graphspec, analysis);\n const depths = computeDepths(analysis.controllerNodeIds, analysis.containmentTree);\n const dimensionMap: Record<string, NodeDimensions> = {};\n\n // Create a map from node ID to its ELK leaf node\n const nodeById = new Map<string, GraphNode>();\n for (const node of nodes) nodeById.set(node.id, node);\n\n // Build controller compound nodes (bottom-up: leaf controllers first)\n const controllerElkNodes: Record<string, ElkNode> = {};\n const controllerIds = Array.from(analysis.controllerNodeIds);\n controllerIds.sort((a, b) => (depths[a] ?? 0) - (depths[b] ?? 0));\n\n for (const ctrlId of controllerIds) {\n const depth = depths[ctrlId] ?? 0;\n const depthScale = 1 + depth * 0.15;\n const padX = Math.round(CONTROLLER_PADDING_X * depthScale);\n const padTop = Math.round(CONTROLLER_PADDING_TOP * depthScale);\n const padBottom = Math.round(CONTROLLER_PADDING_BOTTOM * depthScale);\n\n const ctrlLayoutOptions: LayoutOptions = {\n \"elk.padding\": `[top=${padTop},left=${padX},bottom=${padBottom},right=${padX}]`,\n \"elk.spacing.nodeNode\": String(nodesep),\n \"elk.layered.spacing.nodeNodeBetweenLayers\": String(ranksep),\n \"elk.spacing.edgeNode\": edgeNodeSpacing,\n \"elk.layered.spacing.edgeNodeBetweenLayers\": edgeNodeSpacing,\n };\n\n const children: ElkNode[] = [];\n const directChildren = analysis.containmentTree[ctrlId] || [];\n\n for (const childId of directChildren) {\n if (analysis.controllerNodeIds.has(childId)) {\n // Child is a controller — use its already-built compound node\n const childElk = controllerElkNodes[childId];\n if (childElk) children.push(childElk);\n } else {\n // Child is an operator — create leaf node with ports\n const graphNode = nodeById.get(childId);\n if (graphNode) {\n const dims = estimateNodeDimensions(graphNode, isHorizontal);\n dimensionMap[childId] = dims;\n children.push(makeLeafNode(childId, dims, direction));\n }\n }\n }\n\n // Add stuff nodes that belong to this controller\n for (const node of nodes) {\n if (node.data.isStuff && childToCtrl[node.id] === ctrlId) {\n if (!children.some((c) => c.id === node.id)) {\n const dims = estimateNodeDimensions(node, isHorizontal);\n dimensionMap[node.id] = dims;\n children.push(makeLeafNode(node.id, dims, direction));\n }\n }\n }\n\n controllerElkNodes[ctrlId] = {\n id: ctrlId,\n layoutOptions: ctrlLayoutOptions,\n children,\n };\n }\n\n // Build root children: top-level controllers + loose nodes\n const rootChildren: ElkNode[] = [];\n\n // Add top-level controllers (those not contained by another controller)\n for (const ctrlId of controllerIds) {\n if (!childToCtrl[ctrlId]) {\n const elkNode = controllerElkNodes[ctrlId];\n if (elkNode) rootChildren.push(elkNode);\n }\n }\n\n // Add loose nodes (not inside any controller and not controllers themselves)\n for (const node of nodes) {\n if (!childToCtrl[node.id] && !analysis.controllerNodeIds.has(node.id)) {\n const dims = estimateNodeDimensions(node, isHorizontal);\n dimensionMap[node.id] = dims;\n rootChildren.push(makeLeafNode(node.id, dims, direction));\n }\n }\n\n // All edges at root level — INCLUDE_CHILDREN handles cross-hierarchy routing\n const nodeIdSet = new Set(nodes.map((n) => n.id));\n const elkEdges: ElkExtendedEdge[] = edges\n .filter((e) => nodeIdSet.has(e.source) && nodeIdSet.has(e.target))\n .map((edge) => ({\n id: edge.id,\n sources: [outputPortId(edge.source)],\n targets: [inputPortId(edge.target)],\n }));\n\n return {\n elkGraph: {\n id: \"root\",\n layoutOptions: rootLayoutOptions,\n children: rootChildren,\n edges: elkEdges,\n },\n dimensionMap,\n };\n}\n\n// ─── Extract absolute positions from ELK output ────────────────────────────\n\nexport interface ElkPositionResult {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport function extractAbsolutePositions(elkResult: ElkNode): Record<string, ElkPositionResult> {\n const positions: Record<string, ElkPositionResult> = {};\n\n function walk(node: ElkNode, parentX: number, parentY: number) {\n const absX = parentX + (node.x ?? 0);\n const absY = parentY + (node.y ?? 0);\n\n if (node.id !== \"root\") {\n positions[node.id] = {\n x: absX,\n y: absY,\n width: node.width ?? 0,\n height: node.height ?? 0,\n };\n }\n\n for (const child of node.children ?? []) {\n walk(child, absX, absY);\n }\n }\n\n walk(elkResult, 0, 0);\n return positions;\n}\n","import ELK from \"elkjs/lib/elk.bundled.js\";\nimport type {\n GraphNode,\n GraphEdge,\n GraphSpec,\n DataflowAnalysis,\n LayoutConfig,\n GraphDirection,\n} from \"./types\";\nimport { buildElkGraph, extractAbsolutePositions, estimateNodeDimensions } from \"./elkGraphBuilder\";\nimport type { ElkPositionResult } from \"./elkGraphBuilder\";\n\n// Cache ELK instance at module level to avoid repeated WASM initialization\nlet elkInstance: InstanceType<typeof ELK> | null = null;\nfunction getElk(): InstanceType<typeof ELK> {\n if (!elkInstance) elkInstance = new ELK();\n return elkInstance;\n}\n\nexport interface LayoutResult {\n nodes: GraphNode[];\n edges: GraphEdge[];\n /** ELK-computed positions/sizes for controller compound nodes. */\n controllerPositions: Record<string, ElkPositionResult>;\n}\n\nexport async function getLayoutedElements(\n nodes: GraphNode[],\n edges: GraphEdge[],\n direction: GraphDirection,\n layoutConfig?: LayoutConfig,\n graphspec?: GraphSpec | null,\n analysis?: DataflowAnalysis | null,\n): Promise<LayoutResult> {\n if (nodes.length === 0) return { nodes: [], edges, controllerPositions: {} };\n\n const isHorizontal = direction === \"LR\" || direction === \"RL\";\n\n const { elkGraph, dimensionMap } = buildElkGraph(\n nodes,\n edges,\n graphspec ?? null,\n analysis ?? null,\n direction,\n layoutConfig,\n );\n\n const layoutResult = await getElk().layout(elkGraph);\n const positions = extractAbsolutePositions(layoutResult);\n\n // Extract controller positions from ELK output\n const controllerPositions: Record<string, ElkPositionResult> = {};\n if (analysis) {\n for (const ctrlId of analysis.controllerNodeIds) {\n if (positions[ctrlId]) {\n controllerPositions[ctrlId] = positions[ctrlId];\n }\n }\n }\n\n const result = nodes.map((node) => {\n const pos = positions[node.id];\n const dims = dimensionMap[node.id] ?? estimateNodeDimensions(node, isHorizontal);\n\n const width = dims.width;\n const height = dims.height;\n\n // Inject direction into pipeCardData so the card component can adjust orientation\n const pipeCardData = node.data.pipeCardData;\n const cardDirection = isHorizontal ? (\"LR\" as const) : (\"TB\" as const);\n const updatedPipeCardData = pipeCardData\n ? { ...pipeCardData, direction: cardDirection }\n : undefined;\n\n return {\n ...node,\n data: {\n ...node.data,\n _estimatedWidth: width,\n _estimatedHeight: height,\n pipeCardData: updatedPipeCardData,\n },\n // Lock the ReactFlow node wrapper to the exact dimensions ELK used for layout.\n // This ensures ReactFlow's Handle (centered on the DOM element) matches\n // the port position ELK computed (centered on the estimated dimensions).\n style: {\n ...node.style,\n width: width + \"px\",\n height: height + \"px\",\n },\n position: {\n x: pos ? pos.x : 0,\n y: pos ? pos.y : 0,\n },\n sourcePosition: (isHorizontal\n ? direction === \"LR\"\n ? \"right\"\n : \"left\"\n : direction === \"TB\"\n ? \"bottom\"\n : \"top\") as GraphNode[\"sourcePosition\"],\n targetPosition: (isHorizontal\n ? direction === \"LR\"\n ? \"left\"\n : \"right\"\n : direction === \"TB\"\n ? \"top\"\n : \"bottom\") as GraphNode[\"targetPosition\"],\n };\n });\n\n return { nodes: result, edges, controllerPositions };\n}\n","import type {\n GraphSpec,\n DataflowAnalysis,\n FoldToggleOptions,\n GraphNode,\n GraphEdge,\n PipeCallNode,\n PipeType,\n} from \"./types\";\nimport {\n CONTROLLER_PADDING_X,\n CONTROLLER_PADDING_TOP,\n CONTROLLER_PADDING_BOTTOM,\n NODE_TYPE_CONTROLLER,\n graphSpecMode,\n nodeWidth,\n nodeHeight,\n isStuffNodeId,\n} from \"./types\";\nimport { buildChildToControllerMap } from \"./graphAnalysis\";\nimport { asPipeCallNode, GraphSpecValidationError } from \"./validateGraphSpec\";\n\n/** Max visible children before a parallel/batch controller auto-collapses. */\nexport const MAX_VISIBLE_CONTROLLER_CHILDREN = 5;\n\n/**\n * Collect all descendant node IDs of a controller (recursive).\n */\nfunction getDescendants(\n controllerId: string,\n containmentTree: Readonly<Record<string, readonly string[]>>,\n controllerNodeIds: ReadonlySet<string>,\n): Set<string> {\n const result = new Set<string>();\n const stack = [controllerId];\n while (stack.length > 0) {\n const id = stack.pop()!;\n for (const childId of containmentTree[id] || []) {\n result.add(childId);\n if (controllerNodeIds.has(childId)) stack.push(childId);\n }\n }\n return result;\n}\n\n/** Position and size for a controller, as computed by the layout engine. */\nexport interface ControllerRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Build controller group nodes that wrap child operators/stuff nodes.\n *\n * When `controllerPositions` is provided (from ELK layout), uses those exact\n * positions/sizes instead of recomputing from child bounding boxes. This ensures\n * controller containers match the layout engine's spacing and edge routing.\n *\n * **Side effect:** mutates `layoutedNodes` entries to set `parentId`, `extent`,\n * and convert positions to parent-relative coordinates.\n */\nexport function buildControllerNodes(\n graphspec: GraphSpec,\n analysis: DataflowAnalysis,\n layoutedNodes: GraphNode[],\n controllerPositions?: Record<string, ControllerRect>,\n): GraphNode[] {\n const nodeById: Record<string, GraphNode> = {};\n const graphMode = graphSpecMode(graphspec);\n for (const n of layoutedNodes) {\n nodeById[n.id] = n;\n }\n\n // A controller node is a pipe-call node; the guard makes a malformed spec\n // fail loudly here rather than surfacing later as an undefined pipe_code.\n const controllerInfo: Record<string, PipeCallNode> = {};\n for (const node of graphspec.nodes) {\n if (analysis.controllerNodeIds.has(node.id)) {\n controllerInfo[node.id] = asPipeCallNode(node, `nodes[${node.id}]`);\n }\n }\n\n const depthCache: Record<string, number> = {};\n const depthVisiting = new Set<string>();\n function getDepth(controllerId: string): number {\n if (depthCache[controllerId] !== undefined) return depthCache[controllerId];\n if (depthVisiting.has(controllerId)) {\n throw new Error(\n `Cycle detected in containment tree: controller \"${controllerId}\" is part of a containment cycle`,\n );\n }\n depthVisiting.add(controllerId);\n const children = analysis.containmentTree[controllerId] || [];\n let maxChildDepth = -1;\n for (const childId of children) {\n if (analysis.controllerNodeIds.has(childId)) {\n maxChildDepth = Math.max(maxChildDepth, getDepth(childId));\n }\n }\n depthVisiting.delete(controllerId);\n depthCache[controllerId] = maxChildDepth + 1;\n return depthCache[controllerId];\n }\n\n const childToController = buildChildToControllerMap(graphspec, analysis);\n const controllerStuffChildren: Record<string, string[]> = {};\n for (const [nodeId, ctrlId] of Object.entries(childToController)) {\n if (!isStuffNodeId(nodeId)) continue;\n if (!nodeById[nodeId]) continue;\n if (!controllerStuffChildren[ctrlId]) controllerStuffChildren[ctrlId] = [];\n controllerStuffChildren[ctrlId].push(nodeId);\n }\n\n const controllerIds = Array.from(analysis.controllerNodeIds);\n for (const id of controllerIds) getDepth(id);\n controllerIds.sort((a, b) => depthCache[a] - depthCache[b]);\n\n const controllerNodes: GraphNode[] = [];\n const childToParent: Record<string, string> = {};\n\n for (const controllerId of controllerIds) {\n const directChildren = analysis.containmentTree[controllerId] || [];\n const renderedChildren = directChildren.filter((cid) => nodeById[cid]);\n const stuffChildren = controllerStuffChildren[controllerId] || [];\n const allChildren = [...renderedChildren, ...stuffChildren];\n\n if (allChildren.length === 0) continue;\n\n let groupX: number, groupY: number, groupW: number, groupH: number;\n\n const elkPos = controllerPositions?.[controllerId];\n if (elkPos) {\n // Use ELK's computed position and size — accounts for edge routing and spacing\n groupX = elkPos.x;\n groupY = elkPos.y;\n groupW = elkPos.width;\n groupH = elkPos.height;\n } else {\n // Fallback: compute bounding box from child positions\n let minX = Infinity,\n minY = Infinity,\n maxX = -Infinity,\n maxY = -Infinity;\n for (const childId of allChildren) {\n const child = nodeById[childId];\n const pos = child.position;\n const w = nodeWidth(child);\n const h = nodeHeight(child);\n minX = Math.min(minX, pos.x);\n minY = Math.min(minY, pos.y);\n maxX = Math.max(maxX, pos.x + w);\n maxY = Math.max(maxY, pos.y + h);\n }\n\n const depth = depthCache[controllerId] ?? 0;\n const depthScale = 1 + depth * 0.15;\n const padX = Math.round(CONTROLLER_PADDING_X * depthScale);\n const padTop = Math.round(CONTROLLER_PADDING_TOP * depthScale);\n const padBottom = Math.round(CONTROLLER_PADDING_BOTTOM * depthScale);\n\n groupX = minX - padX;\n groupY = minY - padTop;\n groupW = maxX - minX + 2 * padX;\n groupH = maxY - minY + padTop + padBottom;\n }\n\n const info = controllerInfo[controllerId];\n if (!info) {\n // controllerId comes from a `contains` edge source with no matching node.\n throw new GraphSpecValidationError(\n `nodes[${controllerId}]`,\n `controller \"${controllerId}\" is referenced by a \"contains\" edge but ` +\n `has no corresponding node in graphspec.nodes`,\n );\n }\n const pipeCode = info.pipe_code;\n const groupNode: GraphNode = {\n id: controllerId,\n type: NODE_TYPE_CONTROLLER,\n data: {\n label: pipeCode,\n pipeType: info.pipe_type,\n isController: true,\n isPipe: false,\n isStuff: false,\n pipeCode: pipeCode,\n labelText: pipeCode,\n graphMode,\n },\n position: { x: groupX, y: groupY },\n style: {\n width: groupW + \"px\",\n height: groupH + \"px\",\n padding: \"0\",\n },\n };\n\n controllerNodes.push(groupNode);\n nodeById[controllerId] = groupNode;\n\n for (const childId of allChildren) {\n childToParent[childId] = controllerId;\n }\n }\n\n // Convert child positions to parent-relative and set parentId\n for (const [childId, parentId] of Object.entries(childToParent)) {\n const child = nodeById[childId];\n const parent = nodeById[parentId];\n if (!child || !parent) continue;\n child.position = {\n x: child.position.x - parent.position.x,\n y: child.position.y - parent.position.y,\n };\n child.parentId = parentId;\n child.extent = \"parent\";\n }\n\n return controllerNodes;\n}\n\n/**\n * Apply controller containers to layouted nodes if showControllers is enabled.\n *\n * When `expandedControllers` is provided, PipeParallel/PipeBatch controllers with\n * more than MAX_VISIBLE_CONTROLLER_CHILDREN children are auto-collapsed unless the\n * controller ID is in the expanded set.\n */\nexport function applyControllers(\n layoutedNodes: GraphNode[],\n layoutedEdges: GraphEdge[],\n graphspec: GraphSpec | null,\n analysis: DataflowAnalysis | null,\n showControllers: boolean,\n expandedControllers?: ReadonlySet<string>,\n onToggleCollapse?: (controllerId: string) => void,\n controllerPositions?: Record<string, ControllerRect>,\n onToggleFold?: (controllerId: string, options?: FoldToggleOptions) => void,\n): { nodes: GraphNode[]; edges: GraphEdge[] } {\n if (!showControllers || !analysis || !graphspec) {\n return { nodes: layoutedNodes, edges: layoutedEdges };\n }\n\n // ─── Compute child counts and effective collapse state ─────────────────\n const childCounts: Record<string, number> = {};\n const collapsedSet = new Set<string>();\n\n const controllerTypeMap: Record<string, PipeType> = {};\n for (const node of graphspec.nodes) {\n if (analysis.controllerNodeIds.has(node.id)) {\n controllerTypeMap[node.id] = node.pipe_type;\n }\n }\n\n for (const ctrlId of analysis.controllerNodeIds) {\n const directChildren = analysis.containmentTree[ctrlId] || [];\n childCounts[ctrlId] = directChildren.length;\n const pipeType = controllerTypeMap[ctrlId];\n const isCollapsible = pipeType === \"PipeParallel\" || pipeType === \"PipeBatch\";\n if (\n isCollapsible &&\n directChildren.length > MAX_VISIBLE_CONTROLLER_CHILDREN &&\n !expandedControllers?.has(ctrlId)\n ) {\n collapsedSet.add(ctrlId);\n }\n }\n\n // ─── Filter hidden children for collapsed controllers ──────────────────\n let filteredNodes = layoutedNodes;\n let filteredEdges = layoutedEdges;\n\n if (collapsedSet.size > 0) {\n const hiddenNodes = new Set<string>();\n\n for (const ctrlId of collapsedSet) {\n const directChildren = analysis.containmentTree[ctrlId] || [];\n const toHide = directChildren.slice(MAX_VISIBLE_CONTROLLER_CHILDREN);\n for (const childId of toHide) {\n hiddenNodes.add(childId);\n if (analysis.controllerNodeIds.has(childId)) {\n for (const d of getDescendants(\n childId,\n analysis.containmentTree,\n analysis.controllerNodeIds,\n )) {\n hiddenNodes.add(d);\n }\n }\n }\n }\n\n // Also hide stuff nodes inside collapsed controllers that have no visible\n // pipe connection. We ignore stuff-to-stuff edges (batch_item/batch_aggregate)\n // because those would keep orphaned branch stuff nodes alive.\n const childToCtrl = buildChildToControllerMap(graphspec, analysis);\n for (const node of layoutedNodes) {\n if (!isStuffNodeId(node.id) || hiddenNodes.has(node.id)) continue;\n const ctrlId = childToCtrl[node.id];\n if (!ctrlId || (!collapsedSet.has(ctrlId) && !hiddenNodes.has(ctrlId))) continue;\n const pipeEdges = layoutedEdges.filter((e) => {\n if (e.source !== node.id && e.target !== node.id) return false;\n const other = e.source === node.id ? e.target : e.source;\n return !isStuffNodeId(other); // only pipe connections\n });\n if (\n pipeEdges.length === 0 ||\n pipeEdges.every((e) => {\n const other = e.source === node.id ? e.target : e.source;\n return hiddenNodes.has(other);\n })\n ) {\n hiddenNodes.add(node.id);\n }\n }\n\n filteredNodes = layoutedNodes.filter((n) => !hiddenNodes.has(n.id));\n filteredEdges = layoutedEdges.filter(\n (e) => !hiddenNodes.has(e.source) && !hiddenNodes.has(e.target),\n );\n }\n\n // ─── Build controller group nodes from visible children ────────────────\n const controllerNodes = buildControllerNodes(\n graphspec,\n analysis,\n filteredNodes,\n controllerPositions,\n );\n if (controllerNodes.length === 0) {\n return { nodes: filteredNodes, edges: filteredEdges };\n }\n\n // Inject collapse + fold metadata into controller node data\n for (const cn of controllerNodes) {\n const count = childCounts[cn.id] ?? 0;\n const isCollapsed = collapsedSet.has(cn.id);\n cn.data.childCount = count;\n cn.data.isCollapsed = isCollapsed;\n if (onToggleCollapse) {\n const id = cn.id;\n cn.data.onToggleCollapse = () => onToggleCollapse(id);\n }\n if (onToggleFold) {\n const id = cn.id;\n cn.data.onToggleFold = (options?: FoldToggleOptions) => onToggleFold(id, options);\n }\n }\n\n const allNodes = [...controllerNodes, ...filteredNodes];\n\n // Sort: ReactFlow requires parent group nodes before their children.\n const nodeMap: Record<string, GraphNode> = {};\n for (const n of allNodes) nodeMap[n.id] = n;\n const depthOf: Record<string, number> = {};\n const depthVisiting = new Set<string>();\n function getContainmentDepth(id: string): number {\n if (depthOf[id] !== undefined) return depthOf[id];\n if (depthVisiting.has(id)) {\n throw new Error(\n `Cycle detected in node parent chain: node \"${id}\" references itself as an ancestor`,\n );\n }\n depthVisiting.add(id);\n const n = nodeMap[id];\n depthOf[id] = n && n.parentId ? 1 + getContainmentDepth(n.parentId) : 0;\n depthVisiting.delete(id);\n return depthOf[id];\n }\n for (const n of allNodes) getContainmentDepth(n.id);\n allNodes.sort((a, b) => depthOf[a.id] - depthOf[b.id]);\n\n return { nodes: allNodes, edges: filteredEdges };\n}\n"],"mappings":"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","names":["dimensionMap","elkEdges","_a","_b"]}