@remnic/core 1.1.12 → 1.1.13

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 (1324) hide show
  1. package/dist/access-cli.d.ts +2 -1
  2. package/dist/access-cli.js +263 -82
  3. package/dist/access-cli.js.map +1 -1
  4. package/dist/access-http.d.ts +26 -60
  5. package/dist/access-http.js +43 -29
  6. package/dist/access-mcp.d.ts +24 -6
  7. package/dist/access-mcp.js +35 -28
  8. package/dist/access-schema.d.ts +9 -6
  9. package/dist/access-schema.js +7 -5
  10. package/dist/access-service-DcCDmNYC.d.ts +1542 -0
  11. package/dist/access-service.d.ts +25 -7
  12. package/dist/access-service.js +33 -26
  13. package/dist/active-memory-bridge.js +2 -2
  14. package/dist/active-recall.js +11 -3
  15. package/dist/active-recall.js.map +1 -1
  16. package/dist/adapters/claude-code.d.ts +24 -0
  17. package/dist/adapters/claude-code.js +9 -0
  18. package/dist/adapters/codex.d.ts +25 -0
  19. package/dist/adapters/codex.js +9 -0
  20. package/dist/adapters/hermes.d.ts +35 -0
  21. package/dist/adapters/hermes.js +9 -0
  22. package/dist/adapters/index.d.ts +6 -0
  23. package/dist/adapters/index.js +26 -0
  24. package/dist/adapters/registry.d.ts +20 -0
  25. package/dist/adapters/registry.js +13 -0
  26. package/dist/adapters/replit.d.ts +28 -0
  27. package/dist/adapters/replit.js +9 -0
  28. package/dist/adapters/types.d.ts +43 -0
  29. package/dist/adapters/types.js +8 -0
  30. package/dist/bootstrap.d.ts +20 -5
  31. package/dist/boxes.d.ts +7 -0
  32. package/dist/boxes.js +1 -1
  33. package/dist/briefing.d.ts +5 -3
  34. package/dist/briefing.js +9 -6
  35. package/dist/buffer-surprise-report.js +1 -1
  36. package/dist/buffer.d.ts +18 -4
  37. package/dist/buffer.js +1 -1
  38. package/dist/calibration.js +4 -4
  39. package/dist/capsule-cli.d.ts +4 -4
  40. package/dist/capsule-cli.js +1 -1
  41. package/dist/capsule-crypto-5CYAGVC5.js +18 -0
  42. package/dist/capsule-merge-4MGKE7C5.js +189 -0
  43. package/dist/causal-behavior.d.ts +8 -28
  44. package/dist/causal-behavior.js +6 -3
  45. package/dist/causal-behavior.js.map +1 -1
  46. package/dist/causal-chain.js +3 -2
  47. package/dist/causal-consolidation.d.ts +1 -1
  48. package/dist/causal-consolidation.js +24 -13
  49. package/dist/causal-consolidation.js.map +1 -1
  50. package/dist/causal-retrieval.js +3 -3
  51. package/dist/causal-trajectory.js +1 -1
  52. package/dist/chunk-25MQ7IHJ.js +427 -0
  53. package/dist/chunk-25MQ7IHJ.js.map +1 -0
  54. package/dist/chunk-2F2W355T.js +256 -0
  55. package/dist/chunk-2F2W355T.js.map +1 -0
  56. package/dist/chunk-2KI4QFHU.js +228 -0
  57. package/dist/chunk-2KI4QFHU.js.map +1 -0
  58. package/dist/chunk-2PRQG7PV.js +86 -0
  59. package/dist/chunk-2PRQG7PV.js.map +1 -0
  60. package/dist/chunk-2QR3XXIC.js +2272 -0
  61. package/dist/chunk-2QR3XXIC.js.map +1 -0
  62. package/dist/chunk-2WWLHTZY.js +121 -0
  63. package/dist/chunk-326G7DJK.js +2185 -0
  64. package/dist/chunk-326G7DJK.js.map +1 -0
  65. package/dist/chunk-34DQE4KF.js +174 -0
  66. package/dist/chunk-34DQE4KF.js.map +1 -0
  67. package/dist/chunk-3APJ5EVB.js +601 -0
  68. package/dist/chunk-3APJ5EVB.js.map +1 -0
  69. package/dist/chunk-3HPAPHUK.js +51 -0
  70. package/dist/chunk-3HPAPHUK.js.map +1 -0
  71. package/dist/chunk-3JXBXXM2.js +69 -0
  72. package/dist/chunk-3JXBXXM2.js.map +1 -0
  73. package/dist/chunk-3KW65B36.js +681 -0
  74. package/dist/chunk-3KW65B36.js.map +1 -0
  75. package/dist/chunk-3UXOZBHV.js +20 -0
  76. package/dist/chunk-3UXOZBHV.js.map +1 -0
  77. package/dist/chunk-3VAL7ZL2.js +266 -0
  78. package/dist/chunk-3VAL7ZL2.js.map +1 -0
  79. package/dist/chunk-3Y4P7RXM.js +31 -0
  80. package/dist/chunk-3Y4P7RXM.js.map +1 -0
  81. package/dist/chunk-47VWKCAF.js +273 -0
  82. package/dist/chunk-47VWKCAF.js.map +1 -0
  83. package/dist/chunk-4CRG46BG.js +271 -0
  84. package/dist/chunk-5375UYTQ.js +914 -0
  85. package/dist/chunk-5375UYTQ.js.map +1 -0
  86. package/dist/chunk-56K5QLHX.js +506 -0
  87. package/dist/chunk-56K5QLHX.js.map +1 -0
  88. package/dist/chunk-5RGLBDQF.js +596 -0
  89. package/dist/chunk-5RGLBDQF.js.map +1 -0
  90. package/dist/chunk-5UZXUTVO.js +9 -0
  91. package/dist/chunk-5UZXUTVO.js.map +1 -0
  92. package/dist/chunk-65PG43EQ.js +105 -0
  93. package/dist/chunk-65PG43EQ.js.map +1 -0
  94. package/dist/chunk-66DHUKLO.js +57 -0
  95. package/dist/chunk-66DHUKLO.js.map +1 -0
  96. package/dist/chunk-6FC5EGNV.js +46 -0
  97. package/dist/chunk-6FC5EGNV.js.map +1 -0
  98. package/dist/chunk-6H2TESSP.js +62 -0
  99. package/dist/chunk-6H2TESSP.js.map +1 -0
  100. package/dist/chunk-6LVVDPJ4.js +32 -0
  101. package/dist/chunk-6LVVDPJ4.js.map +1 -0
  102. package/dist/chunk-6RVI47ZR.js +159 -0
  103. package/dist/chunk-6RVI47ZR.js.map +1 -0
  104. package/dist/chunk-7AAT6G4Q.js +5117 -0
  105. package/dist/chunk-7AAT6G4Q.js.map +1 -0
  106. package/dist/chunk-7DTASS5T.js +29 -0
  107. package/dist/chunk-7DTASS5T.js.map +1 -0
  108. package/dist/chunk-7IASACLB.js +596 -0
  109. package/dist/chunk-7MNMYOFP.js +32 -0
  110. package/dist/chunk-7MNMYOFP.js.map +1 -0
  111. package/dist/chunk-7N4KAIGN.js +133 -0
  112. package/dist/chunk-7N4KAIGN.js.map +1 -0
  113. package/dist/chunk-7OZ53EXP.js +101 -0
  114. package/dist/chunk-7OZ53EXP.js.map +1 -0
  115. package/dist/chunk-7XYTQGCC.js +134 -0
  116. package/dist/chunk-7XYTQGCC.js.map +1 -0
  117. package/dist/chunk-A2XUIMJ3.js +341 -0
  118. package/dist/chunk-A2XUIMJ3.js.map +1 -0
  119. package/dist/chunk-AGZQD76C.js +201 -0
  120. package/dist/chunk-AGZQD76C.js.map +1 -0
  121. package/dist/chunk-APO3DCMU.js +361 -0
  122. package/dist/chunk-APO3DCMU.js.map +1 -0
  123. package/dist/chunk-BFBF3XEF.js +283 -0
  124. package/dist/chunk-BFBF3XEF.js.map +1 -0
  125. package/dist/chunk-BJ3KMYTB.js +1974 -0
  126. package/dist/chunk-BJ3KMYTB.js.map +1 -0
  127. package/dist/chunk-CHEL3SKB.js +6758 -0
  128. package/dist/chunk-CHEL3SKB.js.map +1 -0
  129. package/dist/chunk-CQZRLNMV.js +1491 -0
  130. package/dist/chunk-CQZRLNMV.js.map +1 -0
  131. package/dist/chunk-D46YSIYX.js +892 -0
  132. package/dist/chunk-D46YSIYX.js.map +1 -0
  133. package/dist/chunk-DINWEURR.js +648 -0
  134. package/dist/chunk-DINWEURR.js.map +1 -0
  135. package/dist/chunk-DK5LDEQM.js +530 -0
  136. package/dist/chunk-DK5LDEQM.js.map +1 -0
  137. package/dist/chunk-DOM4GKSW.js +34 -0
  138. package/dist/chunk-DOM4GKSW.js.map +1 -0
  139. package/dist/chunk-EDTHC6UD.js +1075 -0
  140. package/dist/chunk-EFJ3MQ4V.js +721 -0
  141. package/dist/chunk-EHRTFRWW.js +89 -0
  142. package/dist/chunk-EHRTFRWW.js.map +1 -0
  143. package/dist/chunk-FAJ7FZYM.js +11 -0
  144. package/dist/chunk-FAJ7FZYM.js.map +1 -0
  145. package/dist/chunk-FBYESMQ2.js +570 -0
  146. package/dist/chunk-FDU6HUUL.js +147 -0
  147. package/dist/chunk-FF4KLI5W.js +99 -0
  148. package/dist/chunk-FF4KLI5W.js.map +1 -0
  149. package/dist/chunk-FIT6DMX6.js +310 -0
  150. package/dist/chunk-FIT6DMX6.js.map +1 -0
  151. package/dist/chunk-FJ43PRLT.js +272 -0
  152. package/dist/chunk-FJ43PRLT.js.map +1 -0
  153. package/dist/chunk-FKFMOY3N.js +32 -0
  154. package/dist/chunk-FKFMOY3N.js.map +1 -0
  155. package/dist/chunk-FLTNHQK6.js +262 -0
  156. package/dist/chunk-FLTNHQK6.js.map +1 -0
  157. package/dist/chunk-GA454ALV.js +12436 -0
  158. package/dist/chunk-GA454ALV.js.map +1 -0
  159. package/dist/chunk-GGKRUQOO.js +228 -0
  160. package/dist/chunk-GIF42EW3.js +63 -0
  161. package/dist/chunk-GIF42EW3.js.map +1 -0
  162. package/dist/chunk-GL6I6MEQ.js +647 -0
  163. package/dist/chunk-H3ME6L6D.js +709 -0
  164. package/dist/chunk-H3ME6L6D.js.map +1 -0
  165. package/dist/chunk-HHLLAQGZ.js +1 -0
  166. package/dist/chunk-HXXBL2KD.js +2040 -0
  167. package/dist/chunk-I5V2VDIW.js +219 -0
  168. package/dist/chunk-I5V2VDIW.js.map +1 -0
  169. package/dist/chunk-I6K5FBRQ.js +35 -0
  170. package/dist/chunk-I6K5FBRQ.js.map +1 -0
  171. package/dist/chunk-ICRIXAP2.js +121 -0
  172. package/dist/chunk-ICRIXAP2.js.map +1 -0
  173. package/dist/chunk-J4EB7DNW.js +11 -0
  174. package/dist/chunk-J4EB7DNW.js.map +1 -0
  175. package/dist/chunk-JLFA7DQG.js +62 -0
  176. package/dist/chunk-JLFA7DQG.js.map +1 -0
  177. package/dist/chunk-KJTKLXTH.js +9 -0
  178. package/dist/chunk-KJTKLXTH.js.map +1 -0
  179. package/dist/chunk-KLAO5DGL.js +917 -0
  180. package/dist/chunk-KLAO5DGL.js.map +1 -0
  181. package/dist/chunk-KNKUID7G.js +183 -0
  182. package/dist/chunk-KOSORCJG.js +624 -0
  183. package/dist/chunk-KOSORCJG.js.map +1 -0
  184. package/dist/chunk-KUJVMMZQ.js +1262 -0
  185. package/dist/chunk-KUJVMMZQ.js.map +1 -0
  186. package/dist/chunk-LCR46JY5.js +123 -0
  187. package/dist/chunk-LCR46JY5.js.map +1 -0
  188. package/dist/chunk-LLQ2LLWF.js +148 -0
  189. package/dist/chunk-LLQ2LLWF.js.map +1 -0
  190. package/dist/chunk-LPMVBPA3.js +236 -0
  191. package/dist/chunk-LT3NLYSI.js +50 -0
  192. package/dist/chunk-LT3NLYSI.js.map +1 -0
  193. package/dist/chunk-LUDTDZLK.js +287 -0
  194. package/dist/chunk-LUDTDZLK.js.map +1 -0
  195. package/dist/chunk-M23FSH32.js +3963 -0
  196. package/dist/chunk-M23FSH32.js.map +1 -0
  197. package/dist/chunk-MC26UJIM.js +118 -0
  198. package/dist/chunk-ME6ESPZU.js +119 -0
  199. package/dist/chunk-ME6ESPZU.js.map +1 -0
  200. package/dist/chunk-MGKYQQYF.js +272 -0
  201. package/dist/chunk-MJFNCJXV.js +66 -0
  202. package/dist/chunk-MJFNCJXV.js.map +1 -0
  203. package/dist/chunk-MSWG7JI6.js +237 -0
  204. package/dist/chunk-MSWG7JI6.js.map +1 -0
  205. package/dist/chunk-MT25YHYH.js +141 -0
  206. package/dist/chunk-MT25YHYH.js.map +1 -0
  207. package/dist/chunk-MT4HVDUZ.js +53 -0
  208. package/dist/chunk-MY6TPVXW.js +219 -0
  209. package/dist/chunk-N2D6GXBM.js +267 -0
  210. package/dist/chunk-N2D6GXBM.js.map +1 -0
  211. package/dist/chunk-NJ3MJQZX.js +46 -0
  212. package/dist/chunk-NJ3MJQZX.js.map +1 -0
  213. package/dist/chunk-NMZY542O.js +335 -0
  214. package/dist/chunk-NMZY542O.js.map +1 -0
  215. package/dist/chunk-NNVTUXEB.js +23 -0
  216. package/dist/chunk-NZL6GGQE.js +375 -0
  217. package/dist/chunk-NZL6GGQE.js.map +1 -0
  218. package/dist/chunk-P4NEIHUT.js +108 -0
  219. package/dist/chunk-P7FMDTKL.js +103 -0
  220. package/dist/chunk-P7FMDTKL.js.map +1 -0
  221. package/dist/chunk-PHK3HARR.js +32 -0
  222. package/dist/chunk-PHK3HARR.js.map +1 -0
  223. package/dist/chunk-PIRJPV5T.js +98 -0
  224. package/dist/chunk-PIRJPV5T.js.map +1 -0
  225. package/dist/chunk-PK7H5L6Y.js +159 -0
  226. package/dist/chunk-PK7H5L6Y.js.map +1 -0
  227. package/dist/chunk-PR5FBTFU.js +233 -0
  228. package/dist/chunk-PR5FBTFU.js.map +1 -0
  229. package/dist/chunk-PU63GXWS.js +174 -0
  230. package/dist/chunk-PU63GXWS.js.map +1 -0
  231. package/dist/chunk-PZIAX57I.js +124 -0
  232. package/dist/chunk-PZIAX57I.js.map +1 -0
  233. package/dist/chunk-Q7P4WJDP.js +26 -0
  234. package/dist/chunk-Q7P4WJDP.js.map +1 -0
  235. package/dist/chunk-QQUAB63I.js +63 -0
  236. package/dist/chunk-QQUAB63I.js.map +1 -0
  237. package/dist/chunk-QRNI5JBH.js +18 -0
  238. package/dist/chunk-RHY3HH7P.js +601 -0
  239. package/dist/chunk-RHY3HH7P.js.map +1 -0
  240. package/dist/chunk-RRF5UOBJ.js +91 -0
  241. package/dist/chunk-RXDLTSWT.js +124 -0
  242. package/dist/chunk-RXDLTSWT.js.map +1 -0
  243. package/dist/chunk-RYED3SPJ.js +42 -0
  244. package/dist/chunk-RYED3SPJ.js.map +1 -0
  245. package/dist/chunk-S7KDBTWT.js +106 -0
  246. package/dist/chunk-S7KDBTWT.js.map +1 -0
  247. package/dist/chunk-SEDEKFYQ.js +1 -0
  248. package/dist/chunk-TECVW3JP.js +36 -0
  249. package/dist/chunk-TECVW3JP.js.map +1 -0
  250. package/dist/chunk-TFO23QT4.js +88 -0
  251. package/dist/chunk-TFO23QT4.js.map +1 -0
  252. package/dist/chunk-TK4UEOSK.js +76 -0
  253. package/dist/chunk-TK4UEOSK.js.map +1 -0
  254. package/dist/chunk-TKWGAOLV.js +122 -0
  255. package/dist/chunk-TKWGAOLV.js.map +1 -0
  256. package/dist/chunk-TMM4S4IJ.js +597 -0
  257. package/dist/chunk-TMM4S4IJ.js.map +1 -0
  258. package/dist/chunk-TMQLARTH.js +188 -0
  259. package/dist/chunk-TMQLARTH.js.map +1 -0
  260. package/dist/chunk-TPDBFYEG.js +130 -0
  261. package/dist/chunk-TPDBFYEG.js.map +1 -0
  262. package/dist/chunk-TPMQ3G6Z.js +145 -0
  263. package/dist/chunk-TPMQ3G6Z.js.map +1 -0
  264. package/dist/chunk-TZOLIGIG.js +61 -0
  265. package/dist/chunk-TZOLIGIG.js.map +1 -0
  266. package/dist/chunk-U3PN77QT.js +113 -0
  267. package/dist/chunk-U3WSW6PZ.js +277 -0
  268. package/dist/chunk-U4SCL7B7.js +640 -0
  269. package/dist/chunk-U4SCL7B7.js.map +1 -0
  270. package/dist/chunk-UWK5OXUJ.js +156 -0
  271. package/dist/chunk-UWK5OXUJ.js.map +1 -0
  272. package/dist/chunk-UWVJF25J.js +74 -0
  273. package/dist/chunk-UXHQAFNA.js +1317 -0
  274. package/dist/chunk-UXHQAFNA.js.map +1 -0
  275. package/dist/chunk-V5OCT34X.js +1 -0
  276. package/dist/chunk-VLXA6PI2.js +304 -0
  277. package/dist/chunk-VLXA6PI2.js.map +1 -0
  278. package/dist/chunk-VNO6ZJ35.js +500 -0
  279. package/dist/chunk-VNO6ZJ35.js.map +1 -0
  280. package/dist/chunk-VW676BEI.js +827 -0
  281. package/dist/chunk-VW676BEI.js.map +1 -0
  282. package/dist/chunk-W3LR522O.js +2296 -0
  283. package/dist/chunk-W4L6CZKA.js +96 -0
  284. package/dist/chunk-W4L6CZKA.js.map +1 -0
  285. package/dist/chunk-W4RVMTHR.js +372 -0
  286. package/dist/chunk-W4RVMTHR.js.map +1 -0
  287. package/dist/chunk-WEHSQBFR.js +188 -0
  288. package/dist/chunk-WEHSQBFR.js.map +1 -0
  289. package/dist/chunk-WELDCG6C.js +380 -0
  290. package/dist/chunk-WELDCG6C.js.map +1 -0
  291. package/dist/chunk-WZYKANL3.js +2800 -0
  292. package/dist/chunk-WZYKANL3.js.map +1 -0
  293. package/dist/chunk-XIG5PDM7.js +48 -0
  294. package/dist/chunk-XJNBEDFE.js +193 -0
  295. package/dist/chunk-XJNBEDFE.js.map +1 -0
  296. package/dist/chunk-XVVIG67A.js +291 -0
  297. package/dist/chunk-XVVIG67A.js.map +1 -0
  298. package/dist/chunk-XVZ7B3HG.js +135 -0
  299. package/dist/chunk-YBPYIAA5.js +73 -0
  300. package/dist/chunk-YBPYIAA5.js.map +1 -0
  301. package/dist/chunk-Z734BLO3.js +21 -0
  302. package/dist/chunk-Z734BLO3.js.map +1 -0
  303. package/dist/chunk-ZKSK55RC.js +269 -0
  304. package/dist/chunk-ZKSK55RC.js.map +1 -0
  305. package/dist/chunk-ZTFCYYEZ.js +69 -0
  306. package/dist/chunk-ZTFCYYEZ.js.map +1 -0
  307. package/dist/chunk-ZY2MNJR6.js +329 -0
  308. package/dist/chunk-ZY2MNJR6.js.map +1 -0
  309. package/dist/cli-D3VpkVwB.d.ts +1136 -0
  310. package/dist/cli.d.ts +39 -10
  311. package/dist/cli.js +108 -49
  312. package/dist/commitment-ledger.js +1 -1
  313. package/dist/compat/checks.d.ts +5 -0
  314. package/dist/compat/checks.js +11 -0
  315. package/dist/compat/checks.js.map +1 -0
  316. package/dist/compat/types.d.ts +30 -0
  317. package/dist/compat/types.js +1 -0
  318. package/dist/compat/types.js.map +1 -0
  319. package/dist/compounding/engine.d.ts +221 -0
  320. package/dist/compounding/engine.js +32 -0
  321. package/dist/compounding/engine.js.map +1 -0
  322. package/dist/compounding/preference-consolidator.d.ts +92 -0
  323. package/dist/compounding/preference-consolidator.js +553 -0
  324. package/dist/compounding/preference-consolidator.js.map +1 -0
  325. package/dist/config.d.ts +4 -2
  326. package/dist/config.js +9 -4
  327. package/dist/conflict-policy-DyJ2wd-h.d.ts +4 -0
  328. package/dist/connectors/codex-materialize-runner.d.ts +64 -0
  329. package/dist/connectors/codex-materialize-runner.js +33 -0
  330. package/dist/connectors/codex-materialize-runner.js.map +1 -0
  331. package/dist/connectors/codex-materialize.d.ts +195 -0
  332. package/dist/connectors/codex-materialize.js +38 -0
  333. package/dist/connectors/codex-materialize.js.map +1 -0
  334. package/dist/connectors/index.d.ts +444 -0
  335. package/dist/connectors/index.js +115 -0
  336. package/dist/connectors/index.js.map +1 -0
  337. package/dist/connectors-cli-CwbyjGR7.d.ts +257 -0
  338. package/dist/connectors-cli.d.ts +1 -1
  339. package/dist/consolidation-provenance-check.d.ts +3 -1
  340. package/dist/consolidation-undo.d.ts +3 -1
  341. package/dist/contradiction/index.d.ts +258 -0
  342. package/dist/contradiction/index.js +43 -0
  343. package/dist/contradiction/index.js.map +1 -0
  344. package/dist/contradiction-review-ATP4S6IC.js +30 -0
  345. package/dist/contradiction-review-ATP4S6IC.js.map +1 -0
  346. package/dist/contradiction-scan-5A4IDZV5.js +13 -0
  347. package/dist/contradiction-scan-5A4IDZV5.js.map +1 -0
  348. package/dist/conversation-index/backend.d.ts +97 -0
  349. package/dist/conversation-index/backend.js +13 -0
  350. package/dist/conversation-index/backend.js.map +1 -0
  351. package/dist/conversation-index/chunker.d.ts +16 -0
  352. package/dist/conversation-index/chunker.js +8 -0
  353. package/dist/conversation-index/chunker.js.map +1 -0
  354. package/dist/conversation-index/cleanup.d.ts +11 -0
  355. package/dist/conversation-index/cleanup.js +9 -0
  356. package/dist/conversation-index/cleanup.js.map +1 -0
  357. package/dist/conversation-index/faiss-adapter.d.ts +6 -0
  358. package/dist/conversation-index/faiss-adapter.js +16 -0
  359. package/dist/conversation-index/faiss-adapter.js.map +1 -0
  360. package/dist/conversation-index/indexer.d.ts +23 -0
  361. package/dist/conversation-index/indexer.js +15 -0
  362. package/dist/conversation-index/indexer.js.map +1 -0
  363. package/dist/conversation-index/search.d.ts +6 -0
  364. package/dist/conversation-index/search.js +11 -0
  365. package/dist/conversation-index/search.js.map +1 -0
  366. package/dist/embedding-fallback.js +2 -2
  367. package/dist/enrichment/index.d.ts +163 -0
  368. package/dist/enrichment/index.js +18 -0
  369. package/dist/enrichment/index.js.map +1 -0
  370. package/dist/entity-retrieval.d.ts +4 -2
  371. package/dist/entity-retrieval.js +8 -5
  372. package/dist/evals.js +1 -1
  373. package/dist/explicit-capture.d.ts +20 -5
  374. package/dist/explicit-capture.js +2 -2
  375. package/dist/extraction-judge-training.js +1 -1
  376. package/dist/extraction.js +8 -8
  377. package/dist/faiss-adapter-CzPghc4C.d.ts +70 -0
  378. package/dist/fallback-llm.d.ts +2 -0
  379. package/dist/fallback-llm.js +4 -4
  380. package/dist/graph-edge-decay-5DI5GUNL.js +207 -0
  381. package/dist/index.d.ts +66 -711
  382. package/dist/index.js +556 -2680
  383. package/dist/index.js.map +1 -1
  384. package/dist/lcm/archive.d.ts +89 -0
  385. package/dist/lcm/archive.js +12 -0
  386. package/dist/lcm/archive.js.map +1 -0
  387. package/dist/lcm/dag.d.ts +48 -0
  388. package/dist/lcm/dag.js +8 -0
  389. package/dist/lcm/dag.js.map +1 -0
  390. package/dist/lcm/engine.d.ts +116 -0
  391. package/dist/lcm/engine.js +20 -0
  392. package/dist/lcm/engine.js.map +1 -0
  393. package/dist/lcm/index.d.ts +12 -0
  394. package/dist/lcm/index.js +44 -0
  395. package/dist/lcm/index.js.map +1 -0
  396. package/dist/lcm/queue.d.ts +62 -0
  397. package/dist/lcm/queue.js +8 -0
  398. package/dist/lcm/queue.js.map +1 -0
  399. package/dist/lcm/recall.d.ts +20 -0
  400. package/dist/lcm/recall.js +8 -0
  401. package/dist/lcm/recall.js.map +1 -0
  402. package/dist/lcm/schema.d.ts +16 -0
  403. package/dist/lcm/schema.js +14 -0
  404. package/dist/lcm/schema.js.map +1 -0
  405. package/dist/lcm/summarizer.d.ts +38 -0
  406. package/dist/lcm/summarizer.js +12 -0
  407. package/dist/lcm/summarizer.js.map +1 -0
  408. package/dist/lcm/tools.d.ts +29 -0
  409. package/dist/lcm/tools.js +8 -0
  410. package/dist/lcm/tools.js.map +1 -0
  411. package/dist/live-connectors-runner.js +5 -5
  412. package/dist/local-llm.js +3 -3
  413. package/dist/maintenance/archive-observations.d.ts +18 -0
  414. package/dist/maintenance/archive-observations.js +8 -0
  415. package/dist/maintenance/archive-observations.js.map +1 -0
  416. package/dist/maintenance/backup-stamp.d.ts +3 -0
  417. package/dist/maintenance/backup-stamp.js +8 -0
  418. package/dist/maintenance/backup-stamp.js.map +1 -0
  419. package/dist/maintenance/memory-governance-cron.d.ts +85 -0
  420. package/dist/maintenance/memory-governance-cron.js +22 -0
  421. package/dist/maintenance/memory-governance-cron.js.map +1 -0
  422. package/dist/maintenance/memory-governance.d.ts +137 -0
  423. package/dist/maintenance/memory-governance.js +40 -0
  424. package/dist/maintenance/memory-governance.js.map +1 -0
  425. package/dist/maintenance/migrate-observations.d.ts +18 -0
  426. package/dist/maintenance/migrate-observations.js +9 -0
  427. package/dist/maintenance/migrate-observations.js.map +1 -0
  428. package/dist/maintenance/observation-ledger-utils.d.ts +10 -0
  429. package/dist/maintenance/observation-ledger-utils.js +10 -0
  430. package/dist/maintenance/observation-ledger-utils.js.map +1 -0
  431. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +15 -0
  432. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +28 -0
  433. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js.map +1 -0
  434. package/dist/maintenance/rebuild-memory-projection.d.ts +77 -0
  435. package/dist/maintenance/rebuild-memory-projection.js +35 -0
  436. package/dist/maintenance/rebuild-memory-projection.js.map +1 -0
  437. package/dist/maintenance/rebuild-observations.d.ts +17 -0
  438. package/dist/maintenance/rebuild-observations.js +9 -0
  439. package/dist/maintenance/rebuild-observations.js.map +1 -0
  440. package/dist/mcp-memory-inspector-app.d.ts +24 -6
  441. package/dist/memory-projection-store.d.ts +108 -3
  442. package/dist/memory-projection-store.js +2 -1
  443. package/dist/memory-worth-outcomes.d.ts +4 -2
  444. package/dist/migrate/from-engram.d.ts +24 -0
  445. package/dist/migrate/from-engram.js +12 -0
  446. package/dist/migrate/from-engram.js.map +1 -0
  447. package/dist/namespaces/migrate.d.ts +50 -0
  448. package/dist/namespaces/migrate.js +50 -0
  449. package/dist/namespaces/migrate.js.map +1 -0
  450. package/dist/namespaces/principal.d.ts +17 -0
  451. package/dist/namespaces/principal.js +16 -0
  452. package/dist/namespaces/principal.js.map +1 -0
  453. package/dist/namespaces/search.d.ts +46 -0
  454. package/dist/namespaces/search.js +28 -0
  455. package/dist/namespaces/search.js.map +1 -0
  456. package/dist/namespaces/storage.d.ts +32 -0
  457. package/dist/namespaces/storage.js +28 -0
  458. package/dist/namespaces/storage.js.map +1 -0
  459. package/dist/network/tailscale.d.ts +41 -0
  460. package/dist/network/tailscale.js +9 -0
  461. package/dist/network/tailscale.js.map +1 -0
  462. package/dist/network/webdav.d.ts +39 -0
  463. package/dist/network/webdav.js +10 -0
  464. package/dist/network/webdav.js.map +1 -0
  465. package/dist/objective-state-writers.js +2 -2
  466. package/dist/operator-toolkit.d.ts +4 -2
  467. package/dist/operator-toolkit.js +32 -14
  468. package/dist/opik-exporter.js +2 -2
  469. package/dist/opik-exporter.js.map +1 -1
  470. package/dist/orchestrator-DuWl9Hwx.d.ts +1244 -0
  471. package/dist/orchestrator.d.ts +22 -7
  472. package/dist/orchestrator.js +79 -44
  473. package/dist/path-MR5JPYOP.js +9 -0
  474. package/dist/path-MR5JPYOP.js.map +1 -0
  475. package/dist/qmd-recall-cache.d.ts +1 -1
  476. package/dist/qmd.d.ts +102 -3
  477. package/dist/qmd.js +23 -5
  478. package/dist/recall-explain-renderer.js +3 -3
  479. package/dist/recall-xray-cli.js +4 -4
  480. package/dist/recall-xray-renderer.js +3 -3
  481. package/dist/recall-xray.js +2 -2
  482. package/dist/replay/normalizers/chatgpt.d.ts +6 -0
  483. package/dist/replay/normalizers/chatgpt.js +11 -0
  484. package/dist/replay/normalizers/chatgpt.js.map +1 -0
  485. package/dist/replay/normalizers/claude.d.ts +6 -0
  486. package/dist/replay/normalizers/claude.js +11 -0
  487. package/dist/replay/normalizers/claude.js.map +1 -0
  488. package/dist/replay/normalizers/openclaw.d.ts +6 -0
  489. package/dist/replay/normalizers/openclaw.js +11 -0
  490. package/dist/replay/normalizers/openclaw.js.map +1 -0
  491. package/dist/replay/normalizers/shared.d.ts +16 -0
  492. package/dist/replay/normalizers/shared.js +14 -0
  493. package/dist/replay/normalizers/shared.js.map +1 -0
  494. package/dist/replay/runner.d.ts +35 -0
  495. package/dist/replay/runner.js +16 -0
  496. package/dist/replay/runner.js.map +1 -0
  497. package/dist/replay/types.d.ts +57 -0
  498. package/dist/replay/types.js +19 -0
  499. package/dist/replay/types.js.map +1 -0
  500. package/dist/resolution-B7FNQSSP.js +12 -0
  501. package/dist/resolution-B7FNQSSP.js.map +1 -0
  502. package/dist/resolve-provider-secret.js +2 -2
  503. package/dist/resume-bundles.js +8 -6
  504. package/dist/retrieval-agents.d.ts +1 -1
  505. package/dist/routing/engine.d.ts +35 -0
  506. package/dist/routing/engine.js +16 -0
  507. package/dist/routing/engine.js.map +1 -0
  508. package/dist/routing/store.d.ts +27 -0
  509. package/dist/routing/store.js +10 -0
  510. package/dist/routing/store.js.map +1 -0
  511. package/dist/runtime/better-sqlite.d.ts +8 -0
  512. package/dist/runtime/better-sqlite.js +10 -0
  513. package/dist/runtime/better-sqlite.js.map +1 -0
  514. package/dist/runtime/child-process.d.ts +32 -0
  515. package/dist/runtime/child-process.js +10 -0
  516. package/dist/runtime/child-process.js.map +1 -0
  517. package/dist/runtime/env.d.ts +5 -0
  518. package/dist/runtime/env.js +12 -0
  519. package/dist/runtime/env.js.map +1 -0
  520. package/dist/schemas.d.ts +22 -22
  521. package/dist/sdk-compat.js +1 -1
  522. package/dist/search/document-scanner.d.ts +22 -0
  523. package/dist/search/document-scanner.js +8 -0
  524. package/dist/search/document-scanner.js.map +1 -0
  525. package/dist/search/embed-helper.d.ts +35 -0
  526. package/dist/search/embed-helper.js +9 -0
  527. package/dist/search/embed-helper.js.map +1 -0
  528. package/dist/search/factory.d.ts +32 -0
  529. package/dist/search/factory.js +29 -0
  530. package/dist/search/factory.js.map +1 -0
  531. package/dist/search/index.d.ts +15 -0
  532. package/dist/search/index.js +50 -0
  533. package/dist/search/index.js.map +1 -0
  534. package/dist/search/lancedb-backend.d.ts +51 -0
  535. package/dist/search/lancedb-backend.js +10 -0
  536. package/dist/search/lancedb-backend.js.map +1 -0
  537. package/dist/search/meilisearch-backend.d.ts +48 -0
  538. package/dist/search/meilisearch-backend.js +10 -0
  539. package/dist/search/meilisearch-backend.js.map +1 -0
  540. package/dist/search/noop-backend.d.ts +26 -0
  541. package/dist/search/noop-backend.js +8 -0
  542. package/dist/search/noop-backend.js.map +1 -0
  543. package/dist/search/orama-backend.d.ts +53 -0
  544. package/dist/search/orama-backend.js +10 -0
  545. package/dist/search/orama-backend.js.map +1 -0
  546. package/dist/search/port.d.ts +61 -0
  547. package/dist/search/port.js +1 -0
  548. package/dist/search/port.js.map +1 -0
  549. package/dist/search/remote-backend.d.ts +39 -0
  550. package/dist/search/remote-backend.js +9 -0
  551. package/dist/search/remote-backend.js.map +1 -0
  552. package/dist/secure-store/index.d.ts +890 -0
  553. package/dist/secure-store/index.js +156 -0
  554. package/dist/secure-store/index.js.map +1 -0
  555. package/dist/semantic-VwGI14Ok.d.ts +69 -0
  556. package/dist/semantic-consolidation-4HkHWgeI.d.ts +180 -0
  557. package/dist/semantic-consolidation.d.ts +2 -2
  558. package/dist/semantic-consolidation.js +13 -6
  559. package/dist/semantic-rule-promotion.js +8 -5
  560. package/dist/semantic-rule-verifier.js +8 -5
  561. package/dist/shared-context/manager.d.ts +131 -0
  562. package/dist/shared-context/manager.js +15 -0
  563. package/dist/shared-context/manager.js.map +1 -0
  564. package/dist/skills-registry.js +13 -1
  565. package/dist/skills-registry.js.map +1 -1
  566. package/dist/state-store-VZU2IA53.js +16 -0
  567. package/dist/state-store-VZU2IA53.js.map +1 -0
  568. package/dist/storage-paths.d.ts +9 -0
  569. package/dist/storage-paths.js +20 -0
  570. package/dist/storage-paths.js.map +1 -0
  571. package/dist/storage.d.ts +3 -1
  572. package/dist/storage.js +7 -4
  573. package/dist/summarizer.d.ts +5 -0
  574. package/dist/summarizer.js +9 -8
  575. package/dist/summary-snapshot.js +2 -1
  576. package/dist/surfaces/dreams.d.ts +16 -0
  577. package/dist/surfaces/dreams.js +282 -0
  578. package/dist/surfaces/dreams.js.map +1 -0
  579. package/dist/surfaces/heartbeat.d.ts +17 -0
  580. package/dist/surfaces/heartbeat.js +265 -0
  581. package/dist/surfaces/heartbeat.js.map +1 -0
  582. package/dist/temporal-supersession.d.ts +3 -1
  583. package/dist/threading.d.ts +5 -0
  584. package/dist/threading.js +2 -1
  585. package/dist/tier-migration.d.ts +4 -2
  586. package/dist/tokens.js +2 -2
  587. package/dist/transcript.d.ts +15 -1
  588. package/dist/transcript.js +2 -1
  589. package/dist/transfer/autodetect.d.ts +4 -0
  590. package/dist/transfer/autodetect.js +15 -0
  591. package/dist/transfer/autodetect.js.map +1 -0
  592. package/dist/transfer/backup.d.ts +21 -0
  593. package/dist/transfer/backup.js +17 -0
  594. package/dist/transfer/backup.js.map +1 -0
  595. package/dist/transfer/capsule-export.d.ts +113 -0
  596. package/dist/transfer/capsule-export.js +19 -0
  597. package/dist/transfer/capsule-export.js.map +1 -0
  598. package/dist/transfer/capsule-import.d.ts +124 -0
  599. package/dist/transfer/capsule-import.js +16 -0
  600. package/dist/transfer/capsule-import.js.map +1 -0
  601. package/dist/transfer/constants.d.ts +13 -0
  602. package/dist/transfer/constants.js +12 -0
  603. package/dist/transfer/constants.js.map +1 -0
  604. package/dist/transfer/export-json.d.ts +11 -0
  605. package/dist/transfer/export-json.js +11 -0
  606. package/dist/transfer/export-json.js.map +1 -0
  607. package/dist/transfer/export-md.d.ts +10 -0
  608. package/dist/transfer/export-md.js +13 -0
  609. package/dist/transfer/export-md.js.map +1 -0
  610. package/dist/transfer/export-sqlite.d.ts +9 -0
  611. package/dist/transfer/export-sqlite.js +12 -0
  612. package/dist/transfer/export-sqlite.js.map +1 -0
  613. package/dist/transfer/fs-utils.d.ts +61 -0
  614. package/dist/transfer/fs-utils.js +40 -0
  615. package/dist/transfer/fs-utils.js.map +1 -0
  616. package/dist/transfer/import-json.d.ts +16 -0
  617. package/dist/transfer/import-json.js +13 -0
  618. package/dist/transfer/import-json.js.map +1 -0
  619. package/dist/transfer/import-md.d.ts +14 -0
  620. package/dist/transfer/import-md.js +11 -0
  621. package/dist/transfer/import-md.js.map +1 -0
  622. package/dist/transfer/import-sqlite.d.ts +14 -0
  623. package/dist/transfer/import-sqlite.js +12 -0
  624. package/dist/transfer/import-sqlite.js.map +1 -0
  625. package/dist/transfer/sqlite-schema.d.ts +4 -0
  626. package/dist/transfer/sqlite-schema.js +10 -0
  627. package/dist/transfer/sqlite-schema.js.map +1 -0
  628. package/dist/transfer/types.d.ts +916 -0
  629. package/dist/transfer/types.js +30 -0
  630. package/dist/transfer/types.js.map +1 -0
  631. package/dist/types.d.ts +28 -1
  632. package/dist/types.js +1 -1
  633. package/dist/verified-recall.js +9 -6
  634. package/dist/work/board.d.ts +43 -0
  635. package/dist/work/board.js +14 -0
  636. package/dist/work/board.js.map +1 -0
  637. package/dist/work/boundary.d.ts +8 -0
  638. package/dist/work/boundary.js +14 -0
  639. package/dist/work/boundary.js.map +1 -0
  640. package/dist/work/storage.d.ts +39 -0
  641. package/dist/work/storage.js +11 -0
  642. package/dist/work/storage.js.map +1 -0
  643. package/dist/work/types.d.ts +75 -0
  644. package/dist/work/types.js +1 -0
  645. package/dist/work/types.js.map +1 -0
  646. package/package.json +2767 -6
  647. package/scripts/faiss_index.py +816 -0
  648. package/scripts/faiss_requirements.txt +3 -0
  649. package/skills/remnic-entities/SKILL.md +51 -0
  650. package/skills/remnic-memory-workflow/SKILL.md +61 -0
  651. package/skills/remnic-recall/SKILL.md +51 -0
  652. package/skills/remnic-remember/SKILL.md +56 -0
  653. package/skills/remnic-search/SKILL.md +51 -0
  654. package/skills/remnic-status/SKILL.md +51 -0
  655. package/src/abort-error.test.ts +49 -0
  656. package/src/abort-error.ts +46 -0
  657. package/src/abstraction-nodes.ts +162 -0
  658. package/src/access-audit.test.ts +178 -0
  659. package/src/access-audit.ts +125 -0
  660. package/src/access-cli.test.ts +439 -0
  661. package/src/access-cli.ts +438 -0
  662. package/src/access-http.test.ts +225 -0
  663. package/src/access-http.ts +1899 -0
  664. package/src/access-idempotency.ts +232 -0
  665. package/src/access-mcp.test.ts +568 -0
  666. package/src/access-mcp.ts +3056 -0
  667. package/src/access-schema-pi.test.ts +60 -0
  668. package/src/access-schema.ts +522 -0
  669. package/src/access-service-namespace.test.ts +123 -0
  670. package/src/access-service.ts +5629 -0
  671. package/src/action-confidence.test.ts +206 -0
  672. package/src/action-confidence.ts +466 -0
  673. package/src/active-memory-bridge.test.ts +285 -0
  674. package/src/active-memory-bridge.ts +217 -0
  675. package/src/active-recall.test.ts +484 -0
  676. package/src/active-recall.ts +459 -0
  677. package/src/adapters/claude-code.ts +56 -0
  678. package/src/adapters/codex.ts +57 -0
  679. package/src/adapters/hermes.ts +64 -0
  680. package/src/adapters/index.ts +6 -0
  681. package/src/adapters/registry.ts +41 -0
  682. package/src/adapters/replit.ts +55 -0
  683. package/src/adapters/types.ts +51 -0
  684. package/src/behavior-learner.ts +144 -0
  685. package/src/behavior-signals.ts +73 -0
  686. package/src/binary-lifecycle/backend.ts +117 -0
  687. package/src/binary-lifecycle/index.ts +35 -0
  688. package/src/binary-lifecycle/manifest.ts +79 -0
  689. package/src/binary-lifecycle/pipeline.ts +352 -0
  690. package/src/binary-lifecycle/scanner.ts +89 -0
  691. package/src/binary-lifecycle/types.ts +89 -0
  692. package/src/bootstrap.ts +178 -0
  693. package/src/boxes.ts +521 -0
  694. package/src/briefing.test.ts +1535 -0
  695. package/src/briefing.ts +1382 -0
  696. package/src/buffer-session.test.ts +443 -0
  697. package/src/buffer-surprise-report.ts +176 -0
  698. package/src/buffer-surprise-telemetry.test.ts +606 -0
  699. package/src/buffer-surprise-trigger.test.ts +766 -0
  700. package/src/buffer-surprise.test.ts +339 -0
  701. package/src/buffer-surprise.ts +203 -0
  702. package/src/buffer.ts +900 -0
  703. package/src/bulk-import/cli-command.test.ts +204 -0
  704. package/src/bulk-import/index.ts +34 -0
  705. package/src/bulk-import/pipeline.test.ts +445 -0
  706. package/src/bulk-import/pipeline.ts +178 -0
  707. package/src/bulk-import/registry.test.ts +151 -0
  708. package/src/bulk-import/registry.ts +72 -0
  709. package/src/bulk-import/types.test.ts +272 -0
  710. package/src/bulk-import/types.ts +145 -0
  711. package/src/calibration.ts +394 -0
  712. package/src/capsule-cli.test.ts +398 -0
  713. package/src/capsule-cli.ts +565 -0
  714. package/src/causal-behavior.ts +308 -0
  715. package/src/causal-chain.ts +419 -0
  716. package/src/causal-consolidation.ts +370 -0
  717. package/src/causal-retrieval.ts +286 -0
  718. package/src/causal-trajectory-graph.ts +60 -0
  719. package/src/causal-trajectory.ts +303 -0
  720. package/src/chunking.ts +220 -0
  721. package/src/citations.ts +232 -0
  722. package/src/cli.ts +9403 -0
  723. package/src/codex-cli-fallback.ts +162 -0
  724. package/src/codex-thread-key.ts +1 -0
  725. package/src/coding/access-coding-context.test.ts +197 -0
  726. package/src/coding/coding-branch-scope.test.ts +281 -0
  727. package/src/coding/coding-namespace.test.ts +360 -0
  728. package/src/coding/coding-namespace.ts +412 -0
  729. package/src/coding/coding-orchestrator.test.ts +249 -0
  730. package/src/coding/git-context.test.ts +507 -0
  731. package/src/coding/git-context.ts +336 -0
  732. package/src/coding/mcp-set-coding-context.test.ts +174 -0
  733. package/src/coding/review-context.test.ts +316 -0
  734. package/src/coding/review-context.ts +349 -0
  735. package/src/coding/wire-coding-context.test.ts +468 -0
  736. package/src/commitment-ledger.test.ts +78 -0
  737. package/src/commitment-ledger.ts +337 -0
  738. package/src/compat/checks.test.ts +206 -0
  739. package/src/compat/checks.ts +716 -0
  740. package/src/compat/types.ts +33 -0
  741. package/src/compounding/engine.ts +1686 -0
  742. package/src/compounding/preference-consolidator.ts +778 -0
  743. package/src/compression-optimizer.ts +312 -0
  744. package/src/config.test.ts +930 -0
  745. package/src/config.ts +3807 -0
  746. package/src/connectors/codex/instructions.md +160 -0
  747. package/src/connectors/codex/resources/namespace-cheatsheet.md +48 -0
  748. package/src/connectors/codex-marketplace.ts +500 -0
  749. package/src/connectors/codex-materialize-runner.ts +212 -0
  750. package/src/connectors/codex-materialize.ts +983 -0
  751. package/src/connectors/coerce.ts +62 -0
  752. package/src/connectors/index.test.ts +1570 -0
  753. package/src/connectors/index.ts +3222 -0
  754. package/src/connectors/live/framework.ts +164 -0
  755. package/src/connectors/live/github.test.ts +1218 -0
  756. package/src/connectors/live/github.ts +1068 -0
  757. package/src/connectors/live/gmail.test.ts +1706 -0
  758. package/src/connectors/live/gmail.ts +1293 -0
  759. package/src/connectors/live/google-drive.test.ts +696 -0
  760. package/src/connectors/live/google-drive.ts +724 -0
  761. package/src/connectors/live/index.ts +101 -0
  762. package/src/connectors/live/live-connectors.test.ts +689 -0
  763. package/src/connectors/live/notion.test.ts +1109 -0
  764. package/src/connectors/live/notion.ts +978 -0
  765. package/src/connectors/live/registry.ts +103 -0
  766. package/src/connectors/live/state-store.ts +399 -0
  767. package/src/connectors/live/transient-errors.ts +150 -0
  768. package/src/connectors/weclone-installer.test.ts +850 -0
  769. package/src/connectors-cli.ts +513 -0
  770. package/src/console/state.test.ts +224 -0
  771. package/src/console/state.ts +514 -0
  772. package/src/console/trace.test.ts +813 -0
  773. package/src/console/trace.ts +603 -0
  774. package/src/console/tui.test.ts +582 -0
  775. package/src/console/tui.ts +508 -0
  776. package/src/consolidation-operator.ts +182 -0
  777. package/src/consolidation-provenance-check.ts +551 -0
  778. package/src/consolidation-undo.ts +718 -0
  779. package/src/contradiction/contradiction-judge.test.ts +189 -0
  780. package/src/contradiction/contradiction-judge.ts +333 -0
  781. package/src/contradiction/contradiction-review.ts +574 -0
  782. package/src/contradiction/contradiction-scan.ts +504 -0
  783. package/src/contradiction/contradiction.test.ts +2230 -0
  784. package/src/contradiction/index.ts +37 -0
  785. package/src/contradiction/resolution.ts +383 -0
  786. package/src/conversation-index/backend.ts +323 -0
  787. package/src/conversation-index/chunker.ts +47 -0
  788. package/src/conversation-index/cleanup.ts +53 -0
  789. package/src/conversation-index/faiss-adapter.ts +384 -0
  790. package/src/conversation-index/indexer.test.ts +164 -0
  791. package/src/conversation-index/indexer.ts +192 -0
  792. package/src/conversation-index/search.ts +37 -0
  793. package/src/cross-namespace-budget.test.ts +275 -0
  794. package/src/cross-namespace-budget.ts +365 -0
  795. package/src/cue-anchors.ts +163 -0
  796. package/src/curation/index.ts +544 -0
  797. package/src/dashboard-runtime.ts +337 -0
  798. package/src/day-summary.ts +122 -0
  799. package/src/dedup/index.ts +330 -0
  800. package/src/dedup/semantic.test.ts +1577 -0
  801. package/src/dedup/semantic.ts +148 -0
  802. package/src/delinearize.ts +193 -0
  803. package/src/direct-answer-wiring.test.ts +473 -0
  804. package/src/direct-answer-wiring.ts +180 -0
  805. package/src/direct-answer.test.ts +484 -0
  806. package/src/direct-answer.ts +273 -0
  807. package/src/embedding-fallback.ts +565 -0
  808. package/src/enrichment/audit.ts +89 -0
  809. package/src/enrichment/index.ts +27 -0
  810. package/src/enrichment/pipeline.ts +197 -0
  811. package/src/enrichment/provider-registry.ts +85 -0
  812. package/src/enrichment/types.ts +100 -0
  813. package/src/enrichment/web-search-provider.ts +63 -0
  814. package/src/entity-retrieval.ts +774 -0
  815. package/src/entity-schema.ts +239 -0
  816. package/src/evals.ts +1312 -0
  817. package/src/event-order-recall.test.ts +4164 -0
  818. package/src/event-order-recall.ts +2802 -0
  819. package/src/evidence-pack.test.ts +89 -0
  820. package/src/evidence-pack.ts +388 -0
  821. package/src/explicit-capture.ts +530 -0
  822. package/src/explicit-cue-recall.test.ts +3019 -0
  823. package/src/explicit-cue-recall.ts +5545 -0
  824. package/src/extraction-judge-telemetry.ts +234 -0
  825. package/src/extraction-judge-training.ts +221 -0
  826. package/src/extraction-judge.ts +846 -0
  827. package/src/extraction-timeout.test.ts +265 -0
  828. package/src/extraction.ts +2719 -0
  829. package/src/fallback-llm.test.ts +1060 -0
  830. package/src/fallback-llm.ts +918 -0
  831. package/src/focused-list-recall.test.ts +734 -0
  832. package/src/focused-list-recall.ts +1160 -0
  833. package/src/graph-dashboard-diff.ts +35 -0
  834. package/src/graph-dashboard-key.ts +5 -0
  835. package/src/graph-dashboard-parser.ts +104 -0
  836. package/src/graph-edge-reinforcement.ts +192 -0
  837. package/src/graph-events.ts +151 -0
  838. package/src/graph-recall.test.ts +164 -0
  839. package/src/graph-recall.ts +189 -0
  840. package/src/graph-retrieval.test.ts +809 -0
  841. package/src/graph-retrieval.ts +823 -0
  842. package/src/graph-snapshot.ts +329 -0
  843. package/src/graph.ts +813 -0
  844. package/src/harmonic-retrieval.ts +223 -0
  845. package/src/himem.ts +154 -0
  846. package/src/hygiene.ts +87 -0
  847. package/src/identity-continuity.ts +333 -0
  848. package/src/importance.ts +328 -0
  849. package/src/importers/base.test.ts +294 -0
  850. package/src/importers/base.ts +436 -0
  851. package/src/importers/index.ts +21 -0
  852. package/src/index.ts +1204 -0
  853. package/src/intent.ts +154 -0
  854. package/src/json-extract.ts +85 -0
  855. package/src/json-store.ts +42 -0
  856. package/src/lcm/archive.ts +617 -0
  857. package/src/lcm/dag.ts +199 -0
  858. package/src/lcm/engine.ts +645 -0
  859. package/src/lcm/index.ts +7 -0
  860. package/src/lcm/queue.test.ts +178 -0
  861. package/src/lcm/queue.ts +200 -0
  862. package/src/lcm/recall.ts +117 -0
  863. package/src/lcm/schema.ts +154 -0
  864. package/src/lcm/summarizer.ts +235 -0
  865. package/src/lcm/tools.ts +191 -0
  866. package/src/lcm-engine.test.ts +660 -0
  867. package/src/legacy-hook-compat.test.ts +20 -0
  868. package/src/legacy-hook-compat.ts +45 -0
  869. package/src/lifecycle.ts +289 -0
  870. package/src/live-connectors-runner.ts +385 -0
  871. package/src/local-llm-qos.test.ts +303 -0
  872. package/src/local-llm-thinking.test.ts +292 -0
  873. package/src/local-llm.ts +1464 -0
  874. package/src/logger.ts +49 -0
  875. package/src/maintenance/archive-observations.ts +147 -0
  876. package/src/maintenance/backup-stamp.ts +3 -0
  877. package/src/maintenance/dreams-ledger.ts +516 -0
  878. package/src/maintenance/first-start-migration.ts +362 -0
  879. package/src/maintenance/forget.test.ts +206 -0
  880. package/src/maintenance/forget.ts +126 -0
  881. package/src/maintenance/graph-edge-decay.test.ts +409 -0
  882. package/src/maintenance/graph-edge-decay.ts +394 -0
  883. package/src/maintenance/memory-governance-cron.ts +447 -0
  884. package/src/maintenance/memory-governance.ts +1039 -0
  885. package/src/maintenance/migrate-observations.ts +216 -0
  886. package/src/maintenance/observation-ledger-utils.ts +54 -0
  887. package/src/maintenance/pattern-reinforcement.test.ts +875 -0
  888. package/src/maintenance/pattern-reinforcement.ts +369 -0
  889. package/src/maintenance/purge.ts +334 -0
  890. package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +78 -0
  891. package/src/maintenance/rebuild-memory-projection.ts +1234 -0
  892. package/src/maintenance/rebuild-observations.ts +178 -0
  893. package/src/maintenance/tier-stats.test.ts +378 -0
  894. package/src/maintenance/tier-stats.ts +222 -0
  895. package/src/mcp-memory-inspector-app.ts +421 -0
  896. package/src/memory-action-policy.ts +80 -0
  897. package/src/memory-cache.ts +208 -0
  898. package/src/memory-extension/claude-code-publisher.ts +51 -0
  899. package/src/memory-extension/codex-publisher.ts +149 -0
  900. package/src/memory-extension/hermes-publisher.ts +51 -0
  901. package/src/memory-extension/index.ts +100 -0
  902. package/src/memory-extension/shared-instructions.ts +133 -0
  903. package/src/memory-extension/types.ts +86 -0
  904. package/src/memory-extension-host/host-discovery.ts +276 -0
  905. package/src/memory-extension-host/index.ts +14 -0
  906. package/src/memory-extension-host/render-extensions-block.ts +73 -0
  907. package/src/memory-extension-host/types.ts +21 -0
  908. package/src/memory-lifecycle-ledger-utils.ts +116 -0
  909. package/src/memory-projection-format.ts +11 -0
  910. package/src/memory-projection-store.ts +951 -0
  911. package/src/memory-provenance.test.ts +196 -0
  912. package/src/memory-provenance.ts +484 -0
  913. package/src/memory-worth-bench.test.ts +71 -0
  914. package/src/memory-worth-bench.ts +265 -0
  915. package/src/memory-worth-filter.test.ts +209 -0
  916. package/src/memory-worth-filter.ts +204 -0
  917. package/src/memory-worth-frontmatter.test.ts +311 -0
  918. package/src/memory-worth-outcomes.test.ts +316 -0
  919. package/src/memory-worth-outcomes.ts +286 -0
  920. package/src/memory-worth.test.ts +317 -0
  921. package/src/memory-worth.ts +215 -0
  922. package/src/message-parts/index.ts +806 -0
  923. package/src/message-parts/message-parts.test.ts +421 -0
  924. package/src/migrate/from-engram.ts +789 -0
  925. package/src/model-registry.ts +313 -0
  926. package/src/models-json.ts +76 -0
  927. package/src/namespaces/migrate.ts +187 -0
  928. package/src/namespaces/path.ts +25 -0
  929. package/src/namespaces/principal.test.ts +195 -0
  930. package/src/namespaces/principal.ts +86 -0
  931. package/src/namespaces/search.test.ts +105 -0
  932. package/src/namespaces/search.ts +233 -0
  933. package/src/namespaces/storage.ts +74 -0
  934. package/src/native-knowledge.ts +1823 -0
  935. package/src/negative.ts +72 -0
  936. package/src/network/tailscale.ts +179 -0
  937. package/src/network/webdav.ts +385 -0
  938. package/src/objective-state-writers.ts +951 -0
  939. package/src/objective-state.ts +320 -0
  940. package/src/onboarding/index.ts +529 -0
  941. package/src/openai-chat-compat.ts +56 -0
  942. package/src/operator-toolkit.ts +2132 -0
  943. package/src/opik-exporter.test.ts +72 -0
  944. package/src/opik-exporter.ts +587 -0
  945. package/src/orchestrator-extraction-queue.test.ts +197 -0
  946. package/src/orchestrator-flush.test.ts +1171 -0
  947. package/src/orchestrator-pattern-reinforcement.test.ts +128 -0
  948. package/src/orchestrator-source-attribution.test.ts +701 -0
  949. package/src/orchestrator.ts +16368 -0
  950. package/src/page-versioning.ts +450 -0
  951. package/src/patterns-cli.ts +574 -0
  952. package/src/peers/index.ts +54 -0
  953. package/src/peers/migrate-from-identity-anchor.test.ts +291 -0
  954. package/src/peers/migrate-from-identity-anchor.ts +350 -0
  955. package/src/peers/peers.test.ts +419 -0
  956. package/src/peers/profile-reasoner.ts +694 -0
  957. package/src/peers/storage.ts +1350 -0
  958. package/src/peers/types.ts +138 -0
  959. package/src/plugin-id.ts +84 -0
  960. package/src/policy-runtime.ts +209 -0
  961. package/src/procedural/procedure-miner.ts +150 -0
  962. package/src/procedural/procedure-recall.ts +93 -0
  963. package/src/procedural/procedure-stats.ts +213 -0
  964. package/src/procedural/procedure-types.ts +132 -0
  965. package/src/procedural/reinforcement-core.test.ts +132 -0
  966. package/src/procedural/reinforcement-core.ts +73 -0
  967. package/src/profiling.test.ts +263 -0
  968. package/src/profiling.ts +435 -0
  969. package/src/projection/index.ts +398 -0
  970. package/src/qmd-recall-cache.test.ts +138 -0
  971. package/src/qmd-recall-cache.ts +111 -0
  972. package/src/qmd.test.ts +257 -0
  973. package/src/qmd.ts +2614 -0
  974. package/src/reasoning-trace-recall.ts +201 -0
  975. package/src/reasoning-trace-types.ts +235 -0
  976. package/src/recall-audit-anomaly.test.ts +246 -0
  977. package/src/recall-audit-anomaly.ts +297 -0
  978. package/src/recall-audit.test.ts +51 -0
  979. package/src/recall-audit.ts +72 -0
  980. package/src/recall-budget-config.test.ts +87 -0
  981. package/src/recall-disclosure-escalation.test.ts +196 -0
  982. package/src/recall-disclosure-escalation.ts +158 -0
  983. package/src/recall-disclosure-shaping.test.ts +146 -0
  984. package/src/recall-disclosure.test.ts +214 -0
  985. package/src/recall-explain-renderer.test.ts +140 -0
  986. package/src/recall-explain-renderer.ts +356 -0
  987. package/src/recall-mmr.test.ts +808 -0
  988. package/src/recall-mmr.ts +607 -0
  989. package/src/recall-qos.test.ts +85 -0
  990. package/src/recall-qos.ts +82 -0
  991. package/src/recall-query-policy.ts +221 -0
  992. package/src/recall-state.test.ts +233 -0
  993. package/src/recall-state.ts +456 -0
  994. package/src/recall-tag-filter.ts +143 -0
  995. package/src/recall-tokenization.ts +35 -0
  996. package/src/recall-xray-cli.test.ts +118 -0
  997. package/src/recall-xray-cli.ts +100 -0
  998. package/src/recall-xray-disclosure-telemetry.test.ts +183 -0
  999. package/src/recall-xray-renderer.test.ts +539 -0
  1000. package/src/recall-xray-renderer.ts +487 -0
  1001. package/src/recall-xray.test.ts +503 -0
  1002. package/src/recall-xray.ts +621 -0
  1003. package/src/reconstruct.ts +41 -0
  1004. package/src/release-changelog.ts +35 -0
  1005. package/src/relevance.ts +67 -0
  1006. package/src/replay/normalizers/chatgpt.ts +133 -0
  1007. package/src/replay/normalizers/claude.ts +102 -0
  1008. package/src/replay/normalizers/openclaw.ts +119 -0
  1009. package/src/replay/normalizers/shared.ts +69 -0
  1010. package/src/replay/runner.ts +197 -0
  1011. package/src/replay/types.ts +143 -0
  1012. package/src/rerank.test.ts +48 -0
  1013. package/src/rerank.ts +176 -0
  1014. package/src/resolve-auth-token.test.ts +226 -0
  1015. package/src/resolve-auth-token.ts +151 -0
  1016. package/src/resolve-provider-secret.test.ts +187 -0
  1017. package/src/resolve-provider-secret.ts +410 -0
  1018. package/src/response-guidance-recall.test.ts +3952 -0
  1019. package/src/response-guidance-recall.ts +4431 -0
  1020. package/src/resume-bundles.ts +415 -0
  1021. package/src/retrieval-agents.ts +623 -0
  1022. package/src/retrieval-tiers.ts +25 -0
  1023. package/src/retrieval.ts +104 -0
  1024. package/src/review/index.test.ts +201 -0
  1025. package/src/review/index.ts +536 -0
  1026. package/src/routing/engine.ts +162 -0
  1027. package/src/routing/store.ts +321 -0
  1028. package/src/runtime/better-sqlite.test.ts +32 -0
  1029. package/src/runtime/better-sqlite.ts +76 -0
  1030. package/src/runtime/child-process.ts +67 -0
  1031. package/src/runtime/env.ts +48 -0
  1032. package/src/sanitize.ts +58 -0
  1033. package/src/schemas.ts +449 -0
  1034. package/src/sdk-compat.ts +87 -0
  1035. package/src/search/document-scanner.ts +96 -0
  1036. package/src/search/embed-helper.ts +142 -0
  1037. package/src/search/factory.ts +189 -0
  1038. package/src/search/index.ts +10 -0
  1039. package/src/search/lancedb-backend.ts +342 -0
  1040. package/src/search/meilisearch-backend.ts +232 -0
  1041. package/src/search/noop-backend.ts +57 -0
  1042. package/src/search/orama-backend.ts +358 -0
  1043. package/src/search/port.ts +86 -0
  1044. package/src/search/remote-backend.ts +124 -0
  1045. package/src/secure-store/cipher.ts +271 -0
  1046. package/src/secure-store/cli-handlers.ts +355 -0
  1047. package/src/secure-store/cli-renderer.ts +131 -0
  1048. package/src/secure-store/header.ts +373 -0
  1049. package/src/secure-store/index.ts +137 -0
  1050. package/src/secure-store/kdf.ts +263 -0
  1051. package/src/secure-store/keyring.ts +106 -0
  1052. package/src/secure-store/metadata.ts +394 -0
  1053. package/src/secure-store/passphrase-reader.ts +252 -0
  1054. package/src/secure-store/secure-fs.ts +571 -0
  1055. package/src/secure-store/secure-store.test.ts +755 -0
  1056. package/src/semantic-chunking.ts +545 -0
  1057. package/src/semantic-consolidation.test.ts +182 -0
  1058. package/src/semantic-consolidation.ts +432 -0
  1059. package/src/semantic-rule-promotion.ts +183 -0
  1060. package/src/semantic-rule-verifier.ts +160 -0
  1061. package/src/session-integrity.ts +569 -0
  1062. package/src/session-observer-bands.ts +11 -0
  1063. package/src/session-observer-state.ts +346 -0
  1064. package/src/session-toggles.test.ts +96 -0
  1065. package/src/session-toggles.ts +159 -0
  1066. package/src/shared-context/manager.ts +810 -0
  1067. package/src/signal.ts +84 -0
  1068. package/src/skills-registry.test.ts +277 -0
  1069. package/src/skills-registry.ts +120 -0
  1070. package/src/source-attribution-roundtrip.test.ts +215 -0
  1071. package/src/source-attribution.test.ts +1425 -0
  1072. package/src/source-attribution.ts +639 -0
  1073. package/src/spaces/index.ts +627 -0
  1074. package/src/storage-paths.ts +117 -0
  1075. package/src/storage.ts +6657 -0
  1076. package/src/store-contract.ts +55 -0
  1077. package/src/summarizer.ts +844 -0
  1078. package/src/summary-snapshot.test.ts +681 -0
  1079. package/src/summary-snapshot.ts +238 -0
  1080. package/src/surfaces/dreams.test.ts +394 -0
  1081. package/src/surfaces/dreams.ts +346 -0
  1082. package/src/surfaces/heartbeat.test.ts +415 -0
  1083. package/src/surfaces/heartbeat.ts +325 -0
  1084. package/src/sync/index.ts +308 -0
  1085. package/src/targeted-fact-recall.test.ts +1694 -0
  1086. package/src/targeted-fact-recall.ts +2905 -0
  1087. package/src/taxonomy/default-taxonomy.ts +87 -0
  1088. package/src/taxonomy/index.ts +26 -0
  1089. package/src/taxonomy/resolver-doc-generator.ts +57 -0
  1090. package/src/taxonomy/resolver.ts +184 -0
  1091. package/src/taxonomy/taxonomy-loader.ts +186 -0
  1092. package/src/taxonomy/types.ts +48 -0
  1093. package/src/telemetry-transcript.ts +70 -0
  1094. package/src/temporal-index.ts +890 -0
  1095. package/src/temporal-supersession.test.ts +2703 -0
  1096. package/src/temporal-supersession.ts +493 -0
  1097. package/src/temporal-validity.test.ts +448 -0
  1098. package/src/temporal-validity.ts +123 -0
  1099. package/src/threading.ts +395 -0
  1100. package/src/tier-migration.ts +124 -0
  1101. package/src/tier-routing.ts +102 -0
  1102. package/src/tmt.ts +462 -0
  1103. package/src/tokens.test.ts +178 -0
  1104. package/src/tokens.ts +279 -0
  1105. package/src/topics.ts +147 -0
  1106. package/src/training-export/cli-date-validation.test.ts +258 -0
  1107. package/src/training-export/converter.test.ts +452 -0
  1108. package/src/training-export/converter.ts +319 -0
  1109. package/src/training-export/date-parse.ts +117 -0
  1110. package/src/training-export/index.ts +26 -0
  1111. package/src/training-export/registry.test.ts +85 -0
  1112. package/src/training-export/registry.ts +57 -0
  1113. package/src/training-export/types.ts +31 -0
  1114. package/src/transcript.ts +1179 -0
  1115. package/src/transfer/autodetect.ts +30 -0
  1116. package/src/transfer/backup.ts +138 -0
  1117. package/src/transfer/capsule-crypto.ts +485 -0
  1118. package/src/transfer/capsule-encrypt.test.ts +690 -0
  1119. package/src/transfer/capsule-export.ts +543 -0
  1120. package/src/transfer/capsule-fork.ts +375 -0
  1121. package/src/transfer/capsule-import.ts +564 -0
  1122. package/src/transfer/capsule-merge.ts +433 -0
  1123. package/src/transfer/conflict-policy.ts +16 -0
  1124. package/src/transfer/constants.ts +13 -0
  1125. package/src/transfer/exclusions.ts +37 -0
  1126. package/src/transfer/export-json.ts +65 -0
  1127. package/src/transfer/export-md.ts +59 -0
  1128. package/src/transfer/export-sqlite.ts +52 -0
  1129. package/src/transfer/fs-utils.ts +269 -0
  1130. package/src/transfer/import-json.ts +108 -0
  1131. package/src/transfer/import-md.ts +84 -0
  1132. package/src/transfer/import-sqlite.ts +100 -0
  1133. package/src/transfer/integrity.ts +71 -0
  1134. package/src/transfer/sqlite-schema.ts +16 -0
  1135. package/src/transfer/types.ts +297 -0
  1136. package/src/trust-zones.ts +1186 -0
  1137. package/src/types.ts +3074 -0
  1138. package/src/user-model.test.ts +124 -0
  1139. package/src/user-model.ts +162 -0
  1140. package/src/utility-learner.ts +353 -0
  1141. package/src/utility-runtime.ts +88 -0
  1142. package/src/utility-telemetry.ts +215 -0
  1143. package/src/utils/category-dir.ts +44 -0
  1144. package/src/utils/errno.ts +6 -0
  1145. package/src/utils/iso-timestamp.test.ts +37 -0
  1146. package/src/utils/iso-timestamp.ts +164 -0
  1147. package/src/utils/path.ts +26 -0
  1148. package/src/verified-recall.ts +138 -0
  1149. package/src/version-utils.test.ts +10 -0
  1150. package/src/version-utils.ts +9 -0
  1151. package/src/whitespace.ts +10 -0
  1152. package/src/work/board.ts +359 -0
  1153. package/src/work/boundary.ts +107 -0
  1154. package/src/work/storage.ts +436 -0
  1155. package/src/work/types.ts +82 -0
  1156. package/src/work-product-ledger.ts +265 -0
  1157. package/dist/access-service-DDjzFALq.d.ts +0 -2088
  1158. package/dist/capsule-crypto-SJS5VVAP.js +0 -18
  1159. package/dist/capsule-export-7QNCBZOQ.js +0 -17
  1160. package/dist/capsule-import-EPBHD2EN.js +0 -16
  1161. package/dist/capsule-merge-DI7PNQ2H.js +0 -189
  1162. package/dist/chunk-23ZZK64Y.js +0 -26
  1163. package/dist/chunk-23ZZK64Y.js.map +0 -1
  1164. package/dist/chunk-242S3I2A.js +0 -647
  1165. package/dist/chunk-2LGMW3DJ.js +0 -111
  1166. package/dist/chunk-3B6KIRBH.js +0 -5213
  1167. package/dist/chunk-3B6KIRBH.js.map +0 -1
  1168. package/dist/chunk-457A4P3L.js +0 -119
  1169. package/dist/chunk-457A4P3L.js.map +0 -1
  1170. package/dist/chunk-4IS4SXIQ.js +0 -2040
  1171. package/dist/chunk-4YM32CRU.js +0 -721
  1172. package/dist/chunk-6TBWYBJ3.js +0 -236
  1173. package/dist/chunk-74EMIVE4.js +0 -329
  1174. package/dist/chunk-74EMIVE4.js.map +0 -1
  1175. package/dist/chunk-767ODGE6.js +0 -183
  1176. package/dist/chunk-7V22HTMD.js +0 -623
  1177. package/dist/chunk-7V22HTMD.js.map +0 -1
  1178. package/dist/chunk-7ZM3BFKK.js +0 -9705
  1179. package/dist/chunk-7ZM3BFKK.js.map +0 -1
  1180. package/dist/chunk-AQJNPMOA.js +0 -643
  1181. package/dist/chunk-AQJNPMOA.js.map +0 -1
  1182. package/dist/chunk-ASAITVLA.js +0 -64
  1183. package/dist/chunk-ASAITVLA.js.map +0 -1
  1184. package/dist/chunk-BBE34QBJ.js +0 -275
  1185. package/dist/chunk-BBE34QBJ.js.map +0 -1
  1186. package/dist/chunk-BZSQEPRW.js +0 -14710
  1187. package/dist/chunk-BZSQEPRW.js.map +0 -1
  1188. package/dist/chunk-CPKTBRS2.js +0 -891
  1189. package/dist/chunk-CPKTBRS2.js.map +0 -1
  1190. package/dist/chunk-D4GAOFF6.js +0 -562
  1191. package/dist/chunk-D4GAOFF6.js.map +0 -1
  1192. package/dist/chunk-D54LZC5L.js +0 -147
  1193. package/dist/chunk-DF3RVK3X.js +0 -119
  1194. package/dist/chunk-DF3RVK3X.js.map +0 -1
  1195. package/dist/chunk-DZZPC36E.js +0 -1451
  1196. package/dist/chunk-DZZPC36E.js.map +0 -1
  1197. package/dist/chunk-E2UCDP5S.js +0 -570
  1198. package/dist/chunk-E6K4NIEU.js +0 -747
  1199. package/dist/chunk-E6K4NIEU.js.map +0 -1
  1200. package/dist/chunk-EEQLFRUM.js +0 -89
  1201. package/dist/chunk-ETOW6ACV.js +0 -158
  1202. package/dist/chunk-ETOW6ACV.js.map +0 -1
  1203. package/dist/chunk-FMEBPEAO.js +0 -347
  1204. package/dist/chunk-FMEBPEAO.js.map +0 -1
  1205. package/dist/chunk-FQDPCE3I.js +0 -1837
  1206. package/dist/chunk-FQDPCE3I.js.map +0 -1
  1207. package/dist/chunk-FYIYMQ5N.js +0 -221
  1208. package/dist/chunk-FYIYMQ5N.js.map +0 -1
  1209. package/dist/chunk-G2WADRQ3.js +0 -219
  1210. package/dist/chunk-G4SK7DSQ.js +0 -121
  1211. package/dist/chunk-GVPWB7EY.js +0 -390
  1212. package/dist/chunk-GVPWB7EY.js.map +0 -1
  1213. package/dist/chunk-HELQZFZO.js +0 -1075
  1214. package/dist/chunk-HL5LRPNA.js +0 -1914
  1215. package/dist/chunk-HL5LRPNA.js.map +0 -1
  1216. package/dist/chunk-HQZVVSVB.js +0 -147
  1217. package/dist/chunk-HQZVVSVB.js.map +0 -1
  1218. package/dist/chunk-HY3L4WKC.js +0 -2195
  1219. package/dist/chunk-HY3L4WKC.js.map +0 -1
  1220. package/dist/chunk-IB3BFHGN.js +0 -228
  1221. package/dist/chunk-IXEJRKCZ.js +0 -18
  1222. package/dist/chunk-JBMSGZEQ.js +0 -441
  1223. package/dist/chunk-JBMSGZEQ.js.map +0 -1
  1224. package/dist/chunk-JESOB2HO.js +0 -108
  1225. package/dist/chunk-JKDVIE52.js +0 -272
  1226. package/dist/chunk-JRNQ3RNA.js +0 -284
  1227. package/dist/chunk-JRNQ3RNA.js.map +0 -1
  1228. package/dist/chunk-K6WK37A6.js +0 -865
  1229. package/dist/chunk-K6WK37A6.js.map +0 -1
  1230. package/dist/chunk-MARWOCVP.js +0 -48
  1231. package/dist/chunk-MNU6ZBWT.js +0 -4454
  1232. package/dist/chunk-MNU6ZBWT.js.map +0 -1
  1233. package/dist/chunk-N5AKDXAI.js +0 -74
  1234. package/dist/chunk-OA3L7BFR.js +0 -183
  1235. package/dist/chunk-OA3L7BFR.js.map +0 -1
  1236. package/dist/chunk-OR64ZGRZ.js +0 -23
  1237. package/dist/chunk-P77UEOU2.js +0 -1521
  1238. package/dist/chunk-P77UEOU2.js.map +0 -1
  1239. package/dist/chunk-PH4C2U43.js +0 -239
  1240. package/dist/chunk-PH4C2U43.js.map +0 -1
  1241. package/dist/chunk-RVPLBATS.js +0 -1586
  1242. package/dist/chunk-RVPLBATS.js.map +0 -1
  1243. package/dist/chunk-U5JMRGKX.js +0 -340
  1244. package/dist/chunk-U5JMRGKX.js.map +0 -1
  1245. package/dist/chunk-URB2WSKZ.js +0 -350
  1246. package/dist/chunk-URB2WSKZ.js.map +0 -1
  1247. package/dist/chunk-UVMUAWVT.js +0 -596
  1248. package/dist/chunk-WEJG4TB5.js +0 -118
  1249. package/dist/chunk-X7HPGUVG.js +0 -271
  1250. package/dist/chunk-XAMBKFQS.js +0 -2777
  1251. package/dist/chunk-XAMBKFQS.js.map +0 -1
  1252. package/dist/chunk-XJKFSSDW.js +0 -726
  1253. package/dist/chunk-XJKFSSDW.js.map +0 -1
  1254. package/dist/chunk-XMHBH5H6.js +0 -283
  1255. package/dist/chunk-XMHBH5H6.js.map +0 -1
  1256. package/dist/chunk-XMVFHBHT.js +0 -277
  1257. package/dist/chunk-Y3VMVTYX.js +0 -53
  1258. package/dist/chunk-YNB73F22.js +0 -137
  1259. package/dist/chunk-YNB73F22.js.map +0 -1
  1260. package/dist/chunk-Z2E7VW55.js +0 -335
  1261. package/dist/chunk-Z2E7VW55.js.map +0 -1
  1262. package/dist/chunk-ZG7PTKBK.js +0 -2296
  1263. package/dist/chunk-ZNQN6ZTA.js +0 -135
  1264. package/dist/chunk-ZVTKDVVM.js +0 -827
  1265. package/dist/chunk-ZVTKDVVM.js.map +0 -1
  1266. package/dist/cli-BR8KpIU0.d.ts +0 -1259
  1267. package/dist/codex-materialize-CQlLTzke.d.ts +0 -139
  1268. package/dist/connectors-cli-DFGtY2DB.d.ts +0 -257
  1269. package/dist/contradiction-review-5LTTVDQV.js +0 -22
  1270. package/dist/contradiction-scan-QTXAMBUA.js +0 -414
  1271. package/dist/contradiction-scan-QTXAMBUA.js.map +0 -1
  1272. package/dist/engine-35M5BKQ7.js +0 -28
  1273. package/dist/fs-utils-IRVUFB6G.js +0 -30
  1274. package/dist/graph-edge-decay-PWB63GRE.js +0 -207
  1275. package/dist/memory-governance-IMPQZXFC.js +0 -37
  1276. package/dist/memory-projection-store-CY8TU40w.d.ts +0 -222
  1277. package/dist/orchestrator-DDMPqU6R.d.ts +0 -1792
  1278. package/dist/path-RMTY5Y5A.js +0 -9
  1279. package/dist/port-B6VEDIkC.d.ts +0 -53
  1280. package/dist/resolution-YGIBORXI.js +0 -101
  1281. package/dist/resolution-YGIBORXI.js.map +0 -1
  1282. package/dist/secure-store-4R2GSO7S.js +0 -156
  1283. package/dist/semantic-consolidation-ByBXb-sf.d.ts +0 -180
  1284. package/dist/state-store-3EH7HYIN.js +0 -16
  1285. package/dist/types-V3FJ26TF.js +0 -30
  1286. /package/dist/{capsule-crypto-SJS5VVAP.js.map → adapters/claude-code.js.map} +0 -0
  1287. /package/dist/{capsule-export-7QNCBZOQ.js.map → adapters/codex.js.map} +0 -0
  1288. /package/dist/{capsule-import-EPBHD2EN.js.map → adapters/hermes.js.map} +0 -0
  1289. /package/dist/{contradiction-review-5LTTVDQV.js.map → adapters/index.js.map} +0 -0
  1290. /package/dist/{engine-35M5BKQ7.js.map → adapters/registry.js.map} +0 -0
  1291. /package/dist/{fs-utils-IRVUFB6G.js.map → adapters/replit.js.map} +0 -0
  1292. /package/dist/{memory-governance-IMPQZXFC.js.map → adapters/types.js.map} +0 -0
  1293. /package/dist/{path-RMTY5Y5A.js.map → capsule-crypto-5CYAGVC5.js.map} +0 -0
  1294. /package/dist/{capsule-merge-DI7PNQ2H.js.map → capsule-merge-4MGKE7C5.js.map} +0 -0
  1295. /package/dist/{chunk-G4SK7DSQ.js.map → chunk-2WWLHTZY.js.map} +0 -0
  1296. /package/dist/{chunk-X7HPGUVG.js.map → chunk-4CRG46BG.js.map} +0 -0
  1297. /package/dist/{chunk-UVMUAWVT.js.map → chunk-7IASACLB.js.map} +0 -0
  1298. /package/dist/{chunk-HELQZFZO.js.map → chunk-EDTHC6UD.js.map} +0 -0
  1299. /package/dist/{chunk-4YM32CRU.js.map → chunk-EFJ3MQ4V.js.map} +0 -0
  1300. /package/dist/{chunk-E2UCDP5S.js.map → chunk-FBYESMQ2.js.map} +0 -0
  1301. /package/dist/{chunk-D54LZC5L.js.map → chunk-FDU6HUUL.js.map} +0 -0
  1302. /package/dist/{chunk-IB3BFHGN.js.map → chunk-GGKRUQOO.js.map} +0 -0
  1303. /package/dist/{chunk-242S3I2A.js.map → chunk-GL6I6MEQ.js.map} +0 -0
  1304. /package/dist/{secure-store-4R2GSO7S.js.map → chunk-HHLLAQGZ.js.map} +0 -0
  1305. /package/dist/{chunk-4IS4SXIQ.js.map → chunk-HXXBL2KD.js.map} +0 -0
  1306. /package/dist/{chunk-767ODGE6.js.map → chunk-KNKUID7G.js.map} +0 -0
  1307. /package/dist/{chunk-6TBWYBJ3.js.map → chunk-LPMVBPA3.js.map} +0 -0
  1308. /package/dist/{chunk-WEJG4TB5.js.map → chunk-MC26UJIM.js.map} +0 -0
  1309. /package/dist/{chunk-JKDVIE52.js.map → chunk-MGKYQQYF.js.map} +0 -0
  1310. /package/dist/{chunk-Y3VMVTYX.js.map → chunk-MT4HVDUZ.js.map} +0 -0
  1311. /package/dist/{chunk-G2WADRQ3.js.map → chunk-MY6TPVXW.js.map} +0 -0
  1312. /package/dist/{chunk-OR64ZGRZ.js.map → chunk-NNVTUXEB.js.map} +0 -0
  1313. /package/dist/{chunk-JESOB2HO.js.map → chunk-P4NEIHUT.js.map} +0 -0
  1314. /package/dist/{chunk-IXEJRKCZ.js.map → chunk-QRNI5JBH.js.map} +0 -0
  1315. /package/dist/{chunk-EEQLFRUM.js.map → chunk-RRF5UOBJ.js.map} +0 -0
  1316. /package/dist/{state-store-3EH7HYIN.js.map → chunk-SEDEKFYQ.js.map} +0 -0
  1317. /package/dist/{chunk-2LGMW3DJ.js.map → chunk-U3PN77QT.js.map} +0 -0
  1318. /package/dist/{chunk-XMVFHBHT.js.map → chunk-U3WSW6PZ.js.map} +0 -0
  1319. /package/dist/{chunk-N5AKDXAI.js.map → chunk-UWVJF25J.js.map} +0 -0
  1320. /package/dist/{types-V3FJ26TF.js.map → chunk-V5OCT34X.js.map} +0 -0
  1321. /package/dist/{chunk-ZG7PTKBK.js.map → chunk-W3LR522O.js.map} +0 -0
  1322. /package/dist/{chunk-MARWOCVP.js.map → chunk-XIG5PDM7.js.map} +0 -0
  1323. /package/dist/{chunk-ZNQN6ZTA.js.map → chunk-XVZ7B3HG.js.map} +0 -0
  1324. /package/dist/{graph-edge-decay-PWB63GRE.js.map → graph-edge-decay-5DI5GUNL.js.map} +0 -0
