@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,526 @@
1
+ import { isLocalSkillKey } from '../runtime/localSkills/index.js';
2
+ import { readTaskNodeInputsConfig } from '../runtime/readTaskNodeInputsConfig.js';
3
+ import { getNodeMemoryShape, getNodeNarrixDiscovery, inspectNode, resolveNodeSkillKey, } from './nodeInspection.js';
4
+ import { getGraphNodes } from './graphInspection.js';
5
+ import { getNodeControlDependencies } from './controlInspection.js';
6
+ import { inspectGraph } from './graphInspection.js';
7
+ import { assertCanonicalGraphDocument } from '../runtime/validateCanonicalGraphDocument.js';
8
+ function isFinalizerNode(node) {
9
+ return node.type === 'finalizer';
10
+ }
11
+ function isTaskNode(node) {
12
+ return !isFinalizerNode(node);
13
+ }
14
+ function stripRefPrefix(ref) {
15
+ const prefixes = [
16
+ 'executionMemory.',
17
+ 'jobMemory.',
18
+ 'variables.',
19
+ 'taskMemory.',
20
+ 'input.',
21
+ 'xynthesized.job.',
22
+ 'xynthesized.task.',
23
+ ];
24
+ for (const p of prefixes) {
25
+ if (ref.startsWith(p))
26
+ return ref.slice(p.length);
27
+ }
28
+ return ref;
29
+ }
30
+ function classifyMappingRef(ref) {
31
+ if (ref.startsWith('jobMemory.'))
32
+ return 'jobMemory';
33
+ if (ref.startsWith('variables.'))
34
+ return 'variables';
35
+ if (ref.startsWith('taskMemory.'))
36
+ return 'taskMemory';
37
+ if (ref.startsWith('executionMemory.') ||
38
+ ref.startsWith('input.') ||
39
+ ref.startsWith('execution.') ||
40
+ ref.startsWith('node.') ||
41
+ ref.startsWith('output.')) {
42
+ return 'executionMemory';
43
+ }
44
+ return 'other';
45
+ }
46
+ function deriveExecutionType(node) {
47
+ if (isFinalizerNode(node)) {
48
+ return { executionType: 'finalizer', localSkillKind: undefined, skillKey: undefined };
49
+ }
50
+ const skillKey = resolveNodeSkillKey(node);
51
+ if (!skillKey) {
52
+ return { executionType: undefined, localSkillKind: undefined, skillKey: undefined };
53
+ }
54
+ if (isLocalSkillKey(skillKey)) {
55
+ return {
56
+ executionType: 'local-skill',
57
+ localSkillKind: skillKey,
58
+ skillKey,
59
+ };
60
+ }
61
+ return { executionType: 'ai-task', localSkillKind: undefined, skillKey };
62
+ }
63
+ function buildInputsBindings(task) {
64
+ const inputs = readTaskNodeInputsConfig(task);
65
+ if (Object.keys(inputs).length === 0)
66
+ return [];
67
+ const out = [];
68
+ for (const [key, val] of Object.entries(inputs)) {
69
+ if (val == null) {
70
+ out.push({ key, kind: 'literal' });
71
+ continue;
72
+ }
73
+ if (typeof val === 'string') {
74
+ out.push({ key, kind: 'literal' });
75
+ continue;
76
+ }
77
+ if (typeof val === 'object') {
78
+ const v = val;
79
+ if (v.type === 'executionMemoryPath' && typeof v.path === 'string') {
80
+ out.push({ key, kind: 'executionMemoryPath', path: v.path });
81
+ continue;
82
+ }
83
+ if (typeof v['$path'] === 'string') {
84
+ const raw = v['$path'];
85
+ out.push({ key, kind: 'pathRef', path: stripRefPrefix(raw), rawRef: raw });
86
+ continue;
87
+ }
88
+ out.push({ key, kind: 'other' });
89
+ continue;
90
+ }
91
+ out.push({ key, kind: 'other' });
92
+ }
93
+ return out;
94
+ }
95
+ function partitionMappingRefs(map) {
96
+ const executionMemory = [];
97
+ const jobMemory = [];
98
+ const variables = [];
99
+ const taskMemory = [];
100
+ if (!map)
101
+ return { executionMemory, jobMemory, variables, taskMemory };
102
+ for (const [label, ref] of Object.entries(map)) {
103
+ const kind = classifyMappingRef(ref);
104
+ const path = stripRefPrefix(ref);
105
+ const mp = { path, source: `jobContextMapping.map.${label}` };
106
+ if (kind === 'jobMemory')
107
+ jobMemory.push(mp);
108
+ else if (kind === 'variables')
109
+ variables.push(mp);
110
+ else if (kind === 'taskMemory')
111
+ taskMemory.push(mp);
112
+ else
113
+ executionMemory.push(mp);
114
+ }
115
+ return { executionMemory, jobMemory, variables, taskMemory };
116
+ }
117
+ function mappingSourceReads(task, mappingKey) {
118
+ const mapping = task[mappingKey]?.map;
119
+ if (!mapping)
120
+ return [];
121
+ const reads = [];
122
+ for (const [targetKey, ref] of Object.entries(mapping)) {
123
+ const kind = classifyMappingRef(ref);
124
+ if (kind === 'executionMemory' || kind === 'jobMemory' || kind === 'variables' || kind === 'taskMemory') {
125
+ reads.push({
126
+ path: stripRefPrefix(ref),
127
+ source: `${mappingKey}.map.${targetKey}`,
128
+ });
129
+ }
130
+ }
131
+ return reads;
132
+ }
133
+ function inputsObjectReads(task) {
134
+ const reads = [];
135
+ const inputs = readTaskNodeInputsConfig(task);
136
+ for (const [key, val] of Object.entries(inputs)) {
137
+ if (!val || typeof val !== 'object')
138
+ continue;
139
+ const v = val;
140
+ if (v.type === 'executionMemoryPath' && typeof v.path === 'string') {
141
+ reads.push({ path: v.path, source: `inputsConfig.${key}` });
142
+ }
143
+ else if (typeof v['$path'] === 'string') {
144
+ reads.push({
145
+ path: stripRefPrefix(v['$path']),
146
+ source: `inputsConfig.${key}`,
147
+ });
148
+ }
149
+ }
150
+ return reads;
151
+ }
152
+ function scopedDataDeps(task) {
153
+ const tc = task.taskConfiguration;
154
+ if (!tc)
155
+ return [];
156
+ const sk = resolveNodeSkillKey(task);
157
+ if (sk !== 'scoped-data-reader')
158
+ return [];
159
+ const { scopingMapId, entityIdPath, questionId, pack } = tc;
160
+ if (!scopingMapId && !questionId && !Array.isArray(pack))
161
+ return [];
162
+ return [
163
+ {
164
+ scopingMapId: typeof scopingMapId === 'string' ? scopingMapId : undefined,
165
+ entityIdPath: typeof entityIdPath === 'string' ? entityIdPath : undefined,
166
+ questionId: typeof questionId === 'string' ? questionId : undefined,
167
+ pack: Array.isArray(pack) ? pack : undefined,
168
+ },
169
+ ];
170
+ }
171
+ function finalizerInputBindings(fn) {
172
+ const out = [];
173
+ for (const [key, binding] of Object.entries(fn.inputs ?? {})) {
174
+ if (binding.type === 'executionMemoryPath' || binding.type === 'outputsMemoryPath') {
175
+ out.push({
176
+ key,
177
+ kind: binding.type,
178
+ path: binding.path,
179
+ });
180
+ }
181
+ else if (binding.type === 'literal') {
182
+ out.push({ key, kind: 'literal' });
183
+ }
184
+ else {
185
+ out.push({ key, kind: 'other' });
186
+ }
187
+ }
188
+ return out;
189
+ }
190
+ function buildInputContract(node, memoryShape) {
191
+ if (isFinalizerNode(node)) {
192
+ const fn = node;
193
+ const reads = memoryShape.before.reads;
194
+ return {
195
+ inputsBindings: { items: finalizerInputBindings(fn), provenance: 'declared' },
196
+ executionMemoryReads: { items: reads, provenance: 'declared' },
197
+ jobContextReads: { items: [], provenance: 'declared' },
198
+ variableReads: { items: [], provenance: 'declared' },
199
+ taskMemoryReads: { items: [], provenance: 'declared' },
200
+ outputMappingReads: { items: [], provenance: 'declared' },
201
+ executionMappingReads: { items: [], provenance: 'declared' },
202
+ scopedDataDependencies: { items: [], provenance: 'declared' },
203
+ narrixDependencies: { items: [], provenance: 'declared' },
204
+ webScopeDependencies: { items: [], provenance: 'declared' },
205
+ upstreamExpectedWrites: {
206
+ items: memoryShape.before.expects,
207
+ provenance: 'derived',
208
+ },
209
+ };
210
+ }
211
+ const task = node;
212
+ const jm = partitionMappingRefs(task.jobContextMapping?.map);
213
+ const inputObjReads = inputsObjectReads(task);
214
+ const execReads = [...jm.executionMemory, ...inputObjReads];
215
+ const narrixDisc = getNodeNarrixDiscovery(node);
216
+ const webScopeItems = narrixDisc?.webScope.enabled && narrixDisc.enabled
217
+ ? [
218
+ {
219
+ enabled: true,
220
+ entityIdPath: narrixDisc.webScope.entityIdPath,
221
+ entityTypePath: narrixDisc.webScope.entityTypePath,
222
+ questions: narrixDisc.webScope.questions,
223
+ },
224
+ ]
225
+ : [];
226
+ return {
227
+ inputsBindings: { items: buildInputsBindings(task), provenance: 'declared' },
228
+ executionMemoryReads: { items: execReads, provenance: 'derived' },
229
+ jobContextReads: { items: jm.jobMemory, provenance: 'derived' },
230
+ variableReads: { items: jm.variables, provenance: 'derived' },
231
+ taskMemoryReads: { items: jm.taskMemory, provenance: 'derived' },
232
+ outputMappingReads: { items: [], provenance: 'declared' },
233
+ executionMappingReads: { items: mappingSourceReads(task, 'executionMapping'), provenance: 'declared' },
234
+ scopedDataDependencies: { items: scopedDataDeps(task), provenance: 'declared' },
235
+ narrixDependencies: {
236
+ items: narrixDisc ? [narrixDisc] : [],
237
+ provenance: narrixDisc ? 'declared' : 'declared',
238
+ },
239
+ webScopeDependencies: {
240
+ items: webScopeItems,
241
+ provenance: webScopeItems.length ? 'declared' : 'declared',
242
+ },
243
+ upstreamExpectedWrites: {
244
+ items: memoryShape.before.expects,
245
+ provenance: 'derived',
246
+ },
247
+ };
248
+ }
249
+ function buildOutputContract(node) {
250
+ if (isFinalizerNode(node)) {
251
+ const fn = node;
252
+ const desc = fn.finalizerType === 'synthesize'
253
+ ? 'Graph final output via synthesize utility (AI) + optional outputSchema validation'
254
+ : `Graph final output via ${fn.finalizerType} finalizer (deterministic assembly)`;
255
+ const outputsWrites = [];
256
+ if (fn.outputMapping?.path) {
257
+ outputsWrites.push({
258
+ path: fn.outputMapping.path,
259
+ mode: fn.outputMapping.mode,
260
+ source: 'outputMapping.path',
261
+ });
262
+ }
263
+ return {
264
+ executionMemoryWrites: { items: [], provenance: 'declared' },
265
+ outputsMemoryWrites: { items: outputsWrites, provenance: 'declared' },
266
+ storageReads: { items: [], provenance: 'runtime-known' },
267
+ storageWrites: { items: [], provenance: 'runtime-known' },
268
+ webContextWrites: { items: [], provenance: 'runtime-known' },
269
+ narrixWrites: { items: [], provenance: 'runtime-known' },
270
+ synthesizedContextWrites: { items: [], provenance: 'runtime-known' },
271
+ finalOutputWrites: { items: [{ description: desc }], provenance: 'declared' },
272
+ produces: { items: [], provenance: 'declared' },
273
+ routingOutputs: { items: [], provenance: 'declared' },
274
+ };
275
+ }
276
+ const task = node;
277
+ const readability = task.metadata?.graphReadability;
278
+ const produces = Array.isArray(readability?.produces) ? readability.produces : [];
279
+ const routingOutputs = readability?.kind === 'routing' ? produces : [];
280
+ const execWrites = [];
281
+ if (task.executionMapping?.path) {
282
+ execWrites.push({
283
+ path: task.executionMapping.path,
284
+ mode: task.executionMapping.mode,
285
+ source: 'executionMapping.path',
286
+ });
287
+ }
288
+ const narrixDisc = getNodeNarrixDiscovery(node);
289
+ const narrixWrites = [];
290
+ if (narrixDisc?.enabled) {
291
+ narrixWrites.push({ path: '_narrix.scoping.signals', source: 'narrix (runtime-known)' }, { path: '_narrix.scoping.stories', source: 'narrix (runtime-known)' });
292
+ }
293
+ const tc = task.taskConfiguration;
294
+ const webCfg = tc?.aiTaskProfile;
295
+ const webScoping = webCfg?.webScoping;
296
+ const webWrites = [];
297
+ if (webScoping && webScoping.enabled === true) {
298
+ webWrites.push({ path: 'webContext', source: 'taskConfiguration.aiTaskProfile.webScoping → executeNode (runtime-known)' });
299
+ }
300
+ const synthWrites = [];
301
+ const inputSynth = webCfg?.inputSynthesis;
302
+ if (inputSynth?.enabled === true) {
303
+ synthWrites.push({
304
+ path: 'synthesizedContext',
305
+ source: 'taskConfiguration.aiTaskProfile.inputSynthesis PRE (runtime-known)',
306
+ });
307
+ }
308
+ const sk = resolveNodeSkillKey(task);
309
+ const storageReads = [];
310
+ const storageWrites = [];
311
+ if (sk === 'scoped-data-reader') {
312
+ storageReads.push({ note: 'Reads Memorix entity item via scoped-data-reader (fetchMemorixItem)' });
313
+ }
314
+ if (sk === 'scoped-answer-writer') {
315
+ storageWrites.push({ note: 'Persists inferences/decisions content types via scoped-answer-writer (writeMemorixRecord)' });
316
+ }
317
+ if (sk === 'scoped-answer-assembler') {
318
+ storageWrites.push({
319
+ note: 'Prepares persistence payload (typically consumed by scoped-answer-writer)',
320
+ });
321
+ }
322
+ return {
323
+ executionMemoryWrites: { items: execWrites, provenance: 'declared' },
324
+ outputsMemoryWrites: { items: [], provenance: 'declared' },
325
+ storageReads: { items: storageReads, provenance: 'runtime-known' },
326
+ storageWrites: { items: storageWrites, provenance: 'runtime-known' },
327
+ webContextWrites: { items: webWrites, provenance: 'runtime-known' },
328
+ narrixWrites: { items: narrixWrites, provenance: 'runtime-known' },
329
+ synthesizedContextWrites: { items: synthWrites, provenance: 'runtime-known' },
330
+ finalOutputWrites: { items: [], provenance: 'declared' },
331
+ produces: { items: produces, provenance: 'declared' },
332
+ routingOutputs: { items: routingOutputs, provenance: 'declared' },
333
+ };
334
+ }
335
+ export function getNodeSideEffects(node) {
336
+ const { executionType, localSkillKind, skillKey } = deriveExecutionType(node);
337
+ const notes = [];
338
+ const readsScopedStorage = localSkillKind === 'scoped-data-reader';
339
+ const writesScopedStorage = localSkillKind === 'scoped-answer-writer' || localSkillKind === 'scoped-answer-assembler';
340
+ let callsAiTasks = executionType === 'ai-task';
341
+ let runsNarrix = false;
342
+ let runsLocalWebScope = false;
343
+ let runsPreSynthesis = false;
344
+ let producesFinalOutput = executionType === 'finalizer';
345
+ if (isTaskNode(node)) {
346
+ const tc = node.taskConfiguration;
347
+ runsNarrix = tc?.narrix != null && typeof tc.narrix === 'object';
348
+ const web = tc?.aiTaskProfile;
349
+ const ws = web?.webScoping;
350
+ runsLocalWebScope = ws?.enabled === true;
351
+ const inputSynth = web?.inputSynthesis;
352
+ runsPreSynthesis = inputSynth?.enabled === true;
353
+ }
354
+ if (isFinalizerNode(node) && node.finalizerType === 'synthesize') {
355
+ callsAiTasks = true;
356
+ notes.push('Synthesize finalizer invokes ai-tasks utility (runtime-known).');
357
+ }
358
+ if (executionType === undefined && skillKey === undefined) {
359
+ notes.push('No skillKey resolved; execution class unknown until graph validation.');
360
+ }
361
+ return {
362
+ readsScopedStorage,
363
+ writesScopedStorage,
364
+ callsAiTasks,
365
+ runsNarrix,
366
+ runsLocalWebScope,
367
+ runsPreSynthesis,
368
+ producesFinalOutput,
369
+ notes: notes.length ? notes : undefined,
370
+ provenance: 'derived',
371
+ };
372
+ }
373
+ function getNodeById(graph, id) {
374
+ return getGraphNodes(graph).find((n) => n.id === id);
375
+ }
376
+ function answerPathForQuestionDriven(graph, spec, itemKey) {
377
+ if (spec.answerPath) {
378
+ return { path: spec.answerPath, source: `config.items.${itemKey}.answerPath` };
379
+ }
380
+ if (!graph)
381
+ return undefined;
382
+ const n = getNodeById(graph, spec.nodeId);
383
+ if (!n || isFinalizerNode(n))
384
+ return undefined;
385
+ const path = n.executionMapping?.path;
386
+ return path ? { path, source: `config.items.${itemKey}.node.executionMapping.path` } : undefined;
387
+ }
388
+ /**
389
+ * Finalizer-only contract inspection. Returns null if the node is not a finalizer.
390
+ */
391
+ export function inspectFinalizer(node, options) {
392
+ if (!isFinalizerNode(node))
393
+ return null;
394
+ const fn = node;
395
+ const graph = options?.graph;
396
+ const reads = [];
397
+ const metaReads = [];
398
+ for (const [name, binding] of Object.entries(fn.inputs ?? {})) {
399
+ if ((binding.type === 'executionMemoryPath' || binding.type === 'outputsMemoryPath') && binding.path) {
400
+ reads.push({ path: binding.path, source: `inputs.${name}` });
401
+ }
402
+ }
403
+ const cfg = fn.config;
404
+ if (cfg?.strategy === 'report-schema') {
405
+ const sections = cfg.sections;
406
+ if (sections) {
407
+ for (const [k, spec] of Object.entries(sections)) {
408
+ if (spec?.path) {
409
+ reads.push({ path: spec.path, source: `config.sections.${k}` });
410
+ }
411
+ }
412
+ }
413
+ }
414
+ if (cfg?.strategy === 'question-driven') {
415
+ const items = cfg.items;
416
+ if (items) {
417
+ for (const [k, spec] of Object.entries(items)) {
418
+ const answerPath = answerPathForQuestionDriven(graph, spec, k);
419
+ if (answerPath) {
420
+ reads.push(answerPath);
421
+ }
422
+ }
423
+ }
424
+ const meta = cfg.meta;
425
+ if (meta) {
426
+ for (const [k, b] of Object.entries(meta)) {
427
+ if ((b?.type === 'executionMemoryPath' || b?.type === 'outputsMemoryPath') && b.path) {
428
+ metaReads.push({ path: b.path, source: `config.meta.${k}` });
429
+ }
430
+ }
431
+ }
432
+ }
433
+ const callsAiTasks = fn.finalizerType === 'synthesize';
434
+ const synthesizeUtilityKey = callsAiTasks && cfg && typeof cfg.utilityKey === 'string'
435
+ ? cfg.utilityKey
436
+ : undefined;
437
+ return {
438
+ nodeId: fn.id,
439
+ finalizerType: fn.finalizerType,
440
+ inputs: { ...fn.inputs },
441
+ config: fn.config,
442
+ outputSchema: fn.outputSchema,
443
+ executionMemoryReads: { items: reads, provenance: 'declared' },
444
+ metaExecutionMemoryReads: { items: metaReads, provenance: 'derived' },
445
+ callsAiTasks,
446
+ synthesizeUtilityKey,
447
+ };
448
+ }
449
+ function buildValidationContract(node) {
450
+ if (isFinalizerNode(node)) {
451
+ const fn = node;
452
+ return {
453
+ outputValidation: { items: null, provenance: 'declared' },
454
+ outputSchema: {
455
+ items: fn.outputSchema ?? null,
456
+ provenance: 'declared',
457
+ },
458
+ validatedBeforeMapping: { items: false, provenance: 'runtime-known' },
459
+ metadataConstraints: { items: {}, provenance: 'declared' },
460
+ };
461
+ }
462
+ const task = node;
463
+ const ov = task.outputValidation ?? null;
464
+ return {
465
+ outputValidation: { items: ov, provenance: 'declared' },
466
+ outputSchema: { items: null, provenance: 'declared' },
467
+ validatedBeforeMapping: {
468
+ items: Boolean(ov?.rules && ov.rules.length > 0),
469
+ provenance: 'runtime-known',
470
+ },
471
+ metadataConstraints: { items: {}, provenance: 'declared' },
472
+ };
473
+ }
474
+ /**
475
+ * Unified per-node contract: execution class, grouped I/O, side effects, validation, optional control graph.
476
+ */
477
+ export function inspectNodeContract(node, options) {
478
+ const upstream = options?.upstreamWritePaths;
479
+ const graph = options?.graph;
480
+ const base = inspectNode(node, upstream, graph);
481
+ const memoryShape = getNodeMemoryShape(node, upstream, graph);
482
+ const { executionType, localSkillKind, skillKey } = deriveExecutionType(node);
483
+ const inputs = buildInputContract(node, memoryShape);
484
+ const outputs = buildOutputContract(node);
485
+ const sideEffects = getNodeSideEffects(node);
486
+ const validation = buildValidationContract(node);
487
+ const control = graph != null ? getNodeControlDependencies(graph, node.id) : null;
488
+ const finalizerDetail = inspectFinalizer(node, { graph });
489
+ return {
490
+ nodeId: node.id,
491
+ executionType,
492
+ localSkillKind,
493
+ skillKey,
494
+ nodeType: node.type ?? 'task',
495
+ base,
496
+ inputs,
497
+ outputs,
498
+ sideEffects,
499
+ control,
500
+ validation,
501
+ finalizerDetail,
502
+ };
503
+ }
504
+ /**
505
+ * Graph-level contract view: full node contracts plus execution order and I/O edges.
506
+ */
507
+ export function inspectGraphContracts(graph) {
508
+ assertCanonicalGraphDocument(graph, { graphId: graph?.id });
509
+ const gi = inspectGraph(graph);
510
+ const nodes = {};
511
+ for (const id of Object.keys(gi.nodes)) {
512
+ const n = getGraphNodes(graph).find((x) => x.id === id);
513
+ if (!n)
514
+ continue;
515
+ const upstream = gi.nodes[id].memoryShape.before.expects.map((e) => e.path);
516
+ nodes[id] = inspectNodeContract(n, { upstreamWritePaths: upstream, graph });
517
+ }
518
+ return {
519
+ graphId: gi.graphId,
520
+ executionOrder: gi.executionOrder,
521
+ nodes,
522
+ edges: gi.edges,
523
+ ioEdges: gi.ioEdges,
524
+ virtualIO: gi.virtualIO,
525
+ };
526
+ }
@@ -0,0 +1,137 @@
1
+ import type { GraphEdge, GraphPredicate, OutputSchema, TaskOutputValidation } from '../types/refs.js';
2
+ import type { LocalSkillKey } from '../runtime/localSkills/index.js';
3
+ import type { MemoryPath, NodeInspection, NodeNarrixDiscovery } from './types.js';
4
+ export type { LocalSkillKey };
5
+ /** Normalized runtime operation class for a node (derived from graph + known intercepts). */
6
+ export type NodeExecutionType = 'ai-task' | 'local-skill' | 'finalizer';
7
+ export type FactProvenance = 'declared' | 'derived' | 'runtime-known';
8
+ export type ProvenancedSection<T> = {
9
+ items: T;
10
+ provenance: FactProvenance;
11
+ };
12
+ /** Single binding from `inputs` (declarative). */
13
+ export type NodeInputBindingEntry = {
14
+ key: string;
15
+ kind: 'literal' | 'executionMemoryPath' | 'outputsMemoryPath' | 'pathRef' | 'other';
16
+ /** Execution-memory-relative path when applicable. */
17
+ path?: string;
18
+ /** Original $path / mapping string when applicable. */
19
+ rawRef?: string;
20
+ };
21
+ export type ScopedDataDependency = {
22
+ scopingMapId?: string;
23
+ entityIdPath?: string;
24
+ questionId?: string;
25
+ pack?: unknown[];
26
+ };
27
+ export type NodeInputContract = {
28
+ inputsBindings: ProvenancedSection<NodeInputBindingEntry[]>;
29
+ executionMemoryReads: ProvenancedSection<MemoryPath[]>;
30
+ jobContextReads: ProvenancedSection<MemoryPath[]>;
31
+ variableReads: ProvenancedSection<MemoryPath[]>;
32
+ taskMemoryReads: ProvenancedSection<MemoryPath[]>;
33
+ outputMappingReads: ProvenancedSection<MemoryPath[]>;
34
+ executionMappingReads: ProvenancedSection<MemoryPath[]>;
35
+ scopedDataDependencies: ProvenancedSection<ScopedDataDependency[]>;
36
+ /** Empty when narrix is not configured on the node. */
37
+ narrixDependencies: ProvenancedSection<NodeNarrixDiscovery[]>;
38
+ /** Empty when narrix web scope is off or narrix absent. */
39
+ webScopeDependencies: ProvenancedSection<{
40
+ enabled: boolean;
41
+ entityIdPath?: string;
42
+ entityTypePath?: string;
43
+ questions?: unknown;
44
+ }[]>;
45
+ upstreamExpectedWrites: ProvenancedSection<MemoryPath[]>;
46
+ };
47
+ export type ExecutionMemoryWriteSpec = {
48
+ path: string;
49
+ mode?: string;
50
+ source?: string;
51
+ };
52
+ export type NodeOutputContract = {
53
+ executionMemoryWrites: ProvenancedSection<ExecutionMemoryWriteSpec[]>;
54
+ outputsMemoryWrites: ProvenancedSection<ExecutionMemoryWriteSpec[]>;
55
+ storageReads: ProvenancedSection<{
56
+ note?: string;
57
+ }[]>;
58
+ storageWrites: ProvenancedSection<{
59
+ note?: string;
60
+ }[]>;
61
+ webContextWrites: ProvenancedSection<ExecutionMemoryWriteSpec[]>;
62
+ narrixWrites: ProvenancedSection<ExecutionMemoryWriteSpec[]>;
63
+ synthesizedContextWrites: ProvenancedSection<ExecutionMemoryWriteSpec[]>;
64
+ finalOutputWrites: ProvenancedSection<{
65
+ description: string;
66
+ }[]>;
67
+ produces: ProvenancedSection<string[]>;
68
+ routingOutputs: ProvenancedSection<string[]>;
69
+ };
70
+ export type NodeSideEffects = {
71
+ readsScopedStorage: boolean;
72
+ writesScopedStorage: boolean;
73
+ callsAiTasks: boolean;
74
+ runsNarrix: boolean;
75
+ runsLocalWebScope: boolean;
76
+ runsPreSynthesis: boolean;
77
+ producesFinalOutput: boolean;
78
+ /** Human-readable notes where classification mixes declared and runtime-known. */
79
+ notes?: string[];
80
+ provenance: FactProvenance;
81
+ };
82
+ export type ControlBranchEntry = {
83
+ to: string;
84
+ from: string;
85
+ when?: GraphPredicate;
86
+ matchedExecutionMemoryPaths: string[];
87
+ };
88
+ export type NodeControlContract = {
89
+ isRoutingNode: boolean;
90
+ routingHintFromReadability: boolean;
91
+ edgesConditionalOnThisWriter: ControlBranchEntry[];
92
+ /** All predicate leaf paths from edges gated by this node's writes (executionMemory roots). */
93
+ predicatePathsThatMatchedWrites: string[];
94
+ downstreamBranchMap: ControlBranchEntry[];
95
+ provenance: FactProvenance;
96
+ };
97
+ export type NodeValidationContract = {
98
+ outputValidation: ProvenancedSection<TaskOutputValidation | null>;
99
+ outputSchema: ProvenancedSection<OutputSchema | null>;
100
+ /** Exellix runs outputValidation before executionMapping when rules are present (executeNode). */
101
+ validatedBeforeMapping: ProvenancedSection<boolean>;
102
+ metadataConstraints: ProvenancedSection<Record<string, unknown>>;
103
+ };
104
+ export type FinalizerContractInspection = {
105
+ nodeId: string;
106
+ finalizerType: string;
107
+ inputs: Record<string, unknown>;
108
+ config: unknown;
109
+ outputSchema: OutputSchema | undefined;
110
+ executionMemoryReads: ProvenancedSection<MemoryPath[]>;
111
+ metaExecutionMemoryReads: ProvenancedSection<MemoryPath[]>;
112
+ callsAiTasks: boolean;
113
+ synthesizeUtilityKey?: string;
114
+ };
115
+ export type NodeContractInspection = {
116
+ nodeId: string;
117
+ executionType: NodeExecutionType | undefined;
118
+ localSkillKind: LocalSkillKey | undefined;
119
+ skillKey: string | undefined;
120
+ nodeType: string;
121
+ base: NodeInspection;
122
+ inputs: NodeInputContract;
123
+ outputs: NodeOutputContract;
124
+ sideEffects: NodeSideEffects;
125
+ control: NodeControlContract | null;
126
+ validation: NodeValidationContract;
127
+ finalizerDetail: FinalizerContractInspection | null;
128
+ };
129
+ export type GraphContractsInspection = {
130
+ graphId: string;
131
+ executionOrder: string[];
132
+ nodes: Record<string, NodeContractInspection>;
133
+ edges: GraphEdge[];
134
+ ioEdges: import('./types.js').NodeIOEdge[];
135
+ /** Same virtual Layer 01/08 boundaries as `inspectGraph` (not executable DAG nodes). */
136
+ virtualIO: import('./types.js').GraphVirtualIO;
137
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ import type { Graph, GraphNode, GraphPredicate } from '../types/refs.js';
2
+ import type { NodeControlContract } from './contractTypes.js';
3
+ /**
4
+ * Recursively collects leaf `path` strings from a graph edge predicate.
5
+ */
6
+ export declare function collectPredicatePaths(predicate: GraphPredicate | undefined): string[];
7
+ /** Execution-memory dot-tail (no `executionMemory.` prefix). */
8
+ export declare function executionMemoryPathTail(fullPath: string): string | null;
9
+ /**
10
+ * Same prefix semantics as io edge intersection: exact or parent/child path match.
11
+ */
12
+ export declare function executionMemoryTailsMatch(a: string, b: string): boolean;
13
+ /**
14
+ * All execution-memory write tails this node contributes (for control-flow matching).
15
+ * Includes executionMapping, narrix slots, webContext, synthesizedContext when applicable.
16
+ */
17
+ export declare function getNodeExecutionMemoryWriteTails(node: GraphNode): string[];
18
+ /**
19
+ * Lists edges whose `when` predicates read execution-memory paths produced by `nodeId`,
20
+ * and routing hints from graphReadability.
21
+ */
22
+ export declare function getNodeControlDependencies(graph: Graph, nodeId: string): NodeControlContract;