@exellix/exellix-runtime 3.5.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.
Files changed (318) hide show
  1. package/README.md +422 -0
  2. package/dist/catalox-inventory/catalox-execution-matrix-inventory-cli.d.ts +4 -0
  3. package/dist/catalox-inventory/catalox-execution-matrix-inventory-cli.d.ts.map +1 -0
  4. package/dist/catalox-inventory/catalox-execution-matrix-inventory-cli.js +311 -0
  5. package/dist/catalox-inventory/catalox-execution-matrix-inventory-cli.js.map +1 -0
  6. package/dist/catalox-inventory/catalox-execution-matrix-inventory.d.ts +64 -0
  7. package/dist/catalox-inventory/catalox-execution-matrix-inventory.d.ts.map +1 -0
  8. package/dist/catalox-inventory/catalox-execution-matrix-inventory.js +226 -0
  9. package/dist/catalox-inventory/catalox-execution-matrix-inventory.js.map +1 -0
  10. package/dist/catalox-inventory/catalox-xmemory-entity-count-report.d.ts +145 -0
  11. package/dist/catalox-inventory/catalox-xmemory-entity-count-report.d.ts.map +1 -0
  12. package/dist/catalox-inventory/catalox-xmemory-entity-count-report.js +477 -0
  13. package/dist/catalox-inventory/catalox-xmemory-entity-count-report.js.map +1 -0
  14. package/dist/catalox-inventory/catalox-xmemory-entity-count-report.spec.d.ts +2 -0
  15. package/dist/catalox-inventory/catalox-xmemory-entity-count-report.spec.d.ts.map +1 -0
  16. package/dist/catalox-inventory/catalox-xmemory-entity-count-report.spec.js +34 -0
  17. package/dist/catalox-inventory/catalox-xmemory-entity-count-report.spec.js.map +1 -0
  18. package/dist/cli/argv.d.ts +5 -0
  19. package/dist/cli/argv.d.ts.map +1 -0
  20. package/dist/cli/argv.js +32 -0
  21. package/dist/cli/argv.js.map +1 -0
  22. package/dist/cli/commands/health.d.ts +2 -0
  23. package/dist/cli/commands/health.d.ts.map +1 -0
  24. package/dist/cli/commands/health.js +23 -0
  25. package/dist/cli/commands/health.js.map +1 -0
  26. package/dist/cli/commands/matrix-link.d.ts +2 -0
  27. package/dist/cli/commands/matrix-link.d.ts.map +1 -0
  28. package/dist/cli/commands/matrix-link.js +56 -0
  29. package/dist/cli/commands/matrix-link.js.map +1 -0
  30. package/dist/cli/commands/matrix-read.d.ts +2 -0
  31. package/dist/cli/commands/matrix-read.d.ts.map +1 -0
  32. package/dist/cli/commands/matrix-read.js +73 -0
  33. package/dist/cli/commands/matrix-read.js.map +1 -0
  34. package/dist/cli/env.d.ts +6 -0
  35. package/dist/cli/env.d.ts.map +1 -0
  36. package/dist/cli/env.js +39 -0
  37. package/dist/cli/env.js.map +1 -0
  38. package/dist/cli/exellix-runtime-cli.d.ts +3 -0
  39. package/dist/cli/exellix-runtime-cli.d.ts.map +1 -0
  40. package/dist/cli/exellix-runtime-cli.js +55 -0
  41. package/dist/cli/exellix-runtime-cli.js.map +1 -0
  42. package/dist/cli/help.d.ts +19 -0
  43. package/dist/cli/help.d.ts.map +1 -0
  44. package/dist/cli/help.js +94 -0
  45. package/dist/cli/help.js.map +1 -0
  46. package/dist/client-toolbox/bundle.d.ts +17 -0
  47. package/dist/client-toolbox/bundle.d.ts.map +1 -0
  48. package/dist/client-toolbox/bundle.js +17 -0
  49. package/dist/client-toolbox/bundle.js.map +1 -0
  50. package/dist/client-toolbox/client-toolbox.spec.d.ts +2 -0
  51. package/dist/client-toolbox/client-toolbox.spec.d.ts.map +1 -0
  52. package/dist/client-toolbox/client-toolbox.spec.js +145 -0
  53. package/dist/client-toolbox/client-toolbox.spec.js.map +1 -0
  54. package/dist/client-toolbox/index.d.ts +4 -0
  55. package/dist/client-toolbox/index.d.ts.map +1 -0
  56. package/dist/client-toolbox/index.js +4 -0
  57. package/dist/client-toolbox/index.js.map +1 -0
  58. package/dist/client-toolbox/matrix-config.d.ts +67 -0
  59. package/dist/client-toolbox/matrix-config.d.ts.map +1 -0
  60. package/dist/client-toolbox/matrix-config.js +140 -0
  61. package/dist/client-toolbox/matrix-config.js.map +1 -0
  62. package/dist/client-toolbox/matrix-materialize.d.ts +56 -0
  63. package/dist/client-toolbox/matrix-materialize.d.ts.map +1 -0
  64. package/dist/client-toolbox/matrix-materialize.js +130 -0
  65. package/dist/client-toolbox/matrix-materialize.js.map +1 -0
  66. package/dist/dev/matrix-read-dashboard-smoke.d.ts +2 -0
  67. package/dist/dev/matrix-read-dashboard-smoke.d.ts.map +1 -0
  68. package/dist/dev/matrix-read-dashboard-smoke.js +12 -0
  69. package/dist/dev/matrix-read-dashboard-smoke.js.map +1 -0
  70. package/dist/dev/runtime-real-dev-server.d.ts +2 -0
  71. package/dist/dev/runtime-real-dev-server.d.ts.map +1 -0
  72. package/dist/dev/runtime-real-dev-server.js +90 -0
  73. package/dist/dev/runtime-real-dev-server.js.map +1 -0
  74. package/dist/execution-matrix/catalox-loader.d.ts +55 -0
  75. package/dist/execution-matrix/catalox-loader.d.ts.map +1 -0
  76. package/dist/execution-matrix/catalox-loader.js +199 -0
  77. package/dist/execution-matrix/catalox-loader.js.map +1 -0
  78. package/dist/execution-matrix/catalox-matrix-host.d.ts +20 -0
  79. package/dist/execution-matrix/catalox-matrix-host.d.ts.map +1 -0
  80. package/dist/execution-matrix/catalox-matrix-host.js +19 -0
  81. package/dist/execution-matrix/catalox-matrix-host.js.map +1 -0
  82. package/dist/execution-matrix/collections.d.ts +16 -0
  83. package/dist/execution-matrix/collections.d.ts.map +1 -0
  84. package/dist/execution-matrix/collections.js +75 -0
  85. package/dist/execution-matrix/collections.js.map +1 -0
  86. package/dist/execution-matrix/config-store.d.ts +104 -0
  87. package/dist/execution-matrix/config-store.d.ts.map +1 -0
  88. package/dist/execution-matrix/config-store.js +273 -0
  89. package/dist/execution-matrix/config-store.js.map +1 -0
  90. package/dist/execution-matrix/constants.d.ts +19 -0
  91. package/dist/execution-matrix/constants.d.ts.map +1 -0
  92. package/dist/execution-matrix/constants.js +19 -0
  93. package/dist/execution-matrix/constants.js.map +1 -0
  94. package/dist/execution-matrix/contracts.d.ts +568 -0
  95. package/dist/execution-matrix/contracts.d.ts.map +1 -0
  96. package/dist/execution-matrix/contracts.js +44 -0
  97. package/dist/execution-matrix/contracts.js.map +1 -0
  98. package/dist/execution-matrix/data-source.d.ts +43 -0
  99. package/dist/execution-matrix/data-source.d.ts.map +1 -0
  100. package/dist/execution-matrix/data-source.js +307 -0
  101. package/dist/execution-matrix/data-source.js.map +1 -0
  102. package/dist/execution-matrix/eligibility.d.ts +48 -0
  103. package/dist/execution-matrix/eligibility.d.ts.map +1 -0
  104. package/dist/execution-matrix/eligibility.js +89 -0
  105. package/dist/execution-matrix/eligibility.js.map +1 -0
  106. package/dist/execution-matrix/execution-matrix-claim-pause.d.ts +20 -0
  107. package/dist/execution-matrix/execution-matrix-claim-pause.d.ts.map +1 -0
  108. package/dist/execution-matrix/execution-matrix-claim-pause.js +18 -0
  109. package/dist/execution-matrix/execution-matrix-claim-pause.js.map +1 -0
  110. package/dist/execution-matrix/execution-matrix-claim-pause.spec.d.ts +2 -0
  111. package/dist/execution-matrix/execution-matrix-claim-pause.spec.d.ts.map +1 -0
  112. package/dist/execution-matrix/execution-matrix-claim-pause.spec.js +23 -0
  113. package/dist/execution-matrix/execution-matrix-claim-pause.spec.js.map +1 -0
  114. package/dist/execution-matrix/execution-matrix.live.spec.d.ts +2 -0
  115. package/dist/execution-matrix/execution-matrix.live.spec.d.ts.map +1 -0
  116. package/dist/execution-matrix/execution-matrix.live.spec.js +152 -0
  117. package/dist/execution-matrix/execution-matrix.live.spec.js.map +1 -0
  118. package/dist/execution-matrix/execution-matrix.live.xmemory.spec.d.ts +2 -0
  119. package/dist/execution-matrix/execution-matrix.live.xmemory.spec.d.ts.map +1 -0
  120. package/dist/execution-matrix/execution-matrix.live.xmemory.spec.js +346 -0
  121. package/dist/execution-matrix/execution-matrix.live.xmemory.spec.js.map +1 -0
  122. package/dist/execution-matrix/execution-matrix.spec.d.ts +2 -0
  123. package/dist/execution-matrix/execution-matrix.spec.d.ts.map +1 -0
  124. package/dist/execution-matrix/execution-matrix.spec.js +1786 -0
  125. package/dist/execution-matrix/execution-matrix.spec.js.map +1 -0
  126. package/dist/execution-matrix/execution-mode.d.ts +34 -0
  127. package/dist/execution-matrix/execution-mode.d.ts.map +1 -0
  128. package/dist/execution-matrix/execution-mode.js +72 -0
  129. package/dist/execution-matrix/execution-mode.js.map +1 -0
  130. package/dist/execution-matrix/factory.d.ts +72 -0
  131. package/dist/execution-matrix/factory.d.ts.map +1 -0
  132. package/dist/execution-matrix/factory.js +77 -0
  133. package/dist/execution-matrix/factory.js.map +1 -0
  134. package/dist/execution-matrix/graph-engine-datafilters-reexport.spec.d.ts +2 -0
  135. package/dist/execution-matrix/graph-engine-datafilters-reexport.spec.d.ts.map +1 -0
  136. package/dist/execution-matrix/graph-engine-datafilters-reexport.spec.js +48 -0
  137. package/dist/execution-matrix/graph-engine-datafilters-reexport.spec.js.map +1 -0
  138. package/dist/execution-matrix/graph-entry-xmemory-load.d.ts +130 -0
  139. package/dist/execution-matrix/graph-entry-xmemory-load.d.ts.map +1 -0
  140. package/dist/execution-matrix/graph-entry-xmemory-load.js +146 -0
  141. package/dist/execution-matrix/graph-entry-xmemory-load.js.map +1 -0
  142. package/dist/execution-matrix/graph-entry-xmemory-load.spec.d.ts +2 -0
  143. package/dist/execution-matrix/graph-entry-xmemory-load.spec.d.ts.map +1 -0
  144. package/dist/execution-matrix/graph-entry-xmemory-load.spec.js +66 -0
  145. package/dist/execution-matrix/graph-entry-xmemory-load.spec.js.map +1 -0
  146. package/dist/execution-matrix/graph-operational-aggregates.d.ts +47 -0
  147. package/dist/execution-matrix/graph-operational-aggregates.d.ts.map +1 -0
  148. package/dist/execution-matrix/graph-operational-aggregates.js +137 -0
  149. package/dist/execution-matrix/graph-operational-aggregates.js.map +1 -0
  150. package/dist/execution-matrix/graph-operational-lifecycle.d.ts +43 -0
  151. package/dist/execution-matrix/graph-operational-lifecycle.d.ts.map +1 -0
  152. package/dist/execution-matrix/graph-operational-lifecycle.js +88 -0
  153. package/dist/execution-matrix/graph-operational-lifecycle.js.map +1 -0
  154. package/dist/execution-matrix/graph-operational.spec.d.ts +2 -0
  155. package/dist/execution-matrix/graph-operational.spec.d.ts.map +1 -0
  156. package/dist/execution-matrix/graph-operational.spec.js +203 -0
  157. package/dist/execution-matrix/graph-operational.spec.js.map +1 -0
  158. package/dist/execution-matrix/index.d.ts +73 -0
  159. package/dist/execution-matrix/index.d.ts.map +1 -0
  160. package/dist/execution-matrix/index.js +57 -0
  161. package/dist/execution-matrix/index.js.map +1 -0
  162. package/dist/execution-matrix/live-tier-open.d.ts +6 -0
  163. package/dist/execution-matrix/live-tier-open.d.ts.map +1 -0
  164. package/dist/execution-matrix/live-tier-open.js +6 -0
  165. package/dist/execution-matrix/live-tier-open.js.map +1 -0
  166. package/dist/execution-matrix/materializer.d.ts +99 -0
  167. package/dist/execution-matrix/materializer.d.ts.map +1 -0
  168. package/dist/execution-matrix/materializer.js +210 -0
  169. package/dist/execution-matrix/materializer.js.map +1 -0
  170. package/dist/execution-matrix/matrix-activix.d.ts +24 -0
  171. package/dist/execution-matrix/matrix-activix.d.ts.map +1 -0
  172. package/dist/execution-matrix/matrix-activix.js +34 -0
  173. package/dist/execution-matrix/matrix-activix.js.map +1 -0
  174. package/dist/execution-matrix/matrix-data-tier.d.ts +55 -0
  175. package/dist/execution-matrix/matrix-data-tier.d.ts.map +1 -0
  176. package/dist/execution-matrix/matrix-data-tier.js +74 -0
  177. package/dist/execution-matrix/matrix-data-tier.js.map +1 -0
  178. package/dist/execution-matrix/matrix-execute-graph-adapter.d.ts +43 -0
  179. package/dist/execution-matrix/matrix-execute-graph-adapter.d.ts.map +1 -0
  180. package/dist/execution-matrix/matrix-execute-graph-adapter.js +62 -0
  181. package/dist/execution-matrix/matrix-execute-graph-adapter.js.map +1 -0
  182. package/dist/execution-matrix/matrix-execute-graph-adapter.spec.d.ts +2 -0
  183. package/dist/execution-matrix/matrix-execute-graph-adapter.spec.d.ts.map +1 -0
  184. package/dist/execution-matrix/matrix-execute-graph-adapter.spec.js +60 -0
  185. package/dist/execution-matrix/matrix-execute-graph-adapter.spec.js.map +1 -0
  186. package/dist/execution-matrix/matrix-logxer.d.ts +15 -0
  187. package/dist/execution-matrix/matrix-logxer.d.ts.map +1 -0
  188. package/dist/execution-matrix/matrix-logxer.js +65 -0
  189. package/dist/execution-matrix/matrix-logxer.js.map +1 -0
  190. package/dist/execution-matrix/matrix-read-tier.d.ts +41 -0
  191. package/dist/execution-matrix/matrix-read-tier.d.ts.map +1 -0
  192. package/dist/execution-matrix/matrix-read-tier.js +41 -0
  193. package/dist/execution-matrix/matrix-read-tier.js.map +1 -0
  194. package/dist/execution-matrix/memorix-entity-type-helpers.d.ts +25 -0
  195. package/dist/execution-matrix/memorix-entity-type-helpers.d.ts.map +1 -0
  196. package/dist/execution-matrix/memorix-entity-type-helpers.js +32 -0
  197. package/dist/execution-matrix/memorix-entity-type-helpers.js.map +1 -0
  198. package/dist/execution-matrix/memorix-entity-type-helpers.spec.d.ts +2 -0
  199. package/dist/execution-matrix/memorix-entity-type-helpers.spec.d.ts.map +1 -0
  200. package/dist/execution-matrix/memorix-entity-type-helpers.spec.js +83 -0
  201. package/dist/execution-matrix/memorix-entity-type-helpers.spec.js.map +1 -0
  202. package/dist/execution-matrix/memorix-inference-persister.d.ts +73 -0
  203. package/dist/execution-matrix/memorix-inference-persister.d.ts.map +1 -0
  204. package/dist/execution-matrix/memorix-inference-persister.js +126 -0
  205. package/dist/execution-matrix/memorix-inference-persister.js.map +1 -0
  206. package/dist/execution-matrix/memorix-inference-persister.spec.d.ts +2 -0
  207. package/dist/execution-matrix/memorix-inference-persister.spec.d.ts.map +1 -0
  208. package/dist/execution-matrix/memorix-inference-persister.spec.js +117 -0
  209. package/dist/execution-matrix/memorix-inference-persister.spec.js.map +1 -0
  210. package/dist/execution-matrix/memorix-matrix-entity-facet.d.ts +71 -0
  211. package/dist/execution-matrix/memorix-matrix-entity-facet.d.ts.map +1 -0
  212. package/dist/execution-matrix/memorix-matrix-entity-facet.js +91 -0
  213. package/dist/execution-matrix/memorix-matrix-entity-facet.js.map +1 -0
  214. package/dist/execution-matrix/memorix-matrix-entity-facet.spec.d.ts +2 -0
  215. package/dist/execution-matrix/memorix-matrix-entity-facet.spec.d.ts.map +1 -0
  216. package/dist/execution-matrix/memorix-matrix-entity-facet.spec.js +151 -0
  217. package/dist/execution-matrix/memorix-matrix-entity-facet.spec.js.map +1 -0
  218. package/dist/execution-matrix/memorix-runtime-tier.d.ts +153 -0
  219. package/dist/execution-matrix/memorix-runtime-tier.d.ts.map +1 -0
  220. package/dist/execution-matrix/memorix-runtime-tier.js +185 -0
  221. package/dist/execution-matrix/memorix-runtime-tier.js.map +1 -0
  222. package/dist/execution-matrix/memorix-tier-statistics.d.ts +103 -0
  223. package/dist/execution-matrix/memorix-tier-statistics.d.ts.map +1 -0
  224. package/dist/execution-matrix/memorix-tier-statistics.js +164 -0
  225. package/dist/execution-matrix/memorix-tier-statistics.js.map +1 -0
  226. package/dist/execution-matrix/memory-store.d.ts +20 -0
  227. package/dist/execution-matrix/memory-store.d.ts.map +1 -0
  228. package/dist/execution-matrix/memory-store.js +185 -0
  229. package/dist/execution-matrix/memory-store.js.map +1 -0
  230. package/dist/execution-matrix/navigator.d.ts +97 -0
  231. package/dist/execution-matrix/navigator.d.ts.map +1 -0
  232. package/dist/execution-matrix/navigator.js +119 -0
  233. package/dist/execution-matrix/navigator.js.map +1 -0
  234. package/dist/execution-matrix/orchestrator.d.ts +204 -0
  235. package/dist/execution-matrix/orchestrator.d.ts.map +1 -0
  236. package/dist/execution-matrix/orchestrator.js +656 -0
  237. package/dist/execution-matrix/orchestrator.js.map +1 -0
  238. package/dist/execution-matrix/records-eligibility.d.ts +34 -0
  239. package/dist/execution-matrix/records-eligibility.d.ts.map +1 -0
  240. package/dist/execution-matrix/records-eligibility.js +110 -0
  241. package/dist/execution-matrix/records-eligibility.js.map +1 -0
  242. package/dist/execution-matrix/records-eligibility.spec.d.ts +2 -0
  243. package/dist/execution-matrix/records-eligibility.spec.d.ts.map +1 -0
  244. package/dist/execution-matrix/records-eligibility.spec.js +154 -0
  245. package/dist/execution-matrix/records-eligibility.spec.js.map +1 -0
  246. package/dist/execution-matrix/run-loop.d.ts +140 -0
  247. package/dist/execution-matrix/run-loop.d.ts.map +1 -0
  248. package/dist/execution-matrix/run-loop.js +350 -0
  249. package/dist/execution-matrix/run-loop.js.map +1 -0
  250. package/dist/execution-matrix/runtime-connectivity-health.d.ts +128 -0
  251. package/dist/execution-matrix/runtime-connectivity-health.d.ts.map +1 -0
  252. package/dist/execution-matrix/runtime-connectivity-health.js +253 -0
  253. package/dist/execution-matrix/runtime-connectivity-health.js.map +1 -0
  254. package/dist/execution-matrix/runtime-connectivity-health.spec.d.ts +2 -0
  255. package/dist/execution-matrix/runtime-connectivity-health.spec.d.ts.map +1 -0
  256. package/dist/execution-matrix/runtime-connectivity-health.spec.js +23 -0
  257. package/dist/execution-matrix/runtime-connectivity-health.spec.js.map +1 -0
  258. package/dist/execution-matrix/runtime-objects.d.ts +16 -0
  259. package/dist/execution-matrix/runtime-objects.d.ts.map +1 -0
  260. package/dist/execution-matrix/runtime-objects.js +20 -0
  261. package/dist/execution-matrix/runtime-objects.js.map +1 -0
  262. package/dist/execution-matrix/runtime-store.d.ts +114 -0
  263. package/dist/execution-matrix/runtime-store.d.ts.map +1 -0
  264. package/dist/execution-matrix/runtime-store.js +506 -0
  265. package/dist/execution-matrix/runtime-store.js.map +1 -0
  266. package/dist/execution-matrix/snapshot-runner.d.ts +50 -0
  267. package/dist/execution-matrix/snapshot-runner.d.ts.map +1 -0
  268. package/dist/execution-matrix/snapshot-runner.js +111 -0
  269. package/dist/execution-matrix/snapshot-runner.js.map +1 -0
  270. package/dist/execution-matrix/source-resolver-factories.d.ts +31 -0
  271. package/dist/execution-matrix/source-resolver-factories.d.ts.map +1 -0
  272. package/dist/execution-matrix/source-resolver-factories.js +71 -0
  273. package/dist/execution-matrix/source-resolver-factories.js.map +1 -0
  274. package/dist/execution-matrix/source-resolver-factories.spec.d.ts +2 -0
  275. package/dist/execution-matrix/source-resolver-factories.spec.d.ts.map +1 -0
  276. package/dist/execution-matrix/source-resolver-factories.spec.js +127 -0
  277. package/dist/execution-matrix/source-resolver-factories.spec.js.map +1 -0
  278. package/dist/execution-matrix/source-resolver.d.ts +31 -0
  279. package/dist/execution-matrix/source-resolver.d.ts.map +1 -0
  280. package/dist/execution-matrix/source-resolver.js +26 -0
  281. package/dist/execution-matrix/source-resolver.js.map +1 -0
  282. package/dist/execution-matrix/status.d.ts +7 -0
  283. package/dist/execution-matrix/status.d.ts.map +1 -0
  284. package/dist/execution-matrix/status.js +33 -0
  285. package/dist/execution-matrix/status.js.map +1 -0
  286. package/dist/execution-matrix/xmemory-entity-collections.d.ts +69 -0
  287. package/dist/execution-matrix/xmemory-entity-collections.d.ts.map +1 -0
  288. package/dist/execution-matrix/xmemory-entity-collections.js +120 -0
  289. package/dist/execution-matrix/xmemory-entity-collections.js.map +1 -0
  290. package/dist/execution-matrix/xmemory-entity-collections.spec.d.ts +2 -0
  291. package/dist/execution-matrix/xmemory-entity-collections.spec.d.ts.map +1 -0
  292. package/dist/execution-matrix/xmemory-entity-collections.spec.js +112 -0
  293. package/dist/execution-matrix/xmemory-entity-collections.spec.js.map +1 -0
  294. package/dist/execution-matrix/xmemory-op-tier.d.ts +172 -0
  295. package/dist/execution-matrix/xmemory-op-tier.d.ts.map +1 -0
  296. package/dist/execution-matrix/xmemory-op-tier.js +339 -0
  297. package/dist/execution-matrix/xmemory-op-tier.js.map +1 -0
  298. package/dist/execution-matrix/xmemory-op-tier.spec.d.ts +2 -0
  299. package/dist/execution-matrix/xmemory-op-tier.spec.d.ts.map +1 -0
  300. package/dist/execution-matrix/xmemory-op-tier.spec.js +198 -0
  301. package/dist/execution-matrix/xmemory-op-tier.spec.js.map +1 -0
  302. package/dist/execution-matrix/xronox-matrix-factory.d.ts +38 -0
  303. package/dist/execution-matrix/xronox-matrix-factory.d.ts.map +1 -0
  304. package/dist/execution-matrix/xronox-matrix-factory.js +77 -0
  305. package/dist/execution-matrix/xronox-matrix-factory.js.map +1 -0
  306. package/dist/execution-matrix/xronox-store-native-driver-hooks.d.ts +15 -0
  307. package/dist/execution-matrix/xronox-store-native-driver-hooks.d.ts.map +1 -0
  308. package/dist/execution-matrix/xronox-store-native-driver-hooks.js +41 -0
  309. package/dist/execution-matrix/xronox-store-native-driver-hooks.js.map +1 -0
  310. package/dist/test-fixtures/exellix-test-matrix-ids.d.ts +16 -0
  311. package/dist/test-fixtures/exellix-test-matrix-ids.d.ts.map +1 -0
  312. package/dist/test-fixtures/exellix-test-matrix-ids.js +16 -0
  313. package/dist/test-fixtures/exellix-test-matrix-ids.js.map +1 -0
  314. package/dist/test-fixtures/seed-exellix-test-matrix-config.d.ts +26 -0
  315. package/dist/test-fixtures/seed-exellix-test-matrix-config.d.ts.map +1 -0
  316. package/dist/test-fixtures/seed-exellix-test-matrix-config.js +82 -0
  317. package/dist/test-fixtures/seed-exellix-test-matrix-config.js.map +1 -0
  318. package/package.json +67 -0
