@remnic/core 9.38.2 → 9.39.0

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 (189) hide show
  1. package/dist/access-admin-ops-surface.d.ts +5 -5
  2. package/dist/access-admin-ops-surface.js +13 -13
  3. package/dist/access-authorization-probe.d.ts +5 -5
  4. package/dist/access-authorization-probe.js +14 -14
  5. package/dist/access-boundary.d.ts +5 -5
  6. package/dist/access-boundary.js +13 -13
  7. package/dist/access-cli.js +35 -35
  8. package/dist/access-extraction-force-flush.d.ts +5 -5
  9. package/dist/access-extraction-force-flush.js +13 -13
  10. package/dist/access-http-lcm-compaction.d.ts +5 -5
  11. package/dist/access-http-lifecycle-flush.d.ts +5 -5
  12. package/dist/access-http.d.ts +5 -5
  13. package/dist/access-http.js +18 -18
  14. package/dist/access-identity-continuity-surface.d.ts +4 -4
  15. package/dist/access-identity-continuity-surface.js +13 -13
  16. package/dist/access-lcm-surface.d.ts +5 -5
  17. package/dist/access-lcm-surface.js +13 -13
  18. package/dist/access-mcp.d.ts +5 -5
  19. package/dist/access-mcp.js +16 -16
  20. package/dist/access-namespace-preflight.js +13 -13
  21. package/dist/access-observe-write-surface.d.ts +5 -5
  22. package/dist/access-observe-write-surface.js +13 -13
  23. package/dist/access-operations-batch.js +14 -14
  24. package/dist/access-operations.d.ts +5 -5
  25. package/dist/access-operations.js +15 -15
  26. package/dist/access-recall-concurrency.d.ts +5 -5
  27. package/dist/access-recall-concurrency.js +13 -13
  28. package/dist/access-recall-response.d.ts +5 -5
  29. package/dist/access-recall-response.js +13 -13
  30. package/dist/access-recall-surface.d.ts +5 -5
  31. package/dist/access-recall-surface.js +13 -13
  32. package/dist/{access-service-C2WYT1pO.d.ts → access-service-C6QuKBCG.d.ts} +3 -3
  33. package/dist/access-service-helpers.d.ts +5 -5
  34. package/dist/access-service.d.ts +5 -5
  35. package/dist/access-service.js +13 -13
  36. package/dist/access-surface-catalog.d.ts +5 -5
  37. package/dist/access-wearables-meetings-surface.d.ts +2 -2
  38. package/dist/bootstrap.d.ts +4 -4
  39. package/dist/briefing.d.ts +1 -1
  40. package/dist/briefing.js +5 -5
  41. package/dist/buffer.d.ts +1 -1
  42. package/dist/buffer.js +2 -2
  43. package/dist/causal-consolidation.js +6 -6
  44. package/dist/{chunk-2YJPCRUM.js → chunk-4CSTEPFA.js} +2 -2
  45. package/dist/{chunk-T3FVAHM7.js → chunk-4VXGRIH6.js} +286 -7
  46. package/dist/chunk-4VXGRIH6.js.map +1 -0
  47. package/dist/{chunk-A4P6H25D.js → chunk-5JUYBWJD.js} +19 -19
  48. package/dist/{chunk-JYLN6KHH.js → chunk-5TRIAPT4.js} +7 -9
  49. package/dist/{chunk-JYLN6KHH.js.map → chunk-5TRIAPT4.js.map} +1 -1
  50. package/dist/{chunk-6D5D5A4M.js → chunk-7ERHAARG.js} +2 -2
  51. package/dist/{chunk-GORHSN5C.js → chunk-7OCTH7AJ.js} +2 -2
  52. package/dist/{chunk-ILGC6JH6.js → chunk-7RJUVTVF.js} +16 -1
  53. package/dist/chunk-7RJUVTVF.js.map +1 -0
  54. package/dist/{chunk-FE7MUX7M.js → chunk-AL73FWSS.js} +2 -2
  55. package/dist/{chunk-6TF4M2LB.js → chunk-AVGTOOYP.js} +2 -2
  56. package/dist/{chunk-B6XHIBIB.js → chunk-AX2J2LC4.js} +2 -2
  57. package/dist/{chunk-ZB3YODID.js → chunk-BVJIAIB3.js} +8 -8
  58. package/dist/{chunk-XN3EW6P2.js → chunk-CMENJQ6I.js} +2 -2
  59. package/dist/{chunk-PRP3M5Y3.js → chunk-CMFUYOYB.js} +2 -2
  60. package/dist/{chunk-M3DBB2ND.js → chunk-CNZLKQEL.js} +2 -2
  61. package/dist/{chunk-YVMVVE4B.js → chunk-CPD6C6K6.js} +2 -2
  62. package/dist/{chunk-VU7732DU.js → chunk-CYM2PHLB.js} +5 -5
  63. package/dist/{chunk-RY2XZTFN.js → chunk-DJH35IVS.js} +2 -2
  64. package/dist/{chunk-Q3CVY7LV.js → chunk-ENLZOWYK.js} +201 -231
  65. package/dist/chunk-ENLZOWYK.js.map +1 -0
  66. package/dist/{chunk-IJAQCBGV.js → chunk-F5EVTFQK.js} +2 -2
  67. package/dist/{chunk-RY7CHVGE.js → chunk-G57BGHQ2.js} +2 -2
  68. package/dist/{chunk-F3BNEYX2.js → chunk-GUQYMOPU.js} +2 -2
  69. package/dist/{chunk-IMEXE4XS.js → chunk-GYGXKATH.js} +6 -6
  70. package/dist/{chunk-CKBKHZKZ.js → chunk-JKTHT4KX.js} +3 -3
  71. package/dist/{chunk-HQYYJRU7.js → chunk-KJP2R5MJ.js} +15 -15
  72. package/dist/{chunk-UBWOCQ3I.js → chunk-MHCRASVK.js} +2 -2
  73. package/dist/{chunk-RYMPLSIT.js → chunk-NF3U3MPG.js} +41 -8
  74. package/dist/chunk-NF3U3MPG.js.map +1 -0
  75. package/dist/{chunk-DKKZ6SO2.js → chunk-SHTPVI47.js} +22 -45
  76. package/dist/chunk-SHTPVI47.js.map +1 -0
  77. package/dist/{chunk-PYTUBWAS.js → chunk-UGAZILZG.js} +2 -2
  78. package/dist/{chunk-4TAD3B56.js → chunk-VGK33D3K.js} +2 -2
  79. package/dist/{chunk-BGLDKAYY.js → chunk-VK33JSBR.js} +2 -2
  80. package/dist/{chunk-NBAEGFXT.js → chunk-VQTRSX4R.js} +11 -14
  81. package/dist/chunk-VQTRSX4R.js.map +1 -0
  82. package/dist/{chunk-WET4M3R6.js → chunk-XSPD6KQL.js} +2 -2
  83. package/dist/{chunk-HUS2XN3T.js → chunk-YFHMW37V.js} +2 -2
  84. package/dist/{chunk-HKF5VASQ.js → chunk-ZA53AZND.js} +17 -6
  85. package/dist/chunk-ZA53AZND.js.map +1 -0
  86. package/dist/{chunk-5ZGHUWTT.js → chunk-ZBDORYWM.js} +2 -2
  87. package/dist/{cli-jkmzdT8P.d.ts → cli-ClXRCu08.d.ts} +3 -3
  88. package/dist/cli.d.ts +6 -6
  89. package/dist/cli.js +27 -27
  90. package/dist/compounding/engine.d.ts +1 -1
  91. package/dist/compounding/engine.js +5 -5
  92. package/dist/connectors/codex-materialize-runner.js +5 -5
  93. package/dist/connectors/index.js +5 -5
  94. package/dist/consolidation-provenance-check.d.ts +1 -1
  95. package/dist/consolidation-undo.d.ts +1 -1
  96. package/dist/contradiction/index.d.ts +1 -1
  97. package/dist/corpus-watermark.js +7 -7
  98. package/dist/entity-retrieval.d.ts +1 -1
  99. package/dist/entity-retrieval.js +5 -5
  100. package/dist/explicit-capture.d.ts +4 -4
  101. package/dist/extraction.js +8 -8
  102. package/dist/index.d.ts +10 -10
  103. package/dist/index.js +35 -35
  104. package/dist/maintenance/memory-governance.js +5 -5
  105. package/dist/maintenance/rebuild-memory-lifecycle-ledger.d.ts +1 -1
  106. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -5
  107. package/dist/maintenance/rebuild-memory-projection.d.ts +17 -10
  108. package/dist/maintenance/rebuild-memory-projection.js +6 -6
  109. package/dist/{maintenance-Ha9Dg93M.d.ts → maintenance-Dsvprbod.d.ts} +1 -1
  110. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  111. package/dist/memory-lifecycle-ledger-utils.d.ts +8 -1
  112. package/dist/memory-lifecycle-ledger-utils.js +5 -1
  113. package/dist/memory-worth-outcomes.d.ts +1 -1
  114. package/dist/namespaces/migrate.d.ts +1 -1
  115. package/dist/namespaces/migrate.js +6 -6
  116. package/dist/namespaces/storage.d.ts +1 -1
  117. package/dist/namespaces/storage.js +5 -5
  118. package/dist/offline-sync-impression-drain.js +5 -3
  119. package/dist/operator-doctor-corpus.js +8 -8
  120. package/dist/operator-toolkit.d.ts +1 -1
  121. package/dist/operator-toolkit.js +11 -11
  122. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  123. package/dist/orchestration/maintenance.d.ts +2 -2
  124. package/dist/orchestration/maintenance.js +10 -10
  125. package/dist/{orchestrator-DV_u9bfx.d.ts → orchestrator-CEhod0MJ.d.ts} +3 -3
  126. package/dist/orchestrator.d.ts +4 -4
  127. package/dist/orchestrator.js +35 -35
  128. package/dist/semantic-consolidation.js +6 -6
  129. package/dist/semantic-rule-promotion.js +5 -5
  130. package/dist/semantic-rule-verifier.js +5 -5
  131. package/dist/{service-JxXXY-Eh.d.ts → service-BlOfGid8.d.ts} +1 -1
  132. package/dist/source-agent-qualifier.js +7 -7
  133. package/dist/{storage-BbH4HDUS.d.ts → storage-CNKZocJF.d.ts} +1 -1
  134. package/dist/storage-guards.d.ts +9 -2
  135. package/dist/storage-guards.js +3 -1
  136. package/dist/storage.d.ts +1 -1
  137. package/dist/storage.js +4 -4
  138. package/dist/temporal-supersession.d.ts +1 -1
  139. package/dist/tier-migration.d.ts +1 -1
  140. package/dist/verified-recall.js +5 -5
  141. package/package.json +2 -2
  142. package/src/maintenance/projection-support.ts +192 -1
  143. package/src/maintenance/rebuild-memory-lifecycle-ledger.ts +5 -16
  144. package/src/maintenance/rebuild-memory-projection.ts +28 -60
  145. package/src/memory-lifecycle-ledger-utils.ts +21 -0
  146. package/src/orchestration/extraction-run-helpers.ts +47 -0
  147. package/src/orchestration/extraction-run.test.ts +133 -0
  148. package/src/orchestration/extraction-run.ts +11 -7
  149. package/src/orchestration/maintenance.test.ts +30 -0
  150. package/src/orchestrator-flush.test.ts +51 -0
  151. package/src/storage/memory-lifecycle-ledger-access.ts +198 -1
  152. package/src/storage/secure-line-reader.ts +3 -1
  153. package/src/storage-guards.ts +28 -7
  154. package/src/storage-memory-lifecycle-ledger.test.ts +291 -1
  155. package/src/storage.ts +11 -21
  156. package/dist/chunk-DKKZ6SO2.js.map +0 -1
  157. package/dist/chunk-HKF5VASQ.js.map +0 -1
  158. package/dist/chunk-ILGC6JH6.js.map +0 -1
  159. package/dist/chunk-NBAEGFXT.js.map +0 -1
  160. package/dist/chunk-Q3CVY7LV.js.map +0 -1
  161. package/dist/chunk-RYMPLSIT.js.map +0 -1
  162. package/dist/chunk-T3FVAHM7.js.map +0 -1
  163. /package/dist/{chunk-2YJPCRUM.js.map → chunk-4CSTEPFA.js.map} +0 -0
  164. /package/dist/{chunk-A4P6H25D.js.map → chunk-5JUYBWJD.js.map} +0 -0
  165. /package/dist/{chunk-6D5D5A4M.js.map → chunk-7ERHAARG.js.map} +0 -0
  166. /package/dist/{chunk-GORHSN5C.js.map → chunk-7OCTH7AJ.js.map} +0 -0
  167. /package/dist/{chunk-FE7MUX7M.js.map → chunk-AL73FWSS.js.map} +0 -0
  168. /package/dist/{chunk-6TF4M2LB.js.map → chunk-AVGTOOYP.js.map} +0 -0
  169. /package/dist/{chunk-B6XHIBIB.js.map → chunk-AX2J2LC4.js.map} +0 -0
  170. /package/dist/{chunk-ZB3YODID.js.map → chunk-BVJIAIB3.js.map} +0 -0
  171. /package/dist/{chunk-XN3EW6P2.js.map → chunk-CMENJQ6I.js.map} +0 -0
  172. /package/dist/{chunk-PRP3M5Y3.js.map → chunk-CMFUYOYB.js.map} +0 -0
  173. /package/dist/{chunk-M3DBB2ND.js.map → chunk-CNZLKQEL.js.map} +0 -0
  174. /package/dist/{chunk-YVMVVE4B.js.map → chunk-CPD6C6K6.js.map} +0 -0
  175. /package/dist/{chunk-VU7732DU.js.map → chunk-CYM2PHLB.js.map} +0 -0
  176. /package/dist/{chunk-RY2XZTFN.js.map → chunk-DJH35IVS.js.map} +0 -0
  177. /package/dist/{chunk-IJAQCBGV.js.map → chunk-F5EVTFQK.js.map} +0 -0
  178. /package/dist/{chunk-RY7CHVGE.js.map → chunk-G57BGHQ2.js.map} +0 -0
  179. /package/dist/{chunk-F3BNEYX2.js.map → chunk-GUQYMOPU.js.map} +0 -0
  180. /package/dist/{chunk-IMEXE4XS.js.map → chunk-GYGXKATH.js.map} +0 -0
  181. /package/dist/{chunk-CKBKHZKZ.js.map → chunk-JKTHT4KX.js.map} +0 -0
  182. /package/dist/{chunk-HQYYJRU7.js.map → chunk-KJP2R5MJ.js.map} +0 -0
  183. /package/dist/{chunk-UBWOCQ3I.js.map → chunk-MHCRASVK.js.map} +0 -0
  184. /package/dist/{chunk-PYTUBWAS.js.map → chunk-UGAZILZG.js.map} +0 -0
  185. /package/dist/{chunk-4TAD3B56.js.map → chunk-VGK33D3K.js.map} +0 -0
  186. /package/dist/{chunk-BGLDKAYY.js.map → chunk-VK33JSBR.js.map} +0 -0
  187. /package/dist/{chunk-WET4M3R6.js.map → chunk-XSPD6KQL.js.map} +0 -0
  188. /package/dist/{chunk-HUS2XN3T.js.map → chunk-YFHMW37V.js.map} +0 -0
  189. /package/dist/{chunk-5ZGHUWTT.js.map → chunk-ZBDORYWM.js.map} +0 -0
