@remnic/core 10.0.37 → 10.0.38

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 (245) hide show
  1. package/dist/access-admin-ops-surface.js +24 -24
  2. package/dist/access-authorization-probe.js +25 -25
  3. package/dist/access-boundary.js +24 -24
  4. package/dist/access-cli.js +71 -71
  5. package/dist/access-extraction-force-flush.js +24 -24
  6. package/dist/access-http-briefing.js +25 -25
  7. package/dist/access-http-query.js +26 -26
  8. package/dist/access-http.js +41 -41
  9. package/dist/access-identity-continuity-surface.js +24 -24
  10. package/dist/access-lcm-surface.js +24 -24
  11. package/dist/access-mcp.js +34 -34
  12. package/dist/access-namespace-preflight.js +24 -24
  13. package/dist/access-observe-write-surface.js +24 -24
  14. package/dist/access-operations-batch.js +25 -25
  15. package/dist/access-operations.js +32 -32
  16. package/dist/access-recall-concurrency.js +24 -24
  17. package/dist/access-recall-diagnostics.js +2 -2
  18. package/dist/access-recall-response.js +24 -24
  19. package/dist/access-recall-surface.js +24 -24
  20. package/dist/access-service.js +24 -24
  21. package/dist/access-surface-catalog.js +26 -26
  22. package/dist/active-recall.js +5 -5
  23. package/dist/{auto-sync-R3XGJL5I.js → auto-sync-432USQDH.js} +4 -4
  24. package/dist/briefing.js +5 -5
  25. package/dist/buffer.js +3 -3
  26. package/dist/calibration.js +1 -1
  27. package/dist/causal-consolidation.js +6 -6
  28. package/dist/{chunk-FL6SLVAJ.js → chunk-2AKIVSHP.js} +2 -2
  29. package/dist/{chunk-G6PPA4TH.js → chunk-3AODCBKX.js} +2 -2
  30. package/dist/{chunk-MGXFJOUR.js → chunk-3K5IEJTK.js} +2 -2
  31. package/dist/{chunk-YGYT7S3G.js → chunk-3PLAL2KP.js} +15 -1
  32. package/dist/chunk-3PLAL2KP.js.map +1 -0
  33. package/dist/{chunk-WADPRAZE.js → chunk-3XVBGGF3.js} +2 -2
  34. package/dist/{chunk-BPBUUGAO.js → chunk-4B37KNMP.js} +2 -2
  35. package/dist/{chunk-2RJO7VS4.js → chunk-4IZ6AC2U.js} +2 -2
  36. package/dist/{chunk-RBC4GIZU.js → chunk-53BLBDV6.js} +2 -2
  37. package/dist/{chunk-5UWP5X3T.js → chunk-5ANUG4JZ.js} +2 -2
  38. package/dist/{chunk-Y6Y3TRBN.js → chunk-5DCS4C4S.js} +2 -2
  39. package/dist/{chunk-MH3LC7KB.js → chunk-5K23NQRI.js} +2 -2
  40. package/dist/{chunk-UMFBHYPW.js → chunk-5UPOKIFP.js} +8 -8
  41. package/dist/{chunk-U4JXQCJ3.js → chunk-63YPKHAU.js} +2 -2
  42. package/dist/{chunk-S53WZWGL.js → chunk-6DTIYAAN.js} +2 -2
  43. package/dist/{chunk-RWWYBE7E.js → chunk-6F5BGIAF.js} +2 -2
  44. package/dist/{chunk-Z5AQZRHF.js → chunk-6JEEY42N.js} +2 -2
  45. package/dist/{chunk-HKEK27M4.js → chunk-6SYS5YX3.js} +2 -2
  46. package/dist/{chunk-CCYXCT4B.js → chunk-7HXZOWTR.js} +2 -2
  47. package/dist/{chunk-DGBWPSM6.js → chunk-7VFNGQ4V.js} +2 -2
  48. package/dist/{chunk-ARFT6ZBE.js → chunk-7ZRRJ6RG.js} +2 -2
  49. package/dist/{chunk-GMMZ45C4.js → chunk-AVVCPA7U.js} +6 -8
  50. package/dist/chunk-AVVCPA7U.js.map +1 -0
  51. package/dist/{chunk-LSSCMZQ2.js → chunk-AYBAC2N4.js} +3 -3
  52. package/dist/{chunk-EVVCE7S2.js → chunk-C2KOW2UQ.js} +2 -2
  53. package/dist/{chunk-GCVUBVEN.js → chunk-CVMAOPAH.js} +8 -8
  54. package/dist/{chunk-D2AKUKAQ.js → chunk-DG4H56SK.js} +1 -1
  55. package/dist/{chunk-BQ6DGL6A.js → chunk-DKHX2FHI.js} +2 -2
  56. package/dist/{chunk-HRT2SJPC.js → chunk-E3NBMTTX.js} +2 -2
  57. package/dist/{chunk-V5RJCXLG.js → chunk-EGNONTVT.js} +5 -5
  58. package/dist/{chunk-7PG7QBWD.js → chunk-FGEY2AGV.js} +2 -2
  59. package/dist/{chunk-O6YJI5VX.js → chunk-FKTMWDN2.js} +2 -2
  60. package/dist/{chunk-QIC7YZ3D.js → chunk-FQFMLOAC.js} +12 -12
  61. package/dist/{chunk-ID2PLENW.js → chunk-GGI6FLO6.js} +2 -2
  62. package/dist/{chunk-KC5SVCUJ.js → chunk-I75BWXRZ.js} +2 -2
  63. package/dist/{chunk-ULUX6Q7R.js → chunk-J7G656MY.js} +3 -3
  64. package/dist/{chunk-VKTP3TZB.js → chunk-JF3MEIHO.js} +2 -2
  65. package/dist/{chunk-A23DPFFI.js → chunk-JIA435P3.js} +2 -2
  66. package/dist/{chunk-USOXPN5H.js → chunk-KOAVX2IT.js} +2 -2
  67. package/dist/{chunk-Z5QWUR3Y.js → chunk-L7PGPH4E.js} +2 -2
  68. package/dist/{chunk-5U3NUHMA.js → chunk-LOMSBYNS.js} +33 -33
  69. package/dist/{chunk-FO5AFCRI.js → chunk-MCPSMWUC.js} +4 -4
  70. package/dist/{chunk-64IO6ZEE.js → chunk-MZWHIAOL.js} +2 -2
  71. package/dist/{chunk-LDXS746V.js → chunk-N7DVBHU3.js} +3 -3
  72. package/dist/{chunk-WSLNC5AL.js → chunk-NH6GZEQN.js} +3 -3
  73. package/dist/{chunk-3L5WH6CV.js → chunk-OKKBOTRA.js} +2 -2
  74. package/dist/{chunk-MBMT5FUQ.js → chunk-OLH4XCLU.js} +2 -2
  75. package/dist/{chunk-UXXVOA4D.js → chunk-OLHN4ZNT.js} +2 -2
  76. package/dist/{chunk-LRJKHXU4.js → chunk-POGPI5GR.js} +2 -2
  77. package/dist/{chunk-RVYXSS3Q.js → chunk-QO5KDQGG.js} +3 -3
  78. package/dist/{chunk-7ZBANI3M.js → chunk-QOUKZ2N3.js} +2 -2
  79. package/dist/{chunk-HIMXDRSQ.js → chunk-RGKXF4W3.js} +2 -2
  80. package/dist/{chunk-CNQQNYJ2.js → chunk-RWRHGE75.js} +2 -2
  81. package/dist/{chunk-6R6CU3MR.js → chunk-SWZOAQUM.js} +22 -22
  82. package/dist/{chunk-FBAHBFT5.js → chunk-SZPPCEYT.js} +2 -2
  83. package/dist/{chunk-QEGE5QCL.js → chunk-TAEJ2MRR.js} +19 -19
  84. package/dist/{chunk-BBDASWNT.js → chunk-TJ5YGCPV.js} +81 -76
  85. package/dist/chunk-TJ5YGCPV.js.map +1 -0
  86. package/dist/{chunk-G2SRB62M.js → chunk-TXP7Q7T5.js} +2 -2
  87. package/dist/{chunk-NSQSOLCE.js → chunk-TYLNWE4D.js} +2 -2
  88. package/dist/{chunk-A6PKEU7T.js → chunk-UFM3PJDT.js} +1 -1
  89. package/dist/chunk-UFM3PJDT.js.map +1 -0
  90. package/dist/{chunk-MNDHKZZQ.js → chunk-VC3X7XP3.js} +2 -2
  91. package/dist/{chunk-PTRPOJ7U.js → chunk-VGRM43X6.js} +2 -2
  92. package/dist/{chunk-DK5VMJL3.js → chunk-VSSQIBVU.js} +2 -2
  93. package/dist/{chunk-R6TCM47S.js → chunk-WCBLPKG3.js} +3 -3
  94. package/dist/{chunk-UQWA5QDT.js → chunk-WCIDCJOQ.js} +2 -2
  95. package/dist/{chunk-UFBIOF7C.js → chunk-WEK3OUGO.js} +2 -2
  96. package/dist/{chunk-5EILJ6W2.js → chunk-WXPBDEMW.js} +2 -2
  97. package/dist/{chunk-CU7WDDPV.js → chunk-X247CYL6.js} +3 -3
  98. package/dist/{chunk-JWTUJVIF.js → chunk-XHVO3CGX.js} +2 -2
  99. package/dist/{chunk-3BPMYMPX.js → chunk-XHX67LX6.js} +2 -2
  100. package/dist/{chunk-LAQS5HYU.js → chunk-Y5ZHZKZD.js} +2 -2
  101. package/dist/{chunk-L46Y5FPE.js → chunk-YYGZ4EIY.js} +2 -2
  102. package/dist/{chunk-NQOM6PHO.js → chunk-ZAP7BKTZ.js} +3 -3
  103. package/dist/cli.js +54 -54
  104. package/dist/coding/export-okf-codegraph.js +4 -4
  105. package/dist/compounding/engine.js +6 -6
  106. package/dist/config.d.ts.map +1 -1
  107. package/dist/config.js +5 -5
  108. package/dist/connectors/codex-materialize-runner.js +5 -5
  109. package/dist/connectors/index.js +5 -5
  110. package/dist/convergence-refresh.js +7 -7
  111. package/dist/corpus-watermark.js +7 -7
  112. package/dist/deep-recall-policy-llm.js +2 -2
  113. package/dist/entity-retrieval.js +5 -5
  114. package/dist/external-wiki-access.js +25 -25
  115. package/dist/extraction-faithfulness.js +2 -2
  116. package/dist/extraction-judge.d.ts +42 -2
  117. package/dist/extraction-judge.d.ts.map +1 -1
  118. package/dist/extraction-judge.js +12 -2
  119. package/dist/extraction.js +9 -9
  120. package/dist/fallback-llm.d.ts +1 -0
  121. package/dist/fallback-llm.d.ts.map +1 -1
  122. package/dist/fallback-llm.js +1 -1
  123. package/dist/harmonic-retrieval.js +5 -5
  124. package/dist/index.js +71 -71
  125. package/dist/location/index.js +7 -7
  126. package/dist/maintenance/memory-governance.js +5 -5
  127. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -5
  128. package/dist/maintenance/rebuild-memory-projection-runner.js +7 -7
  129. package/dist/maintenance/rebuild-memory-projection.js +6 -6
  130. package/dist/memory-browse-operations.js +25 -25
  131. package/dist/memory-browse.js +3 -3
  132. package/dist/namespaces/migrate.js +6 -6
  133. package/dist/namespaces/storage.js +5 -5
  134. package/dist/operator-doctor-corpus.js +8 -8
  135. package/dist/operator-toolkit.js +14 -14
  136. package/dist/orchestration/maintenance.js +15 -15
  137. package/dist/orchestrator.js +71 -71
  138. package/dist/recall-explain-renderer.js +3 -3
  139. package/dist/recall-navigate-access.js +2 -2
  140. package/dist/recall-navigate-disclosure.js +2 -2
  141. package/dist/recall-navigate.js +2 -2
  142. package/dist/recall-navigation-operations.js +25 -25
  143. package/dist/recall-navigation.js +24 -24
  144. package/dist/recall-planner-llm.js +1 -1
  145. package/dist/recall-state-view-admission.js +3 -3
  146. package/dist/recall-why-service.js +3 -3
  147. package/dist/recall-xray-cli.js +4 -4
  148. package/dist/recall-xray-renderer.js +3 -3
  149. package/dist/recall-xray.js +2 -2
  150. package/dist/resume-bundles.js +6 -6
  151. package/dist/semantic-consolidation.js +6 -6
  152. package/dist/semantic-rule-promotion.js +5 -5
  153. package/dist/semantic-rule-verifier.js +5 -5
  154. package/dist/source-agent-qualifier.js +8 -8
  155. package/dist/standup/build.js +5 -5
  156. package/dist/storage.js +4 -4
  157. package/dist/summarizer.js +2 -2
  158. package/dist/support-passport/index.js +27 -27
  159. package/dist/transfer/export-okf.js +5 -5
  160. package/dist/types.d.ts +12 -0
  161. package/dist/types.d.ts.map +1 -1
  162. package/dist/types.js +1 -1
  163. package/dist/verified-recall.js +5 -5
  164. package/dist/who-knows-cli.js +6 -6
  165. package/dist/who-knows.js +5 -5
  166. package/package.json +2 -2
  167. package/src/config.test.ts +16 -0
  168. package/src/config.ts +14 -0
  169. package/src/extraction-judge-chain.test.ts +298 -2
  170. package/src/extraction-judge.ts +147 -82
  171. package/src/fallback-llm.test.ts +94 -0
  172. package/src/fallback-llm.ts +7 -7
  173. package/src/types.ts +12 -0
  174. package/dist/chunk-A6PKEU7T.js.map +0 -1
  175. package/dist/chunk-BBDASWNT.js.map +0 -1
  176. package/dist/chunk-GMMZ45C4.js.map +0 -1
  177. package/dist/chunk-YGYT7S3G.js.map +0 -1
  178. /package/dist/{auto-sync-R3XGJL5I.js.map → auto-sync-432USQDH.js.map} +0 -0
  179. /package/dist/{chunk-FL6SLVAJ.js.map → chunk-2AKIVSHP.js.map} +0 -0
  180. /package/dist/{chunk-G6PPA4TH.js.map → chunk-3AODCBKX.js.map} +0 -0
  181. /package/dist/{chunk-MGXFJOUR.js.map → chunk-3K5IEJTK.js.map} +0 -0
  182. /package/dist/{chunk-WADPRAZE.js.map → chunk-3XVBGGF3.js.map} +0 -0
  183. /package/dist/{chunk-BPBUUGAO.js.map → chunk-4B37KNMP.js.map} +0 -0
  184. /package/dist/{chunk-2RJO7VS4.js.map → chunk-4IZ6AC2U.js.map} +0 -0
  185. /package/dist/{chunk-RBC4GIZU.js.map → chunk-53BLBDV6.js.map} +0 -0
  186. /package/dist/{chunk-5UWP5X3T.js.map → chunk-5ANUG4JZ.js.map} +0 -0
  187. /package/dist/{chunk-Y6Y3TRBN.js.map → chunk-5DCS4C4S.js.map} +0 -0
  188. /package/dist/{chunk-MH3LC7KB.js.map → chunk-5K23NQRI.js.map} +0 -0
  189. /package/dist/{chunk-UMFBHYPW.js.map → chunk-5UPOKIFP.js.map} +0 -0
  190. /package/dist/{chunk-U4JXQCJ3.js.map → chunk-63YPKHAU.js.map} +0 -0
  191. /package/dist/{chunk-S53WZWGL.js.map → chunk-6DTIYAAN.js.map} +0 -0
  192. /package/dist/{chunk-RWWYBE7E.js.map → chunk-6F5BGIAF.js.map} +0 -0
  193. /package/dist/{chunk-Z5AQZRHF.js.map → chunk-6JEEY42N.js.map} +0 -0
  194. /package/dist/{chunk-HKEK27M4.js.map → chunk-6SYS5YX3.js.map} +0 -0
  195. /package/dist/{chunk-CCYXCT4B.js.map → chunk-7HXZOWTR.js.map} +0 -0
  196. /package/dist/{chunk-DGBWPSM6.js.map → chunk-7VFNGQ4V.js.map} +0 -0
  197. /package/dist/{chunk-ARFT6ZBE.js.map → chunk-7ZRRJ6RG.js.map} +0 -0
  198. /package/dist/{chunk-LSSCMZQ2.js.map → chunk-AYBAC2N4.js.map} +0 -0
  199. /package/dist/{chunk-EVVCE7S2.js.map → chunk-C2KOW2UQ.js.map} +0 -0
  200. /package/dist/{chunk-GCVUBVEN.js.map → chunk-CVMAOPAH.js.map} +0 -0
  201. /package/dist/{chunk-D2AKUKAQ.js.map → chunk-DG4H56SK.js.map} +0 -0
  202. /package/dist/{chunk-BQ6DGL6A.js.map → chunk-DKHX2FHI.js.map} +0 -0
  203. /package/dist/{chunk-HRT2SJPC.js.map → chunk-E3NBMTTX.js.map} +0 -0
  204. /package/dist/{chunk-V5RJCXLG.js.map → chunk-EGNONTVT.js.map} +0 -0
  205. /package/dist/{chunk-7PG7QBWD.js.map → chunk-FGEY2AGV.js.map} +0 -0
  206. /package/dist/{chunk-O6YJI5VX.js.map → chunk-FKTMWDN2.js.map} +0 -0
  207. /package/dist/{chunk-QIC7YZ3D.js.map → chunk-FQFMLOAC.js.map} +0 -0
  208. /package/dist/{chunk-ID2PLENW.js.map → chunk-GGI6FLO6.js.map} +0 -0
  209. /package/dist/{chunk-KC5SVCUJ.js.map → chunk-I75BWXRZ.js.map} +0 -0
  210. /package/dist/{chunk-ULUX6Q7R.js.map → chunk-J7G656MY.js.map} +0 -0
  211. /package/dist/{chunk-VKTP3TZB.js.map → chunk-JF3MEIHO.js.map} +0 -0
  212. /package/dist/{chunk-A23DPFFI.js.map → chunk-JIA435P3.js.map} +0 -0
  213. /package/dist/{chunk-USOXPN5H.js.map → chunk-KOAVX2IT.js.map} +0 -0
  214. /package/dist/{chunk-Z5QWUR3Y.js.map → chunk-L7PGPH4E.js.map} +0 -0
  215. /package/dist/{chunk-5U3NUHMA.js.map → chunk-LOMSBYNS.js.map} +0 -0
  216. /package/dist/{chunk-FO5AFCRI.js.map → chunk-MCPSMWUC.js.map} +0 -0
  217. /package/dist/{chunk-64IO6ZEE.js.map → chunk-MZWHIAOL.js.map} +0 -0
  218. /package/dist/{chunk-LDXS746V.js.map → chunk-N7DVBHU3.js.map} +0 -0
  219. /package/dist/{chunk-WSLNC5AL.js.map → chunk-NH6GZEQN.js.map} +0 -0
  220. /package/dist/{chunk-3L5WH6CV.js.map → chunk-OKKBOTRA.js.map} +0 -0
  221. /package/dist/{chunk-MBMT5FUQ.js.map → chunk-OLH4XCLU.js.map} +0 -0
  222. /package/dist/{chunk-UXXVOA4D.js.map → chunk-OLHN4ZNT.js.map} +0 -0
  223. /package/dist/{chunk-LRJKHXU4.js.map → chunk-POGPI5GR.js.map} +0 -0
  224. /package/dist/{chunk-RVYXSS3Q.js.map → chunk-QO5KDQGG.js.map} +0 -0
  225. /package/dist/{chunk-7ZBANI3M.js.map → chunk-QOUKZ2N3.js.map} +0 -0
  226. /package/dist/{chunk-HIMXDRSQ.js.map → chunk-RGKXF4W3.js.map} +0 -0
  227. /package/dist/{chunk-CNQQNYJ2.js.map → chunk-RWRHGE75.js.map} +0 -0
  228. /package/dist/{chunk-6R6CU3MR.js.map → chunk-SWZOAQUM.js.map} +0 -0
  229. /package/dist/{chunk-FBAHBFT5.js.map → chunk-SZPPCEYT.js.map} +0 -0
  230. /package/dist/{chunk-QEGE5QCL.js.map → chunk-TAEJ2MRR.js.map} +0 -0
  231. /package/dist/{chunk-G2SRB62M.js.map → chunk-TXP7Q7T5.js.map} +0 -0
  232. /package/dist/{chunk-NSQSOLCE.js.map → chunk-TYLNWE4D.js.map} +0 -0
  233. /package/dist/{chunk-MNDHKZZQ.js.map → chunk-VC3X7XP3.js.map} +0 -0
  234. /package/dist/{chunk-PTRPOJ7U.js.map → chunk-VGRM43X6.js.map} +0 -0
  235. /package/dist/{chunk-DK5VMJL3.js.map → chunk-VSSQIBVU.js.map} +0 -0
  236. /package/dist/{chunk-R6TCM47S.js.map → chunk-WCBLPKG3.js.map} +0 -0
  237. /package/dist/{chunk-UQWA5QDT.js.map → chunk-WCIDCJOQ.js.map} +0 -0
  238. /package/dist/{chunk-UFBIOF7C.js.map → chunk-WEK3OUGO.js.map} +0 -0
  239. /package/dist/{chunk-5EILJ6W2.js.map → chunk-WXPBDEMW.js.map} +0 -0
  240. /package/dist/{chunk-CU7WDDPV.js.map → chunk-X247CYL6.js.map} +0 -0
  241. /package/dist/{chunk-JWTUJVIF.js.map → chunk-XHVO3CGX.js.map} +0 -0
  242. /package/dist/{chunk-3BPMYMPX.js.map → chunk-XHX67LX6.js.map} +0 -0
  243. /package/dist/{chunk-LAQS5HYU.js.map → chunk-Y5ZHZKZD.js.map} +0 -0
  244. /package/dist/{chunk-L46Y5FPE.js.map → chunk-YYGZ4EIY.js.map} +0 -0
  245. /package/dist/{chunk-NQOM6PHO.js.map → chunk-ZAP7BKTZ.js.map} +0 -0