@@ -0,0 +1,1786 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { assertCanonicalGraphDocument, buildExellixGraphRuntimeObjects, EXELLIX_AI_TASKS_PACKAGE_NAME, EXELLIX_GRAPH_RUNTIME_PACKAGE_NAME, mergeGraphDocumentModel, } from '@exellix/graph-engine';
3
+ import { ExecutionMatrixCatalogValidationError, executionMatrixPayloadFromCatalogItem, graphCatalogPayloadFromCatalogItem, parseExecutionMatrixCatalogPayload, parseGraphCatalogPayload, } from './catalox-loader.js';
4
+ import { buildMatrixMaterializeContext } from './catalox-matrix-host.js';
5
+ import { MATRIX_FAILURE_PK, MATRIX_ROW_PK } from './constants.js';
6
+ import { fetchExecutionMatrixMultiGraphOverview, fetchExecutionMatrixNavigatorPage, } from './navigator.js';
7
+ import { createMatrixReadTierFromDataTier } from './matrix-read-tier.js';
8
+ import { buildExecutionSeedFromGraphEntry, materializeExecutionMatrixRuntimeRows, mergeMappedInputEntries, resolveInputRowsWithResolver, sortGraphRecordsForMatrix, } from './materializer.js';
9
+ import { MemoryMatrixCollection } from './memory-store.js';
10
+ import { mergeClaimExtraFilter, mergeMatrixGraphExecuteOverrides, processMatrixGraphBatch, processNextMatrixClaim, sanitizeMatrixGraphExecuteOverrides, } from './orchestrator.js';
11
+ import { buildExecutionMatrixRuntimeObjects } from './runtime-objects.js';
12
+ import { buildFailureRecordsReadFilter, buildSnapshotsReadFilter, createExecutionMatrixRuntime, } from './runtime-store.js';
13
+ import { normalizeExecutionMatrixStatus } from './status.js';
14
+ import { readdirSync, readFileSync } from 'node:fs';
15
+ import { basename, join } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+ /** Minimal injected-runtime graph result shape for orchestrator mocks (graph-engine 5.x `ExecuteGraphResult`). */
18
+ function mockExecuteGraphSuccess(finalOutput = {}) {
19
+ return {
20
+ status: 'completed',
21
+ jobId: 'mock-job',
22
+ taskId: 'mock-task-id',
23
+ graphId: 'G',
24
+ outputsByNodeId: {},
25
+ engineSnapshot: {},
26
+ finalOutput,
27
+ };
28
+ }
29
+ function mockExecuteGraphFailed() {
30
+ return {
31
+ status: 'failed',
32
+ jobId: 'mock-job',
33
+ taskId: 'mock-task-fail',
34
+ graphId: 'G',
35
+ outputsByNodeId: {},
36
+ engineSnapshot: {},
37
+ errors: [{ nodeId: 'n1', error: 'boom' }],
38
+ };
39
+ }
40
+ function graphModelFor(graphId = 'G', graphEntry) {
41
+ return {
42
+ id: graphId,
43
+ response: { shape: { type: 'literal', value: {} } },
44
+ nodes: [],
45
+ ...(graphEntry ? { metadata: { graphEntry } } : {}),
46
+ };
47
+ }
48
+ function resolveGraphModelForTest({ graphId }) {
49
+ return graphModelFor(graphId);
50
+ }
51
+ describe('normalizeExecutionMatrixStatus', () => {
52
+ it('normalizes aliases', () => {
53
+ expect(normalizeExecutionMatrixStatus('not-strated')).toBe('not-started');
54
+ expect(normalizeExecutionMatrixStatus('NOT-STARTED')).toBe('not-started');
55
+ });
56
+ });
57
+ describe('parseExecutionMatrixCatalogPayload', () => {
58
+ it('accepts valid payload with graphs', () => {
59
+ const p = parseExecutionMatrixCatalogPayload({
60
+ input: { mode: 'batch' },
61
+ graphs: ['g.a', 'g.b'],
62
+ });
63
+ expect(p.graphs).toEqual(['g.a', 'g.b']);
64
+ });
65
+ it('rejects invalid payload', () => {
66
+ expect(() => parseExecutionMatrixCatalogPayload({})).toThrow(ExecutionMatrixCatalogValidationError);
67
+ });
68
+ });
69
+ describe('parseGraphCatalogPayload', () => {
70
+ it('accepts graph record', () => {
71
+ const g = parseGraphCatalogPayload({
72
+ graphId: 'my-graph',
73
+ mappedInput: [{ defaults: { x: 1 } }],
74
+ execution: {
75
+ priority: 5,
76
+ conditions: [{ conditionId: 'c1', condition: { op: 'eq' } }],
77
+ conditionRelations: 'c1',
78
+ },
79
+ });
80
+ expect(g.graphId).toBe('my-graph');
81
+ expect(g.execution.priority).toBe(5);
82
+ expect(g.execution.conditions).toHaveLength(1);
83
+ });
84
+ });
85
+ describe('buildMatrixMaterializeContext', () => {
86
+ it('pairs matrix item with graph items by graphId', () => {
87
+ const matrixItem = {
88
+ data: { input: {}, graphs: ['g.a'] },
89
+ metadata: { catalogType: 'execution-matrix' },
90
+ };
91
+ const graphItems = new Map([
92
+ [
93
+ 'g.a',
94
+ {
95
+ data: {
96
+ graphId: 'g.a',
97
+ mappedInput: [],
98
+ execution: { priority: 1 },
99
+ },
100
+ metadata: { catalogType: 'graphs' },
101
+ },
102
+ ],
103
+ ]);
104
+ const { payload, graphRecords } = buildMatrixMaterializeContext(matrixItem, graphItems);
105
+ expect(payload.graphs).toEqual(['g.a']);
106
+ expect(graphRecords).toHaveLength(1);
107
+ expect(graphRecords[0].graphId).toBe('g.a');
108
+ });
109
+ it('throws when a referenced graph item is missing', () => {
110
+ const matrixItem = {
111
+ data: { input: {}, graphs: ['missing'] },
112
+ metadata: { catalogType: 'execution-matrix' },
113
+ };
114
+ expect(() => buildMatrixMaterializeContext(matrixItem, new Map())).toThrow(/missing graph catalog item/);
115
+ });
116
+ });
117
+ describe('executionMatrixPayloadFromCatalogItem', () => {
118
+ it('requires metadata marker', () => {
119
+ expect(() => executionMatrixPayloadFromCatalogItem({
120
+ data: { input: {}, graphs: ['x'] },
121
+ metadata: {},
122
+ })).toThrow(ExecutionMatrixCatalogValidationError);
123
+ });
124
+ it('loads when metadata.catalogType is set', () => {
125
+ const p = executionMatrixPayloadFromCatalogItem({
126
+ data: { input: {}, graphs: ['x'] },
127
+ metadata: { catalogType: 'execution-matrix' },
128
+ });
129
+ expect(p.graphs[0]).toBe('x');
130
+ });
131
+ });
132
+ describe('graphCatalogPayloadFromCatalogItem', () => {
133
+ it('requires graphs metadata', () => {
134
+ expect(() => graphCatalogPayloadFromCatalogItem({
135
+ data: { graphId: 'g', mappedInput: [{}], execution: { priority: 1 } },
136
+ metadata: { catalogType: 'execution-matrix' },
137
+ })).toThrow(ExecutionMatrixCatalogValidationError);
138
+ });
139
+ it('loads when metadata.catalogType is graphs', () => {
140
+ const g = graphCatalogPayloadFromCatalogItem({
141
+ data: {
142
+ graphId: 'g1',
143
+ mappedInput: [{ selector: { type: 'xmemory' } }],
144
+ execution: { priority: 2 },
145
+ },
146
+ metadata: { catalogType: 'graphs' },
147
+ });
148
+ expect(g.graphId).toBe('g1');
149
+ expect(g.execution.priority).toBe(2);
150
+ });
151
+ });
152
+ describe('materializer helpers', () => {
153
+ it('mergeMappedInputEntries merges in order', () => {
154
+ expect(mergeMappedInputEntries([{ a: 1 }, { b: 2 }, { a: 3 }])).toEqual({ a: 3, b: 2 });
155
+ });
156
+ it('sortGraphRecordsForMatrix orders by priority', () => {
157
+ const ordered = sortGraphRecordsForMatrix(['b', 'a'], [
158
+ { graphId: 'a', mappedInput: [], execution: { priority: 10 } },
159
+ { graphId: 'b', mappedInput: [], execution: { priority: 5 } },
160
+ ]);
161
+ expect(ordered.map((x) => x.graphId)).toEqual(['b', 'a']);
162
+ });
163
+ });
164
+ describe('materializer', () => {
165
+ it('builds execution seed from graphEntry paths', () => {
166
+ const graphEntry = {
167
+ inputs: [{ kind: 'record', path: 'input.raw', required: true }],
168
+ };
169
+ const seed = buildExecutionSeedFromGraphEntry(graphEntry, { raw: { a: 1 } });
170
+ expect(seed).toEqual({ input: { raw: { a: 1 } } });
171
+ });
172
+ it('maps nested Layer-01 paths using graph-engine path rules', () => {
173
+ const graphEntry = {
174
+ inputs: [{ kind: 'record', path: 'input.entity.meta.id', required: false }],
175
+ };
176
+ expect(buildExecutionSeedFromGraphEntry(graphEntry, { entity: { meta: { id: 'z' } } })).toEqual({
177
+ input: { entity: { meta: { id: 'z' } } },
178
+ });
179
+ });
180
+ it('materializes rows with stable ordering from graph priorities', () => {
181
+ const rows = materializeExecutionMatrixRuntimeRows({
182
+ matrixCatalogId: 'cat-1',
183
+ matrixItemId: 'item-1',
184
+ matrixRunId: 'run-1',
185
+ payload: {
186
+ input: { template: true },
187
+ graphs: ['g2', 'g1'],
188
+ },
189
+ graphRecords: [
190
+ { graphId: 'g1', mappedInput: [{ tag: 'one' }], execution: { priority: 10 } },
191
+ { graphId: 'g2', mappedInput: [{ tag: 'two' }], execution: { priority: 20 } },
192
+ ],
193
+ inputRows: [{ entityId: 'e1' }, { entityId: 'e2' }],
194
+ });
195
+ expect(rows).toHaveLength(2);
196
+ expect(rows[0].materializationOrder).toBe(0);
197
+ expect(rows[0].execution.map((s) => s.graphId)).toEqual(['g1', 'g2']);
198
+ expect(rows[0].execution.every((s) => s.status === 'not-started')).toBe(true);
199
+ expect(rows[0].input).toMatchObject({
200
+ template: true,
201
+ entityId: 'e1',
202
+ mappedByGraph: {
203
+ g1: { tag: 'one' },
204
+ g2: { tag: 'two' },
205
+ },
206
+ });
207
+ });
208
+ it('merges runtimeScope onto input after row keys (scope wins collisions)', () => {
209
+ const [row] = materializeExecutionMatrixRuntimeRows({
210
+ matrixCatalogId: 'cat',
211
+ matrixItemId: 'item',
212
+ payload: { input: { base: 1 }, graphs: ['G'] },
213
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
214
+ inputRows: [{ entityId: 'e1', tenantId: 'from-row' }],
215
+ runtimeScope: { tenantId: 'from-scope' },
216
+ });
217
+ expect(row.input.tenantId).toBe('from-scope');
218
+ expect(row.input.entityId).toBe('e1');
219
+ });
220
+ });
221
+ describe('fetchExecutionMatrixMultiGraphOverview', () => {
222
+ it('returns one slot per graph with stable ordering by priority', async () => {
223
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
224
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
225
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
226
+ const [row] = materializeExecutionMatrixRuntimeRows({
227
+ matrixCatalogId: 'cat',
228
+ matrixItemId: 'item',
229
+ matrixRunId: 'r1',
230
+ payload: { input: {}, graphs: ['gLow', 'gHigh'] },
231
+ graphRecords: [
232
+ { graphId: 'gLow', mappedInput: [], execution: { priority: 5 } },
233
+ { graphId: 'gHigh', mappedInput: [], execution: { priority: 100 } },
234
+ ],
235
+ inputRows: [{}],
236
+ });
237
+ await rt.insertRuntimeRow(row);
238
+ await rt.claimNext({ matrixCatalogId: 'cat', matrixRunId: 'r1', graphId: 'gLow' });
239
+ await rt.markCompleted(row.matrixRowId, 'gLow', { graphId: 'gLow', knowledge: { ok: 1 } });
240
+ const overview = await fetchExecutionMatrixMultiGraphOverview(rt, {
241
+ matrixCatalogId: 'cat',
242
+ matrixRunId: 'r1',
243
+ });
244
+ expect(overview).toHaveLength(1);
245
+ expect(overview[0].slots.map((s) => s.graphId)).toEqual(['gLow', 'gHigh']);
246
+ expect(overview[0].slots[0].status).toBe('completed');
247
+ expect(overview[0].slots[0].inference?.knowledge).toEqual({ ok: 1 });
248
+ expect(overview[0].slots[1].status).toBe('not-started');
249
+ });
250
+ });
251
+ describe('mergeClaimExtraFilter', () => {
252
+ it('lets runtimeScope override claim extraFilter keys', () => {
253
+ expect(mergeClaimExtraFilter({ 'input.shard': 's1', 'input.tenantId': 'x' }, { 'input.tenantId': 't1' })).toEqual({
254
+ 'input.shard': 's1',
255
+ 'input.tenantId': 't1',
256
+ });
257
+ });
258
+ });
259
+ describe('resolveInputRowsWithResolver', () => {
260
+ it('forwards runtimeScope to the resolver', async () => {
261
+ const resolver = vi.fn().mockResolvedValue([{ ok: true }]);
262
+ await resolveInputRowsWithResolver({ q: 1 }, resolver, { tenantId: 'acme' });
263
+ expect(resolver).toHaveBeenCalledWith({ q: 1 }, { tenantId: 'acme' });
264
+ });
265
+ });
266
+ describe('ExecutionMatrixRuntime (memory)', () => {
267
+ it('claims next by materializationOrder and completes', async () => {
268
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
269
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
270
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
271
+ const r1 = materializeExecutionMatrixRuntimeRows({
272
+ matrixCatalogId: 'cat',
273
+ matrixItemId: 'item',
274
+ matrixRunId: 'r1',
275
+ payload: { input: {}, graphs: ['G'] },
276
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
277
+ inputRows: [{ n: 'first' }, { n: 'second' }],
278
+ });
279
+ await rt.insertRuntimeRow(r1[1]);
280
+ await rt.insertRuntimeRow(r1[0]);
281
+ const c1 = await rt.claimNext({ matrixCatalogId: 'cat', matrixRunId: 'r1', graphId: 'G' });
282
+ expect(c1.ok).toBe(true);
283
+ if (!c1.ok)
284
+ throw new Error('claim');
285
+ expect(c1.record.input.n).toBe('first');
286
+ await rt.markCompleted(c1.record.matrixRowId, 'G', { graphId: 'G', knowledge: { ok: true } });
287
+ const counts = await rt.getStatusCounts('cat', 'G', 'r1');
288
+ expect(counts.completed).toBe(1);
289
+ expect(counts['not-started']).toBe(1);
290
+ const page = await fetchExecutionMatrixNavigatorPage(rt, {
291
+ matrixCatalogId: 'cat',
292
+ matrixRunId: 'r1',
293
+ graphId: 'G',
294
+ limit: 10,
295
+ includeFailureCount: true,
296
+ });
297
+ expect(page.rows).toHaveLength(2);
298
+ expect(page.statusCounts?.completed).toBe(1);
299
+ expect(page.failureCount).toBe(0);
300
+ });
301
+ it('countFailureRecords counts failures (memory)', async () => {
302
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
303
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
304
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
305
+ const template = {
306
+ matrixCatalogId: 'cat',
307
+ matrixItemId: 'item',
308
+ matrixRunId: 'r1',
309
+ payload: { input: {}, graphs: ['G'] },
310
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
311
+ };
312
+ const [rowA] = materializeExecutionMatrixRuntimeRows({ ...template, inputRows: [{}] });
313
+ const [rowB] = materializeExecutionMatrixRuntimeRows({
314
+ ...template,
315
+ matrixItemId: 'item2',
316
+ inputRows: [{}],
317
+ });
318
+ await rt.insertRuntimeRow(rowA);
319
+ await rt.insertRuntimeRow(rowB);
320
+ await rt.claimNext({ matrixCatalogId: 'cat', matrixRunId: 'r1', graphId: 'G' });
321
+ await rt.markFailed(rowA.matrixRowId, 'G', 'e1');
322
+ await new Promise((r) => setTimeout(r, 15));
323
+ await rt.claimNext({ matrixCatalogId: 'cat', matrixRunId: 'r1', graphId: 'G' });
324
+ await rt.markFailed(rowB.matrixRowId, 'G', 'e2');
325
+ expect(await rt.countFailureRecords({ matrixCatalogId: 'cat', matrixRunId: 'r1' })).toBe(2);
326
+ expect(await rt.countFailureRecords({ matrixCatalogId: 'cat', matrixRunId: 'r1', graphId: 'G' })).toBe(2);
327
+ const listed = await rt.listFailureRecords({ matrixCatalogId: 'cat', matrixRunId: 'r1' }, 50_000);
328
+ expect(listed).toHaveLength(2);
329
+ expect(listed[0].reason).toBe('e2');
330
+ expect(listed[1].reason).toBe('e1');
331
+ const one = await rt.getFailureRecord(listed[0].failureId);
332
+ expect(one?.reason).toBe('e2');
333
+ const latest = await rt.getLatestFailureRecordForRowGraph(rowB.matrixRowId, 'G');
334
+ expect(latest?.failureId).toBe(listed[0].failureId);
335
+ });
336
+ it('listFailureRecords respects createdAt bounds (memory)', async () => {
337
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
338
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
339
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
340
+ await fails.insert({
341
+ failureId: 'f_old',
342
+ matrixRowId: 'r1',
343
+ matrixCatalogId: 'cat',
344
+ matrixItemId: 'item',
345
+ matrixRunId: 'r1',
346
+ graphId: 'G',
347
+ reason: 'old',
348
+ createdAt: '2024-01-01T00:00:00.000Z',
349
+ });
350
+ await fails.insert({
351
+ failureId: 'f_new',
352
+ matrixRowId: 'r2',
353
+ matrixCatalogId: 'cat',
354
+ matrixItemId: 'item',
355
+ matrixRunId: 'r1',
356
+ graphId: 'G',
357
+ reason: 'new',
358
+ createdAt: '2025-06-01T00:00:00.000Z',
359
+ });
360
+ const mid = await rt.listFailureRecords({
361
+ matrixCatalogId: 'cat',
362
+ matrixRunId: 'r1',
363
+ createdAtMin: '2025-01-01T00:00:00.000Z',
364
+ createdAtMax: '2025-12-31T00:00:00.000Z',
365
+ });
366
+ expect(mid.map((f) => f.failureId)).toEqual(['f_new']);
367
+ });
368
+ it('buildFailureRecordsReadFilter maps optional bounds and matrixRowId', () => {
369
+ expect(buildFailureRecordsReadFilter({ matrixCatalogId: 'cat' })).toEqual({
370
+ matrixCatalogId: 'cat',
371
+ });
372
+ expect(buildFailureRecordsReadFilter({
373
+ matrixCatalogId: 'cat',
374
+ matrixRunId: 'r1',
375
+ graphId: 'G',
376
+ matrixRowId: 'row-1',
377
+ createdAtMin: '2024-01-01T00:00:00.000Z',
378
+ createdAtMax: '2025-01-01T00:00:00.000Z',
379
+ })).toEqual({
380
+ matrixCatalogId: 'cat',
381
+ matrixRunId: 'r1',
382
+ graphId: 'G',
383
+ matrixRowId: 'row-1',
384
+ createdAt: {
385
+ $gte: '2024-01-01T00:00:00.000Z',
386
+ $lte: '2025-01-01T00:00:00.000Z',
387
+ },
388
+ });
389
+ });
390
+ it('MatrixReadTier delegates failure audit reads to runtime', async () => {
391
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
392
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
393
+ const matrices = new MemoryMatrixCollection('matrixCatalogId');
394
+ const graphs = new MemoryMatrixCollection('graphId');
395
+ const snapshots = new MemoryMatrixCollection('snapshotId');
396
+ const tier = await createMatrixReadTierFromDataTier({
397
+ rows: rows.asCollection(),
398
+ failures: fails.asCollection(),
399
+ snapshots: snapshots.asCollection(),
400
+ matrices: matrices.asCollection(),
401
+ graphs: graphs.asCollection(),
402
+ close: async () => undefined,
403
+ });
404
+ await fails.insert({
405
+ failureId: 'f_tier',
406
+ matrixRowId: 'row-tier',
407
+ matrixCatalogId: 'cat-tier',
408
+ matrixItemId: 'item',
409
+ matrixRunId: 'r-tier',
410
+ graphId: 'G',
411
+ reason: 'tier-delegate',
412
+ createdAt: '2025-06-01T00:00:00.000Z',
413
+ });
414
+ const listed = await tier.listFailureRecords({ matrixCatalogId: 'cat-tier', limit: 10 });
415
+ expect(listed).toHaveLength(1);
416
+ expect(listed[0].reason).toBe('tier-delegate');
417
+ const one = await tier.getFailureRecord('f_tier');
418
+ expect(one?.failureId).toBe('f_tier');
419
+ const latest = await tier.getLatestFailureRecordForRowGraph('row-tier', 'G', {
420
+ matrixCatalogId: 'cat-tier',
421
+ });
422
+ expect(latest?.failureId).toBe('f_tier');
423
+ });
424
+ it('markFailed writes failure side-channel', async () => {
425
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
426
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
427
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
428
+ const [row] = materializeExecutionMatrixRuntimeRows({
429
+ matrixCatalogId: 'cat',
430
+ matrixItemId: 'item',
431
+ payload: { input: {}, graphs: ['G'] },
432
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
433
+ inputRows: [{}],
434
+ });
435
+ await rt.insertRuntimeRow(row);
436
+ await rt.claimNext({ matrixCatalogId: 'cat', graphId: 'G' });
437
+ await rt.markFailed(row.matrixRowId, 'G', 'boom');
438
+ const listed = await fails.readMany({}, { limit: 10 });
439
+ expect(listed.length).toBe(1);
440
+ expect(listed[0].reason).toBe('boom');
441
+ });
442
+ });
443
+ describe('buildExecutionMatrixRuntimeObjects', () => {
444
+ it('composes matrix root clients and preserves graph-engine package row first', () => {
445
+ const graphActivix = { getJobActivities: vi.fn() };
446
+ const graphLogxer = { getJobLogs: vi.fn() };
447
+ const graphRo = buildExellixGraphRuntimeObjects({
448
+ graphActivixClient: graphActivix,
449
+ graphLogxerClient: graphLogxer,
450
+ });
451
+ const matrixActivix = { getJobActivities: vi.fn() };
452
+ const matrixLogxer = { getJobLogs: vi.fn() };
453
+ const composed = buildExecutionMatrixRuntimeObjects({
454
+ matrixActivixClient: matrixActivix,
455
+ matrixLogxerClient: matrixLogxer,
456
+ graphRuntimeObjects: graphRo,
457
+ });
458
+ expect(composed.activixClient).toBe(matrixActivix);
459
+ expect(composed.logxerClient).toBe(matrixLogxer);
460
+ expect(composed.packagesRuntimeObjects[0]).toEqual({
461
+ name: EXELLIX_GRAPH_RUNTIME_PACKAGE_NAME,
462
+ activixClient: graphActivix,
463
+ logxerClient: graphLogxer,
464
+ });
465
+ expect(composed.packagesRuntimeObjects[1]?.name).toBe(EXELLIX_AI_TASKS_PACKAGE_NAME);
466
+ });
467
+ });
468
+ describe('orchestrator batch', () => {
469
+ it('processMatrixGraphBatch with limit 1 invokes executeGraph once', async () => {
470
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
471
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
472
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
473
+ const [row] = materializeExecutionMatrixRuntimeRows({
474
+ matrixCatalogId: 'cat',
475
+ matrixItemId: 'item',
476
+ matrixRunId: 'r1',
477
+ payload: { input: {}, graphs: ['G'] },
478
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
479
+ inputRows: [{}],
480
+ });
481
+ await rt.insertRuntimeRow(row);
482
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess({ done: true }));
483
+ const externalJobId = 'job_external_1';
484
+ const out = await processMatrixGraphBatch({
485
+ runtime: rt,
486
+ executeGraph,
487
+ resolveGraphModel: resolveGraphModelForTest,
488
+ resolveGraphEntry: () => ({ inputs: [] }),
489
+ }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1, jobId: externalJobId });
490
+ expect(executeGraph).toHaveBeenCalledTimes(1);
491
+ expect(out).toHaveLength(1);
492
+ expect(out[0]).toMatchObject({ ok: true, jobId: externalJobId });
493
+ const call = executeGraph.mock.calls[0][0];
494
+ expect(call.model.id).toBe('G');
495
+ expect(call.runtime.jobId).toBe(externalJobId);
496
+ expect(call.runtime.job).toEqual({
497
+ id: externalJobId,
498
+ jobId: externalJobId,
499
+ agentId: 'exellix-runtime',
500
+ jobTypeId: 'execution-matrix-graph-run',
501
+ matrixRowId: row.matrixRowId,
502
+ matrixCatalogId: 'cat',
503
+ matrixRunId: 'r1',
504
+ graphId: 'G',
505
+ });
506
+ const after = await rt.getRecord(row.matrixRowId);
507
+ expect(after?.execution.find((e) => e.graphId === 'G')?.jobId).toBe(externalJobId);
508
+ });
509
+ it('forwards runtimeObjects to executeGraph and sets lastJobId on the composed root', async () => {
510
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
511
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
512
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
513
+ const [row] = materializeExecutionMatrixRuntimeRows({
514
+ matrixCatalogId: 'cat',
515
+ matrixItemId: 'item',
516
+ matrixRunId: 'r1',
517
+ payload: { input: {}, graphs: ['G'] },
518
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
519
+ inputRows: [{}],
520
+ });
521
+ await rt.insertRuntimeRow(row);
522
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess({ done: true }));
523
+ const runtimeObjects = buildExellixGraphRuntimeObjects({});
524
+ const externalJobId = 'job_external_2';
525
+ await processMatrixGraphBatch({
526
+ runtime: rt,
527
+ executeGraph,
528
+ resolveGraphModel: resolveGraphModelForTest,
529
+ resolveGraphEntry: () => ({ inputs: [] }),
530
+ runtimeObjects,
531
+ }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1, jobId: externalJobId });
532
+ const call = executeGraph.mock.calls[0][0];
533
+ expect(call.runtime.runtimeObjects).toBe(runtimeObjects);
534
+ expect(runtimeObjects.lastJobId).toBe(externalJobId);
535
+ });
536
+ it('processNextMatrixClaim still works for a fixed graphId', async () => {
537
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
538
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
539
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
540
+ const [row] = materializeExecutionMatrixRuntimeRows({
541
+ matrixCatalogId: 'cat',
542
+ matrixItemId: 'item',
543
+ payload: { input: {}, graphs: ['G'] },
544
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
545
+ inputRows: [{}],
546
+ });
547
+ await rt.insertRuntimeRow(row);
548
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
549
+ const externalJobId = 'job_external_3';
550
+ const res = await processNextMatrixClaim({ runtime: rt, executeGraph, graphModel: graphModelFor('G', { inputs: [] }) }, { matrixCatalogId: 'cat', graphId: 'G', jobId: externalJobId });
551
+ expect(res).toMatchObject({ ok: true, jobId: externalJobId });
552
+ expect(executeGraph).toHaveBeenCalled();
553
+ const call = executeGraph.mock.calls[0][0];
554
+ expect(call.runtime.jobId).toBe(externalJobId);
555
+ });
556
+ it('processNextMatrixClaim merges deps.runtimeScope into claimNext extraFilter', async () => {
557
+ const claimNext = vi.fn().mockResolvedValue({ ok: false, reason: 'no_eligible_row' });
558
+ const rt = { claimNext };
559
+ await processNextMatrixClaim({
560
+ runtime: rt,
561
+ executeGraph: vi.fn(),
562
+ resolveGraphModel: resolveGraphModelForTest,
563
+ runtimeScope: { 'input.tenantId': 't1' },
564
+ }, { matrixCatalogId: 'c', graphId: 'g', extraFilter: { 'input.shard': 's1' } });
565
+ expect(claimNext).toHaveBeenCalledWith(expect.objectContaining({
566
+ extraFilter: { 'input.shard': 's1', 'input.tenantId': 't1' },
567
+ }));
568
+ });
569
+ it('autonomous mode generates a stable jobId when none is provided', async () => {
570
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
571
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
572
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
573
+ const [row] = materializeExecutionMatrixRuntimeRows({
574
+ matrixCatalogId: 'cat',
575
+ matrixItemId: 'item',
576
+ matrixRunId: 'r1',
577
+ payload: { input: {}, graphs: ['G'] },
578
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
579
+ inputRows: [{}],
580
+ });
581
+ await rt.insertRuntimeRow(row);
582
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
583
+ const out = await processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1 });
584
+ expect(out[0]).toMatchObject({ ok: true, jobId: expect.stringMatching(/^matrix:/) });
585
+ const call = executeGraph.mock.calls[0][0];
586
+ expect(call.runtime.jobId).toMatch(/^matrix:/);
587
+ });
588
+ it('processMatrixGraphBatch: shouldClaimNext false exits before the next claim (in-flight run finishes first)', async () => {
589
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
590
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
591
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
592
+ const two = materializeExecutionMatrixRuntimeRows({
593
+ matrixCatalogId: 'cat',
594
+ matrixItemId: 'item',
595
+ matrixRunId: 'r1',
596
+ payload: { input: {}, graphs: ['G'] },
597
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
598
+ inputRows: [{ sourceId: 'sa' }, { sourceId: 'sb' }],
599
+ });
600
+ expect(two).toHaveLength(2);
601
+ for (const r of two)
602
+ await rt.insertRuntimeRow(r);
603
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
604
+ const gate = vi.fn().mockReturnValueOnce(true).mockReturnValueOnce(true).mockReturnValue(false);
605
+ const out = await processMatrixGraphBatch({
606
+ runtime: rt,
607
+ executeGraph,
608
+ resolveGraphModel: resolveGraphModelForTest,
609
+ resolveGraphEntry: () => ({ inputs: [] }),
610
+ shouldClaimNext: () => gate(),
611
+ }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 10 });
612
+ expect(out).toHaveLength(2);
613
+ expect(out.every((o) => 'jobId' in o && o.ok === true)).toBe(true);
614
+ expect(executeGraph).toHaveBeenCalledTimes(2);
615
+ expect(gate).toHaveBeenCalledTimes(3);
616
+ const gateOff = vi.fn().mockReturnValue(false);
617
+ const outB = await processMatrixGraphBatch({
618
+ runtime: rt,
619
+ executeGraph,
620
+ resolveGraphModel: resolveGraphModelForTest,
621
+ resolveGraphEntry: () => ({ inputs: [] }),
622
+ shouldClaimNext: () => gateOff(),
623
+ }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 10 });
624
+ expect(outB).toHaveLength(0);
625
+ expect(executeGraph).toHaveBeenCalledTimes(2);
626
+ });
627
+ it('runtime debugMode is forwarded on the single executeGraph input when jobId is provided', async () => {
628
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
629
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
630
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
631
+ const [row] = materializeExecutionMatrixRuntimeRows({
632
+ matrixCatalogId: 'cat',
633
+ matrixItemId: 'item',
634
+ matrixRunId: 'r1',
635
+ payload: { input: {}, graphs: ['G'] },
636
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
637
+ inputRows: [{}],
638
+ });
639
+ await rt.insertRuntimeRow(row);
640
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
641
+ await processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1, jobId: 'job_rt_1', debugMode: true });
642
+ expect(executeGraph).toHaveBeenCalledTimes(1);
643
+ const call = executeGraph.mock.calls[0][0];
644
+ expect(call.runtime.jobId).toBe('job_rt_1');
645
+ expect(call.runtime.debugMode).toBe(true);
646
+ });
647
+ it('debugMode is omitted from executeGraph input when not requested', async () => {
648
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
649
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
650
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
651
+ const [row] = materializeExecutionMatrixRuntimeRows({
652
+ matrixCatalogId: 'cat',
653
+ matrixItemId: 'item',
654
+ matrixRunId: 'r1',
655
+ payload: { input: {}, graphs: ['G'] },
656
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
657
+ inputRows: [{}],
658
+ });
659
+ await rt.insertRuntimeRow(row);
660
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
661
+ await processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1, jobId: 'job_no_debug' });
662
+ const call = executeGraph.mock.calls[0][0];
663
+ expect('debugMode' in call.runtime).toBe(false);
664
+ });
665
+ it('debugMode without jobId throws (autonomous mode)', async () => {
666
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
667
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
668
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
669
+ const executeGraph = vi.fn();
670
+ await expect(processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1, debugMode: true })).rejects.toThrow(/debugMode requires jobId/i);
671
+ });
672
+ it('jobId in batch requires limit === 1', async () => {
673
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
674
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
675
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
676
+ const executeGraph = vi.fn();
677
+ await expect(processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 2, jobId: 'job_rt_2' })).rejects.toThrow(/limit === 1/i);
678
+ });
679
+ });
680
+ function matrixRuntimeModelConfig(xynth, skill) {
681
+ return {
682
+ cases: [{ modelConfig: { xynthesisModel: xynth, skillModel: skill } }],
683
+ };
684
+ }
685
+ describe('mergeMatrixGraphExecuteOverrides', () => {
686
+ it('returns undefined when neither side is set', () => {
687
+ expect(mergeMatrixGraphExecuteOverrides(undefined, undefined)).toBeUndefined();
688
+ expect(mergeMatrixGraphExecuteOverrides({}, {})).toBeUndefined();
689
+ });
690
+ it('returns deps-level only when per-call is absent', () => {
691
+ expect(mergeMatrixGraphExecuteOverrides({ modelConfig: matrixRuntimeModelConfig('xynth-a', 'skill-a') }, undefined)).toEqual({ modelConfig: matrixRuntimeModelConfig('xynth-a', 'skill-a') });
692
+ });
693
+ it('returns per-call only when deps is absent', () => {
694
+ expect(mergeMatrixGraphExecuteOverrides(undefined, {
695
+ modelConfig: matrixRuntimeModelConfig('xynth-override', 'skill-override'),
696
+ })).toEqual({
697
+ modelConfig: matrixRuntimeModelConfig('xynth-override', 'skill-override'),
698
+ });
699
+ });
700
+ it('shallow-merges object fields per key (per-call wins on collisions)', () => {
701
+ expect(mergeMatrixGraphExecuteOverrides({
702
+ modelConfig: matrixRuntimeModelConfig('xynth-a', 'skill-a'),
703
+ aliasConfig: { 'xynth-a': 'openrouter/xynth-a' },
704
+ llmCall: { topP: 0.9 },
705
+ }, {
706
+ modelConfig: matrixRuntimeModelConfig('xynth-b', 'skill-b'),
707
+ aliasConfig: { 'skill-b': 'openrouter/skill-b' },
708
+ llmCall: { topP: 0.5, maxTokensCap: 1024 },
709
+ })).toEqual({
710
+ modelConfig: matrixRuntimeModelConfig('xynth-b', 'skill-b'),
711
+ aliasConfig: { 'xynth-a': 'openrouter/xynth-a', 'skill-b': 'openrouter/skill-b' },
712
+ llmCall: { topP: 0.5, maxTokensCap: 1024 },
713
+ });
714
+ });
715
+ it('shallow-merges node runtime overrides by node id', () => {
716
+ expect(mergeMatrixGraphExecuteOverrides({
717
+ nodes: {
718
+ n1: {
719
+ modelConfig: { xynthesisModel: 'xynth-a', skillModel: 'skill-a' },
720
+ aliasConfig: { a: 'model-a' },
721
+ },
722
+ },
723
+ }, {
724
+ nodes: {
725
+ n1: {
726
+ modelConfig: { xynthesisModel: 'xynth-b', skillModel: 'skill-b' },
727
+ aliasConfig: { b: 'model-b' },
728
+ },
729
+ n2: { aliasConfig: { c: 'model-c' } },
730
+ },
731
+ })).toEqual({
732
+ nodes: {
733
+ n1: {
734
+ modelConfig: { xynthesisModel: 'xynth-b', skillModel: 'skill-b' },
735
+ aliasConfig: { a: 'model-a', b: 'model-b' },
736
+ },
737
+ n2: { aliasConfig: { c: 'model-c' } },
738
+ },
739
+ });
740
+ });
741
+ it('replaces scalar fields (per-call wins; otherwise deps)', () => {
742
+ expect(mergeMatrixGraphExecuteOverrides({ runLogMode: 'summary', maxRunLogEntries: 100 }, { runLogMode: 'full' })).toEqual({ runLogMode: 'full', maxRunLogEntries: 100 });
743
+ });
744
+ it('replaces runtime memory/output blobs (per-call wins; otherwise deps)', () => {
745
+ expect(mergeMatrixGraphExecuteOverrides({
746
+ jobMemory: { deps: true },
747
+ taskMemory: { deps: true },
748
+ outputsMemory: { answer: { deps: true } },
749
+ }, {
750
+ outputsMemory: { answer: { call: true } },
751
+ })).toEqual({
752
+ jobMemory: { deps: true },
753
+ taskMemory: { deps: true },
754
+ outputsMemory: { answer: { call: true } },
755
+ });
756
+ });
757
+ it('replaces stepRetryPolicy (per-call wins whole object; aligns with graph-engine HostExecuteGraphRunOptions)', () => {
758
+ expect(mergeMatrixGraphExecuteOverrides({ stepRetryPolicy: { maxAttempts: 5, retryOnTimeout: false } }, { stepRetryPolicy: { maxAttempts: 2 } })).toEqual({ stepRetryPolicy: { maxAttempts: 2 } });
759
+ expect(mergeMatrixGraphExecuteOverrides({ stepRetryPolicy: { maxAttempts: 4 } }, undefined)).toEqual({ stepRetryPolicy: { maxAttempts: 4 } });
760
+ });
761
+ });
762
+ describe('orchestrator executeOverrides', () => {
763
+ function setupSingleRow() {
764
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
765
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
766
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
767
+ const [row] = materializeExecutionMatrixRuntimeRows({
768
+ matrixCatalogId: 'cat',
769
+ matrixItemId: 'item',
770
+ matrixRunId: 'r1',
771
+ payload: { input: {}, graphs: ['G'] },
772
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
773
+ inputRows: [{}],
774
+ });
775
+ return { rt, row: row };
776
+ }
777
+ it('forwards per-call modelConfig to executeGraph (FR acceptance)', async () => {
778
+ const { rt, row } = setupSingleRow();
779
+ await rt.insertRuntimeRow(row);
780
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
781
+ const out = await processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, {
782
+ matrixCatalogId: 'cat',
783
+ matrixRunId: 'r1',
784
+ graphIds: ['G'],
785
+ limit: 1,
786
+ executeOverrides: { modelConfig: matrixRuntimeModelConfig('test-xynth', 'test-skill') },
787
+ });
788
+ expect(out).toHaveLength(1);
789
+ const call = executeGraph.mock.calls[0][0];
790
+ expect(call.runtime.modelConfig).toEqual(matrixRuntimeModelConfig('test-xynth', 'test-skill'));
791
+ });
792
+ it('uses deps-level executeOverrides when per-call is omitted', async () => {
793
+ const { rt, row } = setupSingleRow();
794
+ await rt.insertRuntimeRow(row);
795
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
796
+ await processMatrixGraphBatch({
797
+ runtime: rt,
798
+ executeGraph,
799
+ resolveGraphModel: resolveGraphModelForTest,
800
+ resolveGraphEntry: () => ({ inputs: [] }),
801
+ executeOverrides: { modelConfig: matrixRuntimeModelConfig('xynth-a', 'skill-a'), runLogMode: 'full' },
802
+ }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1 });
803
+ const call = executeGraph.mock.calls[0][0];
804
+ expect(call.runtime.modelConfig).toEqual(matrixRuntimeModelConfig('xynth-a', 'skill-a'));
805
+ expect(call.runtime.runLogMode).toBe('full');
806
+ });
807
+ it('shallow-merges per-call over deps (per-call wins on collisions)', async () => {
808
+ const { rt, row } = setupSingleRow();
809
+ await rt.insertRuntimeRow(row);
810
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
811
+ await processMatrixGraphBatch({
812
+ runtime: rt,
813
+ executeGraph,
814
+ resolveGraphModel: resolveGraphModelForTest,
815
+ resolveGraphEntry: () => ({ inputs: [] }),
816
+ executeOverrides: { modelConfig: matrixRuntimeModelConfig('xynth-a', 'skill-a') },
817
+ }, {
818
+ matrixCatalogId: 'cat',
819
+ matrixRunId: 'r1',
820
+ graphIds: ['G'],
821
+ limit: 1,
822
+ executeOverrides: { modelConfig: matrixRuntimeModelConfig('xynth-b', 'skill-b') },
823
+ });
824
+ const call = executeGraph.mock.calls[0][0];
825
+ expect(call.runtime.modelConfig).toEqual(matrixRuntimeModelConfig('xynth-b', 'skill-b'));
826
+ });
827
+ it('omits runtime override fields when neither side is set', async () => {
828
+ const { rt, row } = setupSingleRow();
829
+ await rt.insertRuntimeRow(row);
830
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
831
+ await processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1 });
832
+ const call = executeGraph.mock.calls[0][0];
833
+ /** Keys introduced only via merged `executeOverrides` — not matrix-owned runtime fields from orchestrator. */
834
+ const noOverridesExpected = [
835
+ 'failFast',
836
+ 'skillKeyResolution',
837
+ 'nodeTimeoutMs',
838
+ 'executionPipeline',
839
+ 'playgroundMeta',
840
+ 'clearSynthesizedContextPerNode',
841
+ 'modelConfig',
842
+ 'aliasConfig',
843
+ 'nodes',
844
+ 'llmCall',
845
+ 'runTaskIdentity',
846
+ 'runTaskExecutionMode',
847
+ 'runLogMode',
848
+ 'maxRunLogEntries',
849
+ 'maxRunLogDataJsonChars',
850
+ 'runTaskDiagnostics',
851
+ 'mode',
852
+ 'goalNodeId',
853
+ 'dimension',
854
+ 'jobMemory',
855
+ 'taskMemory',
856
+ 'outputsMemory',
857
+ 'variables',
858
+ 'initialState',
859
+ 'initialVariables',
860
+ 'runtimeObjects',
861
+ 'playgroundReporter',
862
+ 'eventEmitter',
863
+ 'stepRetryPolicy',
864
+ ];
865
+ for (const k of noOverridesExpected) {
866
+ expect(k in call.runtime).toBe(false);
867
+ }
868
+ });
869
+ it('forwards outputsMemory overrides to graph-engine runtime', async () => {
870
+ const { rt, row } = setupSingleRow();
871
+ await rt.insertRuntimeRow(row);
872
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
873
+ await processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, {
874
+ matrixCatalogId: 'cat',
875
+ matrixRunId: 'r1',
876
+ graphIds: ['G'],
877
+ limit: 1,
878
+ executeOverrides: { outputsMemory: { seeded: { value: 1 } } },
879
+ });
880
+ const call = executeGraph.mock.calls[0][0];
881
+ expect(call.runtime.outputsMemory).toEqual({ seeded: { value: 1 } });
882
+ });
883
+ it('debugMode receives merged overrides on the same single executor', async () => {
884
+ const { rt, row } = setupSingleRow();
885
+ await rt.insertRuntimeRow(row);
886
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
887
+ await processMatrixGraphBatch({
888
+ runtime: rt,
889
+ executeGraph,
890
+ resolveGraphModel: resolveGraphModelForTest,
891
+ resolveGraphEntry: () => ({ inputs: [] }),
892
+ executeOverrides: { modelConfig: matrixRuntimeModelConfig('xynth-a', 'skill-a') },
893
+ }, {
894
+ matrixCatalogId: 'cat',
895
+ matrixRunId: 'r1',
896
+ graphIds: ['G'],
897
+ limit: 1,
898
+ jobId: 'job_rt_dbg',
899
+ debugMode: true,
900
+ executeOverrides: {
901
+ modelConfig: matrixRuntimeModelConfig('xynth-b', 'skill-b'),
902
+ runTaskExecutionMode: 'trace',
903
+ },
904
+ });
905
+ expect(executeGraph).toHaveBeenCalledTimes(1);
906
+ const call = executeGraph.mock.calls[0][0];
907
+ expect(call.runtime.jobId).toBe('job_rt_dbg');
908
+ expect(call.runtime.debugMode).toBe(true);
909
+ expect(call.runtime.modelConfig).toEqual(matrixRuntimeModelConfig('xynth-b', 'skill-b'));
910
+ expect(call.runtime.runTaskExecutionMode).toBe('trace');
911
+ });
912
+ it('processNextMatrixClaim forwards executeOverrides per-call', async () => {
913
+ const { rt, row } = setupSingleRow();
914
+ await rt.insertRuntimeRow(row);
915
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
916
+ await processNextMatrixClaim({ runtime: rt, executeGraph, graphModel: graphModelFor('G', { inputs: [] }) }, {
917
+ matrixCatalogId: 'cat',
918
+ graphId: 'G',
919
+ executeOverrides: { llmCall: { maxTokensCap: 2048 }, runLogMode: 'full' },
920
+ });
921
+ const call = executeGraph.mock.calls[0][0];
922
+ expect(call.runtime.llmCall).toEqual({ maxTokensCap: 2048 });
923
+ expect(call.runtime.runLogMode).toBe('full');
924
+ });
925
+ });
926
+ describe('sanitizeMatrixGraphExecuteOverrides', () => {
927
+ it('strips job correlation keys after merge', () => {
928
+ const dirty = {
929
+ modelConfig: matrixRuntimeModelConfig('xynth-base', 'skill-base'),
930
+ jobId: 'evil',
931
+ graphId: 'evil-g',
932
+ job: { x: 1 },
933
+ input: { x: 1 },
934
+ executionMemory: { input: { x: 1 } },
935
+ };
936
+ expect(sanitizeMatrixGraphExecuteOverrides(dirty)).toEqual({
937
+ modelConfig: matrixRuntimeModelConfig('xynth-base', 'skill-base'),
938
+ });
939
+ });
940
+ });
941
+ describe('matrix boundaries (integration-style)', () => {
942
+ const executionMatrixSrcRoot = fileURLToPath(new URL('.', import.meta.url));
943
+ function listExecutionMatrixTsFiles(dir) {
944
+ const out = [];
945
+ for (const ent of readdirSync(dir, { withFileTypes: true })) {
946
+ const p = join(dir, ent.name);
947
+ if (ent.isDirectory())
948
+ out.push(...listExecutionMatrixTsFiles(p));
949
+ else if (ent.name.endsWith('.ts') && !ent.name.endsWith('.spec.ts'))
950
+ out.push(p);
951
+ }
952
+ return out;
953
+ }
954
+ it('runtime modules do not import @exellix/ai-tasks directly (graph-engine owns ai-tasks)', () => {
955
+ for (const f of listExecutionMatrixTsFiles(executionMatrixSrcRoot)) {
956
+ if (basename(f) === 'index.ts')
957
+ continue;
958
+ const text = readFileSync(f, 'utf8');
959
+ expect(text, basename(f)).not.toMatch(/from ['"]@exellix\/ai-tasks['"]/);
960
+ }
961
+ });
962
+ it('malicious executeOverrides cannot override jobId, job, or graphId on the executor call', async () => {
963
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
964
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
965
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
966
+ const [row] = materializeExecutionMatrixRuntimeRows({
967
+ matrixCatalogId: 'cat',
968
+ matrixItemId: 'item',
969
+ matrixRunId: 'r1',
970
+ payload: { input: {}, graphs: ['G'] },
971
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
972
+ inputRows: [{}],
973
+ });
974
+ await rt.insertRuntimeRow(row);
975
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
976
+ await processMatrixGraphBatch({
977
+ runtime: rt,
978
+ executeGraph,
979
+ resolveGraphModel: resolveGraphModelForTest,
980
+ resolveGraphEntry: () => ({ inputs: [] }),
981
+ executeOverrides: {
982
+ jobId: 'evil-job',
983
+ graphId: 'evil-graph',
984
+ job: { injected: true },
985
+ input: { injected: true },
986
+ executionMemory: { injected: true },
987
+ variables: { only: 'allowed' },
988
+ },
989
+ }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1 });
990
+ const call = executeGraph.mock.calls[0][0];
991
+ expect(call.model.id).toBe('G');
992
+ expect(call.runtime.jobId).toMatch(/^matrix:/);
993
+ expect(call.runtime.job).toEqual({
994
+ id: call.runtime.jobId,
995
+ jobId: call.runtime.jobId,
996
+ agentId: 'exellix-runtime',
997
+ jobTypeId: 'execution-matrix-graph-run',
998
+ matrixRowId: row.matrixRowId,
999
+ matrixCatalogId: 'cat',
1000
+ matrixRunId: 'r1',
1001
+ graphId: 'G',
1002
+ });
1003
+ expect(call.runtime.input).toEqual(row.input);
1004
+ expect(call.runtime.executionMemory).toEqual({});
1005
+ expect(call.runtime.variables).toEqual({ only: 'allowed' });
1006
+ });
1007
+ it('persists graph-engine taskId on graph failure records', async () => {
1008
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1009
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1010
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
1011
+ const [row] = materializeExecutionMatrixRuntimeRows({
1012
+ matrixCatalogId: 'cat',
1013
+ matrixItemId: 'item',
1014
+ matrixRunId: 'r1',
1015
+ payload: { input: {}, graphs: ['G'] },
1016
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1017
+ inputRows: [{}],
1018
+ });
1019
+ await rt.insertRuntimeRow(row);
1020
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphFailed());
1021
+ await processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1 });
1022
+ const audit = await fails.readMany({}, { limit: 5 });
1023
+ expect(audit).toHaveLength(1);
1024
+ expect(audit[0].taskId).toBe('mock-task-fail');
1025
+ expect(audit[0].graphId).toBe('G');
1026
+ expect(audit[0].matrixRunId).toBe('r1');
1027
+ expect(typeof audit[0].jobId).toBe('string');
1028
+ });
1029
+ it('stores finalOutput as inference knowledge on success', async () => {
1030
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1031
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1032
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
1033
+ const [row] = materializeExecutionMatrixRuntimeRows({
1034
+ matrixCatalogId: 'cat',
1035
+ matrixItemId: 'item',
1036
+ matrixRunId: 'r1',
1037
+ payload: { input: {}, graphs: ['G'] },
1038
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1039
+ inputRows: [{}],
1040
+ });
1041
+ await rt.insertRuntimeRow(row);
1042
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess({ verdict: 'ok' }));
1043
+ await processMatrixGraphBatch({ runtime: rt, executeGraph, resolveGraphModel: resolveGraphModelForTest, resolveGraphEntry: () => ({ inputs: [] }) }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1 });
1044
+ const after = await rt.getRecord(row.matrixRowId);
1045
+ expect(after?.inferences).toHaveLength(1);
1046
+ expect(after?.inferences[0].knowledge).toEqual({ verdict: 'ok' });
1047
+ expect(after?.inferences[0].graphId).toBe('G');
1048
+ });
1049
+ it('passes matrix row input into executeGraph execution seed via graphEntry paths', async () => {
1050
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1051
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1052
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), { serializeClaims: true });
1053
+ const [row] = materializeExecutionMatrixRuntimeRows({
1054
+ matrixCatalogId: 'cat',
1055
+ matrixItemId: 'item',
1056
+ matrixRunId: 'r1',
1057
+ payload: { input: {}, graphs: ['G'] },
1058
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1059
+ inputRows: [{ raw: { blob: 9 } }],
1060
+ });
1061
+ await rt.insertRuntimeRow(row);
1062
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
1063
+ await processMatrixGraphBatch({
1064
+ runtime: rt,
1065
+ executeGraph,
1066
+ resolveGraphModel: resolveGraphModelForTest,
1067
+ resolveGraphEntry: () => ({
1068
+ inputs: [{ kind: 'record', path: 'input.raw', required: true }],
1069
+ }),
1070
+ }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphIds: ['G'], limit: 1 });
1071
+ const call = executeGraph.mock.calls[0][0];
1072
+ expect(call.runtime.executionMemory.input.raw).toEqual({ blob: 9 });
1073
+ });
1074
+ });
1075
+ /* ============================================================================
1076
+ * New surface coverage: data sources, run loop, snapshots, eligibility, config CRUD.
1077
+ * ==========================================================================*/
1078
+ describe('parseExecutionMatrixCatalogPayload (extended)', () => {
1079
+ it('accepts a record dataSource with executionMode and eligibility', () => {
1080
+ const p = parseExecutionMatrixCatalogPayload({
1081
+ input: {},
1082
+ graphs: ['g.a'],
1083
+ dataSource: {
1084
+ kind: 'record',
1085
+ collectionRef: 'col.records',
1086
+ recordsPerRun: 5,
1087
+ pollWhenEmptySeconds: 60,
1088
+ eligibility: { fromStatuses: ['not-started'], excludeStatuses: ['in-progress'] },
1089
+ },
1090
+ executionMode: { mode: 'continuous' },
1091
+ });
1092
+ expect(p.dataSource).toMatchObject({ kind: 'record', recordsPerRun: 5 });
1093
+ expect(p.executionMode).toEqual({ mode: 'continuous' });
1094
+ });
1095
+ it('accepts a query-snapshot dataSource with transform', () => {
1096
+ const p = parseExecutionMatrixCatalogPayload({
1097
+ input: {},
1098
+ graphs: ['g.a'],
1099
+ dataSource: {
1100
+ kind: 'query-snapshot',
1101
+ collectionRef: 'col.q',
1102
+ transform: { language: 'js', source: 'return records.length', version: 'v1', timeoutMs: 500 },
1103
+ materialize: 'one-row',
1104
+ pollWhenEmptySeconds: 3600,
1105
+ },
1106
+ });
1107
+ expect(p.dataSource).toMatchObject({ kind: 'query-snapshot' });
1108
+ });
1109
+ it('rejects invalid recordsPerRun', async () => {
1110
+ expect(() => parseExecutionMatrixCatalogPayload({
1111
+ input: {},
1112
+ graphs: ['g.a'],
1113
+ dataSource: { kind: 'record', collectionRef: 'col.r', recordsPerRun: 0 },
1114
+ })).toThrow(ExecutionMatrixCatalogValidationError);
1115
+ expect(() => parseExecutionMatrixCatalogPayload({
1116
+ input: {},
1117
+ graphs: ['g.a'],
1118
+ dataSource: { kind: 'record', collectionRef: 'col.r', recordsPerRun: 99999 },
1119
+ })).toThrow(ExecutionMatrixCatalogValidationError);
1120
+ });
1121
+ it('rejects transform without source or version', () => {
1122
+ expect(() => parseExecutionMatrixCatalogPayload({
1123
+ input: {},
1124
+ graphs: ['g.a'],
1125
+ dataSource: {
1126
+ kind: 'query-snapshot',
1127
+ collectionRef: 'q',
1128
+ transform: { language: 'js', source: '', version: 'v1' },
1129
+ },
1130
+ })).toThrow(ExecutionMatrixCatalogValidationError);
1131
+ expect(() => parseExecutionMatrixCatalogPayload({
1132
+ input: {},
1133
+ graphs: ['g.a'],
1134
+ dataSource: {
1135
+ kind: 'query-snapshot',
1136
+ collectionRef: 'q',
1137
+ transform: { language: 'js', source: 'return 1', version: '' },
1138
+ },
1139
+ })).toThrow(ExecutionMatrixCatalogValidationError);
1140
+ });
1141
+ it('warns about unusual pollWhenEmptySeconds', async () => {
1142
+ const { parseExecutionMatrixCatalogPayloadWithWarnings } = await import('./catalox-loader.js');
1143
+ const r = parseExecutionMatrixCatalogPayloadWithWarnings({
1144
+ input: {},
1145
+ graphs: ['g.a'],
1146
+ dataSource: {
1147
+ kind: 'query-snapshot',
1148
+ collectionRef: 'q',
1149
+ transform: { language: 'js', source: 'return 1', version: 'v1' },
1150
+ pollWhenEmptySeconds: 5,
1151
+ },
1152
+ });
1153
+ expect(r.warnings.length).toBeGreaterThan(0);
1154
+ expect(r.warnings[0]).toMatch(/unusually short/);
1155
+ });
1156
+ it('rejects executionMode unknown value', () => {
1157
+ expect(() => parseExecutionMatrixCatalogPayload({
1158
+ input: {},
1159
+ graphs: ['g.a'],
1160
+ executionMode: 'forever',
1161
+ })).toThrow(ExecutionMatrixCatalogValidationError);
1162
+ });
1163
+ });
1164
+ describe('eligibilityToClaim', () => {
1165
+ it('defaults to fromStatuses=["not-started"]', async () => {
1166
+ const { eligibilityToClaim } = await import('./eligibility.js');
1167
+ expect(eligibilityToClaim(undefined).fromStatuses).toEqual(['not-started']);
1168
+ });
1169
+ it('subtracts excludeStatuses and merges extraFilter', async () => {
1170
+ const { eligibilityToClaim } = await import('./eligibility.js');
1171
+ const r = eligibilityToClaim({
1172
+ fromStatuses: ['not-started', 'failed'],
1173
+ excludeStatuses: ['failed'],
1174
+ extraFilter: { 'input.tier': 'A' },
1175
+ });
1176
+ expect(r.fromStatuses).toEqual(['not-started']);
1177
+ expect(r.extraFilter).toEqual({ 'input.tier': 'A' });
1178
+ });
1179
+ it('emits ageMinMinutes and modelProfileNotIn clauses', async () => {
1180
+ const { eligibilityToClaim } = await import('./eligibility.js');
1181
+ const fixed = new Date('2026-05-08T00:00:00Z');
1182
+ const r = eligibilityToClaim({ ageMinMinutes: 30, modelProfileNotIn: ['gpt-4o-mini'] }, fixed);
1183
+ expect(r.extraFilter?.['execution.lastAttempt.endedAt.$lte']).toBe('2026-05-07T23:30:00.000Z');
1184
+ expect(r.extraFilter?.['execution.lastAttempt.modelProfile.$nin']).toEqual(['gpt-4o-mini']);
1185
+ });
1186
+ });
1187
+ describe('chunkInputRowsForBatch + materializeBatchedRecordRows', () => {
1188
+ it('bundles inputs by recordsPerRun and lifts sourceIds when present', async () => {
1189
+ const { chunkInputRowsForBatch, materializeBatchedRecordRows } = await import('./materializer.js');
1190
+ const chunks = chunkInputRowsForBatch([{ sourceId: 'a' }, { sourceId: 'b' }, { sourceId: 'c' }], 2);
1191
+ expect(chunks).toHaveLength(2);
1192
+ expect(chunks[0].records).toHaveLength(2);
1193
+ expect(chunks[0].sourceIds).toEqual(['a', 'b']);
1194
+ expect(chunks[1].sourceIds).toEqual(['c']);
1195
+ const rows = materializeBatchedRecordRows({
1196
+ matrixCatalogId: 'cat',
1197
+ matrixItemId: 'item',
1198
+ payload: { input: {}, graphs: ['G'] },
1199
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1200
+ inputRows: [{ sourceId: 'a' }, { sourceId: 'b' }, { sourceId: 'c' }],
1201
+ recordsPerRun: 2,
1202
+ });
1203
+ expect(rows).toHaveLength(2);
1204
+ expect(rows[0].input.records).toHaveLength(2);
1205
+ expect(rows[0].input.sourceIds).toEqual(['a', 'b']);
1206
+ });
1207
+ it('falls back to one-row-per-input when recordsPerRun <= 1', async () => {
1208
+ const { materializeBatchedRecordRows } = await import('./materializer.js');
1209
+ const rows = materializeBatchedRecordRows({
1210
+ matrixCatalogId: 'cat',
1211
+ matrixItemId: 'item',
1212
+ payload: { input: {}, graphs: ['G'] },
1213
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1214
+ inputRows: [{ x: 1 }, { x: 2 }],
1215
+ recordsPerRun: 1,
1216
+ });
1217
+ expect(rows).toHaveLength(2);
1218
+ expect(rows[0].input.x).toBe(1);
1219
+ });
1220
+ });
1221
+ describe('snapshot runner', () => {
1222
+ it('runs a JS transform and returns a payload', async () => {
1223
+ const { runSnapshotTransform } = await import('./snapshot-runner.js');
1224
+ const r = runSnapshotTransform({ language: 'js', source: 'return records.length', version: 'v1' }, { records: [{}, {}, {}] });
1225
+ expect(r.payload).toBe(3);
1226
+ expect(r.transformVersion).toBe('v1');
1227
+ });
1228
+ it('honors timeoutMs', async () => {
1229
+ const { runSnapshotTransform } = await import('./snapshot-runner.js');
1230
+ expect(() => runSnapshotTransform({
1231
+ language: 'js',
1232
+ source: 'while (true) { /* spin */ }',
1233
+ version: 'v1',
1234
+ timeoutMs: 50,
1235
+ }, { records: [] })).toThrow(/execution failed/);
1236
+ });
1237
+ it('does not expose require / process', async () => {
1238
+ const { runSnapshotTransform } = await import('./snapshot-runner.js');
1239
+ const r = runSnapshotTransform({
1240
+ language: 'js',
1241
+ source: 'return typeof require + ":" + typeof process',
1242
+ version: 'v1',
1243
+ }, { records: [] });
1244
+ expect(r.payload).toBe('undefined:undefined');
1245
+ });
1246
+ it('builds a snapshot record with stable hash', async () => {
1247
+ const { buildSnapshotRecord, buildSourceQueryHash } = await import('./snapshot-runner.js');
1248
+ const rec = buildSnapshotRecord({
1249
+ matrixCatalogId: 'cat',
1250
+ sourceIds: ['x', 'y'],
1251
+ transformResult: { payload: [1, 2], transformVersion: 'v1' },
1252
+ });
1253
+ expect(rec.matrixCatalogId).toBe('cat');
1254
+ expect(rec.payload).toEqual([1, 2]);
1255
+ expect(rec.sourceQueryHash).toBe(buildSourceQueryHash(undefined, ['x', 'y']));
1256
+ });
1257
+ });
1258
+ describe('per-status helpers + fetchSourceJoinView', () => {
1259
+ async function setupRowsWithMixedStatus() {
1260
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1261
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1262
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1263
+ serializeClaims: true,
1264
+ });
1265
+ const tpl = {
1266
+ matrixCatalogId: 'cat',
1267
+ matrixItemId: 'item',
1268
+ matrixRunId: 'r1',
1269
+ payload: { input: {}, graphs: ['G'] },
1270
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1271
+ };
1272
+ const [a] = materializeExecutionMatrixRuntimeRows({ ...tpl, inputRows: [{ sourceId: 'a' }] });
1273
+ const [b] = materializeExecutionMatrixRuntimeRows({ ...tpl, matrixItemId: 'i2', inputRows: [{ sourceId: 'b' }] });
1274
+ const [c] = materializeExecutionMatrixRuntimeRows({ ...tpl, matrixItemId: 'i3', inputRows: [{ sourceId: 'c' }] });
1275
+ await rt.insertRuntimeRow(a);
1276
+ await rt.insertRuntimeRow(b);
1277
+ await rt.insertRuntimeRow(c);
1278
+ const claim = await rt.claimNext({ matrixCatalogId: 'cat', matrixRunId: 'r1', graphId: 'G' });
1279
+ if (!claim.ok)
1280
+ throw new Error('claim');
1281
+ await rt.markCompleted(claim.record.matrixRowId, 'G', { graphId: 'G', knowledge: {} });
1282
+ const claim2 = await rt.claimNext({ matrixCatalogId: 'cat', matrixRunId: 'r1', graphId: 'G' });
1283
+ if (!claim2.ok)
1284
+ throw new Error('claim2');
1285
+ await rt.markFailed(claim2.record.matrixRowId, 'G', 'boom');
1286
+ return rt;
1287
+ }
1288
+ it('listWaiting / listCompleted / listFailed reflect status', async () => {
1289
+ const rt = await setupRowsWithMixedStatus();
1290
+ const waiting = await rt.listWaiting({ matrixCatalogId: 'cat', graphId: 'G', matrixRunId: 'r1' });
1291
+ const completed = await rt.listCompleted({ matrixCatalogId: 'cat', graphId: 'G', matrixRunId: 'r1' });
1292
+ const failed = await rt.listFailed({ matrixCatalogId: 'cat', graphId: 'G', matrixRunId: 'r1' });
1293
+ expect(waiting).toHaveLength(1);
1294
+ expect(completed).toHaveLength(1);
1295
+ expect(failed).toHaveLength(1);
1296
+ });
1297
+ it('fetchSourceJoinView surfaces waitingInSource diff via resolver', async () => {
1298
+ const { fetchSourceJoinView } = await import('./navigator.js');
1299
+ const rt = await setupRowsWithMixedStatus();
1300
+ const sourceResolver = {
1301
+ listSourceIds: async () => ['a', 'b', 'c', 'd'],
1302
+ fetchRecordsByIds: async (ids) => ids.map((id) => ({ sourceId: id })),
1303
+ };
1304
+ const view = await fetchSourceJoinView({ runtime: rt, sourceResolver }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphId: 'G' });
1305
+ expect(view.waitingInSource).toEqual(['d']);
1306
+ expect(view.processed).toHaveLength(1);
1307
+ expect(view.failed).toHaveLength(1);
1308
+ expect(view.waitingInMatrix).toHaveLength(1);
1309
+ });
1310
+ it('fetchSourceJoinView without resolver returns empty waitingInSource', async () => {
1311
+ const { fetchSourceJoinView } = await import('./navigator.js');
1312
+ const rt = await setupRowsWithMixedStatus();
1313
+ const view = await fetchSourceJoinView({ runtime: rt }, { matrixCatalogId: 'cat', matrixRunId: 'r1', graphId: 'G' });
1314
+ expect(view.waitingInSource).toEqual([]);
1315
+ });
1316
+ });
1317
+ describe('snapshots CRUD on ExecutionMatrixRuntime', () => {
1318
+ it('insert / get / list', async () => {
1319
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1320
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1321
+ const snaps = new MemoryMatrixCollection('snapshotId');
1322
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1323
+ serializeClaims: true,
1324
+ snapshots: snaps.asCollection(),
1325
+ });
1326
+ await rt.insertSnapshot({
1327
+ snapshotId: 's1',
1328
+ matrixCatalogId: 'cat',
1329
+ matrixRunId: 'r1',
1330
+ sourceQueryHash: 'h',
1331
+ transformVersion: 'v1',
1332
+ payload: { ok: 1 },
1333
+ createdAt: new Date().toISOString(),
1334
+ });
1335
+ const got = await rt.getSnapshot('s1');
1336
+ expect(got?.payload).toEqual({ ok: 1 });
1337
+ const list = await rt.listSnapshots({ matrixCatalogId: 'cat' });
1338
+ expect(list).toHaveLength(1);
1339
+ });
1340
+ it('listSnapshots filters by entityType and extraFilter; countSnapshots', async () => {
1341
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1342
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1343
+ const snaps = new MemoryMatrixCollection('snapshotId');
1344
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1345
+ snapshots: snaps.asCollection(),
1346
+ });
1347
+ await rt.insertSnapshot({
1348
+ snapshotId: 's_a',
1349
+ matrixCatalogId: 'cat',
1350
+ entityType: 'etype_a',
1351
+ sourceQueryHash: 'h1',
1352
+ transformVersion: 'v1',
1353
+ payload: {},
1354
+ createdAt: new Date().toISOString(),
1355
+ });
1356
+ await rt.insertSnapshot({
1357
+ snapshotId: 's_b',
1358
+ matrixCatalogId: 'cat',
1359
+ entityType: 'etype_b',
1360
+ sourceQueryHash: 'h2',
1361
+ transformVersion: 'v1',
1362
+ payload: {},
1363
+ createdAt: new Date().toISOString(),
1364
+ });
1365
+ const filtered = await rt.listSnapshots({ matrixCatalogId: 'cat', entityType: 'etype_a' });
1366
+ expect(filtered.map((s) => s.snapshotId)).toEqual(['s_a']);
1367
+ await expect(rt.countSnapshots({ matrixCatalogId: 'cat', entityType: 'etype_b' })).resolves.toBe(1);
1368
+ });
1369
+ it('buildSnapshotsReadFilter merges entityType and extraFilter', () => {
1370
+ expect(buildSnapshotsReadFilter({
1371
+ matrixCatalogId: 'c',
1372
+ matrixRunId: 'r',
1373
+ entityType: 'e',
1374
+ extraFilter: { transformVersion: 'v2' },
1375
+ })).toEqual({
1376
+ matrixCatalogId: 'c',
1377
+ matrixRunId: 'r',
1378
+ entityType: 'e',
1379
+ transformVersion: 'v2',
1380
+ });
1381
+ });
1382
+ it('throws when snapshots collection is not configured', async () => {
1383
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1384
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1385
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1386
+ serializeClaims: true,
1387
+ });
1388
+ await expect(rt.listSnapshots({})).rejects.toThrow(/snapshots collection not configured/);
1389
+ });
1390
+ });
1391
+ describe('orchestrator writes lastAttempt on completion / failure', () => {
1392
+ it('persists lastAttempt with status, endedAt, jobId, modelProfile', async () => {
1393
+ const { processMatrixGraphBatch } = await import('./orchestrator.js');
1394
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1395
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1396
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1397
+ serializeClaims: true,
1398
+ });
1399
+ const [row] = materializeExecutionMatrixRuntimeRows({
1400
+ matrixCatalogId: 'cat',
1401
+ matrixItemId: 'item',
1402
+ matrixRunId: 'r1',
1403
+ payload: { input: {}, graphs: ['G'] },
1404
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1405
+ inputRows: [{}],
1406
+ });
1407
+ await rt.insertRuntimeRow(row);
1408
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess({}));
1409
+ await processMatrixGraphBatch({
1410
+ runtime: rt,
1411
+ executeGraph,
1412
+ resolveGraphModel: resolveGraphModelForTest,
1413
+ resolveGraphEntry: () => ({ inputs: [] }),
1414
+ }, {
1415
+ matrixCatalogId: 'cat',
1416
+ matrixRunId: 'r1',
1417
+ graphIds: ['G'],
1418
+ limit: 1,
1419
+ jobId: 'job-1',
1420
+ executeOverrides: { modelConfig: matrixRuntimeModelConfig('gpt-4o-xynth', 'gpt-4o-skill') },
1421
+ });
1422
+ const after = await rt.getRecord(row.matrixRowId);
1423
+ const step = after?.execution.find((e) => e.graphId === 'G');
1424
+ expect(step?.lastAttempt?.status).toBe('completed');
1425
+ expect(step?.lastAttempt?.endedAt).toMatch(/T/);
1426
+ expect(step?.lastAttempt?.jobId).toBe('job-1');
1427
+ expect(step?.lastAttempt?.modelProfile).toBe('gpt-4o-xynth/gpt-4o-skill');
1428
+ });
1429
+ });
1430
+ describe('runMatrixOncePass', () => {
1431
+ it('record kind: fetches via resolver, materializes, executes', async () => {
1432
+ const { runMatrixOncePass } = await import('./run-loop.js');
1433
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1434
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1435
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1436
+ serializeClaims: true,
1437
+ });
1438
+ const sourceResolver = {
1439
+ listSourceIds: async () => ['a', 'b'],
1440
+ fetchRecordsByIds: async (ids) => ids.map((id) => ({ sourceId: id, payload: id })),
1441
+ };
1442
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
1443
+ const result = await runMatrixOncePass({
1444
+ runtime: rt,
1445
+ executeGraph,
1446
+ sourceResolver,
1447
+ resolveGraphModel: resolveGraphModelForTest,
1448
+ resolveGraphEntry: () => ({ inputs: [] }),
1449
+ }, {
1450
+ matrixCatalogId: 'cat',
1451
+ matrixItemId: 'item',
1452
+ matrixRunId: 'r1',
1453
+ payload: {
1454
+ input: {},
1455
+ graphs: ['G'],
1456
+ dataSource: { kind: 'record', collectionRef: 'col', recordsPerRun: 2 },
1457
+ executionMode: { mode: 'single-pass' },
1458
+ },
1459
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1460
+ });
1461
+ expect(result.fetched).toBe(2);
1462
+ expect(result.materialized).toBe(1);
1463
+ expect(result.executed).toBeGreaterThanOrEqual(1);
1464
+ expect(result.emptyPass).toBe(false);
1465
+ });
1466
+ it('query-snapshot kind: runs transform, persists snapshot, materializes', async () => {
1467
+ const { runMatrixOncePass } = await import('./run-loop.js');
1468
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1469
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1470
+ const snaps = new MemoryMatrixCollection('snapshotId');
1471
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1472
+ serializeClaims: true,
1473
+ snapshots: snaps.asCollection(),
1474
+ });
1475
+ const sourceResolver = {
1476
+ listSourceIds: async () => ['a', 'b', 'c'],
1477
+ fetchRecordsByIds: async (ids) => ids.map((id) => ({ id })),
1478
+ };
1479
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
1480
+ const result = await runMatrixOncePass({
1481
+ runtime: rt,
1482
+ executeGraph,
1483
+ sourceResolver,
1484
+ resolveGraphModel: resolveGraphModelForTest,
1485
+ resolveGraphEntry: () => ({ inputs: [] }),
1486
+ }, {
1487
+ matrixCatalogId: 'cat',
1488
+ matrixItemId: 'item',
1489
+ matrixRunId: 'r1',
1490
+ payload: {
1491
+ input: {},
1492
+ graphs: ['G'],
1493
+ dataSource: {
1494
+ kind: 'query-snapshot',
1495
+ collectionRef: 'col',
1496
+ transform: { language: 'js', source: 'return { count: records.length }', version: 'v1' },
1497
+ },
1498
+ },
1499
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1500
+ });
1501
+ expect(result.fetched).toBe(3);
1502
+ expect(result.materialized).toBe(1);
1503
+ expect(result.snapshotId).toMatch(/^snap_/);
1504
+ const persistedSnapshot = await rt.getSnapshot(result.snapshotId);
1505
+ expect(persistedSnapshot?.payload).toEqual({ count: 3 });
1506
+ });
1507
+ it('event kind: returns empty pass when nothing is supplied (no loop fetch)', async () => {
1508
+ const { runMatrixOncePass } = await import('./run-loop.js');
1509
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1510
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1511
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1512
+ serializeClaims: true,
1513
+ });
1514
+ const result = await runMatrixOncePass({
1515
+ runtime: rt,
1516
+ executeGraph: vi.fn().mockResolvedValue(mockExecuteGraphSuccess()),
1517
+ resolveGraphModel: resolveGraphModelForTest,
1518
+ resolveGraphEntry: () => ({ inputs: [] }),
1519
+ }, {
1520
+ matrixCatalogId: 'cat',
1521
+ matrixItemId: 'item',
1522
+ payload: {
1523
+ input: {},
1524
+ graphs: ['G'],
1525
+ dataSource: { kind: 'event', subKind: 'api' },
1526
+ },
1527
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1528
+ });
1529
+ expect(result.emptyPass).toBe(true);
1530
+ expect(result.fetched).toBe(0);
1531
+ expect(result.materialized).toBe(0);
1532
+ });
1533
+ });
1534
+ describe('runMatrixContinuously', () => {
1535
+ it('returns event-source for event kind matrices', async () => {
1536
+ const { runMatrixContinuously } = await import('./run-loop.js');
1537
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1538
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1539
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1540
+ serializeClaims: true,
1541
+ });
1542
+ const ctrl = new AbortController();
1543
+ const r = await runMatrixContinuously({
1544
+ runtime: rt,
1545
+ executeGraph: vi.fn(),
1546
+ resolveGraphModel: resolveGraphModelForTest,
1547
+ resolveGraphEntry: () => ({ inputs: [] }),
1548
+ }, {
1549
+ matrixCatalogId: 'cat',
1550
+ matrixItemId: 'item',
1551
+ payload: { input: {}, graphs: ['G'], dataSource: { kind: 'event' } },
1552
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1553
+ signal: ctrl.signal,
1554
+ });
1555
+ expect(r.reason).toBe('event-source');
1556
+ });
1557
+ it('respects maxCycles', async () => {
1558
+ const { runMatrixContinuously } = await import('./run-loop.js');
1559
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1560
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1561
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1562
+ serializeClaims: true,
1563
+ });
1564
+ let calls = 0;
1565
+ const sourceResolver = {
1566
+ listSourceIds: async () => {
1567
+ calls += 1;
1568
+ return [`x_${calls}`];
1569
+ },
1570
+ fetchRecordsByIds: async (ids) => ids.map((id) => ({ sourceId: id })),
1571
+ };
1572
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
1573
+ const ctrl = new AbortController();
1574
+ const r = await runMatrixContinuously({
1575
+ runtime: rt,
1576
+ executeGraph,
1577
+ sourceResolver,
1578
+ resolveGraphModel: resolveGraphModelForTest,
1579
+ resolveGraphEntry: () => ({ inputs: [] }),
1580
+ }, {
1581
+ matrixCatalogId: 'cat',
1582
+ matrixItemId: 'item',
1583
+ payload: {
1584
+ input: {},
1585
+ graphs: ['G'],
1586
+ dataSource: { kind: 'record', collectionRef: 'col', pollWhenEmptySeconds: 1 },
1587
+ executionMode: { mode: 'continuous' },
1588
+ },
1589
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1590
+ signal: ctrl.signal,
1591
+ maxCycles: 2,
1592
+ });
1593
+ expect(r.reason).toBe('maxCycles');
1594
+ expect(r.cyclesRun).toBe(2);
1595
+ });
1596
+ it('aborts cleanly during empty-pass sleep', async () => {
1597
+ const { runMatrixContinuously } = await import('./run-loop.js');
1598
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1599
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1600
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1601
+ serializeClaims: true,
1602
+ });
1603
+ const sourceResolver = {
1604
+ listSourceIds: async () => [],
1605
+ fetchRecordsByIds: async () => [],
1606
+ };
1607
+ const ctrl = new AbortController();
1608
+ const promise = runMatrixContinuously({
1609
+ runtime: rt,
1610
+ executeGraph: vi.fn(),
1611
+ sourceResolver,
1612
+ resolveGraphModel: resolveGraphModelForTest,
1613
+ resolveGraphEntry: () => ({ inputs: [] }),
1614
+ }, {
1615
+ matrixCatalogId: 'cat',
1616
+ matrixItemId: 'item',
1617
+ payload: {
1618
+ input: {},
1619
+ graphs: ['G'],
1620
+ dataSource: { kind: 'record', collectionRef: 'col', pollWhenEmptySeconds: 60 },
1621
+ executionMode: { mode: 'continuous' },
1622
+ },
1623
+ graphRecords: [{ graphId: 'G', mappedInput: [], execution: { priority: 1 } }],
1624
+ signal: ctrl.signal,
1625
+ });
1626
+ await new Promise((resolve) => setTimeout(resolve, 30));
1627
+ ctrl.abort();
1628
+ const r = await promise;
1629
+ expect(r.reason).toBe('aborted');
1630
+ expect(r.cyclesRun).toBeGreaterThanOrEqual(1);
1631
+ });
1632
+ });
1633
+ describe('ExellixConfigStore CRUD + config-driven dispatch', () => {
1634
+ async function setupConfigStore() {
1635
+ const { createExellixConfigStore } = await import('./config-store.js');
1636
+ const matrices = new MemoryMatrixCollection('matrixCatalogId');
1637
+ const graphs = new MemoryMatrixCollection('graphId');
1638
+ const configStore = createExellixConfigStore({
1639
+ matrices: matrices.asCollection(),
1640
+ graphs: graphs.asCollection(),
1641
+ });
1642
+ return configStore;
1643
+ }
1644
+ it('matrices.create / get / update / delete with versioning', async () => {
1645
+ const { ConfigStoreConcurrencyError, ConfigStoreNotFoundError } = await import('./config-store.js');
1646
+ const cs = await setupConfigStore();
1647
+ const created = await cs.matrices.create({
1648
+ matrixCatalogId: 'm1',
1649
+ payload: { input: {}, graphs: ['g1'] },
1650
+ });
1651
+ expect(created.version).toBe(1);
1652
+ const got = await cs.matrices.get('m1');
1653
+ expect(got?.matrixCatalogId).toBe('m1');
1654
+ const updated = await cs.matrices.update({
1655
+ matrixCatalogId: 'm1',
1656
+ expectedVersion: 1,
1657
+ payload: { input: { tier: 'A' }, graphs: ['g1', 'g2'] },
1658
+ });
1659
+ expect(updated.version).toBe(2);
1660
+ await expect(cs.matrices.update({
1661
+ matrixCatalogId: 'm1',
1662
+ expectedVersion: 1,
1663
+ payload: { input: {}, graphs: ['g1'] },
1664
+ })).rejects.toBeInstanceOf(ConfigStoreConcurrencyError);
1665
+ await expect(cs.matrices.delete('m1', 99)).rejects.toBeInstanceOf(ConfigStoreConcurrencyError);
1666
+ await expect(cs.matrices.delete('missing', 1)).rejects.toBeInstanceOf(ConfigStoreNotFoundError);
1667
+ });
1668
+ it('rejects invalid payload on create / update', async () => {
1669
+ const cs = await setupConfigStore();
1670
+ await expect(cs.matrices.create({
1671
+ matrixCatalogId: 'm-bad',
1672
+ payload: { input: {}, graphs: [] },
1673
+ })).rejects.toThrow(ExecutionMatrixCatalogValidationError);
1674
+ });
1675
+ it('graphs.create / get with id mismatch rejection', async () => {
1676
+ const cs = await setupConfigStore();
1677
+ await cs.graphs.create({
1678
+ graphId: 'g1',
1679
+ payload: { graphId: 'g1', mappedInput: [], execution: { priority: 1 } },
1680
+ });
1681
+ let caught;
1682
+ try {
1683
+ await cs.graphs.create({
1684
+ graphId: 'g2',
1685
+ payload: { graphId: 'g3', mappedInput: [], execution: { priority: 1 } },
1686
+ });
1687
+ }
1688
+ catch (err) {
1689
+ if (err instanceof ExecutionMatrixCatalogValidationError)
1690
+ caught = err;
1691
+ }
1692
+ expect(caught).toBeInstanceOf(ExecutionMatrixCatalogValidationError);
1693
+ expect(caught?.issues.join('\n')).toMatch(/graphId mismatch/);
1694
+ });
1695
+ it('getEffectiveConfig applies defaults and reports kind', async () => {
1696
+ const cs = await setupConfigStore();
1697
+ await cs.matrices.create({
1698
+ matrixCatalogId: 'm-eff',
1699
+ payload: {
1700
+ input: {},
1701
+ graphs: ['g1'],
1702
+ dataSource: { kind: 'record', collectionRef: 'r' },
1703
+ },
1704
+ });
1705
+ const eff = await cs.matrices.getEffectiveConfig('m-eff');
1706
+ expect(eff?.executionMode.mode).toBe('single-pass');
1707
+ expect(eff?.pollWhenEmptySeconds).toBe(60);
1708
+ expect(eff?.dataSourceKind).toBe('record');
1709
+ });
1710
+ it('runMatrixOncePassByCatalogId resolves config and runs cycle', async () => {
1711
+ const { runMatrixOncePassByCatalogId } = await import('./run-loop.js');
1712
+ const cs = await setupConfigStore();
1713
+ await cs.matrices.create({
1714
+ matrixCatalogId: 'm-rt',
1715
+ payload: {
1716
+ input: {},
1717
+ graphs: ['g1'],
1718
+ dataSource: { kind: 'record', collectionRef: 'r' },
1719
+ },
1720
+ });
1721
+ await cs.graphs.create({
1722
+ graphId: 'g1',
1723
+ payload: { graphId: 'g1', mappedInput: [], execution: { priority: 1 } },
1724
+ });
1725
+ const rows = new MemoryMatrixCollection(MATRIX_ROW_PK);
1726
+ const fails = new MemoryMatrixCollection(MATRIX_FAILURE_PK);
1727
+ const rt = createExecutionMatrixRuntime(rows.asCollection(), fails.asCollection(), {
1728
+ serializeClaims: true,
1729
+ });
1730
+ const sourceResolver = {
1731
+ listSourceIds: async () => ['s1'],
1732
+ fetchRecordsByIds: async (ids) => ids.map((id) => ({ sourceId: id })),
1733
+ };
1734
+ const executeGraph = vi.fn().mockResolvedValue(mockExecuteGraphSuccess());
1735
+ const r = await runMatrixOncePassByCatalogId({
1736
+ runtime: rt,
1737
+ executeGraph,
1738
+ sourceResolver,
1739
+ resolveGraphModel: resolveGraphModelForTest,
1740
+ resolveGraphEntry: () => ({ inputs: [] }),
1741
+ configStore: cs,
1742
+ }, { matrixCatalogId: 'm-rt', matrixItemId: 'item' });
1743
+ expect(r.effective.dataSourceKind).toBe('record');
1744
+ expect(r.fetched).toBe(1);
1745
+ expect(r.materialized).toBe(1);
1746
+ });
1747
+ });
1748
+ describe('graph-engine graph document round-trip', () => {
1749
+ it('preserves smartInput, inputSynthesis, executionStrategies, and executionMemoryPath bindings under canonical rules', () => {
1750
+ const graph = {
1751
+ id: 'g.unit',
1752
+ response: { shape: { type: 'literal', value: {} } },
1753
+ nodes: [
1754
+ {
1755
+ id: 't1',
1756
+ type: 'task',
1757
+ skillKey: 'sk.test',
1758
+ smartInput: { roots: ['input.raw'] },
1759
+ taskConfiguration: {
1760
+ aiTaskProfile: {
1761
+ inputSynthesis: { enabled: true, outputKey: 'synthesized', catalogId: 'x' },
1762
+ },
1763
+ executionStrategies: [{ strategyKey: 'planner', phase: 'before', priority: 0 }],
1764
+ },
1765
+ executionPipeline: [{ phase: 'main', type: 'direct' }],
1766
+ inputs: {
1767
+ body: { type: 'executionMemoryPath', path: 'input.raw' },
1768
+ },
1769
+ },
1770
+ ],
1771
+ metadata: { name: 'UnitGraph' },
1772
+ };
1773
+ assertCanonicalGraphDocument(graph);
1774
+ expect(mergeGraphDocumentModel(graph).name).toBe('UnitGraph');
1775
+ const n = graph.nodes;
1776
+ expect(n[0].smartInput).toBeDefined();
1777
+ expect(n[0].taskConfiguration
1778
+ ?.aiTaskProfile?.inputSynthesis).toBeDefined();
1779
+ expect(n[0].executionPipeline).toHaveLength(1);
1780
+ expect(n[0].inputs?.body).toMatchObject({
1781
+ type: 'executionMemoryPath',
1782
+ path: 'input.raw',
1783
+ });
1784
+ });
1785
+ });
1786
+ //# sourceMappingURL=execution-matrix.spec.js.map