create-principles-disciple 1.93.0 → 1.94.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 (228) hide show
  1. package/console/dist/server/config/pd-config-store.d.ts +7 -1
  2. package/console/dist/server/config/pd-config-store.js +11 -1
  3. package/console/dist/server/index.js +10 -6
  4. package/console/dist/server/models/ApprovalsConsoleModel.js +4 -12
  5. package/console/dist/server/routes/feedback-reports.js +1 -1
  6. package/core/dist/index.d.ts +2 -2
  7. package/core/dist/index.d.ts.map +1 -1
  8. package/core/dist/index.js +1 -1
  9. package/core/dist/index.js.map +1 -1
  10. package/core/dist/prompt-builder/__tests__/model-config.test.d.ts +2 -0
  11. package/core/dist/prompt-builder/__tests__/model-config.test.d.ts.map +1 -0
  12. package/core/dist/prompt-builder/__tests__/model-config.test.js +158 -0
  13. package/core/dist/prompt-builder/__tests__/model-config.test.js.map +1 -0
  14. package/core/dist/prompt-builder/__tests__/xml-escape.test.d.ts +2 -0
  15. package/core/dist/prompt-builder/__tests__/xml-escape.test.d.ts.map +1 -0
  16. package/core/dist/prompt-builder/__tests__/xml-escape.test.js +42 -0
  17. package/core/dist/prompt-builder/__tests__/xml-escape.test.js.map +1 -0
  18. package/core/dist/prompt-builder/index.d.ts +3 -0
  19. package/core/dist/prompt-builder/index.d.ts.map +1 -1
  20. package/core/dist/prompt-builder/index.js +2 -0
  21. package/core/dist/prompt-builder/index.js.map +1 -1
  22. package/core/dist/prompt-builder/model-config.d.ts +42 -0
  23. package/core/dist/prompt-builder/model-config.d.ts.map +1 -0
  24. package/core/dist/prompt-builder/model-config.js +84 -0
  25. package/core/dist/prompt-builder/model-config.js.map +1 -0
  26. package/core/dist/prompt-builder/xml-escape.d.ts +12 -0
  27. package/core/dist/prompt-builder/xml-escape.d.ts.map +1 -0
  28. package/core/dist/prompt-builder/xml-escape.js +19 -0
  29. package/core/dist/prompt-builder/xml-escape.js.map +1 -0
  30. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +87 -16
  31. package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
  32. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.d.ts +2 -0
  33. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.d.ts.map +1 -0
  34. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js +395 -0
  35. package/core/dist/runtime-v2/__tests__/pain-signal-bridge-result-shaping.test.js.map +1 -0
  36. package/core/dist/runtime-v2/bridge-result-shaper.d.ts +53 -0
  37. package/core/dist/runtime-v2/bridge-result-shaper.d.ts.map +1 -0
  38. package/core/dist/runtime-v2/bridge-result-shaper.js +117 -0
  39. package/core/dist/runtime-v2/bridge-result-shaper.js.map +1 -0
  40. package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.d.ts +13 -0
  41. package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.d.ts.map +1 -0
  42. package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.js +111 -0
  43. package/core/dist/runtime-v2/detection/__tests__/detection-funnel-policy.test.js.map +1 -0
  44. package/core/dist/runtime-v2/detection/detection-funnel-policy.d.ts +103 -0
  45. package/core/dist/runtime-v2/detection/detection-funnel-policy.d.ts.map +1 -0
  46. package/core/dist/runtime-v2/detection/detection-funnel-policy.js +135 -0
  47. package/core/dist/runtime-v2/detection/detection-funnel-policy.js.map +1 -0
  48. package/core/dist/runtime-v2/detection/index.d.ts +10 -0
  49. package/core/dist/runtime-v2/detection/index.d.ts.map +1 -0
  50. package/core/dist/runtime-v2/detection/index.js +9 -0
  51. package/core/dist/runtime-v2/detection/index.js.map +1 -0
  52. package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.d.ts +12 -0
  53. package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.d.ts.map +1 -0
  54. package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js +181 -0
  55. package/core/dist/runtime-v2/evidence-triage/__tests__/observation-resolver.test.js.map +1 -0
  56. package/core/dist/runtime-v2/evidence-triage/__tests__/triage-policy.test.js +104 -1
  57. package/core/dist/runtime-v2/evidence-triage/__tests__/triage-policy.test.js.map +1 -1
  58. package/core/dist/runtime-v2/evidence-triage/index.d.ts +3 -0
  59. package/core/dist/runtime-v2/evidence-triage/index.d.ts.map +1 -1
  60. package/core/dist/runtime-v2/evidence-triage/index.js +3 -0
  61. package/core/dist/runtime-v2/evidence-triage/index.js.map +1 -1
  62. package/core/dist/runtime-v2/evidence-triage/observation-resolver.d.ts +128 -0
  63. package/core/dist/runtime-v2/evidence-triage/observation-resolver.d.ts.map +1 -0
  64. package/core/dist/runtime-v2/evidence-triage/observation-resolver.js +203 -0
  65. package/core/dist/runtime-v2/evidence-triage/observation-resolver.js.map +1 -0
  66. package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts +4 -0
  67. package/core/dist/runtime-v2/evidence-triage/triage-policy.d.ts.map +1 -1
  68. package/core/dist/runtime-v2/evidence-triage/triage-policy.js +66 -9
  69. package/core/dist/runtime-v2/evidence-triage/triage-policy.js.map +1 -1
  70. package/core/dist/runtime-v2/evidence-triage/types.d.ts +14 -0
  71. package/core/dist/runtime-v2/evidence-triage/types.d.ts.map +1 -1
  72. package/core/dist/runtime-v2/evidence-triage/types.js.map +1 -1
  73. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +33 -4
  74. package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
  75. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
  76. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +9 -2
  77. package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
  78. package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.d.ts +15 -0
  79. package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.d.ts.map +1 -0
  80. package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.js +450 -0
  81. package/core/dist/runtime-v2/feedback/__tests__/redact-sensitive.test.js.map +1 -0
  82. package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.d.ts +13 -0
  83. package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.d.ts.map +1 -0
  84. package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.js +243 -0
  85. package/core/dist/runtime-v2/feedback/__tests__/render-github-url.test.js.map +1 -0
  86. package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.d.ts +12 -0
  87. package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.d.ts.map +1 -0
  88. package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.js +172 -0
  89. package/core/dist/runtime-v2/feedback/__tests__/safe-stringify.test.js.map +1 -0
  90. package/core/dist/runtime-v2/index.d.ts +8 -4
  91. package/core/dist/runtime-v2/index.d.ts.map +1 -1
  92. package/core/dist/runtime-v2/index.js +4 -2
  93. package/core/dist/runtime-v2/index.js.map +1 -1
  94. package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.d.ts +2 -0
  95. package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.d.ts.map +1 -0
  96. package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.js +306 -0
  97. package/core/dist/runtime-v2/internalization/__tests__/c2-live-runner-chain.test.js.map +1 -0
  98. package/core/dist/runtime-v2/internalization/index.d.ts +0 -16
  99. package/core/dist/runtime-v2/internalization/index.d.ts.map +1 -1
  100. package/core/dist/runtime-v2/internalization/index.js +0 -8
  101. package/core/dist/runtime-v2/internalization/index.js.map +1 -1
  102. package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.d.ts +15 -0
  103. package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.d.ts.map +1 -0
  104. package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.js +179 -0
  105. package/core/dist/runtime-v2/pain-gate/__tests__/pain-diagnostic-gate-policy.test.js.map +1 -0
  106. package/core/dist/runtime-v2/pain-gate/index.d.ts +10 -0
  107. package/core/dist/runtime-v2/pain-gate/index.d.ts.map +1 -0
  108. package/core/dist/runtime-v2/pain-gate/index.js +9 -0
  109. package/core/dist/runtime-v2/pain-gate/index.js.map +1 -0
  110. package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.d.ts +121 -0
  111. package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.d.ts.map +1 -0
  112. package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.js +157 -0
  113. package/core/dist/runtime-v2/pain-gate/pain-diagnostic-gate-policy.js.map +1 -0
  114. package/core/dist/runtime-v2/pain-signal-bridge.d.ts.map +1 -1
  115. package/core/dist/runtime-v2/pain-signal-bridge.js +14 -88
  116. package/core/dist/runtime-v2/pain-signal-bridge.js.map +1 -1
  117. package/core/dist/runtime-v2/pain-signal-observability.d.ts.map +1 -1
  118. package/core/dist/runtime-v2/pain-signal-observability.js +15 -5
  119. package/core/dist/runtime-v2/pain-signal-observability.js.map +1 -1
  120. package/core/dist/runtime-v2/types/event-types.d.ts +0 -27
  121. package/core/dist/runtime-v2/types/event-types.d.ts.map +1 -1
  122. package/core/dist/runtime-v2/types/event-types.js +2 -17
  123. package/core/dist/runtime-v2/types/event-types.js.map +1 -1
  124. package/core/dist/runtime-v2/types/index.d.ts +2 -2
  125. package/core/dist/runtime-v2/types/index.d.ts.map +1 -1
  126. package/core/dist/runtime-v2/types/index.js +3 -1
  127. package/core/dist/runtime-v2/types/index.js.map +1 -1
  128. package/core/dist/runtime-v2/types/pain-signal.d.ts +2 -2
  129. package/core/dist/runtime-v2/types/pain-signal.js +2 -2
  130. package/dist/mvp-config.d.ts +0 -10
  131. package/dist/mvp-config.d.ts.map +1 -1
  132. package/dist/mvp-config.js +0 -65
  133. package/dist/mvp-config.js.map +1 -1
  134. package/package.json +1 -1
  135. package/pd-cli/dist/commands/mvp-smoke.js +1 -1
  136. package/pd-cli/dist/commands/mvp-smoke.js.map +1 -1
  137. package/pd-cli/dist/commands/rulecode.js +1 -1
  138. package/pd-cli/dist/commands/rulecode.js.map +1 -1
  139. package/pd-cli/dist/commands/runtime-canary.d.ts.map +1 -1
  140. package/pd-cli/dist/commands/runtime-canary.js +10 -11
  141. package/pd-cli/dist/commands/runtime-canary.js.map +1 -1
  142. package/pd-cli/dist/commands/runtime-internalization-queue.d.ts.map +1 -1
  143. package/pd-cli/dist/commands/runtime-internalization-queue.js +13 -16
  144. package/pd-cli/dist/commands/runtime-internalization-queue.js.map +1 -1
  145. package/pd-cli/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
  146. package/pd-cli/dist/commands/runtime-internalization-run-once.js +3 -0
  147. package/pd-cli/dist/commands/runtime-internalization-run-once.js.map +1 -1
  148. package/pd-cli/dist/commands/runtime-internalization-run-rulehost.d.ts.map +1 -1
  149. package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js +61 -7
  150. package/pd-cli/dist/commands/runtime-internalization-run-rulehost.js.map +1 -1
  151. package/pd-cli/dist/commands/runtime.js +1 -1
  152. package/pd-cli/dist/commands/runtime.js.map +1 -1
  153. package/pd-cli/dist/index.js +67 -34
  154. package/pd-cli/dist/index.js.map +1 -1
  155. package/pd-cli/dist/services/__tests__/rulehost-readiness.test.d.ts +2 -0
  156. package/pd-cli/dist/services/__tests__/rulehost-readiness.test.d.ts.map +1 -0
  157. package/pd-cli/dist/services/__tests__/rulehost-readiness.test.js +314 -0
  158. package/pd-cli/dist/services/__tests__/rulehost-readiness.test.js.map +1 -0
  159. package/pd-cli/dist/services/__tests__/runtime-adapter-resolver.test.js +20 -12
  160. package/pd-cli/dist/services/__tests__/runtime-adapter-resolver.test.js.map +1 -1
  161. package/pd-cli/dist/services/rulehost-readiness.d.ts +62 -0
  162. package/pd-cli/dist/services/rulehost-readiness.d.ts.map +1 -0
  163. package/pd-cli/dist/services/rulehost-readiness.js +214 -0
  164. package/pd-cli/dist/services/rulehost-readiness.js.map +1 -0
  165. package/pd-cli/dist/services/runtime-adapter-resolver.d.ts +1 -1
  166. package/pd-cli/dist/services/runtime-adapter-resolver.js +3 -3
  167. package/pd-cli/dist/services/runtime-adapter-resolver.js.map +1 -1
  168. package/plugin/dist/commands/evolution-status.js +0 -2
  169. package/plugin/dist/core/detection-funnel.d.ts +25 -11
  170. package/plugin/dist/core/detection-funnel.js +32 -80
  171. package/plugin/dist/core/event-log.d.ts +1 -3
  172. package/plugin/dist/core/event-log.js +10 -21
  173. package/plugin/dist/core/evolution-reducer.d.ts +0 -8
  174. package/plugin/dist/core/evolution-reducer.js +9 -19
  175. package/plugin/dist/core/pain-diagnostic-gate.d.ts +37 -28
  176. package/plugin/dist/core/pain-diagnostic-gate.js +53 -89
  177. package/plugin/dist/core/pain.d.ts +0 -63
  178. package/plugin/dist/core/pain.js +0 -167
  179. package/plugin/dist/core/paths.d.ts +0 -1
  180. package/plugin/dist/core/paths.js +2 -1
  181. package/plugin/dist/core/schema/migrations/001-init-trajectory.js +3 -6
  182. package/plugin/dist/core/schema/schema-definitions.js +4 -9
  183. package/plugin/dist/core/trajectory.d.ts +0 -16
  184. package/plugin/dist/core/trajectory.js +9 -60
  185. package/plugin/dist/hooks/after-tool-call-helpers.d.ts +4 -1
  186. package/plugin/dist/hooks/after-tool-call-helpers.js +13 -17
  187. package/plugin/dist/hooks/gate-block-helper.js +57 -17
  188. package/plugin/dist/hooks/lifecycle.js +3 -6
  189. package/plugin/dist/hooks/llm.js +66 -26
  190. package/plugin/dist/hooks/pain.d.ts +3 -1
  191. package/plugin/dist/hooks/pain.js +119 -49
  192. package/plugin/dist/hooks/prompt-helpers.d.ts +87 -0
  193. package/plugin/dist/hooks/prompt-helpers.js +251 -0
  194. package/plugin/dist/hooks/prompt-types.d.ts +66 -0
  195. package/plugin/dist/hooks/prompt-types.js +12 -0
  196. package/plugin/dist/hooks/prompt.d.ts +7 -38
  197. package/plugin/dist/hooks/prompt.js +361 -325
  198. package/plugin/dist/hooks/raw-observation-adapter.d.ts +9 -50
  199. package/plugin/dist/hooks/raw-observation-adapter.js +9 -164
  200. package/plugin/dist/hooks/raw-observation-types.d.ts +6 -57
  201. package/plugin/dist/hooks/raw-observation-types.js +5 -9
  202. package/plugin/dist/hooks/triage-adapter.js +6 -26
  203. package/plugin/dist/hooks/trigger-cooldown-tracker.d.ts +12 -0
  204. package/plugin/dist/hooks/trigger-cooldown-tracker.js +25 -0
  205. package/plugin/dist/service/evolution-worker.js +6 -64
  206. package/plugin/dist/service/runtime-summary-service.d.ts +0 -2
  207. package/plugin/dist/service/runtime-summary-service.js +0 -4
  208. package/plugin/dist/types/event-types.d.ts +1 -1
  209. package/plugin/scripts/sync-plugin.mjs +33 -22
  210. package/plugin/scripts/validate-live-path.ts +0 -18
  211. package/plugin/templates/langs/en/skills/pd-cli-operator/SKILL.md +20 -11
  212. package/plugin/templates/langs/en/skills/pd-runtime-v2/SKILL.md +10 -0
  213. package/plugin/templates/langs/zh/skills/pd-cli-operator/SKILL.md +20 -11
  214. package/plugin/templates/langs/zh/skills/pd-runtime-v2/SKILL.md +10 -0
  215. package/console/dist/server/config/feature-flags.d.ts +0 -25
  216. package/console/dist/server/config/feature-flags.js +0 -101
  217. package/pd-cli/dist/commands/central-sync.d.ts +0 -10
  218. package/pd-cli/dist/commands/central-sync.d.ts.map +0 -1
  219. package/pd-cli/dist/commands/central-sync.js +0 -32
  220. package/pd-cli/dist/commands/central-sync.js.map +0 -1
  221. package/pd-cli/dist/services/feature-flag-loader.d.ts +0 -6
  222. package/pd-cli/dist/services/feature-flag-loader.d.ts.map +0 -1
  223. package/pd-cli/dist/services/feature-flag-loader.js +0 -53
  224. package/pd-cli/dist/services/feature-flag-loader.js.map +0 -1
  225. package/plugin/dist/core/observability.d.ts +0 -40
  226. package/plugin/dist/core/observability.js +0 -164
  227. package/plugin/dist/hooks/subagent.d.ts +0 -9
  228. package/plugin/dist/hooks/subagent.js +0 -122
