@remnic/core 10.0.39 → 10.0.40

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 (190) hide show
  1. package/dist/access-admin-ops-surface.js +12 -12
  2. package/dist/access-authorization-probe.js +13 -13
  3. package/dist/access-boundary.js +12 -12
  4. package/dist/access-cli.js +50 -50
  5. package/dist/access-extraction-force-flush.js +12 -12
  6. package/dist/access-http-briefing.js +13 -13
  7. package/dist/access-http-query.js +14 -14
  8. package/dist/access-http.js +28 -28
  9. package/dist/access-identity-continuity-surface.js +12 -12
  10. package/dist/access-lcm-surface.js +12 -12
  11. package/dist/access-mcp.js +21 -21
  12. package/dist/access-namespace-preflight.js +12 -12
  13. package/dist/access-observe-write-surface.js +12 -12
  14. package/dist/access-operations-batch.js +13 -13
  15. package/dist/access-operations.js +20 -20
  16. package/dist/access-recall-concurrency.js +12 -12
  17. package/dist/access-recall-response.js +12 -12
  18. package/dist/access-recall-surface.js +12 -12
  19. package/dist/access-service.d.ts +2 -2
  20. package/dist/access-service.d.ts.map +1 -1
  21. package/dist/access-service.js +12 -12
  22. package/dist/access-surface-catalog.js +14 -14
  23. package/dist/active-recall.js +2 -2
  24. package/dist/briefing.js +3 -3
  25. package/dist/causal-consolidation.js +4 -4
  26. package/dist/{chunk-NJ2DZYEK.js → chunk-2T6KEOUL.js} +2 -2
  27. package/dist/{chunk-BUKZ7MTN.js → chunk-5TRU6QQC.js} +2 -2
  28. package/dist/{chunk-SRPGA6WN.js → chunk-7BCYAJKP.js} +2 -2
  29. package/dist/{chunk-JRTKYFFY.js → chunk-AY6LO7GD.js} +2 -2
  30. package/dist/{chunk-5KZNWERU.js → chunk-BIYVUPC6.js} +19 -3
  31. package/dist/{chunk-5KZNWERU.js.map → chunk-BIYVUPC6.js.map} +1 -1
  32. package/dist/{chunk-V2XMG7GM.js → chunk-CHNZPOWX.js} +3 -2
  33. package/dist/{chunk-V2XMG7GM.js.map → chunk-CHNZPOWX.js.map} +1 -1
  34. package/dist/{chunk-GPVGAHXL.js → chunk-CNAL35D5.js} +2 -2
  35. package/dist/{chunk-CR72WZ3M.js → chunk-EPEDMEHO.js} +4 -4
  36. package/dist/{chunk-CR72WZ3M.js.map → chunk-EPEDMEHO.js.map} +1 -1
  37. package/dist/{chunk-U66CTIF5.js → chunk-F2RDRE7M.js} +2 -2
  38. package/dist/{chunk-B7VKRCAG.js → chunk-FNEYSTB6.js} +2 -2
  39. package/dist/{chunk-GSBSGT43.js → chunk-FPHU6KVI.js} +2 -2
  40. package/dist/{chunk-RO2NNWR5.js → chunk-GAUS4XGN.js} +3 -3
  41. package/dist/{chunk-4HJ2QK32.js → chunk-GDOI4U4D.js} +2 -2
  42. package/dist/{chunk-IZRNMXZC.js → chunk-GRN4BVPM.js} +2 -2
  43. package/dist/{chunk-VCOCOBUS.js → chunk-GZMHBRIR.js} +3 -3
  44. package/dist/{chunk-TTQYX7VU.js → chunk-HN35OH2C.js} +2 -2
  45. package/dist/{chunk-F2IU6A2L.js → chunk-HSNV4CSW.js} +16 -16
  46. package/dist/{chunk-EKR6OO4P.js → chunk-I7CWAJHX.js} +2 -2
  47. package/dist/{chunk-LJXBFVI2.js → chunk-ICTJOOWZ.js} +2 -2
  48. package/dist/{chunk-SJHFU52W.js → chunk-IF6EG22P.js} +5 -5
  49. package/dist/chunk-IF6EG22P.js.map +1 -0
  50. package/dist/{chunk-IAOW2L6K.js → chunk-IJJWM2ZA.js} +2 -2
  51. package/dist/{chunk-6Z2ZWBOV.js → chunk-IWDFHVPJ.js} +2 -2
  52. package/dist/{chunk-GCW7UT5I.js → chunk-JJSMSS45.js} +2 -2
  53. package/dist/{chunk-O2O4FDAH.js → chunk-JXQTECMU.js} +2 -2
  54. package/dist/{chunk-PJRKLB4Z.js → chunk-L5PM7B3I.js} +16 -2
  55. package/dist/{chunk-PJRKLB4Z.js.map → chunk-L5PM7B3I.js.map} +1 -1
  56. package/dist/{chunk-ZXFKG7VZ.js → chunk-LB6HIXQC.js} +2 -2
  57. package/dist/{chunk-B3I2QQU7.js → chunk-LWIU5BMA.js} +3 -3
  58. package/dist/{chunk-WQYS47G4.js → chunk-N3PUGD7E.js} +2 -2
  59. package/dist/{chunk-JORSMFL6.js → chunk-NBEM5QEH.js} +5 -5
  60. package/dist/{chunk-VIS23B6O.js → chunk-NFJWB27H.js} +14 -12
  61. package/dist/chunk-NFJWB27H.js.map +1 -0
  62. package/dist/{chunk-JQCP5QW3.js → chunk-O67H7OXJ.js} +2 -2
  63. package/dist/{chunk-4LLV2N3R.js → chunk-ONIVKGNC.js} +2 -2
  64. package/dist/{chunk-WT2VVYBM.js → chunk-PJXSBXEC.js} +2 -2
  65. package/dist/{chunk-ANV373S5.js → chunk-PW63SXFM.js} +2 -2
  66. package/dist/{chunk-RIAKNXZB.js → chunk-Q77SLBWT.js} +3 -3
  67. package/dist/{chunk-7IANFJ24.js → chunk-QFD7OANX.js} +15 -15
  68. package/dist/chunk-QFD7OANX.js.map +1 -0
  69. package/dist/{chunk-22YJQTPN.js → chunk-QGNZ5QPV.js} +2 -2
  70. package/dist/{chunk-GE5ZNDLE.js → chunk-R42VUN5V.js} +3 -3
  71. package/dist/{chunk-MD3W2H3G.js → chunk-RPHCSMTQ.js} +31 -31
  72. package/dist/{chunk-MD3W2H3G.js.map → chunk-RPHCSMTQ.js.map} +1 -1
  73. package/dist/{chunk-LPD6I2U6.js → chunk-SLVR3U4E.js} +2 -2
  74. package/dist/{chunk-JZFJZLJY.js → chunk-UGV256H3.js} +2 -2
  75. package/dist/{chunk-L74NWAD4.js → chunk-UKIIAEJF.js} +2 -2
  76. package/dist/{chunk-5Q6CR65T.js → chunk-VTZSIG6O.js} +2 -2
  77. package/dist/{chunk-4UT2NUAC.js → chunk-WJMAWDAU.js} +2 -2
  78. package/dist/{chunk-JT3IXJIL.js → chunk-XBHUMPIQ.js} +7 -7
  79. package/dist/{chunk-JM6U3SAE.js → chunk-XJ77IOAD.js} +2 -2
  80. package/dist/{chunk-RWW5KPIY.js → chunk-XLUMO5H2.js} +12 -12
  81. package/dist/chunk-XLUMO5H2.js.map +1 -0
  82. package/dist/{chunk-ODJ2HRFW.js → chunk-XXBCUIYQ.js} +7 -7
  83. package/dist/{chunk-JOOGPZJE.js → chunk-XXW3P3RX.js} +2 -2
  84. package/dist/{chunk-P3YUEPSQ.js → chunk-Y473XFTD.js} +2 -2
  85. package/dist/cli.js +38 -38
  86. package/dist/coding/export-okf-codegraph.js +2 -2
  87. package/dist/compounding/engine.js +4 -4
  88. package/dist/config.js +2 -2
  89. package/dist/connectors/codex-materialize-runner.js +3 -3
  90. package/dist/connectors/index.js +3 -3
  91. package/dist/convergence-refresh.js +5 -5
  92. package/dist/corpus-watermark.js +5 -5
  93. package/dist/entity-retrieval.js +3 -3
  94. package/dist/external-wiki-access.js +13 -13
  95. package/dist/extraction-error-classification.d.ts +15 -0
  96. package/dist/extraction-error-classification.d.ts.map +1 -1
  97. package/dist/extraction-error-classification.js +7 -3
  98. package/dist/extraction.js +5 -5
  99. package/dist/harmonic-retrieval.js +3 -3
  100. package/dist/index.js +50 -50
  101. package/dist/location/index.js +5 -5
  102. package/dist/maintenance/memory-governance.js +3 -3
  103. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  104. package/dist/maintenance/rebuild-memory-projection-runner.js +5 -5
  105. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  106. package/dist/memory-browse-operations.js +13 -13
  107. package/dist/namespaces/migrate.js +4 -4
  108. package/dist/namespaces/search.d.ts +1 -0
  109. package/dist/namespaces/search.d.ts.map +1 -1
  110. package/dist/namespaces/search.js +5 -3
  111. package/dist/namespaces/storage.js +3 -3
  112. package/dist/operator-doctor-corpus.js +6 -6
  113. package/dist/operator-toolkit.js +11 -11
  114. package/dist/orchestration/maintenance.js +13 -13
  115. package/dist/orchestration/qmd-result-resolver.d.ts +5 -0
  116. package/dist/orchestration/qmd-result-resolver.d.ts.map +1 -1
  117. package/dist/orchestration/recall-search-pipeline.d.ts.map +1 -1
  118. package/dist/orchestrator.js +50 -50
  119. package/dist/recall-navigation-operations.js +13 -13
  120. package/dist/recall-navigation.js +12 -12
  121. package/dist/resume-bundles.js +2 -2
  122. package/dist/semantic-consolidation.js +4 -4
  123. package/dist/semantic-rule-promotion.js +3 -3
  124. package/dist/semantic-rule-verifier.js +3 -3
  125. package/dist/source-agent-qualifier.js +3 -3
  126. package/dist/standup/build.js +3 -3
  127. package/dist/storage.js +2 -2
  128. package/dist/support-passport/index.js +15 -15
  129. package/dist/transfer/export-okf.js +3 -3
  130. package/dist/verified-recall.js +3 -3
  131. package/dist/who-knows-cli.js +4 -4
  132. package/dist/who-knows.js +3 -3
  133. package/package.json +2 -2
  134. package/src/access-entity-principal.test.ts +190 -0
  135. package/src/access-http.ts +2 -2
  136. package/src/access-operations-batch.ts +2 -2
  137. package/src/access-service.ts +7 -6
  138. package/src/chat/chat-executor.ts +1 -1
  139. package/src/extraction-error-classification.ts +23 -0
  140. package/src/extraction-local-failure-class.test.ts +55 -0
  141. package/src/extraction.ts +9 -9
  142. package/src/namespaces/search.ts +1 -1
  143. package/src/orchestration/extraction-run.test.ts +83 -2
  144. package/src/orchestration/qmd-result-resolver.ts +26 -1
  145. package/src/orchestration/recall-search-pipeline.ts +11 -12
  146. package/dist/chunk-7IANFJ24.js.map +0 -1
  147. package/dist/chunk-RWW5KPIY.js.map +0 -1
  148. package/dist/chunk-SJHFU52W.js.map +0 -1
  149. package/dist/chunk-VIS23B6O.js.map +0 -1
  150. /package/dist/{chunk-NJ2DZYEK.js.map → chunk-2T6KEOUL.js.map} +0 -0
  151. /package/dist/{chunk-BUKZ7MTN.js.map → chunk-5TRU6QQC.js.map} +0 -0
  152. /package/dist/{chunk-SRPGA6WN.js.map → chunk-7BCYAJKP.js.map} +0 -0
  153. /package/dist/{chunk-JRTKYFFY.js.map → chunk-AY6LO7GD.js.map} +0 -0
  154. /package/dist/{chunk-GPVGAHXL.js.map → chunk-CNAL35D5.js.map} +0 -0
  155. /package/dist/{chunk-U66CTIF5.js.map → chunk-F2RDRE7M.js.map} +0 -0
  156. /package/dist/{chunk-B7VKRCAG.js.map → chunk-FNEYSTB6.js.map} +0 -0
  157. /package/dist/{chunk-GSBSGT43.js.map → chunk-FPHU6KVI.js.map} +0 -0
  158. /package/dist/{chunk-RO2NNWR5.js.map → chunk-GAUS4XGN.js.map} +0 -0
  159. /package/dist/{chunk-4HJ2QK32.js.map → chunk-GDOI4U4D.js.map} +0 -0
  160. /package/dist/{chunk-IZRNMXZC.js.map → chunk-GRN4BVPM.js.map} +0 -0
  161. /package/dist/{chunk-VCOCOBUS.js.map → chunk-GZMHBRIR.js.map} +0 -0
  162. /package/dist/{chunk-TTQYX7VU.js.map → chunk-HN35OH2C.js.map} +0 -0
  163. /package/dist/{chunk-F2IU6A2L.js.map → chunk-HSNV4CSW.js.map} +0 -0
  164. /package/dist/{chunk-EKR6OO4P.js.map → chunk-I7CWAJHX.js.map} +0 -0
  165. /package/dist/{chunk-LJXBFVI2.js.map → chunk-ICTJOOWZ.js.map} +0 -0
  166. /package/dist/{chunk-IAOW2L6K.js.map → chunk-IJJWM2ZA.js.map} +0 -0
  167. /package/dist/{chunk-6Z2ZWBOV.js.map → chunk-IWDFHVPJ.js.map} +0 -0
  168. /package/dist/{chunk-GCW7UT5I.js.map → chunk-JJSMSS45.js.map} +0 -0
  169. /package/dist/{chunk-O2O4FDAH.js.map → chunk-JXQTECMU.js.map} +0 -0
  170. /package/dist/{chunk-ZXFKG7VZ.js.map → chunk-LB6HIXQC.js.map} +0 -0
  171. /package/dist/{chunk-B3I2QQU7.js.map → chunk-LWIU5BMA.js.map} +0 -0
  172. /package/dist/{chunk-WQYS47G4.js.map → chunk-N3PUGD7E.js.map} +0 -0
  173. /package/dist/{chunk-JORSMFL6.js.map → chunk-NBEM5QEH.js.map} +0 -0
  174. /package/dist/{chunk-JQCP5QW3.js.map → chunk-O67H7OXJ.js.map} +0 -0
  175. /package/dist/{chunk-4LLV2N3R.js.map → chunk-ONIVKGNC.js.map} +0 -0
  176. /package/dist/{chunk-WT2VVYBM.js.map → chunk-PJXSBXEC.js.map} +0 -0
  177. /package/dist/{chunk-ANV373S5.js.map → chunk-PW63SXFM.js.map} +0 -0
  178. /package/dist/{chunk-RIAKNXZB.js.map → chunk-Q77SLBWT.js.map} +0 -0
  179. /package/dist/{chunk-22YJQTPN.js.map → chunk-QGNZ5QPV.js.map} +0 -0
  180. /package/dist/{chunk-GE5ZNDLE.js.map → chunk-R42VUN5V.js.map} +0 -0
  181. /package/dist/{chunk-LPD6I2U6.js.map → chunk-SLVR3U4E.js.map} +0 -0
  182. /package/dist/{chunk-JZFJZLJY.js.map → chunk-UGV256H3.js.map} +0 -0
  183. /package/dist/{chunk-L74NWAD4.js.map → chunk-UKIIAEJF.js.map} +0 -0
  184. /package/dist/{chunk-5Q6CR65T.js.map → chunk-VTZSIG6O.js.map} +0 -0
  185. /package/dist/{chunk-4UT2NUAC.js.map → chunk-WJMAWDAU.js.map} +0 -0
  186. /package/dist/{chunk-JT3IXJIL.js.map → chunk-XBHUMPIQ.js.map} +0 -0
  187. /package/dist/{chunk-JM6U3SAE.js.map → chunk-XJ77IOAD.js.map} +0 -0
  188. /package/dist/{chunk-ODJ2HRFW.js.map → chunk-XXBCUIYQ.js.map} +0 -0
  189. /package/dist/{chunk-JOOGPZJE.js.map → chunk-XXW3P3RX.js.map} +0 -0
  190. /package/dist/{chunk-P3YUEPSQ.js.map → chunk-Y473XFTD.js.map} +0 -0
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  promoteSemanticRuleFromMemory,
3
3
  setSemanticRulePromotionTestHooks
