openclaw-hybrid-memory 2026.5.310 → 2026.6.10

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 (535) hide show
  1. package/api/plugin-runtime.ts +2 -0
  2. package/backends/facts-db/contradictions.ts +1 -1
  3. package/cli/cmd-extract-directives.ts +225 -11
  4. package/cli/cmd-extract-proposals.ts +5 -6
  5. package/cli/cmd-extract-reinforcement.ts +71 -0
  6. package/cli/cmd-feedback.ts +15 -9
  7. package/cli/commands/manage/register-reflection-pipeline.ts +247 -13
  8. package/cli/commands/manage/register-storage-maintenance.ts +224 -15
  9. package/cli/commands/manage/storage-stats-helpers.ts +13 -2
  10. package/cli/context.ts +9 -19
  11. package/cli/distill.ts +31 -1
  12. package/cli/register.ts +28 -38
  13. package/dist/api/plugin-runtime.js.map +1 -1
  14. package/dist/backends/agent-health-store.js.map +1 -1
  15. package/dist/backends/apitap-store.js.map +1 -1
  16. package/dist/backends/audit-store.js.map +1 -1
  17. package/dist/backends/base-sqlite-store.js.map +1 -1
  18. package/dist/backends/cost-tracker.js.map +1 -1
  19. package/dist/backends/credentials-db.js +2 -3
  20. package/dist/backends/credentials-db.js.map +1 -1
  21. package/dist/backends/crystallization-store.js.map +1 -1
  22. package/dist/backends/edict-store.js.map +1 -1
  23. package/dist/backends/event-bus.js.map +1 -1
  24. package/dist/backends/event-log.js.map +1 -1
  25. package/dist/backends/facts-db/cache-manager.js.map +1 -1
  26. package/dist/backends/facts-db/clusters.js.map +1 -1
  27. package/dist/backends/facts-db/contradictions.js +1 -1
  28. package/dist/backends/facts-db/contradictions.js.map +1 -1
  29. package/dist/backends/facts-db/crud.js.map +1 -1
  30. package/dist/backends/facts-db/db-connection.js.map +1 -1
  31. package/dist/backends/facts-db/entity-autolink.js.map +1 -1
  32. package/dist/backends/facts-db/entity-layer.js.map +1 -1
  33. package/dist/backends/facts-db/episodes.js.map +1 -1
  34. package/dist/backends/facts-db/fact-queries.js.map +1 -1
  35. package/dist/backends/facts-db/fact-read-queries.js.map +1 -1
  36. package/dist/backends/facts-db/facts-db-layer1.js.map +1 -1
  37. package/dist/backends/facts-db/facts-db-layer2.js.map +1 -1
  38. package/dist/backends/facts-db/facts-db-layer3.js.map +1 -1
  39. package/dist/backends/facts-db/fts-text.js.map +1 -1
  40. package/dist/backends/facts-db/generated-skills/policy.js.map +1 -1
  41. package/dist/backends/facts-db/generated-skills.js.map +1 -1
  42. package/dist/backends/facts-db/housekeeping.js.map +1 -1
  43. package/dist/backends/facts-db/links.js.map +1 -1
  44. package/dist/backends/facts-db/maintenance.js.map +1 -1
  45. package/dist/backends/facts-db/procedures/crud.js.map +1 -1
  46. package/dist/backends/facts-db/procedures/internal.js.map +1 -1
  47. package/dist/backends/facts-db/procedures/promotion.js.map +1 -1
  48. package/dist/backends/facts-db/procedures/search.js.map +1 -1
  49. package/dist/backends/facts-db/procedures/stats.js.map +1 -1
  50. package/dist/backends/facts-db/reinforcement.js.map +1 -1
  51. package/dist/backends/facts-db/row-mapper.js.map +1 -1
  52. package/dist/backends/facts-db/scan-cursors.js.map +1 -1
  53. package/dist/backends/facts-db/schema-bootstrap.js.map +1 -1
  54. package/dist/backends/facts-db/scope-sql.js.map +1 -1
  55. package/dist/backends/facts-db/search.js.map +1 -1
  56. package/dist/backends/facts-db/stats.js.map +1 -1
  57. package/dist/backends/facts-db/types.js.map +1 -1
  58. package/dist/backends/facts-db/variants.js.map +1 -1
  59. package/dist/backends/identity-reflection-store.js.map +1 -1
  60. package/dist/backends/issue-store.js.map +1 -1
  61. package/dist/backends/learnings-db.js.map +1 -1
  62. package/dist/backends/migrations/facts-migrations.js.map +1 -1
  63. package/dist/backends/migrations/procedures.js.map +1 -1
  64. package/dist/backends/narratives-db.js.map +1 -1
  65. package/dist/backends/persona-state-store.js.map +1 -1
  66. package/dist/backends/proposals-db.js.map +1 -1
  67. package/dist/backends/scope-filter-sql.js.map +1 -1
  68. package/dist/backends/sqlite-schema-meta.js.map +1 -1
  69. package/dist/backends/tool-proposal-store.js.map +1 -1
  70. package/dist/backends/vector-db/constants.js.map +1 -1
  71. package/dist/backends/vector-db/path-utils.js.map +1 -1
  72. package/dist/backends/vector-db/runtime-locks.js.map +1 -1
  73. package/dist/backends/vector-db/vector-db-class.js.map +1 -1
  74. package/dist/backends/wal.js.map +1 -1
  75. package/dist/backends/workflow-store.js.map +1 -1
  76. package/dist/benchmark/shadow-eval.js.map +1 -1
  77. package/dist/cli/active-tasks.js.map +1 -1
  78. package/dist/cli/backup.js.map +1 -1
  79. package/dist/cli/benchmark.js.map +1 -1
  80. package/dist/cli/cmd-backfill.js.map +1 -1
  81. package/dist/cli/cmd-config.js.map +1 -1
  82. package/dist/cli/cmd-credentials.js.map +1 -1
  83. package/dist/cli/cmd-demo.js.map +1 -1
  84. package/dist/cli/cmd-distill.js.map +1 -1
  85. package/dist/cli/cmd-doctor.js.map +1 -1
  86. package/dist/cli/cmd-examples.js.map +1 -1
  87. package/dist/cli/cmd-extract-daily.js.map +1 -1
  88. package/dist/cli/cmd-extract-directives.js +141 -10
  89. package/dist/cli/cmd-extract-directives.js.map +1 -1
  90. package/dist/cli/cmd-extract-procedures.js.map +1 -1
  91. package/dist/cli/cmd-extract-proposals.js +3 -2
  92. package/dist/cli/cmd-extract-proposals.js.map +1 -1
  93. package/dist/cli/cmd-extract-reinforcement.js +39 -0
  94. package/dist/cli/cmd-extract-reinforcement.js.map +1 -1
  95. package/dist/cli/cmd-extract-sessions.js.map +1 -1
  96. package/dist/cli/cmd-feedback.js +9 -4
  97. package/dist/cli/cmd-feedback.js.map +1 -1
  98. package/dist/cli/cmd-health.js.map +1 -1
  99. package/dist/cli/cmd-providers.js.map +1 -1
  100. package/dist/cli/cmd-selfcorrection.js.map +1 -1
  101. package/dist/cli/cmd-setup.js.map +1 -1
  102. package/dist/cli/cmd-status.js.map +1 -1
  103. package/dist/cli/cmd-store.js.map +1 -1
  104. package/dist/cli/cmd-user-friendly.js.map +1 -1
  105. package/dist/cli/cmd-verify.js.map +1 -1
  106. package/dist/cli/commands/manage/bindings.js.map +1 -1
  107. package/dist/cli/commands/manage/dream-cycle-followup.js.map +1 -1
  108. package/dist/cli/commands/manage/maintenance-heartbeat.js.map +1 -1
  109. package/dist/cli/commands/manage/register-agents-audit-runall.js.map +1 -1
  110. package/dist/cli/commands/manage/register-analyze-maintenance-logs.js.map +1 -1
  111. package/dist/cli/commands/manage/register-budget-proposals.js.map +1 -1
  112. package/dist/cli/commands/manage/register-config-cli.js.map +1 -1
  113. package/dist/cli/commands/manage/register-corrections-and-pipeline.js.map +1 -1
  114. package/dist/cli/commands/manage/register-corrections.js.map +1 -1
  115. package/dist/cli/commands/manage/register-council.js.map +1 -1
  116. package/dist/cli/commands/manage/register-credentials-scope.js.map +1 -1
  117. package/dist/cli/commands/manage/register-digest.js.map +1 -1
  118. package/dist/cli/commands/manage/register-lifecycle.js.map +1 -1
  119. package/dist/cli/commands/manage/register-procedure-lifecycle.js.map +1 -1
  120. package/dist/cli/commands/manage/register-reconcile-cron-ledgers.js.map +1 -1
  121. package/dist/cli/commands/manage/register-reflection-pipeline.js +144 -7
  122. package/dist/cli/commands/manage/register-reflection-pipeline.js.map +1 -1
  123. package/dist/cli/commands/manage/register-self-correction-feedback.js.map +1 -1
  124. package/dist/cli/commands/manage/register-storage-and-stats.js.map +1 -1
  125. package/dist/cli/commands/manage/register-storage-entities-decay.js.map +1 -1
  126. package/dist/cli/commands/manage/register-storage-graph-audit.js.map +1 -1
  127. package/dist/cli/commands/manage/register-storage-maintenance.js +152 -9
  128. package/dist/cli/commands/manage/register-storage-maintenance.js.map +1 -1
  129. package/dist/cli/commands/manage/register-validate-cron-exit.js.map +1 -1
  130. package/dist/cli/commands/manage/storage-stats-helpers.js +10 -3
  131. package/dist/cli/commands/manage/storage-stats-helpers.js.map +1 -1
  132. package/dist/cli/commands/register-manage-commands.js.map +1 -1
  133. package/dist/cli/config-feature-summaries.js.map +1 -1
  134. package/dist/cli/config-output-sink.js.map +1 -1
  135. package/dist/cli/distill-session-jsonl.js.map +1 -1
  136. package/dist/cli/distill.js +10 -1
  137. package/dist/cli/distill.js.map +1 -1
  138. package/dist/cli/global-verbose.js.map +1 -1
  139. package/dist/cli/goals.js.map +1 -1
  140. package/dist/cli/hybrid-mem-commander-utils.js.map +1 -1
  141. package/dist/cli/install/config-merge.js.map +1 -1
  142. package/dist/cli/install/cron-jobs.js.map +1 -1
  143. package/dist/cli/install/embedding-detect.js.map +1 -1
  144. package/dist/cli/install/run-install.js.map +1 -1
  145. package/dist/cli/install/workspace.js.map +1 -1
  146. package/dist/cli/proposals.js.map +1 -1
  147. package/dist/cli/register.js.map +1 -1
  148. package/dist/cli/shared.js.map +1 -1
  149. package/dist/cli/skills.js.map +1 -1
  150. package/dist/cli/task-queue-status.js.map +1 -1
  151. package/dist/cli/verified.js.map +1 -1
  152. package/dist/cli/verify/fact-count.js.map +1 -1
  153. package/dist/cli/verify/openclaw-config.js.map +1 -1
  154. package/dist/cli/verify/plugin-config-credentials.js.map +1 -1
  155. package/dist/cli/verify/sections/config-cron.js.map +1 -1
  156. package/dist/cli/verify/sections/embeddings.js.map +1 -1
  157. package/dist/cli/verify/sections/infrastructure.js.map +1 -1
  158. package/dist/cli/verify/sections/llm-models.js.map +1 -1
  159. package/dist/cli/verify/sections/reconcile.js.map +1 -1
  160. package/dist/cli/verify/verify-run-state.js.map +1 -1
  161. package/dist/cli/verify-llm-azure-auth.js.map +1 -1
  162. package/dist/cli/verify.js.map +1 -1
  163. package/dist/config/hybrid-schema.js.map +1 -1
  164. package/dist/config/index.js.map +1 -1
  165. package/dist/config/maintenance-fallback-policy.js.map +1 -1
  166. package/dist/config/parsers/capture.js.map +1 -1
  167. package/dist/config/parsers/core.js.map +1 -1
  168. package/dist/config/parsers/features.js.map +1 -1
  169. package/dist/config/parsers/index.js.map +1 -1
  170. package/dist/config/parsers/maintenance.js.map +1 -1
  171. package/dist/config/parsers/retrieval.js.map +1 -1
  172. package/dist/config/parsers/sensors.js.map +1 -1
  173. package/dist/config/skill-sections.js.map +1 -1
  174. package/dist/config/skill-size-limits.js.map +1 -1
  175. package/dist/config/types/agents.js.map +1 -1
  176. package/dist/config/types/bootstrap.js.map +1 -1
  177. package/dist/config/types/core.js.map +1 -1
  178. package/dist/config/types/index.js.map +1 -1
  179. package/dist/config/utils.js.map +1 -1
  180. package/dist/index-help.js.map +1 -1
  181. package/dist/index-testing-exports.js.map +1 -1
  182. package/dist/index.d.ts +1 -1
  183. package/dist/index.js +2 -2
  184. package/dist/index.js.map +1 -1
  185. package/dist/lifecycle/hook-resolution-api.js.map +1 -1
  186. package/dist/lifecycle/hooks.js +0 -1
  187. package/dist/lifecycle/hooks.js.map +1 -1
  188. package/dist/lifecycle/resolve-agent-id.js.map +1 -1
  189. package/dist/lifecycle/session-state.js.map +1 -1
  190. package/dist/lifecycle/stage-active-task.js.map +1 -1
  191. package/dist/lifecycle/stage-auth-failure.js.map +1 -1
  192. package/dist/lifecycle/stage-capture/run-capture.js.map +1 -1
  193. package/dist/lifecycle/stage-capture.js.map +1 -1
  194. package/dist/lifecycle/stage-cleanup.js.map +1 -1
  195. package/dist/lifecycle/stage-credential-hint.js.map +1 -1
  196. package/dist/lifecycle/stage-frustration.js.map +1 -1
  197. package/dist/lifecycle/stage-goal-stewardship.js.map +1 -1
  198. package/dist/lifecycle/stage-goal-subagent.js.map +1 -1
  199. package/dist/lifecycle/stage-injection.js +1 -1
  200. package/dist/lifecycle/stage-injection.js.map +1 -1
  201. package/dist/lifecycle/stage-recall/run-recall.js.map +1 -1
  202. package/dist/lifecycle/stage-recall.js.map +1 -1
  203. package/dist/lifecycle/stage-setup.js.map +1 -1
  204. package/dist/routes/dashboard/collectors.js.map +1 -1
  205. package/dist/routes/dashboard/html.js.map +1 -1
  206. package/dist/routes/dashboard/server.js.map +1 -1
  207. package/dist/routes/dashboard-graph.js.map +1 -1
  208. package/dist/routes/graphql-resolvers.js.map +1 -1
  209. package/dist/routes/graphql-server.js.map +1 -1
  210. package/dist/services/active-task-checkpoint.js.map +1 -1
  211. package/dist/services/active-task-injection.js.map +1 -1
  212. package/dist/services/active-task.js.map +1 -1
  213. package/dist/services/adaptive-catch-up-pacing.js +25 -0
  214. package/dist/services/adaptive-catch-up-pacing.js.map +1 -0
  215. package/dist/services/adaptive-maintenance-llm.js.map +1 -1
  216. package/dist/services/adaptive-model-limits.js.map +1 -1
  217. package/dist/services/ambient-retrieval.js.map +1 -1
  218. package/dist/services/apitap-service.js.map +1 -1
  219. package/dist/services/audit-health-exit-info.js.map +1 -1
  220. package/dist/services/audit-health-json.js.map +1 -1
  221. package/dist/services/auth-failure-detect.js.map +1 -1
  222. package/dist/services/auto-capture.js.map +1 -1
  223. package/dist/services/auto-classifier.js.map +1 -1
  224. package/dist/services/auto-skills-audit.js.map +1 -1
  225. package/dist/services/bootstrap-optional.js.map +1 -1
  226. package/dist/services/bootstrap-priority.js.map +1 -1
  227. package/dist/services/bootstrap.js.map +1 -1
  228. package/dist/services/capture-provenance.js.map +1 -1
  229. package/dist/services/capture-utils.js.map +1 -1
  230. package/dist/services/chat.js +22 -3
  231. package/dist/services/chat.js.map +1 -1
  232. package/dist/services/classification-scope.js.map +1 -1
  233. package/dist/services/classification.js.map +1 -1
  234. package/dist/services/cli-sql-dump.js.map +1 -1
  235. package/dist/services/consolidation.js.map +1 -1
  236. package/dist/services/context-audit.js +1 -1
  237. package/dist/services/context-audit.js.map +1 -1
  238. package/dist/services/context-budget.js.map +1 -1
  239. package/dist/services/context-engine.js.map +1 -1
  240. package/dist/services/contextual-variants.js.map +1 -1
  241. package/dist/services/continuous-verifier.js.map +1 -1
  242. package/dist/services/contradiction-adjudicator.js.map +1 -1
  243. package/dist/services/cost-context.js.map +1 -1
  244. package/dist/services/cost-feature-labels.js.map +1 -1
  245. package/dist/services/credential-migration.js.map +1 -1
  246. package/dist/services/credential-scanner.js.map +1 -1
  247. package/dist/services/credential-validation.js.map +1 -1
  248. package/dist/services/cron-exit-validator.js.map +1 -1
  249. package/dist/services/cron-guard.js.map +1 -1
  250. package/dist/services/cron-job-bash-harness.js +52 -5
  251. package/dist/services/cron-job-bash-harness.js.map +1 -1
  252. package/dist/services/cron-maintenance-reconciler.js +1 -3
  253. package/dist/services/cron-maintenance-reconciler.js.map +1 -1
  254. package/dist/services/cross-agent-learning.js.map +1 -1
  255. package/dist/services/crystallization-proposer.js.map +1 -1
  256. package/dist/services/dedupe-policy.js.map +1 -1
  257. package/dist/services/deprecated-cron-commands.js.map +1 -1
  258. package/dist/services/directive-extract.js.map +1 -1
  259. package/dist/services/document-chunker.js.map +1 -1
  260. package/dist/services/document-grader.js.map +1 -1
  261. package/dist/services/dream-cycle.js.map +1 -1
  262. package/dist/services/embedding-migration.js.map +1 -1
  263. package/dist/services/embedding-registry.js.map +1 -1
  264. package/dist/services/embeddings/chain-provider.js.map +1 -1
  265. package/dist/services/embeddings/factory.js.map +1 -1
  266. package/dist/services/embeddings/fallback-provider.js.map +1 -1
  267. package/dist/services/embeddings/ollama-provider.js.map +1 -1
  268. package/dist/services/embeddings/onnx-provider.js.map +1 -1
  269. package/dist/services/embeddings/openai-provider.js.map +1 -1
  270. package/dist/services/embeddings/shared.js +3 -3
  271. package/dist/services/embeddings/shared.js.map +1 -1
  272. package/dist/services/embeddings/types.js.map +1 -1
  273. package/dist/services/entity-enrichment-adaptive.js +128 -0
  274. package/dist/services/entity-enrichment-adaptive.js.map +1 -0
  275. package/dist/services/entity-enrichment-cli.js +389 -42
  276. package/dist/services/entity-enrichment-cli.js.map +1 -1
  277. package/dist/services/entity-enrichment.js +31 -5
  278. package/dist/services/entity-enrichment.js.map +1 -1
  279. package/dist/services/error-reporter/noisy-errors.js.map +1 -1
  280. package/dist/services/error-reporter/sanitize.js.map +1 -1
  281. package/dist/services/error-reporter.js.map +1 -1
  282. package/dist/services/event-hub-repair.js.map +1 -1
  283. package/dist/services/export-memory.js.map +1 -1
  284. package/dist/services/fact-extraction.js.map +1 -1
  285. package/dist/services/feedback-effectiveness.js.map +1 -1
  286. package/dist/services/find-duplicates.js.map +1 -1
  287. package/dist/services/frustration-detector.js.map +1 -1
  288. package/dist/services/fts-search.js.map +1 -1
  289. package/dist/services/gap-detector.js.map +1 -1
  290. package/dist/services/generated-skill-lifecycle.js.map +1 -1
  291. package/dist/services/generated-skill-validation.js.map +1 -1
  292. package/dist/services/goal-active-task-mirror.js.map +1 -1
  293. package/dist/services/goal-circuit-breaker.js.map +1 -1
  294. package/dist/services/goal-health.js.map +1 -1
  295. package/dist/services/goal-registry.js.map +1 -1
  296. package/dist/services/goal-stewardship-heartbeat.js.map +1 -1
  297. package/dist/services/goal-stewardship-llm-triage.js.map +1 -1
  298. package/dist/services/goal-stewardship-verify-cron.js.map +1 -1
  299. package/dist/services/goal-stewardship.js.map +1 -1
  300. package/dist/services/goal-subagent.js.map +1 -1
  301. package/dist/services/graph-retrieval.js.map +1 -1
  302. package/dist/services/humanizer-score.js.map +1 -1
  303. package/dist/services/hybrid-mem-cron-default-job-steps.js.map +1 -1
  304. package/dist/services/hyde-helper.js.map +1 -1
  305. package/dist/services/identity-reflection.js.map +1 -1
  306. package/dist/services/implicit-feedback-extract.js.map +1 -1
  307. package/dist/services/index.js.map +1 -1
  308. package/dist/services/ingest-utils.js.map +1 -1
  309. package/dist/services/intent-template.js.map +1 -1
  310. package/dist/services/json-array-parser.js.map +1 -1
  311. package/dist/services/knowledge-gaps.js.map +1 -1
  312. package/dist/services/language-keywords-build.js.map +1 -1
  313. package/dist/services/lifecycle/github-adapter.js.map +1 -1
  314. package/dist/services/llm-rate-limit-headers.js +1 -2
  315. package/dist/services/llm-rate-limit-headers.js.map +1 -1
  316. package/dist/services/maintenance-auto-fix.js.map +1 -1
  317. package/dist/services/maintenance-log-analyzer.js +7 -1
  318. package/dist/services/maintenance-log-analyzer.js.map +1 -1
  319. package/dist/services/maintenance-timestamp.js.map +1 -1
  320. package/dist/services/memory-diagnostics.js.map +1 -1
  321. package/dist/services/memory-index.js.map +1 -1
  322. package/dist/services/merge-results.js.map +1 -1
  323. package/dist/services/model-capabilities.js.map +1 -1
  324. package/dist/services/model-pricing.js.map +1 -1
  325. package/dist/services/narrative-recall.js.map +1 -1
  326. package/dist/services/openclaw-session-artifact.js.map +1 -1
  327. package/dist/services/passive-observer.js.map +1 -1
  328. package/dist/services/pattern-detector-hash.js.map +1 -1
  329. package/dist/services/pattern-detector.js.map +1 -1
  330. package/dist/services/pending-autopilot/foundation.js.map +1 -1
  331. package/dist/services/pending-autopilot/redaction.js.map +1 -1
  332. package/dist/services/pending-autopilot/store.js.map +1 -1
  333. package/dist/services/pending-autopilot/types.js.map +1 -1
  334. package/dist/services/pending-digest-autopilot-cron.js.map +1 -1
  335. package/dist/services/pending-digest-autopilot.js.map +1 -1
  336. package/dist/services/pending-review-digest.js.map +1 -1
  337. package/dist/services/persona-proposal-triage.js.map +1 -1
  338. package/dist/services/persona-state-promotion.js.map +1 -1
  339. package/dist/services/post-compaction-recall.js.map +1 -1
  340. package/dist/services/pre-consolidation-flush.js.map +1 -1
  341. package/dist/services/pre-finalization-guard.js.map +1 -1
  342. package/dist/services/procedure-cluster.js.map +1 -1
  343. package/dist/services/procedure-extractor.js.map +1 -1
  344. package/dist/services/procedure-promotion/duplicate-skill-cache.js.map +1 -1
  345. package/dist/services/procedure-promotion-policy.js.map +1 -1
  346. package/dist/services/procedure-selection-metrics.js.map +1 -1
  347. package/dist/services/procedure-skill-eval.js.map +1 -1
  348. package/dist/services/procedure-skill-generator.js.map +1 -1
  349. package/dist/services/procedure-skill-recipe.js.map +1 -1
  350. package/dist/services/procedure-skill-shrink.js.map +1 -1
  351. package/dist/services/procedure-skill-workflow.js.map +1 -1
  352. package/dist/services/provenance.js.map +1 -1
  353. package/dist/services/public-export-bundle.js.map +1 -1
  354. package/dist/services/python-bridge.js.map +1 -1
  355. package/dist/services/query-expander.js.map +1 -1
  356. package/dist/services/query-validator.js.map +1 -1
  357. package/dist/services/recall-pipeline.js.map +1 -1
  358. package/dist/services/recall-timing.js.map +1 -1
  359. package/dist/services/recent-http-attempts.js.map +1 -1
  360. package/dist/services/reflection/shared.js.map +1 -1
  361. package/dist/services/reflection.js.map +1 -1
  362. package/dist/services/reinforcement-extract.js.map +1 -1
  363. package/dist/services/reranker.js.map +1 -1
  364. package/dist/services/responses-adapter.js.map +1 -1
  365. package/dist/services/retrieval-aliases.js.map +1 -1
  366. package/dist/services/retrieval-mode-policy.js.map +1 -1
  367. package/dist/services/retrieval-orchestrator/packing.js.map +1 -1
  368. package/dist/services/retrieval-orchestrator.d.ts +2 -3
  369. package/dist/services/retrieval-orchestrator.js.map +1 -1
  370. package/dist/services/rrf-fusion.js.map +1 -1
  371. package/dist/services/self-correction-extract.js.map +1 -1
  372. package/dist/services/session-observability.js.map +1 -1
  373. package/dist/services/session-pre-filter.js.map +1 -1
  374. package/dist/services/shortest-path.js.map +1 -1
  375. package/dist/services/skill-allowed-tools.js.map +1 -1
  376. package/dist/services/skill-creator-validator.js.map +1 -1
  377. package/dist/services/skill-crystallizer-helpers.js.map +1 -1
  378. package/dist/services/skill-crystallizer.js.map +1 -1
  379. package/dist/services/skill-description-builder.js.map +1 -1
  380. package/dist/services/skill-eval-synthesizer.js.map +1 -1
  381. package/dist/services/skill-examples-builder.js.map +1 -1
  382. package/dist/services/skill-frontmatter.js.map +1 -1
  383. package/dist/services/skill-name-validator.js.map +1 -1
  384. package/dist/services/skill-prompt-injection.js.map +1 -1
  385. package/dist/services/skill-reference-sidecar.js.map +1 -1
  386. package/dist/services/skill-script-bundler.js.map +1 -1
  387. package/dist/services/skill-validator.js.map +1 -1
  388. package/dist/services/startup-memory-attribution.js.map +1 -1
  389. package/dist/services/task-hygiene.js.map +1 -1
  390. package/dist/services/task-ledger/canonical.js.map +1 -1
  391. package/dist/services/task-ledger-facts.js.map +1 -1
  392. package/dist/services/task-queue-leases.js.map +1 -1
  393. package/dist/services/task-queue-watchdog.js.map +1 -1
  394. package/dist/services/tool-effectiveness.js.map +1 -1
  395. package/dist/services/tool-proposer.js.map +1 -1
  396. package/dist/services/tools-md-section.js.map +1 -1
  397. package/dist/services/topic-clusters.js.map +1 -1
  398. package/dist/services/trajectory-tracker.js.map +1 -1
  399. package/dist/services/vector-backend-observability.js.map +1 -1
  400. package/dist/services/vector-lifecycle-audit.js.map +1 -1
  401. package/dist/services/vector-maintenance.js.map +1 -1
  402. package/dist/services/vector-search.js.map +1 -1
  403. package/dist/services/verification-store.js.map +1 -1
  404. package/dist/services/verified-fact-triage.js.map +1 -1
  405. package/dist/services/wal-helpers.js.map +1 -1
  406. package/dist/services/workflow-tracker.js.map +1 -1
  407. package/dist/setup/bootstrap-databases.js.map +1 -1
  408. package/dist/setup/cli-context/cli-services.js.map +1 -1
  409. package/dist/setup/cli-context/help-text.js.map +1 -1
  410. package/dist/setup/cli-context/metadata.js.map +1 -1
  411. package/dist/setup/cli-context/register-cli-with-help.js.map +1 -1
  412. package/dist/setup/cli-context/register-full.js.map +1 -1
  413. package/dist/setup/cli-context/register-help.js.map +1 -1
  414. package/dist/setup/cost-instrumentation.js.map +1 -1
  415. package/dist/setup/hybrid-memory-generation-state.js.map +1 -1
  416. package/dist/setup/hybrid-memory-reload-coordinator.js +13 -13
  417. package/dist/setup/hybrid-memory-reload-coordinator.js.map +1 -1
  418. package/dist/setup/plugin-service.js.map +1 -1
  419. package/dist/setup/provider-router.js.map +1 -1
  420. package/dist/setup/register-context-engine.js.map +1 -1
  421. package/dist/setup/register-hooks.js.map +1 -1
  422. package/dist/setup/register-plugin.js +25 -21
  423. package/dist/setup/register-plugin.js.map +1 -1
  424. package/dist/setup/register-tools.js.map +1 -1
  425. package/dist/setup/reregister-policy.js +2 -2
  426. package/dist/setup/reregister-policy.js.map +1 -1
  427. package/dist/setup/tool-installers.js.map +1 -1
  428. package/dist/setup/workspace-bootstrap.js.map +1 -1
  429. package/dist/src/worker/narratives.js.map +1 -1
  430. package/dist/tools/apitap-tools.js.map +1 -1
  431. package/dist/tools/credential-tools.js.map +1 -1
  432. package/dist/tools/crystallization-tools.js.map +1 -1
  433. package/dist/tools/dashboard-routes.js.map +1 -1
  434. package/dist/tools/document-tools.js.map +1 -1
  435. package/dist/tools/goal-tools.js.map +1 -1
  436. package/dist/tools/graph-tools.js.map +1 -1
  437. package/dist/tools/issue-tools.js.map +1 -1
  438. package/dist/tools/memory/build-runtime.js.map +1 -1
  439. package/dist/tools/memory/helpers.js.map +1 -1
  440. package/dist/tools/memory/register-checkpoint-tools.js.map +1 -1
  441. package/dist/tools/memory/register-directory-tools.js.map +1 -1
  442. package/dist/tools/memory/register-edict-tools.js.map +1 -1
  443. package/dist/tools/memory/register-episode-tools.js.map +1 -1
  444. package/dist/tools/memory/register-recall-tools.js.map +1 -1
  445. package/dist/tools/memory/register-store-tools.js.map +1 -1
  446. package/dist/tools/memory-tools.js.map +1 -1
  447. package/dist/tools/persona-tools.js.map +1 -1
  448. package/dist/tools/provenance-tools.js.map +1 -1
  449. package/dist/tools/public-api-routes.js.map +1 -1
  450. package/dist/tools/safe-register-http-route.js.map +1 -1
  451. package/dist/tools/self-extension-tools.js.map +1 -1
  452. package/dist/tools/task-hygiene-tools.js.map +1 -1
  453. package/dist/tools/utility-tools.js.map +1 -1
  454. package/dist/tools/verification-tools.js.map +1 -1
  455. package/dist/tools/workflow-tools.js.map +1 -1
  456. package/dist/types/issue-types.js.map +1 -1
  457. package/dist/types/learnings-types.js.map +1 -1
  458. package/dist/types/memory.js.map +1 -1
  459. package/dist/utils/apim-gateway-fetch.js.map +1 -1
  460. package/dist/utils/atomic-write.js.map +1 -1
  461. package/dist/utils/auth-failover.js.map +1 -1
  462. package/dist/utils/auth.js.map +1 -1
  463. package/dist/utils/compaction-model-watchdog.js.map +1 -1
  464. package/dist/utils/consolidation-controls.js.map +1 -1
  465. package/dist/utils/constants.js.map +1 -1
  466. package/dist/utils/date-detector.js.map +1 -1
  467. package/dist/utils/dates.js.map +1 -1
  468. package/dist/utils/decay.js.map +1 -1
  469. package/dist/utils/duration.js.map +1 -1
  470. package/dist/utils/embed-call.js.map +1 -1
  471. package/dist/utils/entity-lookup-resolve.js.map +1 -1
  472. package/dist/utils/entity-mention-quality.js.map +1 -1
  473. package/dist/utils/entity-stopwords.js.map +1 -1
  474. package/dist/utils/env-manager.js.map +1 -1
  475. package/dist/utils/error-tracking.js.map +1 -1
  476. package/dist/utils/event-loop-yield.js.map +1 -1
  477. package/dist/utils/extract-last-user-message.js.map +1 -1
  478. package/dist/utils/extraction-from-template.js.map +1 -1
  479. package/dist/utils/fact-embeddings.js.map +1 -1
  480. package/dist/utils/file-snapshot.js.map +1 -1
  481. package/dist/utils/format.js.map +1 -1
  482. package/dist/utils/fs.js.map +1 -1
  483. package/dist/utils/gh-repo-arg.js.map +1 -1
  484. package/dist/utils/hybrid-mem-json-cli.js.map +1 -1
  485. package/dist/utils/language-keywords.js.map +1 -1
  486. package/dist/utils/lifecycle-generation.js.map +1 -1
  487. package/dist/utils/llm-json-array.js.map +1 -1
  488. package/dist/utils/llm-selection.js.map +1 -1
  489. package/dist/utils/logger.js.map +1 -1
  490. package/dist/utils/model-provider-family.js.map +1 -1
  491. package/dist/utils/model-tier.js.map +1 -1
  492. package/dist/utils/openclaw-agent-defaults.js.map +1 -1
  493. package/dist/utils/path.js.map +1 -1
  494. package/dist/utils/plugin-root.js.map +1 -1
  495. package/dist/utils/plugin-update-check.js.map +1 -1
  496. package/dist/utils/procedure-risk.js.map +1 -1
  497. package/dist/utils/progress-indicators.js.map +1 -1
  498. package/dist/utils/prompt-loader.js.map +1 -1
  499. package/dist/utils/provenance.js.map +1 -1
  500. package/dist/utils/provider-detection.js.map +1 -1
  501. package/dist/utils/registration-superseded.js.map +1 -1
  502. package/dist/utils/salience.js.map +1 -1
  503. package/dist/utils/sanitize-messages.js.map +1 -1
  504. package/dist/utils/scope-filter.js.map +1 -1
  505. package/dist/utils/skill-discovery.js.map +1 -1
  506. package/dist/utils/sqlite-file-perms.js.map +1 -1
  507. package/dist/utils/sqlite-outcome-compat.js.map +1 -1
  508. package/dist/utils/sqlite-transaction.js.map +1 -1
  509. package/dist/utils/stable-stringify.js.map +1 -1
  510. package/dist/utils/subagent-ended-utils.js.map +1 -1
  511. package/dist/utils/tags.js.map +1 -1
  512. package/dist/utils/text.js.map +1 -1
  513. package/dist/utils/timeout.js.map +1 -1
  514. package/dist/utils/typebox.js.map +1 -1
  515. package/dist/utils/version-check.js.map +1 -1
  516. package/dist/utils/wal-replay.js.map +1 -1
  517. package/dist/versionInfo.js.map +1 -1
  518. package/index.ts +2 -2
  519. package/lifecycle/hooks.ts +0 -1
  520. package/npm-shrinkwrap.json +487 -186
  521. package/openclaw.plugin.json +1 -1
  522. package/package.json +2 -2
  523. package/services/adaptive-catch-up-pacing.ts +28 -0
  524. package/services/chat.ts +34 -1
  525. package/services/cron-job-bash-harness.ts +52 -5
  526. package/services/embeddings/shared.ts +5 -2
  527. package/services/entity-enrichment-adaptive.ts +245 -0
  528. package/services/entity-enrichment-cli.ts +553 -47
  529. package/services/entity-enrichment.ts +43 -2
  530. package/services/llm-rate-limit-headers.ts +1 -4
  531. package/services/maintenance-log-analyzer.ts +13 -9
  532. package/services/reinforcement-extract.ts +19 -0
  533. package/setup/hybrid-memory-reload-coordinator.ts +26 -0
  534. package/setup/register-plugin.ts +62 -32
  535. package/setup/reregister-policy.ts +10 -5