@@ -1,30 +1,35 @@
1
- declare const PAIN_DIAGNOSTIC_SOURCES: readonly ["manual", "tool_failure", "dispatch_error", "gate_blocked", "user_empathy", "llm_paralysis", "semantic", "subagent_error"];
2
- export type PainDiagnosticSource = typeof PAIN_DIAGNOSTIC_SOURCES[number];
3
- export type PainDiagnosticGateReason = 'manual' | 'high_gfi' | 'repeated_failure' | 'semantic_pain' | 'llm_paralysis' | 'risky_high_score' | 'subagent_error' | 'gate_blocked' | 'cooldown' | 'below_gate';
4
- export interface PainDiagnosticGateInput {
5
- source: PainDiagnosticSource | string;
6
- score: number;
7
- currentGfi: number;
8
- consecutiveErrors?: number;
9
- isRisky?: boolean;
10
- errorHash?: string;
11
- sessionId?: string;
12
- nowMs?: number;
13
- cooldownMs?: number;
14
- thresholds?: {
15
- painTrigger?: number;
16
- highSeverity?: number;
17
- highGfi?: number;
18
- repeatedFailure?: number;
19
- semanticPain?: number;
20
- };
21
- }
22
- export interface PainDiagnosticGateDecision {
23
- shouldDiagnose: boolean;
24
- reason: PainDiagnosticGateReason;
25
- episodeKey: string;
26
- detail: string;
27
- }
1
+ /**
2
+ * Pain Diagnostic Gate — PRI-446 thin adapter
3
+ *
4
+ * @deprecated PRI-454 — Gate A (PainDiagnosticGate) is superseded by Gate B
5
+ * (TriggerController + EvidenceTriage). This module remains as the rollback
6
+ * path when `painEvidenceAdmission` or `painEvidenceAdmissionDefault` flags
7
+ * are OFF. Do not add new callers. New admission logic must use
8
+ * `evaluateTriggerController` from runtime-v2/evidence-triage.
9
+ *
10
+ * Disposition: Archive (do not delete) per PRI-454 plan step 6.
11
+ * Removal conditions: Both flags confirmed ON in production for 30 days,
12
+ * and all 5 MVP paths verified on Gate B. See
13
+ * docs/plans/2026-06-pain-evidence-admission-track.md.
14
+ *
15
+ * The pure decision logic (threshold tree, cooldown comparison, episode-key
16
+ * construction) now lives in principles-core
17
+ * (runtime-v2/pain-gate/pain-diagnostic-gate-policy.ts). This file is the
18
+ * stateful adapter that owns:
19
+ * - the cooldown Map (lastDiagnosedAtByEpisode)
20
+ * - Date.now() injection
21
+ * - SystemLogger for unknown-source telemetry
22
+ *
23
+ * It preserves the original export names (evaluatePainDiagnosticGate,
24
+ * isCooldownActiveForEpisode, resetPainDiagnosticGateForTest) so all 5 callers
25
+ * (gate-block-helper, llm, pain, prompt x2) and the characterization test keep
26
+ * working unchanged.
27
+ *
28
+ * ERR checklist:
29
+ * - ERR-011: this is a stateful adapter delegating to core pure logic.
30
+ */
31
+ import { type PainDiagnosticSource, type PainDiagnosticGateReason, type PainDiagnosticGateInput, type PainDiagnosticGateDecision } from '@principles/core/runtime-v2';
32
+ export type { PainDiagnosticSource, PainDiagnosticGateReason, PainDiagnosticGateInput, PainDiagnosticGateDecision, };
28
33
  export declare function resetPainDiagnosticGateForTest(): void;
