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
@@ -6,27 +6,28 @@ import {
6
6
  } from '../principle-tree-ledger.js';
7
7
  import type { PrincipleValueMetrics } from '../../types/principle-tree-schema.js';
8
8
  import { buildLifecycleReadModel, type LifecycleReadModel, type PrincipleLifecycleEvidence } from './lifecycle-read-model.js';
9
+ import { FilesystemLifecycleDatasource } from './filesystem-lifecycle-datasource.js';
9
10
  import {
10
11
  computePrincipleAdherence,
11
12
  computeRuleMetrics,
12
13
  type PrincipleAdherenceResult,
13
14
  type RuleMetricResult,
14
- } from './lifecycle-metrics.js';
15
+ } from '@principles/core/runtime-v2';
15
16
  import {
16
17
  assessDeprecatedReadiness,
17
18
  type DeprecatedReadinessAssessment,
18
- } from './deprecated-readiness.js';
19
+ } from '@principles/core/runtime-v2';
19
20
  import {
20
- recommendInternalizationRoute,
21
- type InternalizationRouteRecommendation,
22
- } from './internalization-routing-policy.js';
21
+ recommendLifecycleRoute,
22
+ type LifecycleRouteRecommendation,
23
+ } from '@principles/core/runtime-v2';
23
24
 
24
25
  export interface RecomputedPrincipleLifecycle {
25
26
  principleId: string;
26
27
  ruleMetrics: Record<string, RuleMetricResult>;
27
28
  adherence: PrincipleAdherenceResult;
28
29
  deprecatedReadiness: DeprecatedReadinessAssessment;
29
- routeRecommendation: InternalizationRouteRecommendation;
30
+ routeRecommendation: LifecycleRouteRecommendation;
30
31
  }
31
32
 
