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
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Full persistence layer encapsulating queue file locking, atomic writes,
5
5
  * queue format, and enqueue orchestration. Depends on file-lock.ts, io.ts,
6
- * queue-migration.ts, correction-cue-learner.ts, and pain.ts.
6
+ * queue-migration.ts, and pain.ts.
7
7
  * Zero imports from evolution-worker.ts.
8
8
  */
9
9
 
@@ -16,364 +16,93 @@ import { migrateQueueToV2 } from './queue-migration.js';
16
16
  import type { EvolutionQueueItem } from '../core/evolution-types.js';
17
17
  import type { RawQueueItem } from './queue-migration.js';
18
18
  import type { PluginLogger } from '../openclaw-sdk.js';
19
- import type { WorkspaceContext } from '../core/workspace-context.js';
20
- import { CorrectionCueLearner } from '../core/correction-cue-learner.js';
21
- import { readPainFlagContract } from '../core/pain.js';
22
-
23
- /**
24
- * Extended EvolutionQueueItem that includes the recentPainContext field.
25
- * This field is added inline in evolution-worker.ts but needs to be available
26
- * in queue-io.ts for the enqueue functions.
27
- */
28
- interface EvolutionQueueItemWithPain extends EvolutionQueueItem {
29
- recentPainContext?: RecentPainContext;
30
- }
31
19
 
32
20
  export const EVOLUTION_QUEUE_LOCK_SUFFIX = '.lock';
33
21
  export const LOCK_MAX_RETRIES = 50;
34
22
  export const LOCK_RETRY_DELAY_MS = 50;
35
23
  export const LOCK_STALE_MS = 30_000;
36
24
 
37
- export const SLEEP_REFLECTION_DEDUP_WINDOW_MS = 4 * 60 * 60 * 1000; // 4 hours
38
-
39
- // ---------------------------------------------------------------------------
40
- // requireQueueLock — thin wrapper that adds LockUnavailableError
41
- // ---------------------------------------------------------------------------
42
-
43
- /**
44
- * Acquire a queue lock, throwing LockUnavailableError on failure.
45
- * This is the standard lock used across all queue operations.
46
- */
47
25
  export async function requireQueueLock(
48
- resourcePath: string,
49
- logger: PluginLogger | { warn?: (message: string) => void; info?: (message: string) => void } | undefined,
50
- scope: string,
51
- lockSuffix: string = EVOLUTION_QUEUE_LOCK_SUFFIX,
26
+ resourcePath: string,
27
+ logger: PluginLogger | { warn?: (message: string) => void; info?: (message: string) => void } | undefined,
28
+ scope: string,
29
+ lockSuffix: string = EVOLUTION_QUEUE_LOCK_SUFFIX,
52
30
  ): Promise<() => void> {
53
- try {
54
- return await acquireQueueLock(resourcePath, logger, lockSuffix);
55
- } catch (err) {
56
- throw new LockUnavailableError(resourcePath, scope, { cause: err });
57
- }
31
+ try {
32
+ return await acquireQueueLock(resourcePath, logger, lockSuffix);
33
+ } catch (err) {
34
+ throw new LockUnavailableError(resourcePath, scope, { cause: err });
35
+ }
58
36
  }
59
37
 
60
- // ---------------------------------------------------------------------------
61
- // RecentPainContext
62
- // ---------------------------------------------------------------------------
63
-
64
- export interface RecentPainContext {
65
- mostRecent: {
66
- score: number;
67
- source: string;
68
- reason: string;
69
- timestamp: string;
70
- sessionId: string;
71
- /** Trajectory pain_events row ID — set when pain flag includes pain_event_id */
72
- painEventId?: number;
73
- } | null;
74
- recentPainCount: number;
75
- recentMaxPainScore: number;
76
- }
77
-
78
- // ---------------------------------------------------------------------------
79
- // Task ID creation
80
- // ---------------------------------------------------------------------------
81
-
82
38
  export function createEvolutionTaskId(
83
- source: string,
84
- score: number,
85
- preview: string,
86
- reason: string,
87
- now: number,
39
+ source: string,
40
+ score: number,
41
+ preview: string,
42
+ reason: string,
43
+ now: number,
88
44
  ): string {
89
- return createHash('md5')
90
- .update(`${source}:${score}:${preview}:${reason}:${now}`)
91
- .digest('hex')
92
- .substring(0, 8);
45
+ return createHash('md5')
46
+ .update(`${source}:${score}:${preview}:${reason}:${now}`)
47
+ .digest('hex')
48
+ .substring(0, 8);
93
49
  }
