@remnic/core 9.3.758 → 9.3.760

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 (119) hide show
  1. package/dist/access-admin-ops-surface.d.ts +2 -2
  2. package/dist/access-admin-ops-surface.js +4 -4
  3. package/dist/access-boundary.d.ts +2 -2
  4. package/dist/access-boundary.js +5 -5
  5. package/dist/access-cli.js +25 -25
  6. package/dist/access-http.d.ts +2 -2
  7. package/dist/access-http.js +9 -9
  8. package/dist/access-identity-continuity-surface.d.ts +1 -1
  9. package/dist/access-identity-continuity-surface.js +4 -4
  10. package/dist/access-lcm-surface.d.ts +2 -2
  11. package/dist/access-lcm-surface.js +4 -4
  12. package/dist/access-mcp.d.ts +2 -2
  13. package/dist/access-mcp.js +8 -8
  14. package/dist/access-observe-write-surface.d.ts +2 -2
  15. package/dist/access-observe-write-surface.js +4 -4
  16. package/dist/access-operations-batch.js +6 -6
  17. package/dist/access-operations.d.ts +6 -6
  18. package/dist/access-operations.js +7 -7
  19. package/dist/access-recall-surface.d.ts +2 -2
  20. package/dist/access-recall-surface.js +4 -4
  21. package/dist/access-schema.d.ts +68 -68
  22. package/dist/{access-service-Z-8CnmrW.d.ts → access-service-BW-gb3DL.d.ts} +1 -1
  23. package/dist/access-service.d.ts +2 -2
  24. package/dist/access-service.js +4 -4
  25. package/dist/access-surface-catalog.d.ts +2 -2
  26. package/dist/bootstrap.d.ts +1 -1
  27. package/dist/briefing.js +2 -2
  28. package/dist/causal-consolidation.js +3 -3
  29. package/dist/{chunk-QJUZAUAD.js → chunk-2XE4F3VZ.js} +12 -12
  30. package/dist/{chunk-HO3VUUGI.js → chunk-3JBW3GHN.js} +2 -2
  31. package/dist/{chunk-CJDGB3EG.js → chunk-6CUUFFU7.js} +2 -2
  32. package/dist/{chunk-7I2QTC2K.js → chunk-7HWOEYHW.js} +2 -2
  33. package/dist/{chunk-YQYG24C6.js → chunk-AZSSKOG6.js} +3 -3
  34. package/dist/{chunk-RF6BZHOD.js → chunk-DTSOB2YF.js} +2 -2
  35. package/dist/{chunk-LQDA67TT.js → chunk-EGQ3AVZV.js} +2 -2
  36. package/dist/{chunk-ILB2MFTS.js → chunk-FYJWEGYP.js} +2 -2
  37. package/dist/{chunk-LX4ZWRGD.js → chunk-ILVF6TIY.js} +2 -2
  38. package/dist/{chunk-ZFYML7C3.js → chunk-IOZZG75J.js} +2 -2
  39. package/dist/{chunk-6C6BBBCI.js → chunk-IZLGHKWA.js} +4 -4
  40. package/dist/{chunk-EOTTKLPJ.js → chunk-LLVKDFNU.js} +2 -2
  41. package/dist/{chunk-QEAOKI4U.js → chunk-M2AAYJVI.js} +2 -2
  42. package/dist/{chunk-ZLOD23PD.js → chunk-OLEBPUZ7.js} +4 -4
  43. package/dist/{chunk-QKOTOUVR.js → chunk-P26O6R3Q.js} +3 -3
  44. package/dist/{chunk-K2DJQOE3.js → chunk-PKRRBRY2.js} +2 -2
  45. package/dist/{chunk-TMXTQCJ7.js → chunk-QOM3F6YW.js} +4 -4
  46. package/dist/{chunk-IWI2ICTF.js → chunk-QQJMVF6P.js} +3 -3
  47. package/dist/{chunk-TVWF3GNF.js → chunk-QUGPXPFJ.js} +5 -5
  48. package/dist/{chunk-PJ5AG6D4.js → chunk-SLAZZXBU.js} +2 -2
  49. package/dist/{chunk-7ME6VBF7.js → chunk-SMLMH7S5.js} +118 -79
  50. package/dist/chunk-SMLMH7S5.js.map +1 -0
  51. package/dist/{chunk-CQCCVJZO.js → chunk-SN2EWIAI.js} +2 -2
  52. package/dist/{chunk-RQNV75HR.js → chunk-WIXQ3F5P.js} +2 -2
  53. package/dist/{chunk-DUQHQ3TL.js → chunk-YP23FQPT.js} +3 -4
  54. package/dist/chunk-YP23FQPT.js.map +1 -0
  55. package/dist/{chunk-ODC4HOUZ.js → chunk-ZEQVS6AZ.js} +2 -2
  56. package/dist/{cli-C5pCwszN.d.ts → cli-D551dnva.d.ts} +2 -2
  57. package/dist/cli.d.ts +3 -3
  58. package/dist/cli.js +19 -19
  59. package/dist/compounding/engine.js +2 -2
  60. package/dist/connectors/codex-materialize-runner.js +2 -2
  61. package/dist/connectors/index.js +2 -2
  62. package/dist/entity-retrieval.js +2 -2
  63. package/dist/explicit-capture.d.ts +1 -1
  64. package/dist/index.d.ts +4 -4
  65. package/dist/index.js +25 -25
  66. package/dist/maintenance/memory-governance.js +2 -2
  67. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +2 -2
  68. package/dist/maintenance/rebuild-memory-projection.js +3 -3
  69. package/dist/mcp-memory-inspector-app.d.ts +2 -2
  70. package/dist/namespaces/migrate.js +3 -3
  71. package/dist/namespaces/storage.js +2 -2
  72. package/dist/operator-toolkit.js +6 -6
  73. package/dist/orchestration/maintenance.js +4 -4
  74. package/dist/{orchestrator-Xm6sK5jw.d.ts → orchestrator-BnM187cb.d.ts} +2 -1
  75. package/dist/orchestrator.d.ts +1 -1
  76. package/dist/orchestrator.js +25 -25
  77. package/dist/schemas.d.ts +90 -90
  78. package/dist/semantic-consolidation.js +3 -3
  79. package/dist/semantic-rule-promotion.js +2 -2
  80. package/dist/semantic-rule-verifier.js +2 -2
  81. package/dist/shared-context/manager.d.ts +8 -8
  82. package/dist/storage.js +1 -1
  83. package/dist/transfer/types.d.ts +66 -66
  84. package/dist/verified-recall.js +2 -2
  85. package/package.json +2 -2
  86. package/src/orchestration/recall-background-writes.ts +24 -0
  87. package/src/orchestration/recall-entry.ts +5 -0
  88. package/src/orchestration/recall-internal.ts +15 -11
  89. package/src/orchestration/recall-introspection.ts +5 -0
  90. package/src/orchestrator-background-writes.test.ts +101 -0
  91. package/src/orchestrator.ts +13 -13
  92. package/src/storage-contract/round-trip.test.ts +5 -0
  93. package/src/storage.ts +2 -3
  94. package/src/trust-score-recall-paths.test.ts +2 -0
  95. package/dist/chunk-7ME6VBF7.js.map +0 -1
  96. package/dist/chunk-DUQHQ3TL.js.map +0 -1
  97. /package/dist/{chunk-QJUZAUAD.js.map → chunk-2XE4F3VZ.js.map} +0 -0
  98. /package/dist/{chunk-HO3VUUGI.js.map → chunk-3JBW3GHN.js.map} +0 -0
  99. /package/dist/{chunk-CJDGB3EG.js.map → chunk-6CUUFFU7.js.map} +0 -0
  100. /package/dist/{chunk-7I2QTC2K.js.map → chunk-7HWOEYHW.js.map} +0 -0
  101. /package/dist/{chunk-YQYG24C6.js.map → chunk-AZSSKOG6.js.map} +0 -0
  102. /package/dist/{chunk-RF6BZHOD.js.map → chunk-DTSOB2YF.js.map} +0 -0
  103. /package/dist/{chunk-LQDA67TT.js.map → chunk-EGQ3AVZV.js.map} +0 -0
  104. /package/dist/{chunk-ILB2MFTS.js.map → chunk-FYJWEGYP.js.map} +0 -0
  105. /package/dist/{chunk-LX4ZWRGD.js.map → chunk-ILVF6TIY.js.map} +0 -0
  106. /package/dist/{chunk-ZFYML7C3.js.map → chunk-IOZZG75J.js.map} +0 -0
  107. /package/dist/{chunk-6C6BBBCI.js.map → chunk-IZLGHKWA.js.map} +0 -0
  108. /package/dist/{chunk-EOTTKLPJ.js.map → chunk-LLVKDFNU.js.map} +0 -0
  109. /package/dist/{chunk-QEAOKI4U.js.map → chunk-M2AAYJVI.js.map} +0 -0
  110. /package/dist/{chunk-ZLOD23PD.js.map → chunk-OLEBPUZ7.js.map} +0 -0
  111. /package/dist/{chunk-QKOTOUVR.js.map → chunk-P26O6R3Q.js.map} +0 -0
  112. /package/dist/{chunk-K2DJQOE3.js.map → chunk-PKRRBRY2.js.map} +0 -0
  113. /package/dist/{chunk-TMXTQCJ7.js.map → chunk-QOM3F6YW.js.map} +0 -0
  114. /package/dist/{chunk-IWI2ICTF.js.map → chunk-QQJMVF6P.js.map} +0 -0
  115. /package/dist/{chunk-TVWF3GNF.js.map → chunk-QUGPXPFJ.js.map} +0 -0
  116. /package/dist/{chunk-PJ5AG6D4.js.map → chunk-SLAZZXBU.js.map} +0 -0
  117. /package/dist/{chunk-CQCCVJZO.js.map → chunk-SN2EWIAI.js.map} +0 -0
  118. /package/dist/{chunk-RQNV75HR.js.map → chunk-WIXQ3F5P.js.map} +0 -0
  119. /package/dist/{chunk-ODC4HOUZ.js.map → chunk-ZEQVS6AZ.js.map} +0 -0
