@remnic/core 10.0.77 → 10.0.79

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 (234) hide show
  1. package/dist/access-admin-ops-surface.js +26 -26
  2. package/dist/access-authorization-probe.js +27 -27
  3. package/dist/access-boundary.js +26 -26
  4. package/dist/access-cli.js +77 -76
  5. package/dist/access-cli.js.map +1 -1
  6. package/dist/access-extraction-force-flush.js +26 -26
  7. package/dist/access-http-briefing.js +27 -27
  8. package/dist/access-http-query.js +28 -28
  9. package/dist/access-http.js +44 -44
  10. package/dist/access-identity-continuity-surface.js +26 -26
  11. package/dist/access-lcm-surface.js +26 -26
  12. package/dist/access-mcp.js +36 -36
  13. package/dist/access-namespace-preflight.js +26 -26
  14. package/dist/access-observe-write-category.js +5 -5
  15. package/dist/access-observe-write-surface.js +26 -26
  16. package/dist/access-operations-batch.js +28 -28
  17. package/dist/access-operations.js +35 -35
  18. package/dist/access-recall-concurrency.js +26 -26
  19. package/dist/access-recall-response.js +26 -26
  20. package/dist/access-recall-surface.js +26 -26
  21. package/dist/access-schema.js +4 -4
  22. package/dist/access-service.js +26 -26
  23. package/dist/access-surface-catalog.js +28 -28
  24. package/dist/active-recall.js +7 -7
  25. package/dist/briefing.js +8 -8
  26. package/dist/calibration.js +1 -1
  27. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
  28. package/dist/causal-consolidation.js +9 -9
  29. package/dist/{chunk-Z3CKK5RR.js → chunk-2XG7QECM.js} +3 -3
  30. package/dist/{chunk-BZTA7DR4.js → chunk-35RSL5B4.js} +3 -3
  31. package/dist/{chunk-MUZWS6KB.js → chunk-3RYP4OTZ.js} +2 -2
  32. package/dist/{chunk-TX627XOF.js → chunk-446H5UUO.js} +4 -4
  33. package/dist/{chunk-XC7OYOQC.js → chunk-4BCX6YLW.js} +2 -2
  34. package/dist/{chunk-NUBOY2LQ.js → chunk-4HLPFYF2.js} +7 -7
  35. package/dist/{chunk-WIAXVBQH.js → chunk-65SKM4BF.js} +2 -2
  36. package/dist/{chunk-5HVEYVNQ.js → chunk-6HERQLF4.js} +2 -2
  37. package/dist/{chunk-4DLZ2ITE.js → chunk-6OGFQ5GH.js} +2 -2
  38. package/dist/{chunk-C44DRDZM.js → chunk-6WULHFNJ.js} +2 -2
  39. package/dist/{chunk-IVXOYE43.js → chunk-7IQ5HYBJ.js} +2 -2
  40. package/dist/{chunk-D26XMQP5.js → chunk-A45ZOJV4.js} +2 -2
  41. package/dist/chunk-ADJXJKU6.js +74 -0
  42. package/dist/chunk-ADJXJKU6.js.map +1 -0
  43. package/dist/{chunk-DANFOVQG.js → chunk-B7PLF3HW.js} +2 -2
  44. package/dist/{chunk-PBE7NFB5.js → chunk-BNQJKWWZ.js} +4 -4
  45. package/dist/{chunk-AY2UK5XK.js → chunk-BSBGI4BD.js} +2 -2
  46. package/dist/{chunk-AY2UK5XK.js.map → chunk-BSBGI4BD.js.map} +1 -1
  47. package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
  48. package/dist/{chunk-2JRLKDHV.js → chunk-CZD654DQ.js} +21 -21
  49. package/dist/{chunk-MBENRPMY.js → chunk-D3WNJF7D.js} +12 -12
  50. package/dist/{chunk-5IQL4N37.js → chunk-D4WBMLPD.js} +2 -2
  51. package/dist/{chunk-FYQUUIPI.js → chunk-DLZGSZVC.js} +4 -4
  52. package/dist/{chunk-YK6SFDP2.js → chunk-DOJBV6WR.js} +4 -4
  53. package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
  54. package/dist/{chunk-FETPTCQZ.js → chunk-E33UJHY3.js} +2 -2
  55. package/dist/{chunk-LJUQPT5G.js → chunk-EFRMEOZQ.js} +3 -3
  56. package/dist/{chunk-HTDXNIO6.js → chunk-HK3CUTAG.js} +2 -2
  57. package/dist/{chunk-FGUWCE5I.js → chunk-HUF4S4MY.js} +2 -2
  58. package/dist/{chunk-6Q6AQ36B.js → chunk-HWHNQVRV.js} +2 -2
  59. package/dist/{chunk-SYDPJUFR.js → chunk-IDGCL5OP.js} +2 -2
  60. package/dist/{chunk-F3FNXE7C.js → chunk-JHJP2IAU.js} +3 -3
  61. package/dist/{chunk-FQU65RJX.js → chunk-JIGHVQF6.js} +6 -6
  62. package/dist/{chunk-P7HNMNN2.js → chunk-K4SVTZWP.js} +7 -7
  63. package/dist/{chunk-6L62IDS6.js → chunk-KDWO22ZK.js} +2 -2
  64. package/dist/{chunk-4NDDRYBY.js → chunk-KYVBGDGA.js} +2 -2
  65. package/dist/{chunk-HB5TNQMM.js → chunk-L7BOS7KV.js} +2 -2
  66. package/dist/{chunk-3MBSD53O.js → chunk-LE4MQ2WF.js} +2 -2
  67. package/dist/{chunk-I4LJJ44E.js → chunk-LNHBYT3F.js} +2 -2
  68. package/dist/{chunk-SHVLNI4L.js → chunk-LU66I56Q.js} +2 -2
  69. package/dist/{chunk-MXQKGSMW.js → chunk-N2H6VC65.js} +3 -3
  70. package/dist/{chunk-L4QYW2HO.js → chunk-NBFHOQIO.js} +2 -2
  71. package/dist/{chunk-KNZDGZSY.js → chunk-NVYY2TJG.js} +2 -2
  72. package/dist/{chunk-7FFGWIBN.js → chunk-PCSQRQPJ.js} +2 -2
  73. package/dist/{chunk-P3AQ2YSX.js → chunk-PFUXPTBT.js} +4 -4
  74. package/dist/{chunk-KQAFEZQX.js → chunk-R45L4TV6.js} +6 -6
  75. package/dist/{chunk-EYIBIGIU.js → chunk-R63X5BQA.js} +12 -12
  76. package/dist/{chunk-TWHVCSLX.js → chunk-RF7QJ736.js} +2 -2
  77. package/dist/{chunk-ZZSFRWKD.js → chunk-RIBCP4DJ.js} +2 -2
  78. package/dist/{chunk-HDN7IVIO.js → chunk-RIZ5NUNN.js} +16 -62
  79. package/dist/chunk-RIZ5NUNN.js.map +1 -0
  80. package/dist/{chunk-I4W2ADBP.js → chunk-S34XZUTY.js} +36 -36
  81. package/dist/{chunk-DEGE32C3.js → chunk-SLORPQZT.js} +2 -2
  82. package/dist/{chunk-6RPPZL7W.js → chunk-SMSJOWVE.js} +2 -2
  83. package/dist/{chunk-X53HJENJ.js → chunk-SPYFXSFZ.js} +2 -2
  84. package/dist/{chunk-IRFQKR4Y.js → chunk-SW6OAWK7.js} +2 -2
  85. package/dist/{chunk-D3USVQIV.js → chunk-SZEPOUW2.js} +2 -2
  86. package/dist/{chunk-COIQ5N4J.js → chunk-TSITK6QK.js} +2 -2
  87. package/dist/{chunk-HCFNZWFB.js → chunk-VBNXDC7P.js} +2 -2
  88. package/dist/{chunk-G3PBNYDH.js → chunk-VJ3HFCG2.js} +2 -2
  89. package/dist/{chunk-OBQ2NZAR.js → chunk-VKDAJJQP.js} +4 -4
  90. package/dist/{chunk-HZNURRDS.js → chunk-VUROWXFL.js} +2 -2
  91. package/dist/{chunk-G5NH3SSX.js → chunk-X3KFSJLQ.js} +2 -2
  92. package/dist/{chunk-GCJA5KKT.js → chunk-XBNO56HC.js} +2 -2
  93. package/dist/{chunk-GWOFCHPN.js → chunk-YGECOOTF.js} +2 -2
  94. package/dist/{chunk-2R7OCBRR.js → chunk-YK7GOPIE.js} +2 -2
  95. package/dist/{chunk-ELUG6NKQ.js → chunk-YSA4CYTK.js} +2 -2
  96. package/dist/{chunk-233S3MXC.js → chunk-YXUNSOHD.js} +3 -3
  97. package/dist/{chunk-MAURCRPQ.js → chunk-Z3O7ZOCC.js} +30 -30
  98. package/dist/{chunk-LXDERMOU.js → chunk-ZAU2OPDW.js} +2 -2
  99. package/dist/cli.js +62 -61
  100. package/dist/coding/export-okf-codegraph.js +7 -7
  101. package/dist/compounding/engine.js +9 -9
  102. package/dist/config.js +7 -7
  103. package/dist/connectors/codex-materialize-runner.js +8 -8
  104. package/dist/connectors/index.js +8 -8
  105. package/dist/convergence-refresh.js +10 -10
  106. package/dist/corpus-watermark.js +10 -10
  107. package/dist/deep-recall-http-glue.js +5 -5
  108. package/dist/entity-retrieval.js +8 -8
  109. package/dist/external-wiki-access.js +27 -27
  110. package/dist/extraction.js +10 -10
  111. package/dist/harmonic-retrieval.js +8 -8
  112. package/dist/index.js +85 -84
  113. package/dist/lcm/engine.js +2 -2
  114. package/dist/lcm/index.js +5 -5
  115. package/dist/local-llm.js +1 -1
  116. package/dist/location/index.js +10 -10
  117. package/dist/maintenance/memory-governance.js +8 -8
  118. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +8 -8
  119. package/dist/maintenance/rebuild-memory-projection-runner.js +10 -10
  120. package/dist/maintenance/rebuild-memory-projection.js +9 -9
  121. package/dist/memory-browse-operations.js +27 -27
  122. package/dist/namespaces/migrate.js +9 -9
  123. package/dist/namespaces/search.js +6 -6
  124. package/dist/namespaces/storage.js +8 -8
  125. package/dist/operator-doctor-corpus.js +11 -11
  126. package/dist/operator-toolkit.js +16 -16
  127. package/dist/orchestration/backlog-scheduler.js +78 -77
  128. package/dist/orchestration/backlog-scheduler.js.map +1 -1
  129. package/dist/orchestration/buffer-drain-runner.js +78 -77
  130. package/dist/orchestration/maintenance.js +19 -19
  131. package/dist/orchestrator.js +77 -76
  132. package/dist/recall-navigation-operations.js +27 -27
  133. package/dist/recall-navigation.js +26 -26
  134. package/dist/resume-bundles.js +10 -9
  135. package/dist/search/factory.js +5 -5
  136. package/dist/search/index.js +5 -5
  137. package/dist/search/lancedb-backend.js +2 -2
  138. package/dist/search/meilisearch-backend.js +2 -2
  139. package/dist/search/orama-backend.js +2 -2
  140. package/dist/semantic-consolidation.js +9 -9
  141. package/dist/semantic-rule-promotion.js +8 -8
  142. package/dist/semantic-rule-verifier.js +8 -8
  143. package/dist/source-agent-qualifier.js +8 -8
  144. package/dist/standup/build.js +8 -8
  145. package/dist/storage.js +7 -7
  146. package/dist/summarizer.js +2 -2
  147. package/dist/support-passport/index.js +29 -29
  148. package/dist/transcript-ownership-digest.d.ts +31 -0
  149. package/dist/transcript-ownership-digest.d.ts.map +1 -0
  150. package/dist/transcript-ownership-digest.js +10 -0
  151. package/dist/transcript-ownership-digest.js.map +1 -0
  152. package/dist/transcript.d.ts +2 -5
  153. package/dist/transcript.d.ts.map +1 -1
  154. package/dist/transcript.js +2 -1
  155. package/dist/transfer/autodetect.js +1 -1
  156. package/dist/transfer/backup.js +2 -2
  157. package/dist/transfer/capsule-export.js +3 -3
  158. package/dist/transfer/capsule-import.js +2 -2
  159. package/dist/transfer/export-okf.js +8 -8
  160. package/dist/verified-recall.js +8 -8
  161. package/dist/who-knows-cli.js +9 -9
  162. package/dist/who-knows.js +8 -8
  163. package/package.json +2 -2
  164. package/src/local-llm-qos.test.ts +59 -0
  165. package/src/local-llm.ts +1 -1
  166. package/src/transcript-ownership-digest.test.ts +403 -0
  167. package/src/transcript-ownership-digest.ts +99 -0
  168. package/src/transcript.ts +14 -76
  169. package/dist/chunk-HDN7IVIO.js.map +0 -1
  170. /package/dist/{capsule-crypto-7FJQINUR.js.map → capsule-crypto-YO5QJ6L3.js.map} +0 -0
  171. /package/dist/{chunk-Z3CKK5RR.js.map → chunk-2XG7QECM.js.map} +0 -0
  172. /package/dist/{chunk-BZTA7DR4.js.map → chunk-35RSL5B4.js.map} +0 -0
  173. /package/dist/{chunk-MUZWS6KB.js.map → chunk-3RYP4OTZ.js.map} +0 -0
  174. /package/dist/{chunk-TX627XOF.js.map → chunk-446H5UUO.js.map} +0 -0
  175. /package/dist/{chunk-XC7OYOQC.js.map → chunk-4BCX6YLW.js.map} +0 -0
  176. /package/dist/{chunk-NUBOY2LQ.js.map → chunk-4HLPFYF2.js.map} +0 -0
  177. /package/dist/{chunk-WIAXVBQH.js.map → chunk-65SKM4BF.js.map} +0 -0
  178. /package/dist/{chunk-5HVEYVNQ.js.map → chunk-6HERQLF4.js.map} +0 -0
  179. /package/dist/{chunk-4DLZ2ITE.js.map → chunk-6OGFQ5GH.js.map} +0 -0
  180. /package/dist/{chunk-C44DRDZM.js.map → chunk-6WULHFNJ.js.map} +0 -0
  181. /package/dist/{chunk-IVXOYE43.js.map → chunk-7IQ5HYBJ.js.map} +0 -0
  182. /package/dist/{chunk-D26XMQP5.js.map → chunk-A45ZOJV4.js.map} +0 -0
  183. /package/dist/{chunk-DANFOVQG.js.map → chunk-B7PLF3HW.js.map} +0 -0
  184. /package/dist/{chunk-PBE7NFB5.js.map → chunk-BNQJKWWZ.js.map} +0 -0
  185. /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
  186. /package/dist/{chunk-2JRLKDHV.js.map → chunk-CZD654DQ.js.map} +0 -0
  187. /package/dist/{chunk-MBENRPMY.js.map → chunk-D3WNJF7D.js.map} +0 -0
  188. /package/dist/{chunk-5IQL4N37.js.map → chunk-D4WBMLPD.js.map} +0 -0
  189. /package/dist/{chunk-FYQUUIPI.js.map → chunk-DLZGSZVC.js.map} +0 -0
  190. /package/dist/{chunk-YK6SFDP2.js.map → chunk-DOJBV6WR.js.map} +0 -0
  191. /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
  192. /package/dist/{chunk-FETPTCQZ.js.map → chunk-E33UJHY3.js.map} +0 -0
  193. /package/dist/{chunk-LJUQPT5G.js.map → chunk-EFRMEOZQ.js.map} +0 -0
  194. /package/dist/{chunk-HTDXNIO6.js.map → chunk-HK3CUTAG.js.map} +0 -0
  195. /package/dist/{chunk-FGUWCE5I.js.map → chunk-HUF4S4MY.js.map} +0 -0
  196. /package/dist/{chunk-6Q6AQ36B.js.map → chunk-HWHNQVRV.js.map} +0 -0
  197. /package/dist/{chunk-SYDPJUFR.js.map → chunk-IDGCL5OP.js.map} +0 -0
  198. /package/dist/{chunk-F3FNXE7C.js.map → chunk-JHJP2IAU.js.map} +0 -0
  199. /package/dist/{chunk-FQU65RJX.js.map → chunk-JIGHVQF6.js.map} +0 -0
  200. /package/dist/{chunk-P7HNMNN2.js.map → chunk-K4SVTZWP.js.map} +0 -0
  201. /package/dist/{chunk-6L62IDS6.js.map → chunk-KDWO22ZK.js.map} +0 -0
  202. /package/dist/{chunk-4NDDRYBY.js.map → chunk-KYVBGDGA.js.map} +0 -0
  203. /package/dist/{chunk-HB5TNQMM.js.map → chunk-L7BOS7KV.js.map} +0 -0
  204. /package/dist/{chunk-3MBSD53O.js.map → chunk-LE4MQ2WF.js.map} +0 -0
  205. /package/dist/{chunk-I4LJJ44E.js.map → chunk-LNHBYT3F.js.map} +0 -0
  206. /package/dist/{chunk-SHVLNI4L.js.map → chunk-LU66I56Q.js.map} +0 -0
  207. /package/dist/{chunk-MXQKGSMW.js.map → chunk-N2H6VC65.js.map} +0 -0
  208. /package/dist/{chunk-L4QYW2HO.js.map → chunk-NBFHOQIO.js.map} +0 -0
  209. /package/dist/{chunk-KNZDGZSY.js.map → chunk-NVYY2TJG.js.map} +0 -0
  210. /package/dist/{chunk-7FFGWIBN.js.map → chunk-PCSQRQPJ.js.map} +0 -0
  211. /package/dist/{chunk-P3AQ2YSX.js.map → chunk-PFUXPTBT.js.map} +0 -0
  212. /package/dist/{chunk-KQAFEZQX.js.map → chunk-R45L4TV6.js.map} +0 -0
  213. /package/dist/{chunk-EYIBIGIU.js.map → chunk-R63X5BQA.js.map} +0 -0
  214. /package/dist/{chunk-TWHVCSLX.js.map → chunk-RF7QJ736.js.map} +0 -0
  215. /package/dist/{chunk-ZZSFRWKD.js.map → chunk-RIBCP4DJ.js.map} +0 -0
  216. /package/dist/{chunk-I4W2ADBP.js.map → chunk-S34XZUTY.js.map} +0 -0
  217. /package/dist/{chunk-DEGE32C3.js.map → chunk-SLORPQZT.js.map} +0 -0
  218. /package/dist/{chunk-6RPPZL7W.js.map → chunk-SMSJOWVE.js.map} +0 -0
  219. /package/dist/{chunk-X53HJENJ.js.map → chunk-SPYFXSFZ.js.map} +0 -0
  220. /package/dist/{chunk-IRFQKR4Y.js.map → chunk-SW6OAWK7.js.map} +0 -0
  221. /package/dist/{chunk-D3USVQIV.js.map → chunk-SZEPOUW2.js.map} +0 -0
  222. /package/dist/{chunk-COIQ5N4J.js.map → chunk-TSITK6QK.js.map} +0 -0
  223. /package/dist/{chunk-HCFNZWFB.js.map → chunk-VBNXDC7P.js.map} +0 -0
  224. /package/dist/{chunk-G3PBNYDH.js.map → chunk-VJ3HFCG2.js.map} +0 -0
  225. /package/dist/{chunk-OBQ2NZAR.js.map → chunk-VKDAJJQP.js.map} +0 -0
  226. /package/dist/{chunk-HZNURRDS.js.map → chunk-VUROWXFL.js.map} +0 -0
  227. /package/dist/{chunk-G5NH3SSX.js.map → chunk-X3KFSJLQ.js.map} +0 -0
  228. /package/dist/{chunk-GCJA5KKT.js.map → chunk-XBNO56HC.js.map} +0 -0
  229. /package/dist/{chunk-GWOFCHPN.js.map → chunk-YGECOOTF.js.map} +0 -0
  230. /package/dist/{chunk-2R7OCBRR.js.map → chunk-YK7GOPIE.js.map} +0 -0
  231. /package/dist/{chunk-ELUG6NKQ.js.map → chunk-YSA4CYTK.js.map} +0 -0
  232. /package/dist/{chunk-233S3MXC.js.map → chunk-YXUNSOHD.js.map} +0 -0
  233. /package/dist/{chunk-MAURCRPQ.js.map → chunk-Z3O7ZOCC.js.map} +0 -0
  234. /package/dist/{chunk-LXDERMOU.js.map → chunk-ZAU2OPDW.js.map} +0 -0
