hippo-memory 1.70.0 → 1.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (629) hide show
  1. package/README.md +1 -1
  2. package/dist/agent-memories/claude-code.d.ts +4 -2
  3. package/dist/agent-memories/claude-code.js +14 -5
  4. package/dist/agent-memories/files.js +23 -12
  5. package/dist/agent-memories/markdown.d.ts +1 -3
  6. package/dist/agent-memories/markdown.js +1 -3
  7. package/dist/agent-memories/report.js +2 -1
  8. package/dist/agent-memories/sync.d.ts +4 -2
  9. package/dist/agent-memories/sync.js +10 -5
  10. package/dist/api/assemble.d.ts +7 -44
  11. package/dist/api/assemble.js +2 -22
  12. package/dist/api/audit.d.ts +5 -1
  13. package/dist/api/audit.js +9 -1
  14. package/dist/api/auth.d.ts +13 -22
  15. package/dist/api/auth.js +34 -24
  16. package/dist/api/auto-sleep.js +2 -2
  17. package/dist/api/availability.d.ts +2 -15
  18. package/dist/api/availability.js +2 -15
  19. package/dist/api/context-select.js +3 -4
  20. package/dist/api/context-types.d.ts +10 -35
  21. package/dist/api/context.d.ts +5 -22
  22. package/dist/api/context.js +21 -38
  23. package/dist/api/dormant.d.ts +5 -21
  24. package/dist/api/dormant.js +7 -26
  25. package/dist/api/drill-down.d.ts +7 -46
  26. package/dist/api/drill-down.js +5 -26
  27. package/dist/api/forget.d.ts +5 -24
  28. package/dist/api/forget.js +5 -28
  29. package/dist/api/graph.d.ts +8 -0
  30. package/dist/api/graph.js +7 -0
  31. package/dist/api/index.d.ts +2 -0
  32. package/dist/api/index.js +2 -0
  33. package/dist/api/instruction-detect.js +16 -5
  34. package/dist/api/ledger-db.d.ts +2 -1
  35. package/dist/api/ledger-db.js +5 -3
  36. package/dist/api/memories.d.ts +5 -0
  37. package/dist/api/memories.js +7 -0
  38. package/dist/api/objects.d.ts +9 -0
  39. package/dist/api/objects.js +11 -0
  40. package/dist/api/on-store.js +5 -3
  41. package/dist/api/predictions.d.ts +9 -0
  42. package/dist/api/predictions.js +18 -0
  43. package/dist/api/promote.d.ts +13 -17
  44. package/dist/api/promote.js +11 -19
  45. package/dist/api/prompt-hook.d.ts +4 -4
  46. package/dist/api/prompt-hook.js +10 -9
  47. package/dist/api/recall-cli.d.ts +55 -0
  48. package/dist/api/recall-cli.js +94 -0
  49. package/dist/api/recall-core.js +14 -6
  50. package/dist/api/recall-finish.d.ts +53 -0
  51. package/dist/api/recall-finish.js +30 -0
  52. package/dist/api/recall-history.d.ts +17 -84
  53. package/dist/api/recall-history.js +15 -88
  54. package/dist/api/recall-pipeline.d.ts +2 -3
  55. package/dist/api/recall-pipeline.js +16 -9
  56. package/dist/api/recall-types.d.ts +64 -304
  57. package/dist/api/recall.d.ts +5 -33
  58. package/dist/api/recall.js +59 -60
  59. package/dist/api/refine.d.ts +7 -0
  60. package/dist/api/refine.js +10 -0
  61. package/dist/api/remember-local.d.ts +57 -0
  62. package/dist/api/remember-local.js +90 -0
  63. package/dist/api/remember.d.ts +18 -1
  64. package/dist/api/remember.js +13 -1
  65. package/dist/api/sleep-run.d.ts +1 -3
  66. package/dist/api/sleep-run.js +17 -21
  67. package/dist/api/sleep.d.ts +9 -28
  68. package/dist/api/tokens.d.ts +3 -10
  69. package/dist/api/tokens.js +3 -10
  70. package/dist/api/types.d.ts +6 -29
  71. package/dist/api/types.js +4 -22
  72. package/dist/capture/command.d.ts +4 -12
  73. package/dist/capture/command.js +6 -22
  74. package/dist/capture/compact.d.ts +4 -15
  75. package/dist/capture/compact.js +16 -25
  76. package/dist/capture/compaction-record.js +101 -69
  77. package/dist/capture/compaction-spool.d.ts +1 -1
  78. package/dist/capture/compaction-spool.js +1 -1
  79. package/dist/capture/session-digest.d.ts +1 -1
  80. package/dist/capture/session-digest.js +13 -7
  81. package/dist/capture/transcript.d.ts +2 -10
  82. package/dist/capture/transcript.js +4 -18
  83. package/dist/cli/api-context.d.ts +3 -0
  84. package/dist/cli/api-context.js +6 -0
  85. package/dist/cli/audit-prune.d.ts +6 -39
  86. package/dist/cli/audit-prune.js +6 -39
  87. package/dist/cli/audit.d.ts +1 -1
  88. package/dist/cli/audit.js +33 -34
  89. package/dist/cli/auth.d.ts +2 -2
  90. package/dist/cli/auth.js +57 -39
  91. package/dist/cli/briefs.d.ts +4 -4
  92. package/dist/cli/briefs.js +18 -22
  93. package/dist/cli/card.d.ts +2 -2
  94. package/dist/cli/card.js +31 -32
  95. package/dist/cli/client.d.ts +7 -27
  96. package/dist/cli/client.js +24 -43
  97. package/dist/cli/compact-resume-payload.js +3 -2
  98. package/dist/cli/context.d.ts +1 -2
  99. package/dist/cli/context.js +12 -8
  100. package/dist/cli/continuity.d.ts +6 -6
  101. package/dist/cli/continuity.js +62 -64
  102. package/dist/cli/correction-latency.d.ts +2 -14
  103. package/dist/cli/correction-latency.js +2 -14
  104. package/dist/cli/curate.d.ts +13 -17
  105. package/dist/cli/curate.js +68 -92
  106. package/dist/cli/dag.d.ts +4 -4
  107. package/dist/cli/dag.js +33 -27
  108. package/dist/cli/decisions.d.ts +4 -4
  109. package/dist/cli/decisions.js +33 -47
  110. package/dist/cli/eval.js +15 -13
  111. package/dist/cli/exit.d.ts +6 -0
  112. package/dist/cli/exit.js +11 -0
  113. package/dist/cli/explain.d.ts +1 -2
  114. package/dist/cli/explain.js +6 -4
  115. package/dist/cli/flag-values.d.ts +6 -1
  116. package/dist/cli/flag-values.js +27 -10
  117. package/dist/cli/flags.d.ts +1 -0
  118. package/dist/cli/flags.js +1 -1
  119. package/dist/cli/github.d.ts +14 -0
  120. package/dist/{connectors/github/cli-impl.js → cli/github.js} +43 -71
  121. package/dist/cli/goals.d.ts +2 -2
  122. package/dist/cli/goals.js +46 -50
  123. package/dist/cli/hook-runtime.d.ts +9 -27
  124. package/dist/cli/hook-runtime.js +15 -31
  125. package/dist/cli/init.d.ts +2 -2
  126. package/dist/cli/init.js +6 -12
  127. package/dist/cli/install-steps.js +3 -12
  128. package/dist/cli/last-sleep.d.ts +2 -1
  129. package/dist/cli/last-sleep.js +3 -0
  130. package/dist/cli/maintenance.d.ts +4 -4
  131. package/dist/cli/maintenance.js +14 -19
  132. package/dist/cli/object-verbs.js +4 -3
  133. package/dist/cli/owner-validation.d.ts +5 -28
  134. package/dist/cli/owner-validation.js +5 -28
  135. package/dist/cli/playbooks.d.ts +4 -4
  136. package/dist/cli/playbooks.js +23 -28
  137. package/dist/cli/print.d.ts +2 -5
  138. package/dist/cli/print.js +1 -4
  139. package/dist/cli/projects.d.ts +2 -2
  140. package/dist/cli/projects.js +1 -3
  141. package/dist/cli/provenance-coverage.d.ts +2 -6
  142. package/dist/cli/provenance-coverage.js +2 -6
  143. package/dist/cli/quality-repair-once.js +2 -2
  144. package/dist/cli/recall.d.ts +2 -4
  145. package/dist/cli/recall.js +55 -131
  146. package/dist/cli/refine-llm.d.ts +5 -31
  147. package/dist/cli/refine-llm.js +9 -36
  148. package/dist/cli/remember.d.ts +3 -3
  149. package/dist/cli/remember.js +122 -180
  150. package/dist/cli/scheduler.d.ts +2 -17
  151. package/dist/cli/scheduler.js +12 -18
  152. package/dist/cli/serve.js +21 -12
  153. package/dist/cli/session-hooks.d.ts +10 -18
  154. package/dist/cli/session-hooks.js +112 -113
  155. package/dist/cli/setup.d.ts +4 -4
  156. package/dist/cli/setup.js +19 -21
  157. package/dist/cli/shared.d.ts +9 -23
  158. package/dist/cli/shared.js +9 -32
  159. package/dist/cli/slack.d.ts +2 -2
  160. package/dist/cli/slack.js +19 -23
  161. package/dist/cli/sleep.d.ts +3 -2
  162. package/dist/cli/sleep.js +15 -16
  163. package/dist/cli/status.d.ts +9 -12
  164. package/dist/cli/status.js +55 -98
  165. package/dist/cli/stdin.d.ts +4 -6
  166. package/dist/cli/stdin.js +2 -3
  167. package/dist/cli/transfer.d.ts +9 -9
  168. package/dist/cli/transfer.js +66 -89
  169. package/dist/cli/usage.js +11 -5
  170. package/dist/cli.d.ts +66 -448
  171. package/dist/cli.js +87 -263
  172. package/dist/connectors/github/backfill.d.ts +5 -25
  173. package/dist/connectors/github/backfill.js +14 -49
  174. package/dist/connectors/github/deletion.d.ts +4 -18
  175. package/dist/connectors/github/deletion.js +2 -15
  176. package/dist/connectors/github/dlq.d.ts +8 -33
  177. package/dist/connectors/github/dlq.js +12 -29
  178. package/dist/connectors/github/ingest.d.ts +2 -6
  179. package/dist/connectors/github/ingest.js +4 -10
  180. package/dist/connectors/github/octokit-client.d.ts +4 -16
  181. package/dist/connectors/github/octokit-client.js +27 -24
  182. package/dist/connectors/github/ratelimit.d.ts +3 -14
  183. package/dist/connectors/github/ratelimit.js +3 -14
  184. package/dist/connectors/github/scope.d.ts +3 -5
  185. package/dist/connectors/github/scope.js +3 -5
  186. package/dist/connectors/github/signature.d.ts +4 -26
  187. package/dist/connectors/github/signature.js +4 -26
  188. package/dist/connectors/github/tenant-routing.d.ts +2 -24
  189. package/dist/connectors/github/tenant-routing.js +4 -26
  190. package/dist/connectors/github/transform.js +2 -16
  191. package/dist/connectors/github/types.d.ts +3 -15
  192. package/dist/connectors/github/types.js +2 -9
  193. package/dist/connectors/github/webhook.d.ts +2 -16
  194. package/dist/connectors/github/webhook.js +6 -22
  195. package/dist/connectors/slack/backfill.d.ts +4 -17
  196. package/dist/connectors/slack/backfill.js +4 -13
  197. package/dist/connectors/slack/dlq.d.ts +2 -19
  198. package/dist/connectors/slack/dlq.js +2 -19
  199. package/dist/connectors/slack/ingest.d.ts +2 -3
  200. package/dist/connectors/slack/ingest.js +2 -3
  201. package/dist/connectors/slack/scope.d.ts +2 -8
  202. package/dist/connectors/slack/scope.js +2 -8
  203. package/dist/connectors/slack/signature.d.ts +1 -6
  204. package/dist/connectors/slack/tenant-routing.d.ts +2 -19
  205. package/dist/connectors/slack/tenant-routing.js +2 -21
  206. package/dist/connectors/slack/transform.d.ts +2 -18
  207. package/dist/connectors/slack/transform.js +2 -18
  208. package/dist/connectors/slack/types.d.ts +3 -9
  209. package/dist/connectors/slack/types.js +2 -4
  210. package/dist/connectors/slack/web-client.js +33 -27
  211. package/dist/connectors/slack/webhook.d.ts +2 -19
  212. package/dist/connectors/slack/webhook.js +5 -26
  213. package/dist/connectors/slack/workspaces.d.ts +4 -24
  214. package/dist/connectors/slack/workspaces.js +4 -24
  215. package/dist/consolidate/conflicts.js +6 -14
  216. package/dist/consolidate/dag-summary.d.ts +8 -0
  217. package/dist/consolidate/dag-summary.js +41 -0
  218. package/dist/consolidate/dag.d.ts +5 -28
  219. package/dist/consolidate/dag.js +14 -75
  220. package/dist/consolidate/decay.js +7 -19
  221. package/dist/consolidate/dedupe.d.ts +6 -52
  222. package/dist/consolidate/dedupe.js +13 -71
  223. package/dist/consolidate/flush-units.d.ts +3 -4
  224. package/dist/consolidate/flush-units.js +3 -3
  225. package/dist/consolidate/half-life-migration.d.ts +3 -26
  226. package/dist/consolidate/half-life-migration.js +11 -28
  227. package/dist/consolidate/llm-passes.js +4 -21
  228. package/dist/consolidate/memory-value-weights.d.ts +2 -13
  229. package/dist/consolidate/memory-value-weights.js +2 -13
  230. package/dist/consolidate/memory-value.d.ts +11 -84
  231. package/dist/consolidate/memory-value.js +16 -104
  232. package/dist/consolidate/merge.js +10 -31
  233. package/dist/consolidate/merged-row.js +2 -1
  234. package/dist/consolidate/physics-pass.js +1 -3
  235. package/dist/consolidate/replay.d.ts +6 -38
  236. package/dist/consolidate/replay.js +14 -52
  237. package/dist/consolidate/run.js +1 -1
  238. package/dist/consolidate/sleep.d.ts +1 -8
  239. package/dist/consolidate/sleep.js +5 -17
  240. package/dist/consolidate/trace.d.ts +3 -18
  241. package/dist/consolidate/trace.js +3 -18
  242. package/dist/consolidate/traces.js +6 -22
  243. package/dist/core/ablation.d.ts +4 -91
  244. package/dist/core/ablation.js +4 -91
  245. package/dist/core/ambient.d.ts +1 -8
  246. package/dist/core/ambient.js +1 -8
  247. package/dist/core/capture-contract.d.ts +4 -2
  248. package/dist/core/capture-contract.js +4 -2
  249. package/dist/core/card.d.ts +4 -1
  250. package/dist/core/card.js +8 -0
  251. package/dist/core/compare.d.ts +11 -67
  252. package/dist/core/compare.js +9 -63
  253. package/dist/core/config.d.ts +10 -24
  254. package/dist/core/config.js +13 -14
  255. package/dist/core/handoff.d.ts +1 -7
  256. package/dist/core/handoff.js +1 -7
  257. package/dist/core/memory-quality.js +1 -1
  258. package/dist/core/memory.d.ts +41 -164
  259. package/dist/core/memory.js +51 -221
  260. package/dist/core/package-root.d.ts +3 -0
  261. package/dist/core/package-root.js +5 -0
  262. package/dist/core/physics-config.d.ts +1 -4
  263. package/dist/core/physics-config.js +3 -8
  264. package/dist/core/physics.d.ts +15 -61
  265. package/dist/core/physics.js +59 -122
  266. package/dist/core/project-identity.d.ts +17 -58
  267. package/dist/core/project-identity.js +17 -38
  268. package/dist/core/project-remote.js +13 -2
  269. package/dist/core/raw-append-only.d.ts +5 -0
  270. package/dist/core/raw-append-only.js +7 -0
  271. package/dist/core/salience.d.ts +1 -7
  272. package/dist/core/salience.js +1 -7
  273. package/dist/dashboard/dashboard-actions.js +2 -2
  274. package/dist/dashboard/dashboard-snapshot.d.ts +2 -1
  275. package/dist/dashboard/dashboard-snapshot.js +11 -2
  276. package/dist/dashboard/dashboard-types.d.ts +2 -1
  277. package/dist/dashboard/dashboard.d.ts +1 -0
  278. package/dist/dashboard/dashboard.js +50 -4
  279. package/dist/db/busy.d.ts +1 -1
  280. package/dist/db/busy.js +17 -8
  281. package/dist/db/connect.d.ts +1 -0
  282. package/dist/db/connect.js +3 -3
  283. package/dist/db/migrate.js +3 -3
  284. package/dist/db/migrations/types.d.ts +2 -5
  285. package/dist/db/migrations/v14.js +2 -3
  286. package/dist/db/migrations/v15.js +2 -8
  287. package/dist/db/migrations/v16.js +2 -3
  288. package/dist/db/migrations/v17.js +2 -3
  289. package/dist/db/migrations/v19.js +2 -5
  290. package/dist/db/migrations/v20.js +2 -7
  291. package/dist/db/migrations/v22.js +4 -17
  292. package/dist/db/migrations/v23.js +3 -14
  293. package/dist/db/migrations/v24.js +2 -4
  294. package/dist/db/migrations/v25.js +3 -8
  295. package/dist/db/migrations/v26.js +2 -13
  296. package/dist/db/migrations/v27.js +3 -11
  297. package/dist/db/migrations/v28.js +2 -14
  298. package/dist/db/migrations/v29.js +4 -18
  299. package/dist/db/migrations/v30.js +4 -16
  300. package/dist/db/migrations/v31.js +2 -15
  301. package/dist/db/migrations/v32.js +4 -22
  302. package/dist/db/migrations/v33.js +2 -15
  303. package/dist/db/migrations/v34.js +2 -11
  304. package/dist/db/migrations/v35.js +2 -11
  305. package/dist/db/migrations/v36.js +2 -11
  306. package/dist/db/migrations/v37.js +8 -33
  307. package/dist/db/migrations/v38.js +5 -38
  308. package/dist/db/migrations/v39.js +9 -20
  309. package/dist/db/migrations/v40.js +2 -9
  310. package/dist/db/migrations/v41.js +2 -24
  311. package/dist/db/migrations/v43.js +1 -1
  312. package/dist/db/migrations/v44.js +2 -8
  313. package/dist/db/migrations/v45.js +2 -7
  314. package/dist/db/migrations/v47.js +2 -3
  315. package/dist/db/migrations/v51.js +1 -1
  316. package/dist/db/open.d.ts +2 -0
  317. package/dist/db/open.js +17 -1
  318. package/dist/db/physics-state.d.ts +6 -22
  319. package/dist/db/physics-state.js +25 -36
  320. package/dist/db/raw-archive-mirror-cleanup.d.ts +2 -17
  321. package/dist/db/raw-archive-mirror-cleanup.js +2 -17
  322. package/dist/db/vector-store.d.ts +2 -0
  323. package/dist/db/vector-store.js +8 -1
  324. package/dist/doctor.js +74 -19
  325. package/dist/entry/session-text.js +2 -1
  326. package/dist/eval/eval-stats.d.ts +15 -53
  327. package/dist/eval/eval-stats.js +12 -42
  328. package/dist/eval/eval-suite.d.ts +2 -13
  329. package/dist/eval/eval-suite.js +74 -34
  330. package/dist/eval/eval.d.ts +6 -24
  331. package/dist/eval/eval.js +7 -34
  332. package/dist/eval/judgment.d.ts +0 -3
  333. package/dist/eval/judgment.js +19 -11
  334. package/dist/extensions/openclaw-plugin/index.js +1 -1
  335. package/dist/graph/extract.d.ts +5 -27
  336. package/dist/graph/extract.js +7 -33
  337. package/dist/graph/recall.d.ts +7 -20
  338. package/dist/graph/recall.js +14 -76
  339. package/dist/graph/stream.d.ts +7 -39
  340. package/dist/graph/stream.js +11 -34
  341. package/dist/graph/view.d.ts +9 -35
  342. package/dist/graph/view.js +11 -39
  343. package/dist/hooks/codex-wrapper.js +2 -2
  344. package/dist/hooks/copilot.js +2 -1
  345. package/dist/hooks/hook-blocks.d.ts +6 -2
  346. package/dist/hooks/hook-blocks.js +37 -124
  347. package/dist/hooks/json-hooks.d.ts +4 -36
  348. package/dist/hooks/json-hooks.js +18 -57
  349. package/dist/hooks/opencode.d.ts +0 -38
  350. package/dist/hooks/opencode.js +9 -76
  351. package/dist/hooks/shared.d.ts +8 -17
  352. package/dist/hooks/shared.js +29 -20
  353. package/dist/importers/core.d.ts +12 -37
  354. package/dist/importers/core.js +9 -27
  355. package/dist/importers/markdown-parse.d.ts +8 -22
  356. package/dist/importers/markdown-parse.js +8 -25
  357. package/dist/importers/markdown.js +3 -12
  358. package/dist/importers/sources.js +7 -35
  359. package/dist/importers/vault.d.ts +2 -8
  360. package/dist/importers/vault.js +25 -81
  361. package/dist/index.d.ts +6 -2
  362. package/dist/index.js +6 -2
  363. package/dist/learn/autolearn.d.ts +14 -41
  364. package/dist/learn/autolearn.js +14 -41
  365. package/dist/learn/extract.js +2 -4
  366. package/dist/learn/forward-claim-detector.d.ts +6 -30
  367. package/dist/learn/forward-claim-detector.js +14 -66
  368. package/dist/learn/invalidation.d.ts +6 -18
  369. package/dist/learn/invalidation.js +9 -26
  370. package/dist/mcp/admin-tools.js +3 -5
  371. package/dist/mcp/memory-tools.js +4 -9
  372. package/dist/mcp/protocol.d.ts +8 -26
  373. package/dist/mcp/protocol.js +3 -6
  374. package/dist/mcp/recall-tools.js +3 -3
  375. package/dist/mcp/request.d.ts +3 -11
  376. package/dist/mcp/request.js +10 -26
  377. package/dist/mcp/server.d.ts +3 -9
  378. package/dist/mcp/server.js +5 -16
  379. package/dist/mcp/session-state.d.ts +1 -1
  380. package/dist/mcp/session-state.js +5 -11
  381. package/dist/mcp/stdio.d.ts +2 -6
  382. package/dist/mcp/stdio.js +48 -12
  383. package/dist/mcp/tools.js +5 -3
  384. package/dist/objects/customer-notes.d.ts +7 -42
  385. package/dist/objects/customer-notes.js +7 -48
  386. package/dist/objects/decisions.d.ts +12 -50
  387. package/dist/objects/decisions.js +15 -53
  388. package/dist/objects/incidents.d.ts +7 -38
  389. package/dist/objects/incidents.js +7 -41
  390. package/dist/objects/policies.d.ts +11 -89
  391. package/dist/objects/policies.js +11 -98
  392. package/dist/objects/processes.d.ts +7 -52
  393. package/dist/objects/processes.js +7 -61
  394. package/dist/objects/project-briefs.d.ts +11 -55
  395. package/dist/objects/project-briefs.js +14 -75
  396. package/dist/objects/skills.d.ts +7 -42
  397. package/dist/objects/skills.js +8 -54
  398. package/dist/postinstall.js +6 -19
  399. package/dist/predictions/planning-fallacy.d.ts +11 -34
  400. package/dist/rerankers/clef.js +3 -31
  401. package/dist/rerankers/cross-encoder.js +4 -6
  402. package/dist/rerankers/jev.js +9 -6
  403. package/dist/rerankers/llm.d.ts +2 -11
  404. package/dist/rerankers/llm.js +14 -14
  405. package/dist/rerankers/outage-warning.d.ts +2 -1
  406. package/dist/rerankers/outage-warning.js +2 -1
  407. package/dist/rerankers/remote.d.ts +1 -0
  408. package/dist/rerankers/remote.js +2 -0
  409. package/dist/rerankers/types.d.ts +2 -14
  410. package/dist/search/boosts.d.ts +0 -2
  411. package/dist/search/boosts.js +2 -2
  412. package/dist/search/goal-boost.d.ts +23 -0
  413. package/dist/search/goal-boost.js +90 -0
  414. package/dist/search/hybrid.d.ts +2 -0
  415. package/dist/search/multihop.js +2 -3
  416. package/dist/search/path-context.d.ts +5 -18
  417. package/dist/search/path-context.js +5 -18
  418. package/dist/search/physics-search.js +11 -8
  419. package/dist/search/rrf.d.ts +7 -35
  420. package/dist/search/rrf.js +5 -30
  421. package/dist/search/vector.d.ts +7 -0
  422. package/dist/search/vector.js +35 -5
  423. package/dist/server/auth.d.ts +9 -28
  424. package/dist/server/auth.js +32 -25
  425. package/dist/server/boot.d.ts +2 -21
  426. package/dist/server/boot.js +63 -96
  427. package/dist/server/client-ip.d.ts +3 -19
  428. package/dist/server/client-ip.js +5 -28
  429. package/dist/server/defaults.d.ts +3 -0
  430. package/dist/server/defaults.js +4 -0
  431. package/dist/server/key-check-bounds.d.ts +2 -1
  432. package/dist/server/lifecycle.d.ts +5 -4
  433. package/dist/server/lifecycle.js +19 -4
  434. package/dist/server/mcp-http.js +10 -44
  435. package/dist/server/rate-limit.d.ts +5 -18
  436. package/dist/server/rate-limit.js +4 -13
  437. package/dist/server/request.d.ts +4 -8
  438. package/dist/server/request.js +9 -17
  439. package/dist/server/route-table.js +42 -49
  440. package/dist/server/routes/admin.js +22 -28
  441. package/dist/server/routes/customer-notes.js +7 -12
  442. package/dist/server/routes/decisions.js +10 -17
  443. package/dist/server/routes/incidents.js +12 -20
  444. package/dist/server/routes/memories.js +12 -32
  445. package/dist/server/routes/object-routes.d.ts +0 -5
  446. package/dist/server/routes/object-routes.js +7 -15
  447. package/dist/server/routes/policies.js +10 -18
  448. package/dist/server/routes/predictions.js +13 -25
  449. package/dist/server/routes/processes.js +16 -26
  450. package/dist/server/routes/project-briefs.js +9 -16
  451. package/dist/server/routes/recall.js +10 -35
  452. package/dist/server/routes/skills.js +8 -18
  453. package/dist/server/server-detect.d.ts +9 -53
  454. package/dist/server/server-detect.js +24 -90
  455. package/dist/server/sleep-offload.js +4 -1
  456. package/dist/server/types.d.ts +12 -10
  457. package/dist/server/validation.d.ts +3 -1
  458. package/dist/server/validation.js +10 -23
  459. package/dist/server.d.ts +2 -2
  460. package/dist/server.js +3 -2
  461. package/dist/sharing/global-store.d.ts +19 -0
  462. package/dist/sharing/global-store.js +75 -0
  463. package/dist/sharing/global-sync.d.ts +6 -0
  464. package/dist/sharing/global-sync.js +80 -0
  465. package/dist/sharing/project-merge.d.ts +4 -5
  466. package/dist/sharing/project-merge.js +9 -7
  467. package/dist/sharing/scope.d.ts +4 -11
  468. package/dist/sharing/scope.js +4 -11
  469. package/dist/sharing/search-both.d.ts +60 -0
  470. package/dist/sharing/search-both.js +138 -0
  471. package/dist/sharing/share.d.ts +38 -0
  472. package/dist/sharing/share.js +226 -0
  473. package/dist/store/ambient.js +4 -9
  474. package/dist/store/audit-event.d.ts +4 -12
  475. package/dist/store/audit-event.js +4 -12
  476. package/dist/store/audit.d.ts +2 -5
  477. package/dist/store/audit.js +4 -12
  478. package/dist/store/auth.d.ts +6 -6
  479. package/dist/store/auth.js +10 -9
  480. package/dist/store/candidates.d.ts +20 -3
  481. package/dist/store/candidates.js +77 -48
  482. package/dist/store/card-detail.d.ts +2 -1
  483. package/dist/store/card-detail.js +2 -1
  484. package/dist/store/cards.d.ts +14 -9
  485. package/dist/store/cards.js +72 -126
  486. package/dist/store/conflicts.d.ts +4 -21
  487. package/dist/store/conflicts.js +71 -150
  488. package/dist/store/connectors/github.d.ts +10 -10
  489. package/dist/store/connectors/github.js +10 -10
  490. package/dist/store/dashboard-reads.js +4 -8
  491. package/dist/store/delete-and-batch.d.ts +11 -31
  492. package/dist/store/delete-and-batch.js +48 -64
  493. package/dist/store/delivery-recorder.d.ts +8 -4
  494. package/dist/store/delivery-recorder.js +25 -15
  495. package/dist/store/diagnostics.js +6 -13
  496. package/dist/store/dormant.d.ts +7 -29
  497. package/dist/store/dormant.js +15 -56
  498. package/dist/store/embeddings/index.d.ts +11 -80
  499. package/dist/store/embeddings/index.js +71 -207
  500. package/dist/store/embeddings/local.js +15 -32
  501. package/dist/store/embeddings/provider.d.ts +16 -53
  502. package/dist/store/embeddings/provider.js +41 -69
  503. package/dist/store/entry-reads.d.ts +21 -57
  504. package/dist/store/entry-reads.js +65 -126
  505. package/dist/store/entry-row.d.ts +6 -35
  506. package/dist/store/entry-row.js +9 -37
  507. package/dist/store/entry-writes.d.ts +10 -16
  508. package/dist/store/entry-writes.js +17 -35
  509. package/dist/store/goals.d.ts +3 -40
  510. package/dist/store/goals.js +21 -160
  511. package/dist/store/graph-queue.d.ts +6 -22
  512. package/dist/store/graph-queue.js +14 -45
  513. package/dist/store/graph-reads.d.ts +11 -35
  514. package/dist/store/graph-reads.js +20 -58
  515. package/dist/store/graph-rows.d.ts +3 -6
  516. package/dist/store/graph-rows.js +6 -9
  517. package/dist/store/graph-view-rows.d.ts +2 -1
  518. package/dist/store/graph-view-rows.js +2 -1
  519. package/dist/store/graph-writes.d.ts +6 -31
  520. package/dist/store/graph-writes.js +13 -37
  521. package/dist/store/half-life.d.ts +2 -1
  522. package/dist/store/half-life.js +14 -16
  523. package/dist/store/handoffs.d.ts +5 -11
  524. package/dist/store/handoffs.js +16 -34
  525. package/dist/store/index-and-stats.d.ts +6 -19
  526. package/dist/store/index-and-stats.js +34 -82
  527. package/dist/store/markdown.d.ts +2 -6
  528. package/dist/store/markdown.js +21 -20
  529. package/dist/store/mirrors.d.ts +2 -6
  530. package/dist/store/mirrors.js +14 -23
  531. package/dist/store/open.js +6 -13
  532. package/dist/store/planning-fallacy-evidence.d.ts +2 -30
  533. package/dist/store/planning-fallacy-evidence.js +8 -37
  534. package/dist/store/port.d.ts +82 -79
  535. package/dist/store/predictions.d.ts +11 -51
  536. package/dist/store/predictions.js +38 -119
  537. package/dist/{cli → store}/quality-repair.js +15 -31
  538. package/dist/store/raw-archive.d.ts +4 -16
  539. package/dist/store/raw-archive.js +14 -29
  540. package/dist/store/recall-scope.d.ts +19 -79
  541. package/dist/store/recall-scope.js +21 -82
  542. package/dist/store/recall-trace.d.ts +10 -77
  543. package/dist/store/recall-trace.js +19 -95
  544. package/dist/store/rejected-values.js +7 -19
  545. package/dist/store/rejection.d.ts +12 -58
  546. package/dist/store/rejection.js +13 -65
  547. package/dist/store/report-reads.d.ts +6 -0
  548. package/dist/store/report-reads.js +29 -0
  549. package/dist/store/rows.d.ts +9 -19
  550. package/dist/store/rows.js +36 -34
  551. package/dist/store/rule-sql.d.ts +5 -0
  552. package/dist/store/rule-sql.js +37 -0
  553. package/dist/store/search-rows.d.ts +7 -38
  554. package/dist/store/search-rows.js +14 -50
  555. package/dist/store/sessions.d.ts +10 -47
  556. package/dist/store/sessions.js +17 -73
  557. package/dist/store/sqlite/connector-events-group.js +2 -2
  558. package/dist/store/sqlite/entry-writes-group.js +2 -2
  559. package/dist/store/sqlite/error-codec.js +4 -2
  560. package/dist/store/sqlite/executor.d.ts +2 -1
  561. package/dist/store/sqlite/executor.js +2 -1
  562. package/dist/store/sqlite/local.d.ts +3 -3
  563. package/dist/store/sqlite/local.js +1 -0
  564. package/dist/store/sqlite/object-rows.js +6 -3
  565. package/dist/store/sqlite/objects-group.js +4 -2
  566. package/dist/store/sqlite/quarantine-group.js +2 -2
  567. package/dist/store/sqlite/store.d.ts +1 -4
  568. package/dist/store/sqlite/store.js +2 -3
  569. package/dist/store/sqlite/vector-reads-group.js +2 -2
  570. package/dist/store/sqlite/worker-jobs.js +1 -1
  571. package/dist/store/sqlite/worker-ops.d.ts +13 -2
  572. package/dist/store/sqlite/worker-ops.js +13 -2
  573. package/dist/store/sqlite/worker-store.js +5 -2
  574. package/dist/store/summaries.d.ts +10 -62
  575. package/dist/store/summaries.js +34 -146
  576. package/dist/store/summary-dirty.js +1 -1
  577. package/dist/store/tenant-lookup.d.ts +6 -1
  578. package/dist/store/tenant-lookup.js +7 -0
  579. package/dist/store/tenant.d.ts +2 -16
  580. package/dist/store/tenant.js +4 -19
  581. package/dist/store/token-ledger.d.ts +13 -43
  582. package/dist/store/token-ledger.js +19 -50
  583. package/dist/store/usage-reports.js +5 -13
  584. package/dist/store/vector-index.d.ts +46 -0
  585. package/dist/store/vector-index.js +170 -0
  586. package/dist/store/working-memory.d.ts +6 -25
  587. package/dist/store/working-memory.js +18 -52
  588. package/dist/store/yaml.d.ts +1 -5
  589. package/dist/store/yaml.js +2 -6
  590. package/dist/support-bundle.js +7 -5
  591. package/dist/trust/reject-flow.js +1 -3
  592. package/dist/util/anthropic-messages.js +14 -2
  593. package/dist/util/atomic-write.d.ts +2 -1
  594. package/dist/util/atomic-write.js +35 -4
  595. package/dist/util/capped-json.d.ts +6 -0
  596. package/dist/util/capped-json.js +46 -0
  597. package/dist/util/crash-handlers.d.ts +8 -1
  598. package/dist/util/crash-handlers.js +52 -10
  599. package/dist/util/env.d.ts +13 -6
  600. package/dist/util/env.js +14 -7
  601. package/dist/util/home-path.d.ts +2 -1
  602. package/dist/util/home-path.js +4 -2
  603. package/dist/util/http-retry.d.ts +3 -1
  604. package/dist/util/http-retry.js +26 -5
  605. package/dist/util/log.d.ts +3 -2
  606. package/dist/util/log.js +25 -9
  607. package/dist/util/request-scope.d.ts +2 -1
  608. package/dist/util/request-scope.js +2 -1
  609. package/dist/util/secret-detect.d.ts +5 -30
  610. package/dist/util/secret-detect.js +13 -39
  611. package/dist/util/stored-json.d.ts +1 -1
  612. package/dist/util/stored-json.js +1 -1
  613. package/dist/util/token-text.d.ts +1 -4
  614. package/dist/util/token-text.js +1 -4
  615. package/dist/util/transcript-tail.d.ts +2 -0
  616. package/dist/util/transcript-tail.js +24 -23
  617. package/dist/util/version.d.ts +5 -20
  618. package/dist/util/version.js +5 -20
  619. package/extensions/openclaw-plugin/index.ts +1 -1
  620. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  621. package/extensions/openclaw-plugin/package.json +1 -1
  622. package/openclaw.plugin.json +1 -1
  623. package/package.json +1 -1
  624. package/dist/connectors/github/cli-impl.d.ts +0 -25
  625. package/dist/sharing/shared.d.ts +0 -187
  626. package/dist/sharing/shared.js +0 -563
  627. package/dist/store/vector-writes.d.ts +0 -13
  628. package/dist/store/vector-writes.js +0 -89
  629. /package/dist/{cli → store}/quality-repair.d.ts +0 -0