package/dist/who-knows.js CHANGED
@@ -9,8 +9,8 @@ import {
9
9
  loadWhoKnowsEntities,
10
10
  tokenizeTopic,
11
11
  validateWhoKnowsInput
12
- } from "./chunk-DK5VMJL3.js";
13
- import "./chunk-R6TCM47S.js";
12
+ } from "./chunk-VSSQIBVU.js";
13
+ import "./chunk-WCBLPKG3.js";
14
14
  import "./chunk-UHVXE24Y.js";
15
15
  import "./chunk-DM5QZ3YU.js";
16
16
  import "./chunk-VY6BD5KB.js";
@@ -37,7 +37,7 @@ import "./chunk-S2HLHAZ4.js";
37
37
  import "./chunk-DM2T26WE.js";
38
38
  import "./chunk-LDXUBPMO.js";
39
39
  import "./chunk-FF6N7BXC.js";
40
- import "./chunk-5EILJ6W2.js";
40
+ import "./chunk-WXPBDEMW.js";
41
41
  import "./chunk-AAD2ZS6P.js";
42
42
  import "./chunk-YQ6SLFNZ.js";
43
43
  import "./chunk-ZIKENA2C.js";
@@ -64,7 +64,7 @@ import "./chunk-OR42ZI54.js";
64
64
  import "./chunk-23G5P7TA.js";