@@ -5,16 +5,23 @@ import path from "node:path";
5
5
  import test from "node:test";
6
6
  import { randomUUID } from "node:crypto";
7
7
 
8
+ import { setImmediate as yieldToEventLoop } from "node:timers/promises";
8
9
  import { StorageManager } from "./storage.js";
9
10
  import { initLogger, resetLogger } from "./logger.js";
10
- import { __resetProjectionFallbackWarnSuppressionForTest } from "./storage-guards.js";
11
+ import {
12
+ __resetProjectionFallbackWarnSuppressionForTest,
13
+ PROJECTION_LEDGER_LAG_WARN_THRESHOLD_EVENTS,
14
+ warnProjectionFallback,
15
+ } from "./storage-guards.js";
11
16
  import { encryptFileBody, filePathAad, isEncryptedFile, readMaybeEncryptedFile, readMaybeEncryptedFileBuffer } from "./secure-store/secure-fs.js";
12
17
  import type { MemoryLifecycleEvent } from "./types.js";
13
18
  import {
14
19
  appendLifecycleEventsSerialized,
15
20
  drainPendingLifecycleAppendsSerialized,
16
21
  pendingLifecycleLedgerDir,
22
+ ProjectionLedgerLagManager,
17
23
  readAllLifecycleEventsFromLedgerBuffer,
24
+ readBoundedLifecycleEventsWithProjectionLag,
18
25
  type LifecyclePendingIo,
19
26
  } from "./storage/memory-lifecycle-ledger-access.js";
20
27
  import { withHeldFileLock } from "./utils/serialize-mutations.js";
@@ -26,6 +33,10 @@ import {
26
33
  MEMORY_LIFECYCLE_LEDGER_LOCK_STALE_MS,
27
34
  MEMORY_LIFECYCLE_LEDGER_APPEND_LOCK_MAX_WAIT_MS,
28
35
  } from "./memory-lifecycle-ledger-utils.js";
36
+ import {
37
+ readProjectionLifecycleLedgerHighWater,
38
+ } from "./maintenance/projection-support.js";
39
+ import { rebuildMemoryProjection } from "./maintenance/rebuild-memory-projection.js";
29
40
 
30
41
  function lifecycleEvent(
31
42
  eventId: string,
@@ -57,6 +68,32 @@ async function withLifecycleLedger(
57
68
  }
58
69
  }
59
70
 
71
+ async function withStaleLifecycleProjection(
72
+ projectedRows: MemoryLifecycleEvent[],
73
+ appendedRows: MemoryLifecycleEvent[],
74
+ run: (storage: StorageManager, memoryDir: string) => Promise<void>,
75
+ ): Promise<void> {
76
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-projection-"));
77
+ const ledgerPath = path.join(memoryDir, "state", "memory-lifecycle-ledger.jsonl");
78
+ await mkdir(path.dirname(ledgerPath), { recursive: true });
79
+ await writeFile(
80
+ ledgerPath,
81
+ `${projectedRows.map((event) => JSON.stringify(event)).join("\n")}\n`,
82
+ "utf8",
83
+ );
84
+ await rebuildMemoryProjection({ memoryDir, dryRun: false });
85
+ await appendFile(
86
+ ledgerPath,
87
+ `${appendedRows.map((event) => JSON.stringify(event)).join("\n")}\n`,
88
+ "utf8",
89
+ );
90
+ try {
91
+ await run(new StorageManager(memoryDir), memoryDir);
92
+ } finally {
93
+ await rm(memoryDir, { recursive: true, force: true });
94
+ }
95
+ }
96
+
60
97
  test("readAllMemoryLifecycleEvents streams plaintext rows and preserves fail-open sorting", async () => {
61
98
  const later = lifecycleEvent("event-z", "memory-b", "2026-01-03T00:00:00.000Z");
62
99
  const earlier = lifecycleEvent("event-a", "memory-a", "2026-01-02T00:00:00.000Z");
@@ -1303,3 +1340,256 @@ test("getMemoryTimeline fallback WARN is loud with lag and rate-limited when the
1303
1340
  __resetProjectionFallbackWarnSuppressionForTest();
1304
1341
  }
1305
1342
  });
