principles-disciple 1.8.1 → 1.8.3

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 (508) hide show
  1. package/ADVANCED_CONFIG_ZH.md +97 -0
  2. package/AGENT_INSTALL.md +173 -0
  3. package/AGENT_INSTALL_EN.md +173 -0
  4. package/INSTALL.md +256 -0
  5. package/SKILL.md +63 -0
  6. package/docs/COMMAND_REFERENCE.md +76 -0
  7. package/docs/COMMAND_REFERENCE_EN.md +79 -0
  8. package/esbuild.config.js +75 -0
  9. package/openclaw.plugin.json +4 -4
  10. package/package.json +11 -13
  11. package/scripts/build-web.mjs +46 -0
  12. package/scripts/install-dependencies.cjs +47 -0
  13. package/scripts/sync-plugin.mjs +802 -0
  14. package/scripts/verify-build.mjs +109 -0
  15. package/src/agents/nocturnal-dreamer.md +152 -0
  16. package/src/agents/nocturnal-philosopher.md +138 -0
  17. package/src/agents/nocturnal-reflector.md +126 -0
  18. package/src/agents/nocturnal-scribe.md +164 -0
  19. package/src/commands/capabilities.ts +85 -0
  20. package/{dist/commands/context.js → src/commands/context.ts} +78 -38
  21. package/src/commands/evolution-status.ts +146 -0
  22. package/src/commands/export.ts +111 -0
  23. package/src/commands/focus.ts +533 -0
  24. package/src/commands/nocturnal-review.ts +311 -0
  25. package/src/commands/nocturnal-rollout.ts +763 -0
  26. package/src/commands/nocturnal-train.ts +1002 -0
  27. package/{dist/commands/pain.js → src/commands/pain.ts} +68 -49
  28. package/src/commands/principle-rollback.ts +27 -0
  29. package/{dist/commands/rollback.js → src/commands/rollback.ts} +44 -12
  30. package/src/commands/samples.ts +60 -0
  31. package/src/commands/strategy.ts +38 -0
  32. package/{dist/commands/thinking-os.js → src/commands/thinking-os.ts} +59 -36
  33. package/src/commands/workflow-debug.ts +128 -0
  34. package/{dist/config/defaults/runtime.js → src/config/defaults/runtime.ts} +12 -5
  35. package/src/config/errors.ts +163 -0
  36. package/{dist/config/index.d.ts → src/config/index.ts} +2 -1
  37. package/src/constants/diagnostician.ts +66 -0
  38. package/src/constants/tools.ts +62 -0
  39. package/src/core/adaptive-thresholds.ts +476 -0
  40. package/{dist/core/config-service.js → src/core/config-service.ts} +7 -4
  41. package/{dist/core/config.js → src/core/config.ts} +158 -46
  42. package/src/core/control-ui-db.ts +435 -0
  43. package/{dist/core/detection-funnel.js → src/core/detection-funnel.ts} +36 -21
  44. package/{dist/core/detection-service.js → src/core/detection-service.ts} +7 -4
  45. package/{dist/core/dictionary-service.js → src/core/dictionary-service.ts} +7 -4
  46. package/{dist/core/dictionary.js → src/core/dictionary.ts} +57 -34
  47. package/src/core/empathy-keyword-matcher.ts +327 -0
  48. package/src/core/empathy-types.ts +218 -0
  49. package/src/core/event-log.ts +544 -0
  50. package/src/core/evolution-engine.ts +612 -0
  51. package/src/core/evolution-logger.ts +353 -0
  52. package/src/core/evolution-migration.ts +77 -0
  53. package/src/core/evolution-reducer.ts +731 -0
  54. package/src/core/evolution-types.ts +456 -0
  55. package/src/core/external-training-contract.ts +527 -0
  56. package/src/core/focus-history.ts +1458 -0
  57. package/src/core/hygiene/tracker.ts +117 -0
  58. package/{dist/core/init.js → src/core/init.ts} +39 -26
  59. package/src/core/local-worker-routing.ts +617 -0
  60. package/{dist/core/migration.js → src/core/migration.ts} +18 -11
  61. package/src/core/model-deployment-registry.ts +722 -0
  62. package/src/core/model-training-registry.ts +813 -0
  63. package/src/core/nocturnal-arbiter.ts +706 -0
  64. package/src/core/nocturnal-candidate-scoring.ts +392 -0
  65. package/src/core/nocturnal-compliance.ts +1075 -0
  66. package/src/core/nocturnal-dataset.ts +668 -0
  67. package/src/core/nocturnal-executability.ts +428 -0
  68. package/src/core/nocturnal-export.ts +390 -0
  69. package/{dist/core/nocturnal-paths.js → src/core/nocturnal-paths.ts} +49 -23
  70. package/src/core/nocturnal-trajectory-extractor.ts +484 -0
  71. package/src/core/nocturnal-trinity.ts +1384 -0
  72. package/src/core/pain.ts +122 -0
  73. package/{dist/core/path-resolver.js → src/core/path-resolver.ts} +157 -36
  74. package/{dist/core/paths.js → src/core/paths.ts} +13 -4
  75. package/src/core/principle-training-state.ts +450 -0
  76. package/src/core/profile.ts +226 -0
  77. package/src/core/promotion-gate.ts +822 -0
  78. package/{dist/core/risk-calculator.js → src/core/risk-calculator.ts} +42 -16
  79. package/{dist/core/session-tracker.js → src/core/session-tracker.ts} +175 -62
  80. package/src/core/shadow-observation-registry.ts +534 -0
  81. package/{dist/core/system-logger.js → src/core/system-logger.ts} +9 -5
  82. package/src/core/thinking-models.ts +217 -0
  83. package/src/core/training-program.ts +630 -0
  84. package/src/core/trajectory-types.ts +243 -0
  85. package/src/core/trajectory.ts +1673 -0
  86. package/{dist/core/workspace-context.js → src/core/workspace-context.ts} +57 -32
  87. package/src/hooks/bash-risk.ts +171 -0
  88. package/src/hooks/edit-verification.ts +295 -0
  89. package/src/hooks/gate-block-helper.ts +160 -0
  90. package/src/hooks/gate.ts +210 -0
  91. package/src/hooks/gfi-gate.ts +177 -0
  92. package/src/hooks/lifecycle.ts +326 -0
  93. package/{dist/hooks/llm.js → src/hooks/llm.ts} +160 -80
  94. package/src/hooks/message-sanitize.ts +45 -0
  95. package/src/hooks/pain.ts +384 -0
  96. package/src/hooks/progressive-trust-gate.ts +174 -0
  97. package/src/hooks/prompt.ts +920 -0
  98. package/src/hooks/subagent.ts +207 -0
  99. package/src/hooks/thinking-checkpoint.ts +73 -0
  100. package/src/hooks/trajectory-collector.ts +290 -0
  101. package/src/http/principles-console-route.ts +716 -0
  102. package/src/i18n/commands.ts +117 -0
  103. package/src/index.ts +694 -0
  104. package/src/service/central-database.ts +831 -0
  105. package/src/service/control-ui-query-service.ts +888 -0
  106. package/src/service/evolution-query-service.ts +405 -0
  107. package/src/service/evolution-worker.ts +1646 -0
  108. package/src/service/health-query-service.ts +836 -0
  109. package/{dist/service/nocturnal-runtime.js → src/service/nocturnal-runtime.ts} +235 -79
  110. package/src/service/nocturnal-service.ts +1015 -0
  111. package/src/service/nocturnal-target-selector.ts +532 -0
  112. package/src/service/phase3-input-filter.ts +237 -0
  113. package/src/service/runtime-summary-service.ts +757 -0
  114. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +513 -0
  115. package/{dist/service/subagent-workflow/empathy-observer-workflow-manager.js → src/service/subagent-workflow/empathy-observer-workflow-manager.ts} +240 -117
  116. package/src/service/subagent-workflow/index.ts +51 -0
  117. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +856 -0
  118. package/src/service/subagent-workflow/runtime-direct-driver.ts +166 -0
  119. package/{dist/service/subagent-workflow/types.d.ts → src/service/subagent-workflow/types.ts} +137 -18
  120. package/src/service/subagent-workflow/workflow-store.ts +328 -0
  121. package/src/service/trajectory-service.ts +15 -0
  122. package/{dist/tools/critique-prompt.js → src/tools/critique-prompt.ts} +25 -8
  123. package/src/tools/deep-reflect.ts +349 -0
  124. package/{dist/tools/model-index.js → src/tools/model-index.ts} +33 -17
  125. package/src/types/event-types.ts +453 -0
  126. package/src/types/hygiene-types.ts +31 -0
  127. package/src/types/principle-tree-schema.ts +244 -0
  128. package/src/types/runtime-summary.ts +49 -0
  129. package/src/types.ts +74 -0
  130. package/src/utils/file-lock.ts +391 -0
  131. package/{dist/utils/glob-match.js → src/utils/glob-match.ts} +21 -20
  132. package/{dist/utils/hashing.js → src/utils/hashing.ts} +6 -4
  133. package/src/utils/io.ts +110 -0
  134. package/{dist/utils/nlp.js → src/utils/nlp.ts} +19 -12
  135. package/{dist/utils/plugin-logger.js → src/utils/plugin-logger.ts} +33 -8
  136. package/src/utils/subagent-probe.ts +94 -0
  137. package/templates/langs/en/skills/ai-sprint-orchestration/EXAMPLES.md +63 -0
  138. package/templates/langs/en/skills/ai-sprint-orchestration/REFERENCE.md +136 -0
  139. package/templates/langs/en/skills/ai-sprint-orchestration/SKILL.md +67 -0
  140. package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +214 -0
  141. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +107 -0
  142. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +107 -0
  143. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +105 -0
  144. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +108 -0
  145. package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +58 -0
  146. package/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +190 -0
  147. package/templates/langs/en/skills/ai-sprint-orchestration/runtime/.gitignore +2 -0
  148. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +310 -0
  149. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +683 -0
  150. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +604 -0
  151. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +32 -0
  152. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +707 -0
  153. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +3419 -0
  154. package/templates/langs/zh/skills/ai-sprint-orchestration/EXAMPLES.md +63 -0
  155. package/templates/langs/zh/skills/ai-sprint-orchestration/REFERENCE.md +136 -0
  156. package/templates/langs/zh/skills/ai-sprint-orchestration/SKILL.md +67 -0
  157. package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +214 -0
  158. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +107 -0
  159. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +107 -0
  160. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +105 -0
  161. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +108 -0
  162. package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +58 -0
  163. package/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +190 -0
  164. package/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +2 -0
  165. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +310 -0
  166. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +683 -0
  167. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +604 -0
  168. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +32 -0
  169. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +707 -0
  170. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +3419 -0
  171. package/templates/langs/zh/skills/ai-sprint-orchestration/test/archive.test.mjs +230 -0
  172. package/templates/langs/zh/skills/ai-sprint-orchestration/test/contract-enforcement.test.mjs +672 -0
  173. package/templates/langs/zh/skills/ai-sprint-orchestration/test/decision.test.mjs +1321 -0
  174. package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +1419 -0
  175. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +70 -1
  176. package/templates/pain_settings.json +2 -1
  177. package/tests/README.md +120 -0
  178. package/tests/build-artifacts.test.ts +111 -0
  179. package/tests/commands/evolution-status.test.ts +222 -0
  180. package/tests/commands/evolver.test.ts +22 -0
  181. package/tests/commands/export.test.ts +78 -0
  182. package/tests/commands/nocturnal-review.test.ts +448 -0
  183. package/tests/commands/nocturnal-train.test.ts +97 -0
  184. package/tests/commands/pain.test.ts +108 -0
  185. package/tests/commands/samples.test.ts +65 -0
  186. package/tests/commands/strategy.test.ts +34 -0
  187. package/tests/commands/thinking-os.test.ts +88 -0
  188. package/tests/core/adaptive-thresholds.test.ts +261 -0
  189. package/tests/core/config-service.test.ts +89 -0
  190. package/tests/core/config.test.ts +90 -0
  191. package/tests/core/control-ui-db.test.ts +75 -0
  192. package/tests/core/core-template-guidance.test.ts +21 -0
  193. package/tests/core/detection-funnel.test.ts +63 -0
  194. package/tests/core/detection-service.test.ts +50 -0
  195. package/tests/core/dictionary-service.test.ts +116 -0
  196. package/tests/core/dictionary.test.ts +168 -0
  197. package/tests/core/empathy-keyword-matcher.test.ts +209 -0
  198. package/tests/core/event-log.test.ts +181 -0
  199. package/tests/core/evolution-e2e.test.ts +58 -0
  200. package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
  201. package/tests/core/evolution-engine.test.ts +562 -0
  202. package/tests/core/evolution-logger.test.ts +148 -0
  203. package/tests/core/evolution-migration.test.ts +50 -0
  204. package/tests/core/evolution-paths.test.ts +21 -0
  205. package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
  206. package/tests/core/evolution-reducer.test.ts +180 -0
  207. package/tests/core/evolution-types-loop.test.ts +48 -0
  208. package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
  209. package/tests/core/external-training-contract.test.ts +463 -0
  210. package/tests/core/focus-history.test.ts +682 -0
  211. package/tests/core/init-flatten.test.ts +69 -0
  212. package/tests/core/init-refactor.test.ts +87 -0
  213. package/tests/core/init-v1.3.test.ts +46 -0
  214. package/tests/core/init.test.ts +190 -0
  215. package/tests/core/local-worker-routing.test.ts +757 -0
  216. package/tests/core/migration.test.ts +84 -0
  217. package/tests/core/model-deployment-registry.test.ts +845 -0
  218. package/tests/core/model-training-registry.test.ts +889 -0
  219. package/tests/core/nocturnal-arbiter.test.ts +494 -0
  220. package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
  221. package/tests/core/nocturnal-compliance.test.ts +646 -0
  222. package/tests/core/nocturnal-dataset.test.ts +892 -0
  223. package/tests/core/nocturnal-executability.test.ts +357 -0
  224. package/tests/core/nocturnal-export.test.ts +462 -0
  225. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
  226. package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
  227. package/tests/core/nocturnal-trinity.test.ts +953 -0
  228. package/tests/core/pain.test.ts +33 -0
  229. package/tests/core/path-resolver.test.ts +57 -0
  230. package/tests/core/paths-refactor.test.ts +42 -0
  231. package/tests/core/phase7-rollout-integration.test.ts +477 -0
  232. package/tests/core/principle-training-state.test.ts +712 -0
  233. package/tests/core/profile.test.ts +56 -0
  234. package/tests/core/promotion-gate.test.ts +556 -0
  235. package/tests/core/risk-calculator.test.ts +168 -0
  236. package/tests/core/session-tracker.test.ts +191 -0
  237. package/tests/core/training-program.test.ts +472 -0
  238. package/tests/core/trajectory.test.ts +265 -0
  239. package/tests/core/workspace-context-factory.test.ts +18 -0
  240. package/tests/core/workspace-context.test.ts +134 -0
  241. package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
  242. package/tests/fixtures/production-compatibility.test.ts +147 -0
  243. package/tests/fixtures/production-mock-generator.ts +282 -0
  244. package/tests/hooks/bash-risk-integration.test.ts +137 -0
  245. package/tests/hooks/bash-risk.test.ts +81 -0
  246. package/tests/hooks/edit-verification.test.ts +678 -0
  247. package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
  248. package/tests/hooks/gate-edit-verification.test.ts +435 -0
  249. package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
  250. package/tests/hooks/gate.test.ts +271 -0
  251. package/tests/hooks/gfi-gate-unit.test.ts +422 -0
  252. package/tests/hooks/gfi-gate.test.ts +669 -0
  253. package/tests/hooks/lifecycle.test.ts +248 -0
  254. package/tests/hooks/llm.test.ts +308 -0
  255. package/tests/hooks/message-sanitize.test.ts +36 -0
  256. package/tests/hooks/pain.test.ts +141 -0
  257. package/tests/hooks/progressive-trust-gate.test.ts +277 -0
  258. package/tests/hooks/prompt.test.ts +1411 -0
  259. package/tests/hooks/subagent.test.ts +467 -0
  260. package/tests/hooks/thinking-gate.test.ts +313 -0
  261. package/tests/http/principles-console-route.test.ts +140 -0
  262. package/tests/hygiene-tracker.test.ts +77 -0
  263. package/tests/index.integration.test.ts +179 -0
  264. package/tests/index.shadow-routing.integration.test.ts +140 -0
  265. package/tests/index.test.ts +9 -0
  266. package/tests/integration/empathy-workflow-integration.test.ts +627 -0
  267. package/tests/service/control-ui-query-service.test.ts +121 -0
  268. package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
  269. package/tests/service/evolution-worker.test.ts +585 -0
  270. package/tests/service/nocturnal-runtime.test.ts +470 -0
  271. package/tests/service/nocturnal-service.test.ts +577 -0
  272. package/tests/service/nocturnal-target-selector.test.ts +615 -0
  273. package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
  274. package/tests/service/phase3-input-filter.test.ts +289 -0
  275. package/tests/service/runtime-summary-service.test.ts +919 -0
  276. package/tests/task-compliance.test.ts +166 -0
  277. package/tests/test-utils.ts +48 -0
  278. package/tests/tools/critique-prompt.test.ts +260 -0
  279. package/tests/tools/deep-reflect.test.ts +232 -0
  280. package/tests/tools/model-index.test.ts +246 -0
  281. package/tests/ui/app.test.tsx +114 -0
  282. package/tests/utils/file-lock.test.ts +407 -0
  283. package/tests/utils/hashing.test.ts +32 -0
  284. package/tests/utils/io.test.ts +39 -0
  285. package/tests/utils/nlp.test.ts +53 -0
  286. package/tests/utils/plugin-logger.test.ts +156 -0
  287. package/tsconfig.json +16 -0
  288. package/tsconfig.tsbuildinfo +1 -0
  289. package/ui/src/App.tsx +45 -0
  290. package/ui/src/api.ts +216 -0
  291. package/ui/src/charts.tsx +586 -0
  292. package/ui/src/components/ErrorState.tsx +6 -0
  293. package/ui/src/components/Loading.tsx +13 -0
  294. package/ui/src/components/ProtectedRoute.tsx +12 -0
  295. package/ui/src/components/Shell.tsx +91 -0
  296. package/ui/src/components/WorkspaceConfig.tsx +146 -0
  297. package/ui/src/components/index.ts +5 -0
  298. package/ui/src/context/auth.tsx +80 -0
  299. package/ui/src/context/theme.tsx +66 -0
  300. package/ui/src/hooks/useAutoRefresh.ts +39 -0
  301. package/ui/src/i18n/ui.ts +363 -0
  302. package/ui/src/main.tsx +16 -0
  303. package/ui/src/pages/EvolutionPage.tsx +352 -0
  304. package/ui/src/pages/FeedbackPage.tsx +140 -0
  305. package/ui/src/pages/GateMonitorPage.tsx +136 -0
  306. package/ui/src/pages/LoginPage.tsx +88 -0
  307. package/ui/src/pages/OverviewPage.tsx +238 -0
  308. package/ui/src/pages/SamplesPage.tsx +174 -0
  309. package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
  310. package/ui/src/styles.css +1661 -0
  311. package/ui/src/types.ts +368 -0
  312. package/ui/src/utils/format.ts +15 -0
  313. package/vitest.config.ts +23 -0
  314. package/dist/commands/capabilities.d.ts +0 -3
  315. package/dist/commands/capabilities.js +0 -73
  316. package/dist/commands/context.d.ts +0 -5
  317. package/dist/commands/evolution-status.d.ts +0 -4
  318. package/dist/commands/evolution-status.js +0 -117
  319. package/dist/commands/evolver.d.ts +0 -9
  320. package/dist/commands/evolver.js +0 -26
  321. package/dist/commands/export.d.ts +0 -2
  322. package/dist/commands/export.js +0 -98
  323. package/dist/commands/focus.d.ts +0 -14
  324. package/dist/commands/focus.js +0 -457
  325. package/dist/commands/nocturnal-review.d.ts +0 -24
  326. package/dist/commands/nocturnal-review.js +0 -265
  327. package/dist/commands/nocturnal-rollout.d.ts +0 -27
  328. package/dist/commands/nocturnal-rollout.js +0 -671
  329. package/dist/commands/nocturnal-train.d.ts +0 -25
  330. package/dist/commands/nocturnal-train.js +0 -919
  331. package/dist/commands/pain.d.ts +0 -5
  332. package/dist/commands/principle-rollback.d.ts +0 -4
  333. package/dist/commands/principle-rollback.js +0 -22
  334. package/dist/commands/rollback.d.ts +0 -19
  335. package/dist/commands/samples.d.ts +0 -2
  336. package/dist/commands/samples.js +0 -55
  337. package/dist/commands/strategy.d.ts +0 -3
  338. package/dist/commands/strategy.js +0 -29
  339. package/dist/commands/thinking-os.d.ts +0 -2
  340. package/dist/config/defaults/runtime.d.ts +0 -40
  341. package/dist/config/errors.d.ts +0 -84
  342. package/dist/config/errors.js +0 -94
  343. package/dist/config/index.js +0 -7
  344. package/dist/constants/diagnostician.d.ts +0 -12
  345. package/dist/constants/diagnostician.js +0 -56
  346. package/dist/constants/tools.d.ts +0 -17
  347. package/dist/constants/tools.js +0 -54
  348. package/dist/core/adaptive-thresholds.d.ts +0 -186
  349. package/dist/core/adaptive-thresholds.js +0 -300
  350. package/dist/core/config-service.d.ts +0 -15
  351. package/dist/core/config.d.ts +0 -129
  352. package/dist/core/control-ui-db.d.ts +0 -95
  353. package/dist/core/control-ui-db.js +0 -292
  354. package/dist/core/detection-funnel.d.ts +0 -33
  355. package/dist/core/detection-service.d.ts +0 -15
  356. package/dist/core/dictionary-service.d.ts +0 -15
  357. package/dist/core/dictionary.d.ts +0 -38
  358. package/dist/core/event-log.d.ts +0 -82
  359. package/dist/core/event-log.js +0 -463
  360. package/dist/core/evolution-engine.d.ts +0 -118
  361. package/dist/core/evolution-engine.js +0 -464
  362. package/dist/core/evolution-logger.d.ts +0 -137
  363. package/dist/core/evolution-logger.js +0 -256
  364. package/dist/core/evolution-migration.d.ts +0 -5
  365. package/dist/core/evolution-migration.js +0 -65
  366. package/dist/core/evolution-reducer.d.ts +0 -98
  367. package/dist/core/evolution-reducer.js +0 -465
  368. package/dist/core/evolution-types.d.ts +0 -287
  369. package/dist/core/evolution-types.js +0 -78
  370. package/dist/core/external-training-contract.d.ts +0 -276
  371. package/dist/core/external-training-contract.js +0 -269
  372. package/dist/core/focus-history.d.ts +0 -210
  373. package/dist/core/focus-history.js +0 -1185
  374. package/dist/core/hygiene/tracker.d.ts +0 -22
  375. package/dist/core/hygiene/tracker.js +0 -106
  376. package/dist/core/init.d.ts +0 -12
  377. package/dist/core/local-worker-routing.d.ts +0 -175
  378. package/dist/core/local-worker-routing.js +0 -525
  379. package/dist/core/migration.d.ts +0 -6
  380. package/dist/core/model-deployment-registry.d.ts +0 -218
  381. package/dist/core/model-deployment-registry.js +0 -503
  382. package/dist/core/model-training-registry.d.ts +0 -295
  383. package/dist/core/model-training-registry.js +0 -475
  384. package/dist/core/nocturnal-arbiter.d.ts +0 -159
  385. package/dist/core/nocturnal-arbiter.js +0 -534
  386. package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
  387. package/dist/core/nocturnal-candidate-scoring.js +0 -266
  388. package/dist/core/nocturnal-compliance.d.ts +0 -175
  389. package/dist/core/nocturnal-compliance.js +0 -824
  390. package/dist/core/nocturnal-dataset.d.ts +0 -224
  391. package/dist/core/nocturnal-dataset.js +0 -443
  392. package/dist/core/nocturnal-executability.d.ts +0 -85
  393. package/dist/core/nocturnal-executability.js +0 -331
  394. package/dist/core/nocturnal-export.d.ts +0 -124
  395. package/dist/core/nocturnal-export.js +0 -275
  396. package/dist/core/nocturnal-paths.d.ts +0 -124
  397. package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
  398. package/dist/core/nocturnal-trajectory-extractor.js +0 -307
  399. package/dist/core/nocturnal-trinity.d.ts +0 -311
  400. package/dist/core/nocturnal-trinity.js +0 -880
  401. package/dist/core/pain.d.ts +0 -4
  402. package/dist/core/pain.js +0 -70
  403. package/dist/core/path-resolver.d.ts +0 -46
  404. package/dist/core/paths.d.ts +0 -65
  405. package/dist/core/principle-training-state.d.ts +0 -121
  406. package/dist/core/principle-training-state.js +0 -321
  407. package/dist/core/profile.d.ts +0 -62
  408. package/dist/core/profile.js +0 -210
  409. package/dist/core/promotion-gate.d.ts +0 -238
  410. package/dist/core/promotion-gate.js +0 -529
  411. package/dist/core/risk-calculator.d.ts +0 -22
  412. package/dist/core/session-tracker.d.ts +0 -101
  413. package/dist/core/shadow-observation-registry.d.ts +0 -217
  414. package/dist/core/shadow-observation-registry.js +0 -308
  415. package/dist/core/system-logger.d.ts +0 -8
  416. package/dist/core/thinking-models.d.ts +0 -38
  417. package/dist/core/thinking-models.js +0 -170
  418. package/dist/core/training-program.d.ts +0 -233
  419. package/dist/core/training-program.js +0 -433
  420. package/dist/core/trajectory.d.ts +0 -411
  421. package/dist/core/trajectory.js +0 -1307
  422. package/dist/core/workspace-context.d.ts +0 -71
  423. package/dist/hooks/bash-risk.d.ts +0 -57
  424. package/dist/hooks/bash-risk.js +0 -137
  425. package/dist/hooks/edit-verification.d.ts +0 -62
  426. package/dist/hooks/edit-verification.js +0 -256
  427. package/dist/hooks/gate-block-helper.d.ts +0 -44
  428. package/dist/hooks/gate-block-helper.js +0 -119
  429. package/dist/hooks/gate.d.ts +0 -24
  430. package/dist/hooks/gate.js +0 -173
  431. package/dist/hooks/gfi-gate.d.ts +0 -40
  432. package/dist/hooks/gfi-gate.js +0 -113
  433. package/dist/hooks/lifecycle.d.ts +0 -5
  434. package/dist/hooks/lifecycle.js +0 -284
  435. package/dist/hooks/llm.d.ts +0 -13
  436. package/dist/hooks/message-sanitize.d.ts +0 -3
  437. package/dist/hooks/message-sanitize.js +0 -37
  438. package/dist/hooks/pain.d.ts +0 -5
  439. package/dist/hooks/pain.js +0 -301
  440. package/dist/hooks/progressive-trust-gate.d.ts +0 -52
  441. package/dist/hooks/progressive-trust-gate.js +0 -134
  442. package/dist/hooks/prompt.d.ts +0 -49
  443. package/dist/hooks/prompt.js +0 -905
  444. package/dist/hooks/subagent.d.ts +0 -10
  445. package/dist/hooks/subagent.js +0 -387
  446. package/dist/hooks/thinking-checkpoint.d.ts +0 -37
  447. package/dist/hooks/thinking-checkpoint.js +0 -51
  448. package/dist/hooks/trajectory-collector.d.ts +0 -32
  449. package/dist/hooks/trajectory-collector.js +0 -256
  450. package/dist/http/principles-console-route.d.ts +0 -9
  451. package/dist/http/principles-console-route.js +0 -681
  452. package/dist/i18n/commands.d.ts +0 -26
  453. package/dist/i18n/commands.js +0 -116
  454. package/dist/index.d.ts +0 -7
  455. package/dist/index.js +0 -581
  456. package/dist/service/central-database.d.ts +0 -104
  457. package/dist/service/central-database.js +0 -649
  458. package/dist/service/control-ui-query-service.d.ts +0 -221
  459. package/dist/service/control-ui-query-service.js +0 -543
  460. package/dist/service/empathy-observer-manager.d.ts +0 -88
  461. package/dist/service/empathy-observer-manager.js +0 -414
  462. package/dist/service/evolution-query-service.d.ts +0 -155
  463. package/dist/service/evolution-query-service.js +0 -258
  464. package/dist/service/evolution-worker.d.ts +0 -101
  465. package/dist/service/evolution-worker.js +0 -975
  466. package/dist/service/health-query-service.d.ts +0 -170
  467. package/dist/service/health-query-service.js +0 -662
  468. package/dist/service/nocturnal-runtime.d.ts +0 -183
  469. package/dist/service/nocturnal-service.d.ts +0 -163
  470. package/dist/service/nocturnal-service.js +0 -787
  471. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  472. package/dist/service/nocturnal-target-selector.js +0 -315
  473. package/dist/service/phase3-input-filter.d.ts +0 -73
  474. package/dist/service/phase3-input-filter.js +0 -172
  475. package/dist/service/runtime-summary-service.d.ts +0 -122
  476. package/dist/service/runtime-summary-service.js +0 -485
  477. package/dist/service/subagent-workflow/empathy-observer-workflow-manager.d.ts +0 -48
  478. package/dist/service/subagent-workflow/index.d.ts +0 -4
  479. package/dist/service/subagent-workflow/index.js +0 -3
  480. package/dist/service/subagent-workflow/runtime-direct-driver.d.ts +0 -77
  481. package/dist/service/subagent-workflow/runtime-direct-driver.js +0 -75
  482. package/dist/service/subagent-workflow/types.js +0 -11
  483. package/dist/service/subagent-workflow/workflow-store.d.ts +0 -26
  484. package/dist/service/subagent-workflow/workflow-store.js +0 -165
  485. package/dist/service/trajectory-service.d.ts +0 -2
  486. package/dist/service/trajectory-service.js +0 -15
  487. package/dist/tools/critique-prompt.d.ts +0 -14
  488. package/dist/tools/deep-reflect.d.ts +0 -39
  489. package/dist/tools/deep-reflect.js +0 -350
  490. package/dist/tools/model-index.d.ts +0 -9
  491. package/dist/types/event-types.d.ts +0 -306
  492. package/dist/types/event-types.js +0 -106
  493. package/dist/types/hygiene-types.d.ts +0 -20
  494. package/dist/types/hygiene-types.js +0 -12
  495. package/dist/types/runtime-summary.d.ts +0 -47
  496. package/dist/types/runtime-summary.js +0 -1
  497. package/dist/types.d.ts +0 -50
  498. package/dist/types.js +0 -22
  499. package/dist/utils/file-lock.d.ts +0 -71
  500. package/dist/utils/file-lock.js +0 -309
  501. package/dist/utils/glob-match.d.ts +0 -28
  502. package/dist/utils/hashing.d.ts +0 -9
  503. package/dist/utils/io.d.ts +0 -6
  504. package/dist/utils/io.js +0 -106
  505. package/dist/utils/nlp.d.ts +0 -9
  506. package/dist/utils/plugin-logger.d.ts +0 -39
  507. package/dist/utils/subagent-probe.d.ts +0 -34
  508. package/dist/utils/subagent-probe.js +0 -81