4
- } from "./chunk-4LLV2N3R.js";
5
- import "./chunk-5KZNWERU.js";
4
+ } from "./chunk-ONIVKGNC.js";
5
+ import "./chunk-BIYVUPC6.js";
6
6
  import "./chunk-UHVXE24Y.js";
7
7
  import "./chunk-DM5QZ3YU.js";
8
8
  import "./chunk-VY6BD5KB.js";
9
9
  import "./chunk-G6OFEGUR.js";
10
- import "./chunk-V2XMG7GM.js";
10
+ import "./chunk-CHNZPOWX.js";
11
11
  import "./chunk-4QLKVZH6.js";
12
12
  import "./chunk-XKDQTDXN.js";
13
13
  import "./chunk-CYEPCZN5.js";
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  compareVerifiedSemanticRuleResults,
3
3
  searchVerifiedSemanticRules
4
- } from "./chunk-U66CTIF5.js";
5
- import "./chunk-5KZNWERU.js";
4
+ } from "./chunk-F2RDRE7M.js";
5
+ import "./chunk-BIYVUPC6.js";
6
6
  import "./chunk-UHVXE24Y.js";
7
7
  import "./chunk-DM5QZ3YU.js";
8
8
  import "./chunk-VY6BD5KB.js";
9
9
  import "./chunk-G6OFEGUR.js";
