@tenphi/akno-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (485) hide show
  1. package/LICENSE +83 -0
  2. package/README.md +26 -0
  3. package/config/default.jsonc +548 -0
  4. package/dist/bench/answer-corpus.d.ts +48 -0
  5. package/dist/bench/answer-corpus.d.ts.map +1 -0
  6. package/dist/bench/answer-corpus.js +491 -0
  7. package/dist/bench/answer-corpus.js.map +1 -0
  8. package/dist/bench/answer.d.ts +156 -0
  9. package/dist/bench/answer.d.ts.map +1 -0
  10. package/dist/bench/answer.js +608 -0
  11. package/dist/bench/answer.js.map +1 -0
  12. package/dist/bench/auto-recall-answer-corpus.d.ts +21 -0
  13. package/dist/bench/auto-recall-answer-corpus.d.ts.map +1 -0
  14. package/dist/bench/auto-recall-answer-corpus.js +245 -0
  15. package/dist/bench/auto-recall-answer-corpus.js.map +1 -0
  16. package/dist/bench/auto-recall-answer.d.ts +198 -0
  17. package/dist/bench/auto-recall-answer.d.ts.map +1 -0
  18. package/dist/bench/auto-recall-answer.js +720 -0
  19. package/dist/bench/auto-recall-answer.js.map +1 -0
  20. package/dist/bench/auto-recall-corpus.d.ts +45 -0
  21. package/dist/bench/auto-recall-corpus.d.ts.map +1 -0
  22. package/dist/bench/auto-recall-corpus.js +221 -0
  23. package/dist/bench/auto-recall-corpus.js.map +1 -0
  24. package/dist/bench/auto-recall.d.ts +171 -0
  25. package/dist/bench/auto-recall.d.ts.map +1 -0
  26. package/dist/bench/auto-recall.js +651 -0
  27. package/dist/bench/auto-recall.js.map +1 -0
  28. package/dist/bench/entity-resolution.d.ts +37 -0
  29. package/dist/bench/entity-resolution.d.ts.map +1 -0
  30. package/dist/bench/entity-resolution.js +121 -0
  31. package/dist/bench/entity-resolution.js.map +1 -0
  32. package/dist/bench/graph.d.ts +57 -0
  33. package/dist/bench/graph.d.ts.map +1 -0
  34. package/dist/bench/graph.js +573 -0
  35. package/dist/bench/graph.js.map +1 -0
  36. package/dist/bench/llm-ranking-probe.d.ts +27 -0
  37. package/dist/bench/llm-ranking-probe.d.ts.map +1 -0
  38. package/dist/bench/llm-ranking-probe.js +105 -0
  39. package/dist/bench/llm-ranking-probe.js.map +1 -0
  40. package/dist/bench/merge-discovery-corpus.d.ts +26 -0
  41. package/dist/bench/merge-discovery-corpus.d.ts.map +1 -0
  42. package/dist/bench/merge-discovery-corpus.js +114 -0
  43. package/dist/bench/merge-discovery-corpus.js.map +1 -0
  44. package/dist/bench/merge-discovery-review.d.ts +81 -0
  45. package/dist/bench/merge-discovery-review.d.ts.map +1 -0
  46. package/dist/bench/merge-discovery-review.js +149 -0
  47. package/dist/bench/merge-discovery-review.js.map +1 -0
  48. package/dist/bench/merge-discovery.d.ts +122 -0
  49. package/dist/bench/merge-discovery.d.ts.map +1 -0
  50. package/dist/bench/merge-discovery.js +390 -0
  51. package/dist/bench/merge-discovery.js.map +1 -0
  52. package/dist/bench/mixed-retrieval.d.ts +35 -0
  53. package/dist/bench/mixed-retrieval.d.ts.map +1 -0
  54. package/dist/bench/mixed-retrieval.js +355 -0
  55. package/dist/bench/mixed-retrieval.js.map +1 -0
  56. package/dist/bench/ranking-corpus.d.ts +29 -0
  57. package/dist/bench/ranking-corpus.d.ts.map +1 -0
  58. package/dist/bench/ranking-corpus.js +514 -0
  59. package/dist/bench/ranking-corpus.js.map +1 -0
  60. package/dist/bench/ranking-end-to-end.d.ts +112 -0
  61. package/dist/bench/ranking-end-to-end.d.ts.map +1 -0
  62. package/dist/bench/ranking-end-to-end.js +479 -0
  63. package/dist/bench/ranking-end-to-end.js.map +1 -0
  64. package/dist/bench/ranking-latency.d.ts +71 -0
  65. package/dist/bench/ranking-latency.d.ts.map +1 -0
  66. package/dist/bench/ranking-latency.js +130 -0
  67. package/dist/bench/ranking-latency.js.map +1 -0
  68. package/dist/bench/ranking-matrix.d.ts +141 -0
  69. package/dist/bench/ranking-matrix.d.ts.map +1 -0
  70. package/dist/bench/ranking-matrix.js +526 -0
  71. package/dist/bench/ranking-matrix.js.map +1 -0
  72. package/dist/bench/ranking-review.d.ts +93 -0
  73. package/dist/bench/ranking-review.d.ts.map +1 -0
  74. package/dist/bench/ranking-review.js +249 -0
  75. package/dist/bench/ranking-review.js.map +1 -0
  76. package/dist/bench/ranking.d.ts +122 -0
  77. package/dist/bench/ranking.d.ts.map +1 -0
  78. package/dist/bench/ranking.js +547 -0
  79. package/dist/bench/ranking.js.map +1 -0
  80. package/dist/bench.d.ts +60 -0
  81. package/dist/bench.d.ts.map +1 -0
  82. package/dist/bench.js +167 -0
  83. package/dist/bench.js.map +1 -0
  84. package/dist/config/jsonc.d.ts +8 -0
  85. package/dist/config/jsonc.d.ts.map +1 -0
  86. package/dist/config/jsonc.js +85 -0
  87. package/dist/config/jsonc.js.map +1 -0
  88. package/dist/config/load.d.ts +43 -0
  89. package/dist/config/load.d.ts.map +1 -0
  90. package/dist/config/load.js +608 -0
  91. package/dist/config/load.js.map +1 -0
  92. package/dist/config/paths.d.ts +10 -0
  93. package/dist/config/paths.d.ts.map +1 -0
  94. package/dist/config/paths.js +38 -0
  95. package/dist/config/paths.js.map +1 -0
  96. package/dist/config/schema.d.ts +698 -0
  97. package/dist/config/schema.d.ts.map +1 -0
  98. package/dist/config/schema.js +394 -0
  99. package/dist/config/schema.js.map +1 -0
  100. package/dist/config/write-rules.d.ts +41 -0
  101. package/dist/config/write-rules.d.ts.map +1 -0
  102. package/dist/config/write-rules.js +225 -0
  103. package/dist/config/write-rules.js.map +1 -0
  104. package/dist/config/write-setup.d.ts +42 -0
  105. package/dist/config/write-setup.d.ts.map +1 -0
  106. package/dist/config/write-setup.js +358 -0
  107. package/dist/config/write-setup.js.map +1 -0
  108. package/dist/context.d.ts +64 -0
  109. package/dist/context.d.ts.map +1 -0
  110. package/dist/context.js +14 -0
  111. package/dist/context.js.map +1 -0
  112. package/dist/doctor.d.ts +115 -0
  113. package/dist/doctor.d.ts.map +1 -0
  114. package/dist/doctor.js +388 -0
  115. package/dist/doctor.js.map +1 -0
  116. package/dist/index/chunk.d.ts +62 -0
  117. package/dist/index/chunk.d.ts.map +1 -0
  118. package/dist/index/chunk.js +307 -0
  119. package/dist/index/chunk.js.map +1 -0
  120. package/dist/index/defer.d.ts +32 -0
  121. package/dist/index/defer.d.ts.map +1 -0
  122. package/dist/index/defer.js +66 -0
  123. package/dist/index/defer.js.map +1 -0
  124. package/dist/index/derive.d.ts +99 -0
  125. package/dist/index/derive.d.ts.map +1 -0
  126. package/dist/index/derive.js +378 -0
  127. package/dist/index/derive.js.map +1 -0
  128. package/dist/index/entity-resolution.d.ts +68 -0
  129. package/dist/index/entity-resolution.d.ts.map +1 -0
  130. package/dist/index/entity-resolution.js +305 -0
  131. package/dist/index/entity-resolution.js.map +1 -0
  132. package/dist/index/graph.d.ts +46 -0
  133. package/dist/index/graph.d.ts.map +1 -0
  134. package/dist/index/graph.js +618 -0
  135. package/dist/index/graph.js.map +1 -0
  136. package/dist/index/indexer.d.ts +301 -0
  137. package/dist/index/indexer.d.ts.map +1 -0
  138. package/dist/index/indexer.js +1398 -0
  139. package/dist/index/indexer.js.map +1 -0
  140. package/dist/index/revision-barrier.d.ts +30 -0
  141. package/dist/index/revision-barrier.d.ts.map +1 -0
  142. package/dist/index/revision-barrier.js +140 -0
  143. package/dist/index/revision-barrier.js.map +1 -0
  144. package/dist/index.d.ts +55 -0
  145. package/dist/index.d.ts.map +1 -0
  146. package/dist/index.js +37 -0
  147. package/dist/index.js.map +1 -0
  148. package/dist/ingest/adoption-eligibility.d.ts +4 -0
  149. package/dist/ingest/adoption-eligibility.d.ts.map +1 -0
  150. package/dist/ingest/adoption-eligibility.js +18 -0
  151. package/dist/ingest/adoption-eligibility.js.map +1 -0
  152. package/dist/ingest/availability.d.ts +15 -0
  153. package/dist/ingest/availability.d.ts.map +1 -0
  154. package/dist/ingest/availability.js +37 -0
  155. package/dist/ingest/availability.js.map +1 -0
  156. package/dist/ingest/extract.d.ts +58 -0
  157. package/dist/ingest/extract.d.ts.map +1 -0
  158. package/dist/ingest/extract.js +255 -0
  159. package/dist/ingest/extract.js.map +1 -0
  160. package/dist/ingest/fetch.d.ts +35 -0
  161. package/dist/ingest/fetch.d.ts.map +1 -0
  162. package/dist/ingest/fetch.js +142 -0
  163. package/dist/ingest/fetch.js.map +1 -0
  164. package/dist/ingest/inbox.d.ts +53 -0
  165. package/dist/ingest/inbox.d.ts.map +1 -0
  166. package/dist/ingest/inbox.js +110 -0
  167. package/dist/ingest/inbox.js.map +1 -0
  168. package/dist/ingest/name.d.ts +72 -0
  169. package/dist/ingest/name.d.ts.map +1 -0
  170. package/dist/ingest/name.js +208 -0
  171. package/dist/ingest/name.js.map +1 -0
  172. package/dist/ingest/parts.d.ts +78 -0
  173. package/dist/ingest/parts.d.ts.map +1 -0
  174. package/dist/ingest/parts.js +52 -0
  175. package/dist/ingest/parts.js.map +1 -0
  176. package/dist/ingest/rendition.d.ts +75 -0
  177. package/dist/ingest/rendition.d.ts.map +1 -0
  178. package/dist/ingest/rendition.js +92 -0
  179. package/dist/ingest/rendition.js.map +1 -0
  180. package/dist/ingest/store.d.ts +66 -0
  181. package/dist/ingest/store.d.ts.map +1 -0
  182. package/dist/ingest/store.js +92 -0
  183. package/dist/ingest/store.js.map +1 -0
  184. package/dist/kb/folders.d.ts +37 -0
  185. package/dist/kb/folders.d.ts.map +1 -0
  186. package/dist/kb/folders.js +133 -0
  187. package/dist/kb/folders.js.map +1 -0
  188. package/dist/kb/frontmatter.d.ts +91 -0
  189. package/dist/kb/frontmatter.d.ts.map +1 -0
  190. package/dist/kb/frontmatter.js +274 -0
  191. package/dist/kb/frontmatter.js.map +1 -0
  192. package/dist/kb/line-facts.d.ts +29 -0
  193. package/dist/kb/line-facts.d.ts.map +1 -0
  194. package/dist/kb/line-facts.js +23 -0
  195. package/dist/kb/line-facts.js.map +1 -0
  196. package/dist/kb/page.d.ts +92 -0
  197. package/dist/kb/page.d.ts.map +1 -0
  198. package/dist/kb/page.js +243 -0
  199. package/dist/kb/page.js.map +1 -0
  200. package/dist/kb/scan.d.ts +38 -0
  201. package/dist/kb/scan.d.ts.map +1 -0
  202. package/dist/kb/scan.js +109 -0
  203. package/dist/kb/scan.js.map +1 -0
  204. package/dist/kb/words.d.ts +30 -0
  205. package/dist/kb/words.d.ts.map +1 -0
  206. package/dist/kb/words.js +107 -0
  207. package/dist/kb/words.js.map +1 -0
  208. package/dist/maintenance/adopt.d.ts +65 -0
  209. package/dist/maintenance/adopt.d.ts.map +1 -0
  210. package/dist/maintenance/adopt.js +238 -0
  211. package/dist/maintenance/adopt.js.map +1 -0
  212. package/dist/maintenance/budget.d.ts +55 -0
  213. package/dist/maintenance/budget.d.ts.map +1 -0
  214. package/dist/maintenance/budget.js +61 -0
  215. package/dist/maintenance/budget.js.map +1 -0
  216. package/dist/maintenance/conflicts.d.ts +105 -0
  217. package/dist/maintenance/conflicts.d.ts.map +1 -0
  218. package/dist/maintenance/conflicts.js +368 -0
  219. package/dist/maintenance/conflicts.js.map +1 -0
  220. package/dist/maintenance/contradictions.d.ts +34 -0
  221. package/dist/maintenance/contradictions.d.ts.map +1 -0
  222. package/dist/maintenance/contradictions.js +199 -0
  223. package/dist/maintenance/contradictions.js.map +1 -0
  224. package/dist/maintenance/curate.d.ts +156 -0
  225. package/dist/maintenance/curate.d.ts.map +1 -0
  226. package/dist/maintenance/curate.js +2070 -0
  227. package/dist/maintenance/curate.js.map +1 -0
  228. package/dist/maintenance/dream.d.ts +139 -0
  229. package/dist/maintenance/dream.d.ts.map +1 -0
  230. package/dist/maintenance/dream.js +1632 -0
  231. package/dist/maintenance/dream.js.map +1 -0
  232. package/dist/maintenance/graph-candidates.d.ts +19 -0
  233. package/dist/maintenance/graph-candidates.d.ts.map +1 -0
  234. package/dist/maintenance/graph-candidates.js +120 -0
  235. package/dist/maintenance/graph-candidates.js.map +1 -0
  236. package/dist/maintenance/housekeeping.d.ts +81 -0
  237. package/dist/maintenance/housekeeping.d.ts.map +1 -0
  238. package/dist/maintenance/housekeeping.js +281 -0
  239. package/dist/maintenance/housekeeping.js.map +1 -0
  240. package/dist/maintenance/link-repairs.d.ts +58 -0
  241. package/dist/maintenance/link-repairs.d.ts.map +1 -0
  242. package/dist/maintenance/link-repairs.js +281 -0
  243. package/dist/maintenance/link-repairs.js.map +1 -0
  244. package/dist/maintenance/log.d.ts +41 -0
  245. package/dist/maintenance/log.d.ts.map +1 -0
  246. package/dist/maintenance/log.js +72 -0
  247. package/dist/maintenance/log.js.map +1 -0
  248. package/dist/maintenance/managed-item-routing.d.ts +48 -0
  249. package/dist/maintenance/managed-item-routing.d.ts.map +1 -0
  250. package/dist/maintenance/managed-item-routing.js +281 -0
  251. package/dist/maintenance/managed-item-routing.js.map +1 -0
  252. package/dist/maintenance/managed-item-sources.d.ts +38 -0
  253. package/dist/maintenance/managed-item-sources.d.ts.map +1 -0
  254. package/dist/maintenance/managed-item-sources.js +324 -0
  255. package/dist/maintenance/managed-item-sources.js.map +1 -0
  256. package/dist/maintenance/managed-items.d.ts +162 -0
  257. package/dist/maintenance/managed-items.d.ts.map +1 -0
  258. package/dist/maintenance/managed-items.js +1329 -0
  259. package/dist/maintenance/managed-items.js.map +1 -0
  260. package/dist/maintenance/merge-classifier.d.ts +19 -0
  261. package/dist/maintenance/merge-classifier.d.ts.map +1 -0
  262. package/dist/maintenance/merge-classifier.js +49 -0
  263. package/dist/maintenance/merge-classifier.js.map +1 -0
  264. package/dist/maintenance/model-telemetry.d.ts +45 -0
  265. package/dist/maintenance/model-telemetry.d.ts.map +1 -0
  266. package/dist/maintenance/model-telemetry.js +107 -0
  267. package/dist/maintenance/model-telemetry.js.map +1 -0
  268. package/dist/maintenance/observe.d.ts +72 -0
  269. package/dist/maintenance/observe.d.ts.map +1 -0
  270. package/dist/maintenance/observe.js +265 -0
  271. package/dist/maintenance/observe.js.map +1 -0
  272. package/dist/maintenance/path-policy.d.ts +83 -0
  273. package/dist/maintenance/path-policy.d.ts.map +1 -0
  274. package/dist/maintenance/path-policy.js +360 -0
  275. package/dist/maintenance/path-policy.js.map +1 -0
  276. package/dist/maintenance/plans.d.ts +366 -0
  277. package/dist/maintenance/plans.d.ts.map +1 -0
  278. package/dist/maintenance/plans.js +4060 -0
  279. package/dist/maintenance/plans.js.map +1 -0
  280. package/dist/maintenance/profile.d.ts +33 -0
  281. package/dist/maintenance/profile.d.ts.map +1 -0
  282. package/dist/maintenance/profile.js +99 -0
  283. package/dist/maintenance/profile.js.map +1 -0
  284. package/dist/maintenance/recovery.d.ts +38 -0
  285. package/dist/maintenance/recovery.d.ts.map +1 -0
  286. package/dist/maintenance/recovery.js +217 -0
  287. package/dist/maintenance/recovery.js.map +1 -0
  288. package/dist/maintenance/repair.d.ts +37 -0
  289. package/dist/maintenance/repair.d.ts.map +1 -0
  290. package/dist/maintenance/repair.js +183 -0
  291. package/dist/maintenance/repair.js.map +1 -0
  292. package/dist/maintenance/rule-drift.d.ts +104 -0
  293. package/dist/maintenance/rule-drift.d.ts.map +1 -0
  294. package/dist/maintenance/rule-drift.js +507 -0
  295. package/dist/maintenance/rule-drift.js.map +1 -0
  296. package/dist/maintenance/run-verification.d.ts +44 -0
  297. package/dist/maintenance/run-verification.d.ts.map +1 -0
  298. package/dist/maintenance/run-verification.js +253 -0
  299. package/dist/maintenance/run-verification.js.map +1 -0
  300. package/dist/maintenance/runs.d.ts +142 -0
  301. package/dist/maintenance/runs.d.ts.map +1 -0
  302. package/dist/maintenance/runs.js +439 -0
  303. package/dist/maintenance/runs.js.map +1 -0
  304. package/dist/maintenance/semantic-merge-discovery.d.ts +54 -0
  305. package/dist/maintenance/semantic-merge-discovery.d.ts.map +1 -0
  306. package/dist/maintenance/semantic-merge-discovery.js +308 -0
  307. package/dist/maintenance/semantic-merge-discovery.js.map +1 -0
  308. package/dist/maintenance/temporal.d.ts +44 -0
  309. package/dist/maintenance/temporal.d.ts.map +1 -0
  310. package/dist/maintenance/temporal.js +295 -0
  311. package/dist/maintenance/temporal.js.map +1 -0
  312. package/dist/models/client.d.ts +214 -0
  313. package/dist/models/client.d.ts.map +1 -0
  314. package/dist/models/client.js +904 -0
  315. package/dist/models/client.js.map +1 -0
  316. package/dist/models/provider-api.d.ts +28 -0
  317. package/dist/models/provider-api.d.ts.map +1 -0
  318. package/dist/models/provider-api.js +320 -0
  319. package/dist/models/provider-api.js.map +1 -0
  320. package/dist/open.d.ts +163 -0
  321. package/dist/open.d.ts.map +1 -0
  322. package/dist/open.js +382 -0
  323. package/dist/open.js.map +1 -0
  324. package/dist/ops/adopt.d.ts +12 -0
  325. package/dist/ops/adopt.d.ts.map +1 -0
  326. package/dist/ops/adopt.js +138 -0
  327. package/dist/ops/adopt.js.map +1 -0
  328. package/dist/ops/answer.d.ts +29 -0
  329. package/dist/ops/answer.d.ts.map +1 -0
  330. package/dist/ops/answer.js +557 -0
  331. package/dist/ops/answer.js.map +1 -0
  332. package/dist/ops/context.d.ts +18 -0
  333. package/dist/ops/context.d.ts.map +1 -0
  334. package/dist/ops/context.js +713 -0
  335. package/dist/ops/context.js.map +1 -0
  336. package/dist/ops/folder.d.ts +23 -0
  337. package/dist/ops/folder.d.ts.map +1 -0
  338. package/dist/ops/folder.js +130 -0
  339. package/dist/ops/folder.js.map +1 -0
  340. package/dist/ops/forget.d.ts +14 -0
  341. package/dist/ops/forget.d.ts.map +1 -0
  342. package/dist/ops/forget.js +212 -0
  343. package/dist/ops/forget.js.map +1 -0
  344. package/dist/ops/graph.d.ts +10 -0
  345. package/dist/ops/graph.d.ts.map +1 -0
  346. package/dist/ops/graph.js +480 -0
  347. package/dist/ops/graph.js.map +1 -0
  348. package/dist/ops/ingest.d.ts +40 -0
  349. package/dist/ops/ingest.d.ts.map +1 -0
  350. package/dist/ops/ingest.js +434 -0
  351. package/dist/ops/ingest.js.map +1 -0
  352. package/dist/ops/list.d.ts +9 -0
  353. package/dist/ops/list.d.ts.map +1 -0
  354. package/dist/ops/list.js +217 -0
  355. package/dist/ops/list.js.map +1 -0
  356. package/dist/ops/move.d.ts +20 -0
  357. package/dist/ops/move.d.ts.map +1 -0
  358. package/dist/ops/move.js +173 -0
  359. package/dist/ops/move.js.map +1 -0
  360. package/dist/ops/read.d.ts +9 -0
  361. package/dist/ops/read.d.ts.map +1 -0
  362. package/dist/ops/read.js +271 -0
  363. package/dist/ops/read.js.map +1 -0
  364. package/dist/ops/recall.d.ts +13 -0
  365. package/dist/ops/recall.d.ts.map +1 -0
  366. package/dist/ops/recall.js +297 -0
  367. package/dist/ops/recall.js.map +1 -0
  368. package/dist/ops/remember.d.ts +34 -0
  369. package/dist/ops/remember.d.ts.map +1 -0
  370. package/dist/ops/remember.js +660 -0
  371. package/dist/ops/remember.js.map +1 -0
  372. package/dist/ops/timeline.d.ts +11 -0
  373. package/dist/ops/timeline.d.ts.map +1 -0
  374. package/dist/ops/timeline.js +111 -0
  375. package/dist/ops/timeline.js.map +1 -0
  376. package/dist/ops/undo.d.ts +9 -0
  377. package/dist/ops/undo.d.ts.map +1 -0
  378. package/dist/ops/undo.js +38 -0
  379. package/dist/ops/undo.js.map +1 -0
  380. package/dist/ops/write.d.ts +55 -0
  381. package/dist/ops/write.d.ts.map +1 -0
  382. package/dist/ops/write.js +463 -0
  383. package/dist/ops/write.js.map +1 -0
  384. package/dist/recall/assemble.d.ts +81 -0
  385. package/dist/recall/assemble.d.ts.map +1 -0
  386. package/dist/recall/assemble.js +603 -0
  387. package/dist/recall/assemble.js.map +1 -0
  388. package/dist/recall/expand.d.ts +55 -0
  389. package/dist/recall/expand.d.ts.map +1 -0
  390. package/dist/recall/expand.js +282 -0
  391. package/dist/recall/expand.js.map +1 -0
  392. package/dist/recall/graph-arm.d.ts +17 -0
  393. package/dist/recall/graph-arm.d.ts.map +1 -0
  394. package/dist/recall/graph-arm.js +227 -0
  395. package/dist/recall/graph-arm.js.map +1 -0
  396. package/dist/recall/llm-rerank.d.ts +55 -0
  397. package/dist/recall/llm-rerank.d.ts.map +1 -0
  398. package/dist/recall/llm-rerank.js +213 -0
  399. package/dist/recall/llm-rerank.js.map +1 -0
  400. package/dist/recall/reranker-calibration.d.ts +23 -0
  401. package/dist/recall/reranker-calibration.d.ts.map +1 -0
  402. package/dist/recall/reranker-calibration.js +161 -0
  403. package/dist/recall/reranker-calibration.js.map +1 -0
  404. package/dist/recall/search.d.ts +107 -0
  405. package/dist/recall/search.d.ts.map +1 -0
  406. package/dist/recall/search.js +530 -0
  407. package/dist/recall/search.js.map +1 -0
  408. package/dist/reserved.d.ts +39 -0
  409. package/dist/reserved.d.ts.map +1 -0
  410. package/dist/reserved.js +63 -0
  411. package/dist/reserved.js.map +1 -0
  412. package/dist/rules/compile.d.ts +27 -0
  413. package/dist/rules/compile.d.ts.map +1 -0
  414. package/dist/rules/compile.js +105 -0
  415. package/dist/rules/compile.js.map +1 -0
  416. package/dist/setup/model-free.d.ts +15 -0
  417. package/dist/setup/model-free.d.ts.map +1 -0
  418. package/dist/setup/model-free.js +26 -0
  419. package/dist/setup/model-free.js.map +1 -0
  420. package/dist/setup/openai.d.ts +46 -0
  421. package/dist/setup/openai.d.ts.map +1 -0
  422. package/dist/setup/openai.js +165 -0
  423. package/dist/setup/openai.js.map +1 -0
  424. package/dist/store/db.d.ts +61 -0
  425. package/dist/store/db.d.ts.map +1 -0
  426. package/dist/store/db.js +265 -0
  427. package/dist/store/db.js.map +1 -0
  428. package/dist/store/ids.d.ts +29 -0
  429. package/dist/store/ids.d.ts.map +1 -0
  430. package/dist/store/ids.js +0 -0
  431. package/dist/store/ids.js.map +1 -0
  432. package/dist/store/migrations.d.ts +54 -0
  433. package/dist/store/migrations.d.ts.map +1 -0
  434. package/dist/store/migrations.js +923 -0
  435. package/dist/store/migrations.js.map +1 -0
  436. package/dist/store/vectors.d.ts +34 -0
  437. package/dist/store/vectors.d.ts.map +1 -0
  438. package/dist/store/vectors.js +158 -0
  439. package/dist/store/vectors.js.map +1 -0
  440. package/dist/timeline/documents.d.ts +23 -0
  441. package/dist/timeline/documents.d.ts.map +1 -0
  442. package/dist/timeline/documents.js +262 -0
  443. package/dist/timeline/documents.js.map +1 -0
  444. package/dist/watch/watcher.d.ts +43 -0
  445. package/dist/watch/watcher.d.ts.map +1 -0
  446. package/dist/watch/watcher.js +143 -0
  447. package/dist/watch/watcher.js.map +1 -0
  448. package/dist/write/atomic.d.ts +34 -0
  449. package/dist/write/atomic.d.ts.map +1 -0
  450. package/dist/write/atomic.js +58 -0
  451. package/dist/write/atomic.js.map +1 -0
  452. package/dist/write/conflict.d.ts +43 -0
  453. package/dist/write/conflict.d.ts.map +1 -0
  454. package/dist/write/conflict.js +149 -0
  455. package/dist/write/conflict.js.map +1 -0
  456. package/dist/write/edit.d.ts +59 -0
  457. package/dist/write/edit.d.ts.map +1 -0
  458. package/dist/write/edit.js +231 -0
  459. package/dist/write/edit.js.map +1 -0
  460. package/dist/write/gate.d.ts +59 -0
  461. package/dist/write/gate.d.ts.map +1 -0
  462. package/dist/write/gate.js +99 -0
  463. package/dist/write/gate.js.map +1 -0
  464. package/dist/write/journal.d.ts +90 -0
  465. package/dist/write/journal.d.ts.map +1 -0
  466. package/dist/write/journal.js +187 -0
  467. package/dist/write/journal.js.map +1 -0
  468. package/dist/write/ledger.d.ts +28 -0
  469. package/dist/write/ledger.d.ts.map +1 -0
  470. package/dist/write/ledger.js +141 -0
  471. package/dist/write/ledger.js.map +1 -0
  472. package/dist/write/placement.d.ts +29 -0
  473. package/dist/write/placement.d.ts.map +1 -0
  474. package/dist/write/placement.js +140 -0
  475. package/dist/write/placement.js.map +1 -0
  476. package/dist/write/remember-fallback.d.ts +18 -0
  477. package/dist/write/remember-fallback.d.ts.map +1 -0
  478. package/dist/write/remember-fallback.js +48 -0
  479. package/dist/write/remember-fallback.js.map +1 -0
  480. package/dist/write/retain.d.ts +61 -0
  481. package/dist/write/retain.d.ts.map +1 -0
  482. package/dist/write/retain.js +272 -0
  483. package/dist/write/retain.js.map +1 -0
  484. package/package.json +50 -0
  485. package/swift/extract.swift +232 -0
