principles-disciple 1.8.0 → 1.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (460) 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 +6 -1
  10. package/package.json +13 -15
  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} +185 -63
  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} +166 -139
  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} +263 -36
  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/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +603 -0
  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/src/service/subagent-workflow/types.ts +378 -0
  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/zh/skills/pd-diagnostician/SKILL.md +70 -1
  138. package/templates/pain_settings.json +2 -1
  139. package/tests/README.md +120 -0
  140. package/tests/build-artifacts.test.ts +111 -0
  141. package/tests/commands/evolution-status.test.ts +222 -0
  142. package/tests/commands/evolver.test.ts +22 -0
  143. package/tests/commands/export.test.ts +78 -0
  144. package/tests/commands/nocturnal-review.test.ts +448 -0
  145. package/tests/commands/nocturnal-train.test.ts +97 -0
  146. package/tests/commands/pain.test.ts +108 -0
  147. package/tests/commands/samples.test.ts +65 -0
  148. package/tests/commands/strategy.test.ts +34 -0
  149. package/tests/commands/thinking-os.test.ts +88 -0
  150. package/tests/core/adaptive-thresholds.test.ts +261 -0
  151. package/tests/core/config-service.test.ts +89 -0
  152. package/tests/core/config.test.ts +90 -0
  153. package/tests/core/control-ui-db.test.ts +75 -0
  154. package/tests/core/core-template-guidance.test.ts +21 -0
  155. package/tests/core/detection-funnel.test.ts +63 -0
  156. package/tests/core/detection-service.test.ts +50 -0
  157. package/tests/core/dictionary-service.test.ts +116 -0
  158. package/tests/core/dictionary.test.ts +168 -0
  159. package/tests/core/empathy-keyword-matcher.test.ts +209 -0
  160. package/tests/core/event-log.test.ts +181 -0
  161. package/tests/core/evolution-e2e.test.ts +58 -0
  162. package/tests/core/evolution-engine-gate-integration.test.ts +543 -0
  163. package/tests/core/evolution-engine.test.ts +562 -0
  164. package/tests/core/evolution-logger.test.ts +148 -0
  165. package/tests/core/evolution-migration.test.ts +50 -0
  166. package/tests/core/evolution-paths.test.ts +21 -0
  167. package/tests/core/evolution-reducer.detector-metadata.test.ts +602 -0
  168. package/tests/core/evolution-reducer.test.ts +180 -0
  169. package/tests/core/evolution-types-loop.test.ts +48 -0
  170. package/tests/core/evolution-user-stories.e2e.test.ts +249 -0
  171. package/tests/core/external-training-contract.test.ts +463 -0
  172. package/tests/core/focus-history.test.ts +682 -0
  173. package/tests/core/init-flatten.test.ts +69 -0
  174. package/tests/core/init-refactor.test.ts +87 -0
  175. package/tests/core/init-v1.3.test.ts +46 -0
  176. package/tests/core/init.test.ts +190 -0
  177. package/tests/core/local-worker-routing.test.ts +757 -0
  178. package/tests/core/migration.test.ts +84 -0
  179. package/tests/core/model-deployment-registry.test.ts +845 -0
  180. package/tests/core/model-training-registry.test.ts +889 -0
  181. package/tests/core/nocturnal-arbiter.test.ts +494 -0
  182. package/tests/core/nocturnal-candidate-scoring.test.ts +400 -0
  183. package/tests/core/nocturnal-compliance.test.ts +646 -0
  184. package/tests/core/nocturnal-dataset.test.ts +892 -0
  185. package/tests/core/nocturnal-executability.test.ts +357 -0
  186. package/tests/core/nocturnal-export.test.ts +462 -0
  187. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +428 -0
  188. package/tests/core/nocturnal-trajectory-extractor.test.ts +634 -0
  189. package/tests/core/nocturnal-trinity.test.ts +953 -0
  190. package/tests/core/pain.test.ts +33 -0
  191. package/tests/core/path-resolver.test.ts +57 -0
  192. package/tests/core/paths-refactor.test.ts +42 -0
  193. package/tests/core/phase7-rollout-integration.test.ts +477 -0
  194. package/tests/core/principle-training-state.test.ts +712 -0
  195. package/tests/core/profile.test.ts +56 -0
  196. package/tests/core/promotion-gate.test.ts +556 -0
  197. package/tests/core/risk-calculator.test.ts +168 -0
  198. package/tests/core/session-tracker.test.ts +191 -0
  199. package/tests/core/training-program.test.ts +472 -0
  200. package/tests/core/trajectory.test.ts +265 -0
  201. package/tests/core/workspace-context-factory.test.ts +18 -0
  202. package/tests/core/workspace-context.test.ts +134 -0
  203. package/tests/fixtures/nocturnal-reviewed-subset.json +183 -0
  204. package/tests/fixtures/production-compatibility.test.ts +147 -0
  205. package/tests/fixtures/production-mock-generator.ts +282 -0
  206. package/tests/hooks/bash-risk-integration.test.ts +137 -0
  207. package/tests/hooks/bash-risk.test.ts +81 -0
  208. package/tests/hooks/edit-verification.test.ts +678 -0
  209. package/tests/hooks/gate-edit-verification-p1.test.ts +632 -0
  210. package/tests/hooks/gate-edit-verification.test.ts +435 -0
  211. package/tests/hooks/gate-pipeline-integration.test.ts +404 -0
  212. package/tests/hooks/gate.test.ts +271 -0
  213. package/tests/hooks/gfi-gate-unit.test.ts +422 -0
  214. package/tests/hooks/gfi-gate.test.ts +669 -0
  215. package/tests/hooks/lifecycle.test.ts +248 -0
  216. package/tests/hooks/llm.test.ts +308 -0
  217. package/tests/hooks/message-sanitize.test.ts +36 -0
  218. package/tests/hooks/pain.test.ts +141 -0
  219. package/tests/hooks/progressive-trust-gate.test.ts +277 -0
  220. package/tests/hooks/prompt.test.ts +1411 -0
  221. package/tests/hooks/subagent.test.ts +467 -0
  222. package/tests/hooks/thinking-gate.test.ts +313 -0
  223. package/tests/http/principles-console-route.test.ts +140 -0
  224. package/tests/hygiene-tracker.test.ts +77 -0
  225. package/tests/index.integration.test.ts +179 -0
  226. package/tests/index.shadow-routing.integration.test.ts +140 -0
  227. package/tests/index.test.ts +9 -0
  228. package/tests/integration/empathy-workflow-integration.test.ts +627 -0
  229. package/tests/service/control-ui-query-service.test.ts +121 -0
  230. package/tests/service/empathy-observer-workflow-manager.test.ts +176 -0
  231. package/tests/service/evolution-worker.test.ts +585 -0
  232. package/tests/service/nocturnal-runtime.test.ts +470 -0
  233. package/tests/service/nocturnal-service.test.ts +577 -0
  234. package/tests/service/nocturnal-target-selector.test.ts +615 -0
  235. package/tests/service/nocturnal-workflow-manager.test.ts +439 -0
  236. package/tests/service/phase3-input-filter.test.ts +289 -0
  237. package/tests/service/runtime-summary-service.test.ts +919 -0
  238. package/tests/task-compliance.test.ts +166 -0
  239. package/tests/test-utils.ts +48 -0
  240. package/tests/tools/critique-prompt.test.ts +260 -0
  241. package/tests/tools/deep-reflect.test.ts +232 -0
  242. package/tests/tools/model-index.test.ts +246 -0
  243. package/tests/ui/app.test.tsx +114 -0
  244. package/tests/utils/file-lock.test.ts +407 -0
  245. package/tests/utils/hashing.test.ts +32 -0
  246. package/tests/utils/io.test.ts +39 -0
  247. package/tests/utils/nlp.test.ts +53 -0
  248. package/tests/utils/plugin-logger.test.ts +156 -0
  249. package/tsconfig.json +16 -0
  250. package/tsconfig.tsbuildinfo +1 -0
  251. package/ui/src/App.tsx +45 -0
  252. package/ui/src/api.ts +216 -0
  253. package/ui/src/charts.tsx +586 -0
  254. package/ui/src/components/ErrorState.tsx +6 -0
  255. package/ui/src/components/Loading.tsx +13 -0
  256. package/ui/src/components/ProtectedRoute.tsx +12 -0
  257. package/ui/src/components/Shell.tsx +91 -0
  258. package/ui/src/components/WorkspaceConfig.tsx +146 -0
  259. package/ui/src/components/index.ts +5 -0
  260. package/ui/src/context/auth.tsx +80 -0
  261. package/ui/src/context/theme.tsx +66 -0
  262. package/ui/src/hooks/useAutoRefresh.ts +39 -0
  263. package/ui/src/i18n/ui.ts +363 -0
  264. package/ui/src/main.tsx +16 -0
  265. package/ui/src/pages/EvolutionPage.tsx +352 -0
  266. package/ui/src/pages/FeedbackPage.tsx +140 -0
  267. package/ui/src/pages/GateMonitorPage.tsx +136 -0
  268. package/ui/src/pages/LoginPage.tsx +88 -0
  269. package/ui/src/pages/OverviewPage.tsx +238 -0
  270. package/ui/src/pages/SamplesPage.tsx +174 -0
  271. package/ui/src/pages/ThinkingModelsPage.tsx +127 -0
  272. package/ui/src/styles.css +1661 -0
  273. package/ui/src/types.ts +368 -0
  274. package/ui/src/utils/format.ts +15 -0
  275. package/vitest.config.ts +23 -0
  276. package/dist/commands/capabilities.d.ts +0 -3
  277. package/dist/commands/capabilities.js +0 -73
  278. package/dist/commands/context.d.ts +0 -5
  279. package/dist/commands/evolution-status.d.ts +0 -4
  280. package/dist/commands/evolution-status.js +0 -117
  281. package/dist/commands/evolver.d.ts +0 -9
  282. package/dist/commands/evolver.js +0 -26
  283. package/dist/commands/export.d.ts +0 -2
  284. package/dist/commands/export.js +0 -98
  285. package/dist/commands/focus.d.ts +0 -14
  286. package/dist/commands/focus.js +0 -457
  287. package/dist/commands/nocturnal-review.d.ts +0 -24
  288. package/dist/commands/nocturnal-review.js +0 -265
  289. package/dist/commands/nocturnal-rollout.d.ts +0 -27
  290. package/dist/commands/nocturnal-rollout.js +0 -671
  291. package/dist/commands/nocturnal-train.d.ts +0 -25
  292. package/dist/commands/nocturnal-train.js +0 -919
  293. package/dist/commands/pain.d.ts +0 -5
  294. package/dist/commands/principle-rollback.d.ts +0 -4
  295. package/dist/commands/principle-rollback.js +0 -22
  296. package/dist/commands/rollback.d.ts +0 -19
  297. package/dist/commands/samples.d.ts +0 -2
  298. package/dist/commands/samples.js +0 -55
  299. package/dist/commands/strategy.d.ts +0 -3
  300. package/dist/commands/strategy.js +0 -29
  301. package/dist/commands/thinking-os.d.ts +0 -2
  302. package/dist/config/defaults/runtime.d.ts +0 -40
  303. package/dist/config/errors.d.ts +0 -84
  304. package/dist/config/errors.js +0 -94
  305. package/dist/config/index.js +0 -7
  306. package/dist/constants/diagnostician.d.ts +0 -12
  307. package/dist/constants/diagnostician.js +0 -56
  308. package/dist/constants/tools.d.ts +0 -17
  309. package/dist/constants/tools.js +0 -54
  310. package/dist/core/adaptive-thresholds.d.ts +0 -186
  311. package/dist/core/adaptive-thresholds.js +0 -300
  312. package/dist/core/config-service.d.ts +0 -15
  313. package/dist/core/config.d.ts +0 -127
  314. package/dist/core/control-ui-db.d.ts +0 -95
  315. package/dist/core/control-ui-db.js +0 -292
  316. package/dist/core/detection-funnel.d.ts +0 -33
  317. package/dist/core/detection-service.d.ts +0 -15
  318. package/dist/core/dictionary-service.d.ts +0 -15
  319. package/dist/core/dictionary.d.ts +0 -38
  320. package/dist/core/event-log.d.ts +0 -82
  321. package/dist/core/event-log.js +0 -463
  322. package/dist/core/evolution-engine.d.ts +0 -118
  323. package/dist/core/evolution-engine.js +0 -464
  324. package/dist/core/evolution-logger.d.ts +0 -137
  325. package/dist/core/evolution-logger.js +0 -256
  326. package/dist/core/evolution-migration.d.ts +0 -5
  327. package/dist/core/evolution-migration.js +0 -65
  328. package/dist/core/evolution-reducer.d.ts +0 -98
  329. package/dist/core/evolution-reducer.js +0 -465
  330. package/dist/core/evolution-types.d.ts +0 -287
  331. package/dist/core/evolution-types.js +0 -78
  332. package/dist/core/external-training-contract.d.ts +0 -276
  333. package/dist/core/external-training-contract.js +0 -269
  334. package/dist/core/focus-history.d.ts +0 -210
  335. package/dist/core/focus-history.js +0 -1185
  336. package/dist/core/hygiene/tracker.d.ts +0 -22
  337. package/dist/core/hygiene/tracker.js +0 -106
  338. package/dist/core/init.d.ts +0 -12
  339. package/dist/core/local-worker-routing.d.ts +0 -175
  340. package/dist/core/local-worker-routing.js +0 -525
  341. package/dist/core/migration.d.ts +0 -6
  342. package/dist/core/model-deployment-registry.d.ts +0 -218
  343. package/dist/core/model-deployment-registry.js +0 -503
  344. package/dist/core/model-training-registry.d.ts +0 -295
  345. package/dist/core/model-training-registry.js +0 -475
  346. package/dist/core/nocturnal-arbiter.d.ts +0 -159
  347. package/dist/core/nocturnal-arbiter.js +0 -534
  348. package/dist/core/nocturnal-candidate-scoring.d.ts +0 -137
  349. package/dist/core/nocturnal-candidate-scoring.js +0 -266
  350. package/dist/core/nocturnal-compliance.d.ts +0 -175
  351. package/dist/core/nocturnal-compliance.js +0 -824
  352. package/dist/core/nocturnal-dataset.d.ts +0 -224
  353. package/dist/core/nocturnal-dataset.js +0 -443
  354. package/dist/core/nocturnal-executability.d.ts +0 -85
  355. package/dist/core/nocturnal-executability.js +0 -331
  356. package/dist/core/nocturnal-export.d.ts +0 -124
  357. package/dist/core/nocturnal-export.js +0 -275
  358. package/dist/core/nocturnal-paths.d.ts +0 -124
  359. package/dist/core/nocturnal-trajectory-extractor.d.ts +0 -242
  360. package/dist/core/nocturnal-trajectory-extractor.js +0 -307
  361. package/dist/core/nocturnal-trinity.d.ts +0 -311
  362. package/dist/core/nocturnal-trinity.js +0 -880
  363. package/dist/core/pain.d.ts +0 -4
  364. package/dist/core/pain.js +0 -70
  365. package/dist/core/path-resolver.d.ts +0 -46
  366. package/dist/core/paths.d.ts +0 -65
  367. package/dist/core/principle-training-state.d.ts +0 -121
  368. package/dist/core/principle-training-state.js +0 -321
  369. package/dist/core/profile.d.ts +0 -62
  370. package/dist/core/profile.js +0 -210
  371. package/dist/core/promotion-gate.d.ts +0 -238
  372. package/dist/core/promotion-gate.js +0 -529
  373. package/dist/core/risk-calculator.d.ts +0 -22
  374. package/dist/core/session-tracker.d.ts +0 -99
  375. package/dist/core/shadow-observation-registry.d.ts +0 -217
  376. package/dist/core/shadow-observation-registry.js +0 -308
  377. package/dist/core/system-logger.d.ts +0 -8
  378. package/dist/core/thinking-models.d.ts +0 -38
  379. package/dist/core/thinking-models.js +0 -170
  380. package/dist/core/training-program.d.ts +0 -233
  381. package/dist/core/training-program.js +0 -433
  382. package/dist/core/trajectory.d.ts +0 -411
  383. package/dist/core/trajectory.js +0 -1307
  384. package/dist/core/workspace-context.d.ts +0 -71
  385. package/dist/hooks/bash-risk.d.ts +0 -57
  386. package/dist/hooks/bash-risk.js +0 -137
  387. package/dist/hooks/edit-verification.d.ts +0 -62
  388. package/dist/hooks/edit-verification.js +0 -256
  389. package/dist/hooks/gate-block-helper.d.ts +0 -44
  390. package/dist/hooks/gate-block-helper.js +0 -119
  391. package/dist/hooks/gate.d.ts +0 -24
  392. package/dist/hooks/gate.js +0 -173
  393. package/dist/hooks/gfi-gate.d.ts +0 -40
  394. package/dist/hooks/gfi-gate.js +0 -113
  395. package/dist/hooks/lifecycle.d.ts +0 -5
  396. package/dist/hooks/lifecycle.js +0 -284
  397. package/dist/hooks/llm.d.ts +0 -12
  398. package/dist/hooks/message-sanitize.d.ts +0 -3
  399. package/dist/hooks/message-sanitize.js +0 -37
  400. package/dist/hooks/pain.d.ts +0 -5
  401. package/dist/hooks/pain.js +0 -301
  402. package/dist/hooks/progressive-trust-gate.d.ts +0 -51
  403. package/dist/hooks/progressive-trust-gate.js +0 -89
  404. package/dist/hooks/prompt.d.ts +0 -47
  405. package/dist/hooks/prompt.js +0 -884
  406. package/dist/hooks/subagent.d.ts +0 -10
  407. package/dist/hooks/subagent.js +0 -387
  408. package/dist/hooks/thinking-checkpoint.d.ts +0 -37
  409. package/dist/hooks/thinking-checkpoint.js +0 -51
  410. package/dist/hooks/trajectory-collector.d.ts +0 -32
  411. package/dist/hooks/trajectory-collector.js +0 -256
  412. package/dist/http/principles-console-route.d.ts +0 -9
  413. package/dist/http/principles-console-route.js +0 -567
  414. package/dist/i18n/commands.d.ts +0 -26
  415. package/dist/i18n/commands.js +0 -116
  416. package/dist/index.d.ts +0 -7
  417. package/dist/index.js +0 -581
  418. package/dist/service/central-database.d.ts +0 -104
  419. package/dist/service/central-database.js +0 -649
  420. package/dist/service/control-ui-query-service.d.ts +0 -221
  421. package/dist/service/control-ui-query-service.js +0 -543
  422. package/dist/service/empathy-observer-manager.d.ts +0 -52
  423. package/dist/service/empathy-observer-manager.js +0 -229
  424. package/dist/service/evolution-query-service.d.ts +0 -155
  425. package/dist/service/evolution-query-service.js +0 -258
  426. package/dist/service/evolution-worker.d.ts +0 -101
  427. package/dist/service/evolution-worker.js +0 -974
  428. package/dist/service/nocturnal-runtime.d.ts +0 -183
  429. package/dist/service/nocturnal-service.d.ts +0 -163
  430. package/dist/service/nocturnal-service.js +0 -787
  431. package/dist/service/nocturnal-target-selector.d.ts +0 -145
  432. package/dist/service/nocturnal-target-selector.js +0 -315
  433. package/dist/service/phase3-input-filter.d.ts +0 -73
  434. package/dist/service/phase3-input-filter.js +0 -172
  435. package/dist/service/runtime-summary-service.d.ts +0 -122
  436. package/dist/service/runtime-summary-service.js +0 -485
  437. package/dist/service/trajectory-service.d.ts +0 -2
  438. package/dist/service/trajectory-service.js +0 -15
  439. package/dist/tools/critique-prompt.d.ts +0 -14
  440. package/dist/tools/deep-reflect.d.ts +0 -39
  441. package/dist/tools/deep-reflect.js +0 -350
  442. package/dist/tools/model-index.d.ts +0 -9
  443. package/dist/types/event-types.d.ts +0 -306
  444. package/dist/types/event-types.js +0 -106
  445. package/dist/types/hygiene-types.d.ts +0 -20
  446. package/dist/types/hygiene-types.js +0 -12
  447. package/dist/types/runtime-summary.d.ts +0 -47
  448. package/dist/types/runtime-summary.js +0 -1
  449. package/dist/types.d.ts +0 -50
  450. package/dist/types.js +0 -22
  451. package/dist/utils/file-lock.d.ts +0 -71
  452. package/dist/utils/file-lock.js +0 -309
  453. package/dist/utils/glob-match.d.ts +0 -28
  454. package/dist/utils/hashing.d.ts +0 -9
  455. package/dist/utils/io.d.ts +0 -6
  456. package/dist/utils/io.js +0 -106
  457. package/dist/utils/nlp.d.ts +0 -9
  458. package/dist/utils/plugin-logger.d.ts +0 -39
  459. package/dist/utils/subagent-probe.d.ts +0 -34
  460. package/dist/utils/subagent-probe.js +0 -81