65
65
  import "./chunk-C64XATK7.js";
66
66
  import "./chunk-42JKGUFJ.js";
67
- import "./chunk-GMMZ45C4.js";
67
+ import "./chunk-AVVCPA7U.js";
68
68
  import "./chunk-I55KAVET.js";
69
69
  import "./chunk-L2EXJQJP.js";
70
70
  import "./chunk-45GF7Y3V.js";
@@ -77,7 +77,7 @@ import "./chunk-YCVB7X56.js";
77
77
  import "./chunk-PQVCH2AE.js";
78
78
  import "./chunk-PJKTFXE2.js";
79
79
  import "./chunk-W5BIQOAJ.js";
80
- import "./chunk-A6PKEU7T.js";
80
+ import "./chunk-UFM3PJDT.js";
81
81
  import "./chunk-YBA52OKG.js";
82
82
  import "./chunk-TDCR6PQL.js";
83
83
  import "./chunk-BT7NVCML.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "10.0.37",
3
+ "version": "10.0.38",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3347,7 +3347,7 @@
3347
3347
  "core"
3348
3348
  ],
3349
3349
  "peerDependencies": {
3350
- "@remnic/coding-graph": "^10.0.37"
3350
+ "@remnic/coding-graph": "^10.0.38"
3351
3351
  },