@@ -0,0 +1,101 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtemp, rm } from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import test from "node:test";
6
+ import { parseConfig } from "./config.js";
7
+ import { Orchestrator } from "./orchestrator.js";
8
+
9
+ test("destroy cancels maintenance and waits for tracked writes before disposing search backends", async () => {
10
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-background-writes-"));
11
+ const orchestrator = new Orchestrator(
12
+ parseConfig({
13
+ openaiApiKey: "sk-test",
14
+ memoryDir,
15
+ workspaceDir: path.join(memoryDir, "workspace"),
16
+ qmdEnabled: false,
17
+ knowledgeIndexEnabled: false,
18
+ identityContinuityEnabled: false,
19
+ transcriptEnabled: false,
20
+ hourlySummariesEnabled: false,
21
+ compoundingEnabled: false,
22
+ })
23
+ );
24
+ const maintenanceScheduler = (orchestrator as unknown as { maintenanceScheduler: { dispose(): void } })
25
+ .maintenanceScheduler;
26
+ const originalMaintenanceDispose = maintenanceScheduler.dispose.bind(maintenanceScheduler);
27
+ let maintenanceDisposed = false;
28
+ maintenanceScheduler.dispose = () => {
29
+ maintenanceDisposed = true;
30
+ originalMaintenanceDispose();
31
+ };
32
+ const writeGate = Promise.withResolvers<void>();
33
+ let destroySettled = false;
34
+ let destroyPromise: Promise<void> | undefined;
35
+
36
+ try {
37
+ orchestrator.trackRecallBackgroundWrite(writeGate.promise, "test background write");
38
+ destroyPromise = orchestrator.destroy().then(() => {
39
+ destroySettled = true;
40
+ });
41
+
42
+ await new Promise<void>((resolve) => setImmediate(resolve));
43
+ assert.equal(destroySettled, false, "destroy must remain pending while a tracked write is pending");
44
+ assert.equal(maintenanceDisposed, true, "destroy must cancel maintenance before waiting for writes");
45
+
46
+ writeGate.resolve();
47
+ await destroyPromise;
48
+ assert.equal(destroySettled, true);
49
+ } finally {
50
+ writeGate.resolve();
51
+ await (destroyPromise ?? orchestrator.destroy());
52
+ await rm(memoryDir, { recursive: true, force: true });
53
+ }
54
+ });
55
+
56
+ test("destroy waits for a recall-initiated last-recall write", async () => {
57
+ const memoryDir = await mkdtemp(path.join(os.tmpdir(), "remnic-recall-background-write-"));
58
+ const orchestrator = new Orchestrator(
59
+ parseConfig({
60
+ openaiApiKey: "sk-test",
61
+ memoryDir,
62
+ workspaceDir: path.join(memoryDir, "workspace"),
63
+ qmdEnabled: false,
64
+ knowledgeIndexEnabled: false,
65
+ identityContinuityEnabled: false,
66
+ transcriptEnabled: false,
67
+ hourlySummariesEnabled: false,
68
+ compoundingEnabled: false,
69
+ })
70
+ );
71
+ const writeStarted = Promise.withResolvers<void>();
72
+ const writeGate = Promise.withResolvers<void>();
73
+ const originalRecord = orchestrator.lastRecall.record.bind(orchestrator.lastRecall);
74
+ orchestrator.lastRecall.record = async (...args: Parameters<typeof originalRecord>) => {
75
+ writeStarted.resolve();
76
+ await writeGate.promise;
77
+ await originalRecord(...args);
78
+ };
79
+ let destroySettled = false;
80
+ let destroyPromise: Promise<void> | undefined;
81
+
82
+ try {
83
+ await orchestrator.initialize();
84
+ await orchestrator.recall("recall state drain contract", "session-background-write");
85
+ await writeStarted.promise;
86
+ destroyPromise = orchestrator.destroy().then(() => {
87
+ destroySettled = true;
88
+ });
89
+
90
+ await new Promise<void>((resolve) => setImmediate(resolve));
91
+ assert.equal(destroySettled, false, "destroy must wait for the recall-initiated state write");
92
+
93
+ writeGate.resolve();
94
+ await destroyPromise;
95
+ assert.equal(destroySettled, true);
96
+ } finally {
97
+ writeGate.resolve();
98
+ await (destroyPromise ?? orchestrator.destroy());
99
+ await rm(memoryDir, { recursive: true, force: true });
100
+ }
101
+ });
@@ -120,6 +120,7 @@ import { NamespaceReadFanoutCoordinator } from "./orchestration/namespace-read-f
120
120
  import { selfDeps } from "./orchestration/self-deps.js";