94
50
 
95
- // ---------------------------------------------------------------------------
96
- // Queue helpers
97
- // ---------------------------------------------------------------------------
98
-
99
- /**
100
- * Check whether a specific task kind has a pending or in-progress entry.
101
- */
102
51
  export function hasPendingTask(queue: EvolutionQueueItem[], taskKind: string): boolean {
103
- return queue.some(
104
- (t) => t.taskKind === taskKind && (t.status === 'pending' || t.status === 'in_progress'),
105
- );
106
- }
107
-
108
- /**
109
- * Build a dedup key from pain context.
110
- * Returns null when no pain context is available (bypasses dedup).
111
- */
112
- function buildPainSourceKey(
113
- painCtx: ReturnType<typeof readRecentPainContext>,
114
- ): string | null {
115
- if (!painCtx.mostRecent) return null;
116
- return `${painCtx.mostRecent.source}::${painCtx.mostRecent.reason?.slice(0, 50) ?? ''}`;
117
- }
118
-
119
- /**
120
- * Check whether a similar sleep_reflection task completed recently.
121
- */
122
- function hasRecentSimilarReflection(
123
- queue: EvolutionQueueItemWithPain[],
124
- painSourceKey: string,
125
- now: number,
126
- ): EvolutionQueueItem | null {
127
- return queue.find((t) => {
128
- if (t.taskKind !== 'sleep_reflection') return false;
129
- if (t.status !== 'completed') return false;
130
- if (!t.completed_at) return false;
131
- const age = now - new Date(t.completed_at).getTime();
132
- if (age > SLEEP_REFLECTION_DEDUP_WINDOW_MS) return false;
133
- const taskPainKey = buildPainSourceKey(t.recentPainContext ?? { mostRecent: null, recentPainCount: 0, recentMaxPainScore: 0 });
134
- if (!taskPainKey) return false;
135
- return taskPainKey === painSourceKey;
136
- }) ?? null;
137
- }
138
-
139
- // ---------------------------------------------------------------------------
140
- // Pain context
141
- // ---------------------------------------------------------------------------
142
-
143
- export function readRecentPainContext(wctx: WorkspaceContext): RecentPainContext {
144
- const contract = readPainFlagContract(wctx.workspaceDir);
145
- if (contract.status !== 'valid') {
146
- return { mostRecent: null, recentPainCount: 0, recentMaxPainScore: 0 };
147
- }
148
-
149
- try {
150
- const score = parseInt(contract.data.score ?? '0', 10) || 0;
151
- const source = contract.data.source ?? '';
152
- const reason = contract.data.reason ?? '';
153
- const timestamp = contract.data.time ?? '';
154
- const sessionId = contract.data.session_id ?? '';
155
- const painEventIdRaw = contract.data.pain_event_id;
156
- const painEventId = painEventIdRaw ? parseInt(painEventIdRaw, 10) : undefined;
157
-
158
- if (score > 0) {
159
- return {
160
- mostRecent: { score, source, reason, timestamp, sessionId, painEventId },
161
- recentPainCount: 1,
162
- recentMaxPainScore: score,
163
- };
164
- }
165
- } catch (err) {
166
- // Best effort — non-fatal, but surface unexpected errors
167
-
168
- console.warn(`[queue-io] Failed to read pain context (non-fatal): ${String(err)}`);
169
-
170
- }
171
-
172
- return { mostRecent: null, recentPainCount: 0, recentMaxPainScore: 0 };
173
- }
174
-
175
- /**
176
- * Decide whether to skip enqueuing due to a recent similar reflection.
177
- */
178
- export function shouldSkipForDedup(
179
- queue: EvolutionQueueItemWithPain[],
180
- wctx: WorkspaceContext,
181
- logger: PluginLogger | undefined,
182
- ): boolean {
183
- const recentPainContext = readRecentPainContext(wctx);
184
- const painSourceKey = buildPainSourceKey(recentPainContext);
185
-
186
- if (!painSourceKey) return false;
187
-
188
- const now = Date.now();
189
- const recentSimilarReflection = hasRecentSimilarReflection(queue, painSourceKey, now);
190
-
191
- if (recentSimilarReflection) {
192
- const completedTime = new Date(recentSimilarReflection.completed_at!).getTime();
193
- logger?.debug?.(`[PD:EvolutionWorker] Skipping sleep_reflection — similar reflection completed ${Math.round((now - completedTime) / 60000)}min ago (same pain pattern: ${painSourceKey})`);
194
- return true;
195
- }
196
- return false;
197
- }
198
-
199
- // ---------------------------------------------------------------------------
200
- // Enqueue functions
201
- // ---------------------------------------------------------------------------
202
-
203
- function enqueueNewSleepReflectionTask(
204
- queue: EvolutionQueueItemWithPain[],
205
- recentPainContext: ReturnType<typeof readRecentPainContext>,
206
- queuePath: string,
207
- logger: PluginLogger | undefined,
208
- ): void {
209
- const taskId = createEvolutionTaskId('nocturnal', 50, 'idle workspace', 'Sleep-mode reflection', Date.now());
210
- const nowIso = new Date().toISOString();
211
-
212
- queue.push({
213
- id: taskId,
214
- taskKind: 'sleep_reflection',
215
- priority: 'medium',
216
- score: 50,
217
- source: 'nocturnal',
218
- reason: 'Sleep-mode reflection triggered by idle workspace',
219
- trigger_text_preview: 'Idle workspace detected',
220
- timestamp: nowIso,
221
- enqueued_at: nowIso,
222
- status: 'pending',
223
- traceId: taskId,
224
- retryCount: 0,
225
- maxRetries: 1,
226
- recentPainContext,
227
- });
228
-
229
- // Cast to EvolutionQueueItem[] because saveEvolutionQueue expects the base type
230
- // but the queue may contain extended fields (recentPainContext) that are
231
- // serialized as part of the JSON - this is safe at runtime.
232
- saveEvolutionQueue(queuePath, queue as unknown as EvolutionQueueItem[]);
233
- logger?.info?.(`[PD:EvolutionWorker] Enqueued sleep_reflection task ${taskId}`);
234
- }
235
-
236
- /**
237
- * Enqueue a sleep_reflection task if one is not already pending.
238
- */
239
- export async function enqueueSleepReflectionTask(
240
- wctx: WorkspaceContext,
241
- logger: PluginLogger | undefined,
242
- ): Promise<void> {
243
- const queuePath = wctx.resolve('EVOLUTION_QUEUE');
244
- const releaseLock = await requireQueueLock(queuePath, logger, 'enqueueSleepReflection', EVOLUTION_QUEUE_LOCK_SUFFIX);
245
-
246
- try {
247
- const queue = loadEvolutionQueue(queuePath);
248
-
249
- if (hasPendingTask(queue, 'sleep_reflection')) {
250
- logger?.debug?.('[PD:EvolutionWorker] sleep_reflection task already pending/in-progress, skipping');
251
- return;
252
- }
253
-
254
- if (shouldSkipForDedup(queue, wctx, logger)) {
255
- return;
256
- }
257
-
258
- const recentPainContext = readRecentPainContext(wctx);
259
- enqueueNewSleepReflectionTask(queue, recentPainContext, queuePath, logger);
260
- } finally {
261
- releaseLock();
262
- }
263
- }
264
-
265
- /**
266
- * Enqueue a keyword_optimization task if one is not already pending/in-progress.
267
- */
268
- export async function enqueueKeywordOptimizationTask(
269
- wctx: WorkspaceContext,
270
- logger: PluginLogger | undefined,
271
- ): Promise<void> {
272
- const queuePath = wctx.resolve('EVOLUTION_QUEUE');
273
- const releaseLock = await requireQueueLock(queuePath, logger, 'enqueueKeywordOpt', EVOLUTION_QUEUE_LOCK_SUFFIX);
274
-
275
- try {
276
- const queue = loadEvolutionQueue(queuePath);
277
-
278
- if (hasPendingTask(queue, 'keyword_optimization')) {
279
- logger?.debug?.('[PD:EvolutionWorker] keyword_optimization task already pending/in-progress, skipping');
280
- return;
281
- }
282
-
283
- const learner = CorrectionCueLearner.get(wctx.stateDir);
284
- if (!learner.canRunKeywordOptimization()) {
285
- logger?.debug?.('[PD:EvolutionWorker] keyword_optimization throttle exhausted, skipping');
286
- return;
287
- }
288
-
289
- const taskId = createEvolutionTaskId('keyword_optimization', 50, 'keyword optimization', 'Keyword optimization via LLM', Date.now());
290
- const nowIso = new Date().toISOString();
291
-
292
- queue.push({
293
- id: taskId,
294
- taskKind: 'keyword_optimization',
295
- priority: 'medium',
296
- score: 50,
297
- source: 'correction',
298
- reason: 'Keyword optimization triggered by heartbeat',
299
- trigger_text_preview: 'Keyword optimization via LLM',
300
- timestamp: nowIso,
301
- enqueued_at: nowIso,
302
- status: 'pending',
303
- traceId: taskId,
304
- retryCount: 0,
305
- maxRetries: 1,
306
- });
307
-
308
- saveEvolutionQueue(queuePath, queue);
309
- logger?.info?.(`[PD:EvolutionWorker] Enqueued keyword_optimization task ${taskId}`);
310
- } finally {
311
- releaseLock();
312
- }
52
+ return queue.some(
53
+ (t) => t.taskKind === taskKind && (t.status === 'pending' || t.status === 'in_progress'),
54
+ );
313
55
  }
