@remnic/core 9.3.727 → 9.3.729

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 (95) hide show
  1. package/dist/access-boundary.d.ts +2 -2
  2. package/dist/access-boundary.js +6 -6
  3. package/dist/access-cli.js +11 -11
  4. package/dist/access-http.d.ts +2 -2
  5. package/dist/access-http.js +10 -10
  6. package/dist/access-mcp.d.ts +2 -2
  7. package/dist/access-mcp.js +9 -9
  8. package/dist/access-operations-batch.js +7 -7
  9. package/dist/access-operations.d.ts +8 -8
  10. package/dist/access-operations.js +8 -8
  11. package/dist/access-schema.d.ts +46 -46
  12. package/dist/{access-service-Bgpjxo4f.d.ts → access-service-BXMJqkTA.d.ts} +1 -1
  13. package/dist/access-service.d.ts +2 -2
  14. package/dist/access-service.js +5 -5
  15. package/dist/access-surface-catalog.d.ts +2 -2
  16. package/dist/bootstrap.d.ts +1 -1
  17. package/dist/capabilities.d.ts +43 -1
  18. package/dist/capabilities.js +5 -3
  19. package/dist/{chunk-DVRHLN2O.js → chunk-3RCBIOOJ.js} +18 -2
  20. package/dist/{chunk-DVRHLN2O.js.map → chunk-3RCBIOOJ.js.map} +1 -1
  21. package/dist/{chunk-R7IYU5DZ.js → chunk-4ESAR77N.js} +2 -2
  22. package/dist/{chunk-SNKPUJHR.js → chunk-76NHR6ZL.js} +3 -3
  23. package/dist/{chunk-6PY5YJAV.js → chunk-BQCHEV7O.js} +8 -3
  24. package/dist/{chunk-6PY5YJAV.js.map → chunk-BQCHEV7O.js.map} +1 -1
  25. package/dist/{chunk-ZA2S2VLL.js → chunk-C2PG7IEH.js} +5 -2
  26. package/dist/chunk-C2PG7IEH.js.map +1 -0
  27. package/dist/{chunk-MJIHJ7OG.js → chunk-H5BWGCRZ.js} +11 -10
  28. package/dist/chunk-H5BWGCRZ.js.map +1 -0
  29. package/dist/{chunk-XPHVAOBT.js → chunk-HEDZUSCS.js} +180 -101
  30. package/dist/chunk-HEDZUSCS.js.map +1 -0
  31. package/dist/{chunk-N3VNUM4Z.js → chunk-HGNOCPZX.js} +4 -4
  32. package/dist/{chunk-CSRXQ6NB.js → chunk-I5REUWLH.js} +10 -4
  33. package/dist/chunk-I5REUWLH.js.map +1 -0
  34. package/dist/{chunk-NSA5ZRUL.js → chunk-M4AYVEWS.js} +3 -3
  35. package/dist/{chunk-OEEW4KJA.js → chunk-O6YH5F47.js} +3 -3
  36. package/dist/{chunk-27QQC7ZX.js → chunk-UM5AWJNQ.js} +6 -5
  37. package/dist/chunk-UM5AWJNQ.js.map +1 -0
  38. package/dist/{chunk-2KAYTPPT.js → chunk-UTHQPSRC.js} +2 -2
  39. package/dist/{chunk-CTOQEZSN.js → chunk-V4GNSDFH.js} +2 -2
  40. package/dist/{chunk-EHISUJFN.js → chunk-WAS3NV46.js} +6 -3
  41. package/dist/chunk-WAS3NV46.js.map +1 -0
  42. package/dist/{chunk-DKJCRGWM.js → chunk-YGIQORJ3.js} +2 -2
  43. package/dist/{cli-BLME420h.d.ts → cli-DmAiDd8A.d.ts} +2 -2
  44. package/dist/cli.d.ts +3 -3
  45. package/dist/cli.js +13 -13
  46. package/dist/embedding-fallback.js +2 -1
  47. package/dist/explicit-capture.d.ts +1 -1
  48. package/dist/extraction.js +2 -1
  49. package/dist/{first-start-migration-PG5HBC3K.js → first-start-migration-22LPFHD5.js} +6 -2
  50. package/dist/first-start-migration-22LPFHD5.js.map +1 -0
  51. package/dist/index.d.ts +4 -4
  52. package/dist/index.js +16 -16
  53. package/dist/mcp-memory-inspector-app.d.ts +2 -2
  54. package/dist/namespaces/migrate.js +5 -4
  55. package/dist/namespaces/search.js +4 -3
  56. package/dist/operator-toolkit.js +6 -6
  57. package/dist/{orchestrator-DqPAz8ot.d.ts → orchestrator-BR0sGsME.d.ts} +104 -26
  58. package/dist/orchestrator.d.ts +1 -1
  59. package/dist/orchestrator.js +7 -7
  60. package/dist/schemas.d.ts +74 -74
  61. package/dist/search/embed-helper.js +2 -1
  62. package/dist/search/factory.js +3 -2
  63. package/dist/search/index.js +3 -2
  64. package/dist/shared-context/manager.d.ts +2 -2
  65. package/dist/transfer/types.d.ts +12 -12
  66. package/package.json +2 -2
  67. package/src/access-service.ts +2 -1
  68. package/src/capabilities.test.ts +155 -0
  69. package/src/capabilities.ts +91 -0
  70. package/src/chat/chat-engine.test.ts +39 -1
  71. package/src/chat/chat-session.ts +25 -2
  72. package/src/cli.ts +3 -2
  73. package/src/embedding-fallback.ts +2 -1
  74. package/src/extraction.ts +7 -3
  75. package/src/maintenance/first-start-migration.ts +3 -1
  76. package/src/orchestration/extraction-queue-coordinator.ts +175 -0
  77. package/src/orchestrator-extraction-queue.test.ts +26 -38
  78. package/src/orchestrator-flush.test.ts +10 -15
  79. package/src/orchestrator.ts +52 -104
  80. package/src/search/embed-helper.ts +3 -2
  81. package/dist/chunk-27QQC7ZX.js.map +0 -1
  82. package/dist/chunk-CSRXQ6NB.js.map +0 -1
  83. package/dist/chunk-EHISUJFN.js.map +0 -1
  84. package/dist/chunk-MJIHJ7OG.js.map +0 -1
  85. package/dist/chunk-XPHVAOBT.js.map +0 -1
  86. package/dist/chunk-ZA2S2VLL.js.map +0 -1
  87. package/dist/first-start-migration-PG5HBC3K.js.map +0 -1
  88. /package/dist/{chunk-R7IYU5DZ.js.map → chunk-4ESAR77N.js.map} +0 -0
  89. /package/dist/{chunk-SNKPUJHR.js.map → chunk-76NHR6ZL.js.map} +0 -0
  90. /package/dist/{chunk-N3VNUM4Z.js.map → chunk-HGNOCPZX.js.map} +0 -0
  91. /package/dist/{chunk-NSA5ZRUL.js.map → chunk-M4AYVEWS.js.map} +0 -0
  92. /package/dist/{chunk-OEEW4KJA.js.map → chunk-O6YH5F47.js.map} +0 -0
  93. /package/dist/{chunk-2KAYTPPT.js.map → chunk-UTHQPSRC.js.map} +0 -0
  94. /package/dist/{chunk-CTOQEZSN.js.map → chunk-V4GNSDFH.js.map} +0 -0
  95. /package/dist/{chunk-DKJCRGWM.js.map → chunk-YGIQORJ3.js.map} +0 -0