@@ -133,6 +133,7 @@ export interface SnapshotService {
133
133
  embeddedIds(): ReadonlySet<string> | null;
134
134
  close(): void;
135
135
  }
136
- /** Holds one read-only connection for its commit signal (`PRAGMA data_version`) and the snapshot cache; `now` dates the strength projections, `cacheClock` ages the cache. */
136
+ /** Holds one read-only connection for its commit signal (`PRAGMA data_version`) and the
137
+ * snapshot cache; `now` dates the strength projections, `cacheClock` ages the cache. */
137
138
  export declare function createSnapshotService(hippoRoot: string, now: () => number, cacheClock?: () => number): SnapshotService;
138
139
  //# sourceMappingURL=dashboard-snapshot.d.ts.map
@@ -263,7 +263,15 @@ class SnapshotCacheService {
263
263
  highestIssuedId = Math.max(highestIssuedId, this.lastId);
264
264
  // After loadDashboardRows, whose writable open has run any pending migration and legacy embeddings.json import.
265
265
  this.lastEmbeddedIds = this.connection.embeddedIds();
266
- return buildSnapshot({ id: this.lastId, tenantId, nowMs, entries: rows?.live ?? [], excluded: rows?.excluded, openConflicts, embeddedIds: this.lastEmbeddedIds });
266
+ return buildSnapshot({
267
+ id: this.lastId,
268
+ tenantId,
269
+ nowMs,
270
+ entries: rows?.live ?? [],
271
+ excluded: rows?.excluded,
272
+ openConflicts,
273
+ embeddedIds: this.lastEmbeddedIds
274
+ });
267
275
  }