32
33
  export interface PrincipleLifecycleAssessment {
@@ -35,7 +36,7 @@ export interface PrincipleLifecycleAssessment {
35
36
  ruleMetrics: Record<string, RuleMetricResult>;
36
37
  adherence: PrincipleAdherenceResult;
37
38
  deprecatedReadiness: DeprecatedReadinessAssessment;
38
- routeRecommendation: InternalizationRouteRecommendation;
39
+ routeRecommendation: LifecycleRouteRecommendation;
39
40
  }
40
41
 
41
42
 
@@ -83,7 +84,8 @@ export class PrincipleLifecycleService {
83
84
  }
84
85
 
85
86
  buildReadModel(): LifecycleReadModel {
86
- return buildLifecycleReadModel(this.workspaceDir, this.stateDir);
87
+ const datasource = new FilesystemLifecycleDatasource(this.workspaceDir, this.stateDir);
88
+ return buildLifecycleReadModel(datasource);
87
89
  }
88
90
 
89
91
  listAssessments(readModel = this.buildReadModel()): PrincipleLifecycleAssessment[] {
@@ -100,7 +102,7 @@ export class PrincipleLifecycleService {
100
102
  ruleMetrics,
101
103
  adherence,
102
104
  );
103
- const routeRecommendation = recommendInternalizationRoute(
105
+ const routeRecommendation = recommendLifecycleRoute(
104
106
  principleEvidence,
105
107
  ruleMetrics,
106
108
  adherence,
@@ -117,7 +119,7 @@ export class PrincipleLifecycleService {
117
119
  });
118
120
  }
119
121
 
120
- listRouteRecommendations(readModel = this.buildReadModel()): InternalizationRouteRecommendation[] {
122
+ listRouteRecommendations(readModel = this.buildReadModel()): LifecycleRouteRecommendation[] {
121
123
  return this.listAssessments(readModel).map((assessment) => assessment.routeRecommendation);
122
124
  }
123
125
 
@@ -0,0 +1,145 @@
1
+ import { CandidateIntakeError, INTAKE_ERROR_CODES } from '@principles/core/runtime-v2';
2
+ import type { LedgerAdapter, LedgerPrincipleEntry } from '@principles/core/runtime-v2';
3
+ import { addPrincipleToLedger, loadLedger } from './principle-tree-ledger.js';
4
+ import type { LedgerPrinciple } from './principle-tree-ledger.js';
5
+
6
+ const VALID_EVALUABILITIES = ['deterministic', 'weak_heuristic', 'manual_only'] as const;
7
+
8
+ /**
9
+ * PrincipleTreeLedgerAdapter — bridges 11-field LedgerPrincipleEntry to 18+ field LedgerPrinciple.
10
+ *
11
+ * This adapter maintains an in-memory idempotency map. Create once and reuse
12
+ * across calls within the same process lifetime. Do not create a new instance
13
+ * per intake call.
14
+ */
15
+ export class PrincipleTreeLedgerAdapter implements LedgerAdapter {
16
+ #stateDir: string;
17
+ #entryMap = new Map<string, LedgerPrincipleEntry>();
18
+
19
+ constructor(opts: { stateDir: string }) {
20
+ this.#stateDir = opts.stateDir;
21
+ }
22
+
23
+ /**
24
+ * Write a probation entry to the ledger.
25
+ *
26
+ * Idempotency: if the same candidateId was already written, returns the
27
+ * existing entry without writing again.
28
+ *
29
+ * @throws CandidateIntakeError with code LEDGER_WRITE_FAILED on write failure.
30
+ */
31
+ writeProbationEntry(entry: LedgerPrincipleEntry): LedgerPrincipleEntry {
32
+ const candidateId = this.#extractCandidateId(entry.sourceRef);
33
+ const existing = this.#entryMap.get(candidateId);
34
+ if (existing) return existing;
35
+
36
+ const ledgerPrinciple = this.#expandToLedgerPrinciple(entry, candidateId);
37
+
38
+ try {
39
+ addPrincipleToLedger(this.#stateDir, ledgerPrinciple);
40
+ } catch (err) {
41
+ throw new CandidateIntakeError(
42
+ INTAKE_ERROR_CODES.LEDGER_WRITE_FAILED,
43
+ `Failed to write principle ${entry.id} to ledger: ${String(err)}`,
44
+ { cause: err },
45
+ );
46
+ }
47
+
48
+ this.#entryMap.set(candidateId, entry);
49
+ return entry;
50
+ }
51
+
52
+ /**
53
+ * Check if a ledger entry already exists for a given candidate.
54
+ *
55
+ * Queries both the in-memory Map (fast path for same-process repeat calls)
56
+ * and the ledger file (for cross-process idempotency across CLI invocations).
57
+ *
58
+ * @returns The existing LedgerPrincipleEntry if found, null otherwise.
59
+ */
60
+ existsForCandidate(candidateId: string): LedgerPrincipleEntry | null {
61
+ // Fast path: check in-memory Map (covers same-process repeat calls)
62
+ const cached = this.#entryMap.get(candidateId);
63
+ if (cached) return cached;
64
+
65
+ // Cross-process path: check ledger file by derivedFromPainIds
66
+ const ledger = loadLedger(this.#stateDir);
67
+ const found = Object.values(ledger.tree.principles).find((p) =>
68
+ p.derivedFromPainIds.includes(candidateId),
69
+ );
70
+ if (!found) return null;
71
+
72
+ // Reconstruct LedgerPrincipleEntry from LedgerPrinciple fields
73
+ // Note: sourceRef, artifactRef, taskRef are not stored in LedgerPrinciple,
74
+ // so we cannot fully reconstruct the original LedgerPrincipleEntry.
75
+ // Return minimal entry sufficient for idempotency signaling.
76
+ return {
77
+ id: found.id,
78
+ title: '',
79
+ status: 'probation' as const,
80
+ sourceRef: `candidate://${candidateId}`,
81
+ artifactRef: '',
82
+ taskRef: '',
83
+ text: found.text,
84
+ triggerPattern: found.triggerPattern,
85
+ action: found.action,
86
+ evaluability: 'weak_heuristic' as const,
87
+ createdAt: found.createdAt,
88
+ } as LedgerPrincipleEntry;
89
+ }
90
+
91
+ /**
92
+ * Extract candidateId from sourceRef by stripping the 'candidate://' prefix.
93
+ *
94
+ * @internal
95
+ */
96
+ #extractCandidateId(sourceRef: string): string {
97
+ if (sourceRef.startsWith('candidate://')) {
98
+ return sourceRef.slice('candidate://'.length);
99
+ }
100
+ return sourceRef;
101
+ }
102
+
103
+ /**
104
+ * Expand an 11-field LedgerPrincipleEntry to an 18+ field LedgerPrinciple.
105
+ *
106
+ * Applies the field expansion table from CONTEXT.md:
107
+ * - status: 'probation' → 'candidate'
108
+ * - triggerPattern/action: pass through (empty string if absent)
109
+ * - All defaults applied per CONTEXT.md expansion table
110
+ * - sourceRef/artifactRef/taskRef are NOT written to LedgerPrinciple (not stored)
111
+ * - title is NOT written to LedgerPrinciple — intentionally excluded; title
112
+ * is available in LedgerPrincipleEntry but LedgerPrinciple has no title field
113
+ *
114
+ * @internal
115
+ */
116
+ #expandToLedgerPrinciple(entry: LedgerPrincipleEntry, candidateId: string): LedgerPrinciple {
117
+ if (!VALID_EVALUABILITIES.includes(entry.evaluability as (typeof VALID_EVALUABILITIES)[number])) {
118
+ throw new CandidateIntakeError(
119
+ INTAKE_ERROR_CODES.INPUT_INVALID,
120
+ `Invalid evaluability value: ${entry.evaluability}. Must be one of: ${VALID_EVALUABILITIES.join(', ')}`,
121
+ );
122
+ }
123
+
124
+ const result: LedgerPrinciple = {
125
+ id: entry.id,
126
+ version: 1,
127
+ text: entry.text,
128
+ triggerPattern: entry.triggerPattern ?? '',
129
+ action: entry.action ?? '',
130
+ status: 'candidate',
131
+ evaluability: entry.evaluability,
132
+ priority: 'P1',
133
+ scope: 'general',
134
+ valueScore: 0,
135
+ adherenceRate: 0,
136
+ painPreventedCount: 0,
137
+ derivedFromPainIds: [candidateId],
138
+ ruleIds: [],
139
+ conflictsWithPrincipleIds: [],
140
+ createdAt: entry.createdAt,
141
+ updatedAt: entry.createdAt,
142
+ };
143
+ return result;
144
+ }
145
+ }
@@ -294,7 +294,11 @@ function readLedgerFromFile(filePath: string): HybridLedgerStore {
294
294
  }
295
295
 
296
296
  try {
297
- const parsed = JSON.parse(fs.readFileSync(filePath, 'utf-8')) as unknown;
297
+ const content = fs.readFileSync(filePath, 'utf-8');
298
+ if (!content || content.trim() === '') {
299
+ return { trainingStore: {}, tree: createEmptyTree() };
300
+ }
301
+ const parsed = JSON.parse(content) as unknown;
298
302
  const raw = isRecord(parsed) ? parsed : {};
299
303
  // #219: Handle both formats:
300
304
  // - New format: { trainingStore: {...}, tree: {...} }
@@ -305,11 +309,9 @@ function readLedgerFromFile(filePath: string): HybridLedgerStore {
305
309
  trainingStore: parseLegacyTrainingStore(trainingStoreRaw),
306
310
  tree: parseTree(treeRaw),
307
311
  };
308
- } catch {
309
- return {
310
- trainingStore: {},
311
- tree: createEmptyTree(),
312
- };
312
+ } catch (err) {
313
+ console.error(`[principle-tree-ledger] Failed to load ledger from ${filePath}: ${err instanceof Error ? err.message : String(err)}`);
314
+ return { trainingStore: {}, tree: createEmptyTree() };
313
315
  }
314
316
  }
315
317
 
@@ -1,62 +1,20 @@
1
- /**
2
- * ReflectionContextCollector — Unified Pipeline Input
3
- * ====================================================
4
- *
5
- * PURPOSE: Collect all grounding context for a principle into a single
6
- * ReflectionContext object. This is the input to the nocturnal reflection
7
- * pipeline: principle + painEvents + sessionSnapshot + lineage.
8
- *
9
- * DESIGN DECISIONS:
10
- * - If a principle has no derivedFromPainIds, collect() returns null
11
- * (nothing to ground code on).
12
- * - painId -> sessionId resolution is a known gap. For now, we attempt
13
- * best-effort lookup but return what we have with sessionSnapshot = null
14
- * if we can't resolve.
15
- *
16
- * REUSES:
17
- * - principle-tree-ledger: loadLedger() for principle lookup
18
- * - nocturnal-trajectory-extractor: for session snapshots
19
- * - trajectory: TrajectoryDatabase for pain event queries
20
- */
21
-
22
1
  import { loadLedger, type LedgerPrinciple } from '../principle-tree-ledger.js';
23
- import {
24
- NocturnalTrajectoryExtractor,
25
- type NocturnalPainEvent,
26
- type NocturnalSessionSnapshot,
27
- } from '../nocturnal-trajectory-extractor.js';
28
2
  import type { TrajectoryDatabase } from '../trajectory.js';
29
3
  import type { Principle } from '../../types/principle-tree-schema.js';
30
4
 
31
- // ---------------------------------------------------------------------------
32
- // Types
33
- // ---------------------------------------------------------------------------
34
-
35
- /**
36
- * Unified reflection context for the nocturnal pipeline.
37
- */
38
5
  export interface ReflectionContext {
39
- /** The principle being reflected upon */
40
6
  principle: Principle;
41
- /** Pain events associated with this principle (via derivedFromPainIds) */
42
- painEvents: NocturnalPainEvent[];
43
- /** Session snapshot if resolvable, null otherwise */
44
- sessionSnapshot: NocturnalSessionSnapshot | null;
45
- /** Lineage metadata connecting principle to source pain signals */
46
- lineage: {
47
- sourcePainIds: string[];
48
- sessionId: string | null;
49
- };
7
+ painEvents: Array<{ source: string; score: number; severity: string | null; reason: string | null; createdAt: string }>;
8
+ sessionSnapshot: {
9
+ toolCalls: Array<{
10
+ toolName: string;
11
+ outcome: string;
12
+ filePath: string | null;
13
+ errorType: string | null;
14
+ }>;
15
+ } | null;
50
16
  }
51
17
 
52
- // ---------------------------------------------------------------------------
53
- // Collector
54
- // ---------------------------------------------------------------------------
55
-
56
- /**
57
- * Collects ReflectionContext for principles by joining ledger data with
58
- * trajectory data.
59
- */
60
18
  export class ReflectionContextCollector {
61
19
  private readonly stateDir: string;
62
20
  private readonly trajectory: TrajectoryDatabase;
@@ -66,13 +24,6 @@ export class ReflectionContextCollector {
66
24
  this.trajectory = trajectory;
67
25
  }
68
26
 
69
- /**
70
- * Collect full reflection context for a single principle.
71
- *
72
- * Returns null if:
73
- * - The principle is not found in the ledger
74
- * - The principle has no derivedFromPainIds (nothing to ground on)
75
- */
76
27
  collect(principleId: string): ReflectionContext | null {
77
28
  const ledger = loadLedger(this.stateDir);
78
29
  const principle = ledger.tree.principles[principleId];
@@ -88,11 +39,6 @@ export class ReflectionContextCollector {
88
39
  return this.buildContext(principle);
89
40
  }
90
41
 
91
- /**
92
- * Collect reflection contexts for multiple principles, optionally filtered.
93
- *
94
- * Skips principles without derivedFromPainIds.
95
- */
96
42
  collectBatch(filter?: { status?: string }): ReflectionContext[] {
97
43
  const ledger = loadLedger(this.stateDir);
98
44
  const principles = Object.values(ledger.tree.principles);
@@ -100,12 +46,10 @@ export class ReflectionContextCollector {
100
46
  const results: ReflectionContext[] = [];
101
47
 
102
48
  for (const principle of principles) {
103
- // Apply status filter if provided
104
49
  if (filter?.status && principle.status !== filter.status) {
105
50
  continue;
106
51
  }
107
52
 
108
- // Skip principles without pain grounding
109
53
  if (!principle.derivedFromPainIds || principle.derivedFromPainIds.length === 0) {
110
54
  continue;
111
55
  }
@@ -119,62 +63,26 @@ export class ReflectionContextCollector {
119
63
  return results;
120
64
  }
121
65
 
122
- // -----------------------------------------------------------------------
123
- // Private helpers
124
- // -----------------------------------------------------------------------
125
-
126
- /**
127
- * Build a ReflectionContext from a principle.
128
- *
129
- * Attempts to resolve painIds to sessions via best-effort lookup.
130
- * Since painId -> sessionId mapping is a known gap, we may return
131
- * empty painEvents and null sessionSnapshot.
132
- */
133
66
  private buildContext(principle: LedgerPrinciple): ReflectionContext {
134
67
  const sourcePainIds = principle.derivedFromPainIds;
135
-
136
- // Best-effort: try to find a session containing pain events related to this principle.
137
- // The pain_events table uses auto-increment IDs, not the string painIds stored in
138
- // derivedFromPainIds. This is the known gap — for now we attempt session resolution
139
- // but gracefully handle the case where we can't match.
140
- const { painEvents, sessionId } = this.resolvePainEvents(sourcePainIds);
141
-
142
- // If we found a session, get the snapshot
143
- let sessionSnapshot: NocturnalSessionSnapshot | null = null;
144
- if (sessionId) {
145
- const extractor = new NocturnalTrajectoryExtractor(this.trajectory);
146
- sessionSnapshot = extractor.getNocturnalSessionSnapshot(sessionId);
147
- }
68
+ const { painEvents } = this.resolvePainEvents(sourcePainIds);
148
69
 
149
70
  return {
150
71
  principle,
151
72
  painEvents,
152
- sessionSnapshot,
153
- lineage: {
154
- sourcePainIds,
155
- sessionId,
156
- },
73
+ sessionSnapshot: null,
157
74
  };
158
75
  }
159
76
 
160
- /**
161
- * Attempt to resolve painIds to actual pain events and a session.
162
- *
163
- * Two-phase strategy:
164
- * 1. Exact ID match: sourcePainIds are stringified pain_events row IDs.
165
- * If any match String(pe.id) exactly, use those and stop.
166
- * 2. Heuristic fallback: substring match on reason/origin fields.
167
- * Only used when no exact matches are found.
168
- */
169
77
  private resolvePainEvents(sourcePainIds: string[]): {
170
- painEvents: NocturnalPainEvent[];
78
+ painEvents: Array<{ source: string; score: number; severity: string | null; reason: string | null; createdAt: string }>;
171
79
  sessionId: string | null;
172
80
  } {
173
81
  const sessions = this.trajectory.listRecentSessions({ limit: 100 });
174
82
  const sourcePainIdSet = new Set(sourcePainIds);
175
83
 
176
- const exactMatches: NocturnalPainEvent[] = [];
177
- const heuristicMatches: NocturnalPainEvent[] = [];
84
+ const exactMatches: Array<{ source: string; score: number; severity: string | null; reason: string | null; createdAt: string }> = [];
85
+ const heuristicMatches: Array<{ source: string; score: number; severity: string | null; reason: string | null; createdAt: string }> = [];
178
86
  let exactSessionId: string | null = null;
179
87
  let heuristicSessionId: string | null = null;
180
88
 
@@ -182,7 +90,6 @@ export class ReflectionContextCollector {
182
90
  const sessionPainEvents = this.trajectory.listPainEventsForSession(session.sessionId);
183
91
 
184
92
  for (const pe of sessionPainEvents) {
185
- // Phase 1: exact ID match
186
93
  if (sourcePainIdSet.has(String(pe.id))) {
187
94
  exactMatches.push({
188
95
  source: pe.source,
@@ -197,7 +104,6 @@ export class ReflectionContextCollector {
197
104
  continue;
198
105
  }
199
106
 
200
- // Phase 2: heuristic substring match on reason/origin only
201
107
  const peText = [pe.reason, pe.origin].filter(Boolean);
202
108
  const isMatch = sourcePainIds.some((painId) =>
203
109
  peText.some((field) => field?.includes(painId)),
@@ -218,7 +124,6 @@ export class ReflectionContextCollector {
218
124
  }
219
125
  }
220
126
 
221
- // Prefer exact matches over heuristic matches
222
127
  if (exactMatches.length > 0) {
223
128
  return { painEvents: exactMatches, sessionId: exactSessionId };
224
129
  }