@@ -4,28 +4,28 @@ import {
4
4
  exportOkfBundle,
5
5
  firstHeading,
6
6
  parseIncludeStatus
7
- } from "../chunk-I4LJJ44E.js";
7
+ } from "../chunk-LNHBYT3F.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-5IQL4N37.js";
13
+ import "../chunk-D4WBMLPD.js";
14
14
  import "../chunk-UHVXE24Y.js";
15
15
  import "../chunk-QGVCFVX6.js";
16
16
  import "../chunk-IGOW4TJE.js";
17
17
  import "../chunk-G6OFEGUR.js";
18
18
  import "../chunk-7PMOCQOL.js";
19
- import "../chunk-SHVLNI4L.js";
20
- import "../chunk-OBQ2NZAR.js";
19
+ import "../chunk-LU66I56Q.js";
20
+ import "../chunk-VKDAJJQP.js";
21
21
  import "../chunk-OVZIYLBZ.js";
22
22
  import "../chunk-EXYT52NR.js";
23
- import "../chunk-YK6SFDP2.js";
24
- import "../chunk-P3AQ2YSX.js";
23
+ import "../chunk-DOJBV6WR.js";
24
+ import "../chunk-PFUXPTBT.js";
25
25
  import "../chunk-CYEPCZN5.js";