1343
+
1344
+ test("getMemoryTimeline fallback emits below-threshold ledger lag telemetry without a WARN (#2119)", async () => {
1345
+ const warns: string[] = [];
1346
+ const debug: string[] = [];
1347
+ initLogger({ info() {}, warn: (message) => warns.push(message), error() {}, debug: (message) => debug.push(message) }, true);
1348
+ __resetProjectionFallbackWarnSuppressionForTest();
1349
+ try {
1350
+ const projected = lifecycleEvent("projected-1", "memory-existing", "2026-01-01T00:01:00.000Z");
1351
+ const appended = lifecycleEvent("current-1", "memory-target", "2026-01-01T00:02:00.000Z");
1352
+ await withStaleLifecycleProjection([projected], [appended], async (storage, memoryDir) => {
1353
+ const highWater = readProjectionLifecycleLedgerHighWater(memoryDir);
1354
+ assert.equal(highWater?.eventCount, 1, "rebuild persists the source-ledger event-count high-water");
1355
+
1356
+ const timeline = await storage.getMemoryTimeline("memory-target", 5);
1357
+ assert.deepEqual(timeline.map((event) => event.eventId), ["current-1"]);
1358
+ assert.equal(warns.length, 0, "lag at or below the threshold must not WARN");
1359
+ const telemetry = debug.find((message) => message.includes("storage.getMemoryTimeline"));
1360
+ assert.ok(telemetry, "fallback emits ledger-relative lag telemetry below the WARN threshold");
1361
+ assert.match(telemetry, /projected_events=1/);
1362
+ assert.match(telemetry, /current_ledger_events=2/);
1363
+ assert.match(telemetry, /delta_events=1/);
1364
+ assert.match(telemetry, /fallback_action=full-ledger-scan/);
1365
+ });
1366
+ } finally {
1367
+ resetLogger();
1368
+ __resetProjectionFallbackWarnSuppressionForTest();
1369
+ }
1370
+ });
1371
+
1372
+ test("projection lag excludes blank memory ids and deduplicates identities on disk (#2119 review)", async () => {
1373
+ const debug: string[] = [];
1374
+ initLogger({ info() {}, warn() {}, error() {}, debug: (message) => debug.push(message) }, true);
1375
+ __resetProjectionFallbackWarnSuppressionForTest();
1376
+ try {
1377
+ const projected = lifecycleEvent("projected-1", "memory-existing", "2026-01-01T00:01:00.000Z");
1378
+ const appended = lifecycleEvent("current-1", "memory-target", "2026-01-01T00:02:00.000Z");
1379
+ const blank = { ...lifecycleEvent("blank-1", "unused", "2026-01-01T00:03:00.000Z"), memoryId: " " };
1380
+ await withStaleLifecycleProjection([projected], [blank, appended, appended], async (storage) => {
1381
+ await storage.getMemoryTimeline("memory-target", 5);
1382
+ const telemetry = debug.find((message) => message.includes("storage.getMemoryTimeline"));
1383
+ assert.ok(telemetry);
1384
+ assert.match(telemetry, /current_ledger_events=2/);
1385
+ assert.match(telemetry, /delta_events=1/);
1386
+ });
1387
+ } finally {
1388
+ resetLogger();
1389
+ __resetProjectionFallbackWarnSuppressionForTest();
1390
+ }
1391
+ });
1392
+
1393
+ test("getMemoryTimeline fallback WARNS above the ledger lag threshold and rate-limits repeats (#2119)", async () => {
1394
+ const warns: string[] = [];
1395
+ initLogger({ info() {}, warn: (message) => warns.push(message), error() {}, debug() {} }, false);
1396
+ __resetProjectionFallbackWarnSuppressionForTest();
1397
+ try {
1398
+ const projected = lifecycleEvent("projected-1", "memory-existing", "2026-01-01T00:00:00.000Z");
1399
+ const delta = PROJECTION_LEDGER_LAG_WARN_THRESHOLD_EVENTS + 1;
1400
+ const appended = Array.from({ length: delta }, (_, index) =>
1401
+ lifecycleEvent(
1402
+ `current-${index}`,
1403
+ "memory-target",
1404
+ `2026-01-01T00:${String(Math.floor(index / 60)).padStart(2, "0")}:${String(index % 60).padStart(2, "0")}.000Z`,
1405
+ ));
1406
+ await withStaleLifecycleProjection([projected], appended, async (storage) => {
1407
+ const first = await storage.getMemoryTimeline("memory-target", 5);
1408
+ const second = await storage.getMemoryTimeline("memory-target", 5);
1409
+ assert.equal(first.length, 5);
1410
+ assert.deepEqual(second, first);
1411
+
1412
+ const timelineWarns = warns.filter((message) => message.includes("storage.getMemoryTimeline"));
1413
+ assert.equal(timelineWarns.length, 1, "two above-threshold fallbacks emit one WARN per suppression interval");
1414
+ const warning = timelineWarns[0]!;
1415
+ assert.match(warning, /falling back to full corpus/);
1416
+ assert.match(warning, /projected_events=1/);
1417
+ assert.match(warning, new RegExp(`current_ledger_events=${delta + 1}`));
1418
+ assert.match(warning, new RegExp(`delta_events=${delta}`));
1419
+ assert.match(warning, new RegExp(`threshold_events=${PROJECTION_LEDGER_LAG_WARN_THRESHOLD_EVENTS}`));
1420
+ assert.match(warning, /fallback_action=full-ledger-scan/);
1421
+ assert.match(warning, /last rebuilt/);
1422
+ });
1423
+ } finally {
1424
+ resetLogger();
1425
+ __resetProjectionFallbackWarnSuppressionForTest();
1426
+ }
1427
+ });
1428
+
1429
+ test("projection fallback threshold zero still WARNS for positive ledger lag (#2119)", () => {
1430
+ const warns: string[] = [];
1431
+ initLogger({ info() {}, warn: (message) => warns.push(message), error() {}, debug() {} }, false);
1432
+ __resetProjectionFallbackWarnSuppressionForTest();
1433
+ try {
1434
+ warnProjectionFallback(
1435
+ "memory-dir",
1436
+ "getMemoryTimeline",
1437
+ undefined,
1438
+ {
1439
+ projectedEvents: 0,
1440
+ currentLedgerEvents: 1,
1441
+ deltaEvents: 1,
1442
+ warnThresholdEvents: 0,
1443
+ },
1444
+ );
1445
+ assert.equal(warns.length, 1, "zero is an active threshold, not a disabled sentinel");
1446
+ assert.match(warns[0]!, /threshold_events=0/);
1447
+ } finally {
1448
+ resetLogger();
1449
+ __resetProjectionFallbackWarnSuppressionForTest();
1450
+ }
1451
+ });
1452
+
1453
+ test("ledger lag stays event-relative when compaction shrinks and rewrites the ledger (#2119)", async () => {
1454
+ const warns: string[] = [];
1455
+ initLogger({ info() {}, warn: (message) => warns.push(message), error() {}, debug() {} }, false);
1456
+ __resetProjectionFallbackWarnSuppressionForTest();
1457
+ try {
1458
+ const projectedCount = PROJECTION_LEDGER_LAG_WARN_THRESHOLD_EVENTS + 50;
1459
+ const projected = Array.from({ length: projectedCount }, (_, index) =>
1460
+ lifecycleEvent(
1461
+ `projected-${index}`,
1462
+ "memory-existing",
1463
+ `2026-01-01T${String(Math.floor(index / 60)).padStart(2, "0")}:${String(index % 60).padStart(2, "0")}:00.000Z`,
1464
+ ));
1465
+ const delta = PROJECTION_LEDGER_LAG_WARN_THRESHOLD_EVENTS + 1;
1466
+ const appended = Array.from({ length: delta }, (_, index) =>
1467
+ lifecycleEvent(
1468
+ `current-${index}`,
1469
+ "memory-target",
1470
+ `2026-01-02T00:${String(Math.floor(index / 60)).padStart(2, "0")}:${String(index % 60).padStart(2, "0")}.000Z`,
1471
+ ));
1472
+ await withStaleLifecycleProjection(projected, [], async (storage, memoryDir) => {
1473
+ const retained = projected.at(-1)!;
1474
+ const compactedRows = [{
1475
+ ...retained,
1476
+ eventId: `rebuild-${retained.memoryId}-${retained.eventType}-${retained.timestamp}`,
1477
+ }, ...appended];
1478
+ await writeFile(
1479
+ path.join(memoryDir, "state", "memory-lifecycle-ledger.jsonl"),
1480
+ `${compactedRows.map((event) => JSON.stringify(event)).join("\n")}\n`,
1481
+ "utf8",
1482
+ );
1483
+
1484
+ const timeline = await storage.getMemoryTimeline("memory-target", 5);
1485
+ assert.equal(timeline.length, 5);
1486
+ const warning = warns.find((message) => message.includes("storage.getMemoryTimeline"));
1487
+ assert.ok(warning);
1488
+ assert.match(warning, new RegExp(`projected_events=${projectedCount}`));
1489
+ assert.match(warning, new RegExp(`current_ledger_events=${delta + 1}`));
1490
+ assert.match(warning, new RegExp(`delta_events=${delta}`));
1491
+ });
1492
+ } finally {
1493
+ resetLogger();
1494
+ __resetProjectionFallbackWarnSuppressionForTest();
1495
+ }
1496
+ });
1497
+
1498
+ test("concurrent cold fallbacks singleflight the full ledger lag scan (#2119)", async () => {
1499
+ const projected = lifecycleEvent("projected-1", "memory-existing", "2026-01-01T00:00:00.000Z");
1500
+ const appended = lifecycleEvent("current-1", "memory-target", "2026-01-02T00:00:00.000Z");
1501
+ await withStaleLifecycleProjection([projected], [appended], async (storage, memoryDir) => {
1502
+ const ledgerPath = path.join(memoryDir, "state", "memory-lifecycle-ledger.jsonl");
1503
+ const key = Buffer.alloc(32, 11);
1504
+ const plaintext = await readFile(ledgerPath, "utf8");
1505
+ await writeFile(ledgerPath, encryptFileBody(plaintext, key, filePathAad(ledgerPath, memoryDir)));
1506
+ storage.setSecureStoreKey(key);
1507
+
1508
+ const secureStorage = storage as unknown as {
1509
+ readStorageSecureFile(filePath: string): Promise<string>;
1510
+ };
1511
+ const originalRead = secureStorage.readStorageSecureFile.bind(storage);
1512
+ const readRelease = Promise.withResolvers<void>();
1513
+ const readStart = Promise.withResolvers<void>();
1514
+ let secureReads = 0;
1515
+ secureStorage.readStorageSecureFile = async (filePath) => {
1516
+ secureReads += 1;
1517
+ readStart.resolve();
1518
+ await readRelease.promise;
1519
+ return originalRead(filePath);
1520
+ };
1521
+
1522
+ const first = storage.getMemoryTimeline("memory-target", 5);
1523
+ await readStart.promise;
1524
+ const second = storage.getMemoryTimeline("memory-target", 5);
1525
+ await yieldToEventLoop();
1526
+ await yieldToEventLoop();
1527
+ readRelease.resolve();
1528
+ const timelines = await Promise.all([first, second]);
1529
+
1530
+ assert.deepEqual(timelines[0], timelines[1]);
1531
+ assert.equal(secureReads, 1, "concurrent callers share the generation's full ledger scan");
1532
+ });
1533
+ });
1534
+
1535
+ test("scoped rebuild metadata distinguishes source-ledger high-water from projected events (#2119)", async () => {
1536
+ const projected = lifecycleEvent("projected-1", "memory-existing", "2026-01-01T00:00:00.000Z");
1537
+ const outsideScope = lifecycleEvent("current-1", "memory-outside-scope", "2026-01-02T00:00:00.000Z");
1538
+ await withStaleLifecycleProjection([projected], [outsideScope], async (_storage, memoryDir) => {
1539
+ await rebuildMemoryProjection({
1540
+ memoryDir,
1541
+ dryRun: false,
1542
+ updatedAfter: "2026-01-03T00:00:00.000Z",
1543
+ });
1544
+ const highWater = readProjectionLifecycleLedgerHighWater(memoryDir);
1545
+ assert.equal(highWater?.eventCount, 1, "projected count reflects the rows written by the scoped merge");
1546
+ assert.equal(highWater?.sourceEventCount, 2, "source high-water still records the full ledger snapshot");
1547
+ });
1548
+ });
1549
+ test("timeline lag resolver keeps ledger fallback when projection identity probing fails (#2119 review)", async () => {
1550
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-probe-failure-"));
1551
+ const ledgerPath = path.join(memoryDir, "memory-lifecycle-ledger.jsonl");
1552
+ const event = lifecycleEvent("current-1", "memory-target", "2026-01-02T00:00:00.000Z");
1553
+ await writeFile(path.join(memoryDir, "state"), "not a directory", "utf8");
1554
+ await writeFile(ledgerPath, `${JSON.stringify(event)}\n`, "utf8");
1555
+ try {
1556
+ const manager = new ProjectionLedgerLagManager();
1557
+ const timeline = await manager.resolveTimelineWithLag({
1558
+ baseDir: memoryDir,
1559
+ ledgerPath,
1560
+ memoryId: "memory-target",
1561
+ cappedLimit: 5,
1562
+ readSecureFile: (filePath) => readFile(filePath, "utf8"),
1563
+ projectionAge: () => "projection unavailable",
1564
+ });
1565
+ assert.deepEqual(timeline, [event]);
1566
+ } finally {
1567
+ await rm(memoryDir, { recursive: true, force: true });
1568
+ }
1569
+ });
1570
+
1571
+ test("lag tracker failures do not drop valid fallback timeline rows (#2119 review)", async () => {
1572
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-lifecycle-tracker-failure-"));
1573
+ const ledgerPath = path.join(memoryDir, "memory-lifecycle-ledger.jsonl");
1574
+ const event = lifecycleEvent("current-1", "memory-target", "2026-01-02T00:00:00.000Z");
1575
+ await writeFile(ledgerPath, `${JSON.stringify(event)}\n`, "utf8");
1576
+ try {
1577
+ const result = await readBoundedLifecycleEventsWithProjectionLag(
1578
+ ledgerPath,
1579
+ (filePath) => readFile(filePath, "utf8"),
1580
+ 5,
1581
+ "memory-target",
1582
+ {
1583
+ highWater: { eventCount: 0, sourceEventCount: 0 },
1584
+ record() {
1585
+ throw new Error("projection tracker unavailable");
1586
+ },
1587
+ close() {},
1588
+ },
1589
+ );
1590
+ assert.deepEqual(result.events, [event]);
1591
+ assert.equal(result.telemetryAvailable, false);
1592
+ } finally {
1593
+ await rm(memoryDir, { recursive: true, force: true });
1594
+ }
1595
+ });
package/src/storage.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { readProjectionRebuiltAt } from "./maintenance/projection-support.js";
1
+ import { formatProjectionAge, readProjectionRebuiltAt } from "./maintenance/projection-support.js";
2
2
  import {
3
3
  lstat,
4
4
  readdir,
@@ -25,6 +25,8 @@ import {
25
25
  type DrainPendingLifecycleForSyncResult,
26
26
  drainPendingLifecycleLedgerForSync,
27
27
  drainPendingLifecycleLedgerIfAny,
28
+ pendingLifecycleLedgerDir,
29
+ ProjectionLedgerLagManager,
28
30
  readAllLifecycleEventsFromLedger,
29
31
  readAllLifecycleEventsFromLedgerBuffer,
30
32
  readBoundedLifecycleEventsFromLedger,
@@ -1732,7 +1734,7 @@ export type SealedWriteExtras = Omit<
1732
1734
  export class StorageManager extends TombstoneBlockedCaptureIndexHost {
1733
1735
  private knowledgeIndexCache: { result: string; builtAt: number } | null = null;
1734
1736
  private artifactIndexCache: { memories: MemoryFile[]; loadedAtMs: number; writeVersion: number } | null = null;
1735
- /** Read by storage/entity-store.ts (decomposition), hence not `private`. */
1737
+ private projectionLedgerLagManager = new ProjectionLedgerLagManager();
1736
1738
  static readonly KNOWLEDGE_INDEX_CACHE_TTL_MS = 600_000; // 10 minutes (entity mutations invalidate)
1737
1739
  /** Read by storage/memory-read-store.ts (decomposition). */
1738
1740
  static readonly ARTIFACT_INDEX_CACHE_TTL_MS = 60_000; // 1 minute
@@ -6543,26 +6545,14 @@ export class StorageManager extends TombstoneBlockedCaptureIndexHost {
6543
6545
 
6544
6546
  const projected = readProjectedMemoryTimeline(this.baseDir, memoryId, cappedLimit);
6545
6547
  if (projected && projected.length > 0) return projected;
6546
- // Loud, rate-limited staleness telemetry (#2119): a fallback here means the
6547
- // projection is missing/empty/stale, so surface HOW stale it is. The lag is
6548
- // computed lazily — only when warnProjectionFallback actually logs (once per
6549
- // interval) — so a hot fallback path pays for a projection meta read at most
6550
- // once per suppression window, not per call.
6551
- warnProjectionFallback(this.baseDir, "getMemoryTimeline", () => {
6552
- const rebuiltAt = readProjectionRebuiltAt(this.baseDir);
6553
- if (!rebuiltAt) return "projection never rebuilt";
6554
- const ageMs = Date.now() - Date.parse(rebuiltAt);
6555
- if (!Number.isFinite(ageMs)) return `projection rebuiltAt=${rebuiltAt}`;
6556
- const ageMin = Math.max(0, Math.round(ageMs / 60_000));
6557
- const age = ageMin >= 120 ? `${Math.round(ageMin / 60)}h` : `${ageMin}m`;
6558
- return `projection ${age} stale, last rebuilt ${rebuiltAt}`;
6559
- });
6560
- return readBoundedLifecycleEventsFromLedger(
6561
- this.memoryLifecycleLedgerPath,
6562
- (p) => this.readStorageSecureFile(p),
6548
+ return this.projectionLedgerLagManager.resolveTimelineWithLag({
6549
+ baseDir: this.baseDir,
6550
+ ledgerPath: this.memoryLifecycleLedgerPath,
6551
+ memoryId,
6563
6552
  cappedLimit,
6564
- memoryId
6565
- );
6553
+ readSecureFile: (p) => this.readStorageSecureFile(p),
6554
+ projectionAge: () => formatProjectionAge(readProjectionRebuiltAt(this.baseDir)),
6555
+ });
6566
6556
  }
6567
6557
 
6568
6558
  // ---------------------------------------------------------------------------
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/maintenance/rebuild-memory-projection.ts"],"sourcesContent":["import path from \"node:path\";\nimport { mkdir, rm, stat } from \"node:fs/promises\";\nimport { StorageManager } from \"../storage.js\";\nimport { log } from \"../logger.js\";\nimport {\n listMemoryGovernanceRuns,\n readMemoryGovernanceRunArtifact,\n} from \"./memory-governance.js\";\nimport { loadPersistedNativeKnowledgeChunks } from \"../native-knowledge.js\";\nimport { toBackupStamp } from \"./backup-stamp.js\";\nimport type {\n MemoryFile,\n MemoryLifecycleEvent,\n MemoryProjectionCurrentState,\n MemoryStatus,\n} from \"../types.js\";\nimport {\n buildLifecycleEventsForMemory,\n inferMemoryStatus,\n MEMORY_LIFECYCLE_EVENT_SORT_ORDER,\n sortMemoryLifecycleEvents,\n toMemoryPathRel,\n} from \"../memory-lifecycle-ledger-utils.js\";\nimport {\n getMemoryProjectionPath,\n initializeMemoryProjectionDb,\n isProjectedMemoryPathValid,\n type ProjectedEntityMentionRow,\n type MemoryProjectionGovernanceAppliedActionRow,\n type MemoryProjectionGovernanceReviewQueueRow,\n type ProjectedNativeKnowledgeChunkRow,\n MEMORY_PROJECTION_SCHEMA_VERSION,\n memoryCurrentSelectExpressions,\n parseCurrentRow,\n readProjectedEntityMentions,\n readProjectedGovernanceRecord,\n readProjectedNativeKnowledgeChunks,\n parseTimelineRows,\n} from \"../memory-projection-store.js\";\nimport {\n normalizeProjectionPreview,\n normalizeProjectionTags,\n} from \"../memory-projection-format.js\";\nimport { openBetterSqlite3 } from \"../runtime/better-sqlite.js\";\nimport { commitPreparedFileAtomically } from \"./atomic-file.js\";\n\nexport interface RebuildMemoryProjectionOptions {\n memoryDir: string;\n /** Reuse the caller's live StorageManager (must be rooted at memoryDir). */\n storage?: StorageManager;\n defaultNamespace?: string;\n dryRun?: boolean;\n now?: Date;\n updatedAfter?: string;\n updatedBefore?: string;\n}\n\nexport type { SkippedBlankIdMemory, SkippedDuplicateMemory } from \"./projection-support.js\";\nimport { assertInjectedStorageRooted } from \"./projection-support.js\";\nimport type { SkippedBlankIdMemory, SkippedDuplicateMemory } from \"./projection-support.js\";\n\nexport interface SkippedDuplicateTimelineEvent {\n eventId: string;\n keptPath: string;\n skippedPath: string;\n}\n\nexport interface SkippedBlankIdTimelineEvent {\n eventId: string;\n path: string;\n}\n\nexport interface RebuildMemoryProjectionResult {\n dryRun: boolean;\n scannedMemories: number;\n currentRows: number;\n timelineRows: number;\n entityMentionRows: number;\n nativeKnowledgeRows: number;\n reviewQueueRows: number;\n outputPath: string;\n backupPath?: string;\n usedLifecycleLedger: boolean;\n skippedDuplicateMemories: SkippedDuplicateMemory[];\n skippedBlankIdMemories: SkippedBlankIdMemory[];\n skippedDuplicateTimelineEvents: SkippedDuplicateTimelineEvent[];\n skippedBlankIdTimelineEvents: SkippedBlankIdTimelineEvent[];\n scope: {\n updatedAfter: string | null;\n updatedBefore: string | null;\n };\n}\n\nexport interface VerifyMemoryProjectionOptions {\n memoryDir: string;\n defaultNamespace?: string;\n updatedAfter?: string;\n updatedBefore?: string;\n}\n\nexport interface VerifyMemoryProjectionResult {\n outputPath: string;\n projectionExists: boolean;\n ok: boolean;\n expectedCurrentRows: number;\n actualCurrentRows: number;\n expectedTimelineRows: number;\n actualTimelineRows: number;\n expectedEntityMentionRows: number;\n actualEntityMentionRows: number;\n expectedNativeKnowledgeRows: number;\n actualNativeKnowledgeRows: number;\n expectedReviewQueueRows: number;\n actualReviewQueueRows: number;\n missingCurrentMemoryIds: string[];\n extraCurrentMemoryIds: string[];\n mismatchedCurrentMemoryIds: string[];\n missingTimelineEventIds: string[];\n extraTimelineEventIds: string[];\n missingEntityMentionKeys: string[];\n extraEntityMentionKeys: string[];\n mismatchedEntityMentionKeys: string[];\n missingNativeKnowledgeChunkIds: string[];\n extraNativeKnowledgeChunkIds: string[];\n mismatchedNativeKnowledgeChunkIds: string[];\n missingReviewQueueEntryIds: string[];\n extraReviewQueueEntryIds: string[];\n mismatchedReviewQueueEntryIds: string[];\n usedLifecycleLedger: boolean;\n scope: {\n updatedAfter: string | null;\n updatedBefore: string | null;\n };\n}\n\nexport interface RepairMemoryProjectionOptions extends RebuildMemoryProjectionOptions {}\n\nexport interface RepairMemoryProjectionResult {\n dryRun: boolean;\n repaired: boolean;\n verify: VerifyMemoryProjectionResult;\n rebuild?: RebuildMemoryProjectionResult;\n}\n\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return typeof err === \"object\" && err !== null && \"code\" in err;\n}\n\nexport async function backupExistingProjection(\n memoryDir: string,\n outputPath: string,\n now: Date,\n): Promise<string | undefined> {\n try {\n await stat(outputPath);\n } catch (err) {\n if (isNodeError(err) && err.code === \"ENOENT\") {\n return undefined;\n }\n throw err;\n }\n\n const backupPath = path.join(\n memoryDir,\n \"archive\",\n \"memory-projection\",\n toBackupStamp(now),\n \"state\",\n \"memory-projection.sqlite\",\n );\n return backupPath;\n}\n\nfunction inferProjectedStatus(pathRel: string, memory: MemoryFile): MemoryStatus {\n return inferMemoryStatus(memory.frontmatter, pathRel);\n}\n\nfunction toCurrentStateRow(memoryDir: string, memory: MemoryFile): MemoryProjectionCurrentState {\n const pathRel = toMemoryPathRel(memoryDir, memory.path);\n return {\n memoryId: memory.frontmatter.id,\n category: memory.frontmatter.category,\n status: inferProjectedStatus(pathRel, memory),\n lifecycleState: memory.frontmatter.lifecycleState,\n path: memory.path,\n pathRel,\n created: memory.frontmatter.created,\n updated: memory.frontmatter.updated,\n archivedAt: memory.frontmatter.archivedAt,\n supersededAt: memory.frontmatter.supersededAt,\n entityRef: memory.frontmatter.entityRef,\n source: memory.frontmatter.source,\n confidence: memory.frontmatter.confidence,\n confidenceTier: memory.frontmatter.confidenceTier,\n memoryKind: memory.frontmatter.memoryKind,\n accessCount: memory.frontmatter.accessCount,\n lastAccessed: memory.frontmatter.lastAccessed,\n tags: normalizeProjectionTags(memory.frontmatter.tags),\n preview: normalizeProjectionPreview(memory.content),\n };\n}\n\nfunction buildEntityMentionRows(\n currentRows: MemoryProjectionCurrentState[],\n): ProjectedEntityMentionRow[] {\n return currentRows.flatMap((row) => {\n const mentions: ProjectedEntityMentionRow[] = [];\n if (row.entityRef) {\n mentions.push({\n memoryId: row.memoryId,\n entityRef: row.entityRef,\n mentionSource: \"frontmatter.entityRef\",\n created: row.created,\n updated: row.updated,\n });\n }\n for (const tag of row.tags ?? []) {\n if (!tag.includes(\":\")) continue;\n mentions.push({\n memoryId: row.memoryId,\n entityRef: tag,\n mentionSource: \"tag\",\n created: row.created,\n updated: row.updated,\n });\n }\n return mentions;\n });\n}\n\nfunction buildGovernanceActionRowKey(action: {\n action: string;\n memoryId: string;\n reasonCode: string;\n originalPath: string;\n currentPath: string;\n}): string {\n return [\n action.action,\n action.memoryId,\n action.reasonCode,\n action.originalPath,\n action.currentPath,\n ].join(\"::\");\n}\n\nasync function loadLatestGovernanceProjection(memoryDir: string): Promise<{\n runId: string;\n summary: unknown;\n metrics: unknown;\n reviewQueueRows: MemoryProjectionGovernanceReviewQueueRow[];\n appliedActionRows: MemoryProjectionGovernanceAppliedActionRow[];\n report: string;\n} | null> {\n const runId = (await listMemoryGovernanceRuns(memoryDir))[0];\n if (!runId) return null;\n try {\n const artifact = await readMemoryGovernanceRunArtifact(memoryDir, runId);\n return {\n runId,\n summary: artifact.summary,\n metrics: artifact.metrics,\n reviewQueueRows: artifact.reviewQueue.map((entry) => ({\n runId,\n entryId: entry.entryId,\n memoryId: entry.memoryId,\n path: entry.path,\n reasonCode: entry.reasonCode,\n severity: entry.severity,\n suggestedAction: entry.suggestedAction,\n suggestedStatus: entry.suggestedStatus,\n relatedMemoryIds: [...entry.relatedMemoryIds],\n })),\n appliedActionRows: artifact.appliedActions.map((action) => ({\n runId,\n rowKey: buildGovernanceActionRowKey(action),\n action: action.action,\n memoryId: action.memoryId,\n reasonCode: action.reasonCode,\n beforeStatus: action.beforeStatus,\n afterStatus: action.afterStatus,\n originalPath: action.originalPath,\n currentPath: action.currentPath,\n })),\n report: artifact.report,\n };\n } catch {\n return null;\n }\n}\n\nfunction loadTimelineEvents(\n memories: MemoryFile[],\n lifecycleEvents: MemoryLifecycleEvent[],\n): { events: MemoryLifecycleEvent[]; usedLifecycleLedger: boolean } {\n if (lifecycleEvents.length > 0) {\n return {\n events: sortMemoryLifecycleEvents(lifecycleEvents),\n usedLifecycleLedger: true,\n };\n }\n\n return {\n events: sortMemoryLifecycleEvents(memories.flatMap((memory) => buildLifecycleEventsForMemory(memory))),\n usedLifecycleLedger: false,\n };\n}\n\nfunction normalizeScopedIso(value: string | undefined): string | null {\n if (!value) return null;\n const trimmed = value.trim();\n if (!trimmed) return null;\n const parsed = new Date(trimmed);\n if (Number.isNaN(parsed.getTime())) {\n throw new Error(`invalid projection scope timestamp: ${value}`);\n }\n return parsed.toISOString();\n}\n\nfunction normalizeProjectionScope(options: {\n updatedAfter?: string;\n updatedBefore?: string;\n}): {\n updatedAfter: string | null;\n updatedBefore: string | null;\n} {\n const updatedAfter = normalizeScopedIso(options.updatedAfter);\n const updatedBefore = normalizeScopedIso(options.updatedBefore);\n if (\n updatedAfter &&\n updatedBefore &&\n new Date(updatedAfter).getTime() > new Date(updatedBefore).getTime()\n ) {\n throw new Error(\"updatedAfter must be less than or equal to updatedBefore\");\n }\n return {\n updatedAfter,\n updatedBefore,\n };\n}\n\nfunction hasScopedProjectionFilter(scope: {\n updatedAfter: string | null;\n updatedBefore: string | null;\n}): boolean {\n return scope.updatedAfter !== null || scope.updatedBefore !== null;\n}\n\nfunction memoryScopeTimestamp(memory: MemoryFile): string {\n const candidate = memory.frontmatter.updated || memory.frontmatter.created;\n return candidate;\n}\n\nfunction isTimestampInProjectionScope(\n timestamp: string,\n scope: { updatedAfter: string | null; updatedBefore: string | null },\n): boolean {\n if (!scope.updatedAfter && !scope.updatedBefore) return true;\n const parsed = new Date(timestamp);\n if (Number.isNaN(parsed.getTime())) return false;\n if (scope.updatedAfter && parsed.getTime() < new Date(scope.updatedAfter).getTime()) return false;\n if (scope.updatedBefore && parsed.getTime() >= new Date(scope.updatedBefore).getTime()) return false;\n return true;\n}\n\nfunction filterMemoriesForProjectionScope(\n memories: MemoryFile[],\n scope: { updatedAfter: string | null; updatedBefore: string | null },\n): MemoryFile[] {\n if (!scope.updatedAfter && !scope.updatedBefore) return memories;\n return memories.filter((memory) => isTimestampInProjectionScope(memoryScopeTimestamp(memory), scope));\n}\n\nfunction filterCurrentStateRowsForProjectionScope(\n rows: MemoryProjectionCurrentState[],\n scope: { updatedAfter: string | null; updatedBefore: string | null },\n): MemoryProjectionCurrentState[] {\n if (!scope.updatedAfter && !scope.updatedBefore) return rows;\n return rows.filter((row) => isTimestampInProjectionScope(row.updated || row.created, scope));\n}\n\nfunction serializeCurrentStateRow(row: MemoryProjectionCurrentState): string {\n return JSON.stringify({\n memoryId: row.memoryId,\n category: row.category,\n status: row.status,\n lifecycleState: row.lifecycleState ?? null,\n pathRel: row.pathRel,\n created: row.created,\n updated: row.updated,\n archivedAt: row.archivedAt ?? null,\n supersededAt: row.supersededAt ?? null,\n entityRef: row.entityRef ?? null,\n source: row.source,\n confidence: row.confidence,\n confidenceTier: row.confidenceTier,\n memoryKind: row.memoryKind ?? null,\n accessCount: row.accessCount ?? null,\n lastAccessed: row.lastAccessed ?? null,\n tags: row.tags ?? [],\n preview: row.preview ?? \"\",\n });\n}\n\nfunction serializeTimelineEvent(event: MemoryLifecycleEvent): string {\n return JSON.stringify({\n eventId: event.eventId,\n memoryId: event.memoryId,\n eventType: event.eventType,\n timestamp: event.timestamp,\n actor: event.actor,\n reasonCode: event.reasonCode ?? null,\n ruleVersion: event.ruleVersion,\n relatedMemoryIds: event.relatedMemoryIds ?? [],\n before: event.before ?? null,\n after: event.after ?? null,\n correlationId: event.correlationId ?? null,\n });\n}\n\nfunction serializeEntityMentionRow(row: ProjectedEntityMentionRow): string {\n return JSON.stringify(row);\n}\n\nfunction serializeNativeKnowledgeRow(row: ProjectedNativeKnowledgeChunkRow): string {\n return JSON.stringify({\n chunkId: row.chunkId,\n sourceKind: row.sourceKind,\n sourcePath: row.sourcePath,\n title: row.title,\n startLine: row.startLine,\n endLine: row.endLine,\n namespace: row.namespace ?? null,\n privacyClass: row.privacyClass ?? null,\n derivedDate: row.derivedDate ?? null,\n sessionKey: row.sessionKey ?? null,\n workflowKey: row.workflowKey ?? null,\n author: row.author ?? null,\n agent: row.agent ?? null,\n sourceHash: row.sourceHash ?? null,\n preview: row.preview,\n });\n}\n\nfunction serializeGovernanceReviewQueueRow(\n row: MemoryProjectionGovernanceReviewQueueRow,\n): string {\n return JSON.stringify({\n runId: row.runId,\n entryId: row.entryId,\n memoryId: row.memoryId,\n path: row.path,\n reasonCode: row.reasonCode,\n severity: row.severity,\n suggestedAction: row.suggestedAction,\n suggestedStatus: row.suggestedStatus ?? null,\n relatedMemoryIds: row.relatedMemoryIds,\n });\n}\n\nfunction selectProjectionMemories(\n tiers: MemoryFile[][],\n): {\n allMemories: MemoryFile[];\n memories: MemoryFile[];\n skippedDuplicateMemories: SkippedDuplicateMemory[];\n skippedBlankIdMemories: SkippedBlankIdMemory[];\n} {\n const allMemories = tiers.flat();\n const memories: MemoryFile[] = [];\n const keptById = new Map<string, MemoryFile>();\n const skippedDuplicateMemories: SkippedDuplicateMemory[] = [];\n const skippedBlankIdMemories: SkippedBlankIdMemory[] = [];\n\n // Tier order is authoritative: hot wins over cold, and cold wins over archive.\n // Paths break ties within a tier so the winner does not depend on readdir order.\n for (const tier of tiers) {\n for (const memory of [...tier].sort((left, right) => left.path.localeCompare(right.path))) {\n const memoryId = memory.frontmatter.id.trim();\n if (!memoryId) {\n skippedBlankIdMemories.push({ path: memory.path });\n log.warn(`projection rebuild skipped blank memory id: path=${memory.path}`);\n continue;\n }\n const kept = keptById.get(memoryId);\n if (kept) {\n skippedDuplicateMemories.push({\n memoryId,\n keptPath: kept.path,\n skippedPath: memory.path,\n });\n log.warn(\n `projection rebuild skipped duplicate memory id=${memoryId}: kept=${kept.path} skipped=${memory.path}`,\n );\n continue;\n }\n keptById.set(memoryId, memory);\n memories.push(memory);\n }\n }\n\n return { allMemories, memories, skippedDuplicateMemories, skippedBlankIdMemories };\n}\n\nfunction deduplicateTimelineEvents(\n events: MemoryLifecycleEvent[],\n sourcePathFor: (event: MemoryLifecycleEvent) => string,\n): {\n events: MemoryLifecycleEvent[];\n skipped: SkippedDuplicateTimelineEvent[];\n skippedBlankIds: SkippedBlankIdTimelineEvent[];\n} {\n const keptById = new Map<string, { event: MemoryLifecycleEvent; path: string }>();\n const unique: MemoryLifecycleEvent[] = [];\n const skipped: SkippedDuplicateTimelineEvent[] = [];\n const skippedBlankIds: SkippedBlankIdTimelineEvent[] = [];\n for (const event of sortMemoryLifecycleEvents(events)) {\n const sourcePath = sourcePathFor(event);\n if (!event.memoryId.trim()) {\n skippedBlankIds.push({ eventId: event.eventId, path: sourcePath });\n log.warn(\n `projection rebuild skipped timeline event with blank memory id: `\n + `event_id=${event.eventId} path=${sourcePath}`,\n );\n continue;\n }\n const kept = keptById.get(event.eventId);\n if (kept) {\n skipped.push({\n eventId: event.eventId,\n keptPath: kept.path,\n skippedPath: sourcePath,\n });\n log.warn(\n `projection rebuild skipped duplicate timeline event_id=${event.eventId}: `\n + `kept=${kept.path} skipped=${sourcePath}`,\n );\n continue;\n }\n keptById.set(event.eventId, { event, path: sourcePath });\n unique.push(event);\n }\n return { events: unique, skipped, skippedBlankIds };\n}\n\nasync function loadAuthoritativeProjectionSnapshot(options: {\n memoryDir: string;\n defaultNamespace?: string;\n storage?: StorageManager;\n updatedAfter?: string;\n updatedBefore?: string;\n}): Promise<{\n allMemories: MemoryFile[];\n currentRows: MemoryProjectionCurrentState[];\n timelineRows: MemoryLifecycleEvent[];\n scopedCurrentRows: MemoryProjectionCurrentState[];\n scopedTimelineRows: MemoryLifecycleEvent[];\n entityMentionRows: ProjectedEntityMentionRow[];\n scopedEntityMentionRows: ProjectedEntityMentionRow[];\n nativeKnowledgeRows: ProjectedNativeKnowledgeChunkRow[];\n governance:\n | {\n runId: string;\n summary: unknown;\n metrics: unknown;\n reviewQueueRows: MemoryProjectionGovernanceReviewQueueRow[];\n appliedActionRows: MemoryProjectionGovernanceAppliedActionRow[];\n report: string;\n }\n | null;\n usedLifecycleLedger: boolean;\n scope: {\n updatedAfter: string | null;\n updatedBefore: string | null;\n };\n skippedDuplicateMemories: SkippedDuplicateMemory[];\n skippedBlankIdMemories: SkippedBlankIdMemory[];\n skippedDuplicateTimelineEvents: SkippedDuplicateTimelineEvent[];\n skippedBlankIdTimelineEvents: SkippedBlankIdTimelineEvent[];\n}> {\n const storage = assertInjectedStorageRooted(\"rebuildMemoryProjection\", options.memoryDir, options.storage) ?? new StorageManager(options.memoryDir);\n // Force a fresh disk read — projection verify/rebuild must see the true\n // on-disk state, not a potentially stale in-process cache.\n storage.invalidateAllMemoriesCacheForDir();\n const selected = selectProjectionMemories([\n await storage.readAllMemories(),\n await storage.readAllColdMemories(),\n await storage.readArchivedMemories(),\n ]);\n const allMemories = selected.allMemories;\n const projectionMemories = selected.memories;\n const lifecycleEvents = await storage.readAllMemoryLifecycleEvents();\n const timeline = loadTimelineEvents(projectionMemories, lifecycleEvents);\n const lifecycleLedgerPath = path.join(\n options.memoryDir,\n \"state\",\n \"memory-lifecycle-ledger.jsonl\",\n );\n const memoryPathById = new Map(\n projectionMemories.map((memory) => [memory.frontmatter.id, memory.path]),\n );\n const deduplicatedTimeline = deduplicateTimelineEvents(\n timeline.events,\n (event) => timeline.usedLifecycleLedger\n ? lifecycleLedgerPath\n : memoryPathById.get(event.memoryId) ?? lifecycleLedgerPath,\n );\n const events = deduplicatedTimeline.events;\n const usedLifecycleLedger = timeline.usedLifecycleLedger;\n const currentRows = projectionMemories.map((memory) => toCurrentStateRow(options.memoryDir, memory));\n const scope = normalizeProjectionScope(options);\n const scopedMemories = filterMemoriesForProjectionScope(projectionMemories, scope);\n const scopedMemoryIds = new Set(scopedMemories.map((memory) => memory.frontmatter.id));\n const nativeKnowledgeRows = await loadPersistedNativeKnowledgeChunks({\n memoryDir: options.memoryDir,\n defaultNamespace: options.defaultNamespace ?? \"default\",\n }).then((rows) => rows.map((row) => ({\n chunkId: row.chunkId,\n sourceKind: row.sourceKind,\n sourcePath: row.sourcePath,\n title: row.title,\n startLine: row.startLine,\n endLine: row.endLine,\n namespace: row.namespace ?? options.defaultNamespace ?? \"default\",\n privacyClass: row.privacyClass,\n derivedDate: row.derivedDate,\n sessionKey: row.sessionKey,\n workflowKey: row.workflowKey,\n author: row.author,\n agent: row.agent,\n sourceHash: row.sourceHash,\n preview: normalizeProjectionPreview(row.content),\n })));\n const governance = await loadLatestGovernanceProjection(options.memoryDir);\n const entityMentionRows = buildEntityMentionRows(currentRows);\n\n return {\n allMemories,\n currentRows,\n timelineRows: events,\n scopedCurrentRows: currentRows.filter((row) => scopedMemoryIds.has(row.memoryId)),\n scopedTimelineRows: events.filter((event) => scopedMemoryIds.has(event.memoryId)),\n entityMentionRows,\n scopedEntityMentionRows: entityMentionRows.filter((row) => scopedMemoryIds.has(row.memoryId)),\n nativeKnowledgeRows,\n governance,\n usedLifecycleLedger,\n scope,\n skippedDuplicateMemories: selected.skippedDuplicateMemories,\n skippedBlankIdMemories: selected.skippedBlankIdMemories,\n skippedDuplicateTimelineEvents: deduplicatedTimeline.skipped,\n skippedBlankIdTimelineEvents: deduplicatedTimeline.skippedBlankIds,\n };\n}\n\nfunction readProjectedCurrentRows(\n memoryDir: string,\n): { projectionExists: boolean; rows: MemoryProjectionCurrentState[] } {\n const dbPath = getMemoryProjectionPath(memoryDir);\n try {\n const db = openBetterSqlite3(dbPath, { readonly: true, fileMustExist: true });\n try {\n const selectExpressions = memoryCurrentSelectExpressions(db);\n const rows = db.prepare(`\n SELECT\n memory_id,\n category,\n status,\n lifecycle_state,\n path_rel,\n created_at,\n updated_at,\n archived_at,\n superseded_at,\n entity_ref,\n source,\n confidence,\n confidence_tier,\n memory_kind,\n access_count,\n last_accessed,\n ${selectExpressions.tagsJson},\n ${selectExpressions.previewText}\n FROM memory_current\n `).all() as Array<Record<string, unknown>>;\n\n return {\n projectionExists: true,\n rows: rows\n .map((row) => parseCurrentRow(memoryDir, row))\n .filter((row): row is MemoryProjectionCurrentState => row !== null),\n };\n } finally {\n db.close();\n }\n } catch {\n return { projectionExists: false, rows: [] };\n }\n}\n\nfunction readProjectedTimelineRows(\n memoryDir: string,\n): { projectionExists: boolean; rows: MemoryLifecycleEvent[] } {\n const dbPath = getMemoryProjectionPath(memoryDir);\n try {\n const db = openBetterSqlite3(dbPath, { readonly: true, fileMustExist: true });\n try {\n const rows = db.prepare(`\n SELECT\n event_id,\n memory_id,\n event_type,\n timestamp,\n actor,\n reason_code,\n rule_version,\n related_memory_ids_json,\n before_json,\n after_json,\n correlation_id\n FROM memory_timeline\n `).all() as Array<Record<string, unknown>>;\n\n return {\n projectionExists: true,\n rows: parseTimelineRows(rows),\n };\n } finally {\n db.close();\n }\n } catch {\n return { projectionExists: false, rows: [] };\n }\n}\n\nfunction readProjectedEntityMentionRows(\n memoryDir: string,\n): { projectionExists: boolean; rows: ProjectedEntityMentionRow[] } {\n const rows = readProjectedEntityMentions(memoryDir);\n if (rows === null) return { projectionExists: false, rows: [] };\n return { projectionExists: true, rows };\n}\n\nfunction readProjectedNativeKnowledgeRows(\n memoryDir: string,\n): { projectionExists: boolean; rows: ProjectedNativeKnowledgeChunkRow[] } {\n const rows = readProjectedNativeKnowledgeChunks(memoryDir);\n if (rows === null) return { projectionExists: false, rows: [] };\n return { projectionExists: true, rows };\n}\n\nfunction readProjectedGovernanceRows(memoryDir: string): {\n projectionExists: boolean;\n runId: string | null;\n summary: unknown;\n metrics: unknown;\n reviewQueueRows: MemoryProjectionGovernanceReviewQueueRow[];\n appliedActionRows: MemoryProjectionGovernanceAppliedActionRow[];\n report: string;\n} {\n const record = readProjectedGovernanceRecord(memoryDir);\n if (record === null) {\n return {\n projectionExists: false,\n runId: null,\n summary: undefined,\n metrics: undefined,\n reviewQueueRows: [],\n appliedActionRows: [],\n report: \"\",\n };\n }\n return {\n projectionExists: true,\n runId: record.runId,\n summary: record.summary,\n metrics: record.metrics,\n reviewQueueRows: record.reviewQueueRows,\n appliedActionRows: record.appliedActionRows,\n report: record.report,\n };\n}\n\nfunction writeProjectionDb(\n dbPath: string,\n nowIso: string,\n currentRows: MemoryProjectionCurrentState[],\n timelineRows: MemoryLifecycleEvent[],\n entityMentionRows: ProjectedEntityMentionRow[],\n nativeKnowledgeRows: ProjectedNativeKnowledgeChunkRow[],\n governance: Awaited<ReturnType<typeof loadLatestGovernanceProjection>>,\n usedLifecycleLedger: boolean,\n): void {\n const db = openBetterSqlite3(dbPath);\n const memoryDir = path.dirname(path.dirname(dbPath));\n try {\n initializeMemoryProjectionDb(db);\n\n const insertMeta = db.prepare(\"INSERT OR REPLACE INTO meta(key, value) VALUES (?, ?)\");\n insertMeta.run(\"schemaVersion\", String(MEMORY_PROJECTION_SCHEMA_VERSION));\n insertMeta.run(\"rebuiltAt\", nowIso);\n insertMeta.run(\"usedLifecycleLedger\", usedLifecycleLedger ? \"true\" : \"false\");\n insertMeta.run(\"latestGovernanceRunId\", governance?.runId ?? \"\");\n\n const insertCurrent = db.prepare(`\n INSERT INTO memory_current (\n memory_id,\n category,\n status,\n lifecycle_state,\n path_rel,\n path_valid,\n created_at,\n updated_at,\n archived_at,\n superseded_at,\n entity_ref,\n source,\n confidence,\n confidence_tier,\n memory_kind,\n access_count,\n last_accessed,\n tags_json,\n preview_text\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const insertTimeline = db.prepare(`\n INSERT INTO memory_timeline (\n event_id,\n memory_id,\n event_type,\n timestamp,\n event_order,\n actor,\n reason_code,\n rule_version,\n related_memory_ids_json,\n before_json,\n after_json,\n correlation_id\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const insertEntityMention = db.prepare(`\n INSERT INTO memory_entity_mentions (\n memory_id,\n entity_ref,\n mention_source,\n created_at,\n updated_at\n ) VALUES (?, ?, ?, ?, ?)\n `);\n\n const insertNativeKnowledge = db.prepare(`\n INSERT INTO native_knowledge_chunks (\n chunk_id,\n source_kind,\n source_path,\n title,\n start_line,\n end_line,\n namespace,\n privacy_class,\n derived_date,\n session_key,\n workflow_key,\n author,\n agent,\n source_hash,\n preview_text\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const insertGovernanceReviewQueue = db.prepare(`\n INSERT INTO memory_review_queue (\n entry_id,\n run_id,\n memory_id,\n path,\n reason_code,\n severity,\n suggested_action,\n suggested_status,\n related_memory_ids_json\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const insertGovernanceAppliedAction = db.prepare(`\n INSERT INTO memory_review_actions (\n row_key,\n run_id,\n action,\n memory_id,\n reason_code,\n before_status,\n after_status,\n original_path,\n current_path\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n const insertGovernanceRun = db.prepare(`\n INSERT INTO memory_review_runs (\n run_id,\n created_at,\n mode,\n summary_json,\n metrics_json,\n applied_actions_json,\n report_markdown\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n `);\n\n const writeTx = db.transaction(() => {\n for (const row of currentRows) {\n insertCurrent.run(\n row.memoryId,\n row.category,\n row.status,\n row.lifecycleState ?? null,\n row.pathRel,\n isProjectedMemoryPathValid(memoryDir, row.pathRel) ? 1 : 0,\n row.created,\n row.updated,\n row.archivedAt ?? null,\n row.supersededAt ?? null,\n row.entityRef ?? null,\n row.source,\n row.confidence,\n row.confidenceTier,\n row.memoryKind ?? null,\n row.accessCount ?? null,\n row.lastAccessed ?? null,\n JSON.stringify(row.tags ?? []),\n row.preview ?? \"\",\n );\n }\n\n for (const event of timelineRows) {\n insertTimeline.run(\n event.eventId,\n event.memoryId,\n event.eventType,\n event.timestamp,\n MEMORY_LIFECYCLE_EVENT_SORT_ORDER[event.eventType],\n event.actor,\n event.reasonCode ?? null,\n event.ruleVersion,\n JSON.stringify(event.relatedMemoryIds ?? []),\n event.before ? JSON.stringify(event.before) : null,\n event.after ? JSON.stringify(event.after) : null,\n event.correlationId ?? null,\n );\n }\n\n for (const row of entityMentionRows) {\n insertEntityMention.run(\n row.memoryId,\n row.entityRef,\n row.mentionSource,\n row.created,\n row.updated,\n );\n }\n\n for (const row of nativeKnowledgeRows) {\n insertNativeKnowledge.run(\n row.chunkId,\n row.sourceKind,\n row.sourcePath,\n row.title,\n row.startLine,\n row.endLine,\n row.namespace ?? null,\n row.privacyClass ?? null,\n row.derivedDate ?? null,\n row.sessionKey ?? null,\n row.workflowKey ?? null,\n row.author ?? null,\n row.agent ?? null,\n row.sourceHash ?? null,\n row.preview,\n );\n }\n\n for (const row of governance?.reviewQueueRows ?? []) {\n insertGovernanceReviewQueue.run(\n row.entryId,\n row.runId,\n row.memoryId,\n row.path,\n row.reasonCode,\n row.severity,\n row.suggestedAction,\n row.suggestedStatus ?? null,\n JSON.stringify(row.relatedMemoryIds),\n );\n }\n\n for (const row of governance?.appliedActionRows ?? []) {\n insertGovernanceAppliedAction.run(\n row.rowKey,\n row.runId,\n row.action,\n row.memoryId,\n row.reasonCode,\n row.beforeStatus,\n row.afterStatus ?? null,\n row.originalPath,\n row.currentPath,\n );\n }\n\n if (governance) {\n const createdAt =\n typeof (governance.summary as { createdAt?: unknown } | undefined)?.createdAt === \"string\"\n ? (governance.summary as { createdAt: string }).createdAt\n : nowIso;\n const mode =\n typeof (governance.summary as { mode?: unknown } | undefined)?.mode === \"string\"\n ? (governance.summary as { mode: string }).mode\n : \"shadow\";\n insertGovernanceRun.run(\n governance.runId,\n createdAt,\n mode,\n JSON.stringify(governance.summary ?? null),\n JSON.stringify(governance.metrics ?? null),\n JSON.stringify(\n (governance.appliedActionRows ?? []).map((row) => ({\n action: row.action,\n memoryId: row.memoryId,\n reasonCode: row.reasonCode,\n beforeStatus: row.beforeStatus,\n afterStatus: row.afterStatus,\n originalPath: row.originalPath,\n currentPath: row.currentPath,\n })),\n ),\n governance.report,\n );\n }\n });\n\n writeTx();\n } finally {\n db.close();\n }\n}\n\nfunction mergeScopedCurrentRows(\n existingRows: MemoryProjectionCurrentState[],\n replacementRows: MemoryProjectionCurrentState[],\n scopedMemoryIds: Set<string>,\n): MemoryProjectionCurrentState[] {\n return [...existingRows.filter((row) => !scopedMemoryIds.has(row.memoryId)), ...replacementRows]\n .sort((a, b) => a.memoryId.localeCompare(b.memoryId));\n}\n\nfunction mergeScopedTimelineRows(\n existingRows: MemoryLifecycleEvent[],\n replacementRows: MemoryLifecycleEvent[],\n scopedMemoryIds: Set<string>,\n): MemoryLifecycleEvent[] {\n return sortMemoryLifecycleEvents([\n ...existingRows.filter((event) => !scopedMemoryIds.has(event.memoryId)),\n ...replacementRows,\n ]);\n}\n\nfunction mergeScopedEntityMentionRows(\n existingRows: ProjectedEntityMentionRow[],\n replacementRows: ProjectedEntityMentionRow[],\n scopedMemoryIds: Set<string>,\n): ProjectedEntityMentionRow[] {\n return [\n ...existingRows.filter((row) => !scopedMemoryIds.has(row.memoryId)),\n ...replacementRows,\n ].sort((left, right) =>\n [left.entityRef, left.memoryId, left.mentionSource].join(\"::\").localeCompare(\n [right.entityRef, right.memoryId, right.mentionSource].join(\"::\"),\n )\n );\n}\n\nexport async function rebuildMemoryProjection(\n options: RebuildMemoryProjectionOptions,\n): Promise<RebuildMemoryProjectionResult> {\n const dryRun = options.dryRun !== false;\n const now = options.now ?? new Date();\n const outputPath = getMemoryProjectionPath(options.memoryDir);\n const snapshot = await loadAuthoritativeProjectionSnapshot(options);\n\n let backupPath: string | undefined;\n if (!dryRun) {\n let nextCurrentRows = snapshot.currentRows;\n let nextTimelineRows = snapshot.timelineRows;\n let nextEntityMentionRows = snapshot.entityMentionRows;\n let nextNativeKnowledgeRows = snapshot.nativeKnowledgeRows;\n let nextGovernance = snapshot.governance;\n if (hasScopedProjectionFilter(snapshot.scope)) {\n nextCurrentRows = snapshot.scopedCurrentRows;\n nextTimelineRows = snapshot.scopedTimelineRows;\n nextEntityMentionRows = snapshot.scopedEntityMentionRows;\n const projectedCurrent = readProjectedCurrentRows(options.memoryDir);\n const projectedTimeline = readProjectedTimelineRows(options.memoryDir);\n const projectedEntityMentions = readProjectedEntityMentionRows(options.memoryDir);\n const projectedNativeKnowledge = readProjectedNativeKnowledgeRows(options.memoryDir);\n const projectedGovernance = readProjectedGovernanceRows(options.memoryDir);\n if (projectedCurrent.projectionExists && projectedTimeline.projectionExists) {\n const actualScopedCurrentRows = filterCurrentStateRowsForProjectionScope(\n projectedCurrent.rows,\n snapshot.scope,\n );\n const scopedMemoryIds = new Set([\n ...snapshot.scopedCurrentRows.map((row) => row.memoryId),\n ...snapshot.scopedTimelineRows.map((event) => event.memoryId),\n ...actualScopedCurrentRows.map((row) => row.memoryId),\n ]);\n nextCurrentRows = mergeScopedCurrentRows(\n projectedCurrent.rows,\n snapshot.scopedCurrentRows,\n scopedMemoryIds,\n );\n nextTimelineRows = mergeScopedTimelineRows(\n projectedTimeline.rows,\n snapshot.scopedTimelineRows,\n scopedMemoryIds,\n );\n nextEntityMentionRows = mergeScopedEntityMentionRows(\n projectedEntityMentions.rows,\n snapshot.scopedEntityMentionRows,\n scopedMemoryIds,\n );\n }\n if (projectedNativeKnowledge.projectionExists) {\n // Native knowledge rows are always loaded from the full persisted sync state,\n // so scoped memory rebuilds should publish the fresh snapshot instead of\n // pinning the projection to stale previously projected rows.\n nextNativeKnowledgeRows = snapshot.nativeKnowledgeRows;\n }\n if (projectedGovernance.projectionExists && projectedGovernance.runId) {\n // Governance rows are also sourced from standalone artifact snapshots, so\n // scoped memory rebuilds should keep the latest governance artifact data\n // instead of restoring whatever happened to be in the prior projection.\n nextGovernance = snapshot.governance;\n }\n }\n\n const tempPath = `${outputPath}.tmp`;\n await mkdir(path.dirname(outputPath), { recursive: true });\n await rm(tempPath, { force: true });\n writeProjectionDb(\n tempPath,\n now.toISOString(),\n nextCurrentRows,\n nextTimelineRows,\n nextEntityMentionRows,\n nextNativeKnowledgeRows,\n nextGovernance,\n snapshot.usedLifecycleLedger,\n );\n backupPath = await backupExistingProjection(options.memoryDir, outputPath, now);\n backupPath = await commitPreparedFileAtomically(tempPath, outputPath, backupPath);\n }\n\n return {\n dryRun,\n scannedMemories: snapshot.allMemories.length,\n currentRows: snapshot.scopedCurrentRows.length,\n timelineRows: snapshot.scopedTimelineRows.length,\n entityMentionRows: snapshot.scopedEntityMentionRows.length,\n nativeKnowledgeRows: snapshot.nativeKnowledgeRows.length,\n reviewQueueRows: snapshot.governance?.reviewQueueRows.length ?? 0,\n outputPath,\n backupPath,\n usedLifecycleLedger: snapshot.usedLifecycleLedger,\n skippedDuplicateMemories: snapshot.skippedDuplicateMemories,\n skippedBlankIdMemories: snapshot.skippedBlankIdMemories,\n skippedDuplicateTimelineEvents: snapshot.skippedDuplicateTimelineEvents,\n skippedBlankIdTimelineEvents: snapshot.skippedBlankIdTimelineEvents,\n scope: snapshot.scope,\n };\n}\n\nexport async function verifyMemoryProjection(\n options: VerifyMemoryProjectionOptions,\n): Promise<VerifyMemoryProjectionResult> {\n const outputPath = getMemoryProjectionPath(options.memoryDir);\n const snapshot = await loadAuthoritativeProjectionSnapshot(options);\n const projectedCurrent = readProjectedCurrentRows(options.memoryDir);\n const projectedTimeline = readProjectedTimelineRows(options.memoryDir);\n const projectedEntityMentions = readProjectedEntityMentionRows(options.memoryDir);\n const projectedNativeKnowledge = readProjectedNativeKnowledgeRows(options.memoryDir);\n const projectedGovernance = readProjectedGovernanceRows(options.memoryDir);\n const projectionExists = projectedCurrent.projectionExists\n || projectedTimeline.projectionExists\n || projectedEntityMentions.projectionExists\n || projectedNativeKnowledge.projectionExists\n || projectedGovernance.projectionExists;\n\n const actualScopedCurrentRows = filterCurrentStateRowsForProjectionScope(projectedCurrent.rows, snapshot.scope);\n const expectedCurrentById = new Map(\n snapshot.scopedCurrentRows.map((row) => [row.memoryId, serializeCurrentStateRow(row)]),\n );\n const actualCurrentById = new Map(\n actualScopedCurrentRows.map((row) => [row.memoryId, serializeCurrentStateRow(row)]),\n );\n\n const missingCurrentMemoryIds = [...expectedCurrentById.keys()]\n .filter((memoryId) => !actualCurrentById.has(memoryId))\n .sort();\n const extraCurrentMemoryIds = [...actualCurrentById.keys()]\n .filter((memoryId) => !expectedCurrentById.has(memoryId))\n .sort();\n const mismatchedCurrentMemoryIds = [...expectedCurrentById.keys()]\n .filter((memoryId) =>\n actualCurrentById.has(memoryId) && actualCurrentById.get(memoryId) !== expectedCurrentById.get(memoryId)\n )\n .sort();\n\n const selectedMemoryIds = new Set([\n ...snapshot.scopedCurrentRows.map((row) => row.memoryId),\n ...actualScopedCurrentRows.map((row) => row.memoryId),\n ]);\n const expectedTimelineById = new Map(\n snapshot.scopedTimelineRows.map((event) => [event.eventId, serializeTimelineEvent(event)]),\n );\n const actualTimelineRows = projectedTimeline.rows.filter((event) => selectedMemoryIds.has(event.memoryId));\n const actualTimelineById = new Map(\n actualTimelineRows.map((event) => [event.eventId, serializeTimelineEvent(event)]),\n );\n const missingTimelineEventIds = [...expectedTimelineById.keys()]\n .filter((eventId) => !actualTimelineById.has(eventId))\n .sort();\n const extraTimelineEventIds = [...actualTimelineById.keys()]\n .filter((eventId) => !expectedTimelineById.has(eventId))\n .sort();\n\n const expectedEntityMentionsByKey = new Map(\n snapshot.scopedEntityMentionRows.map((row) => [\n `${row.memoryId}::${row.entityRef}::${row.mentionSource}`,\n serializeEntityMentionRow(row),\n ]),\n );\n const actualScopedEntityMentionRows = projectedEntityMentions.rows.filter((row) => selectedMemoryIds.has(row.memoryId));\n const actualEntityMentionsByKey = new Map(\n actualScopedEntityMentionRows.map((row) => [\n `${row.memoryId}::${row.entityRef}::${row.mentionSource}`,\n serializeEntityMentionRow(row),\n ]),\n );\n const missingEntityMentionKeys = [...expectedEntityMentionsByKey.keys()]\n .filter((key) => !actualEntityMentionsByKey.has(key))\n .sort();\n const extraEntityMentionKeys = [...actualEntityMentionsByKey.keys()]\n .filter((key) => !expectedEntityMentionsByKey.has(key))\n .sort();\n const mismatchedEntityMentionKeys = [...expectedEntityMentionsByKey.keys()]\n .filter((key) =>\n actualEntityMentionsByKey.has(key) && actualEntityMentionsByKey.get(key) !== expectedEntityMentionsByKey.get(key)\n )\n .sort();\n\n const expectedNativeKnowledgeById = new Map(\n snapshot.nativeKnowledgeRows.map((row) => [row.chunkId, serializeNativeKnowledgeRow(row)]),\n );\n const actualNativeKnowledgeById = new Map(\n projectedNativeKnowledge.rows.map((row) => [row.chunkId, serializeNativeKnowledgeRow(row)]),\n );\n const missingNativeKnowledgeChunkIds = [...expectedNativeKnowledgeById.keys()]\n .filter((chunkId) => !actualNativeKnowledgeById.has(chunkId))\n .sort();\n const extraNativeKnowledgeChunkIds = [...actualNativeKnowledgeById.keys()]\n .filter((chunkId) => !expectedNativeKnowledgeById.has(chunkId))\n .sort();\n const mismatchedNativeKnowledgeChunkIds = [...expectedNativeKnowledgeById.keys()]\n .filter((chunkId) =>\n actualNativeKnowledgeById.has(chunkId) && actualNativeKnowledgeById.get(chunkId) !== expectedNativeKnowledgeById.get(chunkId)\n )\n .sort();\n\n const expectedReviewQueueById = new Map(\n (snapshot.governance?.reviewQueueRows ?? []).map((row) => [\n `${row.runId}::${row.entryId}`,\n serializeGovernanceReviewQueueRow(row),\n ]),\n );\n const actualReviewQueueById = new Map(\n projectedGovernance.reviewQueueRows.map((row) => [\n `${row.runId}::${row.entryId}`,\n serializeGovernanceReviewQueueRow(row),\n ]),\n );\n const missingReviewQueueEntryIds = [...expectedReviewQueueById.keys()]\n .filter((entryId) => !actualReviewQueueById.has(entryId))\n .sort();\n const extraReviewQueueEntryIds = [...actualReviewQueueById.keys()]\n .filter((entryId) => !expectedReviewQueueById.has(entryId))\n .sort();\n const mismatchedReviewQueueEntryIds = [...expectedReviewQueueById.keys()]\n .filter((entryId) =>\n actualReviewQueueById.has(entryId) && actualReviewQueueById.get(entryId) !== expectedReviewQueueById.get(entryId)\n )\n .sort();\n\n return {\n outputPath,\n projectionExists,\n ok:\n projectionExists &&\n missingCurrentMemoryIds.length === 0 &&\n extraCurrentMemoryIds.length === 0 &&\n mismatchedCurrentMemoryIds.length === 0 &&\n missingTimelineEventIds.length === 0 &&\n extraTimelineEventIds.length === 0 &&\n missingEntityMentionKeys.length === 0 &&\n extraEntityMentionKeys.length === 0 &&\n mismatchedEntityMentionKeys.length === 0 &&\n missingNativeKnowledgeChunkIds.length === 0 &&\n extraNativeKnowledgeChunkIds.length === 0 &&\n mismatchedNativeKnowledgeChunkIds.length === 0 &&\n missingReviewQueueEntryIds.length === 0 &&\n extraReviewQueueEntryIds.length === 0 &&\n mismatchedReviewQueueEntryIds.length === 0,\n expectedCurrentRows: snapshot.scopedCurrentRows.length,\n actualCurrentRows: actualScopedCurrentRows.length,\n expectedTimelineRows: snapshot.scopedTimelineRows.length,\n actualTimelineRows: actualTimelineRows.length,\n expectedEntityMentionRows: snapshot.scopedEntityMentionRows.length,\n actualEntityMentionRows: actualScopedEntityMentionRows.length,\n expectedNativeKnowledgeRows: snapshot.nativeKnowledgeRows.length,\n actualNativeKnowledgeRows: projectedNativeKnowledge.rows.length,\n expectedReviewQueueRows: snapshot.governance?.reviewQueueRows.length ?? 0,\n actualReviewQueueRows: projectedGovernance.reviewQueueRows.length,\n missingCurrentMemoryIds,\n extraCurrentMemoryIds,\n mismatchedCurrentMemoryIds,\n missingTimelineEventIds,\n extraTimelineEventIds,\n missingEntityMentionKeys,\n extraEntityMentionKeys,\n mismatchedEntityMentionKeys,\n missingNativeKnowledgeChunkIds,\n extraNativeKnowledgeChunkIds,\n mismatchedNativeKnowledgeChunkIds,\n missingReviewQueueEntryIds,\n extraReviewQueueEntryIds,\n mismatchedReviewQueueEntryIds,\n usedLifecycleLedger: snapshot.usedLifecycleLedger,\n scope: snapshot.scope,\n };\n}\n\nexport async function repairMemoryProjection(\n options: RepairMemoryProjectionOptions,\n): Promise<RepairMemoryProjectionResult> {\n const dryRun = options.dryRun !== false;\n const verify = await verifyMemoryProjection(options);\n if (verify.ok) {\n return {\n dryRun,\n repaired: false,\n verify,\n };\n }\n if (dryRun) {\n return {\n dryRun: true,\n repaired: false,\n verify,\n };\n }\n\n const rebuild = await rebuildMemoryProjection({\n ...options,\n dryRun: false,\n });\n const verified = await verifyMemoryProjection(options);\n return {\n dryRun: false,\n repaired: verified.ok,\n verify: verified,\n rebuild,\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/storage-guards.ts"],"sourcesContent":["import { log } from \"./logger.js\";\n\nconst PROJECTION_FALLBACK_WARN_INTERVAL_MS = 5 * 60_000;\nconst projectionFallbackWarnedAt = new Map<string, number>();\n\nexport function assertMemoryFrontmatterId(\n fm: { id: string; category?: string; created?: string; entityRef?: string },\n): void {\n if (typeof fm.id !== \"string\" || fm.id.trim().length === 0) {\n const context = [\n fm.category ? `category=${fm.category}` : null,\n fm.created ? `created=${fm.created}` : null,\n fm.entityRef ? `entityRef=${fm.entityRef}` : null,\n ].filter(Boolean).join(\" \");\n throw new Error(\n `memory frontmatter id must not be blank${context ? ` (${context})` : \"\"}`,\n );\n }\n}\n\nexport function warnProjectionFallback(\n memoryDir: string,\n consumer: string,\n // Lazy so the (potentially I/O-bound) lag computation runs only when this\n // call actually logs, not on every rate-limited-suppressed fallback (#2119).\n detail?: () => string | undefined,\n): null {\n const key = `${memoryDir}\\0${consumer}`;\n const now = Date.now();\n const warnedAt = projectionFallbackWarnedAt.get(key) ?? 0;\n if (now - warnedAt >= PROJECTION_FALLBACK_WARN_INTERVAL_MS) {\n projectionFallbackWarnedAt.set(key, now);\n const suffix = detail?.();\n log.warn(\n `storage.${consumer}: memory projection absent or empty; falling back to full corpus`\n + (suffix ? ` (${suffix})` : \"\"),\n );\n }\n return null;\n}\n\n/** @internal Test seam (#2119): clear the fallback-warn rate-limit dedup map so\n * a focused test can prove the once-per-interval spam suppression from a clean\n * slate regardless of prior tests in the same process. */\nexport function __resetProjectionFallbackWarnSuppressionForTest(): void {\n projectionFallbackWarnedAt.clear();\n}\n"],"mappings":";;;;;AAEA,IAAM,uCAAuC,IAAI;AACjD,IAAM,6BAA6B,oBAAI,IAAoB;AAEpD,SAAS,0BACd,IACM;AACN,MAAI,OAAO,GAAG,OAAO,YAAY,GAAG,GAAG,KAAK,EAAE,WAAW,GAAG;AAC1D,UAAM,UAAU;AAAA,MACd,GAAG,WAAW,YAAY,GAAG,QAAQ,KAAK;AAAA,MAC1C,GAAG,UAAU,WAAW,GAAG,OAAO,KAAK;AAAA,MACvC,GAAG,YAAY,aAAa,GAAG,SAAS,KAAK;AAAA,IAC/C,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAC1B,UAAM,IAAI;AAAA,MACR,0CAA0C,UAAU,KAAK,OAAO,MAAM,EAAE;AAAA,IAC1E;AAAA,EACF;AACF;AAEO,SAAS,uBACd,WACA,UAGA,QACM;AACN,QAAM,MAAM,GAAG,SAAS,KAAK,QAAQ;AACrC,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,WAAW,2BAA2B,IAAI,GAAG,KAAK;AACxD,MAAI,MAAM,YAAY,sCAAsC;AAC1D,+BAA2B,IAAI,KAAK,GAAG;AACvC,UAAM,SAAS,SAAS;AACxB,QAAI;AAAA,MACF,WAAW,QAAQ,sEAChB,SAAS,KAAK,MAAM,MAAM;AAAA,IAC/B;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,kDAAwD;AACtE,6BAA2B,MAAM;AACnC;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/memory-lifecycle-ledger-utils.ts"],"sourcesContent":["import path from \"node:path\";\nimport type {\n MemoryFile,\n MemoryLifecycleEvent,\n MemoryLifecycleEventType,\n MemoryLifecycleStateSummary,\n MemoryFrontmatter,\n MemoryStatus,\n} from \"./types.js\";\n\nexport const MEMORY_LIFECYCLE_RULE_VERSION = \"memory-lifecycle-ledger.v1\";\n\nexport const MEMORY_LIFECYCLE_EVENT_SORT_ORDER: Record<MemoryLifecycleEventType, number> = {\n created: 0,\n updated: 1,\n promoted: 2,\n explicit_capture_accepted: 3,\n explicit_capture_queued: 4,\n imported: 5,\n merged: 6,\n restored: 7,\n superseded: 8,\n rejected: 9,\n archived: 10,\n};\n\n/**\n * Deterministic sort rank for a lifecycle event type. The ledger readers admit\n * any structurally valid row (permissive `eventType`, issue #1910), so an\n * unknown/typoed type must still sort deterministically: it ranks AFTER every\n * known type and keeps the comparator total. Without this fallback,\n * `map[unknown] - map[known]` is `NaN`, an invalid comparator result.\n */\nconst UNKNOWN_LIFECYCLE_EVENT_SORT_RANK = Number.MAX_SAFE_INTEGER;\n\nexport function lifecycleEventSortRank(eventType: string): number {\n return (\n MEMORY_LIFECYCLE_EVENT_SORT_ORDER[eventType as MemoryLifecycleEventType] ??\n UNKNOWN_LIFECYCLE_EVENT_SORT_RANK\n );\n}\n\n/**\n * Cross-process lock path guarding lifecycle-ledger mutations (issue #1910,\n * codex): `appendMemoryLifecycleEvents` and the compaction rewrite both hold\n * this lock so a lifecycle event appended during compaction's read->rewrite\n * window cannot be clobbered by the atomic rename that replaces the ledger.\n */\nexport function memoryLifecycleLedgerLockPath(ledgerPath: string): string {\n return `${ledgerPath}.lock`;\n}\n\n/** Stale-break window for the lifecycle-ledger lock, shared by append + rewrite. */\nexport const MEMORY_LIFECYCLE_LEDGER_LOCK_STALE_MS = 30_000;\n\n/**\n * Acquisition budget for a lifecycle append waiting on the shared ledger lock\n * (issue #2033). Set to twice the stale-break window so a normal append waits\n * out an in-progress compaction rewrite instead of giving up at\n * withHeldFileLock's 5s default and dropping the event: a live compaction\n * releases within its own runtime, and a crashed holder's lock is stale-broken\n * at MEMORY_LIFECYCLE_LEDGER_LOCK_STALE_MS, so the append still acquires well\n * inside this budget rather than failing open.\n */\nexport const MEMORY_LIFECYCLE_LEDGER_APPEND_LOCK_MAX_WAIT_MS =\n MEMORY_LIFECYCLE_LEDGER_LOCK_STALE_MS * 2;\n\nexport function toMemoryPathRel(baseDir: string, filePath: string): string {\n if (!baseDir) return filePath.split(path.sep).join(\"/\");\n return path.relative(baseDir, filePath).split(path.sep).join(\"/\");\n}\n\nexport function isArchivedMemoryPath(pathRel: string): boolean {\n return pathRel === \"archive\" || pathRel.startsWith(\"archive/\");\n}\n\nexport function inferMemoryStatus(\n frontmatter: MemoryFrontmatter,\n pathRel: string,\n fallbackStatus: MemoryStatus = \"active\",\n): MemoryStatus {\n if (frontmatter.status && frontmatter.status !== \"active\") return frontmatter.status;\n if (frontmatter.archivedAt) return \"archived\";\n if (isArchivedMemoryPath(pathRel)) return \"archived\";\n if (frontmatter.status) return frontmatter.status;\n return fallbackStatus;\n}\n\nexport function isActiveMemoryStatus(status: MemoryStatus | string | undefined): boolean {\n return status === undefined || status === \"active\";\n}\n\nexport function summarizeMemoryLifecycleState(memory: MemoryFile): MemoryLifecycleStateSummary {\n return {\n category: memory.frontmatter.category,\n path: memory.path,\n status: memory.frontmatter.status ?? \"active\",\n lifecycleState: memory.frontmatter.lifecycleState,\n };\n}\n\nexport function makeRebuiltMemoryLifecycleEvent(\n memory: MemoryFile,\n eventType: MemoryLifecycleEventType,\n timestamp: string,\n): MemoryLifecycleEvent {\n return {\n eventId: `rebuild-${memory.frontmatter.id}-${eventType}-${timestamp}`,\n memoryId: memory.frontmatter.id,\n eventType,\n timestamp,\n actor: \"maintenance.rebuildMemoryLifecycleLedger\",\n ruleVersion: MEMORY_LIFECYCLE_RULE_VERSION,\n after: summarizeMemoryLifecycleState(memory),\n relatedMemoryIds: [\n ...(memory.frontmatter.supersededBy ? [memory.frontmatter.supersededBy] : []),\n ...(memory.frontmatter.supersedes ? [memory.frontmatter.supersedes] : []),\n ...((memory.frontmatter.lineage ?? []).filter(Boolean)),\n ],\n };\n}\n\nexport function buildLifecycleEventsForMemory(memory: MemoryFile): MemoryLifecycleEvent[] {\n const events: MemoryLifecycleEvent[] = [];\n const created = memory.frontmatter.created;\n const updated = memory.frontmatter.updated;\n const archivedAt = memory.frontmatter.archivedAt;\n const supersededAt = memory.frontmatter.supersededAt;\n const effectiveArchivedAt =\n archivedAt ?? (memory.frontmatter.status === \"archived\" && updated ? updated : undefined);\n\n events.push(makeRebuiltMemoryLifecycleEvent(memory, \"created\", created));\n if (\n updated &&\n updated !== created &&\n updated !== effectiveArchivedAt &&\n updated !== supersededAt\n ) {\n events.push(makeRebuiltMemoryLifecycleEvent(memory, \"updated\", updated));\n }\n if (supersededAt) {\n events.push(makeRebuiltMemoryLifecycleEvent(memory, \"superseded\", supersededAt));\n }\n if (effectiveArchivedAt) {\n events.push(makeRebuiltMemoryLifecycleEvent(memory, \"archived\", effectiveArchivedAt));\n }\n\n return events;\n}\n\nexport function compareMemoryLifecycleEvents(\n a: MemoryLifecycleEvent,\n b: MemoryLifecycleEvent,\n): number {\n if (a.memoryId !== b.memoryId) return a.memoryId.localeCompare(b.memoryId);\n if (a.timestamp !== b.timestamp) return a.timestamp.localeCompare(b.timestamp);\n return lifecycleEventSortRank(a.eventType) - lifecycleEventSortRank(b.eventType);\n}\n\nexport function sortMemoryLifecycleEvents(events: MemoryLifecycleEvent[]): MemoryLifecycleEvent[] {\n return [...events].sort(compareMemoryLifecycleEvents);\n}\n"],"mappings":"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","names":[]}