29
34
  /**
30
35
  * Check whether cooldown is currently active for a given episode.
@@ -32,5 +37,9 @@ export declare function resetPainDiagnosticGateForTest(): void;
32
37
  * with the PainDiagnosticGate's cooldown state.
33
38
  */
34
39
  export declare function isCooldownActiveForEpisode(source: string, sessionId: string | undefined, errorHash: string | undefined, cooldownMs?: number): boolean;
40
+ /**
41
+ * Evaluate the pain diagnostic gate. Delegates the pure decision to core and,
42
+ * when the decision is to diagnose, records the current time against the
43
+ * episode so subsequent calls within the cooldown window are suppressed.
44
+ */
35
45
  export declare function evaluatePainDiagnosticGate(input: PainDiagnosticGateInput): PainDiagnosticGateDecision;
36
- export {};
@@ -1,42 +1,37 @@
1
+ /**
2
+ * Pain Diagnostic Gate — PRI-446 thin adapter
3
+ *
4
+ * @deprecated PRI-454 — Gate A (PainDiagnosticGate) is superseded by Gate B
5
+ * (TriggerController + EvidenceTriage). This module remains as the rollback
6
+ * path when `painEvidenceAdmission` or `painEvidenceAdmissionDefault` flags
7
+ * are OFF. Do not add new callers. New admission logic must use
8
+ * `evaluateTriggerController` from runtime-v2/evidence-triage.
9
+ *
10
+ * Disposition: Archive (do not delete) per PRI-454 plan step 6.
11
+ * Removal conditions: Both flags confirmed ON in production for 30 days,
12
+ * and all 5 MVP paths verified on Gate B. See
13
+ * docs/plans/2026-06-pain-evidence-admission-track.md.
14
+ *
15
+ * The pure decision logic (threshold tree, cooldown comparison, episode-key
16
+ * construction) now lives in principles-core
17
+ * (runtime-v2/pain-gate/pain-diagnostic-gate-policy.ts). This file is the
18
+ * stateful adapter that owns:
19
+ * - the cooldown Map (lastDiagnosedAtByEpisode)
20
+ * - Date.now() injection
21
+ * - SystemLogger for unknown-source telemetry
22
+ *
23
+ * It preserves the original export names (evaluatePainDiagnosticGate,
24
+ * isCooldownActiveForEpisode, resetPainDiagnosticGateForTest) so all 5 callers
25
+ * (gate-block-helper, llm, pain, prompt x2) and the characterization test keep
26
+ * working unchanged.
27
+ *
28
+ * ERR checklist:
29
+ * - ERR-011: this is a stateful adapter delegating to core pure logic.
30
+ */
1
31
  import { SystemLogger } from './system-logger.js';