121
121
  import { RecallEntryCoordinator } from "./orchestration/recall-entry.js";
122
122
  import { SessionContextCoordinator } from "./orchestration/session-context.js";
123
+ import { drainRecallWrites, trackRecallWrite } from "./orchestration/recall-background-writes.js";
123
124
  import {
124
125
  abortRecallError,
125
126
  buildCompressionGuidelinesMarkdown,
@@ -135,9 +136,8 @@ import {
135
136
  type QueryAwarePrefilter,
136
137
  type RecallInvocationOptions,
137
138
  } from "./orchestration/orchestrator-helpers.js";
138
- // Issue #1526 seam 25: module-level helpers moved to
139
- // orchestration/orchestrator-helpers.ts; re-exported here so existing
140
- // importers (coordinators, tests, root shims) keep working.
139
+ // Issue #1526 seam 25: helpers moved to orchestration/orchestrator-helpers.ts and are
140
+ // re-exported here so existing importers (coordinators, tests, root shims) keep working.
141
141
  export {
142
142
  BulkImportBatchPartialFailureError,
143
143
  COMPACTION_SIGNAL_MAX_AGE_MS,
@@ -701,8 +701,7 @@ export class Orchestrator {
701
701
  /** Read by NamespaceReadFanoutCoordinator (seam 26), hence not `private`. */
702
702
  static readonly ARTIFACT_STATUS_CACHE_TTL_MS = 60_000;
703
703
 
704
- // Access tracking buffer (Phase 1A)
705
- // Maps memoryId -> {count, lastAccessed} for batched updates
704
+ // Batched access-tracking counts and timestamps (Phase 1A).
706
705
  private accessTrackingBuffer: Map<
707
706
  string,
708
707
  { count: number; lastAccessed: string }
@@ -887,9 +886,7 @@ export class Orchestrator {
887
886
  private utilityRuntimeValues: UtilityRuntimeValues | null = null;
888
887
  private evalShadowWriteChain: Promise<void> = Promise.resolve();
889
888
 
890
- // Pending background observation-mode direct-answer annotations (#518).
891
- // Tracks fire-and-forget `annotateDirectAnswerTier` calls so callers (tests,
892
- // waitForDirectAnswerObservationIdle) can await settlement.
889
+ // Pending fire-and-forget direct-answer tier annotations (#518).
893
890
  private directAnswerObservationChain: Promise<void> = Promise.resolve();
894
891
 
895
892
  // Initialization gate: recall() awaits this before proceeding
@@ -934,8 +931,9 @@ export class Orchestrator {
934
931
  }
935
932
  }
936
933
 
937
- private async disposeSearchBackendIfNeeded(): Promise<void> {
938
- await (this.qmd as { dispose?: () => void | Promise<void> }).dispose?.();
934
+ /** Track a recall-side write so destroy() can wait for it before teardown. @internal */
935
+ trackRecallBackgroundWrite(promise: Promise<void>, label: string): void {
936
+ trackRecallWrite(this, promise, label);
939
937
  }
940
938
 
941
939
  /**
@@ -952,8 +950,9 @@ export class Orchestrator {
952
950
  this.wearablesAutoSyncHandle = null;
953
951
  }
954
952
  this.maintenanceScheduler.dispose();
953
+ await drainRecallWrites(this);
955
954
  await this.namespaceSearchRouter.dispose();
956
- await this.disposeSearchBackendIfNeeded();
955
+ await (this.qmd as { dispose?: () => void | Promise<void> }).dispose?.();
957
956
  if (this.conversationQmd && this.conversationQmd !== this.qmd) {
958
957
  await (this.conversationQmd as { dispose?: () => void | Promise<void> }).dispose?.();
959
958
  }
@@ -3713,8 +3712,9 @@ export class Orchestrator {
3713
3712
  if (
3714
3713
  this.accessTrackingBuffer.size >= this.config.accessTrackingBufferMaxSize
3715
3714
  ) {
3716
- this.flushAccessTracking().catch((err) =>
3717
- log.debug(`background access tracking flush failed: ${err}`),
3715
+ this.trackRecallBackgroundWrite(
3716
+ this.flushAccessTracking(),
3717
+ "background access tracking flush",
3718
3718
  );
3719
3719
  }
3720
3720
  }
@@ -12,6 +12,8 @@
12
12
  */
13
13
 
14
14
  import assert from "node:assert/strict";
15
+ import { utimes } from "node:fs/promises";
16
+ import path from "node:path";
15
17
  import type { MemoryCategory } from "../types.js";
16
18
  import test from "node:test";
17
19
 
@@ -212,6 +214,9 @@ test("question-queue: writeQuestion → readQuestions → resolveQuestion round-
212
214
  // resolve marks it resolved
213
215
  const resolved = await storage.resolveQuestion(id);
214
216
  assert.equal(resolved, true);
217
+ // Directory mtimes are only a cross-process hint and may be coarser than
218
+ // the cache timestamp. Same-process resolution must invalidate directly.
219
+ await utimes(path.join(storage.dir, "questions"), new Date(0), new Date(0));
215
220
 
216
221
  const afterResolve = await storage.readQuestions({ unresolvedOnly: true });
217
222
  assert.ok(!afterResolve.some((x) => x.id === id), "resolved question must not appear in unresolvedOnly");
package/src/storage.ts CHANGED
@@ -5463,9 +5463,7 @@ export class StorageManager {
5463
5463
  filePath: string;
5464
5464
  }>
5465
5465
  > {
5466
- return this.memoryReadStore.readQuestions(
5467
- opts,
5468
- );
5466
+ return this.memoryReadStore.readQuestions(opts);
5469
5467
  }
5470
5468
 
5471
5469
  /** Invalidate the questions cache (call after writing a question). */
@@ -5535,6 +5533,7 @@ export class StorageManager {
5535
5533
  `resolvedAt: "${new Date().toISOString()}"\n---\n\n`,
5536
5534
  );
5537
5535
  await this.writeStorageSecureFile(q.filePath, raw);
5536
+ this.invalidateQuestionsCache();
5538
5537
  log.debug(`resolved question ${id}`);
5539
5538
  return true;
5540
5539
  }
@@ -119,6 +119,7 @@ test("TrustScore runs on the recent-scan path: trust map reaches the X-ray snaps
119
119
  );
120
120
  }
121
121
  } finally {
122
+ await orchestrator.destroy();
122
123
  await rm(memoryDir, { recursive: true, force: true });
123
124
  }
124
125
  });
@@ -152,6 +153,7 @@ test("TrustScore quarantine excludes a contradicted memory from injection but su
152
153
  "quarantined result carries a human-readable reason",
153
154
  );
154
155
  } finally {
156
+ await orchestrator.destroy();
155
157
  await rm(memoryDir, { recursive: true, force: true });
156
158
  }
157
159
  });