@@ -0,0 +1,919 @@
1
+ import { afterEach, describe, expect, it } from 'vitest';
2
+ import * as fs from 'fs';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+ import { EventLogService } from '../../src/core/event-log.js';
6
+ import { clearSession, trackFriction } from '../../src/core/session-tracker.js';
7
+ import { WorkspaceContext } from '../../src/core/workspace-context.js';
8
+ import { serializeKvLines } from '../../src/utils/io.js';
9
+ import { RuntimeSummaryService } from '../../src/service/runtime-summary-service.js';
10
+
11
+ const tempDirs: string[] = [];
12
+
13
+ function makeWorkspace(): string {
14
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pd-runtime-summary-'));
15
+ tempDirs.push(dir);
16
+ fs.mkdirSync(path.join(dir, '.state', 'sessions'), { recursive: true });
17
+ fs.mkdirSync(path.join(dir, '.state', 'logs'), { recursive: true });
18
+ return dir;
19
+ }
20
+
21
+ function writeJson(filePath: string, value: unknown): void {
22
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
23
+ fs.writeFileSync(filePath, JSON.stringify(value, null, 2), 'utf8');
24
+ }
25
+
26
+ function writeSession(workspace: string, sessionId: string, payload: Record<string, unknown>): void {
27
+ writeJson(path.join(workspace, '.state', 'sessions', `${sessionId}.json`), {
28
+ sessionId,
29
+ ...payload,
30
+ });
31
+ }
32
+
33
+ function writeEvents(workspace: string, entries: unknown[]): void {
34
+ const filePath = path.join(workspace, '.state', 'logs', 'events.jsonl');
35
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
36
+ const content = entries.map((entry) => JSON.stringify(entry)).join('\n');
37
+ fs.writeFileSync(filePath, content ? `${content}\n` : '', 'utf8');
38
+ }
39
+
40
+ afterEach(() => {
41
+ for (const dir of tempDirs.splice(0)) {
42
+ fs.rmSync(dir, { recursive: true, force: true });
43
+ }
44
+ WorkspaceContext.clearCache();
45
+ clearSession('live-session');
46
+ });
47
+
48
+ describe('RuntimeSummaryService', () => {
49
+ it('builds an active workspace summary from canonical state files', () => {
50
+ const workspace = makeWorkspace();
51
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
52
+ trust_score: 85,
53
+ success_streak: 50,
54
+ last_updated: '2026-03-20T10:00:00Z',
55
+ });
56
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
57
+ { id: '1', status: 'pending', score: 50 },
58
+ { id: '2', status: 'completed', score: 10 },
59
+ ]);
60
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
61
+ active: true,
62
+ task: 'fix something important',
63
+ timestamp: '2026-03-20T10:00:00Z',
64
+ });
65
+ writeJson(path.join(workspace, '.state', 'pain_candidates.json'), {
66
+ candidates: {
67
+ a: {},
68
+ b: {},
69
+ },
70
+ });
71
+ fs.writeFileSync(
72
+ path.join(workspace, '.state', '.pain_flag'),
73
+ serializeKvLines({
74
+ source: 'tool_failure',
75
+ score: '50',
76
+ time: '2026-03-20T10:00:00Z',
77
+ }),
78
+ 'utf8'
79
+ );
80
+ writeSession(workspace, 's1', {
81
+ currentGfi: 45,
82
+ dailyGfiPeak: 78,
83
+ lastActivityAt: 2,
84
+ });
85
+ writeSession(workspace, 's0', {
86
+ currentGfi: 20,
87
+ dailyGfiPeak: 30,
88
+ lastActivityAt: 1,
89
+ });
90
+ writeEvents(workspace, [
91
+ {
92
+ ts: '2026-03-20T10:00:01Z',
93
+ type: 'pain_signal',
94
+ category: 'detected',
95
+ sessionId: 's1',
96
+ data: { source: 'tool_failure', score: 50, reason: 'write failed' },
97
+ },
98
+ {
99
+ ts: '2026-03-20T10:00:02Z',
100
+ type: 'gate_bypass',
101
+ category: 'bypassed',
102
+ sessionId: 's1',
103
+ data: { toolName: 'write' },
104
+ },
105
+ ]);
106
+
107
+ const summary = RuntimeSummaryService.getSummary(workspace);
108
+
109
+ expect(summary.gfi.current).toBe(45);
110
+ expect(summary.gfi.peak).toBe(78);
111
+ expect(summary.evolution.queue.pending).toBe(1);
112
+ expect(summary.evolution.queue.completed).toBe(1);
113
+ expect(summary.evolution.directive.exists).toBe(false);
114
+ expect(summary.evolution.directive.active).toBeNull();
115
+ expect(summary.evolution.dataQuality).toBe('authoritative');
116
+ expect(summary.pain.activeFlag).toBe(true);
117
+ expect(summary.pain.activeFlagSource).toBe('tool_failure');
118
+ expect(summary.pain.candidates).toBe(2);
119
+ expect(summary.pain.lastSignal?.source).toBe('tool_failure');
120
+ expect(summary.gate.recentBypasses).toBe(1);
121
+ expect(summary.metadata.sessionId).toBe('s1');
122
+ expect(summary.metadata.selectedSessionReason).toBe('latest_active');
123
+ });
124
+
125
+ it('returns partial warnings when canonical files are missing', () => {
126
+ const workspace = makeWorkspace();
127
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
128
+ trust_score: 100,
129
+ });
130
+
131
+ const summary = RuntimeSummaryService.getSummary(workspace);
132
+
133
+ expect(summary.gfi.current).toBeNull();
134
+ expect(summary.evolution.dataQuality).toBe('partial');
135
+ expect(summary.evolution.directive.exists).toBe(false);
136
+ expect(summary.pain.candidates).toBeNull();
137
+ expect(summary.metadata.warnings.join('\n')).toContain('No persisted session state was found');
138
+ expect(summary.metadata.warnings.join('\n')).toContain('partial');
139
+ });
140
+
141
+ it('derives compact phase3 readiness flags from queue inputs', () => {
142
+ const workspace = makeWorkspace();
143
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
144
+ { id: 'task-1', status: 'in_progress' },
145
+ { id: 'task-1', status: 'completed', completed_at: '2026-03-20T10:01:00Z' },
146
+ { id: 'task-2', status: 'completed' },
147
+ ]);
148
+
149
+ const summary = RuntimeSummaryService.getSummary(workspace);
150
+
151
+ expect(summary.phase3.queueTruthReady).toBe(false);
152
+ expect(summary.phase3.phase3ShadowEligible).toBe(false);
153
+ expect(summary.phase3.evolutionRejectedReasons).toEqual(
154
+ expect.arrayContaining([
155
+ 'reused_task_id',
156
+ 'missing_started_at',
157
+ 'missing_completed_at',
158
+ ])
159
+ );
160
+ });
161
+
162
+ it('derives phase3 readiness from valid queue entries', () => {
163
+ const workspace = makeWorkspace();
164
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
165
+ { id: 'task-1', status: 'pending' },
166
+ { id: 'task-2', status: 'in_progress', started_at: '2026-03-20T10:00:00Z' },
167
+ { id: 'task-3', status: 'completed', completed_at: '2026-03-20T10:01:00Z' },
168
+ ]);
169
+
170
+ const summary = RuntimeSummaryService.getSummary(workspace);
171
+
172
+ expect(summary.phase3.queueTruthReady).toBe(true);
173
+ expect(summary.phase3.phase3ShadowEligible).toBe(true);
174
+ });
175
+
176
+ it('prefers the explicit session when provided', () => {
177
+ const workspace = makeWorkspace();
178
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
179
+ trust_score: 30,
180
+ last_updated: '2026-03-20T10:00:00Z',
181
+ });
182
+ writeSession(workspace, 's1', {
183
+ currentGfi: 10,
184
+ dailyGfiPeak: 12,
185
+ lastActivityAt: 10,
186
+ });
187
+ writeSession(workspace, 's2', {
188
+ currentGfi: 70,
189
+ dailyGfiPeak: 80,
190
+ lastActivityAt: 20,
191
+ });
192
+
193
+ const summary = RuntimeSummaryService.getSummary(workspace, { sessionId: 's1' });
194
+
195
+ expect(summary.metadata.sessionId).toBe('s1');
196
+ expect(summary.metadata.selectedSessionReason).toBe('explicit');
197
+ expect(summary.gfi.current).toBe(10);
198
+ expect(summary.gfi.peak).toBe(12);
199
+ });
200
+
201
+ it('prefers the session with the newest control activity timestamp over plain activity', () => {
202
+ const workspace = makeWorkspace();
203
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
204
+ trust_score: 42,
205
+ last_updated: '2026-03-20T10:00:00Z',
206
+ });
207
+ writeSession(workspace, 's1', {
208
+ currentGfi: 11,
209
+ dailyGfiPeak: 20,
210
+ lastActivityAt: 50,
211
+ lastControlActivityAt: 200,
212
+ });
213
+ writeSession(workspace, 's2', {
214
+ currentGfi: 99,
215
+ dailyGfiPeak: 99,
216
+ lastActivityAt: 100,
217
+ lastControlActivityAt: 100,
218
+ });
219
+
220
+ const summary = RuntimeSummaryService.getSummary(workspace);
221
+
222
+ expect(summary.metadata.sessionId).toBe('s1');
223
+ expect(summary.gfi.current).toBe(11);
224
+ });
225
+
226
+ it('warns when a legacy directive is stale relative to an empty queue', () => {
227
+ const workspace = makeWorkspace();
228
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
229
+ trust_score: 100,
230
+ });
231
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), []);
232
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
233
+ active: true,
234
+ task: 'old task',
235
+ timestamp: '2026-03-18T00:00:00Z',
236
+ });
237
+
238
+ const summary = RuntimeSummaryService.getSummary(workspace);
239
+
240
+ expect(summary.evolution.directive.exists).toBe(false);
241
+ expect(summary.evolution.directive.active).toBeNull();
242
+ expect(summary.evolution.dataQuality).toBe('authoritative');
243
+ expect(summary.evolution.directive.ageSeconds).toBeNull();
244
+ expect(summary.metadata.warnings.join('\n')).toContain('Legacy directive file disagrees with queue-derived evolution state');
245
+ });
246
+
247
+ it('derives directive view from queue-only in-progress work and treats it as authoritative without a directive file', () => {
248
+ const workspace = makeWorkspace();
249
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
250
+ trust_score: 55,
251
+ last_updated: '2026-03-20T10:00:00Z',
252
+ });
253
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
254
+ { id: 'task-1', status: 'in_progress', score: 60, task: 'Diagnose systemic pain [ID: task-1]' },
255
+ ]);
256
+
257
+ const summary = RuntimeSummaryService.getSummary(workspace);
258
+
259
+ expect(summary.evolution.queue.inProgress).toBe(1);
260
+ expect(summary.evolution.directive.exists).toBe(true);
261
+ expect(summary.evolution.directive.active).toBe(true);
262
+ expect(summary.evolution.directive.taskPreview).toContain('Diagnose systemic pain [ID: task-1]');
263
+ expect(summary.evolution.dataQuality).toBe('authoritative');
264
+ });
265
+
266
+ it('uses trigger_text_preview when an in-progress queue item is missing task text', () => {
267
+ const workspace = makeWorkspace();
268
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
269
+ trust_score: 55,
270
+ last_updated: '2026-03-20T10:00:00Z',
271
+ });
272
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
273
+ {
274
+ id: 'task-2',
275
+ status: 'in_progress',
276
+ score: 80,
277
+ source: 'tool_failure',
278
+ reason: 'write failed',
279
+ trigger_text_preview: 'Could not find the file to patch',
280
+ },
281
+ ]);
282
+
283
+ const summary = RuntimeSummaryService.getSummary(workspace);
284
+
285
+ expect(summary.evolution.directive.exists).toBe(true);
286
+ expect(summary.evolution.directive.active).toBe(true);
287
+ expect(summary.evolution.directive.taskPreview).toContain('Could not find the file to patch');
288
+ expect(summary.evolution.directive.taskPreview).toContain('Diagnose systemic pain [ID: task-2]');
289
+ });
290
+
291
+ it('skips a malformed top-ranked in-progress task and falls back to the next resolvable task', () => {
292
+ const workspace = makeWorkspace();
293
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
294
+ trust_score: 55,
295
+ last_updated: '2026-03-20T10:00:00Z',
296
+ });
297
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
298
+ {
299
+ status: 'in_progress',
300
+ score: 100,
301
+ task: 'undefined',
302
+ },
303
+ {
304
+ id: 'task-3',
305
+ status: 'in_progress',
306
+ score: 20,
307
+ task: 'Diagnose systemic pain [ID: task-3]',
308
+ },
309
+ ]);
310
+
311
+ const summary = RuntimeSummaryService.getSummary(workspace);
312
+
313
+ expect(summary.evolution.directive.exists).toBe(true);
314
+ expect(summary.evolution.directive.taskPreview).toContain('Diagnose systemic pain [ID: task-3]');
315
+ expect(summary.evolution.directive.taskPreview).not.toContain('undefined');
316
+ });
317
+
318
+ it('warns when a legacy directive disagrees with queue in-progress state', () => {
319
+ const workspace = makeWorkspace();
320
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
321
+ trust_score: 55,
322
+ last_updated: '2026-03-20T10:00:00Z',
323
+ });
324
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
325
+ { id: 'task-1', status: 'in_progress', score: 60, task: 'Diagnose systemic pain [ID: task-1]' },
326
+ ]);
327
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
328
+ active: false,
329
+ task: 'legacy mismatch task',
330
+ timestamp: '2026-03-20T10:00:00Z',
331
+ });
332
+
333
+ const summary = RuntimeSummaryService.getSummary(workspace);
334
+
335
+ expect(summary.evolution.directive.exists).toBe(true);
336
+ expect(summary.evolution.directive.active).toBe(true);
337
+ expect(summary.metadata.warnings.join('\n')).toContain('Legacy directive file disagrees');
338
+ expect(summary.evolution.dataQuality).toBe('authoritative');
339
+ });
340
+
341
+ it('surfaces observer empathy events as authoritative gfi sources', () => {
342
+ const workspace = makeWorkspace();
343
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
344
+ trust_score: 59,
345
+ last_updated: '2026-03-20T10:00:00Z',
346
+ });
347
+ writeSession(workspace, 's-observer', {
348
+ currentGfi: 25,
349
+ dailyGfiPeak: 25,
350
+ lastActivityAt: 5,
351
+ });
352
+ writeEvents(workspace, [
353
+ {
354
+ ts: '2026-03-20T10:00:03Z',
355
+ type: 'pain_signal',
356
+ category: 'detected',
357
+ sessionId: 's-observer',
358
+ data: {
359
+ source: 'user_empathy',
360
+ origin: 'system_infer',
361
+ severity: 'moderate',
362
+ confidence: 0.8,
363
+ score: 25,
364
+ reason: 'observer caught frustration',
365
+ },
366
+ },
367
+ ]);
368
+
369
+ const summary = RuntimeSummaryService.getSummary(workspace, { sessionId: 's-observer' });
370
+
371
+ expect(summary.gfi.sources).toEqual([
372
+ expect.objectContaining({
373
+ source: 'user_empathy',
374
+ origin: 'system_infer',
375
+ score: 25,
376
+ confidence: 0.8,
377
+ }),
378
+ ]);
379
+ expect(summary.pain.lastSignal?.source).toBe('user_empathy');
380
+ });
381
+
382
+ it('includes in-memory session state and buffered events before flush', () => {
383
+ const workspace = makeWorkspace();
384
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
385
+ trust_score: 59,
386
+ last_updated: '2026-03-20T10:00:00Z',
387
+ });
388
+
389
+ trackFriction('live-session', 18, 'user_empathy_mild', workspace, { source: 'user_empathy' });
390
+ const eventLog = EventLogService.get(path.join(workspace, '.state'));
391
+ eventLog.recordPainSignal('live-session', {
392
+ score: 18,
393
+ source: 'user_empathy',
394
+ reason: 'buffered empathy event',
395
+ origin: 'assistant_self_report',
396
+ severity: 'mild',
397
+ confidence: 1,
398
+ detection_mode: 'structured',
399
+ deduped: false,
400
+ eventId: 'live-emp-1',
401
+ });
402
+
403
+ const summary = RuntimeSummaryService.getSummary(workspace, { sessionId: 'live-session' });
404
+
405
+ expect(summary.metadata.sessionId).toBe('live-session');
406
+ expect(summary.metadata.selectedSessionReason).toBe('explicit');
407
+ expect(summary.gfi.current).toBe(18);
408
+ expect(summary.pain.lastSignal?.reason).toBe('buffered empathy event');
409
+ expect(summary.gfi.sources).toEqual([
410
+ expect.objectContaining({
411
+ source: 'user_empathy',
412
+ score: 18,
413
+ origin: 'assistant_self_report',
414
+ }),
415
+ ]);
416
+ expect(summary.metadata.warnings.join('\n')).not.toContain('Live event buffer is unavailable');
417
+ });
418
+
419
+ it('deduplicates persisted and buffered copies of the same event by eventId', () => {
420
+ const workspace = makeWorkspace();
421
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
422
+ trust_score: 59,
423
+ last_updated: '2026-03-20T10:00:00Z',
424
+ });
425
+ writeSession(workspace, 's-dedupe', {
426
+ currentGfi: 18,
427
+ dailyGfiPeak: 18,
428
+ lastActivityAt: 5,
429
+ lastControlActivityAt: 5,
430
+ });
431
+ writeEvents(workspace, [
432
+ {
433
+ ts: '2026-03-20T10:00:03Z',
434
+ type: 'pain_signal',
435
+ category: 'detected',
436
+ sessionId: 's-dedupe',
437
+ data: {
438
+ source: 'user_empathy',
439
+ origin: 'assistant_self_report',
440
+ severity: 'mild',
441
+ confidence: 1,
442
+ score: 18,
443
+ reason: 'same event',
444
+ eventId: 'dup-1',
445
+ },
446
+ },
447
+ ]);
448
+
449
+ const eventLog = EventLogService.get(path.join(workspace, '.state'));
450
+ eventLog.recordPainSignal('s-dedupe', {
451
+ source: 'user_empathy',
452
+ origin: 'assistant_self_report',
453
+ severity: 'mild',
454
+ confidence: 1,
455
+ score: 18,
456
+ reason: 'same event',
457
+ eventId: 'dup-1',
458
+ detection_mode: 'structured',
459
+ deduped: false,
460
+ });
461
+
462
+ const summary = RuntimeSummaryService.getSummary(workspace, { sessionId: 's-dedupe' });
463
+
464
+ expect(summary.gfi.sources).toHaveLength(1);
465
+ expect(summary.pain.lastSignal?.reason).toBe('same event');
466
+ });
467
+
468
+ it('warns when malformed event lines are skipped', () => {
469
+ const workspace = makeWorkspace();
470
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
471
+ trust_score: 59,
472
+ last_updated: '2026-03-20T10:00:00Z',
473
+ });
474
+ fs.writeFileSync(
475
+ path.join(workspace, '.state', 'logs', 'events.jsonl'),
476
+ [
477
+ JSON.stringify({
478
+ ts: '2026-03-20T10:00:01Z',
479
+ type: 'pain_signal',
480
+ category: 'detected',
481
+ sessionId: 's1',
482
+ data: { source: 'tool_failure', score: 10, reason: 'write failed' },
483
+ }),
484
+ '{not-json}',
485
+ ].join('\n'),
486
+ 'utf8'
487
+ );
488
+
489
+ const summary = RuntimeSummaryService.getSummary(workspace);
490
+
491
+ expect(summary.metadata.warnings.join('\n')).toContain('Skipped 1 malformed event line');
492
+ });
493
+
494
+ // Task 8: Updated phase3 integration tests
495
+ describe('Phase 3 Input Quarantine Integration', () => {
496
+ it('reports legacy queue status as rejection reason in phase3 section', () => {
497
+ const workspace = makeWorkspace();
498
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
499
+ trust_score: 85,
500
+ frozen: true,
501
+ last_updated: '2026-03-20T10:00:00Z',
502
+ });
503
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
504
+ { id: '1afdd4bb', status: 'resolved', started_at: '2026-03-24T15:29:39.710Z', completed_at: '2026-03-24T15:29:39.710Z' }
505
+ ]);
506
+
507
+ const summary = RuntimeSummaryService.getSummary(workspace);
508
+
509
+ expect(summary.phase3.queueTruthReady).toBe(false);
510
+ expect(summary.phase3.evolutionRejectedReasons).toContain('legacy_queue_status');
511
+ });
512
+
513
+ it('reports null status as rejection reason in phase3 section', () => {
514
+ const workspace = makeWorkspace();
515
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
516
+ trust_score: 85,
517
+ frozen: true,
518
+ last_updated: '2026-03-20T10:00:00Z',
519
+ });
520
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
521
+ { id: '6a7c7c48', status: null, started_at: '2026-03-24T15:29:39.710Z' }
522
+ ]);
523
+
524
+ const summary = RuntimeSummaryService.getSummary(workspace);
525
+
526
+ expect(summary.phase3.queueTruthReady).toBe(false);
527
+ expect(summary.phase3.evolutionRejectedReasons).toContain('missing_status');
528
+ });
529
+
530
+ it('reports timeout-only outcomes as referenceOnly (not rejected)', () => {
531
+ const workspace = makeWorkspace();
532
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
533
+ { id: 'e5da4f5c', status: 'completed', resolution: 'auto_completed_timeout', completed_at: '2026-03-24T15:29:39.710Z' }
534
+ ]);
535
+
536
+ const summary = RuntimeSummaryService.getSummary(workspace);
537
+
538
+ // Timeout-only outcomes are valid data (queue is ready)
539
+ // They go to referenceOnly, not rejected
540
+ expect(summary.phase3.queueTruthReady).toBe(true);
541
+ // No rejection reasons from timeout
542
+ expect(summary.phase3.evolutionRejectedReasons).not.toContain('timeout_only_outcome');
543
+ });
544
+
545
+ it('labels directive status as compatibility-only when directive file exists', () => {
546
+ const workspace = makeWorkspace();
547
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
548
+ trust_score: 85,
549
+ frozen: true,
550
+ last_updated: '2026-03-20T10:00:00Z',
551
+ });
552
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
553
+ { id: 'task-1', status: 'completed', completed_at: '2026-03-25T10:00:00.000Z' },
554
+ { id: 'task-2', status: 'in_progress', started_at: '2026-03-25T11:00:00.000Z' }
555
+ ]);
556
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
557
+ active: true,
558
+ task: 'some task',
559
+ timestamp: '2026-03-20T10:00:00Z',
560
+ });
561
+
562
+ const summary = RuntimeSummaryService.getSummary(workspace);
563
+
564
+ expect(summary.phase3.directiveStatus).toBe('compatibility-only');
565
+ expect(summary.phase3.directiveIgnoredReason).toBe('queue is only truth source');
566
+ });
567
+
568
+ it('reports directive status as missing when directive file does not exist', () => {
569
+ const workspace = makeWorkspace();
570
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
571
+ trust_score: 85,
572
+ frozen: true,
573
+ last_updated: '2026-03-20T10:00:00Z',
574
+ });
575
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
576
+ { id: 'task-1', status: 'completed', completed_at: '2026-03-25T10:00:00.000Z' }
577
+ ]);
578
+ // No evolution_directive.json file
579
+
580
+ const summary = RuntimeSummaryService.getSummary(workspace);
581
+
582
+ expect(summary.phase3.directiveStatus).toBe('missing');
583
+ expect(summary.phase3.directiveIgnoredReason).toBe('queue is only truth source');
584
+ });
585
+
586
+ it('reports directive as compatibility-only even when stale', () => {
587
+ // Production scenario: directive stopped updating on 2026-03-22
588
+ // Should still be labeled as compatibility-only, not 'stale'
589
+ const workspace = makeWorkspace();
590
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
591
+ trust_score: 85,
592
+ frozen: true,
593
+ last_updated: '2026-03-20T10:00:00Z',
594
+ });
595
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
596
+ { id: 'task-1', status: 'completed', completed_at: '2026-03-25T10:00:00.000Z' }
597
+ ]);
598
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
599
+ active: true,
600
+ task: 'old task',
601
+ timestamp: '2026-03-22T00:00:00Z', // Stale timestamp
602
+ });
603
+
604
+ const summary = RuntimeSummaryService.getSummary(workspace);
605
+
606
+ expect(summary.phase3.directiveStatus).toBe('compatibility-only');
607
+ expect(summary.phase3.directiveIgnoredReason).toBe('queue is only truth source');
608
+ });
609
+
610
+ it('labels directive as compatibility-only even when active flag is false', () => {
611
+ // Directive presence matters for labeling, not the active flag value
612
+ const workspace = makeWorkspace();
613
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
614
+ trust_score: 85,
615
+ frozen: true,
616
+ last_updated: '2026-03-20T10:00:00Z',
617
+ });
618
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
619
+ { id: 'task-1', status: 'completed', completed_at: '2026-03-25T10:00:00.000Z' }
620
+ ]);
621
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
622
+ active: false, // inactive directive
623
+ task: 'inactive task',
624
+ timestamp: '2026-03-20T10:00:00Z',
625
+ });
626
+
627
+ const summary = RuntimeSummaryService.getSummary(workspace);
628
+
629
+ expect(summary.phase3.directiveStatus).toBe('compatibility-only');
630
+ expect(summary.phase3.directiveIgnoredReason).toBe('queue is only truth source');
631
+ });
632
+
633
+ it('labels directive as compatibility-only even with minimal/empty fields', () => {
634
+ // Directive file exists with minimal content should still be labeled
635
+ const workspace = makeWorkspace();
636
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
637
+ trust_score: 85,
638
+ frozen: true,
639
+ last_updated: '2026-03-20T10:00:00Z',
640
+ });
641
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
642
+ { id: 'task-1', status: 'completed', completed_at: '2026-03-25T10:00:00.000Z' }
643
+ ]);
644
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
645
+ // Minimal directive with no task, timestamp, or active fields
646
+ });
647
+
648
+ const summary = RuntimeSummaryService.getSummary(workspace);
649
+
650
+ expect(summary.phase3.directiveStatus).toBe('compatibility-only');
651
+ expect(summary.phase3.directiveIgnoredReason).toBe('queue is only truth source');
652
+ });
653
+ });
654
+
655
+ // Task 8: TDD tests for Runtime vs Analytics Separation (RED phase)
656
+ describe('Runtime vs Analytics Separation', () => {
657
+ it('populates runtime truth section with queue and sessions', () => {
658
+ const workspace = makeWorkspace();
659
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
660
+ { id: 'task-1', status: 'pending' },
661
+ { id: 'task-2', status: 'in_progress' },
662
+ { id: 'task-3', status: 'completed' },
663
+ ]);
664
+
665
+ const summary = RuntimeSummaryService.getSummary(workspace);
666
+
667
+ expect(summary.runtime.queueState.total).toBe(3);
668
+ expect(summary.runtime.queueState.pending).toBe(1);
669
+ expect(summary.runtime.queueState.inProgress).toBe(1);
670
+ expect(summary.runtime.queueState.completed).toBe(1);
671
+ expect(summary.runtime.activeSessions).toEqual(expect.any(Array));
672
+ });
673
+
674
+ it('populates analytics truth section with trajectory, daily stats, trends', () => {
675
+ const workspace = makeWorkspace();
676
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
677
+ trust_score: 75,
678
+ last_updated: '2026-03-20T10:00:00Z',
679
+ });
680
+ writeJson(path.join(workspace, '.state', 'logs', 'daily-stats.json'), {
681
+ '2026-03-20': {
682
+ toolCalls: 120,
683
+ painSignals: 15,
684
+ evolutionTasks: 5,
685
+ },
686
+ });
687
+
688
+ const summary = RuntimeSummaryService.getSummary(workspace);
689
+
690
+ // These properties don't exist yet - tests will FAIL (RED phase)
691
+ expect(summary.analytics.trajectoryData).toBeDefined();
692
+ expect(summary.analytics.dailyStats.toolCalls).toBe(120);
693
+ expect(summary.analytics.dailyStats.painSignals).toBe(15);
694
+ expect(summary.analytics.trends).toBeDefined();
695
+ });
696
+
697
+ it('calculates Phase 3 readiness from runtime truth only', () => {
698
+ const workspace = makeWorkspace();
699
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
700
+ { id: 'task-1', status: 'completed', completed_at: '2026-03-25T10:00:00.000Z' },
701
+ { id: 'task-2', status: 'pending' },
702
+ ]);
703
+
704
+ const summary = RuntimeSummaryService.getSummary(workspace);
705
+
706
+ // Runtime truth drives eligibility
707
+ expect(summary.phase3.queueTruthReady).toBe(true);
708
+ expect(summary.phase3.phase3ShadowEligible).toBe(true);
709
+
710
+ // Phase 3 eligibility source should be runtime truth
711
+ expect(summary.phase3.eligibilitySource).toBe('runtime_truth');
712
+ });
713
+
714
+ it('does not use analytics for Phase 3 eligibility', () => {
715
+ const workspace = makeWorkspace();
716
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
717
+ trust_score: 85,
718
+ frozen: true,
719
+ last_updated: '2026-03-20T10:00:00Z',
720
+ });
721
+ // Invalid runtime queue - no valid entries
722
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
723
+ { id: 'task-1', status: 'resolved' }, // legacy status - invalid
724
+ ]);
725
+
726
+ const summary = RuntimeSummaryService.getSummary(workspace);
727
+
728
+ // Runtime truth invalid → not eligible, regardless of analytics
729
+ expect(summary.phase3.queueTruthReady).toBe(false);
730
+ expect(summary.phase3.phase3ShadowEligible).toBe(false);
731
+
732
+ // Analytics data exists but is ignored for eligibility
733
+ expect(summary.analytics).toBeDefined();
734
+ });
735
+
736
+ it('separates queue into runtime truth section only', () => {
737
+ const workspace = makeWorkspace();
738
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
739
+ trust_score: 75,
740
+ last_updated: '2026-03-20T10:00:00Z',
741
+ });
742
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
743
+ { id: 'task-1', status: 'pending', score: 50 },
744
+ { id: 'task-2', status: 'in_progress', score: 60 },
745
+ { id: 'task-3', status: 'completed', score: 10 },
746
+ ]);
747
+
748
+ const summary = RuntimeSummaryService.getSummary(workspace);
749
+
750
+ // Queue data belongs to runtime truth
751
+ expect(summary.runtime.queueState.total).toBe(3);
752
+ expect(summary.runtime.queueState.pending).toBe(1);
753
+ expect(summary.runtime.queueState.inProgress).toBe(1);
754
+ expect(summary.runtime.queueState.completed).toBe(1);
755
+ expect(summary.runtime.queueState.lastUpdated).toBeDefined();
756
+
757
+ // Analytics section should NOT have queue data
758
+ expect(summary.analytics.trajectoryData).not.toHaveProperty('queue');
759
+ });
760
+
761
+ it('surfaces reference-only Phase 3 evidence in the runtime summary', () => {
762
+ const workspace = makeWorkspace();
763
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
764
+ trust_score: 85,
765
+ frozen: true,
766
+ last_updated: '2026-03-20T10:00:00Z',
767
+ });
768
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
769
+ { id: 'timeout-1', status: 'completed', resolution: 'auto_completed_timeout', completed_at: '2026-03-24T15:29:39.710Z' },
770
+ ]);
771
+
772
+ const summary = RuntimeSummaryService.getSummary(workspace);
773
+
774
+ expect(summary.phase3.queueTruthReady).toBe(true);
775
+ expect(summary.phase3.evolutionReferenceOnly).toBe(1);
776
+ expect(summary.phase3.evolutionReferenceOnlyReasons).toContain('timeout_only');
777
+ expect(summary.phase3.evolutionRejected).toBe(0);
778
+ expect(summary.phase3.phase3ShadowEligible).toBe(false);
779
+ });
780
+
781
+ it('includes lastUpdated timestamps in runtime truth section', () => {
782
+ const workspace = makeWorkspace();
783
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
784
+ { id: 'task-1', status: 'pending' },
785
+ ]);
786
+
787
+ const summary = RuntimeSummaryService.getSummary(workspace);
788
+
789
+ // Runtime truth section includes timing metadata
790
+ expect(summary.runtime.queueState.lastUpdated).toBeDefined();
791
+ });
792
+
793
+ it('populates activeSessions from session tracker in runtime truth', () => {
794
+ const workspace = makeWorkspace();
795
+ writeJson(path.join(workspace, '.state', 'AGENT_SCORECARD.json'), {
796
+ trust_score: 75,
797
+ last_updated: '2026-03-20T10:00:00Z',
798
+ });
799
+ writeSession(workspace, 'session-1', {
800
+ currentGfi: 10,
801
+ lastActivityAt: 100,
802
+ });
803
+ writeSession(workspace, 'session-2', {
804
+ currentGfi: 20,
805
+ lastActivityAt: 200,
806
+ });
807
+
808
+ const summary = RuntimeSummaryService.getSummary(workspace);
809
+
810
+ // Active sessions belong to runtime truth
811
+ expect(summary.runtime.activeSessions).toEqual(expect.any(Array));
812
+ expect(summary.runtime.activeSessions).toContain('session-1');
813
+ expect(summary.runtime.activeSessions).toContain('session-2');
814
+
815
+ // Analytics section should NOT have sessions
816
+ expect(summary.analytics).not.toHaveProperty('sessions');
817
+ });
818
+ });
819
+
820
+ // ═══════════════════════════════════════════════════════════════════════════
821
+ // Task 3: Directive File Does Not Affect Phase 3 Eligibility
822
+ // ═══════════════════════════════════════════════════════════════════════════
823
+ describe('Directive File Is Compatibility-Only Display Artifact', () => {
824
+ /**
825
+ * PURPOSE: Prove that EVOLUTION_DIRECTIVE.json does NOT affect Phase 3 eligibility.
826
+ * Directive is a compatibility-only display artifact, not a truth source.
827
+ * Phase 3 eligibility depends ONLY on queue.
828
+ */
829
+
830
+ it('Phase 3 eligibility is same whether directive exists or not', () => {
831
+ const workspace = makeWorkspace();
832
+
833
+ // Valid queue for Phase 3
834
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
835
+ { id: 'task-1', status: 'pending' },
836
+ ]);
837
+
838
+ // Get summary WITHOUT directive file
839
+ const summaryWithoutDirective = RuntimeSummaryService.getSummary(workspace);
840
+
841
+ // Now add directive file with conflicting content
842
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
843
+ active: false, // Contradicts queue
844
+ task: 'completely different task',
845
+ taskId: 'different-id',
846
+ timestamp: '2026-03-15T10:00:00Z', // Old timestamp
847
+ });
848
+
849
+ const summaryWithDirective = RuntimeSummaryService.getSummary(workspace);
850
+
851
+ // Phase 3 eligibility should be IDENTICAL regardless of directive
852
+ expect(summaryWithDirective.phase3.phase3ShadowEligible).toBe(
853
+ summaryWithoutDirective.phase3.phase3ShadowEligible
854
+ );
855
+ expect(summaryWithDirective.phase3.queueTruthReady).toBe(
856
+ summaryWithoutDirective.phase3.queueTruthReady
857
+ );
858
+
859
+ // Both should be eligible because queue is valid
860
+ expect(summaryWithDirective.phase3.phase3ShadowEligible).toBe(true);
861
+ });
862
+
863
+ it('Phase 3 eligibility is false when queue invalid, regardless of directive', () => {
864
+ const workspace = makeWorkspace();
865
+
866
+ // Invalid queue (legacy status)
867
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
868
+ { id: 'task-1', status: 'resolved' }, // Legacy status
869
+ ]);
870
+
871
+ // Add directive claiming everything is fine
872
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
873
+ active: true,
874
+ task: 'valid active task',
875
+ taskId: 'task-1',
876
+ timestamp: new Date().toISOString(),
877
+ });
878
+
879
+ const summary = RuntimeSummaryService.getSummary(workspace);
880
+
881
+ // Phase 3 eligibility should be false despite directive claiming active
882
+ expect(summary.phase3.phase3ShadowEligible).toBe(false);
883
+ expect(summary.phase3.queueTruthReady).toBe(false);
884
+ });
885
+
886
+ it('directive summary shows queue-derived values, not file content', () => {
887
+ const workspace = makeWorkspace();
888
+
889
+ // Queue has in_progress task
890
+ writeJson(path.join(workspace, '.state', 'evolution_queue.json'), [
891
+ {
892
+ id: 'queue-task-123',
893
+ status: 'in_progress',
894
+ task: 'task from queue',
895
+ started_at: '2026-03-24T10:00:00Z',
896
+ },
897
+ ]);
898
+
899
+ // Directive has completely different content (stale/mismatch)
900
+ writeJson(path.join(workspace, '.state', 'evolution_directive.json'), {
901
+ active: true,
902
+ task: 'stale task from directive file',
903
+ taskId: 'directive-task-999',
904
+ timestamp: '2026-03-15T10:00:00Z',
905
+ });
906
+
907
+ const summary = RuntimeSummaryService.getSummary(workspace);
908
+
909
+ // Directive summary should show queue-derived values
910
+ // The directive taskPreview should come from queue, not directive file
911
+ expect(summary.evolution.directive.exists).toBe(true);
912
+ expect(summary.evolution.directive.active).toBe(true);
913
+
914
+ // The directiveStatus should indicate it's compatibility-only
915
+ expect(summary.phase3.directiveStatus).toBe('compatibility-only');
916
+ expect(summary.phase3.directiveIgnoredReason).toBe('queue is only truth source');
917
+ });
918
+ });
919
+ });