314
56
 
315
57
  export async function acquireQueueLock(
316
- resourcePath: string,
317
- logger: PluginLogger | { warn?: (message: string) => void; info?: (message: string) => void } | undefined,
318
- lockSuffix: string = EVOLUTION_QUEUE_LOCK_SUFFIX,
58
+ resourcePath: string,
59
+ logger: PluginLogger | { warn?: (message: string) => void; info?: (message: string) => void } | undefined,
60
+ lockSuffix: string = EVOLUTION_QUEUE_LOCK_SUFFIX,
319
61
  ): Promise<() => void> {
320
- try {
321
- const ctx: LockContext = await acquireLockAsync(resourcePath, {
322
- lockSuffix,
323
- maxRetries: LOCK_MAX_RETRIES,
324
- baseRetryDelayMs: LOCK_RETRY_DELAY_MS,
325
- lockStaleMs: LOCK_STALE_MS,
326
- });
327
- return () => releaseImportedLock(ctx);
328
- } catch (error: unknown) {
329
- const warn = logger?.warn;
330
- warn?.(`[PD:EvolutionWorker] Failed to acquire lock for ${resourcePath}: ${String(error)}`);
331
- throw error;
332
- }
62
+ try {
63
+ const ctx: LockContext = await acquireLockAsync(resourcePath, {
64
+ lockSuffix,
65
+ maxRetries: LOCK_MAX_RETRIES,
66
+ baseRetryDelayMs: LOCK_RETRY_DELAY_MS,
67
+ lockStaleMs: LOCK_STALE_MS,
68
+ });
69
+ return () => releaseImportedLock(ctx);
70
+ } catch (error: unknown) {
71
+ const warn = logger?.warn;
72
+ warn?.(`[PD:EvolutionWorker] Failed to acquire lock for ${resourcePath}: ${String(error)}`);
73
+ throw error;
74
+ }
333
75
  }