@@ -154,7 +154,7 @@ import {
154
154
  } from "./chunk-LTHVM4XN.js";
155
155
  import {
156
156
  ExtractionEngine
157
- } from "./chunk-CSRXQ6NB.js";
157
+ } from "./chunk-I5REUWLH.js";
158
158
  import {
159
159
  parseMemoryActionEligibilityContext
160
160
  } from "./chunk-5GSUBCZM.js";
@@ -187,7 +187,7 @@ import {
187
187
  } from "./chunk-Q6IP2ARR.js";
188
188
  import {
189
189
  EmbeddingFallback
190
- } from "./chunk-ZA2S2VLL.js";
190
+ } from "./chunk-C2PG7IEH.js";
191
191
  import {
192
192
  buildEntityRecallSection,
193
193
  entityRecentTranscriptLookbackHours,
@@ -333,11 +333,11 @@ import {
333
333
  } from "./chunk-J6BH2OBA.js";
334
334
  import {
335
335
  NamespaceSearchRouter
336
- } from "./chunk-CTOQEZSN.js";
336
+ } from "./chunk-V4GNSDFH.js";
337
337
  import {
338
338
  createConversationIndexRuntime,
339
339
  createSearchBackend
340
- } from "./chunk-2KAYTPPT.js";
340
+ } from "./chunk-UTHQPSRC.js";
341
341
  import {
342
342
  NoopSearchBackend
343
343
  } from "./chunk-CYEPCZN5.js";
@@ -363,8 +363,9 @@ import {
363
363
  } from "./chunk-EH5ED3C6.js";
364
364
  import {
365
365
  resolveCapabilities,
366
- resolveGraphConstructionCapabilities
367
- } from "./chunk-DVRHLN2O.js";
366
+ resolveGraphConstructionCapabilities,
367
+ resolveMemoryLifecycleCapabilities
368
+ } from "./chunk-3RCBIOOJ.js";
368
369
  import {
369
370
  searchCausalTrajectories
370
371
  } from "./chunk-SQNED75R.js";
@@ -745,6 +746,130 @@ var TierMigrationCoordinator = class {
745
746
  }
746
747
  };
747
748
 