10
- import "./chunk-V2XMG7GM.js";
10
+ import "./chunk-CHNZPOWX.js";
11
11
  import "./chunk-4QLKVZH6.js";
12
12
  import "./chunk-XKDQTDXN.js";
13
13
  import "./chunk-CYEPCZN5.js";
@@ -12,7 +12,7 @@ import "./chunk-VEWZZM3H.js";
12
12
  import "./chunk-M7KGIW5F.js";
13
13
  import "./chunk-5TJEOU6Y.js";
14
14
  import "./chunk-754XN6LX.js";
15
- import "./chunk-22YJQTPN.js";
15
+ import "./chunk-QGNZ5QPV.js";
16
16
  import "./chunk-3UXOZBHV.js";
17
17
  import "./chunk-AL3TCNSJ.js";
18
18
  import "./chunk-6X3J4NLZ.js";
@@ -27,12 +27,12 @@ import "./chunk-236PXYG7.js";
27
27
  import "./chunk-ZCUTSMR2.js";
28
28
  import "./chunk-QDW3E4RD.js";
29
29
  import "./chunk-ZJP66Q4I.js";
30
- import "./chunk-5KZNWERU.js";
30
+ import "./chunk-BIYVUPC6.js";
31
31
  import "./chunk-UHVXE24Y.js";
