hippo-memory 1.61.0 → 1.63.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 (377) hide show
  1. package/README.md +37 -53
  2. package/dist/agent-memories/apply.d.ts +3 -1
  3. package/dist/agent-memories/apply.js +23 -1
  4. package/dist/agent-memories/claude-code.d.ts +4 -1
  5. package/dist/agent-memories/claude-code.js +53 -9
  6. package/dist/agent-memories/report.d.ts +1 -0
  7. package/dist/agent-memories/report.js +2 -2
  8. package/dist/agent-memories/sync.d.ts +3 -3
  9. package/dist/agent-memories/sync.js +46 -24
  10. package/dist/agent-memories/types.d.ts +0 -2
  11. package/dist/ambient-store.d.ts +4 -4
  12. package/dist/ambient-store.js +4 -3
  13. package/dist/api/assemble.d.ts +7 -10
  14. package/dist/api/assemble.js +62 -66
  15. package/dist/api/audit.d.ts +2 -2
  16. package/dist/api/audit.js +2 -2
  17. package/dist/api/auth.d.ts +6 -6
  18. package/dist/api/auth.js +5 -7
  19. package/dist/api/context-select.d.ts +50 -0
  20. package/dist/api/context-select.js +342 -0
  21. package/dist/api/context-types.d.ts +12 -17
  22. package/dist/api/context.d.ts +5 -4
  23. package/dist/api/context.js +208 -535
  24. package/dist/api/dormant.js +1 -1
  25. package/dist/api/drill-down.d.ts +4 -4
  26. package/dist/api/drill-down.js +56 -41
  27. package/dist/api/outcome.d.ts +8 -13
  28. package/dist/api/outcome.js +13 -17
  29. package/dist/api/promote.d.ts +5 -8
  30. package/dist/api/promote.js +55 -66
  31. package/dist/api/quarantine.js +3 -2
  32. package/dist/api/recall-types.d.ts +43 -55
  33. package/dist/api/recall.d.ts +3 -3
  34. package/dist/api/recall.js +310 -456
  35. package/dist/api/remember.d.ts +2 -2
  36. package/dist/api/sleep.d.ts +7 -35
  37. package/dist/api/sleep.js +206 -220
  38. package/dist/api/tokens.d.ts +2 -2
  39. package/dist/api/tokens.js +2 -2
  40. package/dist/api/types.d.ts +6 -10
  41. package/dist/api/types.js +2 -4
  42. package/dist/audit-prune.d.ts +4 -6
  43. package/dist/audit-prune.js +3 -5
  44. package/dist/audit.js +11 -33
  45. package/dist/auth.d.ts +8 -9
  46. package/dist/auth.js +5 -7
  47. package/dist/autolearn.d.ts +1 -1
  48. package/dist/autolearn.js +1 -1
  49. package/dist/availability.js +3 -5
  50. package/dist/capture/command.d.ts +5 -4
  51. package/dist/capture/command.js +8 -22
  52. package/dist/capture/compact.d.ts +2 -2
  53. package/dist/capture/compact.js +11 -15
  54. package/dist/capture/extract.js +37 -115
  55. package/dist/capture-error.d.ts +1 -1
  56. package/dist/capture-error.js +1 -1
  57. package/dist/churn-git.d.ts +1 -1
  58. package/dist/churn-git.js +1 -1
  59. package/dist/cli/audit.js +3 -4
  60. package/dist/cli/auth.js +3 -6
  61. package/dist/cli/briefs.js +324 -306
  62. package/dist/cli/context.js +44 -34
  63. package/dist/cli/continuity.js +283 -271
  64. package/dist/cli/curate.d.ts +1 -1
  65. package/dist/cli/curate.js +43 -58
  66. package/dist/cli/dag.js +5 -9
  67. package/dist/cli/decisions.js +334 -345
  68. package/dist/cli/explain.js +68 -61
  69. package/dist/cli/goals.js +1 -1
  70. package/dist/cli/init.js +1 -1
  71. package/dist/cli/maintenance.js +62 -51
  72. package/dist/cli/playbooks.js +391 -379
  73. package/dist/cli/projects.js +11 -6
  74. package/dist/cli/recall.js +30 -44
  75. package/dist/cli/remember.js +118 -87
  76. package/dist/cli/session-hooks.js +106 -115
  77. package/dist/cli/setup.d.ts +1 -1
  78. package/dist/cli/setup.js +267 -250
  79. package/dist/cli/shared.js +3 -3
  80. package/dist/cli/slack.js +1 -1
  81. package/dist/cli/sleep.js +27 -1
  82. package/dist/cli/status.d.ts +4 -4
  83. package/dist/cli/status.js +80 -76
  84. package/dist/cli/transfer.js +88 -107
  85. package/dist/cli/usage.js +9 -6
  86. package/dist/cli.d.ts +1 -1
  87. package/dist/cli.js +4 -9
  88. package/dist/compaction-record.d.ts +2 -2
  89. package/dist/compaction-record.js +89 -68
  90. package/dist/compare.d.ts +11 -16
  91. package/dist/compare.js +11 -16
  92. package/dist/config.d.ts +19 -18
  93. package/dist/config.js +90 -67
  94. package/dist/connectors/github/backfill.d.ts +2 -2
  95. package/dist/connectors/github/backfill.js +8 -15
  96. package/dist/connectors/github/cli-impl.js +3 -8
  97. package/dist/connectors/github/deletion.d.ts +5 -12
  98. package/dist/connectors/github/deletion.js +5 -12
  99. package/dist/connectors/github/dlq.d.ts +6 -9
  100. package/dist/connectors/github/dlq.js +2 -3
  101. package/dist/connectors/github/ingest.d.ts +5 -7
  102. package/dist/connectors/github/ingest.js +8 -12
  103. package/dist/connectors/github/octokit-client.d.ts +3 -5
  104. package/dist/connectors/github/octokit-client.js +5 -6
  105. package/dist/connectors/github/signature.d.ts +9 -39
  106. package/dist/connectors/github/signature.js +9 -39
  107. package/dist/connectors/github/tenant-routing.d.ts +1 -1
  108. package/dist/connectors/github/tenant-routing.js +1 -1
  109. package/dist/connectors/github/transform.js +2 -2
  110. package/dist/connectors/github/types.d.ts +2 -10
  111. package/dist/connectors/github/types.js +1 -3
  112. package/dist/connectors/slack/deletion.d.ts +3 -8
  113. package/dist/connectors/slack/deletion.js +3 -8
  114. package/dist/connectors/slack/dlq.d.ts +1 -1
  115. package/dist/connectors/slack/ingest.d.ts +1 -1
  116. package/dist/connectors/slack/ingest.js +7 -16
  117. package/dist/connectors/slack/signature.d.ts +1 -1
  118. package/dist/connectors/slack/tenant-routing.d.ts +3 -5
  119. package/dist/connectors/slack/tenant-routing.js +3 -5
  120. package/dist/connectors/slack/transform.d.ts +5 -6
  121. package/dist/connectors/slack/transform.js +5 -6
  122. package/dist/connectors/slack/types.d.ts +2 -6
  123. package/dist/connectors/slack/types.js +1 -3
  124. package/dist/connectors/slack/web-client.js +10 -3
  125. package/dist/connectors/slack/workspaces.d.ts +3 -5
  126. package/dist/connectors/slack/workspaces.js +3 -5
  127. package/dist/consolidate/conflicts.js +3 -14
  128. package/dist/consolidate/decay.js +9 -29
  129. package/dist/consolidate/llm-passes.js +4 -5
  130. package/dist/consolidate/merge.js +8 -23
  131. package/dist/consolidate/run.d.ts +1 -8
  132. package/dist/consolidate/run.js +3 -25
  133. package/dist/consolidate/sleep.js +5 -17
  134. package/dist/consolidate/traces.js +9 -21
  135. package/dist/customer-notes.d.ts +5 -7
  136. package/dist/customer-notes.js +82 -76
  137. package/dist/dag.d.ts +10 -21
  138. package/dist/dag.js +189 -203
  139. package/dist/db/continuity.js +2 -2
  140. package/dist/db/migrations/v14.js +1 -1
  141. package/dist/db/migrations/v15.js +1 -2
  142. package/dist/db/migrations/v16.js +3 -4
  143. package/dist/db/migrations/v17.js +2 -3
  144. package/dist/db/migrations/v19.js +1 -1
  145. package/dist/db/migrations/v20.js +1 -1
  146. package/dist/db/migrations/v21.js +2 -6
  147. package/dist/db/migrations/v22.js +2 -4
  148. package/dist/db/migrations/v23.js +1 -1
  149. package/dist/db/migrations/v24.js +4 -6
  150. package/dist/db/migrations/v25.js +2 -3
  151. package/dist/db/migrations/v26.js +3 -3
  152. package/dist/db/migrations/v27.js +2 -10
  153. package/dist/db/migrations/v28.js +5 -8
  154. package/dist/db/migrations/v29.js +3 -4
  155. package/dist/db/migrations/v30.js +2 -2
  156. package/dist/db/migrations/v31.js +1 -1
  157. package/dist/db/migrations/v32.js +1 -1
  158. package/dist/db/migrations/v33.js +3 -3
  159. package/dist/db/migrations/v34.js +1 -1
  160. package/dist/db/migrations/v35.js +3 -4
  161. package/dist/db/migrations/v36.js +3 -4
  162. package/dist/db/migrations/v37.js +5 -5
  163. package/dist/db/migrations/v38.js +7 -8
  164. package/dist/db/migrations/v39.js +1 -1
  165. package/dist/db/migrations/v40.js +4 -16
  166. package/dist/db/migrations/v41.js +3 -4
  167. package/dist/db/migrations/v42.js +3 -4
  168. package/dist/db/migrations/v45.js +1 -1
  169. package/dist/db/migrations/v46.js +1 -1
  170. package/dist/db/migrations/v47.js +1 -1
  171. package/dist/db/migrations/v48.js +1 -1
  172. package/dist/decisions.d.ts +2 -2
  173. package/dist/decisions.js +97 -80
  174. package/dist/dedupe.js +86 -61
  175. package/dist/delivery-recorder.js +154 -135
  176. package/dist/doctor.js +129 -110
  177. package/dist/dormant.js +1 -4
  178. package/dist/embedding-provider.d.ts +4 -8
  179. package/dist/embedding-provider.js +4 -8
  180. package/dist/embeddings.js +55 -47
  181. package/dist/env.d.ts +1 -1
  182. package/dist/env.js +12 -12
  183. package/dist/escape.d.ts +5 -0
  184. package/dist/escape.js +10 -0
  185. package/dist/eval-stats.d.ts +1 -2
  186. package/dist/eval-stats.js +1 -2
  187. package/dist/eval-suite.js +27 -21
  188. package/dist/extract.js +4 -9
  189. package/dist/failure-log.d.ts +3 -3
  190. package/dist/failure-log.js +1 -1
  191. package/dist/forward-claim-detector.d.ts +2 -4
  192. package/dist/forward-claim-detector.js +6 -11
  193. package/dist/goals.d.ts +3 -3
  194. package/dist/goals.js +103 -91
  195. package/dist/graph/read.d.ts +2 -2
  196. package/dist/graph/read.js +5 -6
  197. package/dist/graph/types.d.ts +8 -8
  198. package/dist/graph/write.d.ts +7 -14
  199. package/dist/graph/write.js +16 -23
  200. package/dist/graph-extract.d.ts +7 -8
  201. package/dist/graph-extract.js +62 -72
  202. package/dist/graph-recall.d.ts +2 -2
  203. package/dist/graph-recall.js +55 -49
  204. package/dist/graph-stream.d.ts +5 -6
  205. package/dist/graph-stream.js +66 -57
  206. package/dist/graph-view.d.ts +2 -2
  207. package/dist/graph-view.js +7 -7
  208. package/dist/half-life-migration.d.ts +1 -2
  209. package/dist/half-life-migration.js +2 -3
  210. package/dist/hooks/codex-session.js +1 -1
  211. package/dist/hooks/codex-wrapper.d.ts +1 -1
  212. package/dist/hooks/codex-wrapper.js +3 -2
  213. package/dist/hooks/json-hooks.d.ts +2 -2
  214. package/dist/hooks/json-hooks.js +5 -4
  215. package/dist/hooks/opencode.d.ts +1 -1
  216. package/dist/hooks/opencode.js +5 -4
  217. package/dist/hooks/shared.d.ts +3 -7
  218. package/dist/hooks/shared.js +1 -8
  219. package/dist/http-util.d.ts +2 -3
  220. package/dist/http-util.js +3 -0
  221. package/dist/importers/core.d.ts +2 -9
  222. package/dist/importers/core.js +15 -30
  223. package/dist/importers/sources.js +2 -1
  224. package/dist/importers/vault.js +2 -20
  225. package/dist/incidents.d.ts +1 -1
  226. package/dist/incidents.js +46 -39
  227. package/dist/instruction-detect.d.ts +1 -1
  228. package/dist/instruction-detect.js +1 -1
  229. package/dist/invalidation.d.ts +3 -0
  230. package/dist/invalidation.js +160 -114
  231. package/dist/json.d.ts +5 -0
  232. package/dist/json.js +4 -0
  233. package/dist/judgment.js +1 -2
  234. package/dist/local-embedding.js +1 -1
  235. package/dist/mcp/admin-tools.js +7 -17
  236. package/dist/mcp/format.js +1 -1
  237. package/dist/mcp/framing.js +3 -6
  238. package/dist/mcp/protocol.d.ts +2 -5
  239. package/dist/mcp/protocol.js +1 -3
  240. package/dist/mcp/recall-tools.js +12 -15
  241. package/dist/mcp/request.js +4 -3
  242. package/dist/mcp/session-state.js +2 -3
  243. package/dist/mcp/stdio.js +2 -1
  244. package/dist/mcp/tools.js +9 -6
  245. package/dist/memory-value-weights.d.ts +5 -8
  246. package/dist/memory-value-weights.js +5 -8
  247. package/dist/memory-value.d.ts +13 -13
  248. package/dist/memory-value.js +26 -37
  249. package/dist/memory.d.ts +20 -22
  250. package/dist/memory.js +24 -48
  251. package/dist/multihop.d.ts +1 -1
  252. package/dist/multihop.js +3 -2
  253. package/dist/owner-validation.d.ts +4 -5
  254. package/dist/owner-validation.js +4 -5
  255. package/dist/physics.d.ts +4 -4
  256. package/dist/physics.js +7 -9
  257. package/dist/policies.d.ts +9 -10
  258. package/dist/policies.js +96 -81
  259. package/dist/postinstall.js +3 -6
  260. package/dist/predictions/planning-fallacy.d.ts +9 -14
  261. package/dist/predictions/planning-fallacy.js +10 -16
  262. package/dist/predictions/store.d.ts +15 -23
  263. package/dist/predictions/store.js +36 -33
  264. package/dist/processes.d.ts +2 -7
  265. package/dist/processes.js +88 -72
  266. package/dist/project-briefs.d.ts +2 -3
  267. package/dist/project-briefs.js +141 -118
  268. package/dist/project-identity.d.ts +22 -9
  269. package/dist/project-identity.js +47 -12
  270. package/dist/project-merge.d.ts +28 -5
  271. package/dist/project-merge.js +213 -46
  272. package/dist/project-remote.d.ts +12 -0
  273. package/dist/project-remote.js +138 -0
  274. package/dist/prompt-recall.js +1 -2
  275. package/dist/rate-limit.d.ts +1 -1
  276. package/dist/rate-limit.js +1 -1
  277. package/dist/raw-archive.d.ts +9 -0
  278. package/dist/raw-archive.js +70 -53
  279. package/dist/recall-history.d.ts +19 -20
  280. package/dist/recall-history.js +24 -42
  281. package/dist/recall-pipeline.js +4 -28
  282. package/dist/recall-scope.d.ts +7 -8
  283. package/dist/recall-scope.js +7 -8
  284. package/dist/recall-trace.d.ts +5 -9
  285. package/dist/recall-trace.js +6 -10
  286. package/dist/refine-llm.d.ts +1 -1
  287. package/dist/refine-llm.js +2 -2
  288. package/dist/reject-flow.d.ts +3 -4
  289. package/dist/reject-flow.js +122 -117
  290. package/dist/rejection.d.ts +5 -6
  291. package/dist/rejection.js +7 -15
  292. package/dist/rerankers/clef.d.ts +1 -1
  293. package/dist/rerankers/jev.d.ts +1 -2
  294. package/dist/rerankers/jev.js +4 -5
  295. package/dist/rerankers/llm.d.ts +1 -2
  296. package/dist/rerankers/llm.js +1 -2
  297. package/dist/rerankers/types.d.ts +1 -2
  298. package/dist/rrf.d.ts +2 -2
  299. package/dist/rrf.js +2 -2
  300. package/dist/search/bm25-search.d.ts +1 -1
  301. package/dist/search/bm25-search.js +2 -1
  302. package/dist/search/boosts.js +2 -1
  303. package/dist/search/hybrid.d.ts +1 -1
  304. package/dist/search/hybrid.js +2 -1
  305. package/dist/search/physics-search.d.ts +1 -1
  306. package/dist/search/physics-search.js +2 -1
  307. package/dist/search/types.d.ts +2 -0
  308. package/dist/search/types.js +3 -1
  309. package/dist/secret-detect.d.ts +4 -5
  310. package/dist/secret-detect.js +6 -10
  311. package/dist/server/auth.js +5 -5
  312. package/dist/server/client-ip.js +1 -1
  313. package/dist/server/cursor.js +2 -1
  314. package/dist/server/mcp-http.js +4 -4
  315. package/dist/server/request.d.ts +3 -6
  316. package/dist/server/request.js +6 -7
  317. package/dist/server/routes/admin.js +5 -4
  318. package/dist/server/routes/customer-notes.js +6 -5
  319. package/dist/server/routes/decisions.js +4 -3
  320. package/dist/server/routes/incidents.js +7 -5
  321. package/dist/server/routes/memories.js +7 -7
  322. package/dist/server/routes/policies.js +3 -2
  323. package/dist/server/routes/predictions.js +12 -15
  324. package/dist/server/routes/processes.js +3 -2
  325. package/dist/server/routes/project-briefs.js +8 -7
  326. package/dist/server/routes/recall.js +95 -93
  327. package/dist/server/routes/skills.js +6 -5
  328. package/dist/server/types.d.ts +1 -1
  329. package/dist/server/validation.d.ts +1 -2
  330. package/dist/server/validation.js +7 -14
  331. package/dist/server-detect.js +72 -58
  332. package/dist/server.d.ts +2 -2
  333. package/dist/server.js +131 -117
  334. package/dist/shared.d.ts +26 -17
  335. package/dist/shared.js +102 -104
  336. package/dist/skills.d.ts +3 -3
  337. package/dist/skills.js +88 -72
  338. package/dist/store/audit-event.d.ts +2 -2
  339. package/dist/store/audit-event.js +1 -1
  340. package/dist/store/candidates.d.ts +2 -2
  341. package/dist/store/candidates.js +4 -3
  342. package/dist/store/conflicts.js +30 -22
  343. package/dist/store/delete-and-batch.d.ts +11 -14
  344. package/dist/store/delete-and-batch.js +40 -91
  345. package/dist/store/entry-reads.d.ts +17 -25
  346. package/dist/store/entry-reads.js +59 -40
  347. package/dist/store/entry-row.d.ts +6 -24
  348. package/dist/store/entry-row.js +6 -24
  349. package/dist/store/entry-writes.d.ts +6 -7
  350. package/dist/store/entry-writes.js +13 -11
  351. package/dist/store/handoffs.d.ts +1 -1
  352. package/dist/store/handoffs.js +7 -10
  353. package/dist/store/index-and-stats.d.ts +2 -6
  354. package/dist/store/index-and-stats.js +4 -10
  355. package/dist/store/mirrors.d.ts +6 -19
  356. package/dist/store/mirrors.js +14 -39
  357. package/dist/store/open.js +9 -31
  358. package/dist/store/rows.d.ts +5 -11
  359. package/dist/store/rows.js +6 -11
  360. package/dist/store/search-rows.d.ts +17 -34
  361. package/dist/store/search-rows.js +34 -56
  362. package/dist/store/sessions.d.ts +4 -5
  363. package/dist/store/sessions.js +5 -6
  364. package/dist/store/summaries.d.ts +13 -17
  365. package/dist/store/summaries.js +26 -70
  366. package/dist/support-bundle.js +4 -8
  367. package/dist/tenant.d.ts +1 -5
  368. package/dist/token-ledger.d.ts +1 -1
  369. package/dist/token-ledger.js +3 -5
  370. package/dist/trace.js +1 -3
  371. package/dist/version.d.ts +1 -1
  372. package/dist/version.js +1 -1
  373. package/dist/working-memory.d.ts +1 -1
  374. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  375. package/extensions/openclaw-plugin/package.json +1 -1
  376. package/openclaw.plugin.json +1 -1
  377. package/package.json +1 -1