749
+ // src/orchestration/extraction-queue-coordinator.ts
750
+ var ExtractionQueueCoordinator = class {
751
+ /**
752
+ * Background serial queue for extractions (agent_end optimization).
753
+ * Queue stores tasks that resolve when extraction should run.
754
+ */
755
+ queue = [];
756
+ /** Whether the serial drain loop is currently running. */
757
+ processing = false;
758
+ /** Current queue depth (idle-wait + test seam). */
759
+ get length() {
760
+ return this.queue.length;
761
+ }
762
+ /** Whether the serial drain loop is currently running (idle-wait + test seam). */
763
+ get isProcessing() {
764
+ return this.processing;
765
+ }
766
+ /**
767
+ * Enqueue a task and start the serial processor if it is idle. This is
768
+ * the production entry point — the orchestrator's `queueBufferedExtraction`
769
+ * builds each task closure and hands it here.
770
+ */
771
+ enqueue(task) {
772
+ this.queue.push(task);
773
+ if (!this.processing) {
774
+ this.processing = true;
775
+ this.processQueue().catch((err) => {
776
+ this.logExtractionQueueFailure(err, "processor");
777
+ this.processing = false;
778
+ });
779
+ }
780
+ }
781
+ /**
782
+ * Background serial queue processor.
783
+ * Processes extractions one at a time to avoid race conditions.
784
+ * Called automatically when items are queued via `enqueue`; also exposed
785
+ * for the characterization tests that push raw tasks and assert drain
786
+ * semantics directly.
787
+ */
788
+ async processQueue() {
789
+ while (this.queue.length > 0) {
790
+ const task = this.queue.shift();
791
+ if (task) {
792
+ try {
793
+ await task();
794
+ } catch (err) {
795
+ this.logExtractionQueueFailure(err, "task");
796
+ }
797
+ }
798
+ }
799
+ this.processing = false;
800
+ }
801
+ /**
802
+ * Classify + log a failure from either the per-task catch inside
803
+ * `processQueue()` or the outer `processQueue().catch(...)` in
804
+ * `enqueue()`. Issue #549: `throwIfRecallAborted`
805
+ * (used throughout `runExtraction`) raises an Error whose `name` is
806
+ * `"AbortError"`. That path fires when `before_reset` aborts a
807
+ * queued task to avoid duplicate extraction — it is intentional
808
+ * cancellation, not a failure. Downgrading the log to debug
809
+ * prevents spurious `error`-level lines that routinely appear
810
+ * right next to a successful `persisted: N facts, M entities` log
811
+ * and that confuse operators into thinking extraction is broken.
812
+ * Genuine extraction failures (network, parse, I/O) still log at
813
+ * `error`.
814
+ *
815
+ * Source differentiates the two call sites so the log message
816
+ * names the right layer (`task` vs `processor`).
817
+ */
818
+ logExtractionQueueFailure(err, source) {
819
+ const aborted = source === "task" ? "background extraction task aborted (session transition)" : "background extraction queue processor aborted (session transition)";
820
+ const failed = source === "task" ? "background extraction task failed" : "background extraction queue processor failed";
821
+ if (isAbortError(err)) {
822
+ log.debug(aborted);
823
+ } else {
824
+ log.error(failed, err);
825
+ }
826
+ }
827
+ /**
828
+ * Wait until the extraction queue is fully drained (no tasks queued, no
829
+ * drain in flight) or `timeoutMs` elapses. Used by bootstrap (after a
830
+ * dry-run import) and by tests that need to assert extraction settled.
831
+ * Returns false on timeout, true once idle.
832
+ */
833
+ async waitForIdle(timeoutMs = 6e4) {
834
+ const started = Date.now();
835
+ while (this.processing || this.queue.length > 0) {
836
+ if (Date.now() - started > timeoutMs) {
837
+ log.warn(`waitForExtractionIdle timed out after ${timeoutMs}ms`);
838
+ return false;
839
+ }
840
+ const { promise, resolve } = Promise.withResolvers();
841
+ setTimeout(resolve, 50);
842
+ await promise;
843
+ }
844
+ return true;
845
+ }
846
+ // ── Test seams ─────────────────────────────────────────────────────────
847
+ // Mirror the pre-extraction `orchestrator.extractionQueue` /
848
+ // `orchestrator.queueProcessing` direct-field access the characterization
849
+ // and flush deadline tests relied on. Each is a thin, well-named handle
850
+ // onto the coordinator's private state — no behavior change.
851
+ /**
852
+ * Push a raw task WITHOUT auto-starting the processor, matching the
853
+ * pre-extraction `this.extractionQueue.push(...)` used by the
854
+ * characterization tests that drive the drain manually via `processQueue`.
855
+ */
856
+ pushRaw(task) {
857
+ this.queue.push(task);
858
+ }
859
+ /** Remove + return the front task (test seam for the flush deadline tests). */
860
+ shift() {
861
+ return this.queue.shift();
862
+ }
863
+ /**
864
+ * Force the processor-busy flag so `enqueue` does not auto-start the
865
+ * drain — used by the flush deadline test to simulate a busy queue and
866
+ * assert a queued task's deadline expires while it waits.
867
+ */
868
+ setProcessingForTest(value) {
869
+ this.processing = value;
870
+ }
871
+ };
872
+
748
873
  // src/maintenance/pattern-reinforcement.ts
