@remnic/core 10.0.99 → 10.0.100

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 (36) hide show
  1. package/dist/access-admin-ops-surface.js +2 -2
  2. package/dist/access-cli.js +2 -2
  3. package/dist/access-extraction-force-flush.js +2 -2
  4. package/dist/access-http-briefing.js +2 -2
  5. package/dist/access-http-query.js +2 -2
  6. package/dist/access-http.js +2 -2
  7. package/dist/access-identity-continuity-surface.js +2 -2
  8. package/dist/access-lcm-surface.js +2 -2
  9. package/dist/access-mcp.js +2 -2
  10. package/dist/access-observe-write-surface.js +2 -2
  11. package/dist/access-operations-batch.js +2 -2
  12. package/dist/access-operations.js +2 -2
  13. package/dist/access-recall-concurrency.js +2 -2
  14. package/dist/access-recall-response.js +2 -2
  15. package/dist/access-recall-surface.js +2 -2
  16. package/dist/access-service.js +2 -2
  17. package/dist/{chunk-VZMRKYNR.js → chunk-MMOXCCHF.js} +2 -2
  18. package/dist/{chunk-4PXDXCNE.js → chunk-PL36IQPL.js} +47 -15
  19. package/dist/chunk-PL36IQPL.js.map +1 -0
  20. package/dist/{chunk-UBJ5RPDM.js → chunk-QIPDTAWZ.js} +2 -2
  21. package/dist/cli.js +2 -2
  22. package/dist/explicit-capture.js +2 -2
  23. package/dist/harmonic-retrieval.d.ts +5 -4
  24. package/dist/harmonic-retrieval.d.ts.map +1 -1
  25. package/dist/harmonic-retrieval.js +1 -1
  26. package/dist/index.js +2 -2
  27. package/dist/orchestration/backlog-scheduler.js +3 -3
  28. package/dist/orchestration/buffer-drain-runner.js +3 -3
  29. package/dist/orchestrator.js +2 -2
  30. package/dist/recall-navigation.js +2 -2
  31. package/package.json +2 -2
  32. package/src/harmonic-graph-cache.test.ts +187 -2
  33. package/src/harmonic-retrieval.ts +77 -19
  34. package/dist/chunk-4PXDXCNE.js.map +0 -1
  35. /package/dist/{chunk-VZMRKYNR.js.map → chunk-MMOXCCHF.js.map} +0 -0
  36. /package/dist/{chunk-UBJ5RPDM.js.map → chunk-QIPDTAWZ.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AccessAdminOpsSurface
3
- } from "./chunk-VZMRKYNR.js";
3
+ } from "./chunk-MMOXCCHF.js";
4
4
  import "./chunk-6P7U3HWG.js";
5
5
  import "./chunk-PQM3B54K.js";
6
6
  import "./chunk-B3DR2JBZ.js";
@@ -173,7 +173,7 @@ import "./chunk-MDPT6QFK.js";
173
173
  import "./chunk-UOBPK2OS.js";
174
174
  import "./chunk-2YA5N2BY.js";
175
175
  import "./chunk-3HSRWJTC.js";
176
- import "./chunk-4PXDXCNE.js";
176
+ import "./chunk-PL36IQPL.js";
177
177
  import "./chunk-HUDPXTXW.js";
178
178
  import "./chunk-AZEZSQ5R.js";
179
179
  import "./chunk-YAZNBMNF.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  EngramAccessService,
3
3
  Orchestrator
4
- } from "./chunk-VZMRKYNR.js";
4
+ } from "./chunk-MMOXCCHF.js";
5
5
  import "./chunk-6P7U3HWG.js";
6
6
  import "./chunk-PQM3B54K.js";
7
7
  import "./chunk-B3DR2JBZ.js";
@@ -176,7 +176,7 @@ import "./chunk-MDPT6QFK.js";
176
176
  import "./chunk-UOBPK2OS.js";
177
177
  import "./chunk-2YA5N2BY.js";
178
178
  import "./chunk-3HSRWJTC.js";
179
- import "./chunk-4PXDXCNE.js";
179
+ import "./chunk-PL36IQPL.js";
180
180
  import "./chunk-HUDPXTXW.js";
181
181
  import "./chunk-AZEZSQ5R.js";
182
182
  import "./chunk-YAZNBMNF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  extractionForceFlush
3
- } from "./chunk-VZMRKYNR.js";
3
+ } from "./chunk-MMOXCCHF.js";
4
4
  import "./chunk-6P7U3HWG.js";
5
5
  import "./chunk-PQM3B54K.js";
6
6
  import "./chunk-B3DR2JBZ.js";
@@ -173,7 +173,7 @@ import "./chunk-MDPT6QFK.js";
173
173
  import "./chunk-UOBPK2OS.js";
174
174
  import "./chunk-2YA5N2BY.js";
175
175
  import "./chunk-3HSRWJTC.js";
176
- import "./chunk-4PXDXCNE.js";
176
+ import "./chunk-PL36IQPL.js";
177
177
  import "./chunk-HUDPXTXW.js";
178
178
  import "./chunk-AZEZSQ5R.js";
179
179
  import "./chunk-YAZNBMNF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  respondBriefingHttp
3
- } from "./chunk-VZMRKYNR.js";
3
+ } from "./chunk-MMOXCCHF.js";
4
4
  import "./chunk-6P7U3HWG.js";
5
5
  import "./chunk-PQM3B54K.js";
6
6
  import "./chunk-B3DR2JBZ.js";
@@ -173,7 +173,7 @@ import "./chunk-MDPT6QFK.js";
173
173
  import "./chunk-UOBPK2OS.js";
174
174
  import "./chunk-2YA5N2BY.js";
175
175
  import "./chunk-3HSRWJTC.js";
176
- import "./chunk-4PXDXCNE.js";
176
+ import "./chunk-PL36IQPL.js";
177
177
  import "./chunk-HUDPXTXW.js";
178
178
  import "./chunk-AZEZSQ5R.js";
179
179
  import "./chunk-YAZNBMNF.js";
@@ -3,7 +3,7 @@ import {
3
3
  optionalNamespaceKindQueryParam,
4
4
  optionalQueryString,
5
5
  positiveIntQueryParam
6
- } from "./chunk-VZMRKYNR.js";
6
+ } from "./chunk-MMOXCCHF.js";
7
7
  import "./chunk-6P7U3HWG.js";
8
8
  import "./chunk-PQM3B54K.js";
9
9
  import "./chunk-B3DR2JBZ.js";
@@ -176,7 +176,7 @@ import "./chunk-MDPT6QFK.js";
176
176
  import "./chunk-UOBPK2OS.js";
177
177
  import "./chunk-2YA5N2BY.js";
178
178
  import "./chunk-3HSRWJTC.js";
179
- import "./chunk-4PXDXCNE.js";
179
+ import "./chunk-PL36IQPL.js";
180
180
  import "./chunk-HUDPXTXW.js";
181
181
  import "./chunk-AZEZSQ5R.js";
182
182
  import "./chunk-YAZNBMNF.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  EngramAccessHttpServer,
3
3
  resolveDefaultAdminConsolePublicDir
4
- } from "./chunk-VZMRKYNR.js";
4
+ } from "./chunk-MMOXCCHF.js";
5
5
  import "./chunk-6P7U3HWG.js";
6
6
  import "./chunk-PQM3B54K.js";
7
7
  import "./chunk-B3DR2JBZ.js";
@@ -174,7 +174,7 @@ import "./chunk-MDPT6QFK.js";
174
174
  import "./chunk-UOBPK2OS.js";
175
175
  import "./chunk-2YA5N2BY.js";
176
176
  import "./chunk-3HSRWJTC.js";
177
- import "./chunk-4PXDXCNE.js";
177
+ import "./chunk-PL36IQPL.js";
178
178
  import "./chunk-HUDPXTXW.js";
179
179
  import "./chunk-AZEZSQ5R.js";
180
180
  import "./chunk-YAZNBMNF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AccessIdentityContinuitySurface
3
- } from "./chunk-VZMRKYNR.js";
3
+ } from "./chunk-MMOXCCHF.js";
4
4
  import "./chunk-6P7U3HWG.js";
5
5
  import "./chunk-PQM3B54K.js";
6
6
  import "./chunk-B3DR2JBZ.js";
@@ -173,7 +173,7 @@ import "./chunk-MDPT6QFK.js";
173
173
  import "./chunk-UOBPK2OS.js";
174
174
  import "./chunk-2YA5N2BY.js";
175
175
  import "./chunk-3HSRWJTC.js";
176
- import "./chunk-4PXDXCNE.js";
176
+ import "./chunk-PL36IQPL.js";
177
177
  import "./chunk-HUDPXTXW.js";
178
178
  import "./chunk-AZEZSQ5R.js";
179
179
  import "./chunk-YAZNBMNF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AccessLcmSurface
3
- } from "./chunk-VZMRKYNR.js";
3
+ } from "./chunk-MMOXCCHF.js";
4
4
  import "./chunk-6P7U3HWG.js";
5
5
  import "./chunk-PQM3B54K.js";
6
6
  import "./chunk-B3DR2JBZ.js";
@@ -173,7 +173,7 @@ import "./chunk-MDPT6QFK.js";
173
173
  import "./chunk-UOBPK2OS.js";
174
174
  import "./chunk-2YA5N2BY.js";
175
175
  import "./chunk-3HSRWJTC.js";
176
- import "./chunk-4PXDXCNE.js";
176
+ import "./chunk-PL36IQPL.js";
177
177
  import "./chunk-HUDPXTXW.js";
178
178
  import "./chunk-AZEZSQ5R.js";
179
179
  import "./chunk-YAZNBMNF.js";
@@ -2,7 +2,7 @@ import {
2
2
  EngramMcpServer,
3
3
  MCP_MIGRATED_OPERATIONS,
4
4
  MCP_SUPPORTED_PROTOCOL_VERSIONS
5
- } from "./chunk-VZMRKYNR.js";
5
+ } from "./chunk-MMOXCCHF.js";
6
6
  import "./chunk-6P7U3HWG.js";
7
7
  import "./chunk-PQM3B54K.js";
8
8
  import "./chunk-B3DR2JBZ.js";
@@ -175,7 +175,7 @@ import "./chunk-MDPT6QFK.js";
175
175
  import "./chunk-UOBPK2OS.js";
176
176
  import "./chunk-2YA5N2BY.js";
177
177
  import "./chunk-3HSRWJTC.js";
178
- import "./chunk-4PXDXCNE.js";
178
+ import "./chunk-PL36IQPL.js";
179
179
  import "./chunk-HUDPXTXW.js";
180
180
  import "./chunk-AZEZSQ5R.js";
181
181
  import "./chunk-YAZNBMNF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AccessObserveWriteSurface
3
- } from "./chunk-VZMRKYNR.js";
3
+ } from "./chunk-MMOXCCHF.js";
4
4
  import "./chunk-6P7U3HWG.js";
5
5
  import "./chunk-PQM3B54K.js";
6
6
  import "./chunk-B3DR2JBZ.js";
@@ -173,7 +173,7 @@ import "./chunk-MDPT6QFK.js";
173
173
  import "./chunk-UOBPK2OS.js";
174
174
  import "./chunk-2YA5N2BY.js";
175
175
  import "./chunk-3HSRWJTC.js";
176
- import "./chunk-4PXDXCNE.js";
176
+ import "./chunk-PL36IQPL.js";
177
177
  import "./chunk-HUDPXTXW.js";
178
178
  import "./chunk-AZEZSQ5R.js";
179
179
  import "./chunk-YAZNBMNF.js";
@@ -1,4 +1,4 @@
1
- import "./chunk-VZMRKYNR.js";
1
+ import "./chunk-MMOXCCHF.js";
2
2
  import "./chunk-6P7U3HWG.js";
3
3
  import "./chunk-PQM3B54K.js";
4
4
  import "./chunk-B3DR2JBZ.js";
@@ -171,7 +171,7 @@ import "./chunk-MDPT6QFK.js";
171
171
  import "./chunk-UOBPK2OS.js";
172
172
  import "./chunk-2YA5N2BY.js";
173
173
  import "./chunk-3HSRWJTC.js";
174
- import "./chunk-4PXDXCNE.js";
174
+ import "./chunk-PL36IQPL.js";
175
175
  import "./chunk-HUDPXTXW.js";
176
176
  import "./chunk-AZEZSQ5R.js";
177
177
  import "./chunk-YAZNBMNF.js";
@@ -22,7 +22,7 @@ import {
22
22
  memoryGetOperation,
23
23
  memorySearchOperation,
24
24
  memoryStoreOperation
25
- } from "./chunk-VZMRKYNR.js";
25
+ } from "./chunk-MMOXCCHF.js";
26
26
  import "./chunk-6P7U3HWG.js";
27
27
  import "./chunk-PQM3B54K.js";
28
28
  import "./chunk-B3DR2JBZ.js";
@@ -195,7 +195,7 @@ import "./chunk-MDPT6QFK.js";
195
195
  import "./chunk-UOBPK2OS.js";
196
196
  import "./chunk-2YA5N2BY.js";
197
197
  import "./chunk-3HSRWJTC.js";
198
- import "./chunk-4PXDXCNE.js";
198
+ import "./chunk-PL36IQPL.js";
199
199
  import "./chunk-HUDPXTXW.js";
200
200
  import "./chunk-AZEZSQ5R.js";
201
201
  import "./chunk-YAZNBMNF.js";
