@substrate-ai/factory 0.19.54 → 0.20.2

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 (491) hide show
  1. package/README.md +39 -0
  2. package/dist/config.d.ts +4 -4
  3. package/package.json +12 -3
  4. package/dist/__tests__/config.test.d.ts +0 -11
  5. package/dist/__tests__/config.test.d.ts.map +0 -1
  6. package/dist/__tests__/config.test.js +0 -215
  7. package/dist/__tests__/config.test.js.map +0 -1
  8. package/dist/__tests__/factory-run-command.test.d.ts +0 -12
  9. package/dist/__tests__/factory-run-command.test.d.ts.map +0 -1
  10. package/dist/__tests__/factory-run-command.test.js +0 -454
  11. package/dist/__tests__/factory-run-command.test.js.map +0 -1
  12. package/dist/__tests__/factory-validate-command.test.d.ts +0 -15
  13. package/dist/__tests__/factory-validate-command.test.d.ts.map +0 -1
  14. package/dist/__tests__/factory-validate-command.test.js +0 -339
  15. package/dist/__tests__/factory-validate-command.test.js.map +0 -1
  16. package/dist/__tests__/fixtures/advanced-cross-project-validation.dot.d.ts +0 -72
  17. package/dist/__tests__/fixtures/advanced-cross-project-validation.dot.d.ts.map +0 -1
  18. package/dist/__tests__/fixtures/advanced-cross-project-validation.dot.js +0 -121
  19. package/dist/__tests__/fixtures/advanced-cross-project-validation.dot.js.map +0 -1
  20. package/dist/__tests__/fixtures/llm-edge-routing.dot.d.ts +0 -28
  21. package/dist/__tests__/fixtures/llm-edge-routing.dot.d.ts.map +0 -1
  22. package/dist/__tests__/fixtures/llm-edge-routing.dot.js +0 -55
  23. package/dist/__tests__/fixtures/llm-edge-routing.dot.js.map +0 -1
  24. package/dist/__tests__/fixtures/manager-loop.dot.d.ts +0 -34
  25. package/dist/__tests__/fixtures/manager-loop.dot.d.ts.map +0 -1
  26. package/dist/__tests__/fixtures/manager-loop.dot.js +0 -61
  27. package/dist/__tests__/fixtures/manager-loop.dot.js.map +0 -1
  28. package/dist/__tests__/fixtures/parallel-fan-out-fan-in.dot.d.ts +0 -42
  29. package/dist/__tests__/fixtures/parallel-fan-out-fan-in.dot.d.ts.map +0 -1
  30. package/dist/__tests__/fixtures/parallel-fan-out-fan-in.dot.js +0 -118
  31. package/dist/__tests__/fixtures/parallel-fan-out-fan-in.dot.js.map +0 -1
  32. package/dist/__tests__/fixtures/subgraph-parent.dot.d.ts +0 -35
  33. package/dist/__tests__/fixtures/subgraph-parent.dot.d.ts.map +0 -1
  34. package/dist/__tests__/fixtures/subgraph-parent.dot.js +0 -69
  35. package/dist/__tests__/fixtures/subgraph-parent.dot.js.map +0 -1
  36. package/dist/__tests__/integration/advanced-graph-events.test.d.ts +0 -19
  37. package/dist/__tests__/integration/advanced-graph-events.test.d.ts.map +0 -1
  38. package/dist/__tests__/integration/advanced-graph-events.test.js +0 -288
  39. package/dist/__tests__/integration/advanced-graph-events.test.js.map +0 -1
  40. package/dist/__tests__/integration/checkpoint-resume.test.d.ts +0 -10
  41. package/dist/__tests__/integration/checkpoint-resume.test.d.ts.map +0 -1
  42. package/dist/__tests__/integration/checkpoint-resume.test.js +0 -125
  43. package/dist/__tests__/integration/checkpoint-resume.test.js.map +0 -1
  44. package/dist/__tests__/integration/conditional-pipeline.test.d.ts +0 -10
  45. package/dist/__tests__/integration/conditional-pipeline.test.d.ts.map +0 -1
  46. package/dist/__tests__/integration/conditional-pipeline.test.js +0 -106
  47. package/dist/__tests__/integration/conditional-pipeline.test.js.map +0 -1
  48. package/dist/__tests__/integration/convergence-validation.test.d.ts +0 -14
  49. package/dist/__tests__/integration/convergence-validation.test.d.ts.map +0 -1
  50. package/dist/__tests__/integration/convergence-validation.test.js +0 -449
  51. package/dist/__tests__/integration/convergence-validation.test.js.map +0 -1
  52. package/dist/__tests__/integration/epic44-coverage-gate.test.d.ts +0 -12
  53. package/dist/__tests__/integration/epic44-coverage-gate.test.d.ts.map +0 -1
  54. package/dist/__tests__/integration/epic44-coverage-gate.test.js +0 -58
  55. package/dist/__tests__/integration/epic44-coverage-gate.test.js.map +0 -1
  56. package/dist/__tests__/integration/epic45-coverage-gate.test.d.ts +0 -11
  57. package/dist/__tests__/integration/epic45-coverage-gate.test.d.ts.map +0 -1
  58. package/dist/__tests__/integration/epic45-coverage-gate.test.js +0 -64
  59. package/dist/__tests__/integration/epic45-coverage-gate.test.js.map +0 -1
  60. package/dist/__tests__/integration/epic46-scenario-primary-executor.test.d.ts +0 -2
  61. package/dist/__tests__/integration/epic46-scenario-primary-executor.test.d.ts.map +0 -1
  62. package/dist/__tests__/integration/epic46-scenario-primary-executor.test.js +0 -285
  63. package/dist/__tests__/integration/epic46-scenario-primary-executor.test.js.map +0 -1
  64. package/dist/__tests__/integration/events.test.d.ts +0 -8
  65. package/dist/__tests__/integration/events.test.d.ts.map +0 -1
  66. package/dist/__tests__/integration/events.test.js +0 -194
  67. package/dist/__tests__/integration/events.test.js.map +0 -1
  68. package/dist/__tests__/integration/graphs.d.ts +0 -59
  69. package/dist/__tests__/integration/graphs.d.ts.map +0 -1
  70. package/dist/__tests__/integration/graphs.js +0 -164
  71. package/dist/__tests__/integration/graphs.js.map +0 -1
  72. package/dist/__tests__/integration/helpers.d.ts +0 -127
  73. package/dist/__tests__/integration/helpers.d.ts.map +0 -1
  74. package/dist/__tests__/integration/helpers.js +0 -167
  75. package/dist/__tests__/integration/helpers.js.map +0 -1
  76. package/dist/__tests__/integration/integrity.test.d.ts +0 -8
  77. package/dist/__tests__/integration/integrity.test.d.ts.map +0 -1
  78. package/dist/__tests__/integration/integrity.test.js +0 -198
  79. package/dist/__tests__/integration/integrity.test.js.map +0 -1
  80. package/dist/__tests__/integration/llm-edge-routing.test.d.ts +0 -21
  81. package/dist/__tests__/integration/llm-edge-routing.test.d.ts.map +0 -1
  82. package/dist/__tests__/integration/llm-edge-routing.test.js +0 -341
  83. package/dist/__tests__/integration/llm-edge-routing.test.js.map +0 -1
  84. package/dist/__tests__/integration/manager-loop.test.d.ts +0 -24
  85. package/dist/__tests__/integration/manager-loop.test.d.ts.map +0 -1
  86. package/dist/__tests__/integration/manager-loop.test.js +0 -276
  87. package/dist/__tests__/integration/manager-loop.test.js.map +0 -1
  88. package/dist/__tests__/integration/multi-type-graph.test.d.ts +0 -10
  89. package/dist/__tests__/integration/multi-type-graph.test.d.ts.map +0 -1
  90. package/dist/__tests__/integration/multi-type-graph.test.js +0 -100
  91. package/dist/__tests__/integration/multi-type-graph.test.js.map +0 -1
  92. package/dist/__tests__/integration/parallel-fan-out-fan-in.test.d.ts +0 -22
  93. package/dist/__tests__/integration/parallel-fan-out-fan-in.test.d.ts.map +0 -1
  94. package/dist/__tests__/integration/parallel-fan-out-fan-in.test.js +0 -515
  95. package/dist/__tests__/integration/parallel-fan-out-fan-in.test.js.map +0 -1
  96. package/dist/__tests__/integration/persistence.test.d.ts +0 -8
  97. package/dist/__tests__/integration/persistence.test.d.ts.map +0 -1
  98. package/dist/__tests__/integration/persistence.test.js +0 -129
  99. package/dist/__tests__/integration/persistence.test.js.map +0 -1
  100. package/dist/__tests__/integration/pipeline-templates-integration.test.d.ts +0 -16
  101. package/dist/__tests__/integration/pipeline-templates-integration.test.d.ts.map +0 -1
  102. package/dist/__tests__/integration/pipeline-templates-integration.test.js +0 -171
  103. package/dist/__tests__/integration/pipeline-templates-integration.test.js.map +0 -1
  104. package/dist/__tests__/integration/scenario-pipeline.test.d.ts +0 -11
  105. package/dist/__tests__/integration/scenario-pipeline.test.d.ts.map +0 -1
  106. package/dist/__tests__/integration/scenario-pipeline.test.js +0 -243
  107. package/dist/__tests__/integration/scenario-pipeline.test.js.map +0 -1
  108. package/dist/__tests__/integration/stylesheet-application.test.d.ts +0 -12
  109. package/dist/__tests__/integration/stylesheet-application.test.d.ts.map +0 -1
  110. package/dist/__tests__/integration/stylesheet-application.test.js +0 -119
  111. package/dist/__tests__/integration/stylesheet-application.test.js.map +0 -1
  112. package/dist/__tests__/integration/subgraph-execution.test.d.ts +0 -24
  113. package/dist/__tests__/integration/subgraph-execution.test.d.ts.map +0 -1
  114. package/dist/__tests__/integration/subgraph-execution.test.js +0 -291
  115. package/dist/__tests__/integration/subgraph-execution.test.js.map +0 -1
  116. package/dist/__tests__/integration/validation-errors.test.d.ts +0 -8
  117. package/dist/__tests__/integration/validation-errors.test.d.ts.map +0 -1
  118. package/dist/__tests__/integration/validation-errors.test.js +0 -150
  119. package/dist/__tests__/integration/validation-errors.test.js.map +0 -1
  120. package/dist/agent/__tests__/loop-detection.test.d.ts +0 -2
  121. package/dist/agent/__tests__/loop-detection.test.d.ts.map +0 -1
  122. package/dist/agent/__tests__/loop-detection.test.js +0 -236
  123. package/dist/agent/__tests__/loop-detection.test.js.map +0 -1
  124. package/dist/agent/__tests__/loop.test.d.ts +0 -2
  125. package/dist/agent/__tests__/loop.test.d.ts.map +0 -1
  126. package/dist/agent/__tests__/loop.test.js +0 -868
  127. package/dist/agent/__tests__/loop.test.js.map +0 -1
  128. package/dist/agent/__tests__/truncation.test.d.ts +0 -2
  129. package/dist/agent/__tests__/truncation.test.d.ts.map +0 -1
  130. package/dist/agent/__tests__/truncation.test.js +0 -276
  131. package/dist/agent/__tests__/truncation.test.js.map +0 -1
  132. package/dist/agent/tools/__tests__/anthropic-tools.test.d.ts +0 -6
  133. package/dist/agent/tools/__tests__/anthropic-tools.test.d.ts.map +0 -1
  134. package/dist/agent/tools/__tests__/anthropic-tools.test.js +0 -49
  135. package/dist/agent/tools/__tests__/anthropic-tools.test.js.map +0 -1
  136. package/dist/agent/tools/__tests__/environment.test.d.ts +0 -6
  137. package/dist/agent/tools/__tests__/environment.test.d.ts.map +0 -1
  138. package/dist/agent/tools/__tests__/environment.test.js +0 -33
  139. package/dist/agent/tools/__tests__/environment.test.js.map +0 -1
  140. package/dist/agent/tools/__tests__/gemini-tools.test.d.ts +0 -6
  141. package/dist/agent/tools/__tests__/gemini-tools.test.d.ts.map +0 -1
  142. package/dist/agent/tools/__tests__/gemini-tools.test.js +0 -98
  143. package/dist/agent/tools/__tests__/gemini-tools.test.js.map +0 -1
  144. package/dist/agent/tools/__tests__/openai-tools.test.d.ts +0 -6
  145. package/dist/agent/tools/__tests__/openai-tools.test.d.ts.map +0 -1
  146. package/dist/agent/tools/__tests__/openai-tools.test.js +0 -53
  147. package/dist/agent/tools/__tests__/openai-tools.test.js.map +0 -1
  148. package/dist/agent/tools/__tests__/patch.test.d.ts +0 -6
  149. package/dist/agent/tools/__tests__/patch.test.d.ts.map +0 -1
  150. package/dist/agent/tools/__tests__/patch.test.js +0 -116
  151. package/dist/agent/tools/__tests__/patch.test.js.map +0 -1
  152. package/dist/agent/tools/__tests__/profiles.test.d.ts +0 -6
  153. package/dist/agent/tools/__tests__/profiles.test.d.ts.map +0 -1
  154. package/dist/agent/tools/__tests__/profiles.test.js +0 -125
  155. package/dist/agent/tools/__tests__/profiles.test.js.map +0 -1
  156. package/dist/agent/tools/__tests__/registry.test.d.ts +0 -6
  157. package/dist/agent/tools/__tests__/registry.test.d.ts.map +0 -1
  158. package/dist/agent/tools/__tests__/registry.test.js +0 -94
  159. package/dist/agent/tools/__tests__/registry.test.js.map +0 -1
  160. package/dist/agent/tools/__tests__/shared.test.d.ts +0 -6
  161. package/dist/agent/tools/__tests__/shared.test.d.ts.map +0 -1
  162. package/dist/agent/tools/__tests__/shared.test.js +0 -131
  163. package/dist/agent/tools/__tests__/shared.test.js.map +0 -1
  164. package/dist/backend/__tests__/direct-backend.test.d.ts +0 -14
  165. package/dist/backend/__tests__/direct-backend.test.d.ts.map +0 -1
  166. package/dist/backend/__tests__/direct-backend.test.js +0 -393
  167. package/dist/backend/__tests__/direct-backend.test.js.map +0 -1
  168. package/dist/backend/__tests__/direct-bootstrap.test.d.ts +0 -7
  169. package/dist/backend/__tests__/direct-bootstrap.test.d.ts.map +0 -1
  170. package/dist/backend/__tests__/direct-bootstrap.test.js +0 -177
  171. package/dist/backend/__tests__/direct-bootstrap.test.js.map +0 -1
  172. package/dist/backend/__tests__/mock-backend.test.d.ts +0 -7
  173. package/dist/backend/__tests__/mock-backend.test.d.ts.map +0 -1
  174. package/dist/backend/__tests__/mock-backend.test.js +0 -273
  175. package/dist/backend/__tests__/mock-backend.test.js.map +0 -1
  176. package/dist/backend/__tests__/parity.test.d.ts +0 -17
  177. package/dist/backend/__tests__/parity.test.d.ts.map +0 -1
  178. package/dist/backend/__tests__/parity.test.js +0 -411
  179. package/dist/backend/__tests__/parity.test.js.map +0 -1
  180. package/dist/context/__tests__/auto-summarizer.test.d.ts +0 -14
  181. package/dist/context/__tests__/auto-summarizer.test.d.ts.map +0 -1
  182. package/dist/context/__tests__/auto-summarizer.test.js +0 -189
  183. package/dist/context/__tests__/auto-summarizer.test.js.map +0 -1
  184. package/dist/context/__tests__/context-cli-command.test.d.ts +0 -7
  185. package/dist/context/__tests__/context-cli-command.test.d.ts.map +0 -1
  186. package/dist/context/__tests__/context-cli-command.test.js +0 -331
  187. package/dist/context/__tests__/context-cli-command.test.js.map +0 -1
  188. package/dist/context/__tests__/pyramid-summary-integration.test.d.ts +0 -2
  189. package/dist/context/__tests__/pyramid-summary-integration.test.d.ts.map +0 -1
  190. package/dist/context/__tests__/pyramid-summary-integration.test.js +0 -533
  191. package/dist/context/__tests__/pyramid-summary-integration.test.js.map +0 -1
  192. package/dist/context/__tests__/summarizer.test.d.ts +0 -2
  193. package/dist/context/__tests__/summarizer.test.d.ts.map +0 -1
  194. package/dist/context/__tests__/summarizer.test.js +0 -189
  195. package/dist/context/__tests__/summarizer.test.js.map +0 -1
  196. package/dist/context/__tests__/summary-cache.test.d.ts +0 -2
  197. package/dist/context/__tests__/summary-cache.test.d.ts.map +0 -1
  198. package/dist/context/__tests__/summary-cache.test.js +0 -214
  199. package/dist/context/__tests__/summary-cache.test.js.map +0 -1
  200. package/dist/context/__tests__/summary-metrics.test.d.ts +0 -2
  201. package/dist/context/__tests__/summary-metrics.test.d.ts.map +0 -1
  202. package/dist/context/__tests__/summary-metrics.test.js +0 -172
  203. package/dist/context/__tests__/summary-metrics.test.js.map +0 -1
  204. package/dist/context/__tests__/summary-types.test.d.ts +0 -2
  205. package/dist/context/__tests__/summary-types.test.d.ts.map +0 -1
  206. package/dist/context/__tests__/summary-types.test.js +0 -130
  207. package/dist/context/__tests__/summary-types.test.js.map +0 -1
  208. package/dist/convergence/__tests__/budget.test.d.ts +0 -6
  209. package/dist/convergence/__tests__/budget.test.d.ts.map +0 -1
  210. package/dist/convergence/__tests__/budget.test.js +0 -187
  211. package/dist/convergence/__tests__/budget.test.js.map +0 -1
  212. package/dist/convergence/__tests__/controller.test.d.ts +0 -9
  213. package/dist/convergence/__tests__/controller.test.d.ts.map +0 -1
  214. package/dist/convergence/__tests__/controller.test.js +0 -585
  215. package/dist/convergence/__tests__/controller.test.js.map +0 -1
  216. package/dist/convergence/__tests__/dual-signal.test.d.ts +0 -14
  217. package/dist/convergence/__tests__/dual-signal.test.d.ts.map +0 -1
  218. package/dist/convergence/__tests__/dual-signal.test.js +0 -123
  219. package/dist/convergence/__tests__/dual-signal.test.js.map +0 -1
  220. package/dist/convergence/__tests__/epic46-integration.test.d.ts +0 -15
  221. package/dist/convergence/__tests__/epic46-integration.test.d.ts.map +0 -1
  222. package/dist/convergence/__tests__/epic46-integration.test.js +0 -522
  223. package/dist/convergence/__tests__/epic46-integration.test.js.map +0 -1
  224. package/dist/convergence/__tests__/plateau.test.d.ts +0 -6
  225. package/dist/convergence/__tests__/plateau.test.d.ts.map +0 -1
  226. package/dist/convergence/__tests__/plateau.test.js +0 -163
  227. package/dist/convergence/__tests__/plateau.test.js.map +0 -1
  228. package/dist/convergence/__tests__/remediation.test.d.ts +0 -11
  229. package/dist/convergence/__tests__/remediation.test.d.ts.map +0 -1
  230. package/dist/convergence/__tests__/remediation.test.js +0 -209
  231. package/dist/convergence/__tests__/remediation.test.js.map +0 -1
  232. package/dist/convergence/__tests__/scenario-primary.test.d.ts +0 -13
  233. package/dist/convergence/__tests__/scenario-primary.test.d.ts.map +0 -1
  234. package/dist/convergence/__tests__/scenario-primary.test.js +0 -183
  235. package/dist/convergence/__tests__/scenario-primary.test.js.map +0 -1
  236. package/dist/factory-command.test.d.ts +0 -8
  237. package/dist/factory-command.test.d.ts.map +0 -1
  238. package/dist/factory-command.test.js +0 -304
  239. package/dist/factory-command.test.js.map +0 -1
  240. package/dist/graph/__tests__/attractor-compliance.test.d.ts +0 -10
  241. package/dist/graph/__tests__/attractor-compliance.test.d.ts.map +0 -1
  242. package/dist/graph/__tests__/attractor-compliance.test.js +0 -766
  243. package/dist/graph/__tests__/attractor-compliance.test.js.map +0 -1
  244. package/dist/graph/__tests__/checkpoint.test.d.ts +0 -8
  245. package/dist/graph/__tests__/checkpoint.test.d.ts.map +0 -1
  246. package/dist/graph/__tests__/checkpoint.test.js +0 -329
  247. package/dist/graph/__tests__/checkpoint.test.js.map +0 -1
  248. package/dist/graph/__tests__/condition-parser.test.d.ts +0 -14
  249. package/dist/graph/__tests__/condition-parser.test.d.ts.map +0 -1
  250. package/dist/graph/__tests__/condition-parser.test.js +0 -406
  251. package/dist/graph/__tests__/condition-parser.test.js.map +0 -1
  252. package/dist/graph/__tests__/context.test.d.ts +0 -14
  253. package/dist/graph/__tests__/context.test.d.ts.map +0 -1
  254. package/dist/graph/__tests__/context.test.js +0 -276
  255. package/dist/graph/__tests__/context.test.js.map +0 -1
  256. package/dist/graph/__tests__/edge-selector-events.test.d.ts +0 -11
  257. package/dist/graph/__tests__/edge-selector-events.test.d.ts.map +0 -1
  258. package/dist/graph/__tests__/edge-selector-events.test.js +0 -184
  259. package/dist/graph/__tests__/edge-selector-events.test.js.map +0 -1
  260. package/dist/graph/__tests__/edge-selector.test.d.ts +0 -6
  261. package/dist/graph/__tests__/edge-selector.test.d.ts.map +0 -1
  262. package/dist/graph/__tests__/edge-selector.test.js +0 -452
  263. package/dist/graph/__tests__/edge-selector.test.js.map +0 -1
  264. package/dist/graph/__tests__/executor-convergence.test.d.ts +0 -12
  265. package/dist/graph/__tests__/executor-convergence.test.d.ts.map +0 -1
  266. package/dist/graph/__tests__/executor-convergence.test.js +0 -432
  267. package/dist/graph/__tests__/executor-convergence.test.js.map +0 -1
  268. package/dist/graph/__tests__/executor-fidelity.test.d.ts +0 -13
  269. package/dist/graph/__tests__/executor-fidelity.test.d.ts.map +0 -1
  270. package/dist/graph/__tests__/executor-fidelity.test.js +0 -335
  271. package/dist/graph/__tests__/executor-fidelity.test.js.map +0 -1
  272. package/dist/graph/__tests__/executor.test.d.ts +0 -14
  273. package/dist/graph/__tests__/executor.test.d.ts.map +0 -1
  274. package/dist/graph/__tests__/executor.test.js +0 -901
  275. package/dist/graph/__tests__/executor.test.js.map +0 -1
  276. package/dist/graph/__tests__/fidelity.test.d.ts +0 -8
  277. package/dist/graph/__tests__/fidelity.test.d.ts.map +0 -1
  278. package/dist/graph/__tests__/fidelity.test.js +0 -135
  279. package/dist/graph/__tests__/fidelity.test.js.map +0 -1
  280. package/dist/graph/__tests__/llm-evaluator.test.d.ts +0 -7
  281. package/dist/graph/__tests__/llm-evaluator.test.d.ts.map +0 -1
  282. package/dist/graph/__tests__/llm-evaluator.test.js +0 -106
  283. package/dist/graph/__tests__/llm-evaluator.test.js.map +0 -1
  284. package/dist/graph/__tests__/parser-chaining.test.d.ts +0 -13
  285. package/dist/graph/__tests__/parser-chaining.test.d.ts.map +0 -1
  286. package/dist/graph/__tests__/parser-chaining.test.js +0 -215
  287. package/dist/graph/__tests__/parser-chaining.test.js.map +0 -1
  288. package/dist/graph/__tests__/parser.test.d.ts +0 -22
  289. package/dist/graph/__tests__/parser.test.d.ts.map +0 -1
  290. package/dist/graph/__tests__/parser.test.js +0 -452
  291. package/dist/graph/__tests__/parser.test.js.map +0 -1
  292. package/dist/graph/__tests__/run-state.test.d.ts +0 -13
  293. package/dist/graph/__tests__/run-state.test.d.ts.map +0 -1
  294. package/dist/graph/__tests__/run-state.test.js +0 -189
  295. package/dist/graph/__tests__/run-state.test.js.map +0 -1
  296. package/dist/graph/__tests__/transformer.test.d.ts +0 -16
  297. package/dist/graph/__tests__/transformer.test.d.ts.map +0 -1
  298. package/dist/graph/__tests__/transformer.test.js +0 -350
  299. package/dist/graph/__tests__/transformer.test.js.map +0 -1
  300. package/dist/graph/__tests__/validator-errors.test.d.ts +0 -15
  301. package/dist/graph/__tests__/validator-errors.test.d.ts.map +0 -1
  302. package/dist/graph/__tests__/validator-errors.test.js +0 -572
  303. package/dist/graph/__tests__/validator-errors.test.js.map +0 -1
  304. package/dist/graph/__tests__/validator-warnings.test.d.ts +0 -15
  305. package/dist/graph/__tests__/validator-warnings.test.d.ts.map +0 -1
  306. package/dist/graph/__tests__/validator-warnings.test.js +0 -363
  307. package/dist/graph/__tests__/validator-warnings.test.js.map +0 -1
  308. package/dist/handlers/__tests__/codergen-handler.test.d.ts +0 -14
  309. package/dist/handlers/__tests__/codergen-handler.test.d.ts.map +0 -1
  310. package/dist/handlers/__tests__/codergen-handler.test.js +0 -442
  311. package/dist/handlers/__tests__/codergen-handler.test.js.map +0 -1
  312. package/dist/handlers/__tests__/fan-in.test.d.ts +0 -14
  313. package/dist/handlers/__tests__/fan-in.test.d.ts.map +0 -1
  314. package/dist/handlers/__tests__/fan-in.test.js +0 -399
  315. package/dist/handlers/__tests__/fan-in.test.js.map +0 -1
  316. package/dist/handlers/__tests__/join-policy.test.d.ts +0 -9
  317. package/dist/handlers/__tests__/join-policy.test.d.ts.map +0 -1
  318. package/dist/handlers/__tests__/join-policy.test.js +0 -201
  319. package/dist/handlers/__tests__/join-policy.test.js.map +0 -1
  320. package/dist/handlers/__tests__/manager-loop.test.d.ts +0 -14
  321. package/dist/handlers/__tests__/manager-loop.test.d.ts.map +0 -1
  322. package/dist/handlers/__tests__/manager-loop.test.js +0 -322
  323. package/dist/handlers/__tests__/manager-loop.test.js.map +0 -1
  324. package/dist/handlers/__tests__/parallel-events.test.d.ts +0 -12
  325. package/dist/handlers/__tests__/parallel-events.test.d.ts.map +0 -1
  326. package/dist/handlers/__tests__/parallel-events.test.js +0 -252
  327. package/dist/handlers/__tests__/parallel-events.test.js.map +0 -1
  328. package/dist/handlers/__tests__/parallel-handler.test.d.ts +0 -14
  329. package/dist/handlers/__tests__/parallel-handler.test.d.ts.map +0 -1
  330. package/dist/handlers/__tests__/parallel-handler.test.js +0 -337
  331. package/dist/handlers/__tests__/parallel-handler.test.js.map +0 -1
  332. package/dist/handlers/__tests__/parallel-join.test.d.ts +0 -9
  333. package/dist/handlers/__tests__/parallel-join.test.d.ts.map +0 -1
  334. package/dist/handlers/__tests__/parallel-join.test.js +0 -267
  335. package/dist/handlers/__tests__/parallel-join.test.js.map +0 -1
  336. package/dist/handlers/__tests__/registry.test.d.ts +0 -14
  337. package/dist/handlers/__tests__/registry.test.d.ts.map +0 -1
  338. package/dist/handlers/__tests__/registry.test.js +0 -315
  339. package/dist/handlers/__tests__/registry.test.js.map +0 -1
  340. package/dist/handlers/__tests__/subgraph-events.test.d.ts +0 -10
  341. package/dist/handlers/__tests__/subgraph-events.test.d.ts.map +0 -1
  342. package/dist/handlers/__tests__/subgraph-events.test.js +0 -189
  343. package/dist/handlers/__tests__/subgraph-events.test.js.map +0 -1
  344. package/dist/handlers/__tests__/subgraph-inheritance.test.d.ts +0 -14
  345. package/dist/handlers/__tests__/subgraph-inheritance.test.d.ts.map +0 -1
  346. package/dist/handlers/__tests__/subgraph-inheritance.test.js +0 -267
  347. package/dist/handlers/__tests__/subgraph-inheritance.test.js.map +0 -1
  348. package/dist/handlers/__tests__/subgraph.test.d.ts +0 -14
  349. package/dist/handlers/__tests__/subgraph.test.d.ts.map +0 -1
  350. package/dist/handlers/__tests__/subgraph.test.js +0 -369
  351. package/dist/handlers/__tests__/subgraph.test.js.map +0 -1
  352. package/dist/handlers/__tests__/tool-handler.test.d.ts +0 -11
  353. package/dist/handlers/__tests__/tool-handler.test.d.ts.map +0 -1
  354. package/dist/handlers/__tests__/tool-handler.test.js +0 -184
  355. package/dist/handlers/__tests__/tool-handler.test.js.map +0 -1
  356. package/dist/handlers/__tests__/tool-scenario.test.d.ts +0 -12
  357. package/dist/handlers/__tests__/tool-scenario.test.d.ts.map +0 -1
  358. package/dist/handlers/__tests__/tool-scenario.test.js +0 -222
  359. package/dist/handlers/__tests__/tool-scenario.test.js.map +0 -1
  360. package/dist/handlers/__tests__/wait-human-handler.test.d.ts +0 -11
  361. package/dist/handlers/__tests__/wait-human-handler.test.d.ts.map +0 -1
  362. package/dist/handlers/__tests__/wait-human-handler.test.js +0 -251
  363. package/dist/handlers/__tests__/wait-human-handler.test.js.map +0 -1
  364. package/dist/llm/__tests__/client.test.d.ts +0 -2
  365. package/dist/llm/__tests__/client.test.d.ts.map +0 -1
  366. package/dist/llm/__tests__/client.test.js +0 -198
  367. package/dist/llm/__tests__/client.test.js.map +0 -1
  368. package/dist/llm/__tests__/types.test.d.ts +0 -2
  369. package/dist/llm/__tests__/types.test.d.ts.map +0 -1
  370. package/dist/llm/__tests__/types.test.js +0 -289
  371. package/dist/llm/__tests__/types.test.js.map +0 -1
  372. package/dist/llm/middleware/__tests__/cost-tracking.test.d.ts +0 -2
  373. package/dist/llm/middleware/__tests__/cost-tracking.test.d.ts.map +0 -1
  374. package/dist/llm/middleware/__tests__/cost-tracking.test.js +0 -73
  375. package/dist/llm/middleware/__tests__/cost-tracking.test.js.map +0 -1
  376. package/dist/llm/middleware/__tests__/logging.test.d.ts +0 -2
  377. package/dist/llm/middleware/__tests__/logging.test.d.ts.map +0 -1
  378. package/dist/llm/middleware/__tests__/logging.test.js +0 -127
  379. package/dist/llm/middleware/__tests__/logging.test.js.map +0 -1
  380. package/dist/llm/middleware/__tests__/retry.test.d.ts +0 -2
  381. package/dist/llm/middleware/__tests__/retry.test.d.ts.map +0 -1
  382. package/dist/llm/middleware/__tests__/retry.test.js +0 -126
  383. package/dist/llm/middleware/__tests__/retry.test.js.map +0 -1
  384. package/dist/llm/providers/__tests__/anthropic.test.d.ts +0 -2
  385. package/dist/llm/providers/__tests__/anthropic.test.d.ts.map +0 -1
  386. package/dist/llm/providers/__tests__/anthropic.test.js +0 -412
  387. package/dist/llm/providers/__tests__/anthropic.test.js.map +0 -1
  388. package/dist/llm/providers/__tests__/gemini.test.d.ts +0 -2
  389. package/dist/llm/providers/__tests__/gemini.test.d.ts.map +0 -1
  390. package/dist/llm/providers/__tests__/gemini.test.js +0 -591
  391. package/dist/llm/providers/__tests__/gemini.test.js.map +0 -1
  392. package/dist/llm/providers/__tests__/openai.test.d.ts +0 -2
  393. package/dist/llm/providers/__tests__/openai.test.d.ts.map +0 -1
  394. package/dist/llm/providers/__tests__/openai.test.js +0 -546
  395. package/dist/llm/providers/__tests__/openai.test.js.map +0 -1
  396. package/dist/persistence/__tests__/factory-queries.test.d.ts +0 -9
  397. package/dist/persistence/__tests__/factory-queries.test.d.ts.map +0 -1
  398. package/dist/persistence/__tests__/factory-queries.test.js +0 -372
  399. package/dist/persistence/__tests__/factory-queries.test.js.map +0 -1
  400. package/dist/persistence/__tests__/factory-schema.test.d.ts +0 -6
  401. package/dist/persistence/__tests__/factory-schema.test.d.ts.map +0 -1
  402. package/dist/persistence/__tests__/factory-schema.test.js +0 -105
  403. package/dist/persistence/__tests__/factory-schema.test.js.map +0 -1
  404. package/dist/scenarios/__tests__/cli-command-list.test.d.ts +0 -7
  405. package/dist/scenarios/__tests__/cli-command-list.test.d.ts.map +0 -1
  406. package/dist/scenarios/__tests__/cli-command-list.test.js +0 -237
  407. package/dist/scenarios/__tests__/cli-command-list.test.js.map +0 -1
  408. package/dist/scenarios/__tests__/cli-command.test.d.ts +0 -11
  409. package/dist/scenarios/__tests__/cli-command.test.d.ts.map +0 -1
  410. package/dist/scenarios/__tests__/cli-command.test.js +0 -275
  411. package/dist/scenarios/__tests__/cli-command.test.js.map +0 -1
  412. package/dist/scenarios/__tests__/integrity-pipeline.test.d.ts +0 -15
  413. package/dist/scenarios/__tests__/integrity-pipeline.test.d.ts.map +0 -1
  414. package/dist/scenarios/__tests__/integrity-pipeline.test.js +0 -318
  415. package/dist/scenarios/__tests__/integrity-pipeline.test.js.map +0 -1
  416. package/dist/scenarios/__tests__/runner-twins.test.d.ts +0 -13
  417. package/dist/scenarios/__tests__/runner-twins.test.d.ts.map +0 -1
  418. package/dist/scenarios/__tests__/runner-twins.test.js +0 -205
  419. package/dist/scenarios/__tests__/runner-twins.test.js.map +0 -1
  420. package/dist/scenarios/__tests__/scorer.test.d.ts +0 -11
  421. package/dist/scenarios/__tests__/scorer.test.d.ts.map +0 -1
  422. package/dist/scenarios/__tests__/scorer.test.js +0 -225
  423. package/dist/scenarios/__tests__/scorer.test.js.map +0 -1
  424. package/dist/scenarios/__tests__/scoring-integration.test.d.ts +0 -8
  425. package/dist/scenarios/__tests__/scoring-integration.test.d.ts.map +0 -1
  426. package/dist/scenarios/__tests__/scoring-integration.test.js +0 -178
  427. package/dist/scenarios/__tests__/scoring-integration.test.js.map +0 -1
  428. package/dist/scenarios/__tests__/store.test.d.ts +0 -5
  429. package/dist/scenarios/__tests__/store.test.d.ts.map +0 -1
  430. package/dist/scenarios/__tests__/store.test.js +0 -169
  431. package/dist/scenarios/__tests__/store.test.js.map +0 -1
  432. package/dist/stylesheet/__tests__/stylesheet.test.d.ts +0 -17
  433. package/dist/stylesheet/__tests__/stylesheet.test.d.ts.map +0 -1
  434. package/dist/stylesheet/__tests__/stylesheet.test.js +0 -368
  435. package/dist/stylesheet/__tests__/stylesheet.test.js.map +0 -1
  436. package/dist/templates/__tests__/templates.test.d.ts +0 -7
  437. package/dist/templates/__tests__/templates.test.d.ts.map +0 -1
  438. package/dist/templates/__tests__/templates.test.js +0 -92
  439. package/dist/templates/__tests__/templates.test.js.map +0 -1
  440. package/dist/twins/__tests__/docker-compose.test.d.ts +0 -13
  441. package/dist/twins/__tests__/docker-compose.test.d.ts.map +0 -1
  442. package/dist/twins/__tests__/docker-compose.test.js +0 -247
  443. package/dist/twins/__tests__/docker-compose.test.js.map +0 -1
  444. package/dist/twins/__tests__/health-monitor.test.d.ts +0 -19
  445. package/dist/twins/__tests__/health-monitor.test.d.ts.map +0 -1
  446. package/dist/twins/__tests__/health-monitor.test.js +0 -301
  447. package/dist/twins/__tests__/health-monitor.test.js.map +0 -1
  448. package/dist/twins/__tests__/integration/e2e.test.d.ts +0 -18
  449. package/dist/twins/__tests__/integration/e2e.test.d.ts.map +0 -1
  450. package/dist/twins/__tests__/integration/e2e.test.js +0 -146
  451. package/dist/twins/__tests__/integration/e2e.test.js.map +0 -1
  452. package/dist/twins/__tests__/integration/health-monitor-integration.test.d.ts +0 -16
  453. package/dist/twins/__tests__/integration/health-monitor-integration.test.d.ts.map +0 -1
  454. package/dist/twins/__tests__/integration/health-monitor-integration.test.js +0 -183
  455. package/dist/twins/__tests__/integration/health-monitor-integration.test.js.map +0 -1
  456. package/dist/twins/__tests__/integration/helpers.d.ts +0 -32
  457. package/dist/twins/__tests__/integration/helpers.d.ts.map +0 -1
  458. package/dist/twins/__tests__/integration/helpers.js +0 -67
  459. package/dist/twins/__tests__/integration/helpers.js.map +0 -1
  460. package/dist/twins/__tests__/integration/lifecycle.test.d.ts +0 -14
  461. package/dist/twins/__tests__/integration/lifecycle.test.d.ts.map +0 -1
  462. package/dist/twins/__tests__/integration/lifecycle.test.js +0 -127
  463. package/dist/twins/__tests__/integration/lifecycle.test.js.map +0 -1
  464. package/dist/twins/__tests__/integration/persistence-integration.test.d.ts +0 -14
  465. package/dist/twins/__tests__/integration/persistence-integration.test.d.ts.map +0 -1
  466. package/dist/twins/__tests__/integration/persistence-integration.test.js +0 -132
  467. package/dist/twins/__tests__/integration/persistence-integration.test.js.map +0 -1
  468. package/dist/twins/__tests__/persistence.test.d.ts +0 -10
  469. package/dist/twins/__tests__/persistence.test.d.ts.map +0 -1
  470. package/dist/twins/__tests__/persistence.test.js +0 -300
  471. package/dist/twins/__tests__/persistence.test.js.map +0 -1
  472. package/dist/twins/__tests__/registry.test.d.ts +0 -7
  473. package/dist/twins/__tests__/registry.test.d.ts.map +0 -1
  474. package/dist/twins/__tests__/registry.test.js +0 -282
  475. package/dist/twins/__tests__/registry.test.js.map +0 -1
  476. package/dist/twins/__tests__/run-state.test.d.ts +0 -9
  477. package/dist/twins/__tests__/run-state.test.d.ts.map +0 -1
  478. package/dist/twins/__tests__/run-state.test.js +0 -112
  479. package/dist/twins/__tests__/run-state.test.js.map +0 -1
  480. package/dist/twins/__tests__/templates-cli.test.d.ts +0 -10
  481. package/dist/twins/__tests__/templates-cli.test.d.ts.map +0 -1
  482. package/dist/twins/__tests__/templates-cli.test.js +0 -187
  483. package/dist/twins/__tests__/templates-cli.test.js.map +0 -1
  484. package/dist/twins/__tests__/templates.test.d.ts +0 -7
  485. package/dist/twins/__tests__/templates.test.d.ts.map +0 -1
  486. package/dist/twins/__tests__/templates.test.js +0 -87
  487. package/dist/twins/__tests__/templates.test.js.map +0 -1
  488. package/dist/twins/__tests__/twins-cli.test.d.ts +0 -11
  489. package/dist/twins/__tests__/twins-cli.test.d.ts.map +0 -1
  490. package/dist/twins/__tests__/twins-cli.test.js +0 -365
  491. package/dist/twins/__tests__/twins-cli.test.js.map +0 -1