26
- import "../chunk-FYQUUIPI.js";
27
- import "../chunk-Y5NLBXPV.js";
26
+ import "../chunk-DLZGSZVC.js";
28
27
  import "../chunk-WNEVEMJ3.js";
28
+ import "../chunk-Y5NLBXPV.js";
29
29
  import "../chunk-TFA6HPOA.js";
30
30
  import "../chunk-F4TWWUMP.js";
31
31
  import "../chunk-72A4L5JJ.js";
@@ -1,24 +1,24 @@
1
1
  import {
2
2
  compareVerifiedEpisodeResults,
3
3
  searchVerifiedEpisodes
4
- } from "./chunk-GCJA5KKT.js";
4
+ } from "./chunk-XBNO56HC.js";
5
5
  import "./chunk-B7RWBZXW.js";
6
- import "./chunk-5IQL4N37.js";
6
+ import "./chunk-D4WBMLPD.js";
7
7
  import "./chunk-UHVXE24Y.js";
8
8
  import "./chunk-QGVCFVX6.js";
9
9
  import "./chunk-IGOW4TJE.js";
10
10
  import "./chunk-G6OFEGUR.js";
11
11
  import "./chunk-7PMOCQOL.js";
12
- import "./chunk-SHVLNI4L.js";
13
- import "./chunk-OBQ2NZAR.js";
12
+ import "./chunk-LU66I56Q.js";
13
+ import "./chunk-VKDAJJQP.js";
14
14
  import "./chunk-OVZIYLBZ.js";
