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,33 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import {
5
+ computePainScore,
6
+ painSeverityLabel,
7
+ writePainFlag,
8
+ readPainFlagData
9
+ } from '../../src/core/pain';
10
+
11
+ vi.mock('fs');
12
+
13
+ describe('Pain Detection Module', () => {
14
+ describe('computePainScore', () => {
15
+ it('should compute score correctly', () => {
16
+ expect(computePainScore(0, false, false, 0)).toBe(0);
17
+ expect(computePainScore(1, false, false, 0)).toBe(70);
18
+ expect(computePainScore(0, true, false, 0)).toBe(40);
19
+ expect(computePainScore(0, false, true, 0)).toBe(30);
20
+ expect(computePainScore(1, true, true, 20)).toBe(100); // capped at 100
21
+ });
22
+ });
23
+
24
+ describe('painSeverityLabel', () => {
25
+ it('should return correct severity labels', () => {
26
+ expect(painSeverityLabel(0, true)).toBe('critical');
27
+ expect(painSeverityLabel(80)).toBe('high');
28
+ expect(painSeverityLabel(50)).toBe('medium');
29
+ expect(painSeverityLabel(25)).toBe('low');
30
+ expect(painSeverityLabel(10)).toBe('info');
31
+ });
32
+ });
33
+ });
@@ -0,0 +1,57 @@
1
+ import { describe, it, expect } from 'vitest';
2
+
3
+ describe('PathResolver', () => {
4
+ it('should have correct exports', async () => {
5
+ const { PathResolver, PD_ENV_VARS, PD_ENV_DESCRIPTIONS } = await import('../../src/core/path-resolver.js');
6
+ expect(PathResolver).toBeDefined();
7
+ expect(PD_ENV_VARS).toBeDefined();
8
+ expect(PD_ENV_DESCRIPTIONS).toBeDefined();
9
+ });
10
+
11
+
12
+
13
+ it('normalizes workspaceDir passed via constructor', async () => {
14
+ const { PathResolver } = await import('../../src/core/path-resolver.js');
15
+ const resolver = new PathResolver({ workspaceDir: '/tmp/../tmp/workspace' });
16
+ expect(resolver.getWorkspaceDir()).toBe('/tmp/workspace');
17
+ });
18
+
19
+ it('should have all required path keys', async () => {
20
+ const { PathResolver } = await import('../../src/core/path-resolver.js');
21
+ const resolver = new PathResolver({ workspaceDir: '/test/workspace' });
22
+
23
+ const requiredKeys = ['PROFILE', 'PLAN', 'AGENT_SCORECARD', 'PAIN_FLAG', 'EVOLUTION_QUEUE', 'THINKING_OS', 'THINKING_OS_USAGE', 'THINKING_OS_CANDIDATES'];
24
+
25
+ for (const key of requiredKeys) {
26
+ expect(() => resolver.resolve(key)).not.toThrow();
27
+ }
28
+ });
29
+ });
30
+
31
+ describe('Persistence Fix - Placeholder', () => {
32
+ it('trust engine persistence is tested via workspace-context tests', () => {
33
+ expect(true).toBe(true);
34
+ });
35
+
36
+ it('pain dictionary persistence is tested via workspace-context tests', () => {
37
+ expect(true).toBe(true);
38
+ });
39
+
40
+ it('pain config save method exists', async () => {
41
+ const { PainConfig } = await import('../../src/core/config.js');
42
+ const config = new PainConfig('/test/state');
43
+ expect(typeof config.save).toBe('function');
44
+ });
45
+ });
46
+
47
+
48
+ it('should resolve extension anchors and worker path', async () => {
49
+ const { PathResolver } = await import('../../src/core/path-resolver.js');
50
+ PathResolver.setExtensionRoot('/tmp/ext-root');
51
+ const resolver = new PathResolver({ workspaceDir: '/test/workspace' });
52
+
53
+ expect(resolver.resolve('EXTENSION_ROOT')).toBe('/tmp/ext-root');
54
+ expect(resolver.resolve('EXTENSION_SRC')).toBe('/tmp/ext-root/src');
55
+ expect(resolver.resolve('EXTENSION_DIST')).toBe('/tmp/ext-root/dist');
56
+ expect(resolver.resolve('EVOLUTION_WORKER')).toMatch(/\/tmp\/ext-root\/(src|dist)\/service\/evolution-worker\.(ts|js)$/);
57
+ });
@@ -0,0 +1,42 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { planStatus } from '../../src/utils/io.js';
3
+ import { resolvePdPath } from '../../src/core/paths.js';
4
+ import * as fs from 'fs';
5
+
6
+ vi.mock('fs');
7
+
8
+ describe('Path Anchoring Integration', () => {
9
+ const workspaceDir = '/mock/workspace';
10
+
11
+ beforeEach(() => {
12
+ vi.clearAllMocks();
13
+ });
14
+
15
+ it('should resolve PROFILE.json inside .principles/', () => {
16
+ const expected = '/mock/workspace/.principles/PROFILE.json';
17
+ expect(resolvePdPath(workspaceDir, 'PROFILE')).toBe(expected);
18
+ });
19
+
20
+ it('should resolve PLAN.md at the project root', () => {
21
+ const expected = '/mock/workspace/PLAN.md';
22
+ expect(resolvePdPath(workspaceDir, 'PLAN')).toBe(expected);
23
+ });
24
+
25
+ it('should resolve AGENT_SCORECARD.json inside .state/', () => {
26
+ const expected = '/mock/workspace/.state/AGENT_SCORECARD.json';
27
+ expect(resolvePdPath(workspaceDir, 'AGENT_SCORECARD')).toBe(expected);
28
+ });
29
+
30
+ it('planStatus should look for PLAN.md in the root', () => {
31
+ const rootPlanPath = '/mock/workspace/PLAN.md';
32
+ vi.mocked(fs.existsSync).mockImplementation((p) => p === rootPlanPath);
33
+ vi.mocked(fs.readFileSync).mockReturnValue('STATUS: READY');
34
+
35
+ const status = planStatus(workspaceDir);
36
+
37
+ expect(status).toBe('READY');
38
+ expect(fs.existsSync).toHaveBeenCalledWith(rootPlanPath);
39
+ // Verify it does NOT look in docs/
40
+ expect(fs.existsSync).not.toHaveBeenCalledWith(expect.stringContaining('docs/PLAN.md'));
41
+ });
42
+ });
@@ -0,0 +1,477 @@
1
+ /**
2
+ * Integration Tests for Phase 7 Rollout
3
+ * =====================================
4
+ *
5
+ * Tests the complete integration flow:
6
+ * - Training → checkpoint → eval → promotion gate → deployment binding
7
+ * - Only local-reader eligible for first rollout
8
+ * - Orchestrator review required for promotion
9
+ * - Rollback path works
10
+ */
11
+
12
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
13
+ import * as fs from 'fs';
14
+ import * as path from 'path';
15
+ import * as os from 'os';
16
+ import {
17
+ registerTrainingRun,
18
+ startTrainingRun,
19
+ completeTrainingRun,
20
+ registerCheckpoint,
21
+ attachEvalSummary,
22
+ markCheckpointDeployable,
23
+ getCheckpoint,
24
+ } from '../../src/core/model-training-registry.js';
25
+ import {
26
+ bindCheckpointToWorkerProfile,
27
+ getDeployment,
28
+ enableRoutingForProfile,
29
+ disableRoutingForProfile,
30
+ rollbackDeployment,
31
+ isRoutingEnabledForProfile,
32
+ getActiveCheckpointForProfile,
33
+ } from '../../src/core/model-deployment-registry.js';
34
+ import {
35
+ evaluatePromotionGate,
36
+ advancePromotion,
37
+ getPromotionState,
38
+ getPromotionRecord,
39
+ DEFAULT_BASELINE_METRICS,
40
+ DEFAULT_MIN_DELTA,
41
+ } from '../../src/core/promotion-gate.js';
42
+
43
+ describe('Phase 7 Rollout Integration', () => {
44
+ // -------------------------------------------------------------------------
45
+ // Test setup
46
+ // -------------------------------------------------------------------------
47
+
48
+ let tempDir: string;
49
+ let stateDir: string;
50
+
51
+ beforeEach(() => {
52
+ tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'pd-rollout-test-'));
53
+ stateDir = path.join(tempDir, '.state', 'nocturnal');
54
+ fs.mkdirSync(stateDir, { recursive: true });
55
+ });
56
+
57
+ afterEach(() => {
58
+ try {
59
+ if (fs.existsSync(tempDir)) {
60
+ fs.rmSync(tempDir, { recursive: true, force: true });
61
+ }
62
+ } catch {
63
+ // Ignore cleanup errors
64
+ }
65
+ });
66
+
67
+ // -------------------------------------------------------------------------
68
+ // Helper: Create a deployable checkpoint with eval
69
+ // -------------------------------------------------------------------------
70
+
71
+ function createDeployableCheckpoint(params: {
72
+ delta?: number;
73
+ verdict?: 'pass' | 'fail' | 'compare_only';
74
+ candidateScore?: number;
75
+ targetModelFamily?: string;
76
+ markDeplorable?: boolean; // If false, skip markCheckpointDeployable
77
+ }): string {
78
+ const {
79
+ delta = 0.08,
80
+ verdict = 'pass',
81
+ candidateScore = 0.8,
82
+ targetModelFamily = 'qwen2.5-7b-reader',
83
+ markDeplorable = true,
84
+ } = params;
85
+
86
+ // Register training run
87
+ const run = registerTrainingRun(stateDir, {
88
+ targetModelFamily,
89
+ datasetFingerprint: 'fp-dataset-abc',
90
+ exportId: 'export-123',
91
+ sampleCount: 100,
92
+ configFingerprint: 'fp-config-xyz',
93
+ });
94
+
95
+ // Complete the training run so checkpoint can be marked deployable
96
+ startTrainingRun(stateDir, run.trainRunId);
97
+ completeTrainingRun(stateDir, run.trainRunId);
98
+
99
+ // Register checkpoint
100
+ const checkpoint = registerCheckpoint(stateDir, {
101
+ trainRunId: run.trainRunId,
102
+ targetModelFamily,
103
+ artifactPath: path.join(tempDir, 'checkpoints', 'ckpt-001'),
104
+ });
105
+
106
+ // Attach eval
107
+ const evalId = `eval-${Date.now()}`;
108
+ attachEvalSummary(stateDir, checkpoint.checkpointId, {
109
+ evalId,
110
+ checkpointId: checkpoint.checkpointId,
111
+ benchmarkId: 'benchmark-001',
112
+ targetModelFamily,
113
+ mode: 'reduced_prompt',
114
+ baselineScore: 0.7,
115
+ candidateScore,
116
+ delta,
117
+ verdict,
118
+ });
119
+
120
+ // Mark deployable (only if verdict is pass/compare_only and markDeployable is true)
121
+ if (markDeplorable && (verdict === 'pass' || verdict === 'compare_only')) {
122
+ markCheckpointDeployable(stateDir, checkpoint.checkpointId, true);
123
+ }
124
+
125
+ return checkpoint.checkpointId;
126
+ }
127
+
128
+ // -------------------------------------------------------------------------
129
+ // Helper: Advance checkpoint to shadow_ready
130
+ // -------------------------------------------------------------------------
131
+
132
+ function advanceToShadowReady(checkpointId: string): void {
133
+ advancePromotion(stateDir, {
134
+ checkpointId,
135
+ targetProfile: 'local-reader',
136
+ baselineMetrics: DEFAULT_BASELINE_METRICS,
137
+ orchestratorReviewPassed: true,
138
+ reviewNote: 'Approved for shadow rollout',
139
+ });
140
+ }
141
+
142
+ // -------------------------------------------------------------------------
143
+ // Test: Complete rollout flow
144
+ // -------------------------------------------------------------------------
145
+
146
+ describe('Complete Rollout Flow', () => {
147
+ it('should complete: checkpoint → eval → promotion → binding → routing', () => {
148
+ // Step 1: Create deployable checkpoint
149
+ const checkpointId = createDeployableCheckpoint({
150
+ delta: 0.15,
151
+ verdict: 'pass',
152
+ candidateScore: 0.85,
153
+ });
154
+
155
+ // Step 2: Evaluate promotion gate
156
+ const gateResult = evaluatePromotionGate(stateDir, {
157
+ checkpointId,
158
+ targetProfile: 'local-reader',
159
+ baselineMetrics: DEFAULT_BASELINE_METRICS,
160
+ });
161
+ expect(gateResult.passes).toBe(true);
162
+
163
+ // Step 3: Advance promotion state
164
+ advanceToShadowReady(checkpointId);
165
+ expect(getPromotionState(stateDir, checkpointId)).toBe('shadow_ready');
166
+
167
+ // Step 4: Bind checkpoint to worker profile
168
+ const deployment = bindCheckpointToWorkerProfile(
169
+ stateDir,
170
+ 'local-reader',
171
+ checkpointId,
172
+ 'Initial shadow deployment'
173
+ );
174
+ expect(deployment.activeCheckpointId).toBe(checkpointId);
175
+ expect(deployment.routingEnabled).toBe(false);
176
+
177
+ // Step 5: Verify routing is disabled initially
178
+ expect(isRoutingEnabledForProfile(stateDir, 'local-reader')).toBe(false);
179
+
180
+ // Step 6: Enable routing
181
+ const updated = enableRoutingForProfile(stateDir, 'local-reader');
182
+ expect(updated.routingEnabled).toBe(true);
183
+
184
+ // Step 7: Verify routing is enabled
185
+ expect(isRoutingEnabledForProfile(stateDir, 'local-reader')).toBe(true);
186
+
187
+ // Step 8: Disable routing
188
+ disableRoutingForProfile(stateDir, 'local-reader');
189
+ expect(isRoutingEnabledForProfile(stateDir, 'local-reader')).toBe(false);
190
+ });
191
+ });
192
+
193
+ // -------------------------------------------------------------------------
194
+ // Test: Only local-reader eligible for first rollout
195
+ // -------------------------------------------------------------------------
196
+
197
+ describe('First Rollout Profile Constraint', () => {
198
+ it('should allow local-reader for first rollout', () => {
199
+ const checkpointId = createDeployableCheckpoint({
200
+ delta: 0.15,
201
+ verdict: 'pass',
202
+ });
203
+
204
+ advanceToShadowReady(checkpointId);
205
+
206
+ // Should succeed
207
+ const deployment = bindCheckpointToWorkerProfile(stateDir, 'local-reader', checkpointId);
208
+ expect(deployment.workerProfile).toBe('local-reader');
209
+ });
210
+
211
+ it('should allow deployment binding without promotion gate check (backward compat)', () => {
212
+ // This tests the case where a checkpoint is already bound
213
+ // and the promotion gate check is added later
214
+ // First, create a checkpoint WITHOUT promotion gate
215
+ const run = registerTrainingRun(stateDir, {
216
+ targetModelFamily: 'qwen2.5-7b-reader',
217
+ datasetFingerprint: 'fp-dataset-abc',
218
+ exportId: 'export-123',
219
+ sampleCount: 100,
220
+ configFingerprint: 'fp-config-xyz',
221
+ });
222
+ startTrainingRun(stateDir, run.trainRunId);
223
+ completeTrainingRun(stateDir, run.trainRunId);
224
+
225
+ const checkpoint = registerCheckpoint(stateDir, {
226
+ trainRunId: run.trainRunId,
227
+ targetModelFamily: 'qwen2.5-7b-reader',
228
+ artifactPath: path.join(tempDir, 'checkpoints', 'ckpt-no-promotion'),
229
+ });
230
+
231
+ // Attach eval but DON'T mark deployable (simulating old state before promotion)
232
+ attachEvalSummary(stateDir, checkpoint.checkpointId, {
233
+ evalId: 'eval-no-promotion',
234
+ checkpointId: checkpoint.checkpointId,
235
+ benchmarkId: 'benchmark-001',
236
+ targetModelFamily: 'qwen2.5-7b-reader',
237
+ mode: 'reduced_prompt',
238
+ baselineScore: 0.7,
239
+ candidateScore: 0.8,
240
+ delta: 0.1,
241
+ verdict: 'pass',
242
+ });
243
+
244
+ // Without promotion gate evaluated, binding should fail
245
+ expect(() => {
246
+ bindCheckpointToWorkerProfile(stateDir, 'local-reader', checkpoint.checkpointId);
247
+ }).toThrow(/not deployable/);
248
+ });
249
+ });
250
+
251
+ // -------------------------------------------------------------------------
252
+ // Test: Orchestrator review required
253
+ // -------------------------------------------------------------------------
254
+
255
+ describe('Orchestrator Review Requirement', () => {
256
+ it('should not reach shadow_ready without orchestrator review', () => {
257
+ const checkpointId = createDeployableCheckpoint({
258
+ delta: 0.15,
259
+ verdict: 'pass',
260
+ candidateScore: 0.85,
261
+ });
262
+
263
+ // Advance without orchestrator review
264
+ const promotion = advancePromotion(stateDir, {
265
+ checkpointId,
266
+ targetProfile: 'local-reader',
267
+ baselineMetrics: DEFAULT_BASELINE_METRICS,
268
+ orchestratorReviewPassed: false,
269
+ });
270
+
271
+ // Should be candidate_only, not shadow_ready
272
+ expect(promotion.state).toBe('candidate_only');
273
+ expect(promotion.orchestratorReviewPassed).toBe(false);
274
+ });
275
+
276
+ it('should reach shadow_ready with orchestrator review', () => {
277
+ const checkpointId = createDeployableCheckpoint({
278
+ delta: 0.15,
279
+ verdict: 'pass',
280
+ candidateScore: 0.85,
281
+ });
282
+
283
+ // Advance with orchestrator review
284
+ const promotion = advancePromotion(stateDir, {
285
+ checkpointId,
286
+ targetProfile: 'local-reader',
287
+ baselineMetrics: DEFAULT_BASELINE_METRICS,
288
+ orchestratorReviewPassed: true,
289
+ reviewNote: 'Looks good, proceed',
290
+ });
291
+
292
+ expect(promotion.state).toBe('shadow_ready');
293
+ expect(promotion.orchestratorReviewPassed).toBe(true);
294
+ expect(promotion.reviewNote).toBe('Looks good, proceed');
295
+ });
296
+ });
297
+
298
+ // -------------------------------------------------------------------------
299
+ // Test: Rollback path
300
+ // -------------------------------------------------------------------------
301
+
302
+ describe('Rollback Path', () => {
303
+ it('should preserve previous checkpoint on re-binding', () => {
304
+ // Create first checkpoint
305
+ const checkpoint1 = createDeployableCheckpoint({
306
+ delta: 0.1,
307
+ verdict: 'pass',
308
+ targetModelFamily: 'qwen2.5-7b-reader',
309
+ });
310
+ advanceToShadowReady(checkpoint1);
311
+
312
+ // Bind first checkpoint
313
+ bindCheckpointToWorkerProfile(stateDir, 'local-reader', checkpoint1);
314
+ expect(getActiveCheckpointForProfile(stateDir, 'local-reader')).toBe(checkpoint1);
315
+
316
+ // Create second checkpoint
317
+ const checkpoint2 = createDeployableCheckpoint({
318
+ delta: 0.15,
319
+ verdict: 'pass',
320
+ targetModelFamily: 'qwen2.5-7b-reader',
321
+ });
322
+ advanceToShadowReady(checkpoint2);
323
+
324
+ // Bind second checkpoint (should update, not replace chain)
325
+ bindCheckpointToWorkerProfile(stateDir, 'local-reader', checkpoint2, 'Update to newer checkpoint');
326
+
327
+ const deployment = getDeployment(stateDir, 'local-reader');
328
+ expect(deployment.activeCheckpointId).toBe(checkpoint2);
329
+ expect(deployment.previousCheckpointId).toBe(checkpoint1);
330
+ });
331
+
332
+ it('should rollback to previous checkpoint', () => {
333
+ // Create and bind first checkpoint
334
+ const checkpoint1 = createDeployableCheckpoint({
335
+ delta: 0.1,
336
+ verdict: 'pass',
337
+ targetModelFamily: 'qwen2.5-7b-reader',
338
+ });
339
+ advanceToShadowReady(checkpoint1);
340
+ bindCheckpointToWorkerProfile(stateDir, 'local-reader', checkpoint1);
341
+
342
+ // Create and bind second checkpoint
343
+ const checkpoint2 = createDeployableCheckpoint({
344
+ delta: 0.15,
345
+ verdict: 'pass',
346
+ targetModelFamily: 'qwen2.5-7b-reader',
347
+ });
348
+ advanceToShadowReady(checkpoint2);
349
+ bindCheckpointToWorkerProfile(stateDir, 'local-reader', checkpoint2);
350
+
351
+ // Enable routing
352
+ enableRoutingForProfile(stateDir, 'local-reader');
353
+
354
+ // Rollback
355
+ const rolledBack = rollbackDeployment(stateDir, 'local-reader', 'Rollback due to instability');
356
+
357
+ // Verify rollback
358
+ expect(rolledBack.activeCheckpointId).toBe(checkpoint1);
359
+ expect(rolledBack.previousCheckpointId).toBe(checkpoint2);
360
+ expect(rolledBack.routingEnabled).toBe(false); // Routing disabled after rollback
361
+
362
+ // Verify routing is disabled
363
+ expect(isRoutingEnabledForProfile(stateDir, 'local-reader')).toBe(false);
364
+ });
365
+
366
+ it('should fail rollback when no previous checkpoint exists', () => {
367
+ // Single checkpoint with no previous - rollback should fail
368
+ const checkpointId = createDeployableCheckpoint({
369
+ delta: 0.08,
370
+ verdict: 'pass',
371
+ targetModelFamily: 'qwen2.5-7b-reader',
372
+ });
373
+ advanceToShadowReady(checkpointId);
374
+ bindCheckpointToWorkerProfile(stateDir, 'local-reader', checkpointId);
375
+
376
+ // Rollback should fail because there's no previous checkpoint
377
+ expect(() => {
378
+ rollbackDeployment(stateDir, 'local-reader');
379
+ }).toThrow(/no previous checkpoint/);
380
+ });
381
+ });
382
+
383
+ // -------------------------------------------------------------------------
384
+ // Test: Fail-closed on various scenarios
385
+ // -------------------------------------------------------------------------
386
+
387
+ describe('Fail-Closed Behavior', () => {
388
+ it('should fail binding if checkpoint has no eval', () => {
389
+ const run = registerTrainingRun(stateDir, {
390
+ targetModelFamily: 'qwen2.5-7b-reader',
391
+ datasetFingerprint: 'fp-dataset-abc',
392
+ exportId: 'export-123',
393
+ sampleCount: 100,
394
+ configFingerprint: 'fp-config-xyz',
395
+ });
396
+
397
+ const checkpoint = registerCheckpoint(stateDir, {
398
+ trainRunId: run.trainRunId,
399
+ targetModelFamily: 'qwen2.5-7b-reader',
400
+ artifactPath: path.join(tempDir, 'checkpoints', 'ckpt-no-eval'),
401
+ });
402
+
403
+ // Should fail because checkpoint is not deployable (no eval)
404
+ expect(() => {
405
+ bindCheckpointToWorkerProfile(stateDir, 'local-reader', checkpoint.checkpointId);
406
+ }).toThrow(/not deployable/);
407
+ });
408
+
409
+ it('should fail binding if eval verdict is fail', () => {
410
+ const checkpointId = createDeployableCheckpoint({
411
+ delta: -0.1,
412
+ verdict: 'fail',
413
+ candidateScore: 0.3,
414
+ });
415
+
416
+ advancePromotion(stateDir, {
417
+ checkpointId,
418
+ targetProfile: 'local-reader',
419
+ baselineMetrics: DEFAULT_BASELINE_METRICS,
420
+ orchestratorReviewPassed: true,
421
+ });
422
+
423
+ // Should fail because promotion state is rejected
424
+ expect(getPromotionState(stateDir, checkpointId)).toBe('rejected');
425
+ });
426
+ });
427
+
428
+ // -------------------------------------------------------------------------
429
+ // Test: Promotion state machine
430
+ // -------------------------------------------------------------------------
431
+
432
+ describe('Promotion State Machine', () => {
433
+ it('should flow: candidate_only → shadow_ready → promotable', () => {
434
+ const checkpointId = createDeployableCheckpoint({
435
+ delta: 0.1,
436
+ verdict: 'pass',
437
+ candidateScore: 0.8,
438
+ });
439
+
440
+ // Initial evaluation: should be candidate_only (no review)
441
+ let promotion = advancePromotion(stateDir, {
442
+ checkpointId,
443
+ targetProfile: 'local-reader',
444
+ baselineMetrics: DEFAULT_BASELINE_METRICS,
445
+ orchestratorReviewPassed: false,
446
+ });
447
+ expect(promotion.state).toBe('candidate_only');
448
+
449
+ // After orchestrator review: should be shadow_ready
450
+ promotion = advancePromotion(stateDir, {
451
+ checkpointId,
452
+ targetProfile: 'local-reader',
453
+ baselineMetrics: DEFAULT_BASELINE_METRICS,
454
+ orchestratorReviewPassed: true,
455
+ });
456
+ expect(promotion.state).toBe('shadow_ready');
457
+ expect(promotion.shadowStartedAt).toBeDefined();
458
+ });
459
+
460
+ it('should reject if delta is negative', () => {
461
+ const checkpointId = createDeployableCheckpoint({
462
+ delta: -0.05,
463
+ verdict: 'fail',
464
+ candidateScore: 0.3,
465
+ });
466
+
467
+ const promotion = advancePromotion(stateDir, {
468
+ checkpointId,
469
+ targetProfile: 'local-reader',
470
+ baselineMetrics: DEFAULT_BASELINE_METRICS,
471
+ orchestratorReviewPassed: true,
472
+ });
473
+
474
+ expect(promotion.state).toBe('rejected');
475
+ });
476
+ });
477
+ });