334
76
 
335
- /**
336
- * RAII-style lock guard — always releases the lock on exceptions.
337
- */
338
77
  export async function withQueueLock<T>(
339
- resourcePath: string,
340
- logger: PluginLogger | { warn?: (message: string) => void; info?: (message: string) => void } | undefined,
341
- scope: string,
342
- fn: () => Promise<T>,
78
+ resourcePath: string,
79
+ logger: PluginLogger | { warn?: (message: string) => void; info?: (message: string) => void } | undefined,
80
+ scope: string,
81
+ fn: () => Promise<T>,
343
82
  ): Promise<T> {
344
- const releaseLock = await acquireQueueLock(resourcePath, logger, EVOLUTION_QUEUE_LOCK_SUFFIX);
345
- try {
346
- return await fn();
347
- } finally {
348
- releaseLock();
349
- }
83
+ const releaseLock = await acquireQueueLock(resourcePath, logger, EVOLUTION_QUEUE_LOCK_SUFFIX);
84
+ try {
85
+ return await fn();
86
+ } finally {
87
+ releaseLock();
88
+ }
350
89
  }
351
90
 
352
- /**
353
- * Load and migrate the evolution queue. Returns empty array if file doesn't exist.
354
- */
355
91
  export function loadEvolutionQueue(queuePath: string): EvolutionQueueItem[] {
356
- let rawQueue: RawQueueItem[] = [];
357
- try {
358
- rawQueue = JSON.parse(fs.readFileSync(queuePath, 'utf8'));
359
- } catch (err) {
360
- if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
361
- // Queue doesn't exist yet - create empty array
362
- rawQueue = [];
363
- } else {
364
- // Corrupted JSON or other read error — warn and recover with empty queue
365
-
366
- console.warn(`[queue-io] Failed to load evolution queue (recovering with empty): ${String(err)}`);
367
-
368
- rawQueue = [];
369
- }
92
+ let rawQueue: RawQueueItem[] = [];
93
+ try {
94
+ rawQueue = JSON.parse(fs.readFileSync(queuePath, 'utf8'));
95
+ } catch (err) {
96
+ if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
97
+ rawQueue = [];
98
+ } else {
99
+ console.warn(`[queue-io] Failed to load evolution queue (recovering with empty): ${String(err)}`);
100
+ rawQueue = [];
370
101
  }
371
- return migrateQueueToV2(rawQueue) as unknown as EvolutionQueueItem[];
102
+ }
103
+ return migrateQueueToV2(rawQueue) as unknown as EvolutionQueueItem[];
372
104
  }