15
15
  import "./chunk-EXYT52NR.js";
16
- import "./chunk-YK6SFDP2.js";
17
- import "./chunk-P3AQ2YSX.js";
16
+ import "./chunk-DOJBV6WR.js";
17
+ import "./chunk-PFUXPTBT.js";
18
18
  import "./chunk-CYEPCZN5.js";
19
- import "./chunk-FYQUUIPI.js";
20
- import "./chunk-Y5NLBXPV.js";
19
+ import "./chunk-DLZGSZVC.js";
21
20
  import "./chunk-WNEVEMJ3.js";
21
+ import "./chunk-Y5NLBXPV.js";
22
22
  import "./chunk-TFA6HPOA.js";
23
23
  import "./chunk-F4TWWUMP.js";
24
24
  import "./chunk-72A4L5JJ.js";
@@ -4,24 +4,24 @@ import {
4
4
  renderWhoKnows,
5
5
  renderWhoKnowsJson,
6
6
  renderWhoKnowsText
7
- } from "./chunk-6RPPZL7W.js";
8
- import "./chunk-ELUG6NKQ.js";
9
- import "./chunk-5IQL4N37.js";
7
+ } from "./chunk-SMSJOWVE.js";
8
+ import "./chunk-YSA4CYTK.js";
9
+ import "./chunk-D4WBMLPD.js";
10
10
  import "./chunk-UHVXE24Y.js";
11
11
  import "./chunk-QGVCFVX6.js";
12
12
  import "./chunk-IGOW4TJE.js";
13
13
  import "./chunk-G6OFEGUR.js";
14
14
  import "./chunk-7PMOCQOL.js";
15
- import "./chunk-SHVLNI4L.js";
16
- import "./chunk-OBQ2NZAR.js";
15
+ import "./chunk-LU66I56Q.js";
16
+ import "./chunk-VKDAJJQP.js";
17
17
  import "./chunk-OVZIYLBZ.js";
18
18
  import "./chunk-EXYT52NR.js";
19
- import "./chunk-YK6SFDP2.js";
20
- import "./chunk-P3AQ2YSX.js";
19
+ import "./chunk-DOJBV6WR.js";
20
+ import "./chunk-PFUXPTBT.js";
21
21
  import "./chunk-CYEPCZN5.js";
22
- import "./chunk-FYQUUIPI.js";
23
- import "./chunk-Y5NLBXPV.js";
22
+ import "./chunk-DLZGSZVC.js";
24
23
  import "./chunk-WNEVEMJ3.js";
24
+ import "./chunk-Y5NLBXPV.js";
25
25
  import "./chunk-TFA6HPOA.js";
26
26
  import "./chunk-F4TWWUMP.js";
27
27
  import "./chunk-72A4L5JJ.js";