package/dist/physics.d.ts CHANGED
@@ -52,7 +52,7 @@ export declare function computeMass(strength: number, retrievalCount: number): n
52
52
  export declare function computeCharge(valence: EmotionalValence): number;
53
53
  export declare function computeTemperature(ageDays: number, temperatureDecay: number): number;
54
54
  /**
55
- * F1: Query gravity (retrieval-time, virtual — does not update position).
55
+ * Query gravity (retrieval-time, virtual — does not update position).
56
56
  * Returns scalar force magnitude for ranking.
57
57
  *
58
58
  * F_query(i) = G_Q * mass(i) * max(0, cosine(pos_i, query))^2
@@ -64,7 +64,7 @@ export declare function queryGravityMagnitude(particle: PhysicsParticle, queryEm
64
64
  */
65
65
  export declare function velocityAlignmentBonus(particle: PhysicsParticle, queryEmbedding: number[]): number;
66
66
  /**
67
- * F2: Inter-memory attraction force vector (consolidation-time).
67
+ * Inter-memory attraction force vector (consolidation-time).
68
68
  * Attractive force from particle j on particle i.
69
69
  *
70
70
  * F_attract(i,j) = G_M * m_i * m_j * max(0, cosine(i,j))^3 * direction(j→i in embedding space)
@@ -74,7 +74,7 @@ export declare function velocityAlignmentBonus(particle: PhysicsParticle, queryE
74
74
  */
