@soleri/core 9.0.3 → 9.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 (701) hide show
  1. package/dist/brain/intelligence.d.ts +27 -0
  2. package/dist/brain/intelligence.d.ts.map +1 -1
  3. package/dist/brain/intelligence.js +160 -14
  4. package/dist/brain/intelligence.js.map +1 -1
  5. package/dist/brain/learning-radar.d.ts +4 -0
  6. package/dist/brain/learning-radar.d.ts.map +1 -1
  7. package/dist/brain/learning-radar.js +20 -1
  8. package/dist/brain/learning-radar.js.map +1 -1
  9. package/dist/brain/strength-scorer.d.ts +31 -0
  10. package/dist/brain/strength-scorer.d.ts.map +1 -0
  11. package/dist/brain/strength-scorer.js +264 -0
  12. package/dist/brain/strength-scorer.js.map +1 -0
  13. package/dist/chat/agent-loop.d.ts.map +1 -1
  14. package/dist/chat/agent-loop.js +2 -0
  15. package/dist/chat/agent-loop.js.map +1 -1
  16. package/dist/chat/notifications.d.ts.map +1 -1
  17. package/dist/chat/notifications.js +2 -0
  18. package/dist/chat/notifications.js.map +1 -1
  19. package/dist/claudemd/compose.js +1 -1
  20. package/dist/claudemd/compose.js.map +1 -1
  21. package/dist/control/intent-router.d.ts.map +1 -1
  22. package/dist/control/intent-router.js +12 -4
  23. package/dist/control/intent-router.js.map +1 -1
  24. package/dist/curator/contradiction-detector.d.ts +27 -0
  25. package/dist/curator/contradiction-detector.d.ts.map +1 -0
  26. package/dist/curator/contradiction-detector.js +62 -0
  27. package/dist/curator/contradiction-detector.js.map +1 -0
  28. package/dist/curator/curator.d.ts +3 -4
  29. package/dist/curator/curator.d.ts.map +1 -1
  30. package/dist/curator/curator.js +90 -525
  31. package/dist/curator/curator.js.map +1 -1
  32. package/dist/curator/duplicate-detector.d.ts +14 -0
  33. package/dist/curator/duplicate-detector.d.ts.map +1 -0
  34. package/dist/curator/duplicate-detector.js +77 -0
  35. package/dist/curator/duplicate-detector.js.map +1 -0
  36. package/dist/curator/health-audit.d.ts +15 -0
  37. package/dist/curator/health-audit.d.ts.map +1 -0
  38. package/dist/curator/health-audit.js +97 -0
  39. package/dist/curator/health-audit.js.map +1 -0
  40. package/dist/curator/metadata-enricher.d.ts +17 -0
  41. package/dist/curator/metadata-enricher.d.ts.map +1 -0
  42. package/dist/curator/metadata-enricher.js +60 -0
  43. package/dist/curator/metadata-enricher.js.map +1 -0
  44. package/dist/curator/schema.d.ts +7 -0
  45. package/dist/curator/schema.d.ts.map +1 -0
  46. package/dist/curator/schema.js +62 -0
  47. package/dist/curator/schema.js.map +1 -0
  48. package/dist/curator/tag-manager.d.ts +36 -0
  49. package/dist/curator/tag-manager.d.ts.map +1 -0
  50. package/dist/curator/tag-manager.js +78 -0
  51. package/dist/curator/tag-manager.js.map +1 -0
  52. package/dist/engine/bin/soleri-engine.js +55 -3
  53. package/dist/engine/bin/soleri-engine.js.map +1 -1
  54. package/dist/engine/core-ops.d.ts.map +1 -1
  55. package/dist/engine/core-ops.js +33 -10
  56. package/dist/engine/core-ops.js.map +1 -1
  57. package/dist/engine/module-manifest.d.ts.map +1 -1
  58. package/dist/engine/module-manifest.js +22 -2
  59. package/dist/engine/module-manifest.js.map +1 -1
  60. package/dist/engine/register-engine.d.ts.map +1 -1
  61. package/dist/engine/register-engine.js +26 -2
  62. package/dist/engine/register-engine.js.map +1 -1
  63. package/dist/errors/retry.d.ts.map +1 -1
  64. package/dist/errors/retry.js +2 -0
  65. package/dist/errors/retry.js.map +1 -1
  66. package/dist/facades/types.d.ts +1 -1
  67. package/dist/flows/chain-types.d.ts +18 -18
  68. package/dist/flows/gate-evaluator.d.ts.map +1 -1
  69. package/dist/flows/gate-evaluator.js +22 -0
  70. package/dist/flows/gate-evaluator.js.map +1 -1
  71. package/dist/flows/types.d.ts +157 -28
  72. package/dist/flows/types.d.ts.map +1 -1
  73. package/dist/flows/types.js +4 -0
  74. package/dist/flows/types.js.map +1 -1
  75. package/dist/index.d.ts +10 -2
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +9 -1
  78. package/dist/index.js.map +1 -1
  79. package/dist/intake/intake-pipeline.d.ts.map +1 -1
  80. package/dist/intake/intake-pipeline.js +1 -0
  81. package/dist/intake/intake-pipeline.js.map +1 -1
  82. package/dist/intake/text-ingester.d.ts.map +1 -1
  83. package/dist/intake/text-ingester.js +2 -0
  84. package/dist/intake/text-ingester.js.map +1 -1
  85. package/dist/llm/key-pool.d.ts +1 -1
  86. package/dist/llm/key-pool.d.ts.map +1 -1
  87. package/dist/llm/key-pool.js +3 -4
  88. package/dist/llm/key-pool.js.map +1 -1
  89. package/dist/llm/utils.d.ts.map +1 -1
  90. package/dist/llm/utils.js +2 -0
  91. package/dist/llm/utils.js.map +1 -1
  92. package/dist/migrations/migration-runner.test-helpers.d.ts +13 -0
  93. package/dist/migrations/migration-runner.test-helpers.d.ts.map +1 -0
  94. package/dist/migrations/migration-runner.test-helpers.js +47 -0
  95. package/dist/migrations/migration-runner.test-helpers.js.map +1 -0
  96. package/dist/operator/operator-profile.d.ts +44 -0
  97. package/dist/operator/operator-profile.d.ts.map +1 -0
  98. package/dist/operator/operator-profile.js +377 -0
  99. package/dist/operator/operator-profile.js.map +1 -0
  100. package/dist/operator/operator-signals.d.ts +45 -0
  101. package/dist/operator/operator-signals.d.ts.map +1 -0
  102. package/dist/operator/operator-signals.js +228 -0
  103. package/dist/operator/operator-signals.js.map +1 -0
  104. package/dist/operator/operator-types.d.ts +360 -0
  105. package/dist/operator/operator-types.d.ts.map +1 -0
  106. package/dist/operator/operator-types.js +24 -0
  107. package/dist/operator/operator-types.js.map +1 -0
  108. package/dist/packs/types.d.ts +27 -27
  109. package/dist/paths.d.ts +40 -0
  110. package/dist/paths.d.ts.map +1 -0
  111. package/dist/paths.js +98 -0
  112. package/dist/paths.js.map +1 -0
  113. package/dist/persistence/index.d.ts +1 -1
  114. package/dist/persistence/index.d.ts.map +1 -1
  115. package/dist/persistence/index.js +1 -1
  116. package/dist/persistence/index.js.map +1 -1
  117. package/dist/persistence/sqlite-provider.d.ts +2 -0
  118. package/dist/persistence/sqlite-provider.d.ts.map +1 -1
  119. package/dist/persistence/sqlite-provider.js +8 -5
  120. package/dist/persistence/sqlite-provider.js.map +1 -1
  121. package/dist/planning/evidence-collector.d.ts +13 -1
  122. package/dist/planning/evidence-collector.d.ts.map +1 -1
  123. package/dist/planning/evidence-collector.js +33 -0
  124. package/dist/planning/evidence-collector.js.map +1 -1
  125. package/dist/planning/gap-analysis.d.ts +5 -4
  126. package/dist/planning/gap-analysis.d.ts.map +1 -1
  127. package/dist/planning/gap-analysis.js +7 -341
  128. package/dist/planning/gap-analysis.js.map +1 -1
  129. package/dist/planning/gap-passes.d.ts +19 -0
  130. package/dist/planning/gap-passes.d.ts.map +1 -0
  131. package/dist/planning/gap-passes.js +157 -0
  132. package/dist/planning/gap-passes.js.map +1 -0
  133. package/dist/planning/gap-patterns.d.ts +29 -0
  134. package/dist/planning/gap-patterns.d.ts.map +1 -0
  135. package/dist/planning/gap-patterns.js +129 -0
  136. package/dist/planning/gap-patterns.js.map +1 -0
  137. package/dist/planning/gap-types.d.ts +1 -1
  138. package/dist/planning/gap-types.d.ts.map +1 -1
  139. package/dist/planning/gap-types.js +1 -0
  140. package/dist/planning/gap-types.js.map +1 -1
  141. package/dist/planning/github-projection.d.ts +122 -0
  142. package/dist/planning/github-projection.d.ts.map +1 -0
  143. package/dist/planning/github-projection.js +294 -0
  144. package/dist/planning/github-projection.js.map +1 -0
  145. package/dist/planning/impact-analyzer.d.ts +26 -0
  146. package/dist/planning/impact-analyzer.d.ts.map +1 -0
  147. package/dist/planning/impact-analyzer.js +199 -0
  148. package/dist/planning/impact-analyzer.js.map +1 -0
  149. package/dist/planning/plan-lifecycle.d.ts +136 -0
  150. package/dist/planning/plan-lifecycle.d.ts.map +1 -0
  151. package/dist/planning/plan-lifecycle.js +296 -0
  152. package/dist/planning/plan-lifecycle.js.map +1 -0
  153. package/dist/planning/planner-types.d.ts +202 -0
  154. package/dist/planning/planner-types.d.ts.map +1 -0
  155. package/dist/planning/planner-types.js +6 -0
  156. package/dist/planning/planner-types.js.map +1 -0
  157. package/dist/planning/planner.d.ts +31 -383
  158. package/dist/planning/planner.d.ts.map +1 -1
  159. package/dist/planning/planner.js +154 -878
  160. package/dist/planning/planner.js.map +1 -1
  161. package/dist/planning/rationalization-detector.d.ts +32 -0
  162. package/dist/planning/rationalization-detector.d.ts.map +1 -0
  163. package/dist/planning/rationalization-detector.js +89 -0
  164. package/dist/planning/rationalization-detector.js.map +1 -0
  165. package/dist/planning/reconciliation-engine.d.ts +47 -0
  166. package/dist/planning/reconciliation-engine.d.ts.map +1 -0
  167. package/dist/planning/reconciliation-engine.js +128 -0
  168. package/dist/planning/reconciliation-engine.js.map +1 -0
  169. package/dist/planning/task-verifier.d.ts +85 -0
  170. package/dist/planning/task-verifier.d.ts.map +1 -0
  171. package/dist/planning/task-verifier.js +227 -0
  172. package/dist/planning/task-verifier.js.map +1 -0
  173. package/dist/plugins/types.d.ts +4 -4
  174. package/dist/runtime/admin-ops.d.ts +2 -2
  175. package/dist/runtime/admin-ops.d.ts.map +1 -1
  176. package/dist/runtime/admin-ops.js +44 -17
  177. package/dist/runtime/admin-ops.js.map +1 -1
  178. package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
  179. package/dist/runtime/admin-setup-ops.js +21 -46
  180. package/dist/runtime/admin-setup-ops.js.map +1 -1
  181. package/dist/runtime/archive-ops.d.ts +10 -0
  182. package/dist/runtime/archive-ops.d.ts.map +1 -0
  183. package/dist/runtime/archive-ops.js +310 -0
  184. package/dist/runtime/archive-ops.js.map +1 -0
  185. package/dist/runtime/capture-ops.d.ts.map +1 -1
  186. package/dist/runtime/capture-ops.js +42 -7
  187. package/dist/runtime/capture-ops.js.map +1 -1
  188. package/dist/runtime/claude-md-helpers.js +1 -1
  189. package/dist/runtime/claude-md-helpers.js.map +1 -1
  190. package/dist/runtime/context-health.d.ts +31 -0
  191. package/dist/runtime/context-health.d.ts.map +1 -0
  192. package/dist/runtime/context-health.js +57 -0
  193. package/dist/runtime/context-health.js.map +1 -0
  194. package/dist/runtime/facades/archive-facade.d.ts +10 -0
  195. package/dist/runtime/facades/archive-facade.d.ts.map +1 -0
  196. package/dist/runtime/facades/archive-facade.js +11 -0
  197. package/dist/runtime/facades/archive-facade.js.map +1 -0
  198. package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
  199. package/dist/runtime/facades/brain-facade.js +2 -0
  200. package/dist/runtime/facades/brain-facade.js.map +1 -1
  201. package/dist/runtime/facades/chat-facade.d.ts +7 -0
  202. package/dist/runtime/facades/chat-facade.d.ts.map +1 -1
  203. package/dist/runtime/facades/chat-facade.js +15 -800
  204. package/dist/runtime/facades/chat-facade.js.map +1 -1
  205. package/dist/runtime/facades/chat-service-ops.d.ts +9 -0
  206. package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -0
  207. package/dist/runtime/facades/chat-service-ops.js +330 -0
  208. package/dist/runtime/facades/chat-service-ops.js.map +1 -0
  209. package/dist/runtime/facades/chat-session-ops.d.ts +8 -0
  210. package/dist/runtime/facades/chat-session-ops.d.ts.map +1 -0
  211. package/dist/runtime/facades/chat-session-ops.js +136 -0
  212. package/dist/runtime/facades/chat-session-ops.js.map +1 -0
  213. package/dist/runtime/facades/chat-state.d.ts +31 -0
  214. package/dist/runtime/facades/chat-state.d.ts.map +1 -0
  215. package/dist/runtime/facades/chat-state.js +32 -0
  216. package/dist/runtime/facades/chat-state.js.map +1 -0
  217. package/dist/runtime/facades/chat-transport-ops.d.ts +9 -0
  218. package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -0
  219. package/dist/runtime/facades/chat-transport-ops.js +337 -0
  220. package/dist/runtime/facades/chat-transport-ops.js.map +1 -0
  221. package/dist/runtime/facades/control-facade.d.ts.map +1 -1
  222. package/dist/runtime/facades/control-facade.js +4 -1
  223. package/dist/runtime/facades/control-facade.js.map +1 -1
  224. package/dist/runtime/facades/index.d.ts.map +1 -1
  225. package/dist/runtime/facades/index.js +6 -0
  226. package/dist/runtime/facades/index.js.map +1 -1
  227. package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
  228. package/dist/runtime/facades/memory-facade.js +75 -6
  229. package/dist/runtime/facades/memory-facade.js.map +1 -1
  230. package/dist/runtime/facades/operator-facade.d.ts +8 -0
  231. package/dist/runtime/facades/operator-facade.d.ts.map +1 -0
  232. package/dist/runtime/facades/operator-facade.js +220 -0
  233. package/dist/runtime/facades/operator-facade.js.map +1 -0
  234. package/dist/runtime/facades/orchestrate-facade.js +3 -3
  235. package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
  236. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  237. package/dist/runtime/facades/plan-facade.js +39 -6
  238. package/dist/runtime/facades/plan-facade.js.map +1 -1
  239. package/dist/runtime/facades/review-facade.d.ts +7 -0
  240. package/dist/runtime/facades/review-facade.d.ts.map +1 -0
  241. package/dist/runtime/facades/review-facade.js +8 -0
  242. package/dist/runtime/facades/review-facade.js.map +1 -0
  243. package/dist/runtime/facades/sync-facade.d.ts +7 -0
  244. package/dist/runtime/facades/sync-facade.d.ts.map +1 -0
  245. package/dist/runtime/facades/sync-facade.js +8 -0
  246. package/dist/runtime/facades/sync-facade.js.map +1 -0
  247. package/dist/runtime/facades/vault-facade.d.ts +4 -1
  248. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  249. package/dist/runtime/facades/vault-facade.js +13 -66
  250. package/dist/runtime/facades/vault-facade.js.map +1 -1
  251. package/dist/runtime/github-integration.d.ts +49 -0
  252. package/dist/runtime/github-integration.d.ts.map +1 -0
  253. package/dist/runtime/github-integration.js +113 -0
  254. package/dist/runtime/github-integration.js.map +1 -0
  255. package/dist/runtime/grading-ops.js +1 -1
  256. package/dist/runtime/grading-ops.js.map +1 -1
  257. package/dist/runtime/memory-extra-ops.d.ts.map +1 -1
  258. package/dist/runtime/memory-extra-ops.js +6 -2
  259. package/dist/runtime/memory-extra-ops.js.map +1 -1
  260. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  261. package/dist/runtime/orchestrate-ops.js +367 -40
  262. package/dist/runtime/orchestrate-ops.js.map +1 -1
  263. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  264. package/dist/runtime/planning-extra-ops.js +69 -4
  265. package/dist/runtime/planning-extra-ops.js.map +1 -1
  266. package/dist/runtime/review-ops.d.ts +10 -0
  267. package/dist/runtime/review-ops.d.ts.map +1 -0
  268. package/dist/runtime/review-ops.js +97 -0
  269. package/dist/runtime/review-ops.js.map +1 -0
  270. package/dist/runtime/runtime.d.ts.map +1 -1
  271. package/dist/runtime/runtime.js +27 -12
  272. package/dist/runtime/runtime.js.map +1 -1
  273. package/dist/runtime/session-briefing.d.ts +3 -0
  274. package/dist/runtime/session-briefing.d.ts.map +1 -1
  275. package/dist/runtime/session-briefing.js +68 -1
  276. package/dist/runtime/session-briefing.js.map +1 -1
  277. package/dist/runtime/sync-ops.d.ts +12 -0
  278. package/dist/runtime/sync-ops.d.ts.map +1 -0
  279. package/dist/runtime/sync-ops.js +288 -0
  280. package/dist/runtime/sync-ops.js.map +1 -0
  281. package/dist/runtime/types.d.ts +10 -4
  282. package/dist/runtime/types.d.ts.map +1 -1
  283. package/dist/runtime/vault-extra-ops.d.ts +5 -4
  284. package/dist/runtime/vault-extra-ops.d.ts.map +1 -1
  285. package/dist/runtime/vault-extra-ops.js +5 -300
  286. package/dist/runtime/vault-extra-ops.js.map +1 -1
  287. package/dist/runtime/vault-sharing-ops.d.ts +4 -4
  288. package/dist/runtime/vault-sharing-ops.d.ts.map +1 -1
  289. package/dist/runtime/vault-sharing-ops.js +5 -300
  290. package/dist/runtime/vault-sharing-ops.js.map +1 -1
  291. package/dist/skills/sync-skills.d.ts +27 -0
  292. package/dist/skills/sync-skills.d.ts.map +1 -0
  293. package/dist/skills/sync-skills.js +81 -0
  294. package/dist/skills/sync-skills.js.map +1 -0
  295. package/dist/update-check.d.ts +14 -0
  296. package/dist/update-check.d.ts.map +1 -0
  297. package/dist/update-check.js +96 -0
  298. package/dist/update-check.js.map +1 -0
  299. package/dist/vault/linking.d.ts +10 -12
  300. package/dist/vault/linking.d.ts.map +1 -1
  301. package/dist/vault/linking.js +104 -161
  302. package/dist/vault/linking.js.map +1 -1
  303. package/dist/vault/vault-entries.d.ts +69 -0
  304. package/dist/vault/vault-entries.d.ts.map +1 -0
  305. package/dist/vault/vault-entries.js +257 -0
  306. package/dist/vault/vault-entries.js.map +1 -0
  307. package/dist/vault/vault-interfaces.d.ts +153 -0
  308. package/dist/vault/vault-interfaces.d.ts.map +1 -0
  309. package/dist/vault/vault-interfaces.js +2 -0
  310. package/dist/vault/vault-interfaces.js.map +1 -0
  311. package/dist/vault/vault-maintenance.d.ts +40 -0
  312. package/dist/vault/vault-maintenance.d.ts.map +1 -0
  313. package/dist/vault/vault-maintenance.js +142 -0
  314. package/dist/vault/vault-maintenance.js.map +1 -0
  315. package/dist/vault/vault-markdown-sync.d.ts +22 -0
  316. package/dist/vault/vault-markdown-sync.d.ts.map +1 -0
  317. package/dist/vault/vault-markdown-sync.js +143 -0
  318. package/dist/vault/vault-markdown-sync.js.map +1 -0
  319. package/dist/vault/vault-memories.d.ts +61 -0
  320. package/dist/vault/vault-memories.d.ts.map +1 -0
  321. package/dist/vault/vault-memories.js +240 -0
  322. package/dist/vault/vault-memories.js.map +1 -0
  323. package/dist/vault/vault-schema.d.ts +9 -0
  324. package/dist/vault/vault-schema.d.ts.map +1 -0
  325. package/dist/vault/vault-schema.js +179 -0
  326. package/dist/vault/vault-schema.js.map +1 -0
  327. package/dist/vault/vault.d.ts +29 -81
  328. package/dist/vault/vault.d.ts.map +1 -1
  329. package/dist/vault/vault.js +78 -931
  330. package/dist/vault/vault.js.map +1 -1
  331. package/package.json +1 -1
  332. package/src/agency/agency-manager.test.ts +600 -0
  333. package/src/agency/default-rules.test.ts +228 -0
  334. package/src/{__tests__ → brain}/brain-intelligence.test.ts +37 -14
  335. package/src/{__tests__ → brain}/brain.test.ts +1 -1
  336. package/src/brain/intelligence.ts +196 -15
  337. package/src/brain/learning-radar.ts +22 -1
  338. package/src/{__tests__ → brain}/second-brain-features.test.ts +4 -4
  339. package/src/{__tests__ → brain}/session-lifecycle.test.ts +2 -2
  340. package/src/brain/strength-scorer.ts +404 -0
  341. package/src/capabilities/chain-mapping.test.ts +66 -0
  342. package/src/capabilities/registry.test.ts +369 -0
  343. package/src/chat/agent-loop.test.ts +394 -0
  344. package/src/chat/agent-loop.ts +2 -0
  345. package/src/{__tests__ → chat}/chat-differentiators.test.ts +3 -3
  346. package/src/{__tests__ → chat}/chat-enhanced.test.ts +4 -4
  347. package/src/{__tests__ → chat}/chat-transport.test.ts +6 -6
  348. package/src/chat/mcp-bridge.test.ts +173 -0
  349. package/src/chat/notifications.ts +2 -0
  350. package/src/chat/output-compressor.test.ts +164 -0
  351. package/src/claudemd/compose.test.ts +178 -0
  352. package/src/claudemd/compose.ts +1 -1
  353. package/src/claudemd/inject.test.ts +211 -0
  354. package/src/context/context-engine.test.ts +461 -0
  355. package/src/control/identity-manager.test.ts +305 -0
  356. package/src/control/intent-router.test.ts +360 -0
  357. package/src/control/intent-router.ts +13 -4
  358. package/src/curator/classifier.test.ts +104 -0
  359. package/src/curator/contradiction-detector.test.ts +180 -0
  360. package/src/curator/contradiction-detector.ts +87 -0
  361. package/src/{__tests__ → curator}/curator-pipeline-e2e.test.ts +10 -10
  362. package/src/{__tests__ → curator}/curator.test.ts +77 -1
  363. package/src/curator/curator.ts +115 -777
  364. package/src/curator/duplicate-detector.test.ts +183 -0
  365. package/src/curator/duplicate-detector.ts +103 -0
  366. package/src/curator/health-audit.ts +126 -0
  367. package/src/curator/metadata-enricher.ts +84 -0
  368. package/src/curator/quality-gate.test.ts +135 -0
  369. package/src/curator/schema.ts +65 -0
  370. package/src/curator/tag-manager.test.ts +165 -0
  371. package/src/curator/tag-manager.ts +109 -0
  372. package/src/domain-packs/inject-rules.test.ts +117 -0
  373. package/src/domain-packs/knowledge-installer.test.ts +171 -0
  374. package/src/domain-packs/loader.test.ts +86 -0
  375. package/src/domain-packs/pack-runtime.test.ts +140 -0
  376. package/src/domain-packs/skills-installer.test.ts +135 -0
  377. package/src/domain-packs/token-resolver.test.ts +150 -0
  378. package/src/domain-packs/types.test.ts +130 -0
  379. package/src/enforcement/adapters/claude-code.test.ts +216 -0
  380. package/src/enforcement/registry.test.ts +264 -0
  381. package/src/engine/bin/soleri-engine.ts +59 -3
  382. package/src/engine/core-ops.test.ts +254 -0
  383. package/src/engine/core-ops.ts +35 -10
  384. package/src/engine/module-manifest.test.ts +124 -0
  385. package/src/engine/module-manifest.ts +22 -2
  386. package/src/engine/register-engine.test.ts +230 -0
  387. package/src/engine/register-engine.ts +26 -2
  388. package/src/errors/classify.test.ts +199 -0
  389. package/src/errors/retry.test.ts +156 -0
  390. package/src/errors/retry.ts +2 -0
  391. package/src/errors/types.test.ts +108 -0
  392. package/src/events/event-bus.test.ts +149 -0
  393. package/src/extensions/middleware.test.ts +234 -0
  394. package/src/facades/facade-factory.test.ts +424 -0
  395. package/src/flows/chain-runner.test.ts +273 -0
  396. package/src/flows/context-router.test.ts +52 -0
  397. package/src/flows/dispatch-registry.test.ts +128 -0
  398. package/src/flows/epilogue.test.ts +107 -0
  399. package/src/flows/executor.test.ts +263 -0
  400. package/src/flows/gate-evaluator.test.ts +194 -0
  401. package/src/flows/gate-evaluator.ts +25 -0
  402. package/src/flows/types.ts +4 -0
  403. package/src/governance/governance.test.ts +726 -0
  404. package/src/health/health-registry.test.ts +186 -0
  405. package/src/health/vault-integrity.test.ts +110 -0
  406. package/src/index.ts +92 -0
  407. package/src/intake/content-classifier.test.ts +209 -0
  408. package/src/intake/dedup-gate.test.ts +131 -0
  409. package/src/intake/intake-pipeline.test.ts +506 -0
  410. package/src/intake/intake-pipeline.ts +1 -0
  411. package/src/intake/text-ingester.test.ts +194 -0
  412. package/src/intake/text-ingester.ts +2 -0
  413. package/src/llm/key-pool.test.ts +236 -0
  414. package/src/llm/key-pool.ts +3 -4
  415. package/src/llm/llm-client.test.ts +345 -0
  416. package/src/llm/oauth-discovery.test.ts +180 -0
  417. package/src/llm/utils.test.ts +327 -0
  418. package/src/llm/utils.ts +2 -0
  419. package/src/{__tests__ → logging}/logger.test.ts +41 -62
  420. package/src/loop/loop-manager.test.ts +519 -0
  421. package/src/migrations/migration-runner.edge-cases.test.ts +319 -0
  422. package/src/migrations/migration-runner.test-helpers.ts +64 -0
  423. package/src/migrations/migration-runner.test.ts +385 -0
  424. package/src/operator/auto-signal-pipeline.test.ts +207 -0
  425. package/src/operator/operator-profile-extended.test.ts +320 -0
  426. package/src/operator/operator-profile.test.ts +314 -0
  427. package/src/operator/operator-profile.ts +469 -0
  428. package/src/operator/operator-signals-extended.test.ts +245 -0
  429. package/src/operator/operator-signals.test.ts +281 -0
  430. package/src/operator/operator-signals.ts +261 -0
  431. package/src/operator/operator-types.ts +444 -0
  432. package/src/operator/prompts/hook-precompact-operator-dispatch.md +94 -0
  433. package/src/operator/prompts/subagent-soft-signal-extractor.md +125 -0
  434. package/src/operator/prompts/subagent-synthesis-cognition.md +181 -0
  435. package/src/operator/prompts/subagent-synthesis-communication.md +140 -0
  436. package/src/operator/prompts/subagent-synthesis-technical.md +160 -0
  437. package/src/operator/prompts/subagent-synthesis-trust.md +143 -0
  438. package/src/{__tests__ → packs}/pack-lockfile.test.ts +3 -3
  439. package/src/{__tests__ → packs}/pack-system.test.ts +2 -2
  440. package/src/paths.ts +115 -0
  441. package/src/persistence/index.ts +1 -1
  442. package/src/persistence/sqlite-provider.test.ts +540 -0
  443. package/src/persistence/sqlite-provider.ts +8 -5
  444. package/src/persona/defaults.test.ts +59 -0
  445. package/src/persona/loader.test.ts +67 -0
  446. package/src/persona/prompt-generator.test.ts +127 -0
  447. package/src/planning/evidence-collector.test.ts +406 -0
  448. package/src/planning/evidence-collector.ts +50 -0
  449. package/src/planning/gap-analysis-alternatives.test.ts +169 -0
  450. package/src/planning/gap-analysis.ts +21 -636
  451. package/src/planning/gap-passes.test.ts +372 -0
  452. package/src/planning/gap-passes.ts +298 -0
  453. package/src/planning/gap-patterns.test.ts +320 -0
  454. package/src/planning/gap-patterns.ts +234 -0
  455. package/src/planning/gap-types.ts +4 -1
  456. package/src/planning/github-projection.test.ts +177 -0
  457. package/src/planning/github-projection.ts +425 -0
  458. package/src/planning/impact-analyzer.test.ts +180 -0
  459. package/src/planning/impact-analyzer.ts +264 -0
  460. package/src/planning/plan-lifecycle.test.ts +312 -0
  461. package/src/planning/plan-lifecycle.ts +346 -0
  462. package/src/planning/planner-types.ts +215 -0
  463. package/src/{__tests__ → planning}/planner.test.ts +169 -15
  464. package/src/planning/planner.ts +197 -1228
  465. package/src/planning/rationalization-detector.test.ts +171 -0
  466. package/src/planning/rationalization-detector.ts +138 -0
  467. package/src/planning/reconciliation-engine.test.ts +141 -0
  468. package/src/planning/reconciliation-engine.ts +162 -0
  469. package/src/planning/task-verifier.test.ts +235 -0
  470. package/src/planning/task-verifier.ts +303 -0
  471. package/src/planning/verification-protocol.test.ts +201 -0
  472. package/src/playbooks/generic/generic-playbooks.test.ts +438 -0
  473. package/src/playbooks/index.test.ts +77 -0
  474. package/src/playbooks/playbook-executor.test.ts +255 -0
  475. package/src/playbooks/playbook-registry.test.ts +232 -0
  476. package/src/playbooks/playbook-seeder.test.ts +153 -0
  477. package/src/plugins/plugin-loader.test.ts +212 -0
  478. package/src/plugins/plugin-registry.test.ts +272 -0
  479. package/src/project/project-registry.test.ts +428 -0
  480. package/src/prompts/parser.test.ts +100 -0
  481. package/src/prompts/template-manager.test.ts +109 -0
  482. package/src/{__tests__ → queue}/async-infrastructure.test.ts +3 -3
  483. package/src/queue/job-queue.test.ts +331 -0
  484. package/src/queue/pipeline-runner.test.ts +209 -0
  485. package/src/runtime/admin-extra-ops.test.ts +527 -0
  486. package/src/runtime/admin-ops.test.ts +257 -0
  487. package/src/runtime/admin-ops.ts +45 -17
  488. package/src/runtime/admin-setup-ops.test.ts +328 -0
  489. package/src/runtime/admin-setup-ops.ts +20 -43
  490. package/src/runtime/archive-ops.test.ts +269 -0
  491. package/src/runtime/archive-ops.ts +347 -0
  492. package/src/runtime/capture-ops.test.ts +433 -0
  493. package/src/runtime/capture-ops.ts +50 -8
  494. package/src/runtime/chain-ops.test.ts +149 -0
  495. package/src/runtime/claude-md-helpers.test.ts +191 -0
  496. package/src/runtime/claude-md-helpers.ts +1 -1
  497. package/src/runtime/context-health.test.ts +78 -0
  498. package/src/runtime/context-health.ts +85 -0
  499. package/src/runtime/curator-extra-ops.test.ts +202 -0
  500. package/src/runtime/deprecation.test.ts +98 -0
  501. package/src/runtime/domain-ops.test.ts +268 -0
  502. package/src/runtime/facades/admin-facade.test.ts +333 -0
  503. package/src/runtime/facades/agency-facade.test.ts +278 -0
  504. package/src/runtime/facades/archive-facade.test.ts +294 -0
  505. package/src/runtime/facades/archive-facade.ts +14 -0
  506. package/src/runtime/facades/brain-facade.test.ts +714 -0
  507. package/src/runtime/facades/brain-facade.ts +2 -0
  508. package/src/runtime/facades/chat-facade.test.ts +166 -0
  509. package/src/runtime/facades/chat-facade.ts +15 -906
  510. package/src/runtime/facades/chat-service-ops.test.ts +276 -0
  511. package/src/runtime/facades/chat-service-ops.ts +374 -0
  512. package/src/runtime/facades/chat-session-ops.test.ts +197 -0
  513. package/src/runtime/facades/chat-session-ops.ts +146 -0
  514. package/src/runtime/facades/chat-state.ts +60 -0
  515. package/src/runtime/facades/chat-transport-ops.test.ts +269 -0
  516. package/src/runtime/facades/chat-transport-ops.ts +380 -0
  517. package/src/runtime/facades/context-facade.test.ts +108 -0
  518. package/src/runtime/facades/control-facade.test.ts +436 -0
  519. package/src/runtime/facades/control-facade.ts +6 -1
  520. package/src/runtime/facades/curator-facade.test.ts +303 -0
  521. package/src/runtime/facades/index.ts +6 -0
  522. package/src/runtime/facades/loop-facade.test.ts +245 -0
  523. package/src/runtime/facades/memory-facade.test.ts +269 -0
  524. package/src/runtime/facades/memory-facade.ts +78 -6
  525. package/src/runtime/facades/operator-facade.test.ts +208 -0
  526. package/src/runtime/facades/operator-facade.ts +236 -0
  527. package/src/runtime/facades/orchestrate-facade.test.ts +185 -0
  528. package/src/runtime/facades/orchestrate-facade.ts +3 -3
  529. package/src/runtime/facades/plan-facade.test.ts +266 -0
  530. package/src/runtime/facades/plan-facade.ts +42 -6
  531. package/src/runtime/facades/review-facade.test.ts +82 -0
  532. package/src/runtime/facades/review-facade.ts +11 -0
  533. package/src/runtime/facades/sync-facade.test.ts +113 -0
  534. package/src/runtime/facades/sync-facade.ts +11 -0
  535. package/src/runtime/facades/vault-facade.test.ts +631 -0
  536. package/src/runtime/facades/vault-facade.ts +15 -70
  537. package/src/runtime/feature-flags.test.ts +140 -0
  538. package/src/runtime/github-integration.test.ts +89 -0
  539. package/src/runtime/github-integration.ts +159 -0
  540. package/src/runtime/grading-ops.test.ts +141 -0
  541. package/src/runtime/grading-ops.ts +1 -1
  542. package/src/runtime/intake-ops.test.ts +208 -0
  543. package/src/runtime/loop-ops.test.ts +238 -0
  544. package/src/runtime/memory-cross-project-ops.test.ts +177 -0
  545. package/src/runtime/memory-extra-ops.test.ts +453 -0
  546. package/src/runtime/memory-extra-ops.ts +6 -2
  547. package/src/runtime/orchestrate-ops.test.ts +302 -0
  548. package/src/runtime/orchestrate-ops.ts +435 -46
  549. package/src/runtime/pack-ops.test.ts +158 -0
  550. package/src/runtime/planning-extra-ops.test.ts +583 -0
  551. package/src/runtime/planning-extra-ops.ts +72 -4
  552. package/src/{__tests__ → runtime}/playbook-ops-execution.test.ts +3 -3
  553. package/src/runtime/playbook-ops.test.ts +262 -0
  554. package/src/runtime/plugin-ops.test.ts +201 -0
  555. package/src/runtime/project-ops.test.ts +235 -0
  556. package/src/runtime/review-ops.test.ts +142 -0
  557. package/src/runtime/review-ops.ts +99 -0
  558. package/src/runtime/runtime.test.ts +363 -0
  559. package/src/runtime/runtime.ts +39 -12
  560. package/src/runtime/session-briefing.test.ts +302 -0
  561. package/src/runtime/session-briefing.ts +80 -1
  562. package/src/runtime/sync-ops.test.ts +221 -0
  563. package/src/runtime/sync-ops.ts +325 -0
  564. package/src/runtime/telemetry-ops.test.ts +132 -0
  565. package/src/runtime/types.ts +10 -4
  566. package/src/runtime/vault-extra-ops.test.ts +246 -0
  567. package/src/runtime/vault-extra-ops.ts +5 -332
  568. package/src/runtime/vault-linking-ops.test.ts +237 -0
  569. package/src/runtime/vault-sharing-ops.test.ts +130 -0
  570. package/src/runtime/vault-sharing-ops.ts +5 -329
  571. package/src/skills/sync-skills.ts +108 -0
  572. package/src/streams/normalize.test.ts +95 -0
  573. package/src/streams/replayable-stream.test.ts +166 -0
  574. package/src/telemetry/telemetry.test.ts +143 -0
  575. package/src/transport/http-server.test.ts +394 -0
  576. package/src/transport/lsp-server.test.ts +458 -0
  577. package/src/transport/rate-limiter.test.ts +126 -0
  578. package/src/transport/session-manager.test.ts +133 -0
  579. package/src/transport/token-auth.test.ts +136 -0
  580. package/src/transport/ws-server.test.ts +294 -0
  581. package/src/update-check.ts +111 -0
  582. package/src/vault/__tests__/vault-characterization.test.ts +168 -0
  583. package/src/vault/content-hash.test.ts +78 -0
  584. package/src/vault/git-vault-sync.test.ts +234 -0
  585. package/src/vault/knowledge-review.test.ts +269 -0
  586. package/src/vault/linking.test.ts +358 -0
  587. package/src/vault/linking.ts +149 -183
  588. package/src/vault/obsidian-sync.test.ts +342 -0
  589. package/src/vault/playbook.test.ts +152 -0
  590. package/src/vault/scope-detector.test.ts +187 -0
  591. package/src/vault/vault-branching.test.ts +250 -0
  592. package/src/{__tests__ → vault}/vault-connect.test.ts +1 -1
  593. package/src/vault/vault-entries.ts +282 -0
  594. package/src/vault/vault-interfaces.ts +56 -0
  595. package/src/vault/vault-maintenance.ts +205 -0
  596. package/src/vault/vault-manager.test.ts +206 -0
  597. package/src/vault/vault-markdown-sync.test.ts +203 -0
  598. package/src/vault/vault-markdown-sync.ts +160 -0
  599. package/src/vault/vault-memories.ts +339 -0
  600. package/src/{__tests__ → vault}/vault-scaling.test.ts +1 -1
  601. package/src/vault/vault-schema.ts +181 -0
  602. package/src/{__tests__ → vault}/vault-sharing.test.ts +4 -4
  603. package/src/{__tests__ → vault}/vault.test.ts +2 -2
  604. package/src/vault/vault.ts +89 -1171
  605. package/dist/cognee/client.d.ts +0 -43
  606. package/dist/cognee/client.d.ts.map +0 -1
  607. package/dist/cognee/client.js +0 -375
  608. package/dist/cognee/client.js.map +0 -1
  609. package/dist/cognee/sync-manager.d.ts +0 -153
  610. package/dist/cognee/sync-manager.d.ts.map +0 -1
  611. package/dist/cognee/sync-manager.js +0 -390
  612. package/dist/cognee/sync-manager.js.map +0 -1
  613. package/dist/cognee/types.d.ts +0 -62
  614. package/dist/cognee/types.d.ts.map +0 -1
  615. package/dist/cognee/types.js +0 -3
  616. package/dist/cognee/types.js.map +0 -1
  617. package/dist/governance/index.d.ts +0 -3
  618. package/dist/governance/index.d.ts.map +0 -1
  619. package/dist/governance/index.js +0 -2
  620. package/dist/governance/index.js.map +0 -1
  621. package/dist/health/doctor-checks.d.ts +0 -15
  622. package/dist/health/doctor-checks.d.ts.map +0 -1
  623. package/dist/health/doctor-checks.js +0 -98
  624. package/dist/health/doctor-checks.js.map +0 -1
  625. package/dist/persistence/postgres-provider.d.ts +0 -81
  626. package/dist/persistence/postgres-provider.d.ts.map +0 -1
  627. package/dist/persistence/postgres-provider.js +0 -256
  628. package/dist/persistence/postgres-provider.js.map +0 -1
  629. package/dist/runtime/cognee-sync-ops.d.ts +0 -12
  630. package/dist/runtime/cognee-sync-ops.d.ts.map +0 -1
  631. package/dist/runtime/cognee-sync-ops.js +0 -93
  632. package/dist/runtime/cognee-sync-ops.js.map +0 -1
  633. package/dist/runtime/core-ops.d.ts +0 -23
  634. package/dist/runtime/core-ops.d.ts.map +0 -1
  635. package/dist/runtime/core-ops.js +0 -1296
  636. package/dist/runtime/core-ops.js.map +0 -1
  637. package/dist/runtime/facades/cognee-facade.d.ts +0 -8
  638. package/dist/runtime/facades/cognee-facade.d.ts.map +0 -1
  639. package/dist/runtime/facades/cognee-facade.js +0 -156
  640. package/dist/runtime/facades/cognee-facade.js.map +0 -1
  641. package/src/__tests__/admin-extra-ops.test.ts +0 -484
  642. package/src/__tests__/admin-ops.test.ts +0 -268
  643. package/src/__tests__/admin-setup-ops.test.ts +0 -355
  644. package/src/__tests__/agency-manager.test.ts +0 -374
  645. package/src/__tests__/agent-loop.test.ts +0 -256
  646. package/src/__tests__/capture-ops.test.ts +0 -784
  647. package/src/__tests__/claudemd.test.ts +0 -282
  648. package/src/__tests__/content-hash.test.ts +0 -60
  649. package/src/__tests__/context-engine.test.ts +0 -251
  650. package/src/__tests__/core-ops.test.ts +0 -550
  651. package/src/__tests__/curator-extra-ops.test.ts +0 -383
  652. package/src/__tests__/deprecation.test.ts +0 -78
  653. package/src/__tests__/domain-ops.test.ts +0 -226
  654. package/src/__tests__/domain-packs.test.ts +0 -421
  655. package/src/__tests__/enforcement.test.ts +0 -153
  656. package/src/__tests__/errors.test.ts +0 -388
  657. package/src/__tests__/extensions.test.ts +0 -233
  658. package/src/__tests__/facade-factory.test.ts +0 -271
  659. package/src/__tests__/feature-flags.test.ts +0 -137
  660. package/src/__tests__/flows.test.ts +0 -604
  661. package/src/__tests__/git-vault-sync.test.ts +0 -230
  662. package/src/__tests__/governance.test.ts +0 -522
  663. package/src/__tests__/grading-ops.test.ts +0 -361
  664. package/src/__tests__/health-registry.test.ts +0 -173
  665. package/src/__tests__/identity-manager.test.ts +0 -243
  666. package/src/__tests__/intake-pipeline.test.ts +0 -162
  667. package/src/__tests__/intent-router.test.ts +0 -222
  668. package/src/__tests__/knowledge-review.test.ts +0 -104
  669. package/src/__tests__/llm-client.test.ts +0 -69
  670. package/src/__tests__/llm.test.ts +0 -556
  671. package/src/__tests__/loader.test.ts +0 -176
  672. package/src/__tests__/loop-ops.test.ts +0 -469
  673. package/src/__tests__/lsp-transport.test.ts +0 -442
  674. package/src/__tests__/memory-cross-project-ops.test.ts +0 -248
  675. package/src/__tests__/memory-extra-ops.test.ts +0 -352
  676. package/src/__tests__/migration-runner.test.ts +0 -170
  677. package/src/__tests__/module-manifest-drift.test.ts +0 -59
  678. package/src/__tests__/normalize.test.ts +0 -85
  679. package/src/__tests__/obsidian-sync.test.ts +0 -354
  680. package/src/__tests__/orchestrate-ops.test.ts +0 -289
  681. package/src/__tests__/pack-ops.test.ts +0 -146
  682. package/src/__tests__/persistence.test.ts +0 -291
  683. package/src/__tests__/planning-extra-ops.test.ts +0 -706
  684. package/src/__tests__/playbook-executor.test.ts +0 -249
  685. package/src/__tests__/playbook-registry.test.ts +0 -326
  686. package/src/__tests__/playbook-seeder.test.ts +0 -163
  687. package/src/__tests__/playbook.test.ts +0 -389
  688. package/src/__tests__/plugin-ops.test.ts +0 -411
  689. package/src/__tests__/plugin-system.test.ts +0 -509
  690. package/src/__tests__/project-ops.test.ts +0 -381
  691. package/src/__tests__/replayable-stream.test.ts +0 -177
  692. package/src/__tests__/runtime.test.ts +0 -95
  693. package/src/__tests__/scope-detector.test.ts +0 -121
  694. package/src/__tests__/template-manager.test.ts +0 -222
  695. package/src/__tests__/token-resolver.test.ts +0 -79
  696. package/src/__tests__/transport.test.ts +0 -758
  697. package/src/__tests__/vault-branching.test.ts +0 -274
  698. package/src/__tests__/vault-extra-ops.test.ts +0 -482
  699. package/src/__tests__/vault-integrity.test.ts +0 -71
  700. package/src/__tests__/vault-manager.test.ts +0 -238
  701. package/src/__tests__/ws-transport.test.ts +0 -479