3352
3352
  "peerDependenciesMeta": {
3353
3353
  "@remnic/coding-graph": {
@@ -1060,6 +1060,22 @@ test("parseConfig localLlmTimeoutMs clamps invalid values to a positive timeout"
1060
1060
  assert.equal(parseConfig({ localLlmTimeoutMs: Number.NaN }).localLlmTimeoutMs, 180_000);
1061
1061
  });
1062
1062
 
1063
+ test("parseConfig extractionJudgeTimeoutMs defaults to 20000 — compact verdict measures 2.1-2.5 s on a small fast judge model", () => {
1064
+ assert.equal(parseConfig({}).extractionJudgeTimeoutMs, 20_000);
1065
+ });
1066
+
1067
+ test("parseConfig extractionJudgeTimeoutMs accepts numbers and CLI-style numeric strings", () => {
1068
+ assert.equal(parseConfig({ extractionJudgeTimeoutMs: 45_000 }).extractionJudgeTimeoutMs, 45_000);
1069
+ assert.equal(parseConfig({ extractionJudgeTimeoutMs: "90000" }).extractionJudgeTimeoutMs, 90_000);
1070
+ });
1071
+
1072
+ test("parseConfig extractionJudgeTimeoutMs falls back to the default on unusable values and caps the top", () => {
1073
+ for (const value of [0, -1, Number.NaN, "abc"]) {
1074
+ assert.equal(parseConfig({ extractionJudgeTimeoutMs: value }).extractionJudgeTimeoutMs, 20_000);
1075
+ }
1076
+ assert.equal(parseConfig({ extractionJudgeTimeoutMs: 10_000_000 }).extractionJudgeTimeoutMs, 3_600_000);
1077
+ });
1078
+
1063
1079
  test("parseConfig validates localLlmMaxContext as a usable context window", () => {
1064
1080
  assert.equal(parseConfig({ localLlmMaxContext: 4096 }).localLlmMaxContext, 4096);
1065
1081
  assert.equal(parseConfig({ localLlmMaxContext: "8192" }).localLlmMaxContext, 8192);
package/src/config.ts CHANGED
@@ -2731,6 +2731,20 @@ export function parseConfig(
2731
2731
  typeof cfg.extractionJudgeBatchSize === "number" && Number.isFinite(cfg.extractionJudgeBatchSize)
2732
2732
  ? Math.max(1, Math.round(cfg.extractionJudgeBatchSize))
2733
2733
  : 20,
2734
+ // Judge LLM timeout (issue #376 follow-up, Studio 2026-10-29; tightened in
2735
+ // PR 3264): the judge requests a compact verdict with a batch-scaled
2736
+ // completion budget (24 tokens per candidate, up to 2048). Measured
2737
+ // 2.1-2.5 s per call on a small fast judge
2738
+ // model; the big shared core model measured 13-22 s per compact call,
2739
+ // 41 s verbose. The 20s default assumes the fast model, stays fail-open
2740
+ // on timeout, and needs a raise if extractionJudgeModel points at the
2741
+ // slow core model. Non-positive / unusable values fall back to the
2742
+ // default rather than a 1ms timeout that would silently disable judging.
2743
+ extractionJudgeTimeoutMs: ((): number => {
2744
+ const coerced = coerceNumber(cfg.extractionJudgeTimeoutMs);
2745
+ if (coerced === undefined || coerced < 1) return 20_000;
2746
+ return Math.min(3_600_000, Math.floor(coerced));
2747
+ })(),
2734
2748
  extractionJudgeShadow: cfg.extractionJudgeShadow === true,
2735
2749
  // Defer cap (issue #562 PR 2): max re-deferrals for the same candidate
2736
2750
  // text before the verdict is forcibly converted to reject.
@@ -2,8 +2,11 @@ import assert from "node:assert/strict";
2
2
  import test from "node:test";
3
3
 
4
4
  import { parseConfig } from "./config.js";
5
- import { judgeFactDurability } from "./extraction-judge.js";
6
- import type { FallbackLlmClient } from "./fallback-llm.js";
5
+ import { judgeFactDurability, JUDGE_SYSTEM_PROMPT, judgeMaxTokens, MAX_JUDGE_BATCH, MAX_JUDGE_TOKENS } from "./extraction-judge.js";
6
+ import { FallbackLlmClient } from "./fallback-llm.js";
7
+ import type { FallbackLlmOptions, FallbackLlmResponse } from "./fallback-llm.js";
8
+ import { LocalLlmClient } from "./local-llm.js";
9
+ import type { LocalLlmChatCompletionOptions, LocalLlmChatCompletionResult } from "./local-llm-helpers.js";
7
10
 
8
11
  // Regression for cursor review on #1425: the extraction judge must route gateway
9
12
  // fallback calls through the SAME precedence as ExtractionEngine.withGatewayAgent
@@ -53,3 +56,296 @@ test("judge falls back to gatewayAgentId when no taskModelChain is set", async (
53
56
  assert.equal(captured[0]?.agentId, "persona-agent");
54
57
  assert.equal(captured[0]?.modelChain, undefined);
55
58
  });
59
+
60
+ type ChatOptions = LocalLlmChatCompletionOptions;
61
+
62
+ /** A real FallbackLlmClient whose gateway call is replaced: records the options the judge passes. */
63
+ class RecordingFallbackLlm extends FallbackLlmClient {
64
+ constructor(private readonly sink: FallbackLlmOptions[]) {
65
+ super();
66
+ }
67
+
68
+ override isAvailable(): boolean {
69
+ return true;
70
+ }
71
+
72
+ override async chatCompletion(
73
+ _messages: Array<{ role: "system" | "user" | "assistant"; content: string }>,
74
+ options: FallbackLlmOptions = {},
75
+ ): Promise<FallbackLlmResponse | null> {
76
+ this.sink.push(options);
77
+ return { content: JSON.stringify([{ index: 0, durable: true, reason: "ok" }]), modelUsed: "recording-fake" };
78
+ }
79
+ }
80
+
81
+ /** A real LocalLlmClient whose network call is replaced: records the options the judge passes. */
82
+ class RecordingLocalLlm extends LocalLlmClient {
83
+ constructor(
84
+ private readonly sink: ChatOptions[],
85
+ private readonly reply: string,
86
+ ) {
87
+ super(parseConfig({}));
88
+ }
89
+
90
+ override async chatCompletion(
91
+ _messages: Array<{ role: string; content: string }>,
92
+ options: ChatOptions = {},
93
+ ): Promise<LocalLlmChatCompletionResult | null> {
94
+ this.sink.push(options);
95
+ return { content: this.reply };
96
+ }
97
+ }
98
+
99
+ interface ExampleVerdict {
100
+ index?: number;
101
+ kind?: string;
102
+ reason?: string;
103
+ durable?: boolean;
104
+ }
105
+
106
+ // Regression (Studio 2026-10-29): the judge hardcoded timeoutMs: 1500 while the
107
+ // deployed local model needs tens of seconds — 94 straight aborts, 0 completions.
108
+ // The timeout must come from config so operators can set one the model can meet.
109
+
110
+ test("judge forwards the configured timeout to the local LLM call", async () => {
111
+ const config = parseConfig({ extractionJudgeTimeoutMs: 45_000 });
112
+ const captured: ChatOptions[] = [];
113
+ const localLlm = new RecordingLocalLlm(captured, JSON.stringify([{ index: 0, durable: true, reason: "ok" }]));
114
+
115
+ await judgeFactDurability([candidate], config, localLlm, null, new Map(), new Map());
116
+
117
+ assert.equal(captured.length, 1, "judge should call the local LLM once");
118
+ assert.equal(captured[0]?.timeoutMs, 45_000);
119
+ });
120
+
121
+ // ---------------------------------------------------------------------------
122
+ // Compact verdict request (PR 3264 follow-up): the judge asks for a minimal
123
+ // `[{"index":N,"kind":"accept|reject|defer"}]` reply with a batch-scaled
124
+ // completion budget (24 tokens per candidate, up to 2048) instead of a flat 2048. The big budget let
125
+ // a verbose 59-305s reply hide inside the old 150s timeout; the compact one
126
+ // measures 2.1-2.5 s per call on a small fast judge model (13-22 s, 41 s
127
+ // verbose on the big shared core model), inside the 20s default.
128
+ // ---------------------------------------------------------------------------
129
+
130
+ function captureLocal(captured: ChatOptions[], content?: string): LocalLlmClient {
131
+ return new RecordingLocalLlm(captured, content ?? JSON.stringify([{ index: 0, kind: "reject" }]));
132
+ }
133
+
134
+ const EIGHT_CANDIDATES = Array.from({ length: 8 }, (_, i) => ({
135
+ text: `sample candidate fact ${i}`,
136
+ category: "preference",
137
+ confidence: 0.5,
138
+ }));
139
+
140
+ test("judge uses a compact completion budget scaled to the batch size", async () => {
141
+ const config = parseConfig({});
142
+ const captured: ChatOptions[] = [];
143
+
144
+ await judgeFactDurability(EIGHT_CANDIDATES, config, captureLocal(captured), null, new Map(), new Map());
145
+
146
+ assert.equal(captured.length, 1, "judge should call the local LLM once");
147
+ assert.equal(captured[0]?.maxTokens, judgeMaxTokens(8));
148
+ assert.ok(
149
+ (captured[0]?.maxTokens ?? Number.POSITIVE_INFINITY) <= judgeMaxTokens(8),
150
+ `completion budget must stay small, got ${captured[0]?.maxTokens}`,
151
+ );
152
+ });
153
+
154
+ test("judgeMaxTokens leaves room for one verdict per candidate, up to a cap", () => {
155
+ assert.equal(judgeMaxTokens(1), 64);
156
+ assert.equal(judgeMaxTokens(8), 192);
157
+ assert.ok(judgeMaxTokens(50) >= 50 * 16, "a 50-candidate batch needs a verdict array that fits");
158
+ assert.equal(judgeMaxTokens(500), 2048, "cap");
159
+ });
160
+
161
+ test("judge bounds the whole local call, retries included, with one deadline signal", async () => {
162
+ const config = parseConfig({ extractionJudgeTimeoutMs: 45_000 });
163
+ const captured: ChatOptions[] = [];
164
+
165
+ await judgeFactDurability([candidate], config, captureLocal(captured), null, new Map(), new Map());
166
+
167
+ assert.ok(captured[0]?.signal instanceof AbortSignal, "judge passes an AbortSignal so retries share one deadline");
168
+ assert.equal(captured[0]?.signal?.aborted, false);
169
+ });
170
+
171
+
172
+ test("system prompt requests the compact verdict shape only", () => {
173
+ const lines = JUDGE_SYSTEM_PROMPT.split("\n");
174
+ const exampleIdx = lines.findIndex((l) => l.trim() === "Example output:");
175
+ assert.ok(exampleIdx >= 0, "prompt must contain an 'Example output:' line");
176
+ // SAFETY: the line is the example JSON checked into the prompt text this test pins.
177
+ const example = JSON.parse(lines[exampleIdx + 1].trim()) as { verdicts?: ExampleVerdict[] };
178
+ assert.ok(
179
+ Array.isArray(example.verdicts) && example.verdicts.length > 0,
180
+ 'example must use the {"verdicts":[...]} wrapper — response_format json_object rejects a bare top-level array',
181
+ );
182
+ for (const item of example.verdicts) {
183
+ assert.ok(Number.isInteger(item.index), "example index must be an integer");
184
+ assert.ok(
185
+ item.kind === "accept" || item.kind === "reject" || item.kind === "defer",
186
+ `example kind must be a parser-accepted verdict, got ${item.kind}`,
187
+ );
188
+ assert.equal(item.reason, undefined, "compact request must not ask for reasons");
189
+ assert.equal(item.durable, undefined, "compact request must not ask for the durable flag");
190
+ }
191
+ });
192
+
193
+ test("judge still accepts the legacy verbose verdict shape", async () => {
194
+ const config = parseConfig({});
195
+ const captured: ChatOptions[] = [];
196
+ const llm = captureLocal(
197
+ captured,
198
+ JSON.stringify([
199
+ { index: 0, kind: "accept", durable: true, reason: "Stable preference" },
200
+ { index: 1, durable: false, reason: "Ephemeral build status" },
201
+ { index: 2, kind: "defer", durable: false, reason: "Ambiguous pronoun" },
202
+ ]),
203
+ );
204
+ const candidates = [
205
+ { text: "user prefers dark mode", category: "preference", confidence: 0.5 },
206
+ { text: "the build is running now", category: "task", confidence: 0.5 },
207
+ { text: "he said they'd follow up", category: "task", confidence: 0.5 },
208
+ ];
209
+
210
+ const result = await judgeFactDurability(candidates, config, llm, null, new Map(), new Map());
211
+
212
+ assert.deepEqual(
213
+ { ...result.verdicts.get(0) },
214
+ { durable: true, reason: "Stable preference", kind: "accept" },
215
+ );
216
+ assert.deepEqual(
217
+ { ...result.verdicts.get(1) },
218
+ { durable: false, reason: "Ephemeral build status" },
219
+ );
220
+ assert.deepEqual(
221
+ { ...result.verdicts.get(2) },
222
+ { durable: false, reason: "Ambiguous pronoun", kind: "defer" },
223
+ );
224
+ });
225
+
226
+ test("judge parses the {\"verdicts\":[...]} wrapper object the prompt requests", async () => {
227
+ const config = parseConfig({});
228
+ const captured: ChatOptions[] = [];
229
+ const llm = captureLocal(
230
+ captured,
231
+ JSON.stringify({
232
+ verdicts: [
233
+ { index: 0, kind: "accept" },
234
+ { index: 1, kind: "reject" },
235
+ ],
236
+ }),
237
+ );
238
+ const candidates = [
239
+ { text: "user prefers dark mode", category: "preference", confidence: 0.5 },
240
+ { text: "the build is running now", category: "task", confidence: 0.5 },
241
+ ];
242
+
243
+ const result = await judgeFactDurability(candidates, config, llm, null, new Map(), new Map());
244
+
245
+ assert.equal(result.judged, 2, "both verdicts must resolve from the wrapper");
246
+ assert.equal(result.verdicts.get(0)?.kind, "accept");
247
+ assert.equal(result.verdicts.get(1)?.kind, "reject");
248
+ });
249
+
250
+ test("judge still parses the compact bare-array shape", async () => {
251
+ const config = parseConfig({});
252
+ const captured: ChatOptions[] = [];
253
+ const llm = captureLocal(
254
+ captured,
255
+ JSON.stringify([
256
+ { index: 0, kind: "reject" },
257
+ { index: 1, kind: "accept" },
258
+ ]),
259
+ );
260
+ const candidates = [
261
+ { text: "the build is running now", category: "task", confidence: 0.5 },
262
+ { text: "user prefers dark mode", category: "preference", confidence: 0.5 },
263
+ ];
264
+
265
+ const result = await judgeFactDurability(candidates, config, llm, null, new Map(), new Map());
266
+
267
+ assert.equal(result.judged, 2, "both verdicts must resolve from the bare array");
268
+ assert.equal(result.verdicts.get(0)?.kind, "reject");
269
+ assert.equal(result.verdicts.get(1)?.kind, "accept");
270
+ });
271
+
272
+ test("judge treats a single verdict object as one verdict at its index, not the whole batch", async () => {
273
+ const config = parseConfig({});
274
+ const captured: ChatOptions[] = [];
275
+ const llm = captureLocal(captured, JSON.stringify({ index: 1, kind: "reject" }));
276
+ const candidates = [
277
+ { text: "user prefers dark mode", category: "preference", confidence: 0.5 },
278
+ { text: "the build is running now", category: "task", confidence: 0.5 },
279
+ { text: "he said they'd follow up", category: "task", confidence: 0.5 },
280
+ ];
281
+
282
+ const result = await judgeFactDurability(candidates, config, llm, null, new Map(), new Map());
283
+
284
+ assert.equal(result.judged, 1, "only the indexed candidate comes from the LLM");
285
+ assert.equal(result.verdicts.get(1)?.kind, "reject");
286
+ assert.equal(result.verdicts.get(1)?.durable, false);
287
+ assert.equal(result.verdicts.get(0)?.kind, undefined, "index 0 must not inherit the reject");
288
+ assert.equal(result.verdicts.get(0)?.durable, true, "index 0 fail-open approves");
289
+ assert.equal(result.verdicts.get(2)?.kind, undefined, "index 2 must not inherit the reject");
290
+ assert.equal(result.verdicts.get(2)?.durable, true, "index 2 fail-open approves");
291
+ });
292
+
293
+ // ---------------------------------------------------------------------------
294
+ // Judge model override: extractionJudgeModel must reach the LLM call options
295
+ // (options.model) on both the local and fallback paths, and stay absent when
296
+ // unset so routing keeps the default model.
297
+ // ---------------------------------------------------------------------------
298
+
299
+ test("judge forwards extractionJudgeModel to the local LLM options", async () => {
300
+ const config = parseConfig({ extractionJudgeModel: "qwen3.8-27b-64k-nothink" });
301
+ const captured: ChatOptions[] = [];
302
+
303
+ await judgeFactDurability([candidate], config, captureLocal(captured), null, new Map(), new Map());
304
+
305
+ assert.equal(captured[0]?.model, "qwen3.8-27b-64k-nothink");
306
+ });
307
+
308
+ test("judge omits model from local LLM options when extractionJudgeModel is unset", async () => {
309
+ const config = parseConfig({});
310
+ const captured: ChatOptions[] = [];
311
+
312
+ await judgeFactDurability([candidate], config, captureLocal(captured), null, new Map(), new Map());
313
+
314
+ assert.equal(captured[0]?.model, undefined);
315
+ });
316
+
317
+ test("judge forwards extractionJudgeModel to the fallback LLM options in gateway mode", async () => {
318
+ const config = parseConfig({ modelSource: "gateway", extractionJudgeModel: "fast-judge" });
319
+ const captured: FallbackLlmOptions[] = [];
320
+
321
+ await judgeFactDurability([candidate], config, null, new RecordingFallbackLlm(captured), new Map(), new Map());
322
+
323
+ assert.equal(captured[0]?.model, "fast-judge");
324
+ });
325
+
326
+ test("judge defaults to a 20s timeout when none is configured", async () => {
327
+ const config = parseConfig({});
328
+ const captured: FallbackLlmOptions[] = [];
329
+
330
+ await judgeFactDurability([candidate], config, null, new RecordingFallbackLlm(captured), new Map(), new Map());
331
+
332
+ assert.equal(captured[0]?.timeoutMs, 20_000);
333
+ });
334
+
335
+ test("a configured batch size above what the token cap can answer is split", async () => {
336
+ const config = parseConfig({ extractionJudgeBatchSize: 200 });
337
+ const captured: ChatOptions[] = [];
338
+ const candidates = Array.from({ length: 200 }, (_, i) => ({
339
+ text: `distinct candidate fact number ${i}`,
340
+ category: "preference",
341
+ confidence: 0.5,
342
+ }));
343
+
344
+ await judgeFactDurability(candidates, config, captureLocal(captured), null, new Map(), new Map());
345
+
346
+ assert.equal(captured.length, 3, "200 candidates at 85 per request");
347
+ for (const call of captured) {
348
+ assert.ok((call.maxTokens ?? 0) <= MAX_JUDGE_TOKENS, "never above the cap");
349
+ }
350
+ assert.equal(MAX_JUDGE_BATCH * 24 <= MAX_JUDGE_TOKENS, true, "a full batch fits its own budget");
351
+ });