@@ -0,0 +1,953 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import {
3
+ runTrinity,
4
+ runTrinityAsync,
5
+ validateDraftArtifact,
6
+ draftToArtifact,
7
+ DEFAULT_TRINITY_CONFIG,
8
+ type TrinityConfig,
9
+ type DreamerOutput,
10
+ type PhilosopherOutput,
11
+ type TrinityDraftArtifact,
12
+ type TrinityRuntimeAdapter,
13
+ } from '../../src/core/nocturnal-trinity.js';
14
+ import {
15
+ validateDreamerOutput,
16
+ validatePhilosopherOutput,
17
+ validateTrinityDraft,
18
+ } from '../../src/core/nocturnal-arbiter.js';
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // Test Fixtures
22
+ // ---------------------------------------------------------------------------
23
+
24
+ function makeSnapshot(overrides: Partial<{
25
+ failureCount: number;
26
+ totalPainEvents: number;
27
+ totalGateBlocks: number;
28
+ }> = {}): {
29
+ sessionId: string;
30
+ stats: { failureCount: number; totalPainEvents: number; totalGateBlocks: number; totalAssistantTurns: number; totalToolCalls: number };
31
+ } {
32
+ return {
33
+ sessionId: 'session-test-123',
34
+ stats: {
35
+ failureCount: overrides.failureCount ?? 0,
36
+ totalPainEvents: overrides.totalPainEvents ?? 0,
37
+ totalGateBlocks: overrides.totalGateBlocks ?? 0,
38
+ totalAssistantTurns: 5,
39
+ totalToolCalls: 10,
40
+ },
41
+ };
42
+ }
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // Tests: validateDreamerOutput
46
+ // ---------------------------------------------------------------------------
47
+
48
+ describe('validateDreamerOutput', () => {
49
+ it('passes a valid Dreamer output with candidates', () => {
50
+ const output = {
51
+ valid: true,
52
+ candidates: [
53
+ {
54
+ candidateIndex: 0,
55
+ badDecision: 'Did something wrong',
56
+ betterDecision: 'Do it right',
57
+ rationale: 'Because the principle says so',
58
+ confidence: 0.9,
59
+ },
60
+ ],
61
+ generatedAt: '2026-03-27T12:00:00.000Z',
62
+ };
63
+ const result = validateDreamerOutput(output);
64
+ expect(result.valid).toBe(true);
65
+ expect(result.failures).toHaveLength(0);
66
+ });
67
+
68
+ it('passes a valid Dreamer output with multiple candidates', () => {
69
+ const output = {
70
+ valid: true,
71
+ candidates: [
72
+ {
73
+ candidateIndex: 0,
74
+ badDecision: 'Did something wrong',
75
+ betterDecision: 'Do it right',
76
+ rationale: 'Because the principle says so',
77
+ confidence: 0.9,
78
+ },
79
+ {
80
+ candidateIndex: 1,
81
+ badDecision: 'Did another wrong thing',
82
+ betterDecision: 'Do it differently',
83
+ rationale: 'Alternative approach is better',
84
+ confidence: 0.8,
85
+ },
86
+ ],
87
+ generatedAt: '2026-03-27T12:00:00.000Z',
88
+ };
89
+ const result = validateDreamerOutput(output);
90
+ expect(result.valid).toBe(true);
91
+ expect(result.failures).toHaveLength(0);
92
+ });
93
+
94
+ it('rejects Dreamer output marked invalid', () => {
95
+ const output = {
96
+ valid: false,
97
+ candidates: [],
98
+ reason: 'No signal found',
99
+ generatedAt: '2026-03-27T12:00:00.000Z',
100
+ };
101
+ const result = validateDreamerOutput(output);
102
+ expect(result.valid).toBe(false);
103
+ expect(result.failures.some(f => f.includes('marked invalid'))).toBe(true);
104
+ });
105
+
106
+ it('rejects Dreamer output marked invalid without reason', () => {
107
+ const output = {
108
+ valid: false,
109
+ candidates: [],
110
+ generatedAt: '2026-03-27T12:00:00.000Z',
111
+ };
112
+ const result = validateDreamerOutput(output);
113
+ expect(result.valid).toBe(false);
114
+ });
115
+
116
+ it('rejects Dreamer output without candidates array', () => {
117
+ const output = {
118
+ valid: true,
119
+ generatedAt: '2026-03-27T12:00:00.000Z',
120
+ };
121
+ const result = validateDreamerOutput(output);
122
+ expect(result.valid).toBe(false);
123
+ expect(result.failures.some(f => f.includes('candidates array'))).toBe(true);
124
+ });
125
+
126
+ it('rejects Dreamer candidate missing required fields', () => {
127
+ const output = {
128
+ valid: true,
129
+ candidates: [
130
+ {
131
+ candidateIndex: 0,
132
+ badDecision: 'Has badDecision but missing betterDecision',
133
+ // missing: betterDecision, rationale, confidence
134
+ },
135
+ ],
136
+ generatedAt: '2026-03-27T12:00:00.000Z',
137
+ };
138
+ const result = validateDreamerOutput(output);
139
+ expect(result.valid).toBe(false);
140
+ expect(result.failures.some(f => f.includes('betterDecision'))).toBe(true);
141
+ expect(result.failures.some(f => f.includes('rationale'))).toBe(true);
142
+ expect(result.failures.some(f => f.includes('confidence'))).toBe(true);
143
+ });
144
+
145
+ it('rejects Dreamer candidate with invalid confidence (out of range)', () => {
146
+ const output = {
147
+ valid: true,
148
+ candidates: [
149
+ {
150
+ candidateIndex: 0,
151
+ badDecision: 'Wrong',
152
+ betterDecision: 'Right',
153
+ rationale: 'Because',
154
+ confidence: 1.5, // out of range
155
+ },
156
+ ],
157
+ generatedAt: '2026-03-27T12:00:00.000Z',
158
+ };
159
+ const result = validateDreamerOutput(output);
160
+ expect(result.valid).toBe(false);
161
+ expect(result.failures.some(f => f.includes('confidence'))).toBe(true);
162
+ });
163
+
164
+ it('rejects Dreamer candidate with duplicate candidateIndex', () => {
165
+ const output = {
166
+ valid: true,
167
+ candidates: [
168
+ {
169
+ candidateIndex: 0,
170
+ badDecision: 'Wrong 1',
171
+ betterDecision: 'Right 1',
172
+ rationale: 'Because 1',
173
+ confidence: 0.9,
174
+ },
175
+ {
176
+ candidateIndex: 0, // duplicate
177
+ badDecision: 'Wrong 2',
178
+ betterDecision: 'Right 2',
179
+ rationale: 'Because 2',
180
+ confidence: 0.8,
181
+ },
182
+ ],
183
+ generatedAt: '2026-03-27T12:00:00.000Z',
184
+ };
185
+ const result = validateDreamerOutput(output);
186
+ expect(result.valid).toBe(false);
187
+ expect(result.failures.some(f => f.includes('duplicate'))).toBe(true);
188
+ });
189
+
190
+ it('rejects Dreamer candidate with identical badDecision and betterDecision', () => {
191
+ const output = {
192
+ valid: true,
193
+ candidates: [
194
+ {
195
+ candidateIndex: 0,
196
+ badDecision: 'Do the same thing',
197
+ betterDecision: 'Do the same thing', // identical
198
+ rationale: 'Because it is correct',
199
+ confidence: 0.9,
200
+ },
201
+ ],
202
+ generatedAt: '2026-03-27T12:00:00.000Z',
203
+ };
204
+ const result = validateDreamerOutput(output);
205
+ expect(result.valid).toBe(false);
206
+ expect(result.failures.some(f => f.includes('identical'))).toBe(true);
207
+ });
208
+
209
+ it('rejects Dreamer output missing generatedAt', () => {
210
+ const output = {
211
+ valid: true,
212
+ candidates: [
213
+ {
214
+ candidateIndex: 0,
215
+ badDecision: 'Wrong',
216
+ betterDecision: 'Right',
217
+ rationale: 'Because',
218
+ confidence: 0.9,
219
+ },
220
+ ],
221
+ // missing generatedAt
222
+ };
223
+ const result = validateDreamerOutput(output);
224
+ expect(result.valid).toBe(false);
225
+ expect(result.failures.some(f => f.includes('generatedAt'))).toBe(true);
226
+ });
227
+
228
+ it('rejects non-object input', () => {
229
+ const result = validateDreamerOutput(null);
230
+ expect(result.valid).toBe(false);
231
+ });
232
+
233
+ it('rejects string input', () => {
234
+ const result = validateDreamerOutput('not an object');
235
+ expect(result.valid).toBe(false);
236
+ });
237
+ });
238
+
239
+ // ---------------------------------------------------------------------------
240
+ // Tests: validatePhilosopherOutput
241
+ // ---------------------------------------------------------------------------
242
+
243
+ describe('validatePhilosopherOutput', () => {
244
+ it('passes a valid Philosopher output', () => {
245
+ const output = {
246
+ valid: true,
247
+ judgments: [
248
+ {
249
+ candidateIndex: 0,
250
+ critique: 'Strong alignment',
251
+ principleAligned: true,
252
+ score: 0.92,
253
+ rank: 1,
254
+ },
255
+ ],
256
+ overallAssessment: 'Good candidate set',
257
+ generatedAt: '2026-03-27T12:00:00.000Z',
258
+ };
259
+ const result = validatePhilosopherOutput(output);
260
+ expect(result.valid).toBe(true);
261
+ expect(result.failures).toHaveLength(0);
262
+ });
263
+
264
+ it('rejects Philosopher output marked invalid', () => {
265
+ const output = {
266
+ valid: false,
267
+ judgments: [],
268
+ reason: 'No candidates to judge',
269
+ generatedAt: '2026-03-27T12:00:00.000Z',
270
+ };
271
+ const result = validatePhilosopherOutput(output);
272
+ expect(result.valid).toBe(false);
273
+ });
274
+
275
+ it('rejects Philosopher output without judgments array', () => {
276
+ const output = {
277
+ valid: true,
278
+ overallAssessment: 'Good',
279
+ generatedAt: '2026-03-27T12:00:00.000Z',
280
+ };
281
+ const result = validatePhilosopherOutput(output);
282
+ expect(result.valid).toBe(false);
283
+ expect(result.failures.some(f => f.includes('judgments array'))).toBe(true);
284
+ });
285
+
286
+ it('rejects Philosopher judgment missing required fields', () => {
287
+ const output = {
288
+ valid: true,
289
+ judgments: [
290
+ {
291
+ candidateIndex: 0,
292
+ // missing: critique, principleAligned, score, rank
293
+ },
294
+ ],
295
+ overallAssessment: 'Good',
296
+ generatedAt: '2026-03-27T12:00:00.000Z',
297
+ };
298
+ const result = validatePhilosopherOutput(output);
299
+ expect(result.valid).toBe(false);
300
+ });
301
+
302
+ it('rejects Philosopher judgment with invalid score (out of range)', () => {
303
+ const output = {
304
+ valid: true,
305
+ judgments: [
306
+ {
307
+ candidateIndex: 0,
308
+ critique: 'Good',
309
+ principleAligned: true,
310
+ score: 1.5, // out of range
311
+ rank: 1,
312
+ },
313
+ ],
314
+ overallAssessment: 'Good',
315
+ generatedAt: '2026-03-27T12:00:00.000Z',
316
+ };
317
+ const result = validatePhilosopherOutput(output);
318
+ expect(result.valid).toBe(false);
319
+ expect(result.failures.some(f => f.includes('score'))).toBe(true);
320
+ });
321
+
322
+ it('rejects Philosopher judgment with invalid rank (must be >= 1)', () => {
323
+ const output = {
324
+ valid: true,
325
+ judgments: [
326
+ {
327
+ candidateIndex: 0,
328
+ critique: 'Good',
329
+ principleAligned: true,
330
+ score: 0.9,
331
+ rank: 0, // invalid
332
+ },
333
+ ],
334
+ overallAssessment: 'Good',
335
+ generatedAt: '2026-03-27T12:00:00.000Z',
336
+ };
337
+ const result = validatePhilosopherOutput(output);
338
+ expect(result.valid).toBe(false);
339
+ expect(result.failures.some(f => f.includes('rank'))).toBe(true);
340
+ });
341
+
342
+ it('rejects Philosopher output with non-sequential ranks', () => {
343
+ const output = {
344
+ valid: true,
345
+ judgments: [
346
+ {
347
+ candidateIndex: 0,
348
+ critique: 'Good',
349
+ principleAligned: true,
350
+ score: 0.9,
351
+ rank: 1,
352
+ },
353
+ {
354
+ candidateIndex: 1,
355
+ critique: 'Also good',
356
+ principleAligned: true,
357
+ score: 0.8,
358
+ rank: 3, // should be 2
359
+ },
360
+ ],
361
+ overallAssessment: 'Good',
362
+ generatedAt: '2026-03-27T12:00:00.000Z',
363
+ };
364
+ const result = validatePhilosopherOutput(output);
365
+ expect(result.valid).toBe(false);
366
+ expect(result.failures.some(f => f.includes('sequential ranks'))).toBe(true);
367
+ });
368
+
369
+ it('rejects Philosopher output missing overallAssessment', () => {
370
+ const output = {
371
+ valid: true,
372
+ judgments: [
373
+ {
374
+ candidateIndex: 0,
375
+ critique: 'Good',
376
+ principleAligned: true,
377
+ score: 0.9,
378
+ rank: 1,
379
+ },
380
+ ],
381
+ // missing overallAssessment
382
+ generatedAt: '2026-03-27T12:00:00.000Z',
383
+ };
384
+ const result = validatePhilosopherOutput(output);
385
+ expect(result.valid).toBe(false);
386
+ expect(result.failures.some(f => f.includes('overallAssessment'))).toBe(true);
387
+ });
388
+ });
389
+
390
+ // ---------------------------------------------------------------------------
391
+ // Tests: validateTrinityDraft
392
+ // ---------------------------------------------------------------------------
393
+
394
+ describe('validateTrinityDraft', () => {
395
+ function makeValidDraft(overrides: Record<string, unknown> = {}): Record<string, unknown> {
396
+ return {
397
+ selectedCandidateIndex: 0,
398
+ badDecision: 'Did something wrong',
399
+ betterDecision: 'Do it right',
400
+ rationale: 'Because the principle says so and this is the right approach',
401
+ sessionId: 'session-test-123',
402
+ principleId: 'T-01',
403
+ sourceSnapshotRef: 'snapshot-test-001',
404
+ telemetry: {
405
+ chainMode: 'trinity',
406
+ dreamerPassed: true,
407
+ philosopherPassed: true,
408
+ scribePassed: true,
409
+ candidateCount: 3,
410
+ selectedCandidateIndex: 0,
411
+ stageFailures: [],
412
+ },
413
+ ...overrides,
414
+ };
415
+ }
416
+
417
+ it('passes a valid Trinity draft artifact', () => {
418
+ const draft = makeValidDraft();
419
+ const result = validateTrinityDraft(draft);
420
+ expect(result.valid).toBe(true);
421
+ expect(result.failures).toHaveLength(0);
422
+ });
423
+
424
+ it('rejects draft with missing badDecision', () => {
425
+ const draft = makeValidDraft();
426
+ delete draft.badDecision;
427
+ const result = validateTrinityDraft(draft);
428
+ expect(result.valid).toBe(false);
429
+ expect(result.failures.some(f => f.includes('badDecision'))).toBe(true);
430
+ });
431
+
432
+ it('rejects draft with empty badDecision', () => {
433
+ const draft = makeValidDraft({ badDecision: ' ' });
434
+ const result = validateTrinityDraft(draft);
435
+ expect(result.valid).toBe(false);
436
+ expect(result.failures.some(f => f.includes('badDecision'))).toBe(true);
437
+ });
438
+
439
+ it('rejects draft with short rationale (< 20 chars)', () => {
440
+ const draft = makeValidDraft({ rationale: 'Too short' });
441
+ const result = validateTrinityDraft(draft);
442
+ expect(result.valid).toBe(false);
443
+ expect(result.failures.some(f => f.includes('rationale'))).toBe(true);
444
+ });
445
+
446
+ it('rejects draft with identical badDecision and betterDecision', () => {
447
+ const draft = makeValidDraft({
448
+ badDecision: 'Same thing',
449
+ betterDecision: 'Same thing',
450
+ });
451
+ const result = validateTrinityDraft(draft);
452
+ expect(result.valid).toBe(false);
453
+ expect(result.failures.some(f => f.includes('identical'))).toBe(true);
454
+ });
455
+
456
+ it('rejects draft with invalid telemetry', () => {
457
+ const draft = makeValidDraft({ telemetry: null });
458
+ const result = validateTrinityDraft(draft);
459
+ expect(result.valid).toBe(false);
460
+ expect(result.failures.some(f => f.includes('telemetry'))).toBe(true);
461
+ });
462
+
463
+ it('rejects draft with invalid chainMode in telemetry', () => {
464
+ const draft = makeValidDraft({
465
+ telemetry: {
466
+ chainMode: 'invalid-mode', // must be 'trinity' or 'single-reflector'
467
+ dreamerPassed: true,
468
+ philosopherPassed: true,
469
+ scribePassed: true,
470
+ candidateCount: 3,
471
+ selectedCandidateIndex: 0,
472
+ stageFailures: [],
473
+ },
474
+ });
475
+ const result = validateTrinityDraft(draft);
476
+ expect(result.valid).toBe(false);
477
+ expect(result.failures.some(f => f.includes('chainMode'))).toBe(true);
478
+ });
479
+ });
480
+
481
+ // ---------------------------------------------------------------------------
482
+ // Tests: runTrinity — successful path
483
+ // ---------------------------------------------------------------------------
484
+
485
+ describe('runTrinity', () => {
486
+ it('produces a successful Trinity result with valid snapshot (failure signal)', () => {
487
+ const snapshot = makeSnapshot({ failureCount: 2 });
488
+ const config: TrinityConfig = {
489
+ useTrinity: true,
490
+ maxCandidates: 3,
491
+ useStubs: true, // Use stub implementations
492
+ };
493
+
494
+ const result = runTrinity({ snapshot, principleId: 'T-08', config });
495
+
496
+ expect(result.success).toBe(true);
497
+ expect(result.artifact).toBeDefined();
498
+ expect(result.telemetry.chainMode).toBe('trinity');
499
+ expect(result.telemetry.dreamerPassed).toBe(true);
500
+ expect(result.telemetry.philosopherPassed).toBe(true);
501
+ expect(result.telemetry.scribePassed).toBe(true);
502
+ expect(result.telemetry.candidateCount).toBeGreaterThan(0);
503
+ expect(result.telemetry.selectedCandidateIndex).toBeGreaterThanOrEqual(0);
504
+ expect(result.failures).toHaveLength(0);
505
+ expect(result.fallbackOccurred).toBe(false);
506
+ });
507
+
508
+ it('produces a successful Trinity result with pain signal', () => {
509
+ const snapshot = makeSnapshot({ totalPainEvents: 3 });
510
+ const config: TrinityConfig = {
511
+ useTrinity: true,
512
+ maxCandidates: 3,
513
+ useStubs: true,
514
+ };
515
+
516
+ const result = runTrinity({ snapshot, principleId: 'T-08', config });
517
+
518
+ expect(result.success).toBe(true);
519
+ expect(result.artifact).toBeDefined();
520
+ });
521
+
522
+ it('produces a successful Trinity result with gate block signal', () => {
523
+ const snapshot = makeSnapshot({ totalGateBlocks: 1 });
524
+ const config: TrinityConfig = {
525
+ useTrinity: true,
526
+ maxCandidates: 3,
527
+ useStubs: true,
528
+ };
529
+
530
+ const result = runTrinity({ snapshot, principleId: 'T-03', config });
531
+
532
+ expect(result.success).toBe(true);
533
+ expect(result.artifact).toBeDefined();
534
+ });
535
+
536
+ it('respects maxCandidates config', () => {
537
+ const snapshot = makeSnapshot({ failureCount: 5 });
538
+ const config: TrinityConfig = {
539
+ useTrinity: true,
540
+ maxCandidates: 2,
541
+ useStubs: true,
542
+ };
543
+
544
+ const result = runTrinity({ snapshot, principleId: 'T-08', config });
545
+
546
+ expect(result.success).toBe(true);
547
+ expect(result.telemetry.candidateCount).toBeLessThanOrEqual(2);
548
+ });
549
+ });
550
+
551
+ // ---------------------------------------------------------------------------
552
+ // Tests: runTrinity — failure paths
553
+ // ---------------------------------------------------------------------------
554
+
555
+ describe('runTrinity — failure paths', () => {
556
+ it('fails when snapshot has no signal and generates no candidates', () => {
557
+ // Snapshot with all zero stats - stub will fail to generate candidates
558
+ const snapshot = makeSnapshot({
559
+ failureCount: 0,
560
+ totalPainEvents: 0,
561
+ totalGateBlocks: 0,
562
+ });
563
+ const config: TrinityConfig = {
564
+ useTrinity: true,
565
+ maxCandidates: 3,
566
+ useStubs: true,
567
+ };
568
+
569
+ const result = runTrinity({ snapshot, principleId: 'T-08', config });
570
+
571
+ expect(result.success).toBe(false);
572
+ expect(result.failures.length).toBeGreaterThan(0);
573
+ expect(result.failures[0].stage).toBe('dreamer');
574
+ expect(result.telemetry.dreamerPassed).toBe(false);
575
+ });
576
+ });
577
+
578
+ // ---------------------------------------------------------------------------
579
+ // Tests: validateDraftArtifact
580
+ // ---------------------------------------------------------------------------
581
+
582
+ describe('validateDraftArtifact', () => {
583
+ function makeValidArtifact(): TrinityDraftArtifact {
584
+ return {
585
+ selectedCandidateIndex: 0,
586
+ badDecision: 'Did something wrong',
587
+ betterDecision: 'Do it right',
588
+ rationale: 'Because the principle says so and this is the correct approach',
589
+ sessionId: 'session-test-123',
590
+ principleId: 'T-01',
591
+ sourceSnapshotRef: 'snapshot-test-001',
592
+ telemetry: {
593
+ chainMode: 'trinity',
594
+ dreamerPassed: true,
595
+ philosopherPassed: true,
596
+ scribePassed: true,
597
+ candidateCount: 3,
598
+ selectedCandidateIndex: 0,
599
+ stageFailures: [],
600
+ },
601
+ };
602
+ }
603
+
604
+ it('passes a valid TrinityDraftArtifact', () => {
605
+ const artifact = makeValidArtifact();
606
+ const result = validateDraftArtifact(artifact);
607
+ expect(result.valid).toBe(true);
608
+ expect(result.failures).toHaveLength(0);
609
+ });
610
+
611
+ it('rejects artifact with missing badDecision', () => {
612
+ const artifact = makeValidArtifact();
613
+ delete (artifact as Record<string, unknown>).badDecision;
614
+ const result = validateDraftArtifact(artifact);
615
+ expect(result.valid).toBe(false);
616
+ });
617
+
618
+ it('rejects artifact with empty betterDecision', () => {
619
+ const artifact = makeValidArtifact();
620
+ artifact.betterDecision = ' ';
621
+ const result = validateDraftArtifact(artifact);
622
+ expect(result.valid).toBe(false);
623
+ });
624
+
625
+ it('rejects artifact with short rationale', () => {
626
+ const artifact = makeValidArtifact();
627
+ artifact.rationale = 'Too short';
628
+ const result = validateDraftArtifact(artifact);
629
+ expect(result.valid).toBe(false);
630
+ });
631
+
632
+ it('rejects artifact with identical badDecision and betterDecision', () => {
633
+ const artifact = makeValidArtifact();
634
+ artifact.badDecision = 'Same';
635
+ artifact.betterDecision = 'Same';
636
+ const result = validateDraftArtifact(artifact);
637
+ expect(result.valid).toBe(false);
638
+ expect(result.failures.some(f => f.includes('identical'))).toBe(true);
639
+ });
640
+ });
641
+
642
+ // ---------------------------------------------------------------------------
643
+ // Tests: draftToArtifact
644
+ // ---------------------------------------------------------------------------
645
+
646
+ describe('draftToArtifact', () => {
647
+ it('converts TrinityDraftArtifact to NocturnalArtifact-compatible structure', () => {
648
+ const draft: TrinityDraftArtifact = {
649
+ selectedCandidateIndex: 1,
650
+ badDecision: 'Did something wrong',
651
+ betterDecision: 'Do it right',
652
+ rationale: 'Because the principle says so',
653
+ sessionId: 'session-test-123',
654
+ principleId: 'T-01',
655
+ sourceSnapshotRef: 'snapshot-test-001',
656
+ telemetry: {
657
+ chainMode: 'trinity',
658
+ dreamerPassed: true,
659
+ philosopherPassed: true,
660
+ scribePassed: true,
661
+ candidateCount: 3,
662
+ selectedCandidateIndex: 1,
663
+ stageFailures: [],
664
+ },
665
+ };
666
+
667
+ const artifact = draftToArtifact(draft);
668
+
669
+ expect(artifact.artifactId).toBeDefined(); // Generated UUID
670
+ expect(artifact.sessionId).toBe('session-test-123');
671
+ expect(artifact.principleId).toBe('T-01');
672
+ expect(artifact.badDecision).toBe('Did something wrong');
673
+ expect(artifact.betterDecision).toBe('Do it right');
674
+ expect(artifact.rationale).toBe('Because the principle says so');
675
+ expect(artifact.sourceSnapshotRef).toBe('snapshot-test-001');
676
+ expect(artifact.createdAt).toBeDefined(); // Current timestamp
677
+ });
678
+ });
679
+
680
+ // ---------------------------------------------------------------------------
681
+ // Tests: DEFAULT_TRINITY_CONFIG
682
+ // ---------------------------------------------------------------------------
683
+
684
+ describe('DEFAULT_TRINITY_CONFIG', () => {
685
+ it('has sensible defaults', () => {
686
+ expect(DEFAULT_TRINITY_CONFIG.useTrinity).toBe(true);
687
+ expect(DEFAULT_TRINITY_CONFIG.maxCandidates).toBe(3);
688
+ expect(DEFAULT_TRINITY_CONFIG.useStubs).toBe(false); // real subagent execution is now the default
689
+ });
690
+ });
691
+
692
+ // ---------------------------------------------------------------------------
693
+ // Tests: runTrinity — useStubs=false without adapter (sync failure)
694
+ // ---------------------------------------------------------------------------
695
+
696
+ describe('runTrinity — useStubs=false without adapter', () => {
697
+ it('fails with clear error when useStubs=false but no runtimeAdapter provided', () => {
698
+ const snapshot = makeSnapshot({ failureCount: 2 });
699
+ const config: TrinityConfig = {
700
+ useTrinity: true,
701
+ maxCandidates: 3,
702
+ useStubs: false, // No adapter provided!
703
+ };
704
+
705
+ const result = runTrinity({ snapshot, principleId: 'T-08', config });
706
+
707
+ expect(result.success).toBe(false);
708
+ expect(result.failures.length).toBeGreaterThan(0);
709
+ expect(result.failures[0].stage).toBe('dreamer');
710
+ expect(result.failures[0].reason).toContain('runtimeAdapter');
711
+ expect(result.telemetry.usedStubs).toBe(false);
712
+ expect(result.telemetry.dreamerPassed).toBe(false);
713
+ });
714
+ });
715
+
716
+ // ---------------------------------------------------------------------------
717
+ // Tests: runTrinityAsync — with mock runtime adapter
718
+ // ---------------------------------------------------------------------------
719
+
720
+ describe('runTrinityAsync — with mock runtime adapter', () => {
721
+ function makeMockAdapter(overrides: Partial<{
722
+ dreamerOutput: DreamerOutput;
723
+ philosopherOutput: PhilosopherOutput;
724
+ scribeArtifact: TrinityDraftArtifact | null;
725
+ closeCalled: boolean;
726
+ }> = {}): TrinityRuntimeAdapter & { closeCalled: boolean } {
727
+ const defaultDreamerOutput: DreamerOutput = {
728
+ valid: true,
729
+ candidates: [
730
+ {
731
+ candidateIndex: 0,
732
+ badDecision: 'Did something wrong',
733
+ betterDecision: 'Do it right',
734
+ rationale: 'Because the principle says so',
735
+ confidence: 0.9,
736
+ },
737
+ ],
738
+ generatedAt: new Date().toISOString(),
739
+ };
740
+
741
+ const defaultPhilosopherOutput: PhilosopherOutput = {
742
+ valid: true,
743
+ judgments: [
744
+ {
745
+ candidateIndex: 0,
746
+ critique: 'Good alignment',
747
+ principleAligned: true,
748
+ score: 0.92,
749
+ rank: 1,
750
+ },
751
+ ],
752
+ overallAssessment: 'Good candidate',
753
+ generatedAt: new Date().toISOString(),
754
+ };
755
+
756
+ const defaultScribeArtifact: TrinityDraftArtifact = {
757
+ selectedCandidateIndex: 0,
758
+ badDecision: 'Did something wrong',
759
+ betterDecision: 'Do it right',
760
+ rationale: 'Because the principle says so and this is the right approach',
761
+ sessionId: 'session-test-123',
762
+ principleId: 'T-01',
763
+ sourceSnapshotRef: 'snapshot-test-001',
764
+ telemetry: {
765
+ chainMode: 'trinity',
766
+ usedStubs: false,
767
+ dreamerPassed: true,
768
+ philosopherPassed: true,
769
+ scribePassed: true,
770
+ candidateCount: 1,
771
+ selectedCandidateIndex: 0,
772
+ stageFailures: [],
773
+ },
774
+ };
775
+
776
+ return {
777
+ closeCalled: overrides.closeCalled ?? false,
778
+ invokeDreamer: vi.fn().mockResolvedValue(overrides.dreamerOutput ?? defaultDreamerOutput),
779
+ invokePhilosopher: vi.fn().mockResolvedValue(overrides.philosopherOutput ?? defaultPhilosopherOutput),
780
+ invokeScribe: vi.fn().mockResolvedValue(
781
+ overrides.scribeArtifact === null ? null : (overrides.scribeArtifact ?? defaultScribeArtifact)
782
+ ),
783
+ close: vi.fn().mockResolvedValue(undefined),
784
+ } as unknown as TrinityRuntimeAdapter & { closeCalled: boolean; invokeDreamer: ReturnType<typeof vi.fn>; invokePhilosopher: ReturnType<typeof vi.fn>; invokeScribe: ReturnType<typeof vi.fn> };
785
+ }
786
+
787
+ it('uses runtime adapter when useStubs=false with adapter provided', async () => {
788
+ const snapshot = makeSnapshot({ failureCount: 2 });
789
+ const adapter = makeMockAdapter();
790
+ const config: TrinityConfig = {
791
+ useTrinity: true,
792
+ maxCandidates: 3,
793
+ useStubs: false,
794
+ runtimeAdapter: adapter,
795
+ };
796
+
797
+ const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
798
+
799
+ expect(result.success).toBe(true);
800
+ expect(adapter.invokeDreamer).toHaveBeenCalledWith(snapshot, 'T-08', 3);
801
+ expect(adapter.invokePhilosopher).toHaveBeenCalled();
802
+ expect(adapter.invokeScribe).toHaveBeenCalled();
803
+ expect(result.telemetry.usedStubs).toBe(false);
804
+ expect(result.telemetry.dreamerPassed).toBe(true);
805
+ expect(result.telemetry.philosopherPassed).toBe(true);
806
+ expect(result.telemetry.scribePassed).toBe(true);
807
+ });
808
+
809
+ it('fails closed when Dreamer stage returns invalid output', async () => {
810
+ const snapshot = makeSnapshot({ failureCount: 2 });
811
+ const adapter = makeMockAdapter({
812
+ dreamerOutput: { valid: false, candidates: [], reason: 'No signal found', generatedAt: new Date().toISOString() },
813
+ });
814
+ const config: TrinityConfig = {
815
+ useTrinity: true,
816
+ maxCandidates: 3,
817
+ useStubs: false,
818
+ runtimeAdapter: adapter,
819
+ };
820
+
821
+ const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
822
+
823
+ expect(result.success).toBe(false);
824
+ expect(result.failures.length).toBeGreaterThan(0);
825
+ expect(result.failures[0].stage).toBe('dreamer');
826
+ expect(result.telemetry.dreamerPassed).toBe(false);
827
+ expect(result.telemetry.philosopherPassed).toBe(false);
828
+ expect(result.telemetry.scribePassed).toBe(false);
829
+ });
830
+
831
+ it('fails closed when Philosopher stage returns invalid output', async () => {
832
+ const snapshot = makeSnapshot({ failureCount: 2 });
833
+ const adapter = makeMockAdapter({
834
+ philosopherOutput: { valid: false, judgments: [], overallAssessment: '', reason: 'No candidates', generatedAt: new Date().toISOString() },
835
+ });
836
+ const config: TrinityConfig = {
837
+ useTrinity: true,
838
+ maxCandidates: 3,
839
+ useStubs: false,
840
+ runtimeAdapter: adapter,
841
+ };
842
+
843
+ const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
844
+
845
+ expect(result.success).toBe(false);
846
+ expect(result.failures.some(f => f.stage === 'dreamer')).toBe(false); // Dreamer passed
847
+ expect(result.failures.some(f => f.stage === 'philosopher')).toBe(true);
848
+ expect(result.telemetry.dreamerPassed).toBe(true);
849
+ expect(result.telemetry.philosopherPassed).toBe(false);
850
+ });
851
+
852
+ it('fails closed when Scribe stage returns null', async () => {
853
+ const snapshot = makeSnapshot({ failureCount: 2 });
854
+ const adapter = makeMockAdapter({ scribeArtifact: null });
855
+ const config: TrinityConfig = {
856
+ useTrinity: true,
857
+ maxCandidates: 3,
858
+ useStubs: false,
859
+ runtimeAdapter: adapter,
860
+ };
861
+
862
+ const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
863
+
864
+ expect(result.success).toBe(false);
865
+ expect(result.failures.some(f => f.stage === 'scribe')).toBe(true);
866
+ expect(result.telemetry.dreamerPassed).toBe(true);
867
+ expect(result.telemetry.philosopherPassed).toBe(true);
868
+ expect(result.telemetry.scribePassed).toBe(false);
869
+ });
870
+
871
+ it('calls adapter.close() after successful execution', async () => {
872
+ const snapshot = makeSnapshot({ failureCount: 2 });
873
+ const adapter = makeMockAdapter();
874
+ const config: TrinityConfig = {
875
+ useTrinity: true,
876
+ maxCandidates: 3,
877
+ useStubs: false,
878
+ runtimeAdapter: adapter,
879
+ };
880
+
881
+ await runTrinityAsync({ snapshot, principleId: 'T-08', config });
882
+
883
+ expect(adapter.close).toHaveBeenCalled();
884
+ });
885
+
886
+ it('calls adapter.close() even when execution fails', async () => {
887
+ const snapshot = makeSnapshot({ failureCount: 2 });
888
+ const adapter = makeMockAdapter({
889
+ dreamerOutput: { valid: false, candidates: [], reason: 'No signal', generatedAt: new Date().toISOString() },
890
+ });
891
+ const config: TrinityConfig = {
892
+ useTrinity: true,
893
+ maxCandidates: 3,
894
+ useStubs: false,
895
+ runtimeAdapter: adapter,
896
+ };
897
+
898
+ await runTrinityAsync({ snapshot, principleId: 'T-08', config });
899
+
900
+ expect(adapter.close).toHaveBeenCalled();
901
+ });
902
+
903
+ it('produces artifact compatible with draftToArtifact', async () => {
904
+ const snapshot = makeSnapshot({ failureCount: 2 });
905
+ const adapter = makeMockAdapter();
906
+ const config: TrinityConfig = {
907
+ useTrinity: true,
908
+ maxCandidates: 3,
909
+ useStubs: false,
910
+ runtimeAdapter: adapter,
911
+ };
912
+
913
+ const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
914
+
915
+ expect(result.success).toBe(true);
916
+ expect(result.artifact).toBeDefined();
917
+ const artifact = draftToArtifact(result.artifact!);
918
+ expect(artifact.artifactId).toBeDefined();
919
+ expect(artifact.sessionId).toBe('session-test-123');
920
+ expect(artifact.principleId).toBe('T-01');
921
+ expect(artifact.badDecision).toBeDefined();
922
+ expect(artifact.betterDecision).toBeDefined();
923
+ });
924
+ });
925
+
926
+ // ---------------------------------------------------------------------------
927
+ // Tests: runTrinityAsync — useStubs=true still uses stubs
928
+ // ---------------------------------------------------------------------------
929
+
930
+ describe('runTrinityAsync — useStubs=true uses synchronous stubs', () => {
931
+ it('still uses stub implementations when useStubs=true even with adapter', async () => {
932
+ const snapshot = makeSnapshot({ failureCount: 2 });
933
+ const adapter = {
934
+ invokeDreamer: vi.fn().mockResolvedValue({ valid: true, candidates: [], generatedAt: new Date().toISOString() }),
935
+ invokePhilosopher: vi.fn().mockResolvedValue({ valid: true, judgments: [], overallAssessment: '', generatedAt: new Date().toISOString() }),
936
+ invokeScribe: vi.fn().mockResolvedValue(null),
937
+ };
938
+ const config: TrinityConfig = {
939
+ useTrinity: true,
940
+ maxCandidates: 3,
941
+ useStubs: true, // Explicitly use stubs
942
+ runtimeAdapter: adapter as unknown as TrinityRuntimeAdapter,
943
+ };
944
+
945
+ // With stubs, adapter is ignored - stub produces success with failureCount signal
946
+ const result = await runTrinityAsync({ snapshot, principleId: 'T-08', config });
947
+
948
+ expect(result.success).toBe(true); // Stub succeeds because snapshot has failureCount
949
+ expect(adapter.invokeDreamer).not.toHaveBeenCalled(); // Adapter NOT called
950
+ expect(adapter.invokePhilosopher).not.toHaveBeenCalled();
951
+ expect(adapter.invokeScribe).not.toHaveBeenCalled();
952
+ });
953
+ });