@hawkeyexl/manni 4.5.0 → 4.6.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 (215) hide show
  1. package/README.md +1 -1
  2. package/dist/batch-OZOACN4G.js +41 -0
  3. package/dist/build-Z5VOVADH.js +32 -0
  4. package/dist/calibrate-TZYT42DR.js +36 -0
  5. package/dist/capture-SL4MNDDP.js +34 -0
  6. package/dist/check-5OMA42Y6.js +26 -0
  7. package/dist/{check-ESNS7ZBC.js → check-OAJWC3WD.js} +7 -5
  8. package/dist/{check-RQIIIURI.js → check-PKY7KTQE.js} +13 -14
  9. package/dist/check-WB2QDHJQ.js +880 -0
  10. package/dist/check-WB2QDHJQ.js.map +1 -0
  11. package/dist/{chunk-F2OVHJNC.js → chunk-2JFPBZJK.js} +11 -11
  12. package/dist/{chunk-CP4ZM43V.js → chunk-2KRB3EG7.js} +2 -2
  13. package/dist/{chunk-QLUMKWQQ.js → chunk-2M6DVNI5.js} +10 -6
  14. package/dist/{chunk-QLUMKWQQ.js.map → chunk-2M6DVNI5.js.map} +1 -1
  15. package/dist/{chunk-HQFVJDEN.js → chunk-3NWX34ZI.js} +19 -19
  16. package/dist/{chunk-TCC737IS.js → chunk-5G53XATW.js} +4 -4
  17. package/dist/{chunk-B7XUEQF3.js → chunk-6KKZXB2O.js} +7 -5
  18. package/dist/{chunk-B7XUEQF3.js.map → chunk-6KKZXB2O.js.map} +1 -1
  19. package/dist/{chunk-SNEHX4VE.js → chunk-733Y2STG.js} +2 -2
  20. package/dist/{chunk-ELZ2IIOF.js → chunk-73TC4DYH.js} +2 -2
  21. package/dist/{chunk-QY3DOZMS.js → chunk-7WRP5FFP.js} +4 -4
  22. package/dist/{chunk-3R5Y3XOL.js → chunk-APKH2T6E.js} +29 -591
  23. package/dist/chunk-APKH2T6E.js.map +1 -0
  24. package/dist/{chunk-FLF6AECQ.js → chunk-B3TS4WRM.js} +17 -15
  25. package/dist/{chunk-FLF6AECQ.js.map → chunk-B3TS4WRM.js.map} +1 -1
  26. package/dist/chunk-BWCWTHYS.js +146 -0
  27. package/dist/chunk-BWCWTHYS.js.map +1 -0
  28. package/dist/{chunk-C6HZ6C5T.js → chunk-C3B2VJNC.js} +2 -2
  29. package/dist/{chunk-NN4ASVTY.js → chunk-C73RSUIC.js} +4 -4
  30. package/dist/chunk-CU57HT2E.js +116 -0
  31. package/dist/chunk-CU57HT2E.js.map +1 -0
  32. package/dist/chunk-CWXZ2MRT.js +222 -0
  33. package/dist/chunk-CWXZ2MRT.js.map +1 -0
  34. package/dist/{chunk-GAZFKZHM.js → chunk-DC5DDJVE.js} +6 -6
  35. package/dist/{chunk-52PDIZKV.js → chunk-ECVQNGTH.js} +3 -3
  36. package/dist/chunk-FLAO4ZS3.js +502 -0
  37. package/dist/chunk-FLAO4ZS3.js.map +1 -0
  38. package/dist/chunk-FQGLRJGX.js +174 -0
  39. package/dist/chunk-FQGLRJGX.js.map +1 -0
  40. package/dist/{chunk-XWFNO5PO.js → chunk-GAJIJKET.js} +3 -3
  41. package/dist/{chunk-QCBICNKC.js → chunk-GREQKO6M.js} +202 -54
  42. package/dist/chunk-GREQKO6M.js.map +1 -0
  43. package/dist/chunk-HX44GB4Z.js +30 -0
  44. package/dist/chunk-HX44GB4Z.js.map +1 -0
  45. package/dist/{chunk-7ZUCEMCY.js → chunk-IY7NYNPZ.js} +9 -11
  46. package/dist/{chunk-7ZUCEMCY.js.map → chunk-IY7NYNPZ.js.map} +1 -1
  47. package/dist/{chunk-527HHQPS.js → chunk-KCOFEWV5.js} +6 -4
  48. package/dist/{chunk-527HHQPS.js.map → chunk-KCOFEWV5.js.map} +1 -1
  49. package/dist/chunk-M2RLHZ4J.js +849 -0
  50. package/dist/chunk-M2RLHZ4J.js.map +1 -0
  51. package/dist/{chunk-K3U5F2QT.js → chunk-M6GSS72T.js} +12 -12
  52. package/dist/{chunk-UK2I3ACY.js → chunk-MHM4QEBV.js} +4 -4
  53. package/dist/{chunk-EL2BZTDL.js → chunk-MOWMCEOJ.js} +13 -11
  54. package/dist/{chunk-EL2BZTDL.js.map → chunk-MOWMCEOJ.js.map} +1 -1
  55. package/dist/{chunk-OIZ3XMKB.js → chunk-MWBJ3KTF.js} +4 -4
  56. package/dist/chunk-N7JSEDSC.js +233 -0
  57. package/dist/chunk-N7JSEDSC.js.map +1 -0
  58. package/dist/{chunk-MZC62HPZ.js → chunk-NBMPHD4I.js} +2 -2
  59. package/dist/{chunk-YA63PVWI.js → chunk-NHHOPZRA.js} +12 -10
  60. package/dist/{chunk-YA63PVWI.js.map → chunk-NHHOPZRA.js.map} +1 -1
  61. package/dist/{chunk-DX32P2DT.js → chunk-NTWW7J76.js} +2 -2
  62. package/dist/{chunk-6XTQDFGP.js → chunk-PCFG7E6B.js} +3 -3
  63. package/dist/{chunk-6XTQDFGP.js.map → chunk-PCFG7E6B.js.map} +1 -1
  64. package/dist/{chunk-SJO2FTPG.js → chunk-PL4UAF4S.js} +73 -1304
  65. package/dist/chunk-PL4UAF4S.js.map +1 -0
  66. package/dist/chunk-QCHVR4ZM.js +286 -0
  67. package/dist/chunk-QCHVR4ZM.js.map +1 -0
  68. package/dist/{chunk-JQU7FHYH.js → chunk-QW77LCOU.js} +10 -10
  69. package/dist/{chunk-IA7BMIPE.js → chunk-SM6NOMJS.js} +2 -2
  70. package/dist/{chunk-DE7JSWXV.js → chunk-SWSTHZBI.js} +8 -6
  71. package/dist/{chunk-DE7JSWXV.js.map → chunk-SWSTHZBI.js.map} +1 -1
  72. package/dist/{chunk-NGK3N6F2.js → chunk-T6SYGLWR.js} +3 -3
  73. package/dist/chunk-TH4JVQPF.js +133 -0
  74. package/dist/chunk-TH4JVQPF.js.map +1 -0
  75. package/dist/{chunk-TVIX653Q.js → chunk-TLXE7LYK.js} +4 -4
  76. package/dist/{chunk-HVFR66GQ.js → chunk-TUAAR3MM.js} +3280 -283
  77. package/dist/chunk-TUAAR3MM.js.map +1 -0
  78. package/dist/{chunk-TA42STP7.js → chunk-UAKNZVCD.js} +4 -4
  79. package/dist/{chunk-C3KI45RF.js → chunk-UJSGS2Y5.js} +4 -4
  80. package/dist/{chunk-ZX43SRZR.js → chunk-UWQ2UVHE.js} +8 -6
  81. package/dist/{chunk-ZX43SRZR.js.map → chunk-UWQ2UVHE.js.map} +1 -1
  82. package/dist/chunk-WQWKYAAK.js +86 -0
  83. package/dist/chunk-WQWKYAAK.js.map +1 -0
  84. package/dist/{chunk-LJ2RDH3F.js → chunk-XG6PVB5S.js} +1 -23
  85. package/dist/chunk-XG6PVB5S.js.map +1 -0
  86. package/dist/{chunk-Q35YIDBV.js → chunk-XKBEHKWO.js} +29 -264
  87. package/dist/chunk-XKBEHKWO.js.map +1 -0
  88. package/dist/chunk-XPEWUK7J.js +532 -0
  89. package/dist/chunk-XPEWUK7J.js.map +1 -0
  90. package/dist/{chunk-BOIF2XGG.js → chunk-XXDXIIQ4.js} +2 -2
  91. package/dist/chunk-YLK2J5YK.js +610 -0
  92. package/dist/chunk-YLK2J5YK.js.map +1 -0
  93. package/dist/{chunk-7OQAU4EA.js → chunk-Z4IZGEM3.js} +16 -12
  94. package/dist/{chunk-7OQAU4EA.js.map → chunk-Z4IZGEM3.js.map} +1 -1
  95. package/dist/{cli-E3H6ZP4I.js → cli-6EWVMEN6.js} +5 -3
  96. package/dist/{cli-E3H6ZP4I.js.map → cli-6EWVMEN6.js.map} +1 -1
  97. package/dist/{cli-MHTYPVOD.js → cli-6H7HVDMQ.js} +113 -20
  98. package/dist/{cli-MHTYPVOD.js.map → cli-6H7HVDMQ.js.map} +1 -1
  99. package/dist/{cli-HUIMNJT6.js → cli-EPVZHAZS.js} +19 -20
  100. package/dist/{cli-HUIMNJT6.js.map → cli-EPVZHAZS.js.map} +1 -1
  101. package/dist/{cli-6PGVHP7Y.js → cli-LUCSGTVI.js} +17 -19
  102. package/dist/{cli-6PGVHP7Y.js.map → cli-LUCSGTVI.js.map} +1 -1
  103. package/dist/{cli-PRZHQ3QB.js → cli-NIG4N3XM.js} +14 -15
  104. package/dist/{cli-PRZHQ3QB.js.map → cli-NIG4N3XM.js.map} +1 -1
  105. package/dist/{cli-TYGOHJOJ.js → cli-PSKNB66T.js} +225 -58
  106. package/dist/cli-PSKNB66T.js.map +1 -0
  107. package/dist/{cli-QKIJOXGW.js → cli-UO4NHIB3.js} +17 -17
  108. package/dist/{cli-AAG3N4NB.js → cli-UQ7A3YA2.js} +17 -18
  109. package/dist/{cli-AAG3N4NB.js.map → cli-UQ7A3YA2.js.map} +1 -1
  110. package/dist/{cli-YW6VWBHX.js → cli-YHYDLQAF.js} +10 -10
  111. package/dist/cli.js +11 -11
  112. package/dist/config-P4HDNTYD.js +26 -0
  113. package/dist/conformance-ZFCMKM6M.js +18 -0
  114. package/dist/docmeta.js +9 -9
  115. package/dist/github-7ZCH5PSO.js +26 -0
  116. package/dist/github-POT6724K.js +31 -0
  117. package/dist/host-6GURH5HE.js +23 -0
  118. package/dist/index.d.ts +72 -4
  119. package/dist/index.js +176 -166
  120. package/dist/index.js.map +1 -1
  121. package/dist/{json-4DCKDGUV.js → json-KT2K62L5.js} +12 -13
  122. package/dist/lint-5AQ5C2BV.js +29 -0
  123. package/dist/list-5JZKX2NK.js +28 -0
  124. package/dist/list-SWPFXQMU.js +30 -0
  125. package/dist/{page-QEDB7EVU.js → page-UPSXRP75.js} +11 -12
  126. package/dist/prepare-6GNEWCNH.js +155 -0
  127. package/dist/prepare-6GNEWCNH.js.map +1 -0
  128. package/dist/{pretty-SQX33UM2.js → pretty-Q6FQAOK4.js} +13 -14
  129. package/dist/{pretty-5DGEBZSV.js → pretty-SQRPFPSQ.js} +12 -13
  130. package/dist/provider-AMGRDY6V.js +34 -0
  131. package/dist/release-IECYCLTD.js +36 -0
  132. package/dist/release-IECYCLTD.js.map +1 -0
  133. package/dist/{reporters-OHSI3RMV.js → reporters-45MMC2ID.js} +11 -12
  134. package/dist/{reporters-YELDDYJD.js → reporters-XUV4MM64.js} +7 -5
  135. package/dist/reporters-XUV4MM64.js.map +1 -0
  136. package/dist/run-KMWY2IAN.js +32 -0
  137. package/dist/run-KMWY2IAN.js.map +1 -0
  138. package/dist/{term-2WMDZ4PY.js → term-PCJUCWNF.js} +16 -17
  139. package/dist/{term-2WMDZ4PY.js.map → term-PCJUCWNF.js.map} +1 -1
  140. package/dist/validate-IMNCZNWG.js +17 -0
  141. package/dist/validate-IMNCZNWG.js.map +1 -0
  142. package/package.json +2 -2
  143. package/plugin/manni/.claude-plugin/plugin.json +1 -1
  144. package/plugin/manni/hooks/hooks.json +47 -0
  145. package/dist/batch-GOE3UXOD.js +0 -36
  146. package/dist/build-M7BMEHL2.js +0 -33
  147. package/dist/calibrate-6RRAILUY.js +0 -31
  148. package/dist/capture-RJPQ6B4N.js +0 -32
  149. package/dist/check-BQD64X3N.js +0 -27
  150. package/dist/chunk-3R5Y3XOL.js.map +0 -1
  151. package/dist/chunk-3YHAYXBC.js +0 -164
  152. package/dist/chunk-3YHAYXBC.js.map +0 -1
  153. package/dist/chunk-HVFR66GQ.js.map +0 -1
  154. package/dist/chunk-LJ2RDH3F.js.map +0 -1
  155. package/dist/chunk-NAZRLJAK.js +0 -3090
  156. package/dist/chunk-NAZRLJAK.js.map +0 -1
  157. package/dist/chunk-Q35YIDBV.js.map +0 -1
  158. package/dist/chunk-QCBICNKC.js.map +0 -1
  159. package/dist/chunk-SJO2FTPG.js.map +0 -1
  160. package/dist/chunk-TU2WUBVZ.js +0 -2
  161. package/dist/cli-TYGOHJOJ.js.map +0 -1
  162. package/dist/github-3WMSTNTK.js +0 -32
  163. package/dist/github-OXSJQ4PS.js +0 -27
  164. package/dist/lint-YDHVVZHT.js +0 -30
  165. package/dist/list-3ZO2NIYO.js +0 -31
  166. package/dist/list-EJH6VAOW.js +0 -29
  167. package/dist/run-IP6NZHAG.js +0 -33
  168. package/dist/validate-G6HH3YXL.js +0 -16
  169. /package/dist/{batch-GOE3UXOD.js.map → batch-OZOACN4G.js.map} +0 -0
  170. /package/dist/{build-M7BMEHL2.js.map → build-Z5VOVADH.js.map} +0 -0
  171. /package/dist/{calibrate-6RRAILUY.js.map → calibrate-TZYT42DR.js.map} +0 -0
  172. /package/dist/{capture-RJPQ6B4N.js.map → capture-SL4MNDDP.js.map} +0 -0
  173. /package/dist/{check-BQD64X3N.js.map → check-5OMA42Y6.js.map} +0 -0
  174. /package/dist/{check-ESNS7ZBC.js.map → check-OAJWC3WD.js.map} +0 -0
  175. /package/dist/{check-RQIIIURI.js.map → check-PKY7KTQE.js.map} +0 -0
  176. /package/dist/{chunk-F2OVHJNC.js.map → chunk-2JFPBZJK.js.map} +0 -0
  177. /package/dist/{chunk-CP4ZM43V.js.map → chunk-2KRB3EG7.js.map} +0 -0
  178. /package/dist/{chunk-HQFVJDEN.js.map → chunk-3NWX34ZI.js.map} +0 -0
  179. /package/dist/{chunk-TCC737IS.js.map → chunk-5G53XATW.js.map} +0 -0
  180. /package/dist/{chunk-SNEHX4VE.js.map → chunk-733Y2STG.js.map} +0 -0
  181. /package/dist/{chunk-ELZ2IIOF.js.map → chunk-73TC4DYH.js.map} +0 -0
  182. /package/dist/{chunk-QY3DOZMS.js.map → chunk-7WRP5FFP.js.map} +0 -0
  183. /package/dist/{chunk-C6HZ6C5T.js.map → chunk-C3B2VJNC.js.map} +0 -0
  184. /package/dist/{chunk-NN4ASVTY.js.map → chunk-C73RSUIC.js.map} +0 -0
  185. /package/dist/{chunk-GAZFKZHM.js.map → chunk-DC5DDJVE.js.map} +0 -0
  186. /package/dist/{chunk-52PDIZKV.js.map → chunk-ECVQNGTH.js.map} +0 -0
  187. /package/dist/{chunk-XWFNO5PO.js.map → chunk-GAJIJKET.js.map} +0 -0
  188. /package/dist/{chunk-K3U5F2QT.js.map → chunk-M6GSS72T.js.map} +0 -0
  189. /package/dist/{chunk-UK2I3ACY.js.map → chunk-MHM4QEBV.js.map} +0 -0
  190. /package/dist/{chunk-OIZ3XMKB.js.map → chunk-MWBJ3KTF.js.map} +0 -0
  191. /package/dist/{chunk-MZC62HPZ.js.map → chunk-NBMPHD4I.js.map} +0 -0
  192. /package/dist/{chunk-DX32P2DT.js.map → chunk-NTWW7J76.js.map} +0 -0
  193. /package/dist/{chunk-JQU7FHYH.js.map → chunk-QW77LCOU.js.map} +0 -0
  194. /package/dist/{chunk-IA7BMIPE.js.map → chunk-SM6NOMJS.js.map} +0 -0
  195. /package/dist/{chunk-NGK3N6F2.js.map → chunk-T6SYGLWR.js.map} +0 -0
  196. /package/dist/{chunk-TVIX653Q.js.map → chunk-TLXE7LYK.js.map} +0 -0
  197. /package/dist/{chunk-TA42STP7.js.map → chunk-UAKNZVCD.js.map} +0 -0
  198. /package/dist/{chunk-C3KI45RF.js.map → chunk-UJSGS2Y5.js.map} +0 -0
  199. /package/dist/{chunk-BOIF2XGG.js.map → chunk-XXDXIIQ4.js.map} +0 -0
  200. /package/dist/{cli-QKIJOXGW.js.map → cli-UO4NHIB3.js.map} +0 -0
  201. /package/dist/{chunk-TU2WUBVZ.js.map → cli-YHYDLQAF.js.map} +0 -0
  202. /package/dist/{cli-YW6VWBHX.js.map → config-P4HDNTYD.js.map} +0 -0
  203. /package/dist/{github-3WMSTNTK.js.map → conformance-ZFCMKM6M.js.map} +0 -0
  204. /package/dist/{github-OXSJQ4PS.js.map → github-7ZCH5PSO.js.map} +0 -0
  205. /package/dist/{json-4DCKDGUV.js.map → github-POT6724K.js.map} +0 -0
  206. /package/dist/{lint-YDHVVZHT.js.map → host-6GURH5HE.js.map} +0 -0
  207. /package/dist/{list-3ZO2NIYO.js.map → json-KT2K62L5.js.map} +0 -0
  208. /package/dist/{list-EJH6VAOW.js.map → lint-5AQ5C2BV.js.map} +0 -0
  209. /package/dist/{page-QEDB7EVU.js.map → list-5JZKX2NK.js.map} +0 -0
  210. /package/dist/{pretty-5DGEBZSV.js.map → list-SWPFXQMU.js.map} +0 -0
  211. /package/dist/{pretty-SQX33UM2.js.map → page-UPSXRP75.js.map} +0 -0
  212. /package/dist/{reporters-OHSI3RMV.js.map → pretty-Q6FQAOK4.js.map} +0 -0
  213. /package/dist/{reporters-YELDDYJD.js.map → pretty-SQRPFPSQ.js.map} +0 -0
  214. /package/dist/{run-IP6NZHAG.js.map → provider-AMGRDY6V.js.map} +0 -0
  215. /package/dist/{validate-G6HH3YXL.js.map → reporters-45MMC2ID.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/graph/commands/export.ts","../src/graph/core/emit-jsonld.ts","../src/graph/core/emit-rdfxml.ts","../src/graph/core/iirds-package.ts","../src/graph/core/zip.ts","../src/graph/core/search-index.ts","../src/graph/runtime/resolve.ts","../src/graph/runtime/graph.ts","../src/graph/commands/query.ts","../src/graph/commands/fill.ts","../src/graph/core/frontmatter-edit.ts","../src/graph/core/fill-guard.ts","../src/graph/llm/cache.ts","../src/graph/llm/prompt.ts","../src/graph/llm/provider.ts","../src/graph/commands/embed.ts","../src/graph/core/vector-index.ts","../src/graph/embed/local.ts","../src/graph/embed/mock.ts","../src/graph/commands/search.ts","../src/graph/runtime/vector.ts","../src/graph/runtime/trace.ts","../src/graph/runtime/entry.ts","../src/graph/runtime/lexical.ts","../src/graph/commands/stats.ts","../src/graph/commands/traverse.ts","../src/graph/runtime/traverse.ts"],"sourcesContent":["/**\n * `manni graph export` — reserialize the built graph into a consumer format. Reads\n * the graph the same way `stats`/`check` do (loadGraph over the config `out`,\n * missing graph → exit 2) and writes a deterministic rendering. `jsonld` emits a\n * whole-graph JSON-LD file; `iirds` projects the graph into a conformant,\n * deterministic unrestricted iiRDS package (`.iirds` ZIP) — see ADR 01017.\n */\nimport { createHash } from \"node:crypto\";\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { GraphError } from \"../types.js\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { documentBase } from \"../core/discover.js\";\nimport { emitJsonLd } from \"../core/emit-jsonld.js\";\nimport { emitRdfXml } from \"../core/emit-rdfxml.js\";\nimport { projectPackage } from \"../core/iirds-package.js\";\nimport { loadGraph, storeToQuads } from \"../core/load.js\";\nimport {\n buildSearchIndex,\n documentsByLanguage,\n emitSearchIndex,\n partitionByLanguage,\n} from \"../core/search-index.js\";\nimport {\n emitLocalizations,\n isLanguageTag,\n LOCALIZATIONS_FILENAME,\n searchIndexFilename,\n type LocalizationEntry,\n} from \"../core/localizations.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\nimport { PREFIXES } from \"../core/vocab.js\";\nimport { GraphIndex } from \"../runtime/graph.js\";\nimport { writeZip, type ZipEntry } from \"../core/zip.js\";\n\n/**\n * What `manni graph export <target>` can write, in the order messages list them.\n * The CLI names its positional against this list, and `runExport` holds a\n * library caller to it too.\n */\nexport const EXPORT_TARGETS = [\"jsonld\", \"iirds\", \"search\"] as const;\n\nexport type ExportFormat = (typeof EXPORT_TARGETS)[number];\n\nexport interface ExportOptions {\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`). */\n graph?: string;\n format: ExportFormat;\n /** Output path (default: the graph path with the format's extension). */\n out?: string;\n cwd?: string;\n}\n\nexport interface ExportResult {\n outPath: string;\n format: ExportFormat;\n /** Distinct subject nodes in the emitted (or projected) graph. */\n nodes: number;\n /** Non-fatal projection warnings (iiRDS only; empty otherwise). */\n warnings: string[];\n}\n\n/** File extension each single-file format writes to. */\nconst EXTENSION: Record<\"jsonld\" | \"iirds\", string> = {\n jsonld: \".jsonld\",\n iirds: \".iirds\",\n};\n\n/** Replace a path's extension (or append one) with `.jsonld`-style ext. */\nfunction withExtension(path: string, ext: string): string {\n return path.replace(/\\.[^./\\\\]*$/, \"\") + ext;\n}\n\nfunction runJsonLd(cwd: string, graphPath: string, out?: string): ExportResult {\n const store = loadGraph(graphPath);\n const quads = storeToQuads(store);\n const serialized = emitJsonLd(quads);\n const nodes = new Set(quads.map((q) => q.s)).size;\n const outPath = out\n ? resolve(cwd, out)\n : withExtension(graphPath, EXTENSION.jsonld);\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, serialized, \"utf8\");\n return { outPath, format: \"jsonld\", nodes, warnings: [] };\n}\n\nfunction runIirds(\n cwd: string,\n sources: string,\n graphPath: string,\n iirds: { title?: string; creator?: string; version: \"1.2\" | \"1.3\" },\n baseIri: string,\n out?: string,\n): ExportResult {\n const store = loadGraph(graphPath);\n const projection = projectPackage(\n store,\n {\n baseIri,\n version: iirds.version,\n title: iirds.title,\n creator: iirds.creator,\n },\n sources,\n );\n const metadata = emitRdfXml(projection.quads, projection.prefixes);\n\n // Deterministic entry order: mimetype (stored, first) → metadata → content\n // files sorted by their in-archive path.\n const content = [...projection.contentFiles]\n .sort((a, b) => byCodeUnit(a.zipPath, b.zipPath))\n .map((f): ZipEntry => ({ name: f.zipPath, data: readFileSync(f.absPath) }));\n const entries: ZipEntry[] = [\n {\n name: \"mimetype\",\n data: Buffer.from(\"application/iirds+zip\"),\n store: true,\n },\n { name: \"META-INF/metadata.rdf\", data: Buffer.from(metadata, \"utf8\") },\n ...content,\n ];\n\n const outPath = out\n ? resolve(cwd, out)\n : withExtension(graphPath, EXTENSION.iirds);\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, writeZip(entries));\n const nodes = new Set(projection.quads.map((q) => q.s)).size;\n return { outPath, format: \"iirds\", nodes, warnings: projection.warnings };\n}\n\n/**\n * The same digest `manni graph embed` records as a sidecar's `source` and the runtime\n * recomputes in a browser: SHA-256 over the index file's exact bytes. Computed\n * here from the string about to be written, so the manifest cannot disagree\n * with the file it describes.\n */\nfunction searchIndexDigest(raw: string): string {\n return `sha256:${createHash(\"sha256\").update(raw, \"utf8\").digest(\"hex\")}`;\n}\n\n/**\n * The lexical search artifacts. Reads each document's source from disk — the\n * same thing the iiRDS projection does for renditions — because the graph\n * deliberately carries no prose (ADR 01008/01019).\n *\n * Fans out per language and writes a manifest beside them (ADR 01038). The\n * fan-out is unconditional, including for a monolingual corpus: one rule beats\n * a filename that changes shape the day someone adds a translation.\n */\nfunction runSearchIndex(\n cwd: string,\n sources: string,\n graphPath: string,\n out?: string,\n): ExportResult {\n const store = loadGraph(graphPath);\n const graph = GraphIndex.fromQuads(\n storeToQuads(store),\n Object.fromEntries(PREFIXES),\n );\n const warnings: string[] = [];\n const index = buildSearchIndex(graph, sources, { warnings });\n const byLanguage = partitionByLanguage(graph, index);\n const docCounts = documentsByLanguage(graph);\n\n // Siblings of the graph, named for what they are: `graph.json` next to\n // `graph.jsonld` would be a trap. `--out` names the directory here, not a\n // file, because there is more than one.\n const outDir = out ? resolve(cwd, out) : dirname(graphPath);\n mkdirSync(outDir, { recursive: true });\n\n const languages: LocalizationEntry[] = [];\n for (const [language, doc] of byLanguage) {\n // The tag becomes a filename, and `export` does not run SHACL — so a\n // `dcterms:language` literal reaches this line exactly as the corpus wrote\n // it. Unchecked, `lang: ../escaped` would put a path segment into\n // `writeFileSync` and crash with a raw stack trace (exit 1) instead of the\n // operational error this is (exit 2).\n if (!isLanguageTag(language)) {\n throw new GraphError(\n `Cannot write an index for language \"${language}\": not a BCP-47 tag. ` +\n `Fix the \\`lang\\`/\\`language\\` frontmatter, or the route's \\`language\\`, ` +\n `and rebuild — \\`manni graph check\\` reports which document carries it.`,\n );\n }\n const filename = searchIndexFilename(language);\n const serialized = emitSearchIndex(doc);\n writeFileSync(join(outDir, filename), serialized, \"utf8\");\n languages.push({\n language,\n documents: docCounts.get(language) ?? 0,\n search: {\n path: filename,\n entries: doc.entries.length,\n digest: searchIndexDigest(serialized),\n },\n });\n }\n\n const manifestPath = join(outDir, LOCALIZATIONS_FILENAME);\n writeFileSync(\n manifestPath,\n emitLocalizations({ version: 1, languages }),\n \"utf8\",\n );\n return {\n outPath: manifestPath,\n format: \"search\",\n nodes: index.entries.length,\n warnings,\n };\n}\n\n/**\n * Async by contract — every command core is, and the CLI awaits this one — but\n * synchronous in fact: all three writers are `writeFileSync`. Spelled as a\n * `Promise` the body never awaits, through the constructor rather than\n * `Promise.resolve().then`, so the executor still runs eagerly and a usage\n * error still *rejects* the returned promise instead of throwing before the\n * caller holds one. That is what `async` did, said without claiming an `await`\n * that is not there.\n */\nexport function runExport(opts: ExportOptions): Promise<ExportResult> {\n return new Promise((ok) => {\n ok(exportOnce(opts));\n });\n}\n\nfunction exportOnce(opts: ExportOptions): ExportResult {\n const cwd = opts.cwd ?? process.cwd();\n if (!(EXPORT_TARGETS as readonly string[]).includes(opts.format)) {\n throw new GraphError(\n `Unknown export target \"${opts.format}\". Use ${EXPORT_TARGETS.join(\" | \")}.`,\n );\n }\n\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 // A page's `graph:path` is read from where a bare `build` labels it from:\n // the config's directory when it declares collections, else the working one.\n const sources = documentBase(config, {}, cwd);\n\n if (opts.format === \"jsonld\") return runJsonLd(cwd, graphPath, opts.out);\n if (opts.format === \"search\") {\n return runSearchIndex(cwd, sources, graphPath, opts.out);\n }\n return runIirds(\n cwd,\n sources,\n graphPath,\n config.export.iirds,\n config.baseIri,\n opts.out,\n );\n}\n","/**\n * Deterministic JSON-LD serialization — the web-native rendering of the same\n * graph the Turtle emitter produces. Canonical form: an `@context` carrying the\n * fixed prefix table, then `@graph` as one node object per subject sorted by\n * `@id`. Within a node: `@id`, then `@type` (compacted class IRIs, sorted),\n * then predicate CURIE keys sorted, each value array sorted. Objects are built\n * in that sorted key order so `JSON.stringify(_, null, 2)` is byte-stable.\n * Byte-identical output for any input quad order.\n *\n * Deliberately hand-rolled rather than the `jsonld` library, for the same\n * reason the Turtle emitter avoids N3.Writer: library formatting and ordering\n * are incidental, not a stability contract. dockg emits no blank nodes and no\n * language-tagged literals, so neither is handled here.\n */\nimport { compactIri } from \"./load.js\";\nimport type { Quad, Term } from \"./derive.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS, PREFIXES, RDF_TYPE } from \"./vocab.js\";\n\nconst XSD_STRING = `${NS.xsd}string`;\n\n/**\n * A rendered JSON-LD object value plus the fields it sorts by. Sorting compares\n * field by field (never a joined string with a separator — that would need a\n * delimiter byte, and NUL/control bytes in source are forbidden): IRIs before\n * literals (mirroring the Turtle emitter), then lexical value, then datatype.\n */\ninterface RenderedValue {\n value: unknown;\n /** 0 = IRI, 1 = literal — IRIs sort first. */\n kind: 0 | 1;\n /** IRI value or literal lexical form. */\n primary: string;\n /** Datatype IRI for typed literals; \"\" for IRIs and plain literals. */\n datatype: string;\n}\n\nfunction renderValue(term: Term): RenderedValue {\n if (term.kind === \"iri\") {\n return {\n value: { \"@id\": term.value },\n kind: 0,\n primary: term.value,\n datatype: \"\",\n };\n }\n if (term.datatype && term.datatype !== XSD_STRING) {\n return {\n value: { \"@value\": term.value, \"@type\": compactIri(term.datatype) },\n kind: 1,\n primary: term.value,\n datatype: term.datatype,\n };\n }\n return { value: term.value, kind: 1, primary: term.value, datatype: \"\" };\n}\n\nfunction compareRendered(a: RenderedValue, b: RenderedValue): number {\n if (a.kind !== b.kind) return a.kind - b.kind;\n const p = byCodeUnit(a.primary, b.primary);\n if (p !== 0) return p;\n return byCodeUnit(a.datatype, b.datatype);\n}\n\n/** Collapse a sorted value list to a scalar (n=1) or array (n>1). */\nfunction collapse(values: RenderedValue[]): unknown {\n const rendered = [...values].sort(compareRendered).map((v) => v.value);\n return rendered.length === 1 ? rendered[0] : rendered;\n}\n\nexport function emitJsonLd(quads: Quad[]): string {\n const context: Record<string, string> = {};\n for (const [prefix, ns] of PREFIXES) context[prefix] = ns;\n\n // subject → predicate → terms\n const subjects = new Map<string, Map<string, Term[]>>();\n for (const quad of quads) {\n let preds = subjects.get(quad.s);\n if (!preds) {\n preds = new Map();\n subjects.set(quad.s, preds);\n }\n let terms = preds.get(quad.p);\n if (!terms) {\n terms = [];\n preds.set(quad.p, terms);\n }\n terms.push(quad.o);\n }\n\n // Sorting the entries rather than the keys: each predicate map arrives with\n // the subject it belongs to, so there is no second lookup to assert on.\n const graph = [...subjects.entries()]\n .sort(([a], [b]) => byCodeUnit(a, b))\n .map(([subject, preds]) => {\n const node: Record<string, unknown> = { \"@id\": subject };\n\n const types = preds.get(RDF_TYPE);\n if (types) {\n const compacted = types\n .map((t) => compactIri(t.value))\n .sort(byCodeUnit);\n node[\"@type\"] = compacted.length === 1 ? compacted[0] : compacted;\n }\n\n const predEntries = [...preds.entries()]\n .filter(([p]) => p !== RDF_TYPE)\n .sort(([a], [b]) => byCodeUnit(a, b));\n for (const [p, terms] of predEntries) {\n node[compactIri(p)] = collapse(terms.map(renderValue));\n }\n return node;\n });\n\n return `${JSON.stringify({ \"@context\": context, \"@graph\": graph }, null, 2)}\\n`;\n}\n","/**\n * Deterministic RDF/XML serialization — the metadata half of the iiRDS package\n * export (ADR 01017). RDF/XML is what `META-INF/metadata.rdf` must be (the iiRDS\n * container rule; Turtle/JSON-LD are not accepted there). Hand-rolled like the\n * Turtle/JSON-LD emitters ([emit.ts], [emit-jsonld.ts]) so the bytes are a\n * stability contract.\n *\n * Canonical form: an XML declaration, then `<rdf:RDF>` with namespace\n * declarations in sorted prefix order, then one `<rdf:Description>` per subject\n * sorted by IRI. Within a subject, predicates are sorted; each object is an\n * `rdf:resource` (IRI) or escaped element text (literal, with `rdf:datatype`\n * when typed). No blank nodes. Byte-identical for any input quad order.\n *\n * The prefix table is passed in (not the global `PREFIXES`) so the package can\n * declare `vcard` without touching the main graph's Turtle/JSON-LD headers.\n */\nimport type { Quad, Term } from \"./derive.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS } from \"./vocab.js\";\n\nconst XSD_STRING = `${NS.xsd}string`;\n\nfunction escapeText(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction escapeAttr(value: string): string {\n return escapeText(value).replace(/\"/g, \"&quot;\");\n}\n\n/** Compact an IRI to `prefix:local` using the supplied table (longest NS wins). */\nfunction toQName(\n iri: string,\n prefixes: ReadonlyArray<[string, string]>,\n): string {\n let best: string | undefined;\n let bestNs = \"\";\n for (const [prefix, ns] of prefixes) {\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 if (best === undefined) {\n throw new Error(`emitRdfXml: no prefix covers the IRI ${iri}`);\n }\n return best;\n}\n\n/** Sort objects: IRIs before literals, then by value, then by datatype. */\nfunction compareTerms(a: Term, b: Term): 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 return byCodeUnit(da, db);\n}\n\nexport function emitRdfXml(\n quads: Quad[],\n prefixes: Record<string, string>,\n): string {\n const sortedPrefixes = Object.entries(prefixes).sort(([a], [b]) =>\n byCodeUnit(a, b),\n );\n\n const lines: string[] = ['<?xml version=\"1.0\" encoding=\"UTF-8\"?>'];\n lines.push(\"<rdf:RDF\");\n sortedPrefixes.forEach(([prefix, ns], i) => {\n const tail = i === sortedPrefixes.length - 1 ? \">\" : \"\";\n lines.push(` xmlns:${prefix}=\"${escapeAttr(ns)}\"${tail}`);\n });\n\n // subject → predicate → terms\n const subjects = new Map<string, Map<string, Term[]>>();\n for (const quad of quads) {\n let preds = subjects.get(quad.s);\n if (!preds) {\n preds = new Map();\n subjects.set(quad.s, preds);\n }\n let terms = preds.get(quad.p);\n if (!terms) {\n terms = [];\n preds.set(quad.p, terms);\n }\n terms.push(quad.o);\n }\n\n // Sorting the entries rather than the keys: each predicate map arrives with\n // the subject it belongs to and each term list with its predicate, so there\n // is no second lookup left to assert on.\n const sortedSubjects = [...subjects.entries()].sort(([a], [b]) =>\n byCodeUnit(a, b),\n );\n for (const [subject, preds] of sortedSubjects) {\n lines.push(` <rdf:Description rdf:about=\"${escapeAttr(subject)}\">`);\n const sortedPreds = [...preds.entries()].sort(([a], [b]) =>\n byCodeUnit(a, b),\n );\n for (const [p, terms] of sortedPreds) {\n const qname = toQName(p, sortedPrefixes);\n for (const term of [...terms].sort(compareTerms)) {\n if (term.kind === \"iri\") {\n lines.push(\n ` <${qname} rdf:resource=\"${escapeAttr(term.value)}\"/>`,\n );\n } else if (term.datatype && term.datatype !== XSD_STRING) {\n lines.push(\n ` <${qname} rdf:datatype=\"${escapeAttr(term.datatype)}\">${escapeText(term.value)}</${qname}>`,\n );\n } else {\n lines.push(` <${qname}>${escapeText(term.value)}</${qname}>`);\n }\n }\n }\n lines.push(\" </rdf:Description>\");\n }\n\n lines.push(\"</rdf:RDF>\");\n return `${lines.join(\"\\n\")}\\n`;\n}\n","/**\n * Graph → iiRDS package projection (ADR 01017). Reads the built graph and emits\n * the metadata quads + content-file manifest for an unrestricted iiRDS package:\n * one `iirds:Package`, each `graph:Document` re-typed as an `iirds:Topic` linked\n * via `iirds:is-part-of-package`, each source file exposed as an `iirds:Rendition`\n * (`iirds:source` + `iirds:format`), and the Phase-2 iiRDS classification carried\n * across. This is a *projection* — it builds a fresh quad set (never the whole\n * store), so the package graph contains only iiRDS terms, not dockg-internal\n * types. Deterministic: baseIri-derived IRIs (no random UUIDs), no blank nodes.\n */\nimport { existsSync } from \"node:fs\";\nimport { extname, resolve } from \"node:path\";\nimport { DataFactory, type Store } from \"n3\";\nimport { GraphError } from \"../types.js\";\nimport type { Quad, Term } from \"./derive.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS, RDF_TYPE } from \"./vocab.js\";\nimport { escapesArchiveRoot } from \"./zip.js\";\nimport {\n IIRDS_CREATOR,\n IIRDS_HAS_PARTY_ROLE,\n IIRDS_HAS_RENDITION,\n IIRDS_HAS_SUBJECT,\n IIRDS_HAS_TOPIC_TYPE,\n IIRDS_IIRDS_VERSION,\n IIRDS_IS_PART_OF_PACKAGE,\n IIRDS_LANGUAGE,\n IIRDS_PACKAGE,\n IIRDS_PARTY,\n IIRDS_PRODUCT_VARIANT,\n IIRDS_RELATES_TO_LIFECYCLE_PHASE,\n IIRDS_RELATES_TO_PARTY,\n IIRDS_RELATES_TO_PRODUCT_VARIANT,\n IIRDS_RELATES_TO_VCARD,\n IIRDS_RENDITION,\n IIRDS_SOURCE,\n IIRDS_FORMAT,\n IIRDS_TITLE,\n IIRDS_TOPIC,\n VCARD_NS,\n VCARD_ORGANIZATION,\n VCARD_ORGANIZATION_NAME,\n} from \"./iirds.js\";\n\nconst GRAPH_DOCUMENT = `${NS.graph}Document`;\nconst XSD_STRING = `${NS.xsd}string`;\n\n/**\n * A rendition's media type, by its source's extension (proposal 0077 §2).\n * The graph keeps a page's path and not the format it was parsed as, so a\n * page read under `--as` from an unclaimed extension falls back to Markdown,\n * the one format every such page was before 0077.\n */\nconst MEDIA_TYPES: Readonly<Record<string, string>> = {\n \".html\": \"text/html\",\n \".htm\": \"text/html\",\n \".adoc\": \"text/asciidoc\",\n \".asciidoc\": \"text/asciidoc\",\n \".rst\": \"text/x-rst\",\n \".dita\": \"application/dita+xml\",\n \".ditamap\": \"application/dita+xml\",\n \".xml\": \"application/xml\",\n};\n\nfunction mediaTypeOf(path: string): string {\n return MEDIA_TYPES[extname(path).toLowerCase()] ?? \"text/markdown\";\n}\n\n/** iiRDS classification edges carried from each Document verbatim. */\nconst CARRIED = [\n IIRDS_HAS_TOPIC_TYPE,\n IIRDS_HAS_SUBJECT,\n IIRDS_RELATES_TO_PRODUCT_VARIANT,\n IIRDS_RELATES_TO_LIFECYCLE_PHASE,\n];\n\nexport interface IirdsPackageOptions {\n baseIri: string;\n version: string;\n title?: string;\n creator?: string;\n}\n\nexport interface ContentFile {\n /** In-archive path (matches the Rendition's iirds:source). */\n zipPath: string;\n /** Absolute path of the source file on disk. */\n absPath: string;\n}\n\nexport interface PackageProjection {\n quads: Quad[];\n prefixes: Record<string, string>;\n contentFiles: ContentFile[];\n warnings: string[];\n}\n\nconst iri = (value: string): Term => ({ kind: \"iri\", value });\nconst lit = (value: string, datatype?: string): Term =>\n datatype ? { kind: \"literal\", value, datatype } : { kind: \"literal\", value };\n\nfunction firstObject(store: Store, s: string, p: string): string | undefined {\n const q = store.getQuads(DataFactory.namedNode(s), DataFactory.namedNode(p), null, null)[0];\n return q?.object.value;\n}\n\nexport function projectPackage(\n store: Store,\n opts: IirdsPackageOptions,\n cwd: string,\n): PackageProjection {\n const quads: Quad[] = [];\n const contentFiles: ContentFile[] = [];\n const warnings: string[] = [];\n const add = (s: string, p: string, o: Term): void => {\n quads.push({ s, p, o });\n };\n\n const pkg = `${opts.baseIri}package`;\n add(pkg, RDF_TYPE, iri(IIRDS_PACKAGE));\n add(pkg, IIRDS_IIRDS_VERSION, lit(opts.version));\n add(pkg, IIRDS_TITLE, lit(opts.title ?? \"manni graph export\"));\n\n if (opts.creator) {\n const party = `${opts.baseIri}party/creator`;\n const org = `${opts.baseIri}vcard/creator`;\n add(pkg, IIRDS_RELATES_TO_PARTY, iri(party));\n add(party, RDF_TYPE, iri(IIRDS_PARTY));\n add(party, IIRDS_HAS_PARTY_ROLE, iri(IIRDS_CREATOR));\n add(party, IIRDS_RELATES_TO_VCARD, iri(org));\n add(org, RDF_TYPE, iri(VCARD_ORGANIZATION));\n add(org, VCARD_ORGANIZATION_NAME, lit(opts.creator));\n }\n\n const docs = store\n .getQuads(null, DataFactory.namedNode(RDF_TYPE), DataFactory.namedNode(GRAPH_DOCUMENT), null)\n .map((q) => q.subject.value)\n .sort(byCodeUnit);\n\n const variants = new Set<string>();\n for (const doc of docs) {\n add(doc, RDF_TYPE, iri(IIRDS_TOPIC));\n add(doc, IIRDS_IS_PART_OF_PACKAGE, iri(pkg));\n\n const title = firstObject(store, doc, `${NS.dcterms}title`);\n if (title) add(doc, IIRDS_TITLE, lit(title));\n const language = firstObject(store, doc, `${NS.dcterms}language`);\n if (language) add(doc, IIRDS_LANGUAGE, lit(language));\n\n const path = firstObject(store, doc, `${NS.graph}path`);\n if (path) {\n // `graph:path` is relative to the directory the build labelled from: the\n // working directory for typed paths, the config's for a collection. A\n // corpus above it (`manni graph build ../external/*.md`, or a collection\n // whose `paths:` climb past the config file) is labelled\n // `../external/page.md`. Every other verb is happy with that — only a\n // container minds, because a container has a root and that path names\n // somewhere outside it. Refused here rather than in `resolveDocumentSet`\n // for exactly that reason: `build`, `query` and the rest keep working on\n // outside paths, and the one command that cannot represent them says so.\n // Checked before the file exists, since the escape is the finding even\n // when the file is also missing.\n if (escapesArchiveRoot(path)) {\n throw new GraphError(\n `Cannot package \"${path}\": an iiRDS package has one root, and a path that climbs above it has no place inside it. ` +\n \"Re-run `manni graph build` from a directory that contains every document, then export again.\",\n );\n }\n const absPath = resolve(cwd, path);\n if (!existsSync(absPath)) {\n throw new GraphError(\n `Content file for ${path} not found at ${absPath} — re-run \\`manni graph build\\`, or the source moved.`,\n );\n }\n const zipPath = `content/${path}`;\n const rendition = `${doc}/rendition`;\n add(doc, IIRDS_HAS_RENDITION, iri(rendition));\n add(rendition, RDF_TYPE, iri(IIRDS_RENDITION));\n add(rendition, IIRDS_SOURCE, lit(zipPath));\n add(rendition, IIRDS_FORMAT, lit(mediaTypeOf(path)));\n contentFiles.push({ zipPath, absPath });\n } else {\n warnings.push(\n `Document ${doc} has no graph:path — no rendition emitted.`,\n );\n }\n\n for (const pred of CARRIED) {\n for (const q of store.getQuads(\n DataFactory.namedNode(doc),\n DataFactory.namedNode(pred),\n null,\n null,\n )) {\n const o = q.object;\n if (o.termType === \"Literal\") {\n const dt = o.datatype.value;\n add(doc, pred, lit(o.value, dt !== XSD_STRING ? dt : undefined));\n } else {\n add(doc, pred, iri(o.value));\n if (pred === IIRDS_RELATES_TO_PRODUCT_VARIANT) variants.add(o.value);\n }\n }\n }\n }\n\n // Include the referenced ProductVariant nodes (type + label).\n for (const v of [...variants].sort(byCodeUnit)) {\n add(v, RDF_TYPE, iri(IIRDS_PRODUCT_VARIANT));\n const label = firstObject(store, v, `${NS.dcterms}title`);\n if (label) add(v, `${NS.dcterms}title`, lit(label));\n }\n\n const prefixes: Record<string, string> = {\n dcterms: NS.dcterms,\n iirds: NS.iirds,\n iirdsSft: NS.iirdsSft,\n rdf: NS.rdf,\n vcard: VCARD_NS,\n };\n\n return { quads, prefixes, contentFiles, warnings };\n}\n","/**\n * Deterministic ZIP writer — the container half of the iiRDS package export\n * (ADR 01017). Hand-rolled rather than a library, for the same reason the Turtle\n * emitter avoids N3.Writer: byte output must be a stability contract, not\n * incidental library behavior. Node is `>=24`, so `zlib.crc32`/`deflateRawSync`\n * are native — no dependency.\n *\n * Determinism: DOS timestamps pinned to a fixed epoch (1980-01-01, never the\n * wall clock), no extra fields, fixed version bytes, and entry order = the order\n * passed in. Two `writeZip` calls with the same input produce identical bytes.\n * The caller is responsible for putting a stored `mimetype` entry first (the\n * iiRDS/OCF container rule).\n */\nimport { crc32, deflateRawSync } from \"node:zlib\";\nimport { GraphError } from \"../types.js\";\n\n/**\n * Does this name let an extractor write outside the archive root?\n *\n * A ZIP entry name is a path a consumer joins onto its extraction directory,\n * and many implementations join without normalizing first. So `content/../x`\n * lands beside `content/`, not inside it, and `/etc/passwd` or `C:/…` lands\n * wherever it says. Absolute, drive-qualified, UNC and `..`-bearing names are\n * all refused; backslashes count as separators because a Windows-authored path\n * that reached here unconverted would otherwise smuggle `..` past a `/` split.\n *\n * Exported so the one predicate serves both ends: the iiRDS projection uses it\n * to refuse by document name, `writeZip` to refuse whatever it is handed.\n */\nexport function escapesArchiveRoot(name: string): boolean {\n const segments = name.split(/[/\\\\]/);\n return (\n name.startsWith(\"/\") ||\n name.startsWith(\"\\\\\") ||\n /^[A-Za-z]:/.test(name) ||\n segments.includes(\"..\")\n );\n}\n\nexport interface ZipEntry {\n /** In-archive path (forward slashes). */\n name: string;\n data: Buffer;\n /** Store uncompressed. Required for the leading `mimetype` entry. */\n store?: boolean;\n}\n\n// Pinned deterministic DOS date/time: 1980-01-01 00:00:00. A zeroed date byte\n// would encode an invalid day 0; 0x0021 is the earliest valid DOS date.\nconst DOS_DATE = 0x0021;\nconst DOS_TIME = 0x0000;\nconst VERSION = 20; // 2.0 — supports deflate; used for made-by and needed.\n\nexport function writeZip(entries: ZipEntry[]): Buffer {\n const locals: Buffer[] = [];\n const centrals: Buffer[] = [];\n let offset = 0;\n\n for (const entry of entries) {\n // The backstop under the projection's own refusal, which names the\n // document. This one names only the entry, because by here the document is\n // out of scope — but it is the guard that holds for a caller the export\n // command does not own yet.\n if (escapesArchiveRoot(entry.name)) {\n throw new GraphError(\n `Refusing ZIP entry \"${entry.name}\": an archive entry may not be absolute or climb above the archive root.`,\n );\n }\n const name = Buffer.from(entry.name, \"utf8\");\n // Flag bit 11 signals UTF-8 filenames; only needed for non-ASCII names.\n const flags = name.some((b) => b > 0x7f) ? 0x0800 : 0x0000;\n const method = entry.store ? 0 : 8;\n const stored = entry.store ? entry.data : deflateRawSync(entry.data);\n const crc = crc32(entry.data) >>> 0;\n\n const local = Buffer.alloc(30);\n local.writeUInt32LE(0x04034b50, 0);\n local.writeUInt16LE(VERSION, 4);\n local.writeUInt16LE(flags, 6);\n local.writeUInt16LE(method, 8);\n local.writeUInt16LE(DOS_TIME, 10);\n local.writeUInt16LE(DOS_DATE, 12);\n local.writeUInt32LE(crc, 14);\n local.writeUInt32LE(stored.length, 18);\n local.writeUInt32LE(entry.data.length, 22);\n local.writeUInt16LE(name.length, 26);\n local.writeUInt16LE(0, 28); // extra field length\n locals.push(local, name, stored);\n\n const central = Buffer.alloc(46);\n central.writeUInt32LE(0x02014b50, 0);\n central.writeUInt16LE(VERSION, 4); // version made by (host 0 = MS-DOS)\n central.writeUInt16LE(VERSION, 6); // version needed\n central.writeUInt16LE(flags, 8);\n central.writeUInt16LE(method, 10);\n central.writeUInt16LE(DOS_TIME, 12);\n central.writeUInt16LE(DOS_DATE, 14);\n central.writeUInt32LE(crc, 16);\n central.writeUInt32LE(stored.length, 20);\n central.writeUInt32LE(entry.data.length, 24);\n central.writeUInt16LE(name.length, 28);\n central.writeUInt16LE(0, 30); // extra field length\n central.writeUInt16LE(0, 32); // file comment length\n central.writeUInt16LE(0, 34); // disk number start\n central.writeUInt16LE(0, 36); // internal file attributes\n central.writeUInt32LE(0, 38); // external file attributes\n central.writeUInt32LE(offset, 42); // relative offset of local header\n centrals.push(central, name);\n\n offset += local.length + name.length + stored.length;\n }\n\n const centralBuf = Buffer.concat(centrals);\n const eocd = Buffer.alloc(22);\n eocd.writeUInt32LE(0x06054b50, 0);\n eocd.writeUInt16LE(0, 4); // number of this disk\n eocd.writeUInt16LE(0, 6); // disk where central directory starts\n eocd.writeUInt16LE(entries.length, 8); // cd records on this disk\n eocd.writeUInt16LE(entries.length, 10); // total cd records\n eocd.writeUInt32LE(centralBuf.length, 12); // size of central directory\n eocd.writeUInt32LE(offset, 16); // offset of start of central directory\n eocd.writeUInt16LE(0, 20); // .zip file comment length\n\n return Buffer.concat([...locals, centralBuf, eocd]);\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\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 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 const end = next?.start ?? lines.length;\n return lines.slice(match.start, end).join(\"\\n\").trimEnd();\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 };\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 return byCodeUnit(da, db);\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.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 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","/**\n * `manni graph query` — triple-pattern matching over the built graph. Any of\n * s/p/o may be omitted (wildcard). Prefixed names (`dcterms:references`)\n * and full IRIs are accepted; `--object` also matches literal values verbatim.\n */\nimport { resolve } from \"node:path\";\nimport { DataFactory } from \"n3\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { compactIri, expandTerm, loadGraph } from \"../core/load.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\n\nexport interface QueryOptions {\n s?: string;\n p?: string;\n o?: string;\n config?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n /** Graph path override (default: config `out`). */\n graph?: string;\n cwd?: string;\n}\n\nexport interface QueryMatch {\n s: string;\n p: string;\n o: { kind: \"iri\" | \"literal\"; value: string; datatype?: string };\n}\n\nexport interface QueryResult {\n matches: QueryMatch[];\n}\n\nexport function runQuery(opts: QueryOptions = {}): QueryResult {\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 store = loadGraph(resolve(cwd, opts.graph ?? config.out));\n\n const s = opts.s ? DataFactory.namedNode(expandTerm(opts.s)) : null;\n const p = opts.p ? DataFactory.namedNode(expandTerm(opts.p)) : null;\n const oValue = opts.o ? expandTerm(opts.o) : null;\n\n const matches: QueryMatch[] = [];\n for (const quad of store.getQuads(s, p, null, null)) {\n const obj = quad.object;\n if (oValue !== null && obj.value !== oValue) continue;\n matches.push({\n s: quad.subject.value,\n p: quad.predicate.value,\n o:\n obj.termType === \"Literal\"\n ? {\n kind: \"literal\",\n value: obj.value,\n ...(obj.datatype.value !==\n \"http://www.w3.org/2001/XMLSchema#string\"\n ? { datatype: obj.datatype.value }\n : {}),\n }\n : { kind: \"iri\", value: obj.value },\n });\n }\n\n // Compare field by field rather than joining into one key: every separator\n // choice is wrong in some way. NUL orders correctly (it sorts before any\n // real character) but makes git classify this file as binary, exempting it\n // from the repo's LF normalization. A printable separator like `|` keeps the\n // file text but sorts *after* most characters, which would rank a subject\n // behind one that merely extends it (`…/configuration.md` after\n // `…/configuration.md#advanced`). Field-wise comparison has neither problem\n // and is exactly equivalent to the original NUL-joined ordering.\n matches.sort(\n (a, b) =>\n byCodeUnit(a.s, b.s) ||\n byCodeUnit(a.p, b.p) ||\n byCodeUnit(a.o.kind, b.o.kind) ||\n byCodeUnit(a.o.value, b.o.value),\n );\n return { matches };\n}\n\nexport function renderQuery(\n result: QueryResult,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") return JSON.stringify(result, null, 2);\n if (result.matches.length === 0) return \"No matches.\";\n const lines = result.matches.map((m) => {\n const o =\n m.o.kind === \"iri\"\n ? `<${m.o.value}>`\n : `\"${m.o.value}\"${m.o.datatype ? `^^${compactIri(m.o.datatype)}` : \"\"}`;\n return `<${m.s}> ${compactIri(m.p)} ${o}`;\n });\n lines.push(`\\n${result.matches.length} match(es)`);\n return lines.join(\"\\n\");\n}\n","/**\n * `manni graph fill` — propose SKOS frontmatter fields (the `graph:` block) with an\n * LLM and write them back. Single-shot structured output per doc, content-hash\n * cached, bounded by a turn budget. Human-set fields are never overwritten\n * without `--force`; `--dry-run` reports without writing. Any per-doc failure\n * is recorded as a result, never aborts the run.\n */\nimport { readFileSync, writeFileSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\n\nimport {\n analyzeDoc,\n formatOf,\n metadataOf,\n type DocFormat,\n} from \"../core/analyze.js\";\nimport { loadRunConfig, type FillField } from \"../core/config.js\";\nimport type { DocModel } from \"../types.js\";\nimport {\n assertInputFormat,\n documentBase,\n documentSetPatterns,\n resolveDocumentSet,\n routesFrom,\n STDIN,\n type DocumentInputOptions,\n} from \"../core/discover.js\";\nimport { STDIN_PATH } from \"../core/iri.js\";\nimport {\n applyGraphFields,\n frontmatterKind,\n writeGraphFields,\n} from \"../core/frontmatter-edit.js\";\nimport { writeFileAtomic } from \"../../meta/index.js\";\nimport { DocmetaError } from \"../../meta/types.js\";\nimport {\n mergeMetaProvenance,\n spliceManifestValue,\n urlManifestMessage,\n type KeyHome,\n type MetaPageView,\n} from \"../../meta/internal.js\";\nimport { isMissing } from \"../../shared/manifest-cas.js\";\nimport { mergePage, openMetaView } from \"../core/external.js\";\nimport { FillGuard } from \"../core/fill-guard.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\nimport { bundledShapesPath } from \"../core/pkg.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { warn } from \"../../shared/warn.js\";\nimport { GraphError } from \"../types.js\";\nimport {\n completeValidatedJSON,\n validatorFor,\n type InferenceProvider,\n} from \"@hawkeyexl/inference\";\nimport { FillCache, cacheKey } from \"../llm/cache.js\";\nimport {\n SYSTEM_PROMPT,\n SECTION_FILL_FIELDS,\n buildUserPrompt,\n proposalSchema,\n} from \"../llm/prompt.js\";\nimport {\n announceSelection,\n assertProviderSelection,\n constructProvider,\n resolveProviderIdentity,\n selectProvider,\n} from \"../llm/provider.js\";\n\nexport interface FillOptions extends DocumentInputOptions {\n cwd?: string;\n dryRun?: boolean;\n force?: boolean;\n noCache?: boolean;\n /**\n * Stop after this many inference calls; overrides `fill.maxTurns`. A cached\n * proposal spends none (proposal 0051 §3).\n */\n maxTurns?: number;\n /**\n * Minimum model confidence to write a field; overrides\n * `fill.confidenceThreshold`.\n */\n confidence?: number;\n /** Fields to propose; overrides `fill.fields`. */\n fields?: FillField[];\n provider?: string;\n model?: string;\n /** Run inference on this machine with llama-cpp, over every configured choice. */\n local?: boolean;\n /** Disable the graph guardrail (`--no-validate-graph`). */\n noValidateGraph?: boolean;\n /** Propose per-section metadata as well as document-level (ADR 01032). */\n sections?: boolean;\n /** Injection seam for tests: bypasses the provider factory. */\n providerInstance?: InferenceProvider;\n /**\n * What `-` reads: the document from stdin, read by the caller. Required when\n * `paths` holds `-`. It is never written to disk: the report's\n * `stdinDocument` carries it back, filled or as it came.\n */\n stdinContent?: string;\n /** `--allow-empty`: zero matched files is an empty report, not an error. */\n allowEmpty?: boolean;\n}\n\nexport type FillStatus =\n | \"filled\"\n | \"proposed\" // dry run: would write\n | \"complete\" // nothing missing\n | \"nothing-proposed\"\n | \"skipped\"\n | \"error\";\n\n/** Why a page was skipped. The only reason today is the turn budget. */\nexport const TURN_BUDGET_REASON = \"turn budget\";\n\nexport interface FillDocResult {\n path: string;\n status: FillStatus;\n /**\n * Why a `skipped` page was skipped, said rather than left to be inferred —\n * the half of graph ADR 01027 that survives the dollar cap's removal.\n */\n reason?: string;\n /** Fields written (or that would be written under --dry-run). */\n fields: string[];\n /** Human-set fields the proposal was not allowed to touch. */\n preserved: string[];\n /** Fields dropped by the graph guardrail (fill.validateGraph). */\n rejected?: string[];\n /**\n * Section slugs the model proposed that match no heading in the document.\n * Dropped rather than written: writing one would mint a\n * graph:brokenSectionRef, a finding fill must report and never manufacture\n * (ADR 01032).\n */\n unknownSections?: string[];\n /** Fields the model proposed but scored below the confidence threshold (ADR 01015). */\n lowConfidence?: Array<{\n field: string;\n confidence: number;\n reasoning?: string;\n }>;\n cached: boolean;\n error?: string;\n}\n\nexport interface FillReport {\n results: FillDocResult[];\n /**\n * Inference calls this run made. Turns are countable for every model, where\n * a price was known for six of them — which is why the dollar cap went (graph\n * ADR 01027, proposal 0051 §3).\n */\n turnsUsed: number;\n /** The budget in force, or `null` for unbounded. */\n maxTurns: number | null;\n /** Non-fatal diagnostics. Never affects the exit code. */\n warnings: string[];\n exitCode: 0 | 1;\n /**\n * The document read from stdin, with the accepted fields written into it,\n * or unchanged when nothing was written. Absent when the run read no stdin\n * or the page errored. The CLI prints it to stdout; it is not part of the\n * rendered report.\n */\n stdinDocument?: string;\n}\n\n/** SKOS relation fields that require a `label` to attach to. */\nconst RELATION_FIELDS = [\n \"alt-labels\",\n \"broader\",\n \"narrower\",\n \"related-concepts\",\n] as const;\n\n/** A record's `{field → number}` sub-map, ignoring non-number entries. */\nfunction numberMap(v: unknown): Record<string, number> {\n const out: Record<string, number> = {};\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n // In range, or not a score at all (ADR 01034). A model that answers 90\n // where 0..1 was asked for meant \"very confident\", but reading it as\n // written would clear every threshold there is — the model's slip\n // becoming certainty. GBNF cannot express `minimum`/`maximum`, so no\n // grammar stops this upstream; dropping the score leaves the field\n // unscored, which the confidence gate already knows how to handle.\n if (typeof val === \"number\" && val >= 0 && val <= 1) out[k] = val;\n }\n }\n return out;\n}\n\n/** A record's `{field → string}` sub-map, ignoring non-string entries. */\nfunction stringMap(v: unknown): Record<string, string> {\n const out: Record<string, string> = {};\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n if (typeof val === \"string\") out[k] = val;\n }\n }\n return out;\n}\n\n/** Confidence stored to 2 decimals so the graph decimal literal is stable. */\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\n/** The page-level key `fill` records the fields it wrote in (proposal 0046). */\nconst META_PROVENANCE_KEY = \"meta-provenance\";\n\n/** A graph field as an RFC 6901 JSON Pointer into the page's `graph` block. */\nfunction graphPointer(field: string): string {\n return `/graph/${field.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")}`;\n}\n\nexport async function runFill(opts: FillOptions = {}): Promise<FillReport> {\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 ...(opts.paths === undefined ? {} : { paths: opts.paths }),\n ...(opts.collection === undefined ? {} : { collection: opts.collection }),\n },\n cwd,\n );\n\n // The flag, then `graph.provider`/`graph.model`, then the family's `providers:`,\n // then `auto`. `--local` is llama-cpp over both levels, so detection never\n // runs under it; a `--provider` it contradicts is refused by name, and a\n // configured one is set aside and said.\n //\n // Checked BEFORE the document set is resolved, and regardless of whether a\n // provider was injected. A contradiction in the flags is a usage error, and\n // a usage error must not be reported as whatever the file walk found first;\n // construction is lazy besides, so a typo would otherwise exit 0 on any run\n // where no page happened to need inference.\n const flags = {\n ...(opts.provider === undefined ? {} : { provider: opts.provider }),\n ...(opts.model === undefined ? {} : { model: opts.model }),\n ...(opts.local === undefined ? {} : { local: opts.local }),\n };\n const selection = selectProvider(config, flags);\n assertProviderSelection(selection);\n\n const format = assertInputFormat(opts.paths ?? [], opts.as);\n // Labels and reads share one base, the one `build` uses (`documentBase`).\n const base = documentBase(config, opts, cwd);\n const files = resolveDocumentSet(config, opts, \"fill\", cwd, base);\n const usingStdin = (opts.paths ?? []).includes(STDIN);\n if (files.length === 0 && !usingStdin) {\n if (opts.allowEmpty) {\n return {\n results: [],\n turnsUsed: 0,\n maxTurns: opts.maxTurns ?? config.fill.maxTurns,\n warnings: [],\n exitCode: 0,\n };\n }\n throw new GraphError(\n `No input files matched: ${documentSetPatterns(config, opts).join(\", \")} (cwd: ${cwd})`,\n );\n }\n if (usingStdin && opts.stdinContent === undefined) {\n throw new GraphError(\"graph fill was given `-` but no stdin content.\");\n }\n const stdinContent = usingStdin ? opts.stdinContent : undefined;\n const analyzeOptions = {\n routes: routesFrom(config, base),\n ...(format === undefined ? {} : { format }),\n };\n\n // Identity (for cache keys) is resolvable without constructing the provider;\n // construction — which may demand an API key — is deferred to the first\n // actual LLM call, so complete/cached runs need no credentials.\n //\n // The two branches are kept apart rather than merged behind a cast: an\n // injected provider's `provider()` is a free-form string, and only the\n // resolved path yields a name `constructProvider` can be trusted with.\n let identity: { provider: string; model: string };\n let construct: () => InferenceProvider;\n if (opts.providerInstance) {\n const injected = opts.providerInstance;\n identity = { provider: injected.provider(), model: injected.modelName() };\n construct = () => injected;\n // Still announce what `--local` replaced: the selection is what a real\n // run would have used, and the seam is a test's business, not the user's.\n announceSelection(selection);\n } else {\n const resolved = await resolveProviderIdentity(config, flags);\n identity = resolved;\n // Build from the RESOLVED identity, never the selection we started with:\n // under `auto` that still says \"auto\", and the synchronous library\n // constructor rightly refuses to guess.\n construct = () => constructProvider(config, resolved);\n }\n let provider: InferenceProvider | undefined;\n const getProvider = (): InferenceProvider => (provider ??= construct());\n\n const fields = opts.fields ?? config.fill.fields;\n // Compiled against the full configured field set, not any one doc's missing\n // subset: proposals are validated leniently and narrowed afterwards, so a\n // provider that volunteers a field this doc didn't ask for is fine.\n const withSections = opts.sections ?? config.fill.sections;\n // The section half of the schema is built from the FULL configured field\n // set, never from a document's missing set (ADR 01032): section presence is\n // independent of document presence, so a page whose `graph.type` is already\n // set must still be offered a section-level `type`. Narrowing this the way the\n // document half is narrowed handed a strictly-constrained provider a section\n // item with no data properties on it at all.\n const sectionFields = withSections\n ? fields.filter((f) => SECTION_FILL_FIELDS.includes(f))\n : undefined;\n // Validation uses the LENIENT schema (ADR 01034): the values are checked\n // exactly as strictly as ever, while the model's self-reported confidence and\n // reasoning are accepted in whatever shape they arrive. A weak provider that\n // scores one field with a string must not cost the run every other field it\n // got right.\n const validateProposal = validatorFor(\n proposalSchema(fields, { sections: sectionFields, lenient: true }),\n );\n const cache = new FillCache(\n resolve(cwd, config.fill.cacheDir),\n !opts.noCache,\n );\n const confidenceThreshold = opts.confidence ?? config.fill.confidenceThreshold;\n // Turns, not dollars. A turn is one inference call, which every model makes\n // and every model can be counted making — where a price was known for six\n // of them, so the cap it replaces read as zero for all the rest (graph ADR\n // 01027, docevals ADR 01019). `null` is unbounded.\n const maxTurns = opts.maxTurns ?? config.fill.maxTurns;\n\n const warnings: string[] = [];\n /**\n * Docs whose section fields were written but could not be recorded. A list\n * rather than a flag because `fillOne` sets it and `runFill` reads it: a\n * captured `let` assigned only inside a nested function stays narrowed to\n * its initializer at the read, so the warning below would be unreachable\n * code the compiler is entitled to assume never runs.\n */\n const sectionsUnrecorded: string[] = [];\n\n const allPaths = new Set(\n stdinContent === undefined ? files : [...files, STDIN_PATH],\n );\n const results: FillDocResult[] = [];\n let turnsUsed = 0;\n\n // Graph guardrail: simulate each proposal against the SHACL shapes before\n // writing it. Off via fill.validateGraph: false or --no-validate-graph.\n // The guard's base state is the FULL configured corpus, not the positional\n // path subset — a proposal for one doc can cycle with hierarchy that lives\n // in a doc outside the subset being filled. With no collections declared\n // there is no wider corpus to know about, so the subset is the corpus.\n const shapesPaths =\n config.check.shapes.length > 0\n ? config.check.shapes.map((p) => resolve(cwd, p))\n : [bundledShapesPath(import.meta.url)];\n const guardFiles = [\n ...new Set([\n ...(config.collections.length > 0\n ? resolveDocumentSet(config, {}, \"fill\", cwd, base)\n : []),\n ...files,\n ]),\n ];\n // `--as` is how the run's own inputs are parsed. A corpus page the guard\n // reads for context is parsed by its extension, as `build` would read it.\n const inputs = new Set(files);\n const formatFor = (path: string): DocFormat | undefined =>\n inputs.has(path) ? format : undefined;\n // Each page as `manni meta validate` reads it (proposal 0047): its own\n // frontmatter plus every key a manifest of its collections owns. What a page\n // already holds, the guard's corpus and the `meta-provenance` list a fill\n // extends are all read through it, so a value kept beside the page counts.\n //\n // A page meta will not read is that page's problem, not the run's. Named,\n // it is that page's error, reported by `fillOne`. Read only for context,\n // it is left out of the guard, and one warning lists it.\n const mergeErrors = new Map<string, unknown>();\n const view = await openMetaViewPerPage(\n {\n ...(opts.config === undefined ? {} : { configPath: opts.config }),\n ...(opts.noConfig === undefined ? {} : { noConfig: opts.noConfig }),\n },\n cwd,\n guardFiles,\n base,\n mergeErrors,\n );\n // Each page's merged text, computed once. `fillOne` reads it from here, so\n // no page is merged twice.\n const mergedTexts = new Map<string, string>();\n // The stdin page joins the guard's corpus from memory: it has no file. A\n // page whose manifests supply a key joins it as merged, so the simulation\n // sees what `graph build` would.\n const inline = new Map<string, string>();\n for (const path of guardFiles) {\n if (mergeErrors.has(path)) continue;\n let text: string;\n try {\n text = readFileSync(resolve(base, path), \"utf8\");\n } catch (e) {\n // A named page that cannot be read aborts the run below, as it always\n // has. One read only for context is left out of the guard.\n mergeErrors.set(path, e);\n continue;\n }\n let asMetaReadsIt: string;\n try {\n asMetaReadsIt = await mergedText(\n view,\n path,\n text,\n formatOf(path, formatFor(path)),\n );\n } catch (e) {\n mergeErrors.set(path, e);\n continue;\n }\n mergedTexts.set(path, asMetaReadsIt);\n if (asMetaReadsIt !== text) inline.set(path, asMetaReadsIt);\n }\n if (stdinContent !== undefined) inline.set(STDIN_PATH, stdinContent);\n const guard =\n !opts.noValidateGraph && config.fill.validateGraph\n ? FillGuard.create(\n guardFiles.filter((path) => !mergeErrors.has(path)),\n base,\n { ...config, routes: routesFrom(config, base) },\n shapesPaths,\n opts.force ?? false,\n {\n inline,\n ...(format === undefined ? {} : { format }),\n inputs: new Set([...files, STDIN_PATH]),\n },\n )\n : undefined;\n if (guard) {\n const leftOut = [\n ...guardFiles.filter((path) => !inputs.has(path) && mergeErrors.has(path)),\n ...guard.unreadable.filter((path) => !inputs.has(path) && path !== STDIN_PATH),\n ].sort(byCodeUnit);\n if (leftOut.length > 0) {\n warn(\n `The graph check left out ${String(leftOut.length)} page${leftOut.length === 1 ? \"\" : \"s\"} it could not read: ${leftOut.join(\", \")}. ` +\n \"Proposals were vetted without them. `manni meta validate` says what is wrong with each.\",\n );\n }\n }\n\n for (const path of files) {\n // Read failures are operational (deleted file, permissions) — abort the\n // whole run with exit 2 rather than burning LLM budget on the rest.\n const absPath = resolve(base, path);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf8\");\n } catch (e) {\n throw new GraphError(\n `cannot read ${path}: ${errorMessage(e)}`,\n );\n }\n try {\n results.push(await fillOne(path, absPath, content));\n } catch (e) {\n results.push({\n path,\n status: \"error\",\n fields: [],\n preserved: [],\n cached: false,\n error: errorMessage(e),\n });\n }\n }\n\n // The stdin page is filled last, after the named files, and never written:\n // what would have gone to disk comes back as `stdinDocument`.\n let stdinDocument: string | undefined;\n if (stdinContent !== undefined) {\n try {\n const result = await fillOne(STDIN_PATH, undefined, stdinContent);\n results.push(result);\n stdinDocument = result.filledContent ?? stdinContent;\n Reflect.deleteProperty(result, \"filledContent\");\n } catch (e) {\n results.push({\n path: STDIN_PATH,\n status: \"error\",\n fields: [],\n preserved: [],\n cached: false,\n error: errorMessage(e),\n });\n }\n }\n\n if (sectionsUnrecorded.length > 0) {\n warnings.push(\n \"Section metadata was written but is NOT recorded in meta-provenance: /graph/sections is \" +\n \"one of the three hand-curated pointers graph refuses, with /graph/revision-of and \" +\n \"/graph/derived-from, so recording it would make `manni graph check` report an error. \" +\n \"Review section values by hand — the review queue will not list them.\",\n );\n }\n\n const hasErrors = results.some((r) => r.status === \"error\");\n return {\n results,\n turnsUsed,\n maxTurns,\n warnings,\n exitCode: hasErrors ? 1 : 0,\n ...(stdinDocument === undefined ? {} : { stdinDocument }),\n };\n\n /**\n * Fill one page. `absPath` is where an accepted result is written; a page\n * read from stdin has none, and its result carries the filled text back in\n * `filledContent` instead.\n */\n async function fillOne(\n path: string,\n absPath: string | undefined,\n content: string,\n ): Promise<FillDocResult & { filledContent?: string }> {\n // `--as` is how every input parses, the stdin page included.\n const pageFormat = formatOf(path, format);\n // Refused before a turn is spent. graph's YAML editor is the Markdown\n // writer; every other format's writer is meta's, which refuses for itself.\n if (\n (pageFormat === \"markdown\" || pageFormat === \"mdx\") &&\n frontmatterKind(content) === \"unsupported\"\n ) {\n throw new GraphError(\n \"only YAML frontmatter can be edited (found a TOML/JSON fence) — exclude this file or convert its frontmatter\",\n );\n }\n\n // The page as meta reads it. Identical to `content` unless a manifest\n // supplies one of its keys, which is every page in a corpus with none.\n const effective = absPath === undefined ? content : mergedTexts.get(path);\n if (effective === undefined) {\n const failure = mergeErrors.get(path);\n throw failure instanceof Error\n ? failure\n : new GraphError(errorMessage(failure));\n }\n // A page that carries `graph:` while a manifest owns it is meta's\n // collision. meta's merge keeps the page's block, so a fill written to\n // the manifest would never reach `build`. Refused before any turn is spent.\n if (absPath !== undefined) {\n const own = metadataOf(content, path, pageFormat).data;\n if (GRAPH_KEY in own) {\n const home = await view.home(path, own, GRAPH_KEY);\n if (home.kind !== \"unowned\") {\n throw new GraphError(\n `\"${GRAPH_KEY}\" is owned by manifest ${home.file} (collection ${home.collection}); remove it from the document`,\n );\n }\n }\n }\n // What the page already holds, read as `build` reads its format.\n const held = metadataOf(effective, path, pageFormat).data;\n const heldGraph = held[GRAPH_KEY];\n const present = new Set(\n heldGraph !== null && typeof heldGraph === \"object\" && !Array.isArray(heldGraph)\n ? Object.keys(heldGraph)\n : [],\n );\n const missing = opts.force ? fields : fields.filter((f) => !present.has(f));\n // With --sections, a document whose own fields are complete may still have\n // unfilled sections, so completeness at document level is not completeness\n // (ADR 01032).\n if (missing.length === 0 && !withSections) {\n return {\n path,\n status: \"complete\",\n fields: [],\n preserved: [],\n cached: false,\n };\n }\n\n const key = cacheKey(\n identity.provider,\n identity.model,\n content,\n missing,\n withSections,\n );\n // Cached proposals are validated too: a stale or hand-edited cache entry\n // must not bypass the schema (treat invalid entries as a miss).\n let proposal = cache.get(key);\n if (proposal !== undefined && !validateProposal(proposal)) {\n proposal = undefined;\n }\n const cached = proposal !== undefined;\n\n // Lazy: a *cached* proposal can carry sections, so the slugs still need\n // checking outside the cache-miss branch — but a sections-off run that hits\n // the cache should not pay for a full markdown parse it never reads.\n let docModel: DocModel | undefined;\n const doc = (): DocModel =>\n (docModel ??= analyzeDoc(effective, path, allPaths, analyzeOptions));\n\n if (proposal === undefined) {\n // The budget is claimed here rather than at the top of the page, so a\n // cached proposal spends nothing: it makes no inference call, and a\n // budget that stopped a free page would report a skip nobody paid for\n // (docevals ADR 01019). Say why, which is the half of graph ADR 01027 that\n // outlives the dollar.\n if (maxTurns !== null && turnsUsed >= maxTurns) {\n return {\n path,\n status: \"skipped\",\n reason: TURN_BUDGET_REASON,\n fields: [],\n preserved: [],\n cached: false,\n };\n }\n turnsUsed++;\n // completeValidatedJSON validates and retries once before giving up.\n // fill previously aborted the document on a single malformed response;\n // one bad completion is not worth losing the work over.\n //\n // The request schema is narrowed to this doc's missing fields, so the\n // provider cannot propose fields the run should not touch. Validation\n // deliberately uses the WIDER configured-field schema: a provider that\n // volunteers extra fields is tolerated and narrowed below, not failed.\n const run = await completeValidatedJSON<Record<string, unknown>>({\n provider: getProvider(),\n system: SYSTEM_PROMPT,\n user: buildUserPrompt(doc(), content, missing, {\n sections: withSections,\n }),\n schema: proposalSchema(missing, { sections: sectionFields }),\n validate: validateProposal,\n temperature: config.fill.temperature,\n });\n if (run.result === undefined) {\n throw new Error(run.error ?? \"provider returned no proposal\");\n }\n proposal = run.result;\n cache.set(key, proposal);\n }\n\n // Per-field confidence + reasoning ride alongside the values (ADR 01015);\n // pull them out before narrowing filters to field keys.\n const confidence = numberMap(proposal[\"confidence\"]);\n const reasoning = stringMap(proposal[\"reasoning\"]);\n\n // Only requested fields survive, even if the cache or provider offered\n // more; string arrays are deduplicated (the 0.1 schema enforces\n // uniqueItems on what we write).\n const narrowed = Object.fromEntries(\n Object.entries(proposal)\n .filter(([k]) => missing.includes(k as FillField))\n .map(([k, v]) => [k, Array.isArray(v) ? [...new Set(v)] : v]),\n );\n\n // Section proposals arrive as a list of {slug, …} and become dotted field\n // names — `sections.<slug>.type` — so the writer, the confidence gate, the\n // graph guardrail and the provenance record all treat them as ordinary\n // fields (ADR 01032).\n const unknownSlugs: string[] = [];\n if (withSections) {\n const realSlugs = new Set(doc().sections.map((s) => s.slug));\n for (const entry of Array.isArray(proposal[\"sections\"])\n ? (proposal[\"sections\"] as Array<Record<string, unknown>>)\n : []) {\n const slug = typeof entry[\"slug\"] === \"string\" ? entry[\"slug\"] : \"\";\n // A slug matching no heading is dropped, never written. Writing it\n // would mint a graph:brokenSectionRef — a finding fill must report\n // rather than manufacture.\n if (!realSlugs.has(slug)) {\n if (slug) unknownSlugs.push(slug);\n continue;\n }\n const entryConfidence = numberMap(entry[\"confidence\"]);\n const entryReasoning = stringMap(entry[\"reasoning\"]);\n for (const [field, value] of Object.entries(entry)) {\n if (!SECTION_FILL_FIELDS.includes(field as FillField)) continue;\n if (!fields.includes(field as FillField)) continue;\n const name = `sections.${slug}.${field}`;\n narrowed[name] = Array.isArray(value) ? [...new Set(value)] : value;\n // Fold the per-section scores into the flat maps the gate reads, so\n // one code path scores document and section fields alike.\n if (entryConfidence[field] !== undefined)\n confidence[name] = entryConfidence[field];\n if (entryReasoning[field] !== undefined)\n reasoning[name] = entryReasoning[field];\n }\n }\n }\n\n // manni:graph requires `label` alongside any alt-label/relation field\n // (dependentRequired) — never write output our own validate rejects.\n // Rechecked after the guardrail: rejecting `label` takes the relation\n // fields down with it.\n const gateLabel = (): void => {\n const hasLabel =\n present.has(\"label\") ||\n (typeof narrowed[\"label\"] === \"string\" && narrowed[\"label\"].length > 0);\n if (!hasLabel) {\n for (const field of RELATION_FIELDS) Reflect.deleteProperty(narrowed, field);\n }\n };\n gateLabel();\n\n // Confidence gate (ADR 01015): drop any field the model scored below the\n // threshold (or did not score at all — no score means no write). This\n // runs before the structural guardrail; the two are orthogonal, and the\n // confidence gate covers every field, not just the guarded subset. A drop\n // here is normal operation, reported but never an error (exit stays 0).\n const lowConfidence: FillDocResult[\"lowConfidence\"] = [];\n for (const field of Object.keys(narrowed)) {\n // Unscored counts as 0, so `confidenceThreshold: 0` stays a working\n // opt-out from the gate. The related hazard — stamping a confidence the\n // model never gave into meta-provenance — is fixed where that record is\n // built, not here.\n const c = confidence[field] ?? 0;\n if (c < confidenceThreshold) {\n lowConfidence.push({\n field,\n confidence: c,\n ...(reasoning[field] ? { reasoning: reasoning[field] } : {}),\n });\n Reflect.deleteProperty(narrowed, field);\n }\n }\n if (lowConfidence.length > 0) gateLabel();\n const lowConf = lowConfidence.length > 0 ? { lowConfidence } : {};\n\n // Graph guardrail: drop any field whose triples would violate the\n // shapes contract (cycles, related⨯broader conflicts, second spellings\n // of an existing concept). Cached proposals are vetted too — rejection\n // sits downstream of the cache, so a later corpus change can re-admit\n // a proposal without re-asking the LLM.\n let rejected: string[] | undefined;\n if (guard) {\n const vetted = await guard.vet(path, effective, narrowed);\n if (vetted.rejected.length > 0) {\n rejected = vetted.rejected.map((r) => r.field);\n for (const field of rejected) Reflect.deleteProperty(narrowed, field);\n gateLabel();\n }\n }\n\n // Which fields will actually be written (mirrors applyGraphFields' filter);\n // empty means nothing to do — and no provenance entry either.\n const realFields = Object.keys(narrowed).filter((k) => {\n const v = narrowed[k];\n return (\n v !== undefined && v !== null && !(Array.isArray(v) && v.length === 0)\n );\n });\n if (realFields.length === 0) {\n return {\n path,\n status: \"nothing-proposed\",\n fields: [],\n preserved: [],\n ...(rejected ? { rejected } : {}),\n ...(unknownSlugs.length > 0 ? { unknownSections: unknownSlugs } : {}),\n ...lowConf,\n cached,\n };\n }\n\n // Record machine attribution alongside the fields, in the SAME write.\n // It goes in the page-level `meta-provenance` now (proposal 0046), through\n // meta's own merge: one entry per model, this model's entry gaining the\n // pointers this run wrote, and every other entry — including the ones\n // `manni docevals fill` wrote — carried through untouched.\n let provenanceList: unknown[] | undefined;\n if (config.fill.writeProvenance) {\n // Document-level names only. `sections.<slug>.<field>` is a pointer\n // under `/graph/sections`, and `sections` is one of the three fields\n // curated by hand — recording it is exactly what graph's harvest now\n // reports as a `manni graph check` error (0046 stress test 13). So the\n // rule stays, and the reason it stays is a different one.\n const recordable = realFields.filter((f) => !f.includes(\".\")).sort();\n // Loud, not silent: metadata a model wrote with no entry in the review\n // queue is exactly the thing this record exists to prevent.\n if (recordable.length < realFields.length) sectionsUnrecorded.push(path);\n // Only record a score the model actually gave. `?? 0` stamped a\n // confidence of 0.00 the model never asserted whenever it omitted one,\n // which `fill.confidenceThreshold: 0` makes reachable.\n // As held, uncoerced: `mergeMetaProvenance` decides what a non-list\n // means, and carries through every key of an entry it does not know.\n const heldProvenance = held[META_PROVENANCE_KEY];\n const priorEntry = Array.isArray(heldProvenance)\n ? (heldProvenance as unknown[]).find(\n (e): e is Record<string, unknown> =>\n !!e &&\n typeof e === \"object\" &&\n !Array.isArray(e) &&\n (e as Record<string, unknown>)[\"generated-by\"] ===\n identity.model,\n )\n : undefined;\n const priorConfidence = numberMap(priorEntry?.[\"confidence\"]);\n const proposed = recordable.map((f) => {\n const name = graphPointer(f);\n const c = confidence[f];\n return {\n name,\n confidence: c === undefined ? (priorConfidence[name] ?? 0) : round2(c),\n };\n });\n const unscored = recordable\n .map((f) => [f, graphPointer(f)] as const)\n .filter(\n ([f, name]) =>\n confidence[f] === undefined && priorConfidence[name] === undefined,\n )\n .map(([, name]) => name);\n const merged = mergeMetaProvenance(\n heldProvenance,\n identity.model,\n \"fields\",\n proposed,\n );\n // `undefined` is a page holding something other than a list under the\n // key. Reported by `manni meta validate`, not worth failing the fill over:\n // a side record that could block filling would be worse than none.\n if (merged) {\n // The merge sets a confidence for every name it is handed; a pointer\n // nobody has ever scored keeps none.\n for (const name of unscored)\n Reflect.deleteProperty(merged.entry.confidence, name);\n provenanceList = merged.list;\n }\n }\n\n // Applied to the page as meta reads it, so a value a manifest holds is\n // preserved exactly as one on the page would be.\n const applied = writeGraphFields(effective, path, pageFormat, narrowed, {\n force: opts.force,\n });\n const reportedFields = applied.applied;\n\n if (reportedFields.length === 0) {\n return {\n path,\n status: \"nothing-proposed\",\n fields: [],\n preserved: applied.skipped,\n ...(rejected ? { rejected } : {}),\n ...(unknownSlugs.length > 0 ? { unknownSections: unknownSlugs } : {}),\n ...lowConf,\n cached,\n };\n }\n\n // Where each key is written is meta's rule (proposal 0047), the one\n // `manni meta fill` follows: a key a local manifest owns goes to the page's\n // entry there, and every other key stays on the page. A page from stdin\n // has no manifest, so everything it gets is in the text printed back.\n const own = metadataOf(content, path, pageFormat).data;\n const graphHome =\n absPath === undefined ? undefined : await view.home(path, own, GRAPH_KEY);\n const provenanceHome =\n absPath === undefined || provenanceList === undefined\n ? undefined\n : await view.home(path, own, META_PROVENANCE_KEY);\n const graphTarget = writeTarget(path, graphHome, GRAPH_KEY);\n if (typeof graphTarget === \"string\") throw new GraphError(graphTarget);\n let provenanceTarget = writeTarget(path, provenanceHome, META_PROVENANCE_KEY);\n if (typeof provenanceTarget === \"string\") {\n // A side record that could block filling would be worse than none, so\n // the fields are written and the record is not, and the run says so.\n warnings.push(`${provenanceTarget} The fill of ${path} is not recorded.`);\n provenanceList = undefined;\n provenanceTarget = null;\n }\n\n const pageKeys: Record<string, unknown> = {};\n if (provenanceList !== undefined && provenanceTarget === null) {\n pageKeys[META_PROVENANCE_KEY] = provenanceList;\n }\n const pageContent = writeGraphFields(\n content,\n path,\n pageFormat,\n graphTarget === null ? narrowed : {},\n { force: opts.force, page: pageKeys },\n ).content;\n\n const manifestWrites: ManifestWrite[] = [];\n // A manifest that owns `graph:` gets the whole block as meta reads it,\n // merged and then filled. A page that also carries one was refused above:\n // meta keeps the page's value, so the manifest's would never be read.\n if (graphTarget !== null) {\n manifestWrites.push({\n home: graphTarget,\n key: GRAPH_KEY,\n value: metadataOf(applied.content, path, pageFormat).data[GRAPH_KEY],\n });\n }\n if (provenanceList !== undefined && provenanceTarget !== null) {\n manifestWrites.push({\n home: provenanceTarget,\n key: META_PROVENANCE_KEY,\n value: provenanceList,\n });\n }\n // Every splice is made before anything is written, so a manifest meta\n // refuses leaves the page untouched too.\n const manifests = await spliceAll(manifestWrites);\n\n if (!opts.dryRun && absPath !== undefined) {\n if (pageContent !== content) writeFileSync(absPath, pageContent, \"utf8\");\n for (const m of manifests) {\n if (m.text !== m.before) {\n await writeFileAtomic(m.absPath, m.text, { createParents: true });\n }\n }\n }\n // Fold the accepted result into the guard even on --dry-run, so the dry\n // run predicts exactly what a real run would accept and reject.\n guard?.commit(path, applied.content);\n return {\n path,\n status: opts.dryRun ? \"proposed\" : \"filled\",\n fields: reportedFields,\n preserved: applied.skipped,\n ...(rejected ? { rejected } : {}),\n ...(unknownSlugs.length > 0 ? { unknownSections: unknownSlugs } : {}),\n ...lowConf,\n cached,\n ...(absPath === undefined && !opts.dryRun\n ? { filledContent: pageContent }\n : {}),\n };\n }\n}\n\n/** The page key holding the graph block. */\nconst GRAPH_KEY = \"graph\";\n\n/** A manifest a key is written to, with the page's entry there. */\ninterface ManifestTarget {\n file: string;\n absPath: string;\n join: string;\n entry: string;\n perPage: boolean;\n}\n\n/** One value written into one manifest entry. */\ninterface ManifestWrite {\n home: ManifestTarget;\n key: string;\n value: unknown;\n}\n\n/**\n * Where `key` goes: `null` for the page, the manifest entry, or meta's\n * sentence for a manifest that cannot take it, which is a fetched one or one\n * that joins on a field the page lacks.\n */\nfunction writeTarget(\n path: string,\n home: KeyHome | undefined,\n key: string,\n): ManifestTarget | string | null {\n if (home === undefined || home.kind === \"unowned\") return null;\n if (home.kind === \"url\") return urlManifestMessage(key, home.file);\n if (home.entry === undefined) {\n return `${path} carries no ${home.join}, which ${home.file} joins on, so its ${key} has no entry there.`;\n }\n return {\n file: home.file,\n absPath: home.absPath,\n join: home.join,\n entry: home.entry,\n perPage: home.perPage,\n };\n}\n\n/**\n * Each manifest's text with its writes spliced in, through meta's splice, which\n * changes no other byte of the file. A `{page}` manifest that is not on disk\n * yet is held as empty and created by the write, as `manni meta fill` does.\n */\nasync function spliceAll(\n writes: readonly ManifestWrite[],\n): Promise<Array<{ absPath: string; before: string; text: string }>> {\n const out = new Map<string, { absPath: string; before: string; text: string }>();\n for (const w of writes) {\n let held = out.get(w.home.absPath);\n if (held === undefined) {\n let before: string;\n try {\n before = await readFile(w.home.absPath, \"utf8\");\n } catch (e) {\n if (!(w.home.perPage && isMissing(e))) {\n throw new GraphError(`${w.home.file} could not be read: ${errorMessage(e)}`);\n }\n before = \"\";\n }\n held = { absPath: w.home.absPath, before, text: before };\n out.set(w.home.absPath, held);\n }\n try {\n held.text = spliceManifestValue(held.text, {\n entry: w.home.entry,\n key: w.key,\n value: w.value,\n join: w.home.join,\n file: w.home.file,\n }).text;\n } catch (e) {\n throw new GraphError(errorMessage(e));\n }\n }\n return [...out.values()];\n}\n\n/**\n * `content` with every key its manifests supply written into its metadata,\n * so it reads as meta reads the page. `content` itself when none does. A\n * Markdown frontmatter graph cannot edit is left alone, and `fill` refuses\n * that page.\n */\nasync function mergedText(\n view: MetaPageView,\n path: string,\n content: string,\n format: DocFormat,\n): Promise<string> {\n const markdown = format === \"markdown\" || format === \"mdx\";\n if (markdown && frontmatterKind(content) === \"unsupported\") return content;\n const own = metadataOf(content, path, format);\n const { supplied } = await mergePage(view, path, own.data, own.present, format);\n if (Object.keys(supplied).length === 0) return content;\n try {\n return writeGraphFields(content, path, format, {}, { page: supplied })\n .content;\n } catch (e) {\n // An AsciiDoc or reStructuredText page with no fence cannot take a write,\n // and need not when its manifest holds every key fill writes. This text\n // is read, never written, and both readers read a YAML fence, so a new\n // one reads as meta's merge does. A key whose home is the page still\n // meets meta's refusal when it is written. Only that refusal falls back:\n // anything else is the page's own problem, and a new fence would hide it.\n const noFence =\n (format === \"asciidoc\" || format === \"rst\") && e instanceof DocmetaError;\n if (!noFence) throw e;\n return applyGraphFields(content, path, {}, { page: supplied }).content;\n }\n}\n\n/**\n * Meta's view of `paths`, with a page meta refuses left out rather than\n * failing the run. One view over every page is tried first, so the common\n * case reads each manifest once. When it is refused, each page is opened on\n * its own to find the ones at fault, and each lands in `failures`.\n *\n * A refusal that holds with no page at all is not any page's. A broken\n * config or shared manifest stays an operational error, exit 2.\n */\nasync function openMetaViewPerPage(\n source: Parameters<typeof openMetaView>[0],\n cwd: string,\n paths: readonly string[],\n base: string,\n failures: Map<string, unknown>,\n): Promise<MetaPageView> {\n try {\n return await openMetaView(source, cwd, paths, base);\n } catch (whole) {\n await openMetaView(source, cwd, [], base);\n const readable: string[] = [];\n for (const path of paths) {\n try {\n await openMetaView(source, cwd, [path], base);\n readable.push(path);\n } catch (e) {\n failures.set(path, e);\n }\n }\n if (readable.length === paths.length) throw whole;\n return openMetaView(source, cwd, readable, base);\n }\n}\n\nexport function renderFill(\n report: FillReport,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") {\n // The stdin document is output of its own, never part of the report.\n return JSON.stringify({ ...report, stdinDocument: undefined }, null, 2);\n }\n const lines: string[] = [];\n for (const r of report.results) {\n const dropped =\n r.rejected && r.rejected.length > 0\n ? ` [graph check rejected: ${r.rejected.join(\", \")}]`\n : \"\";\n const lowConf =\n r.lowConfidence && r.lowConfidence.length > 0\n ? ` [low confidence, not written: ${r.lowConfidence\n .map((l) => `${l.field} ${l.confidence.toFixed(2)}`)\n .join(\", \")}]`\n : \"\";\n // Visible rather than silent: the model addressed a heading that is not\n // there, which usually means the page was edited after it was described.\n const unknown =\n r.unknownSections && r.unknownSections.length > 0\n ? ` [no such section: ${r.unknownSections.join(\", \")}]`\n : \"\";\n switch (r.status) {\n case \"filled\":\n lines.push(\n `filled ${r.path} (${r.fields.join(\", \")})${r.cached ? \" [cached]\" : \"\"}${dropped}${unknown}${lowConf}`,\n );\n break;\n case \"proposed\":\n lines.push(\n `proposed ${r.path} (${r.fields.join(\", \")})${r.cached ? \" [cached]\" : \"\"}${dropped}${unknown}${lowConf} — dry run, not written`,\n );\n break;\n case \"complete\":\n lines.push(`complete ${r.path}`);\n break;\n case \"nothing-proposed\":\n lines.push(\n `no-op ${r.path} (model proposed nothing new)${dropped}${unknown}${lowConf}`,\n );\n break;\n case \"skipped\":\n lines.push(`skipped ${r.path} (${r.reason ?? \"not processed\"})`);\n break;\n case \"error\":\n lines.push(`error ${r.path}: ${r.error ?? \"\"}`);\n break;\n }\n }\n // A run cut short covered less than it was asked to, and the per-page lines\n // say which pages. Say once that the budget is why, so the number to raise\n // is on screen next to them.\n if (\n report.maxTurns !== null &&\n report.results.some((r) => r.status === \"skipped\")\n ) {\n lines.push(\n \"\",\n `--max-turns reached (${report.maxTurns}); some pages were not processed.`,\n );\n }\n return lines.join(\"\\n\");\n}\n","/**\n * Surgical YAML edits (ported from docevals). Only the frontmatter block is\n * re-serialized via the `yaml` Document API — the page body is carried over\n * byte-for-byte, and untouched YAML keeps its comments and ordering. When a\n * file has no frontmatter, a new block holding only the `graph` key is created.\n * YAML frontmatter only; TOML/JSON frontmatter cannot be edited in place.\n * `writeGraphFields` routes every other format to meta's writer.\n */\nimport { Document, YAMLMap, YAMLSeq, isMap, parseDocument } from \"yaml\";\nimport { GraphError } from \"../types.js\";\nimport { extractorFor, metadataOf, type DocFormat } from \"./analyze.js\";\n\nconst GRAPH_KEY = \"graph\";\n\ninterface Split {\n /** The opening fence line including its newline (plus any BOM). */\n open: string;\n /** Raw YAML between the fences. */\n block: string;\n /** Everything from the closing fence to EOF, byte-identical. */\n suffix: string;\n /** Line ending style of the file. */\n eol: \"\\n\" | \"\\r\\n\";\n}\n\n/**\n * What kind of frontmatter block a file opens with. docmeta reads TOML (+++)\n * and JSON (;;;) fences too, but only YAML is editable in place — callers\n * must not treat \"unsupported\" as \"absent\" or they will stack a second block.\n */\nexport function frontmatterKind(\n content: string,\n): \"yaml\" | \"unsupported\" | \"none\" {\n const body = content.charCodeAt(0) === 0xfeff ? content.slice(1) : content;\n if (/^---(\\r?\\n)/.test(body)) return \"yaml\";\n if (/^(\\+\\+\\+|;;;)(\\r?\\n)/.test(body)) return \"unsupported\";\n return \"none\";\n}\n\nfunction splitYamlFrontmatter(content: string, path: string): Split | null {\n // `slice` rather than `content[0]`: it yields a string for an empty input\n // too, which is the only case the index could have missed.\n const bom = content.charCodeAt(0) === 0xfeff ? content.slice(0, 1) : \"\";\n const body = bom ? content.slice(1) : content;\n const openMatch = /^---(\\r?\\n)/.exec(body);\n if (!openMatch) return null;\n const eol: \"\\n\" | \"\\r\\n\" = openMatch[1] === \"\\r\\n\" ? \"\\r\\n\" : \"\\n\";\n // `String.split` always yields at least one element, and the regex matched\n // `---\\n` at the start, so the first line is the opening fence.\n const [openLine = \"\", ...rest] = body.split(/(?<=\\n)/); // keep line endings\n let offset = openLine.length;\n for (const line of rest) {\n const stripped = line.replace(/\\r?\\n$/, \"\");\n if (stripped === \"---\" || stripped === \"...\") {\n const blockEnd = offset;\n return {\n open: bom + openLine,\n block: body.slice(openLine.length, blockEnd),\n suffix: body.slice(blockEnd),\n eol,\n };\n }\n offset += line.length;\n }\n throw new GraphError(`${path}: unterminated frontmatter block`);\n}\n\nexport interface GraphApplyResult {\n content: string;\n /** Fields written. */\n applied: string[];\n /** Fields left alone because a human-set value exists (and no force). */\n skipped: string[];\n}\n\n/** Render every sequence under `node` flow-style: [a, b]. */\nfunction flowSeqs(node: unknown): void {\n if (node instanceof YAMLSeq) {\n node.flow = true;\n for (const item of node.items) flowSeqs(item);\n } else if (node instanceof YAMLMap) {\n for (const item of node.items) flowSeqs(item.value);\n }\n}\n\n/** Set `value` on a map in the graph block; arrays (incl. nested) render flow. */\nfunction setField(\n doc: Document,\n map: YAMLMap,\n field: string,\n value: unknown,\n): void {\n const node = doc.createNode(value);\n flowSeqs(node);\n map.set(field, node);\n}\n\nexport interface GraphApplyOptions {\n /** Overwrite values a human already set. */\n force?: boolean;\n /**\n * Keys to write at the TOP level of the frontmatter, beside `graph` rather\n * than inside it — `meta-provenance` is the one caller (proposal 0046).\n * They are always overwritten, because the caller computes each value\n * whole, and they are written even when `values` is empty. Kept in this\n * one function so a fill is still one parse and one serialization of the\n * block, and the body stays byte-identical either way.\n */\n page?: Record<string, unknown>;\n}\n\n/**\n * Apply proposed values to the top-level `graph` map of a doc's frontmatter,\n * plus any `options.page` keys beside it. Existing field values win unless\n * `force`. The body after the closing fence is byte-identical to the input.\n */\nexport function applyGraphFields(\n content: string,\n path: string,\n values: Record<string, unknown>,\n options: GraphApplyOptions = {},\n): GraphApplyResult {\n const entries = writable(values);\n const pageEntries = Object.entries(options.page ?? {});\n if (entries.length === 0 && pageEntries.length === 0) {\n return { content, applied: [], skipped: [] };\n }\n\n if (frontmatterKind(content) === \"unsupported\") {\n throw new GraphError(\n `${path}: only YAML frontmatter can be edited (found a TOML/JSON fence)`,\n );\n }\n\n const split = splitYamlFrontmatter(content, path);\n\n if (split === null) {\n // No frontmatter — create a block holding only the graph key. Dotted\n // names nest here too, or `sections.intro.type` would become a literal key.\n const eol: \"\\n\" | \"\\r\\n\" = content.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const nested: Record<string, unknown> = {};\n for (const [field, value] of entries) {\n const segments = field.split(\".\");\n let target = nested;\n for (const segment of segments.slice(0, -1)) {\n target[segment] ??= {};\n target = target[segment] as Record<string, unknown>;\n }\n // An undotted field is its own leaf, so `field` is the right fallback\n // rather than a stand-in: `split(\".\")` cannot return an empty list.\n target[segments.at(-1) ?? field] = value;\n }\n const doc = new Document({\n ...Object.fromEntries(pageEntries),\n ...(entries.length > 0 ? { graph: nested } : {}),\n });\n const graph = doc.get(\"graph\", true);\n if (isMap(graph)) flowSeqs(graph);\n let block = doc.toString();\n if (eol === \"\\r\\n\") block = block.replace(/(?<!\\r)\\n/g, \"\\r\\n\");\n return {\n content: `---${eol}${block}---${eol}${eol}${content}`,\n applied: entries.map(([k]) => k),\n skipped: [],\n };\n }\n\n const doc = parseDocument(split.block);\n if (doc.errors.length > 0) {\n throw new GraphError(\n `${path}: cannot edit frontmatter — ${doc.errors[0]?.message ?? \"parse error\"}`,\n );\n }\n\n let graph = doc.get(\"graph\", true);\n if (graph !== undefined && !isMap(graph)) {\n throw new GraphError(`${path}: frontmatter key \"graph\" is not a map`);\n }\n if (graph === undefined && entries.length > 0) {\n graph = doc.createNode({});\n doc.set(\"graph\", graph);\n }\n const graphMap = (graph ?? doc.createNode({})) as YAMLMap;\n\n const { applied, skipped } = mergeFields(doc, graphMap, entries, options.force);\n\n // Top-level keys, after the graph map so a new `graph` sorts where it always\n // did.\n // Block style, not `flowSeqs`: this is a record a reviewer reads and edits\n // by hand, one entry per line, not a value the graph derives from.\n for (const [key, value] of pageEntries) {\n doc.set(key, doc.createNode(value));\n }\n\n if (applied.length === 0 && pageEntries.length === 0) {\n return { content, applied, skipped };\n }\n\n let newBlock = doc.toString();\n if (split.eol === \"\\r\\n\") newBlock = newBlock.replace(/(?<!\\r)\\n/g, \"\\r\\n\");\n return { content: split.open + newBlock + split.suffix, applied, skipped };\n}\n\n/** The proposed values worth writing: no empty value and no empty list. */\nfunction writable(values: Record<string, unknown>): Array<[string, unknown]> {\n return Object.entries(values).filter(\n ([, v]) =>\n v !== undefined && v !== null && !(Array.isArray(v) && v.length === 0),\n );\n}\n\n/**\n * Merge `entries` into a page's `graph` map. This is the rule for what a fill\n * may change, and both writers run it: a human-set value stays unless `force`,\n * decided at the leaf, and a non-map where a map must go is left alone.\n */\nfunction mergeFields(\n doc: Document,\n graphMap: YAMLMap,\n entries: ReadonlyArray<[string, unknown]>,\n force: boolean | undefined,\n): { applied: string[]; skipped: string[] } {\n const applied: string[] = [];\n const skipped: string[] = [];\n for (const [field, value] of entries) {\n // A dotted name addresses a nested field — `sections.<slug>.type` writes\n // into graph.sections.<slug>.type (ADR 01032). Preservation is decided at\n // the *leaf*, so filling one section's type never disturbs a value a human\n // set on the section beside it.\n const segments = field.split(\".\");\n // An undotted field is its own leaf, so `field` is the right fallback\n // rather than a stand-in: `split(\".\")` cannot return an empty list.\n const leaf = segments.at(-1) ?? field;\n let target = graphMap;\n let missingParent = false;\n for (const segment of segments.slice(0, -1)) {\n const existing = target.get(segment, true);\n if (existing === undefined) {\n const created = doc.createNode({}) as YAMLMap;\n target.set(segment, created);\n target = created;\n } else if (isMap(existing)) {\n target = existing;\n } else {\n // A non-map where a map must go: leave the author's value alone rather\n // than overwrite a shape we do not understand.\n missingParent = true;\n break;\n }\n }\n if (missingParent) {\n skipped.push(field);\n continue;\n }\n if (target.has(leaf) && !force) {\n skipped.push(field);\n continue;\n }\n setField(doc, target, leaf, value);\n applied.push(field);\n }\n return { applied, skipped };\n}\n\n/**\n * Write a proposal into a page of any format: the one writer `fill`'s real\n * write, its guard's simulation and its manifest merge all use, so what is\n * vetted is what is written.\n *\n * Markdown and MDX keep graph's YAML editor above. Every other format is\n * written by its meta extractor's `apply`, with the page's `graph` map merged\n * by the same rule, so HTML gets a `<meta name=\"graph\">`, DITA an\n * `<othermeta>`, and a fenced AsciiDoc or reStructuredText page its fence\n * (proposal 0077 §4). A page that writer cannot take throws meta's\n * `DocmetaError`, in meta's words.\n */\nexport function writeGraphFields(\n content: string,\n path: string,\n format: DocFormat,\n values: Record<string, unknown>,\n options: GraphApplyOptions = {},\n): GraphApplyResult {\n if (format === \"markdown\" || format === \"mdx\") {\n return applyGraphFields(content, path, values, options);\n }\n const entries = writable(values);\n const patch: Record<string, unknown> = {};\n let applied: string[] = [];\n let skipped: string[] = [];\n if (entries.length > 0) {\n // The page's map, held as a YAML document so the merge is the one the\n // Markdown writer runs on its frontmatter, not a second spelling of it.\n const doc = new Document(\n metadataOf(content, path, format).data[GRAPH_KEY] ?? {},\n );\n if (!isMap(doc.contents)) {\n throw new GraphError(`${path}: metadata key \"graph\" is not a map`);\n }\n ({ applied, skipped } = mergeFields(\n doc,\n doc.contents,\n entries,\n options.force,\n ));\n if (applied.length > 0) patch[GRAPH_KEY] = doc.toJS();\n }\n Object.assign(patch, options.page);\n if (Object.keys(patch).length === 0) return { content, applied, skipped };\n const apply = extractorFor(format)?.apply;\n if (apply === undefined) {\n throw new GraphError(`${path}: manni cannot write ${format} metadata`);\n }\n return { content: apply(content, patch, { filePath: path }), applied, skipped };\n}\n\n/** The doc's parsed frontmatter as plain data, `{}` when there is none. */\nfunction frontmatterData(content: string): Record<string, unknown> {\n const split = splitYamlFrontmatter(content, \"\");\n if (split === null) return {};\n const doc = parseDocument(split.block);\n if (doc.errors.length > 0) return {};\n const plain = doc.toJS() as unknown;\n return plain !== null && typeof plain === \"object\" && !Array.isArray(plain)\n ? (plain as Record<string, unknown>)\n : {};\n}\n\n/**\n * The doc's page-level `meta-provenance` value, exactly as held — `undefined`\n * when the page has none. Uncoerced on purpose: `mergeMetaProvenance` decides\n * what a non-list means, and every key of an entry it does not know is carried\n * through, so a `docevals` entry survives a `graph fill`.\n */\nexport function existingMetaProvenance(content: string): unknown {\n return frontmatterData(content)[\"meta-provenance\"];\n}\n\n/** Fields already present on the doc's `graph` map ([] when none). */\nexport function existingGraphFields(content: string): string[] {\n const split = splitYamlFrontmatter(content, \"\");\n if (split === null) return [];\n const doc = parseDocument(split.block);\n if (doc.errors.length > 0) return [];\n const graph = doc.get(\"graph\", true);\n if (!isMap(graph)) return [];\n return graph.items\n .map((item) => {\n const value = (item.key as { value?: unknown }).value;\n return typeof value === \"string\" || typeof value === \"number\"\n ? String(value)\n : \"\";\n })\n .filter((k) => k.length > 0);\n}\n","/**\n * Graph guardrail for `manni graph fill`: before a proposal is written to\n * frontmatter, simulate it in the derived graph and drop any field that\n * would violate the SHACL shapes contract — broader/narrower cycles,\n * related⨯broaderTransitive conflicts, label collisions. Accepted\n * proposals fold into the guard's state so two docs in one run cannot\n * jointly corrupt the graph.\n */\nimport { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { DataFactory, Store } from \"n3\";\nimport type { DocModel } from \"../types.js\";\nimport {\n analyzeDoc,\n formatOf,\n type AnalyzeOptions,\n type DocFormat,\n} from \"./analyze.js\";\nimport type { DeriveSource, GraphConfig } from \"./config.js\";\nimport { deriveGraph, type Quad } from \"./derive.js\";\nimport { writeGraphFields } from \"./frontmatter-edit.js\";\nimport { validateGraph, type CheckFinding } from \"./shacl.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS } from \"./vocab.js\";\nimport {\n GRAPH_NOT_APPLICABLE_TO_VARIANT,\n GRAPH_NOT_SOFTWARE_SUBJECT,\n} from \"./iirds.js\";\n\n/**\n * Proposal fields the guard simulates; others cannot break the shapes. The\n * SKOS relation fields can form cycles/collisions; the applicability fields can\n * form an applies-to⨯not-applicable-to (or about-product-aspect⨯not-about-product-aspect)\n * `sh:disjoint` conflict (ADR 01015). type/about-product-lifecycle carry\n * only enum constraints, which the proposal JSON schema already enforces, so\n * they need no structural simulation.\n */\nconst GUARDED_FIELDS = [\n \"label\",\n \"broader\",\n \"narrower\",\n \"related-concepts\",\n \"applies-to\",\n \"not-applicable-to\",\n \"about-product-aspect\",\n \"not-about-product-aspect\",\n] as const;\n\n/** Concept + iiRDS edges: the SKOS subgraph plus the applicability predicates.\n * `sections` is in because a section carries the same disjoint applicability\n * predicates a document does (ADR 01032) — without it the simulated store has\n * no `graph:Section` node for the shapes to target, and a section-level\n * contradiction sails through. Links/provenance stay out to keep per-doc\n * simulation cheap and git-free. */\nconst GUARD_SOURCES: DeriveSource[] = [\"frontmatter\", \"tags\", \"sections\"];\n\n/** The bare field name a possibly-dotted proposal key addresses. */\nfunction leafOf(field: string): string {\n const dot = field.lastIndexOf(\".\");\n return dot === -1 ? field : field.slice(dot + 1);\n}\n\nfunction toStore(quads: Quad[]): Store {\n const store = new Store();\n for (const q of quads) {\n store.addQuad(\n DataFactory.quad(\n DataFactory.namedNode(q.s),\n DataFactory.namedNode(q.p),\n q.o.kind === \"iri\"\n ? DataFactory.namedNode(q.o.value)\n : DataFactory.literal(\n q.o.value,\n q.o.datatype ? DataFactory.namedNode(q.o.datatype) : undefined,\n ),\n ),\n );\n }\n return store;\n}\n\nexport interface VetResult {\n /** The proposal minus rejected fields. */\n values: Record<string, unknown>;\n /** Rejected field names with the finding that condemned them. */\n rejected: Array<{ field: string; reason: string }>;\n}\n\nexport class FillGuard {\n private readonly models = new Map<string, DocModel>();\n private baselineKeys: Set<string> | null = null;\n /**\n * Pages left out of the simulation because they would not analyze, sorted.\n * The caller decides what each one means: a named page fails on its own,\n * and a page read only for context is worth a warning.\n */\n readonly unreadable: string[] = [];\n\n private constructor(\n private readonly allPaths: Set<string>,\n private readonly analyzeOptions: AnalyzeOptions,\n private readonly baseIri: string,\n private readonly sources: DeriveSource[],\n private readonly shapesPaths: string[],\n private readonly force: boolean,\n ) {}\n\n /**\n * Read and analyze the whole corpus once, up front. A path in `inline` is\n * taken from memory rather than disk: that is how a page read from stdin\n * joins the corpus. `format` is `--as`, applied to the run's `inputs`. Any\n * other page is parsed by its extension, as `build` reads it. A page that\n * will not read or analyze is left out and listed in `unreadable`.\n */\n static create(\n files: string[],\n cwd: string,\n config: GraphConfig,\n shapesPaths: string[],\n force: boolean,\n {\n inline = new Map<string, string>(),\n format,\n inputs = new Set<string>(),\n }: {\n inline?: ReadonlyMap<string, string>;\n format?: DocFormat;\n inputs?: ReadonlySet<string>;\n } = {},\n ): FillGuard {\n const sources = config.build.derive.filter((s) =>\n GUARD_SOURCES.includes(s),\n );\n const all = [...files, ...inline.keys()];\n const guard = new FillGuard(\n new Set(all),\n {\n routes: config.routes,\n ...(format === undefined ? {} : { format }),\n },\n config.baseIri,\n sources,\n shapesPaths,\n force,\n );\n const byExtension: AnalyzeOptions = { routes: config.routes };\n for (const path of all) {\n try {\n guard.models.set(\n path,\n analyzeDoc(\n inline.get(path) ?? readFileSync(resolve(cwd, path), \"utf8\"),\n path,\n guard.allPaths,\n inputs.has(path) ? guard.analyzeOptions : byExtension,\n ),\n );\n } catch {\n guard.unreadable.push(path);\n }\n }\n guard.unreadable.sort(byCodeUnit);\n return guard;\n }\n\n private buildStore(override?: { path: string; model: DocModel }): Store {\n const models: DocModel[] = [];\n for (const [path, model] of this.models) {\n models.push(override && path === override.path ? override.model : model);\n }\n return toStore(\n deriveGraph(models, { baseIri: this.baseIri, derive: this.sources }),\n );\n }\n\n private static key(f: CheckFinding): string {\n return `${f.severity}|${f.focusNode}|${f.path ?? \"\"}|${f.message}`;\n }\n\n /** Findings already present before any proposal — never blamed on one. */\n private async baseline(): Promise<Set<string>> {\n if (this.baselineKeys === null) {\n const findings = await validateGraph(this.buildStore(), this.shapesPaths);\n this.baselineKeys = new Set(findings.map((f) => FillGuard.key(f)));\n }\n return this.baselineKeys;\n }\n\n /** Fields a finding condemns, restricted to what the proposal contains. */\n private static offendingFields(\n finding: CheckFinding,\n proposed: Set<string>,\n ): string[] {\n // A finding on a section node names it by fragment\n // (`…/doc/a.md#install-the-sdk`), so blame the proposal key for THAT\n // section rather than the document-level field of the same name — which\n // would drop an innocent value and leave the offending one written.\n const hash = finding.focusNode.indexOf(\"#\");\n const slug = hash === -1 ? undefined : finding.focusNode.slice(hash + 1);\n const pick = (leaf: string): string[] => {\n if (slug !== undefined) {\n const dotted = `sections.${slug}.${leaf}`;\n if (proposed.has(dotted)) return [dotted];\n // A section finding that the proposal did not cause: say nothing, so\n // the caller's \"cannot pin it\" fallback decides.\n return [];\n }\n return proposed.has(leaf) ? [leaf] : [];\n };\n const hierarchy = [\"broader\", \"narrower\"].flatMap(pick);\n if (finding.path === `${NS.skos}prefLabel`) {\n return pick(\"label\");\n }\n if (finding.message.includes(\"cycle\")) return hierarchy;\n if (finding.path === `${NS.skos}broader`) return hierarchy;\n if (finding.path === `${NS.skos}narrower`) return hierarchy;\n if (finding.path === `${NS.skos}related`) {\n return pick(\"related-concepts\");\n }\n // Negative-scope disjointness (ADR 01014/01015): the finding sits on the\n // negative predicate's shape. Drop the proposed side of the conflict,\n // preferring the negative when both were proposed.\n if (finding.path === GRAPH_NOT_APPLICABLE_TO_VARIANT) {\n const negative = pick(\"not-applicable-to\");\n if (negative.length > 0) return negative;\n return pick(\"applies-to\");\n }\n if (finding.path === GRAPH_NOT_SOFTWARE_SUBJECT) {\n const negative = pick(\"not-about-product-aspect\");\n if (negative.length > 0) return negative;\n return pick(\"about-product-aspect\");\n }\n return []; // unattributable — caller rejects everything guarded\n }\n\n /**\n * Simulate `values` applied to the doc and drop fields until the graph\n * stays clean. New violations always reject; new label warnings\n * reject the proposed label (an LLM must not introduce a second\n * spelling of an existing concept).\n */\n async vet(\n path: string,\n content: string,\n values: Record<string, unknown>,\n ): Promise<VetResult> {\n const current = { ...values };\n const rejected: Array<{ field: string; reason: string }> = [];\n // Match on the LEAF, so `sections.<slug>.applies-to` is guarded exactly as\n // `applies-to` is. Keying on the bare name alone let every section-level\n // proposal skip the simulation entirely (ADR 01032).\n const guardedLeaves = new Set<string>(GUARDED_FIELDS);\n const guarded = (): string[] =>\n Object.keys(current).filter(\n (f) => current[f] !== undefined && guardedLeaves.has(leafOf(f)),\n );\n if (guarded().length === 0) return { values: current, rejected };\n\n const baseline = await this.baseline();\n // Each pass drops at least one field, so this terminates.\n while (guarded().length > 0) {\n const applied = writeGraphFields(\n content,\n path,\n formatOf(path, this.analyzeOptions.format),\n current,\n { force: this.force },\n );\n const model = analyzeDoc(\n applied.content,\n path,\n this.allPaths,\n this.analyzeOptions,\n );\n const findings = await validateGraph(\n this.buildStore({ path, model }),\n this.shapesPaths,\n );\n const introduced = findings.filter(\n (f) => !baseline.has(FillGuard.key(f)),\n );\n const bad = introduced.filter(\n (f) =>\n f.severity === \"error\" ||\n (f.severity === \"warning\" && f.path === `${NS.skos}prefLabel`),\n );\n if (bad.length === 0) break;\n\n const proposed = new Set(guarded());\n const condemned = new Map<string, string>();\n for (const f of bad) {\n for (const field of FillGuard.offendingFields(f, proposed)) {\n if (!condemned.has(field)) condemned.set(field, f.message);\n }\n }\n const firstBad = bad[0];\n if (condemned.size === 0 && firstBad !== undefined) {\n // Can't pin the new violation on a specific field — reject the\n // whole guarded proposal rather than write a graph that fails check.\n // `bad` is non-empty (the loop broke out above when it was not), and\n // reading its head is how that gets said instead of asserted.\n for (const field of guarded()) {\n condemned.set(field, firstBad.message);\n }\n }\n for (const [field, reason] of condemned) {\n rejected.push({ field, reason });\n Reflect.deleteProperty(current, field);\n }\n }\n\n rejected.sort((a, b) => byCodeUnit(a.field, b.field));\n return { values: current, rejected };\n }\n\n /** Fold an accepted (written or would-be-written) doc into guard state. */\n commit(path: string, content: string): void {\n this.models.set(\n path,\n analyzeDoc(content, path, this.allPaths, this.analyzeOptions),\n );\n this.baselineKeys = null;\n }\n}\n","/**\n * Fill proposal cache. Storage is the inference library's `JsonCache`; what\n * stays here is what only dockg can decide — what invalidates an entry:\n * provider, model, prompt version, the requested fields, and the full file\n * content.\n */\nimport { JsonCache, buildCacheKey, sha256 } from \"@hawkeyexl/inference\";\nimport type { FillField } from \"../core/config.js\";\nimport { PROMPT_VERSION } from \"./prompt.js\";\n\nexport { sha256 };\n\nexport function cacheKey(\n provider: string,\n model: string,\n content: string,\n fields: FillField[],\n /** Whether the request also asked for per-section metadata (ADR 01032). */\n sections = false,\n): string {\n return buildCacheKey([\n provider,\n model,\n `v${PROMPT_VERSION}`,\n // Pre-hashed: documents are large and key parts should stay short.\n sha256(content),\n fields.join(\",\"),\n // Same fields, different request: a sections run sends a different schema\n // and a different prompt, so its answer must not be served from a\n // doc-only entry (or the other way round).\n sections ? \"sections\" : \"doc-only\",\n ]);\n}\n\n/**\n * Proposals are plain JSON objects. Callers re-validate what comes back\n * against the proposal schema — a hand-edited or stale entry must not bypass\n * validation just because it parsed.\n */\nexport class FillCache extends JsonCache<Record<string, unknown>> {\n constructor(dir: string, enabled: boolean = true) {\n super(dir, enabled, \"manni\");\n }\n}\n","/**\n * Fill prompt and proposal schema. The proposal schema is restricted to the\n * fields being requested for the specific doc, so a provider physically\n * cannot propose fields the run should not touch. Alongside the field values,\n * the model returns a per-field `confidence` (0..1) and `reasoning`; the fill\n * command gates on confidence (ADR 01015).\n */\nimport type { FillField } from \"../core/config.js\";\nimport type { DocModel } from \"../types.js\";\n\n/**\n * Bump when the prompt changes — invalidates the fill cache.\n *\n * 4 is the move to `manni:kg:1.0.0-proposal.3` (proposal 0051 §4). The fields\n * a proposal may carry did not change, but what `fill` does with the answer\n * did: the attribution it writes is now the page-level `meta-provenance`, by\n * JSON Pointer. A cache entry written before that replays a proposal shaped\n * for the old vocabulary, so every key misses once and is rewritten.\n */\nexport const PROMPT_VERSION = 4;\n\nconst TOPIC_TYPES = [\n \"task\",\n \"concept\",\n \"reference\",\n \"learning\",\n \"troubleshooting\",\n \"form\",\n];\nconst LIFECYCLE_PHASES = [\n \"administration\",\n \"customization\",\n \"update\",\n \"deployment\",\n \"integration\",\n \"deinstallation\",\n];\nconst SOFTWARE_SUBJECTS = [\"architecture\", \"interface\", \"system-requirement\"];\n\nconst labelArray = (description: string) => ({\n type: \"array\",\n items: { type: \"string\", minLength: 1 },\n uniqueItems: true,\n description,\n});\nconst enumArray = (values: string[], description: string) => ({\n type: \"array\",\n items: { enum: values },\n uniqueItems: true,\n description,\n});\n\n/** Exported for the schema-sync drift guard (test/unit/schema-sync.test.ts). */\nexport const FIELD_SCHEMAS: Record<FillField, Record<string, unknown>> = {\n label: {\n type: \"string\",\n minLength: 1,\n description:\n \"Preferred label of the single concept this document is primarily about.\",\n },\n \"alt-labels\": labelArray(\n \"Alternative labels: synonyms, abbreviations, common variants.\",\n ),\n broader: labelArray(\"Labels of broader (parent) concepts.\"),\n narrower: labelArray(\"Labels of narrower (child) concepts.\"),\n \"related-concepts\": labelArray(\"Labels of associatively related concepts.\"),\n concepts: labelArray(\"Subject labels for the document, like tags.\"),\n type: {\n enum: TOPIC_TYPES,\n description:\n \"iiRDS topic type — the functional kind of this page. Only if the page clearly fits one.\",\n },\n \"applies-to\": labelArray(\n \"Product/variant names this page applies to. ONLY names the text explicitly states; never guess product names.\",\n ),\n \"about-product-lifecycle\": enumArray(\n LIFECYCLE_PHASES,\n \"Software lifecycle phases this page covers, only if clearly evidenced.\",\n ),\n \"about-product-aspect\": enumArray(\n SOFTWARE_SUBJECTS,\n \"Software information subjects this page is about, only if clearly evidenced.\",\n ),\n \"not-applicable-to\": labelArray(\n \"Product/variant names the text EXPLICITLY says this page does NOT apply to. Only with explicit textual evidence.\",\n ),\n \"not-about-product-aspect\": enumArray(\n SOFTWARE_SUBJECTS,\n \"Software subjects the text EXPLICITLY says this page is NOT about. Only with explicit textual evidence.\",\n ),\n};\n\n/**\n * Memoized by the requested field set. A corpus has only a handful of distinct\n * field combinations, but a fresh schema object per document would defeat the\n * inference library's identity-keyed validator cache and recompile Ajv once per\n * file. The returned object must therefore be treated as immutable.\n */\nconst schemaCache = new Map<string, Record<string, unknown>>();\n\n/**\n * The `graph` fields a section block accepts (ADR 01013). `label` is absent\n * deliberately — a \"primary topic per section\" is meaningless, so it is not\n * proposable either.\n */\nexport const SECTION_FILL_FIELDS: readonly FillField[] = [\n \"type\",\n \"applies-to\",\n \"about-product-lifecycle\",\n \"about-product-aspect\",\n \"not-applicable-to\",\n \"not-about-product-aspect\",\n \"concepts\",\n];\n\n/**\n * @param fields Document-level fields to offer — narrowed to what this\n * document is missing, so a provider cannot propose over a human's value.\n * @param options.sections Section-level fields to offer, or absent for no\n * section half. Passed **separately and unnarrowed** on purpose: section\n * presence is independent of document presence (ADR 01032), so a page whose\n * `graph.type` is already set must still be able to type its sections. Deriving\n * this list from `fields` handed a strictly-constrained provider a section\n * item with no data properties at all.\n */\nexport function proposalSchema(\n fields: FillField[],\n options: { sections?: FillField[]; lenient?: boolean } = {},\n): Record<string, unknown> {\n // Build from the SAME sorted list the key is derived from. Keying on the\n // sorted set while building from the caller's order would make the cached\n // schema's property order depend on whichever call arrived first — and that\n // order is observable: the schema is JSON.stringify'd into the claude-cli\n // and json_object prompts, so identical inputs could produce different\n // prompts across runs. Determinism is the product contract here.\n const sorted = [...fields].sort();\n // Sorted for the same reason `fields` is: the section item's property order\n // is observable through the stringified schema in the prompt.\n const sortedSections = options.sections\n ? [...options.sections]\n .filter((f) => SECTION_FILL_FIELDS.includes(f))\n .sort()\n : undefined;\n const lenient = options.lenient === true;\n const key = [\n sortedSections ? `s:${sortedSections.join(\",\")}` : \"\",\n lenient ? \"l:\" : \"\",\n sorted.join(\",\"),\n ].join(\"|\");\n const memoized = schemaCache.get(key);\n if (memoized) return memoized;\n const built = buildProposalSchema(sorted, sortedSections, lenient);\n schemaCache.set(key, built);\n return built;\n}\n\nfunction buildProposalSchema(\n fields: FillField[],\n sectionFields: FillField[] | undefined,\n lenient: boolean,\n): Record<string, unknown> {\n // The value schemas are the contract and never relax. `confidence` and\n // `reasoning` are the model's own commentary on those values, and in the\n // validation schema they are accepted in whatever shape they arrive\n // (ADR 01034): `numberMap`/`stringMap` already ignore anything of the wrong\n // type, so a malformed score costs that one field its score rather than\n // discarding an otherwise good proposal. The REQUEST schema keeps the types,\n // so a provider is still asked — and a grammar-capable one still constrained\n // — to send a number.\n const scoreSchema = lenient ? {} : { type: \"number\", minimum: 0, maximum: 1 };\n const noteSchema = lenient ? {} : { type: \"string\" };\n const properties: Record<string, unknown> = {};\n const confidence: Record<string, unknown> = {};\n const reasoning: Record<string, unknown> = {};\n for (const field of fields) {\n properties[field] = FIELD_SCHEMAS[field];\n confidence[field] = scoreSchema;\n reasoning[field] = noteSchema;\n }\n properties[\"confidence\"] = {\n type: \"object\",\n additionalProperties: false,\n properties: confidence,\n description:\n \"For every field you propose a value for, a confidence 0..1 that the value is correct.\",\n };\n properties[\"reasoning\"] = {\n type: \"object\",\n additionalProperties: false,\n properties: reasoning,\n description:\n \"For every field you propose a value for, a one-sentence justification grounded in the page text.\",\n };\n\n if (sectionFields !== undefined) {\n // A **list** keyed by an explicit `slug`, not a map keyed by slug. Strict\n // structured output (OpenAI's json_schema, and the GBNF grammar it becomes)\n // requires `additionalProperties: false` on every object, which cannot\n // express an open-keyed map. A list of {slug, …} says the same thing in a\n // shape every provider can constrain.\n const sectionProps: Record<string, unknown> = {\n slug: {\n type: \"string\",\n minLength: 1,\n description:\n \"The heading slug, copied exactly from the outline. Do not invent one.\",\n },\n };\n const sectionConfidence: Record<string, unknown> = {};\n const sectionReasoning: Record<string, unknown> = {};\n for (const field of sectionFields) {\n sectionProps[field] = FIELD_SCHEMAS[field];\n sectionConfidence[field] = scoreSchema;\n sectionReasoning[field] = noteSchema;\n }\n sectionProps[\"confidence\"] = {\n type: \"object\",\n additionalProperties: false,\n properties: sectionConfidence,\n description:\n \"For every field you propose on this section, a confidence 0..1.\",\n };\n sectionProps[\"reasoning\"] = {\n type: \"object\",\n additionalProperties: false,\n properties: sectionReasoning,\n description:\n \"For every field you propose on this section, a one-sentence justification.\",\n };\n properties[\"sections\"] = {\n type: \"array\",\n items: {\n type: \"object\",\n additionalProperties: false,\n required: [\"slug\"],\n properties: sectionProps,\n },\n description:\n \"Per-section metadata. Only for sections whose own content differs meaningfully from the page as a whole; omit a section rather than repeating the page's values.\",\n };\n }\n\n return {\n type: \"object\",\n additionalProperties: false,\n properties,\n };\n}\n\nexport const SYSTEM_PROMPT = [\n \"You classify documentation pages into a controlled metadata vocabulary\",\n \"(SKOS concepts and iiRDS typing). For each requested field, first reason\",\n \"about whether the page's own text supports a value; propose a value only\",\n \"when it clearly does, and omit the field otherwise. Reuse the document's\",\n \"own terminology; do not invent concepts, product names, or classifications\",\n \"the document does not discuss.\",\n \"\",\n \"For every field you propose a value for, include a `confidence` (0..1) and\",\n \"a one-sentence `reasoning` grounded in the text. Score honestly and\",\n \"conservatively. Product/variant fields (applies-to, not-applicable-to) and the\",\n \"negative fields (not-applicable-to, not-about-product-aspect) require EXPLICIT\",\n \"textual evidence — score them low and prefer to omit unless the page states\",\n \"them outright. A field with no value needs no confidence or reasoning.\",\n].join(\"\\n\");\n\nconst EXCERPT_CHARS = 2000;\n\nexport function buildUserPrompt(\n doc: DocModel,\n body: string,\n fields: FillField[],\n options: { sections?: boolean } = {},\n): string {\n const title =\n (typeof doc.frontmatter[\"title\"] === \"string\" &&\n doc.frontmatter[\"title\"]) ||\n doc.firstH1 ||\n \"(untitled)\";\n const tags = doc.frontmatter[\"tags\"] ?? doc.frontmatter[\"keywords\"];\n // With sections on, the outline carries each heading's slug: it is the key\n // the model must copy, and a slug it invents is dropped rather than written\n // (which would otherwise mint a graph:brokenSectionRef — a finding fill must\n // never manufacture).\n const withSections = options.sections === true && doc.sections.length > 0;\n const outline = doc.sections\n .map(\n (s) =>\n `${\" \".repeat(Math.max(0, s.level - 1))}- ${s.title}` +\n (withSections ? ` [slug: ${s.slug}]` : \"\"),\n )\n .join(\"\\n\");\n\n return [\n `Propose the following frontmatter fields for this documentation page, with per-field confidence and reasoning: ${fields.join(\", \")}.`,\n withSections\n ? \"Also propose per-section metadata in `sections`, using the exact slug shown in the outline. Include a section ONLY when its own content differs meaningfully from the page as a whole — repeating the page's values on every heading adds noise, not granularity.\"\n : \"\",\n \"\",\n `Path: ${doc.path}`,\n `Title: ${title}`,\n Array.isArray(tags) && tags.length > 0\n ? `Existing tags: ${tags.join(\", \")}`\n : \"\",\n \"\",\n \"Heading outline:\",\n outline || \"(no headings)\",\n \"\",\n \"Body excerpt:\",\n body.slice(0, EXCERPT_CHARS),\n ].join(\"\\n\");\n}\n","/**\n * Choosing the provider and model for `manni graph fill`, and building the shared\n * inference library's `ProviderSpec` for it.\n *\n * The providers themselves live in `@hawkeyexl/inference` (ADR 01021). The\n * names a provider may have, the two refusals, the detection call, the\n * level-bound precedence and the mapping of the family's `providers:`\n * connection settings are `src/shared/providers.ts`, the same code\n * `manni meta fill` and `manni docevals` run. What stays here is what only graph\n * can decide: which levels it reads — a flag, then `graph.provider`/`graph.model`,\n * then the family's top-level `providers:` map, then `auto` (proposal\n * 0051 §3).\n *\n * `graph.embed.model` is a local embedding model id, not a provider, and nothing\n * here touches it.\n */\nimport {\n makeProvider as makeInferenceProvider,\n type InferenceProvider,\n type ProviderName as ConcreteProvider,\n type ProviderSelector,\n type ProviderSpec,\n} from \"@hawkeyexl/inference\";\nimport type { GraphConfig } from \"../core/config.js\";\nimport {\n assertKnownProvider,\n assertLocalFlag,\n assertModelHasProvider,\n localNotice,\n providerSpecFor as sharedProviderSpecFor,\n resolveIdentity,\n selectProvider as selectFromLevels,\n type ProviderChoice,\n type ProviderFlags,\n type ProviderSelection,\n} from \"../../shared/providers.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { noticeOnce } from \"../../shared/warn.js\";\nimport { GraphError } from \"../types.js\";\n\nexport type { ProviderChoice, ProviderFlags, ProviderSelection };\n\n/** The key a graph user writes, named by the refusal a bare model gets. */\nconst CONFIG_KEY = \"graph.provider\";\n\nconst toGraphError = (message: string): Error => new GraphError(message);\n\n/**\n * The provider and model in force: a flag, then `graph.provider`/`graph.model`,\n * then the family's `providers.provider`/`model`, then `auto`. A model is\n * carried only to the provider its own level names, so a level whose provider\n * lost takes the winner's default rather than a model it cannot run\n * (`selectProvider` in the shared module).\n *\n * `--local` runs llama-cpp over both levels. A `--provider` it contradicts is\n * refused here, so no path selects past it.\n */\nexport function selectProvider(\n config: GraphConfig,\n flags: ProviderFlags = {},\n): ProviderSelection {\n assertLocalFlag(flags, toGraphError);\n return selectFromLevels(flags, [\n {\n ...(config.provider !== null ? { provider: config.provider } : {}),\n ...(config.model !== null ? { model: config.model } : {}),\n origin: CONFIG_KEY,\n },\n {\n ...(config.providers.provider !== undefined\n ? { provider: config.providers.provider }\n : {}),\n ...(config.providers.model !== undefined\n ? { model: config.providers.model }\n : {}),\n origin: \"providers.provider\",\n },\n ]);\n}\n\n/**\n * Say what `--local` set aside, once per source. Called where a selection is\n * about to be used, never where it is only checked, so a run that sends\n * nothing to a model says nothing.\n */\nexport function announceSelection(selection: ProviderSelection): void {\n const message = localNotice(selection);\n if (message !== undefined) noticeOnce(message);\n}\n\n/**\n * Refuse a selection that cannot be right, with `manni meta fill`'s messages:\n * an unknown name, or a model under `auto`. Both are `GraphError`s, so both exit\n * 2 rather than reading as a finding.\n */\nexport function assertProviderSelection(selection: ProviderSelection): void {\n assertKnownProvider(selection.provider, toGraphError);\n assertModelHasProvider(\n selection.provider,\n selection.model,\n CONFIG_KEY,\n toGraphError,\n );\n}\n\n/**\n * The spec for a selection, with the family's connection settings for the\n * provider it names, and under `auto` the settings detection reads.\n */\nexport function providerSpecFor(\n config: GraphConfig,\n selection: { provider: ProviderSelector; model: string | null },\n): ProviderSpec {\n return sharedProviderSpecFor(config.providers, selection);\n}\n\n/**\n * The concrete provider and model, WITHOUT constructing the provider: cache\n * keys need it, and a fully cached or fully complete run must not require an\n * API key.\n *\n * Under `auto` this is where detection runs, exactly as `manni meta fill`\n * runs it, seeing the same connection settings. The model is the RESOLVED one\n * (the provider's default when none was named, a llama-cpp tier's concrete\n * weights), so a library default that changes changes every cache key built\n * from it.\n */\nexport async function resolveProviderIdentity(\n config: GraphConfig,\n flags: ProviderFlags = {},\n): Promise<{ provider: ConcreteProvider; model: string }> {\n const selection = selectProvider(config, flags);\n const { provider, model } = selection;\n assertKnownProvider(provider, toGraphError);\n assertModelHasProvider(provider, model, CONFIG_KEY, toGraphError);\n announceSelection(selection);\n return resolveIdentity(\n providerSpecFor(config, { provider, model: model ?? null }),\n toGraphError,\n );\n}\n\n/** Construct a provider for an identity already resolved. */\nexport function constructProvider(\n config: GraphConfig,\n identity: { provider: ConcreteProvider; model: string },\n): InferenceProvider {\n try {\n return makeInferenceProvider(providerSpecFor(config, identity));\n } catch (e) {\n // The library raises its own InferenceError (a missing API key, say). It\n // must surface as a GraphError: `fail()` maps only GraphError to exit 2, and\n // letting a foreign error type through turns \"no API key configured\" into\n // an unhandled stack trace.\n throw new GraphError(errorMessage(e));\n }\n}\n\n/** Select, check, detect and construct: the provider `fill` sends pages to. */\nexport async function makeProvider(\n config: GraphConfig,\n flags: ProviderFlags = {},\n): Promise<InferenceProvider> {\n return constructProvider(config, await resolveProviderIdentity(config, flags));\n}\n","/**\n * `manni graph embed` — compute vectors for the search index (ADR 01020).\n *\n * Embeds the text already in `graph/search.<lang>.json` rather than re-reading\n * markdown: vectors then cover exactly what the lexical index covers, with the\n * Phase 8 granularity rule already applied, so both ranking legs score the same\n * units.\n *\n * One sidecar per language, driven by the localization manifest and embedded\n * with that language's model (ADR 01038) — a German corpus under an\n * English-only model returns confident, meaningless vectors and fails nothing.\n *\n * This is the one dockg command that needs a model. It is local — no API, no\n * key, no spend — but the weights are a download, so unlike every other\n * artifact the sidecars cannot be regenerated in CI from a real model.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path, { dirname, join, resolve } from \"node:path\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { type SearchEntry, type SearchIndexDoc } from \"../core/search-index.js\";\nimport {\n canonicalLanguageTag,\n emitLocalizations,\n isSafeRelativePath,\n LOCALIZATIONS_FILENAME,\n parseLocalizations,\n vectorIndexFilename,\n type LocalizationEntry,\n} from \"../core/localizations.js\";\nimport { encodeVectorIndex } from \"../core/vector-index.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { GraphError } from \"../types.js\";\nimport {\n createLocalEmbedder,\n EmbedderUnavailableError,\n} from \"../embed/local.js\";\nimport { createMockEmbedder } from \"../embed/mock.js\";\nimport type { Embedder } from \"../embed/types.js\";\n\nexport interface EmbedOptions {\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 /** Directory to write the sidecars into (default: the index directory). */\n out?: string;\n model?: string;\n dtype?: string;\n /** Skip the vector cache. */\n noCache?: boolean;\n /** Injection seam for tests: bypasses the embedder factory. */\n embedder?: Embedder;\n cwd?: string;\n}\n\n/** One language's sidecar, as this run produced it. */\nexport interface EmbedLanguageReport {\n language: string;\n outPath: string;\n /** The model this language was embedded with, after the per-language override. */\n model: string;\n dims: number;\n /** Entries embedded this run (cache misses). */\n embedded: number;\n /** Entries served from cache. */\n cached: number;\n total: number;\n}\n\nexport interface EmbedReport {\n /** The manifest, rewritten with each language's `vectors` block. */\n manifestPath: string;\n /** One entry per language in the manifest, in its order. */\n languages: EmbedLanguageReport[];\n /** Totals across every language. */\n embedded: number;\n cached: number;\n total: number;\n}\n\n/** The text an entry contributes to its vector — same fields the lexical index scores. */\nexport function embedText(entry: SearchEntry): string {\n return [entry.title, entry.labels, entry.description, entry.text]\n .filter((part): part is string => part !== undefined && part !== \"\")\n .join(\"\\n\\n\");\n}\n\nfunction sha256(text: string): string {\n return createHash(\"sha256\").update(text, \"utf8\").digest(\"hex\");\n}\n\n/**\n * Per-text vector cache. Embedding is slow by construction (single-threaded\n * WASM, one text per call), so editing one section must not re-embed the corpus.\n * Keyed on text + model + dtype, so changing any of them re-embeds rather than\n * serving vectors from a different function.\n */\nclass VectorCache {\n constructor(\n private readonly dir: string,\n private readonly enabled: boolean,\n ) {}\n\n private path(key: string): string {\n return join(this.dir, `${key}.json`);\n }\n\n get(key: string): Float32Array | undefined {\n if (!this.enabled) return undefined;\n const file = this.path(key);\n if (!existsSync(file)) return undefined;\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as number[];\n return Array.isArray(parsed) ? Float32Array.from(parsed) : undefined;\n } catch {\n return undefined; // A corrupt entry is a miss, never a crash.\n }\n }\n\n set(key: string, vector: Float32Array): void {\n if (!this.enabled) return;\n mkdirSync(this.dir, { recursive: true });\n writeFileSync(this.path(key), JSON.stringify([...vector]), \"utf8\");\n }\n}\n\nasync function makeEmbedder(\n opts: EmbedOptions,\n model: string,\n dtype: string,\n): Promise<Embedder> {\n if (opts.embedder) return opts.embedder;\n // `--model mock` keeps the CLI exercisable offline, mirroring `fill`'s mock\n // provider. It produces hash-derived vectors with no semantics.\n if (model === \"mock\") return createMockEmbedder({ dtype });\n try {\n return await createLocalEmbedder({ model, dtype, role: \"passage\" });\n } catch (e) {\n if (e instanceof EmbedderUnavailableError) {\n throw new GraphError(e.message);\n }\n // Everything else the model stack can fail on — an unknown id, a 404 on the\n // hub, corrupt weights — is operational (exit 2), not a raw stack trace.\n throw new GraphError(\n `Failed to load embedding model ${model}: ${errorMessage(e)}`,\n );\n }\n}\n\n/**\n * The sidecar's path as the manifest records it: relative to the manifest,\n * with forward slashes, because a browser resolves it against a URL.\n *\n * On Windows a sidecar on another drive has no relative path, and `relative`\n * returns an absolute one. The reader refuses that, so writing it would leave\n * an artifact set nothing can read back. Refused here instead, before any\n * file is written. `pathApi` is the seam that lets a test be Windows anywhere.\n */\nexport function manifestRelativePath(\n indexDir: string,\n outPath: string,\n pathApi: Pick<typeof path, \"relative\" | \"isAbsolute\" | \"sep\"> = path,\n): string {\n const rel = pathApi.relative(indexDir, outPath);\n const recorded = rel.split(pathApi.sep).join(\"/\");\n if (pathApi.isAbsolute(rel) || !isSafeRelativePath(recorded)) {\n throw new GraphError(\n `Cannot record vectors at ${outPath}: the localization manifest needs a path relative to ${indexDir}. Write the sidecars on the index's drive.`,\n );\n }\n return recorded;\n}\n\nexport async function runEmbed(opts: EmbedOptions = {}): Promise<EmbedReport> {\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 // The manifest is the work list: `export search` wrote one index per\n // language and named them all here, so embed never has to guess which files\n // exist or what language each holds (ADR 01038).\n const indexDir = opts.index ? resolve(cwd, opts.index) : dirname(graphPath);\n const manifestPath = join(indexDir, LOCALIZATIONS_FILENAME);\n\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\n // `-o` over the config's `embed.out`, both from the working directory as\n // `out` is, and the index directory when neither names one.\n const outSetting = opts.out ?? config.embed.out;\n const outDir = outSetting ? resolve(cwd, outSetting) : indexDir;\n mkdirSync(outDir, { recursive: true });\n const cache = new VectorCache(\n resolve(cwd, config.embed.cacheDir),\n !opts.noCache,\n );\n\n // One embedder per (model, dtype), built on the first cache miss that needs\n // it: `pipeline()` downloads tens of megabytes of weights, and a run that is\n // entirely cache hits has no reason to pay for it — for any language.\n const embedders = new Map<string, Promise<Embedder>>();\n const getEmbedder = (model: string, dtype: string): Promise<Embedder> => {\n // JSON, not a joined string: no separator can collide, and no NUL byte\n // enters the source (CLAUDE.md's no-NUL invariant), which is the same\n // reason the vector cache key below is JSON.\n const key = JSON.stringify([model, dtype]);\n const existing = embedders.get(key);\n if (existing) return existing;\n const built = makeEmbedder(opts, model, dtype);\n embedders.set(key, built);\n return built;\n };\n\n const languages: EmbedLanguageReport[] = [];\n const updated: LocalizationEntry[] = [];\n\n for (const entry of manifest.languages) {\n const indexPath = join(indexDir, entry.search.path);\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 const raw = readFileSync(indexPath, \"utf8\");\n const source = `sha256:${sha256(raw)}`;\n // The manifest records the digest of the file it wrote. A mismatch means\n // the pair has drifted, and embedding it would produce a sidecar keyed to\n // bytes nobody has — the same refusal the runtime makes at query time.\n if (entry.search.digest !== source) {\n throw new GraphError(\n `Stale manifest: ${entry.search.path} does not match the digest recorded for \"${entry.language}\" — re-run \\`manni graph export search\\`.`,\n );\n }\n\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.`,\n );\n }\n\n // Per-language model, then the flags, then the corpus-wide default. A\n // German corpus embedded with an English-only model returns confident,\n // meaningless vectors and fails nothing, so this override is the whole\n // reason the fan-out exists.\n //\n // Keys are matched canonically, so `en-us:` configures the `en-US` index.\n const wanted = canonicalLanguageTag(entry.language);\n const perLanguage = Object.entries(config.embed.byLanguage).find(\n ([tag]) => canonicalLanguageTag(tag) === wanted,\n )?.[1];\n const model = opts.model ?? perLanguage?.model ?? config.embed.model;\n const dtype = opts.dtype ?? perLanguage?.dtype ?? config.embed.dtype;\n const identity = opts.embedder\n ? { model: opts.embedder.model, dtype: opts.embedder.dtype }\n : { model, dtype };\n\n const vectors: Array<{ id: string; vector: Float32Array }> = [];\n let embedded = 0;\n let cached = 0;\n\n for (const item of entries) {\n const text = embedText(item);\n if (text === \"\") continue;\n // JSON rather than a joined string: no separator can collide with\n // content, and no NUL byte enters the source (a NUL makes git classify\n // the file as binary — the no-NUL-bytes invariant in CLAUDE.md).\n const key = sha256(\n JSON.stringify([identity.model, identity.dtype, text]),\n );\n let vector = cache.get(key);\n if (vector) {\n cached += 1;\n } else {\n vector = await (await getEmbedder(model, dtype)).embed(text);\n cache.set(key, vector);\n embedded += 1;\n }\n vectors.push({ id: item.id, vector });\n }\n\n const filename = vectorIndexFilename(entry.language);\n const outPath = join(outDir, filename);\n // What the manifest records is relative to the manifest, not to wherever\n // `-o` happened to point — so a sidecar written outside the index\n // directory is still findable from the file that names it. Forward slashes\n // because this is a JSON artifact a browser resolves against a URL.\n const manifestRelative = manifestRelativePath(indexDir, outPath);\n writeFileSync(\n outPath,\n encodeVectorIndex(vectors, {\n model: identity.model,\n dtype: identity.dtype,\n source,\n language: entry.language,\n }),\n );\n\n const dims = vectors[0]?.vector.length ?? 0;\n languages.push({\n language: entry.language,\n outPath,\n model: identity.model,\n dims,\n embedded,\n cached,\n total: vectors.length,\n });\n updated.push({\n ...entry,\n vectors: {\n path: manifestRelative,\n model: identity.model,\n dtype: identity.dtype,\n dims,\n count: vectors.length,\n },\n });\n }\n\n // Rewritten so the manifest describes what is actually on disk: an entry\n // without a `vectors` block means that language has no sidecar yet.\n writeFileSync(\n manifestPath,\n emitLocalizations({ version: 1, languages: updated }),\n \"utf8\",\n );\n\n return {\n manifestPath,\n languages,\n embedded: languages.reduce((n, l) => n + l.embedded, 0),\n cached: languages.reduce((n, l) => n + l.cached, 0),\n total: languages.reduce((n, l) => n + l.total, 0),\n };\n}\n\nexport function renderEmbed(\n report: EmbedReport,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") return JSON.stringify(report, null, 2);\n const lines = report.languages.map(\n (l) =>\n ` ${l.language}: ${l.total} vector${l.total === 1 ? \"\" : \"s\"} (${l.dims}-d, ${l.model}) -> ${l.outPath}`,\n );\n if (lines.length === 0) lines.push(\" (no languages in the manifest)\");\n const n = report.languages.length;\n return [\n // Not \"beside\": `-o` may put the sidecars in a different directory from\n // the manifest, and each line below names the path it actually wrote.\n `Wrote ${n} sidecar${n === 1 ? \"\" : \"s\"}, recorded in ${report.manifestPath}`,\n ...lines,\n ` ${report.embedded} embedded, ${report.cached} from cache`,\n ].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 * 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 * `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, 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 */\nasync function resolveEmbedder(\n opts: SearchOptions,\n vectors: VectorIndex,\n required: boolean,\n): Promise<Embedder | undefined> {\n const { model, dtype } = vectors;\n try {\n const embedder =\n opts.embedder ??\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 * 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 * `manni graph stats` — graph health summary: node/edge counts, orphan docs\n * (no incoming or outgoing references), broken internal links, the\n * most-connected docs, and metadata coverage. `--check` exits 1 when broken\n * links exist or a coverage threshold is unmet.\n */\nimport { resolve } from \"node:path\";\nimport { DataFactory, type Store } from \"n3\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { compactIri, loadGraph } from \"../core/load.js\";\nimport { NS, RDF_TYPE } from \"../core/vocab.js\";\nimport { COVERAGE_FIELDS, SECTION_COVERAGE_FIELDS } from \"../core/coverage.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\n\nexport interface StatsOptions {\n config?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n graph?: string;\n cwd?: string;\n /** Exit 1 when broken links exist or a coverage threshold is unmet. */\n check?: boolean;\n /** How many most-connected docs to list. */\n top?: number;\n /**\n * Uniform minimum coverage percentage, overriding config across every field.\n * The per-field map form is config-only.\n */\n coverageThreshold?: number;\n}\n\n/** One row of the metadata coverage report. */\nexport interface CoverageRow {\n field: string;\n predicate: string;\n /** Documents carrying the predicate. */\n docs: number;\n /** Percentage of documents covered, rounded to one decimal. */\n pct: number;\n}\n\nexport interface StatsReport {\n triples: number;\n docs: number;\n sections: number;\n concepts: number;\n references: number;\n /** graph:path of docs with no in/out dcterms:references. */\n orphans: string[];\n brokenLinks: Array<{ doc: string; target: string }>;\n /** graph.sections keys that matched no heading (graph:brokenSectionRef). */\n brokenSectionRefs: Array<{ doc: string; slug: string }>;\n mostConnected: Array<{ doc: string; degree: number }>;\n /** Per-field metadata coverage over documents, in report order. */\n coverage: CoverageRow[];\n /**\n * Per-field coverage over `graph:Section` nodes (ADR 01029). Reported, not\n * gated: sections are explicit-only, so these start near zero on every corpus\n * and a default gate would fail every one of them.\n */\n sectionCoverage: CoverageRow[];\n /**\n * Per-language reporting (ADR 01037). The whole-corpus `coverage` table\n * blends every locale into one number that describes no audience; this says\n * which audience is under-served and what is still untranslated.\n *\n * Reported, not gated — `coverageFindings` stays whole-corpus, per\n * ADR 01009's rule that reporting on does not imply gating on.\n */\n localization: LocalizationReport;\n /** Fields whose document coverage is below their configured threshold. */\n coverageFindings: Array<{ field: string; pct: number; threshold: number }>;\n exitCode: 0 | 1;\n}\n\nexport interface LanguageReport {\n /** BCP-47 tag exactly as the graph carries it. */\n language: string;\n /** Documents carrying this tag. */\n docs: number;\n /** The same fields as `coverage`, scored over this language's documents. */\n coverage: CoverageRow[];\n /**\n * `graph:path` of source documents with no translation into this language,\n * sorted. A *source* is a document carrying no `schema:translationOfWork` —\n * so a translation is never its own backlog item — and a source already in\n * this language is excluded. Nothing here is inferred: a page counts as\n * translated only where the graph carries the edge.\n */\n untranslated: string[];\n}\n\nexport interface LocalizationReport {\n /** Documents carrying no `dcterms:language` at all. */\n unlabelled: number;\n /** One block per language present, sorted by tag. */\n languages: LanguageReport[];\n}\n\nfunction subjectsOfType(store: Store, typeIri: string): string[] {\n return store\n .getQuads(null, DataFactory.namedNode(RDF_TYPE), DataFactory.namedNode(typeIri), null)\n .map((q) => q.subject.value)\n .sort();\n}\n\n/** Strip a fragment so section references count toward their doc. */\nfunction base(iri: string): string {\n const hash = iri.indexOf(\"#\");\n return hash === -1 ? iri : iri.slice(0, hash);\n}\n\n/** Round a percentage to one decimal place for display. */\nfunction round1(pct: number): number {\n return Math.round(pct * 10) / 10;\n}\n\nexport function runStats(opts: StatsOptions = {}): StatsReport {\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 store = loadGraph(resolve(cwd, opts.graph ?? config.out));\n const top = opts.top ?? 5;\n\n const docIris = subjectsOfType(store, `${NS.graph}Document`);\n const docSet = new Set(docIris);\n // One indexed scan for all paths instead of a per-doc lookup.\n const pathOf = new Map<string, string>(docIris.map((d) => [d, d]));\n for (const quad of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.graph}path`),\n null,\n null,\n )) {\n pathOf.set(quad.subject.value, quad.object.value);\n }\n\n const refQuads = store.getQuads(\n null,\n DataFactory.namedNode(`${NS.dcterms}references`),\n null,\n null,\n );\n const degree = new Map<string, number>(docIris.map((d) => [d, 0]));\n for (const quad of refQuads) {\n const from = quad.subject.value;\n const to = base(quad.object.value);\n if (docSet.has(from)) degree.set(from, (degree.get(from) ?? 0) + 1);\n if (docSet.has(to) && to !== from)\n degree.set(to, (degree.get(to) ?? 0) + 1);\n }\n\n const orphans = docIris\n .filter((d) => (degree.get(d) ?? 0) === 0)\n .map((d) => pathOf.get(d) ?? d)\n .sort();\n\n const brokenLinks = store\n .getQuads(null, DataFactory.namedNode(`${NS.graph}brokenLink`), null, null)\n .map((q) => ({\n doc: pathOf.get(q.subject.value) ?? q.subject.value,\n target: q.object.value,\n }))\n .sort((a, b) => (a.doc + a.target < b.doc + b.target ? -1 : 1));\n\n const brokenSectionRefs = store\n .getQuads(null, DataFactory.namedNode(`${NS.graph}brokenSectionRef`), null, null)\n .map((q) => ({\n doc: pathOf.get(q.subject.value) ?? q.subject.value,\n slug: q.object.value,\n }))\n .sort((a, b) => (a.doc + a.slug < b.doc + b.slug ? -1 : 1));\n\n const mostConnected = [...degree.entries()]\n .filter(([, deg]) => deg > 0)\n .map(([doc, deg]) => ({ doc: pathOf.get(doc) ?? doc, degree: deg }))\n .sort((a, b) => b.degree - a.degree || (a.doc < b.doc ? -1 : 1))\n .slice(0, top);\n\n // Coverage: one indexed scan per field over Document subjects. Measured\n // against the graph, so git-derived values count (ADR 01008/01011). A\n // zero-document graph is vacuously 100% — no divide-by-zero, no false gate.\n const total = docIris.length;\n /** Count subjects carrying each predicate, as a share of `subjects`. */\n const coverageOver = (\n subjects: readonly string[],\n fields: readonly { field: string; iri: string }[],\n ): CoverageRow[] =>\n fields.map(({ field, iri }) => {\n let docs = 0;\n for (const s of subjects) {\n if (store.countQuads(DataFactory.namedNode(s), DataFactory.namedNode(iri), null, null) > 0)\n docs++;\n }\n const ratio =\n subjects.length === 0 ? 100 : (docs / subjects.length) * 100;\n // Report the rounded value; gate on the raw ratio (below) so a corpus at\n // 79.96% does not clear an 80 threshold on display rounding alone.\n return { field, predicate: compactIri(iri), docs, pct: round1(ratio) };\n });\n\n const coverage = coverageOver(docIris, COVERAGE_FIELDS);\n const sectionCoverage = coverageOver(\n subjectsOfType(store, `${NS.graph}Section`),\n SECTION_COVERAGE_FIELDS,\n );\n\n // --- Localization (ADR 01037) ---------------------------------------------\n const languageOf = new Map<string, string>();\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.dcterms}language`),\n null,\n null,\n )) {\n if (docSet.has(q.subject.value))\n languageOf.set(q.subject.value, q.object.value);\n }\n\n const byLanguage = new Map<string, string[]>();\n for (const d of docIris) {\n const tag = languageOf.get(d);\n if (tag === undefined) continue;\n // Push into the existing array rather than rebuilding it: spreading copies\n // the whole bucket per document, which is quadratic in a corpus where one\n // language holds most of the pages.\n const bucket = byLanguage.get(tag);\n if (bucket) bucket.push(d);\n else byLanguage.set(tag, [d]);\n }\n\n // A source is a document that is not itself a translation. Translations are\n // excluded so a German page never appears in the German backlog.\n const sources = docIris.filter(\n (d) =>\n store.countQuads(\n DataFactory.namedNode(d),\n DataFactory.namedNode(`${NS.schema}translationOfWork`),\n null,\n null,\n ) === 0,\n );\n\n // Which languages each source already has a translation into, from one scan\n // over the inverse edges. Asking the store per source per language instead\n // scales with #sources × #languages, and every one of those lookups walks\n // the same quads this single pass already visited.\n const translatedInto = new Map<string, Set<string>>();\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.schema}workTranslation`),\n null,\n null,\n )) {\n const target = languageOf.get(q.object.value);\n if (target === undefined) continue;\n const known = translatedInto.get(q.subject.value);\n if (known) known.add(target);\n else translatedInto.set(q.subject.value, new Set([target]));\n }\n\n const localization: LocalizationReport = {\n unlabelled: docIris.length - languageOf.size,\n // `entries()`, not `keys()` and a lookup: the docs come out of the map\n // with the tag they are keyed by, so there is nothing left to assert.\n languages: [...byLanguage.entries()]\n .sort(([a], [b]) => byCodeUnit(a, b))\n .map(([language, docsIn]) => {\n const untranslated = sources\n .filter((s) => languageOf.get(s) !== language)\n .filter((s) => !translatedInto.get(s)?.has(language))\n .map((s) => pathOf.get(s) ?? s)\n .sort(byCodeUnit);\n return {\n language,\n docs: docsIn.length,\n coverage: coverageOver(docsIn, COVERAGE_FIELDS),\n untranslated,\n };\n }),\n };\n\n // A uniform --coverage-threshold overrides the resolved config map. Bind it\n // to a local first so the null-narrowing survives the .map() closure.\n const uniform = opts.coverageThreshold;\n const thresholds =\n uniform != null\n ? Object.fromEntries(coverage.map((c) => [c.field, uniform]))\n : config.stats.coverageThreshold;\n // One read of the threshold, which is both the \"is this field gated\" test\n // and the value the finding reports — where `in` plus two lookups needed an\n // assertion to say they were the same fact.\n const coverageFindings = coverage.flatMap((c) => {\n const threshold = thresholds[c.field];\n if (threshold === undefined) return [];\n const pct = total === 0 ? 100 : (c.docs / total) * 100;\n return pct < threshold ? [{ field: c.field, pct: c.pct, threshold }] : [];\n });\n\n const failed =\n !!opts.check &&\n (brokenLinks.length > 0 ||\n brokenSectionRefs.length > 0 ||\n coverageFindings.length > 0);\n\n return {\n triples: store.size,\n docs: docIris.length,\n // countQuads avoids materializing + sorting arrays used only for counting.\n sections: store.countQuads(\n null,\n DataFactory.namedNode(RDF_TYPE),\n DataFactory.namedNode(`${NS.graph}Section`),\n null,\n ),\n concepts: store.countQuads(\n null,\n DataFactory.namedNode(RDF_TYPE),\n DataFactory.namedNode(`${NS.skos}Concept`),\n null,\n ),\n references: refQuads.length,\n orphans,\n brokenLinks,\n brokenSectionRefs,\n mostConnected,\n coverage,\n sectionCoverage,\n localization,\n coverageFindings,\n exitCode: failed ? 1 : 0,\n };\n}\n\nexport function renderStats(\n report: StatsReport,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") {\n const { exitCode: _exitCode, ...rest } = report;\n return JSON.stringify(rest, null, 2);\n }\n const lines = [\n `Triples: ${report.triples}`,\n `Documents: ${report.docs}`,\n `Sections: ${report.sections}`,\n `Concepts: ${report.concepts}`,\n `References: ${report.references}`,\n ];\n lines.push(\"\", \"Most connected:\");\n if (report.mostConnected.length === 0) lines.push(\" (none)\");\n for (const { doc, degree } of report.mostConnected) {\n lines.push(` ${doc} (${degree})`);\n }\n lines.push(\"\", `Orphan docs (${report.orphans.length}):`);\n for (const orphan of report.orphans) lines.push(` ${orphan}`);\n if (report.orphans.length === 0) lines.push(\" (none)\");\n lines.push(\"\", `Broken internal links (${report.brokenLinks.length}):`);\n for (const { doc, target } of report.brokenLinks) {\n lines.push(` ${doc} -> ${target}`);\n }\n if (report.brokenLinks.length === 0) lines.push(\" (none)\");\n\n lines.push(\"\", `Broken section refs (${report.brokenSectionRefs.length}):`);\n for (const { doc, slug } of report.brokenSectionRefs) {\n lines.push(` ${doc} -> #${slug}`);\n }\n if (report.brokenSectionRefs.length === 0) lines.push(\" (none)\");\n\n const belowThreshold = new Set(report.coverageFindings.map((f) => f.field));\n const width = Math.max(\n ...report.coverage.map((c) => c.field.length),\n ...report.sectionCoverage.map((c) => c.field.length),\n );\n lines.push(\"\", \"Coverage (documents):\");\n for (const { field, docs, pct } of report.coverage) {\n const flag = belowThreshold.has(field) ? \" ! below threshold\" : \"\";\n lines.push(\n ` ${field.padEnd(width)} ${docs}/${report.docs} ${pct.toFixed(1)}%${flag}`,\n );\n }\n\n // Sections are explicit-only (ADR 01013), so this block is reported and not\n // gated — a corpus that has not started on section metadata should not fail.\n lines.push(\"\", \"Coverage (sections, not gated):\");\n if (report.sections === 0) {\n // The vacuous-100% convention exists to stop an empty graph tripping a\n // gate. This block gates nothing, so printing \"0/0 100.0%\" on a corpus with\n // no sections would just assert the opposite of the truth.\n lines.push(\" (no sections in this graph)\");\n } else {\n for (const { field, docs, pct } of report.sectionCoverage) {\n lines.push(\n ` ${field.padEnd(width)} ${docs}/${report.sections} ${pct.toFixed(1)}%`,\n );\n }\n }\n\n // Omitted entirely on a corpus that declares no language, rather than\n // printed empty: a block that says nothing on most corpora teaches readers to\n // skip the report (the failure ADR 01029 recorded for always-zero rows).\n if (report.localization.languages.length > 0) {\n const tagWidth = Math.max(\n ...report.localization.languages.map((l) => l.language.length),\n );\n lines.push(\"\", \"Localization:\");\n for (const { language, docs, untranslated } of report.localization\n .languages) {\n const plural = docs === 1 ? \"doc\" : \"docs\";\n const backlog =\n untranslated.length === 0\n ? \"\"\n : ` ${untranslated.length} untranslated`;\n lines.push(` ${language.padEnd(tagWidth)} ${docs} ${plural}${backlog}`);\n }\n lines.push(` no language: ${report.localization.unlabelled}`);\n }\n return lines.join(\"\\n\");\n}\n","/**\n * `manni graph traverse` — node-centric graph walking from the CLI (ADR 01018).\n *\n * A thin Node wrapper over the browser-native runtime: it reads the built\n * Turtle, hands the quads to the same `GraphIndex` a browser would build from\n * `graph.jsonld`, and runs the same walker. `query` stays triple-pattern;\n * `traverse` answers \"what is connected to this node, and why\".\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 { resolve } from \"node:path\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport {\n compactIri,\n expandTerm,\n loadGraph,\n storeToQuads,\n} from \"../core/load.js\";\nimport { SOFTWARE_SUBJECT_IRIS } from \"../core/iirds.js\";\nimport { NS, PREFIXES } from \"../core/vocab.js\";\nimport { GraphError } from \"../types.js\";\nimport { GraphIndex } from \"../runtime/graph.js\";\nimport {\n impact,\n resolveSubject,\n resolveVariant,\n traverse,\n type Direction,\n type TraverseResult,\n} from \"../runtime/traverse.js\";\n\nexport interface TraverseOptions {\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`). */\n graph?: string;\n /** Starting node: full IRI or a `prefix:local` CURIE. */\n node: string;\n depth?: number;\n predicates?: string[];\n /** Walk inbound edges instead of outbound. */\n reverse?: boolean;\n /** Transitive inbound reach — what is affected if this node changes. */\n impact?: boolean;\n /** Scope filter: a product variant IRI, title, or slug. */\n variant?: string;\n /** Scope filter: a software subject. */\n subject?: string;\n /** Scope filter: a BCP-47 language tag, matched in any case (ADR 01037). */\n lang?: string;\n limit?: number;\n cwd?: string;\n}\n\nexport interface TraverseReport {\n /** The resolved starting IRI. */\n node: string;\n nodes: Array<{ iri: string; depth: number; title?: string }>;\n trace: TraverseResult[\"trace\"];\n}\n\nexport function runTraverse(opts: TraverseOptions): TraverseReport {\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 store = loadGraph(resolve(cwd, opts.graph ?? config.out));\n const quads = storeToQuads(store);\n const graph = GraphIndex.fromQuads(quads, Object.fromEntries(PREFIXES));\n\n const node = expandTerm(opts.node);\n if (!graph.has(node)) {\n throw new GraphError(\n `Node not found in the graph: ${opts.node} — check the IRI, or run \\`manni graph build\\` first.`,\n );\n }\n if (opts.variant && !resolveVariant(graph, opts.variant)) {\n throw new GraphError(\n `Unknown product variant: ${opts.variant} — no iirds:ProductVariant matches that IRI, title, or slug.`,\n );\n }\n // An unresolvable scope filter silently disables itself in the walker, which\n // would hand back exactly the nodes the filter was meant to exclude. Fail\n // loudly instead — same contract as --variant above.\n if (opts.subject && !resolveSubject(graph, opts.subject)) {\n throw new GraphError(\n `Unknown software subject: ${opts.subject} — expected one of ` +\n `${Object.keys(SOFTWARE_SUBJECT_IRIS).sort().join(\", \")}, or a full IRI.`,\n );\n }\n\n const predicates = opts.predicates?.map(expandTerm);\n // A misspelt predicate matches no edge, so the walk returns the seed alone\n // and looks like an answer. Same contract as --variant: fail loudly.\n if (predicates && predicates.length > 0) {\n const used = new Set<string>();\n for (const quad of quads) {\n if (quad.o.kind === \"iri\") used.add(quad.p);\n }\n predicates.forEach((predicate, i) => {\n if (!used.has(predicate)) {\n throw new GraphError(\n `Unknown predicate: ${opts.predicates?.[i] ?? predicate}. No edge in the graph uses it.`,\n );\n }\n });\n }\n const direction: Direction = opts.reverse ? \"in\" : \"out\";\n const result = opts.impact\n ? impact(graph, node, {\n depth: opts.depth,\n predicates,\n variant: opts.variant,\n subject: opts.subject,\n language: opts.lang,\n limit: opts.limit,\n })\n : traverse(graph, {\n seeds: [node],\n depth: opts.depth,\n predicates,\n direction,\n variant: opts.variant,\n subject: opts.subject,\n language: opts.lang,\n limit: opts.limit,\n });\n\n return {\n node,\n nodes: result.nodes.map((n) => {\n const title = graph.literal(n.iri, `${NS.dcterms}title`);\n return title === undefined\n ? { iri: n.iri, depth: n.depth }\n : { iri: n.iri, depth: n.depth, title };\n }),\n trace: result.trace,\n };\n}\n\nexport function renderTraverse(\n report: TraverseReport,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") return JSON.stringify(report, null, 2);\n\n const lines: string[] = [];\n for (const n of report.nodes) {\n const indent = \" \".repeat(n.depth);\n const title = n.title ? ` — ${n.title}` : \"\";\n lines.push(`${indent}${compactIri(n.iri)}${title}`);\n }\n if (report.nodes.length === 0) lines.push(\"(no nodes)\");\n\n if (report.trace.exclusions.length > 0) {\n lines.push(\"\");\n lines.push(\"excluded by scope:\");\n for (const e of report.trace.exclusions) {\n lines.push(\n ` ${compactIri(e.node)} — ${compactIri(e.rule)} ${compactIri(e.value)}`,\n );\n }\n }\n\n lines.push(\"\");\n lines.push(\n `${report.nodes.length} node${report.nodes.length === 1 ? \"\" : \"s\"}, ` +\n `${report.trace.hops.length} hop${report.trace.hops.length === 1 ? \"\" : \"s\"}, ` +\n `${report.trace.exclusions.length} excluded`,\n );\n return lines.join(\"\\n\");\n}\n","/**\n * The deterministic walker (ADR 01018) — breadth-first traversal over a\n * `GraphIndex` with scope filtering, recording every hop and every exclusion\n * into a `QueryTrace`. This is the engine: generic RDF engines return bindings\n * without the path that produced them, and dockg's scope rules (ADR 01014)\n * are domain semantics no general engine knows.\n *\n * Determinism: neighbors come back sorted from the index, the frontier is\n * processed in (depth, IRI) order, and results are emitted in discovery order —\n * so the same graph + query always yields the same nodes *and* the same trace.\n *\n * Platform-neutral: no `node:` imports, no npm dependencies.\n */\nimport { byCodeUnit } from \"../core/sort.js\";\nimport { NS, RDF_TYPE } from \"../core/vocab.js\";\nimport { canonicalLanguageTag } from \"../core/localizations.js\";\nimport {\n GRAPH_NOT_APPLICABLE_TO_VARIANT,\n GRAPH_NOT_SOFTWARE_SUBJECT,\n IIRDS_HAS_SUBJECT,\n IIRDS_RELATES_TO_PRODUCT_VARIANT,\n SOFTWARE_SUBJECT_IRIS,\n} from \"../core/iirds.js\";\nimport type { GraphIndex } from \"./graph.js\";\nimport { createTrace, type QueryTrace, type ScopeExclusion } from \"./trace.js\";\n\nconst DCTERMS_TITLE = `${NS.dcterms}title`;\nconst DCTERMS_REFERENCES = `${NS.dcterms}references`;\nconst DCTERMS_LANGUAGE = `${NS.dcterms}language`;\n\n/** A section IRI's document, or the IRI itself when it has no fragment. */\nfunction documentOf(iri: string): string {\n const hash = iri.indexOf(\"#\");\n return hash === -1 ? iri : iri.slice(0, hash);\n}\n\nexport type Direction = \"out\" | \"in\" | \"both\";\n\nexport interface ScopeFilter {\n /** Product variant: an IRI, a `dcterms:title` (e.g. \"SP-X100\"), or a slug. */\n variant?: string;\n /** Software subject: an IRI or a `graph.about-product-aspect` value (e.g. \"architecture\"). */\n subject?: string;\n /**\n * BCP-47 tag (ADR 01037). Matched against `dcterms:language` after both are\n * canonicalized, since tags are case-insensitive. There is no fallback:\n * `de-AT` is not `de`, because relatedness between locales is an inference\n * and this runtime does not infer.\n */\n language?: string;\n}\n\nexport interface TraverseOptions extends ScopeFilter {\n /** Starting nodes (IRIs). */\n seeds: string[];\n /** Maximum hops from a seed. Default 1. */\n depth?: number;\n /** Restrict to these predicates (full IRIs). Default: every predicate. */\n predicates?: string[];\n /** Which edge directions to follow. Default \"out\". */\n direction?: Direction;\n /** Stop after this many nodes (seeds included). */\n limit?: number;\n /**\n * Follow `rdf:type` edges into class nodes. Default false, deliberately:\n * class nodes are schema, not content, and every document shares them — so\n * traversing them makes every document reachable from every other in two\n * hops (`a → graph:Document → b`). That is exactly the edge contamination\n * graph-governed retrieval exists to avoid. A `predicates` list that names\n * `rdf:type` follows them too, because it asked for them by name.\n */\n includeTypeEdges?: boolean;\n /** Append to an existing trace instead of starting a new one. */\n trace?: QueryTrace;\n}\n\nexport interface TraversedNode {\n iri: string;\n /** Hops from the nearest seed; seeds are 0. */\n depth: number;\n}\n\nexport interface TraverseResult {\n nodes: TraversedNode[];\n trace: QueryTrace;\n}\n\n/**\n * Resolve a variant input to its IRI: an exact node IRI, a `dcterms:title`\n * match on an `iirds:ProductVariant`, or a trailing-segment slug match.\n */\nexport function resolveVariant(\n graph: GraphIndex,\n input: string,\n): string | undefined {\n if (graph.has(input)) return input;\n const wanted = input.toLowerCase();\n const variants = graph.instancesOf(`${NS.iirds}ProductVariant`);\n for (const v of variants) {\n if (graph.literal(v, DCTERMS_TITLE)?.toLowerCase() === wanted) return v;\n }\n for (const v of variants) {\n if (v.slice(v.lastIndexOf(\"/\") + 1).toLowerCase() === wanted) return v;\n }\n return undefined;\n}\n\n/** Resolve a software-subject input to its iiRDS IRI. */\nexport function resolveSubject(\n graph: GraphIndex,\n input: string,\n): string | undefined {\n const mapped = SOFTWARE_SUBJECT_IRIS[input.toLowerCase()];\n if (mapped) return mapped;\n const expanded = graph.expand(input);\n return expanded.startsWith(\"http\") ? expanded : undefined;\n}\n\n/**\n * Decide whether a node survives the scope filter, and if not, why.\n *\n * Rules, in the spirit of ADR 01014 (absence of a positive claim is not a\n * negative claim, so both polarities are explicit):\n * - An explicit negative (`graph:notApplicableToVariant` /\n * `graph:notSoftwareSubject`) naming the target **excludes** the node.\n * - A node that declares a positive set which omits the target is **excluded**\n * — it scoped itself elsewhere — recorded under the positive predicate so\n * the trace distinguishes this from an explicit negative.\n * - A node that makes no claim is **kept**: unscoped content applies broadly.\n */\nexport function scopeExclusion(\n graph: GraphIndex,\n iri: string,\n scope: { variantIri?: string; subjectIri?: string; language?: string },\n): ScopeExclusion | undefined {\n // [target, positive predicate, negative predicate, object kind]. Language\n // joins the same table with two differences, both deliberate: its objects are\n // literals, and it has **no negative predicate** — a document has one\n // language (`sh:maxCount 1`), so \"not in German\" is not a claim an author\n // makes and there is nothing for a `graph:not*` term to express (ADR 01037).\n const checks: Array<\n [string | undefined, string, string | undefined, \"iri\" | \"literal\"]\n > = [\n [\n scope.variantIri,\n IIRDS_RELATES_TO_PRODUCT_VARIANT,\n GRAPH_NOT_APPLICABLE_TO_VARIANT,\n \"iri\",\n ],\n [scope.subjectIri, IIRDS_HAS_SUBJECT, GRAPH_NOT_SOFTWARE_SUBJECT, \"iri\"],\n [scope.language, DCTERMS_LANGUAGE, undefined, \"literal\"],\n ];\n for (const [target, positive, negative, kind] of checks) {\n if (!target) continue;\n if (negative !== undefined) {\n const denied = graph\n .values(iri, negative)\n .some((v) => v.kind === kind && v.value === target);\n if (denied) return { node: iri, rule: negative, value: target };\n }\n\n // Language is the one dimension a section inherits. Applicability is\n // explicit-only by ADR 01013 — a section may legitimately scope itself\n // differently from its document — but a section's *text* is in its\n // document's language and cannot differ, and the per-locale indexes file it\n // that way (`partitionByLanguage`). Without this a link with an anchor\n // reaches a section directly (derive.ts mints section IRIs as\n // `dcterms:references` targets) and carries English prose past a `de`\n // filter that excluded the document it belongs to.\n const subject = positive === DCTERMS_LANGUAGE ? documentOf(iri) : iri;\n const claimed = graph.values(subject, positive);\n if (claimed.length > 0) {\n const matches = claimed.some(\n (v) => v.kind === kind && v.value === target,\n );\n if (!matches) return { node: iri, rule: positive, value: target };\n }\n }\n return undefined;\n}\n\n/** Breadth-first traversal with scope filtering and full trace recording. */\nexport function traverse(\n graph: GraphIndex,\n options: TraverseOptions,\n): TraverseResult {\n const trace = options.trace ?? createTrace();\n const maxDepth = options.depth ?? 1;\n const direction: Direction = options.direction ?? \"out\";\n const allowed =\n options.predicates && options.predicates.length > 0\n ? new Set(options.predicates.map((p) => graph.expand(p)))\n : undefined;\n\n const variantIri = options.variant\n ? resolveVariant(graph, options.variant)\n : undefined;\n const subjectIri = options.subject\n ? resolveSubject(graph, options.subject)\n : undefined;\n // Language needs no resolution step, only a spelling: the filter value and\n // the graph value are both BCP-47 tags, and `derive` writes the canonical one.\n const language =\n options.language === undefined\n ? undefined\n : canonicalLanguageTag(options.language);\n const scope = { variantIri, subjectIri, language };\n // A predicate list that names `rdf:type` asked for type edges. Dropping them\n // anyway answered a question nobody asked, with an empty result.\n const followTypes =\n options.includeTypeEdges === true || allowed?.has(RDF_TYPE) === true;\n\n const excluded = new Set<string>();\n const keep = (iri: string): boolean => {\n if (excluded.has(iri)) return false;\n const exclusion = scopeExclusion(graph, iri, scope);\n if (exclusion) {\n excluded.add(iri);\n trace.exclusions.push(exclusion);\n return false;\n }\n return true;\n };\n\n const nodes: TraversedNode[] = [];\n const seen = new Set<string>();\n let frontier: string[] = [];\n\n // A seed `findEntry` already recorded keeps its real provenance. Re-recording\n // it as `explicit`/1 would leave the trace answering \"why did retrieval start\n // here?\" twice, with the lexical/vector score contradicted by a flat 1.\n const alreadySeeded = new Set(trace.entry.map((e) => e.iri));\n\n for (const seed of [...options.seeds].sort(byCodeUnit)) {\n if (!graph.has(seed) || seen.has(seed)) continue;\n seen.add(seed);\n if (!alreadySeeded.has(seed)) {\n trace.entry.push({ iri: seed, score: 1, via: \"explicit\" });\n }\n // A seed always expands, even when the scope filter excludes it. The\n // filter governs what the walk *reaches*, not where the caller chose to\n // start — and the canonical query is exactly this shape: from an English\n // page, `--impact --lang de` asks what German content a change here\n // affects. Gating the seed made that return nothing at all, because the\n // seed excluded itself before the frontier was ever populated.\n //\n // It is still kept out of the results and recorded in the trace, so the\n // answer honors the filter even though the walk started outside it.\n if (keep(seed)) nodes.push({ iri: seed, depth: 0 });\n frontier.push(seed);\n }\n\n const limit = options.limit ?? Infinity;\n for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth++) {\n const next: string[] = [];\n for (const from of frontier) {\n if (nodes.length >= limit) break;\n for (const { predicate, target, dir } of neighbors(\n graph,\n from,\n direction,\n )) {\n if (allowed && !allowed.has(predicate)) continue;\n if (!followTypes && predicate === RDF_TYPE) continue;\n // The hop is recorded before filtering: the trace shows the edge was\n // walked even when the target is then scope-excluded.\n trace.hops.push({ from, predicate, to: target, depth, direction: dir });\n if (seen.has(target)) continue;\n seen.add(target);\n if (!keep(target)) continue;\n if (nodes.length >= limit) break;\n nodes.push({ iri: target, depth });\n next.push(target);\n }\n }\n frontier = next;\n }\n\n return { nodes, trace };\n}\n\nfunction neighbors(\n graph: GraphIndex,\n iri: string,\n direction: Direction,\n): Array<{ predicate: string; target: string; dir: \"out\" | \"in\" }> {\n const out: Array<{ predicate: string; target: string; dir: \"out\" | \"in\" }> =\n [];\n if (direction === \"out\" || direction === \"both\") {\n for (const e of graph.out(iri)) out.push({ ...e, dir: \"out\" });\n }\n if (direction === \"in\" || direction === \"both\") {\n for (const e of graph.in(iri)) out.push({ ...e, dir: \"in\" });\n }\n return out;\n}\n\n/** Who links to this node (one hop inbound over `dcterms:references`). */\nexport function reverseReferences(\n graph: GraphIndex,\n iri: string,\n options: Omit<TraverseOptions, \"seeds\" | \"direction\" | \"predicates\"> = {},\n): TraverseResult {\n return traverse(graph, {\n ...options,\n seeds: [iri],\n direction: \"in\",\n predicates: [DCTERMS_REFERENCES],\n depth: options.depth ?? 1,\n });\n}\n\n/**\n * Transitive inbound reach — \"what is affected if this node changes\".\n * Excludes the node itself from the returned set. Defaults to depth 3 rather\n * than the walker's 1, because impact analysis is only useful transitively.\n */\nexport function impact(\n graph: GraphIndex,\n iri: string,\n options: Omit<TraverseOptions, \"seeds\" | \"direction\"> = {},\n): TraverseResult {\n const result = traverse(graph, {\n ...options,\n seeds: [iri],\n direction: \"in\",\n depth: options.depth ?? 3,\n // The seed *may* occupy a slot in the walker's limit, so ask for one more:\n // `limit` means \"this many *affected* nodes\". Whether it actually takes\n // one depends on the scope filter — a seed the filter excludes still\n // expands but is not in `nodes` — so the slack is trimmed below rather\n // than assumed spent.\n limit: options.limit === undefined ? undefined : options.limit + 1,\n });\n const affected = result.nodes.filter((n) => n.iri !== iri);\n return {\n nodes:\n options.limit === undefined ? affected : affected.slice(0, options.limit),\n trace: result.trace,\n };\n}\n"],"mappings":"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","names":["readFileSync","resolve","XSD_STRING","iri","entry","XSD_STRING","path","existsSync","resolve","iri","path","slice","GRAPH_DOCUMENT","GRAPH_PATH","GRAPH_LEVEL","DCTERMS_TITLE","path","resolve","existsSync","entry","XSD_STRING","iri","path","resolve","readFileSync","resolve","DataFactory","resolve","DataFactory","readFileSync","writeFileSync","resolve","path","doc","graph","readFileSync","resolve","DataFactory","DataFactory","path","readFileSync","resolve","selectProvider","providerSpecFor","selectProvider","base","resolve","path","readFileSync","own","GRAPH_KEY","entry","writeFileSync","createHash","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","resolve","entry","entry","sha256","createHash","join","existsSync","readFileSync","mkdirSync","writeFileSync","resolve","dirname","createHash","existsSync","readFileSync","dirname","join","resolve","searchIndexDigest","iri","iri","iri","readFileSync","createHash","join","existsSync","resolve","dirname","entry","resolve","DataFactory","DataFactory","iri","resolve","resolve","DCTERMS_TITLE","DCTERMS_LANGUAGE","iri","resolve"]}
1
+ {"version":3,"sources":["../src/graph/commands/export.ts","../src/graph/core/emit-jsonld.ts","../src/graph/core/emit-rdfxml.ts","../src/graph/core/iirds-package.ts","../src/graph/core/zip.ts","../src/graph/core/search-index.ts","../src/graph/runtime/resolve.ts","../src/graph/runtime/graph.ts","../src/graph/commands/query.ts","../src/graph/commands/fill.ts","../src/graph/core/frontmatter-edit.ts","../src/graph/core/fill-guard.ts","../src/graph/llm/cache.ts","../src/graph/llm/prompt.ts","../src/graph/llm/provider.ts","../src/graph/commands/embed.ts","../src/graph/core/vector-index.ts","../src/graph/embed/local.ts","../src/graph/embed/mock.ts","../src/graph/commands/search.ts","../src/graph/runtime/vector.ts","../src/graph/runtime/trace.ts","../src/graph/runtime/entry.ts","../src/graph/runtime/lexical.ts","../src/graph/commands/stats.ts","../src/graph/commands/traverse.ts","../src/graph/runtime/traverse.ts"],"sourcesContent":["/**\n * `manni graph export` — reserialize the built graph into a consumer format. Reads\n * the graph the same way `stats`/`check` do (loadGraph over the config `out`,\n * missing graph → exit 2) and writes a deterministic rendering. `jsonld` emits a\n * whole-graph JSON-LD file; `iirds` projects the graph into a conformant,\n * deterministic unrestricted iiRDS package (`.iirds` ZIP) — see ADR 01017.\n */\nimport { createHash } from \"node:crypto\";\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport { GraphError } from \"../types.js\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { documentBase } from \"../core/discover.js\";\nimport { emitJsonLd } from \"../core/emit-jsonld.js\";\nimport { emitRdfXml } from \"../core/emit-rdfxml.js\";\nimport { projectPackage } from \"../core/iirds-package.js\";\nimport { loadGraph, storeToQuads } from \"../core/load.js\";\nimport {\n buildSearchIndex,\n documentsByLanguage,\n emitSearchIndex,\n partitionByLanguage,\n} from \"../core/search-index.js\";\nimport {\n emitLocalizations,\n isLanguageTag,\n LOCALIZATIONS_FILENAME,\n searchIndexFilename,\n type LocalizationEntry,\n} from \"../core/localizations.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\nimport { PREFIXES } from \"../core/vocab.js\";\nimport { GraphIndex } from \"../runtime/graph.js\";\nimport { writeZip, type ZipEntry } from \"../core/zip.js\";\n\n/**\n * What `manni graph export <target>` can write, in the order messages list them.\n * The CLI names its positional against this list, and `runExport` holds a\n * library caller to it too.\n */\nexport const EXPORT_TARGETS = [\"jsonld\", \"iirds\", \"search\"] as const;\n\nexport type ExportFormat = (typeof EXPORT_TARGETS)[number];\n\nexport interface ExportOptions {\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`). */\n graph?: string;\n format: ExportFormat;\n /** Output path (default: the graph path with the format's extension). */\n out?: string;\n cwd?: string;\n}\n\nexport interface ExportResult {\n outPath: string;\n format: ExportFormat;\n /** Distinct subject nodes in the emitted (or projected) graph. */\n nodes: number;\n /** Non-fatal projection warnings (iiRDS only; empty otherwise). */\n warnings: string[];\n}\n\n/** File extension each single-file format writes to. */\nconst EXTENSION: Record<\"jsonld\" | \"iirds\", string> = {\n jsonld: \".jsonld\",\n iirds: \".iirds\",\n};\n\n/** Replace a path's extension (or append one) with `.jsonld`-style ext. */\nfunction withExtension(path: string, ext: string): string {\n return path.replace(/\\.[^./\\\\]*$/, \"\") + ext;\n}\n\nfunction runJsonLd(cwd: string, graphPath: string, out?: string): ExportResult {\n const store = loadGraph(graphPath);\n const quads = storeToQuads(store);\n const serialized = emitJsonLd(quads);\n const nodes = new Set(quads.map((q) => q.s)).size;\n const outPath = out\n ? resolve(cwd, out)\n : withExtension(graphPath, EXTENSION.jsonld);\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, serialized, \"utf8\");\n return { outPath, format: \"jsonld\", nodes, warnings: [] };\n}\n\nfunction runIirds(\n cwd: string,\n sources: string,\n graphPath: string,\n iirds: { title?: string; creator?: string; version: \"1.2\" | \"1.3\" },\n baseIri: string,\n out?: string,\n): ExportResult {\n const store = loadGraph(graphPath);\n const projection = projectPackage(\n store,\n {\n baseIri,\n version: iirds.version,\n title: iirds.title,\n creator: iirds.creator,\n },\n sources,\n );\n const metadata = emitRdfXml(projection.quads, projection.prefixes);\n\n // Deterministic entry order: mimetype (stored, first) → metadata → content\n // files sorted by their in-archive path.\n const content = [...projection.contentFiles]\n .sort((a, b) => byCodeUnit(a.zipPath, b.zipPath))\n .map((f): ZipEntry => ({ name: f.zipPath, data: readFileSync(f.absPath) }));\n const entries: ZipEntry[] = [\n {\n name: \"mimetype\",\n data: Buffer.from(\"application/iirds+zip\"),\n store: true,\n },\n { name: \"META-INF/metadata.rdf\", data: Buffer.from(metadata, \"utf8\") },\n ...content,\n ];\n\n const outPath = out\n ? resolve(cwd, out)\n : withExtension(graphPath, EXTENSION.iirds);\n mkdirSync(dirname(outPath), { recursive: true });\n writeFileSync(outPath, writeZip(entries));\n const nodes = new Set(projection.quads.map((q) => q.s)).size;\n return { outPath, format: \"iirds\", nodes, warnings: projection.warnings };\n}\n\n/**\n * The same digest `manni graph embed` records as a sidecar's `source` and the runtime\n * recomputes in a browser: SHA-256 over the index file's exact bytes. Computed\n * here from the string about to be written, so the manifest cannot disagree\n * with the file it describes.\n */\nfunction searchIndexDigest(raw: string): string {\n return `sha256:${createHash(\"sha256\").update(raw, \"utf8\").digest(\"hex\")}`;\n}\n\n/**\n * The lexical search artifacts. Reads each document's source from disk — the\n * same thing the iiRDS projection does for renditions — because the graph\n * deliberately carries no prose (ADR 01008/01019).\n *\n * Fans out per language and writes a manifest beside them (ADR 01038). The\n * fan-out is unconditional, including for a monolingual corpus: one rule beats\n * a filename that changes shape the day someone adds a translation.\n */\nfunction runSearchIndex(\n cwd: string,\n sources: string,\n graphPath: string,\n out?: string,\n): ExportResult {\n const store = loadGraph(graphPath);\n const graph = GraphIndex.fromQuads(\n storeToQuads(store),\n Object.fromEntries(PREFIXES),\n );\n const warnings: string[] = [];\n const index = buildSearchIndex(graph, sources, { warnings });\n const byLanguage = partitionByLanguage(graph, index);\n const docCounts = documentsByLanguage(graph);\n\n // Siblings of the graph, named for what they are: `graph.json` next to\n // `graph.jsonld` would be a trap. `--out` names the directory here, not a\n // file, because there is more than one.\n const outDir = out ? resolve(cwd, out) : dirname(graphPath);\n mkdirSync(outDir, { recursive: true });\n\n const languages: LocalizationEntry[] = [];\n for (const [language, doc] of byLanguage) {\n // The tag becomes a filename, and `export` does not run SHACL — so a\n // `dcterms:language` literal reaches this line exactly as the corpus wrote\n // it. Unchecked, `lang: ../escaped` would put a path segment into\n // `writeFileSync` and crash with a raw stack trace (exit 1) instead of the\n // operational error this is (exit 2).\n if (!isLanguageTag(language)) {\n throw new GraphError(\n `Cannot write an index for language \"${language}\": not a BCP-47 tag. ` +\n `Fix the \\`lang\\`/\\`language\\` frontmatter, or the route's \\`language\\`, ` +\n `and rebuild — \\`manni graph check\\` reports which document carries it.`,\n );\n }\n const filename = searchIndexFilename(language);\n const serialized = emitSearchIndex(doc);\n writeFileSync(join(outDir, filename), serialized, \"utf8\");\n languages.push({\n language,\n documents: docCounts.get(language) ?? 0,\n search: {\n path: filename,\n entries: doc.entries.length,\n digest: searchIndexDigest(serialized),\n },\n });\n }\n\n const manifestPath = join(outDir, LOCALIZATIONS_FILENAME);\n writeFileSync(\n manifestPath,\n emitLocalizations({ version: 1, languages }),\n \"utf8\",\n );\n return {\n outPath: manifestPath,\n format: \"search\",\n nodes: index.entries.length,\n warnings,\n };\n}\n\n/**\n * Async by contract — every command core is, and the CLI awaits this one — but\n * synchronous in fact: all three writers are `writeFileSync`. Spelled as a\n * `Promise` the body never awaits, through the constructor rather than\n * `Promise.resolve().then`, so the executor still runs eagerly and a usage\n * error still *rejects* the returned promise instead of throwing before the\n * caller holds one. That is what `async` did, said without claiming an `await`\n * that is not there.\n */\nexport function runExport(opts: ExportOptions): Promise<ExportResult> {\n return new Promise((ok) => {\n ok(exportOnce(opts));\n });\n}\n\nfunction exportOnce(opts: ExportOptions): ExportResult {\n const cwd = opts.cwd ?? process.cwd();\n if (!(EXPORT_TARGETS as readonly string[]).includes(opts.format)) {\n throw new GraphError(\n `Unknown export target \"${opts.format}\". Use ${EXPORT_TARGETS.join(\" | \")}.`,\n );\n }\n\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 // A page's `graph:path` is read from where a bare `build` labels it from:\n // the config's directory when it declares collections, else the working one.\n const sources = documentBase(config, {}, cwd);\n\n if (opts.format === \"jsonld\") return runJsonLd(cwd, graphPath, opts.out);\n if (opts.format === \"search\") {\n return runSearchIndex(cwd, sources, graphPath, opts.out);\n }\n return runIirds(\n cwd,\n sources,\n graphPath,\n config.export.iirds,\n config.baseIri,\n opts.out,\n );\n}\n","/**\n * Deterministic JSON-LD serialization — the web-native rendering of the same\n * graph the Turtle emitter produces. Canonical form: an `@context` carrying the\n * fixed prefix table, then `@graph` as one node object per subject sorted by\n * `@id`. Within a node: `@id`, then `@type` (compacted class IRIs, sorted),\n * then predicate CURIE keys sorted, each value array sorted. Objects are built\n * in that sorted key order so `JSON.stringify(_, null, 2)` is byte-stable.\n * Byte-identical output for any input quad order.\n *\n * Deliberately hand-rolled rather than the `jsonld` library, for the same\n * reason the Turtle emitter avoids N3.Writer: library formatting and ordering\n * are incidental, not a stability contract. dockg emits no blank nodes and no\n * language-tagged literals, so neither is handled here.\n */\nimport { compactIri } from \"./load.js\";\nimport type { Quad, Term } from \"./derive.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS, PREFIXES, RDF_TYPE } from \"./vocab.js\";\n\nconst XSD_STRING = `${NS.xsd}string`;\n\n/**\n * A rendered JSON-LD object value plus the fields it sorts by. Sorting compares\n * field by field (never a joined string with a separator — that would need a\n * delimiter byte, and NUL/control bytes in source are forbidden): IRIs before\n * literals (mirroring the Turtle emitter), then lexical value, then datatype.\n */\ninterface RenderedValue {\n value: unknown;\n /** 0 = IRI, 1 = literal — IRIs sort first. */\n kind: 0 | 1;\n /** IRI value or literal lexical form. */\n primary: string;\n /** Datatype IRI for typed literals; \"\" for IRIs and plain literals. */\n datatype: string;\n}\n\nfunction renderValue(term: Term): RenderedValue {\n if (term.kind === \"iri\") {\n return {\n value: { \"@id\": term.value },\n kind: 0,\n primary: term.value,\n datatype: \"\",\n };\n }\n if (term.datatype && term.datatype !== XSD_STRING) {\n return {\n value: { \"@value\": term.value, \"@type\": compactIri(term.datatype) },\n kind: 1,\n primary: term.value,\n datatype: term.datatype,\n };\n }\n return { value: term.value, kind: 1, primary: term.value, datatype: \"\" };\n}\n\nfunction compareRendered(a: RenderedValue, b: RenderedValue): number {\n if (a.kind !== b.kind) return a.kind - b.kind;\n const p = byCodeUnit(a.primary, b.primary);\n if (p !== 0) return p;\n return byCodeUnit(a.datatype, b.datatype);\n}\n\n/** Collapse a sorted value list to a scalar (n=1) or array (n>1). */\nfunction collapse(values: RenderedValue[]): unknown {\n const rendered = [...values].sort(compareRendered).map((v) => v.value);\n return rendered.length === 1 ? rendered[0] : rendered;\n}\n\nexport function emitJsonLd(quads: Quad[]): string {\n const context: Record<string, string> = {};\n for (const [prefix, ns] of PREFIXES) context[prefix] = ns;\n\n // subject → predicate → terms\n const subjects = new Map<string, Map<string, Term[]>>();\n for (const quad of quads) {\n let preds = subjects.get(quad.s);\n if (!preds) {\n preds = new Map();\n subjects.set(quad.s, preds);\n }\n let terms = preds.get(quad.p);\n if (!terms) {\n terms = [];\n preds.set(quad.p, terms);\n }\n terms.push(quad.o);\n }\n\n // Sorting the entries rather than the keys: each predicate map arrives with\n // the subject it belongs to, so there is no second lookup to assert on.\n const graph = [...subjects.entries()]\n .sort(([a], [b]) => byCodeUnit(a, b))\n .map(([subject, preds]) => {\n const node: Record<string, unknown> = { \"@id\": subject };\n\n const types = preds.get(RDF_TYPE);\n if (types) {\n const compacted = types\n .map((t) => compactIri(t.value))\n .sort(byCodeUnit);\n node[\"@type\"] = compacted.length === 1 ? compacted[0] : compacted;\n }\n\n const predEntries = [...preds.entries()]\n .filter(([p]) => p !== RDF_TYPE)\n .sort(([a], [b]) => byCodeUnit(a, b));\n for (const [p, terms] of predEntries) {\n node[compactIri(p)] = collapse(terms.map(renderValue));\n }\n return node;\n });\n\n return `${JSON.stringify({ \"@context\": context, \"@graph\": graph }, null, 2)}\\n`;\n}\n","/**\n * Deterministic RDF/XML serialization — the metadata half of the iiRDS package\n * export (ADR 01017). RDF/XML is what `META-INF/metadata.rdf` must be (the iiRDS\n * container rule; Turtle/JSON-LD are not accepted there). Hand-rolled like the\n * Turtle/JSON-LD emitters ([emit.ts], [emit-jsonld.ts]) so the bytes are a\n * stability contract.\n *\n * Canonical form: an XML declaration, then `<rdf:RDF>` with namespace\n * declarations in sorted prefix order, then one `<rdf:Description>` per subject\n * sorted by IRI. Within a subject, predicates are sorted; each object is an\n * `rdf:resource` (IRI) or escaped element text (literal, with `rdf:datatype`\n * when typed). No blank nodes. Byte-identical for any input quad order.\n *\n * The prefix table is passed in (not the global `PREFIXES`) so the package can\n * declare `vcard` without touching the main graph's Turtle/JSON-LD headers.\n */\nimport type { Quad, Term } from \"./derive.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS } from \"./vocab.js\";\n\nconst XSD_STRING = `${NS.xsd}string`;\n\nfunction escapeText(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction escapeAttr(value: string): string {\n return escapeText(value).replace(/\"/g, \"&quot;\");\n}\n\n/** Compact an IRI to `prefix:local` using the supplied table (longest NS wins). */\nfunction toQName(\n iri: string,\n prefixes: ReadonlyArray<[string, string]>,\n): string {\n let best: string | undefined;\n let bestNs = \"\";\n for (const [prefix, ns] of prefixes) {\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 if (best === undefined) {\n throw new Error(`emitRdfXml: no prefix covers the IRI ${iri}`);\n }\n return best;\n}\n\n/** Sort objects: IRIs before literals, then by value, then by datatype. */\nfunction compareTerms(a: Term, b: Term): 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 return byCodeUnit(da, db);\n}\n\nexport function emitRdfXml(\n quads: Quad[],\n prefixes: Record<string, string>,\n): string {\n const sortedPrefixes = Object.entries(prefixes).sort(([a], [b]) =>\n byCodeUnit(a, b),\n );\n\n const lines: string[] = ['<?xml version=\"1.0\" encoding=\"UTF-8\"?>'];\n lines.push(\"<rdf:RDF\");\n sortedPrefixes.forEach(([prefix, ns], i) => {\n const tail = i === sortedPrefixes.length - 1 ? \">\" : \"\";\n lines.push(` xmlns:${prefix}=\"${escapeAttr(ns)}\"${tail}`);\n });\n\n // subject → predicate → terms\n const subjects = new Map<string, Map<string, Term[]>>();\n for (const quad of quads) {\n let preds = subjects.get(quad.s);\n if (!preds) {\n preds = new Map();\n subjects.set(quad.s, preds);\n }\n let terms = preds.get(quad.p);\n if (!terms) {\n terms = [];\n preds.set(quad.p, terms);\n }\n terms.push(quad.o);\n }\n\n // Sorting the entries rather than the keys: each predicate map arrives with\n // the subject it belongs to and each term list with its predicate, so there\n // is no second lookup left to assert on.\n const sortedSubjects = [...subjects.entries()].sort(([a], [b]) =>\n byCodeUnit(a, b),\n );\n for (const [subject, preds] of sortedSubjects) {\n lines.push(` <rdf:Description rdf:about=\"${escapeAttr(subject)}\">`);\n const sortedPreds = [...preds.entries()].sort(([a], [b]) =>\n byCodeUnit(a, b),\n );\n for (const [p, terms] of sortedPreds) {\n const qname = toQName(p, sortedPrefixes);\n for (const term of [...terms].sort(compareTerms)) {\n if (term.kind === \"iri\") {\n lines.push(\n ` <${qname} rdf:resource=\"${escapeAttr(term.value)}\"/>`,\n );\n } else if (term.datatype && term.datatype !== XSD_STRING) {\n lines.push(\n ` <${qname} rdf:datatype=\"${escapeAttr(term.datatype)}\">${escapeText(term.value)}</${qname}>`,\n );\n } else {\n lines.push(` <${qname}>${escapeText(term.value)}</${qname}>`);\n }\n }\n }\n lines.push(\" </rdf:Description>\");\n }\n\n lines.push(\"</rdf:RDF>\");\n return `${lines.join(\"\\n\")}\\n`;\n}\n","/**\n * Graph → iiRDS package projection (ADR 01017). Reads the built graph and emits\n * the metadata quads + content-file manifest for an unrestricted iiRDS package:\n * one `iirds:Package`, each `graph:Document` re-typed as an `iirds:Topic` linked\n * via `iirds:is-part-of-package`, each source file exposed as an `iirds:Rendition`\n * (`iirds:source` + `iirds:format`), and the Phase-2 iiRDS classification carried\n * across. This is a *projection* — it builds a fresh quad set (never the whole\n * store), so the package graph contains only iiRDS terms, not dockg-internal\n * types. Deterministic: baseIri-derived IRIs (no random UUIDs), no blank nodes.\n */\nimport { existsSync } from \"node:fs\";\nimport { extname, resolve } from \"node:path\";\nimport { DataFactory, type Store } from \"n3\";\nimport { GraphError } from \"../types.js\";\nimport type { Quad, Term } from \"./derive.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS, RDF_TYPE } from \"./vocab.js\";\nimport { escapesArchiveRoot } from \"./zip.js\";\nimport {\n IIRDS_CREATOR,\n IIRDS_HAS_PARTY_ROLE,\n IIRDS_HAS_RENDITION,\n IIRDS_HAS_SUBJECT,\n IIRDS_HAS_TOPIC_TYPE,\n IIRDS_IIRDS_VERSION,\n IIRDS_IS_PART_OF_PACKAGE,\n IIRDS_LANGUAGE,\n IIRDS_PACKAGE,\n IIRDS_PARTY,\n IIRDS_PRODUCT_VARIANT,\n IIRDS_RELATES_TO_LIFECYCLE_PHASE,\n IIRDS_RELATES_TO_PARTY,\n IIRDS_RELATES_TO_PRODUCT_VARIANT,\n IIRDS_RELATES_TO_VCARD,\n IIRDS_RENDITION,\n IIRDS_SOURCE,\n IIRDS_FORMAT,\n IIRDS_TITLE,\n IIRDS_TOPIC,\n VCARD_NS,\n VCARD_ORGANIZATION,\n VCARD_ORGANIZATION_NAME,\n} from \"./iirds.js\";\n\nconst GRAPH_DOCUMENT = `${NS.graph}Document`;\nconst XSD_STRING = `${NS.xsd}string`;\n\n/**\n * A rendition's media type, by its source's extension (proposal 0077 §2).\n * The graph keeps a page's path and not the format it was parsed as, so a\n * page read under `--as` from an unclaimed extension falls back to Markdown,\n * the one format every such page was before 0077.\n */\nconst MEDIA_TYPES: Readonly<Record<string, string>> = {\n \".html\": \"text/html\",\n \".htm\": \"text/html\",\n \".adoc\": \"text/asciidoc\",\n \".asciidoc\": \"text/asciidoc\",\n \".rst\": \"text/x-rst\",\n \".dita\": \"application/dita+xml\",\n \".ditamap\": \"application/dita+xml\",\n \".xml\": \"application/xml\",\n};\n\nfunction mediaTypeOf(path: string): string {\n return MEDIA_TYPES[extname(path).toLowerCase()] ?? \"text/markdown\";\n}\n\n/** iiRDS classification edges carried from each Document verbatim. */\nconst CARRIED = [\n IIRDS_HAS_TOPIC_TYPE,\n IIRDS_HAS_SUBJECT,\n IIRDS_RELATES_TO_PRODUCT_VARIANT,\n IIRDS_RELATES_TO_LIFECYCLE_PHASE,\n];\n\nexport interface IirdsPackageOptions {\n baseIri: string;\n version: string;\n title?: string;\n creator?: string;\n}\n\nexport interface ContentFile {\n /** In-archive path (matches the Rendition's iirds:source). */\n zipPath: string;\n /** Absolute path of the source file on disk. */\n absPath: string;\n}\n\nexport interface PackageProjection {\n quads: Quad[];\n prefixes: Record<string, string>;\n contentFiles: ContentFile[];\n warnings: string[];\n}\n\nconst iri = (value: string): Term => ({ kind: \"iri\", value });\nconst lit = (value: string, datatype?: string): Term =>\n datatype ? { kind: \"literal\", value, datatype } : { kind: \"literal\", value };\n\nfunction firstObject(store: Store, s: string, p: string): string | undefined {\n const q = store.getQuads(DataFactory.namedNode(s), DataFactory.namedNode(p), null, null)[0];\n return q?.object.value;\n}\n\nexport function projectPackage(\n store: Store,\n opts: IirdsPackageOptions,\n cwd: string,\n): PackageProjection {\n const quads: Quad[] = [];\n const contentFiles: ContentFile[] = [];\n const warnings: string[] = [];\n const add = (s: string, p: string, o: Term): void => {\n quads.push({ s, p, o });\n };\n\n const pkg = `${opts.baseIri}package`;\n add(pkg, RDF_TYPE, iri(IIRDS_PACKAGE));\n add(pkg, IIRDS_IIRDS_VERSION, lit(opts.version));\n add(pkg, IIRDS_TITLE, lit(opts.title ?? \"manni graph export\"));\n\n if (opts.creator) {\n const party = `${opts.baseIri}party/creator`;\n const org = `${opts.baseIri}vcard/creator`;\n add(pkg, IIRDS_RELATES_TO_PARTY, iri(party));\n add(party, RDF_TYPE, iri(IIRDS_PARTY));\n add(party, IIRDS_HAS_PARTY_ROLE, iri(IIRDS_CREATOR));\n add(party, IIRDS_RELATES_TO_VCARD, iri(org));\n add(org, RDF_TYPE, iri(VCARD_ORGANIZATION));\n add(org, VCARD_ORGANIZATION_NAME, lit(opts.creator));\n }\n\n const docs = store\n .getQuads(null, DataFactory.namedNode(RDF_TYPE), DataFactory.namedNode(GRAPH_DOCUMENT), null)\n .map((q) => q.subject.value)\n .sort(byCodeUnit);\n\n const variants = new Set<string>();\n for (const doc of docs) {\n add(doc, RDF_TYPE, iri(IIRDS_TOPIC));\n add(doc, IIRDS_IS_PART_OF_PACKAGE, iri(pkg));\n\n const title = firstObject(store, doc, `${NS.dcterms}title`);\n if (title) add(doc, IIRDS_TITLE, lit(title));\n const language = firstObject(store, doc, `${NS.dcterms}language`);\n if (language) add(doc, IIRDS_LANGUAGE, lit(language));\n\n const path = firstObject(store, doc, `${NS.graph}path`);\n if (path) {\n // `graph:path` is relative to the directory the build labelled from: the\n // working directory for typed paths, the config's for a collection. A\n // corpus above it (`manni graph build ../external/*.md`, or a collection\n // whose `paths:` climb past the config file) is labelled\n // `../external/page.md`. Every other verb is happy with that — only a\n // container minds, because a container has a root and that path names\n // somewhere outside it. Refused here rather than in `resolveDocumentSet`\n // for exactly that reason: `build`, `query` and the rest keep working on\n // outside paths, and the one command that cannot represent them says so.\n // Checked before the file exists, since the escape is the finding even\n // when the file is also missing.\n if (escapesArchiveRoot(path)) {\n throw new GraphError(\n `Cannot package \"${path}\": an iiRDS package has one root, and a path that climbs above it has no place inside it. ` +\n \"Re-run `manni graph build` from a directory that contains every document, then export again.\",\n );\n }\n const absPath = resolve(cwd, path);\n if (!existsSync(absPath)) {\n throw new GraphError(\n `Content file for ${path} not found at ${absPath} — re-run \\`manni graph build\\`, or the source moved.`,\n );\n }\n const zipPath = `content/${path}`;\n const rendition = `${doc}/rendition`;\n add(doc, IIRDS_HAS_RENDITION, iri(rendition));\n add(rendition, RDF_TYPE, iri(IIRDS_RENDITION));\n add(rendition, IIRDS_SOURCE, lit(zipPath));\n add(rendition, IIRDS_FORMAT, lit(mediaTypeOf(path)));\n contentFiles.push({ zipPath, absPath });\n } else {\n warnings.push(\n `Document ${doc} has no graph:path — no rendition emitted.`,\n );\n }\n\n for (const pred of CARRIED) {\n for (const q of store.getQuads(\n DataFactory.namedNode(doc),\n DataFactory.namedNode(pred),\n null,\n null,\n )) {\n const o = q.object;\n if (o.termType === \"Literal\") {\n const dt = o.datatype.value;\n add(doc, pred, lit(o.value, dt !== XSD_STRING ? dt : undefined));\n } else {\n add(doc, pred, iri(o.value));\n if (pred === IIRDS_RELATES_TO_PRODUCT_VARIANT) variants.add(o.value);\n }\n }\n }\n }\n\n // Include the referenced ProductVariant nodes (type + label).\n for (const v of [...variants].sort(byCodeUnit)) {\n add(v, RDF_TYPE, iri(IIRDS_PRODUCT_VARIANT));\n const label = firstObject(store, v, `${NS.dcterms}title`);\n if (label) add(v, `${NS.dcterms}title`, lit(label));\n }\n\n const prefixes: Record<string, string> = {\n dcterms: NS.dcterms,\n iirds: NS.iirds,\n iirdsSft: NS.iirdsSft,\n rdf: NS.rdf,\n vcard: VCARD_NS,\n };\n\n return { quads, prefixes, contentFiles, warnings };\n}\n","/**\n * Deterministic ZIP writer — the container half of the iiRDS package export\n * (ADR 01017). Hand-rolled rather than a library, for the same reason the Turtle\n * emitter avoids N3.Writer: byte output must be a stability contract, not\n * incidental library behavior. Node is `>=24`, so `zlib.crc32`/`deflateRawSync`\n * are native — no dependency.\n *\n * Determinism: DOS timestamps pinned to a fixed epoch (1980-01-01, never the\n * wall clock), no extra fields, fixed version bytes, and entry order = the order\n * passed in. Two `writeZip` calls with the same input produce identical bytes.\n * The caller is responsible for putting a stored `mimetype` entry first (the\n * iiRDS/OCF container rule).\n */\nimport { crc32, deflateRawSync } from \"node:zlib\";\nimport { GraphError } from \"../types.js\";\n\n/**\n * Does this name let an extractor write outside the archive root?\n *\n * A ZIP entry name is a path a consumer joins onto its extraction directory,\n * and many implementations join without normalizing first. So `content/../x`\n * lands beside `content/`, not inside it, and `/etc/passwd` or `C:/…` lands\n * wherever it says. Absolute, drive-qualified, UNC and `..`-bearing names are\n * all refused; backslashes count as separators because a Windows-authored path\n * that reached here unconverted would otherwise smuggle `..` past a `/` split.\n *\n * Exported so the one predicate serves both ends: the iiRDS projection uses it\n * to refuse by document name, `writeZip` to refuse whatever it is handed.\n */\nexport function escapesArchiveRoot(name: string): boolean {\n const segments = name.split(/[/\\\\]/);\n return (\n name.startsWith(\"/\") ||\n name.startsWith(\"\\\\\") ||\n /^[A-Za-z]:/.test(name) ||\n segments.includes(\"..\")\n );\n}\n\nexport interface ZipEntry {\n /** In-archive path (forward slashes). */\n name: string;\n data: Buffer;\n /** Store uncompressed. Required for the leading `mimetype` entry. */\n store?: boolean;\n}\n\n// Pinned deterministic DOS date/time: 1980-01-01 00:00:00. A zeroed date byte\n// would encode an invalid day 0; 0x0021 is the earliest valid DOS date.\nconst DOS_DATE = 0x0021;\nconst DOS_TIME = 0x0000;\nconst VERSION = 20; // 2.0 — supports deflate; used for made-by and needed.\n\nexport function writeZip(entries: ZipEntry[]): Buffer {\n const locals: Buffer[] = [];\n const centrals: Buffer[] = [];\n let offset = 0;\n\n for (const entry of entries) {\n // The backstop under the projection's own refusal, which names the\n // document. This one names only the entry, because by here the document is\n // out of scope — but it is the guard that holds for a caller the export\n // command does not own yet.\n if (escapesArchiveRoot(entry.name)) {\n throw new GraphError(\n `Refusing ZIP entry \"${entry.name}\": an archive entry may not be absolute or climb above the archive root.`,\n );\n }\n const name = Buffer.from(entry.name, \"utf8\");\n // Flag bit 11 signals UTF-8 filenames; only needed for non-ASCII names.\n const flags = name.some((b) => b > 0x7f) ? 0x0800 : 0x0000;\n const method = entry.store ? 0 : 8;\n const stored = entry.store ? entry.data : deflateRawSync(entry.data);\n const crc = crc32(entry.data) >>> 0;\n\n const local = Buffer.alloc(30);\n local.writeUInt32LE(0x04034b50, 0);\n local.writeUInt16LE(VERSION, 4);\n local.writeUInt16LE(flags, 6);\n local.writeUInt16LE(method, 8);\n local.writeUInt16LE(DOS_TIME, 10);\n local.writeUInt16LE(DOS_DATE, 12);\n local.writeUInt32LE(crc, 14);\n local.writeUInt32LE(stored.length, 18);\n local.writeUInt32LE(entry.data.length, 22);\n local.writeUInt16LE(name.length, 26);\n local.writeUInt16LE(0, 28); // extra field length\n locals.push(local, name, stored);\n\n const central = Buffer.alloc(46);\n central.writeUInt32LE(0x02014b50, 0);\n central.writeUInt16LE(VERSION, 4); // version made by (host 0 = MS-DOS)\n central.writeUInt16LE(VERSION, 6); // version needed\n central.writeUInt16LE(flags, 8);\n central.writeUInt16LE(method, 10);\n central.writeUInt16LE(DOS_TIME, 12);\n central.writeUInt16LE(DOS_DATE, 14);\n central.writeUInt32LE(crc, 16);\n central.writeUInt32LE(stored.length, 20);\n central.writeUInt32LE(entry.data.length, 24);\n central.writeUInt16LE(name.length, 28);\n central.writeUInt16LE(0, 30); // extra field length\n central.writeUInt16LE(0, 32); // file comment length\n central.writeUInt16LE(0, 34); // disk number start\n central.writeUInt16LE(0, 36); // internal file attributes\n central.writeUInt32LE(0, 38); // external file attributes\n central.writeUInt32LE(offset, 42); // relative offset of local header\n centrals.push(central, name);\n\n offset += local.length + name.length + stored.length;\n }\n\n const centralBuf = Buffer.concat(centrals);\n const eocd = Buffer.alloc(22);\n eocd.writeUInt32LE(0x06054b50, 0);\n eocd.writeUInt16LE(0, 4); // number of this disk\n eocd.writeUInt16LE(0, 6); // disk where central directory starts\n eocd.writeUInt16LE(entries.length, 8); // cd records on this disk\n eocd.writeUInt16LE(entries.length, 10); // total cd records\n eocd.writeUInt32LE(centralBuf.length, 12); // size of central directory\n eocd.writeUInt32LE(offset, 16); // offset of start of central directory\n eocd.writeUInt16LE(0, 20); // .zip file comment length\n\n return Buffer.concat([...locals, centralBuf, eocd]);\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\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 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 const end = next?.start ?? lines.length;\n return lines.slice(match.start, end).join(\"\\n\").trimEnd();\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 };\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 return byCodeUnit(da, db);\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.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 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","/**\n * `manni graph query` — triple-pattern matching over the built graph. Any of\n * s/p/o may be omitted (wildcard). Prefixed names (`dcterms:references`)\n * and full IRIs are accepted; `--object` also matches literal values verbatim.\n */\nimport { resolve } from \"node:path\";\nimport { DataFactory } from \"n3\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { compactIri, expandTerm, loadGraph } from \"../core/load.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\n\nexport interface QueryOptions {\n s?: string;\n p?: string;\n o?: string;\n config?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n /** Graph path override (default: config `out`). */\n graph?: string;\n cwd?: string;\n}\n\nexport interface QueryMatch {\n s: string;\n p: string;\n o: { kind: \"iri\" | \"literal\"; value: string; datatype?: string };\n}\n\nexport interface QueryResult {\n matches: QueryMatch[];\n}\n\nexport function runQuery(opts: QueryOptions = {}): QueryResult {\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 store = loadGraph(resolve(cwd, opts.graph ?? config.out));\n\n const s = opts.s ? DataFactory.namedNode(expandTerm(opts.s)) : null;\n const p = opts.p ? DataFactory.namedNode(expandTerm(opts.p)) : null;\n const oValue = opts.o ? expandTerm(opts.o) : null;\n\n const matches: QueryMatch[] = [];\n for (const quad of store.getQuads(s, p, null, null)) {\n const obj = quad.object;\n if (oValue !== null && obj.value !== oValue) continue;\n matches.push({\n s: quad.subject.value,\n p: quad.predicate.value,\n o:\n obj.termType === \"Literal\"\n ? {\n kind: \"literal\",\n value: obj.value,\n ...(obj.datatype.value !==\n \"http://www.w3.org/2001/XMLSchema#string\"\n ? { datatype: obj.datatype.value }\n : {}),\n }\n : { kind: \"iri\", value: obj.value },\n });\n }\n\n // Compare field by field rather than joining into one key: every separator\n // choice is wrong in some way. NUL orders correctly (it sorts before any\n // real character) but makes git classify this file as binary, exempting it\n // from the repo's LF normalization. A printable separator like `|` keeps the\n // file text but sorts *after* most characters, which would rank a subject\n // behind one that merely extends it (`…/configuration.md` after\n // `…/configuration.md#advanced`). Field-wise comparison has neither problem\n // and is exactly equivalent to the original NUL-joined ordering.\n matches.sort(\n (a, b) =>\n byCodeUnit(a.s, b.s) ||\n byCodeUnit(a.p, b.p) ||\n byCodeUnit(a.o.kind, b.o.kind) ||\n byCodeUnit(a.o.value, b.o.value),\n );\n return { matches };\n}\n\nexport function renderQuery(\n result: QueryResult,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") return JSON.stringify(result, null, 2);\n if (result.matches.length === 0) return \"No matches.\";\n const lines = result.matches.map((m) => {\n const o =\n m.o.kind === \"iri\"\n ? `<${m.o.value}>`\n : `\"${m.o.value}\"${m.o.datatype ? `^^${compactIri(m.o.datatype)}` : \"\"}`;\n return `<${m.s}> ${compactIri(m.p)} ${o}`;\n });\n lines.push(`\\n${result.matches.length} match(es)`);\n return lines.join(\"\\n\");\n}\n","/**\n * `manni graph fill` — propose SKOS frontmatter fields (the `graph:` block) with an\n * LLM and write them back. Single-shot structured output per doc, content-hash\n * cached, bounded by a turn budget. Human-set fields are never overwritten\n * without `--force`; `--dry-run` reports without writing. Any per-doc failure\n * is recorded as a result, never aborts the run.\n */\nimport { readFileSync, writeFileSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\n\nimport {\n analyzeDoc,\n formatOf,\n metadataOf,\n type DocFormat,\n} from \"../core/analyze.js\";\nimport { loadRunConfig, type FillField } from \"../core/config.js\";\nimport type { DocModel } from \"../types.js\";\nimport {\n assertInputFormat,\n documentBase,\n documentSetPatterns,\n resolveDocumentSet,\n routesFrom,\n STDIN,\n type DocumentInputOptions,\n} from \"../core/discover.js\";\nimport { STDIN_PATH } from \"../core/iri.js\";\nimport {\n applyGraphFields,\n frontmatterKind,\n writeGraphFields,\n} from \"../core/frontmatter-edit.js\";\nimport { writeFileAtomic } from \"../../meta/index.js\";\nimport { DocmetaError } from \"../../meta/types.js\";\nimport {\n mergeMetaProvenance,\n spliceManifestValue,\n urlManifestMessage,\n type KeyHome,\n type MetaPageView,\n} from \"../../meta/internal.js\";\nimport { isMissing } from \"../../shared/manifest-cas.js\";\nimport { mergePage, openMetaView } from \"../core/external.js\";\nimport { FillGuard } from \"../core/fill-guard.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\nimport { bundledShapesPath } from \"../core/pkg.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { warn } from \"../../shared/warn.js\";\nimport { GraphError } from \"../types.js\";\nimport {\n completeValidatedJSON,\n validatorFor,\n type InferenceProvider,\n} from \"@hawkeyexl/inference\";\nimport { FillCache, cacheKey } from \"../llm/cache.js\";\nimport {\n SYSTEM_PROMPT,\n SECTION_FILL_FIELDS,\n buildUserPrompt,\n proposalSchema,\n} from \"../llm/prompt.js\";\nimport {\n announceSelection,\n assertProviderSelection,\n constructProvider,\n resolveProviderIdentity,\n selectProvider,\n} from \"../llm/provider.js\";\n\nexport interface FillOptions extends DocumentInputOptions {\n cwd?: string;\n dryRun?: boolean;\n force?: boolean;\n noCache?: boolean;\n /**\n * Stop after this many inference calls; overrides `fill.maxTurns`. A cached\n * proposal spends none (proposal 0051 §3).\n */\n maxTurns?: number;\n /**\n * Minimum model confidence to write a field; overrides\n * `fill.confidenceThreshold`.\n */\n confidence?: number;\n /** Fields to propose; overrides `fill.fields`. */\n fields?: FillField[];\n provider?: string;\n model?: string;\n /** Run inference on this machine with llama-cpp, over every configured choice. */\n local?: boolean;\n /** Disable the graph guardrail (`--no-validate-graph`). */\n noValidateGraph?: boolean;\n /** Propose per-section metadata as well as document-level (ADR 01032). */\n sections?: boolean;\n /** Injection seam for tests: bypasses the provider factory. */\n providerInstance?: InferenceProvider;\n /**\n * What `-` reads: the document from stdin, read by the caller. Required when\n * `paths` holds `-`. It is never written to disk: the report's\n * `stdinDocument` carries it back, filled or as it came.\n */\n stdinContent?: string;\n /** `--allow-empty`: zero matched files is an empty report, not an error. */\n allowEmpty?: boolean;\n}\n\nexport type FillStatus =\n | \"filled\"\n | \"proposed\" // dry run: would write\n | \"complete\" // nothing missing\n | \"nothing-proposed\"\n | \"skipped\"\n | \"error\";\n\n/** Why a page was skipped. The only reason today is the turn budget. */\nexport const TURN_BUDGET_REASON = \"turn budget\";\n\nexport interface FillDocResult {\n path: string;\n status: FillStatus;\n /**\n * Why a `skipped` page was skipped, said rather than left to be inferred —\n * the half of graph ADR 01027 that survives the dollar cap's removal.\n */\n reason?: string;\n /** Fields written (or that would be written under --dry-run). */\n fields: string[];\n /** Human-set fields the proposal was not allowed to touch. */\n preserved: string[];\n /** Fields dropped by the graph guardrail (fill.validateGraph). */\n rejected?: string[];\n /**\n * Section slugs the model proposed that match no heading in the document.\n * Dropped rather than written: writing one would mint a\n * graph:brokenSectionRef, a finding fill must report and never manufacture\n * (ADR 01032).\n */\n unknownSections?: string[];\n /** Fields the model proposed but scored below the confidence threshold (ADR 01015). */\n lowConfidence?: Array<{\n field: string;\n confidence: number;\n reasoning?: string;\n }>;\n cached: boolean;\n error?: string;\n}\n\nexport interface FillReport {\n results: FillDocResult[];\n /**\n * Inference calls this run made. Turns are countable for every model, where\n * a price was known for six of them — which is why the dollar cap went (graph\n * ADR 01027, proposal 0051 §3).\n */\n turnsUsed: number;\n /** The budget in force, or `null` for unbounded. */\n maxTurns: number | null;\n /** Non-fatal diagnostics. Never affects the exit code. */\n warnings: string[];\n exitCode: 0 | 1;\n /**\n * The document read from stdin, with the accepted fields written into it,\n * or unchanged when nothing was written. Absent when the run read no stdin\n * or the page errored. The CLI prints it to stdout; it is not part of the\n * rendered report.\n */\n stdinDocument?: string;\n}\n\n/** SKOS relation fields that require a `label` to attach to. */\nconst RELATION_FIELDS = [\n \"alt-labels\",\n \"broader\",\n \"narrower\",\n \"related-concepts\",\n] as const;\n\n/** A record's `{field → number}` sub-map, ignoring non-number entries. */\nfunction numberMap(v: unknown): Record<string, number> {\n const out: Record<string, number> = {};\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n // In range, or not a score at all (ADR 01034). A model that answers 90\n // where 0..1 was asked for meant \"very confident\", but reading it as\n // written would clear every threshold there is — the model's slip\n // becoming certainty. GBNF cannot express `minimum`/`maximum`, so no\n // grammar stops this upstream; dropping the score leaves the field\n // unscored, which the confidence gate already knows how to handle.\n if (typeof val === \"number\" && val >= 0 && val <= 1) out[k] = val;\n }\n }\n return out;\n}\n\n/** A record's `{field → string}` sub-map, ignoring non-string entries. */\nfunction stringMap(v: unknown): Record<string, string> {\n const out: Record<string, string> = {};\n if (v && typeof v === \"object\" && !Array.isArray(v)) {\n for (const [k, val] of Object.entries(v as Record<string, unknown>)) {\n if (typeof val === \"string\") out[k] = val;\n }\n }\n return out;\n}\n\n/** Confidence stored to 2 decimals so the graph decimal literal is stable. */\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\n/** The page-level key `fill` records the fields it wrote in (proposal 0046). */\nconst META_PROVENANCE_KEY = \"meta-provenance\";\n\n/** A graph field as an RFC 6901 JSON Pointer into the page's `graph` block. */\nfunction graphPointer(field: string): string {\n return `/graph/${field.replace(/~/g, \"~0\").replace(/\\//g, \"~1\")}`;\n}\n\nexport async function runFill(opts: FillOptions = {}): Promise<FillReport> {\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 ...(opts.paths === undefined ? {} : { paths: opts.paths }),\n ...(opts.collection === undefined ? {} : { collection: opts.collection }),\n },\n cwd,\n );\n\n // The flag, then `graph.provider`/`graph.model`, then the family's `providers:`,\n // then `auto`. `--local` is llama-cpp over both levels, so detection never\n // runs under it; a `--provider` it contradicts is refused by name, and a\n // configured one is set aside and said.\n //\n // Checked BEFORE the document set is resolved, and regardless of whether a\n // provider was injected. A contradiction in the flags is a usage error, and\n // a usage error must not be reported as whatever the file walk found first;\n // construction is lazy besides, so a typo would otherwise exit 0 on any run\n // where no page happened to need inference.\n const flags = {\n ...(opts.provider === undefined ? {} : { provider: opts.provider }),\n ...(opts.model === undefined ? {} : { model: opts.model }),\n ...(opts.local === undefined ? {} : { local: opts.local }),\n };\n const selection = selectProvider(config, flags);\n assertProviderSelection(selection);\n\n const format = assertInputFormat(opts.paths ?? [], opts.as);\n // Labels and reads share one base, the one `build` uses (`documentBase`).\n const base = documentBase(config, opts, cwd);\n const files = resolveDocumentSet(config, opts, \"fill\", cwd, base);\n const usingStdin = (opts.paths ?? []).includes(STDIN);\n if (files.length === 0 && !usingStdin) {\n if (opts.allowEmpty) {\n return {\n results: [],\n turnsUsed: 0,\n maxTurns: opts.maxTurns ?? config.fill.maxTurns,\n warnings: [],\n exitCode: 0,\n };\n }\n throw new GraphError(\n `No input files matched: ${documentSetPatterns(config, opts).join(\", \")} (cwd: ${cwd})`,\n );\n }\n if (usingStdin && opts.stdinContent === undefined) {\n throw new GraphError(\"graph fill was given `-` but no stdin content.\");\n }\n const stdinContent = usingStdin ? opts.stdinContent : undefined;\n const analyzeOptions = {\n routes: routesFrom(config, base),\n ...(format === undefined ? {} : { format }),\n };\n\n // Identity (for cache keys) is resolvable without constructing the provider;\n // construction — which may demand an API key — is deferred to the first\n // actual LLM call, so complete/cached runs need no credentials.\n //\n // The two branches are kept apart rather than merged behind a cast: an\n // injected provider's `provider()` is a free-form string, and only the\n // resolved path yields a name `constructProvider` can be trusted with.\n let identity: { provider: string; model: string };\n let construct: () => InferenceProvider;\n if (opts.providerInstance) {\n const injected = opts.providerInstance;\n identity = { provider: injected.provider(), model: injected.modelName() };\n construct = () => injected;\n // Still announce what `--local` replaced: the selection is what a real\n // run would have used, and the seam is a test's business, not the user's.\n announceSelection(selection);\n } else {\n const resolved = await resolveProviderIdentity(config, flags);\n identity = resolved;\n // Build from the RESOLVED identity, never the selection we started with:\n // under `auto` that still says \"auto\", and the synchronous library\n // constructor rightly refuses to guess.\n construct = () => constructProvider(config, resolved);\n }\n let provider: InferenceProvider | undefined;\n const getProvider = (): InferenceProvider => (provider ??= construct());\n\n const fields = opts.fields ?? config.fill.fields;\n // Compiled against the full configured field set, not any one doc's missing\n // subset: proposals are validated leniently and narrowed afterwards, so a\n // provider that volunteers a field this doc didn't ask for is fine.\n const withSections = opts.sections ?? config.fill.sections;\n // The section half of the schema is built from the FULL configured field\n // set, never from a document's missing set (ADR 01032): section presence is\n // independent of document presence, so a page whose `graph.type` is already\n // set must still be offered a section-level `type`. Narrowing this the way the\n // document half is narrowed handed a strictly-constrained provider a section\n // item with no data properties on it at all.\n const sectionFields = withSections\n ? fields.filter((f) => SECTION_FILL_FIELDS.includes(f))\n : undefined;\n // Validation uses the LENIENT schema (ADR 01034): the values are checked\n // exactly as strictly as ever, while the model's self-reported confidence and\n // reasoning are accepted in whatever shape they arrive. A weak provider that\n // scores one field with a string must not cost the run every other field it\n // got right.\n const validateProposal = validatorFor(\n proposalSchema(fields, { sections: sectionFields, lenient: true }),\n );\n const cache = new FillCache(\n resolve(cwd, config.fill.cacheDir),\n !opts.noCache,\n );\n const confidenceThreshold = opts.confidence ?? config.fill.confidenceThreshold;\n // Turns, not dollars. A turn is one inference call, which every model makes\n // and every model can be counted making — where a price was known for six\n // of them, so the cap it replaces read as zero for all the rest (graph ADR\n // 01027, docevals ADR 01019). `null` is unbounded.\n const maxTurns = opts.maxTurns ?? config.fill.maxTurns;\n\n const warnings: string[] = [];\n /**\n * Docs whose section fields were written but could not be recorded. A list\n * rather than a flag because `fillOne` sets it and `runFill` reads it: a\n * captured `let` assigned only inside a nested function stays narrowed to\n * its initializer at the read, so the warning below would be unreachable\n * code the compiler is entitled to assume never runs.\n */\n const sectionsUnrecorded: string[] = [];\n\n const allPaths = new Set(\n stdinContent === undefined ? files : [...files, STDIN_PATH],\n );\n const results: FillDocResult[] = [];\n let turnsUsed = 0;\n\n // Graph guardrail: simulate each proposal against the SHACL shapes before\n // writing it. Off via fill.validateGraph: false or --no-validate-graph.\n // The guard's base state is the FULL configured corpus, not the positional\n // path subset — a proposal for one doc can cycle with hierarchy that lives\n // in a doc outside the subset being filled. With no collections declared\n // there is no wider corpus to know about, so the subset is the corpus.\n const shapesPaths =\n config.check.shapes.length > 0\n ? config.check.shapes.map((p) => resolve(cwd, p))\n : [bundledShapesPath(import.meta.url)];\n const guardFiles = [\n ...new Set([\n ...(config.collections.length > 0\n ? resolveDocumentSet(config, {}, \"fill\", cwd, base)\n : []),\n ...files,\n ]),\n ];\n // `--as` is how the run's own inputs are parsed. A corpus page the guard\n // reads for context is parsed by its extension, as `build` would read it.\n const inputs = new Set(files);\n const formatFor = (path: string): DocFormat | undefined =>\n inputs.has(path) ? format : undefined;\n // Each page as `manni meta validate` reads it (proposal 0047): its own\n // frontmatter plus every key a manifest of its collections owns. What a page\n // already holds, the guard's corpus and the `meta-provenance` list a fill\n // extends are all read through it, so a value kept beside the page counts.\n //\n // A page meta will not read is that page's problem, not the run's. Named,\n // it is that page's error, reported by `fillOne`. Read only for context,\n // it is left out of the guard, and one warning lists it.\n const mergeErrors = new Map<string, unknown>();\n const view = await openMetaViewPerPage(\n {\n ...(opts.config === undefined ? {} : { configPath: opts.config }),\n ...(opts.noConfig === undefined ? {} : { noConfig: opts.noConfig }),\n },\n cwd,\n guardFiles,\n base,\n mergeErrors,\n );\n // Each page's merged text, computed once. `fillOne` reads it from here, so\n // no page is merged twice.\n const mergedTexts = new Map<string, string>();\n // The stdin page joins the guard's corpus from memory: it has no file. A\n // page whose manifests supply a key joins it as merged, so the simulation\n // sees what `graph build` would.\n const inline = new Map<string, string>();\n for (const path of guardFiles) {\n if (mergeErrors.has(path)) continue;\n let text: string;\n try {\n text = readFileSync(resolve(base, path), \"utf8\");\n } catch (e) {\n // A named page that cannot be read aborts the run below, as it always\n // has. One read only for context is left out of the guard.\n mergeErrors.set(path, e);\n continue;\n }\n let asMetaReadsIt: string;\n try {\n asMetaReadsIt = await mergedText(\n view,\n path,\n text,\n formatOf(path, formatFor(path)),\n );\n } catch (e) {\n mergeErrors.set(path, e);\n continue;\n }\n mergedTexts.set(path, asMetaReadsIt);\n if (asMetaReadsIt !== text) inline.set(path, asMetaReadsIt);\n }\n if (stdinContent !== undefined) inline.set(STDIN_PATH, stdinContent);\n const guard =\n !opts.noValidateGraph && config.fill.validateGraph\n ? FillGuard.create(\n guardFiles.filter((path) => !mergeErrors.has(path)),\n base,\n { ...config, routes: routesFrom(config, base) },\n shapesPaths,\n opts.force ?? false,\n {\n inline,\n ...(format === undefined ? {} : { format }),\n inputs: new Set([...files, STDIN_PATH]),\n },\n )\n : undefined;\n if (guard) {\n const leftOut = [\n ...guardFiles.filter((path) => !inputs.has(path) && mergeErrors.has(path)),\n ...guard.unreadable.filter((path) => !inputs.has(path) && path !== STDIN_PATH),\n ].sort(byCodeUnit);\n if (leftOut.length > 0) {\n warn(\n `The graph check left out ${String(leftOut.length)} page${leftOut.length === 1 ? \"\" : \"s\"} it could not read: ${leftOut.join(\", \")}. ` +\n \"Proposals were vetted without them. `manni meta validate` says what is wrong with each.\",\n );\n }\n }\n\n for (const path of files) {\n // Read failures are operational (deleted file, permissions) — abort the\n // whole run with exit 2 rather than burning LLM budget on the rest.\n const absPath = resolve(base, path);\n let content: string;\n try {\n content = readFileSync(absPath, \"utf8\");\n } catch (e) {\n throw new GraphError(\n `cannot read ${path}: ${errorMessage(e)}`,\n );\n }\n try {\n results.push(await fillOne(path, absPath, content));\n } catch (e) {\n results.push({\n path,\n status: \"error\",\n fields: [],\n preserved: [],\n cached: false,\n error: errorMessage(e),\n });\n }\n }\n\n // The stdin page is filled last, after the named files, and never written:\n // what would have gone to disk comes back as `stdinDocument`.\n let stdinDocument: string | undefined;\n if (stdinContent !== undefined) {\n try {\n const result = await fillOne(STDIN_PATH, undefined, stdinContent);\n results.push(result);\n stdinDocument = result.filledContent ?? stdinContent;\n Reflect.deleteProperty(result, \"filledContent\");\n } catch (e) {\n results.push({\n path: STDIN_PATH,\n status: \"error\",\n fields: [],\n preserved: [],\n cached: false,\n error: errorMessage(e),\n });\n }\n }\n\n if (sectionsUnrecorded.length > 0) {\n warnings.push(\n \"Section metadata was written but is NOT recorded in meta-provenance: /graph/sections is \" +\n \"one of the three hand-curated pointers graph refuses, with /graph/revision-of and \" +\n \"/graph/derived-from, so recording it would make `manni graph check` report an error. \" +\n \"Review section values by hand — the review queue will not list them.\",\n );\n }\n\n const hasErrors = results.some((r) => r.status === \"error\");\n return {\n results,\n turnsUsed,\n maxTurns,\n warnings,\n exitCode: hasErrors ? 1 : 0,\n ...(stdinDocument === undefined ? {} : { stdinDocument }),\n };\n\n /**\n * Fill one page. `absPath` is where an accepted result is written; a page\n * read from stdin has none, and its result carries the filled text back in\n * `filledContent` instead.\n */\n async function fillOne(\n path: string,\n absPath: string | undefined,\n content: string,\n ): Promise<FillDocResult & { filledContent?: string }> {\n // `--as` is how every input parses, the stdin page included.\n const pageFormat = formatOf(path, format);\n // Refused before a turn is spent. graph's YAML editor is the Markdown\n // writer; every other format's writer is meta's, which refuses for itself.\n if (\n (pageFormat === \"markdown\" || pageFormat === \"mdx\") &&\n frontmatterKind(content) === \"unsupported\"\n ) {\n throw new GraphError(\n \"only YAML frontmatter can be edited (found a TOML/JSON fence) — exclude this file or convert its frontmatter\",\n );\n }\n\n // The page as meta reads it. Identical to `content` unless a manifest\n // supplies one of its keys, which is every page in a corpus with none.\n const effective = absPath === undefined ? content : mergedTexts.get(path);\n if (effective === undefined) {\n const failure = mergeErrors.get(path);\n throw failure instanceof Error\n ? failure\n : new GraphError(errorMessage(failure));\n }\n // A page that carries `graph:` while a manifest owns it is meta's\n // collision. meta's merge keeps the page's block, so a fill written to\n // the manifest would never reach `build`. Refused before any turn is spent.\n if (absPath !== undefined) {\n const own = metadataOf(content, path, pageFormat).data;\n if (GRAPH_KEY in own) {\n const home = await view.home(path, own, GRAPH_KEY);\n if (home.kind !== \"unowned\") {\n throw new GraphError(\n `\"${GRAPH_KEY}\" is owned by manifest ${home.file} (collection ${home.collection}); remove it from the document`,\n );\n }\n }\n }\n // What the page already holds, read as `build` reads its format.\n const held = metadataOf(effective, path, pageFormat).data;\n const heldGraph = held[GRAPH_KEY];\n const present = new Set(\n heldGraph !== null && typeof heldGraph === \"object\" && !Array.isArray(heldGraph)\n ? Object.keys(heldGraph)\n : [],\n );\n const missing = opts.force ? fields : fields.filter((f) => !present.has(f));\n // With --sections, a document whose own fields are complete may still have\n // unfilled sections, so completeness at document level is not completeness\n // (ADR 01032).\n if (missing.length === 0 && !withSections) {\n return {\n path,\n status: \"complete\",\n fields: [],\n preserved: [],\n cached: false,\n };\n }\n\n const key = cacheKey(\n identity.provider,\n identity.model,\n content,\n missing,\n withSections,\n );\n // Cached proposals are validated too: a stale or hand-edited cache entry\n // must not bypass the schema (treat invalid entries as a miss).\n let proposal = cache.get(key);\n if (proposal !== undefined && !validateProposal(proposal)) {\n proposal = undefined;\n }\n const cached = proposal !== undefined;\n\n // Lazy: a *cached* proposal can carry sections, so the slugs still need\n // checking outside the cache-miss branch — but a sections-off run that hits\n // the cache should not pay for a full markdown parse it never reads.\n let docModel: DocModel | undefined;\n const doc = (): DocModel =>\n (docModel ??= analyzeDoc(effective, path, allPaths, analyzeOptions));\n\n if (proposal === undefined) {\n // The budget is claimed here rather than at the top of the page, so a\n // cached proposal spends nothing: it makes no inference call, and a\n // budget that stopped a free page would report a skip nobody paid for\n // (docevals ADR 01019). Say why, which is the half of graph ADR 01027 that\n // outlives the dollar.\n if (maxTurns !== null && turnsUsed >= maxTurns) {\n return {\n path,\n status: \"skipped\",\n reason: TURN_BUDGET_REASON,\n fields: [],\n preserved: [],\n cached: false,\n };\n }\n turnsUsed++;\n // completeValidatedJSON validates and retries once before giving up.\n // fill previously aborted the document on a single malformed response;\n // one bad completion is not worth losing the work over.\n //\n // The request schema is narrowed to this doc's missing fields, so the\n // provider cannot propose fields the run should not touch. Validation\n // deliberately uses the WIDER configured-field schema: a provider that\n // volunteers extra fields is tolerated and narrowed below, not failed.\n const run = await completeValidatedJSON<Record<string, unknown>>({\n provider: getProvider(),\n system: SYSTEM_PROMPT,\n user: buildUserPrompt(doc(), content, missing, {\n sections: withSections,\n }),\n schema: proposalSchema(missing, { sections: sectionFields }),\n validate: validateProposal,\n temperature: config.fill.temperature,\n });\n if (run.result === undefined) {\n throw new Error(run.error ?? \"provider returned no proposal\");\n }\n proposal = run.result;\n cache.set(key, proposal);\n }\n\n // Per-field confidence + reasoning ride alongside the values (ADR 01015);\n // pull them out before narrowing filters to field keys.\n const confidence = numberMap(proposal[\"confidence\"]);\n const reasoning = stringMap(proposal[\"reasoning\"]);\n\n // Only requested fields survive, even if the cache or provider offered\n // more; string arrays are deduplicated (the 0.1 schema enforces\n // uniqueItems on what we write).\n const narrowed = Object.fromEntries(\n Object.entries(proposal)\n .filter(([k]) => missing.includes(k as FillField))\n .map(([k, v]) => [k, Array.isArray(v) ? [...new Set(v)] : v]),\n );\n\n // Section proposals arrive as a list of {slug, …} and become dotted field\n // names — `sections.<slug>.type` — so the writer, the confidence gate, the\n // graph guardrail and the provenance record all treat them as ordinary\n // fields (ADR 01032).\n const unknownSlugs: string[] = [];\n if (withSections) {\n const realSlugs = new Set(doc().sections.map((s) => s.slug));\n for (const entry of Array.isArray(proposal[\"sections\"])\n ? (proposal[\"sections\"] as Array<Record<string, unknown>>)\n : []) {\n const slug = typeof entry[\"slug\"] === \"string\" ? entry[\"slug\"] : \"\";\n // A slug matching no heading is dropped, never written. Writing it\n // would mint a graph:brokenSectionRef — a finding fill must report\n // rather than manufacture.\n if (!realSlugs.has(slug)) {\n if (slug) unknownSlugs.push(slug);\n continue;\n }\n const entryConfidence = numberMap(entry[\"confidence\"]);\n const entryReasoning = stringMap(entry[\"reasoning\"]);\n for (const [field, value] of Object.entries(entry)) {\n if (!SECTION_FILL_FIELDS.includes(field as FillField)) continue;\n if (!fields.includes(field as FillField)) continue;\n const name = `sections.${slug}.${field}`;\n narrowed[name] = Array.isArray(value) ? [...new Set(value)] : value;\n // Fold the per-section scores into the flat maps the gate reads, so\n // one code path scores document and section fields alike.\n if (entryConfidence[field] !== undefined)\n confidence[name] = entryConfidence[field];\n if (entryReasoning[field] !== undefined)\n reasoning[name] = entryReasoning[field];\n }\n }\n }\n\n // manni:graph requires `label` alongside any alt-label/relation field\n // (dependentRequired) — never write output our own validate rejects.\n // Rechecked after the guardrail: rejecting `label` takes the relation\n // fields down with it.\n const gateLabel = (): void => {\n const hasLabel =\n present.has(\"label\") ||\n (typeof narrowed[\"label\"] === \"string\" && narrowed[\"label\"].length > 0);\n if (!hasLabel) {\n for (const field of RELATION_FIELDS) Reflect.deleteProperty(narrowed, field);\n }\n };\n gateLabel();\n\n // Confidence gate (ADR 01015): drop any field the model scored below the\n // threshold (or did not score at all — no score means no write). This\n // runs before the structural guardrail; the two are orthogonal, and the\n // confidence gate covers every field, not just the guarded subset. A drop\n // here is normal operation, reported but never an error (exit stays 0).\n const lowConfidence: FillDocResult[\"lowConfidence\"] = [];\n for (const field of Object.keys(narrowed)) {\n // Unscored counts as 0, so `confidenceThreshold: 0` stays a working\n // opt-out from the gate. The related hazard — stamping a confidence the\n // model never gave into meta-provenance — is fixed where that record is\n // built, not here.\n const c = confidence[field] ?? 0;\n if (c < confidenceThreshold) {\n lowConfidence.push({\n field,\n confidence: c,\n ...(reasoning[field] ? { reasoning: reasoning[field] } : {}),\n });\n Reflect.deleteProperty(narrowed, field);\n }\n }\n if (lowConfidence.length > 0) gateLabel();\n const lowConf = lowConfidence.length > 0 ? { lowConfidence } : {};\n\n // Graph guardrail: drop any field whose triples would violate the\n // shapes contract (cycles, related⨯broader conflicts, second spellings\n // of an existing concept). Cached proposals are vetted too — rejection\n // sits downstream of the cache, so a later corpus change can re-admit\n // a proposal without re-asking the LLM.\n let rejected: string[] | undefined;\n if (guard) {\n const vetted = await guard.vet(path, effective, narrowed);\n if (vetted.rejected.length > 0) {\n rejected = vetted.rejected.map((r) => r.field);\n for (const field of rejected) Reflect.deleteProperty(narrowed, field);\n gateLabel();\n }\n }\n\n // Which fields will actually be written (mirrors applyGraphFields' filter);\n // empty means nothing to do — and no provenance entry either.\n const realFields = Object.keys(narrowed).filter((k) => {\n const v = narrowed[k];\n return (\n v !== undefined && v !== null && !(Array.isArray(v) && v.length === 0)\n );\n });\n if (realFields.length === 0) {\n return {\n path,\n status: \"nothing-proposed\",\n fields: [],\n preserved: [],\n ...(rejected ? { rejected } : {}),\n ...(unknownSlugs.length > 0 ? { unknownSections: unknownSlugs } : {}),\n ...lowConf,\n cached,\n };\n }\n\n // Record machine attribution alongside the fields, in the SAME write.\n // It goes in the page-level `meta-provenance` now (proposal 0046), through\n // meta's own merge: one entry per model, this model's entry gaining the\n // pointers this run wrote, and every other entry — including the ones\n // `manni docevals fill` wrote — carried through untouched.\n let provenanceList: unknown[] | undefined;\n if (config.fill.writeProvenance) {\n // Document-level names only. `sections.<slug>.<field>` is a pointer\n // under `/graph/sections`, and `sections` is one of the three fields\n // curated by hand — recording it is exactly what graph's harvest now\n // reports as a `manni graph check` error (0046 stress test 13). So the\n // rule stays, and the reason it stays is a different one.\n const recordable = realFields.filter((f) => !f.includes(\".\")).sort();\n // Loud, not silent: metadata a model wrote with no entry in the review\n // queue is exactly the thing this record exists to prevent.\n if (recordable.length < realFields.length) sectionsUnrecorded.push(path);\n // Only record a score the model actually gave. `?? 0` stamped a\n // confidence of 0.00 the model never asserted whenever it omitted one,\n // which `fill.confidenceThreshold: 0` makes reachable.\n // As held, uncoerced: `mergeMetaProvenance` decides what a non-list\n // means, and carries through every key of an entry it does not know.\n const heldProvenance = held[META_PROVENANCE_KEY];\n const priorEntry = Array.isArray(heldProvenance)\n ? (heldProvenance as unknown[]).find(\n (e): e is Record<string, unknown> =>\n !!e &&\n typeof e === \"object\" &&\n !Array.isArray(e) &&\n (e as Record<string, unknown>)[\"generated-by\"] ===\n identity.model,\n )\n : undefined;\n const priorConfidence = numberMap(priorEntry?.[\"confidence\"]);\n const proposed = recordable.map((f) => {\n const name = graphPointer(f);\n const c = confidence[f];\n return {\n name,\n confidence: c === undefined ? (priorConfidence[name] ?? 0) : round2(c),\n };\n });\n const unscored = recordable\n .map((f) => [f, graphPointer(f)] as const)\n .filter(\n ([f, name]) =>\n confidence[f] === undefined && priorConfidence[name] === undefined,\n )\n .map(([, name]) => name);\n const merged = mergeMetaProvenance(\n heldProvenance,\n identity.model,\n \"fields\",\n proposed,\n );\n // `undefined` is a page holding something other than a list under the\n // key. Reported by `manni meta validate`, not worth failing the fill over:\n // a side record that could block filling would be worse than none.\n if (merged) {\n // The merge sets a confidence for every name it is handed; a pointer\n // nobody has ever scored keeps none.\n for (const name of unscored)\n Reflect.deleteProperty(merged.entry.confidence, name);\n provenanceList = merged.list;\n }\n }\n\n // Applied to the page as meta reads it, so a value a manifest holds is\n // preserved exactly as one on the page would be.\n const applied = writeGraphFields(effective, path, pageFormat, narrowed, {\n force: opts.force,\n });\n const reportedFields = applied.applied;\n\n if (reportedFields.length === 0) {\n return {\n path,\n status: \"nothing-proposed\",\n fields: [],\n preserved: applied.skipped,\n ...(rejected ? { rejected } : {}),\n ...(unknownSlugs.length > 0 ? { unknownSections: unknownSlugs } : {}),\n ...lowConf,\n cached,\n };\n }\n\n // Where each key is written is meta's rule (proposal 0047), the one\n // `manni meta fill` follows: a key a local manifest owns goes to the page's\n // entry there, and every other key stays on the page. A page from stdin\n // has no manifest, so everything it gets is in the text printed back.\n const own = metadataOf(content, path, pageFormat).data;\n const graphHome =\n absPath === undefined ? undefined : await view.home(path, own, GRAPH_KEY);\n const provenanceHome =\n absPath === undefined || provenanceList === undefined\n ? undefined\n : await view.home(path, own, META_PROVENANCE_KEY);\n const graphTarget = writeTarget(path, graphHome, GRAPH_KEY);\n if (typeof graphTarget === \"string\") throw new GraphError(graphTarget);\n let provenanceTarget = writeTarget(path, provenanceHome, META_PROVENANCE_KEY);\n if (typeof provenanceTarget === \"string\") {\n // A side record that could block filling would be worse than none, so\n // the fields are written and the record is not, and the run says so.\n warnings.push(`${provenanceTarget} The fill of ${path} is not recorded.`);\n provenanceList = undefined;\n provenanceTarget = null;\n }\n\n const pageKeys: Record<string, unknown> = {};\n if (provenanceList !== undefined && provenanceTarget === null) {\n pageKeys[META_PROVENANCE_KEY] = provenanceList;\n }\n const pageContent = writeGraphFields(\n content,\n path,\n pageFormat,\n graphTarget === null ? narrowed : {},\n { force: opts.force, page: pageKeys },\n ).content;\n\n const manifestWrites: ManifestWrite[] = [];\n // A manifest that owns `graph:` gets the whole block as meta reads it,\n // merged and then filled. A page that also carries one was refused above:\n // meta keeps the page's value, so the manifest's would never be read.\n if (graphTarget !== null) {\n manifestWrites.push({\n home: graphTarget,\n key: GRAPH_KEY,\n value: metadataOf(applied.content, path, pageFormat).data[GRAPH_KEY],\n });\n }\n if (provenanceList !== undefined && provenanceTarget !== null) {\n manifestWrites.push({\n home: provenanceTarget,\n key: META_PROVENANCE_KEY,\n value: provenanceList,\n });\n }\n // Every splice is made before anything is written, so a manifest meta\n // refuses leaves the page untouched too.\n const manifests = await spliceAll(manifestWrites);\n\n if (!opts.dryRun && absPath !== undefined) {\n if (pageContent !== content) writeFileSync(absPath, pageContent, \"utf8\");\n for (const m of manifests) {\n if (m.text !== m.before) {\n await writeFileAtomic(m.absPath, m.text, { createParents: true });\n }\n }\n }\n // Fold the accepted result into the guard even on --dry-run, so the dry\n // run predicts exactly what a real run would accept and reject.\n guard?.commit(path, applied.content);\n return {\n path,\n status: opts.dryRun ? \"proposed\" : \"filled\",\n fields: reportedFields,\n preserved: applied.skipped,\n ...(rejected ? { rejected } : {}),\n ...(unknownSlugs.length > 0 ? { unknownSections: unknownSlugs } : {}),\n ...lowConf,\n cached,\n ...(absPath === undefined && !opts.dryRun\n ? { filledContent: pageContent }\n : {}),\n };\n }\n}\n\n/** The page key holding the graph block. */\nconst GRAPH_KEY = \"graph\";\n\n/** A manifest a key is written to, with the page's entry there. */\ninterface ManifestTarget {\n file: string;\n absPath: string;\n join: string;\n entry: string;\n perPage: boolean;\n}\n\n/** One value written into one manifest entry. */\ninterface ManifestWrite {\n home: ManifestTarget;\n key: string;\n value: unknown;\n}\n\n/**\n * Where `key` goes: `null` for the page, the manifest entry, or meta's\n * sentence for a manifest that cannot take it, which is a fetched one or one\n * that joins on a field the page lacks.\n */\nfunction writeTarget(\n path: string,\n home: KeyHome | undefined,\n key: string,\n): ManifestTarget | string | null {\n if (home === undefined || home.kind === \"unowned\") return null;\n if (home.kind === \"url\") return urlManifestMessage(key, home.file);\n if (home.entry === undefined) {\n return `${path} carries no ${home.join}, which ${home.file} joins on, so its ${key} has no entry there.`;\n }\n return {\n file: home.file,\n absPath: home.absPath,\n join: home.join,\n entry: home.entry,\n perPage: home.perPage,\n };\n}\n\n/**\n * Each manifest's text with its writes spliced in, through meta's splice, which\n * changes no other byte of the file. A `{page}` manifest that is not on disk\n * yet is held as empty and created by the write, as `manni meta fill` does.\n */\nasync function spliceAll(\n writes: readonly ManifestWrite[],\n): Promise<Array<{ absPath: string; before: string; text: string }>> {\n const out = new Map<string, { absPath: string; before: string; text: string }>();\n for (const w of writes) {\n let held = out.get(w.home.absPath);\n if (held === undefined) {\n let before: string;\n try {\n before = await readFile(w.home.absPath, \"utf8\");\n } catch (e) {\n if (!(w.home.perPage && isMissing(e))) {\n throw new GraphError(`${w.home.file} could not be read: ${errorMessage(e)}`);\n }\n before = \"\";\n }\n held = { absPath: w.home.absPath, before, text: before };\n out.set(w.home.absPath, held);\n }\n try {\n held.text = spliceManifestValue(held.text, {\n entry: w.home.entry,\n key: w.key,\n value: w.value,\n join: w.home.join,\n file: w.home.file,\n }).text;\n } catch (e) {\n throw new GraphError(errorMessage(e));\n }\n }\n return [...out.values()];\n}\n\n/**\n * `content` with every key its manifests supply written into its metadata,\n * so it reads as meta reads the page. `content` itself when none does. A\n * Markdown frontmatter graph cannot edit is left alone, and `fill` refuses\n * that page.\n */\nasync function mergedText(\n view: MetaPageView,\n path: string,\n content: string,\n format: DocFormat,\n): Promise<string> {\n const markdown = format === \"markdown\" || format === \"mdx\";\n if (markdown && frontmatterKind(content) === \"unsupported\") return content;\n const own = metadataOf(content, path, format);\n const { supplied } = await mergePage(view, path, own.data, own.present, format);\n if (Object.keys(supplied).length === 0) return content;\n try {\n return writeGraphFields(content, path, format, {}, { page: supplied })\n .content;\n } catch (e) {\n // An AsciiDoc or reStructuredText page with no fence cannot take a write,\n // and need not when its manifest holds every key fill writes. This text\n // is read, never written, and both readers read a YAML fence, so a new\n // one reads as meta's merge does. A key whose home is the page still\n // meets meta's refusal when it is written. Only that refusal falls back:\n // anything else is the page's own problem, and a new fence would hide it.\n const noFence =\n (format === \"asciidoc\" || format === \"rst\") && e instanceof DocmetaError;\n if (!noFence) throw e;\n return applyGraphFields(content, path, {}, { page: supplied }).content;\n }\n}\n\n/**\n * Meta's view of `paths`, with a page meta refuses left out rather than\n * failing the run. One view over every page is tried first, so the common\n * case reads each manifest once. When it is refused, each page is opened on\n * its own to find the ones at fault, and each lands in `failures`.\n *\n * A refusal that holds with no page at all is not any page's. A broken\n * config or shared manifest stays an operational error, exit 2.\n */\nasync function openMetaViewPerPage(\n source: Parameters<typeof openMetaView>[0],\n cwd: string,\n paths: readonly string[],\n base: string,\n failures: Map<string, unknown>,\n): Promise<MetaPageView> {\n try {\n return await openMetaView(source, cwd, paths, base);\n } catch (whole) {\n await openMetaView(source, cwd, [], base);\n const readable: string[] = [];\n for (const path of paths) {\n try {\n await openMetaView(source, cwd, [path], base);\n readable.push(path);\n } catch (e) {\n failures.set(path, e);\n }\n }\n if (readable.length === paths.length) throw whole;\n return openMetaView(source, cwd, readable, base);\n }\n}\n\nexport function renderFill(\n report: FillReport,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") {\n // The stdin document is output of its own, never part of the report.\n return JSON.stringify({ ...report, stdinDocument: undefined }, null, 2);\n }\n const lines: string[] = [];\n for (const r of report.results) {\n const dropped =\n r.rejected && r.rejected.length > 0\n ? ` [graph check rejected: ${r.rejected.join(\", \")}]`\n : \"\";\n const lowConf =\n r.lowConfidence && r.lowConfidence.length > 0\n ? ` [low confidence, not written: ${r.lowConfidence\n .map((l) => `${l.field} ${l.confidence.toFixed(2)}`)\n .join(\", \")}]`\n : \"\";\n // Visible rather than silent: the model addressed a heading that is not\n // there, which usually means the page was edited after it was described.\n const unknown =\n r.unknownSections && r.unknownSections.length > 0\n ? ` [no such section: ${r.unknownSections.join(\", \")}]`\n : \"\";\n switch (r.status) {\n case \"filled\":\n lines.push(\n `filled ${r.path} (${r.fields.join(\", \")})${r.cached ? \" [cached]\" : \"\"}${dropped}${unknown}${lowConf}`,\n );\n break;\n case \"proposed\":\n lines.push(\n `proposed ${r.path} (${r.fields.join(\", \")})${r.cached ? \" [cached]\" : \"\"}${dropped}${unknown}${lowConf} — dry run, not written`,\n );\n break;\n case \"complete\":\n lines.push(`complete ${r.path}`);\n break;\n case \"nothing-proposed\":\n lines.push(\n `no-op ${r.path} (model proposed nothing new)${dropped}${unknown}${lowConf}`,\n );\n break;\n case \"skipped\":\n lines.push(`skipped ${r.path} (${r.reason ?? \"not processed\"})`);\n break;\n case \"error\":\n lines.push(`error ${r.path}: ${r.error ?? \"\"}`);\n break;\n }\n }\n // A run cut short covered less than it was asked to, and the per-page lines\n // say which pages. Say once that the budget is why, so the number to raise\n // is on screen next to them.\n if (\n report.maxTurns !== null &&\n report.results.some((r) => r.status === \"skipped\")\n ) {\n lines.push(\n \"\",\n `--max-turns reached (${report.maxTurns}); some pages were not processed.`,\n );\n }\n return lines.join(\"\\n\");\n}\n","/**\n * Surgical YAML edits (ported from docevals). Only the frontmatter block is\n * re-serialized via the `yaml` Document API — the page body is carried over\n * byte-for-byte, and untouched YAML keeps its comments and ordering. When a\n * file has no frontmatter, a new block holding only the `graph` key is created.\n * YAML frontmatter only; TOML/JSON frontmatter cannot be edited in place.\n * `writeGraphFields` routes every other format to meta's writer.\n */\nimport { Document, YAMLMap, YAMLSeq, isMap, parseDocument } from \"yaml\";\nimport { GraphError } from \"../types.js\";\nimport { extractorFor, metadataOf, type DocFormat } from \"./analyze.js\";\n\nconst GRAPH_KEY = \"graph\";\n\ninterface Split {\n /** The opening fence line including its newline (plus any BOM). */\n open: string;\n /** Raw YAML between the fences. */\n block: string;\n /** Everything from the closing fence to EOF, byte-identical. */\n suffix: string;\n /** Line ending style of the file. */\n eol: \"\\n\" | \"\\r\\n\";\n}\n\n/**\n * What kind of frontmatter block a file opens with. docmeta reads TOML (+++)\n * and JSON (;;;) fences too, but only YAML is editable in place — callers\n * must not treat \"unsupported\" as \"absent\" or they will stack a second block.\n */\nexport function frontmatterKind(\n content: string,\n): \"yaml\" | \"unsupported\" | \"none\" {\n const body = content.charCodeAt(0) === 0xfeff ? content.slice(1) : content;\n if (/^---(\\r?\\n)/.test(body)) return \"yaml\";\n if (/^(\\+\\+\\+|;;;)(\\r?\\n)/.test(body)) return \"unsupported\";\n return \"none\";\n}\n\nfunction splitYamlFrontmatter(content: string, path: string): Split | null {\n // `slice` rather than `content[0]`: it yields a string for an empty input\n // too, which is the only case the index could have missed.\n const bom = content.charCodeAt(0) === 0xfeff ? content.slice(0, 1) : \"\";\n const body = bom ? content.slice(1) : content;\n const openMatch = /^---(\\r?\\n)/.exec(body);\n if (!openMatch) return null;\n const eol: \"\\n\" | \"\\r\\n\" = openMatch[1] === \"\\r\\n\" ? \"\\r\\n\" : \"\\n\";\n // `String.split` always yields at least one element, and the regex matched\n // `---\\n` at the start, so the first line is the opening fence.\n const [openLine = \"\", ...rest] = body.split(/(?<=\\n)/); // keep line endings\n let offset = openLine.length;\n for (const line of rest) {\n const stripped = line.replace(/\\r?\\n$/, \"\");\n if (stripped === \"---\" || stripped === \"...\") {\n const blockEnd = offset;\n return {\n open: bom + openLine,\n block: body.slice(openLine.length, blockEnd),\n suffix: body.slice(blockEnd),\n eol,\n };\n }\n offset += line.length;\n }\n throw new GraphError(`${path}: unterminated frontmatter block`);\n}\n\nexport interface GraphApplyResult {\n content: string;\n /** Fields written. */\n applied: string[];\n /** Fields left alone because a human-set value exists (and no force). */\n skipped: string[];\n}\n\n/** Render every sequence under `node` flow-style: [a, b]. */\nfunction flowSeqs(node: unknown): void {\n if (node instanceof YAMLSeq) {\n node.flow = true;\n for (const item of node.items) flowSeqs(item);\n } else if (node instanceof YAMLMap) {\n for (const item of node.items) flowSeqs(item.value);\n }\n}\n\n/** Set `value` on a map in the graph block; arrays (incl. nested) render flow. */\nfunction setField(\n doc: Document,\n map: YAMLMap,\n field: string,\n value: unknown,\n): void {\n const node = doc.createNode(value);\n flowSeqs(node);\n map.set(field, node);\n}\n\nexport interface GraphApplyOptions {\n /** Overwrite values a human already set. */\n force?: boolean;\n /**\n * Keys to write at the TOP level of the frontmatter, beside `graph` rather\n * than inside it — `meta-provenance` is the one caller (proposal 0046).\n * They are always overwritten, because the caller computes each value\n * whole, and they are written even when `values` is empty. Kept in this\n * one function so a fill is still one parse and one serialization of the\n * block, and the body stays byte-identical either way.\n */\n page?: Record<string, unknown>;\n}\n\n/**\n * Apply proposed values to the top-level `graph` map of a doc's frontmatter,\n * plus any `options.page` keys beside it. Existing field values win unless\n * `force`. The body after the closing fence is byte-identical to the input.\n */\nexport function applyGraphFields(\n content: string,\n path: string,\n values: Record<string, unknown>,\n options: GraphApplyOptions = {},\n): GraphApplyResult {\n const entries = writable(values);\n const pageEntries = Object.entries(options.page ?? {});\n if (entries.length === 0 && pageEntries.length === 0) {\n return { content, applied: [], skipped: [] };\n }\n\n if (frontmatterKind(content) === \"unsupported\") {\n throw new GraphError(\n `${path}: only YAML frontmatter can be edited (found a TOML/JSON fence)`,\n );\n }\n\n const split = splitYamlFrontmatter(content, path);\n\n if (split === null) {\n // No frontmatter — create a block holding only the graph key. Dotted\n // names nest here too, or `sections.intro.type` would become a literal key.\n const eol: \"\\n\" | \"\\r\\n\" = content.includes(\"\\r\\n\") ? \"\\r\\n\" : \"\\n\";\n const nested: Record<string, unknown> = {};\n for (const [field, value] of entries) {\n const segments = field.split(\".\");\n let target = nested;\n for (const segment of segments.slice(0, -1)) {\n target[segment] ??= {};\n target = target[segment] as Record<string, unknown>;\n }\n // An undotted field is its own leaf, so `field` is the right fallback\n // rather than a stand-in: `split(\".\")` cannot return an empty list.\n target[segments.at(-1) ?? field] = value;\n }\n const doc = new Document({\n ...Object.fromEntries(pageEntries),\n ...(entries.length > 0 ? { graph: nested } : {}),\n });\n const graph = doc.get(\"graph\", true);\n if (isMap(graph)) flowSeqs(graph);\n let block = doc.toString();\n if (eol === \"\\r\\n\") block = block.replace(/(?<!\\r)\\n/g, \"\\r\\n\");\n return {\n content: `---${eol}${block}---${eol}${eol}${content}`,\n applied: entries.map(([k]) => k),\n skipped: [],\n };\n }\n\n const doc = parseDocument(split.block);\n if (doc.errors.length > 0) {\n throw new GraphError(\n `${path}: cannot edit frontmatter — ${doc.errors[0]?.message ?? \"parse error\"}`,\n );\n }\n\n let graph = doc.get(\"graph\", true);\n if (graph !== undefined && !isMap(graph)) {\n throw new GraphError(`${path}: frontmatter key \"graph\" is not a map`);\n }\n if (graph === undefined && entries.length > 0) {\n graph = doc.createNode({});\n doc.set(\"graph\", graph);\n }\n const graphMap = (graph ?? doc.createNode({})) as YAMLMap;\n\n const { applied, skipped } = mergeFields(doc, graphMap, entries, options.force);\n\n // Top-level keys, after the graph map so a new `graph` sorts where it always\n // did.\n // Block style, not `flowSeqs`: this is a record a reviewer reads and edits\n // by hand, one entry per line, not a value the graph derives from.\n for (const [key, value] of pageEntries) {\n doc.set(key, doc.createNode(value));\n }\n\n if (applied.length === 0 && pageEntries.length === 0) {\n return { content, applied, skipped };\n }\n\n let newBlock = doc.toString();\n if (split.eol === \"\\r\\n\") newBlock = newBlock.replace(/(?<!\\r)\\n/g, \"\\r\\n\");\n return { content: split.open + newBlock + split.suffix, applied, skipped };\n}\n\n/** The proposed values worth writing: no empty value and no empty list. */\nfunction writable(values: Record<string, unknown>): Array<[string, unknown]> {\n return Object.entries(values).filter(\n ([, v]) =>\n v !== undefined && v !== null && !(Array.isArray(v) && v.length === 0),\n );\n}\n\n/**\n * Merge `entries` into a page's `graph` map. This is the rule for what a fill\n * may change, and both writers run it: a human-set value stays unless `force`,\n * decided at the leaf, and a non-map where a map must go is left alone.\n */\nfunction mergeFields(\n doc: Document,\n graphMap: YAMLMap,\n entries: ReadonlyArray<[string, unknown]>,\n force: boolean | undefined,\n): { applied: string[]; skipped: string[] } {\n const applied: string[] = [];\n const skipped: string[] = [];\n for (const [field, value] of entries) {\n // A dotted name addresses a nested field — `sections.<slug>.type` writes\n // into graph.sections.<slug>.type (ADR 01032). Preservation is decided at\n // the *leaf*, so filling one section's type never disturbs a value a human\n // set on the section beside it.\n const segments = field.split(\".\");\n // An undotted field is its own leaf, so `field` is the right fallback\n // rather than a stand-in: `split(\".\")` cannot return an empty list.\n const leaf = segments.at(-1) ?? field;\n let target = graphMap;\n let missingParent = false;\n for (const segment of segments.slice(0, -1)) {\n const existing = target.get(segment, true);\n if (existing === undefined) {\n const created = doc.createNode({}) as YAMLMap;\n target.set(segment, created);\n target = created;\n } else if (isMap(existing)) {\n target = existing;\n } else {\n // A non-map where a map must go: leave the author's value alone rather\n // than overwrite a shape we do not understand.\n missingParent = true;\n break;\n }\n }\n if (missingParent) {\n skipped.push(field);\n continue;\n }\n if (target.has(leaf) && !force) {\n skipped.push(field);\n continue;\n }\n setField(doc, target, leaf, value);\n applied.push(field);\n }\n return { applied, skipped };\n}\n\n/**\n * Write a proposal into a page of any format: the one writer `fill`'s real\n * write, its guard's simulation and its manifest merge all use, so what is\n * vetted is what is written.\n *\n * Markdown and MDX keep graph's YAML editor above. Every other format is\n * written by its meta extractor's `apply`, with the page's `graph` map merged\n * by the same rule, so HTML gets a `<meta name=\"graph\">`, DITA an\n * `<othermeta>`, and a fenced AsciiDoc or reStructuredText page its fence\n * (proposal 0077 §4). A page that writer cannot take throws meta's\n * `DocmetaError`, in meta's words.\n */\nexport function writeGraphFields(\n content: string,\n path: string,\n format: DocFormat,\n values: Record<string, unknown>,\n options: GraphApplyOptions = {},\n): GraphApplyResult {\n if (format === \"markdown\" || format === \"mdx\") {\n return applyGraphFields(content, path, values, options);\n }\n const entries = writable(values);\n const patch: Record<string, unknown> = {};\n let applied: string[] = [];\n let skipped: string[] = [];\n if (entries.length > 0) {\n // The page's map, held as a YAML document so the merge is the one the\n // Markdown writer runs on its frontmatter, not a second spelling of it.\n const doc = new Document(\n metadataOf(content, path, format).data[GRAPH_KEY] ?? {},\n );\n if (!isMap(doc.contents)) {\n throw new GraphError(`${path}: metadata key \"graph\" is not a map`);\n }\n ({ applied, skipped } = mergeFields(\n doc,\n doc.contents,\n entries,\n options.force,\n ));\n if (applied.length > 0) patch[GRAPH_KEY] = doc.toJS();\n }\n Object.assign(patch, options.page);\n if (Object.keys(patch).length === 0) return { content, applied, skipped };\n const apply = extractorFor(format)?.apply;\n if (apply === undefined) {\n throw new GraphError(`${path}: manni cannot write ${format} metadata`);\n }\n return { content: apply(content, patch, { filePath: path }), applied, skipped };\n}\n\n/** The doc's parsed frontmatter as plain data, `{}` when there is none. */\nfunction frontmatterData(content: string): Record<string, unknown> {\n const split = splitYamlFrontmatter(content, \"\");\n if (split === null) return {};\n const doc = parseDocument(split.block);\n if (doc.errors.length > 0) return {};\n const plain = doc.toJS() as unknown;\n return plain !== null && typeof plain === \"object\" && !Array.isArray(plain)\n ? (plain as Record<string, unknown>)\n : {};\n}\n\n/**\n * The doc's page-level `meta-provenance` value, exactly as held — `undefined`\n * when the page has none. Uncoerced on purpose: `mergeMetaProvenance` decides\n * what a non-list means, and every key of an entry it does not know is carried\n * through, so a `docevals` entry survives a `graph fill`.\n */\nexport function existingMetaProvenance(content: string): unknown {\n return frontmatterData(content)[\"meta-provenance\"];\n}\n\n/** Fields already present on the doc's `graph` map ([] when none). */\nexport function existingGraphFields(content: string): string[] {\n const split = splitYamlFrontmatter(content, \"\");\n if (split === null) return [];\n const doc = parseDocument(split.block);\n if (doc.errors.length > 0) return [];\n const graph = doc.get(\"graph\", true);\n if (!isMap(graph)) return [];\n return graph.items\n .map((item) => {\n const value = (item.key as { value?: unknown }).value;\n return typeof value === \"string\" || typeof value === \"number\"\n ? String(value)\n : \"\";\n })\n .filter((k) => k.length > 0);\n}\n","/**\n * Graph guardrail for `manni graph fill`: before a proposal is written to\n * frontmatter, simulate it in the derived graph and drop any field that\n * would violate the SHACL shapes contract — broader/narrower cycles,\n * related⨯broaderTransitive conflicts, label collisions. Accepted\n * proposals fold into the guard's state so two docs in one run cannot\n * jointly corrupt the graph.\n */\nimport { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { DataFactory, Store } from \"n3\";\nimport type { DocModel } from \"../types.js\";\nimport {\n analyzeDoc,\n formatOf,\n type AnalyzeOptions,\n type DocFormat,\n} from \"./analyze.js\";\nimport type { DeriveSource, GraphConfig } from \"./config.js\";\nimport { deriveGraph, type Quad } from \"./derive.js\";\nimport { writeGraphFields } from \"./frontmatter-edit.js\";\nimport { validateGraph, type CheckFinding } from \"./shacl.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS } from \"./vocab.js\";\nimport {\n GRAPH_NOT_APPLICABLE_TO_VARIANT,\n GRAPH_NOT_SOFTWARE_SUBJECT,\n} from \"./iirds.js\";\n\n/**\n * Proposal fields the guard simulates; others cannot break the shapes. The\n * SKOS relation fields can form cycles/collisions; the applicability fields can\n * form an applies-to⨯not-applicable-to (or about-product-aspect⨯not-about-product-aspect)\n * `sh:disjoint` conflict (ADR 01015). type/about-product-lifecycle carry\n * only enum constraints, which the proposal JSON schema already enforces, so\n * they need no structural simulation.\n */\nconst GUARDED_FIELDS = [\n \"label\",\n \"broader\",\n \"narrower\",\n \"related-concepts\",\n \"applies-to\",\n \"not-applicable-to\",\n \"about-product-aspect\",\n \"not-about-product-aspect\",\n] as const;\n\n/** Concept + iiRDS edges: the SKOS subgraph plus the applicability predicates.\n * `sections` is in because a section carries the same disjoint applicability\n * predicates a document does (ADR 01032) — without it the simulated store has\n * no `graph:Section` node for the shapes to target, and a section-level\n * contradiction sails through. Links/provenance stay out to keep per-doc\n * simulation cheap and git-free. */\nconst GUARD_SOURCES: DeriveSource[] = [\"frontmatter\", \"tags\", \"sections\"];\n\n/** The bare field name a possibly-dotted proposal key addresses. */\nfunction leafOf(field: string): string {\n const dot = field.lastIndexOf(\".\");\n return dot === -1 ? field : field.slice(dot + 1);\n}\n\nfunction toStore(quads: Quad[]): Store {\n const store = new Store();\n for (const q of quads) {\n store.addQuad(\n DataFactory.quad(\n DataFactory.namedNode(q.s),\n DataFactory.namedNode(q.p),\n q.o.kind === \"iri\"\n ? DataFactory.namedNode(q.o.value)\n : DataFactory.literal(\n q.o.value,\n q.o.datatype ? DataFactory.namedNode(q.o.datatype) : undefined,\n ),\n ),\n );\n }\n return store;\n}\n\nexport interface VetResult {\n /** The proposal minus rejected fields. */\n values: Record<string, unknown>;\n /** Rejected field names with the finding that condemned them. */\n rejected: Array<{ field: string; reason: string }>;\n}\n\nexport class FillGuard {\n private readonly models = new Map<string, DocModel>();\n private baselineKeys: Set<string> | null = null;\n /**\n * Pages left out of the simulation because they would not analyze, sorted.\n * The caller decides what each one means: a named page fails on its own,\n * and a page read only for context is worth a warning.\n */\n readonly unreadable: string[] = [];\n\n private constructor(\n private readonly allPaths: Set<string>,\n private readonly analyzeOptions: AnalyzeOptions,\n private readonly baseIri: string,\n private readonly sources: DeriveSource[],\n private readonly shapesPaths: string[],\n private readonly force: boolean,\n ) {}\n\n /**\n * Read and analyze the whole corpus once, up front. A path in `inline` is\n * taken from memory rather than disk: that is how a page read from stdin\n * joins the corpus. `format` is `--as`, applied to the run's `inputs`. Any\n * other page is parsed by its extension, as `build` reads it. A page that\n * will not read or analyze is left out and listed in `unreadable`.\n */\n static create(\n files: string[],\n cwd: string,\n config: GraphConfig,\n shapesPaths: string[],\n force: boolean,\n {\n inline = new Map<string, string>(),\n format,\n inputs = new Set<string>(),\n }: {\n inline?: ReadonlyMap<string, string>;\n format?: DocFormat;\n inputs?: ReadonlySet<string>;\n } = {},\n ): FillGuard {\n const sources = config.build.derive.filter((s) =>\n GUARD_SOURCES.includes(s),\n );\n const all = [...files, ...inline.keys()];\n const guard = new FillGuard(\n new Set(all),\n {\n routes: config.routes,\n ...(format === undefined ? {} : { format }),\n },\n config.baseIri,\n sources,\n shapesPaths,\n force,\n );\n const byExtension: AnalyzeOptions = { routes: config.routes };\n for (const path of all) {\n try {\n guard.models.set(\n path,\n analyzeDoc(\n inline.get(path) ?? readFileSync(resolve(cwd, path), \"utf8\"),\n path,\n guard.allPaths,\n inputs.has(path) ? guard.analyzeOptions : byExtension,\n ),\n );\n } catch {\n guard.unreadable.push(path);\n }\n }\n guard.unreadable.sort(byCodeUnit);\n return guard;\n }\n\n private buildStore(override?: { path: string; model: DocModel }): Store {\n const models: DocModel[] = [];\n for (const [path, model] of this.models) {\n models.push(override && path === override.path ? override.model : model);\n }\n return toStore(\n deriveGraph(models, { baseIri: this.baseIri, derive: this.sources }),\n );\n }\n\n private static key(f: CheckFinding): string {\n return `${f.severity}|${f.focusNode}|${f.path ?? \"\"}|${f.message}`;\n }\n\n /** Findings already present before any proposal — never blamed on one. */\n private async baseline(): Promise<Set<string>> {\n if (this.baselineKeys === null) {\n const findings = await validateGraph(this.buildStore(), this.shapesPaths);\n this.baselineKeys = new Set(findings.map((f) => FillGuard.key(f)));\n }\n return this.baselineKeys;\n }\n\n /** Fields a finding condemns, restricted to what the proposal contains. */\n private static offendingFields(\n finding: CheckFinding,\n proposed: Set<string>,\n ): string[] {\n // A finding on a section node names it by fragment\n // (`…/doc/a.md#install-the-sdk`), so blame the proposal key for THAT\n // section rather than the document-level field of the same name — which\n // would drop an innocent value and leave the offending one written.\n const hash = finding.focusNode.indexOf(\"#\");\n const slug = hash === -1 ? undefined : finding.focusNode.slice(hash + 1);\n const pick = (leaf: string): string[] => {\n if (slug !== undefined) {\n const dotted = `sections.${slug}.${leaf}`;\n if (proposed.has(dotted)) return [dotted];\n // A section finding that the proposal did not cause: say nothing, so\n // the caller's \"cannot pin it\" fallback decides.\n return [];\n }\n return proposed.has(leaf) ? [leaf] : [];\n };\n const hierarchy = [\"broader\", \"narrower\"].flatMap(pick);\n if (finding.path === `${NS.skos}prefLabel`) {\n return pick(\"label\");\n }\n if (finding.message.includes(\"cycle\")) return hierarchy;\n if (finding.path === `${NS.skos}broader`) return hierarchy;\n if (finding.path === `${NS.skos}narrower`) return hierarchy;\n if (finding.path === `${NS.skos}related`) {\n return pick(\"related-concepts\");\n }\n // Negative-scope disjointness (ADR 01014/01015): the finding sits on the\n // negative predicate's shape. Drop the proposed side of the conflict,\n // preferring the negative when both were proposed.\n if (finding.path === GRAPH_NOT_APPLICABLE_TO_VARIANT) {\n const negative = pick(\"not-applicable-to\");\n if (negative.length > 0) return negative;\n return pick(\"applies-to\");\n }\n if (finding.path === GRAPH_NOT_SOFTWARE_SUBJECT) {\n const negative = pick(\"not-about-product-aspect\");\n if (negative.length > 0) return negative;\n return pick(\"about-product-aspect\");\n }\n return []; // unattributable — caller rejects everything guarded\n }\n\n /**\n * Simulate `values` applied to the doc and drop fields until the graph\n * stays clean. New violations always reject; new label warnings\n * reject the proposed label (an LLM must not introduce a second\n * spelling of an existing concept).\n */\n async vet(\n path: string,\n content: string,\n values: Record<string, unknown>,\n ): Promise<VetResult> {\n const current = { ...values };\n const rejected: Array<{ field: string; reason: string }> = [];\n // Match on the LEAF, so `sections.<slug>.applies-to` is guarded exactly as\n // `applies-to` is. Keying on the bare name alone let every section-level\n // proposal skip the simulation entirely (ADR 01032).\n const guardedLeaves = new Set<string>(GUARDED_FIELDS);\n const guarded = (): string[] =>\n Object.keys(current).filter(\n (f) => current[f] !== undefined && guardedLeaves.has(leafOf(f)),\n );\n if (guarded().length === 0) return { values: current, rejected };\n\n const baseline = await this.baseline();\n // Each pass drops at least one field, so this terminates.\n while (guarded().length > 0) {\n const applied = writeGraphFields(\n content,\n path,\n formatOf(path, this.analyzeOptions.format),\n current,\n { force: this.force },\n );\n const model = analyzeDoc(\n applied.content,\n path,\n this.allPaths,\n this.analyzeOptions,\n );\n const findings = await validateGraph(\n this.buildStore({ path, model }),\n this.shapesPaths,\n );\n const introduced = findings.filter(\n (f) => !baseline.has(FillGuard.key(f)),\n );\n const bad = introduced.filter(\n (f) =>\n f.severity === \"error\" ||\n (f.severity === \"warning\" && f.path === `${NS.skos}prefLabel`),\n );\n if (bad.length === 0) break;\n\n const proposed = new Set(guarded());\n const condemned = new Map<string, string>();\n for (const f of bad) {\n for (const field of FillGuard.offendingFields(f, proposed)) {\n if (!condemned.has(field)) condemned.set(field, f.message);\n }\n }\n const firstBad = bad[0];\n if (condemned.size === 0 && firstBad !== undefined) {\n // Can't pin the new violation on a specific field — reject the\n // whole guarded proposal rather than write a graph that fails check.\n // `bad` is non-empty (the loop broke out above when it was not), and\n // reading its head is how that gets said instead of asserted.\n for (const field of guarded()) {\n condemned.set(field, firstBad.message);\n }\n }\n for (const [field, reason] of condemned) {\n rejected.push({ field, reason });\n Reflect.deleteProperty(current, field);\n }\n }\n\n rejected.sort((a, b) => byCodeUnit(a.field, b.field));\n return { values: current, rejected };\n }\n\n /** Fold an accepted (written or would-be-written) doc into guard state. */\n commit(path: string, content: string): void {\n this.models.set(\n path,\n analyzeDoc(content, path, this.allPaths, this.analyzeOptions),\n );\n this.baselineKeys = null;\n }\n}\n","/**\n * Fill proposal cache. Storage is the inference library's `JsonCache`; what\n * stays here is what only dockg can decide — what invalidates an entry:\n * provider, model, prompt version, the requested fields, and the full file\n * content.\n */\nimport { JsonCache, buildCacheKey, sha256 } from \"@hawkeyexl/inference\";\nimport type { FillField } from \"../core/config.js\";\nimport { PROMPT_VERSION } from \"./prompt.js\";\n\nexport { sha256 };\n\nexport function cacheKey(\n provider: string,\n model: string,\n content: string,\n fields: FillField[],\n /** Whether the request also asked for per-section metadata (ADR 01032). */\n sections = false,\n): string {\n return buildCacheKey([\n provider,\n model,\n `v${PROMPT_VERSION}`,\n // Pre-hashed: documents are large and key parts should stay short.\n sha256(content),\n fields.join(\",\"),\n // Same fields, different request: a sections run sends a different schema\n // and a different prompt, so its answer must not be served from a\n // doc-only entry (or the other way round).\n sections ? \"sections\" : \"doc-only\",\n ]);\n}\n\n/**\n * Proposals are plain JSON objects. Callers re-validate what comes back\n * against the proposal schema — a hand-edited or stale entry must not bypass\n * validation just because it parsed.\n */\nexport class FillCache extends JsonCache<Record<string, unknown>> {\n constructor(dir: string, enabled: boolean = true) {\n super(dir, enabled, \"manni\");\n }\n}\n","/**\n * Fill prompt and proposal schema. The proposal schema is restricted to the\n * fields being requested for the specific doc, so a provider physically\n * cannot propose fields the run should not touch. Alongside the field values,\n * the model returns a per-field `confidence` (0..1) and `reasoning`; the fill\n * command gates on confidence (ADR 01015).\n */\nimport type { FillField } from \"../core/config.js\";\nimport type { DocModel } from \"../types.js\";\n\n/**\n * Bump when the prompt changes — invalidates the fill cache.\n *\n * 4 is the move to `manni:kg:1.0.0-proposal.3` (proposal 0051 §4). The fields\n * a proposal may carry did not change, but what `fill` does with the answer\n * did: the attribution it writes is now the page-level `meta-provenance`, by\n * JSON Pointer. A cache entry written before that replays a proposal shaped\n * for the old vocabulary, so every key misses once and is rewritten.\n */\nexport const PROMPT_VERSION = 4;\n\nconst TOPIC_TYPES = [\n \"task\",\n \"concept\",\n \"reference\",\n \"learning\",\n \"troubleshooting\",\n \"form\",\n];\nconst LIFECYCLE_PHASES = [\n \"administration\",\n \"customization\",\n \"update\",\n \"deployment\",\n \"integration\",\n \"deinstallation\",\n];\nconst SOFTWARE_SUBJECTS = [\"architecture\", \"interface\", \"system-requirement\"];\n\nconst labelArray = (description: string) => ({\n type: \"array\",\n items: { type: \"string\", minLength: 1 },\n uniqueItems: true,\n description,\n});\nconst enumArray = (values: string[], description: string) => ({\n type: \"array\",\n items: { enum: values },\n uniqueItems: true,\n description,\n});\n\n/** Exported for the schema-sync drift guard (test/unit/schema-sync.test.ts). */\nexport const FIELD_SCHEMAS: Record<FillField, Record<string, unknown>> = {\n label: {\n type: \"string\",\n minLength: 1,\n description:\n \"Preferred label of the single concept this document is primarily about.\",\n },\n \"alt-labels\": labelArray(\n \"Alternative labels: synonyms, abbreviations, common variants.\",\n ),\n broader: labelArray(\"Labels of broader (parent) concepts.\"),\n narrower: labelArray(\"Labels of narrower (child) concepts.\"),\n \"related-concepts\": labelArray(\"Labels of associatively related concepts.\"),\n concepts: labelArray(\"Subject labels for the document, like tags.\"),\n type: {\n enum: TOPIC_TYPES,\n description:\n \"iiRDS topic type — the functional kind of this page. Only if the page clearly fits one.\",\n },\n \"applies-to\": labelArray(\n \"Product/variant names this page applies to. ONLY names the text explicitly states; never guess product names.\",\n ),\n \"about-product-lifecycle\": enumArray(\n LIFECYCLE_PHASES,\n \"Software lifecycle phases this page covers, only if clearly evidenced.\",\n ),\n \"about-product-aspect\": enumArray(\n SOFTWARE_SUBJECTS,\n \"Software information subjects this page is about, only if clearly evidenced.\",\n ),\n \"not-applicable-to\": labelArray(\n \"Product/variant names the text EXPLICITLY says this page does NOT apply to. Only with explicit textual evidence.\",\n ),\n \"not-about-product-aspect\": enumArray(\n SOFTWARE_SUBJECTS,\n \"Software subjects the text EXPLICITLY says this page is NOT about. Only with explicit textual evidence.\",\n ),\n};\n\n/**\n * Memoized by the requested field set. A corpus has only a handful of distinct\n * field combinations, but a fresh schema object per document would defeat the\n * inference library's identity-keyed validator cache and recompile Ajv once per\n * file. The returned object must therefore be treated as immutable.\n */\nconst schemaCache = new Map<string, Record<string, unknown>>();\n\n/**\n * The `graph` fields a section block accepts (ADR 01013). `label` is absent\n * deliberately — a \"primary topic per section\" is meaningless, so it is not\n * proposable either.\n */\nexport const SECTION_FILL_FIELDS: readonly FillField[] = [\n \"type\",\n \"applies-to\",\n \"about-product-lifecycle\",\n \"about-product-aspect\",\n \"not-applicable-to\",\n \"not-about-product-aspect\",\n \"concepts\",\n];\n\n/**\n * @param fields Document-level fields to offer — narrowed to what this\n * document is missing, so a provider cannot propose over a human's value.\n * @param options.sections Section-level fields to offer, or absent for no\n * section half. Passed **separately and unnarrowed** on purpose: section\n * presence is independent of document presence (ADR 01032), so a page whose\n * `graph.type` is already set must still be able to type its sections. Deriving\n * this list from `fields` handed a strictly-constrained provider a section\n * item with no data properties at all.\n */\nexport function proposalSchema(\n fields: FillField[],\n options: { sections?: FillField[]; lenient?: boolean } = {},\n): Record<string, unknown> {\n // Build from the SAME sorted list the key is derived from. Keying on the\n // sorted set while building from the caller's order would make the cached\n // schema's property order depend on whichever call arrived first — and that\n // order is observable: the schema is JSON.stringify'd into the claude-cli\n // and json_object prompts, so identical inputs could produce different\n // prompts across runs. Determinism is the product contract here.\n const sorted = [...fields].sort();\n // Sorted for the same reason `fields` is: the section item's property order\n // is observable through the stringified schema in the prompt.\n const sortedSections = options.sections\n ? [...options.sections]\n .filter((f) => SECTION_FILL_FIELDS.includes(f))\n .sort()\n : undefined;\n const lenient = options.lenient === true;\n const key = [\n sortedSections ? `s:${sortedSections.join(\",\")}` : \"\",\n lenient ? \"l:\" : \"\",\n sorted.join(\",\"),\n ].join(\"|\");\n const memoized = schemaCache.get(key);\n if (memoized) return memoized;\n const built = buildProposalSchema(sorted, sortedSections, lenient);\n schemaCache.set(key, built);\n return built;\n}\n\nfunction buildProposalSchema(\n fields: FillField[],\n sectionFields: FillField[] | undefined,\n lenient: boolean,\n): Record<string, unknown> {\n // The value schemas are the contract and never relax. `confidence` and\n // `reasoning` are the model's own commentary on those values, and in the\n // validation schema they are accepted in whatever shape they arrive\n // (ADR 01034): `numberMap`/`stringMap` already ignore anything of the wrong\n // type, so a malformed score costs that one field its score rather than\n // discarding an otherwise good proposal. The REQUEST schema keeps the types,\n // so a provider is still asked — and a grammar-capable one still constrained\n // — to send a number.\n const scoreSchema = lenient ? {} : { type: \"number\", minimum: 0, maximum: 1 };\n const noteSchema = lenient ? {} : { type: \"string\" };\n const properties: Record<string, unknown> = {};\n const confidence: Record<string, unknown> = {};\n const reasoning: Record<string, unknown> = {};\n for (const field of fields) {\n properties[field] = FIELD_SCHEMAS[field];\n confidence[field] = scoreSchema;\n reasoning[field] = noteSchema;\n }\n properties[\"confidence\"] = {\n type: \"object\",\n additionalProperties: false,\n properties: confidence,\n description:\n \"For every field you propose a value for, a confidence 0..1 that the value is correct.\",\n };\n properties[\"reasoning\"] = {\n type: \"object\",\n additionalProperties: false,\n properties: reasoning,\n description:\n \"For every field you propose a value for, a one-sentence justification grounded in the page text.\",\n };\n\n if (sectionFields !== undefined) {\n // A **list** keyed by an explicit `slug`, not a map keyed by slug. Strict\n // structured output (OpenAI's json_schema, and the GBNF grammar it becomes)\n // requires `additionalProperties: false` on every object, which cannot\n // express an open-keyed map. A list of {slug, …} says the same thing in a\n // shape every provider can constrain.\n const sectionProps: Record<string, unknown> = {\n slug: {\n type: \"string\",\n minLength: 1,\n description:\n \"The heading slug, copied exactly from the outline. Do not invent one.\",\n },\n };\n const sectionConfidence: Record<string, unknown> = {};\n const sectionReasoning: Record<string, unknown> = {};\n for (const field of sectionFields) {\n sectionProps[field] = FIELD_SCHEMAS[field];\n sectionConfidence[field] = scoreSchema;\n sectionReasoning[field] = noteSchema;\n }\n sectionProps[\"confidence\"] = {\n type: \"object\",\n additionalProperties: false,\n properties: sectionConfidence,\n description:\n \"For every field you propose on this section, a confidence 0..1.\",\n };\n sectionProps[\"reasoning\"] = {\n type: \"object\",\n additionalProperties: false,\n properties: sectionReasoning,\n description:\n \"For every field you propose on this section, a one-sentence justification.\",\n };\n properties[\"sections\"] = {\n type: \"array\",\n items: {\n type: \"object\",\n additionalProperties: false,\n required: [\"slug\"],\n properties: sectionProps,\n },\n description:\n \"Per-section metadata. Only for sections whose own content differs meaningfully from the page as a whole; omit a section rather than repeating the page's values.\",\n };\n }\n\n return {\n type: \"object\",\n additionalProperties: false,\n properties,\n };\n}\n\nexport const SYSTEM_PROMPT = [\n \"You classify documentation pages into a controlled metadata vocabulary\",\n \"(SKOS concepts and iiRDS typing). For each requested field, first reason\",\n \"about whether the page's own text supports a value; propose a value only\",\n \"when it clearly does, and omit the field otherwise. Reuse the document's\",\n \"own terminology; do not invent concepts, product names, or classifications\",\n \"the document does not discuss.\",\n \"\",\n \"For every field you propose a value for, include a `confidence` (0..1) and\",\n \"a one-sentence `reasoning` grounded in the text. Score honestly and\",\n \"conservatively. Product/variant fields (applies-to, not-applicable-to) and the\",\n \"negative fields (not-applicable-to, not-about-product-aspect) require EXPLICIT\",\n \"textual evidence — score them low and prefer to omit unless the page states\",\n \"them outright. A field with no value needs no confidence or reasoning.\",\n].join(\"\\n\");\n\nconst EXCERPT_CHARS = 2000;\n\nexport function buildUserPrompt(\n doc: DocModel,\n body: string,\n fields: FillField[],\n options: { sections?: boolean } = {},\n): string {\n const title =\n (typeof doc.frontmatter[\"title\"] === \"string\" &&\n doc.frontmatter[\"title\"]) ||\n doc.firstH1 ||\n \"(untitled)\";\n const tags = doc.frontmatter[\"tags\"] ?? doc.frontmatter[\"keywords\"];\n // With sections on, the outline carries each heading's slug: it is the key\n // the model must copy, and a slug it invents is dropped rather than written\n // (which would otherwise mint a graph:brokenSectionRef — a finding fill must\n // never manufacture).\n const withSections = options.sections === true && doc.sections.length > 0;\n const outline = doc.sections\n .map(\n (s) =>\n `${\" \".repeat(Math.max(0, s.level - 1))}- ${s.title}` +\n (withSections ? ` [slug: ${s.slug}]` : \"\"),\n )\n .join(\"\\n\");\n\n return [\n `Propose the following frontmatter fields for this documentation page, with per-field confidence and reasoning: ${fields.join(\", \")}.`,\n withSections\n ? \"Also propose per-section metadata in `sections`, using the exact slug shown in the outline. Include a section ONLY when its own content differs meaningfully from the page as a whole — repeating the page's values on every heading adds noise, not granularity.\"\n : \"\",\n \"\",\n `Path: ${doc.path}`,\n `Title: ${title}`,\n Array.isArray(tags) && tags.length > 0\n ? `Existing tags: ${tags.join(\", \")}`\n : \"\",\n \"\",\n \"Heading outline:\",\n outline || \"(no headings)\",\n \"\",\n \"Body excerpt:\",\n body.slice(0, EXCERPT_CHARS),\n ].join(\"\\n\");\n}\n","/**\n * Choosing the provider and model for `manni graph fill`, and building the shared\n * inference library's `ProviderSpec` for it.\n *\n * The providers themselves live in `@hawkeyexl/inference` (ADR 01021). The\n * names a provider may have, the two refusals, the detection call, the\n * level-bound precedence and the mapping of the family's `providers:`\n * connection settings are `src/shared/providers.ts`, the same code\n * `manni meta fill` and `manni docevals` run. What stays here is what only graph\n * can decide: which levels it reads — a flag, then `graph.provider`/`graph.model`,\n * then the family's top-level `providers:` map, then `auto` (proposal\n * 0051 §3).\n *\n * `graph.embed.model` is a local embedding model id, not a provider, and nothing\n * here touches it.\n */\nimport {\n makeProvider as makeInferenceProvider,\n type InferenceProvider,\n type ProviderName as ConcreteProvider,\n type ProviderSelector,\n type ProviderSpec,\n} from \"@hawkeyexl/inference\";\nimport type { GraphConfig } from \"../core/config.js\";\nimport {\n assertKnownProvider,\n assertLocalFlag,\n assertModelHasProvider,\n localNotice,\n providerSpecFor as sharedProviderSpecFor,\n resolveIdentity,\n selectProvider as selectFromLevels,\n type ProviderChoice,\n type ProviderFlags,\n type ProviderSelection,\n} from \"../../shared/providers.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { noticeOnce } from \"../../shared/warn.js\";\nimport { GraphError } from \"../types.js\";\n\nexport type { ProviderChoice, ProviderFlags, ProviderSelection };\n\n/** The key a graph user writes, named by the refusal a bare model gets. */\nconst CONFIG_KEY = \"graph.provider\";\n\nconst toGraphError = (message: string): Error => new GraphError(message);\n\n/**\n * The provider and model in force: a flag, then `graph.provider`/`graph.model`,\n * then the family's `providers.provider`/`model`, then `auto`. A model is\n * carried only to the provider its own level names, so a level whose provider\n * lost takes the winner's default rather than a model it cannot run\n * (`selectProvider` in the shared module).\n *\n * `--local` runs llama-cpp over both levels. A `--provider` it contradicts is\n * refused here, so no path selects past it.\n */\nexport function selectProvider(\n config: GraphConfig,\n flags: ProviderFlags = {},\n): ProviderSelection {\n assertLocalFlag(flags, toGraphError);\n return selectFromLevels(flags, [\n {\n ...(config.provider !== null ? { provider: config.provider } : {}),\n ...(config.model !== null ? { model: config.model } : {}),\n origin: CONFIG_KEY,\n },\n {\n ...(config.providers.provider !== undefined\n ? { provider: config.providers.provider }\n : {}),\n ...(config.providers.model !== undefined\n ? { model: config.providers.model }\n : {}),\n origin: \"providers.provider\",\n },\n ]);\n}\n\n/**\n * Say what `--local` set aside, once per source. Called where a selection is\n * about to be used, never where it is only checked, so a run that sends\n * nothing to a model says nothing.\n */\nexport function announceSelection(selection: ProviderSelection): void {\n const message = localNotice(selection);\n if (message !== undefined) noticeOnce(message);\n}\n\n/**\n * Refuse a selection that cannot be right, with `manni meta fill`'s messages:\n * an unknown name, or a model under `auto`. Both are `GraphError`s, so both exit\n * 2 rather than reading as a finding.\n */\nexport function assertProviderSelection(selection: ProviderSelection): void {\n assertKnownProvider(selection.provider, toGraphError);\n assertModelHasProvider(\n selection.provider,\n selection.model,\n CONFIG_KEY,\n toGraphError,\n );\n}\n\n/**\n * The spec for a selection, with the family's connection settings for the\n * provider it names, and under `auto` the settings detection reads.\n */\nexport function providerSpecFor(\n config: GraphConfig,\n selection: { provider: ProviderSelector; model: string | null },\n): ProviderSpec {\n return sharedProviderSpecFor(config.providers, selection);\n}\n\n/**\n * The concrete provider and model, WITHOUT constructing the provider: cache\n * keys need it, and a fully cached or fully complete run must not require an\n * API key.\n *\n * Under `auto` this is where detection runs, exactly as `manni meta fill`\n * runs it, seeing the same connection settings. The model is the RESOLVED one\n * (the provider's default when none was named, a llama-cpp tier's concrete\n * weights), so a library default that changes changes every cache key built\n * from it.\n */\nexport async function resolveProviderIdentity(\n config: GraphConfig,\n flags: ProviderFlags = {},\n): Promise<{ provider: ConcreteProvider; model: string }> {\n const selection = selectProvider(config, flags);\n const { provider, model } = selection;\n assertKnownProvider(provider, toGraphError);\n assertModelHasProvider(provider, model, CONFIG_KEY, toGraphError);\n announceSelection(selection);\n return resolveIdentity(\n providerSpecFor(config, { provider, model: model ?? null }),\n toGraphError,\n );\n}\n\n/** Construct a provider for an identity already resolved. */\nexport function constructProvider(\n config: GraphConfig,\n identity: { provider: ConcreteProvider; model: string },\n): InferenceProvider {\n try {\n return makeInferenceProvider(providerSpecFor(config, identity));\n } catch (e) {\n // The library raises its own InferenceError (a missing API key, say). It\n // must surface as a GraphError: `fail()` maps only GraphError to exit 2, and\n // letting a foreign error type through turns \"no API key configured\" into\n // an unhandled stack trace.\n throw new GraphError(errorMessage(e));\n }\n}\n\n/** Select, check, detect and construct: the provider `fill` sends pages to. */\nexport async function makeProvider(\n config: GraphConfig,\n flags: ProviderFlags = {},\n): Promise<InferenceProvider> {\n return constructProvider(config, await resolveProviderIdentity(config, flags));\n}\n","/**\n * `manni graph embed` — compute vectors for the search index (ADR 01020).\n *\n * Embeds the text already in `graph/search.<lang>.json` rather than re-reading\n * markdown: vectors then cover exactly what the lexical index covers, with the\n * Phase 8 granularity rule already applied, so both ranking legs score the same\n * units.\n *\n * One sidecar per language, driven by the localization manifest and embedded\n * with that language's model (ADR 01038) — a German corpus under an\n * English-only model returns confident, meaningless vectors and fails nothing.\n *\n * This is the one dockg command that needs a model. It is local — no API, no\n * key, no spend — but the weights are a download, so unlike every other\n * artifact the sidecars cannot be regenerated in CI from a real model.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport path, { dirname, join, resolve } from \"node:path\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { type SearchEntry, type SearchIndexDoc } from \"../core/search-index.js\";\nimport {\n canonicalLanguageTag,\n emitLocalizations,\n isSafeRelativePath,\n LOCALIZATIONS_FILENAME,\n parseLocalizations,\n vectorIndexFilename,\n type LocalizationEntry,\n} from \"../core/localizations.js\";\nimport { encodeVectorIndex } from \"../core/vector-index.js\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { GraphError } from \"../types.js\";\nimport {\n createLocalEmbedder,\n EmbedderUnavailableError,\n} from \"../embed/local.js\";\nimport { createMockEmbedder } from \"../embed/mock.js\";\nimport type { Embedder } from \"../embed/types.js\";\n\nexport interface EmbedOptions {\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 /** Directory to write the sidecars into (default: the index directory). */\n out?: string;\n model?: string;\n dtype?: string;\n /** Skip the vector cache. */\n noCache?: boolean;\n /** Injection seam for tests: bypasses the embedder factory. */\n embedder?: Embedder;\n cwd?: string;\n}\n\n/** One language's sidecar, as this run produced it. */\nexport interface EmbedLanguageReport {\n language: string;\n outPath: string;\n /** The model this language was embedded with, after the per-language override. */\n model: string;\n dims: number;\n /** Entries embedded this run (cache misses). */\n embedded: number;\n /** Entries served from cache. */\n cached: number;\n total: number;\n}\n\nexport interface EmbedReport {\n /** The manifest, rewritten with each language's `vectors` block. */\n manifestPath: string;\n /** One entry per language in the manifest, in its order. */\n languages: EmbedLanguageReport[];\n /** Totals across every language. */\n embedded: number;\n cached: number;\n total: number;\n}\n\n/** The text an entry contributes to its vector — same fields the lexical index scores. */\nexport function embedText(entry: SearchEntry): string {\n return [entry.title, entry.labels, entry.description, entry.text]\n .filter((part): part is string => part !== undefined && part !== \"\")\n .join(\"\\n\\n\");\n}\n\nfunction sha256(text: string): string {\n return createHash(\"sha256\").update(text, \"utf8\").digest(\"hex\");\n}\n\n/**\n * Per-text vector cache. Embedding is slow by construction (single-threaded\n * WASM, one text per call), so editing one section must not re-embed the corpus.\n * Keyed on text + model + dtype, so changing any of them re-embeds rather than\n * serving vectors from a different function.\n */\nclass VectorCache {\n constructor(\n private readonly dir: string,\n private readonly enabled: boolean,\n ) {}\n\n private path(key: string): string {\n return join(this.dir, `${key}.json`);\n }\n\n get(key: string): Float32Array | undefined {\n if (!this.enabled) return undefined;\n const file = this.path(key);\n if (!existsSync(file)) return undefined;\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as number[];\n return Array.isArray(parsed) ? Float32Array.from(parsed) : undefined;\n } catch {\n return undefined; // A corrupt entry is a miss, never a crash.\n }\n }\n\n set(key: string, vector: Float32Array): void {\n if (!this.enabled) return;\n mkdirSync(this.dir, { recursive: true });\n writeFileSync(this.path(key), JSON.stringify([...vector]), \"utf8\");\n }\n}\n\nasync function makeEmbedder(\n opts: EmbedOptions,\n model: string,\n dtype: string,\n): Promise<Embedder> {\n if (opts.embedder) return opts.embedder;\n // `--model mock` keeps the CLI exercisable offline, mirroring `fill`'s mock\n // provider. It produces hash-derived vectors with no semantics.\n if (model === \"mock\") return createMockEmbedder({ dtype });\n try {\n return await createLocalEmbedder({ model, dtype, role: \"passage\" });\n } catch (e) {\n if (e instanceof EmbedderUnavailableError) {\n throw new GraphError(e.message);\n }\n // Everything else the model stack can fail on — an unknown id, a 404 on the\n // hub, corrupt weights — is operational (exit 2), not a raw stack trace.\n throw new GraphError(\n `Failed to load embedding model ${model}: ${errorMessage(e)}`,\n );\n }\n}\n\n/**\n * The sidecar's path as the manifest records it: relative to the manifest,\n * with forward slashes, because a browser resolves it against a URL.\n *\n * On Windows a sidecar on another drive has no relative path, and `relative`\n * returns an absolute one. The reader refuses that, so writing it would leave\n * an artifact set nothing can read back. Refused here instead, before any\n * file is written. `pathApi` is the seam that lets a test be Windows anywhere.\n */\nexport function manifestRelativePath(\n indexDir: string,\n outPath: string,\n pathApi: Pick<typeof path, \"relative\" | \"isAbsolute\" | \"sep\"> = path,\n): string {\n const rel = pathApi.relative(indexDir, outPath);\n const recorded = rel.split(pathApi.sep).join(\"/\");\n if (pathApi.isAbsolute(rel) || !isSafeRelativePath(recorded)) {\n throw new GraphError(\n `Cannot record vectors at ${outPath}: the localization manifest needs a path relative to ${indexDir}. Write the sidecars on the index's drive.`,\n );\n }\n return recorded;\n}\n\nexport async function runEmbed(opts: EmbedOptions = {}): Promise<EmbedReport> {\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 // The manifest is the work list: `export search` wrote one index per\n // language and named them all here, so embed never has to guess which files\n // exist or what language each holds (ADR 01038).\n const indexDir = opts.index ? resolve(cwd, opts.index) : dirname(graphPath);\n const manifestPath = join(indexDir, LOCALIZATIONS_FILENAME);\n\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\n // `-o` over the config's `embed.out`, both from the working directory as\n // `out` is, and the index directory when neither names one.\n const outSetting = opts.out ?? config.embed.out;\n const outDir = outSetting ? resolve(cwd, outSetting) : indexDir;\n mkdirSync(outDir, { recursive: true });\n const cache = new VectorCache(\n resolve(cwd, config.embed.cacheDir),\n !opts.noCache,\n );\n\n // One embedder per (model, dtype), built on the first cache miss that needs\n // it: `pipeline()` downloads tens of megabytes of weights, and a run that is\n // entirely cache hits has no reason to pay for it — for any language.\n const embedders = new Map<string, Promise<Embedder>>();\n const getEmbedder = (model: string, dtype: string): Promise<Embedder> => {\n // JSON, not a joined string: no separator can collide, and no NUL byte\n // enters the source (CLAUDE.md's no-NUL invariant), which is the same\n // reason the vector cache key below is JSON.\n const key = JSON.stringify([model, dtype]);\n const existing = embedders.get(key);\n if (existing) return existing;\n const built = makeEmbedder(opts, model, dtype);\n embedders.set(key, built);\n return built;\n };\n\n const languages: EmbedLanguageReport[] = [];\n const updated: LocalizationEntry[] = [];\n\n for (const entry of manifest.languages) {\n const indexPath = join(indexDir, entry.search.path);\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 const raw = readFileSync(indexPath, \"utf8\");\n const source = `sha256:${sha256(raw)}`;\n // The manifest records the digest of the file it wrote. A mismatch means\n // the pair has drifted, and embedding it would produce a sidecar keyed to\n // bytes nobody has — the same refusal the runtime makes at query time.\n if (entry.search.digest !== source) {\n throw new GraphError(\n `Stale manifest: ${entry.search.path} does not match the digest recorded for \"${entry.language}\" — re-run \\`manni graph export search\\`.`,\n );\n }\n\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.`,\n );\n }\n\n // Per-language model, then the flags, then the corpus-wide default. A\n // German corpus embedded with an English-only model returns confident,\n // meaningless vectors and fails nothing, so this override is the whole\n // reason the fan-out exists.\n //\n // Keys are matched canonically, so `en-us:` configures the `en-US` index.\n const wanted = canonicalLanguageTag(entry.language);\n const perLanguage = Object.entries(config.embed.byLanguage).find(\n ([tag]) => canonicalLanguageTag(tag) === wanted,\n )?.[1];\n const model = opts.model ?? perLanguage?.model ?? config.embed.model;\n const dtype = opts.dtype ?? perLanguage?.dtype ?? config.embed.dtype;\n const identity = opts.embedder\n ? { model: opts.embedder.model, dtype: opts.embedder.dtype }\n : { model, dtype };\n\n const vectors: Array<{ id: string; vector: Float32Array }> = [];\n let embedded = 0;\n let cached = 0;\n\n for (const item of entries) {\n const text = embedText(item);\n if (text === \"\") continue;\n // JSON rather than a joined string: no separator can collide with\n // content, and no NUL byte enters the source (a NUL makes git classify\n // the file as binary — the no-NUL-bytes invariant in CLAUDE.md).\n const key = sha256(\n JSON.stringify([identity.model, identity.dtype, text]),\n );\n let vector = cache.get(key);\n if (vector) {\n cached += 1;\n } else {\n vector = await (await getEmbedder(model, dtype)).embed(text);\n cache.set(key, vector);\n embedded += 1;\n }\n vectors.push({ id: item.id, vector });\n }\n\n const filename = vectorIndexFilename(entry.language);\n const outPath = join(outDir, filename);\n // What the manifest records is relative to the manifest, not to wherever\n // `-o` happened to point — so a sidecar written outside the index\n // directory is still findable from the file that names it. Forward slashes\n // because this is a JSON artifact a browser resolves against a URL.\n const manifestRelative = manifestRelativePath(indexDir, outPath);\n writeFileSync(\n outPath,\n encodeVectorIndex(vectors, {\n model: identity.model,\n dtype: identity.dtype,\n source,\n language: entry.language,\n }),\n );\n\n const dims = vectors[0]?.vector.length ?? 0;\n languages.push({\n language: entry.language,\n outPath,\n model: identity.model,\n dims,\n embedded,\n cached,\n total: vectors.length,\n });\n updated.push({\n ...entry,\n vectors: {\n path: manifestRelative,\n model: identity.model,\n dtype: identity.dtype,\n dims,\n count: vectors.length,\n },\n });\n }\n\n // Rewritten so the manifest describes what is actually on disk: an entry\n // without a `vectors` block means that language has no sidecar yet.\n writeFileSync(\n manifestPath,\n emitLocalizations({ version: 1, languages: updated }),\n \"utf8\",\n );\n\n return {\n manifestPath,\n languages,\n embedded: languages.reduce((n, l) => n + l.embedded, 0),\n cached: languages.reduce((n, l) => n + l.cached, 0),\n total: languages.reduce((n, l) => n + l.total, 0),\n };\n}\n\nexport function renderEmbed(\n report: EmbedReport,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") return JSON.stringify(report, null, 2);\n const lines = report.languages.map(\n (l) =>\n ` ${l.language}: ${l.total} vector${l.total === 1 ? \"\" : \"s\"} (${l.dims}-d, ${l.model}) -> ${l.outPath}`,\n );\n if (lines.length === 0) lines.push(\" (no languages in the manifest)\");\n const n = report.languages.length;\n return [\n // Not \"beside\": `-o` may put the sidecars in a different directory from\n // the manifest, and each line below names the path it actually wrote.\n `Wrote ${n} sidecar${n === 1 ? \"\" : \"s\"}, recorded in ${report.manifestPath}`,\n ...lines,\n ` ${report.embedded} embedded, ${report.cached} from cache`,\n ].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 * 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 * `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, 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 */\nasync function resolveEmbedder(\n opts: SearchOptions,\n vectors: VectorIndex,\n required: boolean,\n): Promise<Embedder | undefined> {\n const { model, dtype } = vectors;\n try {\n const embedder =\n opts.embedder ??\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 * 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 * `manni graph stats` — graph health summary: node/edge counts, orphan docs\n * (no incoming or outgoing references), broken internal links, the\n * most-connected docs, and metadata coverage. `--check` exits 1 when broken\n * links exist or a coverage threshold is unmet.\n */\nimport { resolve } from \"node:path\";\nimport { DataFactory, type Store } from \"n3\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport { compactIri, loadGraph } from \"../core/load.js\";\nimport { NS, RDF_TYPE } from \"../core/vocab.js\";\nimport { COVERAGE_FIELDS, SECTION_COVERAGE_FIELDS } from \"../core/coverage.js\";\nimport { byCodeUnit } from \"../core/sort.js\";\n\nexport interface StatsOptions {\n config?: string;\n /** `--no-config`: skip discovery and run on the built-in defaults. */\n noConfig?: boolean;\n graph?: string;\n cwd?: string;\n /** Exit 1 when broken links exist or a coverage threshold is unmet. */\n check?: boolean;\n /** How many most-connected docs to list. */\n top?: number;\n /**\n * Uniform minimum coverage percentage, overriding config across every field.\n * The per-field map form is config-only.\n */\n coverageThreshold?: number;\n}\n\n/** One row of the metadata coverage report. */\nexport interface CoverageRow {\n field: string;\n predicate: string;\n /** Documents carrying the predicate. */\n docs: number;\n /** Percentage of documents covered, rounded to one decimal. */\n pct: number;\n}\n\nexport interface StatsReport {\n triples: number;\n docs: number;\n sections: number;\n concepts: number;\n references: number;\n /** graph:path of docs with no in/out dcterms:references. */\n orphans: string[];\n brokenLinks: Array<{ doc: string; target: string }>;\n /** graph.sections keys that matched no heading (graph:brokenSectionRef). */\n brokenSectionRefs: Array<{ doc: string; slug: string }>;\n mostConnected: Array<{ doc: string; degree: number }>;\n /** Per-field metadata coverage over documents, in report order. */\n coverage: CoverageRow[];\n /**\n * Per-field coverage over `graph:Section` nodes (ADR 01029). Reported, not\n * gated: sections are explicit-only, so these start near zero on every corpus\n * and a default gate would fail every one of them.\n */\n sectionCoverage: CoverageRow[];\n /**\n * Per-language reporting (ADR 01037). The whole-corpus `coverage` table\n * blends every locale into one number that describes no audience; this says\n * which audience is under-served and what is still untranslated.\n *\n * Reported, not gated — `coverageFindings` stays whole-corpus, per\n * ADR 01009's rule that reporting on does not imply gating on.\n */\n localization: LocalizationReport;\n /** Fields whose document coverage is below their configured threshold. */\n coverageFindings: Array<{ field: string; pct: number; threshold: number }>;\n exitCode: 0 | 1;\n}\n\nexport interface LanguageReport {\n /** BCP-47 tag exactly as the graph carries it. */\n language: string;\n /** Documents carrying this tag. */\n docs: number;\n /** The same fields as `coverage`, scored over this language's documents. */\n coverage: CoverageRow[];\n /**\n * `graph:path` of source documents with no translation into this language,\n * sorted. A *source* is a document carrying no `schema:translationOfWork` —\n * so a translation is never its own backlog item — and a source already in\n * this language is excluded. Nothing here is inferred: a page counts as\n * translated only where the graph carries the edge.\n */\n untranslated: string[];\n}\n\nexport interface LocalizationReport {\n /** Documents carrying no `dcterms:language` at all. */\n unlabelled: number;\n /** One block per language present, sorted by tag. */\n languages: LanguageReport[];\n}\n\nfunction subjectsOfType(store: Store, typeIri: string): string[] {\n return store\n .getQuads(null, DataFactory.namedNode(RDF_TYPE), DataFactory.namedNode(typeIri), null)\n .map((q) => q.subject.value)\n .sort();\n}\n\n/** Strip a fragment so section references count toward their doc. */\nfunction base(iri: string): string {\n const hash = iri.indexOf(\"#\");\n return hash === -1 ? iri : iri.slice(0, hash);\n}\n\n/** Round a percentage to one decimal place for display. */\nfunction round1(pct: number): number {\n return Math.round(pct * 10) / 10;\n}\n\nexport function runStats(opts: StatsOptions = {}): StatsReport {\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 store = loadGraph(resolve(cwd, opts.graph ?? config.out));\n const top = opts.top ?? 5;\n\n const docIris = subjectsOfType(store, `${NS.graph}Document`);\n const docSet = new Set(docIris);\n // One indexed scan for all paths instead of a per-doc lookup.\n const pathOf = new Map<string, string>(docIris.map((d) => [d, d]));\n for (const quad of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.graph}path`),\n null,\n null,\n )) {\n pathOf.set(quad.subject.value, quad.object.value);\n }\n\n const refQuads = store.getQuads(\n null,\n DataFactory.namedNode(`${NS.dcterms}references`),\n null,\n null,\n );\n const degree = new Map<string, number>(docIris.map((d) => [d, 0]));\n for (const quad of refQuads) {\n const from = quad.subject.value;\n const to = base(quad.object.value);\n if (docSet.has(from)) degree.set(from, (degree.get(from) ?? 0) + 1);\n if (docSet.has(to) && to !== from)\n degree.set(to, (degree.get(to) ?? 0) + 1);\n }\n\n const orphans = docIris\n .filter((d) => (degree.get(d) ?? 0) === 0)\n .map((d) => pathOf.get(d) ?? d)\n .sort();\n\n const brokenLinks = store\n .getQuads(null, DataFactory.namedNode(`${NS.graph}brokenLink`), null, null)\n .map((q) => ({\n doc: pathOf.get(q.subject.value) ?? q.subject.value,\n target: q.object.value,\n }))\n .sort((a, b) => (a.doc + a.target < b.doc + b.target ? -1 : 1));\n\n const brokenSectionRefs = store\n .getQuads(null, DataFactory.namedNode(`${NS.graph}brokenSectionRef`), null, null)\n .map((q) => ({\n doc: pathOf.get(q.subject.value) ?? q.subject.value,\n slug: q.object.value,\n }))\n .sort((a, b) => (a.doc + a.slug < b.doc + b.slug ? -1 : 1));\n\n const mostConnected = [...degree.entries()]\n .filter(([, deg]) => deg > 0)\n .map(([doc, deg]) => ({ doc: pathOf.get(doc) ?? doc, degree: deg }))\n .sort((a, b) => b.degree - a.degree || (a.doc < b.doc ? -1 : 1))\n .slice(0, top);\n\n // Coverage: one indexed scan per field over Document subjects. Measured\n // against the graph, so git-derived values count (ADR 01008/01011). A\n // zero-document graph is vacuously 100% — no divide-by-zero, no false gate.\n const total = docIris.length;\n /** Count subjects carrying each predicate, as a share of `subjects`. */\n const coverageOver = (\n subjects: readonly string[],\n fields: readonly { field: string; iri: string }[],\n ): CoverageRow[] =>\n fields.map(({ field, iri }) => {\n let docs = 0;\n for (const s of subjects) {\n if (store.countQuads(DataFactory.namedNode(s), DataFactory.namedNode(iri), null, null) > 0)\n docs++;\n }\n const ratio =\n subjects.length === 0 ? 100 : (docs / subjects.length) * 100;\n // Report the rounded value; gate on the raw ratio (below) so a corpus at\n // 79.96% does not clear an 80 threshold on display rounding alone.\n return { field, predicate: compactIri(iri), docs, pct: round1(ratio) };\n });\n\n const coverage = coverageOver(docIris, COVERAGE_FIELDS);\n const sectionCoverage = coverageOver(\n subjectsOfType(store, `${NS.graph}Section`),\n SECTION_COVERAGE_FIELDS,\n );\n\n // --- Localization (ADR 01037) ---------------------------------------------\n const languageOf = new Map<string, string>();\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.dcterms}language`),\n null,\n null,\n )) {\n if (docSet.has(q.subject.value))\n languageOf.set(q.subject.value, q.object.value);\n }\n\n const byLanguage = new Map<string, string[]>();\n for (const d of docIris) {\n const tag = languageOf.get(d);\n if (tag === undefined) continue;\n // Push into the existing array rather than rebuilding it: spreading copies\n // the whole bucket per document, which is quadratic in a corpus where one\n // language holds most of the pages.\n const bucket = byLanguage.get(tag);\n if (bucket) bucket.push(d);\n else byLanguage.set(tag, [d]);\n }\n\n // A source is a document that is not itself a translation. Translations are\n // excluded so a German page never appears in the German backlog.\n const sources = docIris.filter(\n (d) =>\n store.countQuads(\n DataFactory.namedNode(d),\n DataFactory.namedNode(`${NS.schema}translationOfWork`),\n null,\n null,\n ) === 0,\n );\n\n // Which languages each source already has a translation into, from one scan\n // over the inverse edges. Asking the store per source per language instead\n // scales with #sources × #languages, and every one of those lookups walks\n // the same quads this single pass already visited.\n const translatedInto = new Map<string, Set<string>>();\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.schema}workTranslation`),\n null,\n null,\n )) {\n const target = languageOf.get(q.object.value);\n if (target === undefined) continue;\n const known = translatedInto.get(q.subject.value);\n if (known) known.add(target);\n else translatedInto.set(q.subject.value, new Set([target]));\n }\n\n const localization: LocalizationReport = {\n unlabelled: docIris.length - languageOf.size,\n // `entries()`, not `keys()` and a lookup: the docs come out of the map\n // with the tag they are keyed by, so there is nothing left to assert.\n languages: [...byLanguage.entries()]\n .sort(([a], [b]) => byCodeUnit(a, b))\n .map(([language, docsIn]) => {\n const untranslated = sources\n .filter((s) => languageOf.get(s) !== language)\n .filter((s) => !translatedInto.get(s)?.has(language))\n .map((s) => pathOf.get(s) ?? s)\n .sort(byCodeUnit);\n return {\n language,\n docs: docsIn.length,\n coverage: coverageOver(docsIn, COVERAGE_FIELDS),\n untranslated,\n };\n }),\n };\n\n // A uniform --coverage-threshold overrides the resolved config map. Bind it\n // to a local first so the null-narrowing survives the .map() closure.\n const uniform = opts.coverageThreshold;\n const thresholds =\n uniform != null\n ? Object.fromEntries(coverage.map((c) => [c.field, uniform]))\n : config.stats.coverageThreshold;\n // One read of the threshold, which is both the \"is this field gated\" test\n // and the value the finding reports — where `in` plus two lookups needed an\n // assertion to say they were the same fact.\n const coverageFindings = coverage.flatMap((c) => {\n const threshold = thresholds[c.field];\n if (threshold === undefined) return [];\n const pct = total === 0 ? 100 : (c.docs / total) * 100;\n return pct < threshold ? [{ field: c.field, pct: c.pct, threshold }] : [];\n });\n\n const failed =\n !!opts.check &&\n (brokenLinks.length > 0 ||\n brokenSectionRefs.length > 0 ||\n coverageFindings.length > 0);\n\n return {\n triples: store.size,\n docs: docIris.length,\n // countQuads avoids materializing + sorting arrays used only for counting.\n sections: store.countQuads(\n null,\n DataFactory.namedNode(RDF_TYPE),\n DataFactory.namedNode(`${NS.graph}Section`),\n null,\n ),\n concepts: store.countQuads(\n null,\n DataFactory.namedNode(RDF_TYPE),\n DataFactory.namedNode(`${NS.skos}Concept`),\n null,\n ),\n references: refQuads.length,\n orphans,\n brokenLinks,\n brokenSectionRefs,\n mostConnected,\n coverage,\n sectionCoverage,\n localization,\n coverageFindings,\n exitCode: failed ? 1 : 0,\n };\n}\n\nexport function renderStats(\n report: StatsReport,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") {\n const { exitCode: _exitCode, ...rest } = report;\n return JSON.stringify(rest, null, 2);\n }\n const lines = [\n `Triples: ${report.triples}`,\n `Documents: ${report.docs}`,\n `Sections: ${report.sections}`,\n `Concepts: ${report.concepts}`,\n `References: ${report.references}`,\n ];\n lines.push(\"\", \"Most connected:\");\n if (report.mostConnected.length === 0) lines.push(\" (none)\");\n for (const { doc, degree } of report.mostConnected) {\n lines.push(` ${doc} (${degree})`);\n }\n lines.push(\"\", `Orphan docs (${report.orphans.length}):`);\n for (const orphan of report.orphans) lines.push(` ${orphan}`);\n if (report.orphans.length === 0) lines.push(\" (none)\");\n lines.push(\"\", `Broken internal links (${report.brokenLinks.length}):`);\n for (const { doc, target } of report.brokenLinks) {\n lines.push(` ${doc} -> ${target}`);\n }\n if (report.brokenLinks.length === 0) lines.push(\" (none)\");\n\n lines.push(\"\", `Broken section refs (${report.brokenSectionRefs.length}):`);\n for (const { doc, slug } of report.brokenSectionRefs) {\n lines.push(` ${doc} -> #${slug}`);\n }\n if (report.brokenSectionRefs.length === 0) lines.push(\" (none)\");\n\n const belowThreshold = new Set(report.coverageFindings.map((f) => f.field));\n const width = Math.max(\n ...report.coverage.map((c) => c.field.length),\n ...report.sectionCoverage.map((c) => c.field.length),\n );\n lines.push(\"\", \"Coverage (documents):\");\n for (const { field, docs, pct } of report.coverage) {\n const flag = belowThreshold.has(field) ? \" ! below threshold\" : \"\";\n lines.push(\n ` ${field.padEnd(width)} ${docs}/${report.docs} ${pct.toFixed(1)}%${flag}`,\n );\n }\n\n // Sections are explicit-only (ADR 01013), so this block is reported and not\n // gated — a corpus that has not started on section metadata should not fail.\n lines.push(\"\", \"Coverage (sections, not gated):\");\n if (report.sections === 0) {\n // The vacuous-100% convention exists to stop an empty graph tripping a\n // gate. This block gates nothing, so printing \"0/0 100.0%\" on a corpus with\n // no sections would just assert the opposite of the truth.\n lines.push(\" (no sections in this graph)\");\n } else {\n for (const { field, docs, pct } of report.sectionCoverage) {\n lines.push(\n ` ${field.padEnd(width)} ${docs}/${report.sections} ${pct.toFixed(1)}%`,\n );\n }\n }\n\n // Omitted entirely on a corpus that declares no language, rather than\n // printed empty: a block that says nothing on most corpora teaches readers to\n // skip the report (the failure ADR 01029 recorded for always-zero rows).\n if (report.localization.languages.length > 0) {\n const tagWidth = Math.max(\n ...report.localization.languages.map((l) => l.language.length),\n );\n lines.push(\"\", \"Localization:\");\n for (const { language, docs, untranslated } of report.localization\n .languages) {\n const plural = docs === 1 ? \"doc\" : \"docs\";\n const backlog =\n untranslated.length === 0\n ? \"\"\n : ` ${untranslated.length} untranslated`;\n lines.push(` ${language.padEnd(tagWidth)} ${docs} ${plural}${backlog}`);\n }\n lines.push(` no language: ${report.localization.unlabelled}`);\n }\n return lines.join(\"\\n\");\n}\n","/**\n * `manni graph traverse` — node-centric graph walking from the CLI (ADR 01018).\n *\n * A thin Node wrapper over the browser-native runtime: it reads the built\n * Turtle, hands the quads to the same `GraphIndex` a browser would build from\n * `graph.jsonld`, and runs the same walker. `query` stays triple-pattern;\n * `traverse` answers \"what is connected to this node, and why\".\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 { resolve } from \"node:path\";\nimport { loadRunConfig } from \"../core/config.js\";\nimport {\n compactIri,\n expandTerm,\n loadGraph,\n storeToQuads,\n} from \"../core/load.js\";\nimport { SOFTWARE_SUBJECT_IRIS } from \"../core/iirds.js\";\nimport { NS, PREFIXES } from \"../core/vocab.js\";\nimport { GraphError } from \"../types.js\";\nimport { GraphIndex } from \"../runtime/graph.js\";\nimport {\n impact,\n resolveSubject,\n resolveVariant,\n traverse,\n type Direction,\n type TraverseResult,\n} from \"../runtime/traverse.js\";\n\nexport interface TraverseOptions {\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`). */\n graph?: string;\n /** Starting node: full IRI or a `prefix:local` CURIE. */\n node: string;\n depth?: number;\n predicates?: string[];\n /** Walk inbound edges instead of outbound. */\n reverse?: boolean;\n /** Transitive inbound reach — what is affected if this node changes. */\n impact?: boolean;\n /** Scope filter: a product variant IRI, title, or slug. */\n variant?: string;\n /** Scope filter: a software subject. */\n subject?: string;\n /** Scope filter: a BCP-47 language tag, matched in any case (ADR 01037). */\n lang?: string;\n limit?: number;\n cwd?: string;\n}\n\nexport interface TraverseReport {\n /** The resolved starting IRI. */\n node: string;\n nodes: Array<{ iri: string; depth: number; title?: string }>;\n trace: TraverseResult[\"trace\"];\n}\n\nexport function runTraverse(opts: TraverseOptions): TraverseReport {\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 store = loadGraph(resolve(cwd, opts.graph ?? config.out));\n const quads = storeToQuads(store);\n const graph = GraphIndex.fromQuads(quads, Object.fromEntries(PREFIXES));\n\n const node = expandTerm(opts.node);\n if (!graph.has(node)) {\n throw new GraphError(\n `Node not found in the graph: ${opts.node} — check the IRI, or run \\`manni graph build\\` first.`,\n );\n }\n if (opts.variant && !resolveVariant(graph, opts.variant)) {\n throw new GraphError(\n `Unknown product variant: ${opts.variant} — no iirds:ProductVariant matches that IRI, title, or slug.`,\n );\n }\n // An unresolvable scope filter silently disables itself in the walker, which\n // would hand back exactly the nodes the filter was meant to exclude. Fail\n // loudly instead — same contract as --variant above.\n if (opts.subject && !resolveSubject(graph, opts.subject)) {\n throw new GraphError(\n `Unknown software subject: ${opts.subject} — expected one of ` +\n `${Object.keys(SOFTWARE_SUBJECT_IRIS).sort().join(\", \")}, or a full IRI.`,\n );\n }\n\n const predicates = opts.predicates?.map(expandTerm);\n // A misspelt predicate matches no edge, so the walk returns the seed alone\n // and looks like an answer. Same contract as --variant: fail loudly.\n if (predicates && predicates.length > 0) {\n const used = new Set<string>();\n for (const quad of quads) {\n if (quad.o.kind === \"iri\") used.add(quad.p);\n }\n predicates.forEach((predicate, i) => {\n if (!used.has(predicate)) {\n throw new GraphError(\n `Unknown predicate: ${opts.predicates?.[i] ?? predicate}. No edge in the graph uses it.`,\n );\n }\n });\n }\n const direction: Direction = opts.reverse ? \"in\" : \"out\";\n const result = opts.impact\n ? impact(graph, node, {\n depth: opts.depth,\n predicates,\n variant: opts.variant,\n subject: opts.subject,\n language: opts.lang,\n limit: opts.limit,\n })\n : traverse(graph, {\n seeds: [node],\n depth: opts.depth,\n predicates,\n direction,\n variant: opts.variant,\n subject: opts.subject,\n language: opts.lang,\n limit: opts.limit,\n });\n\n return {\n node,\n nodes: result.nodes.map((n) => {\n const title = graph.literal(n.iri, `${NS.dcterms}title`);\n return title === undefined\n ? { iri: n.iri, depth: n.depth }\n : { iri: n.iri, depth: n.depth, title };\n }),\n trace: result.trace,\n };\n}\n\nexport function renderTraverse(\n report: TraverseReport,\n format: \"pretty\" | \"json\",\n): string {\n if (format === \"json\") return JSON.stringify(report, null, 2);\n\n const lines: string[] = [];\n for (const n of report.nodes) {\n const indent = \" \".repeat(n.depth);\n const title = n.title ? ` — ${n.title}` : \"\";\n lines.push(`${indent}${compactIri(n.iri)}${title}`);\n }\n if (report.nodes.length === 0) lines.push(\"(no nodes)\");\n\n if (report.trace.exclusions.length > 0) {\n lines.push(\"\");\n lines.push(\"excluded by scope:\");\n for (const e of report.trace.exclusions) {\n lines.push(\n ` ${compactIri(e.node)} — ${compactIri(e.rule)} ${compactIri(e.value)}`,\n );\n }\n }\n\n lines.push(\"\");\n lines.push(\n `${report.nodes.length} node${report.nodes.length === 1 ? \"\" : \"s\"}, ` +\n `${report.trace.hops.length} hop${report.trace.hops.length === 1 ? \"\" : \"s\"}, ` +\n `${report.trace.exclusions.length} excluded`,\n );\n return lines.join(\"\\n\");\n}\n","/**\n * The deterministic walker (ADR 01018) — breadth-first traversal over a\n * `GraphIndex` with scope filtering, recording every hop and every exclusion\n * into a `QueryTrace`. This is the engine: generic RDF engines return bindings\n * without the path that produced them, and dockg's scope rules (ADR 01014)\n * are domain semantics no general engine knows.\n *\n * Determinism: neighbors come back sorted from the index, the frontier is\n * processed in (depth, IRI) order, and results are emitted in discovery order —\n * so the same graph + query always yields the same nodes *and* the same trace.\n *\n * Platform-neutral: no `node:` imports, no npm dependencies.\n */\nimport { byCodeUnit } from \"../core/sort.js\";\nimport { NS, RDF_TYPE } from \"../core/vocab.js\";\nimport { canonicalLanguageTag } from \"../core/localizations.js\";\nimport {\n GRAPH_NOT_APPLICABLE_TO_VARIANT,\n GRAPH_NOT_SOFTWARE_SUBJECT,\n IIRDS_HAS_SUBJECT,\n IIRDS_RELATES_TO_PRODUCT_VARIANT,\n SOFTWARE_SUBJECT_IRIS,\n} from \"../core/iirds.js\";\nimport type { GraphIndex } from \"./graph.js\";\nimport { createTrace, type QueryTrace, type ScopeExclusion } from \"./trace.js\";\n\nconst DCTERMS_TITLE = `${NS.dcterms}title`;\nconst DCTERMS_REFERENCES = `${NS.dcterms}references`;\nconst DCTERMS_LANGUAGE = `${NS.dcterms}language`;\n\n/** A section IRI's document, or the IRI itself when it has no fragment. */\nfunction documentOf(iri: string): string {\n const hash = iri.indexOf(\"#\");\n return hash === -1 ? iri : iri.slice(0, hash);\n}\n\nexport type Direction = \"out\" | \"in\" | \"both\";\n\nexport interface ScopeFilter {\n /** Product variant: an IRI, a `dcterms:title` (e.g. \"SP-X100\"), or a slug. */\n variant?: string;\n /** Software subject: an IRI or a `graph.about-product-aspect` value (e.g. \"architecture\"). */\n subject?: string;\n /**\n * BCP-47 tag (ADR 01037). Matched against `dcterms:language` after both are\n * canonicalized, since tags are case-insensitive. There is no fallback:\n * `de-AT` is not `de`, because relatedness between locales is an inference\n * and this runtime does not infer.\n */\n language?: string;\n}\n\nexport interface TraverseOptions extends ScopeFilter {\n /** Starting nodes (IRIs). */\n seeds: string[];\n /** Maximum hops from a seed. Default 1. */\n depth?: number;\n /** Restrict to these predicates (full IRIs). Default: every predicate. */\n predicates?: string[];\n /** Which edge directions to follow. Default \"out\". */\n direction?: Direction;\n /** Stop after this many nodes (seeds included). */\n limit?: number;\n /**\n * Follow `rdf:type` edges into class nodes. Default false, deliberately:\n * class nodes are schema, not content, and every document shares them — so\n * traversing them makes every document reachable from every other in two\n * hops (`a → graph:Document → b`). That is exactly the edge contamination\n * graph-governed retrieval exists to avoid. A `predicates` list that names\n * `rdf:type` follows them too, because it asked for them by name.\n */\n includeTypeEdges?: boolean;\n /** Append to an existing trace instead of starting a new one. */\n trace?: QueryTrace;\n}\n\nexport interface TraversedNode {\n iri: string;\n /** Hops from the nearest seed; seeds are 0. */\n depth: number;\n}\n\nexport interface TraverseResult {\n nodes: TraversedNode[];\n trace: QueryTrace;\n}\n\n/**\n * Resolve a variant input to its IRI: an exact node IRI, a `dcterms:title`\n * match on an `iirds:ProductVariant`, or a trailing-segment slug match.\n */\nexport function resolveVariant(\n graph: GraphIndex,\n input: string,\n): string | undefined {\n if (graph.has(input)) return input;\n const wanted = input.toLowerCase();\n const variants = graph.instancesOf(`${NS.iirds}ProductVariant`);\n for (const v of variants) {\n if (graph.literal(v, DCTERMS_TITLE)?.toLowerCase() === wanted) return v;\n }\n for (const v of variants) {\n if (v.slice(v.lastIndexOf(\"/\") + 1).toLowerCase() === wanted) return v;\n }\n return undefined;\n}\n\n/** Resolve a software-subject input to its iiRDS IRI. */\nexport function resolveSubject(\n graph: GraphIndex,\n input: string,\n): string | undefined {\n const mapped = SOFTWARE_SUBJECT_IRIS[input.toLowerCase()];\n if (mapped) return mapped;\n const expanded = graph.expand(input);\n return expanded.startsWith(\"http\") ? expanded : undefined;\n}\n\n/**\n * Decide whether a node survives the scope filter, and if not, why.\n *\n * Rules, in the spirit of ADR 01014 (absence of a positive claim is not a\n * negative claim, so both polarities are explicit):\n * - An explicit negative (`graph:notApplicableToVariant` /\n * `graph:notSoftwareSubject`) naming the target **excludes** the node.\n * - A node that declares a positive set which omits the target is **excluded**\n * — it scoped itself elsewhere — recorded under the positive predicate so\n * the trace distinguishes this from an explicit negative.\n * - A node that makes no claim is **kept**: unscoped content applies broadly.\n */\nexport function scopeExclusion(\n graph: GraphIndex,\n iri: string,\n scope: { variantIri?: string; subjectIri?: string; language?: string },\n): ScopeExclusion | undefined {\n // [target, positive predicate, negative predicate, object kind]. Language\n // joins the same table with two differences, both deliberate: its objects are\n // literals, and it has **no negative predicate** — a document has one\n // language (`sh:maxCount 1`), so \"not in German\" is not a claim an author\n // makes and there is nothing for a `graph:not*` term to express (ADR 01037).\n const checks: Array<\n [string | undefined, string, string | undefined, \"iri\" | \"literal\"]\n > = [\n [\n scope.variantIri,\n IIRDS_RELATES_TO_PRODUCT_VARIANT,\n GRAPH_NOT_APPLICABLE_TO_VARIANT,\n \"iri\",\n ],\n [scope.subjectIri, IIRDS_HAS_SUBJECT, GRAPH_NOT_SOFTWARE_SUBJECT, \"iri\"],\n [scope.language, DCTERMS_LANGUAGE, undefined, \"literal\"],\n ];\n for (const [target, positive, negative, kind] of checks) {\n if (!target) continue;\n if (negative !== undefined) {\n const denied = graph\n .values(iri, negative)\n .some((v) => v.kind === kind && v.value === target);\n if (denied) return { node: iri, rule: negative, value: target };\n }\n\n // Language is the one dimension a section inherits. Applicability is\n // explicit-only by ADR 01013 — a section may legitimately scope itself\n // differently from its document — but a section's *text* is in its\n // document's language and cannot differ, and the per-locale indexes file it\n // that way (`partitionByLanguage`). Without this a link with an anchor\n // reaches a section directly (derive.ts mints section IRIs as\n // `dcterms:references` targets) and carries English prose past a `de`\n // filter that excluded the document it belongs to.\n const subject = positive === DCTERMS_LANGUAGE ? documentOf(iri) : iri;\n const claimed = graph.values(subject, positive);\n if (claimed.length > 0) {\n const matches = claimed.some(\n (v) => v.kind === kind && v.value === target,\n );\n if (!matches) return { node: iri, rule: positive, value: target };\n }\n }\n return undefined;\n}\n\n/** Breadth-first traversal with scope filtering and full trace recording. */\nexport function traverse(\n graph: GraphIndex,\n options: TraverseOptions,\n): TraverseResult {\n const trace = options.trace ?? createTrace();\n const maxDepth = options.depth ?? 1;\n const direction: Direction = options.direction ?? \"out\";\n const allowed =\n options.predicates && options.predicates.length > 0\n ? new Set(options.predicates.map((p) => graph.expand(p)))\n : undefined;\n\n const variantIri = options.variant\n ? resolveVariant(graph, options.variant)\n : undefined;\n const subjectIri = options.subject\n ? resolveSubject(graph, options.subject)\n : undefined;\n // Language needs no resolution step, only a spelling: the filter value and\n // the graph value are both BCP-47 tags, and `derive` writes the canonical one.\n const language =\n options.language === undefined\n ? undefined\n : canonicalLanguageTag(options.language);\n const scope = { variantIri, subjectIri, language };\n // A predicate list that names `rdf:type` asked for type edges. Dropping them\n // anyway answered a question nobody asked, with an empty result.\n const followTypes =\n options.includeTypeEdges === true || allowed?.has(RDF_TYPE) === true;\n\n const excluded = new Set<string>();\n const keep = (iri: string): boolean => {\n if (excluded.has(iri)) return false;\n const exclusion = scopeExclusion(graph, iri, scope);\n if (exclusion) {\n excluded.add(iri);\n trace.exclusions.push(exclusion);\n return false;\n }\n return true;\n };\n\n const nodes: TraversedNode[] = [];\n const seen = new Set<string>();\n let frontier: string[] = [];\n\n // A seed `findEntry` already recorded keeps its real provenance. Re-recording\n // it as `explicit`/1 would leave the trace answering \"why did retrieval start\n // here?\" twice, with the lexical/vector score contradicted by a flat 1.\n const alreadySeeded = new Set(trace.entry.map((e) => e.iri));\n\n for (const seed of [...options.seeds].sort(byCodeUnit)) {\n if (!graph.has(seed) || seen.has(seed)) continue;\n seen.add(seed);\n if (!alreadySeeded.has(seed)) {\n trace.entry.push({ iri: seed, score: 1, via: \"explicit\" });\n }\n // A seed always expands, even when the scope filter excludes it. The\n // filter governs what the walk *reaches*, not where the caller chose to\n // start — and the canonical query is exactly this shape: from an English\n // page, `--impact --lang de` asks what German content a change here\n // affects. Gating the seed made that return nothing at all, because the\n // seed excluded itself before the frontier was ever populated.\n //\n // It is still kept out of the results and recorded in the trace, so the\n // answer honors the filter even though the walk started outside it.\n if (keep(seed)) nodes.push({ iri: seed, depth: 0 });\n frontier.push(seed);\n }\n\n const limit = options.limit ?? Infinity;\n for (let depth = 1; depth <= maxDepth && frontier.length > 0; depth++) {\n const next: string[] = [];\n for (const from of frontier) {\n if (nodes.length >= limit) break;\n for (const { predicate, target, dir } of neighbors(\n graph,\n from,\n direction,\n )) {\n if (allowed && !allowed.has(predicate)) continue;\n if (!followTypes && predicate === RDF_TYPE) continue;\n // The hop is recorded before filtering: the trace shows the edge was\n // walked even when the target is then scope-excluded.\n trace.hops.push({ from, predicate, to: target, depth, direction: dir });\n if (seen.has(target)) continue;\n seen.add(target);\n if (!keep(target)) continue;\n if (nodes.length >= limit) break;\n nodes.push({ iri: target, depth });\n next.push(target);\n }\n }\n frontier = next;\n }\n\n return { nodes, trace };\n}\n\nfunction neighbors(\n graph: GraphIndex,\n iri: string,\n direction: Direction,\n): Array<{ predicate: string; target: string; dir: \"out\" | \"in\" }> {\n const out: Array<{ predicate: string; target: string; dir: \"out\" | \"in\" }> =\n [];\n if (direction === \"out\" || direction === \"both\") {\n for (const e of graph.out(iri)) out.push({ ...e, dir: \"out\" });\n }\n if (direction === \"in\" || direction === \"both\") {\n for (const e of graph.in(iri)) out.push({ ...e, dir: \"in\" });\n }\n return out;\n}\n\n/** Who links to this node (one hop inbound over `dcterms:references`). */\nexport function reverseReferences(\n graph: GraphIndex,\n iri: string,\n options: Omit<TraverseOptions, \"seeds\" | \"direction\" | \"predicates\"> = {},\n): TraverseResult {\n return traverse(graph, {\n ...options,\n seeds: [iri],\n direction: \"in\",\n predicates: [DCTERMS_REFERENCES],\n depth: options.depth ?? 1,\n });\n}\n\n/**\n * Transitive inbound reach — \"what is affected if this node changes\".\n * Excludes the node itself from the returned set. Defaults to depth 3 rather\n * than the walker's 1, because impact analysis is only useful transitively.\n */\nexport function impact(\n graph: GraphIndex,\n iri: string,\n options: Omit<TraverseOptions, \"seeds\" | \"direction\"> = {},\n): TraverseResult {\n const result = traverse(graph, {\n ...options,\n seeds: [iri],\n direction: \"in\",\n depth: options.depth ?? 3,\n // The seed *may* occupy a slot in the walker's limit, so ask for one more:\n // `limit` means \"this many *affected* nodes\". Whether it actually takes\n // one depends on the scope filter — a seed the filter excludes still\n // expands but is not in `nodes` — so the slack is trimmed below rather\n // than assumed spent.\n limit: options.limit === undefined ? undefined : options.limit + 1,\n });\n const affected = result.nodes.filter((n) => n.iri !== iri);\n return {\n nodes:\n options.limit === undefined ? affected : affected.slice(0, options.limit),\n trace: result.trace,\n };\n}\n"],"mappings":"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","names":["readFileSync","resolve","XSD_STRING","iri","entry","XSD_STRING","path","existsSync","resolve","iri","path","slice","GRAPH_DOCUMENT","GRAPH_PATH","GRAPH_LEVEL","DCTERMS_TITLE","path","resolve","existsSync","entry","XSD_STRING","iri","path","resolve","readFileSync","resolve","DataFactory","resolve","DataFactory","readFileSync","writeFileSync","resolve","path","doc","graph","readFileSync","resolve","DataFactory","DataFactory","path","readFileSync","resolve","selectProvider","providerSpecFor","selectProvider","base","resolve","path","readFileSync","own","GRAPH_KEY","entry","writeFileSync","createHash","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","resolve","entry","entry","sha256","createHash","join","existsSync","readFileSync","mkdirSync","writeFileSync","resolve","dirname","createHash","existsSync","readFileSync","dirname","join","resolve","searchIndexDigest","iri","iri","iri","readFileSync","createHash","join","existsSync","resolve","dirname","entry","resolve","DataFactory","DataFactory","iri","resolve","resolve","DCTERMS_TITLE","DCTERMS_LANGUAGE","iri","resolve"]}