32
32
  import "./chunk-DM5QZ3YU.js";
33
33
  import "./chunk-VY6BD5KB.js";
34
34
  import "./chunk-G6OFEGUR.js";
35
- import "./chunk-V2XMG7GM.js";
35
+ import "./chunk-CHNZPOWX.js";
36
36
  import "./chunk-4QLKVZH6.js";
37
37
  import "./chunk-XKDQTDXN.js";
38
38
  import "./chunk-CYEPCZN5.js";
@@ -3,13 +3,13 @@ import {
3
3
  parseStandupDate,
4
4
  previousActiveDate,
5
5
  standupHelp
6
- } from "../chunk-GCW7UT5I.js";
7
- import "../chunk-5KZNWERU.js";
6
+ } from "../chunk-JJSMSS45.js";
7
+ import "../chunk-BIYVUPC6.js";
8
8
  import "../chunk-UHVXE24Y.js";
9
9
  import "../chunk-DM5QZ3YU.js";
10
10
  import "../chunk-VY6BD5KB.js";
11
11
  import "../chunk-G6OFEGUR.js";
12
- import "../chunk-V2XMG7GM.js";
12
+ import "../chunk-CHNZPOWX.js";
13
13
  import "../chunk-4QLKVZH6.js";
14
14
  import "../chunk-XKDQTDXN.js";
15
15
  import "../chunk-CYEPCZN5.js";
package/dist/storage.js CHANGED
@@ -14,12 +14,12 @@ import {
14
14
  parseFrontmatter,
15
15
  parseFrontmatterStringValue,
16
16
  serializeEntityFile
17
- } from "./chunk-5KZNWERU.js";
17
+ } from "./chunk-BIYVUPC6.js";
18
18
  import "./chunk-UHVXE24Y.js";
19
19
  import "./chunk-DM5QZ3YU.js";
20
20
  import "./chunk-VY6BD5KB.js";
21
21
  import "./chunk-G6OFEGUR.js";
22
- import "./chunk-V2XMG7GM.js";
22
+ import "./chunk-CHNZPOWX.js";
23
23
  import "./chunk-4QLKVZH6.js";
24
24
  import "./chunk-XKDQTDXN.js";
25
25
  import "./chunk-CYEPCZN5.js";
@@ -4,7 +4,7 @@ import {
4
4
  SUPPORT_PASSPORT_MODEL_RESULT_PATH,
5
5
  SupportPassportModelBridge,
6
6
  parseSupportPassportModelJob
7
- } from "../chunk-P3YUEPSQ.js";
7
+ } from "../chunk-Y473XFTD.js";
8
8
  import {
9
9
  DEFAULT_SUPPORT_PASSPORT_CONFIG,
10
10
  parseSupportPassportConfig
@@ -14,8 +14,8 @@ import {
14
14
  buildSupportPassportPublicRequestHandler,
15
15
  composeSupportPassportExternalRequestHandlers,
16
16
  normalizeSupportPassportNetworkAddress
17
- } from "../chunk-ZXFKG7VZ.js";
18
- import "../chunk-4UT2NUAC.js";
17
+ } from "../chunk-LB6HIXQC.js";
18
+ import "../chunk-WJMAWDAU.js";
19
19
  import {
20
20
  SUPPORT_PASSPORT_DRAFT_MAX_CONTENT_CHARACTERS,
21
21
  SUPPORT_PASSPORT_DRAFT_MAX_MEMORIES,
@@ -56,7 +56,7 @@ import {
56
56
  notifySupportPassportCommitted,
57
57
  resolveSupportPassportModelRoutePlan,
58
58
  syncDirectoryForDurability
59
- } from "../chunk-7IANFJ24.js";
59
+ } from "../chunk-QFD7OANX.js";
60
60
  import "../chunk-W4F3C7N7.js";
61
61
  import "../chunk-MPC7TYTZ.js";
62
62
  import "../chunk-IJH6METJ.js";
@@ -64,7 +64,7 @@ import "../chunk-IFBSZGW3.js";
64
64
  import "../chunk-OGXXGHW6.js";
65
65
  import "../chunk-VSHWPOUB.js";
66
66
  import "../chunk-VQ7B2Q6M.js";
67
- import "../chunk-WT2VVYBM.js";
67
+ import "../chunk-PJXSBXEC.js";
68
68
  import "../chunk-BANSBRNX.js";
69
69
  import "../chunk-GNVZQ5JN.js";
70
70
  import "../chunk-YN2UN7N3.js";
@@ -87,7 +87,7 @@ import "../chunk-H7XKCNR6.js";
87
87
  import "../chunk-WUL6LDJ4.js";
88
88
  import "../chunk-SOBJ6NEY.js";
89
89
  import "../chunk-VHBGJAYC.js";
90
- import "../chunk-O2O4FDAH.js";
90
+ import "../chunk-JXQTECMU.js";
91
91
  import "../chunk-7XZ7TOLQ.js";
92
92
  import "../chunk-E6UNM67F.js";
93
93
  import "../chunk-Z64TS5V4.js";
@@ -98,7 +98,7 @@ import "../chunk-IISBCCWR.js";
98
98
  import "../chunk-6ITNEPJO.js";
99
99
  import "../chunk-AER3HD3B.js";
100
100
  import "../chunk-2YA5N2BY.js";
101
- import "../chunk-JQCP5QW3.js";
101
+ import "../chunk-O67H7OXJ.js";
102
102
  import "../chunk-HUDPXTXW.js";
103
103
  import "../chunk-AZEZSQ5R.js";
104
104
  import "../chunk-23ZMQONL.js";
@@ -120,12 +120,12 @@ import "../chunk-VZIAVM72.js";
120
120
  import "../chunk-LXATZLSC.js";
121
121
  import "../chunk-E3NBMTTX.js";
122
122
  import "../chunk-RF2SMMPP.js";
