ppef 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (295) hide show
  1. package/README.md +76 -125
  2. package/bin/ppef.mjs +20 -0
  3. package/dist/__tests__/cli/evaluate-command.integration.test.d.ts +8 -0
  4. package/dist/__tests__/cli/evaluate-command.integration.test.d.ts.map +1 -0
  5. package/dist/__tests__/cli/evaluate-command.integration.test.js +308 -0
  6. package/dist/__tests__/cli/evaluate-command.integration.test.js.map +1 -0
  7. package/dist/__tests__/evaluators/claims-evaluator.unit.test.d.ts +8 -0
  8. package/dist/__tests__/evaluators/claims-evaluator.unit.test.d.ts.map +1 -0
  9. package/dist/__tests__/evaluators/claims-evaluator.unit.test.js +405 -0
  10. package/dist/__tests__/evaluators/claims-evaluator.unit.test.js.map +1 -0
  11. package/dist/__tests__/evaluators/metrics-evaluator.unit.test.d.ts +8 -0
  12. package/dist/__tests__/evaluators/metrics-evaluator.unit.test.d.ts.map +1 -0
  13. package/dist/__tests__/evaluators/metrics-evaluator.unit.test.js +424 -0
  14. package/dist/__tests__/evaluators/metrics-evaluator.unit.test.js.map +1 -0
  15. package/dist/__tests__/evaluators/registry.unit.test.d.ts +7 -0
  16. package/dist/__tests__/evaluators/registry.unit.test.d.ts.map +1 -0
  17. package/dist/__tests__/evaluators/registry.unit.test.js +173 -0
  18. package/dist/__tests__/evaluators/registry.unit.test.js.map +1 -0
  19. package/dist/__tests__/evaluators/robustness-evaluator.unit.test.d.ts +8 -0
  20. package/dist/__tests__/evaluators/robustness-evaluator.unit.test.d.ts.map +1 -0
  21. package/dist/__tests__/evaluators/robustness-evaluator.unit.test.js +260 -0
  22. package/dist/__tests__/evaluators/robustness-evaluator.unit.test.js.map +1 -0
  23. package/dist/__tests__/framework-pipeline.integration.test.js +49 -20
  24. package/dist/__tests__/framework-pipeline.integration.test.js.map +1 -1
  25. package/dist/__tests__/index-exports.unit.test.d.ts +8 -0
  26. package/dist/__tests__/index-exports.unit.test.d.ts.map +1 -0
  27. package/dist/__tests__/index-exports.unit.test.js +124 -0
  28. package/dist/__tests__/index-exports.unit.test.js.map +1 -0
  29. package/dist/__tests__/registry-executor.integration.test.js +12 -9
  30. package/dist/__tests__/registry-executor.integration.test.js.map +1 -1
  31. package/dist/aggregation/__tests__/aggregators.unit.test.d.ts +7 -0
  32. package/dist/aggregation/__tests__/aggregators.unit.test.d.ts.map +1 -0
  33. package/dist/aggregation/__tests__/aggregators.unit.test.js +350 -0
  34. package/dist/aggregation/__tests__/aggregators.unit.test.js.map +1 -0
  35. package/dist/aggregation/__tests__/pipeline.unit.test.d.ts +7 -0
  36. package/dist/aggregation/__tests__/pipeline.unit.test.d.ts.map +1 -0
  37. package/dist/aggregation/__tests__/pipeline.unit.test.js +213 -0
  38. package/dist/aggregation/__tests__/pipeline.unit.test.js.map +1 -0
  39. package/dist/aggregation/aggregators.d.ts +9 -0
  40. package/dist/aggregation/aggregators.d.ts.map +1 -1
  41. package/dist/aggregation/aggregators.js +1 -1
  42. package/dist/aggregation/aggregators.js.map +1 -1
  43. package/dist/aggregation/index.d.ts +1 -1
  44. package/dist/aggregation/index.d.ts.map +1 -1
  45. package/dist/aggregation/index.js +1 -1
  46. package/dist/aggregation/index.js.map +1 -1
  47. package/dist/aggregation/pipeline.d.ts.map +1 -1
  48. package/dist/aggregation/pipeline.js +40 -3
  49. package/dist/aggregation/pipeline.js.map +1 -1
  50. package/dist/claims/index.d.ts +6 -3
  51. package/dist/claims/index.d.ts.map +1 -1
  52. package/dist/claims/index.js +6 -3
  53. package/dist/claims/index.js.map +1 -1
  54. package/dist/cli/__tests__/aggregate.command.unit.test.d.ts +7 -0
  55. package/dist/cli/__tests__/aggregate.command.unit.test.d.ts.map +1 -0
  56. package/dist/cli/__tests__/aggregate.command.unit.test.js +399 -0
  57. package/dist/cli/__tests__/aggregate.command.unit.test.js.map +1 -0
  58. package/dist/cli/__tests__/binary-sut.integration.test.d.ts +8 -0
  59. package/dist/cli/__tests__/binary-sut.integration.test.d.ts.map +1 -0
  60. package/dist/cli/__tests__/binary-sut.integration.test.js +165 -0
  61. package/dist/cli/__tests__/binary-sut.integration.test.js.map +1 -0
  62. package/dist/cli/__tests__/commands.unit.test.d.ts +10 -0
  63. package/dist/cli/__tests__/commands.unit.test.d.ts.map +1 -0
  64. package/dist/cli/__tests__/commands.unit.test.js +217 -0
  65. package/dist/cli/__tests__/commands.unit.test.js.map +1 -0
  66. package/dist/cli/__tests__/config-loader.unit.test.d.ts +7 -0
  67. package/dist/cli/__tests__/config-loader.unit.test.d.ts.map +1 -0
  68. package/dist/cli/__tests__/config-loader.unit.test.js +611 -0
  69. package/dist/cli/__tests__/config-loader.unit.test.js.map +1 -0
  70. package/dist/cli/__tests__/index.unit.test.d.ts +10 -0
  71. package/dist/cli/__tests__/index.unit.test.d.ts.map +1 -0
  72. package/dist/cli/__tests__/index.unit.test.js +65 -0
  73. package/dist/cli/__tests__/index.unit.test.js.map +1 -0
  74. package/dist/cli/__tests__/logger.unit.test.d.ts +11 -0
  75. package/dist/cli/__tests__/logger.unit.test.d.ts.map +1 -0
  76. package/dist/cli/__tests__/logger.unit.test.js +180 -0
  77. package/dist/cli/__tests__/logger.unit.test.js.map +1 -0
  78. package/dist/cli/__tests__/module-loader.unit.test.d.ts +11 -0
  79. package/dist/cli/__tests__/module-loader.unit.test.d.ts.map +1 -0
  80. package/dist/cli/__tests__/module-loader.unit.test.js +262 -0
  81. package/dist/cli/__tests__/module-loader.unit.test.js.map +1 -0
  82. package/dist/cli/__tests__/output-writer.unit.test.d.ts +10 -0
  83. package/dist/cli/__tests__/output-writer.unit.test.d.ts.map +1 -0
  84. package/dist/cli/__tests__/output-writer.unit.test.js +216 -0
  85. package/dist/cli/__tests__/output-writer.unit.test.js.map +1 -0
  86. package/dist/cli/__tests__/plan.command.unit.test.d.ts +7 -0
  87. package/dist/cli/__tests__/plan.command.unit.test.d.ts.map +1 -0
  88. package/dist/cli/__tests__/plan.command.unit.test.js +289 -0
  89. package/dist/cli/__tests__/plan.command.unit.test.js.map +1 -0
  90. package/dist/cli/__tests__/run.command.unit.test.d.ts +7 -0
  91. package/dist/cli/__tests__/run.command.unit.test.d.ts.map +1 -0
  92. package/dist/cli/__tests__/run.command.unit.test.js +422 -0
  93. package/dist/cli/__tests__/run.command.unit.test.js.map +1 -0
  94. package/dist/cli/__tests__/validate.command.unit.test.d.ts +7 -0
  95. package/dist/cli/__tests__/validate.command.unit.test.d.ts.map +1 -0
  96. package/dist/cli/__tests__/validate.command.unit.test.js +226 -0
  97. package/dist/cli/__tests__/validate.command.unit.test.js.map +1 -0
  98. package/dist/cli/command-deps.d.ts +137 -0
  99. package/dist/cli/command-deps.d.ts.map +1 -0
  100. package/dist/cli/command-deps.js +7 -0
  101. package/dist/cli/command-deps.js.map +1 -0
  102. package/dist/cli/commands/aggregate.d.ts +35 -0
  103. package/dist/cli/commands/aggregate.d.ts.map +1 -0
  104. package/dist/cli/commands/aggregate.js +124 -0
  105. package/dist/cli/commands/aggregate.js.map +1 -0
  106. package/dist/cli/commands/evaluate.d.ts +41 -0
  107. package/dist/cli/commands/evaluate.d.ts.map +1 -0
  108. package/dist/cli/commands/evaluate.js +287 -0
  109. package/dist/cli/commands/evaluate.js.map +1 -0
  110. package/dist/cli/commands/plan.d.ts +36 -0
  111. package/dist/cli/commands/plan.d.ts.map +1 -0
  112. package/dist/cli/commands/plan.js +109 -0
  113. package/dist/cli/commands/plan.js.map +1 -0
  114. package/dist/cli/commands/run.d.ts +33 -0
  115. package/dist/cli/commands/run.d.ts.map +1 -0
  116. package/dist/cli/commands/run.js +277 -0
  117. package/dist/cli/commands/run.js.map +1 -0
  118. package/dist/cli/commands/validate.d.ts +27 -0
  119. package/dist/cli/commands/validate.d.ts.map +1 -0
  120. package/dist/cli/commands/validate.js +88 -0
  121. package/dist/cli/commands/validate.js.map +1 -0
  122. package/dist/cli/config-loader.d.ts +30 -0
  123. package/dist/cli/config-loader.d.ts.map +1 -0
  124. package/dist/cli/config-loader.js +181 -0
  125. package/dist/cli/config-loader.js.map +1 -0
  126. package/dist/cli/index.d.ts +27 -0
  127. package/dist/cli/index.d.ts.map +1 -0
  128. package/dist/cli/index.js +60 -0
  129. package/dist/cli/index.js.map +1 -0
  130. package/dist/cli/logger.d.ts +75 -0
  131. package/dist/cli/logger.d.ts.map +1 -0
  132. package/dist/cli/logger.js +131 -0
  133. package/dist/cli/logger.js.map +1 -0
  134. package/dist/cli/module-loader.d.ts +68 -0
  135. package/dist/cli/module-loader.d.ts.map +1 -0
  136. package/dist/cli/module-loader.js +134 -0
  137. package/dist/cli/module-loader.js.map +1 -0
  138. package/dist/cli/output-writer.d.ts +51 -0
  139. package/dist/cli/output-writer.d.ts.map +1 -0
  140. package/dist/cli/output-writer.js +65 -0
  141. package/dist/cli/output-writer.js.map +1 -0
  142. package/dist/cli/types.d.ts +193 -0
  143. package/dist/cli/types.d.ts.map +1 -0
  144. package/dist/cli/types.js +7 -0
  145. package/dist/cli/types.js.map +1 -0
  146. package/dist/collector/__tests__/result-collector.unit.test.d.ts +7 -0
  147. package/dist/collector/__tests__/result-collector.unit.test.d.ts.map +1 -0
  148. package/dist/collector/__tests__/result-collector.unit.test.js +1021 -0
  149. package/dist/collector/__tests__/result-collector.unit.test.js.map +1 -0
  150. package/dist/collector/__tests__/schema.unit.test.d.ts +7 -0
  151. package/dist/collector/__tests__/schema.unit.test.d.ts.map +1 -0
  152. package/dist/collector/__tests__/schema.unit.test.js +360 -0
  153. package/dist/collector/__tests__/schema.unit.test.js.map +1 -0
  154. package/dist/evaluators/claims-evaluator.d.ts +87 -0
  155. package/dist/evaluators/claims-evaluator.d.ts.map +1 -0
  156. package/dist/evaluators/claims-evaluator.js +289 -0
  157. package/dist/evaluators/claims-evaluator.js.map +1 -0
  158. package/dist/evaluators/exploratory-evaluator.d.ts +136 -0
  159. package/dist/evaluators/exploratory-evaluator.d.ts.map +1 -0
  160. package/dist/evaluators/exploratory-evaluator.js +545 -0
  161. package/dist/evaluators/exploratory-evaluator.js.map +1 -0
  162. package/dist/evaluators/index.d.ts +13 -0
  163. package/dist/evaluators/index.d.ts.map +1 -0
  164. package/dist/evaluators/index.js +14 -0
  165. package/dist/evaluators/index.js.map +1 -0
  166. package/dist/evaluators/metrics-evaluator.d.ts +114 -0
  167. package/dist/evaluators/metrics-evaluator.d.ts.map +1 -0
  168. package/dist/evaluators/metrics-evaluator.js +433 -0
  169. package/dist/evaluators/metrics-evaluator.js.map +1 -0
  170. package/dist/evaluators/registry.d.ts +106 -0
  171. package/dist/evaluators/registry.d.ts.map +1 -0
  172. package/dist/evaluators/registry.js +148 -0
  173. package/dist/evaluators/registry.js.map +1 -0
  174. package/dist/evaluators/robustness-evaluator.d.ts +57 -0
  175. package/dist/evaluators/robustness-evaluator.d.ts.map +1 -0
  176. package/dist/evaluators/robustness-evaluator.js +186 -0
  177. package/dist/evaluators/robustness-evaluator.js.map +1 -0
  178. package/dist/executor/__tests__/binary-sut.unit.test.d.ts +8 -0
  179. package/dist/executor/__tests__/binary-sut.unit.test.d.ts.map +1 -0
  180. package/dist/executor/__tests__/binary-sut.unit.test.js +313 -0
  181. package/dist/executor/__tests__/binary-sut.unit.test.js.map +1 -0
  182. package/dist/executor/__tests__/checkpoint-manager.unit.test.js +83 -1
  183. package/dist/executor/__tests__/checkpoint-manager.unit.test.js.map +1 -1
  184. package/dist/executor/__tests__/checkpoint-merge-bug.diagnostic.test.d.ts +3 -6
  185. package/dist/executor/__tests__/checkpoint-merge-bug.diagnostic.test.d.ts.map +1 -1
  186. package/dist/executor/__tests__/checkpoint-merge-bug.diagnostic.test.js +428 -159
  187. package/dist/executor/__tests__/checkpoint-merge-bug.diagnostic.test.js.map +1 -1
  188. package/dist/executor/__tests__/checkpoint-storage.unit.test.js +148 -1
  189. package/dist/executor/__tests__/checkpoint-storage.unit.test.js.map +1 -1
  190. package/dist/executor/__tests__/executor.unit.test.js +123 -8
  191. package/dist/executor/__tests__/executor.unit.test.js.map +1 -1
  192. package/dist/executor/__tests__/memory-monitor.unit.test.d.ts +7 -0
  193. package/dist/executor/__tests__/memory-monitor.unit.test.d.ts.map +1 -0
  194. package/dist/executor/__tests__/memory-monitor.unit.test.js +285 -0
  195. package/dist/executor/__tests__/memory-monitor.unit.test.js.map +1 -0
  196. package/dist/executor/__tests__/parallel-executor.unit.test.d.ts +2 -1
  197. package/dist/executor/__tests__/parallel-executor.unit.test.d.ts.map +1 -1
  198. package/dist/executor/__tests__/parallel-executor.unit.test.js +426 -156
  199. package/dist/executor/__tests__/parallel-executor.unit.test.js.map +1 -1
  200. package/dist/executor/__tests__/resource-calculator.unit.test.d.ts +10 -0
  201. package/dist/executor/__tests__/resource-calculator.unit.test.d.ts.map +1 -0
  202. package/dist/executor/__tests__/resource-calculator.unit.test.js +104 -0
  203. package/dist/executor/__tests__/resource-calculator.unit.test.js.map +1 -0
  204. package/dist/executor/__tests__/run-id.unit.test.d.ts +8 -0
  205. package/dist/executor/__tests__/run-id.unit.test.d.ts.map +1 -0
  206. package/dist/executor/__tests__/run-id.unit.test.js +156 -0
  207. package/dist/executor/__tests__/run-id.unit.test.js.map +1 -0
  208. package/dist/executor/__tests__/worker-entry.integration.test.d.ts +24 -0
  209. package/dist/executor/__tests__/worker-entry.integration.test.d.ts.map +1 -0
  210. package/dist/executor/__tests__/worker-entry.integration.test.js +82 -0
  211. package/dist/executor/__tests__/worker-entry.integration.test.js.map +1 -0
  212. package/dist/executor/__tests__/worker-entry.unit.test.d.ts +7 -0
  213. package/dist/executor/__tests__/worker-entry.unit.test.d.ts.map +1 -0
  214. package/dist/executor/__tests__/worker-entry.unit.test.js +364 -0
  215. package/dist/executor/__tests__/worker-entry.unit.test.js.map +1 -0
  216. package/dist/executor/__tests__/worker-threads-executor.unit.test.d.ts +8 -0
  217. package/dist/executor/__tests__/worker-threads-executor.unit.test.d.ts.map +1 -0
  218. package/dist/executor/__tests__/worker-threads-executor.unit.test.js +276 -0
  219. package/dist/executor/__tests__/worker-threads-executor.unit.test.js.map +1 -0
  220. package/dist/executor/binary-sut.d.ts +105 -0
  221. package/dist/executor/binary-sut.d.ts.map +1 -0
  222. package/dist/executor/binary-sut.js +174 -0
  223. package/dist/executor/binary-sut.js.map +1 -0
  224. package/dist/executor/checkpoint-storage.d.ts.map +1 -1
  225. package/dist/executor/checkpoint-storage.js +6 -4
  226. package/dist/executor/checkpoint-storage.js.map +1 -1
  227. package/dist/executor/executor.d.ts +28 -0
  228. package/dist/executor/executor.d.ts.map +1 -1
  229. package/dist/executor/executor.js +85 -24
  230. package/dist/executor/executor.js.map +1 -1
  231. package/dist/executor/index.d.ts +4 -0
  232. package/dist/executor/index.d.ts.map +1 -1
  233. package/dist/executor/index.js +4 -0
  234. package/dist/executor/index.js.map +1 -1
  235. package/dist/executor/parallel-executor.d.ts +186 -0
  236. package/dist/executor/parallel-executor.d.ts.map +1 -1
  237. package/dist/executor/parallel-executor.js +218 -83
  238. package/dist/executor/parallel-executor.js.map +1 -1
  239. package/dist/executor/resource-calculator.d.ts +49 -0
  240. package/dist/executor/resource-calculator.d.ts.map +1 -0
  241. package/dist/executor/resource-calculator.js +129 -0
  242. package/dist/executor/resource-calculator.js.map +1 -0
  243. package/dist/executor/run-id.d.ts.map +1 -1
  244. package/dist/executor/run-id.js +8 -1
  245. package/dist/executor/run-id.js.map +1 -1
  246. package/dist/executor/worker-entry.d.ts +2 -0
  247. package/dist/executor/worker-entry.d.ts.map +1 -1
  248. package/dist/executor/worker-entry.js +46 -55
  249. package/dist/executor/worker-entry.js.map +1 -1
  250. package/dist/executor/worker-executor.d.ts +257 -0
  251. package/dist/executor/worker-executor.d.ts.map +1 -0
  252. package/dist/executor/worker-executor.js +308 -0
  253. package/dist/executor/worker-executor.js.map +1 -0
  254. package/dist/executor/worker-threads-executor.d.ts +245 -0
  255. package/dist/executor/worker-threads-executor.d.ts.map +1 -0
  256. package/dist/executor/worker-threads-executor.js +332 -0
  257. package/dist/executor/worker-threads-executor.js.map +1 -0
  258. package/dist/index.d.ts +1 -0
  259. package/dist/index.d.ts.map +1 -1
  260. package/dist/index.js +4 -2
  261. package/dist/index.js.map +1 -1
  262. package/dist/renderers/latex-renderer.d.ts +60 -0
  263. package/dist/renderers/latex-renderer.d.ts.map +1 -1
  264. package/dist/renderers/latex-renderer.js +299 -0
  265. package/dist/renderers/latex-renderer.js.map +1 -1
  266. package/dist/renderers/types.d.ts +9 -0
  267. package/dist/renderers/types.d.ts.map +1 -1
  268. package/dist/renderers/types.js.map +1 -1
  269. package/dist/robustness/__tests__/perturbations.unit.test.d.ts +11 -0
  270. package/dist/robustness/__tests__/perturbations.unit.test.d.ts.map +1 -0
  271. package/dist/robustness/__tests__/perturbations.unit.test.js +284 -0
  272. package/dist/robustness/__tests__/perturbations.unit.test.js.map +1 -0
  273. package/dist/robustness/index.d.ts +5 -2
  274. package/dist/robustness/index.d.ts.map +1 -1
  275. package/dist/robustness/index.js +4 -2
  276. package/dist/robustness/index.js.map +1 -1
  277. package/dist/statistical/__tests__/mann-whitney-u.unit.test.d.ts +7 -0
  278. package/dist/statistical/__tests__/mann-whitney-u.unit.test.d.ts.map +1 -0
  279. package/dist/statistical/__tests__/mann-whitney-u.unit.test.js +185 -0
  280. package/dist/statistical/__tests__/mann-whitney-u.unit.test.js.map +1 -0
  281. package/dist/types/evaluator.d.ts +449 -0
  282. package/dist/types/evaluator.d.ts.map +1 -0
  283. package/dist/types/evaluator.js +9 -0
  284. package/dist/types/evaluator.js.map +1 -0
  285. package/dist/types/result.d.ts +2 -0
  286. package/dist/types/result.d.ts.map +1 -1
  287. package/package.json +8 -1
  288. package/dist/claims/evaluator.d.ts +0 -33
  289. package/dist/claims/evaluator.d.ts.map +0 -1
  290. package/dist/claims/evaluator.js +0 -174
  291. package/dist/claims/evaluator.js.map +0 -1
  292. package/dist/robustness/analyzer.d.ts +0 -61
  293. package/dist/robustness/analyzer.d.ts.map +0 -1
  294. package/dist/robustness/analyzer.js +0 -191
  295. package/dist/robustness/analyzer.js.map +0 -1
