@remnic/core 9.69.77 → 9.69.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 (211) 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 +53 -53
  5. package/dist/access-extraction-force-flush.js +12 -12
  6. package/dist/access-http-briefing.js +13 -13
  7. package/dist/access-http-lcm-compaction.d.ts +2 -1
  8. package/dist/access-http-lcm-compaction.d.ts.map +1 -1
  9. package/dist/access-http-lcm-compaction.js +1 -1
  10. package/dist/access-http-lifecycle-flush.d.ts.map +1 -1
  11. package/dist/access-http-lifecycle-flush.js +2 -2
  12. package/dist/access-http-query.js +14 -14
  13. package/dist/access-http.js +30 -30
  14. package/dist/access-identity-continuity-surface.js +12 -12
  15. package/dist/access-lcm-surface.js +12 -12
  16. package/dist/access-mcp.js +21 -21
  17. package/dist/access-namespace-preflight.js +12 -12
  18. package/dist/access-observe-write-surface.js +12 -12
  19. package/dist/access-operations-batch.js +13 -13
  20. package/dist/access-operations.js +20 -20
  21. package/dist/access-recall-concurrency.js +12 -12
  22. package/dist/access-recall-response.js +12 -12
  23. package/dist/access-recall-surface.js +12 -12
  24. package/dist/access-service-helpers.d.ts +1 -0
  25. package/dist/access-service-helpers.d.ts.map +1 -1
  26. package/dist/access-service-helpers.js +1 -1
  27. package/dist/access-service.js +12 -12
  28. package/dist/access-surface-catalog.js +14 -14
  29. package/dist/active-recall.js +2 -2
  30. package/dist/briefing.js +2 -2
  31. package/dist/causal-consolidation.js +3 -3
  32. package/dist/{chunk-TIDEL77O.js → chunk-2BPPGNAQ.js} +4 -3
  33. package/dist/chunk-2BPPGNAQ.js.map +1 -0
  34. package/dist/{chunk-3AGCSD42.js → chunk-3GN2PEOT.js} +2 -2
  35. package/dist/{chunk-RGX4DGOG.js → chunk-3XQYM4RE.js} +2 -2
  36. package/dist/{chunk-GATQP7CE.js → chunk-4V44AA7O.js} +2 -2
  37. package/dist/{chunk-RRMIACBG.js → chunk-55FCXCXJ.js} +7 -3
  38. package/dist/{chunk-RRMIACBG.js.map → chunk-55FCXCXJ.js.map} +1 -1
  39. package/dist/{chunk-2L5FSNPC.js → chunk-5FNZ3G6X.js} +40 -11
  40. package/dist/chunk-5FNZ3G6X.js.map +1 -0
  41. package/dist/{chunk-7QXTCONH.js → chunk-7QK5TUTW.js} +2 -2
  42. package/dist/{chunk-OJ3TV57W.js → chunk-7UUKRS3J.js} +2 -2
  43. package/dist/{chunk-DCPAAAIC.js → chunk-AXDOF4VI.js} +2 -2
  44. package/dist/{chunk-RKTT72XV.js → chunk-B47OHVFT.js} +4 -4
  45. package/dist/chunk-B47OHVFT.js.map +1 -0
  46. package/dist/{chunk-NYZRJW5X.js → chunk-BJX3VQWZ.js} +2 -2
  47. package/dist/{chunk-3QL24R5Y.js → chunk-C2WWQ4OR.js} +1 -1
  48. package/dist/chunk-C2WWQ4OR.js.map +1 -0
  49. package/dist/{chunk-CDEI5S5W.js → chunk-C7JAUNFC.js} +2 -2
  50. package/dist/{chunk-MQQPONTM.js → chunk-CK5U7JGH.js} +2 -2
  51. package/dist/{chunk-RDUM6BKQ.js → chunk-CRKWSSS4.js} +2 -2
  52. package/dist/{chunk-XNYTMLPS.js → chunk-DGAWEJVI.js} +2 -2
  53. package/dist/{chunk-GZ3R6XOE.js → chunk-DJSJ4ULL.js} +22 -12
  54. package/dist/chunk-DJSJ4ULL.js.map +1 -0
  55. package/dist/{chunk-SUSMEKBE.js → chunk-EU3N5MK3.js} +3 -3
  56. package/dist/{chunk-QJAGDPY7.js → chunk-FYAU4S6E.js} +3 -3
  57. package/dist/{chunk-LEP46X5Y.js → chunk-GEX5NI36.js} +2 -2
  58. package/dist/{chunk-X3NZ2HAO.js → chunk-GZAGLCQH.js} +2 -2
  59. package/dist/{chunk-AVO2CBIL.js → chunk-HKFJ3PF3.js} +2 -2
  60. package/dist/{chunk-K2SXIWEV.js → chunk-IA3X2Y4K.js} +2 -2
  61. package/dist/{chunk-QIDMGBUY.js → chunk-IMAP236M.js} +2 -2
  62. package/dist/{chunk-OHRIBMSS.js → chunk-JS3S2HVG.js} +2 -2
  63. package/dist/{chunk-FVK5NQ3V.js → chunk-JVY556FW.js} +2 -2
  64. package/dist/{chunk-3K3PITOE.js → chunk-JXMECXMF.js} +2 -2
  65. package/dist/{chunk-NGFRFDSK.js → chunk-KERNN6BC.js} +2 -2
  66. package/dist/{chunk-LZLJK2IA.js → chunk-L2LBMKSI.js} +5 -5
  67. package/dist/{chunk-NHV6WCM5.js → chunk-ML2MVAEZ.js} +1 -1
  68. package/dist/{chunk-TPDBFYEG.js → chunk-MMCO4SRG.js} +17 -6
  69. package/dist/chunk-MMCO4SRG.js.map +1 -0
  70. package/dist/{chunk-GXQ5GDUH.js → chunk-N3MNDVJO.js} +2 -2
  71. package/dist/{chunk-WGXWZE3K.js → chunk-NAYBHNGN.js} +2 -2
  72. package/dist/{chunk-X33QB7LW.js → chunk-NKFLHW7J.js} +2 -2
  73. package/dist/{chunk-GARVFCV6.js → chunk-NMBX4D7P.js} +2 -2
  74. package/dist/{chunk-A2XDQ3JW.js → chunk-OM5BIPBR.js} +2 -2
  75. package/dist/{chunk-ALOMLIRC.js → chunk-Q5TRJ4BX.js} +26 -21
  76. package/dist/chunk-Q5TRJ4BX.js.map +1 -0
  77. package/dist/{chunk-ZYBLNHUB.js → chunk-QB75LKQQ.js} +3 -3
  78. package/dist/{chunk-2CH6MMO2.js → chunk-RDEUG2M2.js} +5 -5
  79. package/dist/{chunk-5X7ZTLFS.js → chunk-RIEX7NOZ.js} +2 -2
  80. package/dist/{chunk-ZWWF7PI5.js → chunk-S42HZILI.js} +2 -2
  81. package/dist/{chunk-YUAOU2B2.js → chunk-S55WTPFJ.js} +3 -5
  82. package/dist/chunk-S55WTPFJ.js.map +1 -0
  83. package/dist/{chunk-RMG22TH2.js → chunk-SQDKX4RW.js} +2 -2
  84. package/dist/{chunk-2GKLHU2D.js → chunk-SV72F4DS.js} +2 -2
  85. package/dist/{chunk-FMT52ROU.js → chunk-SVZWVZ7E.js} +11 -11
  86. package/dist/chunk-SVZWVZ7E.js.map +1 -0
  87. package/dist/{chunk-6MJGDUC7.js → chunk-T4BE5KJM.js} +3 -3
  88. package/dist/{chunk-7DZHRPCO.js → chunk-T4QGUXCV.js} +2 -2
  89. package/dist/{chunk-IILMR37Z.js → chunk-TEV2JGU5.js} +12 -12
  90. package/dist/{chunk-UKB7ZDKK.js → chunk-TIQZNDZ5.js} +2 -2
  91. package/dist/{chunk-7WO66MKJ.js → chunk-UNJOB4DY.js} +2 -2
  92. package/dist/{chunk-DSQWTXHP.js → chunk-W75BBBSY.js} +8 -8
  93. package/dist/{chunk-YL273SOF.js → chunk-WB2I2EQK.js} +2 -2
  94. package/dist/{chunk-CYCE3L2I.js → chunk-X22B4KTI.js} +18 -18
  95. package/dist/cli.js +42 -42
  96. package/dist/coding/export-okf-codegraph.js +1 -1
  97. package/dist/compounding/engine.js +2 -2
  98. package/dist/config.js +2 -2
  99. package/dist/connectors/codex-materialize-runner.js +2 -2
  100. package/dist/connectors/index.js +2 -2
  101. package/dist/convergence-refresh.js +4 -4
  102. package/dist/corpus-watermark.js +4 -4
  103. package/dist/entity-retrieval.js +2 -2
  104. package/dist/external-wiki-access.js +13 -13
  105. package/dist/extraction.js +2 -2
  106. package/dist/harmonic-retrieval.js +1 -1
  107. package/dist/index.js +53 -53
  108. package/dist/lcm/engine.d.ts +2 -2
  109. package/dist/lcm/engine.d.ts.map +1 -1
  110. package/dist/lcm/engine.js +2 -2
  111. package/dist/lcm/index.js +2 -2
  112. package/dist/lcm/queue.d.ts +1 -1
  113. package/dist/lcm/queue.d.ts.map +1 -1
  114. package/dist/lcm/queue.js +1 -1
  115. package/dist/lifecycle/seed-graduation.d.ts.map +1 -1
  116. package/dist/location/index.js +4 -4
  117. package/dist/maintenance/memory-governance.js +2 -2
  118. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +2 -2
  119. package/dist/maintenance/rebuild-memory-projection.js +3 -3
  120. package/dist/memory-browse-operations.js +13 -13
  121. package/dist/namespaces/migrate.js +3 -3
  122. package/dist/namespaces/storage.js +2 -2
  123. package/dist/operator-doctor-corpus.js +5 -5
  124. package/dist/operator-toolkit.js +11 -11
  125. package/dist/orchestration/lifecycle-policy-coordinator.d.ts.map +1 -1
  126. package/dist/orchestration/maintenance.js +10 -10
  127. package/dist/orchestrator.js +53 -53
  128. package/dist/recall-navigation-operations.js +13 -13
  129. package/dist/recall-navigation.js +12 -12
  130. package/dist/resume-bundles.js +3 -3
  131. package/dist/semantic-consolidation.js +3 -3
  132. package/dist/semantic-rule-promotion.js +2 -2
  133. package/dist/semantic-rule-verifier.js +2 -2
  134. package/dist/source-agent-qualifier.js +2 -2
  135. package/dist/standup/build.js +2 -2
  136. package/dist/storage.d.ts.map +1 -1
  137. package/dist/storage.js +1 -1
  138. package/dist/support-passport/index.js +15 -15
  139. package/dist/transfer/export-okf.js +2 -2
  140. package/dist/verified-recall.js +2 -2
  141. package/dist/who-knows-cli.js +3 -3
  142. package/dist/who-knows.js +2 -2
  143. package/package.json +2 -2
  144. package/src/access-http-extraction-force-flush.test.ts +6 -2
  145. package/src/access-http-lcm-compaction.abort.test.ts +60 -0
  146. package/src/access-http-lcm-compaction.ts +20 -9
  147. package/src/access-http-lifecycle-flush.ts +1 -0
  148. package/src/access-http.test.ts +4 -2
  149. package/src/access-operations-batch.ts +1 -1
  150. package/src/access-service-helpers.ts +1 -0
  151. package/src/access-service.ts +2 -2
  152. package/src/lcm/engine.ts +39 -9
  153. package/src/lcm/queue.test.ts +19 -0
  154. package/src/lcm/queue.ts +16 -5
  155. package/src/lcm-engine.test.ts +72 -0
  156. package/src/lifecycle/seed-graduation.test.ts +124 -0
  157. package/src/lifecycle/seed-graduation.ts +7 -2
  158. package/src/orchestration/lifecycle-policy-coordinator.ts +6 -1
  159. package/src/storage.ts +2 -4
  160. package/dist/chunk-2L5FSNPC.js.map +0 -1
  161. package/dist/chunk-3QL24R5Y.js.map +0 -1
  162. package/dist/chunk-ALOMLIRC.js.map +0 -1
  163. package/dist/chunk-FMT52ROU.js.map +0 -1
  164. package/dist/chunk-GZ3R6XOE.js.map +0 -1
  165. package/dist/chunk-RKTT72XV.js.map +0 -1
  166. package/dist/chunk-TIDEL77O.js.map +0 -1
  167. package/dist/chunk-TPDBFYEG.js.map +0 -1
  168. package/dist/chunk-YUAOU2B2.js.map +0 -1
  169. /package/dist/{chunk-3AGCSD42.js.map → chunk-3GN2PEOT.js.map} +0 -0
  170. /package/dist/{chunk-RGX4DGOG.js.map → chunk-3XQYM4RE.js.map} +0 -0
  171. /package/dist/{chunk-GATQP7CE.js.map → chunk-4V44AA7O.js.map} +0 -0
  172. /package/dist/{chunk-7QXTCONH.js.map → chunk-7QK5TUTW.js.map} +0 -0
  173. /package/dist/{chunk-OJ3TV57W.js.map → chunk-7UUKRS3J.js.map} +0 -0
  174. /package/dist/{chunk-DCPAAAIC.js.map → chunk-AXDOF4VI.js.map} +0 -0
  175. /package/dist/{chunk-NYZRJW5X.js.map → chunk-BJX3VQWZ.js.map} +0 -0
  176. /package/dist/{chunk-CDEI5S5W.js.map → chunk-C7JAUNFC.js.map} +0 -0
  177. /package/dist/{chunk-MQQPONTM.js.map → chunk-CK5U7JGH.js.map} +0 -0
  178. /package/dist/{chunk-RDUM6BKQ.js.map → chunk-CRKWSSS4.js.map} +0 -0
  179. /package/dist/{chunk-XNYTMLPS.js.map → chunk-DGAWEJVI.js.map} +0 -0
  180. /package/dist/{chunk-SUSMEKBE.js.map → chunk-EU3N5MK3.js.map} +0 -0
  181. /package/dist/{chunk-QJAGDPY7.js.map → chunk-FYAU4S6E.js.map} +0 -0
  182. /package/dist/{chunk-LEP46X5Y.js.map → chunk-GEX5NI36.js.map} +0 -0
  183. /package/dist/{chunk-X3NZ2HAO.js.map → chunk-GZAGLCQH.js.map} +0 -0
  184. /package/dist/{chunk-AVO2CBIL.js.map → chunk-HKFJ3PF3.js.map} +0 -0
  185. /package/dist/{chunk-K2SXIWEV.js.map → chunk-IA3X2Y4K.js.map} +0 -0
  186. /package/dist/{chunk-QIDMGBUY.js.map → chunk-IMAP236M.js.map} +0 -0
  187. /package/dist/{chunk-OHRIBMSS.js.map → chunk-JS3S2HVG.js.map} +0 -0
  188. /package/dist/{chunk-FVK5NQ3V.js.map → chunk-JVY556FW.js.map} +0 -0
  189. /package/dist/{chunk-3K3PITOE.js.map → chunk-JXMECXMF.js.map} +0 -0
  190. /package/dist/{chunk-NGFRFDSK.js.map → chunk-KERNN6BC.js.map} +0 -0
  191. /package/dist/{chunk-LZLJK2IA.js.map → chunk-L2LBMKSI.js.map} +0 -0
  192. /package/dist/{chunk-NHV6WCM5.js.map → chunk-ML2MVAEZ.js.map} +0 -0
  193. /package/dist/{chunk-GXQ5GDUH.js.map → chunk-N3MNDVJO.js.map} +0 -0
  194. /package/dist/{chunk-WGXWZE3K.js.map → chunk-NAYBHNGN.js.map} +0 -0
  195. /package/dist/{chunk-X33QB7LW.js.map → chunk-NKFLHW7J.js.map} +0 -0
  196. /package/dist/{chunk-GARVFCV6.js.map → chunk-NMBX4D7P.js.map} +0 -0
  197. /package/dist/{chunk-A2XDQ3JW.js.map → chunk-OM5BIPBR.js.map} +0 -0
  198. /package/dist/{chunk-ZYBLNHUB.js.map → chunk-QB75LKQQ.js.map} +0 -0
  199. /package/dist/{chunk-2CH6MMO2.js.map → chunk-RDEUG2M2.js.map} +0 -0
  200. /package/dist/{chunk-5X7ZTLFS.js.map → chunk-RIEX7NOZ.js.map} +0 -0
  201. /package/dist/{chunk-ZWWF7PI5.js.map → chunk-S42HZILI.js.map} +0 -0
  202. /package/dist/{chunk-RMG22TH2.js.map → chunk-SQDKX4RW.js.map} +0 -0
  203. /package/dist/{chunk-2GKLHU2D.js.map → chunk-SV72F4DS.js.map} +0 -0
  204. /package/dist/{chunk-6MJGDUC7.js.map → chunk-T4BE5KJM.js.map} +0 -0
  205. /package/dist/{chunk-7DZHRPCO.js.map → chunk-T4QGUXCV.js.map} +0 -0
  206. /package/dist/{chunk-IILMR37Z.js.map → chunk-TEV2JGU5.js.map} +0 -0
  207. /package/dist/{chunk-UKB7ZDKK.js.map → chunk-TIQZNDZ5.js.map} +0 -0
  208. /package/dist/{chunk-7WO66MKJ.js.map → chunk-UNJOB4DY.js.map} +0 -0
  209. /package/dist/{chunk-DSQWTXHP.js.map → chunk-W75BBBSY.js.map} +0 -0
  210. /package/dist/{chunk-YL273SOF.js.map → chunk-WB2I2EQK.js.map} +0 -0
  211. /package/dist/{chunk-CYCE3L2I.js.map → chunk-X22B4KTI.js.map} +0 -0