2
- const PAIN_DIAGNOSTIC_SOURCES = [
3
- 'manual',
4
- 'tool_failure',
5
- 'dispatch_error',
6
- 'gate_blocked',
7
- 'user_empathy',
8
- 'llm_paralysis',
9
- 'semantic',
10
- 'subagent_error',
11
- ];
12
- const DEFAULT_COOLDOWN_MS = 15 * 60 * 1000;
32
+ import { evaluatePainDiagnosticGateDecision, normalizedSource, buildEpisodeKey, isCooldownActive as isCooldownActiveCore, } from '@principles/core/runtime-v2';
33
+ // Module-level cooldown state — owned by this adapter (core is stateless).
13
34
  const lastDiagnosedAtByEpisode = new Map();
14
- function normalizedSource(source) {
15
- if (source.startsWith('llm_') && source !== 'llm_paralysis') {
16
- return 'semantic';
17
- }
18
- if (!PAIN_DIAGNOSTIC_SOURCES.includes(source)) {
19
- SystemLogger.log('', 'GATE_UNKNOWN_SOURCE', `Unknown pain source: "${source}"`);
20
- }
21
- return source;
22
- }
23
- function buildEpisodeKey(input) {
24
- const source = normalizedSource(input.source);
25
- const sessionId = input.sessionId || 'unknown';
26
- const hash = input.errorHash || 'no-hash';
27
- return `${sessionId}:${source}:${hash}`;
28
- }
29
- function withinCooldown(input, episodeKey) {
30
- const cooldownMs = input.cooldownMs ?? DEFAULT_COOLDOWN_MS;
31
- if (cooldownMs <= 0)
32
- return false;
33
- const nowMs = input.nowMs ?? Date.now();
34
- const last = lastDiagnosedAtByEpisode.get(episodeKey);
35
- return last !== undefined && nowMs - last < cooldownMs;
36
- }
37
- function markDiagnosed(input, episodeKey) {
38
- lastDiagnosedAtByEpisode.set(episodeKey, input.nowMs ?? Date.now());
39
- }
40
35
  export function resetPainDiagnosticGateForTest() {
41
36
  lastDiagnosedAtByEpisode.clear();
42
37
  }