75
75
  export declare function attractionForce(pi: PhysicsParticle, pj: PhysicsParticle, G_memory: number): number[];
76
76
  /**
77
- * F3: Conflict repulsion force vector (consolidation-time).
77
+ * Conflict repulsion force vector (consolidation-time).
78
78
  * Repulsive force pushing i away from j.
79
79
  *
80
80
  * F_repel(i,j) = K_R * m_i * m_j / max(0.01, cosine_distance(i,j))^2
@@ -82,7 +82,7 @@ export declare function attractionForce(pi: PhysicsParticle, pj: PhysicsParticle
82
82
  */
83
83
  export declare function repulsionForce(pi: PhysicsParticle, pj: PhysicsParticle, K_repulsion: number): number[];
84
84
  /**
85
- * F4: Drag force vector (consolidation-time).
85
+ * Drag force vector (consolidation-time).
86
86
  * F_drag(i) = -drag * velocity(i) / max(1, effective_half_life(i))
87
87
  *
88
88
  * effectiveHalfLife should be passed in from the memory's current half_life_days.
package/dist/physics.js CHANGED
@@ -79,11 +79,9 @@ const CHARGE_MAP = {
79
79
  critical: -1.0,
80
80
  };
81
81
  export function computeMass(strength, retrievalCount) {
82
- // EVAL-ONLY ablation (see ablation.ts): under the recall-boost flag, particle
83
- // mass must not scale with retrieval history either - query gravity ranks by
84
- // mass, so prior retrieval counts would leak strengthening into the ablated
85
- // arm's physics-pool rankings (codex P2). Covers both the init and refresh
86
- // callers in physics-state.ts.
82
+ // EVAL-ONLY ablation (see ablation.ts): under the recall-boost flag mass ignores retrieval history, since
83
+ // query gravity ranks by mass and prior counts would leak strengthening into the ablated arm's
84
+ // physics-pool rankings. Covers both the init and refresh callers in physics-state.ts.
87
85
  const effectiveCount = isRecallBoostAblated() ? 0 : retrievalCount;
88
86
  return Math.max(0.01, strength * (1 + 0.1 * Math.log2(effectiveCount + 1)));
89
87
  }
@@ -97,7 +95,7 @@ export function computeTemperature(ageDays, temperatureDecay) {
97
95
  // Force computations
98
96
  // ---------------------------------------------------------------------------
99
97
  /**
100
- * F1: Query gravity (retrieval-time, virtual — does not update position).
98
+ * Query gravity (retrieval-time, virtual — does not update position).
101
99
  * Returns scalar force magnitude for ranking.
102
100
  *
103
101
  * F_query(i) = G_Q * mass(i) * max(0, cosine(pos_i, query))^2
@@ -121,7 +119,7 @@ export function velocityAlignmentBonus(particle, queryEmbedding) {
121
119
  return Math.max(0, alignment);
122
120
  }
123
121
  /**
124
- * F2: Inter-memory attraction force vector (consolidation-time).
122
+ * Inter-memory attraction force vector (consolidation-time).
125
123
  * Attractive force from particle j on particle i.
126
124
  *
127
125
  * F_attract(i,j) = G_M * m_i * m_j * max(0, cosine(i,j))^3 * direction(j→i in embedding space)
@@ -139,7 +137,7 @@ export function attractionForce(pi, pj, G_memory) {
139
137
  return vecScale(direction, magnitude);
140
138
  }
141
139
  /**
142
- * F3: Conflict repulsion force vector (consolidation-time).
140
+ * Conflict repulsion force vector (consolidation-time).
143
141
  * Repulsive force pushing i away from j.
144
142
  *
145
143
  * F_repel(i,j) = K_R * m_i * m_j / max(0.01, cosine_distance(i,j))^2
@@ -154,7 +152,7 @@ export function repulsionForce(pi, pj, K_repulsion) {
154
152
  return vecScale(direction, magnitude);
155
153
  }
156
154
  /**
157
- * F4: Drag force vector (consolidation-time).
155
+ * Drag force vector (consolidation-time).
158
156
  * F_drag(i) = -drag * velocity(i) / max(1, effective_half_life(i))
159
157
  *
160
158
  * effectiveHalfLife should be passed in from the memory's current half_life_days.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * E2 policy first-class object (docs/plans/2026-05-30-e2-policy-object.md).
2
+ * Policy first-class object.
3
3
  *
4
4
  * The "bi-temporal-first" object type: a named rule/statement that is in force
5
5
  * over an EFFECTIVE-TIME range and evolves via supersession. Two time axes:
@@ -30,8 +30,8 @@
30
30
  * loadPoliciesAsOf's asOfDate) is normalized to canonical ISO-8601 datetime
31
31
  * (`toISOString`) at the store boundary BEFORE any persist or compare, so the
32
32
  * fixed-width values sort lexically and the half-open [valid_from, valid_to)
33
- * comparison is correct (plan-eng-critic round-1 CRIT fix: a date-only asOf vs a
34
- * datetime valid_from otherwise made a same-day policy invisible).
33
+ * comparison is correct (a date-only asOf vs a datetime valid_from would
34
+ * otherwise make a same-day policy invisible).
35
35
  *
36
36
  * Dual-write atomicity: `savePolicy` writes the memory + policies row (and, on
37
37
  * supersede, the predecessor's UPDATE) inside writeEntry's SAVEPOINT.
@@ -129,21 +129,20 @@ export declare function loadActivePolicies(hippoRoot: string, tenantId: string,
129
129
  * - `superseded` rows that cover T BUT whose successor was not yet effective at T
130
130
  * (successor.valid_from > asOf) - i.e. an earlier version that was genuinely in
131
131
  * force then. This is the core valid-time correctness: a Jan-Jun policy
132
- * superseded in May is still the answer for `asof March`. (codex review
133
- * 2026-05-30, P2 #2: filtering on status='active' alone dropped historically-
134
- * valid superseded versions, conflating transaction-time with valid-time. The
135
- * successor-aware filter mirrors the existing recall-history.ts asOf pattern.)
132
+ * superseded in May is still the answer for `asof March`. Filtering on
133
+ * status='active' alone would conflate transaction-time with valid-time; the
134
+ * successor-aware filter mirrors the existing recall-history.ts asOf pattern.
136
135
  *
137
136
  * `closed` rows are EXCLUDED: closing is a deliberate transaction-time retirement,
138
137
  * and resurrecting closed policies for a historical valid-time is full
139
138
  * transaction-time-travel (deferred). Returns an ARRAY (overlapping same-name
140
139
  * ranges are allowed in v1). Optionally filtered to one policy_name.
141
140
  *
142
- * Date-only `asOfDate` (e.g. "2026-05-30", no time component) resolves to the END
141
+ * Date-only `asOfDate` (YYYY-MM-DD, no time component) resolves to the END
143
142
  * of that UTC day (23:59:59.999Z), so "as of [day D]" includes a policy that
144
143
  * became effective at any instant during D - this is the read-side fix for the
145
- * common create-then-asof-today workflow, keeping the stored valid_from honest
146
- * (codex review 2026-05-30). A full datetime asOf is used as the precise instant.
144
+ * common create-then-asof-today workflow, keeping the stored valid_from honest.
145
+ * A full datetime asOf is used as the precise instant.
147
146
  */