123
- import "../chunk-B7VKRCAG.js";
124
- import "../chunk-5Q6CR65T.js";
125
- import "../chunk-RO2NNWR5.js";
126
- import "../chunk-4HJ2QK32.js";
123
+ import "../chunk-FNEYSTB6.js";
124
+ import "../chunk-VTZSIG6O.js";
125
+ import "../chunk-GAUS4XGN.js";
126
+ import "../chunk-GDOI4U4D.js";
127
127
  import "../chunk-UFGFMWAD.js";
128
- import "../chunk-22YJQTPN.js";
128
+ import "../chunk-QGNZ5QPV.js";
129
129
  import "../chunk-3UXOZBHV.js";
130
130
  import "../chunk-AL3TCNSJ.js";
131
131
  import "../chunk-WUBGMV3G.js";
@@ -145,7 +145,7 @@ import "../chunk-5YQXWVCP.js";
145
145
  import "../chunk-QEDLJDHP.js";
146
146
  import "../chunk-U4LUIE6Y.js";
147
147
  import "../chunk-ZY2MNJR6.js";
148
- import "../chunk-JZFJZLJY.js";
148
+ import "../chunk-UGV256H3.js";
149
149
  import "../chunk-GZFKCLRC.js";
150
150
  import "../chunk-FRXS6SC7.js";
151
151
  import "../chunk-KZMRMKC7.js";
@@ -169,12 +169,12 @@ import "../chunk-ZCUTSMR2.js";
169
169
  import "../chunk-QDW3E4RD.js";
170
170
  import "../chunk-VECRSYQG.js";
171
171
  import "../chunk-ZJP66Q4I.js";
172
- import "../chunk-5KZNWERU.js";
172
+ import "../chunk-BIYVUPC6.js";
173
173
  import "../chunk-UHVXE24Y.js";
174
174
  import "../chunk-DM5QZ3YU.js";
175
175
  import "../chunk-VY6BD5KB.js";
176
176
  import "../chunk-G6OFEGUR.js";
177
- import "../chunk-V2XMG7GM.js";
177
+ import "../chunk-CHNZPOWX.js";
178
178
  import "../chunk-4QLKVZH6.js";
179
179
  import "../chunk-XKDQTDXN.js";
180
180
  import "../chunk-CYEPCZN5.js";
@@ -4,18 +4,18 @@ import {
4
4
  exportOkfBundle,
5
5
  firstHeading,
6
6
  parseIncludeStatus
7
- } from "../chunk-GPVGAHXL.js";
7
+ } from "../chunk-CNAL35D5.js";
8
8
  import {
9
9
  OKF_EXPORT_VERSION
10
10
  } from "../chunk-I7TR2OCU.js";
11
11
  import "../chunk-D24OXEPB.js";
12
12
  import "../chunk-3UXOZBHV.js";
13
- import "../chunk-5KZNWERU.js";
13
+ import "../chunk-BIYVUPC6.js";
14
14
  import "../chunk-UHVXE24Y.js";
15
15
  import "../chunk-DM5QZ3YU.js";
16
16
  import "../chunk-VY6BD5KB.js";
17
17
  import "../chunk-G6OFEGUR.js";
18
- import "../chunk-V2XMG7GM.js";
18
+ import "../chunk-CHNZPOWX.js";
19
19
  import "../chunk-4QLKVZH6.js";
20
20
  import "../chunk-XKDQTDXN.js";
21
21
  import "../chunk-CYEPCZN5.js";
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-JOOGPZJE.js";
4
+ } from "./chunk-XXW3P3RX.js";
5
5
  import "./chunk-B7RWBZXW.js";
6
- import "./chunk-5KZNWERU.js";
6
+ import "./chunk-BIYVUPC6.js";
7
7
  import "./chunk-UHVXE24Y.js";
8
8
  import "./chunk-DM5QZ3YU.js";
9
9
  import "./chunk-VY6BD5KB.js";
10
10
  import "./chunk-G6OFEGUR.js";
11
- import "./chunk-V2XMG7GM.js";
11
+ import "./chunk-CHNZPOWX.js";
12
12
  import "./chunk-4QLKVZH6.js";
13
13
  import "./chunk-XKDQTDXN.js";
14
14
  import "./chunk-CYEPCZN5.js";
@@ -4,14 +4,14 @@ import {
4
4
  renderWhoKnows,
5
5
  renderWhoKnowsJson,
6
6
  renderWhoKnowsText
7
- } from "./chunk-GSBSGT43.js";
8
- import "./chunk-WT2VVYBM.js";
9
- import "./chunk-5KZNWERU.js";
7
+ } from "./chunk-FPHU6KVI.js";
8
+ import "./chunk-PJXSBXEC.js";
9
+ import "./chunk-BIYVUPC6.js";
10
10
  import "./chunk-UHVXE24Y.js";
11
11
  import "./chunk-DM5QZ3YU.js";
12
12
  import "./chunk-VY6BD5KB.js";
13
13
  import "./chunk-G6OFEGUR.js";
14
- import "./chunk-V2XMG7GM.js";
14
+ import "./chunk-CHNZPOWX.js";
15
15
  import "./chunk-4QLKVZH6.js";
16
16
  import "./chunk-XKDQTDXN.js";
17
17
  import "./chunk-CYEPCZN5.js";
package/dist/who-knows.js CHANGED
@@ -9,13 +9,13 @@ import {
9
9
  loadWhoKnowsEntities,
10
10
  tokenizeTopic,
11
11
  validateWhoKnowsInput
12
- } from "./chunk-WT2VVYBM.js";
13
- import "./chunk-5KZNWERU.js";
12
+ } from "./chunk-PJXSBXEC.js";
13
+ import "./chunk-BIYVUPC6.js";
14
14
  import "./chunk-UHVXE24Y.js";
15
15
  import "./chunk-DM5QZ3YU.js";
16
16
  import "./chunk-VY6BD5KB.js";
17
17
  import "./chunk-G6OFEGUR.js";
18
- import "./chunk-V2XMG7GM.js";
18
+ import "./chunk-CHNZPOWX.js";
19
19
  import "./chunk-4QLKVZH6.js";
20
20
  import "./chunk-XKDQTDXN.js";
21
21
  import "./chunk-CYEPCZN5.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "10.0.39",
3
+ "version": "10.0.40",
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.39"
3350
+ "@remnic/coding-graph": "^10.0.40"
3351
3351
  },