@@ -46,60 +41,29 @@ export function resetPainDiagnosticGateForTest() {
46
41
  * with the PainDiagnosticGate's cooldown state.
47
42
  */
48
43
  export function isCooldownActiveForEpisode(source, sessionId, errorHash, cooldownMs) {
49
- const episodeKey = buildEpisodeKey({ source, sessionId, errorHash });
50
- return withinCooldown({ source, sessionId, errorHash, cooldownMs }, episodeKey);
44
+ const episodeKey = buildEpisodeKey({ source, sessionId, errorHash, score: 0, currentGfi: 0 });
45
+ const last = lastDiagnosedAtByEpisode.get(episodeKey);
46
+ const nowMs = Date.now();
47
+ return isCooldownActiveCore({ source, sessionId, errorHash, cooldownMs, nowMs, lastDiagnosedAtMs: last });
51
48
  }
49
+ /**
50
+ * Evaluate the pain diagnostic gate. Delegates the pure decision to core and,
51
+ * when the decision is to diagnose, records the current time against the
52
+ * episode so subsequent calls within the cooldown window are suppressed.
53
+ */
52
54
  export function evaluatePainDiagnosticGate(input) {
53
- const source = normalizedSource(input.source);
54
- const episodeKey = buildEpisodeKey(input);
55
- const painTrigger = input.thresholds?.painTrigger ?? 40;
56
- const highSeverity = input.thresholds?.highSeverity ?? 70;
57
- const highGfi = input.thresholds?.highGfi ?? Math.max(highSeverity, painTrigger + 30);
58
- const repeatedFailure = input.thresholds?.repeatedFailure ?? 4;
59
- const semanticPain = input.thresholds?.semanticPain ?? Math.max(painTrigger, 60);
60
- const score = Number.isFinite(input.score) ? input.score : 0;
61
- const currentGfi = Number.isFinite(input.currentGfi) ? input.currentGfi : 0;
62
- const consecutiveErrors = Number.isFinite(input.consecutiveErrors) ? input.consecutiveErrors : 0;
63
- const approve = (reason, detail) => {
64
- if (withinCooldown(input, episodeKey)) {
65
- return {
66
- shouldDiagnose: false,
67
- reason: 'cooldown',
68
- episodeKey,
69
- detail: `recently diagnosed; ${detail}`,
70
- };
71
- }
72
- markDiagnosed(input, episodeKey);
73
- return { shouldDiagnose: true, reason, episodeKey, detail };
74
- };
75
- if (source === 'manual') {
76
- return approve('manual', 'manual pain signal bypasses automatic gate');
77
- }
78
- if (source === 'subagent_error' && score >= painTrigger) {
79
- return approve('subagent_error', `subagent error score ${score} >= ${painTrigger}`);
80
- }
81
- if (source === 'llm_paralysis' && score >= painTrigger) {
82
- return approve('llm_paralysis', `llm paralysis score ${score} >= ${painTrigger}`);
83
- }
84
- if (source === 'gate_blocked' && score >= painTrigger) {
85
- return approve('gate_blocked', `gate blocked score ${score} >= ${painTrigger}`);
86
- }
87
- if ((source === 'user_empathy' || source === 'semantic') && score >= semanticPain) {
88
- return approve('semantic_pain', `semantic pain score ${score} >= ${semanticPain}`);
55
+ // Surface unknown sources via telemetry (core cannot log).
56
+ const { unknown } = normalizedSource(input.source);
57
+ if (unknown) {
58
+ SystemLogger.log('', 'GATE_UNKNOWN_SOURCE', `Unknown pain source: "${input.source}"`);
89
59
  }
90
- if (input.isRisky === true && score >= highSeverity) {
91
- return approve('risky_high_score', `risky operation score ${score} >= ${highSeverity}`);
92
- }
93
- if (consecutiveErrors >= repeatedFailure) {
94
- return approve('repeated_failure', `consecutive errors ${consecutiveErrors} >= ${repeatedFailure}`);
95
- }
96
- if (currentGfi >= highGfi) {
97
- return approve('high_gfi', `GFI ${currentGfi.toFixed(1)} >= ${highGfi}`);
60
+ const episodeKey = buildEpisodeKey(input);
61
+ const last = lastDiagnosedAtByEpisode.get(episodeKey);
62
+ const nowMs = input.nowMs ?? Date.now();
63
+ const decision = evaluatePainDiagnosticGateDecision({ ...input, nowMs }, last);
64
+ // Record the diagnosis time when approved (matches prior markDiagnosed behavior).
65
+ if (decision.shouldDiagnose) {
66
+ lastDiagnosedAtByEpisode.set(episodeKey, nowMs);
98
67
  }
99
- return {
100
- shouldDiagnose: false,
101
- reason: 'below_gate',
102
- episodeKey,
103
- detail: `score=${score}; gfi=${currentGfi.toFixed(1)}; consecutive=${consecutiveErrors}`,
104
- };
68
+ return decision;
105
69
  }
@@ -1,67 +1,4 @@
1
- /**
2
- * Required fields — every pain flag MUST have these.
3
- */
4
- export interface PainFlagData {
5
- /** What triggered this pain signal (e.g., tool_failure, human_intervention, intercept_extraction) */
6
- source: string;
7
- /** Pain score 0-100 */
8
- score: string;
9
- /** ISO 8601 timestamp */
10
- time: string;
11
- /** Human-readable reason / error description */
12
- reason: string;
13
- /** Session ID — identifies which conversation this happened in */
14
- session_id: string;
15
- /** Agent ID — identifies which agent (main, builder, diagnostician, etc.) */
16
- agent_id: string;
17
- /** Whether this involves risky operation ('true' / 'false') */
18
- is_risky: string;
19
- /** Correlation trace ID (for linking events across the pipeline) */
20
- trace_id: string;
21
- /** Preview of the text that triggered this pain */
22
- trigger_text_preview: string;
23
- /** Trajectory pain_events row ID (set by recordPainEvent) */
24
- pain_event_id?: string;
25
- }
26
- export interface PainFlagContractResult {
27
- status: 'missing' | 'valid' | 'invalid';
28
- format: 'missing' | 'empty' | 'kv' | 'json' | 'invalid_json';
29
- data: Record<string, string>;
30
- missingFields: string[];
31
- }
32
- /**
33
- * Builds legacy pain flag data for compatibility tests and historical readers.
34
- * Do not use this to create new Runtime V2 diagnosis requests.
35
- */
36
- export declare function buildPainFlag(input: {
37
- source: string;
38
- score: string;
39
- time?: string;
40
- reason: string;
41
- session_id?: string;
42
- agent_id?: string;
43
- is_risky?: boolean;
44
- trace_id?: string;
45
- trigger_text_preview?: string;
46
- pain_event_id?: string;
47
- }): PainFlagData;
48
- /**
49
- * Validates a pain flag read from disk.
50
- * Returns list of missing required fields — empty string means all present.
51
- */
52
- export declare function validatePainFlag(data: Record<string, string>): string[];
53
1
  export declare function computePainScore(rc: number, isSpiral: boolean, missingTestCommand: boolean, softScore: number, projectDir?: string): number;
54
- export declare function painSeverityLabel(painScore: number, isSpiral?: boolean, projectDir?: string): string;
55
- /**
56
- * Reads and validates the legacy pain flag file.
57
- *
58
- * - If file doesn't exist → returns {}
59
- * - If file is JSON format → converts to KV in memory only
60
- * - If file is KV format → validates required fields, logs warning if missing
61
- * - If file has unknown fields → silently ignores them (forward-compatible)
62
- */
63
- export declare function readPainFlagData(projectDir: string): Record<string, string>;
64
- export declare function readPainFlagContract(projectDir: string): PainFlagContractResult;
65
2
  /**
66
3
  * Track principle value metrics when a pain signal is written.
67
4
  * This is observation-only — it does NOT affect the pain flag write flow.
@@ -1,44 +1,5 @@
1
- import * as fs from 'fs';
2
- import { parseKvLines } from '../utils/io.js';
3
1
  import { resolvePdPath } from './paths.js';
4
2
  import { ConfigService } from './config-service.js';
5
- import { SystemLogger } from './system-logger.js';
6
- /**
7
- * Builds legacy pain flag data for compatibility tests and historical readers.
8
- * Do not use this to create new Runtime V2 diagnosis requests.
9
- */
10
- export function buildPainFlag(input) {
11
- // Omit optional fields when not provided — prevents writing empty lines to disk
12
- // which causes agent confusion (SKILL.md vs reality drift)
13
- return {
14
- source: input.source,
15
- score: input.score,
16
- time: input.time || new Date().toISOString(),
17
- reason: input.reason,
18
- session_id: input.session_id ?? '',
19
- agent_id: input.agent_id ?? '',
20
- is_risky: input.is_risky ? 'true' : 'false',
21
- trace_id: input.trace_id ?? '',
22
- trigger_text_preview: input.trigger_text_preview ?? '',
23
- pain_event_id: input.pain_event_id,
24
- };
25
- }
26
- /**
27
- * Validates a pain flag read from disk.
28
- * Returns list of missing required fields — empty string means all present.
29
- */
30
- export function validatePainFlag(data) {
31
- const missing = [];
32
- // Only source/score/time/reason are truly required — session_id/agent_id
33
- // may be empty in automated contexts (heartbeat, background workers)
34
- const required = ['source', 'score', 'time', 'reason'];
35
- for (const field of required) {
36
- if (!data[field] || data[field].trim() === '') {
37
- missing.push(field);
38
- }
39
- }
40
- return missing;
41
- }
42
3
  export function computePainScore(rc, isSpiral, missingTestCommand, softScore, projectDir) {
43
4
  let score = Math.max(0, softScore || 0);
44
5
  const stateDir = projectDir ? resolvePdPath(projectDir, 'STATE_DIR') : undefined;
@@ -59,134 +20,6 @@ export function computePainScore(rc, isSpiral, missingTestCommand, softScore, pr
59
20
  }
60
21
  return Math.min(100, score);
61
22
  }
62
- export function painSeverityLabel(painScore, isSpiral = false, projectDir) {
63
- if (isSpiral) {
64
- return "critical";
65
- }
66
- const stateDir = projectDir ? resolvePdPath(projectDir, 'STATE_DIR') : undefined;
67
- const config = stateDir ? ConfigService.get(stateDir) : null;
68
- const thresholds = config ? config.get('severity_thresholds') : {
69
- high: 70,
70
- medium: 40,
71
- low: 20
72
- };
73
- if (painScore >= thresholds.high) {
74
- return "high";
75
- }
76
- else if (painScore >= thresholds.medium) {
77
- return "medium";
78
- }
79
- else if (painScore >= thresholds.low) {
80
- return "low";
81
- }
82
- else {
83
- return "info";
84
- }
85
- }
86
- /**
87
- * Converts a JSON pain flag object to KV format.
88
- */
89
- function convertJsonToKv(json) {
90
- const kvData = {};
91
- const fieldMap = {
92
- source: 'source',
93
- score: 'score',
94
- time: 'time',
95
- timestamp: 'time',
96
- reason: 'reason',
97
- session_id: 'session_id',
98
- sessionId: 'session_id',
99
- agent_id: 'agent_id',
100
- agentId: 'agent_id',
101
- is_risky: 'is_risky',
102
- isRisky: 'is_risky',
103
- severity: 'severity',
104
- painId: 'pain_id',
105
- };
106
- for (const [jsonKey, kvKey] of Object.entries(fieldMap)) {
107
- if (json[jsonKey] !== undefined) {
108
- kvData[kvKey] = String(json[jsonKey]);
109
- }
110
- }
111
- for (const [key, value] of Object.entries(json)) {
112
- if (fieldMap[key] === undefined && value !== undefined && value !== null) {
113
- kvData[key] = String(value);
114
- }
115
- }
116
- return kvData;
117
- }
118
- /**
119
- * Reads and validates the legacy pain flag file.
120
- *
121
- * - If file doesn't exist → returns {}
122
- * - If file is JSON format → converts to KV in memory only
123
- * - If file is KV format → validates required fields, logs warning if missing
124
- * - If file has unknown fields → silently ignores them (forward-compatible)
125
- */
126
- export function readPainFlagData(projectDir) {
127
- const painFlagPath = resolvePdPath(projectDir, 'PAIN_FLAG');
128
- try {
129
- if (!fs.existsSync(painFlagPath)) {
130
- return {};
131
- }
132
- const content = fs.readFileSync(painFlagPath, "utf-8").trim();
133
- if (!content) {
134
- return {};
135
- }
136
- // Detect JSON format. Legacy compatibility only: parse in memory and do not
137
- // rewrite .pain_flag, because Runtime V2 must not create or repair this file.
138
- if (content.startsWith('{')) {
139
- let json;
140
- try {
141
- json = JSON.parse(content);
142
- }
143
- catch {
144
- SystemLogger.log(projectDir, 'PAIN_FLAG_CORRUPT', 'Pain flag file contains invalid JSON');
145
- return {};
146
- }
147
- const kvData = convertJsonToKv(json);
148
- SystemLogger.log(projectDir, 'PAIN_FLAG_LEGACY_JSON_READ', `Read legacy JSON pain flag in memory (${Object.keys(json).length} fields)`);
149
- return kvData;
150
- }
151
- // KV format — parse and validate
152
- const data = parseKvLines(content);
153
- const missing = validatePainFlag(data);
154
- if (missing.length > 0) {
155
- SystemLogger.log(projectDir, 'PAIN_FLAG_INCOMPLETE', `Pain flag missing required fields: ${missing.join(', ')}`);
156
- }
157
- return data;
158
- }
159
- catch (e) {
160
- SystemLogger.log(projectDir, 'PAIN_FLAG_READ_ERROR', `Failed to read pain flag: ${String(e)}`);
161
- return {};
162
- }
163
- }
164
- export function readPainFlagContract(projectDir) {
165
- const data = readPainFlagData(projectDir);
166
- if (Object.keys(data).length === 0) {
167
- const painFlagPath = resolvePdPath(projectDir, 'PAIN_FLAG');
168
- if (!fs.existsSync(painFlagPath)) {
169
- return { status: 'missing', format: 'missing', data: {}, missingFields: [] };
170
- }
171
- const raw = fs.readFileSync(painFlagPath, 'utf-8').trim();
172
- if (!raw) {
173
- return { status: 'missing', format: 'empty', data: {}, missingFields: [] };
174
- }
175
- return {
176
- status: 'invalid',
177
- format: raw.startsWith('{') ? 'invalid_json' : 'kv',
178
- data: {},
179
- missingFields: ['unparseable'],
180
- };
181
- }
182
- const missing = validatePainFlag(data);
183
- return {
184
- status: missing.length > 0 ? 'invalid' : 'valid',
185
- format: 'kv',
186
- data,
187
- missingFields: missing,
188
- };
189
- }
190
23
  /**
191
24
  * Track principle value metrics when a pain signal is written.
192
25
  * This is observation-only — it does NOT affect the pain flag write flow.
@@ -50,7 +50,6 @@ export declare const PD_FILES: {
50
50
  CURRENT_FOCUS: string;
51
51
  WEEK_STATE: string;
52
52
  THINKING_OS_CANDIDATES: string;
53
- SEMANTIC_PAIN: string;
54
53
  EVOLUTION_STREAM: string;
55
54
  EVOLUTION_LOCK: string;
56
55
  };
@@ -64,7 +64,8 @@ export const PD_FILES = {
64
64
  CURRENT_FOCUS: posixJoin(PD_DIRS.OKR, 'CURRENT_FOCUS.md'),
65
65
  WEEK_STATE: posixJoin(PD_DIRS.OKR, 'WEEK_STATE.json'),
66
66
  THINKING_OS_CANDIDATES: posixJoin(PD_DIRS.MEMORY, 'THINKING_OS_CANDIDATES.md'),
67
- SEMANTIC_PAIN: posixJoin(PD_DIRS.PAIN_SAMPLES, 'confusion_samples.md'),
67
+ // SEMANTIC_PAIN (confusion_samples.md) removed (PRI-451 Wave 1): the file
68
+ // had zero readers. The lifecycle write that populated it was also removed.
68
69
  EVOLUTION_STREAM: posixJoin(PD_DIRS.MEMORY, 'evolution.jsonl'),
69
70
  EVOLUTION_LOCK: posixJoin(PD_DIRS.LOCKS, 'evolution'),
70
71
  };
@@ -72,12 +72,9 @@ export const migration = {
72
72
  )`);
73
73
  db.exec(`CREATE INDEX IF NOT EXISTS idx_pain_events_session_id ON pain_events(session_id)`);
74
74
  db.exec(`CREATE INDEX IF NOT EXISTS idx_pain_events_created_at ON pain_events(created_at)`);
75
- // FTS5
76
- db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS pain_events_fts USING fts5(
77
- text,
78
- pain_event_id UNINDEXED,
79
- tokenize='porter unicode61'
80
- )`);
75
+ // pain_events_fts FTS5 virtual table removed (PRI-451 Wave 1): the only
76
+ // reader (searchPainEvents) was dead code. Existing DBs keep the orphan
77
+ // table harmlessly (CREATE was IF NOT EXISTS); new DBs simply don't create it.
81
78
  db.exec(`CREATE TABLE IF NOT EXISTS gate_blocks (
82
79
  id INTEGER PRIMARY KEY AUTOINCREMENT,
83
80
  session_id TEXT,
@@ -370,15 +370,10 @@ export const SCHEMAS = {
370
370
  FROM thinking_model_events GROUP BY date(created_at), model_id ORDER BY day ASC`,
371
371
  },
372
372
  },
373
- fts: {
374
- 'trajectory.pain_events_fts': {
375
- ddl: `CREATE VIRTUAL TABLE IF NOT EXISTS pain_events_fts USING fts5(
376
- text,
377
- pain_event_id UNINDEXED,
378
- tokenize='porter unicode61'
379
- )`,
380
- },
381
- },
373
+ // pain_events_fts FTS5 catalog entry removed (PRI-451 Wave 1): the only
374
+ // reader (searchPainEvents) was dead code. fts is now empty, matching the
375
+ // other DbType catalogs. Existing DBs keep the orphan table harmlessly.
376
+ fts: {},
382
377
  },
383
378
  // ========================================================================
384
379
  // central.db — Aggregated multi-workspace data
@@ -16,22 +16,6 @@ export declare class TrajectoryDatabase {
16
16
  recordUserTurn(input: TrajectoryUserTurnInput): number;
17
17
  recordToolCall(input: TrajectoryToolCallInput): number;
18
18
  recordPainEvent(input: TrajectoryPainEventInput): number;
19
- /**
20
- * Search pain_events using FTS5 full-text search (MEM-04).
21
- * Returns pain events matching the query, ordered by relevance.
22
- */
23
- searchPainEvents(query: string, limit?: number): {
24
- id: number;
25
- sessionId: string;
26
- source: string;
27
- score: number;
28
- reason: string | null;
29
- severity: string | null;
30
- origin: string | null;
31
- confidence: number | null;
32
- text: string | null;
33
- createdAt: string;
34
- }[];
35
19
  recordGateBlock(input: TrajectoryGateBlockInput): void;
36
20
  recordTrustChange(input: TrajectoryTrustChangeInput): void;
37
21
  recordPrincipleEvent(input: TrajectoryPrincipleEventInput): void;
@@ -170,60 +170,14 @@ export class TrajectoryDatabase {
170
170
  }
171
171
  }
172
172
  });