373
105
 
374
- /**
375
- * Atomically write the queue to disk.
376
- */
377
106
  export function saveEvolutionQueue(queuePath: string, queue: EvolutionQueueItem[]): void {
378
- atomicWriteFileSync(queuePath, JSON.stringify(queue, null, 2));
107
+ atomicWriteFileSync(queuePath, JSON.stringify(queue, null, 2));
379
108
  }
@@ -1,13 +1,15 @@
1
1
  import * as fs from 'fs';
2
+ import Database from 'better-sqlite3';
2
3
  import * as path from 'path';
3
4
  import { readPainFlagData } from '../core/pain.js';
4
5
  import { listSessions } from '../core/session-tracker.js';
5
6
  import { WorkspaceContext } from '../core/workspace-context.js';
6
7
  import { evaluatePhase3Inputs } from './phase3-input-filter.js';
7
8
  import { TrajectoryRegistry } from '../core/trajectory.js';
8
- import { getPendingDiagnosticianTasks } from '../core/diagnostician-task-store.js';
9
9
  import type { WorkflowStage } from '../core/workflow-funnel-loader.js';
10
10
  import type { RuntimeTruth, AnalyticsTruth } from '../types/runtime-summary.js';
11
+ import { buildGfiWorkspaceSnapshot } from '@principles/core/runtime-v2';
12
+ import type { GfiWorkspaceSnapshot } from '@principles/core/runtime-v2';
11
13
 
