@remnic/core 9.7.9 → 9.7.10

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 (112) hide show
  1. package/dist/access-admin-ops-surface.js +5 -5
  2. package/dist/access-boundary.js +6 -6
  3. package/dist/access-cli.js +36 -36
  4. package/dist/access-http.js +10 -10
  5. package/dist/access-identity-continuity-surface.js +5 -5
  6. package/dist/access-lcm-surface.js +5 -5
  7. package/dist/access-mcp.js +9 -9
  8. package/dist/access-observe-write-surface.js +5 -5
  9. package/dist/access-operations-batch.js +7 -7
  10. package/dist/access-operations.js +8 -8
  11. package/dist/access-recall-surface.js +5 -5
  12. package/dist/access-service.js +5 -5
  13. package/dist/briefing.js +3 -3
  14. package/dist/causal-consolidation.js +4 -4
  15. package/dist/{chunk-HHAA35A3.js → chunk-2VN4JAX7.js} +548 -161
  16. package/dist/chunk-2VN4JAX7.js.map +1 -0
  17. package/dist/{chunk-MLT5EG6K.js → chunk-3OQ4IZJN.js} +4 -4
  18. package/dist/{chunk-QKVX4Y6D.js → chunk-673NPXE3.js} +2 -2
  19. package/dist/{chunk-KKASNHGF.js → chunk-7CKS4AXY.js} +19 -19
  20. package/dist/{chunk-YGAOLHKN.js → chunk-7EX4YOKH.js} +4 -4
  21. package/dist/{chunk-5CFHYQU3.js → chunk-DLWYAN6A.js} +2 -2
  22. package/dist/{chunk-TY43GBX2.js → chunk-EQF5763Z.js} +2 -2
  23. package/dist/{chunk-VCFADTFS.js → chunk-FNJX2O6G.js} +3 -3
  24. package/dist/{chunk-F3FC7SMO.js → chunk-JZM5QUTE.js} +2 -2
  25. package/dist/{chunk-PV7E2FGY.js → chunk-KXLRMM35.js} +6 -6
  26. package/dist/{chunk-PHXCPVSX.js → chunk-L4H6MQ7I.js} +2 -2
  27. package/dist/{chunk-FKCJH7KP.js → chunk-LQKITFGB.js} +2 -2
  28. package/dist/{chunk-27VEKQQA.js → chunk-MXRMNKSY.js} +3 -3
  29. package/dist/{chunk-DLPXS7BE.js → chunk-N3LWQJ6Y.js} +55 -48
  30. package/dist/chunk-N3LWQJ6Y.js.map +1 -0
  31. package/dist/{chunk-EIKBKQ6L.js → chunk-QVALQE4P.js} +4 -4
  32. package/dist/{chunk-CDGGQGUU.js → chunk-SBFDL2EQ.js} +2 -2
  33. package/dist/{chunk-I2THZUAF.js → chunk-SECMZACR.js} +2 -2
  34. package/dist/{chunk-JU3GHO6J.js → chunk-TGBJ2OMK.js} +2 -2
  35. package/dist/{chunk-DE6ENYLG.js → chunk-TXLGHDHS.js} +2 -2
  36. package/dist/{chunk-KGNFFCZJ.js → chunk-U4KHQTJ6.js} +2 -2
  37. package/dist/{chunk-Y5U35ZVS.js → chunk-UTDA43TB.js} +2 -2
  38. package/dist/{chunk-POUD5BLV.js → chunk-UZRIKUFS.js} +2 -2
  39. package/dist/{chunk-CK6RI52P.js → chunk-VCEH5UYS.js} +2 -2
  40. package/dist/{chunk-SKXBOZDF.js → chunk-VDLMAJXS.js} +3 -3
  41. package/dist/{chunk-UXWGPODH.js → chunk-VRAD2FGO.js} +7 -7
  42. package/dist/{chunk-UP25ZZCN.js → chunk-WUDBMLC6.js} +2 -2
  43. package/dist/{chunk-XG5CGR3K.js → chunk-XF4KOVDK.js} +5 -5
  44. package/dist/{chunk-KPXAJ77O.js → chunk-YLTG6BO4.js} +2 -2
  45. package/dist/cli.js +23 -23
  46. package/dist/compounding/engine.js +3 -3
  47. package/dist/connectors/codex-materialize-runner.js +3 -3
  48. package/dist/connectors/index.js +3 -3
  49. package/dist/entity-retrieval.js +3 -3
  50. package/dist/index.js +43 -43
  51. package/dist/lcm/engine.js +3 -3
  52. package/dist/lcm/index.js +8 -8
  53. package/dist/maintenance/memory-governance.js +3 -3
  54. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  55. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  56. package/dist/namespaces/migrate.js +4 -4
  57. package/dist/namespaces/storage.js +3 -3
  58. package/dist/operator-toolkit.js +7 -7
  59. package/dist/orchestration/maintenance.js +5 -5
  60. package/dist/orchestrator.js +36 -36
  61. package/dist/retrieval-agents.js +2 -2
  62. package/dist/schemas.d.ts +22 -22
  63. package/dist/semantic-consolidation.js +4 -4
  64. package/dist/semantic-rule-promotion.js +3 -3
  65. package/dist/semantic-rule-verifier.js +3 -3
  66. package/dist/storage.js +2 -2
  67. package/dist/temporal-index-compat.d.ts +1 -0
  68. package/dist/temporal-index-compat.js +16 -0
  69. package/dist/temporal-index-compat.js.map +1 -0
  70. package/dist/temporal-index.d.ts +58 -7
  71. package/dist/temporal-index.js +23 -3
  72. package/dist/transfer/types.d.ts +12 -12
  73. package/dist/verified-recall.js +3 -3
  74. package/package.json +2 -2
  75. package/src/orchestration/consolidation-run.ts +5 -5
  76. package/src/orchestration/contradiction-linking-coordinator.ts +2 -2
  77. package/src/orchestration/lifecycle-policy-coordinator.ts +2 -2
  78. package/src/orchestration/persistence-index.ts +6 -6
  79. package/src/orchestration/recall-search-pipeline.ts +36 -21
  80. package/src/orchestration/semantic-consolidation-coordinator.ts +2 -2
  81. package/src/orchestrator.ts +0 -4
  82. package/src/temporal-index-compat.ts +311 -0
  83. package/src/temporal-index.test.ts +273 -22
  84. package/src/temporal-index.ts +427 -178
  85. package/dist/chunk-DLPXS7BE.js.map +0 -1
  86. package/dist/chunk-HHAA35A3.js.map +0 -1
  87. /package/dist/{chunk-MLT5EG6K.js.map → chunk-3OQ4IZJN.js.map} +0 -0
  88. /package/dist/{chunk-QKVX4Y6D.js.map → chunk-673NPXE3.js.map} +0 -0
  89. /package/dist/{chunk-KKASNHGF.js.map → chunk-7CKS4AXY.js.map} +0 -0
  90. /package/dist/{chunk-YGAOLHKN.js.map → chunk-7EX4YOKH.js.map} +0 -0
  91. /package/dist/{chunk-5CFHYQU3.js.map → chunk-DLWYAN6A.js.map} +0 -0
  92. /package/dist/{chunk-TY43GBX2.js.map → chunk-EQF5763Z.js.map} +0 -0
  93. /package/dist/{chunk-VCFADTFS.js.map → chunk-FNJX2O6G.js.map} +0 -0
  94. /package/dist/{chunk-F3FC7SMO.js.map → chunk-JZM5QUTE.js.map} +0 -0
  95. /package/dist/{chunk-PV7E2FGY.js.map → chunk-KXLRMM35.js.map} +0 -0
  96. /package/dist/{chunk-PHXCPVSX.js.map → chunk-L4H6MQ7I.js.map} +0 -0
  97. /package/dist/{chunk-FKCJH7KP.js.map → chunk-LQKITFGB.js.map} +0 -0
  98. /package/dist/{chunk-27VEKQQA.js.map → chunk-MXRMNKSY.js.map} +0 -0
  99. /package/dist/{chunk-EIKBKQ6L.js.map → chunk-QVALQE4P.js.map} +0 -0
  100. /package/dist/{chunk-CDGGQGUU.js.map → chunk-SBFDL2EQ.js.map} +0 -0
  101. /package/dist/{chunk-I2THZUAF.js.map → chunk-SECMZACR.js.map} +0 -0
  102. /package/dist/{chunk-JU3GHO6J.js.map → chunk-TGBJ2OMK.js.map} +0 -0
  103. /package/dist/{chunk-DE6ENYLG.js.map → chunk-TXLGHDHS.js.map} +0 -0
  104. /package/dist/{chunk-KGNFFCZJ.js.map → chunk-U4KHQTJ6.js.map} +0 -0
  105. /package/dist/{chunk-Y5U35ZVS.js.map → chunk-UTDA43TB.js.map} +0 -0
  106. /package/dist/{chunk-POUD5BLV.js.map → chunk-UZRIKUFS.js.map} +0 -0
  107. /package/dist/{chunk-CK6RI52P.js.map → chunk-VCEH5UYS.js.map} +0 -0
  108. /package/dist/{chunk-SKXBOZDF.js.map → chunk-VDLMAJXS.js.map} +0 -0
  109. /package/dist/{chunk-UXWGPODH.js.map → chunk-VRAD2FGO.js.map} +0 -0
  110. /package/dist/{chunk-UP25ZZCN.js.map → chunk-WUDBMLC6.js.map} +0 -0
  111. /package/dist/{chunk-XG5CGR3K.js.map → chunk-XF4KOVDK.js.map} +0 -0
  112. /package/dist/{chunk-KPXAJ77O.js.map → chunk-YLTG6BO4.js.map} +0 -0