@@ -4,7 +4,7 @@ import {
4
4
  createAndStartFlight,
5
5
  leadRecallFlight,
6
6
  withRecallConcurrency
7
- } from "./chunk-VZMRKYNR.js";
7
+ } from "./chunk-MMOXCCHF.js";
8
8
  import "./chunk-6P7U3HWG.js";
9
9
  import "./chunk-PQM3B54K.js";
10
10
  import "./chunk-B3DR2JBZ.js";
@@ -177,7 +177,7 @@ import "./chunk-MDPT6QFK.js";
177
177
  import "./chunk-UOBPK2OS.js";
178
178
  import "./chunk-2YA5N2BY.js";
179
179
  import "./chunk-3HSRWJTC.js";
180
- import "./chunk-4PXDXCNE.js";
180
+ import "./chunk-PL36IQPL.js";
181
181
  import "./chunk-HUDPXTXW.js";
182
182
  import "./chunk-AZEZSQ5R.js";
183
183
  import "./chunk-YAZNBMNF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  assembleRecallResponse
3
- } from "./chunk-VZMRKYNR.js";
3
+ } from "./chunk-MMOXCCHF.js";
4
4
  import "./chunk-6P7U3HWG.js";
5
5
  import "./chunk-PQM3B54K.js";
6
6
  import "./chunk-B3DR2JBZ.js";
@@ -173,7 +173,7 @@ import "./chunk-MDPT6QFK.js";
173
173
  import "./chunk-UOBPK2OS.js";
174
174
  import "./chunk-2YA5N2BY.js";
175
175
  import "./chunk-3HSRWJTC.js";
176
- import "./chunk-4PXDXCNE.js";
176
+ import "./chunk-PL36IQPL.js";
177
177
  import "./chunk-HUDPXTXW.js";
178
178
  import "./chunk-AZEZSQ5R.js";
179
179
  import "./chunk-YAZNBMNF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  AccessRecallSurface
3
- } from "./chunk-VZMRKYNR.js";
3
+ } from "./chunk-MMOXCCHF.js";
4
4
  import "./chunk-6P7U3HWG.js";
5
5
  import "./chunk-PQM3B54K.js";
6
6
  import "./chunk-B3DR2JBZ.js";
@@ -173,7 +173,7 @@ import "./chunk-MDPT6QFK.js";
173
173
  import "./chunk-UOBPK2OS.js";
174
174
  import "./chunk-2YA5N2BY.js";
175
175
  import "./chunk-3HSRWJTC.js";
176
- import "./chunk-4PXDXCNE.js";
176
+ import "./chunk-PL36IQPL.js";
177
177
  import "./chunk-HUDPXTXW.js";
178
178
  import "./chunk-AZEZSQ5R.js";
179
179
  import "./chunk-YAZNBMNF.js";
@@ -4,7 +4,7 @@ import {
4
4
  buildProjectedGovernanceProposedActions,
5
5
  hasGroupedGovernanceActions,
6
6
  shapeMemorySummary
7
- } from "./chunk-VZMRKYNR.js";
7
+ } from "./chunk-MMOXCCHF.js";
8
8
  import "./chunk-6P7U3HWG.js";
9
9
  import "./chunk-PQM3B54K.js";
10
10
  import "./chunk-B3DR2JBZ.js";
@@ -177,7 +177,7 @@ import "./chunk-MDPT6QFK.js";
177
177
  import "./chunk-UOBPK2OS.js";
178
178
  import "./chunk-2YA5N2BY.js";
179
179
  import "./chunk-3HSRWJTC.js";
180
- import "./chunk-4PXDXCNE.js";
180
+ import "./chunk-PL36IQPL.js";
181
181
  import "./chunk-HUDPXTXW.js";
182
182
  import "./chunk-AZEZSQ5R.js";
183
183
  import "./chunk-YAZNBMNF.js";
@@ -544,7 +544,7 @@ import {
544
544
  import {
545
545
  readProjectedHarmonicGraph,
546
546
  searchHarmonicRetrieval
547
- } from "./chunk-4PXDXCNE.js";
547
+ } from "./chunk-PL36IQPL.js";
548
548
  import {
549
549
  classifyMemoryKind
550
550
  } from "./chunk-YAZNBMNF.js";
@@ -67200,4 +67200,4 @@ export {
67200
67200
  EngramAccessService,
67201
67201
  AccessAdminOpsSurface
67202
67202
  };
67203
- //# sourceMappingURL=chunk-VZMRKYNR.js.map
67203
+ //# sourceMappingURL=chunk-MMOXCCHF.js.map
@@ -30,6 +30,7 @@ import {
30
30
  stripAttributesSuffix
31
31
  } from "./chunk-JDSVLVCG.js";
32
32
  import {
33
+ raceAbort,
33
34
  throwIfAborted
34
35
  } from "./chunk-R2MBW2S4.js";
