@hawkeyexl/manni 4.10.0 → 4.12.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 (243) hide show
  1. package/README.md +1 -1
  2. package/dist/batch-EFSFG6GC.js +46 -0
  3. package/dist/build-NIO3UIWJ.js +36 -0
  4. package/dist/calibrate-6VO7URRV.js +41 -0
  5. package/dist/capture-NMBVJO3C.js +38 -0
  6. package/dist/check-SHOYX2B5.js +30 -0
  7. package/dist/check-XMJKH3KV.js +34 -0
  8. package/dist/{check-NLL4NRYA.js → check-Y62BJNC4.js} +35 -31
  9. package/dist/{check-NLL4NRYA.js.map → check-Y62BJNC4.js.map} +1 -1
  10. package/dist/{check-7B77ZD2N.js → check-ZMO3ZLMW.js} +19 -15
  11. package/dist/{chunk-PK7EKJ5T.js → chunk-24AJK2RG.js} +5 -10
  12. package/dist/chunk-24AJK2RG.js.map +1 -0
  13. package/dist/chunk-2OZF2VUB.js +164 -0
  14. package/dist/chunk-2OZF2VUB.js.map +1 -0
  15. package/dist/chunk-2UJZXVHR.js +1868 -0
  16. package/dist/chunk-2UJZXVHR.js.map +1 -0
  17. package/dist/{chunk-DNZUBCGZ.js → chunk-3BRJCQPY.js} +36 -7
  18. package/dist/chunk-3BRJCQPY.js.map +1 -0
  19. package/dist/{chunk-D2UW3ZCK.js → chunk-42VFJOAF.js} +13 -11
  20. package/dist/{chunk-D2UW3ZCK.js.map → chunk-42VFJOAF.js.map} +1 -1
  21. package/dist/{chunk-LQZQ5KGG.js → chunk-4Q24OYI3.js} +7 -7
  22. package/dist/{chunk-XU73V5XT.js → chunk-4WJTURRO.js} +15 -15
  23. package/dist/{chunk-WN47MNSK.js → chunk-5SID2SVL.js} +4 -4
  24. package/dist/{chunk-5REEVKGH.js → chunk-AANUY4BH.js} +2 -2
  25. package/dist/chunk-ANPIIYRH.js +2272 -0
  26. package/dist/chunk-ANPIIYRH.js.map +1 -0
  27. package/dist/{chunk-RZVCWX5R.js → chunk-AYVKN3PG.js} +4 -4
  28. package/dist/{chunk-2UCC26MO.js → chunk-CH6IOGXV.js} +9 -9
  29. package/dist/{chunk-RODZ7MB7.js → chunk-D5Z6B4M7.js} +6 -6
  30. package/dist/{chunk-IJ62BB2T.js → chunk-D6SELXQ2.js} +7 -7
  31. package/dist/{chunk-2JV7C4YV.js → chunk-DDILEF5F.js} +890 -1399
  32. package/dist/chunk-DDILEF5F.js.map +1 -0
  33. package/dist/{chunk-3E2X2RBU.js → chunk-DGRLHDM4.js} +9 -9
  34. package/dist/{chunk-2BV4FBC7.js → chunk-DHGB4JBG.js} +4 -3
  35. package/dist/chunk-DHGB4JBG.js.map +1 -0
  36. package/dist/{chunk-6LR73NMO.js → chunk-DLU5FCFT.js} +30 -28
  37. package/dist/chunk-DLU5FCFT.js.map +1 -0
  38. package/dist/chunk-DSWKBZWW.js +16 -0
  39. package/dist/chunk-DSWKBZWW.js.map +1 -0
  40. package/dist/{chunk-BD7IXBWE.js → chunk-F564FHMQ.js} +8 -8
  41. package/dist/{chunk-ABHG6I3G.js → chunk-FKAZUZQU.js} +469 -85
  42. package/dist/chunk-FKAZUZQU.js.map +1 -0
  43. package/dist/{chunk-DFCQ6BMI.js → chunk-G3MBUL5M.js} +4 -4
  44. package/dist/{chunk-SUTMSDQ2.js → chunk-GQ3KRY3B.js} +3 -3
  45. package/dist/chunk-HDPN46JP.js +393 -0
  46. package/dist/chunk-HDPN46JP.js.map +1 -0
  47. package/dist/{chunk-EAUIQADY.js → chunk-IQQAJROD.js} +6 -6
  48. package/dist/{chunk-ZHRPH52H.js → chunk-IZXN3WI6.js} +2 -2
  49. package/dist/{chunk-NCPWXHDO.js → chunk-JEUFYSFQ.js} +4 -4
  50. package/dist/{chunk-G6FNWRAI.js → chunk-JSSM7VVV.js} +4 -4
  51. package/dist/{chunk-CCWMACJL.js → chunk-KFGZPVFA.js} +229 -821
  52. package/dist/chunk-KFGZPVFA.js.map +1 -0
  53. package/dist/{chunk-H26VDFDS.js → chunk-KGFSPJLD.js} +2 -2
  54. package/dist/{chunk-AO5TSDKT.js → chunk-KMORGMCW.js} +7 -7
  55. package/dist/{chunk-WQWKYAAK.js → chunk-NUQF5F5J.js} +2 -2
  56. package/dist/{chunk-2YJ5H5E6.js → chunk-NZ6KSHFD.js} +23 -21
  57. package/dist/{chunk-2YJ5H5E6.js.map → chunk-NZ6KSHFD.js.map} +1 -1
  58. package/dist/{chunk-7Y3N4Y72.js → chunk-OHUDZRLK.js} +3 -3
  59. package/dist/{chunk-GCKHSBEN.js → chunk-OKMTUAWO.js} +4 -4
  60. package/dist/{chunk-6M5VJOC2.js → chunk-OTJOBZJ5.js} +167 -166
  61. package/dist/chunk-OTJOBZJ5.js.map +1 -0
  62. package/dist/{chunk-2W34HX2U.js → chunk-PS257NIU.js} +288 -373
  63. package/dist/chunk-PS257NIU.js.map +1 -0
  64. package/dist/chunk-QDC7JPFG.js +685 -0
  65. package/dist/chunk-QDC7JPFG.js.map +1 -0
  66. package/dist/chunk-QEAGL4V5.js +3185 -0
  67. package/dist/chunk-QEAGL4V5.js.map +1 -0
  68. package/dist/{chunk-GB2XPITA.js → chunk-QMY57PVW.js} +2 -2
  69. package/dist/{chunk-55GMOVKW.js → chunk-QNDDPXFR.js} +2 -2
  70. package/dist/{chunk-GXN7RRHR.js → chunk-QSIXNTRV.js} +4 -4
  71. package/dist/{chunk-G7XD4QH5.js → chunk-RGLFV4KO.js} +11372 -10218
  72. package/dist/chunk-RGLFV4KO.js.map +1 -0
  73. package/dist/{chunk-QBVP3SQP.js → chunk-SGR7ZAVE.js} +13 -7
  74. package/dist/chunk-SGR7ZAVE.js.map +1 -0
  75. package/dist/{chunk-KBG463UK.js → chunk-SMHAYK6I.js} +2409 -5243
  76. package/dist/chunk-SMHAYK6I.js.map +1 -0
  77. package/dist/{chunk-XG6PVB5S.js → chunk-SSQZB5SQ.js} +1 -11
  78. package/dist/chunk-SSQZB5SQ.js.map +1 -0
  79. package/dist/{chunk-GDLHTI5R.js → chunk-STPGIKPY.js} +8 -2
  80. package/dist/chunk-STPGIKPY.js.map +1 -0
  81. package/dist/{chunk-QJRQ4BRC.js → chunk-U22TOL5Y.js} +17 -17
  82. package/dist/{chunk-NGTVREIH.js → chunk-U6IHLEWT.js} +2 -2
  83. package/dist/{chunk-Z5YHMRLF.js → chunk-UUCCV3SI.js} +2 -2
  84. package/dist/{chunk-ZXXFP2LA.js → chunk-UXMCHBOJ.js} +2 -2
  85. package/dist/{chunk-VZVEP2OZ.js → chunk-VFAKGIDG.js} +2 -2
  86. package/dist/{chunk-QCHVR4ZM.js → chunk-VM7VAFJW.js} +33 -7
  87. package/dist/chunk-VM7VAFJW.js.map +1 -0
  88. package/dist/{chunk-VQK4VHLF.js → chunk-YQV75FIL.js} +2 -2
  89. package/dist/chunk-YUTVAMWW.js +2 -0
  90. package/dist/chunk-ZPLVANY2.js +15 -0
  91. package/dist/chunk-ZPLVANY2.js.map +1 -0
  92. package/dist/{cli-BIIUKPTE.js → cli-4CR7QIOK.js} +26 -22
  93. package/dist/{cli-BIIUKPTE.js.map → cli-4CR7QIOK.js.map} +1 -1
  94. package/dist/{cli-V2DI3K2R.js → cli-6R4W3HAH.js} +37 -33
  95. package/dist/{cli-V2DI3K2R.js.map → cli-6R4W3HAH.js.map} +1 -1
  96. package/dist/{cli-HO62TOM2.js → cli-BOMA2FMP.js} +14 -11
  97. package/dist/{cli-EH3I4IUX.js → cli-EDQPQOCE.js} +47 -41
  98. package/dist/cli-EDQPQOCE.js.map +1 -0
  99. package/dist/{cli-P2X7PNY6.js → cli-GBF76EXT.js} +25 -20
  100. package/dist/{cli-P2X7PNY6.js.map → cli-GBF76EXT.js.map} +1 -1
  101. package/dist/{cli-4YYC6LCY.js → cli-MQYCF3SR.js} +27 -23
  102. package/dist/{cli-4YYC6LCY.js.map → cli-MQYCF3SR.js.map} +1 -1
  103. package/dist/{cli-UETKXHJN.js → cli-OJKFXQOM.js} +9 -9
  104. package/dist/{cli-LWST5FQH.js → cli-PHZAO4LZ.js} +4 -4
  105. package/dist/{cli-TELPAMJO.js → cli-PTKFFNOW.js} +59 -35
  106. package/dist/cli-PTKFFNOW.js.map +1 -0
  107. package/dist/{cli-SGVFZOAW.js → cli-UW2K5Z5J.js} +34 -29
  108. package/dist/{cli-SGVFZOAW.js.map → cli-UW2K5Z5J.js.map} +1 -1
  109. package/dist/cli-XXTNPPKB.js +83 -0
  110. package/dist/cli-XXTNPPKB.js.map +1 -0
  111. package/dist/cli.js +24 -12
  112. package/dist/cli.js.map +1 -1
  113. package/dist/{config-TYXYQK3I.js → config-JJW75SBX.js} +5 -5
  114. package/dist/docmeta.js +13 -10
  115. package/dist/docmeta.js.map +1 -1
  116. package/dist/github-6VQKSB67.js +35 -0
  117. package/dist/github-RBSEM7ZK.js +30 -0
  118. package/dist/graph/runtime.d.ts +4 -1
  119. package/dist/graph/runtime.js +20 -9
  120. package/dist/graph/runtime.js.map +1 -1
  121. package/dist/{host-6GURH5HE.js → host-YSTYO5DX.js} +3 -3
  122. package/dist/index.d.ts +1214 -940
  123. package/dist/index.js +190 -160
  124. package/dist/index.js.map +1 -1
  125. package/dist/{json-QR4G35KA.js → json-PU2HLHDQ.js} +18 -14
  126. package/dist/labels-SJNSOPBI.js +73 -0
  127. package/dist/labels-SJNSOPBI.js.map +1 -0
  128. package/dist/lint-KIVTHLGU.js +34 -0
  129. package/dist/list-RDEJDDJF.js +32 -0
  130. package/dist/list-SUTDWL2J.js +35 -0
  131. package/dist/{page-FSXDXCDD.js → page-UMAA3NCM.js} +18 -13
  132. package/dist/{prepare-UPIBTFNS.js → prepare-3I3LOXXD.js} +24 -20
  133. package/dist/{prepare-UPIBTFNS.js.map → prepare-3I3LOXXD.js.map} +1 -1
  134. package/dist/{pretty-4IONWSEP.js → pretty-ANLRHU4O.js} +18 -14
  135. package/dist/{pretty-R4BQD2VH.js → pretty-Q3ZFKOR7.js} +18 -14
  136. package/dist/{provider-527CO4DM.js → provider-LBX4IXGX.js} +3 -3
  137. package/dist/{release-3D5PK6M7.js → release-VV3UTKE5.js} +3 -3
  138. package/dist/{reporters-M6LJ2IYU.js → reporters-26H3N2KW.js} +3 -3
  139. package/dist/{reporters-DHO2BXAD.js → reporters-ILT36CIH.js} +7 -7
  140. package/dist/{reporters-FPP6JNDP.js → reporters-PNDLWT6K.js} +16 -12
  141. package/dist/run-QXCK33Z4.js +37 -0
  142. package/dist/{term-ASM4LVYC.js → term-D2N7UN4P.js} +981 -138
  143. package/dist/term-D2N7UN4P.js.map +1 -0
  144. package/dist/validate-BRUCOT2O.js +19 -0
  145. package/dist/validate-BRUCOT2O.js.map +1 -0
  146. package/package.json +3 -2
  147. package/plugin/manni/.claude-plugin/plugin.json +1 -1
  148. package/shapes/graph/shapes-1.1.0.ttl +785 -0
  149. package/dist/batch-6NICDKRE.js +0 -41
  150. package/dist/build-3KP2K3XN.js +0 -32
  151. package/dist/calibrate-LUA3DWKD.js +0 -36
  152. package/dist/capture-NETOHCB4.js +0 -34
  153. package/dist/check-E4QCB7LS.js +0 -20
  154. package/dist/check-PTECPIIB.js +0 -26
  155. package/dist/chunk-2BV4FBC7.js.map +0 -1
  156. package/dist/chunk-2JV7C4YV.js.map +0 -1
  157. package/dist/chunk-2W34HX2U.js.map +0 -1
  158. package/dist/chunk-4DLF5SA4.js +0 -392
  159. package/dist/chunk-4DLF5SA4.js.map +0 -1
  160. package/dist/chunk-6AGESHHM.js +0 -387
  161. package/dist/chunk-6AGESHHM.js.map +0 -1
  162. package/dist/chunk-6LR73NMO.js.map +0 -1
  163. package/dist/chunk-6M5VJOC2.js.map +0 -1
  164. package/dist/chunk-ABHG6I3G.js.map +0 -1
  165. package/dist/chunk-CCWMACJL.js.map +0 -1
  166. package/dist/chunk-DNZUBCGZ.js.map +0 -1
  167. package/dist/chunk-G7XD4QH5.js.map +0 -1
  168. package/dist/chunk-GDLHTI5R.js.map +0 -1
  169. package/dist/chunk-KBG463UK.js.map +0 -1
  170. package/dist/chunk-PK7EKJ5T.js.map +0 -1
  171. package/dist/chunk-QBVP3SQP.js.map +0 -1
  172. package/dist/chunk-QCHVR4ZM.js.map +0 -1
  173. package/dist/chunk-VVVKBUBO.js +0 -818
  174. package/dist/chunk-VVVKBUBO.js.map +0 -1
  175. package/dist/chunk-XG6PVB5S.js.map +0 -1
  176. package/dist/cli-EH3I4IUX.js.map +0 -1
  177. package/dist/cli-TELPAMJO.js.map +0 -1
  178. package/dist/github-ESK45CEZ.js +0 -26
  179. package/dist/github-WER7JUTN.js +0 -31
  180. package/dist/lint-QTI7XK2A.js +0 -30
  181. package/dist/list-JO4G3TS3.js +0 -30
  182. package/dist/list-O2MJUP5V.js +0 -28
  183. package/dist/run-YH5Z7RJ7.js +0 -32
  184. package/dist/term-ASM4LVYC.js.map +0 -1
  185. package/dist/validate-7JI3H57P.js +0 -17
  186. /package/dist/{batch-6NICDKRE.js.map → batch-EFSFG6GC.js.map} +0 -0
  187. /package/dist/{build-3KP2K3XN.js.map → build-NIO3UIWJ.js.map} +0 -0
  188. /package/dist/{calibrate-LUA3DWKD.js.map → calibrate-6VO7URRV.js.map} +0 -0
  189. /package/dist/{capture-NETOHCB4.js.map → capture-NMBVJO3C.js.map} +0 -0
  190. /package/dist/{check-7B77ZD2N.js.map → check-SHOYX2B5.js.map} +0 -0
  191. /package/dist/{check-E4QCB7LS.js.map → check-XMJKH3KV.js.map} +0 -0
  192. /package/dist/{check-PTECPIIB.js.map → check-ZMO3ZLMW.js.map} +0 -0
  193. /package/dist/{chunk-LQZQ5KGG.js.map → chunk-4Q24OYI3.js.map} +0 -0
  194. /package/dist/{chunk-XU73V5XT.js.map → chunk-4WJTURRO.js.map} +0 -0
  195. /package/dist/{chunk-WN47MNSK.js.map → chunk-5SID2SVL.js.map} +0 -0
  196. /package/dist/{chunk-5REEVKGH.js.map → chunk-AANUY4BH.js.map} +0 -0
  197. /package/dist/{chunk-RZVCWX5R.js.map → chunk-AYVKN3PG.js.map} +0 -0
  198. /package/dist/{chunk-2UCC26MO.js.map → chunk-CH6IOGXV.js.map} +0 -0
  199. /package/dist/{chunk-RODZ7MB7.js.map → chunk-D5Z6B4M7.js.map} +0 -0
  200. /package/dist/{chunk-IJ62BB2T.js.map → chunk-D6SELXQ2.js.map} +0 -0
  201. /package/dist/{chunk-3E2X2RBU.js.map → chunk-DGRLHDM4.js.map} +0 -0
  202. /package/dist/{chunk-BD7IXBWE.js.map → chunk-F564FHMQ.js.map} +0 -0
  203. /package/dist/{chunk-DFCQ6BMI.js.map → chunk-G3MBUL5M.js.map} +0 -0
  204. /package/dist/{chunk-SUTMSDQ2.js.map → chunk-GQ3KRY3B.js.map} +0 -0
  205. /package/dist/{chunk-EAUIQADY.js.map → chunk-IQQAJROD.js.map} +0 -0
  206. /package/dist/{chunk-ZHRPH52H.js.map → chunk-IZXN3WI6.js.map} +0 -0
  207. /package/dist/{chunk-NCPWXHDO.js.map → chunk-JEUFYSFQ.js.map} +0 -0
  208. /package/dist/{chunk-G6FNWRAI.js.map → chunk-JSSM7VVV.js.map} +0 -0
  209. /package/dist/{chunk-H26VDFDS.js.map → chunk-KGFSPJLD.js.map} +0 -0
  210. /package/dist/{chunk-AO5TSDKT.js.map → chunk-KMORGMCW.js.map} +0 -0
  211. /package/dist/{chunk-WQWKYAAK.js.map → chunk-NUQF5F5J.js.map} +0 -0
  212. /package/dist/{chunk-7Y3N4Y72.js.map → chunk-OHUDZRLK.js.map} +0 -0
  213. /package/dist/{chunk-GCKHSBEN.js.map → chunk-OKMTUAWO.js.map} +0 -0
  214. /package/dist/{chunk-GB2XPITA.js.map → chunk-QMY57PVW.js.map} +0 -0
  215. /package/dist/{chunk-55GMOVKW.js.map → chunk-QNDDPXFR.js.map} +0 -0
  216. /package/dist/{chunk-GXN7RRHR.js.map → chunk-QSIXNTRV.js.map} +0 -0
  217. /package/dist/{chunk-QJRQ4BRC.js.map → chunk-U22TOL5Y.js.map} +0 -0
  218. /package/dist/{chunk-NGTVREIH.js.map → chunk-U6IHLEWT.js.map} +0 -0
  219. /package/dist/{chunk-Z5YHMRLF.js.map → chunk-UUCCV3SI.js.map} +0 -0
  220. /package/dist/{chunk-ZXXFP2LA.js.map → chunk-UXMCHBOJ.js.map} +0 -0
  221. /package/dist/{chunk-VZVEP2OZ.js.map → chunk-VFAKGIDG.js.map} +0 -0
  222. /package/dist/{chunk-VQK4VHLF.js.map → chunk-YQV75FIL.js.map} +0 -0
  223. /package/dist/{cli-HO62TOM2.js.map → chunk-YUTVAMWW.js.map} +0 -0
  224. /package/dist/{config-TYXYQK3I.js.map → cli-BOMA2FMP.js.map} +0 -0
  225. /package/dist/{cli-UETKXHJN.js.map → cli-OJKFXQOM.js.map} +0 -0
  226. /package/dist/{cli-LWST5FQH.js.map → cli-PHZAO4LZ.js.map} +0 -0
  227. /package/dist/{github-ESK45CEZ.js.map → config-JJW75SBX.js.map} +0 -0
  228. /package/dist/{github-WER7JUTN.js.map → github-6VQKSB67.js.map} +0 -0
  229. /package/dist/{host-6GURH5HE.js.map → github-RBSEM7ZK.js.map} +0 -0
  230. /package/dist/{json-QR4G35KA.js.map → host-YSTYO5DX.js.map} +0 -0
  231. /package/dist/{lint-QTI7XK2A.js.map → json-PU2HLHDQ.js.map} +0 -0
  232. /package/dist/{list-JO4G3TS3.js.map → lint-KIVTHLGU.js.map} +0 -0
  233. /package/dist/{list-O2MJUP5V.js.map → list-RDEJDDJF.js.map} +0 -0
  234. /package/dist/{page-FSXDXCDD.js.map → list-SUTDWL2J.js.map} +0 -0
  235. /package/dist/{pretty-4IONWSEP.js.map → page-UMAA3NCM.js.map} +0 -0
  236. /package/dist/{pretty-R4BQD2VH.js.map → pretty-ANLRHU4O.js.map} +0 -0
  237. /package/dist/{provider-527CO4DM.js.map → pretty-Q3ZFKOR7.js.map} +0 -0
  238. /package/dist/{reporters-DHO2BXAD.js.map → provider-LBX4IXGX.js.map} +0 -0
  239. /package/dist/{release-3D5PK6M7.js.map → release-VV3UTKE5.js.map} +0 -0
  240. /package/dist/{reporters-FPP6JNDP.js.map → reporters-26H3N2KW.js.map} +0 -0
  241. /package/dist/{reporters-M6LJ2IYU.js.map → reporters-ILT36CIH.js.map} +0 -0
  242. /package/dist/{run-YH5Z7RJ7.js.map → reporters-PNDLWT6K.js.map} +0 -0
  243. /package/dist/{validate-7JI3H57P.js.map → run-QXCK33Z4.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/graph/core/load.ts","../src/graph/core/pkg.ts","../src/graph/core/shacl.ts","../src/graph/commands/search.ts","../src/graph/core/vector-index.ts","../src/graph/runtime/vector.ts","../src/graph/runtime/trace.ts","../src/graph/runtime/entry.ts","../src/graph/runtime/lexical.ts","../src/graph/embed/local.ts","../src/graph/embed/mock.ts","../src/graph/commands/questions.ts","../src/graph/core/search-index.ts","../src/graph/runtime/resolve.ts","../src/graph/runtime/graph.ts"],"sourcesContent":["/** Load a built .ttl into an in-memory N3 store for query/stats. */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { Parser, Store } from \"n3\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { GraphError } from \"../types.js\";\nimport type { Quad, Term } from \"./derive.js\";\nimport { NS, PREFIXES } from \"./vocab.js\";\n\nconst XSD_STRING = `${NS.xsd}string`;\n\nexport function loadGraph(ttlPath: string): Store {\n if (!existsSync(ttlPath)) {\n throw new GraphError(\n `Graph not found: ${ttlPath} — run \\`manni graph build\\` first.`,\n );\n }\n return parseGraph(readFileSync(ttlPath, \"utf8\"), ttlPath);\n}\n\n/** Turtle already in memory into a store; `label` names it in an error. */\nexport function parseGraph(turtle: string, label: string): Store {\n const parser = new Parser({ format: \"text/turtle\" });\n let quads;\n try {\n quads = parser.parse(turtle);\n } catch (e) {\n throw new GraphError(\n `Failed to parse ${label}: ${errorMessage(e)}`,\n );\n }\n return new Store(quads);\n}\n\n/**\n * Convert an in-memory N3 store back to dockg's internal quad shape — the\n * bridge from the Turtle-reading Node side to the platform-neutral emitters and\n * runtime. A redundant `xsd:string` datatype is dropped so the result matches\n * what the JSON-LD path produces.\n */\nexport function storeToQuads(store: Store): Quad[] {\n return store.getQuads(null, null, null, null).map((q) => {\n const o = q.object;\n let term: Term;\n if (o.termType === \"Literal\" && o.language !== \"\") {\n term = { kind: \"literal\", value: o.value, language: o.language };\n } else if (o.termType === \"Literal\") {\n const dt = o.datatype.value;\n term =\n dt && dt !== XSD_STRING\n ? { kind: \"literal\", value: o.value, datatype: dt }\n : { kind: \"literal\", value: o.value };\n } else {\n term = { kind: \"iri\", value: o.value };\n }\n return { s: q.subject.value, p: q.predicate.value, o: term };\n });\n}\n\n/** Expand `dcterms:references`-style prefixed names to full IRIs; pass through the rest. */\nexport function expandTerm(input: string): string {\n const colon = input.indexOf(\":\");\n if (colon > 0) {\n const prefix = input.slice(0, colon);\n const ns = (NS as Record<string, string>)[prefix];\n if (ns) return `${ns}${input.slice(colon + 1)}`;\n }\n return input;\n}\n\n/** Compact a full IRI back to a prefixed name when a known namespace matches. */\nexport function compactIri(iri: string): string {\n for (const [prefix, ns] of PREFIXES) {\n if (iri.startsWith(ns) && iri.length > ns.length) {\n return `${prefix}:${iri.slice(ns.length)}`;\n }\n }\n return iri;\n}\n","/**\n * The one asset that ships with the package and is read by path at runtime: the\n * SHACL shapes. They live under `shapes/graph/` at the package root, listed in\n * `files`, and are reached through the shared package-root walk, which holds\n * both in the source tree (`src/graph/core/`) and in the bundle (`dist/`).\n *\n * The frontmatter schema is no longer one of them. The `graph` page vocabulary\n * is proposal 0023's draft, imported by `src/graph/schema.ts` and inlined by the\n * build, so nothing under `schemas/` is read at run time and nothing under it\n * is published (proposal 0051 §4).\n */\nimport { join } from \"node:path\";\nimport { packageRoot } from \"../../shared/package-root.js\";\n\n/** Absolute path of the bundled SHACL shapes `manni graph check` defaults to. */\nexport function bundledShapesPath(moduleUrl: string): string {\n return join(packageRoot(moduleUrl), \"shapes\", \"graph\", \"shapes-1.1.0.ttl\");\n}\n","/**\n * Graph-level validation: run the published SHACL shapes over a built graph,\n * plus the SKOS integrity checks core SHACL cannot express (broader cycles,\n * related⨯broaderTransitive disjointness, two untagged prefLabels on one\n * concept, a mapping into the scheme itself). Every finding carries the\n * doc paths responsible, so writers get file names instead of bare IRIs.\n */\nimport { readFileSync } from \"node:fs\";\nimport { DataFactory, Parser, Store } from \"n3\";\nimport SHACLValidator from \"rdf-validate-shacl\";\nimport type { Term } from \"@rdfjs/types\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport type { Severity } from \"../../shared/severity.js\";\nimport { GraphError } from \"../types.js\";\nimport { compactIri } from \"./load.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS } from \"./vocab.js\";\n\n/** SHACL's own scale, as `sh:severity` spells it. */\nexport type ShaclSeverity = \"violation\" | \"warning\" | \"info\";\n\nexport interface CheckFinding {\n /**\n * The family's scale (`src/shared/severity.ts`). SHACL's three levels map\n * onto it one for one — violation to error, warning to warning, info to\n * notice — and the source value stays in {@link shaclSeverity}, the way\n * a11y keeps axe's `impact` (proposal 0035, stress test 10).\n */\n severity: Severity;\n /**\n * SHACL's own word for the same finding, kept for lookup. Absent on a\n * finding no shape reported, such as a sample question that missed.\n */\n shaclSeverity?: ShaclSeverity;\n /** Human-readable description (IRIs compacted to prefixed names). */\n message: string;\n /** IRI of the node the finding is about. */\n focusNode: string;\n /** Predicate IRI involved, when the finding concerns one. */\n path?: string;\n /** graph:path of the docs responsible, sorted (empty when untraceable). */\n docs: string[];\n}\n\n/**\n * SHACL's scale onto the family's. The one place the translation happens, so\n * no caller re-derives it: a finding is built through {@link finding} and\n * carries both words from there on.\n */\nconst FAMILY_SEVERITY: Record<ShaclSeverity, Severity> = {\n violation: \"error\",\n warning: \"warning\",\n info: \"notice\",\n};\n\n/** A finding at `shaclSeverity`, carrying the family severity it maps to. */\nfunction finding(\n shaclSeverity: ShaclSeverity,\n rest: Omit<CheckFinding, \"severity\" | \"shaclSeverity\">,\n): CheckFinding {\n return { severity: FAMILY_SEVERITY[shaclSeverity], shaclSeverity, ...rest };\n}\n\n/** Most severe first: error, warning, notice. */\nconst SEVERITY_RANK: Record<Severity, number> = {\n error: 0,\n warning: 1,\n notice: 2,\n};\n\n/**\n * The one order every check finding is reported in: severity, then focus\n * node, path and message. Exported so findings from outside the shapes sort\n * among them the same way.\n */\nexport function compareFindings(a: CheckFinding, b: CheckFinding): number {\n return (\n SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity] ||\n byCodeUnit(a.focusNode, b.focusNode) ||\n byCodeUnit(a.path ?? \"\", b.path ?? \"\") ||\n byCodeUnit(a.message, b.message)\n );\n}\n\n/** Parse one or more shapes .ttl files into a single store. */\nexport function loadShapes(paths: string[]): Store {\n const store = new Store();\n for (const path of paths) {\n let text: string;\n try {\n text = readFileSync(path, \"utf8\");\n } catch {\n throw new GraphError(`Shapes file not found: ${path}`);\n }\n try {\n store.addQuads(new Parser({ format: \"text/turtle\" }).parse(text));\n } catch (e) {\n throw new GraphError(\n `Failed to parse shapes ${path}: ${errorMessage(e)}`,\n );\n }\n }\n return store;\n}\n\n/**\n * Trace a focus node back to the doc(s) responsible: its own graph:path,\n * the path of its fragment-stripped base (sections, provenance fragments),\n * or — for shared nodes like concepts and agents — the paths of docs that\n * point at it, up to two hops back. Sorted and deduplicated.\n */\nexport function blameDocs(store: Store, focus: string): string[] {\n const pathPred = DataFactory.namedNode(`${NS.graph}path`);\n const pathOf = (iri: string): string | undefined =>\n store.getQuads(DataFactory.namedNode(iri), pathPred, null, null)[0]?.object.value;\n\n const found = new Set<string>();\n const visited = new Set<string>();\n\n const walk = (iri: string, depth: number): void => {\n if (visited.has(iri)) return;\n visited.add(iri);\n\n const own = pathOf(iri);\n if (own !== undefined) {\n found.add(own);\n return;\n }\n const hash = iri.indexOf(\"#\");\n if (hash !== -1) {\n const base = pathOf(iri.slice(0, hash));\n if (base !== undefined) {\n found.add(base);\n return;\n }\n }\n if (depth === 0) return;\n for (const quad of store.getQuads(null, null, DataFactory.namedNode(iri), null)) {\n if (quad.subject.termType === \"NamedNode\") {\n walk(quad.subject.value, depth - 1);\n }\n }\n };\n\n walk(focus, 2);\n return [...found].sort();\n}\n\ninterface Edge {\n s: string;\n o: string;\n}\n\n/** skos:broader edges, folding narrower in as its inverse. */\nfunction broaderEdges(store: Store): Edge[] {\n const edges: Edge[] = [];\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.skos}broader`),\n null,\n null,\n )) {\n if (q.object.termType === \"NamedNode\") {\n edges.push({ s: q.subject.value, o: q.object.value });\n }\n }\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.skos}narrower`),\n null,\n null,\n )) {\n if (q.object.termType === \"NamedNode\") {\n edges.push({ s: q.object.value, o: q.subject.value });\n }\n }\n return edges;\n}\n\n/**\n * Strongly connected components of the broader graph (iterative Tarjan —\n * no recursion, taxonomy depth can't blow the stack). Returns only real\n * cycles: components of 2+ nodes, or single nodes with a self-loop.\n */\nexport function broaderCycles(store: Store): string[][] {\n const adjacency = new Map<string, string[]>();\n const selfLoops = new Set<string>();\n for (const { s, o } of broaderEdges(store)) {\n if (s === o) selfLoops.add(s);\n const list = adjacency.get(s);\n if (list) list.push(o);\n else adjacency.set(s, [o]);\n if (!adjacency.has(o)) adjacency.set(o, []);\n }\n for (const list of adjacency.values()) list.sort();\n\n const index = new Map<string, number>();\n const lowlink = new Map<string, number>();\n const onStack = new Set<string>();\n const stack: string[] = [];\n const components: string[][] = [];\n let counter = 0;\n\n /**\n * A node's Tarjan number. Every node is stamped into both maps on the frame\n * where `childIdx === 0`, before any edge out of it is followed, so a miss\n * here is not a missing value but a broken traversal — which is worth\n * saying rather than reading as `NaN` three lines later.\n */\n const numberOf = (map: Map<string, number>, node: string): number => {\n const value = map.get(node);\n if (value === undefined) {\n throw new GraphError(\n `internal: ${node} was visited before it was numbered`,\n );\n }\n return value;\n };\n\n const nodes = [...adjacency.keys()].sort();\n for (const root of nodes) {\n if (index.has(root)) continue;\n // Explicit work stack of [node, next-child-index] frames. The loop reads\n // the top frame as its condition, so the frame is proven present by the\n // same test that keeps the loop running.\n const frames: Array<[string, number]> = [[root, 0]];\n for (let frame = frames.at(-1); frame !== undefined; frame = frames.at(-1)) {\n const [node, childIdx] = frame;\n if (childIdx === 0) {\n index.set(node, counter);\n lowlink.set(node, counter);\n counter += 1;\n stack.push(node);\n onStack.add(node);\n }\n const children = adjacency.get(node) ?? [];\n // Reading the child *is* the bounds check: `adjacency` holds dense\n // arrays of strings, so a hit is a child and a miss is the end of them.\n const child = children[childIdx];\n if (child !== undefined) {\n frame[1] += 1;\n if (!index.has(child)) {\n frames.push([child, 0]);\n } else if (onStack.has(child)) {\n lowlink.set(\n node,\n Math.min(numberOf(lowlink, node), numberOf(index, child)),\n );\n }\n } else {\n if (lowlink.get(node) === index.get(node)) {\n const component: string[] = [];\n let member: string | undefined;\n do {\n member = stack.pop();\n if (member === undefined) break;\n onStack.delete(member);\n component.push(member);\n } while (member !== node);\n if (component.length > 1 || selfLoops.has(node)) {\n components.push(component.sort());\n }\n }\n frames.pop();\n const parent = frames.at(-1);\n if (parent) {\n lowlink.set(\n parent[0],\n Math.min(numberOf(lowlink, parent[0]), numberOf(lowlink, node)),\n );\n }\n }\n }\n }\n // A component always has a member — it is built by popping at least one —\n // so `?? \"\"` is a spelling of that, not a fallback anyone can reach.\n return components.sort((a, b) => ((a[0] ?? \"\") < (b[0] ?? \"\") ? -1 : 1));\n}\n\n/** Forward reachability over broader edges from each given start node. */\nfunction broaderClosure(edges: Edge[], start: string): Set<string> {\n const adjacency = new Map<string, string[]>();\n for (const { s, o } of edges) {\n const list = adjacency.get(s);\n if (list) list.push(o);\n else adjacency.set(s, [o]);\n }\n const seen = new Set<string>();\n const queue = [...(adjacency.get(start) ?? [])];\n // Shifting *is* the emptiness test, so the queue is never read past its end.\n for (let node = queue.shift(); node !== undefined; node = queue.shift()) {\n if (seen.has(node)) continue;\n seen.add(node);\n queue.push(...(adjacency.get(node) ?? []));\n }\n return seen;\n}\n\n/**\n * SKOS S27: skos:related is disjoint with skos:broaderTransitive. The\n * one-hop case is already a SHACL sh:disjoint violation — skip it here so\n * one mistake doesn't produce two findings.\n */\nfunction relatedConflicts(store: Store): CheckFinding[] {\n const edges = broaderEdges(store);\n // Direct edges indexed by subject — no composite string keys (a joined\n // key would need a separator character, and IRIs make any choice fragile).\n const direct = new Map<string, Set<string>>();\n for (const e of edges) {\n const targets = direct.get(e.s);\n if (targets) targets.add(e.o);\n else direct.set(e.s, new Set([e.o]));\n }\n const findings: CheckFinding[] = [];\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.skos}related`),\n null,\n null,\n )) {\n if (q.object.termType !== \"NamedNode\") continue;\n const s = q.subject.value;\n const o = q.object.value;\n if (direct.get(s)?.has(o)) continue; // covered by sh:disjoint\n const conflict =\n broaderClosure(edges, s).has(o) || broaderClosure(edges, o).has(s);\n if (!conflict) continue;\n findings.push(\n finding(\"violation\", {\n message: `skos:related conflicts with skos:broaderTransitive between ${compactIri(s)} and ${compactIri(o)} — a concept cannot be both related to and an ancestor/descendant of another`,\n focusNode: s,\n path: `${NS.skos}related`,\n docs: blameDocs(store, s),\n }),\n );\n }\n return findings;\n}\n\nfunction cycleFindings(store: Store): CheckFinding[] {\n return broaderCycles(store).map((members) =>\n finding(\"violation\", {\n message: `skos:broader cycle through ${members\n .map((m) => compactIri(m))\n .join(\n \", \",\n )} (${members.map((m) => m).join(\" → \")}) — a concept cannot be its own ancestor`,\n // `broaderCycles` returns only components of at least one member, so\n // the first is there; `?? \"\"` says that without asserting it.\n focusNode: members[0] ?? \"\",\n path: `${NS.skos}broader`,\n docs: [...new Set(members.flatMap((m) => blameDocs(store, m)))].sort(),\n }),\n );\n}\n\n/**\n * The prefLabel collision SHACL Core cannot express. Concept IRIs converge on\n * slugified labels, so \"Configuration\" and \"configuration\" land on one concept\n * with two untagged spellings. `sh:uniqueLang` (shapes 1.1.0) catches two\n * labels in one language and ignores untagged ones, so this catches those.\n */\nexport const PREF_LABEL_COLLISION =\n \"concept carries multiple prefLabels (same slug, different spellings) — settle on one spelling\";\n\nfunction untaggedPrefLabelFindings(store: Store): CheckFinding[] {\n const prefLabel = `${NS.skos}prefLabel`;\n const untagged = new Map<string, number>();\n for (const q of store.getQuads(null, DataFactory.namedNode(prefLabel), null, null)) {\n if (q.object.termType !== \"Literal\" || q.object.language !== \"\") continue;\n untagged.set(q.subject.value, (untagged.get(q.subject.value) ?? 0) + 1);\n }\n return [...untagged]\n .filter(([, count]) => count > 1)\n .map(([focusNode]) =>\n finding(\"warning\", {\n message: PREF_LABEL_COLLISION,\n focusNode,\n path: prefLabel,\n docs: blameDocs(store, focusNode),\n }),\n );\n}\n\n/** The SKOS mapping properties: each links a concept to one in another scheme. */\nconst MAPPINGS = [\"exactMatch\", \"closeMatch\", \"broadMatch\", \"narrowMatch\", \"relatedMatch\"] as const;\n\n/**\n * A mapping whose object is a concept in this graph's scheme. SKOS keeps the\n * mapping properties for links between schemes, so inside one the relation is\n * broader, narrower or related.\n */\nfunction inSchemeMappingFindings(store: Store): CheckFinding[] {\n const inScheme = DataFactory.namedNode(`${NS.skos}inScheme`);\n const findings: CheckFinding[] = [];\n for (const mapping of MAPPINGS) {\n const path = `${NS.skos}${mapping}`;\n for (const q of store.getQuads(null, DataFactory.namedNode(path), null, null)) {\n if (q.object.termType !== \"NamedNode\") continue;\n // Into *this* scheme: the target shares a scheme with the concept that\n // maps to it. A concept of an outside scheme carried in the graph keeps\n // its own `skos:inScheme`, and mapping to it is the point of a match.\n const schemes = new Set(store.getObjects(q.subject, inScheme, null).map((o) => o.value));\n const shared = store.getObjects(q.object, inScheme, null).some((o) => schemes.has(o.value));\n if (!shared) continue;\n findings.push(\n finding(\"violation\", {\n message: `skos:${mapping} points into this scheme (${compactIri(q.object.value)}), so use broader, narrower or related instead.`,\n focusNode: q.subject.value,\n path,\n docs: blameDocs(store, q.subject.value),\n }),\n );\n }\n }\n return findings;\n}\n\n/**\n * The three `graph` fields a machine may never be attributed for. The old\n * `kg.provenance` schema enumerated the twelve *fillable* fields, which kept\n * these out; a free JSON Pointer cannot express that, so proposal 0046 stress\n * test 13 moved the guard into graph's harvest and, from there, to here.\n */\nconst CURATED_FIELDS = new Set([\"sections\", \"revision-of\", \"derived-from\"]);\n\n/** The fragment a `graph fill` activity's IRI carries, before its model slug. */\nconst GRAPH_FILL_FRAGMENT = \"#prov.graph-fill.\";\n\n/**\n * A machine attribution on a hand-curated field. `check` reads only the built\n * graph and `build` has no findings channel, so the store is where the fact is\n * read: the harvest has already put `graph:filledField \"sections\"` on a field\n * node under a `#prov.graph-fill.` activity.\n */\nfunction curatedFieldFindings(store: Store): CheckFinding[] {\n const filledField = `${NS.graph}filledField`;\n const pathPred = DataFactory.namedNode(`${NS.graph}path`);\n const findings: CheckFinding[] = [];\n for (const q of store.getQuads(null, DataFactory.namedNode(filledField), null, null)) {\n if (q.object.termType !== \"Literal\") continue;\n const field = q.object.value;\n if (!CURATED_FIELDS.has(field)) continue;\n const node = q.subject.value;\n const at = node.indexOf(GRAPH_FILL_FRAGMENT);\n const fieldAt = node.lastIndexOf(\".field.\");\n if (at === -1 || fieldAt <= at) continue;\n const activity = node.slice(0, fieldAt);\n // The model the activity is for, from its own fragment. Naming it beats\n // repeating the activity IRI, which the reporter already prints as the\n // focus node ahead of this message.\n const model = node.slice(at + GRAPH_FILL_FRAGMENT.length, fieldAt);\n // These activities hang off no document edge, so `blameDocs` cannot walk\n // back to one. The doc IRI is the activity's own, minus its fragment.\n const docIri = activity.slice(0, activity.indexOf(\"#\"));\n const path = store.getQuads(DataFactory.namedNode(docIri), pathPred, null, null)[0]\n ?.object.value;\n findings.push(\n finding(\"violation\", {\n message: `meta-provenance attributes /graph/${field} to ${model} — ${field} is curated by hand, never filled by a machine`,\n focusNode: activity,\n path: filledField,\n docs: path === undefined ? blameDocs(store, activity) : [path],\n }),\n );\n }\n return findings;\n}\n\n/**\n * One validation result, with the nullability its library documents in code\n * rather than in its `.d.ts`.\n *\n * `rdf-validate-shacl` declares `path`, `focusNode` and `severity` as `Term`,\n * and every one of them is `…out(ns.sh.resultPath).term || null` at runtime. A\n * result with no path is ordinary — a node-shape constraint has none — so the\n * guards at the read site are the real contract and the declaration is the\n * optimistic one. Saying so once here is what keeps them from reading as\n * checks that cannot fail.\n */\ninterface ShaclResult {\n message: Term[];\n path: Term | null;\n focusNode: Term | null;\n severity: Term | null;\n}\n\nfunction severityOf(iri: string | undefined): ShaclSeverity {\n if (iri === \"http://www.w3.org/ns/shacl#Warning\") return \"warning\";\n if (iri === \"http://www.w3.org/ns/shacl#Info\") return \"info\";\n return \"violation\";\n}\n\n/**\n * Validate a built graph against SHACL shapes files, merge in the TS-side\n * SKOS checks, and return deterministic, doc-blamed findings.\n */\nexport async function validateGraph(\n store: Store,\n shapesPaths: string[],\n): Promise<CheckFinding[]> {\n const shapes = loadShapes(shapesPaths);\n const validator = new SHACLValidator(shapes);\n let report;\n try {\n report = await validator.validate(store);\n } catch (e) {\n throw new GraphError(\n `SHACL validation failed: ${errorMessage(e)}`,\n );\n }\n\n const findings: CheckFinding[] = [];\n for (const result of report.results as ShaclResult[]) {\n const focus = result.focusNode?.value ?? \"\";\n const path = result.path?.value;\n const messages = result.message\n .map((m) => m.value)\n .filter((m) => m.length > 0);\n const message =\n messages.length > 0\n ? messages.join(\"; \")\n : `constraint violated${path ? ` on ${compactIri(path)}` : \"\"}`;\n findings.push(\n finding(severityOf(result.severity?.value), {\n message,\n focusNode: focus,\n ...(path !== undefined ? { path } : {}),\n docs: blameDocs(store, focus),\n }),\n );\n }\n\n // Shapes 1.0.0 still says the untagged collision itself, with this message.\n // The check core's copy adds nothing beside it.\n const said = new Set(\n findings\n .filter((f) => f.message === PREF_LABEL_COLLISION)\n .map((f) => f.focusNode),\n );\n findings.push(\n ...cycleFindings(store),\n ...relatedConflicts(store),\n ...curatedFieldFindings(store),\n ...inSchemeMappingFindings(store),\n ...untaggedPrefLabelFindings(store).filter((f) => !said.has(f.focusNode)),\n );\n\n findings.sort(compareFindings);\n return findings;\n}\n","/**\n * `manni graph search` — text query → ranked seed nodes (ADR 01019).\n *\n * A thin Node wrapper over the browser-native lexical entry stage: it loads the\n * `search.json` artifact and runs the same `findEntry` a browser would. This is\n * the stage before `traverse`; Phase 9's `retrieve` chains the two.\n *\n * The trace is always in the JSON output — retrieval provenance is part of the\n * contract, not an opt-in (ADR 01018).\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { compactIri } from \"../core/load.js\";\nimport { type SearchIndexDoc } from \"../core/search-index.js\";\nimport {\n canonicalLanguageTag,\n LOCALIZATIONS_FILENAME,\n parseLocalizations,\n type LocalizationEntry,\n} from \"../core/localizations.js\";\nimport { VectorIndexError } from \"../core/vector-index.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { GraphError } from \"../types.js\";\nimport { warn } from \"../../shared/warn.js\";\nimport { findEntry } from \"../runtime/entry.js\";\nimport { createLexicalIndex } from \"../runtime/lexical.js\";\nimport {\n createVectorIndex,\n VectorMismatchError,\n type VectorIndex,\n} from \"../runtime/vector.js\";\nimport {\n createLocalEmbedder,\n EmbedderUnavailableError,\n} from \"../embed/local.js\";\nimport { createMockEmbedder } from \"../embed/mock.js\";\nimport type { Embedder } from \"../embed/types.js\";\nimport type { QueryTrace } from \"../runtime/trace.js\";\n\n/**\n * Which legs `--mode` can ask for, in the order messages list them. Stated\n * once so the union, the help text and the refusal sentence cannot drift.\n */\nexport const SEARCH_MODES = [\"lexical\", \"hybrid\", \"vector\"] as const;\nexport type SearchMode = (typeof SEARCH_MODES)[number];\n\nexport interface SearchOptions {\n config?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n /** Graph .ttl path (default: config `out`) — locates the sibling index. */\n graph?: string;\n /** Directory holding the indexes and manifest (default: beside the graph). */\n index?: string;\n /**\n * Which localization to search (ADR 01038). Optional when the corpus has one;\n * required when it has more, because picking for the user is how a query gets\n * answered out of the wrong language.\n */\n lang?: string;\n query: string;\n limit?: number;\n /** Vector sidecar path (default: the sidecar the manifest records). */\n vectors?: string;\n /**\n * Which legs to run. \"lexical\" is always available; \"vector\"/\"hybrid\" need an\n * embedder and a sidecar. Default \"hybrid\" when both are present, else\n * \"lexical\" — additive, never a new failure mode.\n */\n mode?: SearchMode;\n /** Injection seam for tests: bypasses the embedder factory. */\n embedder?: Embedder;\n cwd?: string;\n}\n\nexport interface SearchHit {\n iri: string;\n score: number;\n via: string;\n type?: string;\n title?: string;\n}\n\nexport interface SearchReport {\n query: string;\n /** Which legs actually ran. */\n mode: SearchMode;\n /** The fused ranking (or the single leg's, when only one ran). */\n results: SearchHit[];\n /** The lexical leg's own ranking. */\n lexical: SearchHit[];\n /** The vector leg's own ranking; empty when it did not run. */\n vector: SearchHit[];\n trace: QueryTrace;\n}\n\n/**\n * Read and shape-check the artifact. A truncated write, or `-i` pointed at the\n * wrong file, is an operational error (exit 2) like an unparseable graph — not\n * a raw stack trace, and not a confident \"0 results\".\n *\n * The digest travels with the document: it is what the vector sidecar records\n * as its `source`, and comparing them is how a stale sidecar is refused rather\n * than ranked against (ADR 01020).\n */\nfunction loadSearchIndex(indexPath: string): {\n doc: SearchIndexDoc;\n source: string;\n} {\n const raw = readFileSync(indexPath, \"utf8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (e) {\n throw new GraphError(\n `Failed to parse ${indexPath}: ${errorMessage(e)} — re-run \\`manni graph export search\\`.`,\n );\n }\n const entries = (parsed as SearchIndexDoc | null)?.entries;\n if (!Array.isArray(entries)) {\n throw new GraphError(\n `Not a manni graph search index: ${indexPath} — expected an \\`entries\\` array; re-run \\`manni graph export search\\`.`,\n );\n }\n return {\n doc: parsed as SearchIndexDoc,\n // Same recipe `manni graph embed` uses, so the two digests are comparable.\n source: `sha256:${createHash(\"sha256\").update(raw, \"utf8\").digest(\"hex\")}`,\n };\n}\n\n/**\n * Pick the localization to search from the manifest (ADR 01038).\n *\n * With one language the choice is unambiguous and made silently. With more, an\n * unspecified `--lang` is a **refusal**, not a default: answering a German\n * question out of the English index is the failure the fan-out exists to\n * prevent, and guessing would hide it behind a confident result.\n */\nfunction resolveLocalization(\n indexDir: string,\n lang: string | undefined,\n): LocalizationEntry {\n const manifestPath = join(indexDir, LOCALIZATIONS_FILENAME);\n if (!existsSync(manifestPath)) {\n throw new GraphError(\n `Localization manifest not found: ${manifestPath} — run \\`manni graph export search\\` first.`,\n );\n }\n const manifest = parseLocalizations(readFileSync(manifestPath, \"utf8\"));\n if (!manifest) {\n throw new GraphError(\n `Not a manni graph localization manifest: ${manifestPath} — re-run \\`manni graph export search\\`.`,\n );\n }\n const available = manifest.languages.map((l) => l.language);\n if (lang !== undefined) {\n // Tags are case-insensitive: `--lang en-us` names the `en-US` index.\n const wanted = canonicalLanguageTag(lang);\n const hit = manifest.languages.find(\n (l) => canonicalLanguageTag(l.language) === wanted,\n );\n if (!hit) {\n throw new GraphError(\n `No index for language \"${lang}\" — this corpus has ${available.join(\", \") || \"none\"}.`,\n );\n }\n return hit;\n }\n const only = manifest.languages[0];\n if (!only) {\n throw new GraphError(\n `The localization manifest lists no languages: ${manifestPath} — re-run \\`manni graph export search\\`.`,\n );\n }\n if (manifest.languages.length > 1) {\n throw new GraphError(\n `This corpus has more than one localization (${available.join(\", \")}) — pass --lang to choose one.`,\n );\n }\n return only;\n}\n\nexport async function runSearch(opts: SearchOptions): Promise<SearchReport> {\n const cwd = opts.cwd ?? process.cwd();\n const config = loadRunConfig(\n {\n ...(opts.config === undefined ? {} : { configPath: opts.config }),\n ...(opts.noConfig === undefined ? {} : { noConfig: opts.noConfig }),\n },\n cwd,\n );\n const graphPath = resolve(cwd, opts.graph ?? config.out);\n const indexDir = opts.index ? resolve(cwd, opts.index) : dirname(graphPath);\n const localization = resolveLocalization(indexDir, opts.lang);\n const indexPath = join(indexDir, localization.search.path);\n\n if (!existsSync(indexPath)) {\n throw new GraphError(\n `Search index not found: ${indexPath} — the manifest names it; re-run \\`manni graph export search\\`.`,\n );\n }\n\n const { doc, source } = loadSearchIndex(indexPath);\n // The manifest records the digest of the index it wrote, and embed refuses a\n // pair that has drifted. Searching one anyway answers from bytes the\n // manifest does not describe, with a confident ranking.\n if (localization.search.digest !== source) {\n throw new GraphError(\n `Stale manifest: ${localization.search.path} does not match the digest recorded for \"${localization.language}\". Re-run \\`manni graph export search\\`.`,\n );\n }\n const lexical = createLexicalIndex(doc);\n\n // The vector leg is opt-in by availability: a sidecar plus an embedder. Asked\n // for explicitly (`--mode vector|hybrid`) a missing piece is an error, since\n // silently answering lexically would look like the semantic leg ran.\n // \"Asked for\" means an explicit `--mode vector|hybrid` *or* an explicit\n // `--vectors <path>`. A typo'd path would otherwise fall through to the\n // default-path branch, find nothing, and return lexical results with exit 0 —\n // a confident answer to a question the user did not ask.\n //\n // One predicate for both decisions. Testing `!== undefined` here while the\n // path below tested truthiness meant `--vectors \"\"` demanded the vector leg\n // and then resolved the *default* sidecar — failing, or answering, about a\n // file the user never named.\n const explicitVectors =\n opts.vectors !== undefined && opts.vectors !== \"\"\n ? opts.vectors\n : undefined;\n const wantsVector =\n opts.mode === \"vector\" ||\n opts.mode === \"hybrid\" ||\n (explicitVectors !== undefined && opts.mode !== \"lexical\");\n // Default to the sidecar the manifest records for *this* language, so the\n // pair can never be crossed. An entry with no `vectors` block simply has no\n // sidecar yet, and the leg stays unavailable.\n //\n // Resolved against the manifest's own directory, because that is what\n // `vectors.path` is relative to. Resolving it against `config.embed.out`\n // instead made the vector leg silently vanish for any layout where the two\n // differ — a lexical answer to a question that asked for both.\n const vectorsPath = explicitVectors\n ? resolve(cwd, explicitVectors)\n : localization.vectors\n ? resolve(indexDir, localization.vectors.path)\n : undefined;\n let vectors: VectorIndex | undefined;\n if (\n opts.mode !== \"lexical\" &&\n vectorsPath !== undefined &&\n existsSync(vectorsPath)\n ) {\n try {\n vectors = createVectorIndex(readFileSync(vectorsPath));\n } catch (e) {\n // A truncated write or `--vectors` pointed at the wrong file is an\n // operational error (exit 2), exactly as for the search index above —\n // not a raw VectorIndexError stack trace out of an async action.\n if (e instanceof VectorIndexError) {\n throw new GraphError(\n `${e.message} (${vectorsPath}) — re-run \\`manni graph embed\\`, or use \\`--mode lexical\\`.`,\n );\n }\n throw e;\n }\n // Refuse rather than rank: vectors built from a different corpus point at\n // IRIs that may no longer exist and miss everything added since\n // (ADR 01020, \"Mismatch is refused, not ranked\").\n //\n // But only refuse when the vector leg was *asked for*. A plain `dockg\n // search` that merely happens to find a stale sidecar beside the graph\n // should degrade to lexical, not fail — the leg is additive, and turning a\n // working lexical search into exit 2 is the new failure mode ADR 01009\n // forbids. Warned about rather than silently dropped, so a user who\n // expected semantic results learns why they did not get them.\n const stale = vectors.check({ source });\n if (stale && wantsVector) throw new GraphError(stale.detail);\n if (stale) {\n warn(`${stale.detail} Falling back to lexical.`);\n vectors = undefined;\n }\n } else if (wantsVector) {\n // Named by the manifest when there is one to name, and by the language\n // otherwise: \"no sidecar for de\" is actionable, an undefined path is not.\n const named =\n vectorsPath ?? `no sidecar recorded for \"${localization.language}\"`;\n throw new GraphError(\n `Vector index not found: ${named} — run \\`manni graph embed\\` first, or use \\`--mode lexical\\`.`,\n );\n }\n\n let embedder: Embedder | undefined;\n if (vectors) {\n // Only an explicit `--mode vector|hybrid` makes a missing embedder fatal.\n // Naming a sidecar says which file to use, not that the optional\n // transformers peer must be installed — threading `wantsVector` here turned\n // `--vectors ./v.bin` on a machine without the peer from \"degrade to\n // lexical, exit 0\" into exit 2.\n const requireEmbedder = opts.mode === \"vector\" || opts.mode === \"hybrid\";\n embedder = await resolveEmbedder(opts.embedder, vectors, requireEmbedder);\n }\n\n const entry = await findEntry(opts.query, {\n lexical,\n // Pass the embedder, not a bare function: findEntry then verifies it\n // against the index itself rather than trusting the CLI to have done so.\n ...(embedder && vectors ? { vectors, embedder } : {}),\n limit: opts.limit,\n }).catch((e: unknown) => {\n // `resolveEmbedder` has already checked model and dtype, so reaching here\n // means a dimension disagreement the header did not predict — a real\n // operational error (exit 2), not a stack trace out of an async action.\n if (e instanceof VectorMismatchError) {\n throw new GraphError(`${e.message} Re-run \\`manni graph embed\\`.`);\n }\n throw e;\n });\n\n const decorate = (c: {\n iri: string;\n score: number;\n via: string;\n }): SearchHit => {\n const found = lexical.entry(c.iri);\n return {\n iri: c.iri,\n score: c.score,\n via: c.via,\n ...(found?.type === undefined ? {} : { type: found.type }),\n ...(found?.title === undefined ? {} : { title: found.title }),\n };\n };\n\n // Which legs *ran*, not which produced hits: a vector leg that matched\n // nothing (blank query, everything below `minScore`) still ran, and reporting\n // \"lexical\" for an explicit `--mode vector` would deny it ever happened. An\n // explicit mode is authoritative — the guards above already errored if it\n // could not be honored.\n const mode = opts.mode ?? (embedder && vectors ? \"hybrid\" : \"lexical\");\n\n // `--mode vector` reports the vector leg alone rather than the fusion.\n const results = opts.mode === \"vector\" ? entry.vector : entry.candidates;\n if (opts.mode === \"vector\") {\n // The trace is the answer to \"why did these come back\" (ADR 01018), so it\n // must describe the ranking actually returned, not the fusion that seeded\n // nothing in this mode.\n entry.trace.entry.length = 0;\n entry.trace.entry.push(...entry.vector);\n }\n\n return {\n query: opts.query,\n mode,\n results: results.map(decorate),\n lexical: entry.lexical.map(decorate),\n vector: entry.vector.map(decorate),\n trace: entry.trace,\n };\n}\n\n/**\n * Build an embedder for the query side, matching the sidecar. A mismatch is\n * refused rather than ranked against: comparing vectors from two different\n * models compares outputs of two different functions (ADR 01020).\n *\n * Both the model *and* the dtype come from the sidecar header rather than from\n * config: `embed.*` is a build-time knob, and q8 weights are a different\n * function from fp32 ones, so following config here would silently compare\n * query vectors against corpus vectors produced by different weights.\n *\n * `graph check` asks sample questions through it too, so both rank alike.\n */\nexport async function resolveEmbedder(\n override: Embedder | undefined,\n vectors: VectorIndex,\n required: boolean,\n): Promise<Embedder | undefined> {\n const { model, dtype } = vectors;\n try {\n const embedder =\n override ??\n (model === \"mock\"\n ? createMockEmbedder({ dtype })\n : await createLocalEmbedder({ model, dtype, role: \"query\" }));\n const mismatch = vectors.check({\n model: embedder.model,\n dtype: embedder.dtype,\n // Defense in depth: a future model that changes output size without\n // changing its id would otherwise only surface deep inside search().\n ...(embedder.dims > 0 ? { dims: embedder.dims } : {}),\n });\n if (mismatch) throw new GraphError(mismatch.detail);\n return embedder;\n } catch (e) {\n if (e instanceof GraphError) throw e;\n if (e instanceof EmbedderUnavailableError) {\n // Only fatal when the vector leg was asked for; otherwise degrade to\n // lexical rather than failing a search that can still be answered.\n if (required) throw new GraphError(e.message);\n return undefined;\n }\n // A model that will not load (bad id, 404, corrupt weights) is fatal either\n // way — but as an operational error with a message, not a stack trace.\n throw new GraphError(\n `Failed to load embedding model ${model}: ${errorMessage(e)}`,\n );\n }\n}\n\nexport function renderSearch(\n report: SearchReport,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") return JSON.stringify(report, null, 2);\n\n const lines: string[] = [];\n for (const r of report.results) {\n const label = r.title ? ` — ${r.title}` : \"\";\n const type = r.type ? ` [${r.type}]` : \"\";\n lines.push(`${r.score.toFixed(4)} ${compactIri(r.iri)}${type}${label}`);\n }\n if (report.results.length === 0) {\n lines.push(\"(no matches)\");\n }\n lines.push(\"\");\n lines.push(\n `${report.results.length} result${report.results.length === 1 ? \"\" : \"s\"} (${report.mode})`,\n );\n return lines.join(\"\\n\");\n}\n","/**\n * The vector sidecar (ADR 01020) — `graph/vectors.<lang>.bin`, embeddings for the\n * same text that language's lexical index covers (ADR 01038).\n *\n * Layout, fixed. The magic is four ASCII bytes in file order; every number\n * after it is little-endian:\n *\n * ```\n * 0 magic \"MGRV\" 4 bytes\n * 4 format version (u32) 4 bytes\n * 8 header length (u32) 4 bytes\n * 12 header JSON (UTF-8) headerLength bytes\n * . float32 payload count * dims * 4 bytes\n * ```\n *\n * The header names the model, dtype, dimensions, the node IRIs in payload order\n * (sorted), and a digest of the `search.json` the vectors were built from — so\n * the runtime can refuse to rank against vectors from a different model or a\n * stale corpus rather than returning quietly wrong results.\n *\n * Vectors are **L2-normalized at build time and stored as float32**. Normalizing\n * makes cosine collapse to a dot product at query time; float32 rather than int8\n * because int8 retains only ~91% of retrieval quality at 384 dimensions — see\n * ADR 01020, where that correction is recorded.\n *\n * No `node:` imports: the encoder runs in the CLI, the decoder in the browser.\n */\nimport { byCodeUnit } from \"./sort.js\";\n\n/**\n * \"MGRV\", manni graph vectors, as the bytes a hex dump shows first. It read\n * \"DKGV\" while the tool was dockg and \"MKGV\" while it was manni kg. Nothing was\n * published under either name, so no sidecar in the wild carries the old bytes.\n * Raw bytes rather than a little-endian u32: a u32 lands on disk reversed.\n */\nconst MAGIC = new Uint8Array([0x4d, 0x47, 0x52, 0x56]);\n// 2 since ADR 01038: the header names the language its vectors cover, so a\n// consumer cannot pair a sidecar with the wrong locale's index. A version-1\n// file is refused by `decodeVectorIndex` rather than read as if it had one.\nconst FORMAT_VERSION = 2;\nconst HEADER_OFFSET = 12;\n\nexport interface VectorIndexHeader {\n /** Embedding model id, e.g. an HF repo path. */\n model: string;\n /** Model-weight quantization the vectors were produced under. */\n dtype: string;\n /** Vector dimensions. Never assumed — always read from here. */\n dims: number;\n /** Number of vectors; equals `ids.length`. */\n count: number;\n /** Node IRIs, sorted, in payload order. */\n ids: string[];\n /** Digest of the `search.<lang>.json` these were built from (staleness detection). */\n source: string;\n /**\n * BCP-47 tag of the index these cover, or `und` (ADR 01038). Recorded so a\n * host that fetched the wrong pair is refused rather than ranked against a\n * model that never saw the language.\n */\n language: string;\n}\n\nexport interface VectorIndexDoc {\n header: VectorIndexHeader;\n /** `count * dims` floats, L2-normalized, row-major in `ids` order. */\n vectors: Float32Array;\n}\n\n/** Thrown for malformed input so callers can map it to an exit code / refusal. */\nexport class VectorIndexError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"VectorIndexError\";\n }\n}\n\n/**\n * L2-normalize a vector in place and return it. A zero vector is left alone —\n * dividing by its norm would produce NaNs that silently poison every later dot\n * product.\n */\nexport function normalize(vector: Float32Array): Float32Array {\n let sum = 0;\n // Iterating rather than indexing: every element is an element, which is what\n // the assertions here used to say.\n for (const value of vector) sum += value * value;\n if (sum === 0) return vector;\n const inv = 1 / Math.sqrt(sum);\n // `set(map(…))` scales every element in place with the same per-element\n // float32 rounding the indexed loop had, and without an index to assert.\n vector.set(vector.map((value) => value * inv));\n return vector;\n}\n\n/**\n * Encode entries into the sidecar. Entries are sorted by IRI first, so the bytes\n * depend on the set of entries and not on the order they were produced in.\n */\nexport function encodeVectorIndex(\n entries: Array<{ id: string; vector: Float32Array }>,\n meta: { model: string; dtype: string; source: string; language: string },\n): Uint8Array {\n const sorted = [...entries].sort((a, b) => byCodeUnit(a.id, b.id));\n const dims = sorted[0]?.vector.length ?? 0;\n for (const entry of sorted) {\n if (entry.vector.length !== dims) {\n throw new VectorIndexError(\n `Inconsistent vector dimensions: ${entry.id} has ${entry.vector.length}, expected ${dims}.`,\n );\n }\n }\n\n const header: VectorIndexHeader = {\n model: meta.model,\n dtype: meta.dtype,\n dims,\n count: sorted.length,\n ids: sorted.map((e) => e.id),\n source: meta.source,\n language: meta.language,\n };\n const headerBytes = new TextEncoder().encode(JSON.stringify(header));\n\n const payloadBytes = sorted.length * dims * 4;\n const out = new Uint8Array(HEADER_OFFSET + headerBytes.length + payloadBytes);\n const view = new DataView(out.buffer);\n out.set(MAGIC, 0);\n view.setUint32(4, FORMAT_VERSION, true);\n view.setUint32(8, headerBytes.length, true);\n out.set(headerBytes, HEADER_OFFSET);\n\n let offset = HEADER_OFFSET + headerBytes.length;\n for (const entry of sorted) {\n // Normalize a copy: the caller's array is not ours to mutate.\n const vector = normalize(Float32Array.from(entry.vector));\n // Exactly `dims` elements: the loop above rejected any entry of another\n // length, so iterating the vector is the same walk without the index.\n for (const value of vector) {\n view.setFloat32(offset, value, true);\n offset += 4;\n }\n }\n return out;\n}\n\n/** Decode a sidecar, rejecting anything malformed rather than mis-reading it. */\nexport function decodeVectorIndex(bytes: Uint8Array): VectorIndexDoc {\n if (bytes.length < HEADER_OFFSET) {\n throw new VectorIndexError(\"Not a manni graph vector index: file is too short.\");\n }\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n if (!MAGIC.every((byte, i) => bytes[i] === byte)) {\n throw new VectorIndexError(\n \"Not a manni graph vector index: bad magic — is this the right file?\",\n );\n }\n const version = view.getUint32(4, true);\n if (version !== FORMAT_VERSION) {\n throw new VectorIndexError(\n `Unsupported vector index version ${version} (this build reads ${FORMAT_VERSION}) — re-run \\`manni graph embed\\`.`,\n );\n }\n\n const headerLength = view.getUint32(8, true);\n if (HEADER_OFFSET + headerLength > bytes.length) {\n throw new VectorIndexError(\"Vector index is truncated: header overruns.\");\n }\n\n let header: VectorIndexHeader;\n try {\n header = JSON.parse(\n new TextDecoder().decode(\n bytes.subarray(HEADER_OFFSET, HEADER_OFFSET + headerLength),\n ),\n ) as VectorIndexHeader;\n } catch {\n throw new VectorIndexError(\"Vector index header is not valid JSON.\");\n }\n if (\n !Array.isArray(header.ids) ||\n typeof header.dims !== \"number\" ||\n header.ids.length !== header.count\n ) {\n throw new VectorIndexError(\"Vector index header is malformed.\");\n }\n\n const start = HEADER_OFFSET + headerLength;\n const expected = header.count * header.dims * 4;\n if (bytes.length - start !== expected) {\n throw new VectorIndexError(\n `Vector index is truncated: expected ${expected} payload bytes, found ${bytes.length - start}.`,\n );\n }\n\n // Copy rather than aliasing: `bytes` may be a view into a larger buffer whose\n // byteOffset is not 4-aligned, which Float32Array construction rejects.\n const vectors = new Float32Array(header.count * header.dims);\n for (let i = 0; i < vectors.length; i++) {\n vectors[i] = view.getFloat32(start + i * 4, true);\n }\n return { header, vectors };\n}\n","/**\n * Vector search (ADR 01020) — semantic entry, and a standalone capability.\n *\n * `search()` is usable on its own: give it a query vector and it ranks nodes by\n * meaning, with no lexical index and no graph involved. `findEntry` composes it\n * with the lexical leg, but does not own it.\n *\n * Hand-written rather than taken from a library, on evidence: the dedicated\n * browser vector libraries are 3 years stale, no maintained micro-package does\n * cosine top-k over typed arrays (the popular one throws on `Float32Array`), and\n * the engines that do exist run this same brute-force loop internally. See ADR\n * 01020 for the full survey.\n *\n * Vectors are L2-normalized at build time, so cosine similarity **is** the dot\n * product — no norms, no division, at query time. The loop is indexed rather\n * than `.reduce()`, which measures ~13× slower on typed arrays.\n *\n * Platform-neutral: no `node:` imports, no dependencies.\n */\nimport { byCodeUnit } from \"../core/sort.js\";\nimport {\n decodeVectorIndex,\n normalize,\n type VectorIndexHeader,\n} from \"../core/vector-index.js\";\nimport type { EntryCandidate } from \"./trace.js\";\n\nexport interface VectorSearchOptions {\n /** Maximum candidates to return. Default 10. */\n limit?: number;\n /**\n * Drop candidates scoring below this. Default 0 — every model has its own\n * useful range, so dockg does not impose a threshold the user did not choose.\n */\n minScore?: number;\n}\n\n/** Why a vector index cannot be used with the embedder or corpus at hand. */\nexport interface VectorMismatch {\n reason: \"model\" | \"dtype\" | \"dims\" | \"stale-source\";\n detail: string;\n}\n\n/**\n * Thrown when a query would be ranked against vectors it cannot be compared to.\n *\n * A distinct type so hosts can catch exactly this — and so it cannot be mistaken\n * for \"no results\". Ranking on regardless is the silent-wrong-answer failure\n * ADR 01020 exists to prevent, so this is loud by design.\n */\nexport class VectorMismatchError extends Error {\n readonly reason: VectorMismatch[\"reason\"];\n constructor(mismatch: VectorMismatch) {\n super(mismatch.detail);\n this.name = \"VectorMismatchError\";\n this.reason = mismatch.reason;\n }\n}\n\n/**\n * The digest `manni graph embed` records as a sidecar's `source`, computed the same\n * way in a browser — SHA-256 over the **raw bytes of `search.json` exactly as\n * fetched**, hex, prefixed `sha256:`.\n *\n * Exists so a host can pass `source` to `findEntry` and get the staleness half\n * of the refusal (ADR 01020) without reconstructing the recipe. Re-serializing\n * the parsed JSON would change the bytes and so the digest — pass the response\n * text, not `JSON.stringify(doc)`.\n *\n * Uses Web Crypto, which is platform-neutral: browsers and Node 18+ both have\n * it on `globalThis`.\n */\nexport async function searchIndexDigest(raw: string): Promise<string> {\n // `lib.dom` and @types/node both declare `globalThis.crypto.subtle` as\n // always present. A page served over plain HTTP gets `crypto` without\n // `subtle`, which is the case this throw exists for: the declaration is the\n // optimistic one, and reading through `Partial` is how the guard gets to say\n // so instead of reading as a test that cannot fail.\n const webCrypto = globalThis.crypto as\n | Partial<typeof globalThis.crypto>\n | undefined;\n const subtle = webCrypto?.subtle;\n if (!subtle) {\n throw new Error(\n \"searchIndexDigest needs Web Crypto (globalThis.crypto.subtle), which is unavailable here — a page served over plain HTTP does not get it.\",\n );\n }\n const digest = await subtle.digest(\"SHA-256\", new TextEncoder().encode(raw));\n const hex = [...new Uint8Array(digest)]\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n return `sha256:${hex}`;\n}\n\nexport interface VectorIndex {\n /**\n * Rank nodes against a query vector. The vector is normalized here, so\n * callers need not — an unnormalized query would otherwise scale every score.\n */\n search(query: Float32Array, options?: VectorSearchOptions): EntryCandidate[];\n /**\n * Check this index against the embedder and corpus in play. Returns the\n * mismatch, or undefined when they agree. Ranking against vectors from a\n * different model compares outputs of two different functions (ADR 01020), so\n * callers should refuse rather than proceed.\n */\n check(expected: {\n model?: string;\n dtype?: string;\n dims?: number;\n source?: string;\n }): VectorMismatch | undefined;\n readonly model: string;\n /**\n * Weight quantization the corpus vectors were produced under. The query side\n * must embed at the *same* dtype — q8 and fp32 weights are different\n * functions, so mixing them compares incomparable vectors (ADR 01020).\n */\n readonly dtype: string;\n readonly dims: number;\n readonly source: string;\n size(): number;\n /** The IRI at a payload row, for callers walking the index directly. */\n idAt(row: number): string | undefined;\n}\n\n/** Build a vector index from encoded sidecar bytes. */\nexport function createVectorIndex(bytes: Uint8Array): VectorIndex {\n const { header, vectors } = decodeVectorIndex(bytes);\n const { dims, ids } = header;\n\n return {\n model: header.model,\n dtype: header.dtype,\n dims,\n source: header.source,\n size: () => ids.length,\n idAt: (row) => ids[row],\n\n check(expected) {\n if (expected.model !== undefined && expected.model !== header.model) {\n return {\n reason: \"model\",\n detail: `Vector index was built with ${header.model}, but the embedder is ${expected.model}. Re-run \\`manni graph embed\\`.`,\n };\n }\n if (expected.dtype !== undefined && expected.dtype !== header.dtype) {\n return {\n reason: \"dtype\",\n detail: `Vector index was built at dtype ${header.dtype}, but the embedder is at ${expected.dtype} — different weights are a different function. Re-run \\`manni graph embed\\`.`,\n };\n }\n if (expected.dims !== undefined && expected.dims !== dims) {\n return {\n reason: \"dims\",\n detail: `Vector index has ${dims} dimensions, but the embedder produces ${expected.dims}.`,\n };\n }\n if (expected.source !== undefined && expected.source !== header.source) {\n return {\n reason: \"stale-source\",\n detail:\n \"Vector index was built from a different search index — the corpus changed. Re-run `manni graph embed`.\",\n };\n }\n return undefined;\n },\n\n search(query, options = {}) {\n if (dims === 0 || ids.length === 0) return [];\n if (query.length !== dims) {\n // A silent zero-fill or truncate here would return confident nonsense.\n // Typed like every other mismatch so a caller (and the CLI's exit-code\n // mapping) handles it the same way rather than seeing a raw stack.\n throw new VectorMismatchError({\n reason: \"dims\",\n detail: `Query vector has ${query.length} dimensions, but the index has ${dims}.`,\n });\n }\n const limit = normalizeLimit(options.limit);\n if (limit === 0) return [];\n const minScore = options.minScore ?? 0;\n\n // Copy before normalizing: the caller's vector is not ours to mutate.\n const q = normalize(Float32Array.from(query));\n\n const scored: EntryCandidate[] = [];\n // `entries()` pairs each row with its IRI, so the id is proven present\n // by the iteration rather than asserted after an index.\n for (const [row, iri] of ids.entries()) {\n // The payload is `count × dims` floats, so this row is exactly these\n // `dims` of them — and `q` was checked to be `dims` long above. Both\n // walks are therefore in range; `?? 0` spells that a term outside the\n // row contributes nothing, which is what out of range means for a dot\n // product.\n const stored = vectors.subarray(row * dims, (row + 1) * dims);\n let score = 0;\n for (const [i, value] of q.entries()) score += value * (stored[i] ?? 0);\n if (score >= minScore) {\n scored.push({ iri, score, via: \"vector\" });\n }\n }\n\n scored.sort((a, b) =>\n a.score === b.score ? byCodeUnit(a.iri, b.iri) : b.score - a.score,\n );\n return scored.slice(0, limit);\n },\n };\n}\n\n/**\n * A limit that is not a non-negative integer falls back to the documented\n * default — `slice(0, NaN)` is empty, which would report a confident \"no\n * results\" for a query that does match.\n */\nfunction normalizeLimit(limit: number | undefined): number {\n return typeof limit === \"number\" && Number.isInteger(limit) && limit >= 0\n ? limit\n : 10;\n}\n\nexport type { VectorIndexHeader };\n","/**\n * Query trace — the explainability contract (ADR 01018). Every runtime stage\n * appends to a trace, and no API returns results without one: retrieval\n * provenance is part of the contract exactly as PROV provenance is part of the\n * build. The trace answers \"how and why did this result come back\": which nodes\n * were seeded, every hop walked, every node scope excluded (and by which rule),\n * and every content resolution attempted.\n *\n * Events are appended in traversal order, which is itself deterministic, so the\n * trace is byte-stable for a given graph + query.\n */\n\n/** How a seed was found. `hybrid` means several legs agreed on it. */\nexport type EntryVia = \"explicit\" | \"lexical\" | \"vector\" | \"hybrid\";\n\n/** A starting node, with the score/reason that made it a seed. */\nexport interface EntryCandidate {\n iri: string;\n /**\n * Relevance score: 1 for an explicitly requested seed, otherwise the fused\n * `rrfMerge` score. Note that fusion is **rank**-based, so a searched seed's\n * score reflects its position (1/(60 + rank)), not the engine's relevance —\n * it orders candidates but is not a magnitude to threshold on.\n */\n score: number;\n via: EntryVia;\n}\n\n/** One edge walked, in either direction. */\nexport interface Hop {\n from: string;\n predicate: string;\n to: string;\n /** Hops from the nearest seed (seeds are depth 0; their neighbors are 1). */\n depth: number;\n direction: \"out\" | \"in\";\n}\n\n/** A node the scope filter removed, and why. */\nexport interface ScopeExclusion {\n node: string;\n /**\n * The predicate that disqualified the node: a `graph:not*` IRI when an\n * explicit negative named the target, or the positive predicate (e.g.\n * `iirds:relates-to-product-variant`) when the node declared a scope set that\n * omits the target.\n */\n rule: string;\n /**\n * The filter target being applied — the variant or subject IRI the query\n * asked for. Under a `graph:not*` rule the node named this explicitly; under\n * a positive rule this is what the node's declared set was missing.\n */\n value: string;\n}\n\n/** One content-resolution attempt. */\nexport interface Resolution {\n iri: string;\n sourceUrl: string;\n ok: boolean;\n /** Present when `ok` is false. */\n error?: string;\n}\n\nexport interface QueryTrace {\n entry: EntryCandidate[];\n hops: Hop[];\n exclusions: ScopeExclusion[];\n resolutions: Resolution[];\n}\n\nexport function createTrace(): QueryTrace {\n return { entry: [], hops: [], exclusions: [], resolutions: [] };\n}\n\n/**\n * Every node named anywhere in the trace as reached — seeds plus hop targets.\n * The trace-completeness contract: a traversal's results must be a subset of\n * this, so every returned node is explainable by recorded events.\n */\nexport function reachedNodes(trace: QueryTrace): Set<string> {\n const reached = new Set<string>();\n for (const e of trace.entry) reached.add(e.iri);\n for (const h of trace.hops) reached.add(h.to);\n return reached;\n}\n","/**\n * Entry-point finding (ADR 01019, extended by ADR 01020) — the stage that turns\n * a question into seed nodes for the walker.\n *\n * Two rankings now: lexical (BM25 over the search artifact) and, when the host\n * supplies an embedder, vector (cosine over the sidecar). `rrfMerge` fuses them.\n *\n * **Each leg is returned separately as well as fused.** A caller rendering a\n * search UI wants to show \"text matches\" and \"semantic matches\" as distinct\n * things, and either leg is usable on its own — `lexical.search` and\n * `vectors.search` are public and independent of this function.\n *\n * Every candidate is appended to the trace, so \"why did retrieval start here?\"\n * is answerable alongside \"why did it walk there?\" (ADR 01018 invariant 2).\n *\n * Platform-neutral: no `node:` imports.\n */\nimport { byCodeUnit } from \"../core/sort.js\";\nimport type { LexicalIndex } from \"./lexical.js\";\nimport { VectorMismatchError, type VectorIndex } from \"./vector.js\";\nimport {\n createTrace,\n type EntryCandidate,\n type EntryVia,\n type QueryTrace,\n} from \"./trace.js\";\n\n/**\n * Enough of an embedder to verify it against a vector index. Structural rather\n * than the `Embedder` interface itself, so the runtime stays independent of\n * `@hawkeyexl/manni/graph/embed` — any object with these three fields works.\n */\nexport interface QueryEmbedder {\n readonly model: string;\n readonly dtype: string;\n embed(text: string): Promise<Float32Array> | Float32Array;\n}\n\nexport interface FindEntryOptions {\n /** The lexical index to query. */\n lexical: LexicalIndex;\n /** The vector index. Without it (and an embedder), entry is lexical-only. */\n vectors?: VectorIndex;\n /**\n * The embedder for the query side. **Prefer this over `embedQuery`**: it\n * carries the model and dtype, so `findEntry` can verify they match the\n * vector index and refuse rather than rank against incomparable vectors.\n */\n embedder?: QueryEmbedder;\n /**\n * Embed the query with a bare function. An escape hatch for hosts wiring\n * their own model — but it carries no identity, so **the model/dtype match\n * cannot be verified**; only the dimension check inside `search` applies.\n * Prefer `embedder`.\n */\n embedQuery?: (query: string) => Promise<Float32Array> | Float32Array;\n /**\n * Digest of the `search.json` this caller loaded, from `searchIndexDigest`.\n * Supplied, a sidecar built from a *different* corpus is refused rather than\n * ranked — its IRIs may no longer exist, and it misses everything added\n * since. Omitted, that half of the check simply does not run: the runtime\n * cannot derive the digest, since it never sees the raw bytes.\n */\n source?: string;\n /** Maximum seeds to return. Default 10. */\n limit?: number;\n /** Append candidates here instead of starting a new trace. */\n trace?: QueryTrace;\n}\n\nexport interface EntryResult {\n /** The fused ranking — what seeds traversal. */\n candidates: EntryCandidate[];\n /** The lexical leg's own ranking. */\n lexical: EntryCandidate[];\n /** The vector leg's own ranking; empty when no embedder was supplied. */\n vector: EntryCandidate[];\n trace: QueryTrace;\n}\n\n/**\n * Reciprocal rank fusion over N ranked lists: score = Σ 1/(k + rank).\n *\n * Rank-based rather than score-based on purpose — lexical BM25 scores and\n * cosine similarities are not on a comparable scale, so fusing raw scores would\n * let whichever leg happens to produce bigger numbers dominate. `k = 60` is the\n * standard damping constant.\n *\n * Deterministic: input list order does not affect the result, and ties break by\n * IRI.\n */\nexport function rrfMerge(\n rankings: EntryCandidate[][],\n k = 60,\n): EntryCandidate[] {\n const fused = new Map<string, { score: number; vias: Set<EntryVia> }>();\n for (const ranking of rankings) {\n ranking.forEach((candidate, i) => {\n const current = fused.get(candidate.iri) ?? {\n score: 0,\n vias: new Set<EntryVia>(),\n };\n current.score += 1 / (k + i + 1);\n current.vias.add(candidate.via);\n fused.set(candidate.iri, current);\n });\n }\n\n return [...fused.entries()]\n .map(([iri, { score, vias }]) => {\n // One leg keeps its own provenance; several means the seed was fused.\n // Destructuring rather than `[...vias][0]!` so the single-leg case needs\n // no non-null assertion — an empty set simply falls through to \"hybrid\",\n // which is unreachable anyway (a set only exists once a leg added to it).\n const [only] = vias;\n return {\n iri,\n score,\n via: vias.size === 1 && only !== undefined ? only : \"hybrid\",\n };\n })\n .sort((a, b) =>\n a.score === b.score ? byCodeUnit(a.iri, b.iri) : b.score - a.score,\n );\n}\n\n/**\n * Find seed nodes for a question, returning each ranking leg and their fusion.\n *\n * Async because embedding a query is: local models are a WASM forward pass.\n * Uniformly async rather than sync-when-lexical-only, so callers have one\n * contract to hold rather than a return type that changes with the options.\n *\n * The vector leg runs only when both a `vectors` index and an `embedQuery` are\n * supplied. Absent either, this is lexical entry exactly as Phase 8 shipped it —\n * additive, never a new failure mode (ADR 01009's degrade-don't-fail rule).\n */\nexport async function findEntry(\n query: string,\n options: FindEntryOptions,\n): Promise<EntryResult> {\n const trace = options.trace ?? createTrace();\n // `--limit abc` parses to NaN, and `slice(0, NaN)` is empty — a typo'd flag\n // would report a confident \"0 results\" for a query that does match. Anything\n // that is not a non-negative integer falls back to the documented default.\n const limit =\n typeof options.limit === \"number\" &&\n Number.isInteger(options.limit) &&\n options.limit >= 0\n ? options.limit\n : 10;\n\n const lexical = options.lexical.search(query, { limit });\n\n // Bound first: the closure then captures the embedder the test found, rather\n // than re-reading a property the type cannot know is still the same one.\n const embedder = options.embedder;\n const embed = embedder ? (q: string) => embedder.embed(q) : options.embedQuery;\n\n let vector: EntryCandidate[] = [];\n if (options.vectors && embed && query.trim() !== \"\") {\n // Verify *before* embedding. The refusal is enforced here, not only in the\n // CLI, because this is the browser-facing surface — and the whole reason\n // ADR 01020 exists is that the browser must embed with a function that\n // agrees with the one that embedded the corpus. Ranking a stale or\n // wrong-model index would be the silent wrong answer this design prevents.\n const mismatch = options.vectors.check({\n ...(options.embedder\n ? { model: options.embedder.model, dtype: options.embedder.dtype }\n : {}),\n // Staleness is checked whichever way the query is embedded — it is a\n // property of the corpus, not of the embedder, so even the unverified\n // `embedQuery` path gets it when the caller supplies a digest.\n ...(options.source === undefined ? {} : { source: options.source }),\n });\n if (mismatch) throw new VectorMismatchError(mismatch);\n const queryVector = await embed(query);\n vector = options.vectors.search(queryVector, { limit });\n }\n\n const rankings = vector.length > 0 ? [lexical, vector] : [lexical];\n const candidates = rrfMerge(rankings).slice(0, limit);\n\n for (const candidate of candidates) trace.entry.push(candidate);\n return { candidates, lexical, vector, trace };\n}\n","/**\n * Lexical entry (ADR 01019) — text query → ranked seed nodes.\n *\n * Loads the `search.json` artifact (produced by `manni graph export search`)\n * and scores it with MiniSearch. The artifact carries body text, which the graph\n * deliberately does not (ADR 01008), so a query can match what a document *says*\n * and not merely what it is titled.\n *\n * MiniSearch is this runtime's one production dependency; the bundle-purity gate\n * allow-lists exactly it. Two guards keep ranking a dockg contract rather than a\n * library's: ties are broken by IRI here (MiniSearch does not define tie order),\n * and the on-disk artifact format is ours, so upgrading MiniSearch can never\n * change a committed artifact.\n *\n * Platform-neutral: no `node:` imports.\n */\nimport MiniSearch from \"minisearch\";\nimport type { SearchEntry, SearchIndexDoc } from \"../core/search-index.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\nimport type { EntryCandidate } from \"./trace.js\";\n\nexport interface LexicalSearchOptions {\n /** Maximum candidates to return. Default 10. */\n limit?: number;\n}\n\nexport interface LexicalIndex {\n /** Ranked candidates, best first, ties broken by IRI. */\n search(query: string, options?: LexicalSearchOptions): EntryCandidate[];\n /** Indexed entry count. */\n size(): number;\n /** The entry behind an IRI, for callers that want its title/type. */\n entry(iri: string): SearchEntry | undefined;\n}\n\n/**\n * Build a lexical index from the search artifact — a JSON string or the parsed\n * document.\n */\nexport function createLexicalIndex(\n input: string | SearchIndexDoc,\n): LexicalIndex {\n const doc = (\n typeof input === \"string\" ? (JSON.parse(input) as SearchIndexDoc) : input\n ) as SearchIndexDoc | null;\n // Shape-check rather than trust: handed something that is valid JSON but not\n // a search artifact, MiniSearch's `addAll` throws \"documents is not\n // iterable\" from inside the library. An empty index is the honest answer.\n const entries = Array.isArray(doc?.entries) ? doc.entries : [];\n\n const mini = new MiniSearch<SearchEntry>({\n fields: [\"title\", \"labels\", \"description\", \"text\"],\n storeFields: [\"id\"],\n idField: \"id\",\n // Titles and labels are the strongest signal that a node *is* the subject;\n // body text is evidence it merely mentions it.\n searchOptions: {\n boost: { title: 3, labels: 2, description: 1.5 },\n prefix: true,\n fuzzy: 0.2,\n },\n });\n mini.addAll(entries);\n\n const byIri = new Map(entries.map((e) => [e.id, e]));\n\n return {\n size: () => entries.length,\n entry: (iri) => byIri.get(iri),\n search(query, options = {}) {\n const trimmed = query.trim();\n if (trimmed === \"\") return [];\n const hits = mini.search(trimmed);\n // MiniSearch does not define an order for equal scores; sort explicitly so\n // the same query against the same artifact always ranks identically.\n hits.sort((a, b) =>\n a.score === b.score\n ? byCodeUnit(String(a.id), String(b.id))\n : b.score - a.score,\n );\n return hits\n .slice(0, options.limit ?? 10)\n .map((h) => ({ iri: String(h.id), score: h.score, via: \"lexical\" }));\n },\n };\n}\n","/**\n * The local embedder ([ADR 01020](../../adrs/01020-local-embeddings.md), corrected\n * by [ADR 01025](../../adrs/01025-embedder-cross-platform-reality.md)).\n *\n * Node and the browser **do not** run the same implementation, and cannot be made\n * to. transformers.js v4 takes disjoint `device` vocabularies per platform — Node\n * accepts `dml | webgpu | cpu`, the browser accepts `webgpu | wasm` — so no single\n * value selects one backend everywhere. An earlier version of this file forced\n * `device: \"wasm\"`, which threw on every real Node run; see ADR 01025 for the\n * measurements.\n *\n * What that costs, measured on granite q8: Node native vs browser WASM agree to\n * cosine 0.999914 (max component diff 2.2e-3). dockg's guarantee is therefore\n * **ranking agreement**, gated by `test/real/cross-platform.mjs`, not float\n * equality.\n *\n * Three disciplines are real and pinned here:\n *\n * 1. `numThreads = 1` — binds on the WASM side, where the default follows\n * `hardwareConcurrency` and would vary reduction splits per machine. Inert\n * on the Node side, whose env object does not carry it.\n * 2. `dtype: \"q8\"` — int8 GEMM accumulates in int32, and integer addition is\n * associative.\n * 3. One text per call — a batched vector depends on what it was batched with,\n * so adding a document would perturb its neighbours.\n *\n * `device` is deliberately **not** passed: transformers.js then picks its platform\n * default, which in Node is bit-identical to an explicit `cpu` (measured) and in\n * the browser is WASM. A caller wanting `webgpu` can pass it.\n *\n * `@huggingface/transformers` is an **optional peer dependency**, imported\n * dynamically: it hard-depends on both ONNX runtimes plus native `sharp`, and\n * most dockg users never enable embeddings. Behind this subpath, a consumer who\n * never imports `@hawkeyexl/manni/graph/embed` never resolves it.\n */\nimport { errorMessage } from \"../../shared/errors.js\";\nimport {\n profileFor,\n withPrefix,\n type EmbedRole,\n type Embedder,\n type ModelProfile,\n} from \"./types.js\";\nimport { DEFAULT_MODEL } from \"./types.js\";\n\n/**\n * A built feature-extraction pipeline, as this module calls it.\n *\n * One text, mean-pooled and normalized (disciplines 2 and 3 above), returning\n * something array-like of numbers. `Tensor` carries far more than that; naming\n * only what is read keeps the peer's real type out of the build.\n */\nexport type FeatureExtractionPipeline = (\n text: string,\n options: { pooling: \"mean\"; normalize: boolean },\n) => Promise<{ data: ArrayLike<number> }>;\n\n/**\n * The slice of `@huggingface/transformers` this module touches.\n *\n * The package is an **optional peer**, so importing its types would make it a\n * hard dependency for everyone — the thing the dynamic import exists to avoid.\n * Declaring the used surface here instead keeps the boundary narrow rather\n * than untyped: three members, each one a line the code below actually runs.\n * `env` is optional all the way down because the Node build's\n * `backends.onnx.wasm` may be absent or a stub, which is the mistake ADR 01025\n * documents.\n */\nexport interface TransformersModule {\n env?: {\n backends?: {\n onnx?: { wasm?: { numThreads?: number } };\n };\n };\n pipeline: (\n task: \"feature-extraction\",\n model: string,\n options: { device?: string; dtype: string },\n ) => Promise<FeatureExtractionPipeline>;\n}\n\nexport interface LocalEmbedderOptions {\n /** Hugging Face model id. Any id is accepted; the tested set is documented. */\n model?: string;\n /** Weight quantization. Default `q8` — see discipline 2 above. */\n dtype?: string;\n /**\n * ONNX execution provider. **Omitted by default on purpose** — the accepted\n * values differ by platform (Node: `dml | webgpu | cpu`; browser: `webgpu |\n * wasm`), so any hardcoded value throws somewhere. Pass one only if you know\n * which platform this embedder runs on.\n */\n device?: string;\n /**\n * What these embeddings are for. Decides which prefix convention applies for\n * models that need one. Default \"passage\" (indexing); the query side passes\n * \"query\".\n */\n role?: EmbedRole;\n /**\n * Inject the transformers.js module (tests, or a host that already imported\n * it). Absent, it is imported dynamically.\n */\n transformers?: TransformersModule;\n}\n\n/** Thrown when the optional peer is not installed, with the fix in the message. */\nexport class EmbedderUnavailableError extends Error {\n constructor(detail: string) {\n super(\n `Local embeddings need @huggingface/transformers, which is an optional peer dependency.\\n` +\n ` Install it: npm install @huggingface/transformers\\n` +\n ` (${detail})`,\n );\n this.name = \"EmbedderUnavailableError\";\n }\n}\n\nasync function loadTransformers(\n injected?: TransformersModule,\n): Promise<TransformersModule> {\n if (injected) return injected;\n try {\n // A literal specifier, so a consumer's bundler can resolve and chunk it\n // normally when they *have* opted in. Nothing is lost by leaving it\n // untyped: this boundary is untyped by design (see the note above), and\n // the missing-package path is what the catch handles.\n //\n // `@ts-ignore`, not `@ts-expect-error`, precisely because whether this\n // line errors depends on whether the optional peer happens to be\n // installed. `@ts-expect-error` fails with TS2578 (\"unused directive\") the\n // moment someone follows the README and installs it — which is exactly\n // what the `embed-real` CI job does, and how this was caught.\n // @ts-ignore optional peer dependency, may or may not be installed\n return (await import(\"@huggingface/transformers\")) as TransformersModule;\n } catch (e) {\n throw new EmbedderUnavailableError(\n errorMessage(e),\n );\n }\n}\n\n/**\n * Create an embedder backed by a local model.\n *\n * **Constructing it is the expensive step**: `pipeline()` fetches the model's\n * config and weights (tens of megabytes on a cold cache) and builds the ONNX\n * session before returning, so callers that may not need to embed anything —\n * `manni graph embed` on an all-cache-hit run — should construct it lazily.\n */\nexport async function createLocalEmbedder(\n options: LocalEmbedderOptions = {},\n): Promise<Embedder> {\n const model = options.model ?? DEFAULT_MODEL;\n const dtype = options.dtype ?? \"q8\";\n const role: EmbedRole = options.role ?? \"passage\";\n const profile: ModelProfile = profileFor(model);\n\n const transformers = await loadTransformers(options.transformers);\n\n // Discipline 1, set before the pipeline is built. Optional-chained because\n // the Node build's `env.backends.onnx.wasm` may be absent or a stub — this\n // pins the browser side, and asserting it pinned both is the mistake ADR\n // 01025 documents.\n if (transformers.env?.backends?.onnx?.wasm) {\n transformers.env.backends.onnx.wasm.numThreads = 1;\n }\n\n const extractor = await transformers.pipeline(\"feature-extraction\", model, {\n // No `device`: its accepted values are disjoint across platforms, so any\n // hardcoded choice throws on one of them (ADR 01025).\n ...(options.device === undefined ? {} : { device: options.device }),\n dtype,\n });\n\n let dims = 0;\n\n return {\n model,\n dtype,\n get dims() {\n return dims;\n },\n async embed(text: string): Promise<Float32Array> {\n // Discipline 3: one text per call, never a batch.\n const output = await extractor(withPrefix(profile, role, text), {\n pooling: \"mean\",\n normalize: true,\n });\n const data = Float32Array.from(output.data);\n dims = data.length;\n return data;\n },\n };\n}\n","/**\n * A deterministic offline embedder (ADR 01020) — the counterpart to\n * `MockProvider` for the LLM seam.\n *\n * CI must stay hermetic: real embedding downloads tens of megabytes of model\n * weights, which the no-network rule forbids. This produces vectors from a hash\n * of the text, so they are stable across runs, machines, and platforms — which\n * makes the `vectors.bin` golden and the double-build determinism gate possible\n * without a model.\n *\n * The vectors carry no semantics. They are useful for testing plumbing,\n * ordering, and refusal paths — never for judging retrieval quality.\n *\n * Platform-neutral: no `node:` imports, no dependencies.\n */\nimport type { Embedder } from \"./types.js\";\n\n/** FNV-1a, 32-bit. Small, fast, and identical everywhere. */\nfunction fnv1a(text: string, seed: number): number {\n let hash = (0x81_1c_9d_c5 ^ seed) >>> 0;\n for (let i = 0; i < text.length; i++) {\n hash = (hash ^ text.charCodeAt(i)) >>> 0;\n // hash *= 16777619, via shifts to stay in 32-bit integer range.\n hash =\n (hash +\n ((hash << 1) +\n (hash << 4) +\n (hash << 7) +\n (hash << 8) +\n (hash << 24))) >>>\n 0;\n }\n return hash >>> 0;\n}\n\nexport interface MockEmbedderOptions {\n /** Output dimensions. Default 8 — small keeps fixtures readable. */\n dims?: number;\n /** Reported model id. Default \"mock\". */\n model?: string;\n /** Reported dtype. Default \"mock\". */\n dtype?: string;\n}\n\n/**\n * Build a deterministic embedder. The same text always yields the same vector;\n * different texts yield different ones with high probability.\n */\nexport function createMockEmbedder(\n options: MockEmbedderOptions = {},\n): Embedder {\n const dims = options.dims ?? 8;\n const model = options.model ?? \"mock\";\n const dtype = options.dtype ?? \"mock\";\n\n return {\n model,\n dtype,\n dims,\n embed(text: string): Promise<Float32Array> {\n const vector = new Float32Array(dims);\n for (let i = 0; i < dims; i++) {\n // Map each hash into [-1, 1) so vectors spread over the sphere rather\n // than crowding one orthant.\n vector[i] = (fnv1a(text, i) / 0x1_00_00_00_00) * 2 - 1;\n }\n return Promise.resolve(vector);\n },\n };\n}\n","/**\n * Sample questions as findability checks (proposals 0086 §7 and 0087), the\n * half of `manni graph check` no shape can express.\n *\n * Questions are read from each page's source, not from the graph: an item's\n * answer pins and review state are test data, and never reach the graph. A\n * question is asked through the retrieval `graph search` uses by default:\n * `findEntry` over the lexical index, fused with the vector leg when a sidecar\n * and an embedder are present beside the graph. The lexical index is built in\n * memory from the graph, so no `export search` run is needed, and a question\n * is asked in its page's language's index.\n *\n * An unpinned question must find its page, or a section of it. A pinned\n * answer must find the node whose own text holds its lines. Each pin is first\n * compared with the page as it is now, under cite's hashing rule: an answer\n * that moved is checked at its new lines, and one that changed is not asked.\n *\n * A golden-set file (`graph.questionFiles`) holds questions that span pages\n * or that the docs don't answer. Each of its answers names its page, and is\n * asked as a page's pin is. Across both homes, a question asked twice and a\n * question that repeats its answer's words are reported, and the whole set's\n * health is summed up for `check` to print and gate on.\n *\n * It measures finding, not answering. Nothing here reaches a model beyond the\n * embedder `search` would use, and the same inputs give the same findings.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport GithubSlugger from \"github-slugger\";\nimport type { Store } from \"n3\";\nimport { locateFrontmatter } from \"../../meta/index.js\";\nimport {\n bodyLineOf,\n findWindows,\n pinOfLines,\n spellLines,\n splitLines,\n toFileLines,\n type PageLines,\n} from \"../../shared/pin.js\";\nimport type { Severity } from \"../../shared/severity.js\";\nimport { warn } from \"../../shared/warn.js\";\nimport {\n formatOf,\n type DocFormat,\n isTreeFormat,\n metadataOf,\n mintTreeSections,\n parseTree,\n} from \"../core/analyze.js\";\nimport type { GraphConfig } from \"../core/config.js\";\nimport { mergePage, openMetaView, type MetaViewSource } from \"../core/external.js\";\nimport { STDIN_PATH } from \"../core/iri.js\";\nimport { compactIri, storeToQuads } from \"../core/load.js\";\nimport {\n canonicalLanguageTag,\n LOCALIZATIONS_FILENAME,\n parseLocalizations,\n UNDETERMINED,\n type LocalizationEntry,\n} from \"../core/localizations.js\";\nimport {\n COPIED_SHARE,\n copiedPairs,\n questionKey,\n readQuestionFile,\n readSampleQuestions,\n type AnswerPin,\n type SampleQuestion,\n} from \"../core/questions.js\";\nimport {\n buildSearchIndex,\n emitSearchIndex,\n partitionByLanguage,\n type SearchIndexDoc,\n} from \"../core/search-index.js\";\nimport type { CheckFinding } from \"../core/shacl.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\nimport { VectorIndexError } from \"../core/vector-index.js\";\nimport { NS, PREFIXES } from \"../core/vocab.js\";\nimport type { Embedder } from \"../embed/types.js\";\nimport { findEntry } from \"../runtime/entry.js\";\nimport { GraphIndex } from \"../runtime/graph.js\";\nimport { createLexicalIndex, type LexicalIndex } from \"../runtime/lexical.js\";\nimport { sectionOccurrences, sectionOwnLines } from \"../runtime/resolve.js\";\nimport {\n createVectorIndex,\n VectorMismatchError,\n type VectorIndex,\n} from \"../runtime/vector.js\";\nimport type { Position } from \"../../lint/types.js\";\nimport { GraphError } from \"../types.js\";\nimport { resolveEmbedder } from \"./search.js\";\n\nconst DOCUMENT = `${NS.graph}Document`;\nconst SECTION = `${NS.graph}Section`;\nconst PATH = `${NS.graph}path`;\nconst LEVEL = `${NS.graph}level`;\nconst TITLE = `${NS.dcterms}title`;\nconst LANGUAGE = `${NS.dcterms}language`;\nexport const SAMPLE_QUESTION = `${NS.graph}sampleQuestion`;\nconst DOCUMENT_TYPE = compactIri(DOCUMENT);\nconst SECTION_TYPE = compactIri(SECTION);\n\n/** One language's retrieval: the lexical leg, and the vector leg when present. */\ninterface Retriever {\n lexical: LexicalIndex;\n vectors?: VectorIndex;\n embedder?: Embedder;\n}\n\n/** A page whose source is on disk, with the questions it declares. */\ninterface Page {\n doc: string;\n path: string;\n language: string;\n /** File line of body line 1, as cite counts it. */\n bodyLine: number;\n /** The body's lines, normalized as cite hashes them. */\n body: string[];\n /** Each section node in the graph, with the file lines its own text spans. */\n sections: { iri: string; span: PageLines }[];\n questions: SampleQuestion[];\n}\n\n/** The manifest `export search` and `embed` write beside the graph, if any. */\nfunction readManifest(indexDir: string): LocalizationEntry[] {\n const path = join(indexDir, LOCALIZATIONS_FILENAME);\n if (!existsSync(path)) return [];\n const manifest = parseLocalizations(readFileSync(path, \"utf8\"));\n if (!manifest) {\n throw new GraphError(\n `Not a manni graph localization manifest: ${path} — re-run \\`manni graph export search\\`.`,\n );\n }\n return manifest.languages;\n}\n\n/**\n * The lexical index, plus the vector leg when the manifest records a sidecar\n * for this language and an embedder loads. Every missing piece degrades to\n * lexical, as a plain `graph search` does. A sidecar built from another index\n * is refused with a warning, because its IRIs describe a different corpus.\n */\nasync function openRetriever(\n doc: SearchIndexDoc,\n entry: LocalizationEntry | undefined,\n indexDir: string,\n): Promise<Retriever> {\n const lexical = createLexicalIndex(doc);\n if (!entry?.vectors) return { lexical };\n const path = resolve(indexDir, entry.vectors.path);\n if (!existsSync(path)) return { lexical };\n let vectors: VectorIndex;\n try {\n vectors = createVectorIndex(readFileSync(path));\n } catch (e) {\n if (e instanceof VectorIndexError) {\n throw new GraphError(`${e.message} (${path}) — re-run \\`manni graph embed\\`.`);\n }\n throw e;\n }\n // The digest `export search` would record for this index, so a sidecar\n // embedded from the bytes it wrote is recognized as current.\n const source = `sha256:${createHash(\"sha256\").update(emitSearchIndex(doc), \"utf8\").digest(\"hex\")}`;\n const stale = vectors.check({ source });\n if (stale) {\n warn(`${stale.detail} Falling back to lexical.`);\n return { lexical };\n }\n const embedder = await resolveEmbedder(undefined, vectors, false);\n return embedder ? { lexical, vectors, embedder } : { lexical };\n}\n\n/** The documents and sections a question finds, best first. Concepts belong to no page. */\nasync function rankNodes(question: string, r: Retriever): Promise<string[]> {\n const entry = await findEntry(question, {\n lexical: r.lexical,\n ...(r.vectors && r.embedder ? { vectors: r.vectors, embedder: r.embedder } : {}),\n limit: r.lexical.size(),\n }).catch((e: unknown) => {\n if (e instanceof VectorMismatchError) {\n throw new GraphError(`${e.message} Re-run \\`manni graph embed\\`.`);\n }\n throw e;\n });\n return entry.candidates.flatMap((c) => {\n const type = r.lexical.entry(c.iri)?.type;\n return type === DOCUMENT_TYPE || type === SECTION_TYPE ? [c.iri] : [];\n });\n}\n\n/** The page a document or section node belongs to. */\nfunction pageOf(iri: string): string {\n const hash = iri.indexOf(\"#\");\n return hash < 0 ? iri : iri.slice(0, hash);\n}\n\n/** A node's last line: a half-open span that ends at column 1 ends on the line before. */\nfunction lastLine(position: Position): number {\n const { start, end } = position;\n return end.column <= 1 && end.line > start.line ? end.line - 1 : end.line;\n}\n\n/**\n * Each graph section of a page, with the file lines its own text spans: its\n * heading down to the next heading of any rank, as the search index slices it.\n */\nexport function sectionSpans(\n graph: GraphIndex,\n doc: string,\n path: string,\n content: string,\n sections: readonly string[],\n): { iri: string; span: PageLines }[] {\n const format = formatOf(path);\n const out: { iri: string; span: PageLines }[] = [];\n if (isTreeFormat(format)) {\n const known = new Set(sections);\n const minted = mintTreeSections(parseTree(content, path, format).sections);\n for (const [n, section] of minted.sections.entries()) {\n const iri = `${doc}#${section.slug}`;\n const node = minted.nodes[n];\n if (!known.has(iri) || node === undefined) continue;\n const head = node.titlePosition ?? node.position;\n const end = Math.max(\n lastLine(head),\n ...(minted.owned[n] ?? []).map((c) => lastLine(c.position)),\n );\n out.push({ iri, span: { start: head.start.line, end } });\n }\n return out;\n }\n const occurrences = sectionOccurrences(graph, doc);\n for (const iri of sections) {\n const title = graph.literal(iri, TITLE);\n if (title === undefined) continue;\n const level = Number.parseInt(graph.literal(iri, LEVEL) ?? \"\", 10);\n const span = sectionOwnLines(\n content,\n title,\n Number.isNaN(level) ? undefined : level,\n occurrences.get(iri) ?? 0,\n );\n if (span) out.push({ iri, span });\n }\n return out;\n}\n\n/**\n * A page's body as answer pins count it: the file line of body line 1, and\n * the body's lines, normalized as cite hashes them. HTML and XML carry their\n * metadata inside the body, so body line 1 is file line 1, as cite counts it.\n */\nexport function bodyOf(content: string, format: DocFormat): { bodyLine: number; body: string[] } {\n const bodyLine =\n format === \"html\" || format === \"xml\"\n ? 1\n : bodyLineOf(content, locateFrontmatter(content)?.closeEnd ?? 0);\n return { bodyLine, body: splitLines(content).slice(bodyLine - 1) };\n}\n\n/** Where a pin's lines are now, judged against the page as it reads today. */\nexport type Freshness =\n | { state: \"current\" | \"moved\" | \"ambiguous\"; ranges: PageLines[] }\n | { state: \"changed\" };\n\nexport function freshness(body: readonly string[], pin: AnswerPin): Freshness {\n const { lines, integrity } = pin;\n if (integrity === undefined) {\n return lines.end <= body.length ? { state: \"current\", ranges: [lines] } : { state: \"changed\" };\n }\n if (pinOfLines(body, lines) === integrity) return { state: \"current\", ranges: [lines] };\n const length = lines.end - lines.start + 1;\n const { starts } = findWindows(body, length, integrity, undefined, { around: lines.start });\n const ranges = starts.map((start) => ({ start, end: start + length - 1 }));\n if (ranges.length === 0) return { state: \"changed\" };\n return { state: ranges.length === 1 ? \"moved\" : \"ambiguous\", ranges };\n}\n\n/** `lines 4 and 8 both match`, or `lines 4, 8 and 12 all match`. */\nexport function matchList(ranges: readonly PageLines[]): string {\n const spelled = ranges.map(spellLines);\n const head = spelled.slice(0, -1);\n const last = spelled[spelled.length - 1] ?? \"\";\n // An ambiguous pin always has two or more; one range still reads right.\n if (head.length === 0) return `lines ${last} match`;\n const both = head.length === 1 ? \"both\" : \"all\";\n return `lines ${head.join(\", \")} and ${last} ${both} match`;\n}\n\n/**\n * The pages of the graph that are on disk. `pages` holds each one that\n * declares a question; `pageAt` builds the record of any other, by its\n * absolute path, for a golden-set answer that points at it.\n */\nasync function readPages(\n graph: GraphIndex,\n sources: string,\n view: { source: MetaViewSource; cwd: string },\n verb: \"checked\" | \"exported\",\n): Promise<{\n pages: Page[];\n contents: Map<string, string>;\n pageAt: (abs: string) => Page | undefined;\n}> {\n const contents = new Map<string, string>();\n const onDisk: { doc: string; path: string }[] = [];\n const byAbs = new Map<string, { doc: string; path: string }>();\n let missing = 0;\n for (const doc of graph.instancesOf(DOCUMENT)) {\n const path = graph.literal(doc, PATH);\n if (path === undefined || path === STDIN_PATH) continue;\n const abs = resolve(sources, path);\n if (!existsSync(abs)) {\n missing += 1;\n continue;\n }\n contents.set(path, readFileSync(abs, \"utf8\"));\n onDisk.push({ doc, path });\n byAbs.set(abs, { doc, path });\n }\n if (missing > 0) {\n warn(\n missing === 1\n ? `1 page in the graph is not on disk, so its questions were not ${verb}; run manni graph build.`\n : `${String(missing)} pages in the graph are not on disk, so their questions were not ${verb}; run manni graph build.`,\n );\n }\n\n const sectionsOf = new Map<string, string[]>();\n for (const section of graph.instancesOf(SECTION)) {\n const doc = pageOf(section);\n const siblings = sectionsOf.get(doc);\n if (siblings) siblings.push(section);\n else sectionsOf.set(doc, [section]);\n }\n\n const records = new Map<string, Page>();\n const record = (doc: string, path: string, questions: SampleQuestion[]): Page => {\n const known = records.get(doc);\n if (known) return known;\n const content = contents.get(path) ?? \"\";\n const { bodyLine, body } = bodyOf(content, formatOf(path));\n const tag = graph.literal(doc, LANGUAGE);\n const page: Page = {\n doc,\n path,\n language: tag === undefined ? UNDETERMINED : canonicalLanguageTag(tag),\n bodyLine,\n body,\n sections: sectionSpans(graph, doc, path, content, sectionsOf.get(doc) ?? []),\n questions,\n };\n records.set(doc, page);\n return page;\n };\n\n // The metadata `build` derives from: the page's own, merged with every key\n // a manifest of its collections owns.\n const meta = await openMetaView(view.source, view.cwd, onDisk.map((p) => p.path), sources);\n const pages: Page[] = [];\n for (const { doc, path } of onDisk) {\n const content = contents.get(path) ?? \"\";\n const format = formatOf(path);\n const own = metadataOf(content, path, format);\n const { data } = await mergePage(meta, path, own.data, own.present, format);\n const questions = readSampleQuestions(data[\"sample-questions\"]);\n if (questions.length > 0) pages.push(record(doc, path, questions));\n }\n pages.sort((a, b) => byCodeUnit(a.path, b.path));\n return {\n pages,\n contents,\n pageAt: (abs) => {\n const hit = byAbs.get(abs);\n return hit && record(hit.doc, hit.path, []);\n },\n };\n}\n\n/** The nodes of `page` whose own text holds any of `lines`, in file lines. */\nfunction holdersOf(page: Page, lines: PageLines): string[] {\n const out = page.sections\n .filter(({ span }) => span.start <= lines.end && lines.start <= span.end)\n .map(({ iri }) => iri);\n for (let line = lines.start; line <= lines.end; line++) {\n if (!page.sections.some(({ span }) => span.start <= line && line <= span.end)) {\n return [page.doc, ...out];\n }\n }\n return out;\n}\n\n/** How many of a kind of question are found, and how many first. */\nexport interface FoundCount {\n inTop: number;\n first: number;\n /** The questions with a test: a page, or at least one pin. */\n of: number;\n}\n\n/**\n * The health of the whole question set (proposal 0087 § 7b): what `check`\n * prints after its findings, and the `questions` key of its JSON report.\n */\nexport interface QuestionSummary {\n /** Every question, on pages and in golden-set files. */\n total: number;\n reviewed: number;\n drafted: number;\n /** Pages that declare at least one question. */\n pages: number;\n /** The golden-set files, as `graph.questionFiles` names them. */\n files: string[];\n top: number;\n found: { reviewed: FoundCount; drafted: FoundCount };\n answers: {\n /**\n * Every pin. It can exceed current + moved + changed by the golden-set\n * answers whose page is on disk but in no collection: their freshness\n * cannot be read, and their own findings say why.\n */\n pinned: number;\n /** Pins on a drafted question, or marked `reviewed: false` themselves. */\n unreviewed: number;\n current: number;\n /** Moved to one place or, ambiguously, to several. */\n moved: number;\n /** Changed, or on a page that does not exist. */\n changed: number;\n /** Page questions with no pin, which must find the page itself. */\n unpinned: number;\n };\n /** Golden-set questions with no answers: questions the docs don't answer. */\n gaps: number;\n}\n\n/**\n * A percentage, rounded down so a rate under a threshold never prints as it.\n * None of none is 0%: the summary reads as health, and nothing found is not\n * full marks. The rate gate guards an empty set on its own.\n */\nfunction percent(part: number, of: number): number {\n return of === 0 ? 0 : Math.floor((part / of) * 100);\n}\n\nfunction plural(n: number, word: string): string {\n return `${String(n)} ${word}${n === 1 ? \"\" : \"s\"}`;\n}\n\n/** `a`, `a and b`, or `a, b and c`. */\nfunction listOf(items: readonly string[]): string {\n const head = items.slice(0, -1);\n const last = items[items.length - 1] ?? \"\";\n return head.length === 0 ? last : `${head.join(\", \")} and ${last}`;\n}\n\n/** The health summary as `check` prints it, one line per row. */\nexport function renderQuestionSummary(s: QuestionSummary): string[] {\n const homes = [\n ...(s.pages > 0 ? [`on ${plural(s.pages, \"page\")}`] : []),\n ...(s.files.length > 0 ? [`in ${listOf(s.files)}`] : []),\n ];\n const { reviewed, drafted } = s.found;\n const a = s.answers;\n return [\n `questions ${String(s.total)}: ${String(s.reviewed)} reviewed, ${String(s.drafted)} drafted${homes.length > 0 ? `, ${homes.join(\" and \")}` : \"\"}`,\n ` found ${String(reviewed.inTop)} of ${String(reviewed.of)} reviewed in the top ${String(s.top)} (${String(percent(reviewed.inTop, reviewed.of))}%), ${String(reviewed.first)} first (${String(percent(reviewed.first, reviewed.of))}%)`,\n ...(drafted.of > 0\n ? [` drafted ${String(drafted.inTop)} of ${String(drafted.of)} in the top ${String(s.top)}, not counted until reviewed`]\n : []),\n ` answers ${String(a.pinned)} pinned, ${String(a.unreviewed)} not reviewed: ${String(a.current)} current, ${String(a.moved)} moved, ${String(a.changed)} changed; ${String(a.unpinned)} not pinned`,\n ...(s.gaps > 0 ? [` gaps ${plural(s.gaps, \"question\")} the docs don't answer`] : []),\n ];\n}\n\n/** Where a question's findings go. */\ninterface Target {\n focusNode: string;\n path?: string;\n docs: string[];\n}\n\n/** A finding on one question: `knob` takes `questions.severity`, and a draft reports at notice. */\ntype Report = (kind: \"knob\" | Severity, message: string, draft?: \"question\" | \"pin\") => void;\n\n/**\n * The findings for every page's sample questions and every golden-set file's\n * questions, with the health summary of the whole set. `sources` is where\n * each page's `graph:path` resolves from, `indexDir` is where a vector\n * sidecar's manifest sits, and `view` is the config meta's merge reads.\n * `questionFiles` are the golden-set files, and they and their answers'\n * `file`s resolve from `configDir`. The summary is absent when no question\n * exists.\n */\nexport async function askSampleQuestions(\n store: Store,\n settings: GraphConfig[\"check\"][\"questions\"],\n sources: string,\n indexDir: string,\n view: { source: MetaViewSource; cwd: string },\n questionFiles: readonly string[],\n configDir: string,\n): Promise<{ findings: CheckFinding[]; summary?: QuestionSummary }> {\n const knob = settings.severity;\n const top = settings.top;\n // A golden-set file that cannot be read is an operational error, said\n // before any page is read.\n const sets = questionFiles.map((label) => ({\n label,\n questions: readQuestionFile(resolve(configDir, label), label),\n }));\n const graph = GraphIndex.fromQuads(storeToQuads(store), Object.fromEntries(PREFIXES));\n const { pages, contents, pageAt } = await readPages(graph, sources, view, \"checked\");\n const total =\n pages.reduce((n, p) => n + p.questions.length, 0) +\n sets.reduce((n, f) => n + f.questions.length, 0);\n if (total === 0) return { findings: [] };\n\n // Built on first use: a set of nothing but gaps asks nothing.\n let byLanguage: Map<string, SearchIndexDoc> | undefined;\n let manifest: LocalizationEntry[] = [];\n const retrievers = new Map<string, Retriever>();\n const ranked = new Map<string, string[]>();\n const rank = async (language: string, question: string): Promise<string[]> => {\n const key = JSON.stringify([language, question]);\n const cached = ranked.get(key);\n if (cached) return cached;\n if (byLanguage === undefined) {\n // Missing pages were said once already, so the index's own warnings go.\n byLanguage = partitionByLanguage(\n graph,\n buildSearchIndex(graph, sources, { readDoc: (p) => contents.get(p) }),\n );\n manifest = readManifest(indexDir);\n }\n let retriever = retrievers.get(language);\n if (!retriever) {\n retriever = await openRetriever(\n byLanguage.get(language) ?? { version: 1, entries: [] },\n manifest.find((l) => canonicalLanguageTag(l.language) === language),\n indexDir,\n );\n retrievers.set(language, retriever);\n }\n const nodes = await rankNodes(question, retriever);\n ranked.set(key, nodes);\n return nodes;\n };\n\n const describe = (iri: string): string => {\n const path = graph.literal(pageOf(iri), PATH) ?? pageOf(iri);\n const title = iri.includes(\"#\") ? graph.literal(iri, TITLE) : undefined;\n return title === undefined ? path : `${path} § ${title}`;\n };\n const where = (position: number, first: string | undefined): string =>\n [\n position === 0 ? \"it is not found\" : `it ranks ${String(position)}`,\n ...(first === undefined ? [] : [`first is ${describe(first)}`]),\n ].join(\"; \");\n\n const findings: CheckFinding[] = [];\n const reporter =\n (target: Target): Report =>\n (kind, message, draft) => {\n const level = kind === \"knob\" ? knob : kind;\n if (level === \"off\") return;\n const suffix =\n draft === \"question\" ? \" (drafted, not reviewed)\" : draft === \"pin\" ? \" (answer not reviewed)\" : \"\";\n findings.push({\n severity: draft ? \"notice\" : level,\n message: `${message}${suffix}`,\n focusNode: target.focusNode,\n ...(target.path === undefined ? {} : { path: target.path }),\n docs: target.docs,\n });\n };\n\n const empty = (): FoundCount => ({ inTop: 0, first: 0, of: 0 });\n const summary: QuestionSummary = {\n total,\n reviewed: 0,\n drafted: 0,\n pages: pages.length,\n files: [...questionFiles],\n top,\n found: { reviewed: empty(), drafted: empty() },\n answers: { pinned: 0, unreviewed: 0, current: 0, moved: 0, changed: 0, unpinned: 0 },\n gaps: 0,\n };\n /** Counts one question's outcome: `tests` holds each counted test's position, 0 when missed. */\n const tally = (reviewed: boolean, tests: readonly number[]): void => {\n if (tests.length === 0) return;\n const count = reviewed ? summary.found.reviewed : summary.found.drafted;\n count.of += 1;\n if (tests.every((p) => p >= 1 && p <= top)) count.inTop += 1;\n if (tests.every((p) => p === 1)) count.first += 1;\n };\n\n /**\n * One pin on `page`: its freshness first, then whether the top `top` holds\n * a node whose own text holds its lines. `file` is the page as a golden-set\n * item names it, absent for a page's own question. Returns the best\n * position, 0 when the answer changed or is not found, and the answer's\n * text as it reads now.\n */\n const askPin = async (\n page: Page,\n pin: AnswerPin,\n question: string,\n language: string,\n report: Report,\n draft: \"question\" | \"pin\" | undefined,\n file?: string,\n ): Promise<{ position: number; text?: string }> => {\n const fresh = freshness(page.body, pin);\n if (fresh.state === \"changed\") {\n summary.answers.changed += 1;\n // `fill` re-pairs a page's own question. A golden-set file's is a\n // person's to re-pin, because fill only moves its lines.\n const of = file === undefined ? \"\" : ` of ${file}`;\n const fix =\n file === undefined\n ? \"re-pair it with manni graph fill --fields sample-questions and review it\"\n : \"re-pin it and review it\";\n report(\n \"knob\",\n `lines ${spellLines(pin.lines)}${of} no longer hold the answer to \"${question}\" as pinned, so ${fix}.`,\n draft,\n );\n return { position: 0 };\n }\n const [range] = fresh.ranges;\n const inFile = file === undefined ? \"\" : ` in ${file}`;\n if (fresh.state === \"current\") summary.answers.current += 1;\n else summary.answers.moved += 1;\n if (fresh.state === \"moved\" && range) {\n report(\n \"notice\",\n `the answer to \"${question}\"${inFile} moved from lines ${spellLines(pin.lines)} to ${spellLines(range)}, so manni graph fill --fields sample-questions re-pins it.`,\n draft,\n );\n } else if (fresh.state === \"ambiguous\") {\n report(\n \"warning\",\n `the answer to \"${question}\"${inFile} moved, and ${matchList(fresh.ranges)}, so pin one of them by hand.`,\n draft,\n );\n }\n const text = range ? page.body.slice(range.start - 1, range.end).join(\"\\n\") : undefined;\n const nodes = await rank(language, question);\n const answering = fresh.ranges.flatMap((r) => holdersOf(page, toFileLines(r, page.bodyLine)));\n const positions = answering.map((iri) => nodes.indexOf(iri) + 1);\n // The best-ranked node that holds the answer, else the one holding its\n // first line.\n const best = positions.reduce(\n (b, p, i) => (p >= 1 && (b.p === 0 || p < b.p) ? { p, i } : b),\n { p: 0, i: 0 },\n );\n if (best.p >= 1 && best.p <= top) return { position: best.p, ...(text === undefined ? {} : { text }) };\n const holder = answering[best.i];\n if (holder !== undefined) {\n const title = holder.includes(\"#\") ? graph.literal(holder, TITLE) : undefined;\n const target =\n file !== undefined\n ? `does not find ${describe(holder)}`\n : title === undefined\n ? \"does not find this page, whose own text answers it,\"\n : `does not find the section that answers it, § ${title},`;\n report(\"knob\", `\"${question}\" ${target} in the top ${String(top)} (${where(best.p, nodes[0])})`, draft);\n }\n return { position: best.p, ...(text === undefined ? {} : { text }) };\n };\n\n /** A question that repeats over half its answer's word pairs tests matching more than finding. */\n const copies = (question: string, said: string[], report: Report, draft: \"question\" | undefined): void => {\n const m = said.length === 0 ? undefined : copiedPairs(question, ...said);\n if (m && m.copied / m.of > COPIED_SHARE) {\n report(\n \"notice\",\n `\"${question}\" repeats ${String(m.copied)} of its ${String(m.of)} word pairs from its answer, so it tests matching words more than finding.`,\n draft,\n );\n }\n };\n\n /** Every copy of every question, for duplicates: where it is asked, and its finding's home. */\n const asked: { key: string; where: string; order: number; text: string; report: Report; draft?: \"question\" }[] = [];\n\n for (const page of pages) {\n const report = reporter({ focusNode: page.doc, path: SAMPLE_QUESTION, docs: [page.path] });\n for (const [n, q] of page.questions.entries()) {\n const drafted = q.reviewed ? undefined : (\"question\" as const);\n if (q.reviewed) summary.reviewed += 1;\n else summary.drafted += 1;\n asked.push({ key: questionKey(q.question), where: page.path, order: n, text: q.question, report, ...(drafted ? { draft: drafted } : {}) });\n if (q.answers.length === 0) summary.answers.unpinned += 1;\n const tests: number[] = [];\n // 0086's test: an unpinned question, or a confirmed one whose every\n // pin is still a draft, must find the page itself. A drafted question\n // with any pin skips it and goes straight to the pin checks, which\n // report at notice through `drafted`.\n if (q.answers.length === 0 || (q.reviewed && q.answers.every((a) => !a.reviewed))) {\n const nodes = await rank(page.language, q.question);\n const pagesFound = [...new Set(nodes.map(pageOf))];\n const position = pagesFound.indexOf(page.doc) + 1;\n tests.push(position);\n if (position < 1 || position > top) {\n report(\n \"knob\",\n `\"${q.question}\" does not find this page in the top ${String(top)} (${where(position, pagesFound[0])})`,\n drafted,\n );\n }\n }\n const said: string[] = [];\n for (const pin of q.answers) {\n const draft = drafted ?? (pin.reviewed ? undefined : \"pin\");\n summary.answers.pinned += 1;\n if (draft) summary.answers.unreviewed += 1;\n const { position, text } = await askPin(page, pin, q.question, page.language, report, draft);\n if (text !== undefined) said.push(text);\n // A drafted pin on a confirmed question is reported, not counted.\n if (draft !== \"pin\") tests.push(position);\n }\n copies(q.question, said, report, drafted);\n tally(q.reviewed, tests);\n }\n }\n\n for (const set of sets) {\n for (const [n, q] of set.questions.entries()) {\n const report = reporter({ focusNode: `${set.label}:${String(q.line)}`, docs: [set.label] });\n const drafted = q.reviewed ? undefined : (\"question\" as const);\n if (q.reviewed) summary.reviewed += 1;\n else summary.drafted += 1;\n asked.push({ key: questionKey(q.question), where: set.label, order: n, text: q.question, report, ...(drafted ? { draft: drafted } : {}) });\n // A known gap: search has no score floor, so \"finds nothing\" is no test.\n if (q.answers.length === 0) {\n summary.gaps += 1;\n continue;\n }\n const [firstAnswer] = q.answers;\n const firstPage = firstAnswer && pageAt(resolve(configDir, firstAnswer.file));\n const language =\n q.language !== undefined ? canonicalLanguageTag(q.language) : (firstPage?.language ?? UNDETERMINED);\n const tests: number[] = [];\n const said: string[] = [];\n for (const pin of q.answers) {\n const draft = drafted ?? (pin.reviewed ? undefined : \"pin\");\n summary.answers.pinned += 1;\n if (draft) summary.answers.unreviewed += 1;\n const abs = resolve(configDir, pin.file);\n const page = pageAt(abs);\n if (page === undefined) {\n if (existsSync(abs)) {\n // On disk, but in no collection the graph was built from. Its\n // freshness cannot be read without the page's graph record, so the\n // pin counts in no freshness bucket, and pinned can exceed\n // current + moved + changed by these. Its finding says why.\n const nodes = await rank(language, q.question);\n report(\"knob\", `\"${q.question}\" does not find ${pin.file} in the top ${String(top)} (${where(0, nodes[0])})`, draft);\n } else {\n summary.answers.changed += 1;\n report(\n \"knob\",\n `${pin.file}, which holds the answer to \"${q.question}\", does not exist, so re-pin or remove the question.`,\n draft,\n );\n }\n if (draft !== \"pin\") tests.push(0);\n continue;\n }\n const { position, text } = await askPin(page, pin, q.question, language, report, draft, pin.file);\n if (text !== undefined) said.push(text);\n if (draft !== \"pin\") tests.push(position);\n }\n copies(q.question, said, report, drafted);\n tally(q.reviewed, tests);\n }\n }\n\n // Duplicates: each copy after the first, in path order, names the first.\n asked.sort((a, b) => byCodeUnit(a.where, b.where) || a.order - b.order);\n const firstAt = new Map<string, string>();\n for (const copy of asked) {\n if (copy.key === \"\") continue;\n const first = firstAt.get(copy.key);\n if (first === undefined) firstAt.set(copy.key, copy.where);\n else copy.report(\"knob\", `\"${copy.text}\" is also asked on ${first}, so keep it where it is answered.`, copy.draft);\n }\n\n // The rate gate. questions.severity does not touch it.\n const threshold = settings.foundThreshold;\n const { inTop, of } = summary.found.reviewed;\n if (threshold !== null && of > 0 && (inTop / of) * 100 < threshold) {\n findings.push({\n severity: \"error\",\n message: `${String(inTop)} of ${String(of)} reviewed questions are found in the top ${String(top)} (${String(percent(inTop, of))}%), under the ${String(threshold)}% that graph.check.questions.foundThreshold asks for.`,\n focusNode: \"questions\",\n docs: [],\n });\n }\n return { findings, summary };\n}\n\n/** One answer of an exported question: the node that holds it, and its text as it reads now. */\ninterface ExportedAnswer {\n id?: string;\n file: string;\n lines?: string;\n reviewed: boolean;\n stale?: true;\n text?: string;\n}\n\n/**\n * The golden set as `graph export questions` writes it (proposal 0087 § 7d):\n * one JSON line per question, each page's in path order, then each golden-set\n * file's. An answer's `id` is the node `export search` indexes its first line\n * under, so an index built from that export returns comparable ids. Its text\n * is rendered from the pin, as the page reads now. A changed answer, or one\n * whose page is gone, is marked stale and counted.\n */\nexport async function exportSampleQuestions(\n store: Store,\n sources: string,\n view: { source: MetaViewSource; cwd: string },\n questionFiles: readonly string[],\n configDir: string,\n): Promise<{ lines: string[]; stale: number }> {\n const sets = questionFiles.map((label) => ({\n label,\n questions: readQuestionFile(resolve(configDir, label), label),\n }));\n const graph = GraphIndex.fromQuads(storeToQuads(store), Object.fromEntries(PREFIXES));\n const { pages, pageAt } = await readPages(graph, sources, view, \"exported\");\n let stale = 0;\n\n const pinned = (page: Page, file: string, pin: AnswerPin, reviewed: boolean): ExportedAnswer => {\n const fresh = freshness(page.body, pin);\n const range = fresh.state === \"changed\" ? pin.lines : (fresh.ranges[0] ?? pin.lines);\n if (fresh.state === \"changed\") stale += 1;\n const first = toFileLines({ start: range.start, end: range.start }, page.bodyLine);\n const text = page.body.slice(range.start - 1, range.end).join(\"\\n\");\n return {\n id: holdersOf(page, first)[0] ?? page.doc,\n file,\n lines: spellLines(range),\n reviewed,\n ...(fresh.state === \"changed\" ? { stale: true as const } : {}),\n ...(text === \"\" ? {} : { text }),\n };\n };\n\n const lines: string[] = [];\n const write = (\n id: string,\n question: string,\n language: string,\n reviewed: boolean,\n expected: ExportedAnswer[],\n ): void => {\n lines.push(\n JSON.stringify({ id, question, language, reviewed, answerable: expected.length > 0, expected }),\n );\n };\n\n for (const page of pages) {\n // A question asked twice on one page still gets an id of its own.\n const slugger = new GithubSlugger();\n for (const q of page.questions) {\n const expected =\n q.answers.length === 0\n ? [{ id: page.doc, file: page.path, reviewed: q.reviewed }]\n : q.answers.map((pin) => pinned(page, page.path, pin, q.reviewed && pin.reviewed));\n write(`${page.path}#${slugger.slug(q.question)}`, q.question, page.language, q.reviewed, expected);\n }\n }\n\n for (const set of sets) {\n const slugger = new GithubSlugger();\n for (const q of set.questions) {\n const expected = q.answers.map((pin): ExportedAnswer => {\n const reviewed = q.reviewed && pin.reviewed;\n const abs = resolve(configDir, pin.file);\n const page = pageAt(abs);\n if (page) return pinned(page, pin.file, pin, reviewed);\n // A page outside the graph has no node to name, and its freshness is\n // not checked, since that needs the page's graph record. A page that\n // is gone is stale.\n const gone = !existsSync(abs);\n if (gone) stale += 1;\n return { file: pin.file, lines: spellLines(pin.lines), reviewed, ...(gone ? { stale: true as const } : {}) };\n });\n const [firstAnswer] = q.answers;\n const firstPage = firstAnswer && pageAt(resolve(configDir, firstAnswer.file));\n const language =\n q.language !== undefined ? canonicalLanguageTag(q.language) : (firstPage?.language ?? UNDETERMINED);\n write(`${set.label}#${slugger.slug(q.question)}`, q.question, language, q.reviewed, expected);\n }\n }\n return { lines, stale };\n}\n","/**\n * The lexical search artifact (ADR 01019) — `graph/search.<lang>.json`, a sibling\n * of the graph rather than prose inside it. One file per language since\n * ADR 01038; this module builds the whole index and partitions it.\n *\n * The graph is an index, not a corpus (ADR 01008): sections carry only titles,\n * so a lexical index built from the graph alone cannot find anything a document\n * actually *says*. This module walks the built graph, reads each document's\n * markdown from disk (the same pattern the iiRDS projection uses for\n * renditions), and emits a deterministic JSON index the browser runtime loads in\n * one fetch.\n *\n * Granularity golden rule: **every node indexes exactly the text it owns.** A\n * Section carries its own text down to the next heading of any rank; a Document\n * carries title + description plus the prose no section covers (its preamble,\n * or its whole body when it has no sections). Duplicating would let a node\n * shadow the nodes beneath it in the rankings; carrying nothing would leave\n * that prose findable nowhere.\n *\n * Slicing reuses the runtime's own functions, so index-time and retrieval-time\n * text cannot drift — with one deliberate difference: retrieval uses\n * `sliceSection` (subtree included, because asking for a section should give\n * you its subsections), indexing uses `sectionOwnText`.\n */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { compactIri } from \"./load.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS } from \"./vocab.js\";\nimport { canonicalLanguageTag, UNDETERMINED } from \"./localizations.js\";\nimport type { GraphIndex } from \"../runtime/graph.js\";\nimport type { ContentNode } from \"../../lint/types.js\";\nimport { formatOf, mintTreeSections, parseTree } from \"./analyze.js\";\nimport {\n documentPreamble,\n sectionOccurrences,\n sectionOwnText,\n} from \"../runtime/resolve.js\";\n\nconst GRAPH_DOCUMENT = `${NS.graph}Document`;\nconst GRAPH_SECTION = `${NS.graph}Section`;\nconst SKOS_CONCEPT = `${NS.skos}Concept`;\nconst GRAPH_PATH = `${NS.graph}path`;\nconst GRAPH_LEVEL = `${NS.graph}level`;\nconst DCTERMS_TITLE = `${NS.dcterms}title`;\nconst DCTERMS_DESCRIPTION = `${NS.dcterms}description`;\nconst SKOS_PREF_LABEL = `${NS.skos}prefLabel`;\nconst SKOS_ALT_LABEL = `${NS.skos}altLabel`;\nconst DCTERMS_LANGUAGE = `${NS.dcterms}language`;\n\n/** One indexable node. Empty fields are omitted so the artifact stays tight. */\nexport interface SearchEntry {\n /** Node IRI. */\n id: string;\n /** Compacted class IRI, e.g. `graph:Section`. */\n type: string;\n title?: string;\n /** Space-joined alternative labels, deduped case-insensitively. */\n labels?: string;\n description?: string;\n /** Body text, per the granularity rule. */\n text?: string;\n}\n\nexport interface SearchIndexDoc {\n version: 1;\n entries: SearchEntry[];\n}\n\nexport interface SearchIndexOptions {\n /** Read a document's source. Defaults to reading `cwd`-relative from disk. */\n readDoc?: (path: string) => string | undefined;\n /** Warnings channel (missing sources are non-fatal — the entry loses text). */\n warnings?: string[];\n}\n\n/** Space-join labels, dropping case-insensitive duplicates, sorted. */\nfunction joinLabels(values: string[]): string | undefined {\n const seen = new Map<string, string>();\n for (const v of values) {\n const key = v.trim().toLowerCase();\n if (key && !seen.has(key)) seen.set(key, v.trim());\n }\n const out = [...seen.values()].sort(byCodeUnit);\n return out.length > 0 ? out.join(\" \") : undefined;\n}\n\n/**\n * A leading YAML frontmatter block, and the blank lines after it.\n *\n * Only a document with *no* sections gets body text, and its body is the whole\n * file — frontmatter included, unless it is stripped here. That block is\n * machinery, not prose: left in, a query for `label` or `alt-labels` matches\n * every sectionless document, and the artifact carries YAML nobody can read.\n * Section slices start at their heading, so they never see it.\n */\nconst FRONTMATTER =\n /^---[ \\t]*\\r?\\n(?:[\\s\\S]*?\\r?\\n)?(?:---|\\.\\.\\.)[ \\t]*(?:\\r?\\n|$)(?:\\r?\\n)*/;\n\nfunction stripFrontmatter(markdown: string): string {\n return markdown.replace(FRONTMATTER, \"\");\n}\n\n/** A non-Markdown document's text, per node, read from lint's tree. */\ninterface TreeText {\n /** The prose no section owns: the lead's, or the whole body when sectionless. */\n doc: string | undefined;\n /** Each section's own prose, by its anchor. */\n sections: Map<string, string>;\n}\n\n/** Content nodes' plain text, one block each, LF only. */\nfunction plainText(nodes: readonly ContentNode[]): string[] {\n return nodes\n .map((n) => n.text.replace(/\\r\\n/g, \"\\n\").trim())\n .filter((t) => t !== \"\");\n}\n\n/**\n * The text a non-Markdown document's nodes own, or undefined for Markdown and\n * MDX, which keep the line slicers their goldens pin. Sections are minted by\n * the analyzer's own function, so each text lands on the anchor `build` gave\n * that section. A section's text starts with its title, as a Markdown slice\n * starts at its heading line.\n */\nfunction treeText(source: string, path: string): TreeText | undefined {\n const format = formatOf(path);\n if (format === \"markdown\" || format === \"mdx\") return undefined;\n const minted = mintTreeSections(parseTree(source, path, format).sections);\n const sections = new Map<string, string>();\n for (const [n, section] of minted.sections.entries()) {\n const own = plainText(minted.owned[n] ?? []);\n sections.set(section.slug, [section.title, ...own].join(\"\\n\\n\"));\n }\n const lead = plainText(minted.unowned);\n return { doc: lead.length > 0 ? lead.join(\"\\n\\n\") : undefined, sections };\n}\n\n/** Drop undefined fields so entries serialize identically for equal inputs. */\nfunction entry(\n id: string,\n type: string,\n fields: Omit<SearchEntry, \"id\" | \"type\">,\n): SearchEntry {\n const out: SearchEntry = { id, type };\n if (fields.title !== undefined) out.title = fields.title;\n if (fields.labels !== undefined) out.labels = fields.labels;\n if (fields.description !== undefined) out.description = fields.description;\n if (fields.text !== undefined) out.text = fields.text;\n return out;\n}\n\nexport function buildSearchIndex(\n graph: GraphIndex,\n cwd: string,\n options: SearchIndexOptions = {},\n): SearchIndexDoc {\n const warnings = options.warnings ?? [];\n const readDoc =\n options.readDoc ??\n ((path: string): string | undefined => {\n const abs = resolve(cwd, path);\n return existsSync(abs) ? readFileSync(abs, \"utf8\") : undefined;\n });\n\n const entries: SearchEntry[] = [];\n const sourceOf = new Map<string, string | undefined>();\n const treeTextOf = new Map<string, TreeText>();\n\n // Group sections by their parent document once. Re-scanning every section per\n // document is quadratic across the corpus, and the section loop below needs\n // the same grouping anyway.\n const allSections = graph.instancesOf(GRAPH_SECTION);\n const sectionsOf = new Map<string, string[]>();\n for (const section of allSections) {\n const hash = section.indexOf(\"#\");\n if (hash < 0) continue;\n const doc = section.slice(0, hash);\n const siblings = sectionsOf.get(doc);\n if (siblings) siblings.push(section);\n else sectionsOf.set(doc, [section]);\n }\n\n // Documents. Sections resolve their slice from the parent's source, so read\n // each document once and remember it.\n for (const doc of graph.instancesOf(GRAPH_DOCUMENT)) {\n const path = graph.literal(doc, GRAPH_PATH);\n const source = path === undefined ? undefined : readDoc(path);\n sourceOf.set(doc, source);\n if (path !== undefined && source === undefined) {\n warnings.push(\n `Source not found for ${path} — indexed without body text.`,\n );\n }\n\n // Granularity rule: a section owns its slice, so a document with sections\n // keeps only the prose that belongs to no section — the preamble before the\n // first heading. Without this, that text is indexed nowhere and is\n // unfindable. A document with no sections owns its whole body.\n // Newlines normalized to LF: section slices and `documentPreamble` already\n // re-join on \"\\n\", so without this a sectionless CRLF document is the one\n // entry in the artifact carrying \"\\r\\n\".\n const tree =\n source === undefined || path === undefined\n ? undefined\n : treeText(source, path);\n if (tree) treeTextOf.set(doc, tree);\n const body =\n source === undefined\n ? undefined\n : stripFrontmatter(source).replace(/\\r\\n/g, \"\\n\");\n const text = tree\n ? tree.doc\n : body === undefined\n ? undefined\n : (sectionsOf.get(doc)?.length ?? 0) > 0\n ? documentPreamble(body)\n : body;\n\n entries.push(\n entry(doc, compactIri(GRAPH_DOCUMENT), {\n title: graph.literal(doc, DCTERMS_TITLE),\n description: graph.literal(doc, DCTERMS_DESCRIPTION),\n text,\n }),\n );\n }\n\n // Sections: title plus the slice of the parent document they own. Occurrences\n // are per-document, so compute each document's map once.\n const occurrencesOf = new Map<string, Map<string, number>>();\n for (const section of allSections) {\n const hash = section.indexOf(\"#\");\n const doc = hash < 0 ? section : section.slice(0, hash);\n const title = graph.literal(section, DCTERMS_TITLE);\n const source = sourceOf.get(doc);\n const levelText = graph.literal(section, GRAPH_LEVEL);\n const parsed =\n levelText === undefined ? NaN : Number.parseInt(levelText, 10);\n const level = Number.isNaN(parsed) ? undefined : parsed;\n\n let occurrences = occurrencesOf.get(doc);\n if (!occurrences) {\n occurrences = sectionOccurrences(graph, doc);\n occurrencesOf.set(doc, occurrences);\n }\n\n // Heading text repeats (the corpus has two `## Install`), so the section's\n // occurrence disambiguates which slice is actually its own.\n const tree = treeTextOf.get(doc);\n const text = tree\n ? tree.sections.get(section.slice(hash + 1))\n : source !== undefined && title !== undefined\n ? sectionOwnText(source, title, level, occurrences.get(section) ?? 0)\n : undefined;\n\n entries.push(entry(section, compactIri(GRAPH_SECTION), { title, text }));\n }\n\n // Concepts: label surface only — they are index nodes with no body of their\n // own, but they are worth seeding from (concept → the documents about it).\n for (const concept of graph.instancesOf(SKOS_CONCEPT)) {\n const pref = graph.literals(concept, SKOS_PREF_LABEL);\n const alt = graph.literals(concept, SKOS_ALT_LABEL);\n entries.push(\n entry(concept, compactIri(SKOS_CONCEPT), {\n title: pref[0],\n labels: joinLabels([...pref, ...alt]),\n }),\n );\n }\n\n entries.sort((a, b) => byCodeUnit(a.id, b.id));\n return { version: 1, entries };\n}\n\n/** Serialize deterministically, with the trailing newline the other emitters use. */\nexport function emitSearchIndex(doc: SearchIndexDoc): string {\n return `${JSON.stringify(doc, null, 2)}\\n`;\n}\n\n/**\n * Split one index into per-language indexes (ADR 01038).\n *\n * A document's language is the `dcterms:language` it carries; a **section takes\n * its document's**, which is containment rather than inference — a section is\n * part of exactly one document and has no language of its own. A document\n * declaring none lands in the `und` bucket.\n *\n * **Concepts belong to every locale.** A `skos:Concept` is shared vocabulary\n * minted from labels across the corpus, not a document in some language, so it\n * is replicated into each language's index rather than filed under `und`. Doing\n * otherwise had two visible costs: `--lang de` could never return a concept,\n * and a corpus whose every document declared a language still grew a phantom\n * `und` localization holding only concepts — which then made `manni graph search`\n * demand `--lang` on what is, to its author, a single-language corpus.\n *\n * Entry order inside each index is preserved, so each one is sorted for the\n * same reason the whole index was.\n */\nexport function partitionByLanguage(\n graph: GraphIndex,\n index: SearchIndexDoc,\n): Map<string, SearchIndexDoc> {\n const documentType = compactIri(GRAPH_DOCUMENT);\n const sectionType = compactIri(GRAPH_SECTION);\n\n /** The language of an entry, or undefined when it belongs to every locale. */\n const languageOf = (entry: SearchEntry): string | undefined => {\n if (entry.type !== documentType && entry.type !== sectionType) {\n return undefined;\n }\n const hash = entry.id.indexOf(\"#\");\n const doc = hash === -1 ? entry.id : entry.id.slice(0, hash);\n return languageOfDocument(graph, doc);\n };\n\n const out = new Map<string, SearchIndexDoc>();\n const shared: SearchEntry[] = [];\n for (const entry of index.entries) {\n const language = languageOf(entry);\n if (language === undefined) {\n shared.push(entry);\n continue;\n }\n const bucket = out.get(language);\n if (bucket) bucket.entries.push(entry);\n else out.set(language, { version: 1, entries: [entry] });\n }\n\n // A corpus of nothing but concepts still needs somewhere to put them.\n if (out.size === 0 && shared.length > 0) {\n out.set(UNDETERMINED, { version: 1, entries: [] });\n }\n for (const bucket of out.values()) {\n bucket.entries.push(...shared);\n bucket.entries.sort((a, b) => byCodeUnit(a.id, b.id));\n }\n return out;\n}\n\n/**\n * A document's language, canonically spelled, or `und`. `derive` already\n * writes the canonical tag, so this matters for a graph written by hand: one\n * locale in two spellings would otherwise become two indexes.\n */\nfunction languageOfDocument(graph: GraphIndex, doc: string): string {\n const tag = graph.literal(doc, DCTERMS_LANGUAGE);\n return tag === undefined ? UNDETERMINED : canonicalLanguageTag(tag);\n}\n\n/** Documents (not sections) per language, for the manifest's counts. */\nexport function documentsByLanguage(graph: GraphIndex): Map<string, number> {\n const out = new Map<string, number>();\n for (const doc of graph.instancesOf(GRAPH_DOCUMENT)) {\n const language = languageOfDocument(graph, doc);\n out.set(language, (out.get(language) ?? 0) + 1);\n }\n return out;\n}\n","/**\n * Content resolution (ADR 01018): graph node → the text it stands for.\n *\n * The graph is an index over documents ([ADR 01008](../../adrs/01008-graph-as-index-not-corpus.md)),\n * so retrieval must go back to the source to get text. The seam is a\n * `ContentResolver`; the shipped implementation uses `fetch`, which works\n * unchanged in browsers and in Node ≥18, and is injectable for tests.\n *\n * Section nodes (`doc.md#slug`) resolve by fetching the parent document and\n * slicing it at the heading whose text matches the section's `dcterms:title`\n * — so no line-span predicates need to be added to the graph.\n *\n * Platform-neutral: no `node:` imports, no npm dependencies.\n */\nimport { NS } from \"../core/vocab.js\";\nimport type { GraphIndex } from \"./graph.js\";\nimport type { QueryTrace } from \"./trace.js\";\n\nconst GRAPH_PATH = `${NS.graph}path`;\nconst DCTERMS_TITLE = `${NS.dcterms}title`;\nconst DCTERMS_HAS_PART = `${NS.dcterms}hasPart`;\nconst GRAPH_LEVEL = `${NS.graph}level`;\nconst GRAPH_ORDER = `${NS.graph}order`;\n\nexport interface ResolvedContent {\n iri: string;\n text: string;\n sourceUrl: string;\n title?: string;\n}\n\nexport interface ContentResolver {\n /** Text for a node, or undefined when the node has no content. */\n resolve(iri: string): Promise<ResolvedContent | undefined>;\n}\n\ntype FetchLike = (\n url: string,\n) => Promise<{ ok: boolean; status: number; text(): Promise<string> }>;\n\nexport interface FetchResolverOptions {\n /** Prefix joined to each `graph:path`, e.g. \"https://site/raw/\". */\n baseUrl?: string;\n /** Full control over path → URL. Overrides `baseUrl`. */\n pathToUrl?: (path: string) => string;\n /** Injectable fetch (defaults to the global). */\n fetch?: FetchLike;\n /** Record resolutions here. */\n trace?: QueryTrace;\n}\n\n/** Split a section IRI into its document IRI and fragment. */\nexport function splitFragment(iri: string): { doc: string; fragment?: string } {\n const hash = iri.indexOf(\"#\");\n return hash < 0\n ? { doc: iri }\n : { doc: iri.slice(0, hash), fragment: iri.slice(hash + 1) };\n}\n\n/**\n * Mark every line that sits inside a fenced code block (including the fence\n * delimiters themselves). Without this, a shell comment in a code sample —\n * `# Set the API key` — reads as an h1 and truncates the surrounding section,\n * which silently drops most of the retrieved content.\n *\n * CommonMark rules, minus the ones a heading scan cannot observe: a fence opens\n * on 3+ backticks or tildes indented at most 3 spaces, a backtick fence's info\n * string may not contain a backtick, and it closes on a delimiter of the same\n * character that is at least as long and carries no info string. An unclosed\n * fence runs to end of document.\n */\nfunction fencedLines(lines: string[]): boolean[] {\n const mask = new Array<boolean>(lines.length).fill(false);\n let open: string | undefined;\n for (const [i, line] of lines.entries()) {\n const m = /^ {0,3}(`{3,}|~{3,})(.*)$/.exec(line);\n // Both groups are mandatory in the pattern, so a match carries both.\n // Requiring them is the check that proves it, and it replaces the bare\n // `m &&` the branches already tested — no condition is added, only\n // sharpened.\n const delimiter = m?.[1];\n const info = m?.[2];\n const isFence = delimiter !== undefined && info !== undefined;\n if (open === undefined) {\n if (isFence && !(delimiter.startsWith(\"`\") && info.includes(\"`\"))) {\n open = delimiter;\n mask[i] = true;\n }\n continue;\n }\n mask[i] = true;\n if (\n isFence &&\n delimiter[0] === open[0] &&\n delimiter.length >= open.length &&\n info.trim() === \"\"\n ) {\n open = undefined;\n }\n }\n return mask;\n}\n\n/** One heading as the source spells it, located by the line it starts on. */\ninterface SourceHeading {\n /** First line: the `#` line, or a setext heading's first line of text. */\n start: number;\n level: number;\n /** The heading's raw inline text, markdown and all. */\n text: string;\n}\n\nconst ATX = /^ {0,3}(#{1,6})(?:[ \\t]+(.*?))?[ \\t]*$/;\nconst SETEXT_UNDERLINE = /^ {0,3}(=+|-+)[ \\t]*$/;\n\n/**\n * Whether a line can be paragraph text, which a setext underline turns into a\n * heading. A blank line, an ATX heading, a list item, a block quote, a\n * thematic break and indented code cannot.\n */\nfunction isParagraphLine(line: string): boolean {\n if (line.trim() === \"\") return false;\n if (ATX.test(line)) return false;\n if (/^ {0,3}([-+*]|\\d{1,9}[.)])([ \\t]|$)/.test(line)) return false;\n if (/^ {0,3}>/.test(line)) return false;\n if (/^ {0,3}([-*_])([ \\t]*\\1){2,}[ \\t]*$/.test(line)) return false;\n return !/^ {4}/.test(line);\n}\n\n/**\n * How many leading lines a YAML frontmatter block takes, delimiters included.\n * Its closing `---` follows a line of text, so without this the scan would\n * read the last frontmatter key as a setext heading.\n */\nfunction frontmatterLength(lines: string[]): number {\n if (lines[0]?.trim() !== \"---\") return 0;\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i]?.trim();\n if (line === \"---\" || line === \"...\") return i + 1;\n }\n return 0;\n}\n\n/**\n * Every heading in a markdown source, in order. ATX headings may sit up to\n * three spaces in and lose any closing `#` run. Setext headings are\n * underlined with `=` or `-`. Fenced code and frontmatter hold none.\n *\n * Line-based, so a shape remark reads and this does not is possible. The\n * common ones are covered, and a miss leaves one section unindexed.\n */\nfunction sourceHeadings(lines: string[]): SourceHeading[] {\n const fenced = fencedLines(lines);\n const skip = frontmatterLength(lines);\n const headings: SourceHeading[] = [];\n /** First line of the paragraph the scan is inside, or -1. */\n let paragraph = -1;\n for (const [i, line] of lines.entries()) {\n if (i < skip || fenced[i]) {\n paragraph = -1;\n continue;\n }\n const atx = ATX.exec(line);\n const hashes = atx?.[1];\n if (hashes !== undefined) {\n // A closing run is `#`s after whitespace, or the whole content.\n const text = (atx?.[2] ?? \"\").replace(/(^|[ \\t]+)#+$/, \"\");\n headings.push({ start: i, level: hashes.length, text });\n paragraph = -1;\n continue;\n }\n const underline = SETEXT_UNDERLINE.exec(line)?.[1];\n if (underline !== undefined && paragraph >= 0) {\n headings.push({\n start: paragraph,\n level: underline.startsWith(\"=\") ? 1 : 2,\n text: lines.slice(paragraph, i).join(\"\\n\"),\n });\n paragraph = -1;\n continue;\n }\n if (isParagraphLine(line)) {\n if (paragraph < 0) paragraph = i;\n } else {\n paragraph = -1;\n }\n }\n return headings;\n}\n\nconst ENTITIES: Record<string, string> = {\n amp: \"&\",\n lt: \"<\",\n gt: \">\",\n quot: '\"',\n apos: \"'\",\n nbsp: \" \",\n};\n\n/** Decode the character references a heading is likely to carry. */\nfunction decodeEntities(text: string): string {\n return text.replace(\n /&(#x[0-9a-f]+|#[0-9]+|[a-z]+);/gi,\n (whole, name: string) => {\n if (name.startsWith(\"#\")) {\n const hex = name[1] === \"x\" || name[1] === \"X\";\n const code = Number.parseInt(name.slice(hex ? 2 : 1), hex ? 16 : 10);\n return Number.isNaN(code) || code > 0x10ffff\n ? whole\n : String.fromCodePoint(code);\n }\n return ENTITIES[name.toLowerCase()] ?? whole;\n },\n );\n}\n\n/**\n * The key a heading is matched by, from either side. One side is the\n * plain-text title the build recorded, the other the source text after\n * `stripInline`. Markup characters go, whitespace collapses, and case folds.\n * Both sides pass through it, so a character it drops cannot make them differ.\n */\nexport function headingKey(text: string): string {\n return text\n .replace(/[`*_~\\\\[\\]]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim()\n .toLowerCase();\n}\n\n/**\n * Raw heading source to the text remark reads from it. Links and images keep\n * their text, autolinks their target, and character references decode.\n */\nfunction stripInline(raw: string): string {\n return decodeEntities(\n raw\n .replace(/!?\\[([^\\]]*)\\]\\((?:[^()]|\\([^()]*\\))*\\)/g, \"$1\")\n .replace(/!?\\[([^\\]]*)\\]\\[[^\\]]*\\]/g, \"$1\")\n .replace(/<((?:https?|mailto):[^>\\s]+)>/gi, \"$1\"),\n );\n}\n\n/**\n * Sections of a document in true document order, reconstructed from the\n * `dcterms:hasPart` tree ordered by `graph:order` within each parent.\n *\n * Needed because heading text is not unique: a document with two `## Install`\n * headings produces two section nodes, and matching by title alone would give\n * both the *first* heading's text — wrong content under a confident citation.\n */\nexport function documentSectionOrder(\n graph: GraphIndex,\n docIri: string,\n): string[] {\n const ordered: string[] = [];\n const seen = new Set<string>();\n\n const childrenOf = (iri: string): string[] =>\n graph\n .out(iri, DCTERMS_HAS_PART)\n .map((e) => e.target)\n .sort((a, b) => {\n const oa = Number.parseInt(graph.literal(a, GRAPH_ORDER) ?? \"\", 10);\n const ob = Number.parseInt(graph.literal(b, GRAPH_ORDER) ?? \"\", 10);\n if (Number.isNaN(oa) || Number.isNaN(ob) || oa === ob) {\n return a < b ? -1 : a > b ? 1 : 0;\n }\n return oa - ob;\n });\n\n const walk = (iri: string): void => {\n for (const child of childrenOf(iri)) {\n if (seen.has(child)) continue;\n seen.add(child);\n ordered.push(child);\n walk(child);\n }\n };\n walk(docIri);\n return ordered;\n}\n\n/**\n * Occurrence number of every section of a document, in one walk: section IRI →\n * how many earlier sections share its heading text and level.\n *\n * Batched because the per-section form is quadratic — a document with N\n * sections would otherwise rebuild the whole `hasPart` order N times, once per\n * section indexed or resolved.\n */\nexport function sectionOccurrences(\n graph: GraphIndex,\n docIri: string,\n): Map<string, number> {\n const occurrences = new Map<string, number>();\n // title → level → how many carrying that pair have been seen so far. Nested\n // rather than a joined key, so no separator has to be safe in either field.\n const counts = new Map<string, Map<string, number>>();\n\n for (const section of documentSectionOrder(graph, docIri)) {\n const rawTitle = graph.literal(section, DCTERMS_TITLE);\n if (rawTitle === undefined) {\n occurrences.set(section, 0);\n continue;\n }\n // Keyed exactly the way `sliceSection` matches headings, by `headingKey`.\n // Keyed by the raw title instead, a document with `## Install`\n // and `## install` gives both sections occurrence 0, and the second one\n // then slices the first heading: wrong content under a confident citation.\n const title = headingKey(rawTitle);\n const level = graph.literal(section, GRAPH_LEVEL) ?? \"\";\n let byLevel = counts.get(title);\n if (!byLevel) {\n byLevel = new Map();\n counts.set(title, byLevel);\n }\n const seen = byLevel.get(level) ?? 0;\n occurrences.set(section, seen);\n byLevel.set(level, seen + 1);\n }\n return occurrences;\n}\n\n/**\n * Which occurrence of its heading text a section is (0-based) — the number of\n * earlier same-title, same-level sections in the same document. A section the\n * `hasPart` tree does not reach counts as the first (0).\n */\nexport function sectionOccurrence(\n graph: GraphIndex,\n sectionIri: string,\n): number {\n const { doc } = splitFragment(sectionIri);\n return sectionOccurrences(graph, doc).get(sectionIri) ?? 0;\n}\n\n/**\n * The prose before a document's first heading — the text that belongs to no\n * section, and so would otherwise be indexed nowhere in a document that has\n * sections.\n *\n * Fence-aware for the same reason `sliceSection` is: a `#` comment inside a\n * leading code block is not a heading, and treating it as one would cut the\n * preamble short. Frontmatter is *not* stripped here — the caller decides,\n * since only the search index cares about that.\n */\nexport function documentPreamble(markdown: string): string | undefined {\n const lines = markdown.split(/\\r?\\n/);\n const end = sourceHeadings(lines)[0]?.start ?? lines.length;\n const text = lines.slice(0, end).join(\"\\n\").trim();\n return text === \"\" ? undefined : text;\n}\n\n/**\n * Slice a markdown document at the heading whose text matches `title`,\n * returning that heading through to the next heading of the same or higher\n * rank. Returns undefined when no such heading exists. Handles CRLF, and\n * ignores `#` lines inside fenced code blocks.\n *\n * `occurrence` selects among repeated headings (0 = the first). Heading text is\n * not unique, so callers with a specific section node in hand should pass\n * `sectionOccurrence(graph, iri)` rather than defaulting to the first match.\n */\nexport function sliceSection(\n markdown: string,\n title: string,\n level?: number,\n occurrence = 0,\n): string | undefined {\n return slice(markdown, title, level, occurrence, false);\n}\n\n/**\n * The text a section *owns*: its heading down to the next heading of **any**\n * rank, so nested subsections are excluded.\n *\n * `sliceSection` keeps the subtree because that is what retrieval wants — ask\n * for \"Configuration\" and you should get its subsections too. Indexing wants\n * the opposite: with the subtree, a parent section matches everything its\n * children match and outranks them, so an H1 section shadows every heading\n * beneath it. Same granularity rule as Document vs Section, one level down.\n */\nexport function sectionOwnText(\n markdown: string,\n title: string,\n level?: number,\n occurrence = 0,\n): string | undefined {\n return slice(markdown, title, level, occurrence, true);\n}\n\n/**\n * The file lines `sectionOwnText` slices, 1-based and inclusive: the heading\n * down to the line before the next heading of any rank. `graph check` maps a\n * sample question's pinned answer onto the section that owns it with this.\n */\nexport function sectionOwnLines(\n markdown: string,\n title: string,\n level?: number,\n occurrence = 0,\n): { start: number; end: number } | undefined {\n const span = locate(markdown.split(/\\r?\\n/), title, level, occurrence, true);\n return span === undefined ? undefined : { start: span.start + 1, end: span.end };\n}\n\nfunction slice(\n markdown: string,\n title: string,\n level: number | undefined,\n occurrence: number,\n ownTextOnly: boolean,\n): string | undefined {\n const lines = markdown.split(/\\r?\\n/);\n const span = locate(lines, title, level, occurrence, ownTextOnly);\n if (span === undefined) return undefined;\n return lines.slice(span.start, span.end).join(\"\\n\").trimEnd();\n}\n\n/** The 0-based, end-exclusive line span of a section's slice. */\nfunction locate(\n lines: string[],\n title: string,\n level: number | undefined,\n occurrence: number,\n ownTextOnly: boolean,\n): { start: number; end: number } | undefined {\n const headings = sourceHeadings(lines);\n const wanted = headingKey(title);\n let remaining = occurrence;\n let found = -1;\n\n for (const [n, heading] of headings.entries()) {\n if (level !== undefined && heading.level !== level) continue;\n if (headingKey(stripInline(heading.text)) !== wanted) continue;\n if (remaining > 0) {\n remaining -= 1;\n continue;\n }\n found = n;\n break;\n }\n const match = headings[found];\n if (match === undefined) return undefined;\n\n const next = headings\n .slice(found + 1)\n .find((h) => ownTextOnly || h.level <= match.level);\n return { start: match.start, end: next?.start ?? lines.length };\n}\n\n/**\n * A resolver that fetches document sources over HTTP. Documents map through\n * `graph:path`; sections slice their parent document by heading.\n */\nexport function createFetchResolver(\n graph: GraphIndex,\n options: FetchResolverOptions = {},\n): ContentResolver {\n const doFetch: FetchLike =\n options.fetch ?? ((url: string) => globalThis.fetch(url));\n const toUrl =\n options.pathToUrl ?? ((path: string) => `${options.baseUrl ?? \"\"}${path}`);\n const cache = new Map<string, Promise<string | undefined>>();\n // `assemble` resolves many sections of the same document; the occurrence walk\n // is per-document, so compute it once and reuse it.\n const occurrenceCache = new Map<string, Map<string, number>>();\n\n const occurrenceOf = (docIri: string, sectionIri: string): number => {\n let map = occurrenceCache.get(docIri);\n if (!map) {\n map = sectionOccurrences(graph, docIri);\n occurrenceCache.set(docIri, map);\n }\n return map.get(sectionIri) ?? 0;\n };\n\n const fetchDoc = (url: string): Promise<string | undefined> => {\n let pending = cache.get(url);\n if (!pending) {\n pending = doFetch(url)\n .then((r) => (r.ok ? r.text() : undefined))\n .catch(() => undefined);\n cache.set(url, pending);\n }\n return pending;\n };\n\n return {\n async resolve(iri: string): Promise<ResolvedContent | undefined> {\n const { doc, fragment } = splitFragment(iri);\n const path = graph.literal(doc, GRAPH_PATH);\n if (!path) return undefined;\n\n const sourceUrl = toUrl(path);\n const body = await fetchDoc(sourceUrl);\n const title = graph.literal(iri, DCTERMS_TITLE);\n\n if (body === undefined) {\n options.trace?.resolutions.push({\n iri,\n sourceUrl,\n ok: false,\n error: \"fetch failed\",\n });\n return undefined;\n }\n\n let text = body;\n if (fragment) {\n const levelText = graph.literal(iri, GRAPH_LEVEL);\n const level = levelText ? Number.parseInt(levelText, 10) : undefined;\n const slice =\n title === undefined\n ? undefined\n : sliceSection(\n body,\n title,\n Number.isNaN(level) ? undefined : level,\n occurrenceOf(doc, iri),\n );\n if (slice === undefined) {\n options.trace?.resolutions.push({\n iri,\n sourceUrl,\n ok: false,\n error: \"section heading not found\",\n });\n return undefined;\n }\n text = slice;\n }\n\n options.trace?.resolutions.push({ iri, sourceUrl, ok: true });\n return { iri, text, sourceUrl, title };\n },\n };\n}\n","/**\n * `GraphIndex` — the browser-native in-memory graph (ADR 01018).\n *\n * Built from `graph.jsonld` (the Phase 6 export) with **no RDF parser**: that\n * artifact is plain `JSON.parse`-able, deterministically sorted, and free of\n * blank nodes, so a `Map`-based adjacency index is all the runtime needs. Node\n * callers can also build from quads (`fromQuads`) so the CLI can read Turtle.\n *\n * Platform-neutral: no `node:` imports, no npm dependencies, no I/O — the\n * caller supplies the bytes. Type-only imports are erased at build time.\n *\n * Every accessor returns deterministically sorted results, so traversal order\n * (and therefore the trace) is byte-stable for a given graph.\n */\nimport type { Quad } from \"../core/derive.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\nimport { RDF_TYPE } from \"../core/vocab.js\";\n\n/** An object value: an IRI reference or a literal. */\nexport type Value =\n | { kind: \"iri\"; value: string }\n | { kind: \"literal\"; value: string; datatype?: string; language?: string };\n\nexport interface GraphNode {\n id: string;\n /** Full class IRIs, sorted. */\n types: string[];\n /** Full predicate IRI → values, in insertion-normalized sorted order. */\n props: Map<string, Value[]>;\n}\n\n/** The parsed shape of a `graph.jsonld` document. */\ninterface JsonLdDoc {\n \"@context\"?: Record<string, string>;\n \"@graph\"?: unknown[];\n}\n\nconst XSD_STRING = \"http://www.w3.org/2001/XMLSchema#string\";\n\nfunction compareValues(a: Value, b: Value): number {\n if (a.kind !== b.kind) return a.kind === \"iri\" ? -1 : 1;\n const v = byCodeUnit(a.value, b.value);\n if (v !== 0) return v;\n const da = a.kind === \"literal\" ? (a.datatype ?? \"\") : \"\";\n const db = b.kind === \"literal\" ? (b.datatype ?? \"\") : \"\";\n const la = a.kind === \"literal\" ? (a.language ?? \"\") : \"\";\n const lb = b.kind === \"literal\" ? (b.language ?? \"\") : \"\";\n return byCodeUnit(da, db) || byCodeUnit(la, lb);\n}\n\nexport class GraphIndex {\n private readonly nodes = new Map<string, GraphNode>();\n /** subject → predicate → object IRIs (sorted). */\n private readonly outbound = new Map<string, Map<string, string[]>>();\n /** object → predicate → subject IRIs (sorted). */\n private readonly inbound = new Map<string, Map<string, string[]>>();\n /** class IRI → instance IRIs (sorted). */\n private readonly byType = new Map<string, string[]>();\n /** prefix → namespace, from the artifact's own `@context`. */\n readonly context: Record<string, string>;\n\n private constructor(context: Record<string, string>) {\n this.context = context;\n }\n\n /**\n * Build from a `graph.jsonld` document — a JSON string or the parsed object.\n * CURIE keys and `@type` values are expanded using the document's own\n * `@context`, so the index is self-describing.\n */\n static fromJsonLd(input: string | object): GraphIndex {\n const doc = (\n typeof input === \"string\" ? (JSON.parse(input) as JsonLdDoc) : input\n ) as JsonLdDoc;\n const context = doc[\"@context\"] ?? {};\n const index = new GraphIndex({ ...context });\n for (const raw of doc[\"@graph\"] ?? []) {\n index.addJsonLdNode(raw as Record<string, unknown>);\n }\n index.finalize();\n return index;\n }\n\n /** Build from dockg's internal quad shape (the Node/CLI path). */\n static fromQuads(quads: Quad[], context: Record<string, string> = {}) {\n const index = new GraphIndex({ ...context });\n for (const q of quads) {\n const o = q.o;\n const value: Value =\n o.kind === \"iri\"\n ? { kind: \"iri\", value: o.value }\n : o.language\n ? { kind: \"literal\", value: o.value, language: o.language }\n : o.datatype && o.datatype !== XSD_STRING\n ? { kind: \"literal\", value: o.value, datatype: o.datatype }\n : { kind: \"literal\", value: o.value };\n index.addTriple(q.s, q.p, value);\n }\n index.finalize();\n return index;\n }\n\n /** Expand a CURIE (`dcterms:title`) to a full IRI using `@context`. */\n expand(term: string): string {\n const colon = term.indexOf(\":\");\n if (colon <= 0) return term;\n const ns = this.context[term.slice(0, colon)];\n return ns ? `${ns}${term.slice(colon + 1)}` : term;\n }\n\n /** Compact a full IRI to a CURIE when a context namespace matches. */\n compact(iri: string): string {\n let best = iri;\n let bestNs = \"\";\n for (const [prefix, ns] of Object.entries(this.context)) {\n if (\n iri.startsWith(ns) &&\n iri.length > ns.length &&\n ns.length > bestNs.length\n ) {\n best = `${prefix}:${iri.slice(ns.length)}`;\n bestNs = ns;\n }\n }\n return best;\n }\n\n private addJsonLdNode(raw: Record<string, unknown>): void {\n const id = typeof raw[\"@id\"] === \"string\" ? this.expand(raw[\"@id\"]) : \"\";\n if (!id) return;\n this.ensureNode(id);\n\n const rawTypes = raw[\"@type\"];\n for (const t of toArray(rawTypes)) {\n if (typeof t === \"string\") {\n this.addTriple(id, RDF_TYPE, { kind: \"iri\", value: this.expand(t) });\n }\n }\n\n for (const [key, rawValue] of Object.entries(raw)) {\n if (key === \"@id\" || key === \"@type\") continue;\n const predicate = this.expand(key);\n for (const v of toArray(rawValue)) {\n const value = this.toValue(v);\n if (value) this.addTriple(id, predicate, value);\n }\n }\n }\n\n private toValue(v: unknown): Value | undefined {\n if (typeof v === \"string\") return { kind: \"literal\", value: v };\n if (typeof v === \"number\" || typeof v === \"boolean\") {\n return { kind: \"literal\", value: String(v) };\n }\n if (v && typeof v === \"object\") {\n const o = v as Record<string, unknown>;\n if (typeof o[\"@id\"] === \"string\") {\n return { kind: \"iri\", value: this.expand(o[\"@id\"]) };\n }\n if (o[\"@value\"] !== undefined) {\n const raw = o[\"@value\"];\n // JSON.stringify spells a number or boolean the way String() would,\n // and gives an object a lexical form instead of \"[object Object]\".\n const lexical = typeof raw === \"string\" ? raw : JSON.stringify(raw);\n if (typeof o[\"@language\"] === \"string\") {\n return { kind: \"literal\", value: lexical, language: o[\"@language\"] };\n }\n const dt =\n typeof o[\"@type\"] === \"string\" ? this.expand(o[\"@type\"]) : undefined;\n return dt && dt !== XSD_STRING\n ? { kind: \"literal\", value: lexical, datatype: dt }\n : { kind: \"literal\", value: lexical };\n }\n }\n return undefined;\n }\n\n private ensureNode(id: string): GraphNode {\n let node = this.nodes.get(id);\n if (!node) {\n node = { id, types: [], props: new Map() };\n this.nodes.set(id, node);\n }\n return node;\n }\n\n private addTriple(s: string, p: string, o: Value): void {\n const node = this.ensureNode(s);\n let values = node.props.get(p);\n if (!values) {\n values = [];\n node.props.set(p, values);\n }\n values.push(o);\n\n if (p === RDF_TYPE && o.kind === \"iri\") {\n node.types.push(o.value);\n const instances = this.byType.get(o.value);\n if (instances) instances.push(s);\n else this.byType.set(o.value, [s]);\n }\n\n if (o.kind === \"iri\") {\n addEdge(this.outbound, s, p, o.value);\n addEdge(this.inbound, o.value, p, s);\n // Referenced-only IRIs still resolve as (empty) nodes.\n this.ensureNode(o.value);\n }\n }\n\n /** Sort every collection so traversal order is deterministic. */\n private finalize(): void {\n for (const node of this.nodes.values()) {\n node.types.sort(byCodeUnit);\n for (const values of node.props.values()) values.sort(compareValues);\n }\n for (const instances of this.byType.values()) instances.sort(byCodeUnit);\n for (const map of [this.outbound, this.inbound]) {\n for (const preds of map.values()) {\n for (const targets of preds.values()) targets.sort(byCodeUnit);\n }\n }\n }\n\n /** Every node IRI, sorted. */\n ids(): string[] {\n return [...this.nodes.keys()].sort(byCodeUnit);\n }\n\n size(): number {\n return this.nodes.size;\n }\n\n node(iri: string): GraphNode | undefined {\n return this.nodes.get(iri);\n }\n\n has(iri: string): boolean {\n return this.nodes.has(iri);\n }\n\n /** Class IRIs of a node, sorted. */\n types(iri: string): string[] {\n return this.nodes.get(iri)?.types ?? [];\n }\n\n /** Instances of a class, sorted. */\n instancesOf(classIri: string): string[] {\n return this.byType.get(classIri) ?? [];\n }\n\n /** All values for a predicate, sorted. */\n values(iri: string, predicate: string): Value[] {\n return this.nodes.get(iri)?.props.get(predicate) ?? [];\n }\n\n /** Literal lexical forms for a predicate, sorted. */\n literals(iri: string, predicate: string): string[] {\n return this.values(iri, predicate)\n .filter((v) => v.kind === \"literal\")\n .map((v) => v.value);\n }\n\n /** The first literal for a predicate, if any. */\n literal(iri: string, predicate: string): string | undefined {\n return this.literals(iri, predicate)[0];\n }\n\n /** Outbound IRI targets: all predicates, or one. Sorted. */\n out(\n iri: string,\n predicate?: string,\n ): Array<{ predicate: string; target: string }> {\n return edges(this.outbound, iri, predicate);\n }\n\n /** Inbound IRI sources (who points at this node). Sorted. */\n in(\n iri: string,\n predicate?: string,\n ): Array<{ predicate: string; target: string }> {\n return edges(this.inbound, iri, predicate);\n }\n}\n\nfunction addEdge(\n map: Map<string, Map<string, string[]>>,\n key: string,\n predicate: string,\n target: string,\n): void {\n let preds = map.get(key);\n if (!preds) {\n preds = new Map();\n map.set(key, preds);\n }\n const targets = preds.get(predicate);\n if (targets) targets.push(target);\n else preds.set(predicate, [target]);\n}\n\nfunction edges(\n map: Map<string, Map<string, string[]>>,\n iri: string,\n predicate?: string,\n): Array<{ predicate: string; target: string }> {\n const preds = map.get(iri);\n if (!preds) return [];\n const out: Array<{ predicate: string; target: string }> = [];\n const keys = predicate ? [predicate] : [...preds.keys()].sort(byCodeUnit);\n for (const p of keys) {\n for (const target of preds.get(p) ?? []) out.push({ predicate: p, target });\n }\n return out;\n}\n\nfunction toArray(v: unknown): unknown[] {\n if (v === undefined || v === null) return [];\n return Array.isArray(v) ? v : [v];\n}\n"],"mappings":"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","names":["readFileSync","Parser","Store","Store","readFileSync","Parser","edges","existsSync","readFileSync","join","entry","readFileSync","join","existsSync","entry","createHash","existsSync","readFileSync","join","resolve","existsSync","readFileSync","resolve","slice","GRAPH_PATH","GRAPH_LEVEL","DCTERMS_TITLE","resolve","existsSync","readFileSync","entry","XSD_STRING","join","existsSync","readFileSync","entry","resolve","createHash","of"]}
@@ -15,7 +15,7 @@ import {
15
15
  paragraphAfter,
16
16
  parseSrc,
17
17
  ruleId
18
- } from "./chunk-PK7EKJ5T.js";
18
+ } from "./chunk-24AJK2RG.js";
19
19
  import {
20
20
  findWindows,
21
21
  hashLines,
@@ -24,10 +24,10 @@ import {
24
24
  spellLines,
25
25
  toBodyLines,
26
26
  toFileLines
27
- } from "./chunk-KBG463UK.js";
27
+ } from "./chunk-SMHAYK6I.js";
28
28
  import {
29
29
  isErrorSeverity
30
- } from "./chunk-G7XD4QH5.js";
30
+ } from "./chunk-RGLFV4KO.js";
31
31
 
32
32
  // src/cite/core/spell.ts
33
33
  function shortPin(integrity) {
@@ -619,4 +619,4 @@ export {
619
619
  errorSite,
620
620
  toValidationResult
621
621
  };
622
- //# sourceMappingURL=chunk-RZVCWX5R.js.map
622
+ //# sourceMappingURL=chunk-AYVKN3PG.js.map