principles-disciple 1.72.0 → 1.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/INSTALL.md +1 -3
  2. package/openclaw.plugin.json +10 -5
  3. package/package.json +17 -19
  4. package/scripts/acceptance-test.mjs +16 -73
  5. package/scripts/sync-plugin.mjs +382 -77
  6. package/src/commands/archive-impl.ts +2 -1
  7. package/src/commands/capabilities.ts +2 -2
  8. package/src/commands/context.ts +2 -2
  9. package/src/commands/disable-impl.ts +2 -1
  10. package/src/commands/evolution-status.ts +16 -16
  11. package/src/commands/export.ts +12 -67
  12. package/src/commands/pain.ts +91 -1
  13. package/src/commands/principle-rollback.ts +2 -1
  14. package/src/commands/promote-impl.ts +7 -43
  15. package/src/commands/rollback-impl.ts +2 -1
  16. package/src/commands/rollback.ts +2 -1
  17. package/src/commands/samples.ts +2 -1
  18. package/src/commands/thinking-os.ts +2 -1
  19. package/src/config/errors.ts +18 -2
  20. package/src/constants/diagnostician.ts +2 -2
  21. package/src/constants/tools.ts +2 -1
  22. package/src/core/__tests__/focus-history.test.ts +210 -0
  23. package/src/core/config.ts +1 -1
  24. package/src/core/correction-cue-learner.ts +2 -136
  25. package/src/core/correction-types.ts +16 -88
  26. package/src/core/dictionary.ts +19 -20
  27. package/src/core/empathy-keyword-matcher.ts +17 -289
  28. package/src/core/empathy-types.ts +18 -229
  29. package/src/core/event-log.ts +29 -132
  30. package/src/core/evolution-reducer.ts +21 -2
  31. package/src/core/evolution-types.ts +76 -464
  32. package/src/core/file-store.ts +80 -0
  33. package/src/core/focus-history.ts +228 -955
  34. package/src/core/local-worker-routing.ts +34 -314
  35. package/src/core/merge-gate-audit.ts +0 -195
  36. package/src/core/migration.ts +0 -1
  37. package/src/core/pain-diagnostic-gate.ts +154 -0
  38. package/src/core/pain-signal.ts +21 -138
  39. package/src/core/pain.ts +15 -88
  40. package/src/core/path-resolver.ts +0 -1
  41. package/src/core/paths.ts +0 -1
  42. package/src/core/pd-task-reconciler.ts +26 -115
  43. package/src/core/pd-task-service.ts +9 -9
  44. package/src/core/pd-task-types.ts +23 -127
  45. package/src/core/principle-compiler/__tests__/compiler-replay-gate.test.ts +174 -0
  46. package/src/core/principle-compiler/code-validator.ts +15 -42
  47. package/src/core/principle-compiler/compiler.ts +100 -15
  48. package/src/core/principle-compiler/index.ts +5 -2
  49. package/src/core/principle-compiler/template-generator.ts +4 -104
  50. package/src/core/principle-injection.ts +10 -202
  51. package/src/core/principle-internalization/filesystem-lifecycle-datasource.ts +42 -0
  52. package/src/core/principle-internalization/lifecycle-read-model.ts +39 -242
  53. package/src/core/principle-internalization/principle-lifecycle-service.ts +12 -10
  54. package/src/core/principle-tree-ledger-adapter.ts +145 -0
  55. package/src/core/principle-tree-ledger.ts +8 -6
  56. package/src/core/reflection/reflection-context.ts +14 -109
  57. package/src/core/replay-engine.ts +8 -500
  58. package/src/core/rule-host-helpers.ts +5 -35
  59. package/src/core/rule-host-types.ts +10 -82
  60. package/src/core/rule-host.ts +6 -63
  61. package/src/core/runtime-v2-prompt-activation-reader.ts +231 -0
  62. package/src/core/session-tracker.ts +87 -101
  63. package/src/core/shadow-observation-registry.ts +19 -48
  64. package/src/core/trajectory.ts +3 -1
  65. package/src/core/workflow-funnel-loader.ts +62 -68
  66. package/src/core/workspace-context.ts +46 -0
  67. package/src/core/workspace-dir-service.ts +1 -1
  68. package/src/core/workspace-dir-validation.ts +18 -9
  69. package/src/hooks/AGENTS.md +1 -1
  70. package/src/hooks/gate-block-helper.ts +71 -64
  71. package/src/hooks/gate.ts +183 -31
  72. package/src/hooks/lifecycle.ts +30 -32
  73. package/src/hooks/llm.ts +60 -32
  74. package/src/hooks/pain.ts +297 -103
  75. package/src/hooks/prompt.ts +400 -440
  76. package/src/hooks/subagent.ts +2 -29
  77. package/src/i18n/commands.ts +2 -10
  78. package/src/index.ts +95 -85
  79. package/src/openclaw-sdk.ts +311 -0
  80. package/src/service/central-database.ts +8 -4
  81. package/src/service/evolution-queue-migration.ts +2 -1
  82. package/src/service/evolution-worker.ts +163 -1786
  83. package/src/service/internalization-trigger-adapter.ts +302 -0
  84. package/src/service/keyword-optimization-service.ts +4 -4
  85. package/src/service/monitoring-query-service.ts +1 -215
  86. package/src/service/queue-io.ts +60 -331
  87. package/src/service/runtime-summary-service.ts +59 -16
  88. package/src/service/subagent-workflow/index.ts +0 -41
  89. package/src/service/subagent-workflow/types.ts +9 -120
  90. package/src/service/subagent-workflow/workflow-store.ts +2 -119
  91. package/src/service/workflow-watchdog.ts +0 -43
  92. package/src/types/event-payload.ts +16 -74
  93. package/src/types/event-types.ts +38 -547
  94. package/src/types/hygiene-types.ts +7 -30
  95. package/src/types/principle-tree-schema.ts +20 -222
  96. package/src/types/queue.ts +15 -70
  97. package/src/types/runtime-summary.ts +5 -49
  98. package/src/utils/io.ts +8 -20
  99. package/src/utils/retry.ts +1 -1
  100. package/src/utils/shadow-fingerprint.ts +2 -2
  101. package/src/utils/workspace-resolver.ts +50 -0
  102. package/templates/langs/en/core/AGENTS.md +7 -7
  103. package/templates/langs/en/core/BOOT.md +1 -1
  104. package/templates/langs/en/core/HEARTBEAT.md +2 -2
  105. package/templates/langs/en/principles/THINKING_OS.md +3 -2
  106. package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  107. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  108. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  109. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  110. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  111. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  112. package/templates/langs/en/skills/evolve-task/SKILL.md +3 -3
  113. package/templates/langs/en/skills/pd-cli-operator/SKILL.md +67 -0
  114. package/templates/langs/en/skills/pd-diagnostician/SKILL.md +1 -1
  115. package/templates/langs/en/skills/pd-mentor/SKILL.md +2 -3
  116. package/templates/langs/en/skills/pd-pain-signal/SKILL.md +17 -39
  117. package/templates/langs/en/skills/pd-runtime-v2/SKILL.md +61 -0
  118. package/templates/langs/zh/core/AGENTS.md +7 -7
  119. package/templates/langs/zh/core/BOOT.md +1 -1
  120. package/templates/langs/zh/core/HEARTBEAT.md +2 -2
  121. package/templates/langs/zh/principles/THINKING_OS.md +3 -2
  122. package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  123. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  124. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  125. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +8 -8
  126. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  127. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  128. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  129. package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +21 -5
  130. package/templates/langs/zh/skills/evolve-task/SKILL.md +4 -4
  131. package/templates/langs/zh/skills/pd-cli-operator/SKILL.md +67 -0
  132. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +1 -1
  133. package/templates/langs/zh/skills/pd-mentor/SKILL.md +2 -3
  134. package/templates/langs/zh/skills/pd-pain-signal/SKILL.md +17 -38
  135. package/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +61 -0
  136. package/tests/build-artifacts.test.ts +1 -3
  137. package/tests/commands/evolution-status.test.ts +0 -118
  138. package/tests/core/bootstrap-rules.test.ts +1 -1
  139. package/tests/core/config.test.ts +1 -1
  140. package/tests/core/event-log.test.ts +35 -0
  141. package/tests/core/evolution-engine.test.ts +610 -0
  142. package/tests/core/file-store.test.ts +102 -0
  143. package/tests/core/focus-history.test.ts +203 -11
  144. package/tests/core/merge-gate-audit.test.ts +2 -169
  145. package/tests/core/migration.test.ts +7 -7
  146. package/tests/core/model-deployment-registry.test.ts +7 -1
  147. package/tests/core/model-training-registry.test.ts +19 -0
  148. package/tests/core/observability.test.ts +0 -1
  149. package/tests/core/pain-diagnostic-gate.test.ts +498 -0
  150. package/tests/core/pain.test.ts +0 -1
  151. package/tests/core/path-resolver.test.ts +1 -1
  152. package/tests/core/paths-refactor.test.ts +0 -22
  153. package/tests/core/principle-internalization/deprecated-readiness.test.ts +2 -2
  154. package/tests/core/principle-internalization/lifecycle-metrics.test.ts +2 -2
  155. package/tests/core/principle-internalization/{internalization-routing-policy.test.ts → lifecycle-routing-policy.test.ts} +6 -6
  156. package/tests/core/principle-internalization/lineage-source-retired.test.ts +56 -0
  157. package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +1 -23
  158. package/tests/core/principle-tree-ledger-adapter.test.ts +253 -0
  159. package/tests/core/reflection-context.test.ts +0 -14
  160. package/tests/core/replay-engine.test.ts +127 -215
  161. package/tests/core/rule-host-helpers.test.ts +2 -2
  162. package/tests/core/rule-implementation-runtime.test.ts +0 -27
  163. package/tests/core/workflow-funnel-loader.test.ts +162 -0
  164. package/tests/core/workspace-context.test.ts +2 -2
  165. package/tests/core/workspace-dir-validation.test.ts +8 -1
  166. package/tests/core-anti-growth.test.ts +191 -0
  167. package/tests/hook-workspace-nextaction-contract.test.ts +42 -0
  168. package/tests/hooks/confirm-first-removal.test.ts +188 -0
  169. package/tests/hooks/gate-auto-correct-shadow.test.ts +310 -0
  170. package/tests/hooks/gate-auto-correct.test.ts +665 -0
  171. package/tests/hooks/gate-no-path-write-tool.test.ts +172 -0
  172. package/tests/hooks/gate-rule-host-pipeline.test.ts +2 -1
  173. package/tests/hooks/pain.test.ts +269 -12
  174. package/tests/hooks/prompt-characterization.test.ts +500 -0
  175. package/tests/hooks/prompt-size-guard.test.ts +32 -17
  176. package/tests/hooks/runtime-v2-prompt-activation.test.ts +869 -0
  177. package/tests/index.test.ts +94 -1
  178. package/tests/integration/auto-entry-gate.test.ts +248 -0
  179. package/tests/integration/internalization-trigger-guard.test.ts +69 -0
  180. package/tests/integration/m8-legacy-paths.test.ts +63 -0
  181. package/tests/integration/runtime-v2-pain-guard.test.ts +125 -0
  182. package/tests/plugin-config-resolution-cutover.test.ts +359 -0
  183. package/tests/runtime-v2-discovery-guard.test.ts +154 -0
  184. package/tests/service/central-database.test.ts +457 -0
  185. package/tests/service/evolution-worker.correction-observer.test.ts +173 -0
  186. package/tests/service/evolution-worker.timeout.test.ts +11 -129
  187. package/tests/service/internalization-trigger-adapter.test.ts +251 -0
  188. package/tests/service/monitoring-query-service.test.ts +1 -47
  189. package/tests/service/queue-io.test.ts +1 -62
  190. package/tests/service/runtime-summary-service.test.ts +3 -1
  191. package/tests/service/workflow-watchdog.test.ts +0 -91
  192. package/tests/utils/file-lock.test.ts +5 -3
  193. package/tests/utils/session-key.test.ts +52 -0
  194. package/tests/utils/subagent-probe.test.ts +48 -1
  195. package/vitest.config.ts +4 -11
  196. package/.planning/codebase/ARCHITECTURE.md +0 -157
  197. package/.planning/codebase/CONCERNS.md +0 -145
  198. package/.planning/codebase/CONVENTIONS.md +0 -148
  199. package/.planning/codebase/INTEGRATIONS.md +0 -81
  200. package/.planning/codebase/STACK.md +0 -87
  201. package/.planning/codebase/STRUCTURE.md +0 -193
  202. package/.planning/codebase/TESTING.md +0 -243
  203. package/.planning/phases/01-basic-visualization/01-GAP-CLOSURE-VERIFICATION.md +0 -113
  204. package/docs/COMMAND_REFERENCE.md +0 -76
  205. package/docs/COMMAND_REFERENCE_EN.md +0 -79
  206. package/scripts/build-web.mjs +0 -46
  207. package/scripts/diagnose-nocturnal.mjs +0 -537
  208. package/scripts/seed-nocturnal-scenarios.mjs +0 -384
  209. package/src/commands/nocturnal-review.ts +0 -322
  210. package/src/commands/nocturnal-rollout.ts +0 -790
  211. package/src/commands/nocturnal-train.ts +0 -986
  212. package/src/commands/pd-reflect.ts +0 -88
  213. package/src/core/adaptive-thresholds.ts +0 -478
  214. package/src/core/diagnostician-task-store.ts +0 -192
  215. package/src/core/nocturnal-arbiter.ts +0 -715
  216. package/src/core/nocturnal-artifact-lineage.ts +0 -116
  217. package/src/core/nocturnal-artificer.ts +0 -257
  218. package/src/core/nocturnal-candidate-scoring.ts +0 -530
  219. package/src/core/nocturnal-compliance.ts +0 -1146
  220. package/src/core/nocturnal-dataset.ts +0 -763
  221. package/src/core/nocturnal-executability.ts +0 -428
  222. package/src/core/nocturnal-export.ts +0 -499
  223. package/src/core/nocturnal-paths.ts +0 -240
  224. package/src/core/nocturnal-reasoning-deriver.ts +0 -343
  225. package/src/core/nocturnal-rule-implementation-validator.ts +0 -246
  226. package/src/core/nocturnal-snapshot-contract.ts +0 -99
  227. package/src/core/nocturnal-trajectory-extractor.ts +0 -512
  228. package/src/core/nocturnal-trinity-types.ts +0 -218
  229. package/src/core/nocturnal-trinity.ts +0 -2680
  230. package/src/core/principle-internalization/deprecated-readiness.ts +0 -93
  231. package/src/core/principle-internalization/internalization-routing-policy.ts +0 -208
  232. package/src/core/principle-internalization/lifecycle-metrics.ts +0 -152
  233. package/src/http/principles-console-route.ts +0 -709
  234. package/src/service/central-health-service.ts +0 -49
  235. package/src/service/central-overview-service.ts +0 -138
  236. package/src/service/control-ui-query-service.ts +0 -900
  237. package/src/service/cooldown-strategy.ts +0 -97
  238. package/src/service/evolution-pain-context.ts +0 -79
  239. package/src/service/evolution-query-service.ts +0 -407
  240. package/src/service/health-query-service.ts +0 -1038
  241. package/src/service/nocturnal-config.ts +0 -214
  242. package/src/service/nocturnal-runtime.ts +0 -734
  243. package/src/service/nocturnal-service.ts +0 -1605
  244. package/src/service/nocturnal-target-selector.ts +0 -545
  245. package/src/service/sleep-cycle.ts +0 -157
  246. package/src/service/startup-reconciler.ts +0 -112
  247. package/src/service/subagent-workflow/correction-observer-types.ts +0 -82
  248. package/src/service/subagent-workflow/correction-observer-workflow-manager.ts +0 -250
  249. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +0 -1
  250. package/src/service/subagent-workflow/dynamic-timeout.ts +0 -30
  251. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +0 -268
  252. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +0 -795
  253. package/src/service/subagent-workflow/runtime-direct-driver.ts +0 -268
  254. package/src/service/subagent-workflow/workflow-manager-base.ts +0 -580
  255. package/src/tools/write-pain-flag.ts +0 -215
  256. package/templates/langs/en/skills/plan-script/SKILL.md +0 -32
  257. package/templates/langs/zh/skills/plan-script/SKILL.md +0 -32
  258. package/tests/commands/nocturnal-review.test.ts +0 -448
  259. package/tests/commands/nocturnal-train.test.ts +0 -97
  260. package/tests/commands/pd-reflect.test.ts +0 -49
  261. package/tests/core/adaptive-thresholds.test.ts +0 -261
  262. package/tests/core/nocturnal-arbiter.test.ts +0 -559
  263. package/tests/core/nocturnal-artifact-lineage.test.ts +0 -53
  264. package/tests/core/nocturnal-artificer.test.ts +0 -241
  265. package/tests/core/nocturnal-candidate-scoring.test.ts +0 -532
  266. package/tests/core/nocturnal-compliance-p-principles.test.ts +0 -133
  267. package/tests/core/nocturnal-compliance.test.ts +0 -646
  268. package/tests/core/nocturnal-dataset.test.ts +0 -892
  269. package/tests/core/nocturnal-e2e.test.ts +0 -234
  270. package/tests/core/nocturnal-executability.test.ts +0 -357
  271. package/tests/core/nocturnal-export.test.ts +0 -517
  272. package/tests/core/nocturnal-reasoning-deriver.test.ts +0 -372
  273. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +0 -428
  274. package/tests/core/nocturnal-rule-implementation-validator.test.ts +0 -127
  275. package/tests/core/nocturnal-snapshot-contract.test.ts +0 -121
  276. package/tests/core/nocturnal-trajectory-extractor.test.ts +0 -634
  277. package/tests/core/nocturnal-trinity.test.ts +0 -2053
  278. package/tests/core/pain-auto-repair.test.ts +0 -96
  279. package/tests/core/pain-integration.test.ts +0 -510
  280. package/tests/fixtures/nocturnal-reviewed-subset.json +0 -183
  281. package/tests/http/principles-console-route.test.ts +0 -162
  282. package/tests/integration/chaos-resilience.test.ts +0 -348
  283. package/tests/integration/empathy-workflow-integration.test.ts +0 -626
  284. package/tests/integration/pain-diagnostician-loop.e2e.test.ts +0 -380
  285. package/tests/service/control-ui-query-service.test.ts +0 -121
  286. package/tests/service/cooldown-strategy.test.ts +0 -164
  287. package/tests/service/data-endpoints-regression.test.ts +0 -834
  288. package/tests/service/empathy-observer-workflow-manager.test.ts +0 -175
  289. package/tests/service/evolution-worker.nocturnal.test.ts +0 -601
  290. package/tests/service/nocturnal-runtime-hardening.test.ts +0 -118
  291. package/tests/service/nocturnal-runtime.test.ts +0 -473
  292. package/tests/service/nocturnal-service-code-candidate.test.ts +0 -330
  293. package/tests/service/nocturnal-target-selector.test.ts +0 -615
  294. package/tests/service/startup-reconciler.test.ts +0 -148
  295. package/tests/tools/write-pain-flag.test.ts +0 -358
  296. package/ui/src/App.tsx +0 -45
  297. package/ui/src/api.ts +0 -220
  298. package/ui/src/charts.tsx +0 -955
  299. package/ui/src/components/ErrorState.tsx +0 -6
  300. package/ui/src/components/Loading.tsx +0 -13
  301. package/ui/src/components/ProtectedRoute.tsx +0 -12
  302. package/ui/src/components/Shell.tsx +0 -91
  303. package/ui/src/components/WorkspaceConfig.tsx +0 -178
  304. package/ui/src/components/index.ts +0 -5
  305. package/ui/src/context/auth.tsx +0 -80
  306. package/ui/src/context/theme.tsx +0 -66
  307. package/ui/src/hooks/useAutoRefresh.ts +0 -39
  308. package/ui/src/i18n/ui.ts +0 -473
  309. package/ui/src/main.tsx +0 -16
  310. package/ui/src/pages/EvolutionPage.tsx +0 -333
  311. package/ui/src/pages/FeedbackPage.tsx +0 -138
  312. package/ui/src/pages/GateMonitorPage.tsx +0 -136
  313. package/ui/src/pages/LoginPage.tsx +0 -89
  314. package/ui/src/pages/OverviewPage.tsx +0 -599
  315. package/ui/src/pages/SamplesPage.tsx +0 -174
  316. package/ui/src/pages/ThinkingModelsPage.tsx +0 -702
  317. package/ui/src/styles.css +0 -2020
  318. package/ui/src/types.ts +0 -384
  319. package/ui/src/utils/format.ts +0 -15