35
36
  import {
@@ -348,7 +349,8 @@ async function buildProjectedHarmonicGraph(options) {
348
349
  var GRAPH_CACHE_TTL_MS = 3e4;
349
350
  var GRAPH_CACHE_MAX_ENTRIES = 8;
350
351
  var graphCache = /* @__PURE__ */ new Map();
351
- var harmonicGraphCacheStats = { hits: 0, misses: 0 };
352
+ var graphBuilds = /* @__PURE__ */ new Map();
353
+ var harmonicGraphCacheStats = { hits: 0, misses: 0, shared: 0 };
352
354
  function deepFreeze(value) {
353
355
  if (Object.isFrozen(value)) return value;
354
356
  Object.freeze(value);
@@ -357,6 +359,44 @@ function deepFreeze(value) {
357
359
  }
358
360
  function clearHarmonicGraphCache() {
359
361
  graphCache.clear();
362
+ graphBuilds.clear();
363
+ }
364
+ function startGraphBuild(key, stamp, options) {
365
+ harmonicGraphCacheStats.misses++;
366
+ const startedAtMs = Date.now();
367
+ const controller = new AbortController();
368
+ const promise = buildProjectedHarmonicGraph({
369
+ memoryDir: options.memoryDir,
370
+ abstractionNodeStoreDir: options.abstractionNodeStoreDir,
371
+ anchorsEnabled: options.anchorsEnabled,
372
+ temporalExpiredInInjection: options.temporalExpiredInInjection,
373
+ abortSignal: controller.signal
374
+ }).then((built) => {
375
+ const graph = { nodes: deepFreeze(built.nodes), anchors: deepFreeze(built.anchors) };
376
+ if (graphBuilds.get(key)?.promise !== promise) return graph;
377
+ graphCache.delete(key);
378
+ graphCache.set(key, { stamp, startedAtMs, graph });
379
+ while (graphCache.size > GRAPH_CACHE_MAX_ENTRIES) {
380
+ const oldest = graphCache.keys().next().value;
381
+ if (oldest === void 0) break;
382
+ graphCache.delete(oldest);
383
+ }
384
+ return graph;
385
+ }).finally(() => {
386
+ if (graphBuilds.get(key)?.promise === promise) graphBuilds.delete(key);
387
+ });
388
+ const build = { stamp, promise, controller, waiting: 0 };
389
+ graphBuilds.set(key, build);
390
+ return build;
391
+ }
392
+ function joinGraphBuild(key, build, signal) {
393
+ build.waiting++;
394
+ return raceAbort(build.promise, signal, "harmonic retrieval aborted").finally(() => {
395
+ build.waiting--;
396
+ if (build.waiting > 0) return;
397
+ if (graphBuilds.get(key) === build) graphBuilds.delete(key);
398
+ build.controller.abort();
399
+ });
360
400
  }
361
401
  async function readProjectedHarmonicGraph(options) {
362
402
  if (options.useCache !== true || options.nowMs !== void 0) return buildProjectedHarmonicGraph(options);
@@ -377,20 +417,12 @@ async function readProjectedHarmonicGraph(options) {
377
417
  graphCache.set(key, hit);
378
418
  return hit.graph;
379
419
  }
380
- harmonicGraphCacheStats.misses++;
381
- const built = await buildProjectedHarmonicGraph(options);
382
- const graph = {
383
- nodes: deepFreeze(built.nodes),
384
- anchors: deepFreeze(built.anchors)
385
- };
386
- graphCache.delete(key);
387
- graphCache.set(key, { stamp, startedAtMs, graph });
388
- while (graphCache.size > GRAPH_CACHE_MAX_ENTRIES) {
389
- const oldest = graphCache.keys().next().value;
390
- if (oldest === void 0) break;
391
- graphCache.delete(oldest);
420
+ const running = graphBuilds.get(key);
421
+ if (running?.stamp === stamp) {
422
+ harmonicGraphCacheStats.shared++;
423
+ return joinGraphBuild(key, running, options.abortSignal);
392
424
  }
393
- return graph;
425
+ return joinGraphBuild(key, startGraphBuild(key, stamp, options), options.abortSignal);
394
426
  }
395
427
  async function searchHarmonicRetrieval(options) {
396
428
  throwIfAborted(options.abortSignal, "harmonic retrieval aborted");
@@ -471,4 +503,4 @@ export {
471
503
  readProjectedHarmonicGraph,
472
504
  searchHarmonicRetrieval
473
505
  };
474
- //# sourceMappingURL=chunk-4PXDXCNE.js.map
506
+ //# sourceMappingURL=chunk-PL36IQPL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/harmonic-retrieval.ts"],"sourcesContent":["import path from \"node:path\";\nimport { realpath } from \"node:fs/promises\";\nimport { listJsonFilesStrict, readJsonFile } from \"./json-store.js\";\nimport { raceAbort, throwIfAborted } from \"./abort-error.js\";\nimport { readHarmonicGraphStamp } from \"./harmonic-graph-version.js\";\nimport { inferMemoryStatus, toMemoryPathRel } from \"./memory-lifecycle-ledger-utils.js\";\n import {\n HARMONIC_SOURCE_MEMORY_INSERTED_AT_KEY,\n resolveAbstractionNodeStoreDir,\n validateAbstractionNode,\n type AbstractionNode,\n } from \"./abstraction-nodes.js\";\nimport { resolveCueAnchorStoreDir, validateCueAnchor, type CueAnchor, type CueAnchorType } from \"./cue-anchors.js\";\nimport { compareDeterministicStrings } from \"./deterministic-order.js\";\nimport { countRecallTokenOverlap, normalizeRecallTokens } from \"./recall-tokenization.js\";\nimport { stripAttributesSuffix } from \"./structured-attributes.js\";\nimport { isValidityExpiredNow } from \"./temporal-validity.js\";\nimport { assertSafePathSegment, isRecord } from \"./store-contract.js\";\nimport { isSupportPassportPrivateMemory } from \"./support-passport/card-projection.js\";\nimport type { MemoryFile } from \"./types.js\";\nimport { readProjectedMemoryStates } from \"./memory-projection-batch.js\";\nimport { SecureStoreLockedError } from \"./secure-store/secure-fs.js\";\nimport { StorageManager } from \"./storage.js\";\nimport { RECALL_FALLBACK_DIRS } from \"./utils/category-dir.js\";\nimport { readHarmonicSourceMemory, readUnresolvedHarmonicSources } from \"./harmonic-source-lookup.js\";\n\n\ntype SourceMemoryMap = Map<string, MemoryFile>;\n\n\n// An index older than this is treated as unusable: the date window needed to\n// cover \"created since the last rebuild\" would stop being cheap.\nconst INDEX_MAX_AGE_MS = 7 * 86_400_000;\nconst DAY_MS = 86_400_000;\n\nfunction utcDaysSince(rebuiltMs: number, nowMs: number): string[] {\n const days: string[] = [];\n for (let day = Math.floor((rebuiltMs - DAY_MS) / DAY_MS) * DAY_MS; day <= nowMs; day += DAY_MS) {\n days.push(new Date(day).toISOString().slice(0, 10));\n }\n return days;\n}\n\n\n// Memories the projection has no row for were written after its last rebuild, so\n// their dated directory is normally one of `days`. Hot and cold tiers are probed\n// by exact path. Only recall-corpus categories are probed: `questions/` is a queue\n// and `artifacts/` is outside the recall surface, so neither can be a source.\nfunction unprojectedCandidatePaths(memoryDir: string, id: string, days: string[]): string[] {\n const paths: string[] = [];\n for (const root of [memoryDir, path.join(memoryDir, \"cold\")]) {\n for (const dir of RECALL_FALLBACK_DIRS) {\n paths.push(path.join(root, dir, `${id}.md`));\n for (const day of days) paths.push(path.join(root, dir, day, `${id}.md`));\n }\n }\n return paths;\n}\n\n/** Resolve indexed sources first, then use the durable unresolved-id path cache. */\nasync function readIndexedSourceMemories(options: {\n memoryDir: string;\n abortSignal?: AbortSignal;\n sourceMemoryIds: string[];\n nowMs: number;\n}): Promise<SourceMemoryMap | null> {\n // The ids go to SQL as bound parameters, so any id the projection holds is safe to look up.\n const batch = readProjectedMemoryStates(options.memoryDir, options.sourceMemoryIds);\n const rebuiltMs = Date.parse(batch?.rebuiltAt ?? \"\");\n if (!batch?.complete || !batch.rebuiltAt || !Number.isFinite(rebuiltMs) || options.nowMs - rebuiltMs > INDEX_MAX_AGE_MS) return null;\n const rootReal = await realpath(options.memoryDir).catch(() => null);\n if (rootReal === null) return null;\n\n const storage = new StorageManager(options.memoryDir);\n const days = utcDaysSince(rebuiltMs, options.nowMs);\n const sourceMemories: SourceMemoryMap = new Map();\n const pending: string[] = [];\n for (const id of options.sourceMemoryIds) {\n const state = batch.states.get(id);\n // An id is only ever joined into a path when it is a single safe segment.\n let safeId = true;\n try {\n assertSafePathSegment(id, \"sourceMemoryId\");\n } catch {\n safeId = false;\n }\n // state.path was containment-checked by the projection reader.\n const candidates = state\n ? [state.path, path.join(options.memoryDir, \"cold\", state.pathRel)]\n : safeId ? unprojectedCandidatePaths(options.memoryDir, id, days) : [];\n let found = false;\n for (const candidate of candidates) {\n const memory = await readHarmonicSourceMemory(storage, rootReal, candidate, options.abortSignal);\n if (memory?.frontmatter.id !== id) continue;\n sourceMemories.set(id, memory);\n found = true;\n break;\n }\n if (!found) pending.push(id);\n }\n if (pending.length === 0) return sourceMemories;\n\n const unresolved = await readUnresolvedHarmonicSources({\n storage, rootReal, rebuiltAt: batch.rebuiltAt, sourceMemoryIds: pending,\n nowMs: options.nowMs, abortSignal: options.abortSignal,\n });\n for (const [id, memory] of unresolved) sourceMemories.set(id, memory);\n return sourceMemories;\n}\n\nasync function readCorpusSourceMemories(options: {\n memoryDir: string;\n abortSignal?: AbortSignal;\n}): Promise<SourceMemoryMap> {\n const sourceMemories: SourceMemoryMap = new Map();\n try {\n const storage = new StorageManager(options.memoryDir);\n const [hotMemories, coldMemories] = await Promise.all([\n storage.readAllMemories({ abortSignal: options.abortSignal }),\n storage.readAllColdMemories({ abortSignal: options.abortSignal }),\n ]);\n for (const memory of [...hotMemories, ...coldMemories]) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n sourceMemories.set(memory.frontmatter.id, memory);\n }\n } catch (err) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n if (err instanceof SecureStoreLockedError) return new Map();\n // Source validation fails closed when the authorized memory directory is\n // unreadable. Source-less nodes remain eligible for retrieval.\n sourceMemories.clear();\n }\n return sourceMemories;\n}\n\nasync function readSourceMemories(options: {\n memoryDir: string;\n abortSignal?: AbortSignal;\n sourceMemoryIds: string[];\n nowMs?: number;\n}): Promise<SourceMemoryMap> {\n try {\n const indexed = await readIndexedSourceMemories({\n memoryDir: options.memoryDir,\n abortSignal: options.abortSignal,\n sourceMemoryIds: options.sourceMemoryIds,\n nowMs: options.nowMs ?? Date.now(),\n });\n if (indexed) return indexed;\n } catch (err) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n if (err instanceof SecureStoreLockedError) return new Map();\n }\n return readCorpusSourceMemories(options);\n}\n\nfunction parseSourceMemoryInsertedAt(node: AbstractionNode): Map<string, string> {\n const insertedAtById = new Map<string, string>();\n const insertedAtRaw = node.metadata?.[HARMONIC_SOURCE_MEMORY_INSERTED_AT_KEY];\n if (!insertedAtRaw) return insertedAtById;\n try {\n const parsed = JSON.parse(insertedAtRaw) as unknown;\n if (!isRecord(parsed)) return insertedAtById;\n for (const [memoryId, value] of Object.entries(parsed)) {\n if (typeof value === \"string\") insertedAtById.set(memoryId, value);\n }\n } catch {\n // Malformed insertion metadata leaves ordering on the recordedAt fallback.\n }\n return insertedAtById;\n}\n\nfunction projectSourceBackedNode(\n node: AbstractionNode,\n sourceMemories: SourceMemoryMap,\n memoryDir: string,\n temporalExpiredInInjection: boolean,\n nowMs: number\n): AbstractionNode | null {\n const sourceMemoryIds = node.sourceMemoryIds ?? [];\n if (sourceMemoryIds.length === 0) return node;\n\n const activeSourceMemoryIds = sourceMemoryIds.filter((memoryId) => {\n const memory = sourceMemories.get(memoryId);\n return (\n memory !== undefined &&\n // #2332: a private support-passport record leaves the eligible set the\n // same way a rejected one does — a node title or anchor attribution\n // rebuilt from it would leak governed metadata into the deep-recall\n // frontier (and every other graph reader) before any content check runs.\n !isSupportPassportPrivateMemory(memory) &&\n inferMemoryStatus(memory.frontmatter, toMemoryPathRel(memoryDir, memory.path)) === \"active\" &&\n (temporalExpiredInInjection || !isValidityExpiredNow(memory.frontmatter, nowMs))\n );\n });\n if (activeSourceMemoryIds.length === 0) return null;\n\n // Newest-first source order keeps the projected title and summary on the most\n // recently inserted facts. Equal or missing timestamps fall back to ascending\n // id order, which matches the stored sourceMemoryIds order.\n const insertedAtById = parseSourceMemoryInsertedAt(node);\n const insertedAtMs = (memoryId: string): number => {\n const parsedMs = Date.parse(insertedAtById.get(memoryId) ?? \"\");\n return Number.isFinite(parsedMs) ? parsedMs : Date.parse(node.recordedAt);\n };\n activeSourceMemoryIds.sort(\n (left, right) =>\n insertedAtMs(right) - insertedAtMs(left) || compareDeterministicStrings(left, right)\n );\n\n const activeMemories = activeSourceMemoryIds.flatMap((memoryId) => {\n const memory = sourceMemories.get(memoryId);\n return memory ? [memory] : [];\n });\n const activeContents = activeMemories.map((memory) =>\n memory.frontmatter.structuredAttributes ? stripAttributesSuffix(memory.content) : memory.content\n );\n let metadata: Record<string, string> | undefined;\n const activeInsertedAt = activeSourceMemoryIds.flatMap((memoryId) => {\n const value = insertedAtById.get(memoryId);\n return typeof value === \"string\" ? [[memoryId, value] as const] : [];\n });\n if (activeInsertedAt.length > 0) {\n metadata = {\n [HARMONIC_SOURCE_MEMORY_INSERTED_AT_KEY]: JSON.stringify(Object.fromEntries(activeInsertedAt)),\n };\n }\n\n return {\n ...node,\n sourceMemoryIds: activeSourceMemoryIds,\n title: activeContents[0]?.slice(0, 80) ?? node.title,\n summary: activeContents.slice(0, 3).join(\"; \").slice(0, 400),\n tags: [...new Set(activeMemories.flatMap((memory) => memory.frontmatter.tags))].sort(compareDeterministicStrings),\n entityRefs: [\n ...new Set(\n activeMemories.flatMap((memory) =>\n typeof memory.frontmatter.entityRef === \"string\" ? [memory.frontmatter.entityRef] : []\n )\n ),\n ].sort(compareDeterministicStrings),\n metadata,\n };\n}\n\nfunction anchorMatchesProjectedNode(\n anchor: CueAnchor,\n nodeRef: string,\n node: AbstractionNode,\n allowLegacyAttribution: boolean\n): boolean {\n const activeSourceMemoryIds = node.sourceMemoryIds ?? [];\n if (activeSourceMemoryIds.length === 0) return true;\n if (!anchor.sourceMemoryIdsByNodeRef) return allowLegacyAttribution;\n const anchorSourceMemoryIds = anchor.sourceMemoryIdsByNodeRef[nodeRef] ?? [];\n return anchorSourceMemoryIds.some((sourceMemoryId) => activeSourceMemoryIds.includes(sourceMemoryId));\n}\n\nexport interface HarmonicMatchedAnchor {\n anchorId: string;\n anchorType: CueAnchorType;\n anchorValue: string;\n}\n\nexport interface HarmonicRetrievalResult {\n node: AbstractionNode;\n score: number;\n nodeScore: number;\n anchorScore: number;\n matchedFields: string[];\n matchedAnchors: HarmonicMatchedAnchor[];\n}\n\ninterface HarmonicCandidate {\n node: AbstractionNode;\n nodeScore: number;\n anchorScore: number;\n matchedFields: Set<string>;\n matchedAnchors: Map<string, HarmonicMatchedAnchor>;\n}\n\nfunction scoreNode(node: AbstractionNode, queryTokens: Set<string>): { score: number; matchedFields: string[] } {\n const matchedFields: string[] = [];\n let score = 0;\n\n const titleMatches = countRecallTokenOverlap(queryTokens, node.title);\n if (titleMatches > 0) {\n score += titleMatches * 3;\n matchedFields.push(\"title\");\n }\n\n const summaryMatches = countRecallTokenOverlap(queryTokens, node.summary);\n if (summaryMatches > 0) {\n score += summaryMatches * 3;\n matchedFields.push(\"summary\");\n }\n\n const tagMatches = countRecallTokenOverlap(queryTokens, node.tags?.join(\" \"));\n if (tagMatches > 0) {\n score += tagMatches * 2;\n matchedFields.push(\"tags\");\n }\n\n const entityMatches = countRecallTokenOverlap(queryTokens, node.entityRefs?.join(\" \"));\n if (entityMatches > 0) {\n score += entityMatches * 2;\n matchedFields.push(\"entityRefs\");\n }\n\n const kindMatches = countRecallTokenOverlap(queryTokens, `${node.kind} ${node.abstractionLevel}`);\n if (kindMatches > 0) {\n score += kindMatches;\n matchedFields.push(\"kind\");\n }\n\n return { score, matchedFields };\n}\n\nfunction scoreAnchor(\n anchor: CueAnchor,\n queryTokens: Set<string>,\n eligibleNodeTags: readonly string[]\n): { score: number; matchedFields: string[] } {\n const matchedFields: string[] = [];\n let score = 0;\n\n const valueMatches = countRecallTokenOverlap(queryTokens, anchor.anchorValue);\n const normalizedMatches = countRecallTokenOverlap(queryTokens, anchor.normalizedCue);\n const cueMatches = Math.max(valueMatches, normalizedMatches);\n if (cueMatches > 0) {\n score += cueMatches * 4;\n if (valueMatches > 0) matchedFields.push(\"anchorValue\");\n if (normalizedMatches > 0) matchedFields.push(\"anchor\");\n }\n\n const typeMatches = countRecallTokenOverlap(queryTokens, anchor.anchorType);\n if (typeMatches > 0) {\n score += typeMatches;\n matchedFields.push(\"anchorType\");\n }\n\n const tagMatches = countRecallTokenOverlap(queryTokens, eligibleNodeTags.join(\" \"));\n if (tagMatches > 0) {\n score += tagMatches * 2;\n matchedFields.push(\"anchorTags\");\n }\n\n return { score, matchedFields };\n}\n\nexport async function readAbstractionNodes(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n}): Promise<AbstractionNode[]> {\n const rootDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);\n const files = await listJsonFilesStrict(path.join(rootDir, \"nodes\"), { allowMissingDirectory: true });\n const nodes: AbstractionNode[] = [];\n for (const filePath of files) {\n try {\n nodes.push(validateAbstractionNode(await readJsonFile(filePath)));\n } catch {\n // fail-open: invalid artifacts stay visible via status tooling instead of recall\n }\n }\n return nodes;\n}\n\nexport async function readCueAnchors(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n}): Promise<CueAnchor[]> {\n const abstractionRoot = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);\n const rootDir = resolveCueAnchorStoreDir(abstractionRoot);\n const files = await listJsonFilesStrict(rootDir, { allowMissingDirectory: true });\n const anchors: CueAnchor[] = [];\n for (const filePath of files) {\n try {\n anchors.push(validateCueAnchor(await readJsonFile(filePath)));\n } catch {\n // fail-open: invalid artifacts stay visible via status tooling instead of recall\n }\n }\n return anchors;\n}\n\nexport interface ProjectedHarmonicGraph {\n nodes: AbstractionNode[];\n anchors: CueAnchor[];\n}\n\n/**\n * Read nodes + anchors and project BOTH against the namespace's current active\n * memories. This is the single projection every graph reader shares: a raw\n * `readAbstractionNodes` / `readCueAnchors` pair still carries the stored title,\n * summary, tags, and anchor attribution of a memory that was later rejected,\n * quarantined, or otherwise moved out of the active set, so a second reader\n * that skipped the projection could leak governed metadata even when the\n * memory itself is excluded from the final results.\n *\n * - A node whose every source memory left the active set is dropped.\n * - A surviving node's title/summary/tags/entityRefs are rebuilt from its\n * active sources only.\n * - An anchor keeps a node reference only while its attribution runs through\n * one of that node's surviving active sources, and is dropped once no\n * reference survives.\n */\nasync function buildProjectedHarmonicGraph(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n anchorsEnabled: boolean;\n abortSignal?: AbortSignal;\n temporalExpiredInInjection?: boolean;\n nowMs?: number;\n}): Promise<ProjectedHarmonicGraph> {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodes = await readAbstractionNodes(options);\n const sourceMemoryIds = [...new Set(nodes.flatMap((node) => node.sourceMemoryIds ?? []))];\n const sourceMemories: SourceMemoryMap = sourceMemoryIds.length > 0\n ? await readSourceMemories({\n memoryDir: options.memoryDir,\n abortSignal: options.abortSignal,\n sourceMemoryIds,\n nowMs: options.nowMs,\n })\n : new Map();\n const nowMs = options.nowMs ?? Date.now();\n // A node whose full stored source set survived projection keeps legacy\n // anchor attribution (an anchor written before per-node source ids existed).\n const legacyCompatibleNodeRefs = new Set<string>();\n const projectedNodes = nodes.flatMap((node) => {\n const projected = projectSourceBackedNode(\n node,\n sourceMemories,\n options.memoryDir,\n options.temporalExpiredInInjection === true,\n nowMs\n );\n if (\n projected &&\n (node.sourceMemoryIds?.length ?? 0) > 0 &&\n projected.sourceMemoryIds?.length === node.sourceMemoryIds?.length\n ) {\n legacyCompatibleNodeRefs.add(node.nodeId);\n }\n return projected ? [projected] : [];\n });\n if (!options.anchorsEnabled) return { nodes: projectedNodes, anchors: [] };\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodeIndex = new Map(projectedNodes.map((node) => [node.nodeId, node]));\n const anchors = (await readCueAnchors(options)).flatMap((anchor) => {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodeRefs = anchor.nodeRefs.filter((nodeRef) => {\n const node = nodeIndex.get(nodeRef);\n return (\n node !== undefined &&\n anchorMatchesProjectedNode(anchor, nodeRef, node, legacyCompatibleNodeRefs.has(nodeRef))\n );\n });\n return nodeRefs.length > 0 ? [{ ...anchor, nodeRefs }] : [];\n });\n return { nodes: projectedNodes, anchors };\n}\n\nconst GRAPH_CACHE_TTL_MS = 30_000;\nconst GRAPH_CACHE_MAX_ENTRIES = 8;\n\ninterface GraphCacheEntry {\n stamp: string;\n startedAtMs: number;\n graph: ProjectedHarmonicGraph;\n}\n\nconst graphCache = new Map<string, GraphCacheEntry>();\n\ninterface GraphBuild {\n stamp: string;\n promise: Promise<ProjectedHarmonicGraph>;\n /** Cancels the build's source scan; fired when no caller is waiting for it. */\n controller: AbortController;\n /** Callers currently waiting for this build. */\n waiting: number;\n}\n\n/** One build per cache key at a time: every recall that lands on a miss waits for the same build. */\nconst graphBuilds = new Map<string, GraphBuild>();\n/** Counters for tests and diagnostics. `shared` counts reads that joined a build already running. */\nexport const harmonicGraphCacheStats = { hits: 0, misses: 0, shared: 0 };\n\n/** Freeze records and their nested arrays/objects so a caller cannot corrupt the shared cache. */\nfunction deepFreeze<T extends object>(value: T): T {\n // isFrozen is true for primitives and null, and a frozen value is not revisited, so this ends on cycles too.\n if (Object.isFrozen(value)) return value;\n Object.freeze(value);\n for (const child of Object.values(value)) deepFreeze(child);\n return value;\n}\n\nexport function clearHarmonicGraphCache(): void {\n graphCache.clear();\n graphBuilds.clear();\n}\n\ntype GraphReadOptions = Parameters<typeof buildProjectedHarmonicGraph>[0];\n\n/**\n * Start the one build for `key`. The build owns an abort controller instead of using one caller's signal,\n * so a caller that leaves does not cancel it for the others; `joinGraphBuild` cancels it when the last caller leaves.\n */\nfunction startGraphBuild(key: string, stamp: string, options: GraphReadOptions): GraphBuild {\n harmonicGraphCacheStats.misses++;\n const startedAtMs = Date.now();\n const controller = new AbortController();\n const promise: Promise<ProjectedHarmonicGraph> = buildProjectedHarmonicGraph({\n memoryDir: options.memoryDir,\n abstractionNodeStoreDir: options.abstractionNodeStoreDir,\n anchorsEnabled: options.anchorsEnabled,\n temporalExpiredInInjection: options.temporalExpiredInInjection,\n abortSignal: controller.signal,\n })\n .then((built) => {\n const graph = { nodes: deepFreeze(built.nodes), anchors: deepFreeze(built.anchors) };\n // A cleared cache or a newer build for this key has replaced this one: do not store a stale graph.\n if (graphBuilds.get(key)?.promise !== promise) return graph;\n graphCache.delete(key);\n graphCache.set(key, { stamp, startedAtMs, graph });\n while (graphCache.size > GRAPH_CACHE_MAX_ENTRIES) {\n const oldest = graphCache.keys().next().value;\n if (oldest === undefined) break;\n graphCache.delete(oldest);\n }\n return graph;\n })\n .finally(() => {\n if (graphBuilds.get(key)?.promise === promise) graphBuilds.delete(key);\n });\n const build: GraphBuild = { stamp, promise, controller, waiting: 0 };\n graphBuilds.set(key, build);\n return build;\n}\n\n/**\n * Wait for `build` on behalf of one caller. The caller's own signal ends only its own wait. When the last\n * waiting caller has left, the build is cancelled and dropped, so abandoned recalls do not leave full scans running\n * (cancelling a build that already finished does nothing).\n */\nfunction joinGraphBuild(key: string, build: GraphBuild, signal: AbortSignal | undefined): Promise<ProjectedHarmonicGraph> {\n build.waiting++;\n return raceAbort(build.promise, signal, \"harmonic retrieval aborted\").finally(() => {\n build.waiting--;\n if (build.waiting > 0) return;\n if (graphBuilds.get(key) === build) graphBuilds.delete(key);\n build.controller.abort();\n });\n}\n\n/**\n * `readProjectedHarmonicGraph` with an opt-in in-memory cache. Every recall used\n * to re-read all nodes, anchors and source memories from disk (about 4.7 s on a\n * 2107 node, 9199 anchor, 4105 source graph). With `useCache` a completed graph is\n * reused while the stamp below is unchanged: the memory corpus, memory status and\n * cold-write version sentinels (bumped by every memory write, in any process) and\n * the graph version sentinel (bumped by node and anchor writes). A stamp read is\n * four stats, not a scan of the memories. The TTL bounds the one input a sentinel\n * cannot see, which is wall-clock validity expiry. Concurrent misses share one\n * build. An explicit `nowMs` bypasses the cache so tests stay deterministic. The\n * cached arrays are frozen: callers must not mutate them.\n */\nexport async function readProjectedHarmonicGraph(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n anchorsEnabled: boolean;\n abortSignal?: AbortSignal;\n temporalExpiredInInjection?: boolean;\n nowMs?: number;\n useCache?: boolean;\n}): Promise<ProjectedHarmonicGraph> {\n if (options.useCache !== true || options.nowMs !== undefined) return buildProjectedHarmonicGraph(options);\n // Same cancellation contract as the builder: a cache hit must not mask an aborted signal.\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodeStoreDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);\n const key = JSON.stringify([\n options.memoryDir,\n nodeStoreDir,\n options.anchorsEnabled === true,\n options.temporalExpiredInInjection === true,\n ]);\n // The stamp is read BEFORE the build, so a write that lands mid-build leaves the\n // entry stale and the next call rebuilds.\n const stamp = readHarmonicGraphStamp(options.memoryDir, nodeStoreDir);\n const startedAtMs = Date.now();\n const hit = graphCache.get(key);\n if (hit && hit.stamp === stamp && startedAtMs - hit.startedAtMs < GRAPH_CACHE_TTL_MS) {\n harmonicGraphCacheStats.hits++;\n graphCache.delete(key);\n graphCache.set(key, hit);\n return hit.graph;\n }\n const running = graphBuilds.get(key);\n if (running?.stamp === stamp) {\n harmonicGraphCacheStats.shared++;\n return joinGraphBuild(key, running, options.abortSignal);\n }\n return joinGraphBuild(key, startGraphBuild(key, stamp, options), options.abortSignal);\n}\n\nexport async function searchHarmonicRetrieval(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n query: string;\n maxResults: number;\n sessionKey?: string;\n anchorsEnabled: boolean;\n abortSignal?: AbortSignal;\n temporalExpiredInInjection?: boolean;\n /** Share one projected graph between recalls until a write bumps a version sentinel (see readProjectedHarmonicGraph). */\n useGraphCache?: boolean;\n}): Promise<HarmonicRetrievalResult[]> {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const queryTokens = new Set(normalizeRecallTokens(options.query, [\"what\", \"which\"]));\n if (queryTokens.size === 0 || options.maxResults <= 0) return [];\n\n // One projection for every graph reader: nodes and anchors both arrive\n // already narrowed to the namespace's current active memories.\n const { nodes: eligibleNodes, anchors } = await readProjectedHarmonicGraph({\n ...options,\n useCache: options.useGraphCache === true,\n });\n const candidates = new Map<string, HarmonicCandidate>();\n\n for (const node of eligibleNodes) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const { score, matchedFields } = scoreNode(node, queryTokens);\n if (score <= 0) continue;\n candidates.set(node.nodeId, {\n node,\n nodeScore: score,\n anchorScore: 0,\n matchedFields: new Set(matchedFields),\n matchedAnchors: new Map(),\n });\n }\n\n if (options.anchorsEnabled) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodeIndex = new Map(eligibleNodes.map((node) => [node.nodeId, node]));\n for (const anchor of anchors) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n // `nodeRefs` are the projection's surviving references already.\n const eligibleNodeRefs = anchor.nodeRefs;\n const eligibleNodeTags = new Set(eligibleNodeRefs.flatMap((nodeRef) => nodeIndex.get(nodeRef)?.tags ?? []));\n const eligibleAnchorTags = anchor.tags?.filter((tag) => eligibleNodeTags.has(tag)) ?? [];\n const { score, matchedFields } = scoreAnchor(anchor, queryTokens, eligibleAnchorTags);\n if (score <= 0) continue;\n for (const nodeRef of eligibleNodeRefs) {\n const node = nodeIndex.get(nodeRef);\n if (!node) continue;\n const existing = candidates.get(nodeRef) ?? {\n node,\n nodeScore: 0,\n anchorScore: 0,\n matchedFields: new Set<string>(),\n matchedAnchors: new Map<string, HarmonicMatchedAnchor>(),\n };\n existing.anchorScore += score;\n existing.matchedFields.add(\"anchor\");\n for (const field of matchedFields) existing.matchedFields.add(field);\n existing.matchedAnchors.set(anchor.anchorId, {\n anchorId: anchor.anchorId,\n anchorType: anchor.anchorType,\n anchorValue: anchor.anchorValue,\n });\n candidates.set(nodeRef, existing);\n }\n }\n }\n\n return [...candidates.values()]\n .map((candidate) => {\n let score = candidate.nodeScore + candidate.anchorScore;\n if (options.sessionKey && candidate.node.sessionKey === options.sessionKey) score += 0.5;\n return {\n node: candidate.node,\n score,\n nodeScore: candidate.nodeScore,\n anchorScore: candidate.anchorScore,\n matchedFields: [...candidate.matchedFields].sort(),\n matchedAnchors: [...candidate.matchedAnchors.values()].sort(\n (left, right) =>\n left.anchorType.localeCompare(right.anchorType) || left.anchorValue.localeCompare(right.anchorValue)\n ),\n };\n })\n .filter((result) => result.nodeScore > 0 || result.anchorScore > 0)\n .sort(\n (left, right) =>\n right.score - left.score ||\n right.anchorScore - left.anchorScore ||\n right.node.recordedAt.localeCompare(left.node.recordedAt)\n )\n .slice(0, options.maxResults);\n}\n"],"mappings":"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","names":[]}
@@ -2,7 +2,7 @@ import {
2
2
  ExtractionDrain,
3
3
  TurnIngestionCoordinator,
4
4
  shouldSkipImplicitExtraction
5
- } from "./chunk-VZMRKYNR.js";
5
+ } from "./chunk-MMOXCCHF.js";
6
6
  import {
7
7
  headerConnector,
8
8
  renderExtractionConversation,
@@ -447,4 +447,4 @@ export {
447
447
  ClaimBufferStorage,
448
448
  BufferDrainRunner
449
449
  };
450
- //# sourceMappingURL=chunk-UBJ5RPDM.js.map
450
+ //# sourceMappingURL=chunk-QIPDTAWZ.js.map
package/dist/cli.js CHANGED
@@ -91,7 +91,7 @@ import {
91
91
  runWorkProductStatusCliCommand,
92
92
  runWorkProjectCliCommand,
93
93
  runWorkTaskCliCommand
94
- } from "./chunk-VZMRKYNR.js";
94
+ } from "./chunk-MMOXCCHF.js";
95
95
  import "./chunk-6P7U3HWG.js";
96
96
  import "./chunk-PQM3B54K.js";
97
97
  import "./chunk-B3DR2JBZ.js";
@@ -264,7 +264,7 @@ import "./chunk-MDPT6QFK.js";
264
264
  import "./chunk-UOBPK2OS.js";
265
265
  import "./chunk-2YA5N2BY.js";
266
266
  import "./chunk-3HSRWJTC.js";
267
- import "./chunk-4PXDXCNE.js";
267
+ import "./chunk-PL36IQPL.js";
268
268
  import "./chunk-HUDPXTXW.js";
269
269
  import "./chunk-AZEZSQ5R.js";
270
270
  import "./chunk-YAZNBMNF.js";
@@ -8,7 +8,7 @@ import {
8
8
  shouldSkipImplicitExtraction,
9
9
  stripInlineExplicitCaptureNotes,
10
10
  validateExplicitCaptureInput
11
- } from "./chunk-VZMRKYNR.js";
11
+ } from "./chunk-MMOXCCHF.js";
12
12
  import "./chunk-6P7U3HWG.js";
13
13
  import "./chunk-PQM3B54K.js";
14
14
  import "./chunk-B3DR2JBZ.js";
@@ -181,7 +181,7 @@ import "./chunk-MDPT6QFK.js";
181
181
  import "./chunk-UOBPK2OS.js";
182
182
  import "./chunk-2YA5N2BY.js";
183
183
  import "./chunk-3HSRWJTC.js";
184
- import "./chunk-4PXDXCNE.js";
184
+ import "./chunk-PL36IQPL.js";
185
185
  import "./chunk-HUDPXTXW.js";
186
186
  import "./chunk-AZEZSQ5R.js";
187
187
  import "./chunk-YAZNBMNF.js";
@@ -25,10 +25,11 @@ export interface ProjectedHarmonicGraph {
25
25
  nodes: AbstractionNode[];
26
26
  anchors: CueAnchor[];
27
27
  }
28
- /** Counters for tests and diagnostics. */
28
+ /** Counters for tests and diagnostics. `shared` counts reads that joined a build already running. */
29
29
  export declare const harmonicGraphCacheStats: {
30
30
  hits: number;
31
31
  misses: number;
32
+ shared: number;
32
33
  };
33
34
  export declare function clearHarmonicGraphCache(): void;
34
35
  /**
@@ -39,9 +40,9 @@ export declare function clearHarmonicGraphCache(): void;
39
40
  * cold-write version sentinels (bumped by every memory write, in any process) and
40
41
  * the graph version sentinel (bumped by node and anchor writes). A stamp read is
41
42
  * four stats, not a scan of the memories. The TTL bounds the one input a sentinel
42
- * cannot see, which is wall-clock validity expiry. An explicit `nowMs` bypasses the
43
- * cache so tests stay deterministic. The cached arrays are frozen: callers must not
44
- * mutate them.
43
+ * cannot see, which is wall-clock validity expiry. Concurrent misses share one
44
+ * build. An explicit `nowMs` bypasses the cache so tests stay deterministic. The
45
+ * cached arrays are frozen: callers must not mutate them.
45
46
  */
46
47
  export declare function readProjectedHarmonicGraph(options: {
47
48
  memoryDir: string;
@@ -1 +1 @@
1
- {"version":3,"file":"harmonic-retrieval.d.ts","sourceRoot":"","sources":["../src/harmonic-retrieval.ts"],"names":[],"mappings":"AAMC,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,wBAAwB,CAAC;AACjC,OAAO,EAA+C,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAsPnH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,aAAa,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,qBAAqB,EAAE,CAAC;CACzC;AA+ED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAY7B;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAavB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAqFD,0CAA0C;AAC1C,eAAO,MAAM,uBAAuB;;;CAAyB,CAAC;AAW9D,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAoClC;AAED,wBAAsB,uBAAuB,CAAC,OAAO,EAAE;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,yHAAyH;IACzH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAoFrC"}
1
+ {"version":3,"file":"harmonic-retrieval.d.ts","sourceRoot":"","sources":["../src/harmonic-retrieval.ts"],"names":[],"mappings":"AAMC,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,wBAAwB,CAAC;AACjC,OAAO,EAA+C,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAsPnH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,aAAa,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,eAAe,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,qBAAqB,EAAE,CAAC;CACzC;AA+ED,wBAAsB,oBAAoB,CAAC,OAAO,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAY7B;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAavB;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,OAAO,EAAE,SAAS,EAAE,CAAC;CACtB;AAiGD,qGAAqG;AACrG,eAAO,MAAM,uBAAuB;;;;CAAoC,CAAC;AAWzE,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C;AAuDD;;;;;;;;;;;GAWG;AACH,wBAAsB,0BAA0B,CAAC,OAAO,EAAE;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA4BlC;AAED,wBAAsB,uBAAuB,CAAC,OAAO,EAAE;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,yHAAyH;IACzH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAoFrC"}
@@ -5,7 +5,7 @@ import {
5
5
  readCueAnchors,
6
6
  readProjectedHarmonicGraph,
7
7
  searchHarmonicRetrieval
8
- } from "./chunk-4PXDXCNE.js";
8
+ } from "./chunk-PL36IQPL.js";
9
9
  import "./chunk-HUDPXTXW.js";
10
10
  import "./chunk-AZEZSQ5R.js";
11
11
  import "./chunk-FL3O34XF.js";
package/dist/index.js CHANGED
@@ -259,7 +259,7 @@ import {
259
259
  writeManifest,
260
260
  writeMeetingEpisodeMemory,
261
261
  writeTimelineState
262
- } from "./chunk-VZMRKYNR.js";
262
+ } from "./chunk-MMOXCCHF.js";
263
263
  import "./chunk-6P7U3HWG.js";
264
264
  import "./chunk-PQM3B54K.js";
265
265
  import {
@@ -717,7 +717,7 @@ import {
717
717
  import "./chunk-UOBPK2OS.js";
718
718
  import "./chunk-2YA5N2BY.js";
719
719
  import "./chunk-3HSRWJTC.js";
720
- import "./chunk-4PXDXCNE.js";
720
+ import "./chunk-PL36IQPL.js";
721
721
  import "./chunk-HUDPXTXW.js";
722
722
  import "./chunk-AZEZSQ5R.js";
723
723
  import "./chunk-YAZNBMNF.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  BufferDrainRunner
3
- } from "../chunk-UBJ5RPDM.js";
4
- import "../chunk-VZMRKYNR.js";
3
+ } from "../chunk-QIPDTAWZ.js";
4
+ import "../chunk-MMOXCCHF.js";
5
5
  import "../chunk-6P7U3HWG.js";
6
6
  import "../chunk-PQM3B54K.js";
7
7
  import "../chunk-B3DR2JBZ.js";
@@ -174,7 +174,7 @@ import "../chunk-MDPT6QFK.js";
174
174
  import "../chunk-UOBPK2OS.js";
175
175
  import "../chunk-2YA5N2BY.js";
176
176
  import "../chunk-3HSRWJTC.js";
177
- import "../chunk-4PXDXCNE.js";
177
+ import "../chunk-PL36IQPL.js";
178
178
  import "../chunk-HUDPXTXW.js";
179
179
  import "../chunk-AZEZSQ5R.js";
180
180
  import "../chunk-YAZNBMNF.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  BufferDrainRunner,
3
3
  ClaimBufferStorage
4
- } from "../chunk-UBJ5RPDM.js";
5
- import "../chunk-VZMRKYNR.js";
4
+ } from "../chunk-QIPDTAWZ.js";
5
+ import "../chunk-MMOXCCHF.js";
6
6
  import "../chunk-6P7U3HWG.js";
7
7
  import "../chunk-PQM3B54K.js";
8
8
  import "../chunk-B3DR2JBZ.js";
@@ -175,7 +175,7 @@ import "../chunk-MDPT6QFK.js";
175
175
  import "../chunk-UOBPK2OS.js";
176
176
  import "../chunk-2YA5N2BY.js";
177
177
  import "../chunk-3HSRWJTC.js";
178
- import "../chunk-4PXDXCNE.js";
178
+ import "../chunk-PL36IQPL.js";
179
179
  import "../chunk-HUDPXTXW.js";
180
180
  import "../chunk-AZEZSQ5R.js";
181
181
  import "../chunk-YAZNBMNF.js";
@@ -6,7 +6,7 @@ import {
6
6
  mergeGraphExpandedResults,
7
7
  qmdStartupCollectionChecksWithTimeout,
8
8
  resolveEffectiveIdentityInjectionMode
9
- } from "./chunk-VZMRKYNR.js";
9
+ } from "./chunk-MMOXCCHF.js";
10
10
  import "./chunk-6P7U3HWG.js";