@@ -1,766 +0,0 @@
1
- /**
2
- * Spec compliance tests for the Attractor graph engine.
3
- *
4
- * Replays pseudocode examples from the Attractor spec through
5
- * selectEdge(), evaluateGates(), and checkpoint resume APIs.
6
- *
7
- * Story 42-17.
8
- */
9
- // AttractorBench structural conformance parity — Phase A mandatory
10
- // See: https://github.com/strongdm/attractorbench
11
- // Behavioral conformance tests are advisory in Phase A; required by Phase B exit.
12
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
13
- import os from 'node:os';
14
- import path from 'node:path';
15
- import { mkdir, rm } from 'node:fs/promises';
16
- import crypto from 'node:crypto';
17
- import { selectEdge } from '../edge-selector.js';
18
- import { createConvergenceController } from '../../convergence/controller.js';
19
- import { CheckpointManager } from '../checkpoint.js';
20
- import { createGraphExecutor } from '../executor.js';
21
- import { createValidator } from '../validator.js';
22
- import { parseGraph } from '../parser.js';
23
- import { GraphContext } from '../context.js';
24
- // ---------------------------------------------------------------------------
25
- // DOT fixture for resume/fidelity tests (spec Section 5.3)
26
- // ---------------------------------------------------------------------------
27
- const COMPLIANCE_RESUME_DOT = `
28
- digraph compliance_resume {
29
- graph [goal="Resume compliance test"]
30
- start [shape=Mdiamond]
31
- node1 [type=codergen, prompt="Step 1"]
32
- node2 [type=codergen, prompt="Step 2"]
33
- exit [shape=Msquare]
34
-
35
- start -> node1
36
- node1 -> node2
37
- node2 -> exit
38
- }
39
- `;
40
- const COMPLIANCE_FIDELITY_RESUME_DOT = `
41
- digraph compliance_fidelity_resume {
42
- graph [goal="Fidelity degradation test"]
43
- start [shape=Mdiamond]
44
- node1 [type=codergen, prompt="Step 1", fidelity=full]
45
- node2 [type=codergen, prompt="Step 2"]
46
- exit [shape=Msquare]
47
-
48
- start -> node1
49
- node1 -> node2
50
- node2 -> exit
51
- }
52
- `;
53
- // ---------------------------------------------------------------------------
54
- // Shared helper factories
55
- // ---------------------------------------------------------------------------
56
- /** A node with all required fields at sensible defaults. */
57
- const MINIMAL_NODE = {
58
- id: '',
59
- label: '',
60
- shape: 'box',
61
- type: 'codergen',
62
- prompt: '',
63
- maxRetries: 0,
64
- goalGate: false,
65
- retryTarget: '',
66
- fallbackRetryTarget: '',
67
- fidelity: '',
68
- threadId: '',
69
- class: '',
70
- timeout: 0,
71
- llmModel: '',
72
- llmProvider: '',
73
- reasoningEffort: '',
74
- autoStatus: false,
75
- allowPartial: false,
76
- toolCommand: '',
77
- backend: '',
78
- };
79
- function makeNode(id, overrides) {
80
- return { ...MINIMAL_NODE, id, ...overrides };
81
- }
82
- function makeEdge(fromNode, toNode, overrides) {
83
- return {
84
- fromNode,
85
- toNode,
86
- label: '',
87
- condition: '',
88
- weight: 0,
89
- fidelity: '',
90
- threadId: '',
91
- loopRestart: false,
92
- ...overrides,
93
- };
94
- }
95
- /**
96
- * Build a minimal Graph conforming to the Graph interface.
97
- * startNodeId / exitNodeId control which nodes serve as start/exit.
98
- */
99
- function makeGraph(nodes, edges, startNodeId, exitNodeId) {
100
- const nodeMap = new Map(nodes.map((n) => [n.id, n]));
101
- const resolveStart = () => {
102
- if (startNodeId)
103
- return nodeMap.get(startNodeId);
104
- for (const n of nodeMap.values()) {
105
- if (n.shape === 'Mdiamond')
106
- return n;
107
- }
108
- throw new Error('No start node');
109
- };
110
- const resolveExit = () => {
111
- if (exitNodeId)
112
- return nodeMap.get(exitNodeId);
113
- for (const n of nodeMap.values()) {
114
- if (n.shape === 'Msquare')
115
- return n;
116
- }
117
- throw new Error('No exit node');
118
- };
119
- return {
120
- id: '',
121
- goal: '',
122
- label: '',
123
- modelStylesheet: '',
124
- defaultMaxRetries: 0,
125
- retryTarget: '',
126
- fallbackRetryTarget: '',
127
- defaultFidelity: '',
128
- nodes: nodeMap,
129
- edges,
130
- outgoingEdges: (nodeId) => edges.filter((e) => e.fromNode === nodeId),
131
- startNode: resolveStart,
132
- exitNode: resolveExit,
133
- };
134
- }
135
- /** Build a Graph with only the minimal start/exit structure for lint-rule tests. */
136
- function makeLintGraph(extraNodes, extraEdges, overrides) {
137
- const baseNodes = [
138
- makeNode('start', { shape: 'Mdiamond', type: '' }),
139
- makeNode('exit', { shape: 'Msquare', type: '' }),
140
- ...extraNodes.map((n) => makeNode(n.id, n)),
141
- ];
142
- const baseEdges = extraEdges.map((e) => makeEdge(e.fromNode, e.toNode, {
143
- condition: e.condition ?? '',
144
- loopRestart: e.loopRestart ?? false,
145
- }));
146
- const nodeMap = new Map(baseNodes.map((n) => [n.id, n]));
147
- return {
148
- id: 'test',
149
- goal: '',
150
- label: '',
151
- modelStylesheet: overrides?.modelStylesheet ?? '',
152
- defaultMaxRetries: 0,
153
- retryTarget: overrides?.retryTarget ?? '',
154
- fallbackRetryTarget: overrides?.fallbackRetryTarget ?? '',
155
- defaultFidelity: '',
156
- nodes: nodeMap,
157
- edges: baseEdges,
158
- outgoingEdges: (nodeId) => baseEdges.filter((e) => e.fromNode === nodeId),
159
- startNode: () => nodeMap.get('start'),
160
- exitNode: () => nodeMap.get('exit'),
161
- };
162
- }
163
- /** Build a mock IHandlerRegistry that resolves every node via the given handler factory. */
164
- function makeRegistry(handlerFactory, statusOverride) {
165
- return {
166
- register: vi.fn(),
167
- registerShape: vi.fn(),
168
- setDefault: vi.fn(),
169
- resolve: vi.fn().mockImplementation(() => async (node, ctx) => {
170
- handlerFactory(node, ctx);
171
- return { status: statusOverride ?? 'SUCCESS' };
172
- }),
173
- };
174
- }
175
- /** Build a mock TypedEventBus that captures all emitted events. */
176
- function makeEventBus() {
177
- const nodeStartedIds = [];
178
- const bus = {
179
- emit: vi.fn().mockImplementation((event, payload) => {
180
- if (event === 'graph:node-started') {
181
- nodeStartedIds.push(payload.nodeId);
182
- }
183
- }),
184
- on: vi.fn(),
185
- off: vi.fn(),
186
- };
187
- return { bus, nodeStartedIds: () => [...nodeStartedIds] };
188
- }
189
- // ---------------------------------------------------------------------------
190
- // Task 2: Edge selection compliance — spec Section 3.3
191
- // ---------------------------------------------------------------------------
192
- describe('selectEdge compliance — spec Section 3.3', () => {
193
- // Step 1: Condition-matched edges beat weight
194
- it('AC1 — Step 1: condition match returns conditional edge over high-weight unconditional', async () => {
195
- const node = makeNode('origin');
196
- const condEdge = makeEdge('origin', 'dest-conditional', { condition: 'outcome=success', weight: 0 });
197
- const unconEdge = makeEdge('origin', 'dest-unconditional', { weight: 10 });
198
- const graph = makeGraph([node], [condEdge, unconEdge]);
199
- const ctx = new GraphContext({ outcome: 'success' });
200
- const outcome = { status: 'SUCCESS' };
201
- const selected = await selectEdge(node, outcome, ctx, graph);
202
- expect(selected).toBe(condEdge);
203
- });
204
- it('AC1 variant — Step 1: no condition match falls through to Step 4 (weight)', async () => {
205
- const node = makeNode('origin');
206
- const condEdge = makeEdge('origin', 'dest-conditional', { condition: 'outcome=success', weight: 0 });
207
- const unconEdge = makeEdge('origin', 'dest-unconditional', { weight: 10 });
208
- const graph = makeGraph([node], [condEdge, unconEdge]);
209
- const ctx = new GraphContext({ outcome: 'failure' });
210
- const outcome = { status: 'SUCCESS' };
211
- const selected = await selectEdge(node, outcome, ctx, graph);
212
- expect(selected).toBe(unconEdge);
213
- });
214
- // Step 2: Preferred label with accelerator prefix stripping
215
- it('AC2 — Step 2: [Y] prefix stripped, label matches preferredLabel "yes"', async () => {
216
- const node = makeNode('origin');
217
- const yesEdge = makeEdge('origin', 'yes-target', { label: '[Y] Yes' });
218
- const noEdge = makeEdge('origin', 'no-target', { label: 'No' });
219
- const graph = makeGraph([node], [yesEdge, noEdge]);
220
- const ctx = new GraphContext();
221
- const outcome = { status: 'SUCCESS', preferredLabel: 'yes' };
222
- const selected = await selectEdge(node, outcome, ctx, graph);
223
- expect(selected).toBe(yesEdge);
224
- });
225
- it('AC2 variant — Step 2: Y) prefix stripped, label matches preferredLabel "confirm"', async () => {
226
- const node = makeNode('origin');
227
- const confirmEdge = makeEdge('origin', 'confirm-target', { label: 'Y) Confirm' });
228
- const otherEdge = makeEdge('origin', 'other-target', { label: 'Cancel' });
229
- const graph = makeGraph([node], [confirmEdge, otherEdge]);
230
- const ctx = new GraphContext();
231
- const outcome = { status: 'SUCCESS', preferredLabel: 'confirm' };
232
- const selected = await selectEdge(node, outcome, ctx, graph);
233
- expect(selected).toBe(confirmEdge);
234
- });
235
- // Step 3: Suggested next IDs
236
- it('Step 3: suggestedNextIds matches edge target', async () => {
237
- const node = makeNode('origin');
238
- const edgeA = makeEdge('origin', 'a');
239
- const edgeB = makeEdge('origin', 'b');
240
- const edgeC = makeEdge('origin', 'c');
241
- const graph = makeGraph([node], [edgeA, edgeB, edgeC]);
242
- const ctx = new GraphContext();
243
- const outcome = { status: 'SUCCESS', suggestedNextIds: ['b'] };
244
- const selected = await selectEdge(node, outcome, ctx, graph);
245
- expect(selected).toBe(edgeB);
246
- });
247
- // Steps 4 & 5: Weight with lexical tiebreak
248
- it('AC3 — Steps 4&5: weight 5 tie between charlie and alpha → lexically-first alpha wins', async () => {
249
- const node = makeNode('origin');
250
- const charlieEdge = makeEdge('origin', 'charlie', { weight: 5 });
251
- const alphaEdge = makeEdge('origin', 'alpha', { weight: 5 });
252
- const bravoEdge = makeEdge('origin', 'bravo', { weight: 3 });
253
- const graph = makeGraph([node], [charlieEdge, alphaEdge, bravoEdge]);
254
- const ctx = new GraphContext();
255
- const outcome = { status: 'SUCCESS' };
256
- const selected = await selectEdge(node, outcome, ctx, graph);
257
- expect(selected).toBe(alphaEdge);
258
- expect(selected?.toNode).toBe('alpha');
259
- });
260
- // Empty edges
261
- it('empty edges: no outgoing edges → returns null', async () => {
262
- const node = makeNode('origin');
263
- const graph = makeGraph([node], []);
264
- const ctx = new GraphContext();
265
- const outcome = { status: 'SUCCESS' };
266
- const selected = await selectEdge(node, outcome, ctx, graph);
267
- expect(selected).toBeNull();
268
- });
269
- });
270
- // ---------------------------------------------------------------------------
271
- // Task 3: Goal gate compliance — spec Section 3.4
272
- // ---------------------------------------------------------------------------
273
- describe('evaluateGates compliance — spec Section 3.4', () => {
274
- it('SUCCESS satisfies a goalGate=true node', () => {
275
- const controller = createConvergenceController();
276
- controller.recordOutcome('nodeA', 'SUCCESS');
277
- const graph = makeGraph([makeNode('nodeA', { goalGate: true })], []);
278
- const result = controller.evaluateGates(graph);
279
- expect(result).toEqual({ satisfied: true, failingNodes: [] });
280
- });
281
- it('AC4 — PARTIAL_SUCCESS satisfies a goalGate=true node (spec Section 3.4)', () => {
282
- const controller = createConvergenceController();
283
- controller.recordOutcome('nodeA', 'PARTIAL_SUCCESS');
284
- const graph = makeGraph([makeNode('nodeA', { goalGate: true })], []);
285
- const result = controller.evaluateGates(graph);
286
- expect(result).toEqual({ satisfied: true, failingNodes: [] });
287
- });
288
- it('AC4 — FAILURE does not satisfy goalGate=true node, appears in failingNodes', () => {
289
- const controller = createConvergenceController();
290
- controller.recordOutcome('nodeA', 'FAILURE');
291
- const graph = makeGraph([makeNode('nodeA', { goalGate: true })], []);
292
- const result = controller.evaluateGates(graph);
293
- expect(result.satisfied).toBe(false);
294
- expect(result.failingNodes).toContain('nodeA');
295
- });
296
- it('AC4 — Unrecorded outcome (never executed) fails gate', () => {
297
- const controller = createConvergenceController();
298
- // nodeA has no recorded outcome
299
- const graph = makeGraph([makeNode('nodeA', { goalGate: true })], []);
300
- const result = controller.evaluateGates(graph);
301
- expect(result.satisfied).toBe(false);
302
- expect(result.failingNodes).toContain('nodeA');
303
- });
304
- it('AC4 — PARTIAL_SUCCESS satisfies; FAILURE and unrecorded both fail', () => {
305
- const controller = createConvergenceController();
306
- controller.recordOutcome('partial', 'PARTIAL_SUCCESS');
307
- controller.recordOutcome('failing', 'FAILURE');
308
- // 'unrecorded' has no recorded outcome
309
- const graph = makeGraph([
310
- makeNode('partial', { goalGate: true }),
311
- makeNode('failing', { goalGate: true }),
312
- makeNode('unrecorded', { goalGate: true }),
313
- ], []);
314
- const result = controller.evaluateGates(graph);
315
- expect(result.satisfied).toBe(false);
316
- expect(result.failingNodes).toContain('failing');
317
- expect(result.failingNodes).toContain('unrecorded');
318
- expect(result.failingNodes).not.toContain('partial');
319
- });
320
- it('mixed SUCCESS + PARTIAL_SUCCESS: both satisfied → { satisfied: true, failingNodes: [] }', () => {
321
- const controller = createConvergenceController();
322
- controller.recordOutcome('nodeA', 'SUCCESS');
323
- controller.recordOutcome('nodeB', 'PARTIAL_SUCCESS');
324
- const graph = makeGraph([makeNode('nodeA', { goalGate: true }), makeNode('nodeB', { goalGate: true })], []);
325
- const result = controller.evaluateGates(graph);
326
- expect(result).toEqual({ satisfied: true, failingNodes: [] });
327
- });
328
- it('mixed SUCCESS + FAILURE: only failing node in failingNodes', () => {
329
- const controller = createConvergenceController();
330
- controller.recordOutcome('nodeA', 'SUCCESS');
331
- controller.recordOutcome('nodeB', 'FAILURE');
332
- const graph = makeGraph([makeNode('nodeA', { goalGate: true }), makeNode('nodeB', { goalGate: true })], []);
333
- const result = controller.evaluateGates(graph);
334
- expect(result.satisfied).toBe(false);
335
- expect(result.failingNodes).toEqual(['nodeB']);
336
- expect(result.failingNodes).not.toContain('nodeA');
337
- });
338
- it('no goalGate=true nodes: vacuously satisfied', () => {
339
- const controller = createConvergenceController();
340
- const graph = makeGraph([makeNode('nodeA', { goalGate: false }), makeNode('nodeB', { goalGate: false })], []);
341
- const result = controller.evaluateGates(graph);
342
- expect(result).toEqual({ satisfied: true, failingNodes: [] });
343
- });
344
- });
345
- // ---------------------------------------------------------------------------
346
- // Task 4: Checkpoint resume compliance — spec Section 5.3
347
- // ---------------------------------------------------------------------------
348
- describe('checkpoint resume compliance — spec Section 5.3', () => {
349
- let tmpDir;
350
- beforeEach(async () => {
351
- tmpDir = path.join(os.tmpdir(), `attractor-compliance-${crypto.randomUUID()}`);
352
- await mkdir(tmpDir, { recursive: true });
353
- });
354
- afterEach(async () => {
355
- await rm(tmpDir, { recursive: true, force: true });
356
- });
357
- it('AC5 — completed nodes are skipped and context is restored on resume', async () => {
358
- // Write seed checkpoint using CheckpointManager.save()
359
- const checkpointManager = new CheckpointManager();
360
- const seedContext = new GraphContext({ result: 'ok', attempt: '3' });
361
- await checkpointManager.save(tmpDir, {
362
- currentNode: 'node1',
363
- completedNodes: ['start', 'node1'],
364
- nodeRetries: {},
365
- context: seedContext,
366
- });
367
- // Parse and validate the compliance resume graph
368
- const graph = parseGraph(COMPLIANCE_RESUME_DOT);
369
- const validator = createValidator();
370
- const validationErrors = validator.validate(graph).filter((d) => d.severity === 'error');
371
- expect(validationErrors).toHaveLength(0);
372
- // Track graph:node-started events and captured contexts per node
373
- const { bus, nodeStartedIds } = makeEventBus();
374
- const capturedContextByNode = {};
375
- const registry = makeRegistry((node, ctx) => {
376
- capturedContextByNode[node.id] = ctx;
377
- });
378
- const executor = createGraphExecutor();
379
- const config = {
380
- runId: 'compliance-resume-test',
381
- logsRoot: tmpDir,
382
- handlerRegistry: registry,
383
- eventBus: bus,
384
- checkpointPath: path.join(tmpDir, 'checkpoint.json'),
385
- };
386
- const finalOutcome = await executor.run(graph, config);
387
- // graph:node-started must NOT include 'start' or 'node1' (skipped)
388
- expect(nodeStartedIds()).not.toContain('start');
389
- expect(nodeStartedIds()).not.toContain('node1');
390
- // graph:node-started MUST include 'node2' and 'exit' is never dispatched (exit check)
391
- expect(nodeStartedIds()).toContain('node2');
392
- // Context is restored: node2 handler receives context seeded from checkpoint
393
- expect(capturedContextByNode['node2']).toBeDefined();
394
- expect(capturedContextByNode['node2'].getString('result')).toBe('ok');
395
- expect(capturedContextByNode['node2'].getString('attempt')).toBe('3');
396
- // Final outcome is SUCCESS
397
- expect(finalOutcome.status).toBe('SUCCESS');
398
- });
399
- });
400
- // ---------------------------------------------------------------------------
401
- // Task 5: Fidelity degradation on resume — spec Section 5.3 step 6
402
- // ---------------------------------------------------------------------------
403
- describe('fidelity degradation on resume — spec Section 5.3 step 6', () => {
404
- let tmpDir;
405
- beforeEach(async () => {
406
- tmpDir = path.join(os.tmpdir(), `attractor-fidelity-${crypto.randomUUID()}`);
407
- await mkdir(tmpDir, { recursive: true });
408
- });
409
- afterEach(async () => {
410
- await rm(tmpDir, { recursive: true, force: true });
411
- });
412
- it('first resumed node gets fidelity="summary:high" when last completed node had fidelity="full"', async () => {
413
- // Write seed checkpoint: node1 (which has fidelity=full in the DOT) is the last completed node
414
- const checkpointManager = new CheckpointManager();
415
- const seedContext = new GraphContext({ result: 'ok' });
416
- await checkpointManager.save(tmpDir, {
417
- currentNode: 'node1',
418
- completedNodes: ['start', 'node1'],
419
- nodeRetries: {},
420
- context: seedContext,
421
- });
422
- // Parse graph where node1 has fidelity=full
423
- const graph = parseGraph(COMPLIANCE_FIDELITY_RESUME_DOT);
424
- // Capture the node argument passed to each handler dispatch
425
- const capturedNodeByNodeId = {};
426
- const registry = makeRegistry((node) => {
427
- capturedNodeByNodeId[node.id] = node;
428
- });
429
- const { bus } = makeEventBus();
430
- const config = {
431
- runId: 'compliance-fidelity-test',
432
- logsRoot: tmpDir,
433
- handlerRegistry: registry,
434
- eventBus: bus,
435
- checkpointPath: path.join(tmpDir, 'checkpoint.json'),
436
- };
437
- await createGraphExecutor().run(graph, config);
438
- // node2 is the first resumed node; its fidelity should be degraded to 'summary:high'
439
- expect(capturedNodeByNodeId['node2']).toBeDefined();
440
- expect(capturedNodeByNodeId['node2'].fidelity).toBe('summary:high');
441
- });
442
- it('subsequent resumed nodes use their configured fidelity (not the degraded value)', async () => {
443
- // Extend the graph by adding node3 after node2
444
- const EXTENDED_DOT = `
445
- digraph compliance_fidelity_extended {
446
- graph [goal="Extended fidelity test"]
447
- start [shape=Mdiamond]
448
- node1 [type=codergen, prompt="Step 1", fidelity=full]
449
- node2 [type=codergen, prompt="Step 2", fidelity=medium]
450
- node3 [type=codergen, prompt="Step 3", fidelity=high]
451
- exit [shape=Msquare]
452
-
453
- start -> node1
454
- node1 -> node2
455
- node2 -> node3
456
- node3 -> exit
457
- }
458
- `;
459
- const checkpointManager = new CheckpointManager();
460
- const seedCtx = new GraphContext();
461
- await checkpointManager.save(tmpDir, {
462
- currentNode: 'node1',
463
- completedNodes: ['start', 'node1'],
464
- nodeRetries: {},
465
- context: seedCtx,
466
- });
467
- const graph = parseGraph(EXTENDED_DOT);
468
- const capturedNodeByNodeId = {};
469
- const registry = makeRegistry((node) => {
470
- capturedNodeByNodeId[node.id] = node;
471
- });
472
- const { bus } = makeEventBus();
473
- const config = {
474
- runId: 'compliance-fidelity-extended-test',
475
- logsRoot: tmpDir,
476
- handlerRegistry: registry,
477
- eventBus: bus,
478
- checkpointPath: path.join(tmpDir, 'checkpoint.json'),
479
- };
480
- await createGraphExecutor().run(graph, config);
481
- // node2 is first resumed → degraded to 'summary:high'
482
- expect(capturedNodeByNodeId['node2'].fidelity).toBe('summary:high');
483
- // node3 is subsequent → uses its configured fidelity='high'
484
- expect(capturedNodeByNodeId['node3'].fidelity).toBe('high');
485
- });
486
- });
487
- // ---------------------------------------------------------------------------
488
- // Task 6: Structural conformance — AttractorBench parity
489
- // ---------------------------------------------------------------------------
490
- describe('structural conformance — AttractorBench parity', () => {
491
- // AttractorBench structural conformance parity — Phase A mandatory
492
- // See: https://github.com/strongdm/attractorbench
493
- // Behavioral conformance tests are advisory in Phase A; required by Phase B exit.
494
- // -------------------------------------------------------------------------
495
- // Attribute coverage — nodes (all 17 spec-defined + toolCommand from 42-11 + backend from 48-10)
496
- // -------------------------------------------------------------------------
497
- it('AC6 — all node attributes extracted with correct values from DOT', () => {
498
- const dot = `
499
- digraph compliance_node_attrs {
500
- graph [goal="Attribute coverage"]
501
- start [shape=Mdiamond]
502
- target [
503
- shape=box,
504
- type=codergen,
505
- label="Target Label",
506
- prompt="Target prompt",
507
- max_retries=3,
508
- goal_gate=true,
509
- retry_target="start",
510
- fallback_retry_target="start",
511
- fidelity=high,
512
- thread_id="thread-1",
513
- class="myclass",
514
- timeout=30,
515
- llm_model="gpt-4o",
516
- llm_provider=openai,
517
- reasoning_effort=high,
518
- auto_status=false,
519
- allow_partial=true,
520
- tool_command="echo hello",
521
- backend=direct
522
- ]
523
- exit [shape=Msquare]
524
- start -> target
525
- target -> exit
526
- }
527
- `;
528
- const graph = parseGraph(dot);
529
- const node = graph.nodes.get('target');
530
- expect(node).toBeDefined();
531
- expect(node.id).toBe('target');
532
- expect(node.label).toBe('Target Label');
533
- expect(node.shape).toBe('box');
534
- expect(node.type).toBe('codergen');
535
- expect(node.prompt).toBe('Target prompt');
536
- expect(node.maxRetries).toBe(3);
537
- expect(node.goalGate).toBe(true);
538
- expect(node.retryTarget).toBe('start');
539
- expect(node.fallbackRetryTarget).toBe('start');
540
- expect(node.fidelity).toBe('high');
541
- expect(node.threadId).toBe('thread-1');
542
- expect(node.class).toBe('myclass');
543
- expect(node.timeout).toBe(30);
544
- expect(node.llmModel).toBe('gpt-4o');
545
- expect(node.llmProvider).toBe('openai');
546
- expect(node.reasoningEffort).toBe('high');
547
- expect(node.autoStatus).toBe(false);
548
- expect(node.allowPartial).toBe(true);
549
- expect(node.toolCommand).toBe('echo hello');
550
- expect(node.backend).toBe('direct');
551
- });
552
- // -------------------------------------------------------------------------
553
- // Attribute coverage — edges (all 6 edge attributes)
554
- // -------------------------------------------------------------------------
555
- it('AC6 — all 6 edge attributes extracted with correct values from DOT', () => {
556
- const dot = `
557
- digraph compliance_edge_attrs {
558
- graph [goal="Edge attribute coverage"]
559
- start [shape=Mdiamond]
560
- nodeA [type=codergen, prompt="a"]
561
- exit [shape=Msquare]
562
- start -> nodeA [
563
- label="go",
564
- condition="outcome=success",
565
- weight=5,
566
- fidelity=high,
567
- thread_id="t2",
568
- loop_restart=true
569
- ]
570
- nodeA -> exit
571
- }
572
- `;
573
- const graph = parseGraph(dot);
574
- const edge = graph.edges.find((e) => e.fromNode === 'start' && e.toNode === 'nodeA');
575
- expect(edge).toBeDefined();
576
- expect(edge.label).toBe('go');
577
- expect(edge.condition).toBe('outcome=success');
578
- expect(edge.weight).toBe(5);
579
- expect(edge.fidelity).toBe('high');
580
- expect(edge.threadId).toBe('t2');
581
- expect(edge.loopRestart).toBe(true);
582
- });
583
- // -------------------------------------------------------------------------
584
- // Lint rule coverage — 8 error-level rules (stories 42-4)
585
- // -------------------------------------------------------------------------
586
- it('AC6 — lint rule "start_node" fires (severity=error) when no start node exists', () => {
587
- // Graph with no Mdiamond node and no id=start/Start
588
- const graph = makeLintGraph([{ id: 'work', type: 'codergen', prompt: 'work' }], [{ fromNode: 'work', toNode: 'exit' }]);
589
- // Override the nodes map to remove start (the makeLintGraph adds start by default — use manual build)
590
- const nodeMap = new Map();
591
- nodeMap.set('work', makeNode('work', { type: 'codergen', prompt: 'work' }));
592
- nodeMap.set('exit', makeNode('exit', { shape: 'Msquare', type: '' }));
593
- const edges = [makeEdge('work', 'exit')];
594
- const g = {
595
- id: 'test', goal: '', label: '', modelStylesheet: '',
596
- defaultMaxRetries: 0, retryTarget: '', fallbackRetryTarget: '', defaultFidelity: '',
597
- nodes: nodeMap,
598
- edges,
599
- outgoingEdges: (id) => edges.filter((e) => e.fromNode === id),
600
- startNode: () => { throw new Error('no start'); },
601
- exitNode: () => nodeMap.get('exit'),
602
- };
603
- const diags = createValidator().validate(g);
604
- const rule = diags.find((d) => d.ruleId === 'start_node');
605
- expect(rule).toBeDefined();
606
- expect(rule.severity).toBe('error');
607
- });
608
- it('AC6 — lint rule "terminal_node" fires (severity=error) when no exit node exists', () => {
609
- const nodeMap = new Map();
610
- nodeMap.set('start', makeNode('start', { shape: 'Mdiamond', type: '' }));
611
- nodeMap.set('work', makeNode('work', { type: 'codergen', prompt: 'work' }));
612
- const edges = [makeEdge('start', 'work')];
613
- const g = {
614
- id: 'test', goal: '', label: '', modelStylesheet: '',
615
- defaultMaxRetries: 0, retryTarget: '', fallbackRetryTarget: '', defaultFidelity: '',
616
- nodes: nodeMap,
617
- edges,
618
- outgoingEdges: (id) => edges.filter((e) => e.fromNode === id),
619
- startNode: () => nodeMap.get('start'),
620
- exitNode: () => { throw new Error('no exit'); },
621
- };
622
- const diags = createValidator().validate(g);
623
- const rule = diags.find((d) => d.ruleId === 'terminal_node');
624
- expect(rule).toBeDefined();
625
- expect(rule.severity).toBe('error');
626
- });
627
- it('AC6 — lint rule "start_no_incoming" fires (severity=error) when edge targets the start node', () => {
628
- const graph = makeLintGraph([{ id: 'work', type: 'codergen', prompt: 'work' }], [
629
- { fromNode: 'start', toNode: 'work' },
630
- { fromNode: 'work', toNode: 'exit' },
631
- { fromNode: 'work', toNode: 'start' }, // incoming edge to start
632
- ]);
633
- const diags = createValidator().validate(graph);
634
- const rule = diags.find((d) => d.ruleId === 'start_no_incoming');
635
- expect(rule).toBeDefined();
636
- expect(rule.severity).toBe('error');
637
- });
638
- it('AC6 — lint rule "exit_no_outgoing" fires (severity=error) when exit node has an outgoing edge', () => {
639
- const graph = makeLintGraph([{ id: 'work', type: 'codergen', prompt: 'work' }], [
640
- { fromNode: 'start', toNode: 'work' },
641
- { fromNode: 'work', toNode: 'exit' },
642
- { fromNode: 'exit', toNode: 'work' }, // outgoing edge from exit
643
- ]);
644
- const diags = createValidator().validate(graph);
645
- const rule = diags.find((d) => d.ruleId === 'exit_no_outgoing');
646
- expect(rule).toBeDefined();
647
- expect(rule.severity).toBe('error');
648
- });
649
- it('AC6 — lint rule "edge_target_exists" fires (severity=error) when edge targets non-existent node', () => {
650
- // Build graph directly — DOT auto-creates referenced nodes, so we use in-memory construction
651
- const nodeMap = new Map();
652
- nodeMap.set('start', makeNode('start', { shape: 'Mdiamond', type: '' }));
653
- nodeMap.set('work', makeNode('work', { type: 'codergen', prompt: 'work' }));
654
- nodeMap.set('exit', makeNode('exit', { shape: 'Msquare', type: '' }));
655
- const edges = [
656
- makeEdge('start', 'work'),
657
- makeEdge('work', 'exit'),
658
- makeEdge('work', 'ghost_node'), // ghost_node does NOT exist in nodeMap
659
- ];
660
- const g = {
661
- id: 'test', goal: '', label: '', modelStylesheet: '',
662
- defaultMaxRetries: 0, retryTarget: '', fallbackRetryTarget: '', defaultFidelity: '',
663
- nodes: nodeMap,
664
- edges,
665
- outgoingEdges: (id) => edges.filter((e) => e.fromNode === id),
666
- startNode: () => nodeMap.get('start'),
667
- exitNode: () => nodeMap.get('exit'),
668
- };
669
- const diags = createValidator().validate(g);
670
- const rule = diags.find((d) => d.ruleId === 'edge_target_exists');
671
- expect(rule).toBeDefined();
672
- expect(rule.severity).toBe('error');
673
- });
674
- it('AC6 — lint rule "reachability" fires (severity=error) when a node is unreachable', () => {
675
- const graph = makeLintGraph([
676
- { id: 'work', type: 'codergen', prompt: 'work' },
677
- { id: 'unreachable', type: 'codergen', prompt: 'unreachable' },
678
- ], [
679
- { fromNode: 'start', toNode: 'work' },
680
- { fromNode: 'work', toNode: 'exit' },
681
- // 'unreachable' has no incoming edges from start
682
- ]);
683
- const diags = createValidator().validate(graph);
684
- const rule = diags.find((d) => d.ruleId === 'reachability');
685
- expect(rule).toBeDefined();
686
- expect(rule.severity).toBe('error');
687
- });
688
- it('AC6 — lint rule "condition_syntax" fires (severity=error) for invalid condition expression', () => {
689
- const graph = makeLintGraph([{ id: 'work', type: 'codergen', prompt: 'work' }], [
690
- { fromNode: 'start', toNode: 'work' },
691
- { fromNode: 'work', toNode: 'exit', condition: 'a==b' }, // double-equals is invalid
692
- ]);
693
- const diags = createValidator().validate(graph);
694
- const rule = diags.find((d) => d.ruleId === 'condition_syntax');
695
- expect(rule).toBeDefined();
696
- expect(rule.severity).toBe('error');
697
- });
698
- it('AC6 — lint rule "stylesheet_syntax" fires (severity=error) for invalid stylesheet content', () => {
699
- // Build graph with invalid inline stylesheet
700
- const graph = makeLintGraph([{ id: 'work', type: 'codergen', prompt: 'work' }], [{ fromNode: 'start', toNode: 'work' }, { fromNode: 'work', toNode: 'exit' }], { modelStylesheet: '!!! invalid stylesheet content !!!' });
701
- const diags = createValidator().validate(graph);
702
- const rule = diags.find((d) => d.ruleId === 'stylesheet_syntax');
703
- expect(rule).toBeDefined();
704
- expect(rule.severity).toBe('error');
705
- });
706
- // -------------------------------------------------------------------------
707
- // Lint rule coverage — 5 warning-level rules (stories 42-5)
708
- // -------------------------------------------------------------------------
709
- it('AC6 — lint rule "type_known" fires (severity=warning) for unknown node type', () => {
710
- const graph = makeLintGraph([{ id: 'work', type: 'wizard_type', prompt: 'work' }], // wizard_type is unknown
711
- [{ fromNode: 'start', toNode: 'work' }, { fromNode: 'work', toNode: 'exit' }]);
712
- const diags = createValidator().validate(graph);
713
- const rule = diags.find((d) => d.ruleId === 'type_known');
714
- expect(rule).toBeDefined();
715
- expect(rule.severity).toBe('warning');
716
- });
717
- it('AC6 — lint rule "fidelity_valid" fires (severity=warning) for invalid fidelity value', () => {
718
- const graph = makeLintGraph([{ id: 'work', type: 'codergen', prompt: 'work', fidelity: 'ultra_high' }], // invalid fidelity
719
- [{ fromNode: 'start', toNode: 'work' }, { fromNode: 'work', toNode: 'exit' }]);
720
- const diags = createValidator().validate(graph);
721
- const rule = diags.find((d) => d.ruleId === 'fidelity_valid');
722
- expect(rule).toBeDefined();
723
- expect(rule.severity).toBe('warning');
724
- });
725
- it('AC6 — lint rule "retry_target_exists" fires (severity=warning) for missing retryTarget node', () => {
726
- const graph = makeLintGraph([{ id: 'work', type: 'codergen', prompt: 'work', retryTarget: 'nonexistent' }], [{ fromNode: 'start', toNode: 'work' }, { fromNode: 'work', toNode: 'exit' }]);
727
- const diags = createValidator().validate(graph);
728
- const rule = diags.find((d) => d.ruleId === 'retry_target_exists');
729
- expect(rule).toBeDefined();
730
- expect(rule.severity).toBe('warning');
731
- });
732
- it('AC6 — lint rule "goal_gate_has_retry" fires (severity=warning) when goalGate=true node has no retryTarget', () => {
733
- const graph = makeLintGraph([{ id: 'work', type: 'codergen', prompt: 'work', goalGate: true, retryTarget: '' }], [{ fromNode: 'start', toNode: 'work' }, { fromNode: 'work', toNode: 'exit' }]);
734
- const diags = createValidator().validate(graph);
735
- const rule = diags.find((d) => d.ruleId === 'goal_gate_has_retry');
736
- expect(rule).toBeDefined();
737
- expect(rule.severity).toBe('warning');
738
- });
739
- it('AC6 — lint rule "prompt_on_llm_nodes" fires (severity=warning) for codergen node with no prompt or label', () => {
740
- const graph = makeLintGraph([{ id: 'work', type: 'codergen', prompt: '', label: '' }], // no prompt AND no label
741
- [{ fromNode: 'start', toNode: 'work' }, { fromNode: 'work', toNode: 'exit' }]);
742
- const diags = createValidator().validate(graph);
743
- const rule = diags.find((d) => d.ruleId === 'prompt_on_llm_nodes');
744
- expect(rule).toBeDefined();
745
- expect(rule.severity).toBe('warning');
746
- });
747
- // -------------------------------------------------------------------------
748
- // Edge selection determinism — identical inputs always produce same output
749
- // -------------------------------------------------------------------------
750
- it('AC6 — selectEdge is deterministic: identical inputs always produce same edge', async () => {
751
- const node = makeNode('origin');
752
- const edgeA = makeEdge('origin', 'alpha', { weight: 5 });
753
- const edgeB = makeEdge('origin', 'bravo', { weight: 5 });
754
- const edgeC = makeEdge('origin', 'charlie', { weight: 3 });
755
- const graph = makeGraph([node], [edgeA, edgeB, edgeC]);
756
- const ctx = new GraphContext({ x: '1' });
757
- const outcome = { status: 'SUCCESS' };
758
- const first = await selectEdge(node, outcome, ctx, graph);
759
- const second = await selectEdge(node, outcome, ctx, graph);
760
- const third = await selectEdge(node, outcome, ctx, graph);
761
- expect(first?.toNode).toBe(second?.toNode);
762
- expect(second?.toNode).toBe(third?.toNode);
763
- expect(first?.toNode).toBe('alpha'); // lexically first among weight-5 ties
764
- });
765
- });
766
- //# sourceMappingURL=attractor-compliance.test.js.map