@@ -1,5 +1,6 @@
1
1
  import assert from "node:assert/strict";
2
2
  import { spawn } from "node:child_process";
3
+ import * as fs from "node:fs";
3
4
  import { mkdir, mkdtemp, readFile, rm, symlink, utimes, writeFile } from "node:fs/promises";
4
5
  import { tmpdir } from "node:os";
5
6
  import { join } from "node:path";
@@ -7,23 +8,91 @@ import test from "node:test";
7
8
  import { setTimeout as delay } from "node:timers/promises";
8
9
 
9
10
  import {
10
- deindexMemory,
11
- indexMemory,
12
- indexesExist,
11
+ clearIndexes,
12
+ deindexMemory as deindexMemorySync,
13
+ deindexMemoryAsync as deindexMemory,
14
+ indexMemoriesBatch,
15
+ indexMemory as indexMemorySync,
16
+ indexMemoryAsync as indexMemory,
17
+ indexesExist as indexesExistSync,
18
+ indexesExistAsync as indexesExist,
13
19
  queryByDateRangeAsync,
14
20
  queryByTagsAsync,
15
21
  queryTemporalTimelineAsync,
16
22
  resolvePromptTagPrefilterAsync,
23
+ setIndexReadObserverForTest,
17
24
  } from "./temporal-index.js";