11
11
  import "./chunk-PQM3B54K.js";
12
12
  import "./chunk-B3DR2JBZ.js";
@@ -183,7 +183,7 @@ import "./chunk-MDPT6QFK.js";
183
183
  import "./chunk-UOBPK2OS.js";
184
184
  import "./chunk-2YA5N2BY.js";
185
185
  import "./chunk-3HSRWJTC.js";
186
- import "./chunk-4PXDXCNE.js";
186
+ import "./chunk-PL36IQPL.js";
187
187
  import "./chunk-HUDPXTXW.js";
188
188
  import "./chunk-AZEZSQ5R.js";
189
189
  import "./chunk-YAZNBMNF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  runRecallNavigation
3
- } from "./chunk-VZMRKYNR.js";
3
+ } from "./chunk-MMOXCCHF.js";
4
4
  import "./chunk-6P7U3HWG.js";
5
5
  import "./chunk-PQM3B54K.js";
6
6
  import "./chunk-B3DR2JBZ.js";
@@ -173,7 +173,7 @@ import "./chunk-MDPT6QFK.js";
173
173
  import "./chunk-UOBPK2OS.js";
174
174
  import "./chunk-2YA5N2BY.js";
175
175
  import "./chunk-3HSRWJTC.js";
176
- import "./chunk-4PXDXCNE.js";
176
+ import "./chunk-PL36IQPL.js";
177
177
  import "./chunk-HUDPXTXW.js";