12
14
  export type RuntimeDataQuality = 'authoritative' | 'partial';
13
15
  export type RuntimeRewardPolicy =
@@ -47,6 +49,7 @@ export interface RuntimeSummary {
47
49
  peak: number | null;
48
50
  sources: RuntimeSummarySource[];
49
51
  dataQuality: RuntimeDataQuality;
52
+ workspaceSnapshot?: GfiWorkspaceSnapshot;
50
53
  };
51
54
  evolution: {
52
55
  queue: {
@@ -62,8 +65,8 @@ export interface RuntimeSummary {
62
65
  };
63
66
  dataQuality: RuntimeDataQuality;
64
67
  };
65
- // D: Heartbeat Diagnostician chain — separate from evolution/nocturnal chain
66
- heartbeatDiagnosis: {
68
+ // D: Runtime Diagnostician chain (M8) replaced legacy heartbeat path
69
+ runtimeDiagnosis: {
67
70
  /** Tasks pending in diagnostician_tasks.json (not yet processed by heartbeat) */
68
71
  pendingTasks: number;
69
72
  /** Total diagnosis tasks written by evolution worker (today from event log) */
@@ -123,6 +126,10 @@ export interface RuntimeSummary {
123
126
  interface PersistedSessionState {
124
127
  sessionId: string;
125
128
  currentGfi?: number;
129
+ gfiBySource?: Record<string, number>;
130
+ lastErrorSource?: string;
131
+ consecutiveErrors?: number;
132
+ lastGfiDecayAt?: number;
126
133
  dailyGfiPeak?: number;
127
134
  lastActivityAt?: number;
128
135
  lastControlActivityAt?: number;
@@ -311,6 +318,23 @@ export class RuntimeSummaryService {
311
318
  const gfiPeak =
312
319
  sessionPeak ?? (Number.isFinite(dailyGfiPeak) ? Number(dailyGfiPeak) : null);
313
320
 
321
+ // PRI-78/PRI-82: Build authoritative GFI workspace snapshot (active vs stale)
322
+ // Uses real persisted GFI fields: gfiBySource, consecutiveErrors, lastErrorSource,
323
+ // lastGfiDecayAt, dailyGfiPeak from session-tracker persistence.
324
+ const gfiWorkspaceSnapshot: GfiWorkspaceSnapshot = buildGfiWorkspaceSnapshot({
325
+ sessions: sessions.map((s) => ({
326
+ sessionId: s.sessionId,
327
+ currentGfi: s.currentGfi ?? 0,
328
+ gfiBySource: s.gfiBySource ?? {},
329
+ consecutiveErrors: s.consecutiveErrors ?? 0,
330
+ lastErrorSource: s.lastErrorSource,
331
+ lastGfiDecayAt: s.lastGfiDecayAt,
332
+ dailyGfiPeak: s.dailyGfiPeak,
333
+ lastActivityAt: s.lastControlActivityAt ?? s.lastActivityAt ?? 0,
334
+ })),
335
+ nowMs: Date.now(),
336
+ });
337
+
314
338
  pushWarning(warnings, GFI_PARTIAL_WARNING);
315
339
  if (sessionPeak === null && Number.isFinite(dailyGfiPeak)) {
316
340
  pushWarning(warnings, DAILY_GFI_WARNING);
@@ -343,13 +367,25 @@ export class RuntimeSummaryService {
343
367
  const gfiSources = this.buildGfiSources(events, selectedSessionId);
344
368
  const gateStats = this.buildGateStats(events, selectedSessionId, warnings);
345
369
 
346
- // D: Heartbeat Diagnostician chain — separate from evolution/nocturnal chain
347
- // Read pending tasks from the diagnostician task store
348
- const pendingDiagTasks = getPendingDiagnosticianTasks(wctx.stateDir);
370
+ // D: Runtime Diagnostician chain (M8) queries runtime-v2 SQLite task store
349
371
  // Read heartbeat diagnosis stats from daily event log
350
372
  const diagDailyStats = dailyStats?.[todayStr]?.evolution;
351
- const heartbeatDiagnosis = {
352
- pendingTasks: pendingDiagTasks.length,
373
+ let pendingRuntimeDiagTasks = 0;
374
+ try {
375
+ const taskStoreDbPath = path.join(wctx.stateDir, '.principles', 'db', 'task-store.db');
376
+ if (fs.existsSync(taskStoreDbPath)) {
377
+ const db = new Database(taskStoreDbPath, { readonly: true });
378
+ const row = db.prepare(`
379
+ SELECT COUNT(*) as count FROM tasks
380
+ WHERE task_kind = 'diagnostician' AND status = 'pending'
381
+ `).get() as { count: number };
382
+ pendingRuntimeDiagTasks = row?.count ?? 0;
383
+ db.close();
384
+ }
385
+ } catch { /* task store not yet initialized — 0 pending */ }
386
+ // TODO(PRI-XXX): distinguish "not initialized" from permission/corruption/query errors
387
+ const runtimeDiagnosis = {
388
+ pendingTasks: pendingRuntimeDiagTasks,
353
389
  tasksWrittenToday: diagDailyStats?.diagnosisTasksWritten ?? 0,
354
390
  reportsWrittenToday: diagDailyStats?.diagnosticianReportsWritten ?? 0,
355
391
  reportsMissingJsonToday: diagDailyStats?.reportsMissingJson ?? 0,
@@ -361,15 +397,15 @@ export class RuntimeSummaryService {
361
397
  // D: Stall detection — high-signal warning when the diagnostician loop appears broken.
362
398
  // Conditions: tasks are being injected (heartbeats > 0) but no reports are being written.
363
399
  if (
364
- heartbeatDiagnosis.heartbeatsInjectedToday > 0 &&
365
- heartbeatDiagnosis.reportsWrittenToday === 0 &&
366
- heartbeatDiagnosis.pendingTasks > 0
400
+ runtimeDiagnosis.heartbeatsInjectedToday > 0 &&
401
+ runtimeDiagnosis.reportsWrittenToday === 0 &&
402
+ runtimeDiagnosis.pendingTasks > 0
367
403
  ) {
368
404
  pushWarning(
369
405
  warnings,
370
406
  'Diagnostician appears stalled: heartbeats are injecting tasks ' +
371
- `(${heartbeatDiagnosis.heartbeatsInjectedToday}) but no reports are being written. ` +
372
- `${heartbeatDiagnosis.pendingTasks} task(s) remain pending. ` +
407
+ `(${runtimeDiagnosis.heartbeatsInjectedToday}) but no reports are being written. ` +
408
+ `${runtimeDiagnosis.pendingTasks} task(s) remain pending. ` +
373
409
  'Check prompt injection size limits and diagnostician task processing.'
374
410
  );
375
411
  }
@@ -422,6 +458,7 @@ export class RuntimeSummaryService {
422
458
  peak: gfiPeak,
423
459
  sources: gfiSources,
424
460
  dataQuality: 'partial',
461
+ workspaceSnapshot: gfiWorkspaceSnapshot,
425
462
  },
426
463
  evolution: {
427
464
  queue: queueStats,
@@ -451,8 +488,8 @@ export class RuntimeSummaryService {
451
488
  lastSignal: lastPainSignal,
452
489
  },
453
490
  gate: gateStats,
454
- // D: Heartbeat Diagnostician chain — separate from evolution/nocturnal
455
- heartbeatDiagnosis,
491
+ // D: Heartbeat Diagnostician chain
492
+ runtimeDiagnosis,
456
493
  ...(workflowFunnelsOutput && { workflowFunnels: workflowFunnelsOutput }),
457
494
  metadata: {
458
495
  generatedAt,
@@ -524,6 +561,12 @@ export class RuntimeSummaryService {
524
561
  sessionId: live.sessionId,
525
562
  currentGfi:
526
563
  Number.isFinite(live.currentGfi) ? Number(live.currentGfi) : persisted?.currentGfi,
564
+ gfiBySource:
565
+ live.gfiBySource ? { ...live.gfiBySource } : persisted?.gfiBySource,
566
+ lastErrorSource: live.lastErrorSource || persisted?.lastErrorSource,
567
+ consecutiveErrors:
568
+ Number.isFinite(live.consecutiveErrors) ? Number(live.consecutiveErrors) : persisted?.consecutiveErrors,
569
+ lastGfiDecayAt: live.lastGfiDecayAt || persisted?.lastGfiDecayAt,
527
570
  dailyGfiPeak:
528
571
  Number.isFinite(live.dailyGfiPeak) ? Number(live.dailyGfiPeak) : persisted?.dailyGfiPeak,
529
572
  lastActivityAt:
@@ -711,7 +754,7 @@ export class RuntimeSummaryService {
711
754
 
712
755
  return {
713
756
  source: `tool_failure:${String(entry.data?.toolName ?? 'unknown')}`,
714
- score: this.asFiniteNumber(entry.data?.gfi),
757
+ score: this.asFiniteNumber(entry.data?.gfiAfter ?? entry.data?.gfi),
715
758
  ts: entry.ts,
716
759
  };
717
760
  });
@@ -1,33 +1,7 @@
1
- export {
2
- RuntimeDirectDriver,
3
- type TransportDriver,
4
- type RunParams,
5
- type RunResult,
6
- type WaitParams,
7
- type WaitResult,
8
- type GetResultParams,
9
- type GetResultResult,
10
- type CleanupParams,
11
- } from './runtime-direct-driver.js';
12
-
13
1
  export { isExpectedSubagentError } from './subagent-error-utils.js';
14
2
 
15
3
  export { WorkflowStore, type WorkflowStoreOptions } from './workflow-store.js';
16
4
 
17
- export {
18
- EmpathyObserverWorkflowManager,
19
- createEmpathyObserverWorkflowManager,
20
- empathyObserverWorkflowSpec,
21
- type EmpathyObserverWorkflowOptions,
22
- } from './empathy-observer-workflow-manager.js';
23
-
24
- export {
25
- NocturnalWorkflowManager,
26
- nocturnalWorkflowSpec,
27
- type NocturnalWorkflowOptions,
28
- type NocturnalResult,
29
- } from './nocturnal-workflow-manager.js';
30
-
31
5
  export type {
32
6
  WorkflowState,
33
7
  WorkflowTransport,
@@ -36,23 +10,8 @@ export type {
36
10
  WorkflowPersistContext,
37
11
  WorkflowHandle,
38
12
  SubagentWorkflowSpec,
39
- EmpathyObserverWorkflowSpec,
40
- EmpathyObserverPayload,
41
- EmpathyResult,
42
13
  WorkflowRow,
43
14
  WorkflowEventRow,
44
15
  WorkflowDebugSummary,
45
16
  } from './types.js';
46
17
 
47
- export {
48
- CorrectionObserverWorkflowManager,
49
- createCorrectionObserverWorkflowManager,
50
- correctionObserverWorkflowSpec,
51
- type CorrectionObserverWorkflowOptions,
52
- } from './correction-observer-workflow-manager.js';
53
-
54
- export type {
55
- CorrectionObserverPayload,
56
- CorrectionObserverResult,
57
- CorrectionObserverWorkflowSpec,
58
- } from './correction-observer-types.js';