@@ -0,0 +1,1535 @@
1
+ /**
2
+ * Regression tests for 5 reviewer findings on the daily briefing module.
3
+ * All fixtures are synthetic — no real user data.
4
+ */
5
+
6
+ import assert from "node:assert/strict";
7
+ import test from "node:test";
8
+
9
+ import {
10
+ filterMemoriesByWindow,
11
+ buildRecentEntities,
12
+ eventFallsOnDate,
13
+ parseIcsEvents,
14
+ parseBriefingWindow,
15
+ validateBriefingFormat,
16
+ focusMatchesMemory,
17
+ buildActiveThreads,
18
+ buildBriefing,
19
+ BRIEFING_FOLLOWUP_DEFAULT_MODEL,
20
+ } from "./briefing.js";
21
+ import type {
22
+ MemoryFile,
23
+ EntityFile,
24
+ CalendarEvent,
25
+ BriefingFocus,
26
+ CalendarSource,
27
+ } from "./types.js";
28
+ import type { StorageManager } from "./storage.js";
29
+
30
+ // ──────────────────────────────────────────────────────────────────────────
31
+ // Helpers — synthetic fixtures
32
+ // ──────────────────────────────────────────────────────────────────────────
33
+
34
+ function makeMemory(updated: string): MemoryFile {
35
+ return {
36
+ path: "/synthetic/mem.md",
37
+ frontmatter: {
38
+ id: "test-mem",
39
+ category: "fact",
40
+ created: updated,
41
+ updated,
42
+ source: "test",
43
+ confidence: 0.9,
44
+ confidenceTier: "explicit",
45
+ tags: [],
46
+ },
47
+ content: "synthetic memory",
48
+ };
49
+ }
50
+
51
+ function makeEntity(updated: string): EntityFile {
52
+ return {
53
+ name: "SyntheticEntity",
54
+ type: "project",
55
+ updated,
56
+ facts: ["synthetic fact"],
57
+ timeline: [],
58
+ relationships: [],
59
+ activity: [],
60
+ aliases: [],
61
+ };
62
+ }
63
+
64
+ function makeWindow(fromIso: string, toIso: string) {
65
+ return {
66
+ from: new Date(fromIso),
67
+ to: new Date(toIso),
68
+ label: "test-window",
69
+ };
70
+ }
71
+
72
+ function makeCalendarEvent(start: string): CalendarEvent {
73
+ return { id: "evt-synthetic-1", title: "Test Event", start };
74
+ }
75
+
76
+ // ──────────────────────────────────────────────────────────────────────────
77
+ // Finding 1 — window upper bound uses exclusive check (ts < toMs)
78
+ // ──────────────────────────────────────────────────────────────────────────
79
+
80
+ test("filterMemoriesByWindow: memory at exact window.to is excluded (exclusive upper bound)", () => {
81
+ // Window: [2026-04-10T00:00:00Z, 2026-04-11T00:00:00Z)
82
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
83
+
84
+ // A memory timestamped exactly at midnight — must NOT appear in yesterday's window,
85
+ // or it would double-count against today's window.
86
+ const atMidnight = makeMemory("2026-04-11T00:00:00.000Z");
87
+ const insideWindow = makeMemory("2026-04-10T12:00:00.000Z");
88
+
89
+ const result = filterMemoriesByWindow([atMidnight, insideWindow], window);
90
+ assert.equal(result.length, 1, "only the memory inside the window should be included");
91
+ assert.equal(result[0], insideWindow);
92
+ });
93
+
94
+ test("filterMemoriesByWindow: memory at window.from (inclusive) is included", () => {
95
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
96
+ const atFrom = makeMemory("2026-04-10T00:00:00.000Z");
97
+ const result = filterMemoriesByWindow([atFrom], window);
98
+ assert.equal(result.length, 1);
99
+ });
100
+
101
+ // ──────────────────────────────────────────────────────────────────────────
102
+ // Finding 2 — runBriefingTool removed (verify no public export)
103
+ // ──────────────────────────────────────────────────────────────────────────
104
+
105
+ test("runBriefingTool is not exported from briefing module", async () => {
106
+ const mod = await import("./briefing.js");
107
+ assert.equal(
108
+ (mod as Record<string, unknown>)["runBriefingTool"],
109
+ undefined,
110
+ "runBriefingTool should not be exported",
111
+ );
112
+ });
113
+
114
+ // ──────────────────────────────────────────────────────────────────────────
115
+ // Finding 4 — buildRecentEntities respects upper bound (window.to exclusive)
116
+ // ──────────────────────────────────────────────────────────────────────────
117
+
118
+ test("buildRecentEntities: entity updated after window.to is excluded", () => {
119
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
120
+
121
+ // Entity updated today (after window end) — should be excluded from yesterday's briefing.
122
+ const futureEntity = makeEntity("2026-04-11T08:00:00.000Z");
123
+ const inWindowEntity = makeEntity("2026-04-10T15:00:00.000Z");
124
+
125
+ const result = buildRecentEntities([futureEntity, inWindowEntity], window, null);
126
+ assert.equal(result.length, 1, "entity updated after window.to should be excluded");
127
+ assert.equal(result[0]!.name, "SyntheticEntity");
128
+ assert.equal(result[0]!.updatedAt, "2026-04-10T15:00:00.000Z");
129
+ });
130
+
131
+ test("buildRecentEntities: entity updated exactly at window.to is excluded (exclusive)", () => {
132
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
133
+ const atTo = makeEntity("2026-04-11T00:00:00.000Z");
134
+ const result = buildRecentEntities([atTo], window, null);
135
+ assert.equal(result.length, 0, "entity at exact window.to must be excluded");
136
+ });
137
+
138
+ // ──────────────────────────────────────────────────────────────────────────
139
+ // Finding 5 — eventFallsOnDate uses UTC date, not raw slice
140
+ // ──────────────────────────────────────────────────────────────────────────
141
+
142
+ test("eventFallsOnDate: ISO timestamp with negative UTC offset is normalised to UTC date", () => {
143
+ // 2026-04-10T23:30:00-02:00 is 2026-04-11T01:30:00Z — should match 2026-04-11, not 2026-04-10
144
+ const event = makeCalendarEvent("2026-04-10T23:30:00-02:00");
145
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true, "UTC date should be 2026-04-11");
146
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), false, "local date slice would give wrong result");
147
+ });
148
+
149
+ test("eventFallsOnDate: plain UTC ISO timestamp matches target date", () => {
150
+ const event = makeCalendarEvent("2026-04-11T01:30:00Z");
151
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true);
152
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), false);
153
+ });
154
+
155
+ // ──────────────────────────────────────────────────────────────────────────
156
+ // Regression — Bug 3 (#396): invalid event.start must not throw RangeError
157
+ // ──────────────────────────────────────────────────────────────────────────
158
+
159
+ test("eventFallsOnDate: invalid start string returns false and does not throw", () => {
160
+ const event = makeCalendarEvent("not-a-date");
161
+ assert.doesNotThrow(() => {
162
+ const result = eventFallsOnDate(event, "2026-04-11");
163
+ assert.equal(result, false, "invalid start should be treated as non-matching");
164
+ });
165
+ });
166
+
167
+ test("eventFallsOnDate: empty start string returns false and does not throw", () => {
168
+ const event = makeCalendarEvent("");
169
+ assert.doesNotThrow(() => {
170
+ const result = eventFallsOnDate(event, "2026-04-11");
171
+ assert.equal(result, false);
172
+ });
173
+ });
174
+
175
+ // ──────────────────────────────────────────────────────────────────────────
176
+ // Finding 2 (#396): ICS floating-time events must not be shifted by server TZ
177
+ // ──────────────────────────────────────────────────────────────────────────
178
+
179
+ test("eventFallsOnDate: floating time 01:00 (early morning) matches its calendar day", () => {
180
+ // "20260411T010000" → normalizeIcsDate → "2026-04-11T01:00:00" (no Z).
181
+ // On a server at UTC-8 this would incorrectly become 2026-04-10 if
182
+ // round-tripped through new Date().toISOString().
183
+ const event = makeCalendarEvent("2026-04-11T01:00:00");
184
+ assert.equal(
185
+ eventFallsOnDate(event, "2026-04-11"),
186
+ true,
187
+ "01:00 floating time must match its own calendar day",
188
+ );
189
+ assert.equal(
190
+ eventFallsOnDate(event, "2026-04-10"),
191
+ false,
192
+ "01:00 floating time must NOT match the previous calendar day",
193
+ );
194
+ });
195
+
196
+ test("eventFallsOnDate: floating time 23:00 (late night) matches its calendar day", () => {
197
+ const event = makeCalendarEvent("2026-04-11T23:00:00");
198
+ assert.equal(
199
+ eventFallsOnDate(event, "2026-04-11"),
200
+ true,
201
+ "23:00 floating time must match its own calendar day",
202
+ );
203
+ assert.equal(
204
+ eventFallsOnDate(event, "2026-04-12"),
205
+ false,
206
+ "23:00 floating time must NOT match the following calendar day",
207
+ );
208
+ });
209
+
210
+ test("eventFallsOnDate: Z-suffixed UTC time compares against UTC date", () => {
211
+ // 2026-04-11T01:30:00Z — UTC date is 2026-04-11
212
+ const event = makeCalendarEvent("2026-04-11T01:30:00Z");
213
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true);
214
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), false);
215
+ });
216
+
217
+ // ──────────────────────────────────────────────────────────────────────────
218
+ // Finding 4 (#396): superseded/archived memories must not appear in briefing
219
+ // ──────────────────────────────────────────────────────────────────────────
220
+
221
+ function makeMemoryWithStatus(
222
+ updated: string,
223
+ status?:
224
+ | "active"
225
+ | "superseded"
226
+ | "archived"
227
+ | "forgotten"
228
+ | "pending_review"
229
+ | "rejected"
230
+ | "quarantined",
231
+ ): MemoryFile {
232
+ return {
233
+ path: "/synthetic/mem.md",
234
+ frontmatter: {
235
+ id: "test-mem-status",
236
+ category: "commitment",
237
+ created: updated,
238
+ updated,
239
+ source: "test",
240
+ confidence: 0.9,
241
+ confidenceTier: "explicit",
242
+ tags: ["pending"],
243
+ status,
244
+ },
245
+ content: "Follow up on this commitment.",
246
+ };
247
+ }
248
+
249
+ test("filterMemoriesByWindow: superseded commitment within window is excluded", () => {
250
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
251
+ const superseded = makeMemoryWithStatus("2026-04-10T10:00:00.000Z", "superseded");
252
+ const active = makeMemoryWithStatus("2026-04-10T11:00:00.000Z", "active");
253
+ const noStatus = makeMemoryWithStatus("2026-04-10T12:00:00.000Z", undefined);
254
+
255
+ const result = filterMemoriesByWindow([superseded, active, noStatus], window);
256
+ assert.equal(result.length, 2, "superseded memory must be excluded");
257
+ assert.ok(!result.some((m) => m.frontmatter.status === "superseded"), "no superseded in result");
258
+ });
259
+
260
+ test("filterMemoriesByWindow: archived memory within window is excluded", () => {
261
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
262
+ const archived = makeMemoryWithStatus("2026-04-10T10:00:00.000Z", "archived");
263
+ const result = filterMemoriesByWindow([archived], window);
264
+ assert.equal(result.length, 0, "archived memory must be excluded from briefing");
265
+ });
266
+
267
+ test("filterMemoriesByWindow: rejected memory within window is excluded from briefing", () => {
268
+ // Governance/disposition workflows mark unsafe or invalid memories as
269
+ // `rejected`. filterMemoriesByWindow must NOT leak them into briefings or
270
+ // downstream follow-up generation, since they represent content explicitly
271
+ // flagged as not-actionable.
272
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
273
+ const rejected = makeMemoryWithStatus("2026-04-10T10:00:00.000Z", "rejected");
274
+ const active = makeMemoryWithStatus("2026-04-10T11:00:00.000Z", "active");
275
+ const result = filterMemoriesByWindow([rejected, active], window);
276
+ assert.equal(result.length, 1, "rejected memory must be excluded from briefing");
277
+ assert.equal(result[0]!.frontmatter.status, "active");
278
+ });
279
+
280
+ test("filterMemoriesByWindow: quarantined memory within window is excluded from briefing", () => {
281
+ // Quarantined memories have been flagged as unsafe by governance review.
282
+ // They must not surface in the briefing, even within the time window.
283
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
284
+ const quarantined = makeMemoryWithStatus("2026-04-10T10:00:00.000Z", "quarantined");
285
+ const active = makeMemoryWithStatus("2026-04-10T11:00:00.000Z", "active");
286
+ const result = filterMemoriesByWindow([quarantined, active], window);
287
+ assert.equal(result.length, 1, "quarantined memory must be excluded from briefing");
288
+ assert.equal(result[0]!.frontmatter.status, "active");
289
+ });
290
+
291
+ test("filterMemoriesByWindow: forgotten memory within window is excluded from briefing", () => {
292
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
293
+ const forgotten = makeMemoryWithStatus("2026-04-10T10:00:00.000Z", "forgotten");
294
+ const active = makeMemoryWithStatus("2026-04-10T11:00:00.000Z", "active");
295
+ const result = filterMemoriesByWindow([forgotten, active], window);
296
+ assert.equal(result.length, 1, "forgotten memory must be excluded from briefing");
297
+ assert.equal(result[0]!.frontmatter.status, "active");
298
+ });
299
+
300
+ test("filterMemoriesByWindow: active and undefined-status memories within window are included", () => {
301
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
302
+ const active = makeMemoryWithStatus("2026-04-10T10:00:00.000Z", "active");
303
+ const noStatus = makeMemoryWithStatus("2026-04-10T11:00:00.000Z", undefined);
304
+ const result = filterMemoriesByWindow([active, noStatus], window);
305
+ assert.equal(result.length, 2, "active and status-less memories must be included");
306
+ });
307
+
308
+ // ──────────────────────────────────────────────────────────────────────────
309
+ // Finding A (#396): pending_review memories must be included in briefings
310
+ // ──────────────────────────────────────────────────────────────────────────
311
+
312
+ test("filterMemoriesByWindow: pending_review memory within window is included", () => {
313
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
314
+ const pendingReview = makeMemoryWithStatus("2026-04-10T10:00:00.000Z", "pending_review");
315
+ const result = filterMemoriesByWindow([pendingReview], window);
316
+ assert.equal(result.length, 1, "pending_review memory must be included in briefing");
317
+ assert.equal(result[0]!.frontmatter.status, "pending_review");
318
+ });
319
+
320
+ test("filterMemoriesByWindow: archived memory is excluded but pending_review is included together", () => {
321
+ const window = makeWindow("2026-04-10T00:00:00.000Z", "2026-04-11T00:00:00.000Z");
322
+ const archived = makeMemoryWithStatus("2026-04-10T09:00:00.000Z", "archived");
323
+ const superseded = makeMemoryWithStatus("2026-04-10T10:00:00.000Z", "superseded");
324
+ const pendingReview = makeMemoryWithStatus("2026-04-10T11:00:00.000Z", "pending_review");
325
+ const active = makeMemoryWithStatus("2026-04-10T12:00:00.000Z", "active");
326
+
327
+ const result = filterMemoriesByWindow([archived, superseded, pendingReview, active], window);
328
+ assert.equal(result.length, 2, "only archived and superseded should be excluded");
329
+ assert.ok(result.some((m) => m.frontmatter.status === "pending_review"), "pending_review must be present");
330
+ assert.ok(result.some((m) => m.frontmatter.status === "active"), "active must be present");
331
+ assert.ok(!result.some((m) => m.frontmatter.status === "archived"), "archived must not be present");
332
+ assert.ok(!result.some((m) => m.frontmatter.status === "superseded"), "superseded must not be present");
333
+ });
334
+
335
+ // ──────────────────────────────────────────────────────────────────────────
336
+ // Finding 7 (#396): --format flag must reject invalid values
337
+ // ──────────────────────────────────────────────────────────────────────────
338
+
339
+ test("validateBriefingFormat: returns null for valid format values", () => {
340
+ assert.equal(validateBriefingFormat("markdown"), null);
341
+ assert.equal(validateBriefingFormat("json"), null);
342
+ });
343
+
344
+ test("validateBriefingFormat: rejects 'text' (not a supported output format)", () => {
345
+ const err = validateBriefingFormat("text");
346
+ assert.ok(typeof err === "string" && err.length > 0, "'text' is not a supported format and must be rejected");
347
+ assert.match(err, /text/, "error message should include the rejected value");
348
+ });
349
+
350
+ test("validateBriefingFormat: returns null when value is undefined (flag not supplied)", () => {
351
+ assert.equal(validateBriefingFormat(undefined), null, "absent flag must not produce an error");
352
+ });
353
+
354
+ test("validateBriefingFormat: returns error string for invalid values like 'jsno'", () => {
355
+ const err = validateBriefingFormat("jsno");
356
+ assert.ok(typeof err === "string" && err.length > 0, "typo should produce an error message");
357
+ assert.match(err, /jsno/, "error should include the invalid value");
358
+ });
359
+
360
+ // ──────────────────────────────────────────────────────────────────────────
361
+ // Finding C (#396): compact timezone offsets (±HHMM) must be treated as
362
+ // offset-aware (not floating) so events land on the correct UTC date.
363
+ // ──────────────────────────────────────────────────────────────────────────
364
+
365
+ test("eventFallsOnDate: compact negative offset (-0200) is treated as offset-aware", () => {
366
+ // 2026-04-10T23:30:00-0200 = 2026-04-11T01:30:00Z — must match 2026-04-11, not 2026-04-10
367
+ const event = makeCalendarEvent("2026-04-10T23:30:00-0200");
368
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true, "compact -0200 should land on 2026-04-11 UTC");
369
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), false, "must not match the local date slice");
370
+ });
371
+
372
+ test("eventFallsOnDate: compact positive offset (+0530) is treated as offset-aware", () => {
373
+ // 2026-04-11T04:00:00+0530 = 2026-04-10T22:30:00Z — must match 2026-04-10, not 2026-04-11
374
+ const event = makeCalendarEvent("2026-04-11T04:00:00+0530");
375
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), true, "compact +0530 should land on 2026-04-10 UTC");
376
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), false, "must not match the local date slice");
377
+ });
378
+
379
+ test("eventFallsOnDate: compact +0000 is treated as offset-aware (same as Z)", () => {
380
+ // 2026-04-11T12:00:00+0000 = 2026-04-11T12:00:00Z
381
+ const event = makeCalendarEvent("2026-04-11T12:00:00+0000");
382
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true, "compact +0000 must match 2026-04-11");
383
+ });
384
+
385
+ test("eventFallsOnDate: floating string without any offset suffix is still treated as floating", () => {
386
+ // 2026-04-10T23:30:00 has no offset — floating, compares date portion directly
387
+ const event = makeCalendarEvent("2026-04-10T23:30:00");
388
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), true, "floating time must match its calendar day");
389
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), false, "floating time must not shift to next day");
390
+ });
391
+
392
+ test("validateBriefingFormat: rejects empty string as invalid", () => {
393
+ const err = validateBriefingFormat("");
394
+ assert.ok(typeof err === "string" && err.length > 0, "empty string is not a valid format");
395
+ });
396
+
397
+ test("validateBriefingFormat: rejects arbitrary strings", () => {
398
+ for (const bad of ["xml", "html", "plain", "MARKDOWN"]) {
399
+ const err = validateBriefingFormat(bad);
400
+ assert.ok(typeof err === "string", `"${bad}" should be rejected`);
401
+ }
402
+ });
403
+
404
+ // ──────────────────────────────────────────────────────────────────────────
405
+ // Finding 1 (#396 new): parseBriefingWindow must reject overflow/huge values
406
+ // ──────────────────────────────────────────────────────────────────────────
407
+
408
+ test("parseBriefingWindow: rejects hugely large week value that would overflow Date", () => {
409
+ // 99999999w far exceeds 100 years — must return null, not Invalid Date.
410
+ const result = parseBriefingWindow("99999999w");
411
+ assert.equal(result, null, "99999999w should be rejected as out-of-bounds");
412
+ });
413
+
414
+ test("parseBriefingWindow: rejects hugely large day value that would overflow Date", () => {
415
+ const result = parseBriefingWindow("99999999d");
416
+ assert.equal(result, null, "99999999d should be rejected as out-of-bounds");
417
+ });
418
+
419
+ test("parseBriefingWindow: rejects hugely large hour value that would overflow Date", () => {
420
+ const result = parseBriefingWindow("99999999h");
421
+ assert.equal(result, null, "99999999h should be rejected as out-of-bounds");
422
+ });
423
+
424
+ test("parseBriefingWindow: rejects a window exactly above the 100-year cap", () => {
425
+ // 36501 days = ~100.003 years — just above the 100-year limit.
426
+ const result = parseBriefingWindow("36501d");
427
+ assert.equal(result, null, "36501d exceeds 100-year cap and must be rejected");
428
+ });
429
+
430
+ test("parseBriefingWindow: accepts a reasonable 10-year (3650d) window", () => {
431
+ // 3650d ≈ 10 years — well within the 100-year cap.
432
+ const result = parseBriefingWindow("3650d");
433
+ assert.ok(result !== null, "3650d (≈10 years) should be accepted");
434
+ assert.equal(result.label, "last 3650d");
435
+ assert.ok(Number.isFinite(result.from.getTime()), "from must be a valid Date");
436
+ });
437
+
438
+ test("parseBriefingWindow: from date is always a valid finite Date for normal inputs", () => {
439
+ for (const token of ["1h", "7d", "2w", "365d", "52w"]) {
440
+ const result = parseBriefingWindow(token);
441
+ assert.ok(result !== null, `"${token}" should parse successfully`);
442
+ assert.ok(Number.isFinite(result.from.getTime()), `"${token}" from must be a valid Date`);
443
+ }
444
+ });
445
+
446
+ // ──────────────────────────────────────────────────────────────────────────
447
+ // PR #396 Finding 1: eventFallsOnDate — overlapping / multi-day events
448
+ // ──────────────────────────────────────────────────────────────────────────
449
+
450
+ function makeCalendarEventWithEnd(start: string, end: string): CalendarEvent {
451
+ return { id: "evt-synthetic-span", title: "Span Event", start, end };
452
+ }
453
+
454
+ test("eventFallsOnDate: midnight-crossing event appears on both dates (UTC)", () => {
455
+ // Event 2026-04-10T23:30:00Z → 2026-04-11T01:00:00Z spans midnight UTC.
456
+ // It should be visible on both 2026-04-10 and 2026-04-11.
457
+ const event = makeCalendarEventWithEnd("2026-04-10T23:30:00Z", "2026-04-11T01:00:00Z");
458
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), true, "spans midnight — must appear on start date");
459
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true, "spans midnight — must appear on end date");
460
+ assert.equal(eventFallsOnDate(event, "2026-04-09"), false, "must not appear before start date");
461
+ assert.equal(eventFallsOnDate(event, "2026-04-12"), false, "must not appear after end date");
462
+ });
463
+
464
+ test("eventFallsOnDate: multi-day event appears on every day it spans", () => {
465
+ // Event from 2026-04-09T00:00:00Z to 2026-04-12T00:00:00Z spans 3 full days.
466
+ const event = makeCalendarEventWithEnd("2026-04-09T00:00:00Z", "2026-04-12T00:00:00Z");
467
+ assert.equal(eventFallsOnDate(event, "2026-04-09"), true, "must appear on day 1");
468
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), true, "must appear on day 2");
469
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true, "must appear on day 3");
470
+ // end is exactly midnight of 2026-04-12 — half-open [start, end) means it
471
+ // does NOT count as active on 2026-04-12.
472
+ assert.equal(eventFallsOnDate(event, "2026-04-12"), false, "event ending at midnight must not appear on that day");
473
+ assert.equal(eventFallsOnDate(event, "2026-04-08"), false, "must not appear before start");
474
+ });
475
+
476
+ test("eventFallsOnDate: event ending exactly at day boundary (midnight) excluded from next day", () => {
477
+ // An event ending at exactly 2026-04-11T00:00:00Z ends at the first instant
478
+ // of 2026-04-11 — half-open semantics means it is NOT active on 2026-04-11.
479
+ const event = makeCalendarEventWithEnd("2026-04-10T22:00:00Z", "2026-04-11T00:00:00Z");
480
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), true, "must appear on start date");
481
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), false, "end-at-midnight must NOT appear on next day");
482
+ });
483
+
484
+ test("eventFallsOnDate: point event (no end) still works correctly after refactor", () => {
485
+ const event = makeCalendarEvent("2026-04-11T10:00:00Z");
486
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true);
487
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), false);
488
+ });
489
+
490
+ // PR #396 round 5 — PRRT_kwDORJXyws56UJ14: same-day floating spans were dropped
491
+ // because the original fix used pure `target < endDate` lexicographic compare
492
+ // on date prefixes. A DTSTART:20260411T143000 / DTEND:20260411T150000 event
493
+ // has startDate == endDate == "2026-04-11", so `target < endDate` was false
494
+ // and the event vanished from its own calendar day.
495
+ test("eventFallsOnDate: same-day floating span (no TZID) appears on its calendar day", () => {
496
+ const event = makeCalendarEventWithEnd("2026-04-11T14:30:00", "2026-04-11T15:00:00");
497
+ assert.equal(
498
+ eventFallsOnDate(event, "2026-04-11"),
499
+ true,
500
+ "same-day floating span must match its own calendar day",
501
+ );
502
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), false);
503
+ assert.equal(eventFallsOnDate(event, "2026-04-12"), false);
504
+ });
505
+
506
+ test("eventFallsOnDate: floating span ending exactly at midnight excludes next day", () => {
507
+ // Floating 2026-04-10T22:00:00 → 2026-04-11T00:00:00 — half-open semantics
508
+ // means the end-day (2026-04-11) must NOT be included.
509
+ const event = makeCalendarEventWithEnd("2026-04-10T22:00:00", "2026-04-11T00:00:00");
510
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), true);
511
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), false);
512
+ });
513
+
514
+ test("eventFallsOnDate: floating span crossing midnight appears on both dates", () => {
515
+ // Floating 2026-04-10T23:30:00 → 2026-04-11T01:00:00 crosses the day
516
+ // boundary with a non-zero end time, so the end day is still active.
517
+ const event = makeCalendarEventWithEnd("2026-04-10T23:30:00", "2026-04-11T01:00:00");
518
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), true);
519
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true);
520
+ assert.equal(eventFallsOnDate(event, "2026-04-12"), false);
521
+ });
522
+
523
+ // ──────────────────────────────────────────────────────────────────────────
524
+ // PR #396 Finding 2: parseIcsEvents — RFC 5545 line unfolding
525
+ // ──────────────────────────────────────────────────────────────────────────
526
+
527
+ test("parseIcsEvents: folded SUMMARY line (space continuation) is unfolded correctly", () => {
528
+ // RFC 5545 §3.1 line folding: CRLF followed by a single whitespace character
529
+ // is a fold — the CRLF + that one whitespace byte are removed entirely when
530
+ // unfolding. Real ICS encoders place the fold at a convenient byte boundary;
531
+ // any space that is part of the content appears at the END of the first
532
+ // physical line (before the CRLF), NOT at the start of the continuation.
533
+ // The leading space on the continuation line is purely the fold indicator
534
+ // and is discarded. The fixture below reflects that: the first physical line
535
+ // ends with " physical" (space is part of the value) and the continuation
536
+ // starts with " lines" (leading space is the fold marker, discarded).
537
+ const ics = [
538
+ "BEGIN:VCALENDAR",
539
+ "BEGIN:VEVENT",
540
+ "UID:test-fold-1@synthetic",
541
+ "DTSTART:20260411T100000Z",
542
+ "DTEND:20260411T110000Z",
543
+ // Content space is at end of first line; continuation space is fold marker.
544
+ "SUMMARY:This is a long summary folded across two physical ",
545
+ " lines by the ICS encoder",
546
+ "END:VEVENT",
547
+ "END:VCALENDAR",
548
+ ].join("\r\n");
549
+
550
+ const events = parseIcsEvents(ics);
551
+ assert.equal(events.length, 1, "should parse exactly one event");
552
+ assert.equal(
553
+ events[0]!.title,
554
+ "This is a long summary folded across two physical lines by the ICS encoder",
555
+ "folded SUMMARY must be unfolded into a single string (fold marker space discarded)",
556
+ );
557
+ });
558
+
559
+ test("parseIcsEvents: folded SUMMARY line (tab continuation) is unfolded correctly", () => {
560
+ // RFC 5545 allows either a space or tab as the fold whitespace character.
561
+ // The leading tab on the continuation line is the fold marker and is discarded.
562
+ const ics = [
563
+ "BEGIN:VCALENDAR",
564
+ "BEGIN:VEVENT",
565
+ "UID:test-fold-tab@synthetic",
566
+ "DTSTART:20260412T090000Z",
567
+ "DTEND:20260412T100000Z",
568
+ "SUMMARY:Tab-folded summary part one ",
569
+ "\tcontinued after a tab",
570
+ "END:VEVENT",
571
+ "END:VCALENDAR",
572
+ ].join("\r\n");
573
+
574
+ const events = parseIcsEvents(ics);
575
+ assert.equal(events.length, 1);
576
+ assert.equal(
577
+ events[0]!.title,
578
+ "Tab-folded summary part one continued after a tab",
579
+ "tab-folded SUMMARY must be joined without the fold-marker tab",
580
+ );
581
+ });
582
+
583
+ test("parseIcsEvents: unfolded ICS (no folds) is parsed unchanged", () => {
584
+ const ics = [
585
+ "BEGIN:VCALENDAR",
586
+ "BEGIN:VEVENT",
587
+ "UID:test-no-fold@synthetic",
588
+ "DTSTART:20260413T080000Z",
589
+ "DTEND:20260413T090000Z",
590
+ "SUMMARY:Simple one-line title",
591
+ "END:VEVENT",
592
+ "END:VCALENDAR",
593
+ ].join("\r\n");
594
+
595
+ const events = parseIcsEvents(ics);
596
+ assert.equal(events.length, 1);
597
+ assert.equal(events[0]!.title, "Simple one-line title");
598
+ });
599
+
600
+ // ──────────────────────────────────────────────────────────────────────────
601
+ // Regression — Bug (round 6): zonedFormatToMs must not clamp hour 24 to 0.
602
+ //
603
+ // Some Intl.DateTimeFormat implementations return "24" when the probed
604
+ // instant displays as midnight (00:00) in the target zone. The old code
605
+ // clamped this to 0 without incrementing the day, producing a wallclock-
606
+ // as-UTC value that was 24 hours behind the true value. That corrupted the
607
+ // offset calculation in icsWallclockToUtc and placed TZID-bearing ICS events
608
+ // on the wrong calendar day.
609
+ //
610
+ // The fix: pass Number(hh) directly to Date.UTC, which natively rolls
611
+ // hour=24 to 00:00:00 of the next day.
612
+ //
613
+ // Test strategy: exercise icsWallclockToUtc (private) via parseIcsEvents with
614
+ // a TZID-bearing event at exactly midnight local time in a UTC-offset zone.
615
+ // UTC+05:30 (Asia/Kolkata, no DST) is a reliable probe: midnight local is
616
+ // 18:30 the previous UTC day, so the UTC date is always one day behind the
617
+ // local date. This forces icsWallclockToUtc to perform a non-trivial offset
618
+ // calculation through zonedFormatToMs. A 24-hour clamp error in
619
+ // zonedFormatToMs would skew the offset by ±86400000 ms, landing the event
620
+ // on the wrong UTC day.
621
+ // ──────────────────────────────────────────────────────────────────────────
622
+
623
+ test("parseIcsEvents: TZID midnight event (UTC+5:30) lands on correct UTC day", () => {
624
+ // DTSTART;TZID=Asia/Kolkata:20260412T000000 = 2026-04-11T18:30:00Z
625
+ // Expected UTC date: 2026-04-11.
626
+ const ics = [
627
+ "BEGIN:VCALENDAR",
628
+ "BEGIN:VEVENT",
629
+ "UID:test-tzid-midnight-kolkata@synthetic",
630
+ "DTSTART;TZID=Asia/Kolkata:20260412T000000",
631
+ "DTEND;TZID=Asia/Kolkata:20260412T010000",
632
+ "SUMMARY:Midnight Kolkata event",
633
+ "END:VEVENT",
634
+ "END:VCALENDAR",
635
+ ].join("\r\n");
636
+
637
+ const events = parseIcsEvents(ics);
638
+ assert.equal(events.length, 1, "should parse one event");
639
+ const ev = events[0]!;
640
+ // The start must be a UTC-aware ISO string (has Z or offset suffix).
641
+ assert.ok(
642
+ ev.start.endsWith("Z") || /[+-]\d{2}:?\d{2}$/.test(ev.start),
643
+ `start "${ev.start}" must be UTC-aware (has Z or offset)`,
644
+ );
645
+ // Midnight Asia/Kolkata (+05:30) = 18:30 UTC the *previous* calendar day.
646
+ // So 2026-04-12T00:00:00+05:30 → 2026-04-11T18:30:00Z.
647
+ // The UTC date must be 2026-04-11, NOT 2026-04-12.
648
+ const utcDate = new Date(ev.start).toISOString().slice(0, 10);
649
+ assert.equal(
650
+ utcDate,
651
+ "2026-04-11",
652
+ `midnight Kolkata (UTC+5:30) must land on 2026-04-11 UTC, got "${utcDate}" from start="${ev.start}"`,
653
+ );
654
+ });
655
+
656
+ test("parseIcsEvents: TZID midnight event (UTC-5) lands on correct UTC day", () => {
657
+ // DTSTART;TZID=America/New_York:20260411T000000 in April = EDT (UTC-4).
658
+ // 2026-04-11T00:00:00 EDT = 2026-04-11T04:00:00Z.
659
+ // The UTC date must remain 2026-04-11.
660
+ const ics = [
661
+ "BEGIN:VCALENDAR",
662
+ "BEGIN:VEVENT",
663
+ "UID:test-tzid-midnight-nyc@synthetic",
664
+ "DTSTART;TZID=America/New_York:20260411T000000",
665
+ "DTEND;TZID=America/New_York:20260411T010000",
666
+ "SUMMARY:Midnight New York event",
667
+ "END:VEVENT",
668
+ "END:VCALENDAR",
669
+ ].join("\r\n");
670
+
671
+ const events = parseIcsEvents(ics);
672
+ assert.equal(events.length, 1, "should parse one event");
673
+ const ev = events[0]!;
674
+ assert.ok(
675
+ ev.start.endsWith("Z") || /[+-]\d{2}:?\d{2}$/.test(ev.start),
676
+ `start "${ev.start}" must be UTC-aware`,
677
+ );
678
+ // Midnight EDT (UTC-4): 2026-04-11T00:00:00-04:00 = 2026-04-11T04:00:00Z.
679
+ const utcDate = new Date(ev.start).toISOString().slice(0, 10);
680
+ assert.equal(
681
+ utcDate,
682
+ "2026-04-11",
683
+ `midnight New York (EDT=UTC-4) must land on 2026-04-11 UTC, got "${utcDate}" from start="${ev.start}"`,
684
+ );
685
+ });
686
+
687
+ // ──────────────────────────────────────────────────────────────────────────
688
+ // Round 5 Finding 2 (chatgpt-codex-connector): zonedFormatToMs must clamp
689
+ // Intl hour "24" to 0 on the same calendar day.
690
+ //
691
+ // Some Intl.DateTimeFormat implementations return hour="24" for midnight while
692
+ // keeping the same calendar date (rather than rolling the date forward and
693
+ // returning hour="0"). If the raw "24" is passed to Date.UTC it would roll
694
+ // the day forward, producing a UTC timestamp 24 h later than the actual
695
+ // midnight, corrupting the zone-offset calculation and misplacing TZID
696
+ // midnight events in the daily briefing.
697
+ //
698
+ // The fix: normalise hour 24 → 0 without touching the day digits so the
699
+ // resulting ms is the same midnight, not next-day midnight.
700
+ //
701
+ // Test strategy: use UTC+1 (Europe/London in summer, BST) where midnight
702
+ // local = 23:00 the prior UTC day. Verifying the UTC date is one day
703
+ // behind the local date confirms the offset calculation used the correct
704
+ // midnight, not a next-day midnight.
705
+ // ──────────────────────────────────────────────────────────────────────────
706
+
707
+ test("parseIcsEvents: TZID midnight event (UTC+1, Europe/London BST) lands on correct UTC day", () => {
708
+ // 2026-07-01T00:00:00 BST (Europe/London, UTC+1) = 2026-06-30T23:00:00Z.
709
+ // The UTC date must be 2026-06-30, one day behind the local date.
710
+ const ics = [
711
+ "BEGIN:VCALENDAR",
712
+ "BEGIN:VEVENT",
713
+ "UID:test-tzid-midnight-bst@synthetic",
714
+ "DTSTART;TZID=Europe/London:20260701T000000",
715
+ "DTEND;TZID=Europe/London:20260701T010000",
716
+ "SUMMARY:Midnight BST event",
717
+ "END:VEVENT",
718
+ "END:VCALENDAR",
719
+ ].join("\r\n");
720
+
721
+ const events = parseIcsEvents(ics);
722
+ assert.equal(events.length, 1, "should parse one event");
723
+ const ev = events[0]!;
724
+ assert.ok(
725
+ ev.start.endsWith("Z") || /[+-]\d{2}:?\d{2}$/.test(ev.start),
726
+ `start "${ev.start}" must be UTC-aware`,
727
+ );
728
+ // 2026-07-01T00:00 BST = 2026-06-30T23:00Z — UTC date is 2026-06-30.
729
+ const utcDate = new Date(ev.start).toISOString().slice(0, 10);
730
+ assert.equal(
731
+ utcDate,
732
+ "2026-06-30",
733
+ `midnight BST (UTC+1) must land on 2026-06-30 UTC, got "${utcDate}" from start="${ev.start}"`,
734
+ );
735
+ });
736
+
737
+ // ──────────────────────────────────────────────────────────────────────────
738
+ // Round 7 Finding 1 (UNBW): BRIEFING_FOLLOWUP_DEFAULT_MODEL constant must be
739
+ // exported and must be the same model string used by the extraction engine.
740
+ // ──────────────────────────────────────────────────────────────────────────
741
+
742
+ test("BRIEFING_FOLLOWUP_DEFAULT_MODEL is exported and matches canonical extraction model", () => {
743
+ // The constant must be a non-empty string.
744
+ assert.ok(
745
+ typeof BRIEFING_FOLLOWUP_DEFAULT_MODEL === "string" && BRIEFING_FOLLOWUP_DEFAULT_MODEL.length > 0,
746
+ "BRIEFING_FOLLOWUP_DEFAULT_MODEL must be a non-empty string",
747
+ );
748
+ // Must match the same model family the extraction engine defaults to ("gpt-5.5").
749
+ assert.equal(
750
+ BRIEFING_FOLLOWUP_DEFAULT_MODEL,
751
+ "gpt-5.5",
752
+ "default model must align with the extraction engine default in config.ts",
753
+ );
754
+ });
755
+
756
+ // ──────────────────────────────────────────────────────────────────────────
757
+ // Round 7 Finding 3 (UQZW): Midnight fractional end-times must be treated as
758
+ // day-exclusive, i.e. "2026-04-11T00:00:00.000" must NOT appear on 2026-04-11.
759
+ // ──────────────────────────────────────────────────────────────────────────
760
+
761
+ test("eventFallsOnDate: floating end '2026-04-11T00:00:00.000' (fractional midnight) is day-exclusive", () => {
762
+ // A cross-day floating event ending at exactly midnight WITH a fractional
763
+ // suffix (.000) was previously treated as "after midnight" by the lexicographic
764
+ // `endTime > "00:00:00"` check (because ".000" makes the string longer).
765
+ // The correct result is: the end day must be excluded (half-open [start, end)).
766
+ const event: CalendarEvent = {
767
+ id: "evt-fractional-midnight",
768
+ title: "Overnight synthetic event",
769
+ start: "2026-04-10T22:00:00",
770
+ end: "2026-04-11T00:00:00.000",
771
+ };
772
+ assert.equal(
773
+ eventFallsOnDate(event, "2026-04-10"),
774
+ true,
775
+ "event must appear on the start day",
776
+ );
777
+ assert.equal(
778
+ eventFallsOnDate(event, "2026-04-11"),
779
+ false,
780
+ "end time '00:00:00.000' is midnight — end day must be excluded under [start, end) semantics",
781
+ );
782
+ });
783
+
784
+ test("eventFallsOnDate: floating end '2026-04-11T00:00:00.001' (just after midnight) includes end day", () => {
785
+ // One millisecond past midnight — the event is still running at the start of
786
+ // 2026-04-11 and should therefore be included on that day.
787
+ const event: CalendarEvent = {
788
+ id: "evt-just-after-midnight",
789
+ title: "Just-past-midnight synthetic event",
790
+ start: "2026-04-10T22:00:00",
791
+ end: "2026-04-11T00:00:00.001",
792
+ };
793
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true,
794
+ "end time '00:00:00.001' is just past midnight — end day must be included");
795
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), true, "must appear on start day too");
796
+ });
797
+
798
+ // ──────────────────────────────────────────────────────────────────────────
799
+ // Round 7 Finding 4 (UQZa): Focus tokens must be normalised to slug form
800
+ // before matching entityRef so `person:Jane Doe` matches entityRef
801
+ // `"person-jane-doe"`.
802
+ // ──────────────────────────────────────────────────────────────────────────
803
+
804
+ function makeMemoryWithEntityRef(entityRef: string, content = "synthetic"): MemoryFile {
805
+ return {
806
+ path: "/synthetic/entity-ref-mem.md",
807
+ frontmatter: {
808
+ id: "test-slug-mem",
809
+ category: "fact",
810
+ created: "2026-04-10T10:00:00.000Z",
811
+ updated: "2026-04-10T10:00:00.000Z",
812
+ source: "test",
813
+ confidence: 0.9,
814
+ confidenceTier: "explicit",
815
+ tags: [],
816
+ entityRef,
817
+ },
818
+ content,
819
+ };
820
+ }
821
+
822
+ test("focusMatchesMemory: person:Jane Doe matches entityRef 'person-jane-doe' via slug", () => {
823
+ // entityRef is stored as a slug; the raw focus value "Jane Doe" would never
824
+ // appear in the entityRef string. The fix derives the slug form
825
+ // "person-jane-doe" and matches it against the entityRef.
826
+ const memory = makeMemoryWithEntityRef("person-jane-doe");
827
+ const focus: BriefingFocus = { type: "person", value: "Jane Doe" };
828
+ assert.equal(
829
+ focusMatchesMemory(memory, focus),
830
+ true,
831
+ "person:Jane Doe must match entityRef 'person-jane-doe' after slug normalization",
832
+ );
833
+ });
834
+
835
+ test("focusMatchesMemory: project:My Project matches entityRef 'project-my-project' via slug", () => {
836
+ const memory = makeMemoryWithEntityRef("project-my-project");
837
+ const focus: BriefingFocus = { type: "project", value: "My Project" };
838
+ assert.equal(
839
+ focusMatchesMemory(memory, focus),
840
+ true,
841
+ "project focus slug must match stored entityRef",
842
+ );
843
+ });
844
+
845
+ test("focusMatchesMemory: slug match does not produce false positives for unrelated entityRef", () => {
846
+ const memory = makeMemoryWithEntityRef("person-john-smith");
847
+ const focus: BriefingFocus = { type: "person", value: "Jane Doe" };
848
+ assert.equal(
849
+ focusMatchesMemory(memory, focus),
850
+ false,
851
+ "person-jane-doe slug must not match person-john-smith entityRef",
852
+ );
853
+ });
854
+
855
+ test("focusMatchesMemory: raw content match still works alongside slug fix", () => {
856
+ // The existing raw-substring path must remain intact.
857
+ const memory = makeMemoryWithEntityRef("", "Jane Doe signed the contract.");
858
+ const focus: BriefingFocus = { type: "person", value: "Jane Doe" };
859
+ assert.equal(
860
+ focusMatchesMemory(memory, focus),
861
+ true,
862
+ "raw content match must still work after adding slug logic",
863
+ );
864
+ });
865
+
866
+ // ──────────────────────────────────────────────────────────────────────────
867
+ // Round 8 Finding UQZW+UXE5: Midnight end-time HH:MM form must be excluded
868
+ // ──────────────────────────────────────────────────────────────────────────
869
+
870
+ test("eventFallsOnDate: floating end '2026-04-11T00:00' (HH:MM, no seconds) is day-exclusive", () => {
871
+ // ISO floating-time values with no seconds component (e.g. "2026-04-11T00:00")
872
+ // are valid and must be treated as exact midnight — the end day must be excluded
873
+ // under half-open [start, end) semantics.
874
+ const event: CalendarEvent = {
875
+ id: "evt-hhmm-midnight",
876
+ title: "Overnight event HH:MM end",
877
+ start: "2026-04-10T22:00:00",
878
+ end: "2026-04-11T00:00",
879
+ };
880
+ assert.equal(
881
+ eventFallsOnDate(event, "2026-04-10"),
882
+ true,
883
+ "event must appear on start day",
884
+ );
885
+ assert.equal(
886
+ eventFallsOnDate(event, "2026-04-11"),
887
+ false,
888
+ "end time '00:00' (HH:MM midnight) must be treated as day-exclusive",
889
+ );
890
+ });
891
+
892
+ test("eventFallsOnDate: floating end '2026-04-11T01:00' (HH:MM, non-midnight) includes end day", () => {
893
+ // Non-midnight HH:MM end-time: the event is still running on the end day.
894
+ const event: CalendarEvent = {
895
+ id: "evt-hhmm-non-midnight",
896
+ title: "Cross-day event non-midnight HH:MM end",
897
+ start: "2026-04-10T22:00:00",
898
+ end: "2026-04-11T01:00",
899
+ };
900
+ assert.equal(eventFallsOnDate(event, "2026-04-11"), true, "non-midnight HH:MM end must include end day");
901
+ assert.equal(eventFallsOnDate(event, "2026-04-10"), true, "must appear on start day too");
902
+ });
903
+
904
+ // ──────────────────────────────────────────────────────────────────────────
905
+ // Round 8 Finding UNBW: Model-not-found errors must produce user-friendly message
906
+ // ──────────────────────────────────────────────────────────────────────────
907
+
908
+ // Minimal StorageManager stub that returns empty arrays (no memories/entities).
909
+ function makeEmptyStorage(): StorageManager {
910
+ return {
911
+ readAllMemories: async () => [],
912
+ readAllEntityFiles: async () => [],
913
+ } as unknown as StorageManager;
914
+ }
915
+
916
+ test("buildBriefing: model-not-found 400 error produces user-friendly followupsUnavailableReason", async () => {
917
+ // Inject a mock generator that throws an error resembling a Responses API
918
+ // 400 "model does not exist" response.
919
+ const result = await buildBriefing({
920
+ storage: makeEmptyStorage(),
921
+ allowLlm: true,
922
+ openaiApiKey: "sk-synthetic-key",
923
+ followupGenerator: async () => {
924
+ throw new Error("The model 'gpt-5.5' does not exist");
925
+ },
926
+ now: new Date("2026-04-11T10:00:00.000Z"),
927
+ });
928
+
929
+ assert.ok(
930
+ typeof result.followupsUnavailableReason === "string",
931
+ "followupsUnavailableReason must be set on model error",
932
+ );
933
+ assert.ok(
934
+ result.followupsUnavailableReason!.includes("model"),
935
+ `reason must mention 'model': got "${result.followupsUnavailableReason}"`,
936
+ );
937
+ assert.ok(
938
+ result.followupsUnavailableReason!.includes("not available"),
939
+ `reason must include 'not available': got "${result.followupsUnavailableReason}"`,
940
+ );
941
+ });
942
+
943
+ test("buildBriefing: model 'not found' phrasing also produces user-friendly message", async () => {
944
+ const result = await buildBriefing({
945
+ storage: makeEmptyStorage(),
946
+ allowLlm: true,
947
+ openaiApiKey: "sk-synthetic-key",
948
+ followupGenerator: async () => {
949
+ throw new Error("model not found: gpt-5.5");
950
+ },
951
+ now: new Date("2026-04-11T10:00:00.000Z"),
952
+ });
953
+
954
+ assert.ok(result.followupsUnavailableReason!.includes("not available"),
955
+ `'not found' phrasing must trigger friendly message: got "${result.followupsUnavailableReason}"`);
956
+ });
957
+
958
+ test("buildBriefing: unrelated LLM errors still produce generic message (no false positive)", async () => {
959
+ const result = await buildBriefing({
960
+ storage: makeEmptyStorage(),
961
+ allowLlm: true,
962
+ openaiApiKey: "sk-synthetic-key",
963
+ followupGenerator: async () => {
964
+ throw new Error("network timeout");
965
+ },
966
+ now: new Date("2026-04-11T10:00:00.000Z"),
967
+ });
968
+
969
+ assert.ok(
970
+ result.followupsUnavailableReason!.includes("LLM follow-ups failed"),
971
+ `unrelated errors must use generic message: got "${result.followupsUnavailableReason}"`,
972
+ );
973
+ assert.ok(
974
+ !result.followupsUnavailableReason!.includes("not available"),
975
+ "unrelated errors must NOT produce model-not-available message",
976
+ );
977
+ });
978
+
979
+ // ──────────────────────────────────────────────────────────────────────────
980
+ // Round 8 Finding UXE4: buildActiveThreads must recompute reason from newer memory
981
+ // ──────────────────────────────────────────────────────────────────────────
982
+
983
+ function makeMemoryWithCategory(
984
+ id: string,
985
+ category: "fact" | "commitment" | "decision" | "correction",
986
+ updated: string,
987
+ entityRef?: string,
988
+ ): MemoryFile {
989
+ return {
990
+ path: `/synthetic/${id}.md`,
991
+ frontmatter: {
992
+ id,
993
+ category,
994
+ created: updated,
995
+ updated,
996
+ source: "test",
997
+ confidence: 0.9,
998
+ confidenceTier: "explicit",
999
+ tags: entityRef ? [] : ["topic:synthetic-thread"],
1000
+ entityRef,
1001
+ },
1002
+ content: `Content for ${id}`,
1003
+ };
1004
+ }
1005
+
1006
+ test("buildActiveThreads: reason is updated when a newer memory replaces an older one", () => {
1007
+ // Both memories share the same thread key (same entityRef → same bucket).
1008
+ // The first is a 'fact' (reason="recent activity"), the newer is a 'decision'
1009
+ // (reason="recent decision"). The resulting thread must reflect the newer reason.
1010
+ const olderFact = makeMemoryWithCategory("mem-old", "fact", "2026-04-10T08:00:00.000Z", "topic-alpha");
1011
+ const newerDecision = makeMemoryWithCategory("mem-new", "decision", "2026-04-10T12:00:00.000Z", "topic-alpha");
1012
+
1013
+ const threads = buildActiveThreads([olderFact, newerDecision]);
1014
+
1015
+ assert.equal(threads.length, 1, "both memories share a thread key — expect one thread");
1016
+ assert.equal(
1017
+ threads[0]!.reason,
1018
+ "recent decision",
1019
+ "reason must reflect the newer memory's category, not the older one",
1020
+ );
1021
+ });
1022
+
1023
+ test("buildActiveThreads: reason of first (only) memory is preserved correctly", () => {
1024
+ const commitment = makeMemoryWithCategory("mem-commit", "commitment", "2026-04-10T09:00:00.000Z", "topic-beta");
1025
+ const threads = buildActiveThreads([commitment]);
1026
+ assert.equal(threads[0]!.reason, "open commitment");
1027
+ });
1028
+
1029
+ test("buildActiveThreads: older memory processed first does not win reason when newer arrives", () => {
1030
+ // Process older memory first in the array — the newer one that arrives second
1031
+ // should update both updatedAt AND reason.
1032
+ const olderCorrection = makeMemoryWithCategory(
1033
+ "mem-correction", "correction", "2026-04-09T10:00:00.000Z", "topic-gamma",
1034
+ );
1035
+ const newerFact = makeMemoryWithCategory(
1036
+ "mem-fact", "fact", "2026-04-10T14:00:00.000Z", "topic-gamma",
1037
+ );
1038
+
1039
+ const threads = buildActiveThreads([olderCorrection, newerFact]);
1040
+ assert.equal(threads[0]!.reason, "recent activity", "newer memory is a fact → 'recent activity'");
1041
+ assert.equal(threads[0]!.updatedAt, "2026-04-10T14:00:00.000Z");
1042
+ });
1043
+
1044
+ // ──────────────────────────────────────────────────────────────────────────
1045
+ // Round 8 Finding UXJH: Failing calendar source must suppress calendar section
1046
+ // ──────────────────────────────────────────────────────────────────────────
1047
+
1048
+ test("buildBriefing: failing calendar source suppresses Today's calendar section in markdown", async () => {
1049
+ const throwingCalendar: CalendarSource = {
1050
+ eventsForDate: async (_dateIso: string) => {
1051
+ throw new Error("synthetic calendar fetch failure");
1052
+ },
1053
+ };
1054
+
1055
+ const result = await buildBriefing({
1056
+ storage: makeEmptyStorage(),
1057
+ allowLlm: false,
1058
+ calendarSource: throwingCalendar,
1059
+ now: new Date("2026-04-11T10:00:00.000Z"),
1060
+ });
1061
+
1062
+ assert.ok(
1063
+ !result.markdown.includes("Today's calendar"),
1064
+ "markdown must NOT include 'Today's calendar' when the calendar source throws",
1065
+ );
1066
+ });
1067
+
1068
+ test("buildBriefing: empty calendar (no events) still renders Today's calendar section", async () => {
1069
+ const emptyCalendar: CalendarSource = {
1070
+ eventsForDate: async (_dateIso: string) => [],
1071
+ };
1072
+
1073
+ const result = await buildBriefing({
1074
+ storage: makeEmptyStorage(),
1075
+ allowLlm: false,
1076
+ calendarSource: emptyCalendar,
1077
+ now: new Date("2026-04-11T10:00:00.000Z"),
1078
+ });
1079
+
1080
+ // Empty calendar = source responded with [] — section should appear with "no events" placeholder.
1081
+ assert.ok(
1082
+ result.markdown.includes("Today's calendar"),
1083
+ "markdown must include 'Today's calendar' section even when there are no events",
1084
+ );
1085
+ });
1086
+
1087
+ // ──────────────────────────────────────────────────────────────────────────
1088
+ // Round 9 Finding UZTO: Validate floating-event end timestamps before range checks
1089
+ // ──────────────────────────────────────────────────────────────────────────
1090
+
1091
+ test("eventFallsOnDate: floating event with malformed end only appears on its start date", () => {
1092
+ // A JSON calendar feed emits end: "invalid" for a floating-time event.
1093
+ // Without validation, end.slice(0, 10) produces "invalid " and lexicographic
1094
+ // comparison treats the event as active on every day after start.
1095
+ const event = makeCalendarEventWithEnd("2026-04-11T09:00", "invalid");
1096
+
1097
+ // Must appear on its start date (event is rendered, not dropped).
1098
+ assert.equal(
1099
+ eventFallsOnDate(event, "2026-04-11"),
1100
+ true,
1101
+ "malformed-end event must still appear on its start date",
1102
+ );
1103
+
1104
+ // Must NOT bleed into subsequent days.
1105
+ assert.equal(
1106
+ eventFallsOnDate(event, "2026-04-12"),
1107
+ false,
1108
+ "malformed-end event must NOT appear on the day after start",
1109
+ );
1110
+ assert.equal(
1111
+ eventFallsOnDate(event, "2026-04-13"),
1112
+ false,
1113
+ "malformed-end event must NOT appear two days after start",
1114
+ );
1115
+
1116
+ // Must not appear before start either.
1117
+ assert.equal(
1118
+ eventFallsOnDate(event, "2026-04-10"),
1119
+ false,
1120
+ "malformed-end event must NOT appear before its start date",
1121
+ );
1122
+ });
1123
+
1124
+ test("eventFallsOnDate: floating event with empty-string end is treated as single-day", () => {
1125
+ // Edge case: end is present but is an empty string (structurally invalid).
1126
+ const event: CalendarEvent = {
1127
+ id: "evt-synthetic-empty-end",
1128
+ title: "Empty End Event",
1129
+ start: "2026-04-11T10:00",
1130
+ end: "",
1131
+ };
1132
+
1133
+ assert.equal(
1134
+ eventFallsOnDate(event, "2026-04-11"),
1135
+ true,
1136
+ "empty-end event must appear on its start date",
1137
+ );
1138
+ assert.equal(
1139
+ eventFallsOnDate(event, "2026-04-12"),
1140
+ false,
1141
+ "empty-end event must NOT bleed into the next day",
1142
+ );
1143
+ });
1144
+
1145
+ // Round 10 Finding UhLg: Date-only floating end values must enforce [start, end) semantics
1146
+ // ──────────────────────────────────────────────────────────────────────────
1147
+
1148
+ test("eventFallsOnDate: floating all-day event with date-only end excludes end date ([start, end))", () => {
1149
+ // A JSON calendar feed emits date-only start/end (no time component).
1150
+ // e.g. start: "2026-04-10", end: "2026-04-11" should render only on 2026-04-10.
1151
+ // Before UhLg fix: endTime was "" which did not match the midnight regex, so
1152
+ // endActiveOnEndDay was true and the event incorrectly appeared on 2026-04-11.
1153
+ const event = makeCalendarEventWithEnd("2026-04-10", "2026-04-11");
1154
+
1155
+ assert.equal(
1156
+ eventFallsOnDate(event, "2026-04-10"),
1157
+ true,
1158
+ "date-only all-day event must appear on its start date",
1159
+ );
1160
+ assert.equal(
1161
+ eventFallsOnDate(event, "2026-04-11"),
1162
+ false,
1163
+ "date-only end must be exclusive — event must NOT appear on end date",
1164
+ );
1165
+ assert.equal(
1166
+ eventFallsOnDate(event, "2026-04-09"),
1167
+ false,
1168
+ "date-only all-day event must NOT appear before its start date",
1169
+ );
1170
+ });
1171
+
1172
+ test("eventFallsOnDate: floating multi-day all-day event with date-only end spans [start, end)", () => {
1173
+ // A two-day all-day event: start "2026-04-10", end "2026-04-12"
1174
+ // Should appear on 2026-04-10 and 2026-04-11, but NOT on 2026-04-12.
1175
+ const event = makeCalendarEventWithEnd("2026-04-10", "2026-04-12");
1176
+
1177
+ assert.equal(
1178
+ eventFallsOnDate(event, "2026-04-09"),
1179
+ false,
1180
+ "must not appear before start",
1181
+ );
1182
+ assert.equal(
1183
+ eventFallsOnDate(event, "2026-04-10"),
1184
+ true,
1185
+ "must appear on start date",
1186
+ );
1187
+ assert.equal(
1188
+ eventFallsOnDate(event, "2026-04-11"),
1189
+ true,
1190
+ "must appear on intermediate day",
1191
+ );
1192
+ assert.equal(
1193
+ eventFallsOnDate(event, "2026-04-12"),
1194
+ false,
1195
+ "date-only end must be exclusive — must NOT appear on end date",
1196
+ );
1197
+ assert.equal(
1198
+ eventFallsOnDate(event, "2026-04-13"),
1199
+ false,
1200
+ "must not appear after end",
1201
+ );
1202
+ });
1203
+
1204
+ // Round 10 Finding UhLh: Impossible end dates (passing regex but not real) must fall back
1205
+ // ──────────────────────────────────────────────────────────────────────────
1206
+
1207
+ test("eventFallsOnDate: floating event with impossible end date '2026-99-99' is treated as single-day", () => {
1208
+ // The regex /^\d{4}-\d{2}-\d{2}.../ accepts month 99 and day 99.
1209
+ // Without real-date validation, JavaScript auto-corrects "2026-99-99" to a
1210
+ // future date and the event appears on many unrelated days.
1211
+ const event = makeCalendarEventWithEnd("2026-04-11T09:00", "2026-99-99");
1212
+
1213
+ assert.equal(
1214
+ eventFallsOnDate(event, "2026-04-11"),
1215
+ true,
1216
+ "impossible-end event must still appear on its start date",
1217
+ );
1218
+ assert.equal(
1219
+ eventFallsOnDate(event, "2026-04-12"),
1220
+ false,
1221
+ "impossible-end event must NOT bleed into subsequent days",
1222
+ );
1223
+ // Verify it does not appear on the auto-corrected future date either.
1224
+ assert.equal(
1225
+ eventFallsOnDate(event, "2035-03-09"),
1226
+ false,
1227
+ "impossible-end event must NOT appear on the JavaScript-autocorrected date",
1228
+ );
1229
+ });
1230
+
1231
+ test("eventFallsOnDate: floating event with impossible end date '2026-01-99' is treated as single-day", () => {
1232
+ // "2026-01-99" passes the regex but is impossible; Date auto-corrects to "2026-04-09".
1233
+ const event = makeCalendarEventWithEnd("2026-01-10T09:00", "2026-01-99");
1234
+
1235
+ assert.equal(
1236
+ eventFallsOnDate(event, "2026-01-10"),
1237
+ true,
1238
+ "impossible-end event must appear on its start date",
1239
+ );
1240
+ assert.equal(
1241
+ eventFallsOnDate(event, "2026-04-09"),
1242
+ false,
1243
+ "impossible-end event must NOT appear on the JS-autocorrected date",
1244
+ );
1245
+ });
1246
+
1247
+ // Round 11 Finding PRRT_kwDORJXyws56U7at: Validate time components of floating-event end timestamps
1248
+ // ──────────────────────────────────────────────────────────────────────────────────────────────────
1249
+ // The regex and date-round-trip checks (UhLh) only cover the YYYY-MM-DD portion.
1250
+ // Invalid time fields (hour > 23, minute > 59, second > 59) pass those checks
1251
+ // but cause JavaScript's Date to roll over into unrelated future dates, polluting
1252
+ // the daily calendar output.
1253
+
1254
+ test("eventFallsOnDate: floating event with bad month '2026-13-01T10:00:00' is treated as single-day", () => {
1255
+ // Month 13 passes the shape regex (\d{2}) but is not a real calendar month.
1256
+ // The date round-trip check must catch this and fall back to single-day semantics.
1257
+ const event = makeCalendarEventWithEnd("2026-04-11T09:00", "2026-13-01T10:00:00");
1258
+
1259
+ assert.equal(
1260
+ eventFallsOnDate(event, "2026-04-11"),
1261
+ true,
1262
+ "bad-month end event must still appear on its start date",
1263
+ );
1264
+ assert.equal(
1265
+ eventFallsOnDate(event, "2026-04-12"),
1266
+ false,
1267
+ "bad-month end event must NOT bleed into subsequent days",
1268
+ );
1269
+ // JS auto-corrects 2026-13-01 to 2027-01-01 — verify that date is excluded too.
1270
+ assert.equal(
1271
+ eventFallsOnDate(event, "2027-01-01"),
1272
+ false,
1273
+ "bad-month end event must NOT appear on the JS-autocorrected date",
1274
+ );
1275
+ });
1276
+
1277
+ test("eventFallsOnDate: floating event with bad day '2026-02-30T10:00:00' is treated as single-day", () => {
1278
+ // February 30 passes the shape regex but is never a real date.
1279
+ // The date round-trip check catches this and falls back to single-day semantics.
1280
+ const event = makeCalendarEventWithEnd("2026-02-10T09:00", "2026-02-30T10:00:00");
1281
+
1282
+ assert.equal(
1283
+ eventFallsOnDate(event, "2026-02-10"),
1284
+ true,
1285
+ "bad-day end event must still appear on its start date",
1286
+ );
1287
+ assert.equal(
1288
+ eventFallsOnDate(event, "2026-02-11"),
1289
+ false,
1290
+ "bad-day end event must NOT bleed into subsequent days",
1291
+ );
1292
+ // JS auto-corrects 2026-02-30 to 2026-03-02 — verify that date is excluded too.
1293
+ assert.equal(
1294
+ eventFallsOnDate(event, "2026-03-02"),
1295
+ false,
1296
+ "bad-day end event must NOT appear on the JS-autocorrected date",
1297
+ );
1298
+ });
1299
+
1300
+ test("eventFallsOnDate: floating event with bad hour '2026-04-11T25:00:00' is treated as single-day", () => {
1301
+ // Hour 25 passes the shape regex (\d{2}) and the date portion "2026-04-11" is
1302
+ // real, but 25:00:00 is not a valid time. Without the time-range guard, JS
1303
+ // rolls this over to the next day and the event bleeds into 2026-04-12.
1304
+ const event = makeCalendarEventWithEnd("2026-04-11T09:00", "2026-04-11T25:00:00");
1305
+
1306
+ assert.equal(
1307
+ eventFallsOnDate(event, "2026-04-11"),
1308
+ true,
1309
+ "bad-hour end event must still appear on its start date",
1310
+ );
1311
+ assert.equal(
1312
+ eventFallsOnDate(event, "2026-04-12"),
1313
+ false,
1314
+ "bad-hour end event must NOT bleed into the JS-autocorrected next day",
1315
+ );
1316
+ });
1317
+
1318
+ // ──────────────────────────────────────────────────────────────────────────
1319
+ // Round 12 PRRT_kwDORJXyws56U_7O: Validate floating START timestamp before
1320
+ // date-slice comparisons (symmetric with end validation added in earlier rounds)
1321
+ // ──────────────────────────────────────────────────────────────────────────
1322
+ // JavaScript normalizes impossible dates silently: new Date("2026-02-30T10:00")
1323
+ // returns a valid Date object pointing to 2026-03-02, so the old
1324
+ // "isFinite(probe.getTime())" guard allowed malformed starts through.
1325
+ // With an end present the bad start date slice was then used in lexicographic
1326
+ // overlap logic, placing the event on unrelated real days.
1327
+
1328
+ test("eventFallsOnDate: floating event with impossible start date '2026-02-30T10:00:00' is skipped", () => {
1329
+ // February 30 is not a real date; JavaScript auto-corrects to 2026-03-02.
1330
+ // The old guard (isFinite check) did not catch this.
1331
+ // After the fix the event must be silently skipped (returns false for all dates).
1332
+ const event = makeCalendarEventWithEnd("2026-02-30T10:00:00", "2026-02-30T11:00:00");
1333
+
1334
+ assert.equal(
1335
+ eventFallsOnDate(event, "2026-02-28"),
1336
+ false,
1337
+ "impossible-start event must NOT appear on surrounding real days",
1338
+ );
1339
+ assert.equal(
1340
+ eventFallsOnDate(event, "2026-03-02"),
1341
+ false,
1342
+ "impossible-start event must NOT appear on the JS-autocorrected date",
1343
+ );
1344
+ });
1345
+
1346
+ test("eventFallsOnDate: floating event with impossible start date '2026-99-99T00:00:00' is skipped", () => {
1347
+ // Month 99 / day 99 passes the shape regex but is not a real date.
1348
+ const event = makeCalendarEvent("2026-99-99T00:00:00");
1349
+
1350
+ assert.equal(
1351
+ eventFallsOnDate(event, "2026-04-11"),
1352
+ false,
1353
+ "impossible start month/day must result in event being skipped",
1354
+ );
1355
+ });
1356
+
1357
+ test("eventFallsOnDate: floating event with impossible start month '2026-13-01T10:00:00' is skipped", () => {
1358
+ // Month 13 passes the shape regex but is not a real month.
1359
+ const event = makeCalendarEvent("2026-13-01T10:00:00");
1360
+
1361
+ assert.equal(
1362
+ eventFallsOnDate(event, "2026-04-11"),
1363
+ false,
1364
+ "impossible start month must result in event being skipped",
1365
+ );
1366
+ // JS auto-corrects 2026-13-01 to 2027-01-01 — also excluded.
1367
+ assert.equal(
1368
+ eventFallsOnDate(event, "2027-01-01"),
1369
+ false,
1370
+ "impossible start month must NOT appear on JS-autocorrected date",
1371
+ );
1372
+ });
1373
+
1374
+ test("eventFallsOnDate: floating event with out-of-range start hour '2026-04-11T25:00:00' is skipped", () => {
1375
+ // Hour 25 passes the shape regex and date round-trip, but is not a valid time.
1376
+ // Without the time-range check this would bleed into 2026-04-12.
1377
+ const event = makeCalendarEvent("2026-04-11T25:00:00");
1378
+
1379
+ assert.equal(
1380
+ eventFallsOnDate(event, "2026-04-11"),
1381
+ false,
1382
+ "out-of-range start hour must result in event being skipped",
1383
+ );
1384
+ assert.equal(
1385
+ eventFallsOnDate(event, "2026-04-12"),
1386
+ false,
1387
+ "out-of-range start hour must NOT appear on the JS-autocorrected date",
1388
+ );
1389
+ });
1390
+
1391
+ test("eventFallsOnDate: floating event with out-of-range start time '2026-04-11T10:99:00' is skipped", () => {
1392
+ // Minute 99 passes the shape regex but is an invalid time component.
1393
+ const event = makeCalendarEventWithEnd("2026-04-11T10:99:00", "2026-04-11T11:00:00");
1394
+
1395
+ assert.equal(
1396
+ eventFallsOnDate(event, "2026-04-11"),
1397
+ false,
1398
+ "out-of-range start minute must result in event being skipped",
1399
+ );
1400
+ });
1401
+
1402
+ // ──────────────────────────────────────────────────────────────────────────
1403
+ // Round 8 P2 Finding 2 (briefing.ts:254): Surface calendar source failures
1404
+ // ──────────────────────────────────────────────────────────────────────────
1405
+
1406
+ test("buildBriefing: failing calendar source populates calendarSourceErrors in result", async () => {
1407
+ const throwingCalendar: CalendarSource = {
1408
+ eventsForDate: async (_dateIso: string) => {
1409
+ throw new Error("synthetic permission denied");
1410
+ },
1411
+ };
1412
+
1413
+ const result = await buildBriefing({
1414
+ storage: makeEmptyStorage(),
1415
+ allowLlm: false,
1416
+ calendarSource: throwingCalendar,
1417
+ now: new Date("2026-04-11T10:00:00.000Z"),
1418
+ });
1419
+
1420
+ assert.ok(
1421
+ Array.isArray(result.calendarSourceErrors) && result.calendarSourceErrors.length > 0,
1422
+ "calendarSourceErrors must be non-empty when a calendar source throws",
1423
+ );
1424
+ assert.ok(
1425
+ result.calendarSourceErrors![0]!.error.includes("synthetic permission denied"),
1426
+ "calendarSourceErrors[0].error must contain the original error message",
1427
+ );
1428
+ assert.ok(
1429
+ typeof result.calendarSourceErrors![0]!.source === "string",
1430
+ "calendarSourceErrors[0].source must be a string",
1431
+ );
1432
+ });
1433
+
1434
+ test("buildBriefing: healthy calendar source produces no calendarSourceErrors", async () => {
1435
+ const healthyCalendar: CalendarSource = {
1436
+ eventsForDate: async (_dateIso: string) => [],
1437
+ };
1438
+
1439
+ const result = await buildBriefing({
1440
+ storage: makeEmptyStorage(),
1441
+ allowLlm: false,
1442
+ calendarSource: healthyCalendar,
1443
+ now: new Date("2026-04-11T10:00:00.000Z"),
1444
+ });
1445
+
1446
+ assert.ok(
1447
+ !result.calendarSourceErrors || result.calendarSourceErrors.length === 0,
1448
+ "calendarSourceErrors must be absent or empty when the calendar source succeeds",
1449
+ );
1450
+ });
1451
+
1452
+ test("buildBriefing: no calendar source configured produces no calendarSourceErrors", async () => {
1453
+ const result = await buildBriefing({
1454
+ storage: makeEmptyStorage(),
1455
+ allowLlm: false,
1456
+ now: new Date("2026-04-11T10:00:00.000Z"),
1457
+ });
1458
+
1459
+ assert.ok(
1460
+ !result.calendarSourceErrors || result.calendarSourceErrors.length === 0,
1461
+ "calendarSourceErrors must be absent when no calendarSource is configured",
1462
+ );
1463
+ });
1464
+
1465
+ // ──────────────────────────────────────────────────────────────────────────
1466
+ // Round 8 P2 Finding 3 (briefing.ts:988): Stable sort for equal-timestamp threads
1467
+ // ──────────────────────────────────────────────────────────────────────────
1468
+
1469
+ test("buildActiveThreads: threads with identical updatedAt are sorted deterministically by id", () => {
1470
+ // All three memories have exactly the same updatedAt but different entity thread keys.
1471
+ // Running buildActiveThreads twice on different input orderings must produce
1472
+ // the same output ordering, thanks to the id tiebreaker.
1473
+ const ts = "2026-04-10T12:00:00.000Z";
1474
+
1475
+ function makeEntityMemory(id: string, entityRef: string): MemoryFile {
1476
+ return {
1477
+ path: `/synthetic/${id}.md`,
1478
+ frontmatter: {
1479
+ id,
1480
+ category: "fact",
1481
+ created: ts,
1482
+ updated: ts,
1483
+ source: "test",
1484
+ confidence: 0.9,
1485
+ confidenceTier: "explicit",
1486
+ tags: [],
1487
+ entityRef,
1488
+ },
1489
+ content: `Content for ${id}`,
1490
+ };
1491
+ }
1492
+
1493
+ const memA = makeEntityMemory("mem-alpha", "alpha");
1494
+ const memB = makeEntityMemory("mem-beta", "beta");
1495
+ const memC = makeEntityMemory("mem-gamma", "gamma");
1496
+
1497
+ const resultForward = buildActiveThreads([memA, memB, memC]);
1498
+ const resultReverse = buildActiveThreads([memC, memB, memA]);
1499
+
1500
+ assert.equal(resultForward.length, 3, "should produce 3 threads");
1501
+ assert.deepEqual(
1502
+ resultForward.map((t) => t.id),
1503
+ resultReverse.map((t) => t.id),
1504
+ "order must be identical regardless of input order when timestamps are equal",
1505
+ );
1506
+ });
1507
+
1508
+ test("buildActiveThreads: primary sort by updatedAt overrides id tiebreaker", () => {
1509
+ // "beta" sorts after "alpha" lexicographically (tiebreaker would place alpha first).
1510
+ // But beta has a later updatedAt, so beta must appear first in the output.
1511
+ function makeEntityMemory2(id: string, entityRef: string, updated: string): MemoryFile {
1512
+ return {
1513
+ path: `/synthetic/${id}.md`,
1514
+ frontmatter: {
1515
+ id,
1516
+ category: "fact",
1517
+ created: updated,
1518
+ updated,
1519
+ source: "test",
1520
+ confidence: 0.9,
1521
+ confidenceTier: "explicit",
1522
+ tags: [],
1523
+ entityRef,
1524
+ },
1525
+ content: `Content for ${id}`,
1526
+ };
1527
+ }
1528
+
1529
+ const olderAlpha = makeEntityMemory2("mem-alpha", "alpha", "2026-04-10T08:00:00.000Z");
1530
+ const newerBeta = makeEntityMemory2("mem-beta", "beta", "2026-04-10T12:00:00.000Z");
1531
+
1532
+ const threads = buildActiveThreads([olderAlpha, newerBeta]);
1533
+ assert.equal(threads[0]!.id, "entity:beta", "newer timestamp must rank first, overriding id tiebreaker");
1534
+ assert.equal(threads[1]!.id, "entity:alpha");
1535
+ });