178
178
  import "./chunk-AZEZSQ5R.js";
179
179
  import "./chunk-YAZNBMNF.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "10.0.99",
3
+ "version": "10.0.100",
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.99"
3389
+ "@remnic/coding-graph": "^10.0.100"
3390
3390
  },
3391
3391
  "peerDependenciesMeta": {
3392
3392
  "@remnic/coding-graph": {
@@ -1,13 +1,14 @@
1
1
  import assert from "node:assert/strict";
2
- import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { mkdtemp, readFile, rename, rm, writeFile } from "node:fs/promises";
3
3
  import { tmpdir } from "node:os";
4
4
  import path from "node:path";
5
- import test from "node:test";
5
+ import test, { type TestContext } from "node:test";
6
6
  import { recordAbstractionNode, upsertAbstractionNodes, type AbstractionNode } from "./abstraction-nodes.js";
7
7
  import { pruneOrphanCueAnchors, recordCueAnchor, upsertCueAnchors, type CueAnchor } from "./cue-anchors.js";
8
8
  import {
9
9
  clearHarmonicGraphCache,
10
10
  harmonicGraphCacheStats,
11
+ type ProjectedHarmonicGraph,
11
12
  readProjectedHarmonicGraph,
12
13
  searchHarmonicRetrieval,
13
14
  } from "./harmonic-retrieval.js";
@@ -228,6 +229,61 @@ test("pruneOrphanCueAnchors alone invalidates the cached graph", async () => {
228
229
  });
229
230
  });
230
231
 