@@ -0,0 +1,660 @@
1
+ import { RememberInput, } from '@tenphi/akno-protocol';
2
+ import { ModelClient } from "../models/client.js";
3
+ import { runRetain } from "../write/retain.js";
4
+ import { newPrefixedId, sha256 } from "../store/ids.js";
5
+ import { isReserved } from "../reserved.js";
6
+ import { folderCatalog } from "../kb/folders.js";
7
+ import { parsePage } from "../kb/page.js";
8
+ import { contentWords } from "../kb/words.js";
9
+ import { detectConflict } from "../write/conflict.js";
10
+ import { fileEntry } from "../write/journal.js";
11
+ import { writeFileAtomic } from "../write/atomic.js";
12
+ import { managedSourceReference, placeManagedItems } from "../write/placement.js";
13
+ import { resolveRememberFallback } from "../write/remember-fallback.js";
14
+ import { recall } from "./recall.js";
15
+ import { appendToLedger, titleFromSlug } from "./write.js";
16
+ import fsp from 'node:fs/promises';
17
+ import path from 'node:path';
18
+ /**
19
+ * Hand over a transcript or notes; Akno runs the retain mission with its own
20
+ * model and produces the writes itself. **The answer for a host that does not want
21
+ * to build a curator** — an agent that wants control uses `write` and ignores this.
22
+ *
23
+ * The steps, in order: retain mission → route by recall → conflict check →
24
+ * edit the file → journal → the indexer follows. `remember` never writes a fact.
25
+ * It writes a *sentence into a file*, and facts appear afterwards because facts are
26
+ * derived from sentences.
27
+ *
28
+ * **Two things the caller controls, and one it does not.** It supplies the text and,
29
+ * optionally, a `mission` — what to pay attention to in this particular text, which is the
30
+ * knowledge only the caller has: that a message was forwarded and belongs on somebody else's
31
+ * page, that a channel is mostly logistics, that a subject matters today. What it cannot
32
+ * supply is a replacement for the standing rules; the mission is appended to them. A host
33
+ * that wants to decide phrasing and placement itself has `write` for exactly that.
34
+ *
35
+ * **Retain runs on the cycle's model when one is configured.** It is a maintenance tier, and
36
+ * the tier's output is largely a function of the model behind it — the same measurement that
37
+ * put `maintenance.model` there in the first place. A knowledge base pointing the nightly
38
+ * cycle at a strong model wants its conversation digests to use it too, and would not expect
39
+ * to configure that twice.
40
+ */
41
+ export async function remember(ctx, rawInput) {
42
+ const input = RememberInput.parse(rawInput);
43
+ // Retain is a tier with a mission and an on/off switch like the others. Honouring
44
+ // both here is what makes that config real: a `mission` nothing reads is a promise the file
45
+ // makes and the code breaks.
46
+ if (!ctx.config.maintenance.retain.enabled) {
47
+ return {
48
+ status: 'ok',
49
+ outcome: 'noop',
50
+ note: 'the retain tier is disabled in config (maintenance.retain.enabled) — nothing was kept',
51
+ };
52
+ }
53
+ const curator = ctx.config.maintenance.model
54
+ ? new ModelClient(ctx.config.maintenance.model)
55
+ : ctx.models.derive;
56
+ // The caller's mission wins over the install's, because it is the more specific of the two:
57
+ // config states a standing policy, a call states what is true of this text.
58
+ const mission = input.mission ?? ctx.config.maintenance.retain.mission;
59
+ const catalog = folderCatalog(ctx.config, ctx.store);
60
+ const retained = await runRetain(input.text, curator, {
61
+ today: new Date().toISOString().slice(0, 10),
62
+ ...(mission ? { mission } : {}),
63
+ folders: catalog,
64
+ });
65
+ if (retained.error) {
66
+ // No model means no `remember`. Saying so is the whole contract —
67
+ // silently keeping nothing would look identical to "nothing was worth keeping".
68
+ return {
69
+ status: 'degraded',
70
+ degraded: [curator.degradedReason({})],
71
+ outcome: 'noop',
72
+ note: `the retain mission could not run: ${retained.error}`,
73
+ };
74
+ }
75
+ if (retained.candidates.length === 0 && retained.events.length === 0) {
76
+ return {
77
+ status: 'ok',
78
+ outcome: 'noop',
79
+ considered: [],
80
+ note: 'nothing in that text was worth keeping — no durable claim, decision or preference',
81
+ };
82
+ }
83
+ // ── Route ───────────────────────────────────────────────────────────────
84
+ const routed = await Promise.all(retained.candidates.map(async (candidate) => ({
85
+ candidate,
86
+ ...(await route(ctx, candidate)),
87
+ })));
88
+ const configuredFallback = await resolveRememberFallback(ctx, catalog);
89
+ let fallbackNeeded = false;
90
+ let fallbackUsed = false;
91
+ // `kept` covers a claim bound for a page that does not exist yet, not just one that routed.
92
+ // It used to mean "routed", and once creating became possible that made every new page read
93
+ // back as a claim that had been dropped.
94
+ const considered = routed.map((entry) => {
95
+ const candidateFallback = entry.candidate.page;
96
+ const candidateFallbackExists = candidateFallback !== undefined && pageExists(ctx, candidateFallback);
97
+ const candidateFallbackCanCreate = candidateFallback !== undefined &&
98
+ !candidateFallbackExists &&
99
+ admittedFolder(catalog, candidateFallback) !== null;
100
+ const ordinarySlug = entry.slug ?? (candidateFallbackCanCreate ? candidateFallback : null);
101
+ const canUseConfiguredFallback = ordinarySlug === null && configuredFallback !== null && configuredFallback.status !== 'unavailable';
102
+ if (ordinarySlug === null)
103
+ fallbackNeeded = true;
104
+ if (canUseConfiguredFallback)
105
+ fallbackUsed = true;
106
+ const slug = ordinarySlug ?? (canUseConfiguredFallback ? configuredFallback.slug : null);
107
+ return {
108
+ claim: entry.candidate.text,
109
+ kept: slug !== null,
110
+ slug,
111
+ score: Math.round(entry.score * 1000) / 1000,
112
+ destination: entry.slug
113
+ ? 'existing_admitted_page'
114
+ : candidateFallbackCanCreate
115
+ ? 'new_managed_page'
116
+ : canUseConfiguredFallback
117
+ ? 'configured_fallback'
118
+ : 'no_writable_destination',
119
+ written: false,
120
+ };
121
+ });
122
+ if (input.dry_run) {
123
+ const folders = configuredFallback && configuredFallback.status !== 'unavailable'
124
+ ? []
125
+ : requiredFolders(ctx, catalog, routed);
126
+ const needsApproval = routed.some((entry, index) => {
127
+ if (considered[index].kept || folders.some((folder) => folder.folder === suggestedFolder(entry))) {
128
+ return false;
129
+ }
130
+ const refused = entry.candidate.page && pageExists(ctx, entry.candidate.page) ? entry.candidate.page : undefined;
131
+ return unroutedReasonCode(entry.nearest, refused, entry.blocked) === 'routing_uncertain';
132
+ });
133
+ const noWritableDestination = routed.some((entry, index) => {
134
+ if (considered[index].kept || folders.some((folder) => folder.folder === suggestedFolder(entry))) {
135
+ return false;
136
+ }
137
+ const refused = entry.candidate.page && pageExists(ctx, entry.candidate.page) ? entry.candidate.page : undefined;
138
+ return unroutedReasonCode(entry.nearest, refused, entry.blocked) === 'no_writable_destination';
139
+ });
140
+ return {
141
+ status: 'ok',
142
+ outcome: folders.length > 0
143
+ ? 'requires_folder'
144
+ : noWritableDestination
145
+ ? 'no_writable_destination'
146
+ : needsApproval
147
+ ? 'requires_approval'
148
+ : 'ok',
149
+ considered,
150
+ ...(folders.length > 0 ? { requires_folder: folders } : {}),
151
+ ...fallbackResult(fallbackNeeded, fallbackUsed, configuredFallback),
152
+ note: 'dry run — nothing was written',
153
+ };
154
+ }
155
+ // ── Place and write ─────────────────────────────────────────────────────
156
+ // One group per target means one placement-model call per page and one journal entry for the
157
+ // whole remember operation. A turn that keeps three related facts is one undoable decision.
158
+ const wrote = [];
159
+ const approvals = [];
160
+ const foldersNeeded = [];
161
+ const groups = new Map();
162
+ for (const [index, entry] of routed.entries()) {
163
+ const target = considered[index].slug;
164
+ if (target === null) {
165
+ const refusedPage = entry.candidate.page && pageExists(ctx, entry.candidate.page) ? entry.candidate.page : undefined;
166
+ approvals.push(proposeUnrouted(ctx, entry.candidate, entry.nearest, refusedPage, entry.blocked));
167
+ continue;
168
+ }
169
+ // **Creating a page on a guess is fine. Appending to an existing one is not.**
170
+ //
171
+ // `entry.slug === null` is routing having looked at the ranked candidates and said no page
172
+ // here is a home for this. The claim then fell through to `candidate.page` — a slug the
173
+ // retain model wrote before any of those candidates were scored — and if that slug happened
174
+ // to name a real page, the claim was appended to it with nothing having judged the pairing.
175
+ //
176
+ // Regression shape: a Vulpine Mutual renewal targeted an unrelated existing page that the
177
+ // reranker scored far below threshold. Routing refused correctly, but the fallback used to
178
+ // outrank that refusal and append under a newly invented heading.
179
+ //
180
+ // A guess that names *no* page still creates one: that is the case the fallback exists for,
181
+ // and a new page is inspectable and cheap to move. A guess that lands on somebody else's
182
+ // page becomes a question instead.
183
+ if (considered[index].destination !== 'configured_fallback' &&
184
+ entry.slug === null &&
185
+ pageExists(ctx, target)) {
186
+ considered[index].kept = false;
187
+ considered[index].slug = null;
188
+ considered[index].destination = 'no_writable_destination';
189
+ approvals.push(proposeUnrouted(ctx, entry.candidate, entry.nearest, target, entry.blocked));
190
+ continue;
191
+ }
192
+ const group = groups.get(target) ?? { entries: [], configuredFallback: false };
193
+ group.entries.push({ index, candidate: entry.candidate, blocked: entry.blocked });
194
+ if (considered[index].destination === 'configured_fallback')
195
+ group.configuredFallback = true;
196
+ groups.set(target, group);
197
+ }
198
+ const pending = [];
199
+ for (const [slug, group] of groups) {
200
+ const row = ctx.store.db
201
+ .prepare('SELECT id, rel_path, role, remember_management FROM pages WHERE slug = ?')
202
+ .get(slug);
203
+ if (row && (row.role !== 'knowledge' || row.remember_management !== 'integrate')) {
204
+ for (const entry of group.entries) {
205
+ considered[entry.index].kept = false;
206
+ considered[entry.index].slug = null;
207
+ considered[entry.index].destination = 'no_writable_destination';
208
+ approvals.push(proposeUnrouted(ctx, entry.candidate, [], slug, entry.blocked));
209
+ }
210
+ continue;
211
+ }
212
+ // The same policy, for a page that does not exist yet.
213
+ //
214
+ // The check above reads `role` and `remember_management` off the page row, so a folder
215
+ // declared `remember: "deny"` protected only the pages already in it — creation consulted
216
+ // nothing but whether the parent directory existed. A physical reference folder could
217
+ // therefore receive a new managed page even though no rule admitted injection there.
218
+ // Declining to create is the same answer the folder already gives to writing.
219
+ const parent = slug.slice(0, slug.lastIndexOf('/'));
220
+ if (!row && admittedFolder(catalog, slug) === null) {
221
+ for (const entry of group.entries) {
222
+ considered[entry.index].kept = false;
223
+ considered[entry.index].slug = null;
224
+ }
225
+ foldersNeeded.push({
226
+ folder: parent,
227
+ nearest: catalog
228
+ .filter((folder) => folder.eligible)
229
+ .map((folder) => folder.path)
230
+ .slice(0, 8),
231
+ });
232
+ continue;
233
+ }
234
+ const relPath = row?.rel_path ?? `${slug}.md`;
235
+ const current = row
236
+ ? await fsp.readFile(path.join(ctx.config.aknoPath, relPath), 'utf8')
237
+ : newManagedPage(group.configuredFallback ? titleFromSlug(slug) : titleFor(group.entries[0].candidate, slug));
238
+ const accepted = [];
239
+ for (const entry of group.entries) {
240
+ if (row) {
241
+ const page = parsePage(relPath, current);
242
+ const conflict = detectConflict({
243
+ store: ctx.store,
244
+ pageId: row.id,
245
+ slug,
246
+ body: page.body,
247
+ bodyStartLine: page.bodyLine,
248
+ incoming: entry.candidate.text,
249
+ });
250
+ if (conflict) {
251
+ approvals.push({
252
+ proposal_id: recordConflictProposal(ctx, slug, entry.candidate, conflict.existing),
253
+ reason: `'${slug}' already claims something different: ${conflict.existing}. Ask which is current.`,
254
+ reason_code: 'conflict',
255
+ nearest: [slug],
256
+ });
257
+ continue;
258
+ }
259
+ }
260
+ accepted.push(entry);
261
+ }
262
+ if (accepted.length === 0)
263
+ continue;
264
+ const items = accepted.map(({ candidate }) => ({
265
+ id: newPrefixedId('itm'),
266
+ text: candidate.text,
267
+ source: managedSourceReference(input.source ?? 'remember'),
268
+ origin: candidate.origin ?? 'unknown',
269
+ }));
270
+ const placed = await placeManagedItems(current, items, curator);
271
+ // Placement failure is recoverable and visible in Markdown: no claim is lost, and the next
272
+ // curate pass has an explicit `## Unsorted` inbox to integrate.
273
+ pending.push({
274
+ slug,
275
+ relPath,
276
+ content: placed.content,
277
+ existed: Boolean(row),
278
+ indexes: accepted.map((entry) => entry.index),
279
+ sources: accepted.flatMap((entry, itemIndex) => entry.candidate.evidence
280
+ ? [
281
+ {
282
+ itemId: items[itemIndex].id,
283
+ sourceRef: items[itemIndex].source,
284
+ origin: items[itemIndex].origin,
285
+ evidence: entry.candidate.evidence,
286
+ evidenceHash: sha256(entry.candidate.evidence),
287
+ inputHash: sha256(input.text),
288
+ },
289
+ ]
290
+ : []),
291
+ });
292
+ }
293
+ const files = [];
294
+ const managedSources = [];
295
+ for (const page of pending) {
296
+ const result = await writeFileAtomic(ctx.config.aknoPath, page.relPath, page.content);
297
+ files.push(fileEntry(result));
298
+ page.indexes.forEach((index) => {
299
+ considered[index].written = true;
300
+ });
301
+ wrote.push({ slug: page.slug, action: page.existed ? 'appended' : 'created' });
302
+ managedSources.push(...page.sources);
303
+ }
304
+ for (const event of retained.events) {
305
+ const ledger = await appendToLedger(ctx, event);
306
+ if (ledger.file)
307
+ files.push(ledger.file);
308
+ wrote.push({
309
+ slug: ctx.config.paths.timeline.replace(/\.(md|markdown)$/i, ''),
310
+ line: ledger.line,
311
+ action: 'event',
312
+ });
313
+ }
314
+ const changeId = files.length > 0
315
+ ? ctx.journal.record({
316
+ actor: ctx.actor,
317
+ op: 'remember',
318
+ summary: `remembered ${considered.filter((entry) => entry.written).length} item(s)`,
319
+ files,
320
+ })
321
+ : null;
322
+ persistManagedSources(ctx, managedSources);
323
+ let added = 0;
324
+ if (files.length > 0) {
325
+ const paths = [...new Set(files.map((file) => file.relPath))];
326
+ const report = await ctx.indexer.runForeground({ only: paths, modelPaths: [] });
327
+ ctx.derive.schedule(paths);
328
+ added = report.factsDerived;
329
+ }
330
+ // Deduplicated: three findings bound for the same new folder are one thing to do, not three.
331
+ const folders = deduplicateRequiredFolders(foldersNeeded);
332
+ // `requires_folder` outranks `requires_approval` in the outcome, because they ask different
333
+ // people. A folder is the caller's to declare, now, without leaving the turn; an approval
334
+ // waits on the user. Reporting the first as the second is how a caller learns to stop.
335
+ const noWritableDestination = approvals.some((approval) => approval.reason_code === 'no_writable_destination');
336
+ const routingApproval = approvals.some((approval) => approval.reason_code !== 'no_writable_destination');
337
+ const outcome = folders.length > 0
338
+ ? 'requires_folder'
339
+ : noWritableDestination
340
+ ? 'no_writable_destination'
341
+ : approvals.length > 0
342
+ ? 'requires_approval'
343
+ : null;
344
+ const held = [
345
+ folders.length > 0
346
+ ? `${folders.map((required) => `'${required.folder}'`).join(', ')} ` +
347
+ `${folders.length === 1 ? 'has' : 'have'} not been declared — call \`folder\` with a ` +
348
+ 'description of what belongs there, then repeat this'
349
+ : null,
350
+ noWritableDestination ? 'some claims have no authorized writable destination' : null,
351
+ routingApproval ? 'some claims need the user to say where they go or resolve a conflict' : null,
352
+ ].filter(Boolean);
353
+ if (wrote.length === 0) {
354
+ return {
355
+ status: 'ok',
356
+ outcome: outcome ?? 'noop',
357
+ considered,
358
+ ...(approvals.length > 0 ? { approvals } : {}),
359
+ ...(folders.length > 0 ? { requires_folder: folders } : {}),
360
+ ...fallbackResult(fallbackNeeded, fallbackUsed, configuredFallback),
361
+ note: held.length > 0 ? `nothing was written: ${held.join('; ')}` : 'nothing was written',
362
+ };
363
+ }
364
+ return {
365
+ status: 'ok',
366
+ outcome: outcome ?? 'ok',
367
+ ...(changeId ? { change_id: changeId } : {}),
368
+ wrote,
369
+ facts: { retired: 0, added },
370
+ considered,
371
+ ...(approvals.length > 0 ? { approvals } : {}),
372
+ ...(folders.length > 0 ? { requires_folder: folders } : {}),
373
+ ...fallbackResult(fallbackNeeded, fallbackUsed, configuredFallback),
374
+ ...(held.length > 0 ? { note: held.join('; ') } : {}),
375
+ };
376
+ }
377
+ function fallbackResult(needed, used, resolution) {
378
+ if (!needed || !resolution)
379
+ return {};
380
+ if (resolution.status === 'unavailable') {
381
+ return {
382
+ fallback: { slug: resolution.slug, status: 'unavailable', reason: resolution.reason },
383
+ };
384
+ }
385
+ if (!used)
386
+ return {};
387
+ return {
388
+ fallback: { slug: resolution.slug, status: 'used' },
389
+ };
390
+ }
391
+ function persistManagedSources(ctx, sources) {
392
+ if (sources.length === 0 || ctx.store.readOnly)
393
+ return;
394
+ const insert = ctx.store.db.prepare(`INSERT OR IGNORE INTO managed_item_sources(
395
+ item_id, source_ref, origin, evidence, evidence_hash, input_hash, created_at
396
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)`);
397
+ const createdAt = new Date().toISOString();
398
+ ctx.store.transaction(() => {
399
+ for (const source of sources) {
400
+ insert.run(source.itemId, source.sourceRef, source.origin, source.evidence, source.evidenceHash, source.inputHash, createdAt);
401
+ }
402
+ });
403
+ }
404
+ /**
405
+ * A title for a page being created: the subject the curator named, unless that subject is not
406
+ * what the page is.
407
+ *
408
+ * `write` derives one from the slug when none is given, and a slug-derived title reads like a
409
+ * filename ("Vulpine Claim 2026 08"). The subject is a phrase a person wrote, so it wins wherever
410
+ * the two are about the same thing.
411
+ *
412
+ * They are not always about the same thing, and that is this function's whole problem. The slug
413
+ * comes from routing, which scored ranked candidates; the subject came off one claim. A narrow
414
+ * equipment claim can correctly open `expeditions/blackwater-bay-survey` while still being too
415
+ * specific to name that broader page. A claim is
416
+ * superseded in a week; the title it installed outlives it by months.
417
+ *
418
+ * **One shared content word is enough to keep the subject.** The question is not whether the two
419
+ * agree closely, only whether they are about the same thing at all: `people/ada-marlow` and "Ada
420
+ * Marlow" share both words, `vulpine-claim-2026-08` and "Vulpine claim" share two, while a broad
421
+ * expedition slug and one equipment calibration share none. Falling back costs a plainer title, which is worth
422
+ * paying — a slug-derived title is dull but it is never about the wrong thing.
423
+ */
424
+ function titleFor(candidate, slug) {
425
+ const subject = candidate.subject.trim();
426
+ if (subject.length === 0)
427
+ return titleFromSlug(slug);
428
+ const named = contentWords(slug.slice(slug.lastIndexOf('/') + 1));
429
+ for (const word of contentWords(subject)) {
430
+ if (named.has(word))
431
+ return subject.charAt(0).toUpperCase() + subject.slice(1);
432
+ }
433
+ return titleFromSlug(slug);
434
+ }
435
+ function newManagedPage(title) {
436
+ return `---\ntitle: ${JSON.stringify(title)}\nakno:\n role: knowledge\n management:\n remember: integrate\n---\n\n# ${title}\n`;
437
+ }
438
+ /**
439
+ * An internal `recall` finds where a claim belongs. **Best score at or above
440
+ * `route_threshold` wins and the claim is appended there; below that a page is created** at
441
+ * the slug the curator suggested.
442
+ *
443
+ * The second half is new, and it is the difference between a knowledge base that grows and one
444
+ * that only thickens. Below the threshold used to mean a proposal — a question for the user
445
+ * about where a claim goes — and a proposal is a page nobody writes. It fell hardest on
446
+ * exactly the material a knowledge base most needs new pages for: a finding about the world
447
+ * belongs in `research/` or `wiki/`, those folders have the `source` role, routing refuses
448
+ * source pages on principle, and so every finding reached the one outcome that stores
449
+ * nothing. Creating is the honest answer to "nothing here holds this".
450
+ *
451
+ * 0.5 is a placeholder and cannot be tuned by intuition, because the failure it guards against
452
+ * is invisible until someone reads it back months later. The mechanism is here; only the
453
+ * number moves.
454
+ */
455
+ /**
456
+ * Routing thresholds **`relevance`, never `score`.**
457
+ *
458
+ * `score` orders one result set: the best hit is 1.0 whether it is a perfect match or
459
+ * the least bad of a bad batch. Thresholding it meant every document found a home and
460
+ * "A document with no home stays put" could never fire — routing looked like it
461
+ * worked and was in fact unconditional.
462
+ *
463
+ * `relevance` is absolute when a cross-encoder or the embedding arm supplied one. With
464
+ * neither — a lexical-only search — there is no number to compare, so routing refuses
465
+ * and asks. The failure this guards against — a fact quietly landing on a plausible wrong
466
+ * page — is invisible until someone reads it back months later, and a guess is worse than a
467
+ * question.
468
+ */
469
+ /**
470
+ * Two questions, asked in order.
471
+ *
472
+ * The claim scores first, because the claim is what makes routing *specific*: when two pages
473
+ * could own a subject, only the attribute text says which. But a cross-encoder judges "does
474
+ * this passage answer this query", and a claim carries an attribute the owning page has no
475
+ * reason to already state. The invented regression fixture makes an amenity-heavy claim score
476
+ * poorly against the owning trip page, while the venue subject alone scores that page strongly.
477
+ * Same index, same options, same threshold.
478
+ *
479
+ * So the subject is asked only when the claim found nobody — the ownership question after the
480
+ * answers-this question came back empty. It costs a second recall exactly when the alternative
481
+ * was creating a page, never on the path that already routed, and it can only rescue a miss:
482
+ * a claim that routed keeps the destination its own text chose.
483
+ */
484
+ async function route(ctx, candidate) {
485
+ const byClaim = await scoreDestinations(ctx, `${candidate.subject}. ${candidate.text}`, candidate);
486
+ if (byClaim.slug !== null || byClaim.blocked !== null)
487
+ return byClaim;
488
+ const subject = candidate.subject.trim();
489
+ if (subject.length === 0)
490
+ return byClaim;
491
+ const bySubject = await scoreDestinations(ctx, subject, candidate);
492
+ if (bySubject.slug !== null || bySubject.blocked !== null)
493
+ return bySubject;
494
+ // Neither routed. Report whichever came closer, and prefer the claim pass's suggestions:
495
+ // they were drawn against the text the user actually said.
496
+ const closer = bySubject.score > byClaim.score ? bySubject : byClaim;
497
+ return { ...closer, nearest: byClaim.nearest.length > 0 ? byClaim.nearest : bySubject.nearest };
498
+ }
499
+ async function scoreDestinations(ctx, query, candidate) {
500
+ const result = await recall(ctx, {
501
+ query,
502
+ mode: 'lookup',
503
+ limit: 5,
504
+ // Summaries only: routing is a decision about *which page*, and line windows
505
+ // are budget spent on text nobody reads here.
506
+ depth: 'summary',
507
+ // The query is the claim itself; a model rewriting it cannot improve the match.
508
+ expand: false,
509
+ });
510
+ // Never route into a source page: it is somebody else's words, and the rule is
511
+ // explicit that only claims become facts. Appending a claim to evidence would make
512
+ // the role boundary meaningless.
513
+ //
514
+ // And never into a reserved path. The ledger is the one that bites: it is a plain `full`
515
+ // page, so nothing above disqualified it, and a ledger that already records events about a
516
+ // subject is *the best lexical match for that subject* — which is how a claim about an
517
+ // ongoing complaint came to be appended below the event list of the page recording it, in
518
+ // prose the event parser cannot see. The destination that scores highest is not always a
519
+ // destination.
520
+ const candidates = result.results
521
+ .filter((entry) => entry.type === 'page')
522
+ .filter((card) => card.role === 'knowledge' &&
523
+ !isReserved(card.slug, ctx.config) &&
524
+ isInsideSuggestedFolder(card.slug, candidate.page))
525
+ .map((card) => {
526
+ const policy = ctx.store.db
527
+ .prepare('SELECT remember_management FROM pages WHERE slug = ?')
528
+ .get(card.slug);
529
+ return { ...card, writable: policy?.remember_management === 'integrate' };
530
+ });
531
+ // Suggestions are drawn from the same set, not from every card. Offering a source page as
532
+ // somewhere a claim "could go instead" proposes a destination this very function would refuse.
533
+ // The regression uses evidence-only pages that look topically close but cannot own the claim.
534
+ const nearest = candidates
535
+ .filter((card) => card.writable)
536
+ .slice(0, 4)
537
+ .map((card) => card.slug);
538
+ // **The best-judged candidate, not the best-ranked one.**
539
+ //
540
+ // This took the first card with a relevance and thresholded only that. Card order is
541
+ // `score * rankFactor`, and a card's score is the best of its chunks, so the page that leads
542
+ // is the page with one strong passage — not necessarily the page a cross-encoder considers
543
+ // the right home. When the leader fell below the threshold, routing refused and the claim
544
+ // dropped to the retain model's guessed slug, with every remaining candidate unread.
545
+ //
546
+ // The invented regression ranks an unrelated page first while a later subscription page scores
547
+ // strongly. Reading only the leader discards that measurement. Taking the maximum cannot route
548
+ // anything the old code would have refused *and*
549
+ // the threshold rejects; it can only stop a low leader from hiding a qualified page behind it.
550
+ const scored = candidates.filter((card) => card.relevance !== undefined);
551
+ if (scored.length === 0)
552
+ return { slug: null, score: 0, nearest, blocked: null };
553
+ const best = scored.reduce((winner, card) => (card.relevance > winner.relevance ? card : winner));
554
+ const relevance = best.relevance;
555
+ if (relevance < ctx.config.routeThreshold) {
556
+ return { slug: null, score: relevance, nearest, blocked: null };
557
+ }
558
+ if (!best.writable) {
559
+ // A read-only page winning semantically is evidence that a weaker writable match is the
560
+ // wrong home. Preserve that decision and let the new-page or typed hold path handle it.
561
+ return { slug: null, score: relevance, nearest, blocked: best.slug };
562
+ }
563
+ return { slug: best.slug, score: relevance, nearest, blocked: null };
564
+ }
565
+ /**
566
+ * The retain model chooses the taxonomy branch from the complete folder catalog; recall chooses a
567
+ * page inside that branch. Letting recall cross the branch boundary turns topical similarity into
568
+ * ownership — a general music finding can otherwise land on a person's repertoire page.
569
+ */
570
+ function isInsideSuggestedFolder(slug, suggestedPage) {
571
+ // No taxonomy choice means no automatic destination. The retain prompt asks for one whenever
572
+ // an existing folder fits; omission is uncertainty, and uncertainty should become a proposal.
573
+ if (!suggestedPage)
574
+ return false;
575
+ const folder = suggestedPage.slice(0, suggestedPage.lastIndexOf('/'));
576
+ return slug.startsWith(`${folder}/`);
577
+ }
578
+ export { isInsideSuggestedFolder as isInsideSuggestedFolderForTesting };
579
+ /** Does a page with this slug already exist, whatever its role? */
580
+ function pageExists(ctx, slug) {
581
+ return ctx.store.db.prepare('SELECT 1 FROM pages WHERE slug = ?').get(slug) !== undefined;
582
+ }
583
+ function suggestedFolder(entry) {
584
+ const slug = entry.candidate.page;
585
+ return slug ? slug.slice(0, slug.lastIndexOf('/')) : null;
586
+ }
587
+ function requiredFolders(ctx, catalog, routed) {
588
+ const required = routed.flatMap((entry) => {
589
+ const slug = entry.slug ?? entry.candidate.page ?? null;
590
+ if (!slug || entry.slug !== null || pageExists(ctx, slug) || admittedFolder(catalog, slug))
591
+ return [];
592
+ return [
593
+ {
594
+ folder: slug.slice(0, slug.lastIndexOf('/')),
595
+ nearest: catalog
596
+ .filter((folder) => folder.eligible)
597
+ .map((folder) => folder.path)
598
+ .slice(0, 8),
599
+ },
600
+ ];
601
+ });
602
+ return deduplicateRequiredFolders(required);
603
+ }
604
+ function deduplicateRequiredFolders(folders) {
605
+ return folders.filter((required, index) => folders.findIndex((other) => other.folder === required.folder) === index);
606
+ }
607
+ /** The page does not exist yet, so only an explicit folder rule can admit its creation. */
608
+ function admittedFolder(catalog, slug) {
609
+ const parent = slug.slice(0, slug.lastIndexOf('/'));
610
+ return (catalog.find((folder) => folder.path === parent &&
611
+ folder.role === 'knowledge' &&
612
+ folder.remember === 'integrate' &&
613
+ folder.creatable) ?? null);
614
+ }
615
+ /**
616
+ * `refusedPage` names an existing page the retain model suggested and routing declined to use.
617
+ * It gets its own wording: the other two say a page has to be *found* or *made*, and neither
618
+ * describes the case where one was named, exists, and was judged not to be a home for this.
619
+ */
620
+ function proposeUnrouted(ctx, candidate, nearest, refusedPage, blockedPage) {
621
+ const id = newPrefixedId('prop');
622
+ const threshold = ctx.config.routeThreshold;
623
+ const stored = blockedPage
624
+ ? `the strongest match for "${candidate.subject}" is read-only: "${blockedPage}"`
625
+ : refusedPage
626
+ ? `nothing scored above ${threshold} for "${candidate.subject}"; the suggested page "${refusedPage}" exists but was not judged a home for it`
627
+ : nearest.length > 0
628
+ ? `no page scored above ${threshold} for "${candidate.subject}"`
629
+ : `no page exists that could hold "${candidate.subject}" — every near match is source material`;
630
+ ctx.store.db
631
+ .prepare(`INSERT INTO proposals(id, at, kind, reason, subject, payload, nearest, status)
632
+ VALUES(?, ?, 'route', ?, ?, ?, ?, 'pending')`)
633
+ .run(id, new Date().toISOString(), stored, candidate.subject, JSON.stringify({ append: candidate.text }), JSON.stringify(nearest));
634
+ return {
635
+ proposal_id: id,
636
+ reason: blockedPage
637
+ ? `"${blockedPage}" is the best match for "${candidate.subject}" but is read-only — create or name a managed destination rather than using a weaker page`
638
+ : refusedPage
639
+ ? `"${refusedPage}" already exists and nothing judged it a home for "${candidate.subject}" — ask where this goes rather than appending to it`
640
+ : nearest.length > 0
641
+ ? `nothing scored above ${threshold} for "${candidate.subject}" — ask where this goes`
642
+ : `no page could hold "${candidate.subject}" — every near match is source material, so this needs a new page`,
643
+ reason_code: unroutedReasonCode(nearest, refusedPage, blockedPage),
644
+ nearest,
645
+ };
646
+ }
647
+ function unroutedReasonCode(nearest, refusedPage, blockedPage) {
648
+ return blockedPage || (!refusedPage && nearest.length === 0)
649
+ ? 'no_writable_destination'
650
+ : 'routing_uncertain';
651
+ }
652
+ function recordConflictProposal(ctx, slug, candidate, existing) {
653
+ const id = newPrefixedId('prop');
654
+ ctx.store.db
655
+ .prepare(`INSERT INTO proposals(id, at, kind, reason, subject, payload, nearest, status)
656
+ VALUES(?, ?, 'conflict', ?, ?, ?, ?, 'pending')`)
657
+ .run(id, new Date().toISOString(), `'${slug}' already claims: ${existing}`, slug, JSON.stringify({ slug, append: candidate.text }), JSON.stringify([slug]));
658
+ return id;
659
+ }
660
+ //# sourceMappingURL=remember.js.map