@@ -1,4 +1,4 @@
1
-
1
+
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
4
  import type {
@@ -17,36 +17,22 @@ import type {
17
17
  PlanApprovalEventData,
18
18
  EvolutionTaskEventData,
19
19
  EmpathyRollbackEventData,
20
- // C: New event data types
21
20
  DiagnosisTaskEventData,
22
21
  HeartbeatDiagnosisEventData,
23
22
  DiagnosticianReportEventData,
24
23
  PrincipleCandidateEventData,
25
24
  RuleEnforcedEventData,
26
- // C: Nocturnal funnel events (PD-FUNNEL-2.3)
27
- NocturnalDreamerCompletedEventData,
28
- NocturnalArtifactPersistedEventData,
29
- NocturnalCodeCandidateCreatedEventData,
30
- // C: RuleHost funnel events (PD-FUNNEL-2.4)
31
25
  RuleHostEvaluatedEventData,
32
26
  RuleHostBlockedEventData,
33
27
  RuleHostRequireApprovalEventData,
28
+ RuleHostAutoCorrectProposedEventData,
29
+ RuleHostAutoCorrectAppliedEventData,
30
+ RuntimeV2PromptActivationsInjectedEventData,
34
31
  } from '../types/event-types.js';
35
32
  import { createEmptyDailyStats } from '../types/event-types.js';
36
33
  import { atomicWriteFileSync } from '../utils/io.js';
37
34
  import type { PluginLogger } from '../openclaw-sdk.js';
38
35
 
39
- /**
40
- * EventLog - Structured event logging with daily statistics aggregation.
41
- *
42
- * Log files are date-stamped: events_YYYY-MM-DD.jsonl
43
- * Old event files are automatically cleaned up based on retention policy.
44
- */
45
-
46
- /**
47
- * Event log retention in days.
48
- * Files older than this are deleted on cleanup.
49
- */
50
36
  const EVENT_LOG_RETENTION_DAYS = 7;
51
37
 
52
38
  export class EventLog {
@@ -60,11 +46,9 @@ export class EventLog {
60
46
  private readonly flushIntervalMs = 30000;
61
47
  private flushTimer?: ReturnType<typeof setInterval>;
62
48
 
63
- // Cached event file path for current date
64
49
  private currentEventsFile: string | undefined;
65
50
  private currentDate: string | undefined;
66
51
 
67
- // Pain score sum per date (for avgScore calculation)
68
52
  private readonly painScoreSums: Map<string, number> = new Map();
69
53
 
70
54
  constructor(stateDir: string, logger?: PluginLogger) {
@@ -80,37 +64,24 @@ export class EventLog {
80
64
  this.startFlushTimer();
81
65
  }
82
66
 
83
- /**
84
- * Get the event file path for a given date.
85
- */
86
67
  private getEventsFile(date: string): string {
87
68
  return path.join(this.logsDir, `events_${date}.jsonl`);
88
69
  }
89
70
 
90
- /**
91
- * Get today's date string (YYYY-MM-DD).
92
- */
93
71
  private getTodayStr(): string {
94
72
  return new Date().toISOString().split('T')[0];
95
73
  }
96
74
 
97
- /**
98
- * Ensure we have the correct events file for today's date.
99
- */
100
75
  private ensureEventsFile(): string {
101
76
  const today = this.getTodayStr();
102
77
  if (this.currentDate !== today || !this.currentEventsFile) {
103
78
  this.currentDate = today;
104
79
  this.currentEventsFile = this.getEventsFile(today);
105
- // Run cleanup if date changed
106
80
  this.cleanupOldEventFiles(today);
107
81
  }
108
82
  return this.currentEventsFile;
109
83
  }
110
84
 
111
- /**
112
- * Clean up event files older than EVENT_LOG_RETENTION_DAYS.
113
- */
114
85
  private cleanupOldEventFiles(_today: string): void {
115
86
  if (EVENT_LOG_RETENTION_DAYS <= 0) return;
116
87
 
@@ -133,7 +104,7 @@ export class EventLog {
133
104
  }
134
105
 
135
106
  recordToolCall(sessionId: string | undefined, data: ToolCallEventData): void {
136
- const category = data.error ? 'failure' : 'success';
107
+ const category = data.error || (data.exitCode !== undefined && data.exitCode !== 0) ? 'failure' : 'success';
137
108
  this.record('tool_call', category, sessionId, data);
138
109
  }
139
110
 
@@ -189,7 +160,6 @@ export class EventLog {
189
160
  this.record('warn', 'failure', sessionId, { message, ...context });
190
161
  }
191
162
 
192
- // C: Diagnostician heartbeat chain event recorders
193
163
  recordDiagnosisTask(data: DiagnosisTaskEventData): void {
194
164
  this.record('diagnosis_task', 'written', undefined, data);
195
165
  }
@@ -199,8 +169,6 @@ export class EventLog {
199
169
  }
200
170
 
201
171
  recordDiagnosticianReport(data: DiagnosticianReportEventData): void {
202
- // Map three-state category to EventCategory
203
- // Both missing_json and incomplete_fields map to 'failure' in EventCategory
204
172
  const categoryMap: Record<DiagnosticianReportEventData['category'], EventCategory> = {
205
173
  success: 'completed',
206
174
  missing_json: 'failure',
@@ -217,20 +185,6 @@ export class EventLog {
217
185
  this.record('rule_enforced', 'matched', undefined, data);
218
186
  }
219
187
 
220
- // C: Nocturnal funnel event recorders (PD-FUNNEL-2.3)
221
- recordNocturnalDreamerCompleted(data: NocturnalDreamerCompletedEventData): void {
222
- this.record('nocturnal_dreamer_completed', 'completed', undefined, data);
223
- }
224
-
225
- recordNocturnalArtifactPersisted(data: NocturnalArtifactPersistedEventData): void {
226
- this.record('nocturnal_artifact_persisted', 'completed', undefined, data);
227
- }
228
-
229
- recordNocturnalCodeCandidateCreated(data: NocturnalCodeCandidateCreatedEventData): void {
230
- this.record('nocturnal_code_candidate_created', 'created', undefined, data);
231
- }
232
-
233
- // C: RuleHost funnel event recorders (PD-FUNNEL-2.4)
234
188
  recordRuleHostEvaluated(data: RuleHostEvaluatedEventData): void {
235
189
  this.record('rulehost_evaluated', 'evaluated', undefined, data);
236
190
  }
@@ -243,6 +197,18 @@ export class EventLog {
243
197
  this.record('rulehost_requireApproval', 'requireApproval', undefined, data);
244
198
  }
245
199
 
200
+ recordRuleHostAutoCorrectProposed(data: RuleHostAutoCorrectProposedEventData): void {
201
+ this.record('rulehost_auto_correct_proposed', 'auto_correct', undefined, data);
202
+ }
203
+
204
+ recordRuleHostAutoCorrectApplied(data: RuleHostAutoCorrectAppliedEventData): void {
205
+ this.record('rulehost_auto_correct_applied', 'auto_correct', undefined, data);
206
+ }
207
+
208
+ recordRuntimeV2ActivationsInjected(data: RuntimeV2PromptActivationsInjectedEventData): void {
209
+ this.record('runtime_v2_prompt_activations_injected', 'injected', data.sessionId, data);
210
+ }
211
+
246
212
  private record(
247
213
  type: EventType,
248
214
  category: EventCategory,
@@ -269,8 +235,6 @@ export class EventLog {
269
235
  }
270
236
  }
271
237
 
272
-
273
-
274
238
  private formatDate(date: Date): string {
275
239
  return date.toISOString().split('T')[0];
276
240
  }
@@ -288,7 +252,6 @@ export class EventLog {
288
252
  }
289
253
  }
290
254
 
291
-
292
255
  private updateStats(entry: EventLogEntry): void {
293
256
  let stats = this.statsCache.get(entry.date);
294
257
  if (!stats) {
@@ -300,24 +263,29 @@ export class EventLog {
300
263
  stats.tools.total++;
301
264
  if (entry.category === 'success') stats.tools.success++;
302
265
  else stats.tools.failure++;
266
+
267
+ const tcData = entry.data as unknown as ToolCallEventData;
268
+ const observedGfi = tcData.gfiAfter ?? tcData.gfi;
269
+ if (observedGfi !== undefined) {
270
+ stats.gfi.samples++;
271
+ stats.gfi.total += observedGfi;
272
+ stats.gfi.peak = Math.max(stats.gfi.peak, observedGfi);
273
+ }
303
274
  } else if (entry.type === 'pain_signal') {
304
275
  const data = entry.data as unknown as PainSignalEventData;
305
276
  stats.pain.signalsDetected++;
306
277
  stats.pain.maxScore = Math.max(stats.pain.maxScore, data.score);
307
278
 
308
- // Track signals by source
309
279
  if (data.source) {
310
280
  stats.pain.signalsBySource[data.source] = (stats.pain.signalsBySource[data.source] || 0) + 1;
311
281
  }
312
282
 
313
- // Accumulate score for avg calculation
314
283
  const currentSum = this.painScoreSums.get(entry.date) ?? 0;
315
284
  this.painScoreSums.set(entry.date, currentSum + (data.score || 0));
316
285
  stats.pain.avgScore = stats.pain.signalsDetected > 0
317
286
  ? Math.round((currentSum + (data.score || 0)) / stats.pain.signalsDetected)
318
287
  : 0;
319
288
 
320
- // Update empathy stats for user_empathy source
321
289
  if (data.source === 'user_empathy') {
322
290
  if (data.deduped) {
323
291
  stats.empathy.dedupedCount++;
@@ -325,23 +293,19 @@ export class EventLog {
325
293
  stats.empathy.totalEvents++;
326
294
  stats.empathy.totalPenaltyScore += data.score || 0;
327
295
 
328
- // By severity
329
296
  if (data.severity) {
330
297
  stats.empathy.bySeverity[data.severity]++;
331
298
  stats.empathy.scoreBySeverity[data.severity] += data.score || 0;
332
299
  }
333
300
 
334
- // By detection mode
335
301
  if (data.detection_mode) {
336
302
  stats.empathy.byDetectionMode[data.detection_mode]++;
337
303
  }
338
304
 
339
- // By origin
340
305
  if (data.origin) {
341
306
  stats.empathy.byOrigin[data.origin]++;
342
307
  }
343
308
 
344
- // Confidence distribution
345
309
  const conf = data.confidence ?? 1;
346
310
  if (conf >= 0.8) stats.empathy.confidenceDistribution.high++;
347
311
  else if (conf >= 0.5) stats.empathy.confidenceDistribution.medium++;
@@ -357,7 +321,6 @@ export class EventLog {
357
321
  if (entry.category === 'success') stats.hooks.success++;
358
322
  else stats.hooks.failure++;
359
323
 
360
- // Track by type
361
324
  if (data.hook) {
362
325
  if (!stats.hooks.byType[data.hook]) {
363
326
  stats.hooks.byType[data.hook] = { total: 0, success: 0, failure: 0 };
@@ -385,19 +348,13 @@ export class EventLog {
385
348
  stats.evolution.tasksEnqueued++;
386
349
  }
387
350
  }
388
- // C: Diagnostician heartbeat chain event counters
389
351
  else if (entry.type === 'diagnosis_task') {
390
352
  stats.evolution.diagnosisTasksWritten++;
391
353
  } else if (entry.type === 'heartbeat_diagnosis') {
392
354
  stats.evolution.heartbeatsInjected++;
393
355
  } else if (entry.type === 'diagnostician_report') {
394
- // Backward compat: handle old events with success:boolean and new events with category:string
395
- // Widen to Record<string, unknown> because DiagnosticianReportEventData requires
396
- // category (new format) but legacy persisted events have { success: boolean }.
397
356
  const raw = entry.data as unknown as Record<string, unknown>;
398
357
  if (Object.prototype.hasOwnProperty.call(raw, 'category')) {
399
- // New format: category is 'success' | 'missing_json' | 'incomplete_fields'
400
- // All three categories mean diagnosis completed and attempted to produce a report
401
358
  const cat = raw['category'] as string;
402
359
  if (cat === 'success' || cat === 'missing_json' || cat === 'incomplete_fields') {
403
360
  stats.evolution.diagnosticianReportsWritten++;
@@ -409,10 +366,6 @@ export class EventLog {
409
366
  stats.evolution.reportsIncompleteFields++;
410
367
  }
411
368
  } else if (Object.prototype.hasOwnProperty.call(raw, 'success')) {
412
- // Legacy format: { success: boolean }
413
- // Agreed fix: count ALL legacy events in diagnosticianReportsWritten (+1 for both true and false).
414
- // Sub-counters (reportsMissingJson/reportsIncompleteFields) stay untouched because
415
- // legacy events lack enough information to distinguish sub-category — preserve total, don't fake breakdown.
416
369
  stats.evolution.diagnosticianReportsWritten++;
417
370
  }
418
371
  } else if (entry.type === 'principle_candidate') {
@@ -420,32 +373,21 @@ export class EventLog {
420
373
  } else if (entry.type === 'rule_enforced') {
421
374
  stats.evolution.rulesEnforced++;
422
375
  }
423
- // C: Nocturnal funnel event counters (PD-FUNNEL-2.3)
424
- else if (entry.type === 'nocturnal_dreamer_completed') {
425
- const data = entry.data as unknown as NocturnalDreamerCompletedEventData;
426
- stats.evolution.nocturnalDreamerCompleted++;
427
- if (data.chainMode === 'trinity') {
428
- stats.evolution.nocturnalTrinityCompleted++;
429
- }
430
- } else if (entry.type === 'nocturnal_artifact_persisted') {
431
- stats.evolution.nocturnalArtifactPersisted++;
432
- } else if (entry.type === 'nocturnal_code_candidate_created') {
433
- stats.evolution.nocturnalCodeCandidateCreated++;
434
- }
435
- // C: RuleHost funnel event counters (PD-FUNNEL-2.4)
436
376
  else if (entry.type === 'rulehost_evaluated') {
437
377
  stats.evolution.rulehostEvaluated++;
438
378
  } else if (entry.type === 'rulehost_blocked') {
439
379
  stats.evolution.rulehostBlocked++;
440
380
  } else if (entry.type === 'rulehost_requireApproval') {
441
381
  stats.evolution.rulehostRequireApproval++;
382
+ } else if (entry.type === 'rulehost_auto_correct_proposed') {
383
+ stats.evolution.rulehostAutoCorrectProposed++;
384
+ } else if (entry.type === 'rulehost_auto_correct_applied') {
385
+ stats.evolution.rulehostAutoCorrectApplied++;
442
386
  }
443
387
  }
444
388
 
445
389
  private startFlushTimer(): void {
446
390
  this.flushTimer = setInterval(() => this.flush(), this.flushIntervalMs);
447
- // Don't keep the process alive just for this timer
448
- // This allows tests and CLI to exit without waiting for flush
449
391
  this.flushTimer.unref();
450
392
  }
451
393
 
@@ -454,16 +396,10 @@ export class EventLog {
454
396
  this.flushStats();
455
397
  }
456
398
 
457
- /**
458
- * Return in-memory buffered events that have not been flushed yet.
459
- * Intended for live runtime summaries that should not lag behind disk snapshots.
460
- */
461
399
  getBufferedEvents(): EventLogEntry[] {
462
400
  return this.eventBuffer.map((entry) => ({ ...entry, data: { ...entry.data } }));
463
401
  }
464
402
 
465
-
466
-
467
403
  private getEventDedupKey(entry: EventLogEntry): string {
468
404
  const eventId = typeof (entry.data as { eventId?: unknown } | undefined)?.eventId === 'string'
469
405
  ? String((entry.data as { eventId?: string }).eventId)
@@ -545,10 +481,6 @@ export class EventLog {
545
481
  }
546
482
  }
547
483
 
548
- /**
549
- * Get daily statistics for a specific date.
550
- * Returns empty stats if no events recorded for that date.
551
- */
552
484
  getDailyStats(date: string): DailyStats {
553
485
  let stats = this.statsCache.get(date);
554
486
  if (!stats) {
@@ -558,17 +490,10 @@ export class EventLog {
558
490
  return stats;
559
491
  }
560
492
 
561
- /**
562
- * Get aggregated empathy statistics for multiple time ranges.
563
- * @param range 'today' | 'week' | 'session'
564
- * @param sessionId Optional session ID for session-scoped stats
565
- */
566
-
567
493
  getEmpathyStats(range: 'today' | 'week' | 'session', sessionId?: string): EmpathyEventStats {
568
494
  const now = new Date();
569
495
  const today = this.formatDate(now);
570
496
 
571
- // Aggregate stats based on range
572
497
  const result: EmpathyEventStats = {
573
498
  totalEvents: 0,
574
499
  dedupedCount: 0,
@@ -585,10 +510,8 @@ export class EventLog {
585
510
  };
586
511
 
587
512
  if (range === 'session' && sessionId) {
588
- // For session range, scan event buffer and events file
589
513
  this.aggregateSessionEmpathy(sessionId, result);
590
514
  } else if (range === 'week') {
591
- // For week range, aggregate last 7 days
592
515
  for (let i = 0; i < 7; i++) {
593
516
  const date = new Date(now);
594
517
  date.setDate(date.getDate() - i);
@@ -626,7 +549,6 @@ export class EventLog {
626
549
  }
627
550
  }
628
551
  } else {
629
- // Today only
630
552
  const stats = this.getDailyStats(today);
631
553
  Object.assign(result, stats.empathy);
632
554
  if (stats.empathy.totalEvents > 0 || stats.empathy.dedupedCount > 0) {
@@ -638,17 +560,12 @@ export class EventLog {
638
560
  }
639
561
  }
640
562
 
641
- // Calculate dedupe hit rate
642
563
  const total = result.totalEvents + result.dedupedCount;
643
564
  result.dedupeHitRate = total > 0 ? result.dedupedCount / total : 0;
644
565
 
645
566
  return result;
646
567
  }
647
568
 
648
- /**
649
- * Aggregate empathy stats for a specific session.
650
- */
651
-
652
569
  private aggregateSessionEmpathy(sessionId: string, result: EmpathyEventStats): void {
653
570
  for (const entry of this.getMergedEvents()) {
654
571
  if (entry.sessionId === sessionId && entry.type === 'pain_signal') {
@@ -677,15 +594,8 @@ export class EventLog {
677
594
  result.rolledBackScore += data.originalScore || 0;
678
595
  }
679
596
  }
680
-
681
597
  }
682
598
 
683
- /**
684
- * Rollback an empathy event by ID.
685
- * Returns the rolled back score, or 0 if event not found.
686
- */
687
-
688
-
689
599
  rollbackEmpathyEvent(eventId: string, sessionId: string | undefined, reason: string, triggeredBy: 'user_command' | 'natural_language' | 'system'): number {
690
600
  const allEvents = this.getMergedEvents();
691
601
  let foundEvent: { entry: EventLogEntry; data: PainSignalEventData } | null = null;
@@ -706,7 +616,6 @@ export class EventLog {
706
616
 
707
617
  const originalScore = foundEvent.data.score || 0;
708
618
 
709
- // Record the rollback event
710
619
  this.recordEmpathyRollback(sessionId, {
711
620
  eventId,
712
621
  originalScore,
@@ -718,9 +627,6 @@ export class EventLog {
718
627
  return originalScore;
719
628
  }
720
629
 
721
- /**
722
- * Get the last empathy event ID for a session (for rollback).
723
- */
724
630
  getLastEmpathyEventId(sessionId: string): string | null {
725
631
  const allEvents = this.getMergedEvents();
726
632
  for (let i = allEvents.length - 1; i >= 0; i--) {
@@ -736,9 +642,6 @@ export class EventLog {
736
642
  return null;
737
643
  }
738
644
 
739
- /**
740
- * Find the latest pain signal for a given session.
741
- */
742
645
  findLatestPainSignal(sessionId: string | undefined): PainSignalEventData | null {
743
646
  const allEvents = this.getMergedEvents();
744
647
  for (let i = allEvents.length - 1; i >= 0; i--) {
@@ -750,9 +653,6 @@ export class EventLog {
750
653
  return null;
751
654
  }
752
655
 
753
- /**
754
- * Dispose of the EventLog, flushing pending data and clearing timer.
755
- */
756
656
  dispose(): void {
757
657
  if (this.flushTimer) {
758
658
  clearInterval(this.flushTimer);
@@ -762,9 +662,6 @@ export class EventLog {
762
662
  }
763
663
  }
764
664
 
765
- /**
766
- * Service to manage multiple EventLog instances by stateDir.
767
- */
768
665
  export class EventLogService {
769
666
  private static readonly instances: Map<string, EventLog> = new Map();
770
667
 
@@ -105,6 +105,8 @@ export class EvolutionReducerImpl implements EvolutionReducer {
105
105
  private readonly failureStreak = new Map<string, number>();
106
106
  private lastPromotedAt: string | null = null;
107
107
  private isReplaying = false;
108
+ /** Registered pain_detected callbacks (e.g., PainSignalBridge). */
109
+ private readonly _painCallbacks: Array<(event: EvolutionLoopEvent) => void> = [];
108
110
 
109
111
  constructor(opts: { workspaceDir: string; stateDir?: string }) {
110
112
  this.workspaceDir = opts.workspaceDir;
@@ -145,6 +147,15 @@ export class EvolutionReducerImpl implements EvolutionReducer {
145
147
  // Performance: sweepExpiredProbation() moved to getProbationPrinciples() for lazy cleanup
146
148
  }
147
149
 
150
+ /**
151
+ * Register a callback for 'pain_detected' events.
152
+ * The callback is invoked synchronously within emitSync() after applyEvent completes.
153
+ * HG-4: Callbacks are fire-and-forget from the emitSync perspective.
154
+ */
155
+ on(callback: (event: EvolutionLoopEvent) => void): void {
156
+ this._painCallbacks.push(callback);
157
+ }
158
+
148
159
  getEventLog(): EvolutionLoopEvent[] {
149
160
  return [...this.memoryEvents];
150
161
  }
@@ -171,14 +182,14 @@ export class EvolutionReducerImpl implements EvolutionReducer {
171
182
  const p = this.principles.get(principleId);
172
183
  if (!p || p.status === 'active' || p.status === 'deprecated') return;
173
184
 
174
- const nextStatus: PrincipleStatus = p.status === 'candidate' ? 'probation' : 'active';
185
+ const toStatus = (p.status === 'candidate' ? 'probation' : p.status === 'probation' ? 'active' : p.status) as PrincipleStatus;
175
186
  const event: EvolutionLoopEvent = {
176
187
  ts: new Date().toISOString(),
177
188
  type: 'principle_promoted',
178
189
  data: {
179
190
  principleId,
180
191
  from: p.status,
181
- to: nextStatus,
192
+ to: toStatus,
182
193
  reason,
183
194
  successCount: p.validation.successCount,
184
195
  },
@@ -650,6 +661,14 @@ export class EvolutionReducerImpl implements EvolutionReducer {
650
661
  if (!this.isReplaying) {
651
662
  this.onPainDetected(event.data, event.ts);
652
663
  }
664
+ // PainSignalBridge subscriptions: invoke registered callbacks (fire-and-forget)
665
+ for (const cb of this._painCallbacks) {
666
+ try {
667
+ cb(event);
668
+ } catch {
669
+ // Keep the evolution loop resilient — callback errors must not propagate
670
+ }
671
+ }
653
672
  return;
654
673
  case 'candidate_created':
655
674
  this.onCandidateCreated(event.data, event.ts);