package/dist/who-knows.js CHANGED
@@ -9,23 +9,23 @@ import {
9
9
  loadWhoKnowsEntities,
10
10
  tokenizeTopic,
11
11
  validateWhoKnowsInput
12
- } from "./chunk-ELUG6NKQ.js";
13
- import "./chunk-5IQL4N37.js";
12
+ } from "./chunk-YSA4CYTK.js";
13
+ import "./chunk-D4WBMLPD.js";
14
14
  import "./chunk-UHVXE24Y.js";
15
15
  import "./chunk-QGVCFVX6.js";
16
16
  import "./chunk-IGOW4TJE.js";
17
17
  import "./chunk-G6OFEGUR.js";
18
18
  import "./chunk-7PMOCQOL.js";
19
- import "./chunk-SHVLNI4L.js";
20
- import "./chunk-OBQ2NZAR.js";
19
+ import "./chunk-LU66I56Q.js";
20
+ import "./chunk-VKDAJJQP.js";
21
21
  import "./chunk-OVZIYLBZ.js";
22
22
  import "./chunk-EXYT52NR.js";
23
- import "./chunk-YK6SFDP2.js";
24
- import "./chunk-P3AQ2YSX.js";
23
+ import "./chunk-DOJBV6WR.js";
24
+ import "./chunk-PFUXPTBT.js";
25
25
  import "./chunk-CYEPCZN5.js";
26
- import "./chunk-FYQUUIPI.js";
27
- import "./chunk-Y5NLBXPV.js";
26
+ import "./chunk-DLZGSZVC.js";
28
27
  import "./chunk-WNEVEMJ3.js";
28
+ import "./chunk-Y5NLBXPV.js";
29
29
  import "./chunk-TFA6HPOA.js";
30
30
  import "./chunk-F4TWWUMP.js";
31
31
  import "./chunk-72A4L5JJ.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "10.0.77",
3
+ "version": "10.0.79",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -3386,7 +3386,7 @@
3386
3386
  "core"
3387
3387
  ],
3388
3388
  "peerDependencies": {
3389
- "@remnic/coding-graph": "^10.0.77"
3389
+ "@remnic/coding-graph": "^10.0.79"
3390
3390
  },