3352
3352
  "peerDependenciesMeta": {
3353
3353
  "@remnic/coding-graph": {
@@ -0,0 +1,190 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test, { type TestContext } from "node:test";
6
+ import { EngramAccessHttpServer } from "./access-http.js";
7
+ import { getOperation } from "./access-boundary.js";
8
+ import { EngramAccessService } from "./access-service.js";
9
+ import { createChatExecutor } from "./chat/chat-executor.js";
10
+ import { parseConfig } from "./config.js";
11
+ import { NamespaceStorageRouter } from "./namespaces/storage.js";
12
+ import type { Orchestrator } from "./orchestrator.js";
13
+
14
+ interface EntityHttpBody {
15
+ error?: string;
16
+ found?: boolean;
17
+ namespace?: string;
18
+ entities?: Array<{ name?: string }>;
19
+ entity?: { name?: string };
20
+ }
21
+
22
+ interface McpToolBody {
23
+ result: { isError: boolean; content: Array<{ text: string }>; structuredContent: { entity: { name: string } } };
24
+ }
25
+
26
+ async function readMcp(response: Response): Promise<McpToolBody> {
27
+ // SAFETY: /mcp answers tools/call with the JSON-RPC result shape named above; each test asserts the fields it reads.
28
+ return (await response.json()) as McpToolBody;
29
+ }
30
+
31
+ async function readBody(response: Response): Promise<EntityHttpBody> {
32
+ // SAFETY: the access server answers these routes with the JSON shape named above; each test asserts the fields it reads.
33
+ return (await response.json()) as EntityHttpBody;
34
+ }
35
+
36
+ /** Entity reads need only config and real storage routing from the orchestrator. */
37
+ async function createFixture(t: TestContext, namespacesEnabled = true) {
38
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-entity-acl-"));
39
+ t.after(() => rm(memoryDir, { recursive: true, force: true }));
40
+ const config = parseConfig({
41
+ memoryDir,
42
+ namespacesEnabled,
43
+ defaultNamespace: "default",
44
+ sharedNamespace: "shared",
45
+ namespacePolicies: [
46
+ { name: "default", readPrincipals: ["owner"], writePrincipals: ["owner"] },
47
+ { name: "restricted", readPrincipals: ["owner", "reader"], writePrincipals: ["owner"] },
48
+ ],
49
+ });
50
+ const router = new NamespaceStorageRouter(config);
51
+ for (const namespace of namespacesEnabled ? ["default", "restricted"] : ["default"]) {
52
+ const storage = await router.storageFor(namespace);
53
+ const entitiesDir = path.join(storage.dir, "entities");
54
+ await mkdir(entitiesDir, { recursive: true });
55
+ await writeFile(path.join(entitiesDir, "project-widget.md"), [
56
+ `# Widget-${namespace}`,
57
+ "",
58
+ "**Type:** project",
59
+ "",
60
+ "## Summary",
61
+ "",
62
+ `Synthetic entity in ${namespace}.`,
63
+ "",
64
+ ].join("\n"));
65
+ }
66
+ const dependencies: Pick<Orchestrator, "config" | "getStorage"> = {
67
+ config,
68
+ getStorage: (namespace) => router.storageFor(namespace ?? config.defaultNamespace),
69
+ };
70
+ // SAFETY: the entity read paths touch only `config` and `getStorage` (the Pick above); the rest of the Orchestrator is unused here.
71
+ return new EngramAccessService(dependencies as Orchestrator);
72
+ }
73
+
74
+ test("entity service enforces read ACLs and requires a principal before list/get", async (t) => {
75
+ const service = await createFixture(t);
76
+ await assert.rejects(() => service.entityList({ namespace: "restricted" }, "intruder"), /not readable/);
77
+ await assert.rejects(() => service.entityGet("project-widget", "restricted", "intruder"), /not readable/);
78
+ await assert.rejects(() => service.entityList({ namespace: "restricted" }), /authentication required/);
79
+ await assert.rejects(() => service.entityGet("project-widget", "restricted"), /authentication required/);
80
+ await assert.rejects(() => service.entityList({}, "reader"), /not readable/);
81
+ await assert.rejects(() => service.entityGet("project-widget", undefined, "reader"), /not readable/);
82
+
83
+ const list = await service.entityList({ namespace: " restricted ", query: "widget", limit: 1 }, "reader");
84
+ assert.equal(list.namespace, "restricted");
85
+ assert.equal(list.total, 1);
86
+ assert.equal(list.entities[0]?.name, "Widget-restricted");
87
+ const entity = await service.entityGet("project-widget", " restricted ", "reader");
88
+ assert.equal(entity.namespace, "restricted");
89
+ assert.equal(entity.entity?.name, "Widget-restricted");
90
+ assert.deepEqual(await service.entityGet("missing", "restricted", "reader"), {
91
+ found: false, namespace: "restricted",
92
+ });
93
+ });
94
+
95
+ test("entity service retains principal-free reads when namespaces are disabled", async (t) => {
96
+ const service = await createFixture(t, false);
97
+ assert.equal((await service.entityList()).entities[0]?.name, "Widget-default");
98
+ assert.equal((await service.entityGet("project-widget")).entity?.name, "Widget-default");
99
+ });
100
+
101
+ test("entity_list registry dispatch preserves the trusted principal", async (t) => {
102
+ const service = await createFixture(t);
103
+ const operation = getOperation("entity_list");
104
+ assert.ok(operation);
105
+ await assert.rejects(
106
+ () => operation.run({ principal: "owner" }, { service, authenticatedPrincipal: "reader" }),
107
+ /not readable/,
108
+ );
109
+ const output = await operation.run({}, { service, authenticatedPrincipal: "owner" });
110
+ const result = JSON.parse(JSON.stringify(output)).result;
111
+ assert.equal(result.namespace, "default");
112
+ assert.equal(result.entities[0]?.name, "Widget-default");
113
+ });
114
+
115
+ test("HTTP and MCP entity reads bind ACLs to the transport principal across aliases", async (t) => {
116
+ const service = await createFixture(t);
117
+ const token = "synthetic-entity-token";
118
+ const server = new EngramAccessHttpServer({
119
+ service,
120
+ host: "127.0.0.1",
121
+ port: 0,
122
+ principal: "reader",
123
+ enableAdapters: false,
124
+ trustPrincipalHeader: false,
125
+ authTokenEntriesGetter: () => [{
126
+ token,
127
+ capabilities: { version: 1, ops: ["entity_get", "entity_list"], namespaces: ["default", "restricted"] },
128
+ }],
129
+ });
130
+ const started = await server.start();
131
+ t.after(() => server.stop());
132
+ const base = `http://${started.host}:${started.port}`;
133
+ const headers = {
134
+ authorization: `Bearer ${token}`,
135
+ "content-type": "application/json",
136
+ "x-engram-principal": "owner",
137
+ };
138
+ for (const prefix of ["engram", "remnic"]) {
139
+ // The entity HTTP routes are served under /engram/v1 only; the /remnic prefix is an alias for the MCP tool names below.
140
+ for (const suffix of prefix === "engram" ? ["entities", "entities/project-widget"] : []) {
141
+ const denied = await fetch(`${base}/${prefix}/v1/${suffix}?namespace=default&principal=owner`, { headers });
142
+ assert.equal(denied.status, 400);
143
+ assert.match((await readBody(denied)).error ?? "", /not readable/);
144
+ const allowed = await fetch(`${base}/${prefix}/v1/${suffix}?namespace=restricted`, { headers });
145
+ assert.equal(allowed.status, 200);
146
+ const body = await readBody(allowed);
147
+ assert.equal(body.namespace, "restricted");
148
+ assert.equal(suffix === "entities" ? body.entities?.[0]?.name : body.entity?.name, "Widget-restricted");
149
+ }
150
+ if (prefix === "engram") {
151
+ const missing = await fetch(`${base}/${prefix}/v1/entities/missing?namespace=restricted`, { headers });
152
+ assert.equal(missing.status, 404);
153
+ assert.equal((await readBody(missing)).found, false);
154
+ }
155
+
156
+ for (const namespace of ["default", "restricted"]) {
157
+ const response = await fetch(`${base}/mcp`, {
158
+ method: "POST",
159
+ headers,
160
+ body: JSON.stringify({
161
+ jsonrpc: "2.0",
162
+ id: `${prefix}-${namespace}`,
163
+ method: "tools/call",
164
+ params: {
165
+ name: `${prefix}.entity_get`,
166
+ arguments: {
167
+ name: "project-widget", namespace, principal: "owner", authenticatedPrincipal: "owner",
168
+ },
169
+ },
170
+ }),
171
+ });
172
+ assert.equal(response.status, 200);
173
+ const body = await readMcp(response);
174
+ assert.equal(body.result.isError, namespace === "default");
175
+ if (namespace === "default") {
176
+ assert.match(body.result.content[0].text, /not readable/);
177
+ } else {
178
+ assert.equal(body.result.structuredContent.entity.name, "Widget-restricted");
179
+ }
180
+ }
181
+ }
182
+ });
183
+
184
+ test("chat entity reads preserve the bound principal instead of losing identity", async (t) => {
185
+ const service = await createFixture(t);
186
+ const allowed = createChatExecutor({ service, namespace: "restricted", principal: "reader" });
187
+ assert.equal(JSON.parse(await allowed.entityGet("project-widget")).entity.name, "Widget-restricted");
188
+ const denied = createChatExecutor({ service, namespace: "default", principal: "reader" });
189
+ await assert.rejects(() => denied.entityGet("project-widget"), /not readable/);
190
+ });
@@ -2168,7 +2168,7 @@ export class EngramAccessHttpServer extends ReviewDeckAccessHttpBase {
2168
2168
  query: parsed.searchParams.get("q") ?? undefined,
2169
2169
  limit,
2170
2170
  offset,
2171
- });
2171
+ }, this.resolveRequestPrincipal(req));
2172
2172
  this.respondJson(res, 200, response);