@@ -1 +1 @@
1
- {"version":3,"file":"facts-db-layer1.js","names":["getScanCursorHelper","storeVariantImpl","getVariantsImpl","hasVariantsImpl","getEmbeddingsImpl","getEmbeddingsByModelImpl","countCanonicalEmbeddingsImpl","statsDailyWritesImpl","pruneRecallLogImpl","getHotFactsImpl","runCompactionImpl","retierFactsImpl","trimToBudgetImpl","setPreserveUntilImpl","setPreserveTagsImpl","getTokenBudgetStatusImpl","findByIdPrefixImpl","findByIdPrefixScopedImpl","findSimilarForClassificationImpl","getFactsForConsolidationImpl","getByIdImpl","getByIdsImpl","createLinkHelper","getLinksFromHelper","getLinksToHelper","getConnectedFactIdsHelper","expandGraphWithCTEHelper","refreshFactDegreesHelper"],"sources":["../../../backends/facts-db/facts-db-layer1.ts"],"sourcesContent":["/**\n * FactsDB — layer 1: open, variants/embeddings, search/CRUD, graph links (through expandGraphWithCTE).\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { DatabaseSync } from \"node:sqlite\";\n\nimport type { StoreConfig } from \"../../config.js\";\nimport type { MemoryEntry, MemoryScope, MemoryTier, ScopeFilter, SearchResult } from \"../../types/memory.js\";\nimport { normalizedHash } from \"../../utils/tags.js\";\nimport { tryRestrictSqliteDbFileMode } from \"../../utils/sqlite-file-perms.js\";\nimport { BaseSqliteStore } from \"../base-sqlite-store.js\";\nimport { runFactsMigrations } from \"../migrations/facts-migrations.js\";\nimport { SupersededTextsCache } from \"./cache-manager.js\";\nimport {\n deleteFact,\n getDuplicateIdByNormalizedHash,\n hasDuplicateText,\n refreshAccessedFacts as refreshAccessedFactsImpl,\n refreshIndexedFacts as refreshIndexedFactsImpl,\n type StoreFactInput,\n type StoreFactResult,\n statsDailyWrites as statsDailyWritesImpl,\n storeFact,\n} from \"./crud.js\";\nimport { verifyFts5Support } from \"./db-connection.js\";\nimport {\n findSimilarForClassification as findSimilarForClassificationImpl,\n getById as getByIdImpl,\n getByIds as getByIdsImpl,\n getFactsForConsolidation as getFactsForConsolidationImpl,\n getHotFacts as getHotFactsImpl,\n} from \"./fact-read-queries.js\";\nimport {\n createLink as createLinkHelper,\n createOrStrengthenRelatedLink as createOrStrengthenRelatedLinkHelper,\n expandGraphWithCTE as expandGraphWithCTEHelper,\n type GraphConnectedStats,\n getConnectedFactIds as getConnectedFactIdsHelper,\n getLinksFrom as getLinksFromHelper,\n getLinksTo as getLinksToHelper,\n refreshFactDegrees as refreshFactDegreesHelper,\n strengthenRelatedLinksBatch as strengthenRelatedLinksBatchHelper,\n} from \"./links.js\";\nimport {\n logRecall as logRecallImpl,\n pruneRecallLog as pruneRecallLogImpl,\n type RetierReport,\n retierFacts as retierFactsImpl,\n runCompaction as runCompactionImpl,\n setFactTier,\n setPreserveTags as setPreserveTagsImpl,\n setPreserveUntil as setPreserveUntilImpl,\n type TieringOptions,\n trimToBudget as trimToBudgetImpl,\n} from \"./maintenance.js\";\nimport { getScanCursor as getScanCursorHelper, updateScanCursor as updateScanCursorHelper } from \"./scan-cursors.js\";\nimport { bootstrapFactsCoreSchema } from \"./schema-bootstrap.js\";\nimport {\n findByIdPrefix as findByIdPrefixImpl,\n findByIdPrefixScoped as findByIdPrefixScopedImpl,\n lookupFacts,\n searchFacts,\n} from \"./search.js\";\nimport { getTokenBudgetStatus as getTokenBudgetStatusImpl } from \"./stats.js\";\nimport type { MemoryLinkType } from \"./types.js\";\nimport {\n countCanonicalEmbeddings as countCanonicalEmbeddingsImpl,\n deleteEmbeddings as deleteEmbeddingsImpl,\n deleteVariants as deleteVariantsImpl,\n estimateStorageBytesOnDisk,\n getEmbeddingsByModel as getEmbeddingsByModelImpl,\n getEmbeddings as getEmbeddingsImpl,\n getVariants as getVariantsImpl,\n hasVariants as hasVariantsImpl,\n storeEmbedding as storeEmbeddingImpl,\n storeVariant as storeVariantImpl,\n} from \"./variants.js\";\n\nexport class FactsDBLayer1 extends BaseSqliteStore {\n // Responsibility note:\n // - This class is the stable API boundary.\n // - Extracted implementation modules under backends/facts-db/ own links/reinforcement/scan-cursor logic.\n protected readonly dbPath: string;\n protected readonly fuzzyDedupe: boolean;\n protected readonly storeConfig?: StoreConfig;\n protected readonly supersededTextsCacheMgr = new SupersededTextsCache(5 * 60_000);\n private readonly storeDedupeWarnedKeys = new Set<string>();\n\n constructor(dbPath: string, options?: { fuzzyDedupe?: boolean; storeConfig?: StoreConfig }) {\n mkdirSync(dirname(dbPath), { recursive: true });\n const db = new DatabaseSync(dbPath);\n\n try {\n FactsDBLayer1.verifyFts5Support(db);\n } catch (err) {\n try {\n db.close();\n } catch {\n // Ignore close errors during failure cleanup\n }\n throw err;\n }\n\n super(db, {\n foreignKeys: true,\n customPragmas: [\n \"PRAGMA synchronous = NORMAL\",\n \"PRAGMA wal_autocheckpoint = 1000\",\n // Perf: 64MB page cache (up from 2MB default) — avoids repeated disk reads for\n // the ~192MB facts DB during FTS two-phase lookups. Single-connection model so\n // this is the only consumer. Env: OPENCLAW_FACTS_CACHE_SIZE_KB to override.\n `PRAGMA cache_size = -${process.env.OPENCLAW_FACTS_CACHE_SIZE_KB ?? \"64000\"}`,\n // Perf: 256MB memory-mapped I/O — lets the OS page cache serve reads without\n // crossing the user/kernel boundary. Env: OPENCLAW_FACTS_MMAP_SIZE to override.\n `PRAGMA mmap_size = ${process.env.OPENCLAW_FACTS_MMAP_SIZE ?? \"268435456\"}`,\n \"PRAGMA temp_store = MEMORY\",\n ],\n });\n this.dbPath = dbPath;\n tryRestrictSqliteDbFileMode(dbPath);\n this.fuzzyDedupe = options?.fuzzyDedupe ?? false;\n this.storeConfig = options?.storeConfig;\n\n bootstrapFactsCoreSchema(this.liveDb);\n\n // Run all schema migrations\n runFactsMigrations(this.liveDb);\n }\n\n /** Filesystem path to the SQLite database file (for maintenance sidecars next to the DB). */\n get sqlitePath(): string {\n return this.dbPath;\n }\n\n /**\n * Hard-startup guard for SQLite FTS5 support.\n *\n * Some Node.js/SQLite builds can run without FTS5 enabled, which would cause\n * hybrid retrieval to silently degrade to vector-only once the FTS strategy\n * starts failing. Probe FTS5 explicitly and fail fast with an actionable error.\n */\n /** @deprecated Prefer importing `verifyFts5Support` from `./facts-db/db-connection.js` (kept for tests). */\n static verifyFts5Support(db: DatabaseSync): void {\n verifyFts5Support(db);\n }\n\n /** Return the cursor for the given scan type, or null if never run. */\n getScanCursor(scanType: string): {\n lastSessionTs: number;\n lastRunAt: number;\n sessionsProcessed: number;\n lastSessionFile?: string;\n } | null {\n return getScanCursorHelper(this.liveDb, scanType);\n }\n\n /**\n * Upsert the cursor after a successful incremental scan.\n * @param lastSessionTs Timestamp of the newest session processed (file mtime). Pass `Date.now()`\n * when no session watermark is available (e.g. self-correction). Pass `0` when no sessions\n * were processed — `last_session_ts` will not be updated in that case.\n * @param sessionsProcessed Number of sessions processed in this run.\n * @param lastSessionFile Optional tie-breaker when multiple sessions share the same mtime.\n */\n updateScanCursor(scanType: string, lastSessionTs: number, sessionsProcessed: number, lastSessionFile?: string): void {\n updateScanCursorHelper(this.liveDb, scanType, lastSessionTs, sessionsProcessed, lastSessionFile);\n }\n\n /**\n * Store a contextual variant text for a fact.\n * Returns the new row id.\n */\n storeVariant(factId: string, variantType: string, variantText: string): number {\n return storeVariantImpl(this.liveDb, factId, variantType, variantText);\n }\n\n getVariants(factId: string): Array<{\n id: number;\n variantType: string;\n variantText: string;\n createdAt: string;\n }> {\n return getVariantsImpl(this.liveDb, factId);\n }\n\n hasVariants(factId: string): boolean {\n return hasVariantsImpl(this.liveDb, factId);\n }\n\n deleteVariants(factId: string): void {\n deleteVariantsImpl(this.liveDb, factId);\n }\n\n storeEmbedding(factId: string, model: string, variant: string, embedding: Float32Array, dimensions: number): void {\n storeEmbeddingImpl(this.liveDb, factId, model, variant, embedding, dimensions);\n }\n\n getEmbeddings(factId: string): Array<{ model: string; variant: string; embedding: Float32Array }> {\n return getEmbeddingsImpl(this.liveDb, factId);\n }\n\n getEmbeddingsByModel(model: string, limit?: number): Array<{ factId: string; embedding: Float32Array }> {\n return getEmbeddingsByModelImpl(this.liveDb, model, limit);\n }\n\n deleteEmbeddings(factId: string): void {\n deleteEmbeddingsImpl(this.liveDb, factId);\n }\n\n /** Re-apply connection pragmas (used on initial open and auto-reopen). */\n protected getSubsystemName(): string {\n return \"facts-db\";\n }\n\n countCanonicalEmbeddings(): number {\n return countCanonicalEmbeddingsImpl(this.liveDb);\n }\n\n estimateStorageBytes(): {\n sqliteBytes: number;\n walBytes: number;\n shmBytes: number;\n } {\n return estimateStorageBytesOnDisk(this.dbPath);\n }\n\n store(\n entry: StoreFactInput,\n options?: {\n vectorCandidates?: ReadonlyArray<{ id: string; score: number }>;\n /**\n * Namespace for warn-once keys when store dedupe falls back to lexical-only because\n * no `vectorCandidates` were provided (e.g. \"reflection\", \"extract-directives\").\n */\n warnContext?: string;\n /** Suppress the vector-candidates-missing warning entirely (caller will summarise). */\n suppressVectorFallbackWarning?: boolean;\n /** Trusted edit path for re-storing already persisted legacy guarded facts. */\n allowPreStoreGuardBypass?: boolean;\n },\n ): MemoryEntry {\n const result = this.storeWithResult(entry, options);\n // Skipped results carry a non-addressable placeholder entry (id === \"\") for\n // legacy store() callers. storeWithResult() callers must check result.skipped\n // before vector, supersession, provenance, or event side effects.\n return result.entry;\n }\n\n storeWithResult(\n entry: StoreFactInput,\n options?: {\n vectorCandidates?: ReadonlyArray<{ id: string; score: number }>;\n /**\n * Namespace for warn-once keys when store dedupe falls back to lexical-only because\n * no `vectorCandidates` were provided (e.g. \"reflection\", \"extract-directives\").\n */\n warnContext?: string;\n /** Suppress the vector-candidates-missing warning entirely (caller will summarise). */\n suppressVectorFallbackWarning?: boolean;\n /** Trusted edit path for re-storing already persisted legacy guarded facts. */\n allowPreStoreGuardBypass?: boolean;\n },\n ): StoreFactResult {\n const warnOnce = (key: string, message: string): void => {\n if (this.storeDedupeWarnedKeys.has(key)) return;\n this.storeDedupeWarnedKeys.add(key);\n process.stderr.write(`${message}\n`);\n };\n return storeFact(\n {\n db: this.liveDb,\n fuzzyDedupe: this.fuzzyDedupe,\n storeConfig: this.storeConfig,\n getById: (id) => this.getById(id),\n invalidateSupersededCache: () => {\n this.supersededTextsCacheMgr.invalidate();\n },\n vectorCandidates: options?.vectorCandidates,\n warnOnce,\n warnOnceKey: options?.warnContext,\n suppressVectorFallbackWarning: options?.suppressVectorFallbackWarning,\n allowPreStoreGuardBypass: options?.allowPreStoreGuardBypass,\n },\n entry,\n );\n }\n\n statsDailyWrites(): Array<{ source: string; day: string; count: number; dropped: number; evicted: number }> {\n return statsDailyWritesImpl(this.liveDb);\n }\n\n /** Update recall_count and last_accessed for facts (public for progressive disclosure). Bulk UPDATE to avoid N+1. */\n refreshAccessedFacts(ids: string[]): void {\n refreshAccessedFactsImpl(this.liveDb, ids);\n }\n\n /** Update indexed_count and last_indexed for index-only exposures (#1559). Does NOT inflate recall_count. */\n refreshIndexedFacts(ids: string[]): void {\n refreshIndexedFactsImpl(this.liveDb, ids);\n }\n\n /** Record a memory_recall invocation outcome for hit-rate tracking (Issue #148). */\n logRecall(hit: boolean, occurredAtSec?: number): void {\n logRecallImpl(this.liveDb, hit, occurredAtSec);\n }\n\n /** Prune recall_log entries older than N days to prevent unbounded growth (Issue #148). */\n pruneRecallLog(olderThanDays = 30): number {\n return pruneRecallLogImpl(this.liveDb, olderThanDays);\n }\n\n /** Read the last stored embedding provider+model metadata (Issue #153). */\n getEmbeddingMeta(): { provider: string; model: string } | null {\n const row = this.liveDb.prepare(\"SELECT provider, model FROM embedding_meta WHERE id = 1\").get() as\n | { provider: string; model: string }\n | undefined;\n if (!row) return null;\n return { provider: row.provider, model: row.model };\n }\n\n /** Persist the active embedding provider+model metadata (Issue #153). */\n setEmbeddingMeta(provider: string, model: string): void {\n const nowSec = Math.floor(Date.now() / 1000);\n this.liveDb\n .prepare(\n `INSERT INTO embedding_meta (id, provider, model, updated_at)\n VALUES (1, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET provider = excluded.provider, model = excluded.model, updated_at = excluded.updated_at`,\n )\n .run(provider, model, nowSec);\n }\n\n /** Record which embedding model generated the stored vector for a fact (Issue #153). */\n setEmbeddingModel(id: string, model: string | null): void {\n this.liveDb.prepare(\"UPDATE facts SET embedding_model = ? WHERE id = ?\").run(model, id);\n }\n\n /**\n * Restore fact text after a failed dedupe-merge follow-up step (re-embed/vector store),\n * preserving the original row instead of deleting it.\n */\n restoreMergedFactText(id: string, text: string): boolean {\n const res = this.liveDb\n .prepare(\"UPDATE facts SET text = ?, normalized_hash = ? WHERE id = ?\")\n .run(text, normalizedHash(text), id);\n return Number(res.changes ?? 0) > 0;\n }\n\n /** Get HOT-tier facts for session context, capped by token budget. */\n getHotFacts(maxTokens: number, scopeFilter?: ScopeFilter | null): SearchResult[] {\n return getHotFactsImpl(this.liveDb, maxTokens, scopeFilter);\n }\n\n /** Set a fact's tier. */\n setTier(id: string, tier: MemoryTier): boolean {\n return setFactTier(this.liveDb, id, tier);\n }\n\n /** Compaction — retier facts by structural shape, salience, and inactivity. */\n runCompaction(opts: TieringOptions): RetierReport {\n return runCompactionImpl(this.liveDb, opts);\n }\n\n /** Retier facts with optional dry-run support for operator CLI migrations. */\n retier(opts: TieringOptions, apply = true): RetierReport {\n return retierFactsImpl(this.liveDb, opts, apply);\n }\n\n /**\n * Token-budget tiered trimming for context compaction (Issue #792).\n *\n * Retention tiers (never trimmed = P0):\n * - Edict-tagged facts (tag 'edict')\n * - Verified facts (present in verified_facts table)\n * - Facts with active preserveUntil (epoch seconds in future)\n * - Facts with non-empty preserveTags\n *\n * Remaining facts sorted by trim priority:\n * - P1: importance > 0.8 AND created within the last hour\n * - P2: importance 0.5 – 0.8\n * - P3: importance < 0.5\n *\n * Trimming proceeds P3 → P2 → P1 until within budget.\n * Token estimate: Math.ceil(chars / 3.8)\n *\n * Returns a summary of what would be / was trimmed.\n */\n trimToBudget(\n tokenBudget: number,\n simulate = false,\n ): {\n simulate: boolean;\n budget: number;\n beforeTokens: number;\n afterTokens: number;\n trimmed: Array<{\n id: string;\n textPreview: string;\n tier: string;\n importance: number;\n tokenCost: number;\n }>;\n preserved: Array<{ id: string; reason: string }>;\n error?: string;\n } {\n return trimToBudgetImpl(this.liveDb, tokenBudget, simulate);\n }\n\n /**\n * Set or clear preserve_until on a fact.\n * If untilSec is null, clears any existing preserve_until.\n * Returns the updated MemoryEntry or null if not found.\n */\n setPreserveUntil(id: string, untilSec: number | null): MemoryEntry | null {\n return setPreserveUntilImpl(this.liveDb, (i) => this.getById(i), id, untilSec);\n }\n\n /**\n * Add or remove preserve_tags on a fact.\n * mode 'set': replaces all tags with the given array.\n * mode 'add': adds the given tags (deduped).\n * mode 'remove': removes the given tags.\n * Returns the updated MemoryEntry or null if not found.\n */\n setPreserveTags(id: string, tags: string[], mode: \"set\" | \"add\" | \"remove\"): MemoryEntry | null {\n return setPreserveTagsImpl(this.liveDb, (i) => this.getById(i), id, tags, mode);\n }\n\n /**\n * Compute current token estimate for all non-superseded, non-expired facts.\n * Returns { totalTokens, byTier: { p0, p1, p2, p3 }, factCount: { p0, p1, p2, p3 } }.\n */\n getTokenBudgetStatus(): {\n totalTokens: number;\n budget: number;\n overflow: number;\n byTier: { p0: number; p1: number; p2: number; p3: number };\n factCount: { p0: number; p1: number; p2: number; p3: number };\n } {\n return getTokenBudgetStatusImpl(this.liveDb);\n }\n\n search(\n query: string,\n limit = 5,\n options: {\n includeExpired?: boolean;\n tag?: string;\n includeSuperseded?: boolean;\n /** Point-in-time: only facts valid at this epoch second. */\n asOf?: number;\n /** 'warm' = only warm tier (default), 'all' = warm + cold. */\n tierFilter?: \"warm\" | \"all\";\n /** Scope filter — only return global + matching user/agent/session. */\n scopeFilter?: ScopeFilter | null;\n /** Reinforcement boost — added to score when reinforced_count > 0 (default: 0.1). */\n reinforcementBoost?: number;\n /** Weight applied to diversity score when calculating effective boost (default: 1.0). */\n diversityWeight?: number;\n /**\n * Interactive auto-recall hot path: cap FTS OR-term explosion and avoid loading full fact rows\n * until top matches are chosen (reduces WhatsApp/gateway stalls from huge MATCH + wide SELECT f.*).\n */\n interactiveFtsFastPath?: boolean;\n } = {},\n ): SearchResult[] {\n return searchFacts(this.liveDb, query, limit, options);\n }\n\n lookup(\n entity: string,\n key?: string,\n tag?: string,\n options?: {\n includeSuperseded?: boolean;\n asOf?: number;\n scopeFilter?: ScopeFilter | null;\n limit?: number;\n },\n ): SearchResult[] {\n return lookupFacts(this.liveDb, entity, key, tag, options);\n }\n\n /** Find a fact ID by prefix (for truncated ID resolution).\n * Returns { id } for unique match, { ambiguous, count } for multiple, or null for no match.\n * Requires at least 4 hex chars to prevent full-table scans and reduce ambiguity. */\n findByIdPrefix(prefix: string): { id: string } | { ambiguous: true; count: number } | null {\n return findByIdPrefixImpl(this.liveDb, prefix);\n }\n\n /** Find a fact ID by prefix with scope filtering (for public API).\n * Returns { id } for unique match, { ambiguous, count } for multiple, or { id: null } for no match.\n * Requires at least 4 hex chars. Applies UUID dash normalization for bare hex strings. */\n findByIdPrefixScoped(\n prefix: string,\n scopeFilter: ScopeFilter | null | undefined,\n ): { id: string } | { ambiguous: true; count: number } | { id: null } {\n return findByIdPrefixScopedImpl(this.liveDb, prefix, scopeFilter);\n }\n\n delete(id: string): boolean {\n return deleteFact(this.liveDb, id);\n }\n\n /** Exact match or dedupe policy would block a new insert (per-source if `source` set; global probe if omitted, #1202). */\n hasDuplicate(\n text: string,\n source?: string,\n structured?: { category?: string | null; entity?: string | null; key?: string | null; value?: string | null },\n ): boolean {\n return hasDuplicateText(this.liveDb, this.fuzzyDedupe, text, this.storeConfig, source, structured);\n }\n\n /**\n * Return the ID of an existing fact whose normalised hash matches `text`, or null if none.\n * O(1) index lookup. Useful for resolving the canonical fact ID when `hasDuplicate()` returns true.\n */\n getDuplicateIdByNormalizedHash(text: string): string | null {\n return getDuplicateIdByNormalizedHash(this.liveDb, text);\n }\n\n /** Mark a fact as superseded by a new fact. Sets superseded_at, superseded_by, and valid_until (bi-temporal). */\n supersede(oldId: string, newId: string | null): boolean {\n const nowSec = Math.floor(Date.now() / 1000);\n const result = this.liveDb\n .prepare(\n \"UPDATE facts SET superseded_at = ?, superseded_by = ?, valid_until = ? WHERE id = ? AND superseded_at IS NULL\",\n )\n .run(nowSec, newId, nowSec, oldId);\n if (result.changes > 0) {\n this.invalidateSupersededCache();\n }\n return result.changes > 0;\n }\n\n /**\n * Invalidate cached superseded-text snapshots after supersede-equivalent SQL on `liveDb`\n * (e.g. maintenance running inside an explicit transaction where {@link supersede} is not used).\n */\n invalidateSupersededTextsCache(): void {\n this.invalidateSupersededCache();\n }\n\n /** Find top-N most similar existing facts by entity+key overlap and normalized text. Used for ADD/UPDATE/DELETE classification. */\n findSimilarForClassification(\n text: string,\n entity: string | null,\n key: string | null,\n limit = 5,\n scope: MemoryScope | null = null,\n scopeTarget: string | null = null,\n ): MemoryEntry[] {\n return findSimilarForClassificationImpl(this.liveDb, text, entity, key, limit, scope, scopeTarget);\n }\n\n /** For consolidation (2.4): fetch facts with id, text, category, entity, key. Order by created_at DESC. Excludes superseded. */\n getFactsForConsolidation(limit: number): Array<{\n id: string;\n text: string;\n category: string;\n entity: string | null;\n key: string | null;\n }> {\n return getFactsForConsolidationImpl(this.liveDb, limit);\n }\n\n /** Alias for getById for CLI compatibility. */\n get(id: string): MemoryEntry | null {\n return this.getById(id);\n }\n\n /** Get one fact by id (for merge category). Returns null if not found. When asOf is set, returns null if the fact was not valid at that time. When scopeFilter is set, returns null if the fact is not in scope. */\n getById(id: string, options?: { asOf?: number; scopeFilter?: ScopeFilter | null }): MemoryEntry | null {\n return getByIdImpl(this.liveDb, id, options);\n }\n\n /** Batch get facts by id. Returns a Map of id → entry after asOf/scope filtering. */\n getByIds(ids: string[], options?: { asOf?: number; scopeFilter?: ScopeFilter | null }): Map<string, MemoryEntry> {\n return getByIdsImpl(this.liveDb, ids, options);\n }\n\n /** Create a typed link between two facts. Returns link id. */\n createLink(sourceFactId: string, targetFactId: string, linkType: MemoryLinkType, strength = 1.0): string {\n return createLinkHelper(this.liveDb, sourceFactId, targetFactId, linkType, strength);\n }\n\n /** Hebbian: Create or strengthen RELATED_TO link between two facts recalled together. */\n createOrStrengthenRelatedLink(factIdA: string, factIdB: string, deltaStrength = 0.1): void {\n createOrStrengthenRelatedLinkHelper(this.liveDb, factIdA, factIdB, deltaStrength);\n }\n\n /**\n * Hebbian batch: strengthen RELATED_TO links for all pairs in a single SQLite transaction.\n * Reduces O(n²) individual round-trips to 1 transaction regardless of pair count.\n */\n strengthenRelatedLinksBatch(pairs: [string, string][], deltaStrength = 0.1): void {\n strengthenRelatedLinksBatchHelper(this.liveDb, pairs, deltaStrength);\n }\n\n /** Get links from a fact (outgoing). */\n getLinksFrom(factId: string): Array<{\n id: string;\n targetFactId: string;\n linkType: string;\n strength: number;\n }> {\n return getLinksFromHelper(this.liveDb, factId);\n }\n\n /** Get links to a fact (incoming). */\n getLinksTo(factId: string): Array<{\n id: string;\n sourceFactId: string;\n linkType: string;\n strength: number;\n }> {\n return getLinksToHelper(this.liveDb, factId);\n }\n\n /** BFS from given fact IDs up to maxDepth hops. Returns all connected fact IDs (including the seed set).\n * CONTRADICTS links are excluded from traversal — they would otherwise pollute graph-based recall\n * with unrelated contradicted facts and cause traversal explosion when a fact has many contradictions.\n */\n getConnectedFactIds(\n factIds: string[],\n maxDepth: number,\n options?: { hubDegreeCap?: number | null; stats?: GraphConnectedStats },\n ): string[] {\n return getConnectedFactIdsHelper(this.liveDb, factIds, maxDepth, options);\n }\n\n /**\n * Perform graph expansion using a recursive CTE, returning expanded nodes with hop count and path info.\n * This is used by graph-retrieval.ts to avoid N+1 query patterns.\n *\n * @param seedFactIds - Array of seed fact IDs to start expansion from\n * @param maxDepth - Maximum traversal depth\n * @returns Array of expanded nodes with factId, seedId, hopCount, and path (JSON array of link steps)\n */\n expandGraphWithCTE(\n seedFactIds: string[],\n maxDepth: number,\n options?: {\n asOf?: number;\n scopeFilter?: { userId?: string; agentId?: string; sessionId?: string };\n hubDegreeCap?: number | null;\n },\n ): Array<{\n factId: string;\n seedId: string;\n hopCount: number;\n path: string;\n }> {\n return expandGraphWithCTEHelper(this.liveDb, seedFactIds, maxDepth, options);\n }\n\n /**\n * Refresh denormalized `out_degree` / `in_degree` columns on `facts` (#1192). The dream-cycle\n * calls this once per night so the BFS hub guard avoids running `COUNT(*) FROM memory_links`\n * on every traversal.\n */\n refreshFactDegrees(): { updated: number } {\n return refreshFactDegreesHelper(this.liveDb);\n }\n\n /** Invalidate superseded texts cache (called after supersede operations). */\n protected invalidateSupersededCache(): void {\n this.supersededTextsCacheMgr.invalidate();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"facts-db-layer1.js","names":["getScanCursorHelper","storeVariantImpl","getVariantsImpl","hasVariantsImpl","getEmbeddingsImpl","getEmbeddingsByModelImpl","countCanonicalEmbeddingsImpl","statsDailyWritesImpl","pruneRecallLogImpl","getHotFactsImpl","runCompactionImpl","retierFactsImpl","trimToBudgetImpl","setPreserveUntilImpl","setPreserveTagsImpl","getTokenBudgetStatusImpl","findByIdPrefixImpl","findByIdPrefixScopedImpl","findSimilarForClassificationImpl","getFactsForConsolidationImpl","getByIdImpl","getByIdsImpl","createLinkHelper","getLinksFromHelper","getLinksToHelper","getConnectedFactIdsHelper","expandGraphWithCTEHelper","refreshFactDegreesHelper"],"sources":["../../../backends/facts-db/facts-db-layer1.ts"],"sourcesContent":["/**\n * FactsDB — layer 1: open, variants/embeddings, search/CRUD, graph links (through expandGraphWithCTE).\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { DatabaseSync } from \"node:sqlite\";\n\nimport type { StoreConfig } from \"../../config.js\";\nimport type { MemoryEntry, MemoryScope, MemoryTier, ScopeFilter, SearchResult } from \"../../types/memory.js\";\nimport { normalizedHash } from \"../../utils/tags.js\";\nimport { tryRestrictSqliteDbFileMode } from \"../../utils/sqlite-file-perms.js\";\nimport { BaseSqliteStore } from \"../base-sqlite-store.js\";\nimport { runFactsMigrations } from \"../migrations/facts-migrations.js\";\nimport { SupersededTextsCache } from \"./cache-manager.js\";\nimport {\n deleteFact,\n getDuplicateIdByNormalizedHash,\n hasDuplicateText,\n refreshAccessedFacts as refreshAccessedFactsImpl,\n refreshIndexedFacts as refreshIndexedFactsImpl,\n type StoreFactInput,\n type StoreFactResult,\n statsDailyWrites as statsDailyWritesImpl,\n storeFact,\n} from \"./crud.js\";\nimport { verifyFts5Support } from \"./db-connection.js\";\nimport {\n findSimilarForClassification as findSimilarForClassificationImpl,\n getById as getByIdImpl,\n getByIds as getByIdsImpl,\n getFactsForConsolidation as getFactsForConsolidationImpl,\n getHotFacts as getHotFactsImpl,\n} from \"./fact-read-queries.js\";\nimport {\n createLink as createLinkHelper,\n createOrStrengthenRelatedLink as createOrStrengthenRelatedLinkHelper,\n expandGraphWithCTE as expandGraphWithCTEHelper,\n type GraphConnectedStats,\n getConnectedFactIds as getConnectedFactIdsHelper,\n getLinksFrom as getLinksFromHelper,\n getLinksTo as getLinksToHelper,\n refreshFactDegrees as refreshFactDegreesHelper,\n strengthenRelatedLinksBatch as strengthenRelatedLinksBatchHelper,\n} from \"./links.js\";\nimport {\n logRecall as logRecallImpl,\n pruneRecallLog as pruneRecallLogImpl,\n type RetierReport,\n retierFacts as retierFactsImpl,\n runCompaction as runCompactionImpl,\n setFactTier,\n setPreserveTags as setPreserveTagsImpl,\n setPreserveUntil as setPreserveUntilImpl,\n type TieringOptions,\n trimToBudget as trimToBudgetImpl,\n} from \"./maintenance.js\";\nimport { getScanCursor as getScanCursorHelper, updateScanCursor as updateScanCursorHelper } from \"./scan-cursors.js\";\nimport { bootstrapFactsCoreSchema } from \"./schema-bootstrap.js\";\nimport {\n findByIdPrefix as findByIdPrefixImpl,\n findByIdPrefixScoped as findByIdPrefixScopedImpl,\n lookupFacts,\n searchFacts,\n} from \"./search.js\";\nimport { getTokenBudgetStatus as getTokenBudgetStatusImpl } from \"./stats.js\";\nimport type { MemoryLinkType } from \"./types.js\";\nimport {\n countCanonicalEmbeddings as countCanonicalEmbeddingsImpl,\n deleteEmbeddings as deleteEmbeddingsImpl,\n deleteVariants as deleteVariantsImpl,\n estimateStorageBytesOnDisk,\n getEmbeddingsByModel as getEmbeddingsByModelImpl,\n getEmbeddings as getEmbeddingsImpl,\n getVariants as getVariantsImpl,\n hasVariants as hasVariantsImpl,\n storeEmbedding as storeEmbeddingImpl,\n storeVariant as storeVariantImpl,\n} from \"./variants.js\";\n\nexport class FactsDBLayer1 extends BaseSqliteStore {\n // Responsibility note:\n // - This class is the stable API boundary.\n // - Extracted implementation modules under backends/facts-db/ own links/reinforcement/scan-cursor logic.\n protected readonly dbPath: string;\n protected readonly fuzzyDedupe: boolean;\n protected readonly storeConfig?: StoreConfig;\n protected readonly supersededTextsCacheMgr = new SupersededTextsCache(5 * 60_000);\n private readonly storeDedupeWarnedKeys = new Set<string>();\n\n constructor(dbPath: string, options?: { fuzzyDedupe?: boolean; storeConfig?: StoreConfig }) {\n mkdirSync(dirname(dbPath), { recursive: true });\n const db = new DatabaseSync(dbPath);\n\n try {\n FactsDBLayer1.verifyFts5Support(db);\n } catch (err) {\n try {\n db.close();\n } catch {\n // Ignore close errors during failure cleanup\n }\n throw err;\n }\n\n super(db, {\n foreignKeys: true,\n customPragmas: [\n \"PRAGMA synchronous = NORMAL\",\n \"PRAGMA wal_autocheckpoint = 1000\",\n // Perf: 64MB page cache (up from 2MB default) — avoids repeated disk reads for\n // the ~192MB facts DB during FTS two-phase lookups. Single-connection model so\n // this is the only consumer. Env: OPENCLAW_FACTS_CACHE_SIZE_KB to override.\n `PRAGMA cache_size = -${process.env.OPENCLAW_FACTS_CACHE_SIZE_KB ?? \"64000\"}`,\n // Perf: 256MB memory-mapped I/O — lets the OS page cache serve reads without\n // crossing the user/kernel boundary. Env: OPENCLAW_FACTS_MMAP_SIZE to override.\n `PRAGMA mmap_size = ${process.env.OPENCLAW_FACTS_MMAP_SIZE ?? \"268435456\"}`,\n \"PRAGMA temp_store = MEMORY\",\n ],\n });\n this.dbPath = dbPath;\n tryRestrictSqliteDbFileMode(dbPath);\n this.fuzzyDedupe = options?.fuzzyDedupe ?? false;\n this.storeConfig = options?.storeConfig;\n\n bootstrapFactsCoreSchema(this.liveDb);\n\n // Run all schema migrations\n runFactsMigrations(this.liveDb);\n }\n\n /** Filesystem path to the SQLite database file (for maintenance sidecars next to the DB). */\n get sqlitePath(): string {\n return this.dbPath;\n }\n\n /**\n * Hard-startup guard for SQLite FTS5 support.\n *\n * Some Node.js/SQLite builds can run without FTS5 enabled, which would cause\n * hybrid retrieval to silently degrade to vector-only once the FTS strategy\n * starts failing. Probe FTS5 explicitly and fail fast with an actionable error.\n */\n /** @deprecated Prefer importing `verifyFts5Support` from `./facts-db/db-connection.js` (kept for tests). */\n static verifyFts5Support(db: DatabaseSync): void {\n verifyFts5Support(db);\n }\n\n /** Return the cursor for the given scan type, or null if never run. */\n getScanCursor(scanType: string): {\n lastSessionTs: number;\n lastRunAt: number;\n sessionsProcessed: number;\n lastSessionFile?: string;\n } | null {\n return getScanCursorHelper(this.liveDb, scanType);\n }\n\n /**\n * Upsert the cursor after a successful incremental scan.\n * @param lastSessionTs Timestamp of the newest session processed (file mtime). Pass `Date.now()`\n * when no session watermark is available (e.g. self-correction). Pass `0` when no sessions\n * were processed — `last_session_ts` will not be updated in that case.\n * @param sessionsProcessed Number of sessions processed in this run.\n * @param lastSessionFile Optional tie-breaker when multiple sessions share the same mtime.\n */\n updateScanCursor(scanType: string, lastSessionTs: number, sessionsProcessed: number, lastSessionFile?: string): void {\n updateScanCursorHelper(this.liveDb, scanType, lastSessionTs, sessionsProcessed, lastSessionFile);\n }\n\n /**\n * Store a contextual variant text for a fact.\n * Returns the new row id.\n */\n storeVariant(factId: string, variantType: string, variantText: string): number {\n return storeVariantImpl(this.liveDb, factId, variantType, variantText);\n }\n\n getVariants(factId: string): Array<{\n id: number;\n variantType: string;\n variantText: string;\n createdAt: string;\n }> {\n return getVariantsImpl(this.liveDb, factId);\n }\n\n hasVariants(factId: string): boolean {\n return hasVariantsImpl(this.liveDb, factId);\n }\n\n deleteVariants(factId: string): void {\n deleteVariantsImpl(this.liveDb, factId);\n }\n\n storeEmbedding(factId: string, model: string, variant: string, embedding: Float32Array, dimensions: number): void {\n storeEmbeddingImpl(this.liveDb, factId, model, variant, embedding, dimensions);\n }\n\n getEmbeddings(factId: string): Array<{ model: string; variant: string; embedding: Float32Array }> {\n return getEmbeddingsImpl(this.liveDb, factId);\n }\n\n getEmbeddingsByModel(model: string, limit?: number): Array<{ factId: string; embedding: Float32Array }> {\n return getEmbeddingsByModelImpl(this.liveDb, model, limit);\n }\n\n deleteEmbeddings(factId: string): void {\n deleteEmbeddingsImpl(this.liveDb, factId);\n }\n\n /** Re-apply connection pragmas (used on initial open and auto-reopen). */\n protected getSubsystemName(): string {\n return \"facts-db\";\n }\n\n countCanonicalEmbeddings(): number {\n return countCanonicalEmbeddingsImpl(this.liveDb);\n }\n\n estimateStorageBytes(): {\n sqliteBytes: number;\n walBytes: number;\n shmBytes: number;\n } {\n return estimateStorageBytesOnDisk(this.dbPath);\n }\n\n store(\n entry: StoreFactInput,\n options?: {\n vectorCandidates?: ReadonlyArray<{ id: string; score: number }>;\n /**\n * Namespace for warn-once keys when store dedupe falls back to lexical-only because\n * no `vectorCandidates` were provided (e.g. \"reflection\", \"extract-directives\").\n */\n warnContext?: string;\n /** Suppress the vector-candidates-missing warning entirely (caller will summarise). */\n suppressVectorFallbackWarning?: boolean;\n /** Trusted edit path for re-storing already persisted legacy guarded facts. */\n allowPreStoreGuardBypass?: boolean;\n },\n ): MemoryEntry {\n const result = this.storeWithResult(entry, options);\n // Skipped results carry a non-addressable placeholder entry (id === \"\") for\n // legacy store() callers. storeWithResult() callers must check result.skipped\n // before vector, supersession, provenance, or event side effects.\n return result.entry;\n }\n\n storeWithResult(\n entry: StoreFactInput,\n options?: {\n vectorCandidates?: ReadonlyArray<{ id: string; score: number }>;\n /**\n * Namespace for warn-once keys when store dedupe falls back to lexical-only because\n * no `vectorCandidates` were provided (e.g. \"reflection\", \"extract-directives\").\n */\n warnContext?: string;\n /** Suppress the vector-candidates-missing warning entirely (caller will summarise). */\n suppressVectorFallbackWarning?: boolean;\n /** Trusted edit path for re-storing already persisted legacy guarded facts. */\n allowPreStoreGuardBypass?: boolean;\n },\n ): StoreFactResult {\n const warnOnce = (key: string, message: string): void => {\n if (this.storeDedupeWarnedKeys.has(key)) return;\n this.storeDedupeWarnedKeys.add(key);\n process.stderr.write(`${message}\n`);\n };\n return storeFact(\n {\n db: this.liveDb,\n fuzzyDedupe: this.fuzzyDedupe,\n storeConfig: this.storeConfig,\n getById: (id) => this.getById(id),\n invalidateSupersededCache: () => {\n this.supersededTextsCacheMgr.invalidate();\n },\n vectorCandidates: options?.vectorCandidates,\n warnOnce,\n warnOnceKey: options?.warnContext,\n suppressVectorFallbackWarning: options?.suppressVectorFallbackWarning,\n allowPreStoreGuardBypass: options?.allowPreStoreGuardBypass,\n },\n entry,\n );\n }\n\n statsDailyWrites(): Array<{ source: string; day: string; count: number; dropped: number; evicted: number }> {\n return statsDailyWritesImpl(this.liveDb);\n }\n\n /** Update recall_count and last_accessed for facts (public for progressive disclosure). Bulk UPDATE to avoid N+1. */\n refreshAccessedFacts(ids: string[]): void {\n refreshAccessedFactsImpl(this.liveDb, ids);\n }\n\n /** Update indexed_count and last_indexed for index-only exposures (#1559). Does NOT inflate recall_count. */\n refreshIndexedFacts(ids: string[]): void {\n refreshIndexedFactsImpl(this.liveDb, ids);\n }\n\n /** Record a memory_recall invocation outcome for hit-rate tracking (Issue #148). */\n logRecall(hit: boolean, occurredAtSec?: number): void {\n logRecallImpl(this.liveDb, hit, occurredAtSec);\n }\n\n /** Prune recall_log entries older than N days to prevent unbounded growth (Issue #148). */\n pruneRecallLog(olderThanDays = 30): number {\n return pruneRecallLogImpl(this.liveDb, olderThanDays);\n }\n\n /** Read the last stored embedding provider+model metadata (Issue #153). */\n getEmbeddingMeta(): { provider: string; model: string } | null {\n const row = this.liveDb.prepare(\"SELECT provider, model FROM embedding_meta WHERE id = 1\").get() as\n | { provider: string; model: string }\n | undefined;\n if (!row) return null;\n return { provider: row.provider, model: row.model };\n }\n\n /** Persist the active embedding provider+model metadata (Issue #153). */\n setEmbeddingMeta(provider: string, model: string): void {\n const nowSec = Math.floor(Date.now() / 1000);\n this.liveDb\n .prepare(\n `INSERT INTO embedding_meta (id, provider, model, updated_at)\n VALUES (1, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET provider = excluded.provider, model = excluded.model, updated_at = excluded.updated_at`,\n )\n .run(provider, model, nowSec);\n }\n\n /** Record which embedding model generated the stored vector for a fact (Issue #153). */\n setEmbeddingModel(id: string, model: string | null): void {\n this.liveDb.prepare(\"UPDATE facts SET embedding_model = ? WHERE id = ?\").run(model, id);\n }\n\n /**\n * Restore fact text after a failed dedupe-merge follow-up step (re-embed/vector store),\n * preserving the original row instead of deleting it.\n */\n restoreMergedFactText(id: string, text: string): boolean {\n const res = this.liveDb\n .prepare(\"UPDATE facts SET text = ?, normalized_hash = ? WHERE id = ?\")\n .run(text, normalizedHash(text), id);\n return Number(res.changes ?? 0) > 0;\n }\n\n /** Get HOT-tier facts for session context, capped by token budget. */\n getHotFacts(maxTokens: number, scopeFilter?: ScopeFilter | null): SearchResult[] {\n return getHotFactsImpl(this.liveDb, maxTokens, scopeFilter);\n }\n\n /** Set a fact's tier. */\n setTier(id: string, tier: MemoryTier): boolean {\n return setFactTier(this.liveDb, id, tier);\n }\n\n /** Compaction — retier facts by structural shape, salience, and inactivity. */\n runCompaction(opts: TieringOptions): RetierReport {\n return runCompactionImpl(this.liveDb, opts);\n }\n\n /** Retier facts with optional dry-run support for operator CLI migrations. */\n retier(opts: TieringOptions, apply = true): RetierReport {\n return retierFactsImpl(this.liveDb, opts, apply);\n }\n\n /**\n * Token-budget tiered trimming for context compaction (Issue #792).\n *\n * Retention tiers (never trimmed = P0):\n * - Edict-tagged facts (tag 'edict')\n * - Verified facts (present in verified_facts table)\n * - Facts with active preserveUntil (epoch seconds in future)\n * - Facts with non-empty preserveTags\n *\n * Remaining facts sorted by trim priority:\n * - P1: importance > 0.8 AND created within the last hour\n * - P2: importance 0.5 – 0.8\n * - P3: importance < 0.5\n *\n * Trimming proceeds P3 → P2 → P1 until within budget.\n * Token estimate: Math.ceil(chars / 3.8)\n *\n * Returns a summary of what would be / was trimmed.\n */\n trimToBudget(\n tokenBudget: number,\n simulate = false,\n ): {\n simulate: boolean;\n budget: number;\n beforeTokens: number;\n afterTokens: number;\n trimmed: Array<{\n id: string;\n textPreview: string;\n tier: string;\n importance: number;\n tokenCost: number;\n }>;\n preserved: Array<{ id: string; reason: string }>;\n error?: string;\n } {\n return trimToBudgetImpl(this.liveDb, tokenBudget, simulate);\n }\n\n /**\n * Set or clear preserve_until on a fact.\n * If untilSec is null, clears any existing preserve_until.\n * Returns the updated MemoryEntry or null if not found.\n */\n setPreserveUntil(id: string, untilSec: number | null): MemoryEntry | null {\n return setPreserveUntilImpl(this.liveDb, (i) => this.getById(i), id, untilSec);\n }\n\n /**\n * Add or remove preserve_tags on a fact.\n * mode 'set': replaces all tags with the given array.\n * mode 'add': adds the given tags (deduped).\n * mode 'remove': removes the given tags.\n * Returns the updated MemoryEntry or null if not found.\n */\n setPreserveTags(id: string, tags: string[], mode: \"set\" | \"add\" | \"remove\"): MemoryEntry | null {\n return setPreserveTagsImpl(this.liveDb, (i) => this.getById(i), id, tags, mode);\n }\n\n /**\n * Compute current token estimate for all non-superseded, non-expired facts.\n * Returns { totalTokens, byTier: { p0, p1, p2, p3 }, factCount: { p0, p1, p2, p3 } }.\n */\n getTokenBudgetStatus(): {\n totalTokens: number;\n budget: number;\n overflow: number;\n byTier: { p0: number; p1: number; p2: number; p3: number };\n factCount: { p0: number; p1: number; p2: number; p3: number };\n } {\n return getTokenBudgetStatusImpl(this.liveDb);\n }\n\n search(\n query: string,\n limit = 5,\n options: {\n includeExpired?: boolean;\n tag?: string;\n includeSuperseded?: boolean;\n /** Point-in-time: only facts valid at this epoch second. */\n asOf?: number;\n /** 'warm' = only warm tier (default), 'all' = warm + cold. */\n tierFilter?: \"warm\" | \"all\";\n /** Scope filter — only return global + matching user/agent/session. */\n scopeFilter?: ScopeFilter | null;\n /** Reinforcement boost — added to score when reinforced_count > 0 (default: 0.1). */\n reinforcementBoost?: number;\n /** Weight applied to diversity score when calculating effective boost (default: 1.0). */\n diversityWeight?: number;\n /**\n * Interactive auto-recall hot path: cap FTS OR-term explosion and avoid loading full fact rows\n * until top matches are chosen (reduces WhatsApp/gateway stalls from huge MATCH + wide SELECT f.*).\n */\n interactiveFtsFastPath?: boolean;\n } = {},\n ): SearchResult[] {\n return searchFacts(this.liveDb, query, limit, options);\n }\n\n lookup(\n entity: string,\n key?: string,\n tag?: string,\n options?: {\n includeSuperseded?: boolean;\n asOf?: number;\n scopeFilter?: ScopeFilter | null;\n limit?: number;\n },\n ): SearchResult[] {\n return lookupFacts(this.liveDb, entity, key, tag, options);\n }\n\n /** Find a fact ID by prefix (for truncated ID resolution).\n * Returns { id } for unique match, { ambiguous, count } for multiple, or null for no match.\n * Requires at least 4 hex chars to prevent full-table scans and reduce ambiguity. */\n findByIdPrefix(prefix: string): { id: string } | { ambiguous: true; count: number } | null {\n return findByIdPrefixImpl(this.liveDb, prefix);\n }\n\n /** Find a fact ID by prefix with scope filtering (for public API).\n * Returns { id } for unique match, { ambiguous, count } for multiple, or { id: null } for no match.\n * Requires at least 4 hex chars. Applies UUID dash normalization for bare hex strings. */\n findByIdPrefixScoped(\n prefix: string,\n scopeFilter: ScopeFilter | null | undefined,\n ): { id: string } | { ambiguous: true; count: number } | { id: null } {\n return findByIdPrefixScopedImpl(this.liveDb, prefix, scopeFilter);\n }\n\n delete(id: string): boolean {\n return deleteFact(this.liveDb, id);\n }\n\n /** Exact match or dedupe policy would block a new insert (per-source if `source` set; global probe if omitted, #1202). */\n hasDuplicate(\n text: string,\n source?: string,\n structured?: { category?: string | null; entity?: string | null; key?: string | null; value?: string | null },\n ): boolean {\n return hasDuplicateText(this.liveDb, this.fuzzyDedupe, text, this.storeConfig, source, structured);\n }\n\n /**\n * Return the ID of an existing fact whose normalised hash matches `text`, or null if none.\n * O(1) index lookup. Useful for resolving the canonical fact ID when `hasDuplicate()` returns true.\n */\n getDuplicateIdByNormalizedHash(text: string): string | null {\n return getDuplicateIdByNormalizedHash(this.liveDb, text);\n }\n\n /** Mark a fact as superseded by a new fact. Sets superseded_at, superseded_by, and valid_until (bi-temporal). */\n supersede(oldId: string, newId: string | null): boolean {\n const nowSec = Math.floor(Date.now() / 1000);\n const result = this.liveDb\n .prepare(\n \"UPDATE facts SET superseded_at = ?, superseded_by = ?, valid_until = ? WHERE id = ? AND superseded_at IS NULL\",\n )\n .run(nowSec, newId, nowSec, oldId);\n if (result.changes > 0) {\n this.invalidateSupersededCache();\n }\n return result.changes > 0;\n }\n\n /**\n * Invalidate cached superseded-text snapshots after supersede-equivalent SQL on `liveDb`\n * (e.g. maintenance running inside an explicit transaction where {@link supersede} is not used).\n */\n invalidateSupersededTextsCache(): void {\n this.invalidateSupersededCache();\n }\n\n /** Find top-N most similar existing facts by entity+key overlap and normalized text. Used for ADD/UPDATE/DELETE classification. */\n findSimilarForClassification(\n text: string,\n entity: string | null,\n key: string | null,\n limit = 5,\n scope: MemoryScope | null = null,\n scopeTarget: string | null = null,\n ): MemoryEntry[] {\n return findSimilarForClassificationImpl(this.liveDb, text, entity, key, limit, scope, scopeTarget);\n }\n\n /** For consolidation (2.4): fetch facts with id, text, category, entity, key. Order by created_at DESC. Excludes superseded. */\n getFactsForConsolidation(limit: number): Array<{\n id: string;\n text: string;\n category: string;\n entity: string | null;\n key: string | null;\n }> {\n return getFactsForConsolidationImpl(this.liveDb, limit);\n }\n\n /** Alias for getById for CLI compatibility. */\n get(id: string): MemoryEntry | null {\n return this.getById(id);\n }\n\n /** Get one fact by id (for merge category). Returns null if not found. When asOf is set, returns null if the fact was not valid at that time. When scopeFilter is set, returns null if the fact is not in scope. */\n getById(id: string, options?: { asOf?: number; scopeFilter?: ScopeFilter | null }): MemoryEntry | null {\n return getByIdImpl(this.liveDb, id, options);\n }\n\n /** Batch get facts by id. Returns a Map of id → entry after asOf/scope filtering. */\n getByIds(ids: string[], options?: { asOf?: number; scopeFilter?: ScopeFilter | null }): Map<string, MemoryEntry> {\n return getByIdsImpl(this.liveDb, ids, options);\n }\n\n /** Create a typed link between two facts. Returns link id. */\n createLink(sourceFactId: string, targetFactId: string, linkType: MemoryLinkType, strength = 1.0): string {\n return createLinkHelper(this.liveDb, sourceFactId, targetFactId, linkType, strength);\n }\n\n /** Hebbian: Create or strengthen RELATED_TO link between two facts recalled together. */\n createOrStrengthenRelatedLink(factIdA: string, factIdB: string, deltaStrength = 0.1): void {\n createOrStrengthenRelatedLinkHelper(this.liveDb, factIdA, factIdB, deltaStrength);\n }\n\n /**\n * Hebbian batch: strengthen RELATED_TO links for all pairs in a single SQLite transaction.\n * Reduces O(n²) individual round-trips to 1 transaction regardless of pair count.\n */\n strengthenRelatedLinksBatch(pairs: [string, string][], deltaStrength = 0.1): void {\n strengthenRelatedLinksBatchHelper(this.liveDb, pairs, deltaStrength);\n }\n\n /** Get links from a fact (outgoing). */\n getLinksFrom(factId: string): Array<{\n id: string;\n targetFactId: string;\n linkType: string;\n strength: number;\n }> {\n return getLinksFromHelper(this.liveDb, factId);\n }\n\n /** Get links to a fact (incoming). */\n getLinksTo(factId: string): Array<{\n id: string;\n sourceFactId: string;\n linkType: string;\n strength: number;\n }> {\n return getLinksToHelper(this.liveDb, factId);\n }\n\n /** BFS from given fact IDs up to maxDepth hops. Returns all connected fact IDs (including the seed set).\n * CONTRADICTS links are excluded from traversal — they would otherwise pollute graph-based recall\n * with unrelated contradicted facts and cause traversal explosion when a fact has many contradictions.\n */\n getConnectedFactIds(\n factIds: string[],\n maxDepth: number,\n options?: { hubDegreeCap?: number | null; stats?: GraphConnectedStats },\n ): string[] {\n return getConnectedFactIdsHelper(this.liveDb, factIds, maxDepth, options);\n }\n\n /**\n * Perform graph expansion using a recursive CTE, returning expanded nodes with hop count and path info.\n * This is used by graph-retrieval.ts to avoid N+1 query patterns.\n *\n * @param seedFactIds - Array of seed fact IDs to start expansion from\n * @param maxDepth - Maximum traversal depth\n * @returns Array of expanded nodes with factId, seedId, hopCount, and path (JSON array of link steps)\n */\n expandGraphWithCTE(\n seedFactIds: string[],\n maxDepth: number,\n options?: {\n asOf?: number;\n scopeFilter?: { userId?: string; agentId?: string; sessionId?: string };\n hubDegreeCap?: number | null;\n },\n ): Array<{\n factId: string;\n seedId: string;\n hopCount: number;\n path: string;\n }> {\n return expandGraphWithCTEHelper(this.liveDb, seedFactIds, maxDepth, options);\n }\n\n /**\n * Refresh denormalized `out_degree` / `in_degree` columns on `facts` (#1192). The dream-cycle\n * calls this once per night so the BFS hub guard avoids running `COUNT(*) FROM memory_links`\n * on every traversal.\n */\n refreshFactDegrees(): { updated: number } {\n return refreshFactDegreesHelper(this.liveDb);\n }\n\n /** Invalidate superseded texts cache (called after supersede operations). */\n protected invalidateSupersededCache(): void {\n this.supersededTextsCacheMgr.invalidate();\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAgFA,IAAa,gBAAb,MAAa,sBAAsB,gBAAgB;CAIjD;CACA;CACA;CACA,0BAA6C,IAAI,qBAAqB,IAAI,GAAM;CAChF,wCAAyC,IAAI,IAAY;CAEzD,YAAY,QAAgB,SAAgE;EAC1F,UAAU,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;EAC9C,MAAM,KAAK,IAAI,aAAa,MAAM;EAElC,IAAI;GACF,cAAc,kBAAkB,EAAE;EACpC,SAAS,KAAK;GACZ,IAAI;IACF,GAAG,MAAM;GACX,QAAQ,CAER;GACA,MAAM;EACR;EAEA,MAAM,IAAI;GACR,aAAa;GACb,eAAe;IACb;IACA;IAIA,wBAAwB,QAAQ,IAAI,gCAAgC;IAGpE,sBAAsB,QAAQ,IAAI,4BAA4B;IAC9D;GACF;EACF,CAAC;EACD,KAAK,SAAS;EACd,4BAA4B,MAAM;EAClC,KAAK,cAAc,SAAS,eAAe;EAC3C,KAAK,cAAc,SAAS;EAE5B,yBAAyB,KAAK,MAAM;EAGpC,mBAAmB,KAAK,MAAM;CAChC;;CAGA,IAAI,aAAqB;EACvB,OAAO,KAAK;CACd;;;;;;;;;CAUA,OAAO,kBAAkB,IAAwB;EAC/C,kBAAkB,EAAE;CACtB;;CAGA,cAAc,UAKL;EACP,OAAOA,cAAoB,KAAK,QAAQ,QAAQ;CAClD;;;;;;;;;CAUA,iBAAiB,UAAkB,eAAuB,mBAA2B,iBAAgC;EACnH,iBAAuB,KAAK,QAAQ,UAAU,eAAe,mBAAmB,eAAe;CACjG;;;;;CAMA,aAAa,QAAgB,aAAqB,aAA6B;EAC7E,OAAOC,aAAiB,KAAK,QAAQ,QAAQ,aAAa,WAAW;CACvE;CAEA,YAAY,QAKT;EACD,OAAOC,YAAgB,KAAK,QAAQ,MAAM;CAC5C;CAEA,YAAY,QAAyB;EACnC,OAAOC,YAAgB,KAAK,QAAQ,MAAM;CAC5C;CAEA,eAAe,QAAsB;EACnC,eAAmB,KAAK,QAAQ,MAAM;CACxC;CAEA,eAAe,QAAgB,OAAe,SAAiB,WAAyB,YAA0B;EAChH,eAAmB,KAAK,QAAQ,QAAQ,OAAO,SAAS,WAAW,UAAU;CAC/E;CAEA,cAAc,QAAoF;EAChG,OAAOC,cAAkB,KAAK,QAAQ,MAAM;CAC9C;CAEA,qBAAqB,OAAe,OAAoE;EACtG,OAAOC,qBAAyB,KAAK,QAAQ,OAAO,KAAK;CAC3D;CAEA,iBAAiB,QAAsB;EACrC,iBAAqB,KAAK,QAAQ,MAAM;CAC1C;;CAGA,mBAAqC;EACnC,OAAO;CACT;CAEA,2BAAmC;EACjC,OAAOC,yBAA6B,KAAK,MAAM;CACjD;CAEA,uBAIE;EACA,OAAO,2BAA2B,KAAK,MAAM;CAC/C;CAEA,MACE,OACA,SAYa;EAKb,OAJe,KAAK,gBAAgB,OAAO,OAI/B,EAAE;CAChB;CAEA,gBACE,OACA,SAYiB;EACjB,MAAM,YAAY,KAAa,YAA0B;GACvD,IAAI,KAAK,sBAAsB,IAAI,GAAG,GAAG;GACzC,KAAK,sBAAsB,IAAI,GAAG;GAClC,QAAQ,OAAO,MAAM,GAAG,QAAQ;CACrC;EACG;EACA,OAAO,UACL;GACE,IAAI,KAAK;GACT,aAAa,KAAK;GAClB,aAAa,KAAK;GAClB,UAAU,OAAO,KAAK,QAAQ,EAAE;GAChC,iCAAiC;IAC/B,KAAK,wBAAwB,WAAW;GAC1C;GACA,kBAAkB,SAAS;GAC3B;GACA,aAAa,SAAS;GACtB,+BAA+B,SAAS;GACxC,0BAA0B,SAAS;EACrC,GACA,KACF;CACF;CAEA,mBAA4G;EAC1G,OAAOC,iBAAqB,KAAK,MAAM;CACzC;;CAGA,qBAAqB,KAAqB;EACxC,qBAAyB,KAAK,QAAQ,GAAG;CAC3C;;CAGA,oBAAoB,KAAqB;EACvC,oBAAwB,KAAK,QAAQ,GAAG;CAC1C;;CAGA,UAAU,KAAc,eAA8B;EACpD,UAAc,KAAK,QAAQ,KAAK,aAAa;CAC/C;;CAGA,eAAe,gBAAgB,IAAY;EACzC,OAAOC,eAAmB,KAAK,QAAQ,aAAa;CACtD;;CAGA,mBAA+D;EAC7D,MAAM,MAAM,KAAK,OAAO,QAAQ,yDAAyD,EAAE,IAAI;EAG/F,IAAI,CAAC,KAAK,OAAO;EACjB,OAAO;GAAE,UAAU,IAAI;GAAU,OAAO,IAAI;EAAM;CACpD;;CAGA,iBAAiB,UAAkB,OAAqB;EACtD,MAAM,SAAS,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;EAC3C,KAAK,OACF,QACC;;8HAGF,EACC,IAAI,UAAU,OAAO,MAAM;CAChC;;CAGA,kBAAkB,IAAY,OAA4B;EACxD,KAAK,OAAO,QAAQ,mDAAmD,EAAE,IAAI,OAAO,EAAE;CACxF;;;;;CAMA,sBAAsB,IAAY,MAAuB;EACvD,MAAM,MAAM,KAAK,OACd,QAAQ,6DAA6D,EACrE,IAAI,MAAM,eAAe,IAAI,GAAG,EAAE;EACrC,OAAO,OAAO,IAAI,WAAW,CAAC,IAAI;CACpC;;CAGA,YAAY,WAAmB,aAAkD;EAC/E,OAAOC,YAAgB,KAAK,QAAQ,WAAW,WAAW;CAC5D;;CAGA,QAAQ,IAAY,MAA2B;EAC7C,OAAO,YAAY,KAAK,QAAQ,IAAI,IAAI;CAC1C;;CAGA,cAAc,MAAoC;EAChD,OAAOC,cAAkB,KAAK,QAAQ,IAAI;CAC5C;;CAGA,OAAO,MAAsB,QAAQ,MAAoB;EACvD,OAAOC,YAAgB,KAAK,QAAQ,MAAM,KAAK;CACjD;;;;;;;;;;;;;;;;;;;;CAqBA,aACE,aACA,WAAW,OAeX;EACA,OAAOC,aAAiB,KAAK,QAAQ,aAAa,QAAQ;CAC5D;;;;;;CAOA,iBAAiB,IAAY,UAA6C;EACxE,OAAOC,iBAAqB,KAAK,SAAS,MAAM,KAAK,QAAQ,CAAC,GAAG,IAAI,QAAQ;CAC/E;;;;;;;;CASA,gBAAgB,IAAY,MAAgB,MAAoD;EAC9F,OAAOC,gBAAoB,KAAK,SAAS,MAAM,KAAK,QAAQ,CAAC,GAAG,IAAI,MAAM,IAAI;CAChF;;;;;CAMA,uBAME;EACA,OAAOC,qBAAyB,KAAK,MAAM;CAC7C;CAEA,OACE,OACA,QAAQ,GACR,UAmBI,CAAC,GACW;EAChB,OAAO,YAAY,KAAK,QAAQ,OAAO,OAAO,OAAO;CACvD;CAEA,OACE,QACA,KACA,KACA,SAMgB;EAChB,OAAO,YAAY,KAAK,QAAQ,QAAQ,KAAK,KAAK,OAAO;CAC3D;;;;CAKA,eAAe,QAA4E;EACzF,OAAOC,eAAmB,KAAK,QAAQ,MAAM;CAC/C;;;;CAKA,qBACE,QACA,aACoE;EACpE,OAAOC,qBAAyB,KAAK,QAAQ,QAAQ,WAAW;CAClE;CAEA,OAAO,IAAqB;EAC1B,OAAO,WAAW,KAAK,QAAQ,EAAE;CACnC;;CAGA,aACE,MACA,QACA,YACS;EACT,OAAO,iBAAiB,KAAK,QAAQ,KAAK,aAAa,MAAM,KAAK,aAAa,QAAQ,UAAU;CACnG;;;;;CAMA,+BAA+B,MAA6B;EAC1D,OAAO,+BAA+B,KAAK,QAAQ,IAAI;CACzD;;CAGA,UAAU,OAAe,OAA+B;EACtD,MAAM,SAAS,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;EAC3C,MAAM,SAAS,KAAK,OACjB,QACC,+GACF,EACC,IAAI,QAAQ,OAAO,QAAQ,KAAK;EACnC,IAAI,OAAO,UAAU,GACnB,KAAK,0BAA0B;EAEjC,OAAO,OAAO,UAAU;CAC1B;;;;;CAMA,iCAAuC;EACrC,KAAK,0BAA0B;CACjC;;CAGA,6BACE,MACA,QACA,KACA,QAAQ,GACR,QAA4B,MAC5B,cAA6B,MACd;EACf,OAAOC,6BAAiC,KAAK,QAAQ,MAAM,QAAQ,KAAK,OAAO,OAAO,WAAW;CACnG;;CAGA,yBAAyB,OAMtB;EACD,OAAOC,yBAA6B,KAAK,QAAQ,KAAK;CACxD;;CAGA,IAAI,IAAgC;EAClC,OAAO,KAAK,QAAQ,EAAE;CACxB;;CAGA,QAAQ,IAAY,SAAmF;EACrG,OAAOC,QAAY,KAAK,QAAQ,IAAI,OAAO;CAC7C;;CAGA,SAAS,KAAe,SAAyF;EAC/G,OAAOC,SAAa,KAAK,QAAQ,KAAK,OAAO;CAC/C;;CAGA,WAAW,cAAsB,cAAsB,UAA0B,WAAW,GAAa;EACvG,OAAOC,WAAiB,KAAK,QAAQ,cAAc,cAAc,UAAU,QAAQ;CACrF;;CAGA,8BAA8B,SAAiB,SAAiB,gBAAgB,IAAW;EACzF,8BAAoC,KAAK,QAAQ,SAAS,SAAS,aAAa;CAClF;;;;;CAMA,4BAA4B,OAA2B,gBAAgB,IAAW;EAChF,4BAAkC,KAAK,QAAQ,OAAO,aAAa;CACrE;;CAGA,aAAa,QAKV;EACD,OAAOC,aAAmB,KAAK,QAAQ,MAAM;CAC/C;;CAGA,WAAW,QAKR;EACD,OAAOC,WAAiB,KAAK,QAAQ,MAAM;CAC7C;;;;;CAMA,oBACE,SACA,UACA,SACU;EACV,OAAOC,oBAA0B,KAAK,QAAQ,SAAS,UAAU,OAAO;CAC1E;;;;;;;;;CAUA,mBACE,aACA,UACA,SAUC;EACD,OAAOC,mBAAyB,KAAK,QAAQ,aAAa,UAAU,OAAO;CAC7E;;;;;;CAOA,qBAA0C;EACxC,OAAOC,mBAAyB,KAAK,MAAM;CAC7C;;CAGA,4BAA4C;EAC1C,KAAK,wBAAwB,WAAW;CAC1C;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"facts-db-layer2.js","names":["getRecentFactsImpl","getAllImpl","getCountImpl","getAllIdsImpl","getBatchImpl","listFactsImpl","countFactsImpl","listExpiredFactIdsPendingPruneImpl","listLowConfidenceFactIdsPendingPruneImpl","listFactIdsToBeDeletedByDecayRunImpl","pruneExpiredImpl","pruneExpiredWithDetailsImpl","listSessionFactIdsPendingPruneImpl","pruneSessionScopeImpl","promoteScopeImpl","decayConfidenceImpl","decayConfidenceWithDetailsImpl","confirmFactImpl","boostConfidenceHelper","reinforceFactHelper","getReinforcementEventsHelper","calculateDiversityScoreHelper","reinforceProcedureHelper","saveCheckpointImpl","restoreCheckpointImpl","statsBreakdownImpl","statsBreakdownByTierImpl","statsBreakdownBySourceImpl","statsBreakdownByCategoryImpl","statsBreakdownByDecayClassImpl","listForDashboardImpl","uniqueMemoryCategoriesImpl","auditCategoriesImpl","remapCategoryImpl","proposedCategoriesImpl","countVectorlessActiveFactsImpl","vectorlessActiveFactsBySourceImpl","listVectorlessActiveFactsImpl","getProceduresForAuditImpl","proceduresCountImpl","proceduresValidatedCountImpl","proceduresValidatedSinceImpl","proceduresPromotedCountImpl","linksCountImpl","directivesCountImpl","metaPatternsCountImpl","entityCountImpl","topEntitiesImpl","topEntitiesFilteredImpl","cleanEntityStopwordsImpl","estimateStoredTokensImpl","estimateStoredTokensByTierImpl","countExpiredFactsImpl","backfillDecayClassesImpl","reclassifyDecayClassesImpl","lifecycleEntityReportImpl","expireBySourcePatternImpl","getByCategoryImpl","listFactsByCategoryImpl","getProjectFactsImpl","listDirectivesImpl","getMaxCreatedAtByCategoryImpl","updateCategoryImpl","getUnattemptedOtherFactsImpl","procedureFeedbackImpl","getProcedureVersionsImpl","getProcedureFailuresImpl","upsertProcedureImpl","listProceduresImpl","listProceduresUpdatedInLastNDaysImpl","getProcedureByIdImpl","findProcedureByTaskPatternImpl","searchProceduresImpl","searchProceduresRankedImpl","getNegativeProceduresMatchingImpl","recordProcedureSuccessImpl","recordProcedureFailureImpl","getProceduresReadyForSkillImpl","markProcedurePromotedImpl","triageProceduresImpl","getStaleProceduresImpl","listGeneratedSkillProceduresImpl","getGeneratedSkillByNameImpl","recordGeneratedSkillTelemetryImpl","listGeneratedSkillTelemetryImpl","markGeneratedSkillTelemetryFalsePositiveImpl","setGeneratedSkillLifecycleStateImpl","refreshGeneratedSkillLifecycleStateImpl","buildGeneratedSkillTelemetryReportImpl","reconcileGeneratedSkillDiskStateImpl"],"sources":["../../../backends/facts-db/facts-db-layer2.ts"],"sourcesContent":["/**\n * FactsDB — layer 2: bulk reads, maintenance, stats, procedures.\n */\n\nimport type { DatabaseSync } from \"node:sqlite\";\n\nimport type { MemoryEntry, ProcedureEntry, ScopeFilter } from \"../../types/memory.js\";\nimport type { GeneratedSkillLifecycleState, GeneratedSkillTelemetryEntry } from \"../../types/memory.js\";\nimport {\n getAllIds as getAllIdsImpl,\n getAll as getAllImpl,\n getBatch as getBatchImpl,\n getByCategory as getByCategoryImpl,\n getCount as getCountImpl,\n getMaxCreatedAtByCategory as getMaxCreatedAtByCategoryImpl,\n getProjectFacts as getProjectFactsImpl,\n getRecentFacts as getRecentFactsImpl,\n getUnattemptedOtherFacts as getUnattemptedOtherFactsImpl,\n listDirectives as listDirectivesImpl,\n listFactsByCategory as listFactsByCategoryImpl,\n listFacts as listFactsImpl,\n markClassifyAttempt as markClassifyAttemptImpl,\n updateCategory as updateCategoryImpl,\n} from \"./fact-read-queries.js\";\nimport { FactsDBLayer1 } from \"./facts-db-layer1.js\";\nimport {\n type GeneratedSkillLifecyclePolicy,\n type GeneratedSkillTelemetryRecordInput,\n type GeneratedSkillTelemetryReport,\n type GeneratedSkillDoctorReport,\n buildGeneratedSkillTelemetryReport as buildGeneratedSkillTelemetryReportImpl,\n getGeneratedSkillByName as getGeneratedSkillByNameImpl,\n listGeneratedSkillProcedures as listGeneratedSkillProceduresImpl,\n listGeneratedSkillTelemetry as listGeneratedSkillTelemetryImpl,\n markGeneratedSkillTelemetryFalsePositive as markGeneratedSkillTelemetryFalsePositiveImpl,\n reconcileGeneratedSkillDiskState as reconcileGeneratedSkillDiskStateImpl,\n recordGeneratedSkillTelemetry as recordGeneratedSkillTelemetryImpl,\n refreshGeneratedSkillLifecycleState as refreshGeneratedSkillLifecycleStateImpl,\n setGeneratedSkillLifecycleState as setGeneratedSkillLifecycleStateImpl,\n} from \"./generated-skills.js\";\nimport {\n backfillDecayClasses as backfillDecayClassesImpl,\n confirmFact as confirmFactImpl,\n decayConfidence as decayConfidenceImpl,\n decayConfidenceWithDetails as decayConfidenceWithDetailsImpl,\n expireBySourcePattern as expireBySourcePatternImpl,\n lifecycleEntityReport as lifecycleEntityReportImpl,\n listExpiredFactIdsPendingPrune as listExpiredFactIdsPendingPruneImpl,\n listFactIdsToBeDeletedByDecayRun as listFactIdsToBeDeletedByDecayRunImpl,\n listLowConfidenceFactIdsPendingPrune as listLowConfidenceFactIdsPendingPruneImpl,\n listSessionFactIdsPendingPrune as listSessionFactIdsPendingPruneImpl,\n promoteScope as promoteScopeImpl,\n pruneExpired as pruneExpiredImpl,\n pruneExpiredWithDetails as pruneExpiredWithDetailsImpl,\n pruneSessionScope as pruneSessionScopeImpl,\n reclassifyDecayClasses as reclassifyDecayClassesImpl,\n restoreCheckpoint as restoreCheckpointImpl,\n saveCheckpoint as saveCheckpointImpl,\n} from \"./maintenance.js\";\nimport {\n findProcedureByTaskPattern as findProcedureByTaskPatternImpl,\n getNegativeProceduresMatching as getNegativeProceduresMatchingImpl,\n getProcedureById as getProcedureByIdImpl,\n getProcedureFailures as getProcedureFailuresImpl,\n getProcedureVersions as getProcedureVersionsImpl,\n getProceduresForAudit as getProceduresForAuditImpl,\n getProceduresReadyForSkill as getProceduresReadyForSkillImpl,\n getStaleProcedures as getStaleProceduresImpl,\n listProcedures as listProceduresImpl,\n listProceduresUpdatedInLastNDays as listProceduresUpdatedInLastNDaysImpl,\n markProcedurePromoted as markProcedurePromotedImpl,\n procedureFeedback as procedureFeedbackImpl,\n proceduresCount as proceduresCountImpl,\n proceduresPromotedCount as proceduresPromotedCountImpl,\n proceduresValidatedCount as proceduresValidatedCountImpl,\n proceduresValidatedSince as proceduresValidatedSinceImpl,\n recordProcedureFailure as recordProcedureFailureImpl,\n recordProcedureSuccess as recordProcedureSuccessImpl,\n searchProcedures as searchProceduresImpl,\n searchProceduresRanked as searchProceduresRankedImpl,\n triageProcedures as triageProceduresImpl,\n upsertProcedure as upsertProcedureImpl,\n} from \"./procedures.js\";\nimport {\n boostConfidence as boostConfidenceHelper,\n calculateDiversityScore as calculateDiversityScoreHelper,\n getReinforcementEvents as getReinforcementEventsHelper,\n reinforceFact as reinforceFactHelper,\n reinforceProcedure as reinforceProcedureHelper,\n} from \"./reinforcement.js\";\nimport { getSupersededTextsSnapshot } from \"./search.js\";\nimport {\n auditCategories as auditCategoriesImpl,\n cleanEntityStopwords as cleanEntityStopwordsImpl,\n countExpiredFacts as countExpiredFactsImpl,\n countFacts as countFactsImpl,\n countVectorlessActiveFacts as countVectorlessActiveFactsImpl,\n directivesCount as directivesCountImpl,\n entityCount as entityCountImpl,\n estimateStoredTokensByTier as estimateStoredTokensByTierImpl,\n estimateStoredTokens as estimateStoredTokensImpl,\n linksCount as linksCountImpl,\n listForDashboard as listForDashboardImpl,\n listVectorlessActiveFacts as listVectorlessActiveFactsImpl,\n metaPatternsCount as metaPatternsCountImpl,\n proposedCategories as proposedCategoriesImpl,\n remapCategory as remapCategoryImpl,\n statsBreakdownByCategory as statsBreakdownByCategoryImpl,\n statsBreakdownByDecayClass as statsBreakdownByDecayClassImpl,\n statsBreakdownBySource as statsBreakdownBySourceImpl,\n statsBreakdownByTier as statsBreakdownByTierImpl,\n statsBreakdown as statsBreakdownImpl,\n topEntitiesFiltered as topEntitiesFilteredImpl,\n topEntities as topEntitiesImpl,\n uniqueMemoryCategories as uniqueMemoryCategoriesImpl,\n vectorlessActiveFactsBySource as vectorlessActiveFactsBySourceImpl,\n} from \"./stats.js\";\nimport type { ReinforcementContext, ReinforcementEvent } from \"./types.js\";\n\nexport class FactsDBLayer2 extends FactsDBLayer1 {\n /**\n * Get facts from the last N days (for reflection).\n * Excludes `pattern`/`rule` categories and `implicit-feedback`-tagged facts by default\n * so trajectory paraphrases (#1186) do not pollute reflection input.\n * More efficient than getAll+filter.\n */\n getRecentFacts(days: number, options?: { excludeCategories?: string[]; excludeTags?: string[] }): MemoryEntry[] {\n return getRecentFactsImpl(this.liveDb, days, options);\n }\n\n /** Get all non-expired facts (for reflection). Optional point-in-time / include superseded. Optional scope filter. */\n getAll(options?: { includeSuperseded?: boolean; asOf?: number; scopeFilter?: ScopeFilter | null }): MemoryEntry[] {\n return getAllImpl(this.liveDb, options);\n }\n\n /**\n * Count non-expired facts (for migration progress). Same filter as getAll with includeSuperseded.\n */\n getCount(options?: { includeSuperseded?: boolean }): number {\n return getCountImpl(this.liveDb, options);\n }\n\n /**\n * Return all active fact IDs.\n * Active = not expired and not superseded (same filter as getAll() default).\n * Keeping this filter in sync with getAll() ensures that the set of IDs\n * returned here is consistent with what callers expect to be \"live\" facts.\n * Used by the reconcile command to detect orphan entries.\n * IDs are normalized to lowercase to match VectorDB.getAllIds() normalization.\n */\n getAllIds(): string[] {\n return getAllIdsImpl(this.liveDb);\n }\n\n /**\n * Get a batch of non-expired facts (for migration without loading all into memory).\n * Same ordering and filter as getAll; offset/limit applied.\n */\n getBatch(offset: number, limit: number, options?: { includeSuperseded?: boolean }): MemoryEntry[] {\n return getBatchImpl(this.liveDb, offset, limit, options);\n }\n\n /** List recent facts with optional filters (for CLI list command). Order: created_at DESC. */\n list(\n limit: number,\n filters?: {\n category?: string;\n entity?: string;\n key?: string;\n source?: string;\n tier?: string;\n },\n ): MemoryEntry[] {\n return listFactsImpl(this.liveDb, limit, filters);\n }\n\n /** Get texts of superseded facts (for filtering LanceDB results). Cached to avoid repeated full scans. */\n getSupersededTexts(): Set<string> {\n return getSupersededTextsSnapshot(this.supersededTextsCacheMgr, this.liveDb);\n }\n\n count(): number {\n return countFactsImpl(this.liveDb);\n }\n\n /** Fact ids that `pruneExpired()` would delete (same filter as the DELETE). */\n listExpiredFactIdsPendingPrune(): string[] {\n return listExpiredFactIdsPendingPruneImpl(this.liveDb);\n }\n\n /** Fact ids that `decayConfidence()` would delete (same filter as the DELETE). */\n listLowConfidenceFactIdsPendingPrune(): string[] {\n return listLowConfidenceFactIdsPendingPruneImpl(this.liveDb);\n }\n\n /**\n * Return all fact IDs that will be hard-deleted by the next `decayConfidence()` call.\n * Includes facts already below 0.1 confidence AND facts that will be halved below 0.1.\n * Call this *before* `decayConfidence()` to capture the complete set for vector cleanup.\n */\n listFactIdsToBeDeletedByDecayRun(nowSec?: number): string[] {\n return listFactIdsToBeDeletedByDecayRunImpl(this.liveDb, nowSec);\n }\n\n pruneExpired(): number {\n return pruneExpiredImpl(this.liveDb);\n }\n\n pruneExpiredWithDetails(nowSec?: number): { factsPruned: number; deletedFactIds: string[] } {\n return pruneExpiredWithDetailsImpl(this.liveDb, nowSec);\n }\n\n /** Session-scoped fact ids that `pruneSessionScope(sessionId)` would delete. */\n listSessionFactIdsPendingPrune(sessionId: string): string[] {\n return listSessionFactIdsPendingPruneImpl(this.liveDb, sessionId);\n }\n\n /** Prune session-scoped memories for a given session (cleared on session end). Returns count deleted. */\n pruneSessionScope(sessionId: string): number {\n return pruneSessionScopeImpl(this.liveDb, sessionId);\n }\n\n /** Promote a fact's scope (e.g. session → global or agent). Returns true if updated. */\n promoteScope(\n factId: string,\n newScope: \"global\" | \"user\" | \"agent\" | \"session\",\n newScopeTarget: string | null,\n ): boolean {\n return promoteScopeImpl(this.liveDb, factId, newScope, newScopeTarget);\n }\n\n decayConfidence(nowSec?: number): number {\n return decayConfidenceImpl(this.liveDb, nowSec);\n }\n\n decayConfidenceWithDetails(nowSec?: number): { factsDecayed: number; deletedFactIds: string[] } {\n return decayConfidenceWithDetailsImpl(this.liveDb, nowSec);\n }\n\n confirmFact(id: string): boolean {\n return confirmFactImpl(this.liveDb, id);\n }\n\n /**\n * Boost the confidence of a fact by a delta, clamped at maxConfidence.\n * Also increments reinforced_count and updates last_reinforced_at.\n * Returns true if the fact was found and updated.\n */\n boostConfidence(id: string, delta: number, maxConfidence = 1.0): boolean {\n return boostConfidenceHelper(this.liveDb, id, delta, maxConfidence);\n }\n\n /**\n * Annotate a fact with reinforcement from user praise.\n * Increments reinforced_count, updates last_reinforced_at, appends quote (max 10 quotes kept).\n * Optionally records a rich context event in reinforcement_log (#259).\n * Wraps read-modify-write in a transaction to prevent race conditions.\n * Returns true if fact was updated.\n */\n reinforceFact(\n id: string,\n quoteSnippet: string,\n context?: ReinforcementContext,\n opts?: {\n trackContext?: boolean;\n maxEventsPerFact?: number;\n boostAmount?: number;\n },\n ): boolean {\n return reinforceFactHelper(this.liveDb, id, quoteSnippet, context, opts);\n }\n\n /**\n * Get all reinforcement events for a fact from reinforcement_log (#259).\n */\n getReinforcementEvents(factId: string): ReinforcementEvent[] {\n return getReinforcementEventsHelper(this.liveDb, factId);\n }\n\n /**\n * Calculate diversity score for a fact: unique query stems / total events.\n * Score 1.0 = all events from different queries; 0.0 = all from same query (#259).\n */\n calculateDiversityScore(factId: string): number {\n return calculateDiversityScoreHelper(this.liveDb, factId);\n }\n\n /**\n * Phase 2: Annotate a procedure with reinforcement from user praise.\n * Increments reinforced_count, updates last_reinforced_at, appends quote (max 10 quotes kept).\n * Checks if reinforced_count reaches promotion threshold and auto-promotes if needed.\n * Wraps read-modify-write in a transaction to prevent race conditions.\n * Returns true if procedure was updated.\n */\n reinforceProcedure(id: string, quoteSnippet: string, promotionThreshold = 2): boolean {\n return reinforceProcedureHelper(this.liveDb, id, quoteSnippet, promotionThreshold);\n }\n\n saveCheckpoint(context: {\n intent: string;\n state: string;\n expectedOutcome?: string;\n workingFiles?: string[];\n }): string {\n return saveCheckpointImpl((entry) => this.store(entry), context);\n }\n\n restoreCheckpoint(): {\n id: string;\n intent: string;\n state: string;\n expectedOutcome?: string;\n workingFiles?: string[];\n savedAt: string;\n } | null {\n return restoreCheckpointImpl(this.liveDb);\n }\n\n statsBreakdown(): Record<string, number> {\n return statsBreakdownImpl(this.liveDb);\n }\n\n /** Tier breakdown (hot/warm/cold) for non-superseded facts. */\n statsBreakdownByTier(): Record<string, number> {\n return statsBreakdownByTierImpl(this.liveDb);\n }\n\n /** Source breakdown (conversation, cli, distillation, reflection, etc.) for non-superseded facts. */\n statsBreakdownBySource(): Record<string, number> {\n return statsBreakdownBySourceImpl(this.liveDb);\n }\n\n /** Category breakdown for non-superseded facts (for rich stats). */\n statsBreakdownByCategory(): Record<string, number> {\n return statsBreakdownByCategoryImpl(this.liveDb);\n }\n\n /** Decay class breakdown for non-superseded facts (for dashboard stats). */\n statsBreakdownByDecayClass(): Record<string, number> {\n return statsBreakdownByDecayClassImpl(this.liveDb);\n }\n\n /**\n * List facts for dashboard/API: paginated, filterable by category/tier/entity, optional FTS search.\n * Returns entries in dashboard shape (snake_case for JSON) and total count.\n */\n listForDashboard(opts: {\n limit: number;\n offset: number;\n category?: string;\n tier?: string;\n decayClass?: string;\n entity?: string;\n search?: string;\n }): { facts: Array<Record<string, unknown>>; total: number } {\n return listForDashboardImpl(this.liveDb, opts);\n }\n\n /** Distinct memory categories present in non-superseded facts (for CLI stats/categories). */\n uniqueMemoryCategories(): string[] {\n return uniqueMemoryCategoriesImpl(this.liveDb);\n }\n\n /** Compare configured categories with active categories present in facts. */\n auditCategories(configuredCategories: readonly string[], exampleLimit = 5): ReturnType<typeof auditCategoriesImpl> {\n return auditCategoriesImpl(this.liveDb, configuredCategories, exampleLimit);\n }\n\n /** Bulk-remap facts from one category to another; dry-run unless apply=true. */\n remapCategory(from: string, to: string, apply = false): ReturnType<typeof remapCategoryImpl> {\n return remapCategoryImpl(this.liveDb, from, to, apply);\n }\n\n /**\n * List `category-suggested:<label>` tags emitted by the auto-classifier (#1188).\n * Use to surface promotable LLM suggestions via `categories propose`.\n */\n proposedCategories(exampleLimit = 5): ReturnType<typeof proposedCategoriesImpl> {\n return proposedCategoriesImpl(this.liveDb, exampleLimit);\n }\n\n countVectorlessActiveFacts(source?: string): number {\n return countVectorlessActiveFactsImpl(this.liveDb, source);\n }\n\n vectorlessActiveFactsBySource(limit = 20): ReturnType<typeof vectorlessActiveFactsBySourceImpl> {\n return vectorlessActiveFactsBySourceImpl(this.liveDb, limit);\n }\n\n listVectorlessActiveFacts(\n options?: Parameters<typeof listVectorlessActiveFactsImpl>[1],\n ): ReturnType<typeof listVectorlessActiveFactsImpl> {\n return listVectorlessActiveFactsImpl(this.liveDb, options);\n }\n\n /** Snapshot of top procedures for context-audit (sorted by confidence). */\n getProceduresForAudit(limit = 5): ReturnType<typeof getProceduresForAuditImpl> {\n return getProceduresForAuditImpl(this.liveDb, limit);\n }\n\n /** Count of procedures (from procedures table). Returns 0 if table does not exist. */\n proceduresCount(): number {\n return proceduresCountImpl(this.liveDb);\n }\n\n /** Count of procedures with last_validated set (validated at least once). */\n proceduresValidatedCount(): number {\n return proceduresValidatedCountImpl(this.liveDb);\n }\n\n /** Count of procedures whose last_validated is >= sinceSec (e.g., for \"new this week\" digest metrics). */\n proceduresValidatedSince(sinceSec: number): number {\n return proceduresValidatedSinceImpl(this.liveDb, sinceSec);\n }\n\n /** Count of procedures promoted to skill (promoted_to_skill = 1). */\n proceduresPromotedCount(): number {\n return proceduresPromotedCountImpl(this.liveDb);\n }\n\n /** Count of rows in memory_links (graph connections). Returns 0 if table does not exist. */\n linksCount(): number {\n return linksCountImpl(this.liveDb);\n }\n\n /** Count of facts with source LIKE 'directive:%' (extracted directives). */\n directivesCount(): number {\n return directivesCountImpl(this.liveDb);\n }\n\n /** Count of facts with category = 'pattern' and tag 'meta' (meta-patterns). */\n metaPatternsCount(): number {\n return metaPatternsCountImpl(this.liveDb);\n }\n\n /** Distinct entity count (non-null, non-empty entity values). */\n entityCount(): number {\n return entityCountImpl(this.liveDb);\n }\n\n topEntities(limit = 10): ReturnType<typeof topEntitiesImpl> {\n return topEntitiesImpl(this.liveDb, limit);\n }\n\n topEntitiesFiltered(limit = 10, extraStopWords: readonly string[] = []): ReturnType<typeof topEntitiesFilteredImpl> {\n return topEntitiesFilteredImpl(this.liveDb, limit, extraStopWords);\n }\n\n cleanEntityStopwords(\n options?: Parameters<typeof cleanEntityStopwordsImpl>[1],\n ): ReturnType<typeof cleanEntityStopwordsImpl> {\n return cleanEntityStopwordsImpl(this.liveDb, options);\n }\n\n /** Estimated total tokens stored (summary or text) for non-superseded facts. Uses same heuristic as auto-recall. */\n estimateStoredTokens(): number {\n return estimateStoredTokensImpl(this.liveDb);\n }\n\n /** Estimated tokens by tier (hot/warm/cold) for non-superseded facts. */\n estimateStoredTokensByTier(): { hot: number; warm: number; cold: number } {\n return estimateStoredTokensByTierImpl(this.liveDb);\n }\n\n countExpired(): number {\n return countExpiredFactsImpl(this.liveDb);\n }\n\n backfillDecayClasses(options?: Parameters<typeof backfillDecayClassesImpl>[1]): Record<string, number> {\n return backfillDecayClassesImpl(this.liveDb, options);\n }\n\n reclassifyDecayClasses(\n options?: Parameters<typeof reclassifyDecayClassesImpl>[1],\n ): ReturnType<typeof reclassifyDecayClassesImpl> {\n return reclassifyDecayClassesImpl(this.liveDb, options);\n }\n\n lifecycleEntityReport(limit?: number): ReturnType<typeof lifecycleEntityReportImpl> {\n return lifecycleEntityReportImpl(this.liveDb, limit);\n }\n\n expireBySourcePattern(\n options: Parameters<typeof expireBySourcePatternImpl>[1],\n ): ReturnType<typeof expireBySourcePatternImpl> {\n return expireBySourcePatternImpl(this.liveDb, options);\n }\n\n getByCategory(category: string): MemoryEntry[] {\n return getByCategoryImpl(this.liveDb, category);\n }\n\n /** List non-superseded facts by category (for CLI list command). */\n listFactsByCategory(category: string, limit = 100): MemoryEntry[] {\n return listFactsByCategoryImpl(this.liveDb, category, limit);\n }\n\n /**\n * Targeted project-fact query for active-task projection (#1553).\n * Uses a category='project' filter instead of loading all facts, then filtering by category.\n */\n getProjectFacts(limit = 8000, scopeFilter?: ScopeFilter | null): MemoryEntry[] {\n return getProjectFactsImpl(this.liveDb, limit, scopeFilter);\n }\n\n /** List directive facts (source LIKE 'directive:%'), non-superseded, by created_at DESC. */\n listDirectives(limit = 100): MemoryEntry[] {\n return listDirectivesImpl(this.liveDb, limit);\n }\n\n /** Get maximum created_at timestamp for non-superseded facts in a category. */\n getMaxCreatedAtByCategory(category: string): number | null {\n return getMaxCreatedAtByCategoryImpl(this.liveDb, category);\n }\n\n updateCategory(id: string, category: string): boolean {\n return updateCategoryImpl(this.liveDb, id, category);\n }\n\n /**\n * \"other\" facts not yet attempted by auto-classify, or re-ingested since the last attempt.\n */\n getUnattemptedOtherFacts(): MemoryEntry[] {\n return getUnattemptedOtherFactsImpl(this.liveDb);\n }\n\n /** Stamp last_classify_attempt_at on a batch of facts. */\n markClassifyAttempt(ids: string[]): void {\n markClassifyAttemptImpl(this.liveDb, ids);\n }\n\n /** Read a maintenance state value by key. */\n getMaintenanceState(key: string): string | null {\n const row = this.liveDb.prepare(\"SELECT value FROM maintenance_state WHERE key = ?\").get(key) as\n | { value: string }\n | undefined;\n return row?.value ?? null;\n }\n\n /** Write a maintenance state value (upsert). */\n setMaintenanceState(key: string, value: string): void {\n this.liveDb\n .prepare(\n `INSERT INTO maintenance_state (key, value, updated_at)\n VALUES (?, ?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(key, value, Math.floor(Date.now() / 1000));\n }\n\n /** Get the live DB handle, reopening if closed after a SIGUSR1 restart. */\n /**\n * Expose the underlying node:sqlite DatabaseSync for services that require direct\n * SQL access (e.g. the FTS5 search service used by the RRF retrieval pipeline).\n * Returned instance is the same live handle used internally (with auto-reopen).\n */\n getRawDb(): DatabaseSync {\n return this.liveDb;\n }\n\n // ---------- Procedural memory (see facts-db/procedures.ts) ----------\n\n procedureFeedback(input: Parameters<typeof procedureFeedbackImpl>[1]): ProcedureEntry | null {\n return procedureFeedbackImpl(this.liveDb, input);\n }\n\n getProcedureVersions(procedureId: string): ReturnType<typeof getProcedureVersionsImpl> {\n return getProcedureVersionsImpl(this.liveDb, procedureId);\n }\n\n getProcedureFailures(procedureId: string): ReturnType<typeof getProcedureFailuresImpl> {\n return getProcedureFailuresImpl(this.liveDb, procedureId);\n }\n\n upsertProcedure(proc: Parameters<typeof upsertProcedureImpl>[1]): ProcedureEntry {\n return upsertProcedureImpl(this.liveDb, proc);\n }\n\n listProcedures(limit = 100): ProcedureEntry[] {\n return listProceduresImpl(this.liveDb, limit);\n }\n\n listProceduresUpdatedInLastNDays(days: number, limit = 500): ProcedureEntry[] {\n return listProceduresUpdatedInLastNDaysImpl(this.liveDb, days, limit);\n }\n\n getProcedureById(id: string): ProcedureEntry | null {\n return getProcedureByIdImpl(this.liveDb, id);\n }\n\n findProcedureByTaskPattern(taskPattern: string, limit = 5): ProcedureEntry[] {\n return findProcedureByTaskPatternImpl(this.liveDb, taskPattern, limit);\n }\n\n searchProcedures(\n taskDescription: string,\n limit = 10,\n reinforcementBoost = 0.1,\n scopeFilter?: ScopeFilter,\n ): ProcedureEntry[] {\n return searchProceduresImpl(this.liveDb, taskDescription, limit, reinforcementBoost, scopeFilter);\n }\n\n searchProceduresRanked(\n taskDescription: string,\n limit = 10,\n reinforcementBoost = 0.1,\n scopeFilter?: ScopeFilter,\n ): Array<ProcedureEntry & { relevanceScore: number }> {\n return searchProceduresRankedImpl(this.liveDb, taskDescription, limit, reinforcementBoost, scopeFilter);\n }\n\n getNegativeProceduresMatching(taskDescription: string, limit = 5, scopeFilter?: ScopeFilter): ProcedureEntry[] {\n return getNegativeProceduresMatchingImpl(this.liveDb, taskDescription, limit, scopeFilter);\n }\n\n recordProcedureSuccess(id: string, recipeJson?: string, sessionId?: string): boolean {\n return recordProcedureSuccessImpl(this.liveDb, id, recipeJson, sessionId);\n }\n\n recordProcedureFailure(id: string, recipeJson?: string, sessionId?: string): boolean {\n return recordProcedureFailureImpl(this.liveDb, id, recipeJson, sessionId);\n }\n\n getProceduresReadyForSkill(validationThreshold: number, limit = 50, skillTTLDays?: number): ProcedureEntry[] {\n return getProceduresReadyForSkillImpl(this.liveDb, validationThreshold, limit, skillTTLDays);\n }\n\n markProcedurePromoted(id: string, skillPath: string): boolean {\n return markProcedurePromotedImpl(this.liveDb, id, skillPath);\n }\n\n triageProcedures(options?: Parameters<typeof triageProceduresImpl>[1]): ReturnType<typeof triageProceduresImpl> {\n return triageProceduresImpl(this.liveDb, options);\n }\n\n getStaleProcedures(ttlDays: number, limit = 100): ProcedureEntry[] {\n return getStaleProceduresImpl(this.liveDb, ttlDays, limit);\n }\n\n listGeneratedSkillProcedures(): ProcedureEntry[] {\n return listGeneratedSkillProceduresImpl(this.liveDb);\n }\n\n getGeneratedSkillByName(skillName: string, procedureId?: string): ProcedureEntry | null {\n return getGeneratedSkillByNameImpl(this.liveDb, skillName, procedureId);\n }\n\n recordGeneratedSkillTelemetry(\n input: GeneratedSkillTelemetryRecordInput,\n policy?: GeneratedSkillLifecyclePolicy,\n ): GeneratedSkillTelemetryEntry {\n return recordGeneratedSkillTelemetryImpl(this.liveDb, input, policy);\n }\n\n listGeneratedSkillTelemetry(skillName?: string, limit?: number): GeneratedSkillTelemetryEntry[] {\n return listGeneratedSkillTelemetryImpl(this.liveDb, skillName, limit);\n }\n\n markGeneratedSkillTelemetryFalsePositive(\n activationId: string,\n correctionReason: string,\n policy?: GeneratedSkillLifecyclePolicy,\n ): GeneratedSkillTelemetryEntry | null {\n return markGeneratedSkillTelemetryFalsePositiveImpl(this.liveDb, activationId, correctionReason, policy);\n }\n\n setGeneratedSkillLifecycleState(\n skillName: string,\n state: GeneratedSkillLifecycleState,\n reason: string | null,\n at?: number,\n procedureId?: string,\n ): ProcedureEntry | null {\n return setGeneratedSkillLifecycleStateImpl(this.liveDb, skillName, state, reason, at, procedureId);\n }\n\n refreshGeneratedSkillLifecycleState(\n skillName: string,\n policy?: GeneratedSkillLifecyclePolicy,\n now?: number,\n procedureId?: string,\n ): ProcedureEntry | null {\n return refreshGeneratedSkillLifecycleStateImpl(this.liveDb, skillName, policy, now, procedureId);\n }\n\n buildGeneratedSkillTelemetryReport(options?: {\n skillName?: string;\n policy?: Partial<GeneratedSkillLifecyclePolicy>;\n recentActivationLimit?: number;\n now?: number;\n }): GeneratedSkillTelemetryReport {\n return buildGeneratedSkillTelemetryReportImpl(this.liveDb, options);\n }\n\n reconcileGeneratedSkillDiskState(opts?: {\n workspaceRoot?: string;\n fix?: boolean;\n now?: number;\n }): GeneratedSkillDoctorReport {\n return reconcileGeneratedSkillDiskStateImpl(this.liveDb, opts);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"facts-db-layer2.js","names":["getRecentFactsImpl","getAllImpl","getCountImpl","getAllIdsImpl","getBatchImpl","listFactsImpl","countFactsImpl","listExpiredFactIdsPendingPruneImpl","listLowConfidenceFactIdsPendingPruneImpl","listFactIdsToBeDeletedByDecayRunImpl","pruneExpiredImpl","pruneExpiredWithDetailsImpl","listSessionFactIdsPendingPruneImpl","pruneSessionScopeImpl","promoteScopeImpl","decayConfidenceImpl","decayConfidenceWithDetailsImpl","confirmFactImpl","boostConfidenceHelper","reinforceFactHelper","getReinforcementEventsHelper","calculateDiversityScoreHelper","reinforceProcedureHelper","saveCheckpointImpl","restoreCheckpointImpl","statsBreakdownImpl","statsBreakdownByTierImpl","statsBreakdownBySourceImpl","statsBreakdownByCategoryImpl","statsBreakdownByDecayClassImpl","listForDashboardImpl","uniqueMemoryCategoriesImpl","auditCategoriesImpl","remapCategoryImpl","proposedCategoriesImpl","countVectorlessActiveFactsImpl","vectorlessActiveFactsBySourceImpl","listVectorlessActiveFactsImpl","getProceduresForAuditImpl","proceduresCountImpl","proceduresValidatedCountImpl","proceduresValidatedSinceImpl","proceduresPromotedCountImpl","linksCountImpl","directivesCountImpl","metaPatternsCountImpl","entityCountImpl","topEntitiesImpl","topEntitiesFilteredImpl","cleanEntityStopwordsImpl","estimateStoredTokensImpl","estimateStoredTokensByTierImpl","countExpiredFactsImpl","backfillDecayClassesImpl","reclassifyDecayClassesImpl","lifecycleEntityReportImpl","expireBySourcePatternImpl","getByCategoryImpl","listFactsByCategoryImpl","getProjectFactsImpl","listDirectivesImpl","getMaxCreatedAtByCategoryImpl","updateCategoryImpl","getUnattemptedOtherFactsImpl","procedureFeedbackImpl","getProcedureVersionsImpl","getProcedureFailuresImpl","upsertProcedureImpl","listProceduresImpl","listProceduresUpdatedInLastNDaysImpl","getProcedureByIdImpl","findProcedureByTaskPatternImpl","searchProceduresImpl","searchProceduresRankedImpl","getNegativeProceduresMatchingImpl","recordProcedureSuccessImpl","recordProcedureFailureImpl","getProceduresReadyForSkillImpl","markProcedurePromotedImpl","triageProceduresImpl","getStaleProceduresImpl","listGeneratedSkillProceduresImpl","getGeneratedSkillByNameImpl","recordGeneratedSkillTelemetryImpl","listGeneratedSkillTelemetryImpl","markGeneratedSkillTelemetryFalsePositiveImpl","setGeneratedSkillLifecycleStateImpl","refreshGeneratedSkillLifecycleStateImpl","buildGeneratedSkillTelemetryReportImpl","reconcileGeneratedSkillDiskStateImpl"],"sources":["../../../backends/facts-db/facts-db-layer2.ts"],"sourcesContent":["/**\n * FactsDB — layer 2: bulk reads, maintenance, stats, procedures.\n */\n\nimport type { DatabaseSync } from \"node:sqlite\";\n\nimport type { MemoryEntry, ProcedureEntry, ScopeFilter } from \"../../types/memory.js\";\nimport type { GeneratedSkillLifecycleState, GeneratedSkillTelemetryEntry } from \"../../types/memory.js\";\nimport {\n getAllIds as getAllIdsImpl,\n getAll as getAllImpl,\n getBatch as getBatchImpl,\n getByCategory as getByCategoryImpl,\n getCount as getCountImpl,\n getMaxCreatedAtByCategory as getMaxCreatedAtByCategoryImpl,\n getProjectFacts as getProjectFactsImpl,\n getRecentFacts as getRecentFactsImpl,\n getUnattemptedOtherFacts as getUnattemptedOtherFactsImpl,\n listDirectives as listDirectivesImpl,\n listFactsByCategory as listFactsByCategoryImpl,\n listFacts as listFactsImpl,\n markClassifyAttempt as markClassifyAttemptImpl,\n updateCategory as updateCategoryImpl,\n} from \"./fact-read-queries.js\";\nimport { FactsDBLayer1 } from \"./facts-db-layer1.js\";\nimport {\n type GeneratedSkillLifecyclePolicy,\n type GeneratedSkillTelemetryRecordInput,\n type GeneratedSkillTelemetryReport,\n type GeneratedSkillDoctorReport,\n buildGeneratedSkillTelemetryReport as buildGeneratedSkillTelemetryReportImpl,\n getGeneratedSkillByName as getGeneratedSkillByNameImpl,\n listGeneratedSkillProcedures as listGeneratedSkillProceduresImpl,\n listGeneratedSkillTelemetry as listGeneratedSkillTelemetryImpl,\n markGeneratedSkillTelemetryFalsePositive as markGeneratedSkillTelemetryFalsePositiveImpl,\n reconcileGeneratedSkillDiskState as reconcileGeneratedSkillDiskStateImpl,\n recordGeneratedSkillTelemetry as recordGeneratedSkillTelemetryImpl,\n refreshGeneratedSkillLifecycleState as refreshGeneratedSkillLifecycleStateImpl,\n setGeneratedSkillLifecycleState as setGeneratedSkillLifecycleStateImpl,\n} from \"./generated-skills.js\";\nimport {\n backfillDecayClasses as backfillDecayClassesImpl,\n confirmFact as confirmFactImpl,\n decayConfidence as decayConfidenceImpl,\n decayConfidenceWithDetails as decayConfidenceWithDetailsImpl,\n expireBySourcePattern as expireBySourcePatternImpl,\n lifecycleEntityReport as lifecycleEntityReportImpl,\n listExpiredFactIdsPendingPrune as listExpiredFactIdsPendingPruneImpl,\n listFactIdsToBeDeletedByDecayRun as listFactIdsToBeDeletedByDecayRunImpl,\n listLowConfidenceFactIdsPendingPrune as listLowConfidenceFactIdsPendingPruneImpl,\n listSessionFactIdsPendingPrune as listSessionFactIdsPendingPruneImpl,\n promoteScope as promoteScopeImpl,\n pruneExpired as pruneExpiredImpl,\n pruneExpiredWithDetails as pruneExpiredWithDetailsImpl,\n pruneSessionScope as pruneSessionScopeImpl,\n reclassifyDecayClasses as reclassifyDecayClassesImpl,\n restoreCheckpoint as restoreCheckpointImpl,\n saveCheckpoint as saveCheckpointImpl,\n} from \"./maintenance.js\";\nimport {\n findProcedureByTaskPattern as findProcedureByTaskPatternImpl,\n getNegativeProceduresMatching as getNegativeProceduresMatchingImpl,\n getProcedureById as getProcedureByIdImpl,\n getProcedureFailures as getProcedureFailuresImpl,\n getProcedureVersions as getProcedureVersionsImpl,\n getProceduresForAudit as getProceduresForAuditImpl,\n getProceduresReadyForSkill as getProceduresReadyForSkillImpl,\n getStaleProcedures as getStaleProceduresImpl,\n listProcedures as listProceduresImpl,\n listProceduresUpdatedInLastNDays as listProceduresUpdatedInLastNDaysImpl,\n markProcedurePromoted as markProcedurePromotedImpl,\n procedureFeedback as procedureFeedbackImpl,\n proceduresCount as proceduresCountImpl,\n proceduresPromotedCount as proceduresPromotedCountImpl,\n proceduresValidatedCount as proceduresValidatedCountImpl,\n proceduresValidatedSince as proceduresValidatedSinceImpl,\n recordProcedureFailure as recordProcedureFailureImpl,\n recordProcedureSuccess as recordProcedureSuccessImpl,\n searchProcedures as searchProceduresImpl,\n searchProceduresRanked as searchProceduresRankedImpl,\n triageProcedures as triageProceduresImpl,\n upsertProcedure as upsertProcedureImpl,\n} from \"./procedures.js\";\nimport {\n boostConfidence as boostConfidenceHelper,\n calculateDiversityScore as calculateDiversityScoreHelper,\n getReinforcementEvents as getReinforcementEventsHelper,\n reinforceFact as reinforceFactHelper,\n reinforceProcedure as reinforceProcedureHelper,\n} from \"./reinforcement.js\";\nimport { getSupersededTextsSnapshot } from \"./search.js\";\nimport {\n auditCategories as auditCategoriesImpl,\n cleanEntityStopwords as cleanEntityStopwordsImpl,\n countExpiredFacts as countExpiredFactsImpl,\n countFacts as countFactsImpl,\n countVectorlessActiveFacts as countVectorlessActiveFactsImpl,\n directivesCount as directivesCountImpl,\n entityCount as entityCountImpl,\n estimateStoredTokensByTier as estimateStoredTokensByTierImpl,\n estimateStoredTokens as estimateStoredTokensImpl,\n linksCount as linksCountImpl,\n listForDashboard as listForDashboardImpl,\n listVectorlessActiveFacts as listVectorlessActiveFactsImpl,\n metaPatternsCount as metaPatternsCountImpl,\n proposedCategories as proposedCategoriesImpl,\n remapCategory as remapCategoryImpl,\n statsBreakdownByCategory as statsBreakdownByCategoryImpl,\n statsBreakdownByDecayClass as statsBreakdownByDecayClassImpl,\n statsBreakdownBySource as statsBreakdownBySourceImpl,\n statsBreakdownByTier as statsBreakdownByTierImpl,\n statsBreakdown as statsBreakdownImpl,\n topEntitiesFiltered as topEntitiesFilteredImpl,\n topEntities as topEntitiesImpl,\n uniqueMemoryCategories as uniqueMemoryCategoriesImpl,\n vectorlessActiveFactsBySource as vectorlessActiveFactsBySourceImpl,\n} from \"./stats.js\";\nimport type { ReinforcementContext, ReinforcementEvent } from \"./types.js\";\n\nexport class FactsDBLayer2 extends FactsDBLayer1 {\n /**\n * Get facts from the last N days (for reflection).\n * Excludes `pattern`/`rule` categories and `implicit-feedback`-tagged facts by default\n * so trajectory paraphrases (#1186) do not pollute reflection input.\n * More efficient than getAll+filter.\n */\n getRecentFacts(days: number, options?: { excludeCategories?: string[]; excludeTags?: string[] }): MemoryEntry[] {\n return getRecentFactsImpl(this.liveDb, days, options);\n }\n\n /** Get all non-expired facts (for reflection). Optional point-in-time / include superseded. Optional scope filter. */\n getAll(options?: { includeSuperseded?: boolean; asOf?: number; scopeFilter?: ScopeFilter | null }): MemoryEntry[] {\n return getAllImpl(this.liveDb, options);\n }\n\n /**\n * Count non-expired facts (for migration progress). Same filter as getAll with includeSuperseded.\n */\n getCount(options?: { includeSuperseded?: boolean }): number {\n return getCountImpl(this.liveDb, options);\n }\n\n /**\n * Return all active fact IDs.\n * Active = not expired and not superseded (same filter as getAll() default).\n * Keeping this filter in sync with getAll() ensures that the set of IDs\n * returned here is consistent with what callers expect to be \"live\" facts.\n * Used by the reconcile command to detect orphan entries.\n * IDs are normalized to lowercase to match VectorDB.getAllIds() normalization.\n */\n getAllIds(): string[] {\n return getAllIdsImpl(this.liveDb);\n }\n\n /**\n * Get a batch of non-expired facts (for migration without loading all into memory).\n * Same ordering and filter as getAll; offset/limit applied.\n */\n getBatch(offset: number, limit: number, options?: { includeSuperseded?: boolean }): MemoryEntry[] {\n return getBatchImpl(this.liveDb, offset, limit, options);\n }\n\n /** List recent facts with optional filters (for CLI list command). Order: created_at DESC. */\n list(\n limit: number,\n filters?: {\n category?: string;\n entity?: string;\n key?: string;\n source?: string;\n tier?: string;\n },\n ): MemoryEntry[] {\n return listFactsImpl(this.liveDb, limit, filters);\n }\n\n /** Get texts of superseded facts (for filtering LanceDB results). Cached to avoid repeated full scans. */\n getSupersededTexts(): Set<string> {\n return getSupersededTextsSnapshot(this.supersededTextsCacheMgr, this.liveDb);\n }\n\n count(): number {\n return countFactsImpl(this.liveDb);\n }\n\n /** Fact ids that `pruneExpired()` would delete (same filter as the DELETE). */\n listExpiredFactIdsPendingPrune(): string[] {\n return listExpiredFactIdsPendingPruneImpl(this.liveDb);\n }\n\n /** Fact ids that `decayConfidence()` would delete (same filter as the DELETE). */\n listLowConfidenceFactIdsPendingPrune(): string[] {\n return listLowConfidenceFactIdsPendingPruneImpl(this.liveDb);\n }\n\n /**\n * Return all fact IDs that will be hard-deleted by the next `decayConfidence()` call.\n * Includes facts already below 0.1 confidence AND facts that will be halved below 0.1.\n * Call this *before* `decayConfidence()` to capture the complete set for vector cleanup.\n */\n listFactIdsToBeDeletedByDecayRun(nowSec?: number): string[] {\n return listFactIdsToBeDeletedByDecayRunImpl(this.liveDb, nowSec);\n }\n\n pruneExpired(): number {\n return pruneExpiredImpl(this.liveDb);\n }\n\n pruneExpiredWithDetails(nowSec?: number): { factsPruned: number; deletedFactIds: string[] } {\n return pruneExpiredWithDetailsImpl(this.liveDb, nowSec);\n }\n\n /** Session-scoped fact ids that `pruneSessionScope(sessionId)` would delete. */\n listSessionFactIdsPendingPrune(sessionId: string): string[] {\n return listSessionFactIdsPendingPruneImpl(this.liveDb, sessionId);\n }\n\n /** Prune session-scoped memories for a given session (cleared on session end). Returns count deleted. */\n pruneSessionScope(sessionId: string): number {\n return pruneSessionScopeImpl(this.liveDb, sessionId);\n }\n\n /** Promote a fact's scope (e.g. session → global or agent). Returns true if updated. */\n promoteScope(\n factId: string,\n newScope: \"global\" | \"user\" | \"agent\" | \"session\",\n newScopeTarget: string | null,\n ): boolean {\n return promoteScopeImpl(this.liveDb, factId, newScope, newScopeTarget);\n }\n\n decayConfidence(nowSec?: number): number {\n return decayConfidenceImpl(this.liveDb, nowSec);\n }\n\n decayConfidenceWithDetails(nowSec?: number): { factsDecayed: number; deletedFactIds: string[] } {\n return decayConfidenceWithDetailsImpl(this.liveDb, nowSec);\n }\n\n confirmFact(id: string): boolean {\n return confirmFactImpl(this.liveDb, id);\n }\n\n /**\n * Boost the confidence of a fact by a delta, clamped at maxConfidence.\n * Also increments reinforced_count and updates last_reinforced_at.\n * Returns true if the fact was found and updated.\n */\n boostConfidence(id: string, delta: number, maxConfidence = 1.0): boolean {\n return boostConfidenceHelper(this.liveDb, id, delta, maxConfidence);\n }\n\n /**\n * Annotate a fact with reinforcement from user praise.\n * Increments reinforced_count, updates last_reinforced_at, appends quote (max 10 quotes kept).\n * Optionally records a rich context event in reinforcement_log (#259).\n * Wraps read-modify-write in a transaction to prevent race conditions.\n * Returns true if fact was updated.\n */\n reinforceFact(\n id: string,\n quoteSnippet: string,\n context?: ReinforcementContext,\n opts?: {\n trackContext?: boolean;\n maxEventsPerFact?: number;\n boostAmount?: number;\n },\n ): boolean {\n return reinforceFactHelper(this.liveDb, id, quoteSnippet, context, opts);\n }\n\n /**\n * Get all reinforcement events for a fact from reinforcement_log (#259).\n */\n getReinforcementEvents(factId: string): ReinforcementEvent[] {\n return getReinforcementEventsHelper(this.liveDb, factId);\n }\n\n /**\n * Calculate diversity score for a fact: unique query stems / total events.\n * Score 1.0 = all events from different queries; 0.0 = all from same query (#259).\n */\n calculateDiversityScore(factId: string): number {\n return calculateDiversityScoreHelper(this.liveDb, factId);\n }\n\n /**\n * Phase 2: Annotate a procedure with reinforcement from user praise.\n * Increments reinforced_count, updates last_reinforced_at, appends quote (max 10 quotes kept).\n * Checks if reinforced_count reaches promotion threshold and auto-promotes if needed.\n * Wraps read-modify-write in a transaction to prevent race conditions.\n * Returns true if procedure was updated.\n */\n reinforceProcedure(id: string, quoteSnippet: string, promotionThreshold = 2): boolean {\n return reinforceProcedureHelper(this.liveDb, id, quoteSnippet, promotionThreshold);\n }\n\n saveCheckpoint(context: {\n intent: string;\n state: string;\n expectedOutcome?: string;\n workingFiles?: string[];\n }): string {\n return saveCheckpointImpl((entry) => this.store(entry), context);\n }\n\n restoreCheckpoint(): {\n id: string;\n intent: string;\n state: string;\n expectedOutcome?: string;\n workingFiles?: string[];\n savedAt: string;\n } | null {\n return restoreCheckpointImpl(this.liveDb);\n }\n\n statsBreakdown(): Record<string, number> {\n return statsBreakdownImpl(this.liveDb);\n }\n\n /** Tier breakdown (hot/warm/cold) for non-superseded facts. */\n statsBreakdownByTier(): Record<string, number> {\n return statsBreakdownByTierImpl(this.liveDb);\n }\n\n /** Source breakdown (conversation, cli, distillation, reflection, etc.) for non-superseded facts. */\n statsBreakdownBySource(): Record<string, number> {\n return statsBreakdownBySourceImpl(this.liveDb);\n }\n\n /** Category breakdown for non-superseded facts (for rich stats). */\n statsBreakdownByCategory(): Record<string, number> {\n return statsBreakdownByCategoryImpl(this.liveDb);\n }\n\n /** Decay class breakdown for non-superseded facts (for dashboard stats). */\n statsBreakdownByDecayClass(): Record<string, number> {\n return statsBreakdownByDecayClassImpl(this.liveDb);\n }\n\n /**\n * List facts for dashboard/API: paginated, filterable by category/tier/entity, optional FTS search.\n * Returns entries in dashboard shape (snake_case for JSON) and total count.\n */\n listForDashboard(opts: {\n limit: number;\n offset: number;\n category?: string;\n tier?: string;\n decayClass?: string;\n entity?: string;\n search?: string;\n }): { facts: Array<Record<string, unknown>>; total: number } {\n return listForDashboardImpl(this.liveDb, opts);\n }\n\n /** Distinct memory categories present in non-superseded facts (for CLI stats/categories). */\n uniqueMemoryCategories(): string[] {\n return uniqueMemoryCategoriesImpl(this.liveDb);\n }\n\n /** Compare configured categories with active categories present in facts. */\n auditCategories(configuredCategories: readonly string[], exampleLimit = 5): ReturnType<typeof auditCategoriesImpl> {\n return auditCategoriesImpl(this.liveDb, configuredCategories, exampleLimit);\n }\n\n /** Bulk-remap facts from one category to another; dry-run unless apply=true. */\n remapCategory(from: string, to: string, apply = false): ReturnType<typeof remapCategoryImpl> {\n return remapCategoryImpl(this.liveDb, from, to, apply);\n }\n\n /**\n * List `category-suggested:<label>` tags emitted by the auto-classifier (#1188).\n * Use to surface promotable LLM suggestions via `categories propose`.\n */\n proposedCategories(exampleLimit = 5): ReturnType<typeof proposedCategoriesImpl> {\n return proposedCategoriesImpl(this.liveDb, exampleLimit);\n }\n\n countVectorlessActiveFacts(source?: string): number {\n return countVectorlessActiveFactsImpl(this.liveDb, source);\n }\n\n vectorlessActiveFactsBySource(limit = 20): ReturnType<typeof vectorlessActiveFactsBySourceImpl> {\n return vectorlessActiveFactsBySourceImpl(this.liveDb, limit);\n }\n\n listVectorlessActiveFacts(\n options?: Parameters<typeof listVectorlessActiveFactsImpl>[1],\n ): ReturnType<typeof listVectorlessActiveFactsImpl> {\n return listVectorlessActiveFactsImpl(this.liveDb, options);\n }\n\n /** Snapshot of top procedures for context-audit (sorted by confidence). */\n getProceduresForAudit(limit = 5): ReturnType<typeof getProceduresForAuditImpl> {\n return getProceduresForAuditImpl(this.liveDb, limit);\n }\n\n /** Count of procedures (from procedures table). Returns 0 if table does not exist. */\n proceduresCount(): number {\n return proceduresCountImpl(this.liveDb);\n }\n\n /** Count of procedures with last_validated set (validated at least once). */\n proceduresValidatedCount(): number {\n return proceduresValidatedCountImpl(this.liveDb);\n }\n\n /** Count of procedures whose last_validated is >= sinceSec (e.g., for \"new this week\" digest metrics). */\n proceduresValidatedSince(sinceSec: number): number {\n return proceduresValidatedSinceImpl(this.liveDb, sinceSec);\n }\n\n /** Count of procedures promoted to skill (promoted_to_skill = 1). */\n proceduresPromotedCount(): number {\n return proceduresPromotedCountImpl(this.liveDb);\n }\n\n /** Count of rows in memory_links (graph connections). Returns 0 if table does not exist. */\n linksCount(): number {\n return linksCountImpl(this.liveDb);\n }\n\n /** Count of facts with source LIKE 'directive:%' (extracted directives). */\n directivesCount(): number {\n return directivesCountImpl(this.liveDb);\n }\n\n /** Count of facts with category = 'pattern' and tag 'meta' (meta-patterns). */\n metaPatternsCount(): number {\n return metaPatternsCountImpl(this.liveDb);\n }\n\n /** Distinct entity count (non-null, non-empty entity values). */\n entityCount(): number {\n return entityCountImpl(this.liveDb);\n }\n\n topEntities(limit = 10): ReturnType<typeof topEntitiesImpl> {\n return topEntitiesImpl(this.liveDb, limit);\n }\n\n topEntitiesFiltered(limit = 10, extraStopWords: readonly string[] = []): ReturnType<typeof topEntitiesFilteredImpl> {\n return topEntitiesFilteredImpl(this.liveDb, limit, extraStopWords);\n }\n\n cleanEntityStopwords(\n options?: Parameters<typeof cleanEntityStopwordsImpl>[1],\n ): ReturnType<typeof cleanEntityStopwordsImpl> {\n return cleanEntityStopwordsImpl(this.liveDb, options);\n }\n\n /** Estimated total tokens stored (summary or text) for non-superseded facts. Uses same heuristic as auto-recall. */\n estimateStoredTokens(): number {\n return estimateStoredTokensImpl(this.liveDb);\n }\n\n /** Estimated tokens by tier (hot/warm/cold) for non-superseded facts. */\n estimateStoredTokensByTier(): { hot: number; warm: number; cold: number } {\n return estimateStoredTokensByTierImpl(this.liveDb);\n }\n\n countExpired(): number {\n return countExpiredFactsImpl(this.liveDb);\n }\n\n backfillDecayClasses(options?: Parameters<typeof backfillDecayClassesImpl>[1]): Record<string, number> {\n return backfillDecayClassesImpl(this.liveDb, options);\n }\n\n reclassifyDecayClasses(\n options?: Parameters<typeof reclassifyDecayClassesImpl>[1],\n ): ReturnType<typeof reclassifyDecayClassesImpl> {\n return reclassifyDecayClassesImpl(this.liveDb, options);\n }\n\n lifecycleEntityReport(limit?: number): ReturnType<typeof lifecycleEntityReportImpl> {\n return lifecycleEntityReportImpl(this.liveDb, limit);\n }\n\n expireBySourcePattern(\n options: Parameters<typeof expireBySourcePatternImpl>[1],\n ): ReturnType<typeof expireBySourcePatternImpl> {\n return expireBySourcePatternImpl(this.liveDb, options);\n }\n\n getByCategory(category: string): MemoryEntry[] {\n return getByCategoryImpl(this.liveDb, category);\n }\n\n /** List non-superseded facts by category (for CLI list command). */\n listFactsByCategory(category: string, limit = 100): MemoryEntry[] {\n return listFactsByCategoryImpl(this.liveDb, category, limit);\n }\n\n /**\n * Targeted project-fact query for active-task projection (#1553).\n * Uses a category='project' filter instead of loading all facts, then filtering by category.\n */\n getProjectFacts(limit = 8000, scopeFilter?: ScopeFilter | null): MemoryEntry[] {\n return getProjectFactsImpl(this.liveDb, limit, scopeFilter);\n }\n\n /** List directive facts (source LIKE 'directive:%'), non-superseded, by created_at DESC. */\n listDirectives(limit = 100): MemoryEntry[] {\n return listDirectivesImpl(this.liveDb, limit);\n }\n\n /** Get maximum created_at timestamp for non-superseded facts in a category. */\n getMaxCreatedAtByCategory(category: string): number | null {\n return getMaxCreatedAtByCategoryImpl(this.liveDb, category);\n }\n\n updateCategory(id: string, category: string): boolean {\n return updateCategoryImpl(this.liveDb, id, category);\n }\n\n /**\n * \"other\" facts not yet attempted by auto-classify, or re-ingested since the last attempt.\n */\n getUnattemptedOtherFacts(): MemoryEntry[] {\n return getUnattemptedOtherFactsImpl(this.liveDb);\n }\n\n /** Stamp last_classify_attempt_at on a batch of facts. */\n markClassifyAttempt(ids: string[]): void {\n markClassifyAttemptImpl(this.liveDb, ids);\n }\n\n /** Read a maintenance state value by key. */\n getMaintenanceState(key: string): string | null {\n const row = this.liveDb.prepare(\"SELECT value FROM maintenance_state WHERE key = ?\").get(key) as\n | { value: string }\n | undefined;\n return row?.value ?? null;\n }\n\n /** Write a maintenance state value (upsert). */\n setMaintenanceState(key: string, value: string): void {\n this.liveDb\n .prepare(\n `INSERT INTO maintenance_state (key, value, updated_at)\n VALUES (?, ?, ?)\n ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at`,\n )\n .run(key, value, Math.floor(Date.now() / 1000));\n }\n\n /** Get the live DB handle, reopening if closed after a SIGUSR1 restart. */\n /**\n * Expose the underlying node:sqlite DatabaseSync for services that require direct\n * SQL access (e.g. the FTS5 search service used by the RRF retrieval pipeline).\n * Returned instance is the same live handle used internally (with auto-reopen).\n */\n getRawDb(): DatabaseSync {\n return this.liveDb;\n }\n\n // ---------- Procedural memory (see facts-db/procedures.ts) ----------\n\n procedureFeedback(input: Parameters<typeof procedureFeedbackImpl>[1]): ProcedureEntry | null {\n return procedureFeedbackImpl(this.liveDb, input);\n }\n\n getProcedureVersions(procedureId: string): ReturnType<typeof getProcedureVersionsImpl> {\n return getProcedureVersionsImpl(this.liveDb, procedureId);\n }\n\n getProcedureFailures(procedureId: string): ReturnType<typeof getProcedureFailuresImpl> {\n return getProcedureFailuresImpl(this.liveDb, procedureId);\n }\n\n upsertProcedure(proc: Parameters<typeof upsertProcedureImpl>[1]): ProcedureEntry {\n return upsertProcedureImpl(this.liveDb, proc);\n }\n\n listProcedures(limit = 100): ProcedureEntry[] {\n return listProceduresImpl(this.liveDb, limit);\n }\n\n listProceduresUpdatedInLastNDays(days: number, limit = 500): ProcedureEntry[] {\n return listProceduresUpdatedInLastNDaysImpl(this.liveDb, days, limit);\n }\n\n getProcedureById(id: string): ProcedureEntry | null {\n return getProcedureByIdImpl(this.liveDb, id);\n }\n\n findProcedureByTaskPattern(taskPattern: string, limit = 5): ProcedureEntry[] {\n return findProcedureByTaskPatternImpl(this.liveDb, taskPattern, limit);\n }\n\n searchProcedures(\n taskDescription: string,\n limit = 10,\n reinforcementBoost = 0.1,\n scopeFilter?: ScopeFilter,\n ): ProcedureEntry[] {\n return searchProceduresImpl(this.liveDb, taskDescription, limit, reinforcementBoost, scopeFilter);\n }\n\n searchProceduresRanked(\n taskDescription: string,\n limit = 10,\n reinforcementBoost = 0.1,\n scopeFilter?: ScopeFilter,\n ): Array<ProcedureEntry & { relevanceScore: number }> {\n return searchProceduresRankedImpl(this.liveDb, taskDescription, limit, reinforcementBoost, scopeFilter);\n }\n\n getNegativeProceduresMatching(taskDescription: string, limit = 5, scopeFilter?: ScopeFilter): ProcedureEntry[] {\n return getNegativeProceduresMatchingImpl(this.liveDb, taskDescription, limit, scopeFilter);\n }\n\n recordProcedureSuccess(id: string, recipeJson?: string, sessionId?: string): boolean {\n return recordProcedureSuccessImpl(this.liveDb, id, recipeJson, sessionId);\n }\n\n recordProcedureFailure(id: string, recipeJson?: string, sessionId?: string): boolean {\n return recordProcedureFailureImpl(this.liveDb, id, recipeJson, sessionId);\n }\n\n getProceduresReadyForSkill(validationThreshold: number, limit = 50, skillTTLDays?: number): ProcedureEntry[] {\n return getProceduresReadyForSkillImpl(this.liveDb, validationThreshold, limit, skillTTLDays);\n }\n\n markProcedurePromoted(id: string, skillPath: string): boolean {\n return markProcedurePromotedImpl(this.liveDb, id, skillPath);\n }\n\n triageProcedures(options?: Parameters<typeof triageProceduresImpl>[1]): ReturnType<typeof triageProceduresImpl> {\n return triageProceduresImpl(this.liveDb, options);\n }\n\n getStaleProcedures(ttlDays: number, limit = 100): ProcedureEntry[] {\n return getStaleProceduresImpl(this.liveDb, ttlDays, limit);\n }\n\n listGeneratedSkillProcedures(): ProcedureEntry[] {\n return listGeneratedSkillProceduresImpl(this.liveDb);\n }\n\n getGeneratedSkillByName(skillName: string, procedureId?: string): ProcedureEntry | null {\n return getGeneratedSkillByNameImpl(this.liveDb, skillName, procedureId);\n }\n\n recordGeneratedSkillTelemetry(\n input: GeneratedSkillTelemetryRecordInput,\n policy?: GeneratedSkillLifecyclePolicy,\n ): GeneratedSkillTelemetryEntry {\n return recordGeneratedSkillTelemetryImpl(this.liveDb, input, policy);\n }\n\n listGeneratedSkillTelemetry(skillName?: string, limit?: number): GeneratedSkillTelemetryEntry[] {\n return listGeneratedSkillTelemetryImpl(this.liveDb, skillName, limit);\n }\n\n markGeneratedSkillTelemetryFalsePositive(\n activationId: string,\n correctionReason: string,\n policy?: GeneratedSkillLifecyclePolicy,\n ): GeneratedSkillTelemetryEntry | null {\n return markGeneratedSkillTelemetryFalsePositiveImpl(this.liveDb, activationId, correctionReason, policy);\n }\n\n setGeneratedSkillLifecycleState(\n skillName: string,\n state: GeneratedSkillLifecycleState,\n reason: string | null,\n at?: number,\n procedureId?: string,\n ): ProcedureEntry | null {\n return setGeneratedSkillLifecycleStateImpl(this.liveDb, skillName, state, reason, at, procedureId);\n }\n\n refreshGeneratedSkillLifecycleState(\n skillName: string,\n policy?: GeneratedSkillLifecyclePolicy,\n now?: number,\n procedureId?: string,\n ): ProcedureEntry | null {\n return refreshGeneratedSkillLifecycleStateImpl(this.liveDb, skillName, policy, now, procedureId);\n }\n\n buildGeneratedSkillTelemetryReport(options?: {\n skillName?: string;\n policy?: Partial<GeneratedSkillLifecyclePolicy>;\n recentActivationLimit?: number;\n now?: number;\n }): GeneratedSkillTelemetryReport {\n return buildGeneratedSkillTelemetryReportImpl(this.liveDb, options);\n }\n\n reconcileGeneratedSkillDiskState(opts?: {\n workspaceRoot?: string;\n fix?: boolean;\n now?: number;\n }): GeneratedSkillDoctorReport {\n return reconcileGeneratedSkillDiskStateImpl(this.liveDb, opts);\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"facts-db-layer3.js","names":["pruneOrphanedLinksImpl","countActiveFactsByCategoryImpl","pruneLogTablesImpl","getFtsConsistencySnapshotImpl","runFtsTriggerProbeImpl","rebuildFtsIndexFromFactsImpl","freelistSpaceStatsImpl","statsReflectionImpl","selfCorrectionIncidentsCountImpl","countBySourceImpl","languageKeywordsCountImpl","statsBySourceImpl","uniqueScopesImpl","scopeStatsImpl","pruneScopedFactsImpl","listScopedFactIdsPendingPruneImpl","findSessionFactsForPromotionImpl","updateConfidenceImpl","setConfidenceToImpl","findConflictingFactsImpl","recordContradictionImpl","detectContradictionsImpl","getContradictionsImpl","resolveContradictionImpl","isContradictedImpl","getContradictedIdsImpl","resolveContradictionsAutoImpl","previewResolveContradictionsAutoImpl","resolveProjectStateLwwImpl","resolveContradictionsAutonomouslyImpl","applyContradictionReviewDecisionsImpl","getContradictionResolutionAuditImpl","contradictionsCountImpl","countSupersededFactsImpl","countVerifiedFactsImpl","recentActivityImpl","getKnownEntitiesImpl","extractEntitiesFromTextImpl","findEntityAnchorImpl","autoDetectInstanceOfImpl","autoLinkEntitiesImpl","getAllLinkedFactIdsImpl","getAllLinksImpl","getAllEdgesImpl","getClustersImpl","getClusterMembersImpl","getFactClusterIdImpl","recordEpisodeImpl","searchEpisodesImpl","getEpisodeImpl","deleteEpisodeImpl","episodesCountImpl","lookupOrganizationByKeyOrName","entityLayerListContactsForOrg","entityLayerListContactsByNamePrefix","entityLayerListFactIdsForOrg","entityLayerListFactsNeedingEnrichment","entityLayerGetEntityEnrichmentBacklogSummary","entityLayerAuditEntityMentions","entityLayerCleanupEntityMentions"],"sources":["../../../backends/facts-db/facts-db-layer3.ts"],"sourcesContent":["/**\n * FactsDB — layer 3: housekeeping, contradictions, autolink, clusters, episodes, entity layer.\n */\n\nimport type { ExtractedMention } from \"../../services/entity-enrichment.js\";\nimport type { Episode, EpisodeOutcome, MemoryEntry, ScopeFilter } from \"../../types/memory.js\";\nimport {\n getAllEdges as getAllEdgesImpl,\n getAllLinkedFactIds as getAllLinkedFactIdsImpl,\n getAllLinks as getAllLinksImpl,\n getClusterMembers as getClusterMembersImpl,\n getClusters as getClustersImpl,\n getFactClusterId as getFactClusterIdImpl,\n saveClusters as saveClustersImpl,\n} from \"./clusters.js\";\nimport {\n addTag as addTagImpl,\n applyContradictionReviewDecisions as applyContradictionReviewDecisionsImpl,\n contradictionsCount as contradictionsCountImpl,\n detectContradictions as detectContradictionsImpl,\n evaluateLwwEligibility,\n findConflictingFacts as findConflictingFactsImpl,\n getContradictionResolutionAudit as getContradictionResolutionAuditImpl,\n getContradictedIds as getContradictedIdsImpl,\n getContradictions as getContradictionsImpl,\n isContradicted as isContradictedImpl,\n isFactVerified,\n PROJECT_STATE_LWW_KEYS,\n recordContradiction as recordContradictionImpl,\n resolveContradiction as resolveContradictionImpl,\n previewResolveContradictionsAuto as previewResolveContradictionsAutoImpl,\n resolveContradictionsAuto as resolveContradictionsAutoImpl,\n resolveContradictionsAutonomously as resolveContradictionsAutonomouslyImpl,\n resolveProjectStateLww as resolveProjectStateLwwImpl,\n setConfidenceTo as setConfidenceToImpl,\n updateConfidence as updateConfidenceImpl,\n} from \"./contradictions.js\";\nimport type {\n ApplyContradictionReviewResult,\n ContradictionRecord,\n ContradictionResolutionAuditRow,\n ContradictionReviewDecision,\n ProjectStateLwwResult,\n ResolveContradictionsAutoOptions,\n ResolveContradictionsAutoResult,\n} from \"./contradictions.js\";\nimport {\n autoDetectInstanceOf as autoDetectInstanceOfImpl,\n autoLinkEntities as autoLinkEntitiesImpl,\n extractEntitiesFromText as extractEntitiesFromTextImpl,\n findEntityAnchor as findEntityAnchorImpl,\n getKnownEntities as getKnownEntitiesImpl,\n} from \"./entity-autolink.js\";\nimport {\n type EntityEnrichmentBacklogSummary,\n type EntityMentionsAuditSummary,\n type EntityMentionsCleanupSummary,\n type ContactRow,\n type ListFactsNeedingEnrichmentOptions,\n type OrganizationRow,\n getEntityEnrichmentBacklogSummary as entityLayerGetEntityEnrichmentBacklogSummary,\n auditEntityMentions as entityLayerAuditEntityMentions,\n cleanupEntityMentions as entityLayerCleanupEntityMentions,\n listContactsByNamePrefix as entityLayerListContactsByNamePrefix,\n listContactsForOrg as entityLayerListContactsForOrg,\n listFactIdsForOrg as entityLayerListFactIdsForOrg,\n listFactsNeedingEnrichment as entityLayerListFactsNeedingEnrichment,\n getOrganizationByKeyOrName as lookupOrganizationByKeyOrName,\n replaceFactEntityMentions,\n} from \"./entity-layer.js\";\nimport {\n deleteEpisode as deleteEpisodeImpl,\n episodesCount as episodesCountImpl,\n getEpisode as getEpisodeImpl,\n recordEpisode as recordEpisodeImpl,\n searchEpisodes as searchEpisodesImpl,\n} from \"./episodes.js\";\nimport { FactsDBLayer2 } from \"./facts-db-layer2.js\";\nimport {\n countBySource as countBySourceImpl,\n countSupersededFacts as countSupersededFactsImpl,\n countVerifiedFacts as countVerifiedFactsImpl,\n getFtsConsistencySnapshot as getFtsConsistencySnapshotImpl,\n findSessionFactsForPromotion as findSessionFactsForPromotionImpl,\n freelistSpaceStats as freelistSpaceStatsImpl,\n languageKeywordsCount as languageKeywordsCountImpl,\n optimizeFts as optimizeFtsImpl,\n checkpointWalTruncate as checkpointWalTruncateImpl,\n pruneLogTables as pruneLogTablesImpl,\n pruneOrphanedLinks as pruneOrphanedLinksImpl,\n pruneScopedFacts as pruneScopedFactsImpl,\n listScopedFactIdsPendingPrune as listScopedFactIdsPendingPruneImpl,\n recentActivity as recentActivityImpl,\n rebuildFtsIndexFromFacts as rebuildFtsIndexFromFactsImpl,\n runFtsTriggerProbe as runFtsTriggerProbeImpl,\n scopeStats as scopeStatsImpl,\n selfCorrectionIncidentsCount as selfCorrectionIncidentsCountImpl,\n statsBySource as statsBySourceImpl,\n statsReflection as statsReflectionImpl,\n type FtsConsistencySnapshot,\n type FtsTriggerProbeResult,\n uniqueScopes as uniqueScopesImpl,\n vacuumAndCheckpoint as vacuumAndCheckpointImpl,\n countActiveFactsByCategory as countActiveFactsByCategoryImpl,\n} from \"./housekeeping.js\";\n\nexport class FactsDB extends FactsDBLayer2 {\n /** Alias for pruneExpired() for backward compatibility */\n prune(): number {\n return this.pruneExpired();\n }\n\n /**\n * Remove orphaned rows from memory_links where source_fact_id or\n * target_fact_id no longer reference an existing fact.\n * Returns the number of deleted rows.\n */\n pruneOrphanedLinks(): number {\n return pruneOrphanedLinksImpl(this.liveDb);\n }\n\n /**\n * SQL COUNT of active (non-superseded, non-expired) facts for a given category.\n * More efficient than getByCategory() + in-JS filter for maintenance/reporting.\n */\n countActiveFactsByCategory(category: string): number {\n return countActiveFactsByCategoryImpl(this.liveDb, category);\n }\n\n /** Alias for backfillDecayClasses() for backward compatibility */\n backfillDecay(options?: {\n onProgress?: (progress: import(\"./maintenance.js\").BackfillDecayProgress) => void;\n reportEvery?: number;\n }): Record<string, number> {\n return this.backfillDecayClasses(options);\n }\n\n pruneLogTables(retentionDays: number): number {\n return pruneLogTablesImpl(this.liveDb, retentionDays);\n }\n\n optimizeFts(): void {\n optimizeFtsImpl(this.liveDb);\n }\n\n /** Snapshot FTS table/trigger/population consistency for doctor/health checks. */\n getFtsConsistencySnapshot(): FtsConsistencySnapshot {\n return getFtsConsistencySnapshotImpl(this.liveDb);\n }\n\n /** Deep savepointed INSERT/UPDATE/DELETE probe to confirm FTS triggers actually fire. */\n runFtsTriggerProbe(): FtsTriggerProbeResult {\n return runFtsTriggerProbeImpl(this.liveDb);\n }\n\n /** Rebuild FTS contents from `facts` rows (used by doctor --fix when drift is detected). */\n rebuildFtsIndex(): number {\n return rebuildFtsIndexFromFactsImpl(this.liveDb);\n }\n\n freelistSpaceStats(): ReturnType<typeof freelistSpaceStatsImpl> {\n return freelistSpaceStatsImpl(this.liveDb);\n }\n\n checkpointWalTruncate(): void {\n checkpointWalTruncateImpl(this.liveDb);\n }\n\n vacuumAndCheckpoint(): void {\n vacuumAndCheckpointImpl(this.liveDb);\n }\n\n statsReflection(): ReturnType<typeof statsReflectionImpl> {\n return statsReflectionImpl(this.liveDb);\n }\n\n selfCorrectionIncidentsCount(): number {\n return selfCorrectionIncidentsCountImpl(this.liveDb);\n }\n\n countBySource(source: string): number {\n return countBySourceImpl(this.liveDb, source);\n }\n\n languageKeywordsCount(): number {\n return languageKeywordsCountImpl();\n }\n\n statsBySource(): Record<string, number> {\n return statsBySourceImpl(this.liveDb);\n }\n\n uniqueScopes(): Array<{ scope: string; scopeTarget: string | null }> {\n return uniqueScopesImpl(this.liveDb);\n }\n\n scopeStats(): ReturnType<typeof scopeStatsImpl> {\n return scopeStatsImpl(this.liveDb);\n }\n\n pruneScopedFacts(scopeFilter: ScopeFilter): number {\n return pruneScopedFactsImpl(this.liveDb, scopeFilter);\n }\n\n /**\n * Return the fact IDs that `pruneScopedFacts(scopeFilter)` would delete.\n * Call this *before* `pruneScopedFacts` to collect IDs for LanceDB vector cleanup.\n * Excludes verified/pinned facts (same guard as the DELETE).\n */\n listScopedFactIdsPendingPrune(scopeFilter: ScopeFilter): string[] {\n return listScopedFactIdsPendingPruneImpl(this.liveDb, scopeFilter);\n }\n\n findSessionFactsForPromotion(thresholdDays: number, minImportance: number): MemoryEntry[] {\n return findSessionFactsForPromotionImpl(this.liveDb, thresholdDays, minImportance);\n }\n\n // ============================================================================\n // Contradiction Detection (Issue #157)\n // ============================================================================\n\n updateConfidence(id: string, delta: number): number | null {\n return updateConfidenceImpl(this.liveDb, id, delta);\n }\n\n setConfidenceTo(id: string, value: number): number | null {\n return setConfidenceToImpl(this.liveDb, id, value);\n }\n\n addTag(id: string, tag: string): void {\n addTagImpl(this.liveDb, id, tag);\n }\n\n findConflictingFacts(\n entity: string,\n key: string,\n value: string,\n excludeFactId: string,\n scope?: string | null,\n scopeTarget?: string | null,\n ): MemoryEntry[] {\n return findConflictingFactsImpl(this.liveDb, entity, key, value, excludeFactId, scope, scopeTarget);\n }\n\n recordContradiction(factIdNew: string, factIdOld: string): string {\n return recordContradictionImpl(this.liveDb, factIdNew, factIdOld, (a, b, t, s) =>\n this.createLink(a, b, t, s ?? 1.0),\n ).id;\n }\n\n detectContradictions(\n newFactId: string,\n entity: string | null | undefined,\n key: string | null | undefined,\n value: string | null | undefined,\n scope?: string | null,\n scopeTarget?: string | null,\n ): Array<{ contradictionId: string; oldFactId: string; oldFactOriginalConfidence: number }> {\n const results = detectContradictionsImpl(\n this.liveDb,\n newFactId,\n entity,\n key,\n value,\n scope,\n scopeTarget,\n (a, b, t, s) => this.createLink(a, b, t, s ?? 1.0),\n );\n\n // Project-state LWW: immediately resolve contradictions for known mutable keys so\n // active-task/project writes do not leave avoidable unresolved contradictions (#1636).\n if (results.length > 0 && key != null) {\n const keyLower = key.trim().toLowerCase();\n if (PROJECT_STATE_LWW_KEYS.has(keyLower)) {\n const newFact = this.getById(newFactId);\n if (newFact) {\n for (const { contradictionId, oldFactId, oldFactOriginalConfidence } of results) {\n const oldFact = this.getById(oldFactId);\n if (!oldFact) continue;\n const lww = evaluateLwwEligibility(newFact, oldFact, oldFactOriginalConfidence);\n if (lww.eligible && lww.qualifies && !isFactVerified(this.liveDb, oldFactId)) {\n const superseded = this.supersede(oldFactId, newFactId);\n if (superseded) {\n this.resolveContradiction(contradictionId, \"superseded\");\n }\n }\n }\n }\n }\n }\n\n return results;\n }\n\n getContradictions(factId?: string): ContradictionRecord[] {\n return getContradictionsImpl(this.liveDb, factId);\n }\n\n resolveContradiction(contradictionId: string, resolution: \"superseded\" | \"kept\" | \"merged\"): boolean {\n return resolveContradictionImpl(this.liveDb, contradictionId, resolution);\n }\n\n isContradicted(factId: string): boolean {\n return isContradictedImpl(this.liveDb, factId);\n }\n\n getContradictedIds(factIds: string[]): Set<string> {\n return getContradictedIdsImpl(this.liveDb, factIds);\n }\n\n resolveContradictions(): ReturnType<typeof resolveContradictionsAutoImpl> {\n return resolveContradictionsAutoImpl(\n this.liveDb,\n (id) => this.getById(id),\n (o, n) => this.supersede(o, n),\n );\n }\n\n previewResolveContradictions(): ReturnType<typeof previewResolveContradictionsAutoImpl> {\n return previewResolveContradictionsAutoImpl(this.liveDb, (id) => this.getById(id));\n }\n\n /**\n * Project-state latest-wins resolution pass (Issue #1636).\n * Safely resolves stale `project` contradictions for known mutable keys when the newer\n * trusted fact is strictly newer and has equal or higher confidence.\n *\n * Pass `{ dryRun: true }` to inspect candidates without mutating any data.\n */\n resolveContradictionsProjectStateLww(opts: { dryRun?: boolean } = {}): ProjectStateLwwResult {\n return resolveProjectStateLwwImpl(\n this.liveDb,\n (id) => this.getById(id),\n (o, n) => this.supersede(o, n),\n opts,\n );\n }\n\n async resolveContradictionsAuto(\n opts: ResolveContradictionsAutoOptions = {},\n ): Promise<ResolveContradictionsAutoResult> {\n return resolveContradictionsAutonomouslyImpl(\n this.liveDb,\n (id) => this.getById(id),\n (o, n) => this.supersede(o, n),\n opts,\n );\n }\n\n applyContradictionReviewDecisions(\n decisions: ContradictionReviewDecision[],\n opts: { actor?: string; toolVersion?: string | null } = {},\n ): ApplyContradictionReviewResult {\n return applyContradictionReviewDecisionsImpl(\n this.liveDb,\n (id) => this.getById(id),\n (o, n) => this.supersede(o, n),\n decisions,\n opts,\n );\n }\n\n getContradictionResolutionAudit(contradictionId?: string): ContradictionResolutionAuditRow[] {\n return getContradictionResolutionAuditImpl(this.liveDb, contradictionId);\n }\n\n contradictionsCount(): number {\n return contradictionsCountImpl(this.liveDb);\n }\n\n /** Number of facts with `superseded_at IS NOT NULL`. */\n countSupersededFacts(): number {\n return countSupersededFactsImpl(this.liveDb);\n }\n\n /** Number of rows in `verified_facts` (0 when verification disabled / table absent). */\n countVerifiedFacts(): number {\n return countVerifiedFactsImpl(this.liveDb);\n }\n\n /** Recent ingestion activity: last 24h / 7d / 30d, plus newest/oldest active timestamps. */\n recentActivity(): ReturnType<typeof recentActivityImpl> {\n return recentActivityImpl(this.liveDb);\n }\n\n // ---------------------------------------------------------------------------\n // Auto-linking helpers (Issue #154)\n // ---------------------------------------------------------------------------\n\n getKnownEntities(): string[] {\n return getKnownEntitiesImpl(this.liveDb);\n }\n\n extractEntitiesFromText(text: string, knownEntities: string[]): Array<{ entity: string; weight: number }> {\n return extractEntitiesFromTextImpl(text, knownEntities);\n }\n\n findEntityAnchor(entity: string, excludeId?: string): MemoryEntry | null {\n return findEntityAnchorImpl(this.liveDb, entity, excludeId);\n }\n\n autoDetectInstanceOf(newFactId: string, text: string, knownEntities?: string[]): number {\n return autoDetectInstanceOfImpl(\n this.liveDb,\n newFactId,\n text,\n knownEntities,\n (a, b, t, s) => this.createLink(a, b, t, s ?? 1.0),\n getKnownEntitiesImpl,\n );\n }\n\n autoLinkEntities(\n newFactId: string,\n text: string,\n entity: string | null,\n key: string | null,\n sessionId: string | null,\n cfg: { coOccurrenceWeight: number; autoSupersede: boolean },\n scope?: string | null,\n scopeTarget?: string | null,\n ): { linkedCount: number; supersededIds: string[] } {\n return autoLinkEntitiesImpl(\n this.liveDb,\n newFactId,\n text,\n entity,\n key,\n sessionId,\n cfg,\n scope,\n scopeTarget,\n (a, b, t, s) => this.createLink(a, b, t, s ?? 1.0),\n (o, n) => this.supersede(o, n),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Topic cluster storage (Issue #146)\n // ---------------------------------------------------------------------------\n\n getAllLinkedFactIds(): string[] {\n return getAllLinkedFactIdsImpl(this.liveDb);\n }\n\n getAllLinks(): Array<{ sourceFactId: string; targetFactId: string }> {\n return getAllLinksImpl(this.liveDb);\n }\n\n getAllEdges(limit = 5000): ReturnType<typeof getAllEdgesImpl> {\n return getAllEdgesImpl(this.liveDb, limit);\n }\n\n saveClusters(\n clusters: Array<{\n id: string;\n label: string;\n factIds: string[];\n factCount: number;\n createdAt: number;\n updatedAt: number;\n }>,\n ): void {\n saveClustersImpl(this.liveDb, clusters);\n }\n\n getClusters(): ReturnType<typeof getClustersImpl> {\n return getClustersImpl(this.liveDb);\n }\n\n getClusterMembers(clusterId: string): string[] {\n return getClusterMembersImpl(this.liveDb, clusterId);\n }\n\n getFactClusterId(factId: string): string | null {\n return getFactClusterIdImpl(this.liveDb, factId);\n }\n\n // ============================================================================\n // Episodic Memory (#781)\n // ============================================================================\n\n recordEpisode(input: Parameters<typeof recordEpisodeImpl>[1]): Episode {\n return recordEpisodeImpl(this.liveDb, input);\n }\n\n searchEpisodes(\n options: {\n query?: string;\n outcome?: EpisodeOutcome[];\n since?: number;\n until?: number;\n procedureId?: string;\n limit?: number;\n scopeFilter?: ScopeFilter | null;\n } = {},\n ): Episode[] {\n return searchEpisodesImpl(this.liveDb, options);\n }\n\n getEpisode(id: string): Episode | null {\n return getEpisodeImpl(this.liveDb, id);\n }\n\n deleteEpisode(id: string): boolean {\n return deleteEpisodeImpl(this.liveDb, id);\n }\n\n episodesCount(): number {\n return episodesCountImpl(this.liveDb);\n }\n\n // --- Entity layer: NER mentions, organizations, contacts (#985–#987) ---\n\n /** Replace stored NER rows for a fact (typically after LLM extraction). */\n applyEntityEnrichment(factId: string, mentions: ExtractedMention[], detectedLang: string): void {\n replaceFactEntityMentions(\n this.liveDb,\n factId,\n mentions.map((m) => ({\n label: m.label,\n surfaceText: m.surfaceText,\n normalizedSurface: m.normalizedSurface,\n startOffset: m.startOffset,\n endOffset: m.endOffset,\n confidence: m.confidence,\n detectedLang,\n source: \"llm\",\n })),\n );\n }\n\n /** Resolve an organization by canonical key or fuzzy display name. */\n lookupOrganization(query: string): OrganizationRow | null {\n return lookupOrganizationByKeyOrName(this.liveDb, query);\n }\n\n /** Contacts with primary_org_id = org. */\n listContactsForOrganization(orgId: string, limit: number): ContactRow[] {\n return entityLayerListContactsForOrg(this.liveDb, orgId, limit);\n }\n\n /** List contacts by optional name prefix (empty = recent alphabetical cap). */\n listContactsByNamePrefix(prefix: string, limit: number): ContactRow[] {\n return entityLayerListContactsByNamePrefix(this.liveDb, prefix, limit);\n }\n\n /** Fact ids linked to an org via NER/org_fact_links. */\n listFactIdsLinkedToOrg(orgId: string, limit: number): string[] {\n return entityLayerListFactIdsForOrg(this.liveDb, orgId, limit);\n }\n\n /** Facts not yet processed by entity enrichment (see `facts.entity_enrichment_at`). */\n listFactIdsNeedingEntityEnrichment(\n limit: number,\n minTextLen = 24,\n options?: ListFactsNeedingEnrichmentOptions,\n ): string[] {\n return entityLayerListFactsNeedingEnrichment(this.liveDb, limit, minTextLen, options);\n }\n\n /** Aggregate pending enrichment backlog by tier for progress reporting and catch-up planning. */\n getEntityEnrichmentBacklogSummary(minTextLen = 24): EntityEnrichmentBacklogSummary {\n return entityLayerGetEntityEnrichmentBacklogSummary(this.liveDb, minTextLen);\n }\n\n auditEntityMentions(limit = 500): EntityMentionsAuditSummary {\n return entityLayerAuditEntityMentions(this.liveDb, limit);\n }\n\n cleanupEntityMentions(opts: { limit?: number; apply?: boolean } = {}): EntityMentionsCleanupSummary {\n return entityLayerCleanupEntityMentions(this.liveDb, {\n limit: opts.limit ?? 500,\n apply: opts.apply === true,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"facts-db-layer3.js","names":["pruneOrphanedLinksImpl","countActiveFactsByCategoryImpl","pruneLogTablesImpl","getFtsConsistencySnapshotImpl","runFtsTriggerProbeImpl","rebuildFtsIndexFromFactsImpl","freelistSpaceStatsImpl","statsReflectionImpl","selfCorrectionIncidentsCountImpl","countBySourceImpl","languageKeywordsCountImpl","statsBySourceImpl","uniqueScopesImpl","scopeStatsImpl","pruneScopedFactsImpl","listScopedFactIdsPendingPruneImpl","findSessionFactsForPromotionImpl","updateConfidenceImpl","setConfidenceToImpl","findConflictingFactsImpl","recordContradictionImpl","detectContradictionsImpl","getContradictionsImpl","resolveContradictionImpl","isContradictedImpl","getContradictedIdsImpl","resolveContradictionsAutoImpl","previewResolveContradictionsAutoImpl","resolveProjectStateLwwImpl","resolveContradictionsAutonomouslyImpl","applyContradictionReviewDecisionsImpl","getContradictionResolutionAuditImpl","contradictionsCountImpl","countSupersededFactsImpl","countVerifiedFactsImpl","recentActivityImpl","getKnownEntitiesImpl","extractEntitiesFromTextImpl","findEntityAnchorImpl","autoDetectInstanceOfImpl","autoLinkEntitiesImpl","getAllLinkedFactIdsImpl","getAllLinksImpl","getAllEdgesImpl","getClustersImpl","getClusterMembersImpl","getFactClusterIdImpl","recordEpisodeImpl","searchEpisodesImpl","getEpisodeImpl","deleteEpisodeImpl","episodesCountImpl","lookupOrganizationByKeyOrName","entityLayerListContactsForOrg","entityLayerListContactsByNamePrefix","entityLayerListFactIdsForOrg","entityLayerListFactsNeedingEnrichment","entityLayerGetEntityEnrichmentBacklogSummary","entityLayerAuditEntityMentions","entityLayerCleanupEntityMentions"],"sources":["../../../backends/facts-db/facts-db-layer3.ts"],"sourcesContent":["/**\n * FactsDB — layer 3: housekeeping, contradictions, autolink, clusters, episodes, entity layer.\n */\n\nimport type { ExtractedMention } from \"../../services/entity-enrichment.js\";\nimport type { Episode, EpisodeOutcome, MemoryEntry, ScopeFilter } from \"../../types/memory.js\";\nimport {\n getAllEdges as getAllEdgesImpl,\n getAllLinkedFactIds as getAllLinkedFactIdsImpl,\n getAllLinks as getAllLinksImpl,\n getClusterMembers as getClusterMembersImpl,\n getClusters as getClustersImpl,\n getFactClusterId as getFactClusterIdImpl,\n saveClusters as saveClustersImpl,\n} from \"./clusters.js\";\nimport {\n addTag as addTagImpl,\n applyContradictionReviewDecisions as applyContradictionReviewDecisionsImpl,\n contradictionsCount as contradictionsCountImpl,\n detectContradictions as detectContradictionsImpl,\n evaluateLwwEligibility,\n findConflictingFacts as findConflictingFactsImpl,\n getContradictionResolutionAudit as getContradictionResolutionAuditImpl,\n getContradictedIds as getContradictedIdsImpl,\n getContradictions as getContradictionsImpl,\n isContradicted as isContradictedImpl,\n isFactVerified,\n PROJECT_STATE_LWW_KEYS,\n recordContradiction as recordContradictionImpl,\n resolveContradiction as resolveContradictionImpl,\n previewResolveContradictionsAuto as previewResolveContradictionsAutoImpl,\n resolveContradictionsAuto as resolveContradictionsAutoImpl,\n resolveContradictionsAutonomously as resolveContradictionsAutonomouslyImpl,\n resolveProjectStateLww as resolveProjectStateLwwImpl,\n setConfidenceTo as setConfidenceToImpl,\n updateConfidence as updateConfidenceImpl,\n} from \"./contradictions.js\";\nimport type {\n ApplyContradictionReviewResult,\n ContradictionRecord,\n ContradictionResolutionAuditRow,\n ContradictionReviewDecision,\n ProjectStateLwwResult,\n ResolveContradictionsAutoOptions,\n ResolveContradictionsAutoResult,\n} from \"./contradictions.js\";\nimport {\n autoDetectInstanceOf as autoDetectInstanceOfImpl,\n autoLinkEntities as autoLinkEntitiesImpl,\n extractEntitiesFromText as extractEntitiesFromTextImpl,\n findEntityAnchor as findEntityAnchorImpl,\n getKnownEntities as getKnownEntitiesImpl,\n} from \"./entity-autolink.js\";\nimport {\n type EntityEnrichmentBacklogSummary,\n type EntityMentionsAuditSummary,\n type EntityMentionsCleanupSummary,\n type ContactRow,\n type ListFactsNeedingEnrichmentOptions,\n type OrganizationRow,\n getEntityEnrichmentBacklogSummary as entityLayerGetEntityEnrichmentBacklogSummary,\n auditEntityMentions as entityLayerAuditEntityMentions,\n cleanupEntityMentions as entityLayerCleanupEntityMentions,\n listContactsByNamePrefix as entityLayerListContactsByNamePrefix,\n listContactsForOrg as entityLayerListContactsForOrg,\n listFactIdsForOrg as entityLayerListFactIdsForOrg,\n listFactsNeedingEnrichment as entityLayerListFactsNeedingEnrichment,\n getOrganizationByKeyOrName as lookupOrganizationByKeyOrName,\n replaceFactEntityMentions,\n} from \"./entity-layer.js\";\nimport {\n deleteEpisode as deleteEpisodeImpl,\n episodesCount as episodesCountImpl,\n getEpisode as getEpisodeImpl,\n recordEpisode as recordEpisodeImpl,\n searchEpisodes as searchEpisodesImpl,\n} from \"./episodes.js\";\nimport { FactsDBLayer2 } from \"./facts-db-layer2.js\";\nimport {\n countBySource as countBySourceImpl,\n countSupersededFacts as countSupersededFactsImpl,\n countVerifiedFacts as countVerifiedFactsImpl,\n getFtsConsistencySnapshot as getFtsConsistencySnapshotImpl,\n findSessionFactsForPromotion as findSessionFactsForPromotionImpl,\n freelistSpaceStats as freelistSpaceStatsImpl,\n languageKeywordsCount as languageKeywordsCountImpl,\n optimizeFts as optimizeFtsImpl,\n checkpointWalTruncate as checkpointWalTruncateImpl,\n pruneLogTables as pruneLogTablesImpl,\n pruneOrphanedLinks as pruneOrphanedLinksImpl,\n pruneScopedFacts as pruneScopedFactsImpl,\n listScopedFactIdsPendingPrune as listScopedFactIdsPendingPruneImpl,\n recentActivity as recentActivityImpl,\n rebuildFtsIndexFromFacts as rebuildFtsIndexFromFactsImpl,\n runFtsTriggerProbe as runFtsTriggerProbeImpl,\n scopeStats as scopeStatsImpl,\n selfCorrectionIncidentsCount as selfCorrectionIncidentsCountImpl,\n statsBySource as statsBySourceImpl,\n statsReflection as statsReflectionImpl,\n type FtsConsistencySnapshot,\n type FtsTriggerProbeResult,\n uniqueScopes as uniqueScopesImpl,\n vacuumAndCheckpoint as vacuumAndCheckpointImpl,\n countActiveFactsByCategory as countActiveFactsByCategoryImpl,\n} from \"./housekeeping.js\";\n\nexport class FactsDB extends FactsDBLayer2 {\n /** Alias for pruneExpired() for backward compatibility */\n prune(): number {\n return this.pruneExpired();\n }\n\n /**\n * Remove orphaned rows from memory_links where source_fact_id or\n * target_fact_id no longer reference an existing fact.\n * Returns the number of deleted rows.\n */\n pruneOrphanedLinks(): number {\n return pruneOrphanedLinksImpl(this.liveDb);\n }\n\n /**\n * SQL COUNT of active (non-superseded, non-expired) facts for a given category.\n * More efficient than getByCategory() + in-JS filter for maintenance/reporting.\n */\n countActiveFactsByCategory(category: string): number {\n return countActiveFactsByCategoryImpl(this.liveDb, category);\n }\n\n /** Alias for backfillDecayClasses() for backward compatibility */\n backfillDecay(options?: {\n onProgress?: (progress: import(\"./maintenance.js\").BackfillDecayProgress) => void;\n reportEvery?: number;\n }): Record<string, number> {\n return this.backfillDecayClasses(options);\n }\n\n pruneLogTables(retentionDays: number): number {\n return pruneLogTablesImpl(this.liveDb, retentionDays);\n }\n\n optimizeFts(): void {\n optimizeFtsImpl(this.liveDb);\n }\n\n /** Snapshot FTS table/trigger/population consistency for doctor/health checks. */\n getFtsConsistencySnapshot(): FtsConsistencySnapshot {\n return getFtsConsistencySnapshotImpl(this.liveDb);\n }\n\n /** Deep savepointed INSERT/UPDATE/DELETE probe to confirm FTS triggers actually fire. */\n runFtsTriggerProbe(): FtsTriggerProbeResult {\n return runFtsTriggerProbeImpl(this.liveDb);\n }\n\n /** Rebuild FTS contents from `facts` rows (used by doctor --fix when drift is detected). */\n rebuildFtsIndex(): number {\n return rebuildFtsIndexFromFactsImpl(this.liveDb);\n }\n\n freelistSpaceStats(): ReturnType<typeof freelistSpaceStatsImpl> {\n return freelistSpaceStatsImpl(this.liveDb);\n }\n\n checkpointWalTruncate(): void {\n checkpointWalTruncateImpl(this.liveDb);\n }\n\n vacuumAndCheckpoint(): void {\n vacuumAndCheckpointImpl(this.liveDb);\n }\n\n statsReflection(): ReturnType<typeof statsReflectionImpl> {\n return statsReflectionImpl(this.liveDb);\n }\n\n selfCorrectionIncidentsCount(): number {\n return selfCorrectionIncidentsCountImpl(this.liveDb);\n }\n\n countBySource(source: string): number {\n return countBySourceImpl(this.liveDb, source);\n }\n\n languageKeywordsCount(): number {\n return languageKeywordsCountImpl();\n }\n\n statsBySource(): Record<string, number> {\n return statsBySourceImpl(this.liveDb);\n }\n\n uniqueScopes(): Array<{ scope: string; scopeTarget: string | null }> {\n return uniqueScopesImpl(this.liveDb);\n }\n\n scopeStats(): ReturnType<typeof scopeStatsImpl> {\n return scopeStatsImpl(this.liveDb);\n }\n\n pruneScopedFacts(scopeFilter: ScopeFilter): number {\n return pruneScopedFactsImpl(this.liveDb, scopeFilter);\n }\n\n /**\n * Return the fact IDs that `pruneScopedFacts(scopeFilter)` would delete.\n * Call this *before* `pruneScopedFacts` to collect IDs for LanceDB vector cleanup.\n * Excludes verified/pinned facts (same guard as the DELETE).\n */\n listScopedFactIdsPendingPrune(scopeFilter: ScopeFilter): string[] {\n return listScopedFactIdsPendingPruneImpl(this.liveDb, scopeFilter);\n }\n\n findSessionFactsForPromotion(thresholdDays: number, minImportance: number): MemoryEntry[] {\n return findSessionFactsForPromotionImpl(this.liveDb, thresholdDays, minImportance);\n }\n\n // ============================================================================\n // Contradiction Detection (Issue #157)\n // ============================================================================\n\n updateConfidence(id: string, delta: number): number | null {\n return updateConfidenceImpl(this.liveDb, id, delta);\n }\n\n setConfidenceTo(id: string, value: number): number | null {\n return setConfidenceToImpl(this.liveDb, id, value);\n }\n\n addTag(id: string, tag: string): void {\n addTagImpl(this.liveDb, id, tag);\n }\n\n findConflictingFacts(\n entity: string,\n key: string,\n value: string,\n excludeFactId: string,\n scope?: string | null,\n scopeTarget?: string | null,\n ): MemoryEntry[] {\n return findConflictingFactsImpl(this.liveDb, entity, key, value, excludeFactId, scope, scopeTarget);\n }\n\n recordContradiction(factIdNew: string, factIdOld: string): string {\n return recordContradictionImpl(this.liveDb, factIdNew, factIdOld, (a, b, t, s) =>\n this.createLink(a, b, t, s ?? 1.0),\n ).id;\n }\n\n detectContradictions(\n newFactId: string,\n entity: string | null | undefined,\n key: string | null | undefined,\n value: string | null | undefined,\n scope?: string | null,\n scopeTarget?: string | null,\n ): Array<{ contradictionId: string; oldFactId: string; oldFactOriginalConfidence: number }> {\n const results = detectContradictionsImpl(\n this.liveDb,\n newFactId,\n entity,\n key,\n value,\n scope,\n scopeTarget,\n (a, b, t, s) => this.createLink(a, b, t, s ?? 1.0),\n );\n\n // Project-state LWW: immediately resolve contradictions for known mutable keys so\n // active-task/project writes do not leave avoidable unresolved contradictions (#1636).\n if (results.length > 0 && key != null) {\n const keyLower = key.trim().toLowerCase();\n if (PROJECT_STATE_LWW_KEYS.has(keyLower)) {\n const newFact = this.getById(newFactId);\n if (newFact) {\n for (const { contradictionId, oldFactId, oldFactOriginalConfidence } of results) {\n const oldFact = this.getById(oldFactId);\n if (!oldFact) continue;\n const lww = evaluateLwwEligibility(newFact, oldFact, oldFactOriginalConfidence);\n if (lww.eligible && lww.qualifies && !isFactVerified(this.liveDb, oldFactId)) {\n const superseded = this.supersede(oldFactId, newFactId);\n if (superseded) {\n this.resolveContradiction(contradictionId, \"superseded\");\n }\n }\n }\n }\n }\n }\n\n return results;\n }\n\n getContradictions(factId?: string): ContradictionRecord[] {\n return getContradictionsImpl(this.liveDb, factId);\n }\n\n resolveContradiction(contradictionId: string, resolution: \"superseded\" | \"kept\" | \"merged\"): boolean {\n return resolveContradictionImpl(this.liveDb, contradictionId, resolution);\n }\n\n isContradicted(factId: string): boolean {\n return isContradictedImpl(this.liveDb, factId);\n }\n\n getContradictedIds(factIds: string[]): Set<string> {\n return getContradictedIdsImpl(this.liveDb, factIds);\n }\n\n resolveContradictions(): ReturnType<typeof resolveContradictionsAutoImpl> {\n return resolveContradictionsAutoImpl(\n this.liveDb,\n (id) => this.getById(id),\n (o, n) => this.supersede(o, n),\n );\n }\n\n previewResolveContradictions(): ReturnType<typeof previewResolveContradictionsAutoImpl> {\n return previewResolveContradictionsAutoImpl(this.liveDb, (id) => this.getById(id));\n }\n\n /**\n * Project-state latest-wins resolution pass (Issue #1636).\n * Safely resolves stale `project` contradictions for known mutable keys when the newer\n * trusted fact is strictly newer and has equal or higher confidence.\n *\n * Pass `{ dryRun: true }` to inspect candidates without mutating any data.\n */\n resolveContradictionsProjectStateLww(opts: { dryRun?: boolean } = {}): ProjectStateLwwResult {\n return resolveProjectStateLwwImpl(\n this.liveDb,\n (id) => this.getById(id),\n (o, n) => this.supersede(o, n),\n opts,\n );\n }\n\n async resolveContradictionsAuto(\n opts: ResolveContradictionsAutoOptions = {},\n ): Promise<ResolveContradictionsAutoResult> {\n return resolveContradictionsAutonomouslyImpl(\n this.liveDb,\n (id) => this.getById(id),\n (o, n) => this.supersede(o, n),\n opts,\n );\n }\n\n applyContradictionReviewDecisions(\n decisions: ContradictionReviewDecision[],\n opts: { actor?: string; toolVersion?: string | null } = {},\n ): ApplyContradictionReviewResult {\n return applyContradictionReviewDecisionsImpl(\n this.liveDb,\n (id) => this.getById(id),\n (o, n) => this.supersede(o, n),\n decisions,\n opts,\n );\n }\n\n getContradictionResolutionAudit(contradictionId?: string): ContradictionResolutionAuditRow[] {\n return getContradictionResolutionAuditImpl(this.liveDb, contradictionId);\n }\n\n contradictionsCount(): number {\n return contradictionsCountImpl(this.liveDb);\n }\n\n /** Number of facts with `superseded_at IS NOT NULL`. */\n countSupersededFacts(): number {\n return countSupersededFactsImpl(this.liveDb);\n }\n\n /** Number of rows in `verified_facts` (0 when verification disabled / table absent). */\n countVerifiedFacts(): number {\n return countVerifiedFactsImpl(this.liveDb);\n }\n\n /** Recent ingestion activity: last 24h / 7d / 30d, plus newest/oldest active timestamps. */\n recentActivity(): ReturnType<typeof recentActivityImpl> {\n return recentActivityImpl(this.liveDb);\n }\n\n // ---------------------------------------------------------------------------\n // Auto-linking helpers (Issue #154)\n // ---------------------------------------------------------------------------\n\n getKnownEntities(): string[] {\n return getKnownEntitiesImpl(this.liveDb);\n }\n\n extractEntitiesFromText(text: string, knownEntities: string[]): Array<{ entity: string; weight: number }> {\n return extractEntitiesFromTextImpl(text, knownEntities);\n }\n\n findEntityAnchor(entity: string, excludeId?: string): MemoryEntry | null {\n return findEntityAnchorImpl(this.liveDb, entity, excludeId);\n }\n\n autoDetectInstanceOf(newFactId: string, text: string, knownEntities?: string[]): number {\n return autoDetectInstanceOfImpl(\n this.liveDb,\n newFactId,\n text,\n knownEntities,\n (a, b, t, s) => this.createLink(a, b, t, s ?? 1.0),\n getKnownEntitiesImpl,\n );\n }\n\n autoLinkEntities(\n newFactId: string,\n text: string,\n entity: string | null,\n key: string | null,\n sessionId: string | null,\n cfg: { coOccurrenceWeight: number; autoSupersede: boolean },\n scope?: string | null,\n scopeTarget?: string | null,\n ): { linkedCount: number; supersededIds: string[] } {\n return autoLinkEntitiesImpl(\n this.liveDb,\n newFactId,\n text,\n entity,\n key,\n sessionId,\n cfg,\n scope,\n scopeTarget,\n (a, b, t, s) => this.createLink(a, b, t, s ?? 1.0),\n (o, n) => this.supersede(o, n),\n );\n }\n\n // ---------------------------------------------------------------------------\n // Topic cluster storage (Issue #146)\n // ---------------------------------------------------------------------------\n\n getAllLinkedFactIds(): string[] {\n return getAllLinkedFactIdsImpl(this.liveDb);\n }\n\n getAllLinks(): Array<{ sourceFactId: string; targetFactId: string }> {\n return getAllLinksImpl(this.liveDb);\n }\n\n getAllEdges(limit = 5000): ReturnType<typeof getAllEdgesImpl> {\n return getAllEdgesImpl(this.liveDb, limit);\n }\n\n saveClusters(\n clusters: Array<{\n id: string;\n label: string;\n factIds: string[];\n factCount: number;\n createdAt: number;\n updatedAt: number;\n }>,\n ): void {\n saveClustersImpl(this.liveDb, clusters);\n }\n\n getClusters(): ReturnType<typeof getClustersImpl> {\n return getClustersImpl(this.liveDb);\n }\n\n getClusterMembers(clusterId: string): string[] {\n return getClusterMembersImpl(this.liveDb, clusterId);\n }\n\n getFactClusterId(factId: string): string | null {\n return getFactClusterIdImpl(this.liveDb, factId);\n }\n\n // ============================================================================\n // Episodic Memory (#781)\n // ============================================================================\n\n recordEpisode(input: Parameters<typeof recordEpisodeImpl>[1]): Episode {\n return recordEpisodeImpl(this.liveDb, input);\n }\n\n searchEpisodes(\n options: {\n query?: string;\n outcome?: EpisodeOutcome[];\n since?: number;\n until?: number;\n procedureId?: string;\n limit?: number;\n scopeFilter?: ScopeFilter | null;\n } = {},\n ): Episode[] {\n return searchEpisodesImpl(this.liveDb, options);\n }\n\n getEpisode(id: string): Episode | null {\n return getEpisodeImpl(this.liveDb, id);\n }\n\n deleteEpisode(id: string): boolean {\n return deleteEpisodeImpl(this.liveDb, id);\n }\n\n episodesCount(): number {\n return episodesCountImpl(this.liveDb);\n }\n\n // --- Entity layer: NER mentions, organizations, contacts (#985–#987) ---\n\n /** Replace stored NER rows for a fact (typically after LLM extraction). */\n applyEntityEnrichment(factId: string, mentions: ExtractedMention[], detectedLang: string): void {\n replaceFactEntityMentions(\n this.liveDb,\n factId,\n mentions.map((m) => ({\n label: m.label,\n surfaceText: m.surfaceText,\n normalizedSurface: m.normalizedSurface,\n startOffset: m.startOffset,\n endOffset: m.endOffset,\n confidence: m.confidence,\n detectedLang,\n source: \"llm\",\n })),\n );\n }\n\n /** Resolve an organization by canonical key or fuzzy display name. */\n lookupOrganization(query: string): OrganizationRow | null {\n return lookupOrganizationByKeyOrName(this.liveDb, query);\n }\n\n /** Contacts with primary_org_id = org. */\n listContactsForOrganization(orgId: string, limit: number): ContactRow[] {\n return entityLayerListContactsForOrg(this.liveDb, orgId, limit);\n }\n\n /** List contacts by optional name prefix (empty = recent alphabetical cap). */\n listContactsByNamePrefix(prefix: string, limit: number): ContactRow[] {\n return entityLayerListContactsByNamePrefix(this.liveDb, prefix, limit);\n }\n\n /** Fact ids linked to an org via NER/org_fact_links. */\n listFactIdsLinkedToOrg(orgId: string, limit: number): string[] {\n return entityLayerListFactIdsForOrg(this.liveDb, orgId, limit);\n }\n\n /** Facts not yet processed by entity enrichment (see `facts.entity_enrichment_at`). */\n listFactIdsNeedingEntityEnrichment(\n limit: number,\n minTextLen = 24,\n options?: ListFactsNeedingEnrichmentOptions,\n ): string[] {\n return entityLayerListFactsNeedingEnrichment(this.liveDb, limit, minTextLen, options);\n }\n\n /** Aggregate pending enrichment backlog by tier for progress reporting and catch-up planning. */\n getEntityEnrichmentBacklogSummary(minTextLen = 24): EntityEnrichmentBacklogSummary {\n return entityLayerGetEntityEnrichmentBacklogSummary(this.liveDb, minTextLen);\n }\n\n auditEntityMentions(limit = 500): EntityMentionsAuditSummary {\n return entityLayerAuditEntityMentions(this.liveDb, limit);\n }\n\n cleanupEntityMentions(opts: { limit?: number; apply?: boolean } = {}): EntityMentionsCleanupSummary {\n return entityLayerCleanupEntityMentions(this.liveDb, {\n limit: opts.limit ?? 500,\n apply: opts.apply === true,\n });\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fts-text.js","names":[],"sources":["../../../backends/facts-db/fts-text.ts"],"sourcesContent":["/**\n * FTS5 query sanitization for facts search paths (#870, #898).\n * Extracted from FactsDB for reuse and smaller core file size.\n */\n\nconst NULL_BYTE_PATTERN = new RegExp(String.fromCharCode(0), \"g\");\n\n/**\n * Sanitize query for FTS5 MATCH operator: strip FTS5 special characters and operators.\n * Removes: NOT, AND, OR, NEAR (case-insensitive), null bytes, *, :, {, }, (, ), and quotes.\n */\nexport function sanitizeFts5QueryForFacts(query: string): string {\n return query\n .replace(NULL_BYTE_PATTERN, \" \")\n .replace(/['\"*(){}:]/g, \"\")\n .replace(/\\b(NOT|AND|OR|NEAR)\\b/gi, \"\")\n .trim();\n}\n"],"mappings":";;;;;AAKA,MAAM,oBAAoB,IAAI,OAAO,OAAO,aAAa,EAAE,EAAE,IAAI;;;;;AAMjE,SAAgB,0BAA0B,OAAuB;CAC/D,OAAO,MACJ,QAAQ,mBAAmB,IAAI,CAC/B,QAAQ,eAAe,GAAG,CAC1B,QAAQ,2BAA2B,GAAG,CACtC,MAAM"}
1
+ {"version":3,"file":"fts-text.js","names":[],"sources":["../../../backends/facts-db/fts-text.ts"],"sourcesContent":["/**\n * FTS5 query sanitization for facts search paths (#870, #898).\n * Extracted from FactsDB for reuse and smaller core file size.\n */\n\nconst NULL_BYTE_PATTERN = new RegExp(String.fromCharCode(0), \"g\");\n\n/**\n * Sanitize query for FTS5 MATCH operator: strip FTS5 special characters and operators.\n * Removes: NOT, AND, OR, NEAR (case-insensitive), null bytes, *, :, {, }, (, ), and quotes.\n */\nexport function sanitizeFts5QueryForFacts(query: string): string {\n return query\n .replace(NULL_BYTE_PATTERN, \" \")\n .replace(/['\"*(){}:]/g, \"\")\n .replace(/\\b(NOT|AND|OR|NEAR)\\b/gi, \"\")\n .trim();\n}\n"],"mappings":";;;;;AAKA,MAAM,oBAAoB,IAAI,OAAO,OAAO,aAAa,CAAC,GAAG,GAAG;;;;;AAMhE,SAAgB,0BAA0B,OAAuB;CAC/D,OAAO,MACJ,QAAQ,mBAAmB,GAAG,EAC9B,QAAQ,eAAe,EAAE,EACzB,QAAQ,2BAA2B,EAAE,EACrC,KAAK;AACV"}
@@ -1 +1 @@
1
- {"version":3,"file":"policy.js","names":[],"sources":["../../../../backends/facts-db/generated-skills/policy.ts"],"sourcesContent":["import type {\n GeneratedSkillLifecycleState,\n GeneratedSkillTelemetryDecision,\n GeneratedSkillTelemetryEntry,\n GeneratedSkillTelemetryOutcome,\n MemoryScope,\n} from \"../../../types/memory.js\";\n\nexport type GeneratedSkillLifecyclePolicy = {\n promoteAfterSuccessfulUses: number;\n demoteFalsePositiveRate: number;\n demoteMinSamples: number;\n archiveAfterUnusedDays: number;\n revisionNearMissThreshold: number;\n unblockAfterCleanUses: number;\n};\n\nexport type GeneratedSkillTelemetryRecordInput = {\n skillName: string;\n procedureId?: string | null;\n skillVersion?: number | null;\n requestHash?: string | null;\n requestSummary?: string | null;\n decision: GeneratedSkillTelemetryDecision;\n confidence?: number | null;\n reason?: string | null;\n taskOutcome?: GeneratedSkillTelemetryOutcome | null;\n userCorrection?: boolean;\n correctionReason?: string | null;\n falseNegativeSignal?: boolean;\n causedRework?: boolean;\n savedToolCalls?: number | null;\n savedTimeMs?: number | null;\n scope?: MemoryScope | null;\n scopeTarget?: string | null;\n agentId?: string | null;\n sessionId?: string | null;\n createdAt?: number;\n};\n\nexport type GeneratedSkillTelemetryMetrics = {\n activationCountPerWeek: number;\n activationCountTotal: number;\n nearMissCount: number;\n falsePositiveSignals: number;\n falseNegativeSignals: number;\n correctionCount: number;\n repeatedCorrectionCount: number;\n lastUsedAt: number | null;\n successCount: number;\n failureCount: number;\n partialCount: number;\n unknownCount: number;\n successRate: number | null;\n failureRate: number | null;\n partialRate: number | null;\n unknownRate: number | null;\n successfulUsesWithoutCorrection: number;\n consideredCount: number;\n skippedCount: number;\n savedToolCalls: number;\n savedTimeMs: number;\n falsePositiveRate: number | null;\n cleanUsesAfterDemotion: number;\n};\n\nexport type GeneratedSkillTelemetryFlags = {\n promotionCandidate: boolean;\n overTriggering: boolean;\n revisionCandidate: boolean;\n neverUsed: boolean;\n archiveCandidate: boolean;\n unblockCandidate: boolean;\n};\n\nexport type GeneratedSkillTelemetryReportRow = {\n procedureId: string;\n skillName: string;\n skillPath: string;\n skillVersion: number;\n riskLevel: \"low\" | \"medium\" | \"high\";\n state: GeneratedSkillLifecycleState;\n stateReason: string | null;\n generatedAt: number | null;\n metrics: GeneratedSkillTelemetryMetrics;\n flags: GeneratedSkillTelemetryFlags;\n recommendation: \"promote\" | \"demote\" | \"archive\" | \"revise\" | \"unblock\" | \"observe\";\n recentActivations: GeneratedSkillTelemetryEntry[];\n};\n\nexport type GeneratedSkillTelemetryReport = {\n generatedAt: string;\n policy: GeneratedSkillLifecyclePolicy;\n totalSkills: number;\n rows: GeneratedSkillTelemetryReportRow[];\n};\n\nexport const DEFAULT_GENERATED_SKILL_LIFECYCLE_POLICY: GeneratedSkillLifecyclePolicy = {\n promoteAfterSuccessfulUses: 3,\n demoteFalsePositiveRate: 0.4,\n demoteMinSamples: 3,\n archiveAfterUnusedDays: 30,\n revisionNearMissThreshold: 3,\n unblockAfterCleanUses: 5,\n};\n\nexport function effectiveDemoteThresholdsForRisk(\n riskLevel: \"low\" | \"medium\" | \"high\",\n policy: GeneratedSkillLifecyclePolicy,\n): { falsePositiveRate: number; minSamples: number } {\n const fpAdjust = riskLevel === \"high\" ? -0.1 : riskLevel === \"medium\" ? -0.05 : 0.05;\n const minSamplesAdjust = riskLevel === \"high\" ? -1 : 0;\n return {\n falsePositiveRate: Math.min(1, Math.max(0.1, policy.demoteFalsePositiveRate + fpAdjust)),\n minSamples: Math.max(1, policy.demoteMinSamples + minSamplesAdjust),\n };\n}\n"],"mappings":";AAiGA,MAAa,2CAA0E;CACrF,4BAA4B;CAC5B,yBAAyB;CACzB,kBAAkB;CAClB,wBAAwB;CACxB,2BAA2B;CAC3B,uBAAuB;CACxB;AAED,SAAgB,iCACd,WACA,QACmD;CACnD,MAAM,WAAW,cAAc,SAAS,MAAO,cAAc,WAAW,OAAQ;CAChF,MAAM,mBAAmB,cAAc,SAAS,KAAK;CACrD,OAAO;EACL,mBAAmB,KAAK,IAAI,GAAG,KAAK,IAAI,IAAK,OAAO,0BAA0B,SAAS,CAAC;EACxF,YAAY,KAAK,IAAI,GAAG,OAAO,mBAAmB,iBAAiB;EACpE"}
1
+ {"version":3,"file":"policy.js","names":[],"sources":["../../../../backends/facts-db/generated-skills/policy.ts"],"sourcesContent":["import type {\n GeneratedSkillLifecycleState,\n GeneratedSkillTelemetryDecision,\n GeneratedSkillTelemetryEntry,\n GeneratedSkillTelemetryOutcome,\n MemoryScope,\n} from \"../../../types/memory.js\";\n\nexport type GeneratedSkillLifecyclePolicy = {\n promoteAfterSuccessfulUses: number;\n demoteFalsePositiveRate: number;\n demoteMinSamples: number;\n archiveAfterUnusedDays: number;\n revisionNearMissThreshold: number;\n unblockAfterCleanUses: number;\n};\n\nexport type GeneratedSkillTelemetryRecordInput = {\n skillName: string;\n procedureId?: string | null;\n skillVersion?: number | null;\n requestHash?: string | null;\n requestSummary?: string | null;\n decision: GeneratedSkillTelemetryDecision;\n confidence?: number | null;\n reason?: string | null;\n taskOutcome?: GeneratedSkillTelemetryOutcome | null;\n userCorrection?: boolean;\n correctionReason?: string | null;\n falseNegativeSignal?: boolean;\n causedRework?: boolean;\n savedToolCalls?: number | null;\n savedTimeMs?: number | null;\n scope?: MemoryScope | null;\n scopeTarget?: string | null;\n agentId?: string | null;\n sessionId?: string | null;\n createdAt?: number;\n};\n\nexport type GeneratedSkillTelemetryMetrics = {\n activationCountPerWeek: number;\n activationCountTotal: number;\n nearMissCount: number;\n falsePositiveSignals: number;\n falseNegativeSignals: number;\n correctionCount: number;\n repeatedCorrectionCount: number;\n lastUsedAt: number | null;\n successCount: number;\n failureCount: number;\n partialCount: number;\n unknownCount: number;\n successRate: number | null;\n failureRate: number | null;\n partialRate: number | null;\n unknownRate: number | null;\n successfulUsesWithoutCorrection: number;\n consideredCount: number;\n skippedCount: number;\n savedToolCalls: number;\n savedTimeMs: number;\n falsePositiveRate: number | null;\n cleanUsesAfterDemotion: number;\n};\n\nexport type GeneratedSkillTelemetryFlags = {\n promotionCandidate: boolean;\n overTriggering: boolean;\n revisionCandidate: boolean;\n neverUsed: boolean;\n archiveCandidate: boolean;\n unblockCandidate: boolean;\n};\n\nexport type GeneratedSkillTelemetryReportRow = {\n procedureId: string;\n skillName: string;\n skillPath: string;\n skillVersion: number;\n riskLevel: \"low\" | \"medium\" | \"high\";\n state: GeneratedSkillLifecycleState;\n stateReason: string | null;\n generatedAt: number | null;\n metrics: GeneratedSkillTelemetryMetrics;\n flags: GeneratedSkillTelemetryFlags;\n recommendation: \"promote\" | \"demote\" | \"archive\" | \"revise\" | \"unblock\" | \"observe\";\n recentActivations: GeneratedSkillTelemetryEntry[];\n};\n\nexport type GeneratedSkillTelemetryReport = {\n generatedAt: string;\n policy: GeneratedSkillLifecyclePolicy;\n totalSkills: number;\n rows: GeneratedSkillTelemetryReportRow[];\n};\n\nexport const DEFAULT_GENERATED_SKILL_LIFECYCLE_POLICY: GeneratedSkillLifecyclePolicy = {\n promoteAfterSuccessfulUses: 3,\n demoteFalsePositiveRate: 0.4,\n demoteMinSamples: 3,\n archiveAfterUnusedDays: 30,\n revisionNearMissThreshold: 3,\n unblockAfterCleanUses: 5,\n};\n\nexport function effectiveDemoteThresholdsForRisk(\n riskLevel: \"low\" | \"medium\" | \"high\",\n policy: GeneratedSkillLifecyclePolicy,\n): { falsePositiveRate: number; minSamples: number } {\n const fpAdjust = riskLevel === \"high\" ? -0.1 : riskLevel === \"medium\" ? -0.05 : 0.05;\n const minSamplesAdjust = riskLevel === \"high\" ? -1 : 0;\n return {\n falsePositiveRate: Math.min(1, Math.max(0.1, policy.demoteFalsePositiveRate + fpAdjust)),\n minSamples: Math.max(1, policy.demoteMinSamples + minSamplesAdjust),\n };\n}\n"],"mappings":";AAiGA,MAAa,2CAA0E;CACrF,4BAA4B;CAC5B,yBAAyB;CACzB,kBAAkB;CAClB,wBAAwB;CACxB,2BAA2B;CAC3B,uBAAuB;AACzB;AAEA,SAAgB,iCACd,WACA,QACmD;CACnD,MAAM,WAAW,cAAc,SAAS,MAAO,cAAc,WAAW,OAAQ;CAChF,MAAM,mBAAmB,cAAc,SAAS,KAAK;CACrD,OAAO;EACL,mBAAmB,KAAK,IAAI,GAAG,KAAK,IAAI,IAAK,OAAO,0BAA0B,QAAQ,CAAC;EACvF,YAAY,KAAK,IAAI,GAAG,OAAO,mBAAmB,gBAAgB;CACpE;AACF"}