package/src/lcm/engine.ts CHANGED
@@ -42,6 +42,18 @@ function positiveInteger(value: unknown, fallback: number, min = 1): number {
42
42
  return Math.max(min, Math.floor(value));
43
43
  }
44
44
 
45
+ function abortOnSignal<T>(abortSignal: AbortSignal | undefined, work: Promise<T>): Promise<T> {
46
+ if (abortSignal === undefined) return work;
47
+ abortSignal.throwIfAborted();
48
+ return new Promise((resolve, reject) => {
49
+ const onAbort = (): void => {
50
+ reject(abortSignal.reason instanceof Error ? abortSignal.reason : new DOMException("Aborted", "AbortError"));
51
+ };
52
+ abortSignal.addEventListener("abort", onAbort, { once: true });
53
+ work.then(resolve, reject).finally(() => abortSignal.removeEventListener("abort", onAbort));
54
+ });
55
+ }
56
+
45
57
  export function extractLcmConfig(cfg: PluginConfig): LcmEngineConfig {
46
58
  return {
47
59
  enabled: (cfg as any).lcmEnabled === true,
@@ -284,14 +296,16 @@ export class LcmEngine {
284
296
  await this.observeQueue?.whenIdle();
285
297
  }
286
298
 
287
- async waitForSessionObserveIdle(sessionId: string): Promise<void> {
299
+ async waitForSessionObserveIdle(sessionId: string, abortSignal?: AbortSignal): Promise<void> {
300
+ abortSignal?.throwIfAborted();
288
301
  if (!this.config.enabled || this.closed) return;
289
302
  const normalizedSessionId = normalizeLcmSessionId(sessionId);
290
303
  if (!normalizedSessionId) return;
291
304
  await this.ensureInitialized();
305
+ abortSignal?.throwIfAborted();
292
306
  if (this.closed) return;
293
- await this.waitForPendingObserveInitIdle(normalizedSessionId);
294
- await this.observeQueue?.whenSessionIdle(normalizedSessionId);
307
+ await this.waitForPendingObserveInitIdle(normalizedSessionId, abortSignal);
308
+ await this.observeQueue?.whenSessionIdle(normalizedSessionId, abortSignal) ?? Promise.resolve();
295
309
  }
296
310
 
297
311
  private reservePendingObserveInit(sessionId: string): void {
@@ -321,13 +335,25 @@ export class LcmEngine {
321
335
  this.pendingObserveInitCounts.set(sessionId, count - 1);
322
336
  }
323
337
 
324
- private async waitForPendingObserveInitIdle(sessionId?: string): Promise<void> {
338
+ private async waitForPendingObserveInitIdle(sessionId?: string, abortSignal?: AbortSignal): Promise<void> {
339
+ abortSignal?.throwIfAborted();
325
340
  if (sessionId) {
326
341
  if (!this.pendingObserveInitCounts.has(sessionId)) return;
327
- await new Promise<void>((resolve) => {
342
+ await new Promise<void>((resolve, reject) => {
343
+ const finish = (): void => {
344
+ abortSignal?.removeEventListener("abort", onAbort);
345
+ resolve();
346
+ };
347
+ const onAbort = (): void => {
348
+ const remaining = (this.pendingObserveInitWaiters.get(sessionId) ?? []).filter((waiter) => waiter !== finish);
349
+ if (remaining.length === 0) this.pendingObserveInitWaiters.delete(sessionId);
350
+ else this.pendingObserveInitWaiters.set(sessionId, remaining);
351
+ reject(abortSignal?.reason instanceof Error ? abortSignal.reason : new DOMException("Aborted", "AbortError"));
352
+ };
328
353
  const waiters = this.pendingObserveInitWaiters.get(sessionId) ?? [];
329
- waiters.push(resolve);
354
+ waiters.push(finish);
330
355
  this.pendingObserveInitWaiters.set(sessionId, waiters);
356
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
331
357
  });
332
358
  return;
333
359
  }
@@ -404,16 +430,20 @@ export class LcmEngine {
404
430
  }
405
431
 
406
432
  /** Flush pending summaries before compaction (called from before_compaction hook). */
407
- async preCompactionFlush(sessionId: string): Promise<void> {
433
+ async preCompactionFlush(sessionId: string, abortSignal?: AbortSignal): Promise<void> {
434
+ abortSignal?.throwIfAborted();
408
435
  if (!this.config.enabled) return;
409
436
  const normalizedSessionId = normalizeLcmSessionId(sessionId);
410
437
  if (!normalizedSessionId) return;
411
438
  await this.ensureInitialized();
412
- await this.waitForSessionObserveIdle(normalizedSessionId);
439
+ abortSignal?.throwIfAborted();
440
+ await this.waitForSessionObserveIdle(normalizedSessionId, abortSignal);
441
+ abortSignal?.throwIfAborted();
413
442
 
414
443
  try {
415
- await this.summarizer!.summarizeIncremental(normalizedSessionId);
444
+ await abortOnSignal(abortSignal, this.summarizer!.summarizeIncremental(normalizedSessionId));
416
445
  } catch (err) {
446
+ if (abortSignal?.aborted) throw err;
417
447
  log.debug(`LCM pre-compaction flush error: ${err}`);
418
448
  }
419
449
  }
@@ -176,3 +176,22 @@ test("LcmWorkQueue waits for a specific session without waiting for unrelated id
176
176
  assert.equal(sessionIdleResolved, true);
177
177
  await queue.whenIdle();
178
178
  });
179
+
180
+ test("#3077 whenSessionIdle abort unregisters the waiter", async () => {
181
+ const blocker = deferred();
182
+ const queue = new LcmWorkQueue({
183
+ concurrency: 1,
184
+ worker: async () => {
185
+ await blocker.promise;
186
+ },
187
+ });
188
+ queue.enqueue("blocked", [{ role: "user", content: "hold" }]);
189
+ await Promise.resolve();
190
+ const abort = new AbortController();
191
+ const waiting = queue.whenSessionIdle("blocked", abort.signal);
192
+ abort.abort();
193
+ await assert.rejects(waiting, (err: unknown) => err instanceof Error && err.name === "AbortError");
194
+ blocker.resolve();
195
+ await queue.whenIdle();
196
+ await queue.whenSessionIdle("blocked");
197
+ });
package/src/lcm/queue.ts CHANGED
@@ -96,13 +96,24 @@ export class LcmWorkQueue {
96
96
  });
97
97
  }
98
98
 
99
- async whenSessionIdle(sessionId: string): Promise<void> {
100
- if (!this.pending.has(sessionId) && !this.inFlightSessions.has(sessionId))
101
- return;
102
- await new Promise<void>((resolve) => {
99
+ async whenSessionIdle(sessionId: string, abortSignal?: AbortSignal): Promise<void> {
100
+ abortSignal?.throwIfAborted();
101
+ if (!this.pending.has(sessionId) && !this.inFlightSessions.has(sessionId)) return;
102
+ await new Promise<void>((resolve, reject) => {
103
+ const finish = (): void => {
104
+ abortSignal?.removeEventListener("abort", onAbort);
105
+ resolve();
106
+ };
107
+ const onAbort = (): void => {
108
+ const remaining = (this.sessionIdleWaiters.get(sessionId) ?? []).filter((waiter) => waiter !== finish);
109
+ if (remaining.length === 0) this.sessionIdleWaiters.delete(sessionId);
110
+ else this.sessionIdleWaiters.set(sessionId, remaining);
111
+ reject(abortSignal?.reason instanceof Error ? abortSignal.reason : new DOMException("Aborted", "AbortError"));
112
+ };
103
113
  const waiters = this.sessionIdleWaiters.get(sessionId) ?? [];
104
- waiters.push(resolve);
114
+ waiters.push(finish);
105
115
  this.sessionIdleWaiters.set(sessionId, waiters);
116
+ abortSignal?.addEventListener("abort", onAbort, { once: true });
106
117
  });
107
118
  }
108
119
 
@@ -381,6 +381,78 @@ test("waitForSessionObserveIdle waits for deferred enqueue registration", async
381
381
  }
382
382
  });
383
383
 
384
+ test("#3077 waitForSessionObserveIdle rejects when aborted during wait", async () => {
385
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-lcm-engine-abort-"));
386
+ const summarizeStarted = deferred<void>();
387
+ const releaseSummarize = deferred<void>();
388
+ try {
389
+ const engine = new LcmEngine(createPluginConfig(memoryDir), async () => {
390
+ summarizeStarted.resolve();
391
+ await releaseSummarize.promise;
392
+ return "summary";
393
+ });
394
+ await engine.ensureInitialized();
395
+ engine.enqueueObserveMessages("session-1", [{ role: "user", content: "queued after init" }]);
396
+ const abort = new AbortController();
397
+ const waiting = engine.waitForSessionObserveIdle("session-1", abort.signal);
398
+ await summarizeStarted.promise;
399
+ abort.abort();
400
+ await assert.rejects(waiting, (err: unknown) => err instanceof Error && err.name === "AbortError");
401
+ } finally {
402
+ releaseSummarize.resolve();
403
+ await rm(memoryDir, { recursive: true, force: true });
404
+ }
405
+ });
406
+
407
+
408
+ test("#3077 preCompactionFlush rejects when aborted during summarization", async () => {
409
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-lcm-engine-flush-abort-"));
410
+ const summarizeStarted = deferred<void>();
411
+ const releaseSummarize = deferred<void>();
412
+ try {
413
+ const engine = new LcmEngine(createPluginConfig(memoryDir), async () => {
414
+ summarizeStarted.resolve();
415
+ await releaseSummarize.promise;
416
+ return "summary";
417
+ });
418
+ await engine.ensureInitialized();
419
+ engine.enqueueObserveMessages("session-1", [{ role: "user", content: "queued after init" }]);
420
+ const abort = new AbortController();
421
+ const flushing = engine.preCompactionFlush("session-1", abort.signal);
422
+ await summarizeStarted.promise;
423
+ abort.abort();
424
+ await assert.rejects(flushing, (err: unknown) => err instanceof Error && err.name === "AbortError");
425
+ } finally {
426
+ releaseSummarize.resolve();
427
+ await rm(memoryDir, { recursive: true, force: true });
428
+ }
429
+ });
430
+
431
+ test("#3077 preCompactionFlush rethrows a non-AbortError abort reason", async () => {
432
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "engram-lcm-engine-flush-timeout-"));
433
+ const summarizeStarted = deferred<void>();
434
+ const releaseSummarize = deferred<void>();
435
+ try {
436
+ const engine = new LcmEngine(createPluginConfig(memoryDir), async () => {
437
+ summarizeStarted.resolve();
438
+ await releaseSummarize.promise;
439
+ return "summary";
440
+ });
441
+ await engine.ensureInitialized();
442
+ engine.enqueueObserveMessages("session-1", [{ role: "user", content: "queued after init" }]);
443
+ const abort = new AbortController();
444
+ const flushing = engine.preCompactionFlush("session-1", abort.signal);
445
+ await summarizeStarted.promise;
446
+ abort.abort(new Error("custom-cancel"));
447
+ await assert.rejects(flushing, (err: unknown) => err instanceof Error && err.message === "custom-cancel");
448
+ } finally {
449
+ releaseSummarize.resolve();
450
+ await rm(memoryDir, { recursive: true, force: true });
451
+ }
452
+ });
453
+
454
+
455
+
384
456
  test("waitForSessionObserveIdle resolves once the target session drains even if other work remains", async () => {
385
457
  const memoryDir = await mkdtemp(
386
458
  path.join(os.tmpdir(), "engram-lcm-engine-session-idle-"),
@@ -39,6 +39,7 @@ function fakeMemory(overrides: {
39
39
  created: string;
40
40
  source?: string;
41
41
  status?: MemoryFrontmatter["status"];
42
+ verificationState?: MemoryFrontmatter["verificationState"];
42
43
  structuredAttributes?: Record<string, string>;
43
44
  lineage?: string[];
44
45
  }): MemoryFile {
@@ -55,6 +56,7 @@ function fakeMemory(overrides: {
55
56
  confidenceTier: "inferred",
56
57
  tags: [],
57
58
  status: overrides.status,
59
+ verificationState: overrides.verificationState,
58
60
  structuredAttributes: overrides.structuredAttributes,
59
61
  lineage: overrides.lineage,
60
62
  },
@@ -369,6 +371,20 @@ test("an independent negated restatement holds the seed even with enough corrobo
369
371
  assert.ok(decision.reasons.includes("contradiction-observed:1"));
370
372
  });
371
373
 
374
+ test("#3118 disputed evidence cannot corroborate a seed", () => {
375
+ const seed = seedMemory({ id: "seed-1" });
376
+ const disputed = fakeMemory({
377
+ id: "ev-1",
378
+ content: RESTATE_TEXT,
379
+ created: "2026-08-02T10:00:00.000Z",
380
+ source: "wearable:limitless",
381
+ verificationState: "disputed",
382
+ });
383
+ const decision = evaluateSeedGraduation(seed, [disputed], { config: ENABLED });
384
+ assert.equal(decision.decision, "hold");
385
+ assert.equal(decision.corroborationCount, 0);
386
+ });
387
+
372
388
  test("a negated seed restated positively is held (polarity symmetry)", () => {
373
389
  const seed = seedMemory({ id: "seed-1", content: CONTRADICT_TEXT });
374
390
  const positive = fakeMemory({
@@ -543,6 +559,34 @@ test("pass: independent corroboration promotes the seed in place with audit attr
543
559
  }
544
560
  });
545
561
 
562
+ test("#3118 disputed seed is skipped by the graduation pass", async () => {
563
+ const { storage, dir } = makeStorage();
564
+ try {
565
+ const seedWrite = await storage.writeMemory("fact", SEED_TEXT, {
566
+ source: "wearable:bee",
567
+ status: "pending_review",
568
+ });
569
+ await storage.writeMemory("fact", RESTATE_TEXT, {
570
+ source: "wearable:limitless",
571
+ });
572
+ const seed = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === seedWrite.id);
573
+ assert.ok(seed);
574
+ await storage.writeMemoryFrontmatter(seed, { verificationState: "disputed" });
575
+ const summary = await runSeedGraduationPass({
576
+ memories: await storage.readAllMemories(),
577
+ storage,
578
+ config: ENABLED,
579
+ });
580
+ assert.equal(summary.evaluated, 0);
581
+ assert.equal(summary.promoted, 0);
582
+ const held = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === seedWrite.id);
583
+ assert.equal(held?.frontmatter.status, "pending_review");
584
+ } finally {
585
+ rmSync(dir, { recursive: true, force: true });
586
+ }
587
+ });
588
+
589
+
546
590
  test("pass: contradiction during the window holds the seed in place", async () => {
547
591
  const { storage, dir } = makeStorage();
548
592
  try {
@@ -728,6 +772,86 @@ test("lifecycle pass: enabled independent corroboration promotes through the pol
728
772
  }
729
773
  });
730
774
 
775
+ test("#3118 lifecycle pass reindexes after a graduation", async () => {
776
+ const { storage, dir } = makeStorage();
777
+ try {
778
+ await storage.writeMemory("fact", SEED_TEXT, {
779
+ source: "wearable:bee",
780
+ status: "pending_review",
781
+ });
782
+ await storage.writeMemory("fact", RESTATE_TEXT, {
783
+ source: "wearable:limitless",
784
+ });
785
+ const config = parseConfig({
786
+ memoryDir: dir,
787
+ seedGraduation: { enabled: true, minCorroborations: 1 },
788
+ });
789
+ const deps = coordinatorDeps(storage, config);
790
+ let saves = 0;
791
+ deps.saveContentHashIndexes = async () => {
792
+ saves += 1;
793
+ };
794
+ await new LifecyclePolicyCoordinator(deps).runLifecyclePolicyPass(
795
+ await storage.readAllMemories(),
796
+ storage,
797
+ );
798
+ assert.equal(saves, 1, "graduation must persist content-hash indexes");
799
+ } finally {
800
+ rmSync(dir, { recursive: true, force: true });
801
+ }
802
+ });
803
+
804
+
805
+ test("#3118 index-save failure does not unwind a completed graduation", async () => {
806
+ const { storage, dir } = makeStorage();
807
+ try {
808
+ await storage.writeMemory("fact", SEED_TEXT, {
809
+ source: "wearable:bee",
810
+ status: "pending_review",
811
+ });
812
+ await storage.writeMemory("fact", RESTATE_TEXT, {
813
+ source: "wearable:limitless",
814
+ });
815
+ const config = parseConfig({
816
+ memoryDir: dir,
817
+ seedGraduation: { enabled: true, minCorroborations: 1 },
818
+ });
819
+ const deps = coordinatorDeps(storage, config);
820
+ deps.saveContentHashIndexes = async () => {
821
+ throw new Error("index write failed");
822
+ };
823
+ await new LifecyclePolicyCoordinator(deps).runLifecyclePolicyPass(
824
+ await storage.readAllMemories(),
825
+ storage,
826
+ );
827
+ const seed = (await storage.readAllMemories()).find(
828
+ (memory) => memory.frontmatter.source === "wearable:bee",
829
+ );
830
+ assert.equal(seed?.frontmatter.status, "active", "graduation stays durable if reindex fails");
831
+ } finally {
832
+ rmSync(dir, { recursive: true, force: true });
833
+ }
834
+ });
835
+
836
+ test("#3118 promoteWearableMemory refuses a concurrently disputed seed", async () => {
837
+ const { storage, dir } = makeStorage();
838
+ try {
839
+ const seedWrite = await storage.writeMemory("fact", SEED_TEXT, {
840
+ source: "wearable:bee",
841
+ status: "pending_review",
842
+ });
843
+ const seed = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === seedWrite.id);
844
+ assert.ok(seed);
845
+ await storage.writeMemoryFrontmatter(seed, { verificationState: "disputed" });
846
+ assert.equal(await storage.promoteWearableMemory(seedWrite.id, { graduatedBy: "independent-corroboration" }), false);
847
+ const held = (await storage.readAllMemories()).find((memory) => memory.frontmatter.id === seedWrite.id);
848
+ assert.equal(held?.frontmatter.status, "pending_review");
849
+ } finally {
850
+ rmSync(dir, { recursive: true, force: true });
851
+ }
852
+ });
853
+
854
+
731
855
  test("lifecycle pass: recall-handle history suppresses echo corroboration", async () => {
732
856
  const { storage, dir } = makeStorage();
733
857
  try {
@@ -132,6 +132,10 @@ function isEvidenceStatus(status: MemoryStatus | undefined): boolean {
132
132
  return status === undefined || status === "active" || status === "pending_review";
133
133
  }
134
134
 
135
+ function isGraduationEvidence(memory: MemoryFile): boolean {
136
+ return isEvidenceStatus(memory.frontmatter.status) && memory.frontmatter.verificationState !== "disputed";
137
+ }
138
+
135
139
  function hasLineageLink(seed: MemoryFile, evidence: MemoryFile): boolean {
136
140
  const seedLineage = seed.frontmatter.lineage;
137
141
  if (seedLineage !== undefined && seedLineage.includes(evidence.frontmatter.id)) return true;
@@ -279,7 +283,7 @@ export function evaluateSeedGraduation(
279
283
  const candidateCreated = createdMs(candidate);
280
284
  if (!Number.isFinite(seedCreated) || !Number.isFinite(candidateCreated)) continue;
281
285
  if (candidateCreated <= seedCreated) continue;
282
- if (!isEvidenceStatus(candidate.frontmatter.status)) continue;
286
+ if (!isGraduationEvidence(candidate)) continue;
283
287
  const candidateText = stripAttributesSuffix(candidate.content);
284
288
  if (hasNegationWord(candidateText) !== seedNegated) {
285
289
  // Polarity-flipped restatement of the seed's core content is a
@@ -417,7 +421,7 @@ export async function runSeedGraduationPass(
417
421
  return { evaluated: 0, promoted: 0, held: 0, contradictionHeld: 0, echoSuppressed: 0, disabled: true };
418
422
  }
419
423
  const corpus = excludeSupportPassportPrivateMemories(input.memories);
420
- const evidencePool = corpus.filter((memory) => isEvidenceStatus(memory.frontmatter.status));
424
+ const evidencePool = corpus.filter((memory) => isGraduationEvidence(memory));
421
425
 
422
426
  let promoted = 0;
423
427
  let held = 0;
@@ -427,6 +431,7 @@ export async function runSeedGraduationPass(
427
431
 
428
432
  for (const seed of corpus) {
429
433
  if (seed.frontmatter.status !== "pending_review") continue;
434
+ if (seed.frontmatter.verificationState === "disputed") continue;
430
435
  // Tombstone-blocked rows need revokeTombstone first; the promotion
431
436
  // method refuses them anyway, so skip before evaluating.
432
437
  if (seed.frontmatter.blockedBy !== undefined) continue;
@@ -261,12 +261,17 @@ export class LifecyclePolicyCoordinator {
261
261
  }
262
262
 
263
263
  const history = this.deps.getHandleHistory?.();
264
- await runSeedGraduationPass({
264
+ const graduation = await runSeedGraduationPass({
265
265
  memories: allMemories,
266
266
  storage,
267
267
  config: this.config.seedGraduation,
268
268
  recalledBySession: history ? (sessionKey) => history.recent(sessionKey) : undefined,
269
269
  });
270
+ if (graduation.promoted > 0) {
271
+ await this.deps.saveContentHashIndexes().catch((err) =>
272
+ log.warn(`content-hash index save failed during seed graduation: ${err}`),
273
+ );
274
+ }
270
275
 
271
276
  // Report how many memories had frontmatter rewritten so callers can record a
272
277
  // catalog write touch for lifecycle-only passes (codex NR-tS).
package/src/storage.ts CHANGED
@@ -2598,13 +2598,11 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
2598
2598
  const memory = memories.find((entry) => entry.frontmatter.id === id);
2599
2599
  if (!memory) return false;
2600
2600
  if (memory.frontmatter.status !== "pending_review") return false;
2601
+ if (memory.frontmatter.verificationState === "disputed") return false;
2601
2602
  // Tombstone-blocked rows need revokeTombstone first (issue #1579 OcuDx/Ocu1l).
2602
2603
  if (memory.frontmatter.blockedBy) return false;
2603
- return this.writeMemoryFrontmatter(memory, {
2604
+ return this.writeMemoryFrontmatterIfUnchanged(memory, {
2604
2605
  status: "active",
2605
- // Keep frontmatter confidence in step with the re-scored trust —
2606
- // new smart writes persist trust as confidence, and a promoted
2607
- // row must not keep its stale borderline value.
2608
2606
  ...(typeof confidence === "number" && Number.isFinite(confidence)
2609
2607
  ? { confidence: Math.min(1, Math.max(0, confidence)) }
2610
2608
  : {}),
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lcm/engine.ts"],"sourcesContent":["import type Database from \"better-sqlite3\";\nimport { openLcmDatabase, ensureLcmStateDir } from \"./schema.js\";\nimport { LcmArchive, type LcmMessage, type LcmStructuredRecallMatch } from \"./archive.js\";\nimport { LcmDag } from \"./dag.js\";\nimport { LcmSummarizer, type SummarizeFn } from \"./summarizer.js\";\nimport {\n assembleCompressedHistoryWithTrace,\n type LcmRecallConfig,\n type LcmRecallWithTraceResult,\n} from \"./recall.js\";\nimport { LcmWorkQueue, type LcmObserveMessage } from \"./queue.js\";\nimport type { PluginConfig } from \"../types.js\";\nimport { estimateTokenCount } from \"../token-estimate.js\";\nimport { log } from \"../logger.js\";\nimport { nativeBindingRecoveryHint } from \"../native-binding-hint.js\";\nexport interface LcmEngineConfig {\n enabled: boolean;\n leafBatchSize: number;\n rollupFanIn: number;\n freshTailTurns: number;\n maxDepth: number;\n deterministicMaxTokens: number;\n archiveRetentionDays: number;\n recallBudgetShare: number;\n observeConcurrency: number;\n telemetryPrefilterEnabled: boolean;\n messagePartsEnabled: boolean;\n messagePartsRecallMaxResults: number;\n}\n\n/** An expanded archive row with stable lineage identity; content may be budget-truncated. */\nexport interface LcmExpandedMessage {\n id: number;\n session_id: string;\n turn_index: number;\n role: string;\n content: string;\n}\n\nfunction positiveInteger(value: unknown, fallback: number, min = 1): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n return Math.max(min, Math.floor(value));\n}\n\nexport function extractLcmConfig(cfg: PluginConfig): LcmEngineConfig {\n return {\n enabled: (cfg as any).lcmEnabled === true,\n leafBatchSize: positiveInteger((cfg as any).lcmLeafBatchSize, 8),\n rollupFanIn: positiveInteger((cfg as any).lcmRollupFanIn, 4, 2),\n freshTailTurns: positiveInteger((cfg as any).lcmFreshTailTurns, 16),\n maxDepth: positiveInteger((cfg as any).lcmMaxDepth, 5),\n deterministicMaxTokens: positiveInteger((cfg as any).lcmDeterministicMaxTokens, 512),\n archiveRetentionDays: positiveInteger((cfg as any).lcmArchiveRetentionDays, 90, 0),\n recallBudgetShare: (cfg as any).lcmRecallBudgetShare ?? 0.15,\n observeConcurrency:\n typeof (cfg as any).lcmObserveConcurrency === \"number\" &&\n Number.isFinite((cfg as any).lcmObserveConcurrency)\n ? Math.max(1, Math.floor((cfg as any).lcmObserveConcurrency))\n : 1,\n telemetryPrefilterEnabled: (cfg as any).lcmTelemetryPrefilterEnabled !== false,\n messagePartsEnabled: (cfg as any).messagePartsEnabled === true,\n messagePartsRecallMaxResults:\n typeof (cfg as any).messagePartsRecallMaxResults === \"number\"\n ? Math.max(0, Math.floor((cfg as any).messagePartsRecallMaxResults))\n : 6,\n };\n}\n\nfunction normalizeLcmSessionId(sessionId: string): string {\n return sessionId.trim();\n}\n\nfunction normalizeOptionalLcmSessionId(sessionId?: string): string | undefined {\n if (sessionId === undefined) {\n return undefined;\n }\n const normalized = normalizeLcmSessionId(sessionId);\n return normalized.length > 0 ? normalized : undefined;\n}\n\nconst EMPTY_LCM_STATS = {\n totalMessages: 0,\n totalSummaryNodes: 0,\n maxDepth: -1,\n} as const;\n\nexport class LcmEngine {\n private db: Database.Database | null = null;\n private archive: LcmArchive | null = null;\n private dag: LcmDag | null = null;\n private summarizer: LcmSummarizer | null = null;\n private observeQueue: LcmWorkQueue | null = null;\n private closed = false;\n private readonly config: LcmEngineConfig;\n private readonly memoryDir: string;\n private initPromise: Promise<void> | null = null;\n private readonly pendingObserveInitCounts = new Map<string, number>();\n private readonly pendingObserveInitWaiters = new Map<string, Array<() => void>>();\n private readonly pendingObserveInitIdleWaiters: Array<() => void> = [];\n\n constructor(\n pluginConfig: PluginConfig,\n private readonly summarizeFn: SummarizeFn,\n ) {\n this.config = extractLcmConfig(pluginConfig);\n this.memoryDir = pluginConfig.memoryDir;\n }\n\n get enabled(): boolean {\n return this.config.enabled;\n }\n\n /** Lazy init — open database on first use. */\n async ensureInitialized(): Promise<void> {\n if (this.closed) return;\n if (this.db) return;\n if (this.initPromise) {\n await this.initPromise;\n return;\n }\n this.initPromise = this.doInit().catch((err) => {\n // Reset so next call retries instead of caching the failure\n this.initPromise = null;\n throw err;\n });\n await this.initPromise;\n }\n\n private async doInit(): Promise<void> {\n await ensureLcmStateDir(this.memoryDir);\n const db = openLcmDatabase(this.memoryDir);\n const archive = new LcmArchive(db);\n const dag = new LcmDag(db);\n const { telemetryPrefilterEnabled } = this.config;\n const summarizer = new LcmSummarizer(\n archive,\n dag,\n this.summarizeFn,\n {\n leafBatchSize: this.config.leafBatchSize,\n rollupFanIn: this.config.rollupFanIn,\n maxDepth: this.config.maxDepth,\n deterministicMaxTokens: this.config.deterministicMaxTokens,\n telemetryPrefilterEnabled,\n },\n );\n const observeQueue = new LcmWorkQueue({\n concurrency: this.config.observeConcurrency,\n worker: async (sessionId, messages) => {\n await this.processObserveMessages(sessionId, messages);\n },\n hooks: {\n onJobStart: ({ sessionId, depth, inFlight, waitMs }) => {\n log.debug(\n `LCM observe queue start: session=${sessionId}, depth=${depth}, inFlight=${inFlight}, wait=${waitMs}ms`,\n );\n },\n onJobFinish: ({\n sessionId,\n depth,\n inFlight,\n waitMs,\n runMs,\n totalMs,\n error,\n }) => {\n if (error) {\n log.error(\n `LCM observe queue failure: session=${sessionId}, depth=${depth}, inFlight=${inFlight}, wait=${waitMs}ms, run=${runMs}ms, total=${totalMs}ms, error=${error}`,\n );\n return;\n }\n\n log.debug(\n `LCM observe queue finish: session=${sessionId}, depth=${depth}, inFlight=${inFlight}, wait=${waitMs}ms, run=${runMs}ms, total=${totalMs}ms`,\n );\n },\n },\n });\n\n if (this.closed) {\n db.close();\n return;\n }\n\n this.db = db;\n this.archive = archive;\n this.dag = dag;\n this.summarizer = summarizer;\n this.observeQueue = observeQueue;\n log.info(\"LCM engine initialized\");\n }\n\n /**\n * Enqueue messages from agent_end hook.\n * The queue worker performs the archive append and incremental summarization.\n */\n async observeMessages(\n sessionId: string,\n messages: LcmObserveMessage[],\n ): Promise<void> {\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return;\n this.enqueueObserveMessages(normalizedSessionId, messages);\n }\n\n /** Enqueue an observe job without waiting for worker completion. */\n enqueueObserveMessages(\n sessionId: string,\n messages: LcmObserveMessage[],\n ): void {\n if (!this.config.enabled || this.closed) return;\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return;\n if (messages.length === 0) return;\n\n this.reservePendingObserveInit(normalizedSessionId);\n\n void this.ensureInitialized()\n .then(() => {\n if (this.closed || !this.observeQueue) return;\n this.observeQueue.enqueue(normalizedSessionId, messages);\n log.debug(\n `LCM observe enqueued: session=${normalizedSessionId}, depth=${this.observeQueue.depth}, inFlight=${this.observeQueue.inFlightCount}`,\n );\n })\n .catch((err) => {\n if (this.closed) return;\n log.error(\n `LCM observe enqueue initialization error: ${err}${nativeBindingRecoveryHint(err)}`,\n );\n })\n .finally(() => {\n this.releasePendingObserveInit(normalizedSessionId);\n });\n }\n\n private async processObserveMessages(\n sessionId: string,\n messages: LcmObserveMessage[],\n ): Promise<void> {\n if (this.closed) return;\n await this.ensureInitialized();\n if (this.closed || !this.archive || !this.summarizer) return;\n\n if (messages.length === 0) return;\n\n const currentMax = this.archive.getMaxTurnIndex(sessionId);\n const { messagePartsEnabled } = this.config;\n const newMessages = messages.map((m, i) => ({\n turnIndex: currentMax + 1 + i,\n role: m.role,\n content: m.content,\n parts: messagePartsEnabled ? m.parts : undefined,\n rawContent: messagePartsEnabled ? m.rawContent : undefined,\n sourceFormat: messagePartsEnabled ? m.sourceFormat : undefined,\n }));\n\n this.archive.appendMessages(sessionId, newMessages, {\n messagePartsEnabled,\n });\n\n // Trigger incremental summarization inside the worker, after append.\n try {\n await this.summarizer.summarizeIncremental(sessionId);\n } catch (err) {\n log.debug(`LCM incremental summarization error: ${err}`);\n }\n }\n\n get observeQueueDepth(): number {\n return this.observeQueue?.depth ?? 0;\n }\n\n get observeQueueInFlightCount(): number {\n return this.observeQueue?.inFlightCount ?? 0;\n }\n\n async waitForObserveQueueIdle(): Promise<void> {\n if (!this.config.enabled || this.closed) return;\n await this.ensureInitialized();\n if (this.closed) return;\n await this.waitForPendingObserveInitIdle();\n await this.observeQueue?.whenIdle();\n }\n\n async waitForSessionObserveIdle(sessionId: string): Promise<void> {\n if (!this.config.enabled || this.closed) return;\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return;\n await this.ensureInitialized();\n if (this.closed) return;\n await this.waitForPendingObserveInitIdle(normalizedSessionId);\n await this.observeQueue?.whenSessionIdle(normalizedSessionId);\n }\n\n private reservePendingObserveInit(sessionId: string): void {\n const count = this.pendingObserveInitCounts.get(sessionId) ?? 0;\n this.pendingObserveInitCounts.set(sessionId, count + 1);\n }\n\n private releasePendingObserveInit(sessionId: string): void {\n const count = this.pendingObserveInitCounts.get(sessionId);\n if (!count) return;\n\n if (count === 1) {\n this.pendingObserveInitCounts.delete(sessionId);\n const waiters = this.pendingObserveInitWaiters.get(sessionId) ?? [];\n this.pendingObserveInitWaiters.delete(sessionId);\n for (const resolve of waiters) resolve();\n if (this.pendingObserveInitCounts.size === 0) {\n const idleWaiters = this.pendingObserveInitIdleWaiters.splice(\n 0,\n this.pendingObserveInitIdleWaiters.length,\n );\n for (const resolve of idleWaiters) resolve();\n }\n return;\n }\n\n this.pendingObserveInitCounts.set(sessionId, count - 1);\n }\n\n private async waitForPendingObserveInitIdle(sessionId?: string): Promise<void> {\n if (sessionId) {\n if (!this.pendingObserveInitCounts.has(sessionId)) return;\n await new Promise<void>((resolve) => {\n const waiters = this.pendingObserveInitWaiters.get(sessionId) ?? [];\n waiters.push(resolve);\n this.pendingObserveInitWaiters.set(sessionId, waiters);\n });\n return;\n }\n\n if (this.pendingObserveInitCounts.size === 0) return;\n await new Promise<void>((resolve) => {\n this.pendingObserveInitIdleWaiters.push(resolve);\n });\n }\n\n /** Build the compressed history recall section for a session. */\n async assembleRecall(\n sessionId: string,\n budgetChars: number,\n ): Promise<string> {\n return (await this.assembleRecallWithTrace(sessionId, budgetChars)).text;\n }\n\n /** Build compressed recall plus content-free selected-summary receipts. */\n async assembleRecallWithTrace(\n sessionId: string,\n budgetChars: number,\n ): Promise<LcmRecallWithTraceResult> {\n if (!this.config.enabled) return { text: \"\", selectedSummaries: [] };\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return { text: \"\", selectedSummaries: [] };\n await this.ensureInitialized();\n\n const effectiveBudget = Math.ceil(\n budgetChars * this.config.recallBudgetShare,\n );\n if (effectiveBudget <= 0) return { text: \"\", selectedSummaries: [] };\n\n return assembleCompressedHistoryWithTrace(this.dag!, this.archive!, normalizedSessionId, {\n freshTailTurns: this.config.freshTailTurns,\n budgetChars: effectiveBudget,\n });\n }\n\n async searchStructuredParts(\n sessionId: string,\n query: string,\n limit = this.config.messagePartsRecallMaxResults,\n ): Promise<LcmStructuredRecallMatch[]> {\n const { messagePartsEnabled } = this.config;\n if (!this.config.enabled || !messagePartsEnabled) return [];\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return [];\n await this.ensureInitialized();\n if (!this.archive) return [];\n return this.archive.searchStructuredParts(query, limit, normalizedSessionId);\n }\n\n formatStructuredRecall(\n matches: LcmStructuredRecallMatch[],\n budgetChars: number,\n ): string {\n if (matches.length === 0 || budgetChars <= 0) return \"\";\n const lines: string[] = [];\n let used = \"## Structured Session Matches\\n\\n\".length;\n for (const match of matches) {\n const label = match.file_path\n ? `${match.kind} ${match.file_path}`\n : match.tool_name\n ? `${match.kind} ${match.tool_name}`\n : match.kind;\n const excerpt = match.content.replace(/\\s+/g, \" \").slice(0, 220);\n const line = `- turn ${match.turn_index} (${match.role}): ${label} — ${excerpt}`;\n if (used + line.length + 1 > budgetChars) break;\n lines.push(line);\n used += line.length + 1;\n }\n return lines.length > 0 ? `## Structured Session Matches\\n\\n${lines.join(\"\\n\")}` : \"\";\n }\n\n /** Flush pending summaries before compaction (called from before_compaction hook). */\n async preCompactionFlush(sessionId: string): Promise<void> {\n if (!this.config.enabled) return;\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return;\n await this.ensureInitialized();\n await this.waitForSessionObserveIdle(normalizedSessionId);\n\n try {\n await this.summarizer!.summarizeIncremental(normalizedSessionId);\n } catch (err) {\n log.debug(`LCM pre-compaction flush error: ${err}`);\n }\n }\n\n /** Record a compaction event with real token counts (called from after_compaction hook). */\n async recordCompaction(\n sessionId: string,\n tokensBefore: number,\n tokensAfter: number,\n ): Promise<void> {\n if (!this.config.enabled) return;\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return;\n await this.ensureInitialized();\n await this.waitForSessionObserveIdle(normalizedSessionId);\n\n const maxTurn = this.archive!.getMaxTurnIndex(normalizedSessionId);\n\n this.dag!.recordCompaction(normalizedSessionId, maxTurn, tokensBefore, tokensAfter);\n log.info(\n `LCM compaction recorded: session=${normalizedSessionId}, turn=${maxTurn}, tokens ${tokensBefore}→${tokensAfter}`,\n );\n }\n\n /** Verify archive coverage after compaction. */\n async verifyPostCompaction(sessionId: string): Promise<void> {\n if (!this.config.enabled) return;\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return;\n await this.ensureInitialized();\n\n const msgCount = this.archive!.getMessageCount(normalizedSessionId);\n const nodeCount = this.dag!.getNodeCount(normalizedSessionId);\n log.debug(\n `LCM post-compaction verify: session=${normalizedSessionId}, messages=${msgCount}, summaryNodes=${nodeCount}`,\n );\n }\n\n // ── MCP Tool implementations ──\n\n /** Search across all conversation history via FTS (snippet mode). */\n async searchContext(\n query: string,\n limit: number,\n sessionId?: string,\n sessionPrefix?: string,\n ): Promise<\n Array<{\n turn_index: number;\n role: string;\n snippet: string;\n session_id: string;\n }>\n > {\n if (!this.config.enabled) return [];\n const normalizedSessionId = normalizeOptionalLcmSessionId(sessionId);\n if (sessionId !== undefined && !normalizedSessionId) return [];\n const normalizedSessionPrefix = normalizeOptionalLcmSessionId(sessionPrefix);\n if (sessionPrefix !== undefined && !normalizedSessionPrefix) return [];\n await this.ensureInitialized();\n return this.archive!.search(query, limit, normalizedSessionId, normalizedSessionPrefix);\n }\n\n /** Search via FTS returning full message content (not snippets). */\n async searchContextFull(\n query: string,\n limit: number,\n sessionId?: string,\n sessionPrefix?: string,\n ): Promise<\n Array<{\n id: number;\n turn_index: number;\n role: string;\n content: string;\n session_id: string;\n score: number;\n }>\n > {\n if (!this.config.enabled) return [];\n const normalizedSessionId = normalizeOptionalLcmSessionId(sessionId);\n if (sessionId !== undefined && !normalizedSessionId) return [];\n const normalizedSessionPrefix = normalizeOptionalLcmSessionId(sessionPrefix);\n if (sessionPrefix !== undefined && !normalizedSessionPrefix) return [];\n await this.ensureInitialized();\n return this.archive!.searchWithContent(\n query,\n limit,\n normalizedSessionId,\n 1000,\n normalizedSessionPrefix,\n );\n }\n\n /** Get a compressed summary of a turn range. */\n async describeContext(\n sessionId: string,\n fromTurn: number,\n toTurn: number,\n ): Promise<{ summary: string; turn_count: number; depth: number } | null> {\n if (!this.config.enabled) return null;\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return null;\n await this.ensureInitialized();\n\n const nodes = this.dag!.getCoveringNodes(normalizedSessionId, fromTurn, toTurn);\n if (nodes.length === 0) {\n // No summary exists — build a description from raw messages\n const messages = this.archive!.getMessages(normalizedSessionId, fromTurn, toTurn);\n if (messages.length === 0) return null;\n const preview = messages\n .slice(0, 5)\n .map((m) => `[${m.role}] ${m.content.slice(0, 100)}`)\n .join(\"\\n\");\n return {\n summary: `No summary available for this range. Preview of ${messages.length} messages:\\n${preview}`,\n turn_count: messages.length,\n depth: -1,\n };\n }\n\n // Use the deepest covering node\n const best = nodes[0]; // Already sorted by depth DESC\n return {\n summary: best.summary_text,\n turn_count: best.msg_end - best.msg_start + 1,\n depth: best.depth,\n };\n }\n\n /**\n * Retrieve raw archived messages for a turn range (inclusive bounds),\n * read-only and unshaped — no token-budget trimming (issue #2331\n * episodic-context). Callers own truncation and cleaning.\n */\n async getTurnRange(\n sessionId: string,\n fromTurn: number,\n toTurn: number,\n ): Promise<LcmMessage[]> {\n if (!this.config.enabled) return [];\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return [];\n await this.ensureInitialized();\n return this.archive!.getMessages(normalizedSessionId, fromTurn, toTurn);\n }\n\n /** Retrieve raw messages for a turn range (lossless expansion). */\n async expandContext(\n sessionId: string,\n fromTurn: number,\n toTurn: number,\n maxTokens: number,\n ): Promise<LcmExpandedMessage[]> {\n if (!this.config.enabled) return [];\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return [];\n await this.ensureInitialized();\n\n const messages = this.archive!.getMessages(normalizedSessionId, fromTurn, toTurn);\n if (messages.length === 0) return [];\n\n // Enforce the token budget while keeping the existing first/last shape.\n const tokenBudget = Math.max(0, Math.floor(maxTokens));\n if (tokenBudget === 0) return [];\n const totalTokens = messages.reduce(\n (sum, message) => sum + estimateTokenCount(message.content),\n 0,\n );\n if (totalTokens <= tokenBudget) {\n return messages.map((m) => ({\n id: m.id,\n session_id: m.session_id,\n turn_index: m.turn_index,\n role: m.role,\n content: m.content,\n }));\n }\n\n const result: LcmExpandedMessage[] = [];\n const lastMsg = messages[messages.length - 1];\n const reservedLastTokens = Math.min(\n estimateTokenCount(lastMsg.content),\n Math.max(1, Math.floor(tokenBudget * 0.3)),\n );\n let remainingTokens = tokenBudget - reservedLastTokens;\n\n for (let i = 0; i < messages.length - 1; i++) {\n if (remainingTokens <= 0) break;\n const content = truncateToTokenBudget(\n messages[i].content,\n remainingTokens,\n );\n if (!content) continue;\n result.push({\n id: messages[i].id,\n session_id: messages[i].session_id,\n turn_index: messages[i].turn_index,\n role: messages[i].role,\n content,\n });\n remainingTokens -= estimateTokenCount(content);\n }\n\n const lastContent = truncateToTokenBudget(\n lastMsg.content,\n reservedLastTokens + remainingTokens,\n );\n if (lastContent) {\n result.push({\n id: lastMsg.id,\n session_id: lastMsg.session_id,\n turn_index: lastMsg.turn_index,\n role: lastMsg.role,\n content: lastContent,\n });\n }\n return result;\n }\n\n\n /** Get statistics about the LCM archive. */\n async getStats(sessionId?: string): Promise<{\n totalMessages: number;\n totalSummaryNodes: number;\n maxDepth: number;\n maxTurnIndex?: number;\n }> {\n if (!this.config.enabled)\n return { totalMessages: 0, totalSummaryNodes: 0, maxDepth: -1 };\n const normalizedSessionId = normalizeOptionalLcmSessionId(sessionId);\n if (sessionId !== undefined && !normalizedSessionId) {\n return { ...EMPTY_LCM_STATS };\n }\n await this.ensureInitialized();\n\n if (normalizedSessionId) {\n return {\n totalMessages: this.archive!.getMessageCount(normalizedSessionId),\n totalSummaryNodes: this.dag!.getNodeCount(normalizedSessionId),\n maxDepth: this.dag!.getMaxDepth(normalizedSessionId),\n maxTurnIndex: this.archive!.getMaxTurnIndex(normalizedSessionId),\n };\n }\n\n return {\n totalMessages: this.archive!.getTotalMessageCount(),\n totalSummaryNodes: 0, // Would need a global count query\n maxDepth: -1,\n };\n }\n\n /** Clear all LCM archive and summary state for one session. */\n async clearSession(sessionId: string): Promise<void> {\n if (!this.config.enabled || this.closed) return;\n const normalizedSessionId = normalizeLcmSessionId(sessionId);\n if (!normalizedSessionId) return;\n await this.ensureInitialized();\n if (this.closed || !this.archive || !this.dag) return;\n await this.waitForSessionObserveIdle(normalizedSessionId);\n this.dag.deleteSession(normalizedSessionId);\n this.archive.deleteSession(normalizedSessionId);\n }\n\n /** Clear all LCM archive and summary state without closing the engine. */\n async clearAll(): Promise<void> {\n if (!this.config.enabled || this.closed) return;\n await this.ensureInitialized();\n if (this.closed || !this.archive || !this.dag) return;\n await this.waitForObserveQueueIdle();\n this.dag.deleteAll();\n this.archive.deleteAll();\n }\n\n /** Prune old data beyond retention period. */\n async prune(): Promise<{ messagesPruned: number; nodesPruned: number }> {\n if (!this.config.enabled) return { messagesPruned: 0, nodesPruned: 0 };\n await this.ensureInitialized();\n\n const messagesPruned = this.archive!.pruneOldMessages(\n this.config.archiveRetentionDays,\n );\n const nodesPruned = this.dag!.pruneOldNodes(\n this.config.archiveRetentionDays,\n );\n return { messagesPruned, nodesPruned };\n }\n\n /** Close the database connection. */\n close(): void {\n this.closed = true;\n if (this.db) {\n this.db.close();\n }\n this.db = null;\n this.archive = null;\n this.dag = null;\n this.summarizer = null;\n this.observeQueue = null;\n this.initPromise = null;\n }\n}\nfunction truncateToTokenBudget(text: string, maxTokens: number): string {\n if (maxTokens <= 0) return \"\";\n if (estimateTokenCount(text) <= maxTokens) return text;\n const codePoints = [...text];\n let low = 0;\n let high = codePoints.length;\n while (low < high) {\n const mid = Math.ceil((low + high) / 2);\n if (estimateTokenCount(codePoints.slice(0, mid).join(\"\")) <= maxTokens) {\n low = mid;\n } else {\n high = mid - 1;\n }\n }\n return codePoints.slice(0, low).join(\"\");\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/access-service-helpers.ts"],"sourcesContent":["import type { CodingScopedWriteInput } from \"./access-service.js\";\n\n\nexport interface EngramAccessLcmCompactionFlushRequest extends CodingScopedWriteInput {\n sessionKey: string;\n namespace?: string;\n authenticatedPrincipal?: string;\n}\n\nexport interface EngramAccessLcmCompactionFlushResponse {\n enabled: boolean;\n flushed: boolean;\n sessionKey: string;\n namespace: string;\n reason?: string;\n}\n\nexport interface EngramAccessExtractionForceFlushRequest extends CodingScopedWriteInput {\n sessionKey: string;\n namespace?: string;\n authenticatedPrincipal?: string;\n deadlineMs?: number;\n abortSignal?: AbortSignal;\n /** Internal HTTP hook invoked at the durable commit boundary. */\n onCommitted?: () => void;\n}\n\nexport interface EngramAccessExtractionForceFlushResponse {\n flushed: boolean;\n sessionKey: string;\n namespace: string;\n effectiveNamespace: string;\n}\n\nexport interface ExtractionForceFlushDelegate {\n extractionForceFlush(\n request: EngramAccessExtractionForceFlushRequest,\n ): Promise<EngramAccessExtractionForceFlushResponse>;\n}\n\nexport function delegateExtractionForceFlush(\n delegate: ExtractionForceFlushDelegate,\n request: EngramAccessExtractionForceFlushRequest,\n): Promise<EngramAccessExtractionForceFlushResponse> {\n return delegate.extractionForceFlush(request);\n}\n"],"mappings":";AAwCO,SAAS,6BACd,UACA,SACmD;AACnD,SAAO,SAAS,qBAAqB,OAAO;AAC9C;","names":[]}