2173
2173
  return;
2174
2174
  }
@@ -2178,7 +2178,7 @@ export class EngramAccessHttpServer extends ReviewDeckAccessHttpBase {
2178
2178
  this.enforceTokenOp("entity_get"); // boundary dispatch (issue #1525)
2179
2179
  const entityName = decodeURIComponent(entityMatch[1] ?? "");
2180
2180
  const namespace = this.resolveNamespace(req, parsed.searchParams.get("namespace") ?? undefined);
2181
- const response = await this.service.entityGet(entityName, namespace);
2181
+ const response = await this.service.entityGet(entityName, namespace, this.resolveRequestPrincipal(req));
2182
2182
  this.respondJson(res, response.found ? 200 : 404, response);
2183
2183
  return;
2184
2184
  }
@@ -279,7 +279,7 @@ defineOperation({
279
279
  };
280
280
  },
281
281
  });
282
- defineOperation({ name: "entity_get", description: "Get entity.", schema: strictSchema({ name: S.str, namespace: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.entityGet(optStr(input.name) ?? "", optStr(input.namespace)) }) });
282
+ defineOperation({ name: "entity_get", description: "Get entity.", schema: strictSchema({ name: S.str, namespace: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.entityGet(optStr(input.name) ?? "", optStr(input.namespace), ctx.authenticatedPrincipal) }) });
283
283
  defineOperation({ name: "review_queue_list", description: "List review queue.", schema: strictSchema({ runId: S.str, namespace: S.str }), handler: async (input, ctx) => ({ result: await ctx.service.reviewQueue(optStr(input.runId) ?? "", optStr(input.namespace), ctx.authenticatedPrincipal) }) });
284
284
  // Issue #2482: observe validates through the canonical observeRequestSchema
285
285
  // (same as HTTP/MCP wire validation). Nullable wire fields (parts /
@@ -472,7 +472,7 @@ defineOperation({
472
472
  return { result: getRecallTimingStatus(ctx.service.configRef) };
473
473
  },
474
474
  });