268
276
  get(tenantId, fresh = false) {
269
277
  const nowMs = this.now();
@@ -298,7 +306,8 @@ class SnapshotCacheService {
298
306
  this.lastEmbeddedIds = undefined;
299
307
  }
300
308
  }
301
- /** Holds one read-only connection for its commit signal (`PRAGMA data_version`) and the snapshot cache; `now` dates the strength projections, `cacheClock` ages the cache. */
309
+ /** Holds one read-only connection for its commit signal (`PRAGMA data_version`) and the
310
+ * snapshot cache; `now` dates the strength projections, `cacheClock` ages the cache. */
302
311
  export function createSnapshotService(hippoRoot, now, cacheClock = Date.now) {
303
312
  return new SnapshotCacheService(hippoRoot, now, cacheClock);
304
313
  }
@@ -17,7 +17,8 @@ export interface ProjectSummary {
17
17
  bands: Record<Band, number>;
18
18
  layers: Record<Layer, number>;
19
19
  }
20
- /** One KPI card; `series` is 91 daily cumulative points, oldest first (point 0 is the base at the window start, point 90 is now) so `last - first` over any range plus one points is exact; null when hippo recorded no history. */
20
+ /** One KPI card; `series` is 91 daily cumulative points, oldest first (point 0 is the base at the window start,
21
+ * point 90 is now) so `last - first` over any range plus one points is exact; null when hippo recorded no history. */
21
22
  export interface Kpi {
22
23
  id: 'total' | 'projects' | 'atRiskShare' | 'openConflicts' | 'embeddingCoverage';
23
24
  label: string;
@@ -4,5 +4,6 @@ import * as http from 'http';
4
4
  export declare function serveDashboard(hippoRoot: string, port?: number, token?: string, opts?: {
5
5
  now?: () => number;
6
6
  cacheClock?: () => number;
7
+ handleSignals?: boolean;
7
8
  }): http.Server;
8
9
  //# sourceMappingURL=dashboard.d.ts.map
@@ -9,12 +9,16 @@ import { listCards } from '../store/cards.js';
9
9
  import { resolveTenantId } from '../store/tenant.js';
10
10
  import { loadCardDetail } from '../store/card-detail.js';
11
11
  import { bodyDeadlineMs, BodyTimeoutError, closeAfterReply, isCrossSite, LOOPBACK_HOST_HEADER } from '../util/http-util.js';
12
- import { errorMessage, log } from '../util/log.js';
12
+ import { errorFields, errorMessage, log } from '../util/log.js';
13
13
  import { createSnapshotService, isLiveMemory } from './dashboard-snapshot.js';
14
14
  import { buildMemoryDetail, buildMemoryPage, buildOverview, buildProjectDetail, buildSearch, } from './dashboard-queries.js';
15
15
  import { forgetMemory, markWrong, pinMemory, resolveOpenConflict, } from './dashboard-actions.js';
16
16
  import { ParamError, parseActionBody, parseConflictId, parseMemoryId, parseMemoryQuery, parseSearchText, } from './dashboard-params.js';
17
17
  import { runWithRequestId } from '../util/request-scope.js';
18
+ import { installSignalHandlers } from '../util/crash-handlers.js';
19
+ import { DEFAULT_SHUTDOWN_DRAIN_MS, drainAndClose, setKeepAliveTimeouts, shutdownBoundMs } from '../server/lifecycle.js';
20
+ import { printError } from '../cli/output.js';
21
+ import { PACKAGE_ROOT } from '../core/package-root.js';
18
22
  const MIME_TYPES = {
19
23
  '.html': 'text/html; charset=utf-8',
20
24
  '.js': 'application/javascript; charset=utf-8',
@@ -296,7 +300,7 @@ function answerDashboardFailure(req, res, err) {
296
300
  const clientFault = err instanceof ParamError || err instanceof URIError || err instanceof BodyTimeoutError;
297
301
  // A cut-short response is logged even for a client fault; a bare 400 is not.
298
302
  if (res.headersSent || !clientFault) {
299
- log.error('dashboard request failed', { error: errorMessage(err), path: req.url });
303
+ log.error('dashboard request failed', { ...errorFields(err), error: errorMessage(err), path: req.url });
300
304
  }
301
305
  if (res.headersSent) {
302
306
  res.end();
@@ -321,9 +325,51 @@ function printDashboardBanner(boundPort, token, distUiDir) {
321
325
  console.log(`Serving React UI from ${distUiDir}`);
322
326
  console.log('Press Ctrl+C to stop.');
323
327
  }
328
+ /** A port that will not open is the user's to fix, so it gets one plain line and a failure exit code, not an uncaught error's stack. */
329
+ function reportListenFailure(port, err) {
330
+ const inUse = 'code' in err && err.code === 'EADDRINUSE';
331
+ printError(inUse
332
+ ? `hippo dashboard: port ${port} is already in use. Stop the program that holds it, or choose another port with --port <number>.`
333
+ : `hippo dashboard: could not listen on port ${port}: ${err.message}. Choose another port with --port <number>.`);
334
+ process.exitCode = 1;
335
+ }
336
+ /** Ctrl+C or a stop signal: stop listening, give open requests the API server's drain, and leave within its shutdown bound. */
337
+ function stopOnSignal(server) {
338
+ const inflight = new Set();
339
+ server.on('request', (_req, res) => {
340
+ inflight.add(res);
341
+ res.once('close', () => inflight.delete(res));
342
+ });
343
+ installSignalHandlers('dashboard', {
344
+ run: () => drainAndClose(server, inflight, DEFAULT_SHUTDOWN_DRAIN_MS),
345
+ boundMs: shutdownBoundMs(DEFAULT_SHUTDOWN_DRAIN_MS),
346
+ });
347
+ }
348
+ /** Gives the listener the API server's socket deadlines and one close of the store's connection; with `handleSignals`, a signal stops it too. */
349
+ function superviseListener(server, snapshots, port, handleSignals) {
350
+ setKeepAliveTimeouts(server);
351
+ let storeClosed = false;
352
+ const closeStore = () => {
353
+ if (storeClosed)
354
+ return;
355
+ storeClosed = true;
356
+ snapshots.close();
357
+ };
358
+ server.on('close', closeStore);
359
+ server.on('error', (err) => {
360
+ // Once it listens, an 'error' is a failed accept: logged, as the API server does, and the dashboard keeps serving.
361
+ if (server.listening)
362
+ return log.error(`dashboard: listener error: ${err.message}`, errorFields(err));
363
+ reportListenFailure(port, err);
364
+ // A failed listen emits no 'close', so the store closes here.
365
+ closeStore();
366
+ });
367
+ if (handleSignals)
368
+ stopOnSignal(server);
369
+ }
324
370
  /** Serves the dashboard on 127.0.0.1 behind a per-start `token` (tests pass one), since loopback alone lets any local process read every memory; `opts` sets the projection and cache clocks. */
325
371
  export function serveDashboard(hippoRoot, port = 3333, token = randomBytes(32).toString('base64url'), opts) {
326
- const distUiDir = path.resolve(import.meta.dirname, '..', 'dist-ui');
372
+ const distUiDir = path.join(PACKAGE_ROOT, 'dist-ui');
327
373
  const hasDistUi = fs.existsSync(path.join(distUiDir, 'index.html'));
328
374
  const now = opts?.now ?? (() => evalNow().getTime());
329
375
  const snapshots = createSnapshotService(hippoRoot, now, opts?.cacheClock);
@@ -356,7 +402,7 @@ export function serveDashboard(hippoRoot, port = 3333, token = randomBytes(32).t
356
402
  };
357
403
  // One id per request, so the lines it logs can be told apart from a concurrent request's.
358
404
  const server = http.createServer((req, res) => runWithRequestId(randomUUID(), () => onRequest(req, res)));
359
- server.on('close', () => snapshots.close());
405
+ superviseListener(server, snapshots, port, opts?.handleSignals === true);
360
406
  server.listen(port, '127.0.0.1', () => {
361
407
  // SAFETY: listen() was given a TCP port, so address() is AddressInfo, never a pipe name.
362
408
  const boundPort = server.address().port;
package/dist/db/busy.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { DatabaseSyncLike } from './sqlite.js';
2
- export declare function isSqliteBusy(error: unknown): boolean;
2
+ export declare function isSqliteBusy(cause: unknown): boolean;
3
3
  export declare const STORE_BUSY_MESSAGE = "store busy (another hippo process holds the write lock); retry shortly";
4
4
  /** A store behind the port throws this when its lock wait runs out, so the server answers 503 as it does for a busy hippo.db. */
5
5
  export declare class StoreBusyError extends Error {
package/dist/db/busy.js CHANGED
@@ -1,5 +1,8 @@
1
- export function isSqliteBusy(error) {
2
- const code = error?.errcode;
1
+ function carriesErrcode(cause) {
2
+ return typeof cause === 'object' && cause !== null && 'errcode' in cause;
3
+ }
4
+ export function isSqliteBusy(cause) {
5
+ const code = carriesErrcode(cause) ? cause.errcode : undefined;
3
6
  return code === 5 || code === 6 || code === 517;
4
7
  }
5
8
  export const STORE_BUSY_MESSAGE = 'store busy (another hippo process holds the write lock); retry shortly';
@@ -14,9 +17,8 @@ export class StoreBusyError extends Error {
14
17
  export function isStoreBusy(error) {
15
18
  return error instanceof StoreBusyError || isSqliteBusy(error);
16
19
  }
17
- // busy_timeout covers neither of this file's two contended statements: SQLite
18
- // skips the busy handler for `PRAGMA journal_mode` and for a write that upgrades
19
- // a deferred read snapshot. Both need an explicit wait instead.
20
+ // busy_timeout covers neither contended statement here: SQLite skips the busy handler for `PRAGMA journal_mode` and for a write
21
+ // that upgrades a deferred read snapshot, so both need an explicit wait.
20
22
  export function execWithBusyRetry(db, sql, timeoutMs = 30000) {
21
23
  const deadline = Date.now() + timeoutMs;
22
24
  const idle = new Int32Array(new SharedArrayBuffer(4));
@@ -67,12 +69,19 @@ export function withReadSnapshot(db, fn) {
67
69
  if (db.isTransaction !== false)
68
70
  return fn();
69
71
  db.exec('BEGIN');
72
+ let result;
70
73
  try {
71
- return fn();
74
+ result = fn();
72
75
  }
73
- finally {
74
- db.exec('COMMIT');
76
+ catch (error) {
77
+ try {
78
+ db.exec('COMMIT');
79
+ }
80
+ catch { /* snapshot already gone; keep the original error */ }
81
+ throw error;
75
82
  }
83
+ db.exec('COMMIT');
84
+ return result;
76
85
  }
77
86
  /** Runs `fn` and undoes every write it made, throw or not: a dry run that reports what a real run would do. Takes no write lock up front. */
78
87
  export function withTrialScope(db, name, fn) {
@@ -1,5 +1,6 @@
1
1
  import { type DatabaseSyncLike } from './sqlite.js';
2
2
  import { type OpenFacts } from './migrate.js';
3
+ export declare const DEFAULT_BUSY_WAIT_MS = 5000;
3
4
  export declare function getHippoDbPath(hippoRoot: string): string;
4
5
  /** Runs `step` on this store unless it already ran to the end in this process; a throw leaves it due. */
5
6
  export declare function oncePerStore(hippoRoot: string, name: string, step: () => void): void;
@@ -1,12 +1,12 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import { cleanupArchivedMirrors } from './raw-archive-mirror-cleanup.js';
4
- import { errorMessage, log } from '../util/log.js';
4
+ import { errorFields, errorMessage, log } from '../util/log.js';
5
5
  import { DatabaseSync } from './sqlite.js';
6
6
  import { execWithBusyRetry } from './busy.js';
7
7
  import { runMigrations } from './migrate.js';
8
8
  import { autoCheckpointPages } from './wal-checkpointer.js';
9
- const DEFAULT_BUSY_WAIT_MS = 5000;
9
+ export const DEFAULT_BUSY_WAIT_MS = 5000;
10
10
  export function getHippoDbPath(hippoRoot) {
11
11
  return path.join(hippoRoot, 'hippo.db');
12
12
  }
@@ -68,7 +68,7 @@ export function connectWithFacts(hippoRoot, busyWaitMs) {
68
68
  sweepArchivedMirrorsIfDue(hippoRoot, db, facts?.archiveTop);
69
69
  }
70
70
  catch (cleanupErr) {
71
- log.error(`openHippoDb: cleanupArchivedMirrors failed (non-fatal): ${errorMessage(cleanupErr)}`);
71
+ log.error(`openHippoDb: cleanupArchivedMirrors failed (non-fatal): ${errorMessage(cleanupErr)}`, errorFields(cleanupErr));
72
72
  }
73
73
  return { db, facts };
74
74
  }
@@ -125,10 +125,10 @@ function importLegacyVectors(db, hippoRoot) {
125
125
  }
126
126
  }
127
127
  function ensureMetaDefaults(db) {
128
- // Read-first: an already-current store has all 7 keys, so this is one
129
- // SELECT and zero writes instead of 7 no-op INSERT OR IGNOREs, each of
130
- // which takes a RESERVED lock even when nothing changes.
128
+ // Read-first: an already-current store has all 7 keys, so this is one SELECT and zero writes instead of 7 no-op
129
+ // INSERT OR IGNOREs, each of which takes a RESERVED lock even when nothing changes.
131
130
  const keys = META_DEFAULTS.map(([key]) => key);
131
+ // SAFETY: the statement selects only the `key` column of `meta`, which is TEXT NOT NULL, so each row is { key: string }.
132
132
  const present = new Set(db
133
133
  .prepare(`SELECT key FROM meta WHERE key IN (${keys.map(() => '?').join(',')})`)
134
134
  .all(...keys)
@@ -1,9 +1,6 @@
1
1
  import type { DatabaseSyncLike } from '../sqlite.js';
2
- /**
3
- * Context passed to migrations that need to know WHERE the store lives.
4
- * hippoRoot is the store directory (e.g. `<project>/.hippo`); undefined only
5
- * for callers that open a DB without a filesystem store notion (none today).
6
- */
2
+ /** Context for migrations that need to know where the store lives. hippoRoot is the store directory (e.g. `<project>/.hippo`);
3
+ * undefined only for callers that open a DB without a filesystem store. */
7
4
  export type MigrationContext = {
8
5
  hippoRoot?: string;
9
6
  };
@@ -36,9 +36,8 @@ const CREATE_TRIGGER_TRG_MEMORIES_KIND_CHECK_UPDATE_SQL = `
36
36
  export const v14 = {
37
37
  version: 14,
38
38
  up: (db) => {
39
- // Provenance envelope: kind, scope, owner, artifact_ref.
40
- // SQLite ALTER TABLE ADD COLUMN cannot add CHECK; CHECK enforcement lives
41
- // in INSERT/UPDATE triggers added later in this migration.
39
+ // Provenance envelope: kind, scope, owner, artifact_ref. ALTER TABLE ADD COLUMN cannot add CHECK,
40
+ // so enforcement lives in the INSERT/UPDATE triggers added later in this migration.
42
41
  if (!tableHasColumn(db, 'memories', 'kind')) {
43
42
  db.exec(`ALTER TABLE memories ADD COLUMN kind TEXT DEFAULT 'distilled'`);
44
43
  }
@@ -1,14 +1,8 @@
1
1
  export const v15 = {
2
2
  version: 15,
3
3
  up: (db) => {
4
- // Close the NULL-kind bypass and add raw_archive dedup safety.
5
- //
6
- // (1) Original v14 triggers used `WHEN NEW.kind IS NOT NULL AND NEW.kind NOT IN (...)`.
7
- // A direct INSERT/UPDATE setting kind=NULL bypassed the CHECK substitute. Replace
8
- // with `WHEN NEW.kind IS NULL OR NEW.kind NOT IN (...)` so NULL is rejected too.
9
- // (2) Add UNIQUE(memory_id, archived_at) to raw_archive so re-archiving the same id
10
- // in the same instant cannot produce ambiguous audit rows. Per-id history is still
11
- // allowed (different timestamps).
4
+ // Close the NULL-kind bypass: v14 triggers used `WHEN NEW.kind IS NOT NULL AND ...`, so kind=NULL slipped past; now `IS NULL OR NOT IN (...)` rejects it.
5
+ // Add UNIQUE(memory_id, archived_at) to raw_archive so re-archiving in the same instant cannot yield ambiguous audit rows (per-id history stays allowed).
12
6
  db.exec(`DROP TRIGGER IF EXISTS trg_memories_kind_check_insert`);
13
7
  db.exec(`DROP TRIGGER IF EXISTS trg_memories_kind_check_update`);
14
8
  db.exec(`
@@ -51,9 +51,8 @@ export const v16 = {
51
51
  db.exec(`CREATE INDEX IF NOT EXISTS idx_working_memory_tenant ON working_memory(tenant_id, importance DESC, created_at DESC)`);
52
52
  db.exec(`CREATE INDEX IF NOT EXISTS idx_consolidation_runs_tenant_ts ON consolidation_runs(tenant_id, timestamp DESC)`);
53
53
  db.exec(`CREATE INDEX IF NOT EXISTS idx_task_snapshots_tenant_status ON task_snapshots(tenant_id, status, updated_at DESC)`);
54
- // Stub auth: api_keys (scrypt-hashed; plaintext returned to caller exactly once)
55
- // and audit_log (append-only mutation trail). Both carry tenant_id from day 1 so
56
- // future multi-tenant enforcement is a config flip, not a re-migration.
54
+ // Stub auth: api_keys (scrypt-hashed; plaintext returned once) and audit_log (append-only mutation trail), both with tenant_id from day 1
55
+ // so future multi-tenant enforcement is a config flip, not a re-migration.
57
56
  db.exec(CREATE_TABLE_API_KEYS_SQL);
58
57
  db.exec(CREATE_INDEX_IDX_API_KEYS_TENANT_ACTIVE_SQL);
59
58
  db.exec(CREATE_TABLE_AUDIT_LOG_SQL);
@@ -30,9 +30,8 @@ export const v17 = {
30
30
  )
31
31
  `);
32
32
  db.exec(`CREATE INDEX IF NOT EXISTS idx_slack_dlq_tenant_received ON slack_dlq(tenant_id, received_at)`);
33
- // Multi-tenant routing seam. Empty by default: single-
34
- // tenant deployments resolve via HIPPO_TENANT fallback. Multi-workspace
35
- // deployments populate this table to map team_id → tenant_id.
33
+ // Multi-tenant routing seam, empty by default: single-tenant deployments resolve via the HIPPO_TENANT fallback;
34
+ // multi-workspace deployments populate it to map team_id -> tenant_id.
36
35
  db.exec(`
37
36
  CREATE TABLE IF NOT EXISTS slack_workspaces (
38
37
  team_id TEXT PRIMARY KEY,
@@ -2,11 +2,8 @@ import { tableHasColumn } from '../tables.js';
2
2
  export const v19 = {
3
3
  version: 19,
4
4
  up: (db) => {
5
- // Slack hardening: widen slack_dlq with bucketing,
6
- // retry tracking, and the signature/timestamp pair that lets `hippo
7
- // slack dlq replay` re-verify before re-running ingest. ALTER ADD
8
- // COLUMN with DEFAULT is non-destructive — legacy rows take the
9
- // default values. Idempotent via tableHasColumn().
5
+ // Widen slack_dlq with bucketing, retry tracking and the signature/timestamp pair `hippo slack dlq replay` re-verifies;
6
+ // ALTER ADD COLUMN with DEFAULT is non-destructive, so legacy rows take the defaults. Idempotent via tableHasColumn().
10
7
  if (!tableHasColumn(db, 'slack_dlq', 'team_id')) {
11
8
  db.exec(`ALTER TABLE slack_dlq ADD COLUMN team_id TEXT`);
12
9
  }
@@ -2,13 +2,8 @@ import { warnDamagedColumn } from '../../util/stored-json.js';
2
2
  export const v20 = {
3
3
  version: 20,
4
4
  up: (db) => {
5
- // GDPR Path A backfill: redact every existing
6
- // raw_archive.payload_json so historical archives match the new
7
- // metadata-only contract from src/store/raw-archive.ts. Read each row, parse
8
- // the existing JSON to extract tenant_id and kind (best effort), then
9
- // UPDATE with the redacted shape. Rows with unparseable legacy JSON get
10
- // redacted with tenant_id='unknown', kind='unknown'. The audit_log
11
- // remains the compliance record.
5
+ // GDPR Path A backfill: redact every existing raw_archive.payload_json to the metadata-only shape (store/raw-archive.ts); unparseable legacy JSON
6
+ // gets tenant_id='unknown', kind='unknown'. The audit_log remains the compliance record.
12
7
  // SAFETY: rows' shape matches the four columns named in the SELECT above.
13
8
  const rows = db
14
9
  .prepare(`SELECT id, archived_at, reason, payload_json FROM raw_archive`)
@@ -44,17 +44,8 @@ const BACKFILL_SESSION_HANDOFFS_TENANT_SQL = `
44
44
  export const v22 = {
45
45
  version: 22,
46
46
  up: (db) => {
47
- // session_events and session_handoffs predate the v16 tenant migration and were
48
- // never added to it: a cross-tenant leak whenever continuity primitives are used.
49
- // Adds tenant_id (NOT NULL DEFAULT 'default') with smart backfill from
50
- // task_snapshots.session_id when unambiguous, plus an optional scope
51
- // column so a private-channel-derived handoff can default-deny via the
52
- // same rule recall already enforces.
53
- //
54
- // Self-heal partial-init stores: re-run the v4/v5 CREATE TABLE IF NOT
55
- // EXISTS bodies before ALTERing. A silent skip would otherwise stamp
56
- // schema_version=22 on a DB missing the underlying tables, leaving
57
- // them permanently absent.
47
+ // session_events and session_handoffs missed the v16 tenant migration (cross-tenant leak): add tenant_id (NOT NULL DEFAULT 'default') backfilled from
48
+ // task_snapshots when unambiguous, plus a scope column. Re-run v4/v5 CREATE IF NOT EXISTS first so a partial-init store isn't stamped v22 without tables.
58
49
  db.exec(CREATE_TABLE_SESSION_EVENTS_SQL);
59
50
  if (!tableHasColumn(db, 'session_events', 'tenant_id')) {
60
51
  db.exec(`ALTER TABLE session_events ADD COLUMN tenant_id TEXT NOT NULL DEFAULT 'default'`);
@@ -68,12 +59,8 @@ export const v22 = {
68
59
  if (!tableHasColumn(db, 'session_handoffs', 'scope')) {
69
60
  db.exec(`ALTER TABLE session_handoffs ADD COLUMN scope TEXT`);
70
61
  }
71
- // Smart backfill: rows whose session_id maps to exactly one tenant in
72
- // task_snapshots inherit that tenant. Ambiguous or unmapped rows stay
73
- // at the column default ('default'). Conservative: never crosses
74
- // tenant boundaries on guesses. The COUNT(DISTINCT) gate is the load-
75
- // bearing check; without it, rows with multiple tenants under the same
76
- // session_id would silently pick whichever group came first.
62
+ // Smart backfill: a row whose session_id maps to exactly one tenant in task_snapshots inherits it; ambiguous or unmapped rows keep 'default'.
63
+ // The COUNT(DISTINCT) gate is load-bearing: without it a session_id spanning tenants would silently pick whichever group came first.
77
64
  db.exec(BACKFILL_SESSION_EVENTS_TENANT_SQL);
78
65
  db.exec(BACKFILL_SESSION_HANDOFFS_TENANT_SQL);
79
66
  db.exec(`CREATE INDEX IF NOT EXISTS idx_session_events_tenant_session ON session_events(tenant_id, session_id, created_at DESC, id DESC)`);
@@ -2,9 +2,7 @@ import { tableHasColumn, tableExists } from '../tables.js';
2
2
  export const v23 = {
3
3
  version: 23,
4
4
  up: (db) => {
5
- // task_snapshots: add scope so all three continuity tables carry it.
6
- // Self-heal partial-init stores via CREATE TABLE IF NOT EXISTS (the v22
7
- // session_events / session_handoffs healing is upstream).
5
+ // task_snapshots: add scope so all three continuity tables carry it; self-heal partial-init stores via CREATE TABLE IF NOT EXISTS.
8
6
  db.exec(`
9
7
  CREATE TABLE IF NOT EXISTS task_snapshots (
10
8
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -22,17 +20,8 @@ export const v23 = {
22
20
  if (!tableHasColumn(db, 'task_snapshots', 'scope')) {
23
21
  db.exec(`ALTER TABLE task_snapshots ADD COLUMN scope TEXT`);
24
22
  }
25
- // Quarantine policy: pre-existing continuity rows
26
- // with NULL scope cannot be safely classified as public after the fact.
27
- // Mark them 'unknown:legacy' so the api.recall + cmdRecall default-deny
28
- // filter excludes them for no-scope callers. Fresh rows from new
29
- // writers carry NULL when scope is unspecified (legitimate non-Slack
30
- // writes); the 'unknown:legacy' marker is a v23-only one-shot for
31
- // pre-upgrade rows.
32
- //
33
- // Run UPDATEs only on tables that exist (some test paths and edge stores
34
- // skip v22's table healing). The UPDATEs are themselves idempotent via
35
- // the WHERE scope IS NULL clause, so re-running is a no-op.
23
+ // Quarantine pre-existing continuity rows with NULL scope as 'unknown:legacy' so the recall default-deny filter excludes them for no-scope callers;
24
+ // new rows legitimately carry NULL. UPDATE only tables that exist (v22 healing is skipped on some paths); WHERE scope IS NULL keeps it idempotent.
36
25
  if (tableExists(db, 'task_snapshots')) {
37
26
  db.exec(`UPDATE task_snapshots SET scope = 'unknown:legacy' WHERE scope IS NULL`);
38
27
  }
@@ -62,10 +62,8 @@ export const v24 = {
62
62
  db.exec(CREATE_TABLE_GITHUB_DLQ_SQL);
63
63
  db.exec(`CREATE INDEX IF NOT EXISTS idx_github_dlq_tenant_received ON github_dlq(tenant_id, received_at)`);
64
64
  db.exec(CREATE_TABLE_GITHUB_INSTALLATIONS_SQL);
65
- // PAT-mode multi-tenant routing. Maps repo_full_name to
66
- // tenant when the webhook envelope has no `installation` field. Composite
67
- // PK so the same repo can intentionally be visible to multiple tenants
68
- // (e.g., shared tooling accounts) — collision is on (repo, tenant) pair.
65
+ // PAT-mode multi-tenant routing: maps repo_full_name to a tenant when the webhook envelope has no `installation` field.
66
+ // Composite PK so one repo can be visible to several tenants; the collision is on the (repo, tenant) pair.
69
67
  db.exec(CREATE_TABLE_GITHUB_REPOSITORIES_SQL);
70
68
  // Rollback-safety guard: an older binary lacks the *:private:* default-deny and would leak
71
69
  // github:private:* rows; the startup guard refuses a DB whose min_compatible_binary is newer.
@@ -2,11 +2,8 @@ import { tableHasColumn } from '../tables.js';
2
2
  export const v25 = {
3
3
  version: 25,
4
4
  up: (db) => {
5
- // DAG-aware recall: cache summary metadata so the assembler can
6
- // reason about scope without re-walking the DAG. Three additive,
7
- // optional columns. No min_compatible_binary bump: these columns are
8
- // pure metadata; older binaries opening this DB will see them as NULL
9
- // / 0 and behave as before.
5
+ // DAG-aware recall: three additive optional columns cache summary metadata so the assembler need not re-walk the DAG.
6
+ // No min_compatible_binary bump: older binaries see them as NULL / 0 and behave as before.
10
7
  if (!tableHasColumn(db, 'memories', 'descendant_count')) {
11
8
  db.exec(`ALTER TABLE memories ADD COLUMN descendant_count INTEGER NOT NULL DEFAULT 0`);
12
9
  }
@@ -16,9 +13,7 @@ export const v25 = {
16
13
  if (!tableHasColumn(db, 'memories', 'latest_at')) {
17
14
  db.exec(`ALTER TABLE memories ADD COLUMN latest_at TEXT`);
18
15
  }
19
- // Backfill descendant_count for existing level-2 summary rows. Use
20
- // dag_parent_id pointing at the summary id. Level-3 (entity profiles)
21
- // not built today; their descendant_count stays at default 0.
16
+ // Backfill descendant_count for existing level-2 summary rows via dag_parent_id = summary id; level-3 (entity profiles) is not built, so it stays 0.
22
17
  db.exec(`
23
18
  UPDATE memories
24
19
  SET descendant_count = (
@@ -2,19 +2,8 @@ import { tableHasColumn, tableExists } from '../tables.js';
2
2
  export const v26 = {
3
3
  version: 26,
4
4
  up: (db) => {
5
- // Add role column to api_keys for the admin/member
6
- // distinction that gates /v1/sleep. Additive — existing keys backfill to
7
- // 'admin' via DEFAULT (single-tenant operator = admin by definition).
8
- // No min_compatible_binary bump: old binaries ignore the
9
- // column on SELECTs that don't name it; new binaries on old data run
10
- // this migration at openHippoDb time before any createApiKey call.
11
- //
12
- // Defensive: also guard on tableExists. If a DB landed in the
13
- // partial-v16-state (api_keys table missing despite schema_version >= 16),
14
- // running ALTER TABLE here would crash and block all later migrations.
15
- // The v27 heal below recreates api_keys with the role column already
16
- // present, so this ALTER becomes a no-op anyway for that path. Defense
17
- // in depth: guard so v26 never crashes on the partial-apply state.
5
+ // Add api_keys.role for the admin/member split gating /v1/sleep; existing keys backfill to 'admin' via DEFAULT. No min_compatible_binary bump.
6
+ // Guard on tableExists: a partial-v16 DB without api_keys would crash this ALTER and block later migrations (v27 heals it with role present).
18
7
  if (tableExists(db, 'api_keys') && !tableHasColumn(db, 'api_keys', 'role')) {
19
8
  db.exec(`ALTER TABLE api_keys ADD COLUMN role TEXT NOT NULL DEFAULT 'admin'`);
20
9
  }
@@ -2,13 +2,8 @@ import { tableHasColumn, tableExists } from '../tables.js';
2
2
  export const v27 = {
3
3
  version: 27,
4
4
  up: (db) => {
5
- // Self-heal: re-assert the v16 schema (api_keys + audit_log) on stores stamped past
6
- // v16 whose tables are missing anyway (a dropped table or an old-backup restore).
7
- //
8
- // All CREATE IF NOT EXISTS — zero-cost no-op for users without the
9
- // bug, fixes anyone who has it. Includes the role column from the
10
- // start so it matches v26's intent without needing v26 to ALTER on
11
- // this heal path.
5
+ // Self-heal: re-assert the v16 schema (api_keys + audit_log) on stores stamped past v16 whose tables are missing (dropped table or old-backup restore).
6
+ // All CREATE IF NOT EXISTS, so a no-op for healthy stores; includes the role column so v26's ALTER is not needed on this path.
12
7
  db.exec(`
13
8
  CREATE TABLE IF NOT EXISTS api_keys (
14
9
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -37,10 +32,7 @@ export const v27 = {
37
32
  )
38
33
  `);
39
34
  db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_log_tenant_ts ON audit_log(tenant_id, ts DESC)`);
40
- // Belt-and-braces: if api_keys existed before this migration WITHOUT
41
- // the role column (i.e. v16-shape table that v26's ALTER skipped due
42
- // to tableExists=false on an earlier broken run, then someone manually
43
- // CREATEd it without role), backfill role.
35
+ // Belt-and-braces: backfill role on an api_keys table that exists without it (v16-shape table that v26's ALTER skipped on an earlier broken run).
44
36
  if (tableExists(db, 'api_keys') && !tableHasColumn(db, 'api_keys', 'role')) {
45
37
  db.exec(`ALTER TABLE api_keys ADD COLUMN role TEXT NOT NULL DEFAULT 'admin'`);
46
38
  }
@@ -2,20 +2,8 @@ import { tableHasColumn } from '../tables.js';
2
2
  export const v28 = {
3
3
  version: 28,
4
4
  up: (db) => {
5
- // Dirty-flag persistence for level-2 DAG summaries, so child-write propagation and the
6
- // sleep-cycle rebuild can write + read the staleness signal. dag_level_3_built_at lands
7
- // now so the entity-profile build path needs no second migration.
8
- //
9
- // All columns are additive + DEFAULTed/nullable, so backfill is
10
- // automatic for existing rows. No min_compatible_binary bump: old
11
- // binaries ignore the columns on SELECTs that don't name
12
- // them; new binaries on old data hit this migration at openHippoDb
13
- // time before any DAG path touches summary_dirty.
14
- //
15
- // Precedent for column-only guards on memories: v25 (db.ts:827),
16
- // which added the DAG cache columns the same way. memories table
17
- // itself comes from v1 and is always present, so the tableExists
18
- // half of the v26/v27 guard pattern isn't load-bearing here.
5
+ // Dirty-flag persistence for level-2 DAG summaries; dag_level_3_built_at lands now so the entity-profile path needs no second migration.
6
+ // Columns are additive and DEFAULTed/nullable, so no min_compatible_binary bump. Column-only guard: memories comes from v1 and always exists.
19
7
  if (!tableHasColumn(db, 'memories', 'summary_dirty')) {
20
8
  db.exec(`ALTER TABLE memories ADD COLUMN summary_dirty INTEGER NOT NULL DEFAULT 0`);
21
9
  }
@@ -52,28 +52,14 @@ const CREATE_TRIGGER_TRG_PREDICTIONS_TENANT_MATCH_UPDATE_SQL = `
52
52
  export const v29 = {
53
53
  version: 29,
54
54
  up: (db) => {
55
- // Prediction first-class object: a predictions table for the reference-class /
56
- // planning-fallacy detector. Predictions
57
- // duplicate claim_text in the table itself so memory deletion
58
- // (forget/consolidate/archive) does not lose prediction data; FK
59
- // memory_id is NULLABLE with ON DELETE SET NULL.
60
- //
61
- // Cross-tenant safety: BEFORE INSERT + BEFORE UPDATE triggers
62
- // enforce tenant_id match against the referenced memory. SQLite's
63
- // ON DELETE SET NULL is incompatible with composite FK where one
64
- // side is NOT NULL, so the trigger pattern replaces a composite
65
- // FK target. Precedent: v14 memories.kind trigger pair at db.ts:298-322.
66
- //
67
- // CHECK constraint pins closure_state to (open|closed|closed-unknown).
68
- // Accuracy (clean vs regressed) is computed from (estimate_value,
69
- // actual_value) at query time.
55
+ // Prediction first-class object: claim_text is duplicated so deleting the memory loses nothing; memory_id is NULLABLE ON DELETE SET NULL.
56
+ // Tenant-match triggers replace a composite FK, which is incompatible with ON DELETE SET NULL; closure_state is CHECKed to open|closed|closed-unknown.
70
57
  if (!tableExists(db, 'predictions')) {
71
58
  db.exec(CREATE_TABLE_PREDICTIONS_SQL);
72
59
  db.exec(CREATE_INDEX_IDX_PREDICTIONS_TENANT_CLASS_SQL);
73
60
  db.exec(CREATE_INDEX_IDX_PREDICTIONS_MEMORY_SQL);
74
- // Cross-tenant safety: tenant_id must match the referenced memory's
75
- // tenant_id when memory_id IS NOT NULL. INSERT + UPDATE pair, mirroring
76
- // v14 memories.kind enforcement (db.ts:298-322).
61
+ // Cross-tenant safety: tenant_id must match the referenced memory's tenant_id when memory_id IS NOT NULL;
62
+ // INSERT + UPDATE pair, mirroring the v14 memories.kind enforcement.
77
63
  db.exec(CREATE_TRIGGER_TRG_PREDICTIONS_TENANT_MATCH_INSERT_SQL);
78
64
  db.exec(CREATE_TRIGGER_TRG_PREDICTIONS_TENANT_MATCH_UPDATE_SQL);
79
65
  }
@@ -48,10 +48,8 @@ const TRG_DECISIONS_TENANT_MATCH_UPDATE = `
48
48
  END;
49
49
  END
50
50
  `;
51
- // Cross-tenant safety vs the successor decision (self-FK). superseded_by
52
- // is set only via UPDATE (the supersede path); the successor must share
53
- // the tenant. The successor row already exists in the same transaction
54
- // when this fires, so the subquery resolves.
51
+ // Cross-tenant safety vs the successor decision (self-FK): superseded_by is set only via the supersede UPDATE and the successor,
52
+ // which already exists in the same transaction when this fires, must share the tenant.
55
53
  const TRG_DECISIONS_SUPERSEDE_TENANT_MATCH_UPDATE = `
56
54
  CREATE TRIGGER IF NOT EXISTS trg_decisions_supersede_tenant_match_update
57
55
  BEFORE UPDATE ON decisions
@@ -67,18 +65,8 @@ const TRG_DECISIONS_SUPERSEDE_TENANT_MATCH_UPDATE = `
67
65
  export const v30 = {
68
66
  version: 30,
69
67
  up: (db) => {
70
- // Decision first-class object.
71
- // Promotes `hippo decide` from a tagged memory (which decayed on a 90-day
72
- // half-life even while the decision was still in force) to a dedicated
73
- // decisions table that is the source of truth. The memory mirror is kept
74
- // for recall but is no longer authoritative; memory_id is NULLABLE with
75
- // ON DELETE SET NULL so forget/consolidate/archive does not lose a
76
- // decision. Mirrors the v29 predictions tenant-match trigger pattern.
77
- //
78
- // status (active|superseded|closed): superseded carries a self-FK
79
- // superseded_by to the successor decision; closed is a terminal
80
- // retire-without-successor. A superseded_by same-tenant trigger makes
81
- // cross-tenant supersession unrepresentable at the schema level.
68
+ // Decision first-class object, the source of truth for `hippo decide`; the memory mirror serves recall only, memory_id NULLABLE ON DELETE SET NULL.
69
+ // status active|superseded|closed (closed = retired without successor); a same-tenant trigger on superseded_by blocks cross-tenant supersession.
82
70
  if (!tableExists(db, 'decisions')) {
83
71
  db.exec(DECISIONS_TABLE);
84
72
  db.exec(IDX_DECISIONS_TENANT_STATUS);