148
147
  export declare function loadPoliciesAsOf(hippoRoot: string, tenantId: string, asOfDate: string, opts?: {
149
148
  name?: string;
package/dist/policies.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * E2 policy first-class object (docs/plans/2026-05-30-e2-policy-object.md).
2
+ * Policy first-class object.
3
3
  *
4
4
  * The "bi-temporal-first" object type: a named rule/statement that is in force
5
5
  * over an EFFECTIVE-TIME range and evolves via supersession. Two time axes:
@@ -30,8 +30,8 @@
30
30
  * loadPoliciesAsOf's asOfDate) is normalized to canonical ISO-8601 datetime
31
31
  * (`toISOString`) at the store boundary BEFORE any persist or compare, so the
32
32
  * fixed-width values sort lexically and the half-open [valid_from, valid_to)
33
- * comparison is correct (plan-eng-critic round-1 CRIT fix: a date-only asOf vs a
34
- * datetime valid_from otherwise made a same-day policy invisible).
33
+ * comparison is correct (a date-only asOf vs a datetime valid_from would
34
+ * otherwise make a same-day policy invisible).
35
35
  *
36
36
  * Dual-write atomicity: `savePolicy` writes the memory + policies row (and, on
37
37
  * supersede, the predecessor's UPDATE) inside writeEntry's SAVEPOINT.
@@ -111,9 +111,79 @@ function buildPolicyContent(policyName, policyText, validFrom, validTo) {
111
111
  const range = validTo ? `${validFrom} to ${validTo}` : `${validFrom} onward`;
112
112
  return `${policyName}\n\n${policyText}\n\nEffective: ${range}`;
113
113
  }
114
- // ---------------------------------------------------------------------------
115
- // Public API
116
- // ---------------------------------------------------------------------------
114
+ // Preflight the supersede target BEFORE inserting the new row (so the new
115
+ // autoincrement id can never be its own supersede target); read the
116
+ // predecessor version in the same SELECT for server-derived versioning.
117
+ // Mirrors saveProcess / saveDecision.
118
+ function preflightPolicySupersede(db, tenantId, supersedesId) {
119
+ // SAFETY: SELECT projects exactly status, version; .get() returns that
120
+ // shape for the matching row, or undefined when no policy/tenant pair matches.
121
+ const pred = db.prepare(`SELECT status, version FROM policies WHERE id = ? AND tenant_id = ?`).get(supersedesId, tenantId);
122
+ if (!pred) {
123
+ throw new NotFoundError(`savePolicy: policy ${supersedesId} to supersede not found for tenant ${tenantId}`);
124
+ }
125
+ if (pred.status !== 'active') {
126
+ throw new ConflictError(`savePolicy: policy ${supersedesId} is not active (status='${pred.status}'); only active policies can be superseded.`);
127
+ }
128
+ return pred.version + 1;
129
+ }
130
+ function insertPolicyRow(db, memoryId, w, version) {
131
+ const result = db.prepare(`
132
+ INSERT INTO policies(
133
+ memory_id, tenant_id, policy_name, policy_text, valid_from, valid_to,
134
+ version, status, superseded_by, superseded_at, change_summary, closed_at, created_at
135
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, 'active', NULL, NULL, ?, NULL, ?)
136
+ `).run(memoryId, w.tenantId, w.policyName, w.policyText, w.validFrom, w.validTo, version, w.changeSummary, w.now);
137
+ return Number(result.lastInsertRowid ?? 0);
138
+ }
139
+ function supersedePolicyRow(db, w, supersedesId, policyId, version) {
140
+ const sup = db.prepare(`
141
+ UPDATE policies
142
+ SET status = 'superseded', superseded_by = ?, superseded_at = ?
143
+ WHERE id = ? AND tenant_id = ? AND status = 'active' AND id != ?
144
+ `).run(policyId, w.now, supersedesId, w.tenantId, policyId);
145
+ if (sup.changes === 0) {
146
+ throw new ConflictError(`savePolicy: policy ${supersedesId} could not be superseded (no longer active or self-reference).`);
147
+ }
148
+ appendAuditEvent(db, {
149
+ tenantId: w.tenantId,
150
+ actor: w.actor,
151
+ op: 'policy_supersede',
152
+ targetId: String(supersedesId),
153
+ metadata: {
154
+ policy_id: supersedesId,
155
+ superseded_by: policyId,
156
+ new_version: version,
157
+ },
158
+ });
159
+ }
160
+ /** The afterWrite body: preflight, INSERT, supersede, reload, create audit, all in one SAVEPOINT. */
161
+ function writePolicyRow(db, memoryId, w) {
162
+ const version = w.supersedesId !== undefined ? preflightPolicySupersede(db, w.tenantId, w.supersedesId) : 1;
163
+ const policyId = insertPolicyRow(db, memoryId, w, version);
164
+ if (w.supersedesId !== undefined)
165
+ supersedePolicyRow(db, w, w.supersedesId, policyId, version);
166
+ // SAFETY: SELECT ${POLICY_COLS} projects exactly the PolicyRow columns;
167
+ // .get() returns that row, or undefined only if the just-inserted id can't
168
+ // be found.
169
+ const row = db.prepare(`SELECT ${POLICY_COLS} FROM policies WHERE id = ?`)
170
+ .get(policyId);
171
+ if (!row)
172
+ throw new Error('savePolicy: failed to reload saved policy row');
173
+ // GDPR-light metadata: ids + flags only, no policy text.
174
+ appendAuditEvent(db, {
175
+ tenantId: w.tenantId,
176
+ actor: w.actor,
177
+ op: 'policy_create',
178
+ targetId: String(policyId),
179
+ metadata: {
180
+ policy_id: policyId,
181
+ version,
182
+ open_ended: w.validTo === null,
183
+ },
184
+ });
185
+ return row;
186
+ }
117
187
  /**
118
188
  * Create a policy (or a new version that supersedes an existing one). Writes the
119
189
  * memory mirror + the policies row atomically inside writeEntry's SAVEPOINT.
@@ -136,8 +206,7 @@ export function savePolicy(hippoRoot, tenantId, opts, actor = 'cli') {
136
206
  // (a date-only asOf resolves to end-of-day in loadPoliciesAsOf), NOT by
137
207
  // backdating the stored valid_from - backdating to midnight would make an
138
208
  // earlier-same-day as-of wrongly report the policy already in force and would
139
- // hide a superseded predecessor for that earlier time (codex review
140
- // 2026-05-30 round 2). An explicit --from is honored as-is.
209
+ // hide a superseded predecessor for that earlier time. An explicit --from is honored as-is.
141
210
  const { validFrom, validTo } = validatePolicyDates(opts.validFrom, opts.validTo, now);
142
211
  const isSupersede = opts.supersedesPolicyId !== undefined;
143
212
  const changeSummary = isSupersede ? (opts.changeSummary ?? null) : null;
@@ -151,75 +220,22 @@ export function savePolicy(hippoRoot, tenantId, opts, actor = 'cli') {
151
220
  baseHalfLifeDays: objectHalfLifeDays(hippoRoot),
152
221
  tenantId,
153
222
  });
223
+ const w = {
224
+ tenantId,
225
+ actor,
226
+ policyName: opts.policyName,
227
+ policyText: opts.policyText,
228
+ validFrom,
229
+ validTo,
230
+ changeSummary,
231
+ supersedesId: opts.supersedesPolicyId,
232
+ now,
233
+ };
154
234
  let savedRow;
155
235
  writeEntry(hippoRoot, mem, {
156
236
  actor,
157
237
  afterWrite: (db, memoryId) => {
158
- // Preflight the supersede target BEFORE inserting the new row (so the new
159
- // autoincrement id can never be its own supersede target); read the
160
- // predecessor version in the same SELECT for server-derived versioning.
161
- // Mirrors saveProcess / saveDecision (codex P1 2026-05-28).
162
- let version = 1;
163
- if (opts.supersedesPolicyId !== undefined) {
164
- // SAFETY: SELECT projects exactly status, version; .get() returns that
165
- // shape for the matching row, or undefined when no policy/tenant pair matches.
166
- const pred = db.prepare(`SELECT status, version FROM policies WHERE id = ? AND tenant_id = ?`).get(opts.supersedesPolicyId, tenantId);
167
- if (!pred) {
168
- throw new NotFoundError(`savePolicy: policy ${opts.supersedesPolicyId} to supersede not found for tenant ${tenantId}`);
169
- }
170
- if (pred.status !== 'active') {
171
- throw new ConflictError(`savePolicy: policy ${opts.supersedesPolicyId} is not active (status='${pred.status}'); only active policies can be superseded.`);
172
- }
173
- version = pred.version + 1;
174
- }
175
- const result = db.prepare(`
176
- INSERT INTO policies(
177
- memory_id, tenant_id, policy_name, policy_text, valid_from, valid_to,
178
- version, status, superseded_by, superseded_at, change_summary, closed_at, created_at
179
- ) VALUES (?, ?, ?, ?, ?, ?, ?, 'active', NULL, NULL, ?, NULL, ?)
180
- `).run(memoryId, tenantId, opts.policyName, opts.policyText, validFrom, validTo, version, changeSummary, now);
181
- const policyId = Number(result.lastInsertRowid ?? 0);
182
- if (opts.supersedesPolicyId !== undefined) {
183
- const sup = db.prepare(`
184
- UPDATE policies
185
- SET status = 'superseded', superseded_by = ?, superseded_at = ?
186
- WHERE id = ? AND tenant_id = ? AND status = 'active' AND id != ?
187
- `).run(policyId, now, opts.supersedesPolicyId, tenantId, policyId);
188
- if (sup.changes === 0) {
189
- throw new ConflictError(`savePolicy: policy ${opts.supersedesPolicyId} could not be superseded (no longer active or self-reference).`);
190
- }
191
- appendAuditEvent(db, {
192
- tenantId,
193
- actor,
194
- op: 'policy_supersede',
195
- targetId: String(opts.supersedesPolicyId),
196
- metadata: {
197
- policy_id: opts.supersedesPolicyId,
198
- superseded_by: policyId,
199
- new_version: version,
200
- },
201
- });
202
- }
203
- // SAFETY: SELECT ${POLICY_COLS} projects exactly the PolicyRow columns;
204
- // .get() returns that row, or undefined only if the just-inserted id can't
205
- // be found.
206
- const row = db.prepare(`SELECT ${POLICY_COLS} FROM policies WHERE id = ?`)
207
- .get(policyId);
208
- if (!row)
209
- throw new Error('savePolicy: failed to reload saved policy row');
210
- savedRow = row;
211
- // GDPR-light metadata: ids + flags only, no policy text.
212
- appendAuditEvent(db, {
213
- tenantId,
214
- actor,
215
- op: 'policy_create',
216
- targetId: String(policyId),
217
- metadata: {
218
- policy_id: policyId,
219
- version,
220
- open_ended: validTo === null,
221
- },
222
- });
238
+ savedRow = writePolicyRow(db, memoryId, w);
223
239
  },
224
240
  afterCommit: () => markGraphDirty(hippoRoot, tenantId, mem.id),
225
241
  });
@@ -273,7 +289,7 @@ export function closePolicy(hippoRoot, tenantId, id, actor = 'cli') {
273
289
  // Closing removes the object from the graph. Remove its rows DIRECTLY (deterministic),
274
290
  // not only via an enqueued rebuild whose queue item is lost if the mirror is later
275
291
  // forgotten (the queue row cascade-deletes with the memory), which would leave the closed
276
- // object stale and could block that forget (codex P1). Still enqueue when a mirror exists
292
+ // object stale and could block that forget. Still enqueue when a mirror exists
277
293
  // so a concurrent rebuild re-derives consistently (harmless if it also runs).
278
294
  removeGraphEntitiesForObject(hippoRoot, tenantId, 'policy', closed.id);
279
295
  if (closed.memoryId) {
@@ -359,21 +375,20 @@ export function loadActivePolicies(hippoRoot, tenantId, opts = {}) {
359
375
  * - `superseded` rows that cover T BUT whose successor was not yet effective at T
360
376
  * (successor.valid_from > asOf) - i.e. an earlier version that was genuinely in
361
377
  * force then. This is the core valid-time correctness: a Jan-Jun policy
362
- * superseded in May is still the answer for `asof March`. (codex review
363
- * 2026-05-30, P2 #2: filtering on status='active' alone dropped historically-
364
- * valid superseded versions, conflating transaction-time with valid-time. The
365
- * successor-aware filter mirrors the existing recall-history.ts asOf pattern.)
378
+ * superseded in May is still the answer for `asof March`. Filtering on
379
+ * status='active' alone would conflate transaction-time with valid-time; the
380
+ * successor-aware filter mirrors the existing recall-history.ts asOf pattern.
366
381
  *
367
382
  * `closed` rows are EXCLUDED: closing is a deliberate transaction-time retirement,
368
383
  * and resurrecting closed policies for a historical valid-time is full
369
384
  * transaction-time-travel (deferred). Returns an ARRAY (overlapping same-name
370
385
  * ranges are allowed in v1). Optionally filtered to one policy_name.
371
386
  *
372
- * Date-only `asOfDate` (e.g. "2026-05-30", no time component) resolves to the END
387
+ * Date-only `asOfDate` (YYYY-MM-DD, no time component) resolves to the END
373
388
  * of that UTC day (23:59:59.999Z), so "as of [day D]" includes a policy that
374
389
  * became effective at any instant during D - this is the read-side fix for the
375
- * common create-then-asof-today workflow, keeping the stored valid_from honest
376
- * (codex review 2026-05-30). A full datetime asOf is used as the precise instant.
390
+ * common create-then-asof-today workflow, keeping the stored valid_from honest.
391
+ * A full datetime asOf is used as the precise instant.
377
392
  */
378
393
  export function loadPoliciesAsOf(hippoRoot, tenantId, asOfDate, opts = {}) {
379
394
  assertTenantId('loadPoliciesAsOf', tenantId);
@@ -7,12 +7,9 @@ function main() {
7
7
  if (envSkipPostinstall())
8
8
  return;
9
9
  try {
10
- // Repair-only: re-ensure the wrapper for users who previously opted in
11
- // (e.g. a Codex update restored the real binary over our shim). A first
12
- // install never happens here — swapping the codex binary from a package
13
- // postinstall is a consent violation and reads as binary hijacking to
14
- // supply-chain scanners (issue #133). First install is `hippo hook
15
- // install codex` only.
10
+ // Repair-only, for users who opted in (a Codex update can restore the real binary over our shim).
11
+ // Swapping the binary from postinstall is a consent violation that supply-chain scanners read as
12
+ // hijacking, so first install is `hippo hook install codex` only.
16
13
  repairCodexWrapperIfInstalled();
17
14
  }
18
15
  catch {
@@ -1,13 +1,11 @@
1
1
  /**
2
- * J3.2 surface delivered on `RecallResult.planningFallacyHint` when an
2
+ * Surface delivered on `RecallResult.planningFallacyHint` when an
3
3
  * agent's recall query carries a forward-prediction phrase AND the closest
4
4
  * matching prediction class has closed historical data.
5
5
  *
6
6
  * The agent sees its track record at the moment of forecasting, anchoring
7
7
  * on the outside view (Lovallo-Kahneman 2003) rather than the inside-view
8
8
  * inside the planning fallacy.
9
- *
10
- * Plan: docs/plans/2026-05-26-j32-auto-injection.md.
11
9
  */
12
10
  export interface PlanningFallacyHint {
13
11
  classTag: string;
@@ -25,13 +23,11 @@ export interface PlanningFallacyHint {
25
23
  meanRatio: number | null;
26
24
  }
27
25
  /**
28
- * v1.13.4 / J3.2 follow-up — "watching" variant emitted when the
29
- * forward-claim regex matched but no PlanningFallacyHint baserate was
30
- * returned. Dogfood diary (docs/dogfood/2026-05-27-track-j-warnings.md)
31
- * Trial 2a confirmed the pre-v1.13.4 silent paths were the most common
32
- * real-world J3.2 failure mode: a natural-language query carries a
26
+ * "Watching" variant emitted when the forward-claim regex matched but no
27
+ * PlanningFallacyHint baserate was returned. Silence was the most common
28
+ * real-world failure: a natural-language query carries a
33
29
  * forward-claim phrase but its non-stopword tokens don't overlap with
34
- * any prediction class tag, so hippo silently emitted nothing despite
30
+ * any prediction class tag, so hippo emitted nothing despite
35
31
  * the regex match. The watching variant surfaces the detection event
36
32
  * + a one-line suggestion so the agent can either re-tag the prediction
37
33
  * or pass the suggestion through to the user.
@@ -48,7 +44,7 @@ export interface PlanningFallacyWatching {
48
44
  suggestion: string;
49
45
  }
50
46
  /**
51
- * v1.13.4 / J3.2 follow-up — richer return type for
47
+ * Richer return type for
52
48
  * `computePlanningFallacyOutput`. Carries EITHER `hint` (baserate
53
49
  * available) OR `watching` (regex fired, no baserate), or NEITHER (mode=off,
54
50
  * no queryText, no regex match, or nClosed=0 silent path). Never both.
@@ -71,7 +67,7 @@ export interface ComputePlanningFallacyHintOpts {
71
67
  actor?: string;
72
68
  }
73
69
  /**
74
- * J3.2 orchestrator.
70
+ * Planning-fallacy orchestrator.
75
71
  *
76
72
  * Composes the forward-claim detector + class resolver + baserate compute,
77
73
  * with telemetry-grade audit emission at every decision point (success,
@@ -83,7 +79,7 @@ export interface ComputePlanningFallacyHintOpts {
83
79
  * - no forward-claim regex match
84
80
  * - resolved class has nClosed=0 (no historical data yet; silent)
85
81
  *
86
- * Returns `{ watching: ... }` on (v1.13.4 NEW — was silent null pre-1.13.4):
82
+ * Returns `{ watching: ... }` on:
87
83
  * - resolver returns no class (no overlap ≥ 1; emits no_class_match audit)
88
84
  * - resolver returns tiebreak (≥2 classes tied at best; emits tiebreak audit)
89
85
  *
@@ -93,8 +89,7 @@ export interface ComputePlanningFallacyHintOpts {
93
89
  * audit carries n_closed + mean_ratio in metadata so no telemetry is lost),
94
90
  * then emits recall_autodebias_hint audit + returns the hint.
95
91
  *
96
- * Latency budget (plan §Latency): ~50us regex-only on miss; ~750-850us
97
- * on full match+resolve+baserate path. Well under 50ms target.
92
+ * Latency budget: well under 50ms; a miss pays only the regex.
98
93
  */
99
94
  export declare function computePlanningFallacyOutput(hippoRoot: string, tenantId: string, queryText: string, opts?: ComputePlanningFallacyHintOpts): PlanningFallacyOutput;
100
95
  //# sourceMappingURL=planning-fallacy.d.ts.map
@@ -11,8 +11,8 @@ import { computePredictionBaserate } from './store.js';
11
11
  * Indexed via idx_predictions_tenant_class (db.ts:1015) → O(log n) seek
12
12
  * plus a small DISTINCT scan over the per-tenant class-tag set.
13
13
  *
14
- * Scope behaviour (v1 design choice, independent-review-critic round 1
15
- * MED): class_tag selection is TENANT-GLOBAL, NOT scope-filtered against
14
+ * Scope behaviour (deliberate): class_tag selection is TENANT-GLOBAL,
15
+ * NOT scope-filtered against
16
16
  * the recall's opts.scope. The class_tag is an aggregator label across
17
17
  * historical predictions in the class, not a per-memory scope-bound
18
18
  * property. A no-scope recall CAN surface a class_tag from a privately-
@@ -75,7 +75,7 @@ function resolveClassFromTokens(hippoRoot, tenantId, queryTokens) {
75
75
  }
76
76
  }
77
77
  /**
78
- * J3.2 orchestrator.
78
+ * Planning-fallacy orchestrator.
79
79
  *
80
80
  * Composes the forward-claim detector + class resolver + baserate compute,
81
81
  * with telemetry-grade audit emission at every decision point (success,
@@ -87,7 +87,7 @@ function resolveClassFromTokens(hippoRoot, tenantId, queryTokens) {
87
87
  * - no forward-claim regex match
88
88
  * - resolved class has nClosed=0 (no historical data yet; silent)
89
89
  *
90
- * Returns `{ watching: ... }` on (v1.13.4 NEW — was silent null pre-1.13.4):
90
+ * Returns `{ watching: ... }` on:
91
91
  * - resolver returns no class (no overlap ≥ 1; emits no_class_match audit)
92
92
  * - resolver returns tiebreak (≥2 classes tied at best; emits tiebreak audit)
93
93
  *
@@ -97,8 +97,7 @@ function resolveClassFromTokens(hippoRoot, tenantId, queryTokens) {
97
97
  * audit carries n_closed + mean_ratio in metadata so no telemetry is lost),
98
98
  * then emits recall_autodebias_hint audit + returns the hint.
99
99
  *
100
- * Latency budget (plan §Latency): ~50us regex-only on miss; ~750-850us
101
- * on full match+resolve+baserate path. Well under 50ms target.
100
+ * Latency budget: well under 50ms; a miss pays only the regex.
102
101
  */
103
102
  export function computePlanningFallacyOutput(hippoRoot, tenantId, queryText, opts = {}) {
104
103
  // Env read FIRST so AUTODEBIAS=off pays zero regex cost. Per-call read
@@ -115,19 +114,14 @@ export function computePlanningFallacyOutput(hippoRoot, tenantId, queryText, opt
115
114
  const actor = opts.actor ?? 'recall';
116
115
  const resolution = resolveClassFromTokens(hippoRoot, tenantId, match.classQueryTokens);
117
116
  if (resolution.tiebreak) {
118
- // Telemetry: forward-claim detected, ≥2 classes tied at best overlap.
119
- // v1.13.4: now ALSO returns a watching variant so the caller surface
120
- // can render a "watching but no baserate (tiebreak)" line. Audit emission
121
- // unchanged (the audit channel is the telemetry-grade source of truth).
117
+ // Telemetry: forward-claim detected, ≥2 classes tied at best overlap. The watching variant lets the
118
+ // caller render "watching but no baserate (tiebreak)"; the audit channel stays the source of truth.
122
119
  return watchingWithAudit(hippoRoot, tenantId, actor, match, 'tiebreak', TIEBREAK_SUGGESTION);
123
120
  }
124
121
  if (!resolution.classTag) {
125
- // Telemetry: forward-claim detected, no class scored ≥ 1.
126
- // This is the channel that drives the embedding-fallback decision
127
- // for J3.3 — high volume here = regex+token-overlap is missing
128
- // legitimate forward-claims that have NO obvious class signal.
129
- // v1.13.4: now ALSO returns a watching variant so the caller surface
130
- // can render a "watching but no baserate (no class match)" line.
122
+ // Telemetry: forward-claim detected, no class scored ≥ 1. High volume here means regex+token-overlap
123
+ // misses real forward-claims with no class signal, the case for an embedding fallback.
124
+ // The watching variant lets the caller render "watching but no baserate (no class match)".
131
125
  return watchingWithAudit(hippoRoot, tenantId, actor, match, 'no_class_match', NO_CLASS_MATCH_SUGGESTION);
132
126
  }
133
127
  // emitAudit=false: avoid double-write to predict_baserate channel.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * E2 prediction first-class object (v0.31 / docs/plans/2026-05-26-e2-prediction-object.md).
2
+ * Prediction first-class object.
3
3
  *
4
4
  * Canonical store for ex-ante claims that can be closed against ex-post
5
5
  * outcomes. The `predictions` table holds every field (including
@@ -19,10 +19,8 @@
19
19
  * a failure in either step rolls back both. Pattern matches supersede
20
20
  * (api.ts:1486) and the Slack/GitHub connectors.
21
21
  *
22
- * J3 (reference-class / planning-fallacy detector) reads from
23
- * `loadPredictionsByClass` to compute per-class base rates from
24
- * (estimate_value, actual_value) at query time. J3 is a follow-up episode;
25
- * this module ships the data layer.
22
+ * The planning-fallacy detector reads `loadPredictionsByClass` and computes
23
+ * per-class base rates from (estimate_value, actual_value) at query time.
26
24
  */
27
25
  import { type KeysetPosition } from '../keyset.js';
28
26
  export type ClosureState = 'open' | 'closed' | 'closed-unknown';
@@ -71,18 +69,22 @@ export interface ListPredictionsOpts {
71
69
  * The memory is tagged `['prediction', classTag]` with `source='prediction'`
72
70
  * and `kind='distilled'`. It surfaces in `hippo recall` so the agent can
73
71
  * see open predictions naturally; the predictions table is the canonical
74
- * structured store used by J3.
72
+ * structured store used by the planning-fallacy detector.
75
73
  */
76
74
  export declare function savePrediction(hippoRoot: string, tenantId: string, opts: SavePredictionOpts, actor?: string): Prediction;
77
75
  /**
78
76
  * Close an existing open prediction. Updates the predictions row only;
79
77
  * the memory mirror is NOT mutated in v1 (predictions table is canonical).
80
- * J3 computes accuracy (clean vs regressed) from (estimateValue,
81
- * actualValue) at query time.
78
+ * Accuracy is computed from (estimateValue, actualValue) at query time.
82
79
  */
83
80
  export declare function closePrediction(hippoRoot: string, tenantId: string, id: number, opts: ClosePredictionOpts, actor?: string): Prediction;
84
81
  export declare function loadPredictionById(hippoRoot: string, tenantId: string, id: number): Prediction | null;
85
82
  export declare function loadPredictionsByClass(hippoRoot: string, tenantId: string, classTag: string, opts?: ListPredictionsOpts): Prediction[];
83
+ /** Every prediction in the tenant, open and closed, across all classes: the `status=all` list without a class. */
84
+ export declare function loadAllPredictions(hippoRoot: string, tenantId: string, opts?: {
85
+ limit?: number;
86
+ after?: KeysetPosition;
87
+ }): Prediction[];
86
88
  export interface PredictionBaserate {
87
89
  classTag: string;
88
90
  /** Count of closed predictions with a numeric actual_value (excludes
@@ -105,28 +107,18 @@ export interface PredictionBaserate {
105
107
  summary: string;
106
108
  }
107
109
  /**
108
- * Compute base-rate stats for closed predictions in a class. Used by J3
109
- * reference-class / planning-fallacy detector. Direct application of
110
- * Lovallo-Kahneman (2003) inside-vs-outside view.
110
+ * Compute base-rate stats for closed predictions in a class for the
111
+ * planning-fallacy detector: Lovallo-Kahneman (2003) inside-vs-outside view.
111
112
  *
112
113
  * Filter: closure_state='closed' AND estimate_value IS NOT NULL AND
113
114
  * actual_value IS NOT NULL. Excludes closed-unknown (no actual to
114
115
  * compare against) and open (not yet resolved).
115
116
  *
116
- * Audit-emit is BUILT IN here (single source of truth, no caller-site
117
- * drift risk). Plan-eng-critic round 1 HIGH recommendation: emit inside
118
- * helper, not at 3 call sites.
117
+ * Audit-emit is built in here, not at the 3 call sites, so callers cannot drift.
119
118
  */
120
119
  export declare function computePredictionBaserate(hippoRoot: string, tenantId: string, classTag: string, actor?: string,
121
- /** v0.32 / J3.2 — when false, skip the predict_baserate audit emit. The
122
- * J3.2 orchestrator (computePlanningFallacyOutput, below) calls this with
123
- * emitAudit=false and emits its own `recall_autodebias_hint` audit row
124
- * instead, so the predict_baserate channel stays scoped to deliberate
125
- * CLI / HTTP / MCP predict-baserate calls and does NOT pollute on every
126
- * recall containing a forward-claim phrase. Default true preserves the
127
- * v1.13.0 J3 audit semantics for the 3 direct callers (cmdPredict
128
- * baserate, /v1/predictions/stats route, hippo_predict_baserate MCP
129
- * handler) — none of them pass this argument. */
120
+ /** False skips the predict_baserate audit so that channel only records deliberate
121
+ * baserate calls, not every recall the planning-fallacy orchestrator inspects. */
130
122
  emitAudit?: boolean): PredictionBaserate;
131
123
  export declare function loadOpenPredictions(hippoRoot: string, tenantId: string, opts?: {
132
124
  classTag?: string;