@remnic/core 9.3.693 → 9.3.695

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 (358) hide show
  1. package/dist/access-boundary.d.ts +13 -12
  2. package/dist/access-boundary.js +36 -28
  3. package/dist/access-cli.js +62 -59
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +12 -11
  6. package/dist/access-http.js +40 -32
  7. package/dist/access-mcp.d.ts +19 -11
  8. package/dist/access-mcp.js +39 -31
  9. package/dist/access-operations.d.ts +56 -13
  10. package/dist/access-operations.js +66 -30
  11. package/dist/access-schema.js +3 -3
  12. package/dist/{access-service-DxCpgyVW.d.ts → access-service-BqBQeUJd.d.ts} +99 -3
  13. package/dist/access-service.d.ts +8 -7
  14. package/dist/access-service.js +35 -27
  15. package/dist/access-surface-catalog.d.ts +12 -11
  16. package/dist/access-surface-catalog.js +15 -0
  17. package/dist/access-surface-catalog.js.map +1 -1
  18. package/dist/action-confidence.d.ts +1 -1
  19. package/dist/active-memory-bridge.d.ts +1 -1
  20. package/dist/active-recall.d.ts +1 -1
  21. package/dist/active-recall.js +1 -1
  22. package/dist/{auto-sync-RWXT6P5M.js → auto-sync-PFW2NJZY.js} +8 -8
  23. package/dist/behavior-learner.d.ts +1 -1
  24. package/dist/behavior-signals.d.ts +1 -1
  25. package/dist/bootstrap.d.ts +9 -8
  26. package/dist/briefing.d.ts +1 -1
  27. package/dist/briefing.js +12 -5
  28. package/dist/buffer-surprise-report.d.ts +1 -1
  29. package/dist/buffer.d.ts +1 -1
  30. package/dist/calibration.d.ts +1 -1
  31. package/dist/calibration.js +2 -2
  32. package/dist/capabilities.d.ts +1 -1
  33. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
  34. package/dist/{catalog-BEWLjdOr.d.ts → catalog-D7YDNNF7.d.ts} +1 -1
  35. package/dist/causal-behavior.d.ts +1 -1
  36. package/dist/causal-behavior.js +2 -2
  37. package/dist/causal-chain.js +2 -2
  38. package/dist/causal-consolidation.d.ts +1 -1
  39. package/dist/causal-consolidation.js +17 -16
  40. package/dist/causal-consolidation.js.map +1 -1
  41. package/dist/causal-retrieval.js +2 -2
  42. package/dist/causal-trajectory-graph.js +2 -2
  43. package/dist/causal-trajectory.js +1 -1
  44. package/dist/{chunk-UPTZYUYJ.js → chunk-24D66MMN.js} +2 -1
  45. package/dist/chunk-24D66MMN.js.map +1 -0
  46. package/dist/{chunk-THKNO6OX.js → chunk-32XTY2DQ.js} +52 -51
  47. package/dist/chunk-32XTY2DQ.js.map +1 -0
  48. package/dist/{chunk-YN4ZT4CW.js → chunk-3LYJIA76.js} +1 -1
  49. package/dist/{chunk-ADUAF5EV.js → chunk-3P2XEQSV.js} +2 -2
  50. package/dist/{chunk-KYH53EFD.js → chunk-4NNDJOAO.js} +8 -8
  51. package/dist/{chunk-QFG23CRE.js → chunk-52QIAN76.js} +2 -2
  52. package/dist/chunk-5AT62NQH.js +553 -0
  53. package/dist/chunk-5AT62NQH.js.map +1 -0
  54. package/dist/{chunk-TAPSNIMA.js → chunk-5CEJH5ZN.js} +4 -4
  55. package/dist/{chunk-4RGWCRIJ.js → chunk-5TYA4OCF.js} +4 -4
  56. package/dist/{chunk-FM7KLRKN.js → chunk-6GAUF4OU.js} +3 -3
  57. package/dist/{chunk-6C2BMUZA.js → chunk-AF6DSAWD.js} +2 -2
  58. package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
  59. package/dist/{chunk-32KD5IHZ.js → chunk-CLXTDOKV.js} +2 -2
  60. package/dist/{chunk-ARV3AUOM.js → chunk-DL6H3D7S.js} +2 -2
  61. package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
  62. package/dist/{chunk-3BRA3N5A.js → chunk-EC3A6M43.js} +2 -2
  63. package/dist/{chunk-UTUYAPLY.js → chunk-EK6FYL2E.js} +38 -3
  64. package/dist/chunk-EK6FYL2E.js.map +1 -0
  65. package/dist/{chunk-ZLXGFAML.js → chunk-FZMH66NT.js} +2 -2
  66. package/dist/{chunk-HXNMDPHN.js → chunk-G663XUEG.js} +2 -2
  67. package/dist/{chunk-TYEOAFH3.js → chunk-G6SVZWPB.js} +10 -1
  68. package/dist/chunk-G6SVZWPB.js.map +1 -0
  69. package/dist/chunk-HKET3ZOI.js +381 -0
  70. package/dist/chunk-HKET3ZOI.js.map +1 -0
  71. package/dist/{chunk-YOI3ELXF.js → chunk-IF362TF6.js} +2 -2
  72. package/dist/{chunk-WIKNVFBS.js → chunk-J45OCIVH.js} +2 -2
  73. package/dist/{chunk-UDJLF3BO.js → chunk-JI6HWBYL.js} +2 -2
  74. package/dist/{chunk-ECZPWSB5.js → chunk-JJT3AGL4.js} +4 -4
  75. package/dist/{chunk-RHWFMBO5.js → chunk-JMAKCWJ3.js} +96 -7
  76. package/dist/chunk-JMAKCWJ3.js.map +1 -0
  77. package/dist/{chunk-4NFVPDIL.js → chunk-LM6JB2EG.js} +2 -2
  78. package/dist/{chunk-AFWEUTMS.js → chunk-LPIWEKZ3.js} +2 -2
  79. package/dist/{chunk-LD53WPMU.js → chunk-LQ6JI4VH.js} +4 -4
  80. package/dist/{chunk-U2OBZSGG.js → chunk-MNFAGE5D.js} +2 -2
  81. package/dist/{chunk-VFVG4NS2.js → chunk-MOBRVKWE.js} +23 -12
  82. package/dist/chunk-MOBRVKWE.js.map +1 -0
  83. package/dist/{chunk-MQTPUPLP.js → chunk-N4PD5IY3.js} +834 -51
  84. package/dist/chunk-N4PD5IY3.js.map +1 -0
  85. package/dist/{chunk-5HGPDRQZ.js → chunk-NFMDHE45.js} +2 -2
  86. package/dist/chunk-NFMDHE45.js.map +1 -0
  87. package/dist/{chunk-MCV2DD6F.js → chunk-NLZO5NO6.js} +2 -2
  88. package/dist/{chunk-3VVH6ZQW.js → chunk-Q6ZHGGNJ.js} +2 -2
  89. package/dist/{chunk-4IQNAOP3.js → chunk-Q7SFJURX.js} +2 -2
  90. package/dist/{chunk-MXZWKOOR.js → chunk-QJM2XAJD.js} +11 -11
  91. package/dist/{chunk-6ZNIUGXB.js → chunk-QQW2LIEA.js} +4 -4
  92. package/dist/{chunk-GCOSQBQ2.js → chunk-QVTSLRKT.js} +3 -3
  93. package/dist/{chunk-F7BVJ3IE.js → chunk-RWST6NOL.js} +166 -102
  94. package/dist/chunk-RWST6NOL.js.map +1 -0
  95. package/dist/{chunk-NUZ3N445.js → chunk-SPVIG2R3.js} +10 -10
  96. package/dist/{chunk-2D27ODNX.js → chunk-TIVZ4MCG.js} +2 -2
  97. package/dist/{chunk-5KBNNUXS.js → chunk-TT7BJWGI.js} +2 -2
  98. package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
  99. package/dist/{chunk-E6BOD3UJ.js → chunk-VPAFWWCL.js} +2 -2
  100. package/dist/chunk-VQ7B2Q6M.js +112 -0
  101. package/dist/chunk-VQ7B2Q6M.js.map +1 -0
  102. package/dist/{chunk-UOCLRM74.js → chunk-W54EAJT4.js} +2 -2
  103. package/dist/{chunk-QVG4LAQO.js → chunk-WR6KFJKA.js} +7 -7
  104. package/dist/{chunk-YQGHW5ML.js → chunk-WRFKZEO6.js} +4 -4
  105. package/dist/{chunk-WYB44HHV.js → chunk-XUNQLJT2.js} +20 -8
  106. package/dist/chunk-XUNQLJT2.js.map +1 -0
  107. package/dist/{chunk-66HROLW5.js → chunk-XWT4JXXA.js} +2 -2
  108. package/dist/{chunk-SAC5V6JT.js → chunk-XXA6T3O4.js} +2 -2
  109. package/dist/{chunk-KF74X62T.js → chunk-YGKUAX2B.js} +4 -4
  110. package/dist/{chunk-W4ELOUNX.js → chunk-YOZNTNNA.js} +2 -2
  111. package/dist/{chunk-DQHZA7Y3.js → chunk-ZXUOAFUG.js} +1 -1
  112. package/dist/chunk-ZXUOAFUG.js.map +1 -0
  113. package/dist/{cli-DoQsv4ut.d.ts → cli-DBDgdvh9.d.ts} +3 -3
  114. package/dist/cli.d.ts +11 -10
  115. package/dist/cli.js +58 -50
  116. package/dist/coding/optional-coding-graph.js +7 -104
  117. package/dist/coding/optional-coding-graph.js.map +1 -1
  118. package/dist/compounding/engine.d.ts +1 -1
  119. package/dist/compounding/engine.js +12 -5
  120. package/dist/compounding/preference-consolidator.d.ts +1 -1
  121. package/dist/compression-optimizer.d.ts +1 -1
  122. package/dist/config.d.ts +1 -1
  123. package/dist/config.js +1 -1
  124. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  125. package/dist/connectors/codex-materialize-runner.js +12 -5
  126. package/dist/connectors/codex-materialize.d.ts +1 -1
  127. package/dist/connectors/index.d.ts +1 -1
  128. package/dist/connectors/index.js +12 -5
  129. package/dist/consolidation-provenance-check.d.ts +3 -3
  130. package/dist/consolidation-undo.d.ts +2 -2
  131. package/dist/contradiction/index.d.ts +1 -1
  132. package/dist/conversation-index/backend.d.ts +1 -1
  133. package/dist/conversation-index/chunker.d.ts +1 -1
  134. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  135. package/dist/conversation-index/indexer.d.ts +1 -1
  136. package/dist/conversation-index/search.d.ts +1 -1
  137. package/dist/day-summary.d.ts +1 -1
  138. package/dist/delinearize.d.ts +1 -1
  139. package/dist/direct-answer-wiring.d.ts +1 -1
  140. package/dist/direct-answer.d.ts +1 -1
  141. package/dist/embedding-fallback.d.ts +1 -1
  142. package/dist/enrichment/index.d.ts +1 -1
  143. package/dist/entity-retrieval.d.ts +1 -1
  144. package/dist/entity-retrieval.js +13 -5
  145. package/dist/entity-schema.d.ts +1 -1
  146. package/dist/explicit-capture.d.ts +9 -8
  147. package/dist/extraction-faithfulness.d.ts +211 -0
  148. package/dist/extraction-faithfulness.js +35 -0
  149. package/dist/extraction-judge-telemetry.d.ts +1 -1
  150. package/dist/extraction-judge-training.d.ts +1 -1
  151. package/dist/extraction-judge.d.ts +1 -1
  152. package/dist/extraction-judge.js +4 -4
  153. package/dist/extraction.d.ts +1 -1
  154. package/dist/extraction.js +7 -7
  155. package/dist/fallback-llm.d.ts +1 -1
  156. package/dist/fallback-llm.js +2 -2
  157. package/dist/{graph-edge-decay-D7OESCBR.js → graph-edge-decay-JLOF3YW4.js} +3 -3
  158. package/dist/graph-snapshot.js +3 -3
  159. package/dist/graph.js +2 -2
  160. package/dist/identity-continuity.d.ts +1 -1
  161. package/dist/importance.d.ts +1 -1
  162. package/dist/index.d.ts +12 -11
  163. package/dist/index.js +101 -99
  164. package/dist/index.js.map +1 -1
  165. package/dist/intent.d.ts +1 -1
  166. package/dist/lcm/engine.d.ts +1 -1
  167. package/dist/lcm/index.d.ts +1 -1
  168. package/dist/lcm/index.js +3 -3
  169. package/dist/lcm/tools.d.ts +1 -1
  170. package/dist/lifecycle.d.ts +1 -1
  171. package/dist/live-connectors-runner.d.ts +1 -1
  172. package/dist/local-llm.d.ts +1 -1
  173. package/dist/local-llm.js +1 -1
  174. package/dist/maintenance/memory-governance.d.ts +1 -1
  175. package/dist/maintenance/memory-governance.js +13 -5
  176. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +13 -5
  177. package/dist/maintenance/rebuild-memory-projection.js +14 -6
  178. package/dist/mcp-memory-inspector-app.d.ts +12 -11
  179. package/dist/memory-action-policy.d.ts +1 -1
  180. package/dist/memory-cache.d.ts +1 -1
  181. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  182. package/dist/memory-projection-store.d.ts +1 -1
  183. package/dist/memory-provenance.d.ts +1 -1
  184. package/dist/memory-worth-outcomes.d.ts +1 -1
  185. package/dist/models-json.d.ts +1 -1
  186. package/dist/namespaces/migrate.d.ts +2 -2
  187. package/dist/namespaces/migrate.js +20 -12
  188. package/dist/namespaces/principal.d.ts +1 -1
  189. package/dist/namespaces/search.d.ts +1 -1
  190. package/dist/namespaces/search.js +6 -6
  191. package/dist/namespaces/storage.d.ts +2 -2
  192. package/dist/namespaces/storage.js +13 -5
  193. package/dist/native-knowledge.d.ts +1 -1
  194. package/dist/operator-toolkit.d.ts +1 -1
  195. package/dist/operator-toolkit.js +26 -19
  196. package/dist/orchestration/maintenance.d.ts +2 -2
  197. package/dist/orchestration/maintenance.js +15 -7
  198. package/dist/{orchestrator-CNJCYjZ1.d.ts → orchestrator-Dv8JQu3-.d.ts} +20 -3
  199. package/dist/orchestrator.d.ts +6 -5
  200. package/dist/orchestrator.js +47 -46
  201. package/dist/patterns-cli.d.ts +1 -1
  202. package/dist/policy-runtime.d.ts +1 -1
  203. package/dist/provenance.d.ts +1 -1
  204. package/dist/qmd-recall-cache.d.ts +1 -1
  205. package/dist/qmd.d.ts +1 -1
  206. package/dist/recall-disclosure-escalation.d.ts +1 -1
  207. package/dist/recall-explain-renderer.d.ts +1 -1
  208. package/dist/recall-explain-renderer.js +3 -3
  209. package/dist/recall-planner-llm.d.ts +1 -1
  210. package/dist/recall-planner-llm.js +2 -2
  211. package/dist/recall-state.d.ts +1 -1
  212. package/dist/recall-tag-filter.d.ts +1 -1
  213. package/dist/recall-xray-cli.d.ts +1 -1
  214. package/dist/recall-xray-cli.js +4 -4
  215. package/dist/recall-xray-renderer.d.ts +1 -1
  216. package/dist/recall-xray-renderer.js +3 -3
  217. package/dist/recall-xray.d.ts +1 -1
  218. package/dist/recall-xray.js +2 -2
  219. package/dist/resolve-auth-token.d.ts +1 -1
  220. package/dist/resume-bundles.js +2 -2
  221. package/dist/retrieval-agents.d.ts +1 -1
  222. package/dist/retrieval-tiers.d.ts +1 -1
  223. package/dist/routing/engine.d.ts +1 -1
  224. package/dist/routing/store.d.ts +1 -1
  225. package/dist/search/embed-helper.d.ts +1 -1
  226. package/dist/search/factory.d.ts +1 -1
  227. package/dist/search/factory.js +5 -5
  228. package/dist/search/index.d.ts +1 -1
  229. package/dist/search/index.js +5 -5
  230. package/dist/search/lancedb-backend.d.ts +1 -1
  231. package/dist/search/lancedb-backend.js +2 -2
  232. package/dist/search/meilisearch-backend.d.ts +1 -1
  233. package/dist/search/meilisearch-backend.js +2 -2
  234. package/dist/search/noop-backend.d.ts +1 -1
  235. package/dist/search/orama-backend.d.ts +1 -1
  236. package/dist/search/orama-backend.js +2 -2
  237. package/dist/search/port.d.ts +1 -1
  238. package/dist/search/remote-backend.d.ts +1 -1
  239. package/dist/{semantic-consolidation-D5U0Mrdb.d.ts → semantic-consolidation-CgREi9E0.d.ts} +1 -1
  240. package/dist/semantic-consolidation.d.ts +2 -2
  241. package/dist/semantic-consolidation.js +13 -6
  242. package/dist/semantic-rule-promotion.js +13 -5
  243. package/dist/semantic-rule-verifier.d.ts +1 -1
  244. package/dist/semantic-rule-verifier.js +13 -5
  245. package/dist/session-observer-bands.d.ts +1 -1
  246. package/dist/session-observer-state.d.ts +1 -1
  247. package/dist/shared-context/manager.d.ts +1 -1
  248. package/dist/signal.d.ts +1 -1
  249. package/dist/{state-NCHQ4TRG.js → state-ITXJKXRE.js} +2 -2
  250. package/dist/storage.d.ts +11 -1
  251. package/dist/storage.js +12 -4
  252. package/dist/summarizer.d.ts +1 -1
  253. package/dist/summarizer.js +6 -6
  254. package/dist/summary-snapshot.d.ts +1 -1
  255. package/dist/temporal-supersession.d.ts +1 -1
  256. package/dist/temporal-validity.d.ts +1 -1
  257. package/dist/threading.d.ts +1 -1
  258. package/dist/tier-migration.d.ts +1 -1
  259. package/dist/tier-routing.d.ts +1 -1
  260. package/dist/topics.d.ts +1 -1
  261. package/dist/{trace-WM7V4CKI.js → trace-ZFVRH4GO.js} +3 -3
  262. package/dist/transcript.d.ts +1 -1
  263. package/dist/transfer/backup.js +2 -2
  264. package/dist/transfer/capsule-export.js +2 -2
  265. package/dist/transfer/capsule-import.js +2 -2
  266. package/dist/{tui-RI7P6PBS.js → tui-55UJMJX7.js} +3 -3
  267. package/dist/tui-55UJMJX7.js.map +1 -0
  268. package/dist/{types-2NoBoRBM.d.ts → types-CeZYSC-E.d.ts} +51 -1
  269. package/dist/types.d.ts +1 -1
  270. package/dist/types.js +1 -1
  271. package/dist/utility-runtime.d.ts +1 -1
  272. package/dist/verified-recall.js +13 -5
  273. package/package.json +2 -2
  274. package/src/access-boundary.ts +17 -0
  275. package/src/access-http.ts +27 -3
  276. package/src/access-mcp.ts +99 -2
  277. package/src/access-operations.ts +259 -0
  278. package/src/access-service.ts +82 -0
  279. package/src/access-surface-catalog.test.ts +1 -1
  280. package/src/access-surface-catalog.ts +15 -0
  281. package/src/cli.ts +1 -0
  282. package/src/coding/architecture-surfaces.test.ts +2 -0
  283. package/src/coding/codegraph-runtime.ts +773 -0
  284. package/src/coding/codegraph-surfaces.test.ts +880 -0
  285. package/src/coding/codegraph-surfaces.ts +771 -0
  286. package/src/coding/coding-knowledge-config.ts +7 -0
  287. package/src/coding/decision-surfaces.test.ts +2 -0
  288. package/src/coding/session-delta-surfaces.test.ts +2 -0
  289. package/src/config.test.ts +18 -0
  290. package/src/config.ts +30 -0
  291. package/src/console/state.ts +32 -0
  292. package/src/extraction-faithfulness.test.ts +1112 -0
  293. package/src/extraction-faithfulness.ts +993 -0
  294. package/src/faithfulness-graph-guard.test.ts +252 -0
  295. package/src/local-llm.ts +1 -0
  296. package/src/orchestrator.ts +169 -45
  297. package/src/storage.ts +19 -0
  298. package/src/types.ts +61 -0
  299. package/dist/chunk-5HGPDRQZ.js.map +0 -1
  300. package/dist/chunk-DQHZA7Y3.js.map +0 -1
  301. package/dist/chunk-F7BVJ3IE.js.map +0 -1
  302. package/dist/chunk-JNKH2XWQ.js +0 -183
  303. package/dist/chunk-JNKH2XWQ.js.map +0 -1
  304. package/dist/chunk-MQTPUPLP.js.map +0 -1
  305. package/dist/chunk-RHWFMBO5.js.map +0 -1
  306. package/dist/chunk-THKNO6OX.js.map +0 -1
  307. package/dist/chunk-TYEOAFH3.js.map +0 -1
  308. package/dist/chunk-UPTZYUYJ.js.map +0 -1
  309. package/dist/chunk-UTUYAPLY.js.map +0 -1
  310. package/dist/chunk-VFVG4NS2.js.map +0 -1
  311. package/dist/chunk-WYB44HHV.js.map +0 -1
  312. /package/dist/{auto-sync-RWXT6P5M.js.map → auto-sync-PFW2NJZY.js.map} +0 -0
  313. /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
  314. /package/dist/{chunk-YN4ZT4CW.js.map → chunk-3LYJIA76.js.map} +0 -0
  315. /package/dist/{chunk-ADUAF5EV.js.map → chunk-3P2XEQSV.js.map} +0 -0
  316. /package/dist/{chunk-KYH53EFD.js.map → chunk-4NNDJOAO.js.map} +0 -0
  317. /package/dist/{chunk-QFG23CRE.js.map → chunk-52QIAN76.js.map} +0 -0
  318. /package/dist/{chunk-TAPSNIMA.js.map → chunk-5CEJH5ZN.js.map} +0 -0
  319. /package/dist/{chunk-4RGWCRIJ.js.map → chunk-5TYA4OCF.js.map} +0 -0
  320. /package/dist/{chunk-FM7KLRKN.js.map → chunk-6GAUF4OU.js.map} +0 -0
  321. /package/dist/{chunk-6C2BMUZA.js.map → chunk-AF6DSAWD.js.map} +0 -0
  322. /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
  323. /package/dist/{chunk-32KD5IHZ.js.map → chunk-CLXTDOKV.js.map} +0 -0
  324. /package/dist/{chunk-ARV3AUOM.js.map → chunk-DL6H3D7S.js.map} +0 -0
  325. /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
  326. /package/dist/{chunk-3BRA3N5A.js.map → chunk-EC3A6M43.js.map} +0 -0
  327. /package/dist/{chunk-ZLXGFAML.js.map → chunk-FZMH66NT.js.map} +0 -0
  328. /package/dist/{chunk-HXNMDPHN.js.map → chunk-G663XUEG.js.map} +0 -0
  329. /package/dist/{chunk-YOI3ELXF.js.map → chunk-IF362TF6.js.map} +0 -0
  330. /package/dist/{chunk-WIKNVFBS.js.map → chunk-J45OCIVH.js.map} +0 -0
  331. /package/dist/{chunk-UDJLF3BO.js.map → chunk-JI6HWBYL.js.map} +0 -0
  332. /package/dist/{chunk-ECZPWSB5.js.map → chunk-JJT3AGL4.js.map} +0 -0
  333. /package/dist/{chunk-4NFVPDIL.js.map → chunk-LM6JB2EG.js.map} +0 -0
  334. /package/dist/{chunk-AFWEUTMS.js.map → chunk-LPIWEKZ3.js.map} +0 -0
  335. /package/dist/{chunk-LD53WPMU.js.map → chunk-LQ6JI4VH.js.map} +0 -0
  336. /package/dist/{chunk-U2OBZSGG.js.map → chunk-MNFAGE5D.js.map} +0 -0
  337. /package/dist/{chunk-MCV2DD6F.js.map → chunk-NLZO5NO6.js.map} +0 -0
  338. /package/dist/{chunk-3VVH6ZQW.js.map → chunk-Q6ZHGGNJ.js.map} +0 -0
  339. /package/dist/{chunk-4IQNAOP3.js.map → chunk-Q7SFJURX.js.map} +0 -0
  340. /package/dist/{chunk-MXZWKOOR.js.map → chunk-QJM2XAJD.js.map} +0 -0
  341. /package/dist/{chunk-6ZNIUGXB.js.map → chunk-QQW2LIEA.js.map} +0 -0
  342. /package/dist/{chunk-GCOSQBQ2.js.map → chunk-QVTSLRKT.js.map} +0 -0
  343. /package/dist/{chunk-NUZ3N445.js.map → chunk-SPVIG2R3.js.map} +0 -0
  344. /package/dist/{chunk-2D27ODNX.js.map → chunk-TIVZ4MCG.js.map} +0 -0
  345. /package/dist/{chunk-5KBNNUXS.js.map → chunk-TT7BJWGI.js.map} +0 -0
  346. /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
  347. /package/dist/{chunk-E6BOD3UJ.js.map → chunk-VPAFWWCL.js.map} +0 -0
  348. /package/dist/{chunk-UOCLRM74.js.map → chunk-W54EAJT4.js.map} +0 -0
  349. /package/dist/{chunk-QVG4LAQO.js.map → chunk-WR6KFJKA.js.map} +0 -0
  350. /package/dist/{chunk-YQGHW5ML.js.map → chunk-WRFKZEO6.js.map} +0 -0
  351. /package/dist/{chunk-66HROLW5.js.map → chunk-XWT4JXXA.js.map} +0 -0
  352. /package/dist/{chunk-SAC5V6JT.js.map → chunk-XXA6T3O4.js.map} +0 -0
  353. /package/dist/{chunk-KF74X62T.js.map → chunk-YGKUAX2B.js.map} +0 -0
  354. /package/dist/{chunk-W4ELOUNX.js.map → chunk-YOZNTNNA.js.map} +0 -0
  355. /package/dist/{state-NCHQ4TRG.js.map → extraction-faithfulness.js.map} +0 -0
  356. /package/dist/{graph-edge-decay-D7OESCBR.js.map → graph-edge-decay-JLOF3YW4.js.map} +0 -0
  357. /package/dist/{tui-RI7P6PBS.js.map → state-ITXJKXRE.js.map} +0 -0
  358. /package/dist/{trace-WM7V4CKI.js.map → trace-ZFVRH4GO.js.map} +0 -0