3391
3391
  "peerDependenciesMeta": {
3392
3392
  "@remnic/coding-graph": {
@@ -337,3 +337,62 @@ test("LocalLlmClient resolves queued work to null when request execution throws"
337
337
 
338
338
  assert.equal(result, null);
339
339
  });
340
+
341
+ test("LocalLlmClient includes queue wait in the exhausted-abort warning", async () => {
342
+ const logs: string[] = [];
343
+ initLogger(
344
+ {
345
+ info(msg: string) {
346
+ logs.push(`info:${msg}`);
347
+ },
348
+ warn(msg: string) {
349
+ logs.push(`warn:${msg}`);
350
+ },
351
+ error(msg: string) {
352
+ logs.push(`error:${msg}`);
353
+ },
354
+ debug(msg: string) {
355
+ logs.push(`debug:${msg}`);
356
+ },
357
+ },
358
+ true,
359
+ );
360
+
361
+ const originalNow = Date.now;
362
+ let now = originalNow();
363
+ Date.now = () => now;
364
+ const client = new LocalLlmClient(createConfig());
365
+ client["isAvailable"] = true;
366
+ client["lastHealthCheck"] = Date.now();
367
+ const originalFetch = globalThis.fetch;
368
+ const holderResponse = Promise.withResolvers<Response>();
369
+ let calls = 0;
370
+ globalThis.fetch = async () => {
371
+ calls += 1;
372
+ if (calls === 1) return await holderResponse.promise;
373
+ throw new DOMException("request aborted", "AbortError");
374
+ };
375
+
376
+ try {
377
+ const holder = client.chatCompletion(
378
+ [{ role: "user", content: "hold" }],
379
+ { operation: "queue-holder", priority: "background" },
380
+ );
381
+ await tick();
382
+ const summarize = client.chatCompletion(
383
+ [{ role: "user", content: "summarize" }],
384
+ { operation: "lcm-summarize", priority: "background" },
385
+ );
386
+ now += 50;
387
+ holderResponse.resolve(okResponse("held"));
388
+ await holder;
389
+ assert.equal(await summarize, null);
390
+ assert.match(
391
+ logs.join("\n"),
392
+ /local LLM request aborted after \d+ attempt\(s\): op=lcm-summarize timeoutMs=\d+ model=test-local-model promptChars=\d+ durationMs=\d+ waitMs=50/,
393
+ );
394
+ } finally {
395
+ globalThis.fetch = originalFetch;
396
+ Date.now = originalNow;
397
+ }
398
+ });
package/src/local-llm.ts CHANGED
@@ -1093,7 +1093,7 @@ export class LocalLlmClient {
1093
1093
  if (!response) {
1094
1094
  if (lastAbortError) {
1095
1095
  log.warn(
1096
- `local LLM request aborted after ${maxAttempts} attempt(s): op=${operation} timeoutMs=${effectiveTimeoutMs} model=${this.config.localLlmModel} promptChars=${promptChars} durationMs=${Date.now() - startedAtMs}`,
1096
+ `local LLM request aborted after ${maxAttempts} attempt(s): op=${operation} timeoutMs=${effectiveTimeoutMs} model=${this.config.localLlmModel} promptChars=${promptChars} durationMs=${Date.now() - startedAtMs}${queueMeta ? ` waitMs=${startedAtMs - queueMeta.enqueuedAtMs}` : ""}`,
1097
1097
  );
1098
1098
  } else {
1099
1099
  log.warn(
@@ -0,0 +1,403 @@
1
+ import assert from "node:assert/strict";
2
+ import { chmod, mkdir, mkdtemp, readFile, readdir, rm, stat, utimes, writeFile } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test, { mock } from "node:test";
6
+ import { parseConfig } from "./config.js";
7
+ import { JsonlOwnershipDigestCache } from "./transcript-ownership-digest.js";
8
+ import { TranscriptManager } from "./transcript.js";
9
+ import type { TranscriptEntry } from "./types.js";
10
+
11
+ function makeConfig(memoryDir: string) {
12
+ return parseConfig({ memoryDir });
13
+ }
14
+
15
+ async function withManager(
16
+ fn: (ctx: { manager: TranscriptManager; memoryDir: string; root: string }) => Promise<void>,
17
+ ): Promise<void> {
18
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-transcript-digest-"));
19
+ try {
20
+ const manager = new TranscriptManager(makeConfig(memoryDir));
21
+ await manager.initialize();
22
+ await fn({ manager, memoryDir, root: path.join(memoryDir, "transcripts") });
23
+ } finally {
24
+ await rm(memoryDir, { recursive: true, force: true });
25
+ }
26
+ }
27
+
28
+ function entry(sessionKey: string, turnId: string): TranscriptEntry {
29
+ return {
30
+ timestamp: new Date().toISOString(),
31
+ role: "user",
32
+ content: `turn ${turnId}`,
33
+ sessionKey,
34
+ turnId,
35
+ };
36
+ }
37
+
38
+ async function jsonlContents(dir: string): Promise<string> {
39
+ const names = (await readdir(dir).catch(() => [])).filter((n) => n.endsWith(".jsonl")).sort();
40
+ const parts = await Promise.all(names.map((n) => readFile(path.join(dir, n), "utf-8")));
41
+ return parts.join("");
42
+ }
43
+
44
+ /** Overwrite a file in place with the same byte length and the same mtime. */
45
+ async function rewriteSameSize(filePath: string, transform: (text: string) => string): Promise<void> {
46
+ const before = await stat(filePath);
47
+ const original = await readFile(filePath, "utf-8");
48
+ const rewritten = transform(original);
49
+ assert.equal(Buffer.byteLength(rewritten), Buffer.byteLength(original), "test must keep byte length");
50
+ assert.notEqual(rewritten, original);
51
+ await writeFile(filePath, rewritten, "utf-8");
52
+ await utimes(filePath, before.atime, before.mtime);
53
+ assert.equal((await stat(filePath)).size, before.size);
54
+ }
55
+
56
+ test("same-size foreign rewrite with restored mtime is never served a cached owner verdict", async () => {
57
+ await withManager(async ({ manager, root }) => {
58
+ const owner = "pi-geek:digest-same-a";
59
+ const intruder = "pi-geek:digest-same-b";
60
+ assert.equal(owner.length, intruder.length);
61
+ const { dir, alternateDir, file } = manager.getTranscriptPath(owner);
62
+ await manager.append(entry(owner, "1"));
63
+ await manager.append(entry(owner, "2"));
64
+ const primary = path.join(root, dir, file);
65
+ await rewriteSameSize(primary, (text) => text.replaceAll(owner, intruder));
66
+
67
+ await manager.append(entry(owner, "3"));
68
+
69
+ const primaryText = await jsonlContents(path.join(root, dir));
70
+ assert.equal(primaryText.includes('"turnId":"3"'), false, "owner turn must not join foreign-content directory");
71
+ assert.equal(primaryText.includes(owner), false);
72
+ const alternateText = await jsonlContents(path.join(root, alternateDir));
73
+ assert.equal(alternateText.includes('"turnId":"3"'), true);
74
+ });
75
+ });
76
+
77
+ test("same-size malformed rewrite with restored mtime is never served a cached owner verdict", async () => {
78
+ await withManager(async ({ manager, root }) => {
79
+ const owner = "pi-geek:digest-malformed";
80
+ const { dir, alternateDir, file } = manager.getTranscriptPath(owner);
81
+ await manager.append(entry(owner, "1"));
82
+ await manager.append(entry(owner, "2"));
83
+ const primary = path.join(root, dir, file);
84
+ await rewriteSameSize(primary, (text) => text.replace('{"timestamp"', '{"timestamp:'));
85
+
86
+ await manager.append(entry(owner, "3"));
87
+
88
+ assert.equal((await jsonlContents(path.join(root, dir))).includes('"turnId":"3"'), false);
89
+ assert.equal((await jsonlContents(path.join(root, alternateDir))).includes('"turnId":"3"'), true);
90
+ });
91
+ });
92
+
93
+ test("a read error after a cached owner verdict makes the directory occupied", async (t) => {
94
+ if (process.getuid?.() === 0) {
95
+ t.skip("root bypasses file permissions");
96
+ return;
97
+ }
98
+ await withManager(async ({ manager, root }) => {
99
+ const owner = "pi-geek:digest-readerr";
100
+ const { dir, alternateDir, file } = manager.getTranscriptPath(owner);
101
+ await manager.append(entry(owner, "1"));
102
+ await manager.append(entry(owner, "2"));
103
+ const primary = path.join(root, dir, file);
104
+ await chmod(primary, 0o000);
105
+ try {
106
+ await manager.append(entry(owner, "3"));
107
+ } finally {
108
+ await chmod(primary, 0o600);
109
+ }
110
+
111
+ assert.equal((await jsonlContents(path.join(root, dir))).includes('"turnId":"3"'), false);
112
+ assert.equal((await jsonlContents(path.join(root, alternateDir))).includes('"turnId":"3"'), true);
113
+ });
114
+ });
115
+
116
+ test("editing a cached prefix while the file grows is detected by content, not size", async () => {
117
+ await withManager(async ({ manager, root }) => {
118
+ const owner = "pi-geek:digest-prefix-a";
119
+ const intruder = "pi-geek:digest-prefix-b";
120
+ const { dir, alternateDir, file } = manager.getTranscriptPath(owner);
121
+ for (const id of ["1", "2", "3"]) await manager.append(entry(owner, id));
122
+ const primary = path.join(root, dir, file);
123
+ const text = await readFile(primary, "utf-8");
124
+ const [first, ...rest] = text.split("\n");
125
+ await writeFile(primary, [first.replace(owner, intruder), ...rest].join("\n"), "utf-8");
126
+ const grown = (await readFile(primary, "utf-8")) + JSON.stringify(entry(owner, "x")) + "\n";
127
+ await writeFile(primary, grown, "utf-8");
128
+
129
+ await manager.append(entry(owner, "4"));
130
+
131
+ assert.equal((await jsonlContents(path.join(root, dir))).includes('"turnId":"4"'), false);
132
+ assert.equal((await jsonlContents(path.join(root, alternateDir))).includes('"turnId":"4"'), true);
133
+ });
134
+ });
135
+
136
+ test("an owner's cached verdict is never shared with another session on the same directory", async () => {
137
+ await withManager(async ({ manager, root }) => {
138
+ const a = "agent:alpha:discord:channel:777";
139
+ const b = "agent:beta:discord:channel:777";
140
+ const pa = manager.getTranscriptPath(a);
141
+ const pb = manager.getTranscriptPath(b);
142
+ assert.equal(pa.dir, pb.dir, "legacy keys must share a channel directory for this test");
143
+ await manager.append(entry(a, "1"));
144
+ await manager.append(entry(a, "2"));
145
+
146
+ await manager.append(entry(b, "1"));
147
+
148
+ const shared = await jsonlContents(path.join(root, pa.dir));
149
+ assert.equal(shared.includes(b), false, "foreign session must not write into the owner's directory");
150
+ assert.equal((await jsonlContents(path.join(root, pb.alternateDir))).includes(b), true);
151
+ });
152
+ });
153
+
154
+ test("steady-state appends parse only new lines, not the accumulated history", async () => {
155
+ await withManager(async ({ manager, root }) => {
156
+ const owner = "pi-geek:digest-steady";
157
+ const { dir } = manager.getTranscriptPath(owner);
158
+ const channelDir = path.join(root, dir);
159
+ await mkdir(channelDir, { recursive: true });
160
+ const linesPerDay = 100;
161
+ for (let day = 1; day <= 20; day++) {
162
+ const date = new Date(Date.UTC(2026, 8, day)).toISOString().slice(0, 10);
163
+ const lines = Array.from({ length: linesPerDay }, (_, i) =>
164
+ JSON.stringify({ ...entry(owner, `h${day}-${i}`), timestamp: `${date}T12:00:00.000Z` }),
165
+ );
166
+ await writeFile(path.join(channelDir, `${date}.jsonl`), lines.join("\n") + "\n", "utf-8");
167
+ }
168
+
169
+ const parseSpy = mock.method(JSON, "parse");
170
+ try {
171
+ await manager.append(entry(owner, "a1"));
172
+ assert.ok(parseSpy.mock.callCount() >= 20 * linesPerDay, "first append must verify the full history");
173
+ for (const id of ["a2", "a3", "a4"]) {
174
+ parseSpy.mock.resetCalls();
175
+ await manager.append(entry(owner, id));
176
+ const parses = parseSpy.mock.callCount();
177
+ assert.ok(parses <= 2, `append ${id} re-parsed ${parses} lines`);
178
+ }
179
+ } finally {
180
+ parseSpy.mock.restore();
181
+ }
182
+ });
183
+ });
184
+
185
+ test("digest cache: bounded size, exact verdicts across eviction", async () => {
186
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-digest-cache-"));
187
+ try {
188
+ const key = "pi-geek:cache-bound";
189
+ const line = JSON.stringify({ sessionKey: key, content: "x" }) + "\n";
190
+ const cache = new JsonlOwnershipDigestCache(2);
191
+ const files = ["a", "b", "c"].map((n) => path.join(dir, `${n}.jsonl`));
192
+ for (const f of files) await writeFile(f, line, "utf-8");
193
+ for (const f of files) assert.equal(await cache.verify(f, key), "matches");
194
+ assert.ok(cache.size <= 2, `cache grew to ${cache.size}`);
195
+ for (const f of files) assert.equal(await cache.verify(f, key), "matches");
196
+ assert.ok(cache.size <= 2);
197
+ } finally {
198
+ await rm(dir, { recursive: true, force: true });
199
+ }
200
+ });
201
+
202
+ test("digest cache: verdicts are keyed by session and re-derived from bytes", async () => {
203
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-digest-cache-"));
204
+ try {
205
+ const cache = new JsonlOwnershipDigestCache();
206
+ const file = path.join(dir, "d.jsonl");
207
+ const mine = "pi-geek:cache-mine";
208
+ const other = "pi-geek:cache-othr";
209
+ await writeFile(file, JSON.stringify({ sessionKey: mine }) + "\n", "utf-8");
210
+ assert.equal(await cache.verify(file, mine), "matches");
211
+ assert.equal(await cache.verify(file, other), "foreign");
212
+ assert.equal(await cache.verify(file, mine), "matches");
213
+
214
+ await writeFile(file, "\n \n", "utf-8");
215
+ assert.equal(await cache.verify(file, mine), "empty");
216
+
217
+ await writeFile(file, "null\n", "utf-8");
218
+ assert.equal(await cache.verify(file, mine), "foreign", "JSON null has no owner");
219
+ await writeFile(file, "42\n", "utf-8");
220
+ assert.equal(await cache.verify(file, mine), "foreign");
221
+ } finally {
222
+ await rm(dir, { recursive: true, force: true });
223
+ }
224
+ });
225
+
226
+ test("digest cache: unterminated trailing line is judged but never cached as complete", async () => {
227
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-digest-cache-"));
228
+ try {
229
+ const cache = new JsonlOwnershipDigestCache();
230
+ const file = path.join(dir, "p.jsonl");
231
+ const key = "pi-geek:cache-partial";
232
+ const good = JSON.stringify({ sessionKey: key, n: 1 });
233
+ await writeFile(file, `${good}\n${good.slice(0, -4)}`, "utf-8");
234
+ assert.equal(await cache.verify(file, key), "foreign", "torn trailing line is malformed");
235
+
236
+ await writeFile(file, `${good}\n${good}`, "utf-8");
237
+ assert.equal(await cache.verify(file, key), "matches", "valid unterminated last line counts");
238
+
239
+ await writeFile(file, `${good}\n${good}\n`, "utf-8");
240
+ assert.equal(await cache.verify(file, key), "matches");
241
+
242
+ await writeFile(file, `${good}\n`, "utf-8");
243
+ assert.equal(await cache.verify(file, key), "matches", "truncation re-derives from bytes");
244
+
245
+ await writeFile(file, `${good.replace(key, "pi-geek:cache-other")}\n`, "utf-8");
246
+ assert.equal(await cache.verify(file, key), "foreign", "same-length foreign replacement");
247
+ } finally {
248
+ await rm(dir, { recursive: true, force: true });
249
+ }
250
+ });
251
+
252
+ test("digest cache: read errors surface to the caller instead of a cached verdict", async () => {
253
+ const dir = await mkdtemp(path.join(os.tmpdir(), "remnic-digest-cache-"));
254
+ try {
255
+ const cache = new JsonlOwnershipDigestCache();
256
+ const file = path.join(dir, "gone.jsonl");
257
+ const key = "pi-geek:cache-gone";
258
+ await writeFile(file, JSON.stringify({ sessionKey: key }) + "\n", "utf-8");
259
+ assert.equal(await cache.verify(file, key), "matches");
260
+ await rm(file);
261
+ await assert.rejects(cache.verify(file, key));
262
+ } finally {
263
+ await rm(dir, { recursive: true, force: true });
264
+ }
265
+ });
266
+
267
+ async function seedFiles(root: string, dir: string, files: Record<string, string>): Promise<void> {
268
+ const channelDir = path.join(root, dir);
269
+ await mkdir(channelDir, { recursive: true });
270
+ for (const [name, text] of Object.entries(files)) await writeFile(path.join(channelDir, name), text, "utf-8");
271
+ }
272
+
273
+ function line(sessionKey: string, id: string): string {
274
+ return `${JSON.stringify(entry(sessionKey, id))}\n`;
275
+ }
276
+
277
+ const MIXED_CASES: Array<{
278
+ name: string;
279
+ owned: boolean;
280
+ files: (owner: string, other: string) => Record<string, string>;
281
+ }> = [
282
+ {
283
+ name: "every file owned",
284
+ owned: true,
285
+ files: (o) => ({ "2026-01-01.jsonl": line(o, "a") + line(o, "b"), "2026-01-02.jsonl": line(o, "c"), "2026-01-03.jsonl": line(o, "d") }),
286
+ },
287
+ {
288
+ name: "owned files around a blank-only file",
289
+ owned: true,
290
+ files: (o) => ({ "2026-01-01.jsonl": line(o, "a"), "2026-01-02.jsonl": "\n \n", "2026-01-03.jsonl": line(o, "b") }),
291
+ },
292
+ {
293
+ name: "only blank files",
294
+ owned: true,
295
+ files: () => ({ "2026-01-01.jsonl": "\n", "2026-01-02.jsonl": " \n" }),
296
+ },
297
+ {
298
+ name: "foreign file after owned files",
299
+ owned: false,
300
+ files: (o, x) => ({ "2026-01-01.jsonl": line(o, "a"), "2026-01-02.jsonl": line(o, "b"), "2026-01-03.jsonl": line(x, "f") }),
301
+ },
302
+ {
303
+ name: "foreign file before owned files",
304
+ owned: false,
305
+ files: (o, x) => ({ "2026-01-01.jsonl": line(x, "f"), "2026-01-02.jsonl": line(o, "a") }),
306
+ },
307
+ {
308
+ name: "foreign line inside an otherwise owned file",
309
+ owned: false,
310
+ files: (o, x) => ({ "2026-01-01.jsonl": line(o, "a") + line(x, "f") + line(o, "b"), "2026-01-02.jsonl": line(o, "c") }),
311
+ },
312
+ {
313
+ name: "malformed line in a middle file",
314
+ owned: false,
315
+ files: (o) => ({ "2026-01-01.jsonl": line(o, "a"), "2026-01-02.jsonl": line(o, "b") + "{not json\n", "2026-01-03.jsonl": line(o, "c") }),
316
+ },
317
+ {
318
+ name: "torn unterminated final line",
319
+ owned: false,
320
+ files: (o) => ({ "2026-01-01.jsonl": line(o, "a"), "2026-01-02.jsonl": line(o, "b") + line(o, "c").slice(0, -6) }),
321
+ },
322
+ {
323
+ name: "JSON null line",
324
+ owned: false,
325
+ files: (o) => ({ "2026-01-01.jsonl": line(o, "a") + "null\n" }),
326
+ },
327
+ {
328
+ name: "JSON scalar line",
329
+ owned: false,
330
+ files: (o) => ({ "2026-01-01.jsonl": line(o, "a"), "2026-01-02.jsonl": "42\n" }),
331
+ },
332
+ {
333
+ name: "JSON array line",
334
+ owned: false,
335
+ files: (o) => ({ "2026-01-01.jsonl": line(o, "a"), "2026-01-02.jsonl": "[1]\n" }),
336
+ },
337
+ ];
338
+
339
+ for (const mixed of MIXED_CASES) {
340
+ test(`multi-file directory verdict is the conjunction of every file: ${mixed.name}`, async () => {
341
+ await withManager(async ({ manager, root }) => {
342
+ const owner = "pi-geek:digest-mixed-own";
343
+ const other = "pi-geek:digest-mixed-oth";
344
+ const { dir, alternateDir } = manager.getTranscriptPath(owner);
345
+ await seedFiles(root, dir, mixed.files(owner, other));
346
+
347
+ await manager.append(entry(owner, "new"));
348
+
349
+ assert.equal((await jsonlContents(path.join(root, dir))).includes('"turnId":"new"'), mixed.owned);
350
+ assert.equal((await jsonlContents(path.join(root, alternateDir))).includes('"turnId":"new"'), !mixed.owned);
351
+ });
352
+ });
353
+ }
354
+
355
+ const HISTORY = ["2026-01-01.jsonl", "2026-01-02.jsonl", "2026-01-03.jsonl", "2026-01-04.jsonl", "2026-01-05.jsonl"];
356
+
357
+ async function warmedHistory(manager: TranscriptManager, root: string, owner: string): Promise<string> {
358
+ const { dir } = manager.getTranscriptPath(owner);
359
+ await seedFiles(
360
+ root,
361
+ dir,
362
+ Object.fromEntries(HISTORY.map((name, i) => [name, line(owner, `h${i}a`) + line(owner, `h${i}b`)])),
363
+ );
364
+ await manager.append(entry(owner, "warm-1"));
365
+ await manager.append(entry(owner, "warm-2"));
366
+ return path.join(root, dir, HISTORY[2]);
367
+ }
368
+
369
+ test("warm multi-file directory: equal-size restored-mtime foreign rewrite of an older file is re-derived, and restoring owned bytes restores ownership", async () => {
370
+ await withManager(async ({ manager, root }) => {
371
+ const owner = "pi-geek:digest-multi-a";
372
+ const intruder = "pi-geek:digest-multi-b";
373
+ const { dir, alternateDir } = manager.getTranscriptPath(owner);
374
+ const target = await warmedHistory(manager, root, owner);
375
+ const original = await readFile(target, "utf-8");
376
+ await rewriteSameSize(target, (text) => text.replaceAll(owner, intruder));
377
+
378
+ await manager.append(entry(owner, "after-foreign"));
379
+
380
+ assert.equal((await jsonlContents(path.join(root, dir))).includes('"turnId":"after-foreign"'), false);
381
+ assert.equal((await jsonlContents(path.join(root, alternateDir))).includes('"turnId":"after-foreign"'), true);
382
+
383
+ await writeFile(target, original, "utf-8");
384
+ await manager.append(entry(owner, "after-restore"));
385
+
386
+ assert.equal((await jsonlContents(path.join(root, dir))).includes('"turnId":"after-restore"'), true);
387
+ assert.equal((await jsonlContents(path.join(root, alternateDir))).includes('"turnId":"after-restore"'), false);
388
+ });
389
+ });
390
+
391
+ test("warm multi-file directory: equal-size restored-mtime malformed rewrite of an older file is re-derived", async () => {
392
+ await withManager(async ({ manager, root }) => {
393
+ const owner = "pi-geek:digest-multi-m";
394
+ const { dir, alternateDir } = manager.getTranscriptPath(owner);
395
+ const target = await warmedHistory(manager, root, owner);
396
+ await rewriteSameSize(target, (text) => text.replace('{"timestamp"', '{"timestamp:'));
397
+
398
+ await manager.append(entry(owner, "after-malformed"));
399
+
400
+ assert.equal((await jsonlContents(path.join(root, dir))).includes('"turnId":"after-malformed"'), false);
401
+ assert.equal((await jsonlContents(path.join(root, alternateDir))).includes('"turnId":"after-malformed"'), true);
402
+ });
403
+ });