@@ -0,0 +1,183 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import type { IntelligenceEntry } from '../intelligence/types.js';
3
+ import {
4
+ detectDuplicates,
5
+ buildVocabulary,
6
+ entryToText,
7
+ DEFAULT_DUPLICATE_THRESHOLD,
8
+ MERGE_SUGGESTION_THRESHOLD,
9
+ } from './duplicate-detector.js';
10
+
11
+ function makeEntry(overrides: Partial<IntelligenceEntry> = {}): IntelligenceEntry {
12
+ return {
13
+ id: overrides.id ?? 'test-1',
14
+ type: overrides.type ?? 'pattern',
15
+ domain: overrides.domain ?? 'testing',
16
+ title: overrides.title ?? 'Test Pattern',
17
+ severity: overrides.severity ?? 'warning',
18
+ description: overrides.description ?? 'A test pattern for testing.',
19
+ tags: overrides.tags ?? ['testing'],
20
+ };
21
+ }
22
+
23
+ describe('duplicate-detector', () => {
24
+ describe('buildVocabulary', () => {
25
+ it('returns IDF scores for all unique tokens across entries', () => {
26
+ const entries = [
27
+ makeEntry({ id: '1', title: 'Use semantic tokens', description: 'Tokens for colors' }),
28
+ makeEntry({ id: '2', title: 'Avoid raw colors', description: 'Never use hex values' }),
29
+ ];
30
+ const vocab = buildVocabulary(entries);
31
+ expect(vocab.size).toBeGreaterThan(0);
32
+ // Common terms should have lower IDF than unique terms
33
+ for (const [, idf] of vocab) {
34
+ expect(idf).toBeGreaterThan(0);
35
+ }
36
+ });
37
+
38
+ it('returns empty map for empty entries', () => {
39
+ const vocab = buildVocabulary([]);
40
+ expect(vocab.size).toBe(0);
41
+ });
42
+
43
+ it('gives higher IDF to rare terms', () => {
44
+ const entries = [
45
+ makeEntry({ id: '1', title: 'authentication jwt tokens', description: 'auth' }),
46
+ makeEntry({ id: '2', title: 'database connection pooling', description: 'db' }),
47
+ makeEntry({ id: '3', title: 'authentication session cookies', description: 'auth' }),
48
+ ];
49
+ const vocab = buildVocabulary(entries);
50
+ // "authentication" appears in 2/3 docs, "pooling" in 1/3 — pooling should have higher IDF
51
+ const authIdf = vocab.get('authentication') ?? 0;
52
+ const poolingIdf = vocab.get('pooling') ?? 0;
53
+ expect(poolingIdf).toBeGreaterThan(authIdf);
54
+ });
55
+ });
56
+
57
+ describe('entryToText', () => {
58
+ it('concatenates title, description, context, and tags', () => {
59
+ const entry = makeEntry({
60
+ title: 'My Title',
61
+ description: 'My Desc',
62
+ tags: ['tag1', 'tag2'],
63
+ });
64
+ entry.context = 'Some context';
65
+ const text = entryToText(entry);
66
+ expect(text).toContain('My Title');
67
+ expect(text).toContain('My Desc');
68
+ expect(text).toContain('Some context');
69
+ expect(text).toContain('tag1');
70
+ expect(text).toContain('tag2');
71
+ });
72
+
73
+ it('handles missing context', () => {
74
+ const entry = makeEntry({ title: 'Title', description: 'Desc' });
75
+ const text = entryToText(entry);
76
+ expect(text).toContain('Title');
77
+ expect(text).toContain('Desc');
78
+ });
79
+ });
80
+
81
+ describe('constants', () => {
82
+ it('exports expected threshold values', () => {
83
+ expect(DEFAULT_DUPLICATE_THRESHOLD).toBe(0.45);
84
+ expect(MERGE_SUGGESTION_THRESHOLD).toBe(0.65);
85
+ });
86
+ });
87
+
88
+ describe('detectDuplicates', () => {
89
+ it('returns empty array for empty entries', () => {
90
+ expect(detectDuplicates([])).toEqual([]);
91
+ });
92
+
93
+ it('returns empty array for single entry', () => {
94
+ const entries = [makeEntry({ id: '1' })];
95
+ expect(detectDuplicates(entries)).toEqual([]);
96
+ });
97
+
98
+ it('detects duplicates with identical content', () => {
99
+ const entries = [
100
+ makeEntry({ id: 'dup-1', title: 'Validate user input', description: 'Always validate user input before processing.' }),
101
+ makeEntry({ id: 'dup-2', title: 'Validate user input', description: 'Always validate user input before processing.' }),
102
+ ];
103
+ const results = detectDuplicates(entries, undefined, 0.3);
104
+ expect(results.length).toBeGreaterThan(0);
105
+ expect(results[0].matches[0].suggestMerge).toBe(true);
106
+ });
107
+
108
+ it('does not flag unrelated entries', () => {
109
+ const entries = [
110
+ makeEntry({ id: 'a', title: 'Database indexing strategies', description: 'Create indices on columns.' }),
111
+ makeEntry({ id: 'b', title: 'React component lifecycle', description: 'Use useEffect for side effects.' }),
112
+ ];
113
+ const results = detectDuplicates(entries, undefined, 0.8);
114
+ expect(results.length).toBe(0);
115
+ });
116
+
117
+ it('filters by entryId when provided', () => {
118
+ const entries = [
119
+ makeEntry({ id: 'x', title: 'Authentication with JWT', description: 'Use JWT for auth.' }),
120
+ makeEntry({ id: 'y', title: 'JWT authentication pattern', description: 'Implement JWT auth.' }),
121
+ makeEntry({ id: 'z', title: 'Database pooling', description: 'Connection pools.' }),
122
+ ];
123
+ const results = detectDuplicates(entries, 'x', 0.3);
124
+ expect(results.length).toBeLessThanOrEqual(1);
125
+ if (results.length > 0) {
126
+ expect(results[0].entryId).toBe('x');
127
+ }
128
+ });
129
+
130
+ it('skips cross-domain pairs', () => {
131
+ const entries = [
132
+ makeEntry({ id: '1', domain: 'design', title: 'Use semantic tokens', description: 'Always use semantic tokens.' }),
133
+ makeEntry({ id: '2', domain: 'architecture', title: 'Use semantic tokens', description: 'Always use semantic tokens.' }),
134
+ ];
135
+ const results = detectDuplicates(entries, undefined, 0.3);
136
+ expect(results.length).toBe(0);
137
+ });
138
+
139
+ it('flags same-domain similar entries', () => {
140
+ const entries = [
141
+ makeEntry({ id: '1', domain: 'design', title: 'Use semantic tokens for colors', description: 'Always use semantic tokens.' }),
142
+ makeEntry({ id: '2', domain: 'design', title: 'Use semantic tokens for color values', description: 'Prefer semantic color tokens.' }),
143
+ ];
144
+ const results = detectDuplicates(entries, undefined, 0.3);
145
+ expect(results.length).toBeGreaterThan(0);
146
+ });
147
+
148
+ it('sets suggestMerge based on MERGE_SUGGESTION_THRESHOLD', () => {
149
+ const entries = [
150
+ makeEntry({ id: 'a', title: 'Exact same title', description: 'Exact same description for merge test.' }),
151
+ makeEntry({ id: 'b', title: 'Exact same title', description: 'Exact same description for merge test.' }),
152
+ ];
153
+ const results = detectDuplicates(entries, undefined, 0.3);
154
+ expect(results.length).toBeGreaterThan(0);
155
+ // Identical entries should have very high similarity
156
+ expect(results[0].matches[0].suggestMerge).toBe(true);
157
+ });
158
+
159
+ it('sorts matches by descending similarity', () => {
160
+ const entries = [
161
+ makeEntry({ id: 'base', title: 'Use semantic tokens for colors', description: 'Tokens for styling.' }),
162
+ makeEntry({ id: 'close', title: 'Use semantic tokens for color values', description: 'Tokens for styling values.' }),
163
+ makeEntry({ id: 'far', title: 'Semantic approach to colors', description: 'Use semantic color approach.' }),
164
+ ];
165
+ const results = detectDuplicates(entries, 'base', 0.1);
166
+ if (results.length > 0 && results[0].matches.length > 1) {
167
+ expect(results[0].matches[0].similarity).toBeGreaterThanOrEqual(results[0].matches[1].similarity);
168
+ }
169
+ });
170
+
171
+ it('includes scannedCount in results', () => {
172
+ const entries = [
173
+ makeEntry({ id: '1', title: 'Same thing', description: 'Same desc.' }),
174
+ makeEntry({ id: '2', title: 'Same thing', description: 'Same desc.' }),
175
+ makeEntry({ id: '3', title: 'Different thing', description: 'Different desc.' }),
176
+ ];
177
+ const results = detectDuplicates(entries, '1', 0.3);
178
+ if (results.length > 0) {
179
+ expect(results[0].scannedCount).toBe(2); // 3 entries minus self
180
+ }
181
+ });
182
+ });
183
+ });
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Duplicate Detector — pure-logic module for finding duplicate vault entries.
3
+ *
4
+ * Uses TF-IDF cosine similarity to score entry pairs.
5
+ * Database access is NOT performed here — callers supply entry lists.
6
+ */
7
+
8
+ import type { IntelligenceEntry } from '../intelligence/types.js';
9
+ import {
10
+ tokenize,
11
+ calculateTfIdf,
12
+ cosineSimilarity,
13
+ type SparseVector,
14
+ } from '../text/similarity.js';
15
+ import type { DuplicateCandidate, DuplicateDetectionResult } from './types.js';
16
+
17
+ // ─── Constants ──────────────────────────────────────────────────────
18
+
19
+ export const DEFAULT_DUPLICATE_THRESHOLD = 0.45;
20
+ export const MERGE_SUGGESTION_THRESHOLD = 0.65;
21
+
22
+ // ─── Vocabulary Builder ─────────────────────────────────────────────
23
+
24
+ export function buildVocabulary(entries: IntelligenceEntry[]): Map<string, number> {
25
+ const docCount = entries.length;
26
+ const termDocFreq = new Map<string, number>();
27
+ for (const entry of entries) {
28
+ const text = [entry.title, entry.description, entry.context ?? '', entry.tags.join(' ')].join(
29
+ ' ',
30
+ );
31
+ const tokens = new Set(tokenize(text));
32
+ for (const token of tokens) {
33
+ termDocFreq.set(token, (termDocFreq.get(token) ?? 0) + 1);
34
+ }
35
+ }
36
+ const vocabulary = new Map<string, number>();
37
+ for (const [term, df] of termDocFreq) {
38
+ const idf = Math.log((docCount + 1) / (df + 1)) + 1;
39
+ vocabulary.set(term, idf);
40
+ }
41
+ return vocabulary;
42
+ }
43
+
44
+ // ─── Entry → Text ───────────────────────────────────────────────────
45
+
46
+ export function entryToText(entry: IntelligenceEntry): string {
47
+ return [entry.title, entry.description, entry.context ?? '', entry.tags.join(' ')].join(' ');
48
+ }
49
+
50
+ // ─── Detect Duplicates ──────────────────────────────────────────────
51
+
52
+ export function detectDuplicates(
53
+ entries: IntelligenceEntry[],
54
+ entryId?: string,
55
+ threshold?: number,
56
+ ): DuplicateDetectionResult[] {
57
+ const effectiveThreshold = threshold ?? DEFAULT_DUPLICATE_THRESHOLD;
58
+ if (entries.length === 0) return [];
59
+
60
+ const vocabulary = buildVocabulary(entries);
61
+
62
+ // Build vectors for all entries
63
+ const vectors = new Map<string, SparseVector>();
64
+ for (const entry of entries) {
65
+ vectors.set(entry.id, calculateTfIdf(tokenize(entryToText(entry)), vocabulary));
66
+ }
67
+
68
+ const targetEntries = entryId ? entries.filter((e) => e.id === entryId) : entries;
69
+
70
+ const results: DuplicateDetectionResult[] = [];
71
+
72
+ for (const entry of targetEntries) {
73
+ const entryVec = vectors.get(entry.id)!;
74
+ const matches: DuplicateCandidate[] = [];
75
+
76
+ for (const other of entries) {
77
+ if (other.id === entry.id) continue;
78
+ // Skip cross-domain pairs — shared vocabulary across domains causes false positives
79
+ if (entry.domain !== other.domain) continue;
80
+ const otherVec = vectors.get(other.id)!;
81
+ const similarity = cosineSimilarity(entryVec, otherVec);
82
+ if (similarity >= effectiveThreshold) {
83
+ matches.push({
84
+ entryId: other.id,
85
+ title: other.title,
86
+ similarity,
87
+ suggestMerge: similarity >= MERGE_SUGGESTION_THRESHOLD,
88
+ });
89
+ }
90
+ }
91
+
92
+ if (matches.length > 0) {
93
+ matches.sort((a, b) => b.similarity - a.similarity);
94
+ results.push({
95
+ entryId: entry.id,
96
+ matches,
97
+ scannedCount: entries.length - 1,
98
+ });
99
+ }
100
+ }
101
+
102
+ return results;
103
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Health Audit — pure-logic module for computing vault health scores.
3
+ *
4
+ * Receives data through a provider interface; no direct DB access.
5
+ */
6
+
7
+ import type { IntelligenceEntry } from '../intelligence/types.js';
8
+ import type { DuplicateDetectionResult, Contradiction, HealthAuditResult } from './types.js';
9
+
10
+ // ─── Data Provider Interface ────────────────────────────────────────
11
+
12
+ export interface HealthDataProvider {
13
+ getStaleCount(threshold: number): number;
14
+ getGroomedCount(): number;
15
+ getDuplicates(): DuplicateDetectionResult[];
16
+ getOpenContradictions(): Contradiction[];
17
+ }
18
+
19
+ // ─── Compute ────────────────────────────────────────────────────────
20
+
21
+ export function computeHealthAudit(
22
+ entries: IntelligenceEntry[],
23
+ data: HealthDataProvider,
24
+ staleDays: number,
25
+ ): HealthAuditResult {
26
+ const recommendations: string[] = [];
27
+
28
+ if (entries.length === 0) {
29
+ return {
30
+ score: 100,
31
+ metrics: { coverage: 1, freshness: 1, quality: 1, tagHealth: 1 },
32
+ recommendations: ['Vault is empty — add knowledge entries to get started.'],
33
+ };
34
+ }
35
+
36
+ let score = 100;
37
+
38
+ // ── Coverage ──────────────────────────────────────────────────
39
+ const typeCount: Record<string, number> = { pattern: 0, 'anti-pattern': 0, rule: 0 };
40
+ for (const e of entries) typeCount[e.type] = (typeCount[e.type] ?? 0) + 1;
41
+
42
+ let coverageScore = 1;
43
+ if (!typeCount.pattern) {
44
+ score -= 10;
45
+ coverageScore -= 0.33;
46
+ recommendations.push('No patterns found — add patterns to improve coverage.');
47
+ }
48
+ if (!typeCount['anti-pattern']) {
49
+ score -= 5;
50
+ coverageScore -= 0.17;
51
+ recommendations.push('No anti-patterns found — add anti-patterns to detect contradictions.');
52
+ }
53
+ if (!typeCount.rule) {
54
+ score -= 5;
55
+ coverageScore -= 0.17;
56
+ recommendations.push('No rules found — add rules for completeness.');
57
+ }
58
+ coverageScore = Math.max(0, coverageScore);
59
+
60
+ // ── Freshness ─────────────────────────────────────────────────
61
+ const now = Math.floor(Date.now() / 1000);
62
+ const staleThreshold = now - staleDays * 86400;
63
+ const staleCount = data.getStaleCount(staleThreshold);
64
+ const staleRatio = staleCount / entries.length;
65
+ const freshnessScore = 1 - staleRatio;
66
+ if (staleRatio > 0.3) {
67
+ const penalty = Math.min(20, Math.round(staleRatio * 30));
68
+ score -= penalty;
69
+ recommendations.push(
70
+ `${staleCount} stale entries (${Math.round(staleRatio * 100)}%) — run grooming to update.`,
71
+ );
72
+ }
73
+
74
+ // ── Quality ───────────────────────────────────────────────────
75
+ const duplicates = data.getDuplicates();
76
+ const contradictions = data.getOpenContradictions();
77
+ let qualityScore = 1;
78
+ if (duplicates.length > 0) {
79
+ const penalty = Math.min(15, duplicates.length * 3);
80
+ score -= penalty;
81
+ qualityScore -= penalty / 30;
82
+ recommendations.push(`${duplicates.length} entries have duplicates — run consolidation.`);
83
+ }
84
+ if (contradictions.length > 0) {
85
+ const penalty = Math.min(15, contradictions.length * 5);
86
+ score -= penalty;
87
+ qualityScore -= penalty / 30;
88
+ recommendations.push(`${contradictions.length} open contradictions — resolve or dismiss.`);
89
+ }
90
+ qualityScore = Math.max(0, qualityScore);
91
+
92
+ // ── Tag Health ────────────────────────────────────────────────
93
+ const lowTagEntries = entries.filter((e) => e.tags.length < 2);
94
+ const lowTagRatio = lowTagEntries.length / entries.length;
95
+ const tagHealthScore = 1 - lowTagRatio;
96
+ if (lowTagRatio > 0.3) {
97
+ const penalty = Math.min(10, Math.round(lowTagRatio * 15));
98
+ score -= penalty;
99
+ recommendations.push(
100
+ `${lowTagEntries.length} entries have fewer than 2 tags — improve tagging.`,
101
+ );
102
+ }
103
+
104
+ // ── Grooming ──────────────────────────────────────────────────
105
+ const groomedCount = data.getGroomedCount();
106
+ if (groomedCount < entries.length) {
107
+ const ungroomed = entries.length - groomedCount;
108
+ const penalty = Math.min(10, Math.round((ungroomed / entries.length) * 10));
109
+ score -= penalty;
110
+ recommendations.push(`${ungroomed} entries never groomed — run groomAll().`);
111
+ }
112
+
113
+ score = Math.max(0, score);
114
+ if (recommendations.length === 0) recommendations.push('Vault is healthy — no issues detected.');
115
+
116
+ return {
117
+ score,
118
+ metrics: {
119
+ coverage: coverageScore,
120
+ freshness: freshnessScore,
121
+ quality: qualityScore,
122
+ tagHealth: tagHealthScore,
123
+ },
124
+ recommendations,
125
+ };
126
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Metadata Enricher — pure-logic module for rule-based entry metadata enrichment.
3
+ *
4
+ * No DB access. Returns changes and updates to be applied by the caller.
5
+ */
6
+
7
+ import type { IntelligenceEntry } from '../intelligence/types.js';
8
+
9
+ // ─── Types ──────────────────────────────────────────────────────────
10
+
11
+ export interface MetadataChange {
12
+ field: string;
13
+ before: string;
14
+ after: string;
15
+ }
16
+
17
+ export interface EnrichResult {
18
+ changes: MetadataChange[];
19
+ updates: Partial<Pick<IntelligenceEntry, 'title' | 'description' | 'tags' | 'severity' | 'type'>>;
20
+ }
21
+
22
+ // ─── Constants ──────────────────────────────────────────────────────
23
+
24
+ const CRITICAL_KEYWORDS = ['never', 'must not', 'critical', 'security', 'vulnerability'];
25
+ const WARNING_KEYWORDS = ['avoid', 'should not', 'deprecated', 'careful', 'warning'];
26
+ const ANTI_PATTERN_PREFIXES = ['avoid', 'never', "don't", 'do not'];
27
+
28
+ // ─── Enrich ─────────────────────────────────────────────────────────
29
+
30
+ export function enrichEntryMetadata(entry: IntelligenceEntry): EnrichResult {
31
+ const changes: MetadataChange[] = [];
32
+ const updates: EnrichResult['updates'] = {};
33
+
34
+ // Auto-capitalize title
35
+ if (entry.title.length > 0 && entry.title[0] !== entry.title[0].toUpperCase()) {
36
+ const capitalized = entry.title[0].toUpperCase() + entry.title.slice(1);
37
+ changes.push({ field: 'title', before: entry.title, after: capitalized });
38
+ updates.title = capitalized;
39
+ }
40
+
41
+ // Normalize tags: lowercase, trim, dedup
42
+ const normalizedTags = [...new Set(entry.tags.map((t) => t.toLowerCase().trim()))];
43
+ const tagsChanged =
44
+ normalizedTags.length !== entry.tags.length ||
45
+ normalizedTags.some((t, i) => t !== entry.tags[i]);
46
+ if (tagsChanged) {
47
+ changes.push({
48
+ field: 'tags',
49
+ before: JSON.stringify(entry.tags),
50
+ after: JSON.stringify(normalizedTags),
51
+ });
52
+ updates.tags = normalizedTags;
53
+ }
54
+
55
+ // Infer severity from keywords if currently 'suggestion'
56
+ if (entry.severity === 'suggestion') {
57
+ const text = (entry.title + ' ' + entry.description).toLowerCase();
58
+ if (CRITICAL_KEYWORDS.some((k) => text.includes(k))) {
59
+ changes.push({ field: 'severity', before: entry.severity, after: 'critical' });
60
+ updates.severity = 'critical';
61
+ } else if (WARNING_KEYWORDS.some((k) => text.includes(k))) {
62
+ changes.push({ field: 'severity', before: entry.severity, after: 'warning' });
63
+ updates.severity = 'warning';
64
+ }
65
+ }
66
+
67
+ // Infer type from title patterns
68
+ if (entry.type === 'pattern') {
69
+ const titleLower = entry.title.toLowerCase();
70
+ if (ANTI_PATTERN_PREFIXES.some((p) => titleLower.startsWith(p))) {
71
+ changes.push({ field: 'type', before: entry.type, after: 'anti-pattern' });
72
+ updates.type = 'anti-pattern';
73
+ }
74
+ }
75
+
76
+ // Trim whitespace from description
77
+ const trimmed = entry.description.trim();
78
+ if (trimmed !== entry.description) {
79
+ changes.push({ field: 'description', before: entry.description, after: trimmed });
80
+ updates.description = trimmed;
81
+ }
82
+
83
+ return { changes, updates };
84
+ }
@@ -0,0 +1,135 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import { evaluateQuality } from './quality-gate.js';
3
+ import type { IntelligenceEntry } from '../intelligence/types.js';
4
+ import type { LLMClient } from '../llm/llm-client.js';
5
+
6
+ function makeEntry(overrides: Partial<IntelligenceEntry> = {}): IntelligenceEntry {
7
+ return {
8
+ id: overrides.id ?? 'test-1',
9
+ type: overrides.type ?? 'pattern',
10
+ domain: overrides.domain ?? 'testing',
11
+ title: overrides.title ?? 'Test Pattern',
12
+ severity: overrides.severity ?? 'warning',
13
+ description: overrides.description ?? 'A test pattern.',
14
+ tags: overrides.tags ?? ['testing'],
15
+ };
16
+ }
17
+
18
+ function mockLLM(response: string): LLMClient {
19
+ return {
20
+ complete: vi.fn().mockResolvedValue({ text: response }),
21
+ } as unknown as LLMClient;
22
+ }
23
+
24
+ describe('evaluateQuality', () => {
25
+ it('returns ACCEPT fallback when llm is null', async () => {
26
+ const result = await evaluateQuality(makeEntry(), null);
27
+ expect(result.evaluated).toBe(false);
28
+ expect(result.verdict).toBe('ACCEPT');
29
+ expect(result.overallScore).toBe(50);
30
+ expect(result.reasoning).toContain('LLM unavailable');
31
+ });
32
+
33
+ it('returns ACCEPT for high-quality entry', async () => {
34
+ const llm = mockLLM(JSON.stringify({
35
+ verdict: 'ACCEPT',
36
+ overallScore: 85,
37
+ scores: { novelty: 80, actionability: 90, specificity: 85, relevance: 80, informationDensity: 90 },
38
+ reasoning: 'High quality entry with specific guidance.',
39
+ }));
40
+
41
+ const result = await evaluateQuality(makeEntry(), llm);
42
+ expect(result.evaluated).toBe(true);
43
+ expect(result.verdict).toBe('ACCEPT');
44
+ expect(result.overallScore).toBe(85);
45
+ });
46
+
47
+ it('returns REJECT for low-quality entry', async () => {
48
+ const llm = mockLLM(JSON.stringify({
49
+ verdict: 'REJECT',
50
+ overallScore: 30,
51
+ scores: { novelty: 10, actionability: 30, specificity: 40, relevance: 50, informationDensity: 20 },
52
+ reasoning: 'Too generic.',
53
+ rejectReasons: ['Low novelty', 'Not actionable'],
54
+ }));
55
+
56
+ const result = await evaluateQuality(makeEntry(), llm);
57
+ expect(result.evaluated).toBe(true);
58
+ expect(result.verdict).toBe('REJECT');
59
+ expect(result.overallScore).toBe(30);
60
+ expect(result.rejectReasons).toEqual(['Low novelty', 'Not actionable']);
61
+ });
62
+
63
+ it('returns fallback with error on LLM failure', async () => {
64
+ const llm = {
65
+ complete: vi.fn().mockRejectedValue(new Error('timeout')),
66
+ } as unknown as LLMClient;
67
+
68
+ const result = await evaluateQuality(makeEntry(), llm);
69
+ expect(result.evaluated).toBe(false);
70
+ expect(result.verdict).toBe('ACCEPT');
71
+ expect(result.error).toBe('timeout');
72
+ });
73
+
74
+ it('returns fallback with error on invalid JSON', async () => {
75
+ const llm = mockLLM('invalid json response');
76
+ const result = await evaluateQuality(makeEntry(), llm);
77
+ expect(result.evaluated).toBe(false);
78
+ expect(result.error).toBeDefined();
79
+ });
80
+
81
+ it('handles missing fields in LLM response', async () => {
82
+ const llm = mockLLM(JSON.stringify({ verdict: 'ACCEPT' }));
83
+ const result = await evaluateQuality(makeEntry(), llm);
84
+ expect(result.evaluated).toBe(true);
85
+ expect(result.overallScore).toBe(50);
86
+ expect(result.reasoning).toBe('');
87
+ });
88
+
89
+ it('normalizes non-REJECT verdict to ACCEPT', async () => {
90
+ const llm = mockLLM(JSON.stringify({
91
+ verdict: 'MAYBE',
92
+ overallScore: 60,
93
+ scores: { novelty: 60, actionability: 60, specificity: 60, relevance: 60, informationDensity: 60 },
94
+ reasoning: 'Borderline entry.',
95
+ }));
96
+
97
+ const result = await evaluateQuality(makeEntry(), llm);
98
+ expect(result.verdict).toBe('ACCEPT');
99
+ });
100
+
101
+ it('includes optional entry fields in prompt', async () => {
102
+ const llm = mockLLM(JSON.stringify({
103
+ verdict: 'ACCEPT',
104
+ overallScore: 70,
105
+ scores: { novelty: 70, actionability: 70, specificity: 70, relevance: 70, informationDensity: 70 },
106
+ reasoning: 'OK.',
107
+ }));
108
+
109
+ const entry = makeEntry();
110
+ entry.why = 'Because security matters';
111
+ entry.example = 'jwt.verify(token)';
112
+ entry.context = 'Node.js backend';
113
+
114
+ await evaluateQuality(entry, llm);
115
+
116
+ const call = (llm.complete as ReturnType<typeof vi.fn>).mock.calls[0][0];
117
+ expect(call.userPrompt).toContain('Because security matters');
118
+ expect(call.userPrompt).toContain('jwt.verify(token)');
119
+ expect(call.userPrompt).toContain('Node.js backend');
120
+ });
121
+
122
+ it('uses low temperature for consistent scoring', async () => {
123
+ const llm = mockLLM(JSON.stringify({
124
+ verdict: 'ACCEPT',
125
+ overallScore: 70,
126
+ scores: { novelty: 70, actionability: 70, specificity: 70, relevance: 70, informationDensity: 70 },
127
+ reasoning: 'OK.',
128
+ }));
129
+
130
+ await evaluateQuality(makeEntry(), llm);
131
+
132
+ const call = (llm.complete as ReturnType<typeof vi.fn>).mock.calls[0][0];
133
+ expect(call.temperature).toBe(0.1);
134
+ });
135
+ });