@exellix/graph-engine 6.0.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 (202) hide show
  1. package/.env.example +3 -0
  2. package/CHANGELOG.md +208 -0
  3. package/README.md +827 -0
  4. package/dist/src/errors/ExellixGraphError.d.ts +38 -0
  5. package/dist/src/errors/ExellixGraphError.js +21 -0
  6. package/dist/src/errors/exellixGraphErrorCodes.d.ts +31 -0
  7. package/dist/src/errors/exellixGraphErrorCodes.js +32 -0
  8. package/dist/src/index.d.ts +100 -0
  9. package/dist/src/index.js +75 -0
  10. package/dist/src/inspection/contractInspection.d.ts +21 -0
  11. package/dist/src/inspection/contractInspection.js +526 -0
  12. package/dist/src/inspection/contractTypes.d.ts +137 -0
  13. package/dist/src/inspection/contractTypes.js +1 -0
  14. package/dist/src/inspection/controlInspection.d.ts +22 -0
  15. package/dist/src/inspection/controlInspection.js +130 -0
  16. package/dist/src/inspection/graphInspection.d.ts +51 -0
  17. package/dist/src/inspection/graphInspection.js +467 -0
  18. package/dist/src/inspection/index.d.ts +21 -0
  19. package/dist/src/inspection/index.js +17 -0
  20. package/dist/src/inspection/nodeInspection.d.ts +42 -0
  21. package/dist/src/inspection/nodeInspection.js +474 -0
  22. package/dist/src/inspection/types.d.ts +321 -0
  23. package/dist/src/inspection/types.js +14 -0
  24. package/dist/src/inspection/validateAiTasksNodeExtensions.d.ts +12 -0
  25. package/dist/src/inspection/validateAiTasksNodeExtensions.js +119 -0
  26. package/dist/src/inspection/validateCatalogPlanning.d.ts +21 -0
  27. package/dist/src/inspection/validateCatalogPlanning.js +187 -0
  28. package/dist/src/integrations/ActivityTrackerIntegration.d.ts +86 -0
  29. package/dist/src/integrations/ActivityTrackerIntegration.js +134 -0
  30. package/dist/src/integrations/ActivixGraphRunIntegration.d.ts +34 -0
  31. package/dist/src/integrations/ActivixGraphRunIntegration.js +338 -0
  32. package/dist/src/integrations/ActivixNodeActivityIntegration.d.ts +33 -0
  33. package/dist/src/integrations/ActivixNodeActivityIntegration.js +220 -0
  34. package/dist/src/integrations/cataloxGraphCatalog.d.ts +21 -0
  35. package/dist/src/integrations/cataloxGraphCatalog.js +30 -0
  36. package/dist/src/integrations/createActivixExellixIntegration.d.ts +14 -0
  37. package/dist/src/integrations/createActivixExellixIntegration.js +16 -0
  38. package/dist/src/integrations/createActivixFromEnv.d.ts +31 -0
  39. package/dist/src/integrations/createActivixFromEnv.js +53 -0
  40. package/dist/src/loaders/FileGraphLoader.d.ts +23 -0
  41. package/dist/src/loaders/FileGraphLoader.js +31 -0
  42. package/dist/src/playground/PlaygroundReporter.d.ts +40 -0
  43. package/dist/src/playground/PlaygroundReporter.js +480 -0
  44. package/dist/src/playground/index.d.ts +1 -0
  45. package/dist/src/playground/index.js +1 -0
  46. package/dist/src/runtime/ExellixGraphRuntime.d.ts +263 -0
  47. package/dist/src/runtime/ExellixGraphRuntime.js +1716 -0
  48. package/dist/src/runtime/GraphEngine.d.ts +33 -0
  49. package/dist/src/runtime/GraphEngine.js +4 -0
  50. package/dist/src/runtime/aiTasksObservability.d.ts +6 -0
  51. package/dist/src/runtime/aiTasksObservability.js +37 -0
  52. package/dist/src/runtime/aiTasksStrategyPhases.d.ts +46 -0
  53. package/dist/src/runtime/aiTasksStrategyPhases.js +93 -0
  54. package/dist/src/runtime/applyAiTaskProfileWebScopingToNarrix.d.ts +17 -0
  55. package/dist/src/runtime/applyAiTaskProfileWebScopingToNarrix.js +46 -0
  56. package/dist/src/runtime/buildAiTasksRunTaskRequest.d.ts +67 -0
  57. package/dist/src/runtime/buildAiTasksRunTaskRequest.js +164 -0
  58. package/dist/src/runtime/buildRunLog.d.ts +27 -0
  59. package/dist/src/runtime/buildRunLog.js +234 -0
  60. package/dist/src/runtime/buildRunTaskTaskConfigurationForward.d.ts +9 -0
  61. package/dist/src/runtime/buildRunTaskTaskConfigurationForward.js +80 -0
  62. package/dist/src/runtime/buildTaskNodeJobContext.d.ts +11 -0
  63. package/dist/src/runtime/buildTaskNodeJobContext.js +30 -0
  64. package/dist/src/runtime/canonicalModelUsed.d.ts +6 -0
  65. package/dist/src/runtime/canonicalModelUsed.js +36 -0
  66. package/dist/src/runtime/contextualScope.d.ts +7 -0
  67. package/dist/src/runtime/contextualScope.js +121 -0
  68. package/dist/src/runtime/dataFiltersEvaluation.d.ts +60 -0
  69. package/dist/src/runtime/dataFiltersEvaluation.js +169 -0
  70. package/dist/src/runtime/deepMerge.d.ts +5 -0
  71. package/dist/src/runtime/deepMerge.js +22 -0
  72. package/dist/src/runtime/events.d.ts +92 -0
  73. package/dist/src/runtime/events.js +122 -0
  74. package/dist/src/runtime/executionMatrixHost.d.ts +98 -0
  75. package/dist/src/runtime/executionMatrixHost.js +134 -0
  76. package/dist/src/runtime/executionVariableBuckets.d.ts +67 -0
  77. package/dist/src/runtime/executionVariableBuckets.js +96 -0
  78. package/dist/src/runtime/finalizers/errors.d.ts +9 -0
  79. package/dist/src/runtime/finalizers/errors.js +10 -0
  80. package/dist/src/runtime/finalizers/executeFinalizer.d.ts +40 -0
  81. package/dist/src/runtime/finalizers/executeFinalizer.js +471 -0
  82. package/dist/src/runtime/finalizers/schema.d.ts +18 -0
  83. package/dist/src/runtime/finalizers/schema.js +63 -0
  84. package/dist/src/runtime/finalizers/validateFinalizer.d.ts +16 -0
  85. package/dist/src/runtime/finalizers/validateFinalizer.js +534 -0
  86. package/dist/src/runtime/graphDocumentFingerprint.d.ts +8 -0
  87. package/dist/src/runtime/graphDocumentFingerprint.js +21 -0
  88. package/dist/src/runtime/graphEngineMemoryPaths.d.ts +12 -0
  89. package/dist/src/runtime/graphEngineMemoryPaths.js +55 -0
  90. package/dist/src/runtime/graphResponseMapping.d.ts +23 -0
  91. package/dist/src/runtime/graphResponseMapping.js +156 -0
  92. package/dist/src/runtime/graphResponseMigration.d.ts +7 -0
  93. package/dist/src/runtime/graphResponseMigration.js +44 -0
  94. package/dist/src/runtime/graphRunExecutionSeed.d.ts +29 -0
  95. package/dist/src/runtime/graphRunExecutionSeed.js +61 -0
  96. package/dist/src/runtime/graphRunIdentity.d.ts +7 -0
  97. package/dist/src/runtime/graphRunIdentity.js +18 -0
  98. package/dist/src/runtime/localSkills/deterministicRule.d.ts +137 -0
  99. package/dist/src/runtime/localSkills/deterministicRule.js +196 -0
  100. package/dist/src/runtime/localSkills/index.d.ts +12 -0
  101. package/dist/src/runtime/localSkills/index.js +14 -0
  102. package/dist/src/runtime/localSkills/memorixItemToScopedOutput.d.ts +7 -0
  103. package/dist/src/runtime/localSkills/memorixItemToScopedOutput.js +104 -0
  104. package/dist/src/runtime/localSkills/memorixRuntime.d.ts +9 -0
  105. package/dist/src/runtime/localSkills/memorixRuntime.js +70 -0
  106. package/dist/src/runtime/localSkills/memorixScopedConfig.d.ts +16 -0
  107. package/dist/src/runtime/localSkills/memorixScopedConfig.js +18 -0
  108. package/dist/src/runtime/localSkills/scopedAnswerAssembler.d.ts +23 -0
  109. package/dist/src/runtime/localSkills/scopedAnswerAssembler.js +35 -0
  110. package/dist/src/runtime/localSkills/scopedAnswerFields.d.ts +12 -0
  111. package/dist/src/runtime/localSkills/scopedAnswerFields.js +66 -0
  112. package/dist/src/runtime/localSkills/scopedAnswerWriter.d.ts +32 -0
  113. package/dist/src/runtime/localSkills/scopedAnswerWriter.js +156 -0
  114. package/dist/src/runtime/localSkills/scopedDataReader.d.ts +47 -0
  115. package/dist/src/runtime/localSkills/scopedDataReader.js +89 -0
  116. package/dist/src/runtime/localSkills/utils.d.ts +12 -0
  117. package/dist/src/runtime/localSkills/utils.js +39 -0
  118. package/dist/src/runtime/materializeStructuredRunTaskInput.d.ts +9 -0
  119. package/dist/src/runtime/materializeStructuredRunTaskInput.js +34 -0
  120. package/dist/src/runtime/memory.d.ts +51 -0
  121. package/dist/src/runtime/memory.js +250 -0
  122. package/dist/src/runtime/mergeExellixGraphRuntimeInvocation.d.ts +18 -0
  123. package/dist/src/runtime/mergeExellixGraphRuntimeInvocation.js +32 -0
  124. package/dist/src/runtime/modelConfigSelection.d.ts +7 -0
  125. package/dist/src/runtime/modelConfigSelection.js +37 -0
  126. package/dist/src/runtime/narrixIngestEnv.d.ts +9 -0
  127. package/dist/src/runtime/narrixIngestEnv.js +18 -0
  128. package/dist/src/runtime/pathExpr.d.ts +36 -0
  129. package/dist/src/runtime/pathExpr.js +131 -0
  130. package/dist/src/runtime/predicates.d.ts +14 -0
  131. package/dist/src/runtime/predicates.js +86 -0
  132. package/dist/src/runtime/readTaskNodeInputsConfig.d.ts +23 -0
  133. package/dist/src/runtime/readTaskNodeInputsConfig.js +27 -0
  134. package/dist/src/runtime/resolveExecutionPipelineForTaskNode.d.ts +11 -0
  135. package/dist/src/runtime/resolveExecutionPipelineForTaskNode.js +93 -0
  136. package/dist/src/runtime/resolveGraphEngineMemoryPaths.d.ts +63 -0
  137. package/dist/src/runtime/resolveGraphEngineMemoryPaths.js +213 -0
  138. package/dist/src/runtime/resolveModelConfigForNode.d.ts +20 -0
  139. package/dist/src/runtime/resolveModelConfigForNode.js +69 -0
  140. package/dist/src/runtime/resolveNarrixForTaskNode.d.ts +14 -0
  141. package/dist/src/runtime/resolveNarrixForTaskNode.js +19 -0
  142. package/dist/src/runtime/resolveTaskKey.d.ts +11 -0
  143. package/dist/src/runtime/resolveTaskKey.js +28 -0
  144. package/dist/src/runtime/resolveTaskNodeInputs.d.ts +25 -0
  145. package/dist/src/runtime/resolveTaskNodeInputs.js +140 -0
  146. package/dist/src/runtime/runTaskAugments.d.ts +17 -0
  147. package/dist/src/runtime/runTaskAugments.js +37 -0
  148. package/dist/src/runtime/runTaskResponse.d.ts +4 -0
  149. package/dist/src/runtime/runTaskResponse.js +13 -0
  150. package/dist/src/runtime/runtimeObjects.d.ts +85 -0
  151. package/dist/src/runtime/runtimeObjects.js +50 -0
  152. package/dist/src/runtime/smartInputPaths.d.ts +13 -0
  153. package/dist/src/runtime/smartInputPaths.js +38 -0
  154. package/dist/src/runtime/stepRetry.d.ts +21 -0
  155. package/dist/src/runtime/stepRetry.js +238 -0
  156. package/dist/src/runtime/synthesizedContextPipeline.d.ts +12 -0
  157. package/dist/src/runtime/synthesizedContextPipeline.js +28 -0
  158. package/dist/src/runtime/taskNodeConditionsEvaluation.d.ts +27 -0
  159. package/dist/src/runtime/taskNodeConditionsEvaluation.js +140 -0
  160. package/dist/src/runtime/taskNodeMainReadiness.d.ts +45 -0
  161. package/dist/src/runtime/taskNodeMainReadiness.js +164 -0
  162. package/dist/src/runtime/taskNodeRunTaskPreflight.d.ts +89 -0
  163. package/dist/src/runtime/taskNodeRunTaskPreflight.js +204 -0
  164. package/dist/src/runtime/validateCanonicalGraphDocument.d.ts +25 -0
  165. package/dist/src/runtime/validateCanonicalGraphDocument.js +567 -0
  166. package/dist/src/runtime/variables.d.ts +2 -0
  167. package/dist/src/runtime/variables.js +1 -0
  168. package/dist/src/runtime/withTimeout.d.ts +5 -0
  169. package/dist/src/runtime/withTimeout.js +20 -0
  170. package/dist/src/types/aiTaskProfile.d.ts +41 -0
  171. package/dist/src/types/aiTaskProfile.js +6 -0
  172. package/dist/src/types/aiTasksDerivedTypes.d.ts +5 -0
  173. package/dist/src/types/aiTasksDerivedTypes.js +1 -0
  174. package/dist/src/types/events.d.ts +23 -0
  175. package/dist/src/types/events.js +1 -0
  176. package/dist/src/types/job.d.ts +9 -0
  177. package/dist/src/types/job.js +1 -0
  178. package/dist/src/types/narrix.d.ts +60 -0
  179. package/dist/src/types/narrix.js +1 -0
  180. package/dist/src/types/options.d.ts +122 -0
  181. package/dist/src/types/options.js +1 -0
  182. package/dist/src/types/refs.d.ts +747 -0
  183. package/dist/src/types/refs.js +12 -0
  184. package/dist/src/types/results.d.ts +103 -0
  185. package/dist/src/types/results.js +1 -0
  186. package/dist/src/types/runLog.d.ts +72 -0
  187. package/dist/src/types/runLog.js +18 -0
  188. package/dist/src/types/taskNodeConfiguration.d.ts +95 -0
  189. package/dist/src/types/taskNodeConfiguration.js +3 -0
  190. package/dist/src/util/packageVersion.d.ts +2 -0
  191. package/dist/src/util/packageVersion.js +12 -0
  192. package/dist/testkit/RealTasksClient.d.ts +16 -0
  193. package/dist/testkit/RealTasksClient.js +143 -0
  194. package/dist/testkit/depGraphEngineFactory.d.ts +6 -0
  195. package/dist/testkit/depGraphEngineFactory.js +54 -0
  196. package/dist/testkit/exellixRuntimeObjects.d.ts +7 -0
  197. package/dist/testkit/exellixRuntimeObjects.js +25 -0
  198. package/dist/testkit/inMemoryGraphLoader.d.ts +6 -0
  199. package/dist/testkit/inMemoryGraphLoader.js +12 -0
  200. package/dist/testkit/index.d.ts +4 -0
  201. package/dist/testkit/index.js +4 -0
  202. package/package.json +70 -0