749
874
  function patternReinforcementKey(content) {
750
875
  return content.trim().toLowerCase().replace(/\s+/g, " ").slice(0, 200);
@@ -2997,10 +3122,14 @@ var Orchestrator = class _Orchestrator {
2997
3122
  passiveCorrectionDedup = /* @__PURE__ */ new Set();
2998
3123
  _passiveCorrectionService = null;
2999
3124
  passiveCorrectionTelemetry = { detected: 0, queued: 0, autoApplied: 0, suppressedReasonCounts: {} };
3000
- // Background serial queue for extractions (agent_end optimization)
3001
- // Queue stores promises that resolve when extraction should run
3002
- extractionQueue = [];
3003
- queueProcessing = false;
3125
+ /**
3126
+ * Background serial extraction queue coordinator (issue #1526 moved
3127
+ * from inline `extractionQueue`/`queueProcessing` fields). Owns queue
3128
+ * state + scheduling + the serial drain + failure classification; the
3129
+ * orchestrator builds each task closure in `queueBufferedExtraction` and
3130
+ * hands it to `enqueue`.
3131
+ */
3132
+ extractionQueueCoordinator;
3004
3133
  heartbeatObserverChains = /* @__PURE__ */ new Map();
3005
3134
  recentExtractionFingerprints = /* @__PURE__ */ new Map();
3006
3135
  consolidationObservers = /* @__PURE__ */ new Set();
@@ -3705,6 +3834,7 @@ var Orchestrator = class _Orchestrator {
3705
3834
  namespaceSearchRouter: this.namespaceSearchRouter,
3706
3835
  namespaceCatalog: this.namespaceCatalog
3707
3836
  });
3837
+ this.extractionQueueCoordinator = new ExtractionQueueCoordinator();
3708
3838
  const conversationIndexRuntime = createConversationIndexRuntime(config, {
3709
3839
  getQmd: () => this.conversationQmd,
3710
3840
  getFaiss: () => this.conversationFaiss
@@ -3787,8 +3917,9 @@ var Orchestrator = class _Orchestrator {
3787
3917
  path3.join(config.memoryDir, "threads"),
3788
3918
  config.threadingGapMinutes
3789
3919
  );
3920
+ const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
3790
3921
  this.tmtBuilder = new TmtBuilder(config.memoryDir, {
3791
- temporalMemoryTreeEnabled: config.temporalMemoryTreeEnabled,
3922
+ temporalMemoryTreeEnabled: lifecycleCaps.temporalMemoryTree,
3792
3923
  tmtHourlyMinMemories: config.tmtHourlyMinMemories,
3793
3924
  tmtSummaryMaxTokens: config.tmtSummaryMaxTokens
3794
3925
  });
@@ -4182,6 +4313,7 @@ var Orchestrator = class _Orchestrator {
4182
4313
  }
4183
4314
  }
4184
4315
  async deferredInitialize(signal) {
4316
+ const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
4185
4317
  if (this.qmd.isAvailable() && this.config.qmdMaintenanceEnabled) {
4186
4318
  try {
4187
4319
  log.info("QMD startup sync: updating index to match current disk state");
@@ -4215,7 +4347,7 @@ var Orchestrator = class _Orchestrator {
4215
4347
  })
4216
4348
  );
4217
4349
  }
4218
- if (this.config.embeddingFallbackEnabled) {
4350
+ if (resolveMemoryLifecycleCapabilities(this.config).embeddingFallback) {
4219
4351
  warmupPromises.push(
4220
4352
  this.embeddingFallback.isAvailable().then((ok) => {
4221
4353
  log.info(
@@ -4279,9 +4411,9 @@ var Orchestrator = class _Orchestrator {
4279
4411
  if (signal.aborted) return;
4280
4412
  await this.maintenanceScheduler.autoRegisterCrons(signal);
4281
4413
  if (signal.aborted) return;
4282
- if (this.config.lifecyclePolicyEnabled && this.config.qmdTierMigrationEnabled) {
4414
+ if (lifecycleCaps.lifecyclePolicy && this.config.qmdTierMigrationEnabled) {
4283
4415
  try {
4284
- const { runFirstStartMigration } = await import("./first-start-migration-PG5HBC3K.js");
4416
+ const { runFirstStartMigration } = await import("./first-start-migration-22LPFHD5.js");
4285
4417
  const result = await runFirstStartMigration({
4286
4418
  storage: this.storage,
4287
4419
  config: this.config,
@@ -4506,6 +4638,7 @@ var Orchestrator = class _Orchestrator {
4506
4638
  * default storage.
4507
4639
  */
4508
4640
  async runLifecyclePolicyFanout() {
4641
+ const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
4509
4642
  return this.runNamespaceMaintenanceFanoutForJob(
4510
4643
  "lifecycle",
4511
4644
  async (ctx) => {
@@ -4514,7 +4647,7 @@ var Orchestrator = class _Orchestrator {
4514
4647
  const assessed = await this.runLifecyclePolicyPass(corpus, storage);
4515
4648
  return { itemCount: assessed };
4516
4649
  },
4517
- { enabled: this.config.lifecyclePolicyEnabled }
4650
+ { enabled: lifecycleCaps.lifecyclePolicy }
4518
4651
  );
4519
4652
  }
4520
4653
  /**
@@ -4924,15 +5057,7 @@ ${doc.content}` : doc.content,
4924
5057
  return result;
4925
5058
  }
4926
5059
  async waitForExtractionIdle(timeoutMs = 6e4) {
4927
- const started = Date.now();
4928
- while (this.queueProcessing || this.extractionQueue.length > 0) {
4929
- if (Date.now() - started > timeoutMs) {
4930
- log.warn(`waitForExtractionIdle timed out after ${timeoutMs}ms`);
4931
- return false;
4932
- }
4933
- await new Promise((resolve) => setTimeout(resolve, 50));
4934
- }
4935
- return true;
5060
+ return this.extractionQueueCoordinator.waitForIdle(timeoutMs);
4936
5061
  }
4937
5062
  async waitForConsolidationIdle(timeoutMs = 6e4) {
4938
5063
  const started = Date.now();
@@ -6832,7 +6957,7 @@ ${r.snippet.trim()}
6832
6957
  recallAssemblyClockMs() {
6833
6958
  return Date.now();
6834
6959
  }
6835
- async recallInternal(prompt, sessionKey, options = {}, caps = resolveCapabilities(this.config), graphCaps = resolveGraphConstructionCapabilities(this.config)) {
6960
+ async recallInternal(prompt, sessionKey, options = {}, caps = resolveCapabilities(this.config), graphCaps = resolveGraphConstructionCapabilities(this.config), lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config)) {
6836
6961
  const recallStart = Date.now();
6837
6962
  const backendDegradations = [];
6838
6963
  let asOfMs;
@@ -9409,8 +9534,8 @@ ${boxLines.join("\n")}`
9409
9534
  }
9410
9535
  if (this.isRecallSectionEnabled(
9411
9536
  "temporal-memory-tree",
9412
- this.config.temporalMemoryTreeEnabled === true
9413
- ) && this.config.temporalMemoryTreeEnabled && recallMode !== "minimal" && recallMode !== "no_recall") {
9537
+ lifecycleCaps.temporalMemoryTree
9538
+ ) && lifecycleCaps.temporalMemoryTree && recallMode !== "minimal" && recallMode !== "no_recall") {
9414
9539
  const tmtNode = await this.tmtBuilder.getMostRelevantNode();
9415
9540
  if (tmtNode) {
9416
9541
  const levelLabel = tmtNode.level.charAt(0).toUpperCase() + tmtNode.level.slice(1);
@@ -10073,7 +10198,7 @@ ${tmtNode.summary}`
10073
10198
  );
10074
10199
  if (memories.length > 0) {
10075
10200
  const supersessionOptions = {
10076
- enabled: this.config.temporalSupersessionEnabled,
10201
+ enabled: lifecycleCaps.temporalSupersession,
10077
10202
  includeInRecall: this.config.temporalSupersessionIncludeInRecall
10078
10203
  };
10079
10204
  const asOfActive = typeof asOfMs === "number" && Number.isFinite(asOfMs);
@@ -11157,7 +11282,7 @@ _Context: ${topQuestion.context}_`
11157
11282
  settleTask(new Error("replay extraction deadline exceeded (queue_wait)"));
11158
11283
  }, remainingMs);
11159
11284
  }
11160
- this.extractionQueue.push(async () => {
11285
+ this.extractionQueueCoordinator.enqueue(async () => {
11161
11286
  if (settled) return;
11162
11287
  if (typeof extractionDeadlineMs === "number" && extractionDeadlineMs <= Date.now()) {
11163
11288
  settleTask(new Error("replay extraction deadline exceeded (queue_wait)"));
@@ -11183,13 +11308,6 @@ _Context: ${topQuestion.context}_`
11183
11308
  }
11184
11309
  }
11185
11310
  });
11186
- if (!this.queueProcessing) {
11187
- this.queueProcessing = true;
11188
- this.processQueue().catch((err) => {
11189
- this.logExtractionQueueFailure(err, "processor");
11190
- this.queueProcessing = false;
11191
- });
11192
- }
11193
11311
  log.debug(`queued extraction from ${reason}`);
11194
11312
  }
11195
11313
  normalizeExtractionFingerprintTurns(turns) {
@@ -11208,7 +11326,8 @@ _Context: ${topQuestion.context}_`
11208
11326
  ${normalized}`).digest("hex");
11209
11327
  }
11210
11328
  shouldQueueExtraction(turns, options = {}) {
11211
- if (!this.config.extractionDedupeEnabled) return true;
11329
+ const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
11330
+ if (!lifecycleCaps.extractionDedupe) return true;
11212
11331
  if (!Array.isArray(turns) || turns.length === 0) return false;
11213
11332
  const bufferKey = options.bufferKey ?? turns[0]?.sessionKey ?? "default";
11214
11333
  const fingerprint = this.buildExtractionFingerprint(turns, bufferKey);
@@ -11232,50 +11351,6 @@ ${normalized}`).digest("hex");
11232
11351
  }
11233
11352
  return true;
11234
11353
  }
11235
- /**
11236
- * Background serial queue processor.
11237
- * Processes extractions one at a time to avoid race conditions.
11238
- * Called automatically when items are queued.
11239
- */
11240
- async processQueue() {
11241
- while (this.extractionQueue.length > 0) {
11242
- const task = this.extractionQueue.shift();
11243
- if (task) {
11244
- try {
11245
- await task();
11246
- } catch (err) {
11247
- this.logExtractionQueueFailure(err, "task");
11248
- }
11249
- }
11250
- }
11251
- this.queueProcessing = false;
11252
- }
11253
- /**
11254
- * Classify + log a failure from either the per-task catch inside
11255
- * `processQueue()` or the outer `processQueue().catch(...)` in
11256
- * `queueBufferedExtraction()`. Issue #549: `throwIfRecallAborted`
11257
- * (used throughout `runExtraction`) raises an Error whose `name` is
11258
- * `"AbortError"`. That path fires when `before_reset` aborts a
11259
- * queued task to avoid duplicate extraction — it is intentional
11260
- * cancellation, not a failure. Downgrading the log to debug
11261
- * prevents spurious `error`-level lines that routinely appear
11262
- * right next to a successful `persisted: N facts, M entities` log
11263
- * and that confuse operators into thinking extraction is broken.
11264
- * Genuine extraction failures (network, parse, I/O) still log at
11265
- * `error`.
11266
- *
11267
- * Source differentiates the two call sites so the log message
11268
- * names the right layer (`task` vs `processor`).
11269
- */
11270
- logExtractionQueueFailure(err, source) {
11271
- const aborted = source === "task" ? "background extraction task aborted (session transition)" : "background extraction queue processor aborted (session transition)";
11272
- const failed = source === "task" ? "background extraction task failed" : "background extraction queue processor failed";
11273
- if (isAbortError(err)) {
11274
- log.debug(aborted);
11275
- } else {
11276
- log.error(failed, err);
11277
- }
11278
- }
11279
11354
  /**
11280
11355
  * Passive correction capture (issue #1581) — detects corrections expressed
11281
11356
  * passively in conversation turns and routes them to the Correction Contract
@@ -11809,7 +11884,7 @@ ${normalized}`).digest("hex");
11809
11884
  requestQmdMaintenanceForTool(reason) {
11810
11885
  this.maintenanceScheduler.requestQmdMaintenanceForTool(reason);
11811
11886
  }
11812
- async persistExtraction(result, storage, threadIdForExtraction, sourceContext, baseNamespace, scopeProfileWritePlan, sourceText, graphCaps = resolveGraphConstructionCapabilities(this.config)) {
11887
+ async persistExtraction(result, storage, threadIdForExtraction, sourceContext, baseNamespace, scopeProfileWritePlan, sourceText, graphCaps = resolveGraphConstructionCapabilities(this.config), lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config)) {
11813
11888
  const citationEnabled = this.config.inlineSourceAttributionEnabled === true;
11814
11889
  const citationTemplate = this.config.inlineSourceAttributionFormat;
11815
11890
  const citationContextBase = citationEnabled ? {
@@ -11984,7 +12059,7 @@ ${normalized}`).digest("hex");
11984
12059
  ...options.provenance ? { provenance: options.provenance } : {}
11985
12060
  }
11986
12061
  );
11987
- if (this.config.temporalSupersessionEnabled && options.category === "fact" && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
12062
+ if (lifecycleCaps.temporalSupersession && options.category === "fact" && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
11988
12063
  try {
11989
12064
  await applyTemporalSupersession({
11990
12065
  storage: targetStorage,
@@ -12052,7 +12127,7 @@ ${normalized}`).digest("hex");
12052
12127
  options.entityRef
12053
12128
  );
12054
12129
  }
12055
- if (this.config.temporalSupersessionEnabled && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
12130
+ if (lifecycleCaps.temporalSupersession && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
12056
12131
  let hashDedupMatchingFact;
12057
12132
  let hashDedupLookupComplete = false;
12058
12133
  try {
@@ -12131,7 +12206,7 @@ ${normalized}`).digest("hex");
12131
12206
  ...options.provenance ? { provenance: options.provenance } : {}
12132
12207
  }
12133
12208
  );
12134
- if (this.config.temporalSupersessionEnabled && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
12209
+ if (lifecycleCaps.temporalSupersession && options.entityRef && options.structuredAttributes && Object.keys(options.structuredAttributes).length > 0) {
12135
12210
  try {
12136
12211
  await applyTemporalSupersession({
12137
12212
  storage: sharedStorage,
@@ -12309,7 +12384,7 @@ ${normalized}`).digest("hex");
12309
12384
  let judgeVerdictsByFactIndex = null;
12310
12385
  let judgeGatedCount = 0;
12311
12386
  this.lastPersistExtractionDeferredCount = 0;
12312
- if (this.config.extractionJudgeEnabled) {
12387
+ if (lifecycleCaps.extractionJudge) {
12313
12388
  let preJudgeRedactionRules = [];
12314
12389
  try {
12315
12390
  preJudgeRedactionRules = await redactionRulesFor(storage.dir);
@@ -12353,7 +12428,7 @@ ${normalized}`).digest("hex");
12353
12428
  candidateToFactIndex.push(fi);
12354
12429
  }
12355
12430
  const judgeTelemetryOpts = {
12356
- enabled: this.config.extractionJudgeTelemetryEnabled === true,
12431
+ enabled: lifecycleCaps.extractionJudgeTelemetry,
12357
12432
  memoryDir: this.config.memoryDir
12358
12433
  };
12359
12434
  const judgeTrainingOpts = {
@@ -12478,7 +12553,7 @@ ${normalized}`).digest("hex");
12478
12553
  );
12479
12554
  }
12480
12555
  }
12481
- if (this.config.extractionScopeClassificationEnabled && this.config.namespacesEnabled && fact.scope === "global" && !routedNamespaceExplicit) {
12556
+ if (lifecycleCaps.extractionScopeClassification && this.config.namespacesEnabled && fact.scope === "global" && !routedNamespaceExplicit) {
12482
12557
  const currentNs = this.storageDirNamespace(targetStorage.dir);
12483
12558
  if (currentNs !== this.config.sharedNamespace && profileAllowsSharedWrites) {
12484
12559
  try {
@@ -12840,7 +12915,7 @@ ${normalized}`).digest("hex");
12840
12915
  // #1578 r3: an extracted end-only bound (validFrom absent) is
12841
12916
  // historical, not a new authoritative state — never let it
12842
12917
  // supersede a later active fact (codex P1 on :15534).
12843
- enabled: this.config.temporalSupersessionEnabled && !(biTemporal && !biTemporal.validFrom)
12918
+ enabled: lifecycleCaps.temporalSupersession && !(biTemporal && !biTemporal.validFrom)
12844
12919
  });
12845
12920
  } catch (err) {
12846
12921
  log.warn(`temporal-supersession (chunked): unexpected error: ${err}`);
@@ -13003,7 +13078,7 @@ ${normalized}`).digest("hex");
13003
13078
  entityRef: supersessionEntityRef,
13004
13079
  structuredAttributes: fact.structuredAttributes,
13005
13080
  createdAt: supersessionOrderingAt(biTemporal?.validFrom ?? sourceContext?.validAt),
13006
- enabled: this.config.temporalSupersessionEnabled && !(biTemporal && !biTemporal.validFrom)
13081
+ enabled: lifecycleCaps.temporalSupersession && !(biTemporal && !biTemporal.validFrom)
13007
13082
  });
13008
13083
  } catch (err) {
13009
13084
  log.warn(`temporal-supersession: unexpected error: ${err}`);
@@ -13257,7 +13332,7 @@ ${normalized}`).digest("hex");
13257
13332
  }
13258
13333
  }
13259
13334
  async indexPersistedMemory(storage, memoryId) {
13260
- if (!this.config.embeddingFallbackEnabled) return;
13335
+ if (!resolveMemoryLifecycleCapabilities(this.config).embeddingFallback) return;
13261
13336
  if (!await this.embeddingFallback.isAvailable()) return;
13262
13337
  const memory = await storage.getMemoryById(memoryId);
13263
13338
  if (!memory) return;
@@ -13385,6 +13460,7 @@ ${normalized}`).digest("hex");
13385
13460
  /** IDs of facts persisted in the last extraction */
13386
13461
  lastPersistedIds = [];
13387
13462
  async runConsolidation() {
13463
+ const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
13388
13464
  log.info("running consolidation pass");
13389
13465
  let merged = 0;
13390
13466
  let invalidated = 0;
@@ -13549,7 +13625,7 @@ ${normalized}`).digest("hex");
13549
13625
  }
13550
13626
  }
13551
13627
  }
13552
- if (this.config.lifecyclePolicyEnabled) {
13628
+ if (lifecycleCaps.lifecyclePolicy) {
13553
13629
  try {
13554
13630
  const lightSleepStartedAt = (/* @__PURE__ */ new Date()).toISOString();
13555
13631
  const lifecycleCorpus = await this.storage.readAllMemories();
@@ -13699,7 +13775,7 @@ ${normalized}`).digest("hex");
13699
13775
  const meta = await this.storage.loadMeta();
13700
13776
  meta.lastConsolidationAt = (/* @__PURE__ */ new Date()).toISOString();
13701
13777
  await this.storage.saveMeta(meta);
13702
- if (this.config.temporalMemoryTreeEnabled) {
13778
+ if (lifecycleCaps.temporalMemoryTree) {
13703
13779
  try {
13704
13780
  const tmtEntries = allMemories.filter(
13705
13781
  (m) => m.frontmatter.status !== "superseded" && m.frontmatter.status !== "archived" && m.frontmatter.status !== "forgotten" && m.frontmatter.status !== "pending_review"
@@ -14095,6 +14171,7 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
14095
14171
  let updatedCount = 0;
14096
14172
  let disputedCount = 0;
14097
14173
  let evaluatedCount = 0;
14174
+ const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
14098
14175
  const thresholds = this.effectiveLifecycleThresholds();
14099
14176
  const policy = {
14100
14177
  promoteHeatThreshold: thresholds.promoteHeatThreshold,
@@ -14134,7 +14211,7 @@ ${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
14134
14211
  });
14135
14212
  if (wrote) updatedCount += 1;
14136
14213
  }
14137
- if (!this.config.lifecycleMetricsEnabled) return updatedCount;
14214
+ if (!lifecycleCaps.lifecycleMetrics) return updatedCount;
14138
14215
  const total = evaluatedCount;
14139
14216
  const metrics = {
14140
14217
  generatedAt: nowIso,
@@ -15137,7 +15214,7 @@ ${lines.join("\n\n")}`;
15137
15214
  * `memoryDir` root, an exclusion list for `namespaces/*`).
15138
15215
  */
15139
15216
  async semanticDedupLookup(content, limit, targetStorage) {
15140
- if (!this.config.embeddingFallbackEnabled) {
15217
+ if (!resolveMemoryLifecycleCapabilities(this.config).embeddingFallback) {
15141
15218
  throw new Error("semantic dedup: embedding backend not configured");
15142
15219
  }
15143
15220
  if (!await this.embeddingFallback.isAvailable()) {
@@ -15187,7 +15264,7 @@ ${lines.join("\n\n")}`;
15187
15264
  return { pathPrefix: rel };
15188
15265
  }
15189
15266
  async searchEmbeddingFallback(query, limit) {
15190
- if (!this.config.embeddingFallbackEnabled) return [];
15267
+ if (!resolveMemoryLifecycleCapabilities(this.config).embeddingFallback) return [];
15191
15268
  if (!await this.embeddingFallback.isAvailable()) return [];
15192
15269
  const hits = await this.embeddingFallback.search(query, limit);
15193
15270
  if (hits.length === 0) return [];
@@ -15710,6 +15787,7 @@ ${lines.join("\n\n")}`;
15710
15787
  return { memoryByPath, checkedPaths, unreadablePaths, completed: true };
15711
15788
  }
15712
15789
  filterSearchResultsByRecallSafety(results, memoryByPath, options) {
15790
+ const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
15713
15791
  let lifecycleFilteredCount = 0;
15714
15792
  let temporalSupersededFilteredCount = 0;
15715
15793
  let biTemporalExpiredFilteredCount = 0;
@@ -15730,8 +15808,8 @@ ${lines.join("\n\n")}`;
15730
15808
  continue;
15731
15809
  }
15732
15810
  if (options?.allowLifecycleFiltered !== true && shouldFilterLifecycleRecallCandidate(memory.frontmatter, {
15733
- lifecyclePolicyEnabled: this.config.lifecyclePolicyEnabled,
15734
- lifecycleFilterStaleEnabled: this.config.lifecycleFilterStaleEnabled
15811
+ lifecyclePolicyEnabled: lifecycleCaps.lifecyclePolicy,
15812
+ lifecycleFilterStaleEnabled: lifecycleCaps.lifecycleFilterStale
15735
15813
  })) {
15736
15814
  lifecycleFilteredCount += 1;
15737
15815
  continue;
@@ -15754,7 +15832,7 @@ ${lines.join("\n\n")}`;
15754
15832
  // half-open `[valid_at, invalid_at)` evaluation in isValidAsOf
15755
15833
  // is the authoritative gate for historical recall.
15756
15834
  shouldFilterSupersededFromRecall(memory.frontmatter, {
15757
- enabled: this.config.temporalSupersessionEnabled,
15835
+ enabled: lifecycleCaps.temporalSupersession,
15758
15836
  includeInRecall: this.config.temporalSupersessionIncludeInRecall
15759
15837
  })
15760
15838
  ) {
@@ -15844,6 +15922,7 @@ ${lines.join("\n\n")}`;
15844
15922
  * Returns re-ranked results.
15845
15923
  */
15846
15924
  async boostSearchResults(results, _recallNamespaces, prompt, preloadedMemoryMap, options) {
15925
+ const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
15847
15926
  if (results.length === 0) return results;
15848
15927
  const safety = await this.filterSearchResultsForRecall(
15849
15928
  results,
@@ -15977,7 +16056,7 @@ ${lines.join("\n\n")}`;
15977
16056
  const lifecycleDelta = lifecycleRecallScoreAdjustment(
15978
16057
  memory.frontmatter,
15979
16058
  {
15980
- lifecyclePolicyEnabled: this.config.lifecyclePolicyEnabled
16059
+ lifecyclePolicyEnabled: lifecycleCaps.lifecyclePolicy
15981
16060
  }
15982
16061
  );
15983
16062
  score += applyUtilityRankingRuntimeDelta(
@@ -16313,4 +16392,4 @@ export {
16313
16392
  resolvePersistedMemoryRelativePath,
16314
16393
  Orchestrator
16315
16394
  };
16316
- //# sourceMappingURL=chunk-XPHVAOBT.js.map
16395
+ //# sourceMappingURL=chunk-HEDZUSCS.js.map