232
+ // Recall waits for the graph build, so a cache miss costs every recall that lands on it. Production: a
233
+ // 2106 node, 9174 anchor graph rebuilt in 5 s standalone, 7 s inside the daemon, and 17 to 32 s when two
234
+ // recalls overlapped and each ran its own build.
235
+ test("concurrent reads on a cold cache share one build", async () => {
236
+ await withDir(async (memoryDir, storage) => {
237
+ const memory = await storage.writeMemory("fact", "theta shared fact", { source: "test" });
238
+ await recordAbstractionNode({ memoryDir, node: node("n1", "theta shared fact", [memory.id]) });
239
+ const before = { ...harmonicGraphCacheStats };
240
+ const [a, b, c] = await Promise.all([read(memoryDir), read(memoryDir), read(memoryDir)]);
241
+ assert.equal(harmonicGraphCacheStats.misses, before.misses + 1, "one build, not one per caller");
242
+ assert.equal(a, b);
243
+ assert.equal(b, c);
244
+ });
245
+ });
246
+
247
+ test("a caller that aborts leaves the shared build for the others", async () => {
248
+ await withDir(async (memoryDir, storage) => {
249
+ const memory = await storage.writeMemory("fact", "iota abort fact", { source: "test" });
250
+ await recordAbstractionNode({ memoryDir, node: node("n1", "iota abort fact", [memory.id]) });
251
+ const controller = new AbortController();
252
+ const aborted = readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: true, useCache: true, abortSignal: controller.signal });
253
+ const other = read(memoryDir);
254
+ controller.abort();
255
+ await assert.rejects(aborted);
256
+ assert.equal((await other).nodes.length, 1);
257
+ });
258
+ });
259
+
260
+ // Unreadable node store: a file where the nodes directory belongs is not ENOENT, so the strict listing throws
261
+ // (a corrupt node file would not: readAbstractionNodes skips those on purpose).
262
+ async function breakNodeStore(memoryDir: string) {
263
+ const nodesDir = path.join(memoryDir, "state", "abstraction-nodes", "nodes");
264
+ const parked = `${nodesDir}.parked`;
265
+ await rename(nodesDir, parked);
266
+ await writeFile(nodesDir, "not a directory");
267
+ return async () => {
268
+ await rm(nodesDir, { force: true });
269
+ await rename(parked, nodesDir);
270
+ };
271
+ }
272
+
273
+ test("callers that joined a failing build all reject, and the next read retries and succeeds", async () => {
274
+ await withDir(async (memoryDir, storage) => {
275
+ const memory = await storage.writeMemory("fact", "mu retry fact", { source: "test" });
276
+ await recordAbstractionNode({ memoryDir, node: node("n1", "mu retry fact", [memory.id]) });
277
+ const restore = await breakNodeStore(memoryDir);
278
+ const missesBefore = harmonicGraphCacheStats.misses;
279
+ const outcomes = await Promise.allSettled([read(memoryDir), read(memoryDir), read(memoryDir)]);
280
+ assert.deepEqual(outcomes.map((outcome) => outcome.status), ["rejected", "rejected", "rejected"]);
281
+ assert.equal(harmonicGraphCacheStats.misses, missesBefore + 1, "the three callers shared one failing build");
282
+ await restore();
283
+ assert.equal((await read(memoryDir)).nodes.length, 1);
284
+ });
285
+ });
286
+
231
287
  test("an entry older than the TTL is rebuilt", async (t) => {
232
288
  await withDir(async (memoryDir, storage) => {
233
289
  const memory = await storage.writeMemory("fact", "zeta ttl fact", { source: "test" });
@@ -242,3 +298,132 @@ test("an entry older than the TTL is rebuilt", async (t) => {
242
298
  assert.equal((await read(memoryDir)).nodes.length, 0, "rebuilt past the TTL");
243
299
  });
244
300
  });
301
+
302
+ interface BuildHold {
303
+ release: () => void;
304
+ reached: Promise<void>;
305
+ calls: number;
306
+ signal?: AbortSignal;
307
+ }
308
+
309
+ /**
310
+ * Hold the first build inside its source-memory read so a second read can land while it runs. The held call
311
+ * records the build's own abort signal; builds started after it are not held.
312
+ */
313
+ function holdFirstBuild(t: TestContext): BuildHold {
314
+ const original = StorageManager.prototype.readAllMemories;
315
+ let release = () => {};
316
+ const opened = new Promise<void>((resolve) => {
317
+ release = resolve;
318
+ });
319
+ let reachedHold = () => {};
320
+ const reached = new Promise<void>((resolve) => {
321
+ reachedHold = resolve;
322
+ });
323
+ const hold: BuildHold = { release, reached, calls: 0 };
324
+ t.mock.method(StorageManager.prototype, "readAllMemories", async function (this: StorageManager, ...args: Parameters<typeof original>) {
325
+ hold.calls++;
326
+ if (hold.calls === 1) {
327
+ hold.signal = args[0]?.abortSignal;
328
+ reachedHold();
329
+ await opened;
330
+ }
331
+ return original.apply(this, args);
332
+ });
333
+ return hold;
334
+ }
335
+
336
+ /** Fail the test instead of hanging when a promise that must settle does not. */
337
+ function within<T>(promise: Promise<T>, ms: number, what: string): Promise<T> {
338
+ return Promise.race([
339
+ promise,
340
+ new Promise<never>((_resolve, reject) => setTimeout(() => reject(new Error(`${what} did not settle in ${ms} ms`)), ms).unref()),
341
+ ]);
342
+ }
343
+
344
+ test("the shared build aborts once every joined caller has aborted, and the next read starts a fresh one", async (t) => {
345
+ await withDir(async (memoryDir, storage) => {
346
+ const memory = await storage.writeMemory("fact", "nu abort fact", { source: "test" });
347
+ await recordAbstractionNode({ memoryDir, node: node("n1", "nu abort fact", [memory.id]) });
348
+ const hold = holdFirstBuild(t);
349
+ const first = new AbortController();
350
+ const second = new AbortController();
351
+ const options = { memoryDir, anchorsEnabled: true, useCache: true };
352
+ const a = readProjectedHarmonicGraph({ ...options, abortSignal: first.signal });
353
+ const b = readProjectedHarmonicGraph({ ...options, abortSignal: second.signal });
354
+ await within(hold.reached, 2000, "build start");
355
+ assert.equal(hold.calls, 1, "one build for both callers");
356
+ first.abort();
357
+ await assert.rejects(within(a, 1000, "first caller"), { name: "AbortError" });
358
+ assert.equal(hold.signal?.aborted, false, "one caller is still waiting, so the build keeps running");
359
+ second.abort();
360
+ await assert.rejects(within(b, 1000, "second caller"), { name: "AbortError" });
361
+ assert.equal(hold.signal?.aborted, true, "no caller is left, so the build is cancelled");
362
+ const missesBefore = harmonicGraphCacheStats.misses;
363
+ const next = read(memoryDir);
364
+ assert.equal(harmonicGraphCacheStats.misses, missesBefore + 1, "the next read does not join the cancelled build");
365
+ assert.equal((await within(next, 5000, "next read")).nodes.length, 1);
366
+ hold.release();
367
+ });
368
+ });
369
+
370
+ test("a read after a stamp change does not join the build that started on the old stamp", async (t) => {
371
+ await withDir(async (memoryDir, storage) => {
372
+ const first = await storage.writeMemory("fact", "xi stamp fact one", { source: "test" });
373
+ await recordAbstractionNode({ memoryDir, node: node("n1", "xi stamp fact one", [first.id]) });
374
+ const hold = holdFirstBuild(t);
375
+ const missesBefore = harmonicGraphCacheStats.misses;
376
+ const stale = read(memoryDir);
377
+ await within(hold.reached, 2000, "old build start");
378
+ const second = await storage.writeMemory("fact", "xi stamp fact two", { source: "test" });
379
+ await recordAbstractionNode({ memoryDir, node: node("n2", "xi stamp fact two", [second.id]) });
380
+ try {
381
+ const fresh = read(memoryDir);
382
+ assert.equal(harmonicGraphCacheStats.misses, missesBefore + 2, "the second read started its own build");
383
+ assert.equal((await within(fresh, 5000, "fresh read")).nodes.length, 2, "and it sees the write");
384
+ } finally {
385
+ hold.release();
386
+ }
387
+ await stale;
388
+ });
389
+ });
390
+
391
+ test("a joined caller that aborts rejects at once, while the build it joined is still running", async (t) => {
392
+ await withDir(async (memoryDir, storage) => {
393
+ const memory = await storage.writeMemory("fact", "omicron join fact", { source: "test" });
394
+ await recordAbstractionNode({ memoryDir, node: node("n1", "omicron join fact", [memory.id]) });
395
+ const hold = holdFirstBuild(t);
396
+ const owner = read(memoryDir);
397
+ const controller = new AbortController();
398
+ const joiner = readProjectedHarmonicGraph({ memoryDir, anchorsEnabled: true, useCache: true, abortSignal: controller.signal });
399
+ controller.abort();
400
+ try {
401
+ await assert.rejects(within(joiner, 1000, "aborted joiner"), { name: "AbortError" });
402
+ } finally {
403
+ hold.release();
404
+ }
405
+ assert.equal((await owner).nodes.length, 1, "the owner is not affected");
406
+ });
407
+ });
408
+
409
+ test("clearing the cache drops a running build: the next read starts its own and the old build stores nothing", async (t) => {
410
+ await withDir(async (memoryDir, storage) => {
411
+ const memory = await storage.writeMemory("fact", "pi clear fact", { source: "test" });
412
+ await recordAbstractionNode({ memoryDir, node: node("n1", "pi clear fact", [memory.id]) });
413
+ const hold = holdFirstBuild(t);
414
+ const missesBefore = harmonicGraphCacheStats.misses;
415
+ const old = read(memoryDir);
416
+ await within(hold.reached, 2000, "old build start");
417
+ clearHarmonicGraphCache();
418
+ let kept: ProjectedHarmonicGraph;
419
+ try {
420
+ const fresh = read(memoryDir);
421
+ assert.equal(harmonicGraphCacheStats.misses, missesBefore + 2, "the read after the clear did not join the old build");
422
+ kept = await within(fresh, 5000, "fresh read");
423
+ } finally {
424
+ hold.release();
425
+ }
426
+ await old;
427
+ assert.equal(await read(memoryDir), kept, "the finished old build did not overwrite the newer cache entry");
428
+ });
429
+ });
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { realpath } from "node:fs/promises";
3
3
  import { listJsonFilesStrict, readJsonFile } from "./json-store.js";
4
- import { throwIfAborted } from "./abort-error.js";
4
+ import { raceAbort, throwIfAborted } from "./abort-error.js";
5
5
  import { readHarmonicGraphStamp } from "./harmonic-graph-version.js";
6
6
  import { inferMemoryStatus, toMemoryPathRel } from "./memory-lifecycle-ledger-utils.js";
7
7
  import {
@@ -471,8 +471,20 @@ interface GraphCacheEntry {
471
471
  }
472
472
 
473
473
  const graphCache = new Map<string, GraphCacheEntry>();
474
- /** Counters for tests and diagnostics. */
475
- export const harmonicGraphCacheStats = { hits: 0, misses: 0 };
474
+
475
+ interface GraphBuild {
476
+ stamp: string;
477
+ promise: Promise<ProjectedHarmonicGraph>;
478
+ /** Cancels the build's source scan; fired when no caller is waiting for it. */
479
+ controller: AbortController;
480
+ /** Callers currently waiting for this build. */
481
+ waiting: number;
482
+ }
483
+
484
+ /** One build per cache key at a time: every recall that lands on a miss waits for the same build. */
485
+ const graphBuilds = new Map<string, GraphBuild>();
486
+ /** Counters for tests and diagnostics. `shared` counts reads that joined a build already running. */
487
+ export const harmonicGraphCacheStats = { hits: 0, misses: 0, shared: 0 };
476
488
 
477
489
  /** Freeze records and their nested arrays/objects so a caller cannot corrupt the shared cache. */
478
490
  function deepFreeze<T extends object>(value: T): T {
@@ -485,6 +497,60 @@ function deepFreeze<T extends object>(value: T): T {
485
497
 
486
498
  export function clearHarmonicGraphCache(): void {
487
499
  graphCache.clear();
500
+ graphBuilds.clear();
501
+ }
502
+
503
+ type GraphReadOptions = Parameters<typeof buildProjectedHarmonicGraph>[0];
504
+
505
+ /**
506
+ * Start the one build for `key`. The build owns an abort controller instead of using one caller's signal,
507
+ * so a caller that leaves does not cancel it for the others; `joinGraphBuild` cancels it when the last caller leaves.
508
+ */
509
+ function startGraphBuild(key: string, stamp: string, options: GraphReadOptions): GraphBuild {
510
+ harmonicGraphCacheStats.misses++;
511
+ const startedAtMs = Date.now();
512
+ const controller = new AbortController();
513
+ const promise: Promise<ProjectedHarmonicGraph> = buildProjectedHarmonicGraph({
514
+ memoryDir: options.memoryDir,
515
+ abstractionNodeStoreDir: options.abstractionNodeStoreDir,
516
+ anchorsEnabled: options.anchorsEnabled,
517
+ temporalExpiredInInjection: options.temporalExpiredInInjection,
518
+ abortSignal: controller.signal,
519
+ })
520
+ .then((built) => {
521
+ const graph = { nodes: deepFreeze(built.nodes), anchors: deepFreeze(built.anchors) };
522
+ // A cleared cache or a newer build for this key has replaced this one: do not store a stale graph.
523
+ if (graphBuilds.get(key)?.promise !== promise) return graph;
524
+ graphCache.delete(key);
525
+ graphCache.set(key, { stamp, startedAtMs, graph });
526
+ while (graphCache.size > GRAPH_CACHE_MAX_ENTRIES) {
527
+ const oldest = graphCache.keys().next().value;
528
+ if (oldest === undefined) break;
529
+ graphCache.delete(oldest);
530
+ }
531
+ return graph;
532
+ })
533
+ .finally(() => {
534
+ if (graphBuilds.get(key)?.promise === promise) graphBuilds.delete(key);
535
+ });
536
+ const build: GraphBuild = { stamp, promise, controller, waiting: 0 };
537
+ graphBuilds.set(key, build);
538
+ return build;
539
+ }
540
+
541
+ /**
542
+ * Wait for `build` on behalf of one caller. The caller's own signal ends only its own wait. When the last
543
+ * waiting caller has left, the build is cancelled and dropped, so abandoned recalls do not leave full scans running
544
+ * (cancelling a build that already finished does nothing).
545
+ */
546
+ function joinGraphBuild(key: string, build: GraphBuild, signal: AbortSignal | undefined): Promise<ProjectedHarmonicGraph> {
547
+ build.waiting++;
548
+ return raceAbort(build.promise, signal, "harmonic retrieval aborted").finally(() => {
549
+ build.waiting--;
550
+ if (build.waiting > 0) return;
551
+ if (graphBuilds.get(key) === build) graphBuilds.delete(key);
552
+ build.controller.abort();
553
+ });
488
554
  }
489
555
 
490
556
  /**
@@ -495,9 +561,9 @@ export function clearHarmonicGraphCache(): void {
495
561
  * cold-write version sentinels (bumped by every memory write, in any process) and
496
562
  * the graph version sentinel (bumped by node and anchor writes). A stamp read is
497
563
  * four stats, not a scan of the memories. The TTL bounds the one input a sentinel
498
- * cannot see, which is wall-clock validity expiry. An explicit `nowMs` bypasses the
499
- * cache so tests stay deterministic. The cached arrays are frozen: callers must not
500
- * mutate them.
564
+ * cannot see, which is wall-clock validity expiry. Concurrent misses share one
565
+ * build. An explicit `nowMs` bypasses the cache so tests stay deterministic. The
566
+ * cached arrays are frozen: callers must not mutate them.
501
567
  */
502
568
  export async function readProjectedHarmonicGraph(options: {
503
569
  memoryDir: string;
@@ -529,20 +595,12 @@ export async function readProjectedHarmonicGraph(options: {
529
595
  graphCache.set(key, hit);
530
596
  return hit.graph;
531
597
  }
532
- harmonicGraphCacheStats.misses++;
533
- const built = await buildProjectedHarmonicGraph(options);
534
- const graph = {
535
- nodes: deepFreeze(built.nodes),
536
- anchors: deepFreeze(built.anchors),
537
- };
538
- graphCache.delete(key);
539
- graphCache.set(key, { stamp, startedAtMs, graph });
540
- while (graphCache.size > GRAPH_CACHE_MAX_ENTRIES) {
541
- const oldest = graphCache.keys().next().value;
542
- if (oldest === undefined) break;
543
- graphCache.delete(oldest);
598
+ const running = graphBuilds.get(key);
599
+ if (running?.stamp === stamp) {
600
+ harmonicGraphCacheStats.shared++;
601
+ return joinGraphBuild(key, running, options.abortSignal);
544
602
  }
545
- return graph;
603
+ return joinGraphBuild(key, startGraphBuild(key, stamp, options), options.abortSignal);
546
604
  }
547
605
 
548
606
  export async function searchHarmonicRetrieval(options: {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/harmonic-retrieval.ts"],"sourcesContent":["import path from \"node:path\";\nimport { realpath } from \"node:fs/promises\";\nimport { listJsonFilesStrict, readJsonFile } from \"./json-store.js\";\nimport { throwIfAborted } from \"./abort-error.js\";\nimport { readHarmonicGraphStamp } from \"./harmonic-graph-version.js\";\nimport { inferMemoryStatus, toMemoryPathRel } from \"./memory-lifecycle-ledger-utils.js\";\n import {\n HARMONIC_SOURCE_MEMORY_INSERTED_AT_KEY,\n resolveAbstractionNodeStoreDir,\n validateAbstractionNode,\n type AbstractionNode,\n } from \"./abstraction-nodes.js\";\nimport { resolveCueAnchorStoreDir, validateCueAnchor, type CueAnchor, type CueAnchorType } from \"./cue-anchors.js\";\nimport { compareDeterministicStrings } from \"./deterministic-order.js\";\nimport { countRecallTokenOverlap, normalizeRecallTokens } from \"./recall-tokenization.js\";\nimport { stripAttributesSuffix } from \"./structured-attributes.js\";\nimport { isValidityExpiredNow } from \"./temporal-validity.js\";\nimport { assertSafePathSegment, isRecord } from \"./store-contract.js\";\nimport { isSupportPassportPrivateMemory } from \"./support-passport/card-projection.js\";\nimport type { MemoryFile } from \"./types.js\";\nimport { readProjectedMemoryStates } from \"./memory-projection-batch.js\";\nimport { SecureStoreLockedError } from \"./secure-store/secure-fs.js\";\nimport { StorageManager } from \"./storage.js\";\nimport { RECALL_FALLBACK_DIRS } from \"./utils/category-dir.js\";\nimport { readHarmonicSourceMemory, readUnresolvedHarmonicSources } from \"./harmonic-source-lookup.js\";\n\n\ntype SourceMemoryMap = Map<string, MemoryFile>;\n\n\n// An index older than this is treated as unusable: the date window needed to\n// cover \"created since the last rebuild\" would stop being cheap.\nconst INDEX_MAX_AGE_MS = 7 * 86_400_000;\nconst DAY_MS = 86_400_000;\n\nfunction utcDaysSince(rebuiltMs: number, nowMs: number): string[] {\n const days: string[] = [];\n for (let day = Math.floor((rebuiltMs - DAY_MS) / DAY_MS) * DAY_MS; day <= nowMs; day += DAY_MS) {\n days.push(new Date(day).toISOString().slice(0, 10));\n }\n return days;\n}\n\n\n// Memories the projection has no row for were written after its last rebuild, so\n// their dated directory is normally one of `days`. Hot and cold tiers are probed\n// by exact path. Only recall-corpus categories are probed: `questions/` is a queue\n// and `artifacts/` is outside the recall surface, so neither can be a source.\nfunction unprojectedCandidatePaths(memoryDir: string, id: string, days: string[]): string[] {\n const paths: string[] = [];\n for (const root of [memoryDir, path.join(memoryDir, \"cold\")]) {\n for (const dir of RECALL_FALLBACK_DIRS) {\n paths.push(path.join(root, dir, `${id}.md`));\n for (const day of days) paths.push(path.join(root, dir, day, `${id}.md`));\n }\n }\n return paths;\n}\n\n/** Resolve indexed sources first, then use the durable unresolved-id path cache. */\nasync function readIndexedSourceMemories(options: {\n memoryDir: string;\n abortSignal?: AbortSignal;\n sourceMemoryIds: string[];\n nowMs: number;\n}): Promise<SourceMemoryMap | null> {\n // The ids go to SQL as bound parameters, so any id the projection holds is safe to look up.\n const batch = readProjectedMemoryStates(options.memoryDir, options.sourceMemoryIds);\n const rebuiltMs = Date.parse(batch?.rebuiltAt ?? \"\");\n if (!batch?.complete || !batch.rebuiltAt || !Number.isFinite(rebuiltMs) || options.nowMs - rebuiltMs > INDEX_MAX_AGE_MS) return null;\n const rootReal = await realpath(options.memoryDir).catch(() => null);\n if (rootReal === null) return null;\n\n const storage = new StorageManager(options.memoryDir);\n const days = utcDaysSince(rebuiltMs, options.nowMs);\n const sourceMemories: SourceMemoryMap = new Map();\n const pending: string[] = [];\n for (const id of options.sourceMemoryIds) {\n const state = batch.states.get(id);\n // An id is only ever joined into a path when it is a single safe segment.\n let safeId = true;\n try {\n assertSafePathSegment(id, \"sourceMemoryId\");\n } catch {\n safeId = false;\n }\n // state.path was containment-checked by the projection reader.\n const candidates = state\n ? [state.path, path.join(options.memoryDir, \"cold\", state.pathRel)]\n : safeId ? unprojectedCandidatePaths(options.memoryDir, id, days) : [];\n let found = false;\n for (const candidate of candidates) {\n const memory = await readHarmonicSourceMemory(storage, rootReal, candidate, options.abortSignal);\n if (memory?.frontmatter.id !== id) continue;\n sourceMemories.set(id, memory);\n found = true;\n break;\n }\n if (!found) pending.push(id);\n }\n if (pending.length === 0) return sourceMemories;\n\n const unresolved = await readUnresolvedHarmonicSources({\n storage, rootReal, rebuiltAt: batch.rebuiltAt, sourceMemoryIds: pending,\n nowMs: options.nowMs, abortSignal: options.abortSignal,\n });\n for (const [id, memory] of unresolved) sourceMemories.set(id, memory);\n return sourceMemories;\n}\n\nasync function readCorpusSourceMemories(options: {\n memoryDir: string;\n abortSignal?: AbortSignal;\n}): Promise<SourceMemoryMap> {\n const sourceMemories: SourceMemoryMap = new Map();\n try {\n const storage = new StorageManager(options.memoryDir);\n const [hotMemories, coldMemories] = await Promise.all([\n storage.readAllMemories({ abortSignal: options.abortSignal }),\n storage.readAllColdMemories({ abortSignal: options.abortSignal }),\n ]);\n for (const memory of [...hotMemories, ...coldMemories]) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n sourceMemories.set(memory.frontmatter.id, memory);\n }\n } catch (err) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n if (err instanceof SecureStoreLockedError) return new Map();\n // Source validation fails closed when the authorized memory directory is\n // unreadable. Source-less nodes remain eligible for retrieval.\n sourceMemories.clear();\n }\n return sourceMemories;\n}\n\nasync function readSourceMemories(options: {\n memoryDir: string;\n abortSignal?: AbortSignal;\n sourceMemoryIds: string[];\n nowMs?: number;\n}): Promise<SourceMemoryMap> {\n try {\n const indexed = await readIndexedSourceMemories({\n memoryDir: options.memoryDir,\n abortSignal: options.abortSignal,\n sourceMemoryIds: options.sourceMemoryIds,\n nowMs: options.nowMs ?? Date.now(),\n });\n if (indexed) return indexed;\n } catch (err) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n if (err instanceof SecureStoreLockedError) return new Map();\n }\n return readCorpusSourceMemories(options);\n}\n\nfunction parseSourceMemoryInsertedAt(node: AbstractionNode): Map<string, string> {\n const insertedAtById = new Map<string, string>();\n const insertedAtRaw = node.metadata?.[HARMONIC_SOURCE_MEMORY_INSERTED_AT_KEY];\n if (!insertedAtRaw) return insertedAtById;\n try {\n const parsed = JSON.parse(insertedAtRaw) as unknown;\n if (!isRecord(parsed)) return insertedAtById;\n for (const [memoryId, value] of Object.entries(parsed)) {\n if (typeof value === \"string\") insertedAtById.set(memoryId, value);\n }\n } catch {\n // Malformed insertion metadata leaves ordering on the recordedAt fallback.\n }\n return insertedAtById;\n}\n\nfunction projectSourceBackedNode(\n node: AbstractionNode,\n sourceMemories: SourceMemoryMap,\n memoryDir: string,\n temporalExpiredInInjection: boolean,\n nowMs: number\n): AbstractionNode | null {\n const sourceMemoryIds = node.sourceMemoryIds ?? [];\n if (sourceMemoryIds.length === 0) return node;\n\n const activeSourceMemoryIds = sourceMemoryIds.filter((memoryId) => {\n const memory = sourceMemories.get(memoryId);\n return (\n memory !== undefined &&\n // #2332: a private support-passport record leaves the eligible set the\n // same way a rejected one does — a node title or anchor attribution\n // rebuilt from it would leak governed metadata into the deep-recall\n // frontier (and every other graph reader) before any content check runs.\n !isSupportPassportPrivateMemory(memory) &&\n inferMemoryStatus(memory.frontmatter, toMemoryPathRel(memoryDir, memory.path)) === \"active\" &&\n (temporalExpiredInInjection || !isValidityExpiredNow(memory.frontmatter, nowMs))\n );\n });\n if (activeSourceMemoryIds.length === 0) return null;\n\n // Newest-first source order keeps the projected title and summary on the most\n // recently inserted facts. Equal or missing timestamps fall back to ascending\n // id order, which matches the stored sourceMemoryIds order.\n const insertedAtById = parseSourceMemoryInsertedAt(node);\n const insertedAtMs = (memoryId: string): number => {\n const parsedMs = Date.parse(insertedAtById.get(memoryId) ?? \"\");\n return Number.isFinite(parsedMs) ? parsedMs : Date.parse(node.recordedAt);\n };\n activeSourceMemoryIds.sort(\n (left, right) =>\n insertedAtMs(right) - insertedAtMs(left) || compareDeterministicStrings(left, right)\n );\n\n const activeMemories = activeSourceMemoryIds.flatMap((memoryId) => {\n const memory = sourceMemories.get(memoryId);\n return memory ? [memory] : [];\n });\n const activeContents = activeMemories.map((memory) =>\n memory.frontmatter.structuredAttributes ? stripAttributesSuffix(memory.content) : memory.content\n );\n let metadata: Record<string, string> | undefined;\n const activeInsertedAt = activeSourceMemoryIds.flatMap((memoryId) => {\n const value = insertedAtById.get(memoryId);\n return typeof value === \"string\" ? [[memoryId, value] as const] : [];\n });\n if (activeInsertedAt.length > 0) {\n metadata = {\n [HARMONIC_SOURCE_MEMORY_INSERTED_AT_KEY]: JSON.stringify(Object.fromEntries(activeInsertedAt)),\n };\n }\n\n return {\n ...node,\n sourceMemoryIds: activeSourceMemoryIds,\n title: activeContents[0]?.slice(0, 80) ?? node.title,\n summary: activeContents.slice(0, 3).join(\"; \").slice(0, 400),\n tags: [...new Set(activeMemories.flatMap((memory) => memory.frontmatter.tags))].sort(compareDeterministicStrings),\n entityRefs: [\n ...new Set(\n activeMemories.flatMap((memory) =>\n typeof memory.frontmatter.entityRef === \"string\" ? [memory.frontmatter.entityRef] : []\n )\n ),\n ].sort(compareDeterministicStrings),\n metadata,\n };\n}\n\nfunction anchorMatchesProjectedNode(\n anchor: CueAnchor,\n nodeRef: string,\n node: AbstractionNode,\n allowLegacyAttribution: boolean\n): boolean {\n const activeSourceMemoryIds = node.sourceMemoryIds ?? [];\n if (activeSourceMemoryIds.length === 0) return true;\n if (!anchor.sourceMemoryIdsByNodeRef) return allowLegacyAttribution;\n const anchorSourceMemoryIds = anchor.sourceMemoryIdsByNodeRef[nodeRef] ?? [];\n return anchorSourceMemoryIds.some((sourceMemoryId) => activeSourceMemoryIds.includes(sourceMemoryId));\n}\n\nexport interface HarmonicMatchedAnchor {\n anchorId: string;\n anchorType: CueAnchorType;\n anchorValue: string;\n}\n\nexport interface HarmonicRetrievalResult {\n node: AbstractionNode;\n score: number;\n nodeScore: number;\n anchorScore: number;\n matchedFields: string[];\n matchedAnchors: HarmonicMatchedAnchor[];\n}\n\ninterface HarmonicCandidate {\n node: AbstractionNode;\n nodeScore: number;\n anchorScore: number;\n matchedFields: Set<string>;\n matchedAnchors: Map<string, HarmonicMatchedAnchor>;\n}\n\nfunction scoreNode(node: AbstractionNode, queryTokens: Set<string>): { score: number; matchedFields: string[] } {\n const matchedFields: string[] = [];\n let score = 0;\n\n const titleMatches = countRecallTokenOverlap(queryTokens, node.title);\n if (titleMatches > 0) {\n score += titleMatches * 3;\n matchedFields.push(\"title\");\n }\n\n const summaryMatches = countRecallTokenOverlap(queryTokens, node.summary);\n if (summaryMatches > 0) {\n score += summaryMatches * 3;\n matchedFields.push(\"summary\");\n }\n\n const tagMatches = countRecallTokenOverlap(queryTokens, node.tags?.join(\" \"));\n if (tagMatches > 0) {\n score += tagMatches * 2;\n matchedFields.push(\"tags\");\n }\n\n const entityMatches = countRecallTokenOverlap(queryTokens, node.entityRefs?.join(\" \"));\n if (entityMatches > 0) {\n score += entityMatches * 2;\n matchedFields.push(\"entityRefs\");\n }\n\n const kindMatches = countRecallTokenOverlap(queryTokens, `${node.kind} ${node.abstractionLevel}`);\n if (kindMatches > 0) {\n score += kindMatches;\n matchedFields.push(\"kind\");\n }\n\n return { score, matchedFields };\n}\n\nfunction scoreAnchor(\n anchor: CueAnchor,\n queryTokens: Set<string>,\n eligibleNodeTags: readonly string[]\n): { score: number; matchedFields: string[] } {\n const matchedFields: string[] = [];\n let score = 0;\n\n const valueMatches = countRecallTokenOverlap(queryTokens, anchor.anchorValue);\n const normalizedMatches = countRecallTokenOverlap(queryTokens, anchor.normalizedCue);\n const cueMatches = Math.max(valueMatches, normalizedMatches);\n if (cueMatches > 0) {\n score += cueMatches * 4;\n if (valueMatches > 0) matchedFields.push(\"anchorValue\");\n if (normalizedMatches > 0) matchedFields.push(\"anchor\");\n }\n\n const typeMatches = countRecallTokenOverlap(queryTokens, anchor.anchorType);\n if (typeMatches > 0) {\n score += typeMatches;\n matchedFields.push(\"anchorType\");\n }\n\n const tagMatches = countRecallTokenOverlap(queryTokens, eligibleNodeTags.join(\" \"));\n if (tagMatches > 0) {\n score += tagMatches * 2;\n matchedFields.push(\"anchorTags\");\n }\n\n return { score, matchedFields };\n}\n\nexport async function readAbstractionNodes(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n}): Promise<AbstractionNode[]> {\n const rootDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);\n const files = await listJsonFilesStrict(path.join(rootDir, \"nodes\"), { allowMissingDirectory: true });\n const nodes: AbstractionNode[] = [];\n for (const filePath of files) {\n try {\n nodes.push(validateAbstractionNode(await readJsonFile(filePath)));\n } catch {\n // fail-open: invalid artifacts stay visible via status tooling instead of recall\n }\n }\n return nodes;\n}\n\nexport async function readCueAnchors(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n}): Promise<CueAnchor[]> {\n const abstractionRoot = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);\n const rootDir = resolveCueAnchorStoreDir(abstractionRoot);\n const files = await listJsonFilesStrict(rootDir, { allowMissingDirectory: true });\n const anchors: CueAnchor[] = [];\n for (const filePath of files) {\n try {\n anchors.push(validateCueAnchor(await readJsonFile(filePath)));\n } catch {\n // fail-open: invalid artifacts stay visible via status tooling instead of recall\n }\n }\n return anchors;\n}\n\nexport interface ProjectedHarmonicGraph {\n nodes: AbstractionNode[];\n anchors: CueAnchor[];\n}\n\n/**\n * Read nodes + anchors and project BOTH against the namespace's current active\n * memories. This is the single projection every graph reader shares: a raw\n * `readAbstractionNodes` / `readCueAnchors` pair still carries the stored title,\n * summary, tags, and anchor attribution of a memory that was later rejected,\n * quarantined, or otherwise moved out of the active set, so a second reader\n * that skipped the projection could leak governed metadata even when the\n * memory itself is excluded from the final results.\n *\n * - A node whose every source memory left the active set is dropped.\n * - A surviving node's title/summary/tags/entityRefs are rebuilt from its\n * active sources only.\n * - An anchor keeps a node reference only while its attribution runs through\n * one of that node's surviving active sources, and is dropped once no\n * reference survives.\n */\nasync function buildProjectedHarmonicGraph(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n anchorsEnabled: boolean;\n abortSignal?: AbortSignal;\n temporalExpiredInInjection?: boolean;\n nowMs?: number;\n}): Promise<ProjectedHarmonicGraph> {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodes = await readAbstractionNodes(options);\n const sourceMemoryIds = [...new Set(nodes.flatMap((node) => node.sourceMemoryIds ?? []))];\n const sourceMemories: SourceMemoryMap = sourceMemoryIds.length > 0\n ? await readSourceMemories({\n memoryDir: options.memoryDir,\n abortSignal: options.abortSignal,\n sourceMemoryIds,\n nowMs: options.nowMs,\n })\n : new Map();\n const nowMs = options.nowMs ?? Date.now();\n // A node whose full stored source set survived projection keeps legacy\n // anchor attribution (an anchor written before per-node source ids existed).\n const legacyCompatibleNodeRefs = new Set<string>();\n const projectedNodes = nodes.flatMap((node) => {\n const projected = projectSourceBackedNode(\n node,\n sourceMemories,\n options.memoryDir,\n options.temporalExpiredInInjection === true,\n nowMs\n );\n if (\n projected &&\n (node.sourceMemoryIds?.length ?? 0) > 0 &&\n projected.sourceMemoryIds?.length === node.sourceMemoryIds?.length\n ) {\n legacyCompatibleNodeRefs.add(node.nodeId);\n }\n return projected ? [projected] : [];\n });\n if (!options.anchorsEnabled) return { nodes: projectedNodes, anchors: [] };\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodeIndex = new Map(projectedNodes.map((node) => [node.nodeId, node]));\n const anchors = (await readCueAnchors(options)).flatMap((anchor) => {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodeRefs = anchor.nodeRefs.filter((nodeRef) => {\n const node = nodeIndex.get(nodeRef);\n return (\n node !== undefined &&\n anchorMatchesProjectedNode(anchor, nodeRef, node, legacyCompatibleNodeRefs.has(nodeRef))\n );\n });\n return nodeRefs.length > 0 ? [{ ...anchor, nodeRefs }] : [];\n });\n return { nodes: projectedNodes, anchors };\n}\n\nconst GRAPH_CACHE_TTL_MS = 30_000;\nconst GRAPH_CACHE_MAX_ENTRIES = 8;\n\ninterface GraphCacheEntry {\n stamp: string;\n startedAtMs: number;\n graph: ProjectedHarmonicGraph;\n}\n\nconst graphCache = new Map<string, GraphCacheEntry>();\n/** Counters for tests and diagnostics. */\nexport const harmonicGraphCacheStats = { hits: 0, misses: 0 };\n\n/** Freeze records and their nested arrays/objects so a caller cannot corrupt the shared cache. */\nfunction deepFreeze<T extends object>(value: T): T {\n // isFrozen is true for primitives and null, and a frozen value is not revisited, so this ends on cycles too.\n if (Object.isFrozen(value)) return value;\n Object.freeze(value);\n for (const child of Object.values(value)) deepFreeze(child);\n return value;\n}\n\nexport function clearHarmonicGraphCache(): void {\n graphCache.clear();\n}\n\n/**\n * `readProjectedHarmonicGraph` with an opt-in in-memory cache. Every recall used\n * to re-read all nodes, anchors and source memories from disk (about 4.7 s on a\n * 2107 node, 9199 anchor, 4105 source graph). With `useCache` a completed graph is\n * reused while the stamp below is unchanged: the memory corpus, memory status and\n * cold-write version sentinels (bumped by every memory write, in any process) and\n * the graph version sentinel (bumped by node and anchor writes). A stamp read is\n * four stats, not a scan of the memories. The TTL bounds the one input a sentinel\n * cannot see, which is wall-clock validity expiry. An explicit `nowMs` bypasses the\n * cache so tests stay deterministic. The cached arrays are frozen: callers must not\n * mutate them.\n */\nexport async function readProjectedHarmonicGraph(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n anchorsEnabled: boolean;\n abortSignal?: AbortSignal;\n temporalExpiredInInjection?: boolean;\n nowMs?: number;\n useCache?: boolean;\n}): Promise<ProjectedHarmonicGraph> {\n if (options.useCache !== true || options.nowMs !== undefined) return buildProjectedHarmonicGraph(options);\n // Same cancellation contract as the builder: a cache hit must not mask an aborted signal.\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodeStoreDir = resolveAbstractionNodeStoreDir(options.memoryDir, options.abstractionNodeStoreDir);\n const key = JSON.stringify([\n options.memoryDir,\n nodeStoreDir,\n options.anchorsEnabled === true,\n options.temporalExpiredInInjection === true,\n ]);\n // The stamp is read BEFORE the build, so a write that lands mid-build leaves the\n // entry stale and the next call rebuilds.\n const stamp = readHarmonicGraphStamp(options.memoryDir, nodeStoreDir);\n const startedAtMs = Date.now();\n const hit = graphCache.get(key);\n if (hit && hit.stamp === stamp && startedAtMs - hit.startedAtMs < GRAPH_CACHE_TTL_MS) {\n harmonicGraphCacheStats.hits++;\n graphCache.delete(key);\n graphCache.set(key, hit);\n return hit.graph;\n }\n harmonicGraphCacheStats.misses++;\n const built = await buildProjectedHarmonicGraph(options);\n const graph = {\n nodes: deepFreeze(built.nodes),\n anchors: deepFreeze(built.anchors),\n };\n graphCache.delete(key);\n graphCache.set(key, { stamp, startedAtMs, graph });\n while (graphCache.size > GRAPH_CACHE_MAX_ENTRIES) {\n const oldest = graphCache.keys().next().value;\n if (oldest === undefined) break;\n graphCache.delete(oldest);\n }\n return graph;\n}\n\nexport async function searchHarmonicRetrieval(options: {\n memoryDir: string;\n abstractionNodeStoreDir?: string;\n query: string;\n maxResults: number;\n sessionKey?: string;\n anchorsEnabled: boolean;\n abortSignal?: AbortSignal;\n temporalExpiredInInjection?: boolean;\n /** Share one projected graph between recalls until a write bumps a version sentinel (see readProjectedHarmonicGraph). */\n useGraphCache?: boolean;\n}): Promise<HarmonicRetrievalResult[]> {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const queryTokens = new Set(normalizeRecallTokens(options.query, [\"what\", \"which\"]));\n if (queryTokens.size === 0 || options.maxResults <= 0) return [];\n\n // One projection for every graph reader: nodes and anchors both arrive\n // already narrowed to the namespace's current active memories.\n const { nodes: eligibleNodes, anchors } = await readProjectedHarmonicGraph({\n ...options,\n useCache: options.useGraphCache === true,\n });\n const candidates = new Map<string, HarmonicCandidate>();\n\n for (const node of eligibleNodes) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const { score, matchedFields } = scoreNode(node, queryTokens);\n if (score <= 0) continue;\n candidates.set(node.nodeId, {\n node,\n nodeScore: score,\n anchorScore: 0,\n matchedFields: new Set(matchedFields),\n matchedAnchors: new Map(),\n });\n }\n\n if (options.anchorsEnabled) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n const nodeIndex = new Map(eligibleNodes.map((node) => [node.nodeId, node]));\n for (const anchor of anchors) {\n throwIfAborted(options.abortSignal, \"harmonic retrieval aborted\");\n // `nodeRefs` are the projection's surviving references already.\n const eligibleNodeRefs = anchor.nodeRefs;\n const eligibleNodeTags = new Set(eligibleNodeRefs.flatMap((nodeRef) => nodeIndex.get(nodeRef)?.tags ?? []));\n const eligibleAnchorTags = anchor.tags?.filter((tag) => eligibleNodeTags.has(tag)) ?? [];\n const { score, matchedFields } = scoreAnchor(anchor, queryTokens, eligibleAnchorTags);\n if (score <= 0) continue;\n for (const nodeRef of eligibleNodeRefs) {\n const node = nodeIndex.get(nodeRef);\n if (!node) continue;\n const existing = candidates.get(nodeRef) ?? {\n node,\n nodeScore: 0,\n anchorScore: 0,\n matchedFields: new Set<string>(),\n matchedAnchors: new Map<string, HarmonicMatchedAnchor>(),\n };\n existing.anchorScore += score;\n existing.matchedFields.add(\"anchor\");\n for (const field of matchedFields) existing.matchedFields.add(field);\n existing.matchedAnchors.set(anchor.anchorId, {\n anchorId: anchor.anchorId,\n anchorType: anchor.anchorType,\n anchorValue: anchor.anchorValue,\n });\n candidates.set(nodeRef, existing);\n }\n }\n }\n\n return [...candidates.values()]\n .map((candidate) => {\n let score = candidate.nodeScore + candidate.anchorScore;\n if (options.sessionKey && candidate.node.sessionKey === options.sessionKey) score += 0.5;\n return {\n node: candidate.node,\n score,\n nodeScore: candidate.nodeScore,\n anchorScore: candidate.anchorScore,\n matchedFields: [...candidate.matchedFields].sort(),\n matchedAnchors: [...candidate.matchedAnchors.values()].sort(\n (left, right) =>\n left.anchorType.localeCompare(right.anchorType) || left.anchorValue.localeCompare(right.anchorValue)\n ),\n };\n })\n .filter((result) => result.nodeScore > 0 || result.anchorScore > 0)\n .sort(\n (left, right) =>\n right.score - left.score ||\n right.anchorScore - left.anchorScore ||\n right.node.recordedAt.localeCompare(left.node.recordedAt)\n )\n .slice(0, options.maxResults);\n}\n"],"mappings":"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","names":[]}