475
- defineOperation({ name: "entity_list", description: "List entities.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.entityList() }) });
475
+ defineOperation({ name: "entity_list", description: "List entities.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.entityList({}, ctx.authenticatedPrincipal) }) });
476
476
  defineOperation({ name: "maintenance_status", description: "Maintenance status.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.maintenance() }) });
477
477
  defineOperation({ name: "quality_status", description: "Quality status.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.quality() }) });
478
478
  defineOperation({ name: "trust_zones_status", description: "Trust-zone status.", schema: strictSchema({}), handler: async (_i, ctx) => ({ result: await ctx.service.trustZoneStatus() }) });
@@ -3506,10 +3506,11 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
3506
3506
  query?: string;
3507
3507
  limit?: number;
3508
3508
  offset?: number;
3509
- } = {}
3509
+ } = {},
3510
+ principal?: string
3510
3511
  ): Promise<EngramAccessEntityListResponse> {
3511
- const storage = await this.orchestrator.getStorage(options.namespace);
3512
- const resolvedNamespace = options.namespace?.trim() || this.orchestrator.config.defaultNamespace;
3512
+ const resolvedNamespace = this.resolveReadableNamespace(options.namespace, principal);
3513
+ const storage = await this.orchestrator.getStorage(resolvedNamespace);
3513
3514
  const { limit, offset } = normalizePagination(options.limit, options.offset);
3514
3515
  const query = options.query?.trim().toLowerCase() ?? "";
3515
3516
 
@@ -3553,9 +3554,9 @@ export class EngramAccessService extends SupportPassportAccessServiceBase {
3553
3554
  };
3554
3555
  }
3555
3556
 
3556
- async entityGet(name: string, namespace?: string): Promise<EngramAccessEntityResponse> {
3557
- const storage = await this.orchestrator.getStorage(namespace);
3558
- const resolvedNamespace = namespace?.trim() || this.orchestrator.config.defaultNamespace;
3557
+ async entityGet(name: string, namespace?: string, principal?: string): Promise<EngramAccessEntityResponse> {
3558
+ const resolvedNamespace = this.resolveReadableNamespace(namespace, principal);
3559
+ const storage = await this.orchestrator.getStorage(resolvedNamespace);
3559
3560
  const raw = await storage.readEntity(name);
3560
3561
  if (!raw) return { found: false, namespace: resolvedNamespace };
3561
3562
  return {
@@ -60,7 +60,7 @@ export function createChatExecutor(bindings: ChatExecutorBindings): ChatToolExec
60
60
  },
61
61
 
62
62
  async entityGet(name: string): Promise<string> {
63
- const result = await service.entityGet(name, namespace);
63
+ const result = await service.entityGet(name, namespace, principal);
64
64
  return JSON.stringify(result);
65
65
  },
66
66
 
@@ -85,3 +85,26 @@ export function formatExtractionParseFailureLog(input: {
85
85
  `traceId=${input.traceId}`,
86
86
  ].join(" ");
87
87
  }
88
+
89
+ /**
90
+ * The local endpoint answered, and what it said rejects this input (unusable content, or a client error that is not
91
+ * auth, timeout or rate limiting): the chunk's problem, not an outage. Retried like an empty parse, and a trigger-drain
92
+ * chunk that keeps drawing it is dropped after its recovery copy is saved.
93
+ */
94
+ export class LocalLlmRejectedError extends Error {
95
+ constructor(readonly httpStatus?: number) {
96
+ super(httpStatus === undefined ? "local LLM answered with unusable content" : `local LLM rejected the input (HTTP ${httpStatus})`);
97
+ this.name = "LocalLlmRejectedError";
98
+ }
99
+ }
100
+
101
+ /** What the local client recorded about a failed call (`failureDiag`). */
102
+ export interface LocalFailureDiag {
103
+ lastError?: unknown;
104
+ }
105
+
106
+ /** The HTTP status when the local endpoint answered and refuses this input (400, 413, 422); else undefined. A wrong model name or route (404, 405, 410), auth, timeout and rate limiting are the setup's problem, not the chunk's. */
107
+ export function localRejectionStatus(diag: LocalFailureDiag): number | undefined {
108
+ const status = httpStatusFromError(diag.lastError);
109
+ return status !== undefined && [400, 413, 422].includes(status) ? status : undefined;
110
+ }
@@ -0,0 +1,55 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ import { parseConfig } from "./config.js";
5
+ import { ExtractionEngine } from "./extraction.js";
6
+ import type { BufferTurn } from "./types.js";
7
+
8
+ // Follow-up to #3266: the trigger drain drops a chunk after N failures, but not for an outage. Whether a local-model failure
9
+ // is the chunk's fault is decided here, by what the local endpoint did.
10
+ const TURNS: BufferTurn[] = [
11
+ { role: "user", content: "I keep my backups on the NAS in the garage.", timestamp: "2026-10-30T01:00:00.000Z" },
12
+ { role: "assistant", content: "Noted.", timestamp: "2026-10-30T01:00:05.000Z" },
13
+ ];
14
+
15
+ type LocalMessages = Array<{ role: string; content: string }>;
16
+ type LocalStub = (messages: LocalMessages, options: { failureDiag?: { lastError?: Error } }) => Promise<{ content: string } | null>;
17
+
18
+ async function extractWith(local: LocalStub) {
19
+ const engine = new ExtractionEngine(parseConfig({ localLlmEnabled: true, localLlmModel: "fixture-local", localLlmFallback: false }));
20
+ const modelRegistry = { calculateContextSizes: () => ({ maxInputChars: 8_000, maxOutputTokens: 1_000, description: "fixture" }) };
21
+ assert.equal(Reflect.set(engine, "localLlm", { chatCompletion: local }), true);
22
+ assert.equal(Reflect.set(engine, "modelRegistry", modelRegistry), true);
23
+ return await engine.extract(TURNS);
24
+ }
25
+
26
+ const withStatus = (status: number) => Object.assign(new Error("local LLM http failure"), { status });
27
+
28
+ test("a local endpoint that answers with something unusable rejects the chunk: parse_empty", async () => {
29
+ const result = await extractWith(async () => ({ content: "I cannot help with that request." }));
30
+ assert.equal(result.extractionFailure, "local_llm_error");
31
+ assert.equal(result.extractionFailureClass, "parse_empty");
32
+ });
33
+
34
+ test("a local endpoint that answers with a client error rejects the chunk: parse_empty", async () => {
35
+ for (const status of [400, 413, 422]) {
36
+ const result = await extractWith(async (_messages, options) => {
37
+ if (options.failureDiag) options.failureDiag.lastError = withStatus(status);
38
+ return null;
39
+ });
40
+ assert.equal(result.extractionFailureClass, "parse_empty", `HTTP ${status}`);
41
+ }
42
+ });
43
+
44
+ test("not the chunk's fault: unreachable, timeout, 5xx, 429, auth and a wrong model or route (404) stay provider_retryable", async () => {
45
+ const outage = await extractWith(async () => null);
46
+ assert.equal(outage.extractionFailure, "local_llm_unavailable");
47
+ assert.equal(outage.extractionFailureClass, "provider_retryable");
48
+ for (const status of [401, 403, 404, 405, 408, 410, 429, 500, 503]) {
49
+ const result = await extractWith(async (_messages, options) => {
50
+ if (options.failureDiag) options.failureDiag.lastError = withStatus(status);
51
+ return null;
52
+ });
53
+ assert.equal(result.extractionFailureClass, "provider_retryable", `HTTP ${status}`);
54
+ }
55
+ });