18
25
 
26
+ test("legacy temporal-index exports preserve synchronous return timing and booleans", async () => {
27
+ const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-sync-compat-"));
28
+ const firstPath = "/tmp/remnic-temporal-sync-first.md";
29
+ const secondPath = "/tmp/remnic-temporal-sync-second.md";
30
+
31
+ const initiallyExists = indexesExistSync(memoryDir);
32
+ assert.equal(typeof initiallyExists, "boolean");
33
+ assert.equal(initiallyExists, false);
34
+
35
+ assert.equal(
36
+ indexMemorySync(memoryDir, firstPath, "2026-03-09T12:00:00.000Z", ["sync"]),
37
+ undefined,
38
+ );
39
+ const afterIndex = JSON.parse(
40
+ fs.readFileSync(join(memoryDir, "state", "index_time.json"), "utf8"),
41
+ );
42
+ assert.deepEqual(afterIndex.dates["2026-03-09"], [firstPath]);
43
+ assert.equal(indexesExistSync(memoryDir), true);
44
+
45
+ indexMemoriesBatch(memoryDir, [
46
+ {
47
+ path: secondPath,
48
+ createdAt: "2026-03-10T12:00:00.000Z",
49
+ tags: ["sync"],
50
+ },
51
+ ]);
52
+ const afterBatch = JSON.parse(
53
+ fs.readFileSync(join(memoryDir, "state", "index_time.json"), "utf8"),
54
+ );
55
+ assert.deepEqual(afterBatch.dates["2026-03-10"], [secondPath]);
56
+
57
+ deindexMemorySync(memoryDir, firstPath, "2026-03-09T12:00:00.000Z", ["sync"]);
58
+ const afterDeindex = JSON.parse(
59
+ fs.readFileSync(join(memoryDir, "state", "index_time.json"), "utf8"),
60
+ );
61
+ assert.equal(afterDeindex.dates["2026-03-09"], undefined);
62
+
63
+ clearIndexes(memoryDir);
64
+ const afterClear = JSON.parse(
65
+ fs.readFileSync(join(memoryDir, "state", "index_time.json"), "utf8"),
66
+ );
67
+ assert.deepEqual(afterClear, { version: 2, dates: {}, events: {} });
68
+ });
69
+
70
+ test("explicit async mutation exports return promises and complete when awaited", async () => {
71
+ const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-async-surface-"));
72
+ const memoryPath = "/tmp/remnic-temporal-async.md";
73
+ const pending = indexMemory(
74
+ memoryDir,
75
+ memoryPath,
76
+ "2026-03-09T12:00:00.000Z",
77
+ ["async"],
78
+ );
79
+ assert.ok(pending instanceof Promise);
80
+ await pending;
81
+ assert.deepEqual(
82
+ await queryByTagsAsync(memoryDir, ["async"]),
83
+ new Set([memoryPath]),
84
+ );
85
+ assert.equal(await indexesExist(memoryDir), true);
86
+ });
87
+
19
88
  async function runIndexWorker(moduleUrl: string, memoryDir: string, workerId: number, count: number): Promise<void> {
20
89
  const workerSource = `
21
- const { indexMemory } = await import(process.argv[1]);
90
+ const { indexMemoryAsync: indexMemory } = await import(process.argv[1]);
22
91
  const memoryDir = process.argv[2];
23
92
  const workerId = Number(process.argv[3]);
24
93
  const count = Number(process.argv[4]);
25
94
  for (let i = 0; i < count; i += 1) {
26
- indexMemory(
95
+ await indexMemory(
27
96
  memoryDir,
28
97
  \`/tmp/remnic-temporal-worker-\${workerId}-memory-\${i}.md\`,
29
98
  "2026-03-09T12:00:00.000Z",
@@ -87,6 +156,176 @@ test("temporal index concurrent writers retain every date and tag path", async (
87
156
  assert.equal(tagIndex.tags["concurrency/shared"].paths.length, expectedPaths.size);
88
157
  });
89
158
 
159
+ test("temporal index in-process promise concurrency retains every path", async () => {
160
+ const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-in-process-"));
161
+ const expectedPaths = Array.from(
162
+ { length: 40 },
163
+ (_, index) => `/tmp/remnic-temporal-in-process-${index}.md`,
164
+ );
165
+
166
+ await Promise.all(
167
+ expectedPaths.map((memoryPath) =>
168
+ indexMemory(
169
+ memoryDir,
170
+ memoryPath,
171
+ "2026-03-12T12:00:00.000Z",
172
+ ["concurrency/in-process"],
173
+ ),
174
+ ),
175
+ );
176
+
177
+ assert.deepEqual(
178
+ await queryByDateRangeAsync(memoryDir, "2026-03-12", "2026-03-13"),
179
+ new Set(expectedPaths),
180
+ );
181
+ assert.deepEqual(
182
+ await queryByTagsAsync(memoryDir, ["concurrency/in-process"]),
183
+ new Set(expectedPaths),
184
+ );
185
+ });
186
+
187
+ test("parsed cache detects a cross-process atomic replacement", async () => {
188
+ const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-cache-replace-"));
189
+ const moduleUrl = new URL("./temporal-index.ts", import.meta.url).href;
190
+ const initialPath = "/tmp/remnic-temporal-cache-initial.md";
191
+ await indexMemory(
192
+ memoryDir,
193
+ initialPath,
194
+ "2026-03-09T12:00:00.000Z",
195
+ ["concurrency/shared"],
196
+ );
197
+ assert.deepEqual(
198
+ await queryByTagsAsync(memoryDir, ["concurrency/shared"]),
199
+ new Set([initialPath]),
200
+ );
201
+
202
+ await runIndexWorker(moduleUrl, memoryDir, 777, 1);
203
+
204
+ assert.deepEqual(
205
+ await queryByTagsAsync(memoryDir, ["concurrency/shared"]),
206
+ new Set([initialPath, "/tmp/remnic-temporal-worker-777-memory-0.md"]),
207
+ );
208
+ });
209
+
210
+ test("unchanged index identity skips file reads while retaining the stat freshness check", async () => {
211
+ const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-cache-hit-"));
212
+ const statePath = join(memoryDir, "state");
213
+ const tagPath = join(statePath, "index_tags.json");
214
+ await mkdir(statePath, { recursive: true });
215
+ await writeFile(
216
+ tagPath,
217
+ JSON.stringify({ version: 2, tags: { alpha: ["/tmp/alpha.md"] }, aliases: {} }),
218
+ "utf8",
219
+ );
220
+ let reads = 0;
221
+ setIndexReadObserverForTest(() => {
222
+ reads += 1;
223
+ });
224
+ try {
225
+ assert.deepEqual(await queryByTagsAsync(memoryDir, ["alpha"]), new Set(["/tmp/alpha.md"]));
226
+ assert.deepEqual(await queryByTagsAsync(memoryDir, ["alpha"]), new Set(["/tmp/alpha.md"]));
227
+ assert.equal(reads, 1);
228
+
229
+ await writeFile(
230
+ tagPath,
231
+ JSON.stringify({ version: 2, tags: { beta: ["/tmp/beta.md"] }, aliases: {} }),
232
+ "utf8",
233
+ );
234
+ assert.deepEqual(await queryByTagsAsync(memoryDir, ["beta"]), new Set(["/tmp/beta.md"]));
235
+ assert.equal(reads, 2);
236
+ } finally {
237
+ setIndexReadObserverForTest();
238
+ }
239
+ });
240
+
241
+ test("failed atomic commit never publishes a mutated temporal cache", async () => {
242
+ const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-failed-commit-"));
243
+ const originalPath = "/tmp/remnic-temporal-committed.md";
244
+ const rejectedPath = "/tmp/remnic-temporal-rejected.md";
245
+ await indexMemory(memoryDir, originalPath, "2026-03-09T12:00:00.000Z", ["committed"]);
246
+
247
+ const originalRename = fs.promises.rename;
248
+ fs.promises.rename = (async (oldPath, newPath) => {
249
+ if (String(newPath).endsWith("index_time.json")) {
250
+ const error = new Error("injected temporal rename failure") as NodeJS.ErrnoException;
251
+ error.code = "EIO";
252
+ throw error;
253
+ }
254
+ return originalRename(oldPath, newPath);
255
+ }) as typeof originalRename;
256
+ try {
257
+ await indexMemory(memoryDir, rejectedPath, "2026-03-10T12:00:00.000Z", ["rejected"]);
258
+ } finally {
259
+ fs.promises.rename = originalRename;
260
+ }
261
+
262
+ assert.deepEqual(
263
+ await queryByDateRangeAsync(memoryDir, "2026-03-09", "2026-03-11"),
264
+ new Set([originalPath]),
265
+ );
266
+ // The tag half is NOT committed when the temporal write fails (issue #1911,
267
+ // Cursor Medium): committing tags while temporal stays unchanged leaves a
268
+ // durable mismatch. Both halves stay at their prior state, so "rejected" has
269
+ // no tag membership until a later successful (both-halves) index.
270
+ assert.deepEqual(
271
+ await queryByTagsAsync(memoryDir, ["rejected"]),
272
+ new Set<string>(),
273
+ );
274
+
275
+ await indexMemory(memoryDir, rejectedPath, "2026-03-10T12:00:00.000Z", ["rejected"]);
276
+ assert.deepEqual(
277
+ await queryByDateRangeAsync(memoryDir, "2026-03-09", "2026-03-11"),
278
+ new Set([originalPath, rejectedPath]),
279
+ );
280
+ });
281
+
282
+ test("date queries preserve missing, invalid, and valid-empty distinctions", async () => {
283
+ const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-load-states-"));
284
+ const statePath = join(memoryDir, "state");
285
+ const temporalPath = join(statePath, "index_time.json");
286
+ await mkdir(statePath, { recursive: true });
287
+
288
+ assert.equal(await queryByDateRangeAsync(memoryDir, "2026-03-09", "2026-03-10"), null);
289
+
290
+ await writeFile(temporalPath, "{ invalid json", "utf8");
291
+ assert.deepEqual(
292
+ await queryByDateRangeAsync(memoryDir, "2026-03-09", "2026-03-10"),
293
+ new Set(),
294
+ );
295
+ assert.equal(await queryTemporalTimelineAsync(memoryDir), null);
296
+
297
+ await writeFile(
298
+ temporalPath,
299
+ JSON.stringify({ version: 2, dates: {}, events: {} }),
300
+ "utf8",
301
+ );
302
+ await writeFile(
303
+ join(statePath, "index_tags.json"),
304
+ JSON.stringify({ version: 2, tags: {}, aliases: {} }),
305
+ "utf8",
306
+ );
307
+ assert.deepEqual(
308
+ await queryByDateRangeAsync(memoryDir, "2026-03-09", "2026-03-10"),
309
+ new Set(),
310
+ );
311
+ assert.equal(await indexesExist(memoryDir), true);
312
+ });
313
+
314
+ test("index writers persist compact machine-only JSON", async () => {
315
+ const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-compact-"));
316
+ await indexMemory(
317
+ memoryDir,
318
+ "/tmp/remnic-temporal-compact.md",
319
+ "2026-03-09T12:00:00.000Z",
320
+ ["compact"],
321
+ );
322
+
323
+ for (const filename of ["index_time.json", "index_tags.json"]) {
324
+ const raw = await readFile(join(memoryDir, "state", filename), "utf8");
325
+ assert.equal(raw, JSON.stringify(JSON.parse(raw)));
326
+ }
327
+ });
328
+
90
329
  test("temporal index writers wait for old locks owned by live processes", async () => {
91
330
  const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-live-lock-"));
92
331
  const stateDir = join(memoryDir, "state");
@@ -98,8 +337,8 @@ test("temporal index writers wait for old locks owned by live processes", async
98
337
  await utimes(lockDir, oldLockTime, oldLockTime);
99
338
 
100
339
  const workerSource = `
101
- const { indexMemory } = await import(process.argv[1]);
102
- indexMemory(
340
+ const { indexMemoryAsync: indexMemory } = await import(process.argv[1]);
341
+ await indexMemory(
103
342
  process.argv[2],
104
343
  "/tmp/remnic-temporal-live-lock-memory.md",
105
344
  "2026-03-10T12:00:00.000Z",
@@ -195,16 +434,20 @@ test("temporal index writers fail open on symlink lock blockers", async () => {
195
434
  const dateMatches = await queryByDateRangeAsync(memoryDir, "2026-03-09", "2026-03-10");
196
435
  const tagMatches = await queryByTagsAsync(memoryDir, ["concurrency/shared"]);
197
436
  assert.equal(dateMatches, null);
198
- assert.deepEqual(tagMatches, new Set(["/tmp/remnic-temporal-worker-101-memory-0.md"]));
437
+ // Both halves fail open together (issue #1911, Cursor Medium): the symlinked
438
+ // temporal lock blocks the temporal write, so the tag half is also skipped
439
+ // (no durable mismatch). The tag index is never created → query returns null.
440
+ assert.equal(tagMatches, null);
199
441
  });
200
442
 
201
443
  test("tag queries distinguish missing index from valid no-match results", async () => {
202
444
  const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-tag-miss-"));
203
445
 
446
+ assert.equal(await queryByTagsAsync(memoryDir, []), null);
204
447
  const unavailableMatches = await queryByTagsAsync(memoryDir, ["beta"]);
205
448
  assert.equal(unavailableMatches, null);
206
449
 
207
- indexMemory(memoryDir, "/tmp/remnic-temporal-alpha-memory.md", "2026-03-11T12:00:00.000Z", ["alpha"]);
450
+ await indexMemory(memoryDir, "/tmp/remnic-temporal-alpha-memory.md", "2026-03-11T12:00:00.000Z", ["alpha"]);
208
451
 
209
452
  const matchingPaths = await queryByTagsAsync(memoryDir, ["alpha"]);
210
453
  assert.deepEqual(matchingPaths, new Set(["/tmp/remnic-temporal-alpha-memory.md"]));
@@ -226,8 +469,8 @@ test("indexMemory replaces stale date and tag memberships for an existing path",
226
469
  const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-index-update-"));
227
470
  const memoryPath = "/tmp/remnic-temporal-updated-memory.md";
228
471
 
229
- indexMemory(memoryDir, memoryPath, "2026-01-01T00:00:00.000Z", ["alpha"]);
230
- indexMemory(memoryDir, memoryPath, "2026-02-01T00:00:00.000Z", ["beta"]);
472
+ await indexMemory(memoryDir, memoryPath, "2026-01-01T00:00:00.000Z", ["alpha"]);
473
+ await indexMemory(memoryDir, memoryPath, "2026-02-01T00:00:00.000Z", ["beta"]);
231
474
 
232
475
  const januaryMatches = await queryByDateRangeAsync(memoryDir, "2026-01-01", "2026-01-02");
233
476
  const februaryMatches = await queryByDateRangeAsync(memoryDir, "2026-02-01", "2026-02-02");
@@ -242,12 +485,12 @@ test("indexMemory replaces stale date and tag memberships for an existing path",
242
485
 
243
486
  test("temporal timeline orders event time across sessions, not ingest order", async () => {
244
487
  const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-timeline-order-"));
245
- indexMemory(memoryDir, "/tmp/rome.md", "2026-07-02T00:00:00.000Z", [], {
488
+ await indexMemory(memoryDir, "/tmp/rome.md", "2026-07-02T00:00:00.000Z", [], {
246
489
  validAt: "2026-05-10T00:00:00.000Z",
247
490
  observedAt: "2026-07-02T00:00:00.000Z",
248
491
  sessionKey: "session-b",
249
492
  });
250
- indexMemory(memoryDir, "/tmp/paris.md", "2026-07-03T00:00:00.000Z", [], {
493
+ await indexMemory(memoryDir, "/tmp/paris.md", "2026-07-03T00:00:00.000Z", [], {
251
494
  validAt: "2026-03-04T00:00:00.000Z",
252
495
  observedAt: "2026-07-03T00:00:00.000Z",
253
496
  sessionKey: "session-a",
@@ -266,9 +509,9 @@ test("temporal timeline orders event time across sessions, not ingest order", as
266
509
  test("temporal timeline uses stable observation/path ordering for event-time ties", async () => {
267
510
  const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-timeline-tie-"));
268
511
  const eventAt = "2026-03-04T00:00:00.000Z";
269
- indexMemory(memoryDir, "/tmp/z.md", eventAt, [], { validAt: eventAt, observedAt: "2026-07-03T00:00:00.000Z" });
270
- indexMemory(memoryDir, "/tmp/a.md", eventAt, [], { validAt: eventAt, observedAt: "2026-07-02T00:00:00.000Z" });
271
- indexMemory(memoryDir, "/tmp/b.md", eventAt, [], { validAt: eventAt, observedAt: "2026-07-02T00:00:00.000Z" });
512
+ await indexMemory(memoryDir, "/tmp/z.md", eventAt, [], { validAt: eventAt, observedAt: "2026-07-03T00:00:00.000Z" });
513
+ await indexMemory(memoryDir, "/tmp/a.md", eventAt, [], { validAt: eventAt, observedAt: "2026-07-02T00:00:00.000Z" });
514
+ await indexMemory(memoryDir, "/tmp/b.md", eventAt, [], { validAt: eventAt, observedAt: "2026-07-02T00:00:00.000Z" });
272
515
 
273
516
  const first = await queryTemporalTimelineAsync(memoryDir);
274
517
  const second = await queryTemporalTimelineAsync(memoryDir);
@@ -290,7 +533,11 @@ test("old or malformed temporal index shape is unavailable and requests rebuild"
290
533
  "utf8",
291
534
  );
292
535
 
293
- assert.equal(indexesExist(memoryDir), false);
536
+ assert.deepEqual(
537
+ await queryByDateRangeAsync(memoryDir, "2026-01-01", "2026-01-02"),
538
+ new Set(),
539
+ );
540
+ assert.equal(await indexesExist(memoryDir), false);
294
541
  assert.equal(await queryTemporalTimelineAsync(memoryDir), null);
295
542
 
296
543
  await writeFile(
@@ -298,7 +545,11 @@ test("old or malformed temporal index shape is unavailable and requests rebuild"
298
545
  JSON.stringify({ version: 1, dates: {} }),
299
546
  "utf8",
300
547
  );
301
- assert.equal(indexesExist(memoryDir), false);
548
+ assert.deepEqual(
549
+ await queryByDateRangeAsync(memoryDir, "2026-01-01", "2026-01-02"),
550
+ new Set(),
551
+ );
552
+ assert.equal(await indexesExist(memoryDir), false);
302
553
  assert.equal(await queryTemporalTimelineAsync(memoryDir), null);
303
554
  });
304
555
 
@@ -306,8 +557,8 @@ test("deindex removes timeline rows so stale events cannot be recalled", async (
306
557
  const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-timeline-delete-"));
307
558
  const memoryPath = "/tmp/deleted.md";
308
559
  const createdAt = "2026-03-04T00:00:00.000Z";
309
- indexMemory(memoryDir, memoryPath, createdAt, ["trip"], { sessionKey: "session-a" });
310
- deindexMemory(memoryDir, memoryPath, createdAt, ["trip"]);
560
+ await indexMemory(memoryDir, memoryPath, createdAt, ["trip"], { sessionKey: "session-a" });
561
+ await deindexMemory(memoryDir, memoryPath, createdAt, ["trip"]);
311
562
  assert.deepEqual(await queryTemporalTimelineAsync(memoryDir), []);
312
563
  });
313
564
 
@@ -315,7 +566,7 @@ test("large temporal indexes return a bounded relevant oversample before memory
315
566
  const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-timeline-bounded-"));
316
567
  for (let i = 0; i < 600; i += 1) {
317
568
  const day = String((i % 28) + 1).padStart(2, "0");
318
- indexMemory(
569
+ await indexMemory(
319
570
  memoryDir,
320
571
  `/tmp/event-${String(i).padStart(4, "0")}.md`,
321
572
  `2026-03-${day}T00:00:00.000Z`,
@@ -348,7 +599,7 @@ test("temporal timeline generic edge selection honors small and zero limits", as
348
599
  const memoryDir = await mkdtemp(join(tmpdir(), "remnic-temporal-timeline-small-limit-"));
349
600
  for (let day = 1; day <= 4; day += 1) {
350
601
  const timestamp = `2026-04-0${day}T00:00:00.000Z`;
351
- indexMemory(memoryDir, `/tmp/edge-${day}.md`, timestamp, [], {
602
+ await indexMemory(memoryDir, `/tmp/edge-${day}.md`, timestamp, [], {
352
603
  validAt: timestamp,
353
604
  searchText: `unrelated event ${day}`,
354
605
  });