@@ -0,0 +1,130 @@
1
+ import { getGraphNodes } from './graphInspection.js';
2
+ import { getNodeNarrixDiscovery } from './nodeInspection.js';
3
+ /**
4
+ * Recursively collects leaf `path` strings from a graph edge predicate.
5
+ */
6
+ export function collectPredicatePaths(predicate) {
7
+ if (predicate == null)
8
+ return [];
9
+ if (typeof predicate !== 'object')
10
+ return [];
11
+ if ('path' in predicate && typeof predicate.path === 'string') {
12
+ return [predicate.path];
13
+ }
14
+ if ('all' in predicate) {
15
+ const items = predicate.all;
16
+ if (!Array.isArray(items))
17
+ return [];
18
+ return items.flatMap((p) => collectPredicatePaths(p));
19
+ }
20
+ if ('any' in predicate) {
21
+ const items = predicate.any;
22
+ if (!Array.isArray(items))
23
+ return [];
24
+ return items.flatMap((p) => collectPredicatePaths(p));
25
+ }
26
+ if ('not' in predicate) {
27
+ return collectPredicatePaths(predicate.not);
28
+ }
29
+ return [];
30
+ }
31
+ /** Execution-memory dot-tail (no `executionMemory.` prefix). */
32
+ export function executionMemoryPathTail(fullPath) {
33
+ const prefix = 'executionMemory.';
34
+ if (!fullPath.startsWith(prefix))
35
+ return null;
36
+ const tail = fullPath.slice(prefix.length);
37
+ return tail || null;
38
+ }
39
+ /**
40
+ * Same prefix semantics as io edge intersection: exact or parent/child path match.
41
+ */
42
+ export function executionMemoryTailsMatch(a, b) {
43
+ if (a === b)
44
+ return true;
45
+ return a.startsWith(b + '.') || b.startsWith(a + '.');
46
+ }
47
+ /**
48
+ * All execution-memory write tails this node contributes (for control-flow matching).
49
+ * Includes executionMapping, narrix slots, webContext, synthesizedContext when applicable.
50
+ */
51
+ export function getNodeExecutionMemoryWriteTails(node) {
52
+ const tails = new Set();
53
+ if (node.type === 'finalizer') {
54
+ return [];
55
+ }
56
+ const task = node;
57
+ if (task.executionMapping?.path) {
58
+ tails.add(task.executionMapping.path);
59
+ }
60
+ const narrix = getNodeNarrixDiscovery(node);
61
+ if (narrix?.enabled) {
62
+ tails.add('_narrix.scoping.signals');
63
+ tails.add('_narrix.scoping.stories');
64
+ }
65
+ const tc = task.taskConfiguration;
66
+ const profile = tc?.aiTaskProfile;
67
+ const ws = profile?.webScoping;
68
+ if (ws?.enabled === true) {
69
+ tails.add('webContext');
70
+ }
71
+ const inputSynth = profile?.inputSynthesis;
72
+ if (inputSynth?.enabled === true) {
73
+ tails.add('synthesizedContext');
74
+ }
75
+ return [...tails];
76
+ }
77
+ function getNodeById(graph, id) {
78
+ return getGraphNodes(graph).find((n) => n.id === id);
79
+ }
80
+ /**
81
+ * Lists edges whose `when` predicates read execution-memory paths produced by `nodeId`,
82
+ * and routing hints from graphReadability.
83
+ */
84
+ export function getNodeControlDependencies(graph, nodeId) {
85
+ const node = getNodeById(graph, nodeId);
86
+ const writeTails = node ? getNodeExecutionMemoryWriteTails(node) : [];
87
+ const edges = graph.edges ?? [];
88
+ const branches = [];
89
+ const matchedFullPaths = new Set();
90
+ for (const edge of edges) {
91
+ if (edge.when == null)
92
+ continue;
93
+ const paths = collectPredicatePaths(edge.when);
94
+ const matched = [];
95
+ for (const full of paths) {
96
+ const tail = executionMemoryPathTail(full);
97
+ if (tail == null)
98
+ continue;
99
+ for (const w of writeTails) {
100
+ if (executionMemoryTailsMatch(tail, w)) {
101
+ matched.push(full);
102
+ matchedFullPaths.add(full);
103
+ break;
104
+ }
105
+ }
106
+ }
107
+ if (matched.length > 0) {
108
+ branches.push({
109
+ from: edge.from,
110
+ to: edge.to,
111
+ when: edge.when,
112
+ matchedExecutionMemoryPaths: [...new Set(matched)],
113
+ });
114
+ }
115
+ }
116
+ const influencesPredicate = branches.length > 0;
117
+ const readabilityKind = node && node.type !== 'finalizer'
118
+ ? node.metadata?.graphReadability?.kind
119
+ : undefined;
120
+ const routingHintFromReadability = readabilityKind === 'routing';
121
+ const isRoutingNode = routingHintFromReadability || influencesPredicate;
122
+ return {
123
+ isRoutingNode,
124
+ routingHintFromReadability,
125
+ edgesConditionalOnThisWriter: branches,
126
+ predicatePathsThatMatchedWrites: [...matchedFullPaths],
127
+ downstreamBranchMap: branches,
128
+ provenance: 'derived',
129
+ };
130
+ }
@@ -0,0 +1,51 @@
1
+ import type { Graph, GraphNode, GraphEdge } from '../types/refs.js';
2
+ import { type GraphInspection, type GraphCatalogs, type MaterializeVirtualBoundaryDiagramOptions, type MaterializedVirtualBoundaryDiagram, type VirtualGraphEntryLayer, type VirtualGraphResponseLayer } from './types.js';
3
+ /**
4
+ * Returns `graph.nodes`. Canonical 5.x: `graph.nodes` is always a `GraphNode[]`.
5
+ * Record-keyed nodes are rejected by `assertCanonicalGraphDocument` at load time,
6
+ * so this helper is essentially an identity used by callers that still take a
7
+ * permissive `Graph` shape.
8
+ */
9
+ export declare function getGraphNodes(graph: Graph): GraphNode[];
10
+ /**
11
+ * Extracts all catalog references from a graph JSON, aggregated across all nodes.
12
+ */
13
+ export declare function getGraphCatalogs(graph: Graph): GraphCatalogs;
14
+ /**
15
+ * Layer 01 visualization anchor: **not** in `graph.nodes`. Use when building graph diagrams
16
+ * so callers see where `execution.input.*` is seeded before the first real nodes run.
17
+ */
18
+ export declare function getVirtualGraphEntryLayer(graph: Graph): VirtualGraphEntryLayer;
19
+ /**
20
+ * Layer 08 visualization anchor: **not** in `graph.nodes`. Use when building graph diagrams
21
+ * so callers see where `graph.response` / `finalOutput` conceptually leaves the DAG.
22
+ */
23
+ export declare function getVirtualGraphResponseLayer(graph: Graph): VirtualGraphResponseLayer;
24
+ /**
25
+ * Returns **copies** of the graph’s real `nodes` / `edges` plus synthetic Layer 01 / 08 boundary
26
+ * nodes and edges aligned with {@link inspectGraph}'s `virtualIO` field.
27
+ *
28
+ * **Not executable:** exellix-graph ignores these ids in authored JSON today; if you merge this blob
29
+ * back into a graph document, strip synthetic nodes and edges (see {@link stripMaterializedVirtualBoundaryDiagram})
30
+ * before calling {@link executeGraph}.
31
+ *
32
+ * @throws If a real node uses an id reserved for virtual boundaries.
33
+ */
34
+ export declare function materializeVirtualBoundaryDiagram(graph: Graph, options?: MaterializeVirtualBoundaryDiagramOptions): MaterializedVirtualBoundaryDiagram;
35
+ /**
36
+ * Removes synthetic boundary nodes and edges produced by {@link materializeVirtualBoundaryDiagram}.
37
+ * Also drops any edge incident to the reserved virtual ids. Safe on diagrams that only mark
38
+ * synthetic edges (flags) without markers on nodes, as long as ids match the stable virtual ids.
39
+ */
40
+ export declare function stripMaterializedVirtualBoundaryDiagram(diagram: MaterializedVirtualBoundaryDiagram): {
41
+ nodes: GraphNode[];
42
+ edges: GraphEdge[];
43
+ };
44
+ /**
45
+ * Produces a complete planning-level inspection of the graph:
46
+ * - Per-node scoping questions, memory shapes, narrix discovery
47
+ * - Topological execution order
48
+ * - I/O connections between adjacent nodes
49
+ * - Aggregated catalog references
50
+ */
51
+ export declare function inspectGraph(graph: Graph): GraphInspection;
@@ -0,0 +1,467 @@
1
+ import { mergeGraphDocumentModel } from '../types/refs.js';
2
+ import { assertCanonicalGraphDocument } from '../runtime/validateCanonicalGraphDocument.js';
3
+ import { isLocalSkillKey } from '../runtime/localSkills/index.js';
4
+ import { inspectNode, resolveNodeSkillKey } from './nodeInspection.js';
5
+ import { EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID, EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID, EXELLIX_VIRTUAL_BOUNDARY_NODE_METADATA_KEY, EXELLIX_VIRTUAL_BOUNDARY_EDGE_FLAG_KEY, } from './types.js';
6
+ // ---------------------------------------------------------------------------
7
+ // Graph node normalization
8
+ // ---------------------------------------------------------------------------
9
+ /**
10
+ * Returns `graph.nodes`. Canonical 5.x: `graph.nodes` is always a `GraphNode[]`.
11
+ * Record-keyed nodes are rejected by `assertCanonicalGraphDocument` at load time,
12
+ * so this helper is essentially an identity used by callers that still take a
13
+ * permissive `Graph` shape.
14
+ */
15
+ export function getGraphNodes(graph) {
16
+ if (Array.isArray(graph.nodes))
17
+ return graph.nodes;
18
+ return [];
19
+ }
20
+ // ---------------------------------------------------------------------------
21
+ // Topological sort (Kahn's algorithm)
22
+ // ---------------------------------------------------------------------------
23
+ function topoSort(nodeIds, edges) {
24
+ // Build adjacency: from → set of tos, and in-degree counts
25
+ const successors = new Map();
26
+ const inDegree = new Map();
27
+ for (const id of nodeIds) {
28
+ successors.set(id, new Set());
29
+ inDegree.set(id, 0);
30
+ }
31
+ for (const edge of edges) {
32
+ const { from, to } = edge;
33
+ if (!successors.has(from) || !inDegree.has(to))
34
+ continue;
35
+ successors.get(from).add(to);
36
+ inDegree.set(to, (inDegree.get(to) ?? 0) + 1);
37
+ }
38
+ const queue = [];
39
+ for (const id of nodeIds) {
40
+ if ((inDegree.get(id) ?? 0) === 0)
41
+ queue.push(id);
42
+ }
43
+ const order = [];
44
+ while (queue.length > 0) {
45
+ const id = queue.shift();
46
+ order.push(id);
47
+ for (const succ of successors.get(id) ?? []) {
48
+ const deg = (inDegree.get(succ) ?? 1) - 1;
49
+ inDegree.set(succ, deg);
50
+ if (deg === 0)
51
+ queue.push(succ);
52
+ }
53
+ }
54
+ // Append any remaining nodes not reached (disconnected or cyclic) in original order
55
+ const seen = new Set(order);
56
+ for (const id of nodeIds) {
57
+ if (!seen.has(id))
58
+ order.push(id);
59
+ }
60
+ return order;
61
+ }
62
+ // ---------------------------------------------------------------------------
63
+ // Catalog extraction
64
+ // ---------------------------------------------------------------------------
65
+ /**
66
+ * Extracts all catalog references from a graph JSON, aggregated across all nodes.
67
+ */
68
+ export function getGraphCatalogs(graph) {
69
+ const nodes = getGraphNodes(graph);
70
+ const scopingMapIds = new Set();
71
+ const narrixQuestionIds = new Set();
72
+ const narrixLayers = new Set();
73
+ const narrixNarrativeTypeIds = new Set();
74
+ const localSkillKeysSet = new Set();
75
+ const aiSkillKeys = new Set();
76
+ const readabilityKinds = new Set();
77
+ const scopedQuestionCatalogIds = new Set();
78
+ const discoveryDefinitionCatalogIds = new Set();
79
+ const catalogBindings = [];
80
+ let catalogRequestScoped = 0;
81
+ let catalogRequestDiscovery = 0;
82
+ let catalogRequestOther = 0;
83
+ const gm = graph.metadata;
84
+ if (gm?.catalogRequests != null && Array.isArray(gm.catalogRequests)) {
85
+ for (const req of gm.catalogRequests) {
86
+ const ct = req != null && typeof req === 'object' && !Array.isArray(req)
87
+ ? String(req.catalogType ?? '')
88
+ : '';
89
+ if (ct === 'scoped-question')
90
+ catalogRequestScoped += 1;
91
+ else if (ct === 'discovery-definition')
92
+ catalogRequestDiscovery += 1;
93
+ else if (ct)
94
+ catalogRequestOther += 1;
95
+ }
96
+ }
97
+ for (const node of nodes) {
98
+ if (node.type === 'finalizer')
99
+ continue;
100
+ const meta = node.metadata;
101
+ const tc = node.taskConfiguration;
102
+ const skillKey = resolveNodeSkillKey(node);
103
+ // Skill key classification
104
+ if (skillKey) {
105
+ if (isLocalSkillKey(skillKey)) {
106
+ localSkillKeysSet.add(skillKey);
107
+ }
108
+ else {
109
+ aiSkillKeys.add(skillKey);
110
+ }
111
+ }
112
+ if (meta) {
113
+ const cb = meta.catalogBinding;
114
+ if (cb && typeof cb === 'object' && typeof cb.catalogId === 'string' && cb.catalogId) {
115
+ const ct = typeof cb.catalogType === 'string' ? cb.catalogType : '';
116
+ if (ct === 'scoped-question')
117
+ scopedQuestionCatalogIds.add(cb.catalogId);
118
+ if (ct === 'discovery-definition')
119
+ discoveryDefinitionCatalogIds.add(cb.catalogId);
120
+ catalogBindings.push({
121
+ nodeId: String(node.id),
122
+ catalogType: ct || 'unknown',
123
+ catalogId: cb.catalogId,
124
+ version: typeof cb.version === 'string' ? cb.version : '',
125
+ });
126
+ }
127
+ // graphReadability.kind
128
+ if (typeof meta.graphReadability?.kind === 'string') {
129
+ readabilityKinds.add(meta.graphReadability.kind);
130
+ }
131
+ }
132
+ if (!tc)
133
+ continue;
134
+ // scopingMapId (scoped-data-reader config)
135
+ if (typeof tc.scopingMapId === 'string') {
136
+ scopingMapIds.add(tc.scopingMapId);
137
+ }
138
+ // Pack slots may also carry scopingMapIds
139
+ if (Array.isArray(tc.pack)) {
140
+ for (const slot of tc.pack) {
141
+ if (typeof slot.scopingMapId === 'string')
142
+ scopingMapIds.add(slot.scopingMapId);
143
+ }
144
+ }
145
+ // narrix config
146
+ const narrix = tc.narrix;
147
+ if (narrix) {
148
+ if (typeof narrix.questionId === 'string')
149
+ narrixQuestionIds.add(narrix.questionId);
150
+ // Opaque graph/pack label — aggregate only for inspection UIs, no validation.
151
+ if (typeof narrix.layer === 'string')
152
+ narrixLayers.add(narrix.layer);
153
+ if (Array.isArray(narrix.narrativeTypeIds)) {
154
+ for (const id of narrix.narrativeTypeIds)
155
+ narrixNarrativeTypeIds.add(id);
156
+ }
157
+ }
158
+ }
159
+ return {
160
+ scopingMapIds: [...scopingMapIds],
161
+ narrixQuestionIds: [...narrixQuestionIds],
162
+ narrixLayers: [...narrixLayers],
163
+ narrixNarrativeTypeIds: [...narrixNarrativeTypeIds],
164
+ localSkillKeys: [...localSkillKeysSet],
165
+ aiSkillKeys: [...aiSkillKeys],
166
+ graphReadabilityKinds: [...readabilityKinds],
167
+ scopedQuestionCatalogIds: [...scopedQuestionCatalogIds],
168
+ discoveryDefinitionCatalogIds: [...discoveryDefinitionCatalogIds],
169
+ catalogBindings,
170
+ catalogRequestCounts: {
171
+ scopedQuestion: catalogRequestScoped,
172
+ discoveryDefinition: catalogRequestDiscovery,
173
+ other: catalogRequestOther,
174
+ },
175
+ };
176
+ }
177
+ // ---------------------------------------------------------------------------
178
+ // I/O edge derivation
179
+ // ---------------------------------------------------------------------------
180
+ /**
181
+ * Builds an array of NodeIOEdge by cross-referencing what each `from` node writes
182
+ * with what each `to` node reads, for every edge in the graph.
183
+ */
184
+ function buildIOEdges(edges, nodeInspections) {
185
+ return edges.map((edge) => {
186
+ const fromInspection = nodeInspections[edge.from];
187
+ const toInspection = nodeInspections[edge.to];
188
+ const executionWrittenPaths = fromInspection?.memoryShape.after.writes.map((w) => w.path) ?? [];
189
+ const outputsWrittenPaths = fromInspection?.memoryShape.after.outputsMemoryWrites?.map((w) => w.path) ?? [];
190
+ const writtenPaths = [...executionWrittenPaths, ...outputsWrittenPaths];
191
+ const toReads = toInspection?.memoryShape.before.reads ?? [];
192
+ const executionToReadPaths = new Set(toReads.filter((r) => r.memory !== 'outputsMemory').map((r) => r.path));
193
+ const outputsToReadPaths = new Set(toReads.filter((r) => r.memory === 'outputsMemory').map((r) => r.path));
194
+ // Intersection: paths that `from` writes and `to` reads
195
+ const pathMatches = (p, candidates) => {
196
+ // Exact match or prefix match (e.g. `scoped` covers `scoped.subnet.composition`)
197
+ return candidates.has(p) || [...candidates].some((rp) => rp.startsWith(p + '.') || p.startsWith(rp + '.'));
198
+ };
199
+ const executionReadPaths = executionWrittenPaths.filter((p) => pathMatches(p, executionToReadPaths));
200
+ const outputsReadPaths = outputsWrittenPaths.filter((p) => pathMatches(p, outputsToReadPaths));
201
+ const readPaths = [...executionReadPaths, ...outputsReadPaths];
202
+ return {
203
+ from: edge.from,
204
+ to: edge.to,
205
+ writtenPaths,
206
+ executionWrittenPaths,
207
+ outputsWrittenPaths,
208
+ readPaths,
209
+ executionReadPaths,
210
+ outputsReadPaths,
211
+ ...(edge.when != null ? { when: edge.when } : {}),
212
+ };
213
+ });
214
+ }
215
+ // ---------------------------------------------------------------------------
216
+ // Virtual graph I/O (Layer 01 / 08) — inspection only
217
+ // ---------------------------------------------------------------------------
218
+ function findFirstWaveNodeIds(nodeIds, edges) {
219
+ const incoming = new Set();
220
+ for (const e of edges) {
221
+ if (e && typeof e.to === 'string')
222
+ incoming.add(e.to);
223
+ }
224
+ return nodeIds.filter((id) => !incoming.has(id));
225
+ }
226
+ /**
227
+ * When exactly one finalizer exists and it has no outgoing authored edges, returns its id.
228
+ * Otherwise null (invalid graph or cannot name a single canonical `finalOutput` producer).
229
+ */
230
+ function findCanonicalFinalizerId(nodeIds, nodes, edges) {
231
+ const fins = nodes.filter((n) => n.type === 'finalizer');
232
+ if (fins.length !== 1)
233
+ return null;
234
+ const fid = String(fins[0].id);
235
+ if (!nodeIds.includes(fid))
236
+ return null;
237
+ const hasOut = edges.some((e) => e && e.from === fid);
238
+ if (hasOut)
239
+ return null;
240
+ return fid;
241
+ }
242
+ function buildVirtualIO(nodeIds, nodes, edges) {
243
+ const firstWaveNodeIds = findFirstWaveNodeIds(nodeIds, edges);
244
+ const canonicalFinalizerId = findCanonicalFinalizerId(nodeIds, nodes, edges);
245
+ const virtualNodes = [
246
+ {
247
+ id: EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID,
248
+ role: 'graph-entry',
249
+ layer: 1,
250
+ description: 'Layer 01 — Graph entry: caller-provided execution.input.* via ExecuteGraphOptions.execution (not a DAG node).',
251
+ },
252
+ {
253
+ id: EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID,
254
+ role: 'graph-response',
255
+ layer: 8,
256
+ description: 'Layer 08 — Final Response: ExecuteGraphResult.finalOutput resolved from root graph.response (not a DAG node).',
257
+ },
258
+ ];
259
+ const virtualEdges = firstWaveNodeIds.map((to) => ({
260
+ from: EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID,
261
+ to,
262
+ }));
263
+ if (canonicalFinalizerId != null) {
264
+ virtualEdges.push({
265
+ from: canonicalFinalizerId,
266
+ to: EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID,
267
+ });
268
+ }
269
+ return {
270
+ nodes: virtualNodes,
271
+ edges: virtualEdges,
272
+ firstWaveNodeIds,
273
+ canonicalFinalizerId,
274
+ };
275
+ }
276
+ /** Shared virtual I/O computation for `inspectGraph` and visualization helpers. */
277
+ function computeVirtualIO(graph) {
278
+ const nodes = getGraphNodes(graph);
279
+ const edges = graph.edges ?? [];
280
+ return buildVirtualIO(nodes.map((n) => n.id), nodes, edges);
281
+ }
282
+ /**
283
+ * Layer 01 visualization anchor: **not** in `graph.nodes`. Use when building graph diagrams
284
+ * so callers see where `execution.input.*` is seeded before the first real nodes run.
285
+ */
286
+ export function getVirtualGraphEntryLayer(graph) {
287
+ const v = computeVirtualIO(graph);
288
+ const virtualNode = v.nodes.find((n) => n.role === 'graph-entry');
289
+ if (!virtualNode) {
290
+ throw new Error('EXELLIX_VIRTUAL_IO_INVARIANT: missing graph-entry virtual node');
291
+ }
292
+ return {
293
+ virtualNode,
294
+ outgoingEdges: v.edges.filter((e) => e.from === EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID),
295
+ firstWaveNodeIds: v.firstWaveNodeIds,
296
+ };
297
+ }
298
+ /**
299
+ * Layer 08 visualization anchor: **not** in `graph.nodes`. Use when building graph diagrams
300
+ * so callers see where `graph.response` / `finalOutput` conceptually leaves the DAG.
301
+ */
302
+ export function getVirtualGraphResponseLayer(graph) {
303
+ const v = computeVirtualIO(graph);
304
+ const virtualNode = v.nodes.find((n) => n.role === 'graph-response');
305
+ if (!virtualNode) {
306
+ throw new Error('EXELLIX_VIRTUAL_IO_INVARIANT: missing graph-response virtual node');
307
+ }
308
+ return {
309
+ virtualNode,
310
+ incomingEdges: v.edges.filter((e) => e.to === EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID),
311
+ canonicalFinalizerId: v.canonicalFinalizerId,
312
+ };
313
+ }
314
+ const RESERVED_VIRTUAL_BOUNDARY_NODE_IDS = new Set([
315
+ EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID,
316
+ EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID,
317
+ ]);
318
+ function cloneGraphNode(node) {
319
+ return structuredClone(node);
320
+ }
321
+ function cloneGraphEdge(edge) {
322
+ return structuredClone(edge);
323
+ }
324
+ function virtualIONodeToMaterializedGraphNode(vn, markSynthetic) {
325
+ const metadata = {
326
+ woroxVirtualBoundary: {
327
+ role: vn.role,
328
+ layer: vn.layer,
329
+ description: vn.description,
330
+ },
331
+ };
332
+ if (markSynthetic) {
333
+ metadata[EXELLIX_VIRTUAL_BOUNDARY_NODE_METADATA_KEY] = true;
334
+ }
335
+ return {
336
+ id: vn.id,
337
+ type: '__exellixVirtualBoundary',
338
+ metadata,
339
+ };
340
+ }
341
+ /**
342
+ * Returns **copies** of the graph’s real `nodes` / `edges` plus synthetic Layer 01 / 08 boundary
343
+ * nodes and edges aligned with {@link inspectGraph}'s `virtualIO` field.
344
+ *
345
+ * **Not executable:** exellix-graph ignores these ids in authored JSON today; if you merge this blob
346
+ * back into a graph document, strip synthetic nodes and edges (see {@link stripMaterializedVirtualBoundaryDiagram})
347
+ * before calling {@link executeGraph}.
348
+ *
349
+ * @throws If a real node uses an id reserved for virtual boundaries.
350
+ */
351
+ export function materializeVirtualBoundaryDiagram(graph, options) {
352
+ const markNodes = options?.markSyntheticNodes !== false;
353
+ const markEdges = options?.markSyntheticEdges !== false;
354
+ const v = computeVirtualIO(graph);
355
+ const realNodes = getGraphNodes(graph);
356
+ for (const n of realNodes) {
357
+ if (RESERVED_VIRTUAL_BOUNDARY_NODE_IDS.has(String(n.id))) {
358
+ throw new Error(`materializeVirtualBoundaryDiagram: node id "${n.id}" is reserved for Layer 01/08 virtual boundaries`);
359
+ }
360
+ }
361
+ const nodes = [...realNodes.map(cloneGraphNode), ...v.nodes.map((vn) => virtualIONodeToMaterializedGraphNode(vn, markNodes))];
362
+ const realEdges = graph.edges ?? [];
363
+ const syntheticEdges = v.edges.map((e) => {
364
+ const edge = { ...e };
365
+ if (markEdges) {
366
+ edge[EXELLIX_VIRTUAL_BOUNDARY_EDGE_FLAG_KEY] = true;
367
+ }
368
+ return edge;
369
+ });
370
+ return {
371
+ nodes,
372
+ edges: [...realEdges.map(cloneGraphEdge), ...syntheticEdges],
373
+ virtualMeta: {
374
+ entryNodeId: EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID,
375
+ responseNodeId: EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID,
376
+ firstWaveNodeIds: [...v.firstWaveNodeIds],
377
+ canonicalFinalizerId: v.canonicalFinalizerId,
378
+ syntheticNodeIds: [EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID, EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID],
379
+ notExecutable: true,
380
+ nodeMarker: EXELLIX_VIRTUAL_BOUNDARY_NODE_METADATA_KEY,
381
+ edgeMarker: EXELLIX_VIRTUAL_BOUNDARY_EDGE_FLAG_KEY,
382
+ },
383
+ };
384
+ }
385
+ /**
386
+ * Removes synthetic boundary nodes and edges produced by {@link materializeVirtualBoundaryDiagram}.
387
+ * Also drops any edge incident to the reserved virtual ids. Safe on diagrams that only mark
388
+ * synthetic edges (flags) without markers on nodes, as long as ids match the stable virtual ids.
389
+ */
390
+ export function stripMaterializedVirtualBoundaryDiagram(diagram) {
391
+ const nodes = diagram.nodes.filter((n) => {
392
+ const id = String(n.id);
393
+ if (RESERVED_VIRTUAL_BOUNDARY_NODE_IDS.has(id))
394
+ return false;
395
+ const meta = n.metadata;
396
+ if (meta?.[EXELLIX_VIRTUAL_BOUNDARY_NODE_METADATA_KEY] === true)
397
+ return false;
398
+ return true;
399
+ });
400
+ const ids = new Set(nodes.map((n) => String(n.id)));
401
+ const edges = diagram.edges.filter((e) => {
402
+ if (e[EXELLIX_VIRTUAL_BOUNDARY_EDGE_FLAG_KEY] === true)
403
+ return false;
404
+ if (RESERVED_VIRTUAL_BOUNDARY_NODE_IDS.has(e.from) || RESERVED_VIRTUAL_BOUNDARY_NODE_IDS.has(e.to)) {
405
+ return false;
406
+ }
407
+ return ids.has(e.from) && ids.has(e.to);
408
+ });
409
+ return { nodes, edges };
410
+ }
411
+ // ---------------------------------------------------------------------------
412
+ // Full graph inspection
413
+ // ---------------------------------------------------------------------------
414
+ /**
415
+ * Produces a complete planning-level inspection of the graph:
416
+ * - Per-node scoping questions, memory shapes, narrix discovery
417
+ * - Topological execution order
418
+ * - I/O connections between adjacent nodes
419
+ * - Aggregated catalog references
420
+ */
421
+ export function inspectGraph(graph) {
422
+ assertCanonicalGraphDocument(graph, { graphId: graph?.id });
423
+ const nodes = getGraphNodes(graph);
424
+ const edges = graph.edges ?? [];
425
+ const nodeIds = nodes.map((n) => n.id);
426
+ const executionOrder = topoSort(nodeIds, edges);
427
+ // Build a lookup from nodeId → list of upstream write paths
428
+ // We iterate in execution order, accumulating write paths as we go.
429
+ const accumulatedWritePaths = new Map();
430
+ const cumulativeWrites = [];
431
+ // First pass: resolve per-node write paths to populate the map
432
+ const nodeWritePathsMap = new Map();
433
+ for (const node of nodes) {
434
+ const writes = [];
435
+ if (node.type !== 'finalizer') {
436
+ const em = node.executionMapping;
437
+ if (em?.path)
438
+ writes.push(em.path);
439
+ }
440
+ nodeWritePathsMap.set(node.id, writes);
441
+ }
442
+ // Build upstream write paths per node (everything written before this node in topo order)
443
+ for (const nodeId of executionOrder) {
444
+ accumulatedWritePaths.set(nodeId, [...cumulativeWrites]);
445
+ const writes = nodeWritePathsMap.get(nodeId) ?? [];
446
+ cumulativeWrites.push(...writes);
447
+ }
448
+ // Build per-node inspections
449
+ const nodeInspections = {};
450
+ for (const node of nodes) {
451
+ const upstream = accumulatedWritePaths.get(node.id) ?? [];
452
+ nodeInspections[node.id] = inspectNode(node, upstream, graph);
453
+ }
454
+ const ioEdges = buildIOEdges(edges, nodeInspections);
455
+ const catalogs = getGraphCatalogs(graph);
456
+ const virtualIO = computeVirtualIO(graph);
457
+ return {
458
+ graphId: graph.id,
459
+ nodes: nodeInspections,
460
+ executionOrder,
461
+ edges,
462
+ ioEdges,
463
+ catalogs,
464
+ graphDocumentModel: mergeGraphDocumentModel(graph),
465
+ virtualIO,
466
+ };
467
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Graph Inspection API
3
+ *
4
+ * Planning-level visibility into any exellix-graph JSON:
5
+ * - Per-node scoping questions (what a node asks, where it reads, where it writes)
6
+ * - Live scoped-data fetch for a node given an entityId
7
+ * - Execution-memory shapes before and after each node
8
+ * - Narrix discovery configuration per node
9
+ * - Full graph inspection: execution order, I/O edges between nodes, catalog references
10
+ */
11
+ export { getNodeScopingQuestion, getNodeMemoryShape, getNodeNarrixDiscovery, fetchNodeScopingData, inspectNode, resolveNodeSkillKey, } from './nodeInspection.js';
12
+ export { getGraphNodes, getGraphCatalogs, inspectGraph, getVirtualGraphEntryLayer, getVirtualGraphResponseLayer, materializeVirtualBoundaryDiagram, stripMaterializedVirtualBoundaryDiagram, } from './graphInspection.js';
13
+ export { validateCatalogPlanning, isCatalogBinding, isCatalogRequestEntry, } from './validateCatalogPlanning.js';
14
+ export type { CatalogPlanningValidationIssue } from './validateCatalogPlanning.js';
15
+ export { collectPredicatePaths, executionMemoryPathTail, executionMemoryTailsMatch, getNodeExecutionMemoryWriteTails, getNodeControlDependencies, } from './controlInspection.js';
16
+ export { getNodeSideEffects, inspectFinalizer, inspectNodeContract, inspectGraphContracts, } from './contractInspection.js';
17
+ export type { InspectNodeContractOptions } from './contractInspection.js';
18
+ export type { NodeScopingQuestion, NodeScopeSource, NodeScopeTarget, NodeScopingData, NodeMemoryShape, MemoryPath, NodeNarrixDiscovery, NodeInspection, GraphInspection, NodeIOEdge, GraphCatalogs, CatalogBindingSummary, GraphVirtualIO, GraphVirtualIONode, GraphVirtualIOEdge, GraphVirtualIONodeRole, VirtualGraphEntryLayer, VirtualGraphResponseLayer, MaterializeVirtualBoundaryDiagramOptions, MaterializedVirtualBoundaryDiagram, MaterializedVirtualBoundaryDiagramMeta, } from './types.js';
19
+ export { EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID, EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID, EXELLIX_VIRTUAL_BOUNDARY_NODE_METADATA_KEY, EXELLIX_VIRTUAL_BOUNDARY_EDGE_FLAG_KEY, } from './types.js';
20
+ export type { GraphDocumentMetadata } from '../types/refs.js';
21
+ export type { LocalSkillKey, NodeExecutionType, FactProvenance, ProvenancedSection, NodeInputBindingEntry, ScopedDataDependency, NodeInputContract, ExecutionMemoryWriteSpec, NodeOutputContract, NodeSideEffects, ControlBranchEntry, NodeControlContract, NodeValidationContract, FinalizerContractInspection, NodeContractInspection, GraphContractsInspection, } from './contractTypes.js';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Graph Inspection API
3
+ *
4
+ * Planning-level visibility into any exellix-graph JSON:
5
+ * - Per-node scoping questions (what a node asks, where it reads, where it writes)
6
+ * - Live scoped-data fetch for a node given an entityId
7
+ * - Execution-memory shapes before and after each node
8
+ * - Narrix discovery configuration per node
9
+ * - Full graph inspection: execution order, I/O edges between nodes, catalog references
10
+ */
11
+ // Functions
12
+ export { getNodeScopingQuestion, getNodeMemoryShape, getNodeNarrixDiscovery, fetchNodeScopingData, inspectNode, resolveNodeSkillKey, } from './nodeInspection.js';
13
+ export { getGraphNodes, getGraphCatalogs, inspectGraph, getVirtualGraphEntryLayer, getVirtualGraphResponseLayer, materializeVirtualBoundaryDiagram, stripMaterializedVirtualBoundaryDiagram, } from './graphInspection.js';
14
+ export { validateCatalogPlanning, isCatalogBinding, isCatalogRequestEntry, } from './validateCatalogPlanning.js';
15
+ export { collectPredicatePaths, executionMemoryPathTail, executionMemoryTailsMatch, getNodeExecutionMemoryWriteTails, getNodeControlDependencies, } from './controlInspection.js';
16
+ export { getNodeSideEffects, inspectFinalizer, inspectNodeContract, inspectGraphContracts, } from './contractInspection.js';
17
+ export { EXELLIX_VIRTUAL_GRAPH_ENTRY_NODE_ID, EXELLIX_VIRTUAL_GRAPH_RESPONSE_NODE_ID, EXELLIX_VIRTUAL_BOUNDARY_NODE_METADATA_KEY, EXELLIX_VIRTUAL_BOUNDARY_EDGE_FLAG_KEY, } from './types.js';