principles-disciple 1.72.0 → 1.73.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 (309) hide show
  1. package/openclaw.plugin.json +10 -5
  2. package/package.json +17 -19
  3. package/scripts/acceptance-test.mjs +16 -73
  4. package/scripts/sync-plugin.mjs +382 -77
  5. package/src/commands/archive-impl.ts +2 -1
  6. package/src/commands/capabilities.ts +2 -2
  7. package/src/commands/context.ts +2 -2
  8. package/src/commands/disable-impl.ts +2 -1
  9. package/src/commands/evolution-status.ts +16 -16
  10. package/src/commands/export.ts +12 -67
  11. package/src/commands/pain.ts +91 -1
  12. package/src/commands/principle-rollback.ts +2 -1
  13. package/src/commands/promote-impl.ts +7 -43
  14. package/src/commands/rollback-impl.ts +2 -1
  15. package/src/commands/rollback.ts +2 -1
  16. package/src/commands/samples.ts +2 -1
  17. package/src/commands/thinking-os.ts +2 -1
  18. package/src/config/errors.ts +18 -2
  19. package/src/constants/diagnostician.ts +2 -2
  20. package/src/constants/tools.ts +2 -1
  21. package/src/core/__tests__/focus-history.test.ts +210 -0
  22. package/src/core/config.ts +1 -1
  23. package/src/core/confirm-first-gate.ts +255 -0
  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 +38 -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/pain-diagnostic-gate.ts +154 -0
  37. package/src/core/pain-signal.ts +21 -138
  38. package/src/core/pain.ts +15 -88
  39. package/src/core/pd-task-reconciler.ts +26 -115
  40. package/src/core/pd-task-service.ts +9 -9
  41. package/src/core/pd-task-types.ts +23 -127
  42. package/src/core/principle-compiler/__tests__/compiler-replay-gate.test.ts +174 -0
  43. package/src/core/principle-compiler/code-validator.ts +15 -42
  44. package/src/core/principle-compiler/compiler.ts +100 -15
  45. package/src/core/principle-compiler/index.ts +5 -2
  46. package/src/core/principle-compiler/template-generator.ts +4 -104
  47. package/src/core/principle-injection.ts +10 -202
  48. package/src/core/principle-internalization/filesystem-lifecycle-datasource.ts +42 -0
  49. package/src/core/principle-internalization/lifecycle-read-model.ts +39 -242
  50. package/src/core/principle-internalization/principle-lifecycle-service.ts +12 -10
  51. package/src/core/principle-tree-ledger-adapter.ts +145 -0
  52. package/src/core/principle-tree-ledger.ts +8 -6
  53. package/src/core/reflection/reflection-context.ts +14 -109
  54. package/src/core/replay-engine.ts +8 -500
  55. package/src/core/rule-host-helpers.ts +5 -35
  56. package/src/core/rule-host-types.ts +10 -82
  57. package/src/core/rule-host.ts +6 -63
  58. package/src/core/runtime-v2-prompt-activation-reader.ts +231 -0
  59. package/src/core/session-tracker.ts +87 -101
  60. package/src/core/shadow-observation-registry.ts +19 -48
  61. package/src/core/trajectory.ts +3 -1
  62. package/src/core/workflow-funnel-loader.ts +62 -68
  63. package/src/core/workspace-context.ts +46 -0
  64. package/src/core/workspace-dir-service.ts +1 -1
  65. package/src/core/workspace-dir-validation.ts +18 -9
  66. package/src/hooks/AGENTS.md +1 -1
  67. package/src/hooks/gate-block-helper.ts +46 -44
  68. package/src/hooks/gate.ts +207 -7
  69. package/src/hooks/lifecycle.ts +30 -32
  70. package/src/hooks/llm.ts +60 -32
  71. package/src/hooks/pain.ts +297 -103
  72. package/src/hooks/prompt.ts +459 -439
  73. package/src/hooks/subagent.ts +2 -29
  74. package/src/i18n/commands.ts +2 -10
  75. package/src/index.ts +95 -85
  76. package/src/openclaw-sdk.ts +311 -0
  77. package/src/service/central-database.ts +8 -4
  78. package/src/service/evolution-queue-migration.ts +2 -1
  79. package/src/service/evolution-worker.ts +163 -1786
  80. package/src/service/internalization-trigger-adapter.ts +302 -0
  81. package/src/service/keyword-optimization-service.ts +4 -4
  82. package/src/service/monitoring-query-service.ts +1 -215
  83. package/src/service/queue-io.ts +60 -331
  84. package/src/service/runtime-summary-service.ts +59 -16
  85. package/src/service/subagent-workflow/index.ts +0 -41
  86. package/src/service/subagent-workflow/types.ts +9 -120
  87. package/src/service/subagent-workflow/workflow-store.ts +2 -119
  88. package/src/service/workflow-watchdog.ts +0 -43
  89. package/src/types/event-payload.ts +16 -74
  90. package/src/types/event-types.ts +39 -547
  91. package/src/types/hygiene-types.ts +7 -30
  92. package/src/types/principle-tree-schema.ts +20 -222
  93. package/src/types/queue.ts +15 -70
  94. package/src/types/runtime-summary.ts +5 -49
  95. package/src/utils/io.ts +10 -0
  96. package/src/utils/retry.ts +1 -1
  97. package/src/utils/shadow-fingerprint.ts +2 -2
  98. package/src/utils/workspace-resolver.ts +50 -0
  99. package/templates/langs/en/core/AGENTS.md +2 -2
  100. package/templates/langs/en/core/BOOT.md +1 -1
  101. package/templates/langs/en/core/HEARTBEAT.md +2 -2
  102. package/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  103. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  104. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  105. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  106. package/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  107. package/templates/langs/en/skills/ai-sprint-orchestration/runtime/.gitignore +2 -2
  108. package/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  109. package/templates/langs/en/skills/evolve-task/SKILL.md +1 -1
  110. package/templates/langs/en/skills/pd-cli-operator/SKILL.md +67 -0
  111. package/templates/langs/en/skills/pd-diagnostician/SKILL.md +1 -1
  112. package/templates/langs/en/skills/pd-mentor/SKILL.md +1 -1
  113. package/templates/langs/en/skills/pd-pain-signal/SKILL.md +17 -39
  114. package/templates/langs/en/skills/pd-runtime-v2/SKILL.md +61 -0
  115. package/templates/langs/zh/core/AGENTS.md +2 -2
  116. package/templates/langs/zh/core/BOOT.md +1 -1
  117. package/templates/langs/zh/core/HEARTBEAT.md +2 -2
  118. package/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +1 -72
  119. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +6 -6
  120. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +6 -6
  121. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +8 -8
  122. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +2 -12
  123. package/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +2 -12
  124. package/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +2 -2
  125. package/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +51 -15
  126. package/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +21 -5
  127. package/templates/langs/zh/skills/evolve-task/SKILL.md +2 -2
  128. package/templates/langs/zh/skills/pd-cli-operator/SKILL.md +67 -0
  129. package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +1 -1
  130. package/templates/langs/zh/skills/pd-mentor/SKILL.md +1 -1
  131. package/templates/langs/zh/skills/pd-pain-signal/SKILL.md +17 -38
  132. package/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +61 -0
  133. package/tests/build-artifacts.test.ts +1 -3
  134. package/tests/commands/evolution-status.test.ts +0 -118
  135. package/tests/core/bootstrap-rules.test.ts +1 -1
  136. package/tests/core/config.test.ts +1 -1
  137. package/tests/core/event-log.test.ts +35 -0
  138. package/tests/core/evolution-engine.test.ts +610 -0
  139. package/tests/core/file-store.test.ts +102 -0
  140. package/tests/core/focus-history.test.ts +203 -11
  141. package/tests/core/merge-gate-audit.test.ts +2 -169
  142. package/tests/core/model-deployment-registry.test.ts +7 -1
  143. package/tests/core/model-training-registry.test.ts +19 -0
  144. package/tests/core/observability.test.ts +0 -1
  145. package/tests/core/pain-diagnostic-gate.test.ts +498 -0
  146. package/tests/core/pain.test.ts +0 -1
  147. package/tests/core/principle-internalization/deprecated-readiness.test.ts +2 -2
  148. package/tests/core/principle-internalization/lifecycle-metrics.test.ts +2 -2
  149. package/tests/core/principle-internalization/{internalization-routing-policy.test.ts → lifecycle-routing-policy.test.ts} +6 -6
  150. package/tests/core/principle-internalization/lineage-source-retired.test.ts +56 -0
  151. package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +1 -23
  152. package/tests/core/principle-tree-ledger-adapter.test.ts +253 -0
  153. package/tests/core/reflection-context.test.ts +0 -14
  154. package/tests/core/replay-engine.test.ts +127 -215
  155. package/tests/core/rule-host-helpers.test.ts +2 -2
  156. package/tests/core/rule-implementation-runtime.test.ts +0 -27
  157. package/tests/core/workflow-funnel-loader.test.ts +162 -0
  158. package/tests/core/workspace-dir-validation.test.ts +8 -1
  159. package/tests/core-anti-growth.test.ts +192 -0
  160. package/tests/hook-workspace-nextaction-contract.test.ts +42 -0
  161. package/tests/hooks/confirm-first-gate.test.ts +333 -0
  162. package/tests/hooks/gate-auto-correct-shadow.test.ts +310 -0
  163. package/tests/hooks/gate-auto-correct.test.ts +665 -0
  164. package/tests/hooks/gate-rule-host-pipeline.test.ts +2 -1
  165. package/tests/hooks/pain.test.ts +269 -12
  166. package/tests/hooks/prompt-characterization.test.ts +500 -0
  167. package/tests/hooks/prompt-size-guard.test.ts +32 -17
  168. package/tests/hooks/runtime-v2-prompt-activation.test.ts +869 -0
  169. package/tests/index.test.ts +94 -1
  170. package/tests/integration/auto-entry-gate.test.ts +248 -0
  171. package/tests/integration/internalization-trigger-guard.test.ts +69 -0
  172. package/tests/integration/m8-legacy-paths.test.ts +63 -0
  173. package/tests/integration/runtime-v2-pain-guard.test.ts +125 -0
  174. package/tests/plugin-config-resolution-cutover.test.ts +359 -0
  175. package/tests/runtime-v2-discovery-guard.test.ts +154 -0
  176. package/tests/service/central-database.test.ts +457 -0
  177. package/tests/service/evolution-worker.correction-observer.test.ts +173 -0
  178. package/tests/service/evolution-worker.timeout.test.ts +11 -129
  179. package/tests/service/internalization-trigger-adapter.test.ts +251 -0
  180. package/tests/service/monitoring-query-service.test.ts +1 -47
  181. package/tests/service/queue-io.test.ts +1 -62
  182. package/tests/service/runtime-summary-service.test.ts +3 -1
  183. package/tests/service/workflow-watchdog.test.ts +0 -91
  184. package/tests/utils/file-lock.test.ts +5 -3
  185. package/tests/utils/session-key.test.ts +52 -0
  186. package/tests/utils/subagent-probe.test.ts +48 -1
  187. package/vitest.config.ts +4 -11
  188. package/.planning/codebase/ARCHITECTURE.md +0 -157
  189. package/.planning/codebase/CONCERNS.md +0 -145
  190. package/.planning/codebase/CONVENTIONS.md +0 -148
  191. package/.planning/codebase/INTEGRATIONS.md +0 -81
  192. package/.planning/codebase/STACK.md +0 -87
  193. package/.planning/codebase/STRUCTURE.md +0 -193
  194. package/.planning/codebase/TESTING.md +0 -243
  195. package/.planning/phases/01-basic-visualization/01-GAP-CLOSURE-VERIFICATION.md +0 -113
  196. package/docs/COMMAND_REFERENCE.md +0 -76
  197. package/docs/COMMAND_REFERENCE_EN.md +0 -79
  198. package/scripts/build-web.mjs +0 -46
  199. package/scripts/diagnose-nocturnal.mjs +0 -537
  200. package/scripts/seed-nocturnal-scenarios.mjs +0 -384
  201. package/src/commands/nocturnal-review.ts +0 -322
  202. package/src/commands/nocturnal-rollout.ts +0 -790
  203. package/src/commands/nocturnal-train.ts +0 -986
  204. package/src/commands/pd-reflect.ts +0 -88
  205. package/src/core/adaptive-thresholds.ts +0 -478
  206. package/src/core/diagnostician-task-store.ts +0 -192
  207. package/src/core/nocturnal-arbiter.ts +0 -715
  208. package/src/core/nocturnal-artifact-lineage.ts +0 -116
  209. package/src/core/nocturnal-artificer.ts +0 -257
  210. package/src/core/nocturnal-candidate-scoring.ts +0 -530
  211. package/src/core/nocturnal-compliance.ts +0 -1146
  212. package/src/core/nocturnal-dataset.ts +0 -763
  213. package/src/core/nocturnal-executability.ts +0 -428
  214. package/src/core/nocturnal-export.ts +0 -499
  215. package/src/core/nocturnal-paths.ts +0 -240
  216. package/src/core/nocturnal-reasoning-deriver.ts +0 -343
  217. package/src/core/nocturnal-rule-implementation-validator.ts +0 -246
  218. package/src/core/nocturnal-snapshot-contract.ts +0 -99
  219. package/src/core/nocturnal-trajectory-extractor.ts +0 -512
  220. package/src/core/nocturnal-trinity-types.ts +0 -218
  221. package/src/core/nocturnal-trinity.ts +0 -2680
  222. package/src/core/principle-internalization/deprecated-readiness.ts +0 -93
  223. package/src/core/principle-internalization/internalization-routing-policy.ts +0 -208
  224. package/src/core/principle-internalization/lifecycle-metrics.ts +0 -152
  225. package/src/http/principles-console-route.ts +0 -709
  226. package/src/service/central-health-service.ts +0 -49
  227. package/src/service/central-overview-service.ts +0 -138
  228. package/src/service/control-ui-query-service.ts +0 -900
  229. package/src/service/cooldown-strategy.ts +0 -97
  230. package/src/service/evolution-pain-context.ts +0 -79
  231. package/src/service/evolution-query-service.ts +0 -407
  232. package/src/service/health-query-service.ts +0 -1038
  233. package/src/service/nocturnal-config.ts +0 -214
  234. package/src/service/nocturnal-runtime.ts +0 -734
  235. package/src/service/nocturnal-service.ts +0 -1605
  236. package/src/service/nocturnal-target-selector.ts +0 -545
  237. package/src/service/sleep-cycle.ts +0 -157
  238. package/src/service/startup-reconciler.ts +0 -112
  239. package/src/service/subagent-workflow/correction-observer-types.ts +0 -82
  240. package/src/service/subagent-workflow/correction-observer-workflow-manager.ts +0 -250
  241. package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +0 -1
  242. package/src/service/subagent-workflow/dynamic-timeout.ts +0 -30
  243. package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +0 -268
  244. package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +0 -795
  245. package/src/service/subagent-workflow/runtime-direct-driver.ts +0 -268
  246. package/src/service/subagent-workflow/workflow-manager-base.ts +0 -580
  247. package/src/tools/write-pain-flag.ts +0 -215
  248. package/tests/commands/nocturnal-review.test.ts +0 -448
  249. package/tests/commands/nocturnal-train.test.ts +0 -97
  250. package/tests/commands/pd-reflect.test.ts +0 -49
  251. package/tests/core/adaptive-thresholds.test.ts +0 -261
  252. package/tests/core/nocturnal-arbiter.test.ts +0 -559
  253. package/tests/core/nocturnal-artifact-lineage.test.ts +0 -53
  254. package/tests/core/nocturnal-artificer.test.ts +0 -241
  255. package/tests/core/nocturnal-candidate-scoring.test.ts +0 -532
  256. package/tests/core/nocturnal-compliance-p-principles.test.ts +0 -133
  257. package/tests/core/nocturnal-compliance.test.ts +0 -646
  258. package/tests/core/nocturnal-dataset.test.ts +0 -892
  259. package/tests/core/nocturnal-e2e.test.ts +0 -234
  260. package/tests/core/nocturnal-executability.test.ts +0 -357
  261. package/tests/core/nocturnal-export.test.ts +0 -517
  262. package/tests/core/nocturnal-reasoning-deriver.test.ts +0 -372
  263. package/tests/core/nocturnal-reviewed-subset-comparison.test.ts +0 -428
  264. package/tests/core/nocturnal-rule-implementation-validator.test.ts +0 -127
  265. package/tests/core/nocturnal-snapshot-contract.test.ts +0 -121
  266. package/tests/core/nocturnal-trajectory-extractor.test.ts +0 -634
  267. package/tests/core/nocturnal-trinity.test.ts +0 -2053
  268. package/tests/core/pain-auto-repair.test.ts +0 -96
  269. package/tests/core/pain-integration.test.ts +0 -510
  270. package/tests/fixtures/nocturnal-reviewed-subset.json +0 -183
  271. package/tests/http/principles-console-route.test.ts +0 -162
  272. package/tests/integration/chaos-resilience.test.ts +0 -348
  273. package/tests/integration/empathy-workflow-integration.test.ts +0 -626
  274. package/tests/integration/pain-diagnostician-loop.e2e.test.ts +0 -380
  275. package/tests/service/control-ui-query-service.test.ts +0 -121
  276. package/tests/service/cooldown-strategy.test.ts +0 -164
  277. package/tests/service/data-endpoints-regression.test.ts +0 -834
  278. package/tests/service/empathy-observer-workflow-manager.test.ts +0 -175
  279. package/tests/service/evolution-worker.nocturnal.test.ts +0 -601
  280. package/tests/service/nocturnal-runtime-hardening.test.ts +0 -118
  281. package/tests/service/nocturnal-runtime.test.ts +0 -473
  282. package/tests/service/nocturnal-service-code-candidate.test.ts +0 -330
  283. package/tests/service/nocturnal-target-selector.test.ts +0 -615
  284. package/tests/service/startup-reconciler.test.ts +0 -148
  285. package/tests/tools/write-pain-flag.test.ts +0 -358
  286. package/ui/src/App.tsx +0 -45
  287. package/ui/src/api.ts +0 -220
  288. package/ui/src/charts.tsx +0 -955
  289. package/ui/src/components/ErrorState.tsx +0 -6
  290. package/ui/src/components/Loading.tsx +0 -13
  291. package/ui/src/components/ProtectedRoute.tsx +0 -12
  292. package/ui/src/components/Shell.tsx +0 -91
  293. package/ui/src/components/WorkspaceConfig.tsx +0 -178
  294. package/ui/src/components/index.ts +0 -5
  295. package/ui/src/context/auth.tsx +0 -80
  296. package/ui/src/context/theme.tsx +0 -66
  297. package/ui/src/hooks/useAutoRefresh.ts +0 -39
  298. package/ui/src/i18n/ui.ts +0 -473
  299. package/ui/src/main.tsx +0 -16
  300. package/ui/src/pages/EvolutionPage.tsx +0 -333
  301. package/ui/src/pages/FeedbackPage.tsx +0 -138
  302. package/ui/src/pages/GateMonitorPage.tsx +0 -136
  303. package/ui/src/pages/LoginPage.tsx +0 -89
  304. package/ui/src/pages/OverviewPage.tsx +0 -599
  305. package/ui/src/pages/SamplesPage.tsx +0 -174
  306. package/ui/src/pages/ThinkingModelsPage.tsx +0 -702
  307. package/ui/src/styles.css +0 -2020
  308. package/ui/src/types.ts +0 -384
  309. 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';