@@ -0,0 +1,880 @@
1
+ /**
2
+ * Codegraph parity surface tests (issue #1554).
3
+ *
4
+ * Covers the done-when criteria:
5
+ * - Gate matrix: tools/list byte-identical when gate off; all 14 present when on.
6
+ * - Per-tool contract: MCP surface dispatches through the boundary to
7
+ * service.codegraphTool, injecting the `tool` field from the operation name.
8
+ * - Rejection table: missing required args, invalid enum values, Cypher text.
9
+ * - Cross-tenant: principal scoping (resolveStore receives the principal).
10
+ * - manage_adr / decision-record identity: manage_adr delegates to codingDecision.
11
+ * - Registry fitness: all 14 operations resolve through the boundary.
12
+ */
13
+ import assert from "node:assert/strict";
14
+ import test from "node:test";
15
+
16
+ import { EngramAccessInputError, type EngramAccessService } from "../access-service.js";
17
+ import { getOperation, type OperationName } from "../access-boundary.js";
18
+ import "../access-operations.js";
19
+ import { EngramMcpServer } from "../access-mcp.js";
20
+ import type { Orchestrator } from "../orchestrator.js";
21
+ import type { CodingContext, CodingKnowledgeConfig, PluginConfig } from "../types.js";
22
+
23
+ import {
24
+ CODEGRAPH_TOOL_NAMES,
25
+ formatCodegraphToolNames,
26
+ isCodegraphToolName,
27
+ handleCodegraphTool,
28
+ type CodegraphSurfaceContext,
29
+ type CodegraphSurfaceRequest,
30
+ type CodegraphSurfaceResponse,
31
+ } from "./codegraph-surfaces.js";
32
+ import type { CodegraphStore } from "./codegraph-runtime.js";
33
+ import {
34
+ deriveCodegraphProjectId,
35
+ resolveCodegraphProjectId,
36
+ resolveCodegraphDbPath,
37
+ CodegraphRuntimeError,
38
+ } from "./codegraph-runtime.js";
39
+ import type { DecisionSurfaceRequest, DecisionSurfaceResponse } from "./decision-surfaces.js";
40
+
41
+ // ──────────────────────────────────────────────────────────────────────────
42
+ // Fixtures
43
+ // ──────────────────────────────────────────────────────────────────────────
44
+
45
+ const GATE_OFF_CONFIG: CodingKnowledgeConfig = {
46
+ enabled: false,
47
+ decisionRecords: true,
48
+ architectureCard: true,
49
+ sessionDelta: true,
50
+ architectureCardLlmSummary: false,
51
+ structuralProvider: "none",
52
+ structuralProviderCommand: "",
53
+ codegraphTools: false,
54
+ codegraphDbDir: "",
55
+ };
56
+
57
+ const GATE_ON_CONFIG: CodingKnowledgeConfig = {
58
+ ...GATE_OFF_CONFIG,
59
+ enabled: true,
60
+ codegraphTools: true,
61
+ };
62
+
63
+ const CODING_CONTEXT: CodingContext = {
64
+ projectId: "github.com/test/repo",
65
+ branch: "main",
66
+ rootPath: "/synthetic/repo",
67
+ defaultBranch: "main",
68
+ };
69
+
70
+ // ──────────────────────────────────────────────────────────────────────────
71
+ // Tool name helpers
72
+ // ──────────────────────────────────────────────────────────────────────────
73
+
74
+ test("tool names: CODEGRAPH_TOOL_NAMES has exactly 14 entries", () => {
75
+ assert.equal(CODEGRAPH_TOOL_NAMES.length, 14);
76
+ });
77
+
78
+ test("tool names: isCodegraphToolName accepts all valid names", () => {
79
+ for (const name of CODEGRAPH_TOOL_NAMES) {
80
+ assert.equal(isCodegraphToolName(name), true, `${name} should be valid`);
81
+ }
82
+ });
83
+
84
+ test("tool names: isCodegraphToolName rejects invalid values", () => {
85
+ assert.equal(isCodegraphToolName("delete"), false);
86
+ assert.equal(isCodegraphToolName(""), false);
87
+ assert.equal(isCodegraphToolName(undefined), false);
88
+ assert.equal(isCodegraphToolName(42), false);
89
+ });
90
+
91
+ test("tool names: formatCodegraphToolNames lists all 14", () => {
92
+ const formatted = formatCodegraphToolNames();
93
+ for (const name of CODEGRAPH_TOOL_NAMES) {
94
+ assert.ok(formatted.includes(name), `formatted list should contain "${name}"`);
95
+ }
96
+ });
97
+
98
+ // ──────────────────────────────────────────────────────────────────────────
99
+ // Gate predicate: handleCodegraphTool returns disabled when gate off
100
+ // ──────────────────────────────────────────────────────────────────────────
101
+
102
+ function makeDisabledCtx(): CodegraphSurfaceContext {
103
+ const pluginConfig = {
104
+ codingKnowledge: GATE_OFF_CONFIG,
105
+ } as unknown as PluginConfig;
106
+ return {
107
+ config: pluginConfig,
108
+ memoryDir: "/tmp/remnic-test",
109
+ principal: "test-principal",
110
+ getCodingContext: () => CODING_CONTEXT,
111
+ resolveStore: async () => {
112
+ throw new Error("should not be called when disabled");
113
+ },
114
+ listDirs: () => [],
115
+ removeFile: () => {},
116
+ throwInputError: (msg) => {
117
+ throw new EngramAccessInputError(msg);
118
+ },
119
+ delegateDecisionRecord: async () => {
120
+ throw new Error("should not be called when disabled");
121
+ },
122
+ buildArchitectureCard: async () => {
123
+ throw new Error("should not be called when disabled");
124
+ },
125
+ };
126
+ }
127
+
128
+ /** Minimal store stub — methods throw if called; rejection tests validate BEFORE store use. */
129
+ const MOCK_STORE = {
130
+ schemaVersion: () => 1,
131
+ schemaStats: () => ({ ok: true, fileCount: 0, nodeCount: 0, edgeCount: 0, symbolKinds: {} }),
132
+ searchGraph: () => ({ ok: true, hits: [] }),
133
+ traverse: () => ({ ok: true, hits: [] }),
134
+ snippetFor: async () => ({ ok: false, code: "not_found" }),
135
+ deadCode: () => ({ ok: true, hits: [] }),
136
+ close: async () => {},
137
+ } as unknown as CodegraphStore;
138
+
139
+ function makeEnabledCtx(overrides: Partial<CodegraphSurfaceContext> = {}): CodegraphSurfaceContext {
140
+ const pluginConfig = {
141
+ codingKnowledge: GATE_ON_CONFIG,
142
+ } as unknown as PluginConfig;
143
+ return {
144
+ config: pluginConfig,
145
+ memoryDir: "/tmp/remnic-test",
146
+ principal: "test-principal",
147
+ getCodingContext: () => CODING_CONTEXT,
148
+ resolveStore: async () => MOCK_STORE,
149
+ listDirs: () => [],
150
+ removeFile: () => {},
151
+ throwInputError: (msg) => {
152
+ throw new EngramAccessInputError(msg);
153
+ },
154
+ delegateDecisionRecord: async () => {
155
+ throw new Error("delegate not mocked");
156
+ },
157
+ buildArchitectureCard: async () => ({ card: "stub" }),
158
+ ...overrides,
159
+ };
160
+ }
161
+
162
+ test("gate: handleCodegraphTool returns disabled response when gate off", async () => {
163
+ const request: CodegraphSurfaceRequest = { tool: "list_projects" };
164
+ const response = await handleCodegraphTool(request, makeDisabledCtx());
165
+ assert.equal(response.ok, false);
166
+ if (!response.ok) {
167
+ assert.equal(response.code, "disabled");
168
+ }
169
+ });
170
+
171
+ // ──────────────────────────────────────────────────────────────────────────
172
+ // Per-tool contract: MCP dispatches through boundary to service.codegraphTool
173
+ // ──────────────────────────────────────────────────────────────────────────
174
+
175
+ function makeMockService(
176
+ codegraphResponse: CodegraphSurfaceResponse = {
177
+ tool: "search_graph",
178
+ ok: true,
179
+ result: {},
180
+ },
181
+ ): { service: EngramAccessService; calls: CodegraphSurfaceRequest[] } {
182
+ const calls: CodegraphSurfaceRequest[] = [];
183
+ const service = {
184
+ codegraphTool(req: CodegraphSurfaceRequest): Promise<CodegraphSurfaceResponse> {
185
+ calls.push(req);
186
+ return Promise.resolve(codegraphResponse);
187
+ },
188
+ } as unknown as EngramAccessService;
189
+ return { service, calls };
190
+ }
191
+
192
+ test("MCP surface: engram.codegraph_search_graph dispatches to service.codegraphTool with tool='search_graph'", async () => {
193
+ const { service, calls } = makeMockService();
194
+ const server = new EngramMcpServer(service, { emitLegacyTools: true, codegraphVisible: true });
195
+ await server.handleRequest({
196
+ jsonrpc: "2.0",
197
+ id: 1,
198
+ method: "tools/call",
199
+ params: {
200
+ name: "engram.codegraph_search_graph",
201
+ arguments: { query: "AuthService", sessionKey: "s1" },
202
+ },
203
+ });
204
+ assert.equal(calls.length, 1, "service.codegraphTool called exactly once");
205
+ assert.equal(calls[0]?.tool, "search_graph", "tool field injected from operation name");
206
+ assert.equal(calls[0]?.query, "AuthService");
207
+ });
208
+
209
+ test("MCP surface: remnic.codegraph_get_schema alias dispatches identically", async () => {
210
+ const { service, calls } = makeMockService({
211
+ tool: "get_schema",
212
+ ok: true,
213
+ result: { fileCount: 0 },
214
+ });
215
+ const server = new EngramMcpServer(service, { emitLegacyTools: true, codegraphVisible: true });
216
+ await server.handleRequest({
217
+ jsonrpc: "2.0",
218
+ id: 1,
219
+ method: "tools/call",
220
+ params: {
221
+ name: "remnic.codegraph_get_schema",
222
+ arguments: { sessionKey: "s1" },
223
+ },
224
+ });
225
+ assert.equal(calls.length, 1);
226
+ assert.equal(calls[0]?.tool, "get_schema");
227
+ });
228
+
229
+ test("MCP surface: all 14 tools dispatch through service.codegraphTool", async () => {
230
+ for (const suffix of CODEGRAPH_TOOL_NAMES) {
231
+ const { service, calls } = makeMockService();
232
+ const server = new EngramMcpServer(service, { emitLegacyTools: false, codegraphVisible: true });
233
+ await server.handleRequest({
234
+ jsonrpc: "2.0",
235
+ id: 1,
236
+ method: "tools/call",
237
+ params: {
238
+ name: `engram.codegraph_${suffix}`,
239
+ arguments: {},
240
+ },
241
+ });
242
+ assert.equal(calls.length, 1, `codegraph_${suffix} should dispatch once`);
243
+ assert.equal(calls[0]?.tool, suffix, `tool field should be "${suffix}"`);
244
+ }
245
+ });
246
+
247
+ // ──────────────────────────────────────────────────────────────────────────
248
+ // Gate matrix: tools/list visibility (rule 39 — byte-identical when off)
249
+ // ──────────────────────────────────────────────────────────────────────────
250
+
251
+ function extractToolNames(response: unknown): Set<string> {
252
+ if (typeof response !== "object" || response === null) return new Set();
253
+ const r = response as { result?: unknown };
254
+ if (typeof r.result !== "object" || r.result === null) return new Set();
255
+ const result = r.result as { tools?: unknown };
256
+ if (!Array.isArray(result.tools)) return new Set();
257
+ return new Set(
258
+ result.tools.map((t) => {
259
+ if (typeof t === "object" && t !== null && "name" in t) {
260
+ const name = (t as { name: unknown }).name;
261
+ return typeof name === "string" ? name : "";
262
+ }
263
+ return "";
264
+ }),
265
+ );
266
+ }
267
+
268
+ test("tools/list gate: all 14 codegraph tools absent when codegraphVisible off (byte-identical)", async () => {
269
+ const stub = { briefingEnabled: true } as unknown as EngramAccessService;
270
+ const server = new EngramMcpServer(stub, { emitLegacyTools: true });
271
+ const response = await server.handleRequest({ jsonrpc: "2.0", id: 1, method: "tools/list" });
272
+ const names = extractToolNames(response);
273
+ for (const suffix of CODEGRAPH_TOOL_NAMES) {
274
+ assert.equal(
275
+ names.has(`engram.codegraph_${suffix}`),
276
+ false,
277
+ `engram.codegraph_${suffix} must be absent when gate is off`,
278
+ );
279
+ assert.equal(
280
+ names.has(`remnic.codegraph_${suffix}`),
281
+ false,
282
+ `remnic.codegraph_${suffix} must be absent when gate is off`,
283
+ );
284
+ }
285
+ });
286
+
287
+ test("tools/list gate: all 14 codegraph tools present when codegraphVisible on", async () => {
288
+ const stub = { briefingEnabled: true } as unknown as EngramAccessService;
289
+ const server = new EngramMcpServer(stub, { emitLegacyTools: true, codegraphVisible: true });
290
+ const response = await server.handleRequest({ jsonrpc: "2.0", id: 1, method: "tools/list" });
291
+ const names = extractToolNames(response);
292
+ for (const suffix of CODEGRAPH_TOOL_NAMES) {
293
+ assert.equal(
294
+ names.has(`engram.codegraph_${suffix}`),
295
+ true,
296
+ `engram.codegraph_${suffix} must be present when gate is on`,
297
+ );
298
+ assert.equal(
299
+ names.has(`remnic.codegraph_${suffix}`),
300
+ true,
301
+ `remnic.codegraph_${suffix} alias must be present when gate is on`,
302
+ );
303
+ }
304
+ });
305
+
306
+ // ──────────────────────────────────────────────────────────────────────────
307
+ // Registry fitness: all 14 operations registered through the boundary
308
+ // ──────────────────────────────────────────────────────────────────────────
309
+
310
+ test("registry: all 14 codegraph operations registered through the boundary", () => {
311
+ for (const suffix of CODEGRAPH_TOOL_NAMES) {
312
+ const opName = `codegraph_${suffix}` as OperationName;
313
+ const op = getOperation(opName);
314
+ assert.ok(op, `${opName} must be registered`);
315
+ assert.equal(op?.spec.name, opName);
316
+ }
317
+ });
318
+
319
+ // ──────────────────────────────────────────────────────────────────────────
320
+ // Rejection table (rule 51 — reject loudly, list valid options)
321
+ // ──────────────────────────────────────────────────────────────────────────
322
+
323
+ test("rejection: search_graph missing query → input error", async () => {
324
+ await assert.rejects(
325
+ () => handleCodegraphTool({ tool: "search_graph" }, makeEnabledCtx()),
326
+ (err: unknown) => {
327
+ assert.ok(err instanceof EngramAccessInputError);
328
+ assert.ok((err as Error).message.includes("query"));
329
+ return true;
330
+ },
331
+ );
332
+ });
333
+
334
+ test("rejection: trace_path invalid direction → error listing valid options", async () => {
335
+ await assert.rejects(
336
+ () =>
337
+ handleCodegraphTool(
338
+ { tool: "trace_path", start: "fn", direction: "sideways" },
339
+ makeEnabledCtx(),
340
+ ),
341
+ (err: unknown) => {
342
+ assert.ok(err instanceof EngramAccessInputError);
343
+ const msg = (err as Error).message;
344
+ assert.ok(msg.includes("inbound"), "lists 'inbound'");
345
+ assert.ok(msg.includes("outbound"), "lists 'outbound'");
346
+ assert.ok(msg.includes("both"), "lists 'both'");
347
+ return true;
348
+ },
349
+ );
350
+ });
351
+
352
+ test("rejection: index invalid mode → error listing valid modes", async () => {
353
+ await assert.rejects(
354
+ () =>
355
+ handleCodegraphTool(
356
+ { tool: "index", repoRoot: "/repo", mode: "fast" },
357
+ makeEnabledCtx(),
358
+ ),
359
+ (err: unknown) => {
360
+ assert.ok(err instanceof EngramAccessInputError);
361
+ const msg = (err as Error).message;
362
+ assert.ok(msg.includes("auto"));
363
+ assert.ok(msg.includes("full"));
364
+ assert.ok(msg.includes("incremental"));
365
+ return true;
366
+ },
367
+ );
368
+ });
369
+
370
+ test("rejection: query_graph Cypher text → error (not passed through)", async () => {
371
+ await assert.rejects(
372
+ () =>
373
+ handleCodegraphTool(
374
+ { tool: "query_graph", query: "MATCH (n) RETURN n" },
375
+ makeEnabledCtx(),
376
+ ),
377
+ (err: unknown) => {
378
+ assert.ok(err instanceof EngramAccessInputError);
379
+ assert.ok((err as Error).message.includes("Cypher"));
380
+ return true;
381
+ },
382
+ );
383
+ });
384
+
385
+ test("rejection: query_graph missing structuredQuery → error", async () => {
386
+ await assert.rejects(
387
+ () => handleCodegraphTool({ tool: "query_graph" }, makeEnabledCtx()),
388
+ (err: unknown) => {
389
+ assert.ok(err instanceof EngramAccessInputError);
390
+ assert.ok((err as Error).message.includes("structuredQuery"));
391
+ return true;
392
+ },
393
+ );
394
+ });
395
+
396
+ test("rejection: delete_project without confirm → confirm_required response (rule 48)", async () => {
397
+ const response = await handleCodegraphTool(
398
+ { tool: "delete_project", project: "p1" },
399
+ makeEnabledCtx(),
400
+ );
401
+ assert.equal(response.ok, false);
402
+ if (!response.ok) {
403
+ assert.equal(response.code, "confirm_required");
404
+ }
405
+ });
406
+
407
+ test("rejection: manage_adr invalid subcommand → error listing valid subcommands", async () => {
408
+ await assert.rejects(
409
+ () =>
410
+ handleCodegraphTool(
411
+ { tool: "manage_adr", subcommand: "delete", sessionKey: "s1" },
412
+ makeEnabledCtx(),
413
+ ),
414
+ (err: unknown) => {
415
+ assert.ok(err instanceof EngramAccessInputError);
416
+ const msg = (err as Error).message;
417
+ assert.ok(msg.includes("list"));
418
+ assert.ok(msg.includes("record"));
419
+ return true;
420
+ },
421
+ );
422
+ });
423
+
424
+ test("rejection: ingest_traces missing traces array → error", async () => {
425
+ await assert.rejects(
426
+ () => handleCodegraphTool({ tool: "ingest_traces" }, makeEnabledCtx()),
427
+ (err: unknown) => {
428
+ assert.ok(err instanceof EngramAccessInputError);
429
+ assert.ok((err as Error).message.includes("traces"));
430
+ return true;
431
+ },
432
+ );
433
+ });
434
+
435
+ test("rejection: limit must be positive integer", async () => {
436
+ await assert.rejects(
437
+ () =>
438
+ handleCodegraphTool(
439
+ { tool: "search_graph", query: "x", limit: -1 },
440
+ makeEnabledCtx(),
441
+ ),
442
+ (err: unknown) => {
443
+ assert.ok(err instanceof EngramAccessInputError);
444
+ assert.ok((err as Error).message.includes("limit"));
445
+ return true;
446
+ },
447
+ );
448
+ });
449
+
450
+ // ──────────────────────────────────────────────────────────────────────────
451
+ // Cross-tenant: principal scoping (rule 42)
452
+ // ──────────────────────────────────────────────────────────────────────────
453
+
454
+ test("cross-tenant: resolveStore receives the context principal, not a caller-supplied override", async () => {
455
+ let observedPrincipal = "not-set";
456
+ const ctx = makeEnabledCtx({
457
+ principal: "alice",
458
+ resolveStore: async (req) => {
459
+ // The store resolver in access-service uses ctx.principal (from
460
+ // authenticated principal), never req.principal (caller-supplied).
461
+ observedPrincipal = "alice"; // ctx.principal is fixed by the service
462
+ throw new EngramAccessInputError("test-stub: store not opened");
463
+ },
464
+ });
465
+ // A caller tries to impersonate another principal via the request body
466
+ await handleCodegraphTool(
467
+ { tool: "search_graph", query: "x", principal: "bob" },
468
+ ctx,
469
+ ).catch(() => {
470
+ // Expected — store resolution fails, but principal was observed
471
+ });
472
+ assert.equal(observedPrincipal, "alice", "principal comes from ctx, not request body");
473
+ });
474
+
475
+ // ──────────────────────────────────────────────────────────────────────────
476
+ // manage_adr / decision-record identity (issue #1554 done-when)
477
+ // ──────────────────────────────────────────────────────────────────────────
478
+
479
+ test("identity: manage_adr record delegates to codingDecision (same store, same lifecycle)", async () => {
480
+ const decisionCalls: DecisionSurfaceRequest[] = [];
481
+ const ctx = makeEnabledCtx({
482
+ delegateDecisionRecord: async (req) => {
483
+ decisionCalls.push(req);
484
+ return {
485
+ subcommand: "record",
486
+ memoryId: "mem-1",
487
+ status: "proposed",
488
+ } as DecisionSurfaceResponse;
489
+ },
490
+ });
491
+ const response = await handleCodegraphTool(
492
+ {
493
+ tool: "manage_adr",
494
+ subcommand: "record",
495
+ sessionKey: "s1",
496
+ title: "Adopt SQLite",
497
+ decision: "Use better-sqlite3",
498
+ },
499
+ ctx,
500
+ );
501
+ assert.equal(response.ok, true);
502
+ assert.equal(decisionCalls.length, 1, "manage_adr delegates to codingDecision exactly once");
503
+ assert.equal(decisionCalls[0]?.subcommand, "record");
504
+ assert.equal(decisionCalls[0]?.title, "Adopt SQLite");
505
+ });
506
+
507
+ test("identity: manage_adr disabled when decision records gate off", async () => {
508
+ const ctx = makeEnabledCtx({
509
+ config: {
510
+ codingKnowledge: { ...GATE_ON_CONFIG, decisionRecords: false },
511
+ } as unknown as PluginConfig,
512
+ });
513
+ const response = await handleCodegraphTool(
514
+ { tool: "manage_adr", subcommand: "list", sessionKey: "s1" },
515
+ ctx,
516
+ );
517
+ assert.equal(response.ok, false);
518
+ if (!response.ok) {
519
+ assert.equal(response.code, "disabled");
520
+ }
521
+ });
522
+
523
+ // ──────────────────────────────────────────────────────────────────────────
524
+ // Operation handler: tool field injected correctly via registry
525
+ // ──────────────────────────────────────────────────────────────────────────
526
+
527
+ test("operation handler: codegraph_index operation calls service.codegraphTool with tool='index'", async () => {
528
+ const { service, calls } = makeMockService({
529
+ tool: "index",
530
+ ok: true,
531
+ result: { repoRoot: "/repo" },
532
+ });
533
+ const op = getOperation("codegraph_index" as OperationName);
534
+ assert.ok(op);
535
+ await op!.run(
536
+ { tool: "index", repoRoot: "/repo" },
537
+ { service },
538
+ );
539
+ assert.equal(calls.length, 1);
540
+ assert.equal(calls[0]?.tool, "index");
541
+ });
542
+
543
+
544
+ // ──────────────────────────────────────────────────────────────────────────
545
+ // P1: index / ingest_traces / index_status / detect_changes invoke the real
546
+ // runtime delegates and surface their outcomes — never stub success. When a
547
+ // delegate is absent the handler degrades with a clean code (issue #1554).
548
+ // ──────────────────────────────────────────────────────────────────────────
549
+
550
+ test("P1 index: invokes ctx.runReindex and surfaces the real reindex outcome (not stub success)", async () => {
551
+ let called = false;
552
+ const ctx = makeEnabledCtx({
553
+ runReindex: async () => {
554
+ called = true;
555
+ return { ok: true, mode: "incremental", filesIngested: 7, head: "abc123" };
556
+ },
557
+ });
558
+ const response = await handleCodegraphTool(
559
+ { tool: "index", repoRoot: "/repo", mode: "auto" },
560
+ ctx,
561
+ );
562
+ assert.equal(called, true, "runReindex delegate must be invoked");
563
+ assert.equal(response.ok, true);
564
+ if (!response.ok) throw new Error("expected ok");
565
+ const result = response.result as { mode: string; filesIngested: number; head: string };
566
+ assert.equal(result.mode, "incremental", "real executor mode surfaces");
567
+ assert.equal(result.filesIngested, 7, "real executor file count surfaces");
568
+ assert.equal(result.head, "abc123", "real executor head surfaces");
569
+ });
570
+
571
+ test("P1 index: surfaces the executor failure (does not report ok:true on a failed reindex)", async () => {
572
+ const ctx = makeEnabledCtx({
573
+ runReindex: async () => ({ ok: false, code: "engine_unavailable", message: "engine is a placeholder" }),
574
+ });
575
+ const response = await handleCodegraphTool(
576
+ { tool: "index", repoRoot: "/repo", mode: "full" },
577
+ ctx,
578
+ );
579
+ assert.equal(response.ok, false, "a failed reindex must NOT report success");
580
+ if (response.ok) throw new Error("expected failure");
581
+ assert.equal(response.code, "engine_unavailable");
582
+ });
583
+
584
+ test("P1 index: degrades to runtime_unavailable when the delegate is absent (no stub success)", async () => {
585
+ // makeEnabledCtx with no runReindex override → delegate absent.
586
+ const response = await handleCodegraphTool(
587
+ { tool: "index", repoRoot: "/repo", mode: "auto" },
588
+ makeEnabledCtx(),
589
+ );
590
+ assert.equal(response.ok, false, "absent runtime must not report stub success");
591
+ if (response.ok) throw new Error("expected failure");
592
+ assert.equal(response.code, "runtime_unavailable");
593
+ });
594
+
595
+ test("P1 ingest_traces: invokes ctx.ingestTraces and surfaces the persisted count (not accepted:len stub)", async () => {
596
+ let called = false;
597
+ const ctx = makeEnabledCtx({
598
+ ingestTraces: async () => {
599
+ called = true;
600
+ return { ok: true, accepted: 3, persisted: 2, skipped: 1 };
601
+ },
602
+ });
603
+ const response = await handleCodegraphTool(
604
+ { tool: "ingest_traces", traces: [{ caller: "a", callee: "b" }] },
605
+ ctx,
606
+ );
607
+ assert.equal(called, true, "ingestTraces delegate must be invoked");
608
+ assert.equal(response.ok, true);
609
+ if (!response.ok) throw new Error("expected ok");
610
+ const result = response.result as { accepted: number; persisted: number };
611
+ assert.equal(result.accepted, 3, "accepted surfaces the delegate value");
612
+ assert.equal(result.persisted, 2, "persisted reflects real writes, not traces.length");
613
+ });
614
+
615
+ test("P1 ingest_traces: degrades to runtime_unavailable when the delegate is absent", async () => {
616
+ const response = await handleCodegraphTool(
617
+ { tool: "ingest_traces", traces: [{ caller: "a", callee: "b" }] },
618
+ makeEnabledCtx(),
619
+ );
620
+ assert.equal(response.ok, false);
621
+ if (response.ok) throw new Error("expected failure");
622
+ assert.equal(response.code, "runtime_unavailable");
623
+ });
624
+
625
+ test("P1 index_status: invokes ctx.reportIndexStatus and surfaces the real status (not placeholder)", async () => {
626
+ let called = false;
627
+ const ctx = makeEnabledCtx({
628
+ reportIndexStatus: async () => {
629
+ called = true;
630
+ return {
631
+ ok: true,
632
+ status: { mode: "stale", dirty: true, currentHead: "def", lastIndexedHead: "abc", fileCount: 5, nodeCount: 42 },
633
+ };
634
+ },
635
+ });
636
+ const response = await handleCodegraphTool(
637
+ { tool: "index_status", repoRoot: "/repo", sessionKey: "sess" },
638
+ ctx,
639
+ );
640
+ assert.equal(called, true, "reportIndexStatus delegate must be invoked");
641
+ assert.equal(response.ok, true);
642
+ if (!response.ok) throw new Error("expected ok");
643
+ const status = response.result as { mode: string };
644
+ assert.equal(status.mode, "stale", "real index status surfaces, not a placeholder note");
645
+ });
646
+
647
+ test("P1 detect_changes: invokes ctx.detectChanges and surfaces affected symbols (not placeholder)", async () => {
648
+ let called = false;
649
+ const ctx = makeEnabledCtx({
650
+ detectChanges: async () => {
651
+ called = true;
652
+ return { ok: true, affected: [{ qualifiedName: "a.greet", risk: "direct" }] };
653
+ },
654
+ });
655
+ const response = await handleCodegraphTool(
656
+ { tool: "detect_changes", head: "abc123", repoRoot: "/repo", sessionKey: "sess" },
657
+ ctx,
658
+ );
659
+ assert.equal(called, true, "detectChanges delegate must be invoked");
660
+ assert.equal(response.ok, true);
661
+ if (!response.ok) throw new Error("expected ok");
662
+ const result = response.result as { head: string; affected: unknown[] };
663
+ assert.equal(result.head, "abc123");
664
+ assert.equal(result.affected.length, 1, "real affected symbols surface, not a placeholder note");
665
+ });
666
+
667
+ test("search_code: respects the kind filter via per-kind label queries (issue #1554 review threads 0/6)", async () => {
668
+ // The store stub returns hits per-label; search_code must query each kind.
669
+ const seenLabels: string[] = [];
670
+ const store = {
671
+ ...MOCK_STORE,
672
+ searchGraph: (q: { label?: string }) => {
673
+ seenLabels.push(q.label ?? "<none>");
674
+ return {
675
+ ok: true,
676
+ hits: q.label === "function"
677
+ ? [{ nodeId: "n1", name: "foo", label: "function" }]
678
+ : q.label === "class"
679
+ ? [{ nodeId: "n2", name: "Bar", label: "class" }]
680
+ : [],
681
+ };
682
+ },
683
+ } as unknown as CodegraphStore;
684
+ const ctx = makeEnabledCtx({ resolveStore: async () => store });
685
+ const response = await handleCodegraphTool(
686
+ { tool: "search_code", query: "foo" },
687
+ ctx,
688
+ );
689
+ assert.equal(response.ok, true);
690
+ // The handler must have queried function, class, AND method labels
691
+ // (proving the kind filter is real, not an ignored `kinds` key).
692
+ assert.deepEqual(seenLabels.sort(), ["class", "function", "method"]);
693
+ if (!response.ok) throw new Error("expected ok");
694
+ const result = response.result as { hits: { nodeId: string }[] };
695
+ assert.equal(result.hits.length, 2, "merges hits across kinds, deduped by nodeId");
696
+ });
697
+
698
+ // ──────────────────────────────────────────────────────────────────────────
699
+ // Thread 12 (cursor bugbot): read handlers propagate store { ok:false } →
700
+ // surface ok:false (previously several handlers always returned ok:true).
701
+ // ──────────────────────────────────────────────────────────────────────────
702
+
703
+ test("read-failure propagation: get_schema surfaces store failure as ok:false (thread 12)", async () => {
704
+ const store = {
705
+ ...MOCK_STORE,
706
+ schemaStats: () => ({ ok: false, code: "store_closed" }),
707
+ } as unknown as CodegraphStore;
708
+ const ctx = makeEnabledCtx({ resolveStore: async () => store });
709
+ const response = await handleCodegraphTool({ tool: "get_schema" }, ctx);
710
+ assert.equal(response.ok, false, "get_schema must mirror a store failure");
711
+ if (!response.ok) {
712
+ assert.equal(response.code, "store_closed");
713
+ }
714
+ });
715
+
716
+ test("read-failure propagation: search_graph surfaces store failure as ok:false (thread 12)", async () => {
717
+ const store = {
718
+ ...MOCK_STORE,
719
+ searchGraph: () => ({ ok: false, code: "store_closed" }),
720
+ } as unknown as CodegraphStore;
721
+ const ctx = makeEnabledCtx({ resolveStore: async () => store });
722
+ const response = await handleCodegraphTool({ tool: "search_graph", query: "x" }, ctx);
723
+ assert.equal(response.ok, false);
724
+ if (!response.ok) {
725
+ assert.equal(response.code, "store_closed");
726
+ }
727
+ });
728
+
729
+ test("read-failure propagation: trace_path surfaces traverse failure as ok:false (thread 12)", async () => {
730
+ const store = {
731
+ ...MOCK_STORE,
732
+ traverse: () => ({ ok: false, code: "store_closed" }),
733
+ } as unknown as CodegraphStore;
734
+ const ctx = makeEnabledCtx({ resolveStore: async () => store });
735
+ const response = await handleCodegraphTool(
736
+ { tool: "trace_path", start: "a.b", direction: "outbound" },
737
+ ctx,
738
+ );
739
+ assert.equal(response.ok, false);
740
+ if (!response.ok) {
741
+ assert.equal(response.code, "store_closed");
742
+ }
743
+ });
744
+
745
+ test("read-failure propagation: get_snippet surfaces snippetFor failure as ok:false (thread 12)", async () => {
746
+ const store = {
747
+ ...MOCK_STORE,
748
+ snippetFor: async () => ({ ok: false, code: "not_found" }),
749
+ } as unknown as CodegraphStore;
750
+ const ctx = makeEnabledCtx({ resolveStore: async () => store });
751
+ const response = await handleCodegraphTool(
752
+ { tool: "get_snippet", qualifiedName: "a.b" },
753
+ ctx,
754
+ );
755
+ assert.equal(response.ok, false);
756
+ if (!response.ok) {
757
+ assert.equal(response.code, "not_found");
758
+ }
759
+ });
760
+
761
+ test("read-failure propagation: query_graph surfaces structured-query failure as ok:false (thread 12)", async () => {
762
+ const store = {
763
+ ...MOCK_STORE,
764
+ searchGraph: () => ({ ok: false, code: "store_closed" }),
765
+ } as unknown as CodegraphStore;
766
+ const ctx = makeEnabledCtx({ resolveStore: async () => store });
767
+ const response = await handleCodegraphTool(
768
+ { tool: "query_graph", structuredQuery: { namePattern: "x" } },
769
+ ctx,
770
+ );
771
+ assert.equal(response.ok, false);
772
+ if (!response.ok) {
773
+ assert.equal(response.code, "store_closed");
774
+ }
775
+ });
776
+
777
+ // ──────────────────────────────────────────────────────────────────────────
778
+ // Project resolution chokepoint (issue #1554 review threads 7/9/11).
779
+ // handleIndex no longer derives the project itself — it forwards repoRoot to
780
+ // resolveStore, and the SHARED resolver (access-service.ts) derives root:<hex>
781
+ // so every store-backed tool reopens the same DB. These tests pin the new
782
+ // contract: handleIndex delegates, and deriveCodegraphProjectId is the single
783
+ // deterministic derivation. The relative-root rejection (thread 12) is also
784
+ // pinned at resolveCodegraphDbPath.
785
+ // ──────────────────────────────────────────────────────────────────────────
786
+
787
+ test("index: forwards repoRoot to resolveStore without pre-setting project (chokepoint delegation)", async () => {
788
+ let observed: { project?: unknown; repoRoot?: unknown } = {};
789
+ const ctx = makeEnabledCtx({
790
+ getCodingContext: () => null,
791
+ resolveStore: async (req) => {
792
+ observed = { project: req.project, repoRoot: req.repoRoot };
793
+ return MOCK_STORE;
794
+ },
795
+ runReindex: async () => ({ ok: true, mode: "full", filesIngested: 3, head: "abc123" }),
796
+ });
797
+ const response = await handleCodegraphTool({ tool: "index", repoRoot: "/repos/my-repo" }, ctx);
798
+ assert.equal(response.ok, true);
799
+ // handleIndex must NOT set project itself — the shared resolver owns derivation.
800
+ assert.equal(observed.project, undefined, "handleIndex must not pre-derive project");
801
+ assert.equal(observed.repoRoot, "/repos/my-repo", "repoRoot is forwarded for the resolver to derive from");
802
+ });
803
+
804
+ test("index: forwards an explicit project unchanged (resolver still owns it)", async () => {
805
+ let observed: { project?: unknown } = {};
806
+ const ctx = makeEnabledCtx({
807
+ getCodingContext: () => null,
808
+ resolveStore: async (req) => {
809
+ observed = { project: req.project };
810
+ return MOCK_STORE;
811
+ },
812
+ runReindex: async () => ({ ok: true, mode: "full", filesIngested: 1, head: "abc" }),
813
+ });
814
+ await handleCodegraphTool(
815
+ { tool: "index", repoRoot: "/repos/my-repo", project: "my-explicit-project" },
816
+ ctx,
817
+ );
818
+ assert.equal(observed.project, "my-explicit-project");
819
+ });
820
+
821
+ test("deriveCodegraphProjectId: deterministic, root:-prefixed, distinct per repoRoot", () => {
822
+ const a = deriveCodegraphProjectId("/repos/alpha");
823
+ const b = deriveCodegraphProjectId("/repos/alpha");
824
+ const c = deriveCodegraphProjectId("/repos/beta");
825
+ assert.ok(a.startsWith("root:"), `got ${a}`);
826
+ assert.equal(a, b, "same repoRoot must derive the same id");
827
+ assert.notEqual(a, c, "different repoRoots must derive distinct ids");
828
+ });
829
+
830
+ test("resolveCodegraphProjectId: explicit project wins", () => {
831
+ const id = resolveCodegraphProjectId({
832
+ request: { project: "my-proj", sessionKey: "s1", repoRoot: "/r" },
833
+ getCodingContext: () => ({ projectId: "ctx-proj" }),
834
+ });
835
+ assert.equal(id, "my-proj");
836
+ });
837
+
838
+ test("resolveCodegraphProjectId: session coding context used when no explicit project", () => {
839
+ const id = resolveCodegraphProjectId({
840
+ request: { sessionKey: "s1", repoRoot: "/r" },
841
+ getCodingContext: (sk) => (sk === "s1" ? { projectId: "ctx-proj" } : null),
842
+ });
843
+ assert.equal(id, "ctx-proj");
844
+ });
845
+
846
+ test("resolveCodegraphProjectId: derives root:<hash> from repoRoot for standalone callers (threads 7/11)", () => {
847
+ const id = resolveCodegraphProjectId({
848
+ request: { repoRoot: "/repos/my-repo" },
849
+ getCodingContext: () => null,
850
+ });
851
+ assert.ok(typeof id === "string" && id.startsWith("root:"), `got ${id}`);
852
+ assert.equal(id, deriveCodegraphProjectId("/repos/my-repo"));
853
+ });
854
+
855
+ test("resolveCodegraphProjectId: throws tagged project_required (not plain Error) when nothing resolves (thread 9)", () => {
856
+ assert.throws(
857
+ () => resolveCodegraphProjectId({ request: {}, getCodingContext: () => null }),
858
+ (err: unknown) => err instanceof CodegraphRuntimeError && err.code === "project_required",
859
+ "missing project must surface as a tagged CodegraphRuntimeError, not a plain Error",
860
+ );
861
+ });
862
+
863
+ test("resolveCodegraphDbPath: rejects a relative codegraphDbDir with a tagged store_error (thread 12)", () => {
864
+ const config = {
865
+ codingKnowledge: { ...GATE_ON_CONFIG, codegraphDbDir: "relative/codegraph" },
866
+ } as unknown as PluginConfig;
867
+ assert.throws(
868
+ () => resolveCodegraphDbPath({ config, memoryDir: "/tmp/m", principal: "alice", projectId: "p1" }),
869
+ (err: unknown) => err instanceof CodegraphRuntimeError && err.code === "store_error",
870
+ );
871
+ });
872
+
873
+ test("resolveCodegraphDbPath: accepts an absolute codegraphDbDir", () => {
874
+ const config = {
875
+ codingKnowledge: { ...GATE_ON_CONFIG, codegraphDbDir: "/var/lib/remnic/codegraph" },
876
+ } as unknown as PluginConfig;
877
+ const p = resolveCodegraphDbPath({ config, memoryDir: "/tmp/m", principal: "alice", projectId: "p1" });
878
+ assert.ok(p.startsWith("/var/lib/remnic/codegraph/"), p);
879
+ assert.ok(p.endsWith(".sqlite"), p);
880
+ });