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,856 @@
1
+ /**
2
+ * NocturnalWorkflowManager — WorkflowManager interface for Nocturnal Reflection
3
+ * =============================================================================
4
+ *
5
+ * PURPOSE: Wraps OpenClawTrinityRuntimeAdapter in the WorkflowManager interface.
6
+ * Single-reflector path only (useTrinity=false). Trinity multi-stage chain comes
7
+ * in Phase 7.
8
+ *
9
+ * DESIGN:
10
+ * - NocturnalWorkflowManager calls executeNocturnalReflectionAsync synchronously
11
+ * within startWorkflow. There is no wait polling path.
12
+ * - All 5 nocturnal event types are recorded: nocturnal_started, nocturnal_completed,
13
+ * nocturnal_failed, nocturnal_fallback, nocturnal_expired.
14
+ * - sweepExpiredWorkflows marks expired workflows and cleans partial artifact files.
15
+ * - notifyWaitResult and notifyLifecycleEvent are no-ops per D-10.
16
+ *
17
+ * PHASE: Phase 6 — Foundation and Single-Reflector Mode
18
+ */
19
+
20
+ import type { PluginLogger } from '../../openclaw-sdk.js';
21
+ import type {
22
+ WorkflowManager,
23
+ WorkflowHandle,
24
+ SubagentWorkflowSpec,
25
+ WorkflowMetadata,
26
+ WorkflowDebugSummary,
27
+ WorkflowResultContext,
28
+ WorkflowPersistContext,
29
+ WorkflowEventRow,
30
+ } from './types.js';
31
+ import { WorkflowStore } from './workflow-store.js';
32
+ import { resolveNocturnalDir } from '../../core/nocturnal-paths.js';
33
+ import {
34
+ executeNocturnalReflectionAsync,
35
+ type NocturnalRunResult,
36
+ } from '../nocturnal-service.js';
37
+ import { type TrinityStageFailure, type TrinityResult } from '../../core/nocturnal-trinity.js';
38
+ import type { TrinityRuntimeAdapter, TrinityConfig, DreamerOutput, PhilosopherOutput, TrinityTelemetry } from '../../core/nocturnal-trinity.js';
39
+ import type { NocturnalSessionSnapshot } from '../../core/nocturnal-trajectory-extractor.js';
40
+ import { createHash } from 'crypto';
41
+ import * as fs from 'fs';
42
+ import * as path from 'path';
43
+
44
+ // ─────────────────────────────────────────────────────────────────────────────
45
+ // NocturnalResult Type Alias
46
+ // ─────────────────────────────────────────────────────────────────────────────
47
+
48
+ /**
49
+ * Nocturnal workflow result type (mirrors NocturnalRunResult per D-02).
50
+ * This is the result type returned by executeNocturnalReflectionAsync.
51
+ */
52
+ export type NocturnalResult = NocturnalRunResult;
53
+
54
+ // ─────────────────────────────────────────────────────────────────────────────
55
+ // Idempotency Key Computation (D-18)
56
+ // ─────────────────────────────────────────────────────────────────────────────
57
+
58
+ /**
59
+ * Compute idempotency key for the Dreamer stage (D-18).
60
+ * Key = SHA-256(workflowId + stage + inputDigest)
61
+ * inputDigest = SHA-256(snapshot.sessionId + principleId + maxCandidates)
62
+ * Uses simple concatenation (no delimiters) per D-18 spec.
63
+ */
64
+ function computeDreamerIdempotencyKey(
65
+ workflowId: string,
66
+ snapshot: import('../../core/nocturnal-trajectory-extractor.js').NocturnalSessionSnapshot,
67
+ principleId: string,
68
+ maxCandidates: number
69
+ ): string {
70
+ // Use delimiters to prevent collision (e.g., "sess10"+"2"+"3" vs "sess1"+"02"+"3")
71
+ const inputDigest = createHash('sha256')
72
+ .update(`${snapshot.sessionId}::${principleId}::${maxCandidates}`)
73
+ .digest('hex');
74
+ return createHash('sha256')
75
+ .update(`${workflowId}::dreamer::${inputDigest}`)
76
+ .digest('hex');
77
+ }
78
+
79
+ /**
80
+ * Compute idempotency key for the Philosopher stage (D-18).
81
+ * Key = SHA-256(workflowId + stage + inputDigest)
82
+ * inputDigest = SHA-256(workflowId + dreamerOutputJson)
83
+ * Uses simple concatenation (no delimiters) per D-18 spec.
84
+ */
85
+ function computePhilosopherIdempotencyKey(
86
+ workflowId: string,
87
+ dreamerOutput: import('../../core/nocturnal-trinity.js').DreamerOutput
88
+ ): string {
89
+ const dreamerOutputJson = JSON.stringify(dreamerOutput);
90
+ const inputDigest = createHash('sha256')
91
+ .update(workflowId + dreamerOutputJson)
92
+ .digest('hex');
93
+ return createHash('sha256')
94
+ .update(workflowId + 'philosopher' + inputDigest)
95
+ .digest('hex');
96
+ }
97
+
98
+ // ─────────────────────────────────────────────────────────────────────────────
99
+ // NocturnalWorkflowOptions
100
+ // ─────────────────────────────────────────────────────────────────────────────
101
+
102
+ export interface NocturnalWorkflowOptions {
103
+ /** Workspace directory for artifact storage */
104
+ workspaceDir: string;
105
+ /** State directory for nocturnal runtime bookkeeping */
106
+ stateDir: string;
107
+ /** Plugin logger */
108
+ logger: PluginLogger;
109
+ /** Trinity runtime adapter for subagent execution */
110
+ runtimeAdapter: TrinityRuntimeAdapter;
111
+ }
112
+
113
+ // ─────────────────────────────────────────────────────────────────────────────
114
+ // NocturnalWorkflowSpec
115
+ // ─────────────────────────────────────────────────────────────────────────────
116
+
117
+ /**
118
+ * Nocturnal workflow specification.
119
+ * Drives NocturnalWorkflowManager for the nocturnal reflection workflow.
120
+ *
121
+ * Per D-07, D-08, D-09, D-03, D-04:
122
+ * - workflowType: 'nocturnal'
123
+ * - transport: 'runtime_direct'
124
+ * - shouldDeleteSessionAfterFinalize: false (no external session to delete)
125
+ * - timeoutMs: 15 minutes (900000ms)
126
+ * - ttlMs: 30 minutes (1800000ms)
127
+ */
128
+ export const nocturnalWorkflowSpec: SubagentWorkflowSpec<NocturnalResult> = {
129
+ workflowType: 'nocturnal',
130
+ transport: 'runtime_direct',
131
+ timeoutMs: 15 * 60 * 1000, // D-03: 15 minutes
132
+ ttlMs: 30 * 60 * 1000, // D-04: 30 minutes
133
+ shouldDeleteSessionAfterFinalize: false, // D-09: no external session to delete
134
+
135
+ buildPrompt(_taskInput: unknown, _metadata: WorkflowMetadata): string {
136
+ // NocturnalWorkflowManager does not use prompt injection.
137
+ // Execution is driven by executeNocturnalReflectionAsync.
138
+ return '';
139
+ },
140
+
141
+ async parseResult(ctx: WorkflowResultContext): Promise<NocturnalResult | null> {
142
+ // NocturnalWorkflowManager handles execution directly in startWorkflow.
143
+ // This is not called via the standard subagent message path.
144
+ return (ctx.metadata['nocturnalResult'] as NocturnalResult) ?? null;
145
+ },
146
+
147
+ async persistResult(_ctx: WorkflowPersistContext<NocturnalResult>): Promise<void> {
148
+ // Artifact persistence is handled in startWorkflow after
149
+ // executeNocturnalReflectionAsync returns. The artifact is already
150
+ // persisted by the service; nothing more needed here.
151
+ },
152
+
153
+ shouldFinalizeOnWaitStatus(status: 'ok' | 'error' | 'timeout'): boolean {
154
+ return status === 'ok';
155
+ },
156
+ };
157
+
158
+ // ─────────────────────────────────────────────────────────────────────────────
159
+ // Stub Fallback Runtime Adapter (NOC-15)
160
+ // ─────────────────────────────────────────────────────────────────────────────
161
+
162
+ /**
163
+ * Stub fallback runtime adapter for Trinity.
164
+ * Wraps a real adapter and provides stub implementations for fallback when stages fail.
165
+ * Per NOC-15: Fallback degrades to stub, NOT to EmpathyObserver/DeepReflect.
166
+ */
167
+ class StubFallbackRuntimeAdapter implements TrinityRuntimeAdapter {
168
+ constructor(
169
+ private snapshot: NocturnalSessionSnapshot,
170
+ private principleId: string,
171
+ private maxCandidates: number
172
+ ) {}
173
+
174
+ async invokeDreamer(
175
+ snapshot: NocturnalSessionSnapshot,
176
+ principleId: string,
177
+ maxCandidates: number
178
+ ): Promise<DreamerOutput> {
179
+ const { invokeStubDreamer } = await import('../../core/nocturnal-trinity.js');
180
+ return invokeStubDreamer(snapshot, principleId, maxCandidates);
181
+ }
182
+
183
+ async invokePhilosopher(
184
+ dreamerOutput: DreamerOutput,
185
+ principleId: string
186
+ ): Promise<PhilosopherOutput> {
187
+ const { invokeStubPhilosopher } = await import('../../core/nocturnal-trinity.js');
188
+ return invokeStubPhilosopher(dreamerOutput, principleId);
189
+ }
190
+
191
+ async invokeScribe(
192
+ dreamerOutput: DreamerOutput,
193
+ philosopherOutput: PhilosopherOutput,
194
+ snapshot: NocturnalSessionSnapshot,
195
+ principleId: string,
196
+ telemetry: TrinityTelemetry,
197
+ config: TrinityConfig
198
+ ): Promise<import('../../core/nocturnal-trinity.js').TrinityDraftArtifact | null> {
199
+ // Use stub Scribe
200
+ const { invokeStubScribe } = await import('../../core/nocturnal-trinity.js');
201
+ return invokeStubScribe(dreamerOutput, philosopherOutput, snapshot, principleId, telemetry, config);
202
+ }
203
+
204
+ async close(): Promise<void> {
205
+ // No-op for stubs
206
+ }
207
+ }
208
+
209
+ // ─────────────────────────────────────────────────────────────────────────────
210
+ // NocturnalWorkflowManager
211
+ // ─────────────────────────────────────────────────────────────────────────────
212
+
213
+ /**
214
+ * NocturnalWorkflowManager — implements WorkflowManager for nocturnal reflection.
215
+ *
216
+ * Single-reflector path (useTrinity=false) only in Phase 6.
217
+ * Trinity multi-stage chain (Dreamer→Philosopher→Scribe) comes in Phase 7.
218
+ *
219
+ * Key behaviors:
220
+ * - startWorkflow calls executeNocturnalReflectionAsync with useTrinity=false
221
+ * - Records all 5 nocturnal event types to WorkflowStore
222
+ * - notifyWaitResult and notifyLifecycleEvent are no-ops
223
+ * - sweepExpiredWorkflows marks expired workflows and cleans partial artifacts
224
+ */
225
+ export class NocturnalWorkflowManager implements WorkflowManager {
226
+ private readonly workspaceDir: string;
227
+ private readonly stateDir: string;
228
+ private readonly logger: PluginLogger;
229
+ private readonly runtimeAdapter: TrinityRuntimeAdapter;
230
+ private readonly store: WorkflowStore;
231
+
232
+ /** Tracks completion timestamps for idempotency */
233
+ private completedWorkflows = new Map<string, number>();
234
+ /** Maps workflowId → spec (needed for finalizeOnce) */
235
+ private workflowSpecs = new Map<string, SubagentWorkflowSpec<unknown>>();
236
+ /** Maps workflowId → result (needed for finalizeOnce) */
237
+ private executionResults = new Map<string, NocturnalResult>();
238
+ /** Maps workflowId → TrinityStageFailure[] (stored before async launch, used in notifyWaitResult) */
239
+ private pendingTrinityFailures = new Map<string, TrinityStageFailure[]>();
240
+ /** Maps workflowId → TrinityResult (needed by notifyWaitResult for artifact persistence) */
241
+ private pendingTrinityResults = new Map<string, TrinityResult>();
242
+
243
+ constructor(opts: NocturnalWorkflowOptions) {
244
+ this.workspaceDir = opts.workspaceDir;
245
+ this.stateDir = opts.stateDir;
246
+ this.logger = opts.logger;
247
+ this.runtimeAdapter = opts.runtimeAdapter;
248
+ this.store = new WorkflowStore({ workspaceDir: opts.workspaceDir });
249
+ }
250
+
251
+ // ─────────────────────────────────────────────────────────────────────────
252
+ // WorkflowManager Interface: startWorkflow (NOC-01, NOC-02, NOC-03)
253
+ // ─────────────────────────────────────────────────────────────────────────
254
+
255
+ async startWorkflow<TResult>(
256
+ spec: SubagentWorkflowSpec<TResult>,
257
+ options: {
258
+ parentSessionId: string;
259
+ workspaceDir?: string;
260
+ taskInput: unknown;
261
+ metadata?: Record<string, unknown>;
262
+ }
263
+ ): Promise<WorkflowHandle> {
264
+ const workflowId = this.generateWorkflowId();
265
+ const now = Date.now();
266
+
267
+ const metadata: WorkflowMetadata = {
268
+ parentSessionId: options.parentSessionId,
269
+ workspaceDir: options.workspaceDir,
270
+ taskInput: options.taskInput,
271
+ startedAt: now,
272
+ workflowType: spec.workflowType,
273
+ ...options.metadata,
274
+ };
275
+
276
+ this.logger.info(`[PD:NocturnalWorkflow] Starting workflow: workflowId=${workflowId}, type=${spec.workflowType}`);
277
+
278
+ // Record nocturnal_started event (NOC-03)
279
+ this.store.createWorkflow({
280
+ workflow_id: workflowId,
281
+ workflow_type: spec.workflowType,
282
+ transport: spec.transport,
283
+ parent_session_id: options.parentSessionId,
284
+ child_session_key: `nocturnal:internal:${workflowId}`, // D-10: placeholder since adapter manages sessions internally
285
+ run_id: null,
286
+ state: 'active',
287
+ created_at: now,
288
+ updated_at: now,
289
+ metadata_json: JSON.stringify(metadata),
290
+ });
291
+ this.store.recordEvent(workflowId, 'nocturnal_started', null, 'active', 'TrinityRuntimeAdapter invoked', { workflowType: 'nocturnal' });
292
+
293
+ // Extract snapshot and principleId from taskInput.metadata (NOC-07: Trinity async path)
294
+ const snapshot = options.metadata?.snapshot as import('../../core/nocturnal-trajectory-extractor.js').NocturnalSessionSnapshot | undefined;
295
+ const principleId = options.metadata?.principleId as string | undefined;
296
+
297
+ // Validate required metadata (prevent runtime crashes from undefined snapshot)
298
+ if (!snapshot?.sessionId) {
299
+ this.logger.warn(`[PD:NocturnalWorkflow] Missing snapshot.sessionId in metadata for workflow=${workflowId}, terminating`);
300
+ this.store.recordEvent(workflowId, 'nocturnal_failed', null, 'terminal_error', 'Missing required metadata: snapshot.sessionId', { workflowId });
301
+ return {
302
+ workflowId,
303
+ childSessionKey: `nocturnal:internal:${workflowId}`,
304
+ state: 'terminal_error' as const,
305
+ };
306
+ }
307
+ if (!principleId) {
308
+ this.logger.warn(`[PD:NocturnalWorkflow] Missing principleId in metadata for workflow=${workflowId}, terminating`);
309
+ this.store.recordEvent(workflowId, 'nocturnal_failed', null, 'terminal_error', 'Missing required metadata: principleId', { workflowId });
310
+ return {
311
+ workflowId,
312
+ childSessionKey: `nocturnal:internal:${workflowId}`,
313
+ state: 'terminal_error' as const,
314
+ };
315
+ }
316
+
317
+ // Configure Trinity for async execution (NOC-06, NOC-07)
318
+ const trinityConfig: TrinityConfig = {
319
+ useTrinity: true, // NOC-07: Trinity chain, not single-reflector
320
+ maxCandidates: 3,
321
+ useStubs: false,
322
+ runtimeAdapter: this.runtimeAdapter,
323
+ stateDir: this.stateDir,
324
+ };
325
+
326
+ // Create mutable telemetry object (passed to invokeScribe and mutated)
327
+ const telemetry: TrinityTelemetry = {
328
+ chainMode: 'trinity',
329
+ usedStubs: false,
330
+ dreamerPassed: false,
331
+ philosopherPassed: false,
332
+ scribePassed: false,
333
+ candidateCount: 0,
334
+ selectedCandidateIndex: -1,
335
+ stageFailures: [],
336
+ };
337
+
338
+ // NOC-07: Launch Trinity async via Promise.resolve().then() WITHOUT awaiting
339
+ // This offloads the async chain so startWorkflow returns immediately with state='active'
340
+ Promise.resolve().then(async () => {
341
+ try {
342
+ // NOC-15: Track if stub fallback was used
343
+ let fallbackUsed = false;
344
+
345
+ // Step 1: Crash recovery — check for existing stage outputs (NOC-13)
346
+ // Query WorkflowStore for any existing outputs for this workflowId
347
+ const existingOutputs = this.store.getStageOutputs(workflowId);
348
+ const recoveredDreamerOutput = existingOutputs.find(o => o.stage === 'dreamer')?.output as DreamerOutput | undefined;
349
+ const recoveredPhilosopherOutput = existingOutputs.find(o => o.stage === 'philosopher')?.output as PhilosopherOutput | undefined;
350
+
351
+ let dreamerOutput: DreamerOutput;
352
+ let philosopherOutput: PhilosopherOutput;
353
+
354
+ // Step 2: Dreamer — skip if recovered (NOC-12 idempotency)
355
+ if (recoveredDreamerOutput) {
356
+ this.logger.info(`[PD:NocturnalWorkflow] Recovered Dreamer output for workflow=${workflowId}, skipping Dreamer stage`);
357
+ dreamerOutput = recoveredDreamerOutput;
358
+ } else {
359
+ // Compute idempotency key BEFORE calling invokeDreamer
360
+ const dreamerIdemKey = computeDreamerIdempotencyKey(workflowId, snapshot, principleId, trinityConfig.maxCandidates);
361
+
362
+ // Check idempotency — another concurrent run may have completed this stage
363
+ const existingDreamerByKey = this.store.getStageOutputByKey(dreamerIdemKey);
364
+ if (existingDreamerByKey) {
365
+ this.logger.info(`[PD:NocturnalWorkflow] Found existing Dreamer output by idempotency key for workflow=${workflowId}`);
366
+ dreamerOutput = existingDreamerByKey.output as DreamerOutput;
367
+ } else {
368
+ dreamerOutput = await this.runtimeAdapter.invokeDreamer(snapshot, principleId, trinityConfig.maxCandidates);
369
+ // NOC-15: Fallback to stub Dreamer if real Dreamer failed
370
+ if (!dreamerOutput.valid || dreamerOutput.candidates.length === 0) {
371
+ this.logger.info(`[PD:NocturnalWorkflow] Dreamer failed (${dreamerOutput.reason}), falling back to stub`);
372
+ fallbackUsed = true;
373
+ const stubAdapter = new StubFallbackRuntimeAdapter(
374
+ snapshot,
375
+ principleId,
376
+ trinityConfig.maxCandidates
377
+ );
378
+ dreamerOutput = await stubAdapter.invokeDreamer(snapshot, principleId, trinityConfig.maxCandidates);
379
+ }
380
+ // Persist Dreamer output (NOC-11)
381
+ if (dreamerOutput.valid) {
382
+ this.store.recordStageOutput(workflowId, 'dreamer', dreamerOutput, dreamerIdemKey);
383
+ }
384
+ }
385
+ }
386
+
387
+ // Step 3: Philosopher — skip if recovered (NOC-12 idempotency)
388
+ if (recoveredPhilosopherOutput) {
389
+ this.logger.info(`[PD:NocturnalWorkflow] Recovered Philosopher output for workflow=${workflowId}, skipping Philosopher stage`);
390
+ philosopherOutput = recoveredPhilosopherOutput;
391
+ } else {
392
+ // Compute idempotency key BEFORE calling invokePhilosopher
393
+ const philosopherIdemKey = computePhilosopherIdempotencyKey(workflowId, dreamerOutput);
394
+
395
+ // Check idempotency
396
+ const existingPhilosopherByKey = this.store.getStageOutputByKey(philosopherIdemKey);
397
+ if (existingPhilosopherByKey) {
398
+ this.logger.info(`[PD:NocturnalWorkflow] Found existing Philosopher output by idempotency key for workflow=${workflowId}`);
399
+ philosopherOutput = existingPhilosopherByKey.output as PhilosopherOutput;
400
+ } else {
401
+ philosopherOutput = await this.runtimeAdapter.invokePhilosopher(dreamerOutput, principleId);
402
+ // NOC-15: Fallback to stub Philosopher if real Philosopher failed
403
+ if (!philosopherOutput.valid || philosopherOutput.judgments.length === 0) {
404
+ this.logger.info(`[PD:NocturnalWorkflow] Philosopher failed (${philosopherOutput.reason}), falling back to stub`);
405
+ fallbackUsed = true;
406
+ const stubAdapter = new StubFallbackRuntimeAdapter(
407
+ snapshot,
408
+ principleId,
409
+ trinityConfig.maxCandidates
410
+ );
411
+ philosopherOutput = await stubAdapter.invokePhilosopher(dreamerOutput, principleId);
412
+ }
413
+ // Persist Philosopher output (NOC-11)
414
+ if (philosopherOutput.valid) {
415
+ this.store.recordStageOutput(workflowId, 'philosopher', philosopherOutput, philosopherIdemKey);
416
+ }
417
+ }
418
+ }
419
+
420
+ // Step 4: Scribe — always runs (no intermediate Scribe output to persist)
421
+ const draftArtifact = await this.runtimeAdapter.invokeScribe(
422
+ dreamerOutput,
423
+ philosopherOutput,
424
+ snapshot,
425
+ principleId,
426
+ telemetry,
427
+ trinityConfig
428
+ );
429
+
430
+ // Step 5: Build TrinityResult from stage outcomes
431
+ const failures: TrinityStageFailure[] = [];
432
+ if (!dreamerOutput.valid || dreamerOutput.candidates.length === 0) {
433
+ failures.push({ stage: 'dreamer', reason: dreamerOutput.reason ?? 'no valid candidates' });
434
+ }
435
+ if (!philosopherOutput.valid || philosopherOutput.judgments.length === 0) {
436
+ failures.push({ stage: 'philosopher', reason: philosopherOutput.reason ?? 'no judgments produced' });
437
+ }
438
+ if (!draftArtifact) {
439
+ failures.push({ stage: 'scribe', reason: 'Failed to synthesize artifact' });
440
+ }
441
+
442
+ const trinityResult: TrinityResult = {
443
+ success: failures.length === 0 && !!draftArtifact,
444
+ artifact: draftArtifact ?? undefined,
445
+ telemetry: {
446
+ chainMode: 'trinity',
447
+ usedStubs: fallbackUsed, // NOC-15: reflect actual stub usage
448
+ dreamerPassed: dreamerOutput.valid && dreamerOutput.candidates.length > 0,
449
+ philosopherPassed: philosopherOutput.valid && philosopherOutput.judgments.length > 0,
450
+ scribePassed: !!draftArtifact,
451
+ candidateCount: dreamerOutput.candidates.length,
452
+ selectedCandidateIndex: draftArtifact?.selectedCandidateIndex ?? -1,
453
+ stageFailures: failures.map(f => `${f.stage}: ${f.reason}`),
454
+ },
455
+ failures,
456
+ fallbackOccurred: fallbackUsed, // NOC-15: mark when fallback was triggered
457
+ };
458
+
459
+ // Store for notifyWaitResult and proceed with existing flow
460
+ this.pendingTrinityResults.set(workflowId, trinityResult);
461
+ this.pendingTrinityFailures.set(workflowId, failures);
462
+
463
+ // Record stage events (NOC-08, already implemented in Phase 07)
464
+ this.recordStageEvents(workflowId, trinityResult);
465
+
466
+ // Drive state transitions (NOC-10)
467
+ if (trinityResult.success) {
468
+ await this.notifyWaitResult(workflowId, 'ok');
469
+ } else {
470
+ const errorMsg = failures.map(f => `${f.stage}: ${f.reason}`).join('; ');
471
+ await this.notifyWaitResult(workflowId, 'error', errorMsg);
472
+ }
473
+ } catch (err) {
474
+ // Unexpected error - treat as Trinity failure
475
+ const errorMsg = err instanceof Error ? err.message : String(err);
476
+ this.pendingTrinityFailures.set(workflowId, [{ stage: 'dreamer' as const, reason: errorMsg }]);
477
+ await this.notifyWaitResult(workflowId, 'error', errorMsg);
478
+ }
479
+ });
480
+
481
+ // Return immediately with state='active' (NOC-07)
482
+ return {
483
+ workflowId,
484
+ childSessionKey: `nocturnal:internal:${workflowId}`,
485
+ runId: undefined,
486
+ state: 'active',
487
+ };
488
+ }
489
+
490
+ // ─────────────────────────────────────────────────────────────────────────
491
+ // WorkflowManager Interface: notifyWaitResult (NOC-01, D-10: no-op)
492
+ // ─────────────────────────────────────────────────────────────────────────
493
+
494
+ async notifyWaitResult(
495
+ workflowId: string,
496
+ status: 'ok' | 'error' | 'timeout',
497
+ error?: string
498
+ ): Promise<void> {
499
+ const workflow = this.store.getWorkflow(workflowId);
500
+ if (!workflow) {
501
+ this.logger.warn(`[PD:NocturnalWorkflow] notifyWaitResult: workflow not found: ${workflowId}`);
502
+ return;
503
+ }
504
+
505
+ // Only handle workflows in 'active' state (Trinity async path)
506
+ if (workflow.state !== 'active') {
507
+ this.logger.info(`[PD:NocturnalWorkflow] notifyWaitResult: workflow ${workflowId} not in active state: ${workflow.state}`);
508
+ return;
509
+ }
510
+
511
+ const trinityFailures = this.pendingTrinityFailures.get(workflowId) ?? [];
512
+ const trinityResult = this.pendingTrinityResults.get(workflowId);
513
+
514
+ if (status === 'ok') {
515
+ // Trinity succeeded: active -> finalizing -> completed (NOC-10)
516
+ this.store.updateWorkflowState(workflowId, 'finalizing');
517
+ this.store.recordEvent(workflowId, 'trinity_completed', 'active', 'finalizing', 'Trinity chain completed successfully', {
518
+ trinityTelemetry: trinityResult?.telemetry,
519
+ });
520
+
521
+ this.store.updateWorkflowState(workflowId, 'completed');
522
+ this.store.recordEvent(workflowId, 'nocturnal_completed', 'finalizing', 'completed', 'artifact persisted', {
523
+ persistedPath: trinityResult?.artifact ? 'trinity-draft' : undefined,
524
+ });
525
+ } else {
526
+ // Any stage failure: -> terminal_error immediately (NOC-09, NOC-10)
527
+ this.store.updateWorkflowState(workflowId, 'terminal_error');
528
+ this.store.recordEvent(workflowId, 'nocturnal_failed', 'active', 'terminal_error', error ?? 'Trinity stage failed', {
529
+ failures: trinityFailures, // NOC-09: TrinityStageFailure[] in payload
530
+ trinityTelemetry: trinityResult?.telemetry,
531
+ });
532
+ }
533
+
534
+ // Clean up pending state (idempotent - also cleaned in markCompleted)
535
+ this.pendingTrinityFailures.delete(workflowId);
536
+ this.pendingTrinityResults.delete(workflowId);
537
+ this.markCompleted(workflowId);
538
+ }
539
+
540
+ // ─────────────────────────────────────────────────────────────────────────
541
+ // WorkflowManager Interface: notifyLifecycleEvent (NOC-01, D-10: no-op)
542
+ // ─────────────────────────────────────────────────────────────────────────
543
+
544
+ async notifyLifecycleEvent(
545
+ _workflowId: string,
546
+ _event: 'subagent_spawned' | 'subagent_ended',
547
+ _data?: Record<string, unknown>
548
+ ): Promise<void> {
549
+ // D-10: No-op. NocturnalWorkflowManager does not use the wait-on-run pattern.
550
+ // TrinityRuntimeAdapter manages its own internal subagent lifecycle.
551
+ // No external subagent_spawned/subagent_ended events need to be tracked.
552
+ }
553
+
554
+ // ─────────────────────────────────────────────────────────────────────────
555
+ // WorkflowManager Interface: finalizeOnce (NOC-01)
556
+ // ─────────────────────────────────────────────────────────────────────────
557
+
558
+ async finalizeOnce(workflowId: string): Promise<void> {
559
+ const workflow = this.store.getWorkflow(workflowId);
560
+ if (!workflow) {
561
+ this.logger.warn(`[PD:NocturnalWorkflow] finalizeOnce: workflow not found: ${workflowId}`);
562
+ return;
563
+ }
564
+
565
+ if (this.isCompleted(workflowId)) {
566
+ this.logger.info(`[PD:NocturnalWorkflow] finalizeOnce: already completed: ${workflowId}`);
567
+ return;
568
+ }
569
+
570
+ // NocturnalWorkflowManager completes execution synchronously in startWorkflow.
571
+ // If we reach here, the workflow was already marked as completed/failed.
572
+ // Nothing more to do - result already persisted by executeNocturnalReflectionAsync.
573
+ this.logger.info(`[PD:NocturnalWorkflow] finalizeOnce: workflow already in terminal state: ${workflowId}, state=${workflow.state}`);
574
+ this.markCompleted(workflowId);
575
+ }
576
+
577
+ // ─────────────────────────────────────────────────────────────────────────
578
+ // WorkflowManager Interface: sweepExpiredWorkflows (NOC-05)
579
+ // ─────────────────────────────────────────────────────────────────────────
580
+
581
+ async sweepExpiredWorkflows(maxAgeMs = 30 * 60 * 1000): Promise<number> {
582
+ const expired = this.store.getExpiredWorkflows(maxAgeMs);
583
+
584
+ this.logger.info(`[PD:NocturnalWorkflow] sweepExpiredWorkflows: found ${expired.length} expired`);
585
+
586
+ for (const workflow of expired) {
587
+ try {
588
+ this.logger.info(`[PD:NocturnalWorkflow] Sweeping expired workflow: ${workflow.workflow_id}`);
589
+
590
+ // D-06: Mark as expired in WorkflowStore
591
+ this.store.updateWorkflowState(workflow.workflow_id, 'expired');
592
+ this.store.recordEvent(workflow.workflow_id, 'nocturnal_expired', workflow.state, 'expired', 'TTL expired', { workflowId: workflow.workflow_id });
593
+
594
+ // D-06: Clean partial artifact files by workflowId prefix
595
+ const samplesDir = resolveNocturnalDir(this.workspaceDir, 'SAMPLES');
596
+ if (fs.existsSync(samplesDir)) {
597
+ const files = fs.readdirSync(samplesDir).filter(f => f.includes(workflow.workflow_id));
598
+ for (const file of files) {
599
+ const filePath = path.join(samplesDir, file);
600
+ try {
601
+ fs.unlinkSync(filePath);
602
+ this.logger.info(`[PD:NocturnalWorkflow] Removed partial artifact: ${filePath}`);
603
+ } catch (unlinkErr) {
604
+ this.logger.warn(`[PD:NocturnalWorkflow] Failed to remove partial artifact ${filePath}: ${String(unlinkErr)}`);
605
+ }
606
+ }
607
+ }
608
+
609
+ } catch (error) {
610
+ this.logger.error(`[PD:NocturnalWorkflow] Sweep failed for ${workflow.workflow_id}: ${String(error)}`);
611
+ }
612
+ }
613
+
614
+ // Clean up memory Maps to prevent leaks
615
+ const cutoff = Date.now() - 60_000; // 1 minute dedup window
616
+ for (const [id, timestamp] of this.completedWorkflows) {
617
+ if (timestamp < cutoff) {
618
+ this.completedWorkflows.delete(id);
619
+ }
620
+ }
621
+
622
+ return expired.length;
623
+ }
624
+
625
+ // ─────────────────────────────────────────────────────────────────────────
626
+ // WorkflowManager Interface: getWorkflowDebugSummary (NOC-01)
627
+ // ─────────────────────────────────────────────────────────────────────────
628
+
629
+ async getWorkflowDebugSummary(workflowId: string, eventLimit = 10): Promise<WorkflowDebugSummary | null> {
630
+ const workflow = this.store.getWorkflow(workflowId);
631
+ if (!workflow) return null;
632
+
633
+ const metadata = JSON.parse(workflow.metadata_json) as WorkflowMetadata;
634
+ const allEvents = this.store.getEvents(workflowId);
635
+ const recentEvents = allEvents
636
+ .slice(-eventLimit)
637
+ .map((event) => ({
638
+ eventType: event.event_type,
639
+ fromState: event.from_state,
640
+ toState: event.to_state,
641
+ reason: event.reason,
642
+ createdAt: event.created_at,
643
+ payload: JSON.parse(event.payload_json || '{}') as Record<string, unknown>,
644
+ }));
645
+
646
+ // NOC-16: Compute Trinity stage states from events
647
+ const trinityStageStates = this.computeTrinityStageStates(allEvents);
648
+
649
+ return {
650
+ workflowId: workflow.workflow_id,
651
+ workflowType: workflow.workflow_type,
652
+ transport: workflow.transport,
653
+ parentSessionId: workflow.parent_session_id,
654
+ childSessionKey: workflow.child_session_key,
655
+ runId: workflow.run_id,
656
+ state: workflow.state,
657
+ cleanupState: workflow.cleanup_state,
658
+ lastObservedAt: workflow.last_observed_at ?? null,
659
+ metadata,
660
+ recentEvents,
661
+ trinityStageStates, // NOC-16
662
+ };
663
+ }
664
+
665
+ // ─────────────────────────────────────────────────────────────────────────
666
+ // WorkflowManager Interface: dispose (NOC-01)
667
+ // ─────────────────────────────────────────────────────────────────────────
668
+
669
+ dispose(): void {
670
+ this.store.dispose();
671
+ }
672
+
673
+ // ─────────────────────────────────────────────────────────────────────────
674
+ // Helper Methods
675
+ // ─────────────────────────────────────────────────────────────────────────
676
+
677
+ private generateWorkflowId(): string {
678
+ return `wf_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
679
+ }
680
+
681
+ private isCompleted(workflowId: string): boolean {
682
+ const timestamp = this.completedWorkflows.get(workflowId);
683
+ if (!timestamp) return false;
684
+ if (Date.now() - timestamp > 5 * 60 * 1000) {
685
+ this.completedWorkflows.delete(workflowId);
686
+ return false;
687
+ }
688
+ return true;
689
+ }
690
+
691
+ private markCompleted(workflowId: string): void {
692
+ this.completedWorkflows.set(workflowId, Date.now());
693
+ this.workflowSpecs.delete(workflowId);
694
+ this.executionResults.delete(workflowId);
695
+ this.pendingTrinityFailures.delete(workflowId);
696
+ this.pendingTrinityResults.delete(workflowId);
697
+ }
698
+
699
+ /**
700
+ * Compute Trinity stage states from workflow events (NOC-16).
701
+ * Derives current/completed/failed state for each Trinity stage.
702
+ */
703
+ private computeTrinityStageStates(events: WorkflowEventRow[]): Array<{
704
+ stage: 'dreamer' | 'philosopher' | 'scribe';
705
+ status: 'pending' | 'running' | 'completed' | 'failed';
706
+ reason?: string;
707
+ completedAt?: number;
708
+ }> {
709
+ const stages: Array<'dreamer' | 'philosopher' | 'scribe'> = ['dreamer', 'philosopher', 'scribe'];
710
+ const result: Array<{
711
+ stage: 'dreamer' | 'philosopher' | 'scribe';
712
+ status: 'pending' | 'running' | 'completed' | 'failed';
713
+ reason?: string;
714
+ completedAt?: number;
715
+ }> = [];
716
+
717
+ for (const stage of stages) {
718
+ const startEvent = events.find(e => e.event_type === `trinity_${stage}_start`);
719
+ const completeEvent = events.find(e => e.event_type === `trinity_${stage}_complete`);
720
+ const failedEvent = events.find(e => e.event_type === `trinity_${stage}_failed`);
721
+
722
+ if (!startEvent) {
723
+ // Stage never ran
724
+ result.push({ stage, status: 'pending' });
725
+ } else if (failedEvent) {
726
+ // Stage ran and failed
727
+ const payload = JSON.parse(failedEvent.payload_json || '{}') as Record<string, unknown>;
728
+ const failures = payload.failures as Array<{ reason?: string }> | undefined;
729
+ result.push({
730
+ stage,
731
+ status: 'failed',
732
+ reason: failures?.[0]?.reason ?? failedEvent.reason,
733
+ completedAt: failedEvent.created_at,
734
+ });
735
+ } else if (completeEvent) {
736
+ // Stage ran and completed
737
+ result.push({
738
+ stage,
739
+ status: 'completed',
740
+ completedAt: completeEvent.created_at,
741
+ });
742
+ } else {
743
+ // Stage started but not completed or failed — currently running
744
+ result.push({ stage, status: 'running' });
745
+ }
746
+ }
747
+
748
+ return result;
749
+ }
750
+
751
+ /**
752
+ * Record Trinity stage events in batch after the chain completes (per NOC-08).
753
+ * Derives stage events from TrinityResult.telemetry and TrinityResult.failures.
754
+ * Always records _start event for each stage that ran, plus _complete or _failed based on outcome.
755
+ */
756
+ private recordStageEvents(workflowId: string, result: TrinityResult): void {
757
+ const { telemetry, failures } = result;
758
+
759
+ // Dreamer events (always runs if we reach here)
760
+ this.store.recordEvent(
761
+ workflowId,
762
+ 'trinity_dreamer_start',
763
+ null, // fromState: null for first event
764
+ 'active',
765
+ 'Trinity Dreamer stage began',
766
+ {}
767
+ );
768
+
769
+ if (telemetry.dreamerPassed) {
770
+ this.store.recordEvent(
771
+ workflowId,
772
+ 'trinity_dreamer_complete',
773
+ 'active',
774
+ 'active',
775
+ 'Dreamer completed successfully',
776
+ { candidateCount: telemetry.candidateCount }
777
+ );
778
+ } else {
779
+ const dreamerFailure = failures.find(f => f.stage === 'dreamer');
780
+ this.store.recordEvent(
781
+ workflowId,
782
+ 'trinity_dreamer_failed',
783
+ 'active',
784
+ 'active',
785
+ dreamerFailure?.reason ?? 'Dreamer stage failed',
786
+ { failures: failures.filter(f => f.stage === 'dreamer') }
787
+ );
788
+ }
789
+
790
+ // Philosopher events (only if Dreamer passed)
791
+ if (telemetry.dreamerPassed) {
792
+ this.store.recordEvent(
793
+ workflowId,
794
+ 'trinity_philosopher_start',
795
+ 'active',
796
+ 'active',
797
+ 'Trinity Philosopher stage began',
798
+ {}
799
+ );
800
+
801
+ if (telemetry.philosopherPassed) {
802
+ this.store.recordEvent(
803
+ workflowId,
804
+ 'trinity_philosopher_complete',
805
+ 'active',
806
+ 'active',
807
+ 'Philosopher completed successfully',
808
+ {}
809
+ );
810
+ } else {
811
+ const philosopherFailure = failures.find(f => f.stage === 'philosopher');
812
+ this.store.recordEvent(
813
+ workflowId,
814
+ 'trinity_philosopher_failed',
815
+ 'active',
816
+ 'active',
817
+ philosopherFailure?.reason ?? 'Philosopher stage failed',
818
+ { failures: failures.filter(f => f.stage === 'philosopher') }
819
+ );
820
+ }
821
+ }
822
+
823
+ // Scribe events (only if Philosopher passed)
824
+ if (telemetry.philosopherPassed) {
825
+ this.store.recordEvent(
826
+ workflowId,
827
+ 'trinity_scribe_start',
828
+ 'active',
829
+ 'active',
830
+ 'Trinity Scribe stage began',
831
+ {}
832
+ );
833
+
834
+ if (telemetry.scribePassed) {
835
+ this.store.recordEvent(
836
+ workflowId,
837
+ 'trinity_scribe_complete',
838
+ 'active',
839
+ 'finalizing', // NOC-10: scribe complete -> finalizing state
840
+ 'Scribe completed successfully',
841
+ { selectedCandidateIndex: telemetry.selectedCandidateIndex }
842
+ );
843
+ } else {
844
+ const scribeFailure = failures.find(f => f.stage === 'scribe');
845
+ this.store.recordEvent(
846
+ workflowId,
847
+ 'trinity_scribe_failed',
848
+ 'active',
849
+ 'terminal_error', // NOC-10: scribe failure -> terminal_error immediately
850
+ scribeFailure?.reason ?? 'Scribe stage failed',
851
+ { failures: failures.filter(f => f.stage === 'scribe') }
852
+ );
853
+ }
854
+ }
855
+ }
856
+ }