@@ -8,36 +8,77 @@
8
8
  * results/execute/checkpoint-worker-00.json
9
9
  * results/execute/checkpoint-worker-01.json
10
10
  * ...
11
+ *
12
+ * Dependency Injection:
13
+ * - Logger interface enables testing of log output
14
+ * - ProcessSpawner interface enables mocking spawn() calls
15
+ * - SystemInfo interface enables testing CPU count and node path logic
11
16
  */
12
17
  import { spawn } from "node:child_process";
13
18
  import { randomBytes } from "node:crypto";
14
19
  import { cpus } from "node:os";
15
20
  import { dirname, resolve } from "node:path";
16
21
  /**
17
- * Get the package root directory by resolving from the entry point script.
18
- * The CLI entry point is dist/cli.js, so we go up one level from there.
22
+ * Production logger using console.
19
23
  */
20
- const getPackageRoot = () => {
21
- // Get the directory containing the entry point script
22
- // process.argv[1] is the path to the executed script (e.g., /path/to/graphbox/dist/cli.js)
23
- const entryPoint = process.argv[1];
24
- // Resolve to absolute path first (handles relative paths like "dist/cli.js")
25
- const absoluteEntry = resolve(entryPoint);
26
- const entryDir = dirname(absoluteEntry);
27
- // If entry point is in dist/, go up one level to get package root
28
- if (entryDir.endsWith("/dist") || entryDir.endsWith(String.raw `\dist`)) {
29
- return entryDir.slice(0, -5); // Remove "/dist"
24
+ export class ConsoleLogger {
25
+ log(message) {
26
+ console.log(message);
30
27
  }
31
- // Fallback: use current directory
32
- return process.cwd();
33
- };
34
- const PACKAGE_ROOT = getPackageRoot();
28
+ debug(message) {
29
+ console.log(message);
30
+ }
31
+ info(message) {
32
+ console.log(message);
33
+ }
34
+ warn(message) {
35
+ console.warn(message);
36
+ }
37
+ }
38
+ /**
39
+ * Production process spawner using node:child_process.
40
+ */
41
+ export class ProcessSpawner {
42
+ spawn(command, args, options) {
43
+ return spawn(command, args, options);
44
+ }
45
+ }
46
+ /**
47
+ * Production system info using node:os and process.
48
+ */
49
+ export class SystemInfo {
50
+ cpuCount = cpus().length;
51
+ nodePath = process.execPath;
52
+ env = process.env;
53
+ packageRoot;
54
+ constructor() {
55
+ this.packageRoot = this.getPackageRoot();
56
+ }
57
+ /**
58
+ * Get the package root directory by resolving from the entry point script.
59
+ * The CLI entry point is dist/cli.js, so we go up one level from there.
60
+ */
61
+ getPackageRoot() {
62
+ // Get the directory containing the entry point script
63
+ // process.argv[1] is the path to the executed script (e.g., /path/to/graphbox/dist/cli.js)
64
+ const entryPoint = process.argv[1];
65
+ // Resolve to absolute path first (handles relative paths like "dist/cli.js")
66
+ const absoluteEntry = resolve(entryPoint);
67
+ const entryDir = dirname(absoluteEntry);
68
+ // If entry point is in dist/, go up one level to get package root
69
+ if (entryDir.endsWith("/dist") || entryDir.endsWith(String.raw `\dist`)) {
70
+ return entryDir.slice(0, -5); // Remove "/dist"
71
+ }
72
+ // Fallback: use current directory
73
+ return process.cwd();
74
+ }
75
+ }
35
76
  /**
36
77
  * Generate random worker names using tech-themed adjectives.
37
78
  * Returns unique names for each worker.
38
79
  * @param count
39
80
  */
40
- const generateWorkerNames = (count) => {
81
+ export const generateWorkerNames = (count) => {
41
82
  const adjectives = [
42
83
  "swift",
43
84
  "nimble",
@@ -111,84 +152,178 @@ const generateWorkerNames = (count) => {
111
152
  * @returns Path to the worker's checkpoint file
112
153
  */
113
154
  export const shardPath = (checkpointDir, workerIndex) => resolve(checkpointDir, `checkpoint-worker-${String(workerIndex).padStart(2, "0")}.json`);
155
+ /**
156
+ * Parallel executor class with dependency injection.
157
+ *
158
+ * Spawns multiple Node.js processes, each executing a subset of runs.
159
+ * Each worker writes to its own sharded checkpoint file to avoid race conditions.
160
+ */
161
+ export class ParallelExecutor {
162
+ logger;
163
+ spawner;
164
+ systemInfo;
165
+ constructor(logger, spawner, systemInfo) {
166
+ this.logger = logger ?? new ConsoleLogger();
167
+ this.spawner = spawner ?? new ProcessSpawner();
168
+ this.systemInfo = systemInfo ?? new SystemInfo();
169
+ }
170
+ /**
171
+ * Split runs into batches for parallel processing.
172
+ * @param runs - Runs to distribute
173
+ * @param numberWorkers - Number of worker processes
174
+ * @returns Array of run batches
175
+ */
176
+ _createBatches(runs, numberWorkers) {
177
+ const batchSize = Math.ceil(runs.length / numberWorkers);
178
+ const batches = [];
179
+ for (let i = 0; i < runs.length; i += batchSize) {
180
+ const batch = runs.slice(i, i + batchSize);
181
+ const batchIndex = Math.floor(i / batchSize);
182
+ const runIds = new Set(batch.map((r) => r.runId));
183
+ batches.push({
184
+ index: batchIndex,
185
+ runIds: [...runIds],
186
+ filter: JSON.stringify([...runIds]),
187
+ firstRunId: batch[0]?.runId ?? "none",
188
+ lastRunId: batch.at(-1)?.runId ?? "none",
189
+ });
190
+ }
191
+ return batches;
192
+ }
193
+ /**
194
+ * Create worker configurations for all batches.
195
+ * @param batches - Run batches
196
+ * @param workerNames - Names for each worker
197
+ * @param cliPath - Path to CLI entry point
198
+ * @param checkpointDir - Base checkpoint directory
199
+ * @param timeoutMs - Per-run timeout in milliseconds
200
+ * @returns Array of worker configurations
201
+ */
202
+ _createWorkerConfigs(batches, workerNames, cliPath, checkpointDir, timeoutMs) {
203
+ return batches.map((batch) => {
204
+ const workerName = workerNames[batch.index];
205
+ const workerCheckpointPath = shardPath(checkpointDir, batch.index);
206
+ const arguments_ = [
207
+ cliPath,
208
+ "evaluate",
209
+ "--phase=execute",
210
+ "--checkpoint-mode=file",
211
+ `--run-filter=${batch.filter}`,
212
+ ];
213
+ // Add timeout if specified
214
+ if (timeoutMs > 0) {
215
+ arguments_.push(`--timeout=${timeoutMs}`);
216
+ }
217
+ return {
218
+ index: batch.index,
219
+ name: workerName,
220
+ checkpointPath: workerCheckpointPath,
221
+ arguments: arguments_,
222
+ env: {
223
+ ...this.systemInfo.env,
224
+ NODE_OPTIONS: "--max-old-space-size=4096",
225
+ GRAPHBOX_WORKER_NAME: workerName,
226
+ GRAPHBOX_WORKER_INDEX: batch.index.toString(),
227
+ GRAPHBOX_TOTAL_WORKERS: batches.length.toString(),
228
+ GRAPHBOX_CHECKPOINT_DIR: checkpointDir,
229
+ GRAPHBOX_CHECKPOINT_PATH: workerCheckpointPath,
230
+ },
231
+ };
232
+ });
233
+ }
234
+ /**
235
+ * Spawn worker processes for all configurations.
236
+ * @param workerConfigs - Worker configurations
237
+ * @param nodePath - Path to node executable
238
+ * @param packageRoot - Package root directory
239
+ * @returns Array of child processes
240
+ */
241
+ _spawnWorkers(workerConfigs, nodePath, packageRoot) {
242
+ return workerConfigs.map((config) => {
243
+ this.logger.debug(`Spawning worker ${config.index}: ${config.name} with ${config.arguments.length} args`);
244
+ return this.spawner.spawn(nodePath, config.arguments, {
245
+ stdio: "inherit",
246
+ cwd: packageRoot,
247
+ env: config.env,
248
+ });
249
+ });
250
+ }
251
+ /**
252
+ * Wait for all workers to complete.
253
+ * @param workers - Child processes
254
+ * @returns Promise that resolves when all workers exit
255
+ */
256
+ async _waitForWorkers(workers) {
257
+ return Promise.all(workers.map((w) => new Promise((resolve) => {
258
+ w.on("exit", (code) => {
259
+ resolve(code);
260
+ });
261
+ })));
262
+ }
263
+ /**
264
+ * Execute runs using multiple parallel processes.
265
+ *
266
+ * Each worker writes to its own sharded checkpoint file to avoid race conditions.
267
+ * After all workers complete, the main process should merge the shards.
268
+ *
269
+ * @param runs - Planned runs to execute
270
+ * @param suts - SUT definitions (not used directly, passed to workers)
271
+ * @param cases - Case definitions (not used directly, passed to workers)
272
+ * @param config - Executor configuration
273
+ * @param options - Parallel executor options
274
+ * @returns Execution results (empty - CLI will load from shards)
275
+ */
276
+ async execute(runs, _suts, _cases, config, options = {}) {
277
+ const numberWorkers = options.workers ?? this.systemInfo.cpuCount;
278
+ const nodePath = options.nodePath ?? this.systemInfo.nodePath;
279
+ const checkpointDir = options.checkpointDir ?? resolve(this.systemInfo.packageRoot, "results/execute");
280
+ const timeoutMs = options.timeoutMs ?? config.timeoutMs;
281
+ this.logger.info(`ParallelExecutor: Spawning ${numberWorkers} processes for ${runs.length} runs`);
282
+ this.logger.info(`Checkpoint directory: ${checkpointDir}`);
283
+ if (timeoutMs > 0) {
284
+ this.logger.info(`Per-run timeout: ${timeoutMs}ms (${Math.round(timeoutMs / 1000)}s)`);
285
+ }
286
+ // Generate unique names for each worker
287
+ const workerNames = generateWorkerNames(numberWorkers);
288
+ this.logger.info(`Workers: ${workerNames.map((name, index) => `${index + 1}. ${name}`).join(", ")}`);
289
+ // Split runs into batches
290
+ const batches = this._createBatches(runs, numberWorkers);
291
+ // Log batch information
292
+ for (const batch of batches) {
293
+ this.logger.debug(`Batch ${batch.index} has ${batch.runIds.length} runs, filter length: ${batch.filter.length}`);
294
+ this.logger.debug(` First run: ${batch.firstRunId}, Last run: ${batch.lastRunId}`);
295
+ }
296
+ // Create worker configurations
297
+ const cliPath = resolve(this.systemInfo.packageRoot, "dist/cli.js");
298
+ const workerConfigs = this._createWorkerConfigs(batches, workerNames, cliPath, checkpointDir, timeoutMs);
299
+ // Spawn worker processes
300
+ const workers = this._spawnWorkers(workerConfigs, nodePath, this.systemInfo.packageRoot);
301
+ // Wait for all workers to complete
302
+ const exitCodes = await this._waitForWorkers(workers);
303
+ this.logger.debug(`All workers exited with codes: ${exitCodes.join(", ")}`);
304
+ // Load and return aggregated results
305
+ // For now, return empty - the CLI will handle results and merge shards
306
+ return { results: [], errors: [] };
307
+ }
308
+ }
114
309
  /**
115
310
  * Execute runs using multiple parallel processes.
116
311
  *
117
312
  * Each worker writes to its own sharded checkpoint file to avoid race conditions.
118
313
  * After all workers complete, the main process should merge the shards.
119
314
  *
315
+ * This is a convenience function that creates a ParallelExecutor with default dependencies.
316
+ * For testing or custom behavior, use the ParallelExecutor class directly.
317
+ *
120
318
  * @param runs - Planned runs to execute
121
319
  * @param suts - SUT definitions (not used directly, passed to workers)
122
320
  * @param cases - Case definitions (not used directly, passed to workers)
123
321
  * @param config - Executor configuration
124
322
  * @param options - Parallel executor options
323
+ * @returns Execution results (empty - CLI will load from shards)
125
324
  */
126
325
  export const executeParallel = async (runs, suts, cases, config, options = {}) => {
127
- const numberWorkers = options.workers ?? cpus().length;
128
- const nodePath = options.nodePath ?? process.execPath;
129
- const checkpointDir = options.checkpointDir ?? resolve(PACKAGE_ROOT, "results/execute");
130
- const timeoutMs = options.timeoutMs ?? config.timeoutMs;
131
- console.log(`ParallelExecutor: Spawning ${numberWorkers} processes for ${runs.length} runs`);
132
- console.log(`Checkpoint directory: ${checkpointDir}`);
133
- if (timeoutMs > 0) {
134
- console.log(`Per-run timeout: ${timeoutMs}ms (${Math.round(timeoutMs / 1000)}s)`);
135
- }
136
- // Generate unique names for each worker
137
- const workerNames = generateWorkerNames(numberWorkers);
138
- console.log(`Workers: ${workerNames.map((name, index) => `${index + 1}. ${name}`).join(", ")}`);
139
- // Split runs into batches
140
- const batchSize = Math.ceil(runs.length / numberWorkers);
141
- const batches = [];
142
- for (let index = 0; index < runs.length; index += batchSize) {
143
- batches.push(runs.slice(index, index + batchSize));
144
- }
145
- // Create a run filter function for each batch
146
- const runFilters = batches.map((batch, _index) => {
147
- const runIds = new Set(batch.map((r) => r.runId));
148
- const filter = JSON.stringify([...runIds]);
149
- const firstRunId = batch[0]?.runId ?? "none";
150
- const lastRunId = batch.at(-1)?.runId ?? "none";
151
- console.log(`DEBUG: Batch ${_index} has ${batch.length} runs, filter length: ${filter.length}`);
152
- console.log(`DEBUG: First run: ${firstRunId}, Last run: ${lastRunId}`);
153
- return filter;
154
- });
155
- // Spawn worker processes
156
- const workers = runFilters.map((runFilter, index) => {
157
- const workerName = workerNames[index];
158
- const workerCheckpointPath = shardPath(checkpointDir, index);
159
- const arguments_ = [
160
- resolve(PACKAGE_ROOT, "dist/cli.js"),
161
- "evaluate",
162
- "--phase=execute",
163
- "--checkpoint-mode=file",
164
- `--run-filter=${runFilter}`, // JSON array - needs to be quoted in shell but spawn() handles this
165
- ];
166
- // Add timeout if specified
167
- if (timeoutMs > 0) {
168
- arguments_.push(`--timeout=${timeoutMs}`);
169
- }
170
- return spawn(nodePath, arguments_, {
171
- stdio: "inherit",
172
- cwd: PACKAGE_ROOT, // Ensure workers use the package root as working directory
173
- env: {
174
- ...process.env,
175
- NODE_OPTIONS: "--max-old-space-size=4096",
176
- GRAPHBOX_WORKER_NAME: workerName,
177
- GRAPHBOX_WORKER_INDEX: index.toString(),
178
- GRAPHBOX_TOTAL_WORKERS: numberWorkers.toString(),
179
- GRAPHBOX_CHECKPOINT_DIR: checkpointDir,
180
- GRAPHBOX_CHECKPOINT_PATH: workerCheckpointPath,
181
- },
182
- });
183
- });
184
- // Wait for all workers to complete
185
- await Promise.all(workers.map((w) => new Promise((resolve) => {
186
- w.on("exit", (code) => {
187
- resolve(code);
188
- });
189
- })));
190
- // Load and return aggregated results
191
- // For now, return empty - the CLI will handle results and merge shards
192
- return { results: [], errors: [] };
326
+ const executor = new ParallelExecutor();
327
+ return executor.execute(runs, suts, cases, config, options);
193
328
  };
194
329
  //# sourceMappingURL=parallel-executor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parallel-executor.js","sourceRoot":"","sources":["../../src/executor/parallel-executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parallel-executor.js","sourceRoot":"","sources":["../../src/executor/parallel-executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Resource Calculator
3
+ *
4
+ * Automatically calculates optimal resource limits for parallel execution
5
+ * using the "75% rule" - reserves 75% of available resources for workers,
6
+ * leaving 25% for system stability and other processes.
7
+ *
8
+ * Features:
9
+ * - CPU-based worker count (75% of available cores)
10
+ * - Memory per worker calculation (total memory / worker count)
11
+ * - Dynamic disk I/O ceiling measurement (detects throughput plateau)
12
+ * - Caching to avoid repeated measurements
13
+ *
14
+ * Disk I/O Measurement Algorithm:
15
+ * 1. Test concurrent write+read operations at increasing levels (1, 6, 11, 16, ...)
16
+ * 2. Measure throughput (MB/s) for each concurrency level
17
+ * 3. Detect when throughput plateaus (<5% improvement)
18
+ * 4. Return 75% of the detected ceiling
19
+ * 5. Cache result to avoid re-measuring
20
+ */
21
+ /**
22
+ * Resource limits for parallel execution.
23
+ */
24
+ export interface ResourceLimits {
25
+ /** Maximum number of worker threads to spawn */
26
+ maxWorkers: number;
27
+ /** Maximum memory per worker in MB */
28
+ maxMemoryMb: number;
29
+ /** Maximum concurrent I/O operations */
30
+ maxConcurrentIo: number;
31
+ }
32
+ /**
33
+ * Calculate resource limits using the 75% rule.
34
+ *
35
+ * @param reservePercent - Percentage of resources to reserve (default: 0.75 for 75%)
36
+ * @param options - Options for resource calculation
37
+ * @returns Resource limits for parallel execution
38
+ */
39
+ export declare function calculateResources(reservePercent?: number, options?: {
40
+ measureDisk?: boolean;
41
+ }): Promise<ResourceLimits>;
42
+ /**
43
+ * Synchronous version that skips disk measurement (for quick startup).
44
+ *
45
+ * @param reservePercent - Percentage of resources to reserve (default: 0.75 for 75%)
46
+ * @returns Resource limits for parallel execution (with estimated I/O)
47
+ */
48
+ export declare function calculateResourcesSync(reservePercent?: number): ResourceLimits;
49
+ //# sourceMappingURL=resource-calculator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-calculator.d.ts","sourceRoot":"","sources":["../../src/executor/resource-calculator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC9B,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,eAAe,EAAE,MAAM,CAAC;CACxB;AA6ED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACvC,cAAc,SAAO,EACrB,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACrC,OAAO,CAAC,cAAc,CAAC,CAqBzB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,cAAc,SAAO,GAAG,cAAc,CAgB5E"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Resource Calculator
3
+ *
4
+ * Automatically calculates optimal resource limits for parallel execution
5
+ * using the "75% rule" - reserves 75% of available resources for workers,
6
+ * leaving 25% for system stability and other processes.
7
+ *
8
+ * Features:
9
+ * - CPU-based worker count (75% of available cores)
10
+ * - Memory per worker calculation (total memory / worker count)
11
+ * - Dynamic disk I/O ceiling measurement (detects throughput plateau)
12
+ * - Caching to avoid repeated measurements
13
+ *
14
+ * Disk I/O Measurement Algorithm:
15
+ * 1. Test concurrent write+read operations at increasing levels (1, 6, 11, 16, ...)
16
+ * 2. Measure throughput (MB/s) for each concurrency level
17
+ * 3. Detect when throughput plateaus (<5% improvement)
18
+ * 4. Return 75% of the detected ceiling
19
+ * 5. Cache result to avoid re-measuring
20
+ */
21
+ import { cpus, totalmem } from "node:os";
22
+ import { mkdtemp, readFile, writeFile, unlink } from "node:fs/promises";
23
+ import { join } from "node:path";
24
+ import { tmpdir } from "node:os";
25
+ /**
26
+ * Measure disk I/O ceiling by testing throughput at increasing concurrency levels.
27
+ * Returns the concurrency level where throughput stops improving (the ceiling).
28
+ *
29
+ * @param sampleSizeMb - Size of test data in MB (default: 10)
30
+ * @param maxConcurrency - Maximum concurrency to test (default: 100)
31
+ * @param timeoutMs - Timeout per test in milliseconds (default: 5000)
32
+ * @returns The detected concurrency ceiling
33
+ */
34
+ async function measureDiskIoCeiling(sampleSizeMb = 10, maxConcurrency = 100, timeoutMs = 5000) {
35
+ const testData = Buffer.alloc(sampleSizeMb * 1024 * 1024, "x");
36
+ // Test at increasing concurrency levels
37
+ let lastThroughput = 0;
38
+ let ceiling = 10; // Default fallback
39
+ for (let concurrency = 1; concurrency <= maxConcurrency; concurrency += 5) {
40
+ const tempDir = await mkdtemp(join(tmpdir(), "io-test-"));
41
+ const startTime = performance.now();
42
+ try {
43
+ // Run concurrent write+read operations
44
+ const operations = Array.from({ length: concurrency }, async () => {
45
+ const filePath = join(tempDir, `test-${Math.random().toString(36).slice(2)}.dat`);
46
+ await writeFile(filePath, testData);
47
+ await readFile(filePath);
48
+ return filePath;
49
+ });
50
+ await Promise.race([
51
+ Promise.all(operations),
52
+ new Promise((_resolve, reject) => setTimeout(() => {
53
+ reject(new Error("timeout"));
54
+ }, timeoutMs)),
55
+ ]);
56
+ const elapsedMs = performance.now() - startTime;
57
+ const throughput = (concurrency * sampleSizeMb) / (elapsedMs / 1000);
58
+ // Check if we've hit the ceiling (throughput not improving)
59
+ if (throughput > lastThroughput * 1.05) {
60
+ // Still improving
61
+ lastThroughput = throughput;
62
+ ceiling = concurrency;
63
+ }
64
+ else {
65
+ // Throughput plateaued - we found the ceiling
66
+ break;
67
+ }
68
+ }
69
+ catch {
70
+ // Timeout or error - previous level was the ceiling
71
+ break;
72
+ }
73
+ finally {
74
+ // Cleanup
75
+ try {
76
+ const { readdir } = await import("node:fs/promises");
77
+ const files = await readdir(tempDir);
78
+ await Promise.all(files.map((f) => unlink(join(tempDir, f))));
79
+ }
80
+ catch {
81
+ // Ignore cleanup errors
82
+ }
83
+ }
84
+ }
85
+ return ceiling;
86
+ }
87
+ /** Cached disk I/O ceiling measurement */
88
+ let cachedCeiling = null;
89
+ /**
90
+ * Calculate resource limits using the 75% rule.
91
+ *
92
+ * @param reservePercent - Percentage of resources to reserve (default: 0.75 for 75%)
93
+ * @param options - Options for resource calculation
94
+ * @returns Resource limits for parallel execution
95
+ */
96
+ export async function calculateResources(reservePercent = 0.75, options = {}) {
97
+ const cpuCount = cpus().length;
98
+ const totalMemory = totalmem();
99
+ // Clamp reservePercent to [0, 1] range
100
+ const clampedReserve = Math.max(0, Math.min(1, reservePercent));
101
+ const maxWorkers = Math.floor(cpuCount * clampedReserve);
102
+ // Avoid division by zero when maxWorkers is 0
103
+ const maxMemoryMb = maxWorkers > 0 ? Math.floor((totalMemory * clampedReserve) / maxWorkers / (1024 * 1024)) : 0;
104
+ // Measure disk I/O ceiling once, then cache
105
+ let maxConcurrentIo = Math.floor(100 * clampedReserve);
106
+ if (options.measureDisk !== false && maxWorkers > 0) {
107
+ cachedCeiling ??= await measureDiskIoCeiling();
108
+ maxConcurrentIo = Math.floor(cachedCeiling * clampedReserve);
109
+ }
110
+ return { maxWorkers, maxMemoryMb, maxConcurrentIo };
111
+ }
112
+ /**
113
+ * Synchronous version that skips disk measurement (for quick startup).
114
+ *
115
+ * @param reservePercent - Percentage of resources to reserve (default: 0.75 for 75%)
116
+ * @returns Resource limits for parallel execution (with estimated I/O)
117
+ */
118
+ export function calculateResourcesSync(reservePercent = 0.75) {
119
+ const cpuCount = cpus().length;
120
+ const totalMemory = totalmem();
121
+ // Clamp reservePercent to [0, 1] range
122
+ const clampedReserve = Math.max(0, Math.min(1, reservePercent));
123
+ const maxWorkers = Math.floor(cpuCount * clampedReserve);
124
+ // Avoid division by zero when maxWorkers is 0
125
+ const maxMemoryMb = maxWorkers > 0 ? Math.floor((totalMemory * clampedReserve) / maxWorkers / (1024 * 1024)) : 0;
126
+ const maxConcurrentIo = Math.floor(100 * clampedReserve);
127
+ return { maxWorkers, maxMemoryMb, maxConcurrentIo };
128
+ }
129
+ //# sourceMappingURL=resource-calculator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resource-calculator.js","sourceRoot":"","sources":["../../src/executor/resource-calculator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAcjC;;;;;;;;GAQG;AACH,KAAK,UAAU,oBAAoB,CAClC,YAAY,GAAG,EAAE,EACjB,cAAc,GAAG,GAAG,EACpB,SAAS,GAAG,IAAI;IAEhB,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC;IAE/D,wCAAwC;IACxC,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,OAAO,GAAG,EAAE,CAAC,CAAC,mBAAmB;IAErC,KAAK,IAAI,WAAW,GAAG,CAAC,EAAE,WAAW,IAAI,cAAc,EAAE,WAAW,IAAI,CAAC,EAAE,CAAC;QAC3E,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAEpC,IAAI,CAAC;YACJ,uCAAuC;YACvC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,KAAK,IAAI,EAAE;gBACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;gBAClF,MAAM,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;gBACpC,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBACzB,OAAO,QAAQ,CAAC;YACjB,CAAC,CAAC,CAAC;YAEH,MAAM,OAAO,CAAC,IAAI,CAAC;gBAClB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;gBACvB,IAAI,OAAO,CAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,CACvC,UAAU,CAAC,GAAG,EAAE;oBACf,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;gBAC9B,CAAC,EAAE,SAAS,CAAC,CACb;aACD,CAAC,CAAC;YAEH,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAChD,MAAM,UAAU,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;YAErE,4DAA4D;YAC5D,IAAI,UAAU,GAAG,cAAc,GAAG,IAAI,EAAE,CAAC;gBACxC,kBAAkB;gBAClB,cAAc,GAAG,UAAU,CAAC;gBAC5B,OAAO,GAAG,WAAW,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACP,8CAA8C;gBAC9C,MAAM;YACP,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,oDAAoD;YACpD,MAAM;QACP,CAAC;gBAAS,CAAC;YACV,UAAU;YACV,IAAI,CAAC;gBACJ,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;gBACrD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;gBACrC,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC/D,CAAC;YAAC,MAAM,CAAC;gBACR,wBAAwB;YACzB,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,0CAA0C;AAC1C,IAAI,aAAa,GAAkB,IAAI,CAAC;AAExC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,cAAc,GAAG,IAAI,EACrB,UAAqC,EAAE;IAEvC,MAAM,QAAQ,GAAG,IAAI,EAAE,CAAC,MAAM,CAAC;IAC/B,MAAM,WAAW,GAAG,QAAQ,EAAE,CAAC;IAE/B,uCAAuC;IACvC,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;IAEhE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,cAAc,CAAC,CAAC;IAEzD,8CAA8C;IAC9C,MAAM,WAAW,GAChB,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,cAAc,CAAC,GAAG,UAAU,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9F,4CAA4C;IAC5C,IAAI,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,cAAc,CAAC,CAAC;IACvD,IAAI,OAAO,CAAC,WAAW,KAAK,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACrD,aAAa,KAAK,MAAM,oBAAoB,EAAE,CAAC;QAC/C,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,GAAG,cAAc,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;AACrD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CAAC,cAAc,GAAG,IAAI;IAC3D,MAAM,QAAQ,GAAG,IAAI,EAAE,CAAC,MAAM,CAAC;IAC/B,MAAM,WAAW,GAAG,QAAQ,EAAE,CAAC;IAE/B,uCAAuC;IACvC,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;IAEhE,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,cAAc,CAAC,CAAC;IAEzD,8CAA8C;IAC9C,MAAM,WAAW,GAChB,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,GAAG,cAAc,CAAC,GAAG,UAAU,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9F,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,cAAc,CAAC,CAAC;IAEzD,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC;AACrD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-id.d.ts","sourceRoot":"","sources":["../../src/executor/run-id.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IAEd,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IAEf,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,WAAW,KAAG,MAInD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAGpE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,EAAE,QAAQ,WAAW,KAAG,OACnC,CAAC;AAEjC;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAM1E,CAAC"}
1
+ {"version":3,"file":"run-id.d.ts","sourceRoot":"","sources":["../../src/executor/run-id.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IAEd,sBAAsB;IACtB,MAAM,EAAE,MAAM,CAAC;IAEf,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,oCAAoC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,aAAa,GAAI,QAAQ,WAAW,KAAG,MAInD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAUpE,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,EAAE,QAAQ,WAAW,KAAG,OACnC,CAAC;AAEjC;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAM1E,CAAC"}
@@ -38,7 +38,14 @@ export const generateRunId = (inputs) => {
38
38
  * @returns 8-character hex string
39
39
  */
40
40
  export const generateConfigHash = (config) => {
41
- const canonical = JSON.stringify(config, Object.keys(config).sort());
41
+ // Sort keys for consistent ordering, then stringify without replacer
42
+ // (using replacer array would filter nested properties)
43
+ const sortedKeys = Object.keys(config).sort();
44
+ const sortedObj = {};
45
+ for (const key of sortedKeys) {
46
+ sortedObj[key] = config[key];
47
+ }
48
+ const canonical = JSON.stringify(sortedObj);
42
49
  return createHash("sha256").update(canonical).digest("hex").slice(0, 8);
43
50
  };
44
51
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"run-id.js","sourceRoot":"","sources":["../../src/executor/run-id.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAsBzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAmB,EAAU,EAAE;IAC5D,mCAAmC;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACrE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1E,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAA+B,EAAU,EAAE;IAC7E,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACrE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACzE,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAa,EAAE,MAAmB,EAAW,EAAE,CAC5E,KAAK,KAAK,aAAa,CAAC,MAAM,CAAC,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAa,EAAsC,EAAE;IAC/E,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO;QACN,KAAK,EAAE,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE;QACnC,MAAM,EAAE,KAAK,CAAC,MAAM;KACpB,CAAC;AACH,CAAC,CAAC"}
1
+ {"version":3,"file":"run-id.js","sourceRoot":"","sources":["../../src/executor/run-id.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAsBzC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,MAAmB,EAAU,EAAE;IAC5D,mCAAmC;IACnC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACrE,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC1E,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,MAA+B,EAAU,EAAE;IAC7E,qEAAqE;IACrE,wDAAwD;IACxD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC9B,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAC5C,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACzE,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAa,EAAE,MAAmB,EAAW,EAAE,CAC5E,KAAK,KAAK,aAAa,CAAC,MAAM,CAAC,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAAa,EAAsC,EAAE;IAC/E,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO;QACN,KAAK,EAAE,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,EAAE;QACnC,MAAM,EAAE,KAAK,CAAC,MAAM;KACpB,CAAC;AACH,CAAC,CAAC"}
@@ -3,6 +3,8 @@
3
3
  *
4
4
  * This file is loaded as a worker thread and receives messages
5
5
  * with batches of runs to execute.
6
+ *
7
+ * It uses dependency injection to allow testing of the core logic.
6
8
  */
7
9
  export {};
8
10
  //# sourceMappingURL=worker-entry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker-entry.d.ts","sourceRoot":"","sources":["../../src/executor/worker-entry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
1
+ {"version":3,"file":"worker-entry.d.ts","sourceRoot":"","sources":["../../src/executor/worker-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}