173
- // FTS indexing is best-effort — run outside the transaction so it cannot
174
- // roll back the committed pain event row (MEM-03, MEM-04).
175
- if (input.text && insertedId > 0) {
176
- try {
177
- this.db.prepare(`
178
- INSERT INTO pain_events_fts (text, pain_event_id) VALUES (?, ?)
179
- `).run(input.text, insertedId);
180
- }
181
- catch (err) {
182
- // Non-fatal: FTS index is for search convenience, not correctness.
183
- // Log but do not re-throw — the pain event itself is already committed.
184
- console.warn(`[trajectory] FTS index insert failed for pain_event ${insertedId}: ${String(err)}`);
185
- }
186
- }
173
+ // FTS5 index write removed (PRI-451 Wave 1): the only reader (searchPainEvents)
174
+ // was dead code removed in Wave 1.1. The pain event row itself is committed
175
+ // above; nothing reads the FTS index anymore.
187
176
  return insertedId;
188
177
  }
189
- /**
190
- * Search pain_events using FTS5 full-text search (MEM-04).
191
- * Returns pain events matching the query, ordered by relevance.
192
- */
193
- searchPainEvents(query, limit = 10) {
194
- if (!query || query.trim().length === 0) {
195
- return [];
196
- }
197
- // Escape FTS5 special characters and format query for porter tokenizer
198
- const ftsQuery = query.trim().split(/\s+/).map(term => `"${term.replace(/"/g, '""')}"`).join(' ');
199
- try {
200
- const results = this.db.prepare(`
201
- SELECT pe.*
202
- FROM pain_events_fts pf
203
- JOIN pain_events pe ON pe.id = pf.pain_event_id
204
- WHERE pain_events_fts MATCH ?
205
- ORDER BY bm25(pain_events_fts) DESC
206
- LIMIT ?
207
- `).all(ftsQuery, limit);
208
- return results.map(row => ({
209
- id: row.id,
210
- sessionId: row.session_id,
211
- source: row.source,
212
- score: row.score,
213
- reason: row.reason,
214
- severity: row.severity,
215
- origin: row.origin,
216
- confidence: row.confidence,
217
- text: row.text,
218
- createdAt: row.created_at,
219
- }));
220
- }
221
- catch (err) {
222
- // If FTS5 query fails (e.g., syntax error), return empty results
223
- console.warn(`[PD:TrajectoryDatabase] FTS5 search failed: ${String(err)}`);
224
- return [];
225
- }
226
- }
178
+ // searchPainEvents removed (PRI-451 Wave 1): dead code. Its only caller was
179
+ // processDetectionQueue (also removed). The FTS5 index write it read is
180
+ // removed in Wave 1.2.
227
181
  recordGateBlock(input) {
228
182
  this.withWrite(() => {
229
183
  this.db.prepare(`
@@ -1112,14 +1066,9 @@ export class TrajectoryDatabase {
1112
1066
  ON pain_events(canonical_pain_id)
1113
1067
  WHERE canonical_pain_id IS NOT NULL
1114
1068
  `);
1115
- // Create FTS5 virtual table for pain_events text search (MEM-04)
1116
- this.db.exec(`
1117
- CREATE VIRTUAL TABLE IF NOT EXISTS pain_events_fts USING fts5(
1118
- text,
1119
- pain_event_id UNINDEXED,
1120
- tokenize='porter unicode61'
1121
- )
1122
- `);
1069
+ // pain_events_fts FTS5 virtual table creation removed (PRI-451 Wave 1):
1070
+ // the only reader (searchPainEvents) was dead code. Existing DBs keep the
1071
+ // orphan table harmlessly (CREATE was IF NOT EXISTS); new DBs skip it.
1123
1072
  // V2 migration: Add V2 columns to evolution_tasks if they don't exist
1124
1073
  // SQLite does not support IF NOT EXISTS for ADD COLUMN, so we must check manually
1125
1074
  // before each ALTER to avoid "duplicate column name" errors on existing DBs
@@ -86,9 +86,12 @@ export declare function evaluatePainAdmissionForToolCall(event: PluginHookAfterT
86
86
  *
87
87
  * Only called when the admission decision is 'admitted'.
88
88
  */
89
- export declare function emitPainIfAdmitted(wctx: WorkspaceContext, event: PluginHookAfterToolCallEvent, observation: ToolCallObservation, outcome: ToolCallOutcome, admission: PainAdmissionDecision, sessionId: string, agentId: string | undefined, workspaceDir: string, emitPainDetectedEvent: (wctx: WorkspaceContext, event: import('../core/evolution-types.js').EvolutionLoopEvent) => Promise<void>): void;
89
+ export declare function emitPainIfAdmitted(wctx: WorkspaceContext, event: PluginHookAfterToolCallEvent, observation: ToolCallObservation, outcome: ToolCallOutcome, admission: PainAdmissionDecision, sessionId: string, agentId: string | undefined, workspaceDir: string, emitPainDetectedEvent: (wctx: WorkspaceContext, event: import('../core/evolution-types.js').EvolutionLoopEvent, options?: {
90
+ recordObservability?: boolean;
91
+ }) => Promise<void>): void;
90
92
  export { buildTrajectoryEvidence } from './trajectory-evidence.js';
91
93
  /**
92
94
  * Reset trigger cooldown state (for tests).
95
+ * PRI-454: Delegates to shared cooldown Map reset.
93
96
  */
94
97
  export declare function resetTriggerCooldownForTest(): void;