@remnic/core 9.3.744 → 9.3.746

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 (242) hide show
  1. package/dist/access-boundary.d.ts +17 -15
  2. package/dist/access-boundary.js +14 -15
  3. package/dist/access-cli.js +92 -33
  4. package/dist/access-cli.js.map +1 -1
  5. package/dist/access-http.d.ts +17 -15
  6. package/dist/access-http.js +20 -21
  7. package/dist/access-mcp.d.ts +17 -15
  8. package/dist/access-mcp.js +18 -19
  9. package/dist/access-operations-batch.js +16 -17
  10. package/dist/access-operations.d.ts +17 -15
  11. package/dist/access-operations.js +17 -18
  12. package/dist/access-schema.js +3 -3
  13. package/dist/{access-service-OT3Gk79W.d.ts → access-service-Cx16nmCv.d.ts} +3 -30
  14. package/dist/access-service.d.ts +7 -5
  15. package/dist/access-service.js +13 -14
  16. package/dist/access-surface-catalog.d.ts +17 -15
  17. package/dist/action-confidence.d.ts +1 -1
  18. package/dist/active-memory-bridge.d.ts +1 -1
  19. package/dist/active-recall.d.ts +1 -1
  20. package/dist/{auto-sync-XHSKKQAH.js → auto-sync-IEBKPGAM.js} +2 -2
  21. package/dist/behavior-learner.d.ts +1 -1
  22. package/dist/behavior-signals.d.ts +1 -1
  23. package/dist/bootstrap.d.ts +6 -4
  24. package/dist/briefing.d.ts +1 -1
  25. package/dist/briefing.js +3 -3
  26. package/dist/buffer-surprise-report.d.ts +1 -1
  27. package/dist/buffer.d.ts +1 -1
  28. package/dist/calibration.d.ts +1 -1
  29. package/dist/capabilities.d.ts +1 -1
  30. package/dist/{catalog-CX0CjOaf.d.ts → catalog-D_ZDxu8Y.d.ts} +1 -1
  31. package/dist/causal-behavior.d.ts +1 -1
  32. package/dist/causal-consolidation.d.ts +1 -1
  33. package/dist/causal-consolidation.js +4 -4
  34. package/dist/causal-trajectory-graph.d.ts +1 -1
  35. package/dist/{chunk-WPLRJ4XM.js → chunk-24YDB5QP.js} +2098 -230
  36. package/dist/chunk-24YDB5QP.js.map +1 -0
  37. package/dist/{chunk-6XG3NQRC.js → chunk-3IJGF6K2.js} +2 -2
  38. package/dist/{chunk-U5WVRMCA.js → chunk-5IN26V6W.js} +2 -2
  39. package/dist/{chunk-XEADGIAA.js → chunk-DIHCFJVV.js} +7 -7
  40. package/dist/{chunk-C7LDPZJJ.js → chunk-EHYB325U.js} +227 -227
  41. package/dist/chunk-EHYB325U.js.map +1 -0
  42. package/dist/{chunk-E7RGJQWP.js → chunk-HIHCB2S6.js} +2 -2
  43. package/dist/{chunk-JFCS6PQU.js → chunk-JHQUIH3W.js} +5 -5
  44. package/dist/{chunk-MXDG6SRH.js → chunk-JRDPT6DA.js} +2 -2
  45. package/dist/{chunk-BYLC4DKI.js → chunk-KMNYXLPL.js} +2 -2
  46. package/dist/{chunk-TQPSOTC7.js → chunk-L4N7SVNN.js} +8 -10
  47. package/dist/{chunk-TQPSOTC7.js.map → chunk-L4N7SVNN.js.map} +1 -1
  48. package/dist/{chunk-DYK27X7V.js → chunk-LMFS64GY.js} +3 -3
  49. package/dist/{chunk-FWXLKH2H.js → chunk-NVYF5OB6.js} +3 -3
  50. package/dist/{chunk-G5FP7VSQ.js → chunk-P4FW3ZU5.js} +58 -60
  51. package/dist/{chunk-G5FP7VSQ.js.map → chunk-P4FW3ZU5.js.map} +1 -1
  52. package/dist/{chunk-SODQQCAZ.js → chunk-PJE6D3NH.js} +10362 -4909
  53. package/dist/chunk-PJE6D3NH.js.map +1 -0
  54. package/dist/{chunk-56F6EAQ6.js → chunk-Q3X7GUAQ.js} +2 -2
  55. package/dist/{chunk-7N7S2RKF.js → chunk-R2OAN6IP.js} +2 -2
  56. package/dist/{chunk-CHELXDTO.js → chunk-RB6A7OUN.js} +2 -2
  57. package/dist/{chunk-3EA5LIFJ.js → chunk-SIV3JZPP.js} +2 -2
  58. package/dist/{chunk-IP5SANO2.js → chunk-UIKZZ242.js} +2 -2
  59. package/dist/{chunk-UGFPGWJB.js → chunk-URQLO7BX.js} +2 -2
  60. package/dist/{chunk-5UNSGRCR.js → chunk-WK3NK6SP.js} +162 -16
  61. package/dist/chunk-WK3NK6SP.js.map +1 -0
  62. package/dist/{chunk-VE54E6RP.js → chunk-WWVXXSLF.js} +4 -6
  63. package/dist/{chunk-VE54E6RP.js.map → chunk-WWVXXSLF.js.map} +1 -1
  64. package/dist/{chunk-WO22UEM3.js → chunk-XTEWVF3C.js} +2 -2
  65. package/dist/{chunk-FCQ7ZYCQ.js → chunk-ZGAJB74V.js} +2 -2
  66. package/dist/{chunk-NBP3YHHS.js → chunk-ZGZNLRKF.js} +2 -2
  67. package/dist/{chunk-C7C5WIIF.js → chunk-ZPZ4VVLT.js} +2 -2
  68. package/dist/{cli-BQiTZ7Zs.d.ts → cli-D1y3vooB.d.ts} +3 -3
  69. package/dist/cli.d.ts +9 -7
  70. package/dist/cli.js +44 -46
  71. package/dist/compounding/engine.d.ts +1 -1
  72. package/dist/compounding/engine.js +3 -3
  73. package/dist/compounding/preference-consolidator.d.ts +1 -1
  74. package/dist/compression-optimizer.d.ts +1 -1
  75. package/dist/config.d.ts +1 -1
  76. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  77. package/dist/connectors/codex-materialize-runner.js +3 -3
  78. package/dist/connectors/codex-materialize.d.ts +1 -1
  79. package/dist/connectors/index.d.ts +1 -1
  80. package/dist/connectors/index.js +3 -3
  81. package/dist/consolidation-provenance-check.d.ts +1 -1
  82. package/dist/consolidation-undo.d.ts +1 -1
  83. package/dist/contradiction/index.d.ts +1 -1
  84. package/dist/contradiction/index.js +4 -4
  85. package/dist/conversation-index/backend.d.ts +1 -1
  86. package/dist/conversation-index/chunker.d.ts +1 -1
  87. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  88. package/dist/conversation-index/indexer.d.ts +1 -1
  89. package/dist/conversation-index/search.d.ts +1 -1
  90. package/dist/day-summary.d.ts +1 -1
  91. package/dist/delinearize.d.ts +1 -1
  92. package/dist/direct-answer-wiring.d.ts +1 -1
  93. package/dist/direct-answer.d.ts +1 -1
  94. package/dist/embedding-fallback.d.ts +1 -1
  95. package/dist/enrichment/index.d.ts +1 -1
  96. package/dist/entity-retrieval.d.ts +1 -1
  97. package/dist/entity-retrieval.js +3 -3
  98. package/dist/entity-schema.d.ts +1 -1
  99. package/dist/explicit-capture.d.ts +6 -4
  100. package/dist/extraction-faithfulness.d.ts +1 -1
  101. package/dist/extraction-judge-telemetry.d.ts +1 -1
  102. package/dist/extraction-judge-training.d.ts +1 -1
  103. package/dist/extraction-judge.d.ts +1 -1
  104. package/dist/extraction.d.ts +1 -1
  105. package/dist/fallback-llm.d.ts +1 -1
  106. package/dist/graph-dashboard-diff.d.ts +1 -1
  107. package/dist/graph-dashboard-key.d.ts +1 -1
  108. package/dist/graph-dashboard-parser.d.ts +1 -1
  109. package/dist/graph-edge-reinforcement.d.ts +1 -1
  110. package/dist/graph-snapshot.d.ts +1 -1
  111. package/dist/graph.d.ts +1 -1
  112. package/dist/identity-continuity.d.ts +1 -1
  113. package/dist/importance.d.ts +1 -1
  114. package/dist/index.d.ts +12 -10
  115. package/dist/index.js +271 -5362
  116. package/dist/index.js.map +1 -1
  117. package/dist/intent.d.ts +1 -1
  118. package/dist/lcm/engine.d.ts +1 -1
  119. package/dist/lcm/index.d.ts +1 -1
  120. package/dist/lcm/tools.d.ts +1 -1
  121. package/dist/lifecycle.d.ts +1 -1
  122. package/dist/live-connectors-runner.d.ts +1 -1
  123. package/dist/local-llm.d.ts +1 -1
  124. package/dist/local-model-endpoint.d.ts +1 -1
  125. package/dist/maintenance/memory-governance.d.ts +1 -1
  126. package/dist/maintenance/memory-governance.js +3 -3
  127. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  128. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  129. package/dist/mcp-memory-inspector-app.d.ts +16 -14
  130. package/dist/memory-action-policy.d.ts +1 -1
  131. package/dist/memory-cache.d.ts +1 -1
  132. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  133. package/dist/memory-projection-store.d.ts +1 -1
  134. package/dist/memory-provenance.d.ts +1 -1
  135. package/dist/memory-worth-outcomes.d.ts +1 -1
  136. package/dist/models-json.d.ts +1 -1
  137. package/dist/namespaces/migrate.d.ts +2 -2
  138. package/dist/namespaces/migrate.js +4 -4
  139. package/dist/namespaces/principal.d.ts +1 -1
  140. package/dist/namespaces/search.d.ts +1 -1
  141. package/dist/namespaces/storage.d.ts +2 -2
  142. package/dist/namespaces/storage.js +3 -3
  143. package/dist/native-knowledge.d.ts +1 -1
  144. package/dist/operator-toolkit.d.ts +1 -1
  145. package/dist/operator-toolkit.js +10 -11
  146. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  147. package/dist/orchestration/maintenance.d.ts +2 -2
  148. package/dist/orchestration/maintenance.js +5 -5
  149. package/dist/{orchestrator-BPQGHpJz.d.ts → orchestrator-CnCE3Hvq.d.ts} +180 -12
  150. package/dist/orchestrator.d.ts +6 -4
  151. package/dist/orchestrator.js +119 -16
  152. package/dist/patterns-cli.d.ts +1 -1
  153. package/dist/policy-runtime.d.ts +1 -1
  154. package/dist/provenance.d.ts +1 -1
  155. package/dist/qmd-recall-cache.d.ts +1 -1
  156. package/dist/qmd.d.ts +1 -1
  157. package/dist/recall-disclosure-escalation.d.ts +1 -1
  158. package/dist/recall-explain-renderer.d.ts +1 -1
  159. package/dist/recall-planner-llm.d.ts +1 -1
  160. package/dist/recall-state.d.ts +1 -1
  161. package/dist/recall-tag-filter.d.ts +1 -1
  162. package/dist/recall-xray-cli.d.ts +1 -1
  163. package/dist/recall-xray-renderer.d.ts +1 -1
  164. package/dist/recall-xray.d.ts +1 -1
  165. package/dist/resolve-auth-token.d.ts +1 -1
  166. package/dist/retrieval-agents.d.ts +1 -1
  167. package/dist/retrieval-tiers.d.ts +1 -1
  168. package/dist/routing/engine.d.ts +1 -1
  169. package/dist/routing/store.d.ts +1 -1
  170. package/dist/search/embed-helper.d.ts +1 -1
  171. package/dist/search/factory.d.ts +1 -1
  172. package/dist/search/index.d.ts +1 -1
  173. package/dist/search/lancedb-backend.d.ts +1 -1
  174. package/dist/search/meilisearch-backend.d.ts +1 -1
  175. package/dist/search/noop-backend.d.ts +1 -1
  176. package/dist/search/orama-backend.d.ts +1 -1
  177. package/dist/search/port.d.ts +1 -1
  178. package/dist/search/remote-backend.d.ts +1 -1
  179. package/dist/{semantic-consolidation-ByzGwC9c.d.ts → semantic-consolidation-D3aSiu9t.d.ts} +1 -1
  180. package/dist/semantic-consolidation.d.ts +2 -2
  181. package/dist/semantic-consolidation.js +4 -4
  182. package/dist/semantic-rule-promotion.js +3 -3
  183. package/dist/semantic-rule-verifier.d.ts +1 -1
  184. package/dist/semantic-rule-verifier.js +3 -3
  185. package/dist/session-observer-bands.d.ts +1 -1
  186. package/dist/session-observer-state.d.ts +1 -1
  187. package/dist/shared-context/manager.d.ts +1 -1
  188. package/dist/signal.d.ts +1 -1
  189. package/dist/storage.d.ts +1 -1
  190. package/dist/storage.js +2 -2
  191. package/dist/summarizer.d.ts +1 -1
  192. package/dist/summary-snapshot.d.ts +1 -1
  193. package/dist/temporal-supersession.d.ts +1 -1
  194. package/dist/temporal-validity.d.ts +1 -1
  195. package/dist/threading.d.ts +1 -1
  196. package/dist/tier-migration.d.ts +1 -1
  197. package/dist/tier-routing.d.ts +1 -1
  198. package/dist/topics.d.ts +1 -1
  199. package/dist/transcript.d.ts +1 -1
  200. package/dist/transfer/backup.js +2 -2
  201. package/dist/transfer/capsule-export.js +2 -2
  202. package/dist/transfer/capsule-import.js +1 -1
  203. package/dist/trust-score-stage.d.ts +1 -1
  204. package/dist/trust-score.d.ts +1 -1
  205. package/dist/{types-5Jik3r4G.d.ts → types-CZm6rx9-.d.ts} +1 -1
  206. package/dist/types.d.ts +1 -1
  207. package/dist/utility-runtime.d.ts +1 -1
  208. package/dist/verified-recall.js +3 -3
  209. package/package.json +2 -2
  210. package/src/index.ts +2 -0
  211. package/src/orchestration/consolidation-run.ts +633 -0
  212. package/src/orchestration/extraction-persist.ts +2785 -0
  213. package/src/orchestration/extraction-run.ts +874 -0
  214. package/src/orchestrator.ts +206 -3815
  215. package/dist/chunk-5UNSGRCR.js.map +0 -1
  216. package/dist/chunk-A2KKLCOS.js +0 -1889
  217. package/dist/chunk-A2KKLCOS.js.map +0 -1
  218. package/dist/chunk-AVBT5WEW.js +0 -153
  219. package/dist/chunk-AVBT5WEW.js.map +0 -1
  220. package/dist/chunk-C7LDPZJJ.js.map +0 -1
  221. package/dist/chunk-SODQQCAZ.js.map +0 -1
  222. package/dist/chunk-WPLRJ4XM.js.map +0 -1
  223. /package/dist/{auto-sync-XHSKKQAH.js.map → auto-sync-IEBKPGAM.js.map} +0 -0
  224. /package/dist/{chunk-6XG3NQRC.js.map → chunk-3IJGF6K2.js.map} +0 -0
  225. /package/dist/{chunk-U5WVRMCA.js.map → chunk-5IN26V6W.js.map} +0 -0
  226. /package/dist/{chunk-XEADGIAA.js.map → chunk-DIHCFJVV.js.map} +0 -0
  227. /package/dist/{chunk-E7RGJQWP.js.map → chunk-HIHCB2S6.js.map} +0 -0
  228. /package/dist/{chunk-JFCS6PQU.js.map → chunk-JHQUIH3W.js.map} +0 -0
  229. /package/dist/{chunk-MXDG6SRH.js.map → chunk-JRDPT6DA.js.map} +0 -0
  230. /package/dist/{chunk-BYLC4DKI.js.map → chunk-KMNYXLPL.js.map} +0 -0
  231. /package/dist/{chunk-DYK27X7V.js.map → chunk-LMFS64GY.js.map} +0 -0
  232. /package/dist/{chunk-FWXLKH2H.js.map → chunk-NVYF5OB6.js.map} +0 -0
  233. /package/dist/{chunk-56F6EAQ6.js.map → chunk-Q3X7GUAQ.js.map} +0 -0
  234. /package/dist/{chunk-7N7S2RKF.js.map → chunk-R2OAN6IP.js.map} +0 -0
  235. /package/dist/{chunk-CHELXDTO.js.map → chunk-RB6A7OUN.js.map} +0 -0
  236. /package/dist/{chunk-3EA5LIFJ.js.map → chunk-SIV3JZPP.js.map} +0 -0
  237. /package/dist/{chunk-IP5SANO2.js.map → chunk-UIKZZ242.js.map} +0 -0
  238. /package/dist/{chunk-UGFPGWJB.js.map → chunk-URQLO7BX.js.map} +0 -0
  239. /package/dist/{chunk-WO22UEM3.js.map → chunk-XTEWVF3C.js.map} +0 -0
  240. /package/dist/{chunk-FCQ7ZYCQ.js.map → chunk-ZGAJB74V.js.map} +0 -0
  241. /package/dist/{chunk-NBP3YHHS.js.map → chunk-ZGZNLRKF.js.map} +0 -0
  242. /package/dist/{chunk-C7C5WIIF.js.map → chunk-ZPZ4VVLT.js.map} +0 -0
@@ -0,0 +1,633 @@
1
+ /**
2
+ * Consolidation-run coordinator — extracted from the orchestrator
3
+ * (issue #1526, seam 17).
4
+ *
5
+ * Owns the full consolidation maintenance pass:
6
+ * - `run()` — the main consolidation cycle (LLM merge/invalidate/update
7
+ * → entity-file merge → commitment cleanup → TTL cleanup → lifecycle
8
+ * policy → compression guideline learning → tier migration → fact
9
+ * archival → semantic consolidation → identity consolidation → profile
10
+ * consolidation → summarization → topic extraction → TMT rebuild)
11
+ * - `recordScheduledDreamsPhaseRun` — dream-phase ledger recording
12
+ * - `runFactArchival` / `runSummarization` / `runTopicExtraction` —
13
+ * thin delegates to LifecyclePolicyCoordinator
14
+ * - `runCompressionGuidelineLearningPass` — thin delegate to
15
+ * CompressionGuidelineCoordinator
16
+ *
17
+ * The orchestrator constructs one instance and delegates the consolidation
18
+ * pass to it. Everything that must stay orchestrator-owned (access tracking,
19
+ * embedding index, entity synthesis, tier migration, semantic consolidation,
20
+ * identity consolidation, recall section config, fast LLM) arrives as
21
+ * injectable delegates.
22
+ *
23
+ * Behavior-preserving move from orchestrator.ts. No logic changes — the
24
+ * orchestrator keeps a thin delegating method so existing call sites
25
+ * (runConsolidationNow, maintenance scheduler) and tests continue to work.
26
+ */
27
+
28
+ import path from "node:path";
29
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
30
+ import { log } from "../logger.js";
31
+ import { applyCommitmentLedgerLifecycle } from "../commitment-ledger.js";
32
+ import { recordDreamsPhaseRun } from "../maintenance/dreams-ledger.js";
33
+ import { clearIndexes, deindexMemory, indexMemoriesBatch, indexesExist } from "../temporal-index.js";
34
+ import { isActiveMemoryStatus } from "../memory-lifecycle-ledger-utils.js";
35
+ import {
36
+ resolveConsolidationCapabilities,
37
+ resolveCreationMemoryCapabilities,
38
+ resolveIndexingCapabilities,
39
+ resolveMemoryLifecycleCapabilities,
40
+ resolvePipelineProcessingCapabilities,
41
+ resolvePresentationCapabilities,
42
+ resolveRecallEnhancementCapabilities,
43
+ type MemoryLifecycleCapabilitySet,
44
+ } from "../capabilities.js";
45
+ import type { LifecyclePolicyCoordinator } from "./lifecycle-policy-coordinator.js";
46
+ import type { CompressionGuidelineCoordinator } from "./compression-guideline-coordinator.js";
47
+ import type { SemanticConsolidationCoordinator } from "./semantic-consolidation-coordinator.js";
48
+ import type { EntitySynthesisCoordinator } from "./entity-synthesis-coordinator.js";
49
+ import type { RecallSectionCoordinator } from "./recall-section-coordinator.js";
50
+ import type { TierMigrationCoordinator } from "./tier-migration-coordinator.js";
51
+ import type { StorageManager } from "../index.js";
52
+ import type { NamespaceStorageRouter } from "../namespaces/storage.js";
53
+ import type { ExtractionEngine } from "../extraction.js";
54
+ import type { EmbeddingFallback } from "../embedding-fallback.js";
55
+ import type { TmtBuilder } from "../tmt.js";
56
+ import type {
57
+ ConsolidationObservation,
58
+ MemoryFile,
59
+ PluginConfig,
60
+ RecallSectionConfig,
61
+ } from "../types.js";
62
+
63
+ /** Dependencies injected by the orchestrator. Stable references or live
64
+ * accessors — lazy getters for mutable fields tests reassign
65
+ * post-construction (storage, extraction, storageRouter). */
66
+ export interface ConsolidationRunCoordinatorDeps {
67
+ config: PluginConfig;
68
+ getStorage: () => StorageManager;
69
+ getStorageRouter: () => NamespaceStorageRouter;
70
+ getExtraction: () => ExtractionEngine;
71
+ embeddingFallback: EmbeddingFallback;
72
+ tmtBuilder: TmtBuilder;
73
+ consolidationObservers: Set<
74
+ (observation: ConsolidationObservation) => Promise<void> | void
75
+ >;
76
+ getAccessTrackingBuffer: () => Map<
77
+ string,
78
+ { count: number; lastAccessed: string }
79
+ >;
80
+
81
+ lifecyclePolicyCoordinator: LifecyclePolicyCoordinator;
82
+ compressionGuidelineCoordinator: CompressionGuidelineCoordinator;
83
+ semanticConsolidationCoordinator: SemanticConsolidationCoordinator;
84
+ entitySynthesisCoordinator: EntitySynthesisCoordinator;
85
+ recallSectionCoordinator: RecallSectionCoordinator;
86
+ tierMigrationCoordinator: TierMigrationCoordinator;
87
+
88
+ flushAccessTracking: () => Promise<void>;
89
+ indexPersistedMemory: (storage: StorageManager, memoryId: string) => Promise<void>;
90
+ autoConsolidateIdentity: () => Promise<void>;
91
+ fastChatCompletion: (
92
+ messages: Array<{ role: string; content: string }>,
93
+ options: {
94
+ temperature?: number;
95
+ maxTokens?: number;
96
+ timeoutMs?: number;
97
+ operation?: string;
98
+ priority?: "background" | "recall-critical";
99
+ },
100
+ ) => Promise<{ content: string } | null>;
101
+ }
102
+
103
+ export class ConsolidationRunCoordinator {
104
+ constructor(private readonly deps: ConsolidationRunCoordinatorDeps) {}
105
+
106
+ async run(): Promise<{
107
+ memoriesProcessed: number;
108
+ merged: number;
109
+ invalidated: number;
110
+ }> {
111
+ const config = this.deps.config;
112
+ const storage = this.deps.getStorage();
113
+ const lifecycleCaps = resolveMemoryLifecycleCapabilities(config);
114
+ log.info("running consolidation pass");
115
+ let merged = 0;
116
+ let invalidated = 0;
117
+ // Tracks whether any consolidation memory-item action (UPDATE / MERGE /
118
+ // INVALIDATE) durably rewrote memory state. A consolidation pass that only
119
+ // mutates memory items (no profile/entity updates) still changes the default
120
+ // namespace's data, so its catalog `lastWriteAt` must refresh too (NIBOi).
121
+ let memoryItemMutated = false;
122
+
123
+ // Flush access tracking buffer first
124
+ if (this.deps.getAccessTrackingBuffer().size > 0) {
125
+ await this.deps.flushAccessTracking();
126
+ }
127
+
128
+ let allMemories = await storage.readAllMemories();
129
+ if (allMemories.length < 5) {
130
+ return { memoriesProcessed: allMemories.length, merged, invalidated };
131
+ }
132
+
133
+ const recent = allMemories
134
+ .sort(
135
+ (a, b) =>
136
+ new Date(b.frontmatter.created).getTime() -
137
+ new Date(a.frontmatter.created).getTime(),
138
+ )
139
+ .slice(0, 20);
140
+
141
+ const older = allMemories.sort(
142
+ (a, b) =>
143
+ new Date(a.frontmatter.created).getTime() -
144
+ new Date(b.frontmatter.created).getTime(),
145
+ );
146
+
147
+ const profile = await storage.readProfile();
148
+ const result = await this.deps.getExtraction().consolidate(recent, older, profile);
149
+
150
+ // Build a lookup map from the already-loaded corpus to avoid repeated
151
+ // readAllMemories() scans inside getMemoryById for pre-action deindex reads.
152
+ const memoryLookup = resolveIndexingCapabilities(config).queryAwareIndexing
153
+ ? new Map(allMemories.map((m) => [m.frontmatter.id, m]))
154
+ : null;
155
+
156
+ for (const item of result.items) {
157
+ switch (item.action) {
158
+ case "INVALIDATE": {
159
+ // Capture path/frontmatter before invalidation for index cleanup
160
+ const toInvalidate = resolveIndexingCapabilities(config).queryAwareIndexing
161
+ ? (memoryLookup?.get(item.existingId) ?? null)
162
+ : null;
163
+ if (await storage.invalidateMemory(item.existingId)) {
164
+ invalidated += 1;
165
+ memoryItemMutated = true;
166
+ await this.deps.embeddingFallback.removeFromIndex(item.existingId);
167
+ if (toInvalidate?.path && toInvalidate.frontmatter?.created) {
168
+ deindexMemory(
169
+ config.memoryDir,
170
+ toInvalidate.path,
171
+ toInvalidate.frontmatter.created,
172
+ toInvalidate.frontmatter.tags ?? [],
173
+ );
174
+ }
175
+ }
176
+ break;
177
+ }
178
+ case "UPDATE":
179
+ if (item.updatedContent) {
180
+ await storage.updateMemory(
181
+ item.existingId,
182
+ item.updatedContent,
183
+ {
184
+ lineage: [item.existingId],
185
+ },
186
+ );
187
+ memoryItemMutated = true;
188
+ await this.deps.indexPersistedMemory(storage, item.existingId);
189
+ // updateMemory() only changes content/updated/lineage — path, created, and tags
190
+ // are preserved, so the temporal/tag index entry is already correct; no reindex needed.
191
+ }
192
+ break;
193
+ case "MERGE":
194
+ if (item.updatedContent && item.mergeWith) {
195
+ await storage.updateMemory(
196
+ item.existingId,
197
+ item.updatedContent,
198
+ {
199
+ supersedes: item.mergeWith,
200
+ lineage: [item.existingId, item.mergeWith],
201
+ },
202
+ );
203
+ memoryItemMutated = true;
204
+ await this.deps.indexPersistedMemory(storage, item.existingId);
205
+ // updateMemory() only changes content/updated/supersedes/lineage — path, created, and tags
206
+ // are preserved, so the temporal/tag index entry for the survivor is already correct.
207
+ // Capture before invalidation for index cleanup
208
+ const toMergeInvalidate = resolveIndexingCapabilities(config).queryAwareIndexing
209
+ ? (memoryLookup?.get(item.mergeWith) ?? null)
210
+ : null;
211
+ if (await storage.invalidateMemory(item.mergeWith)) {
212
+ invalidated += 1;
213
+ merged += 1;
214
+ await this.deps.embeddingFallback.removeFromIndex(item.mergeWith);
215
+ if (
216
+ toMergeInvalidate?.path &&
217
+ toMergeInvalidate.frontmatter?.created
218
+ ) {
219
+ deindexMemory(
220
+ config.memoryDir,
221
+ toMergeInvalidate.path,
222
+ toMergeInvalidate.frontmatter.created,
223
+ toMergeInvalidate.frontmatter.tags ?? [],
224
+ );
225
+ }
226
+ }
227
+ }
228
+ break;
229
+ }
230
+ }
231
+
232
+ if (result.profileUpdates.length > 0) {
233
+ await storage.appendToProfile(result.profileUpdates);
234
+ }
235
+
236
+ for (const entity of result.entityUpdates) {
237
+ const safeFacts = Array.isArray(entity.facts)
238
+ ? entity.facts.filter((f): f is string => typeof f === "string")
239
+ : [];
240
+ await storage.writeEntity(entity.name, entity.type, safeFacts, {
241
+ source: "consolidation",
242
+ structuredSections: Array.isArray(entity.structuredSections)
243
+ ? entity.structuredSections
244
+ : undefined,
245
+ });
246
+ }
247
+
248
+ // Catalog write touch accounting (issue #1499 sweep): consolidation persists
249
+ // durable mutations directly to the default-namespace storage, bypassing
250
+ // the extraction write path. We do NOT touch here — later maintenance steps in
251
+ // this same function (entity-file merges, expired-commitment / TTL cleanup,
252
+ // fact archival) can ALSO mutate the namespace on a run with no LLM outputs
253
+ // (NIjwl). So we accumulate every durable mutation into `memoryItemMutated` and
254
+ // record ONE consolidated touch AFTER all mutation-producing steps complete,
255
+ // just before returning (rule #25: touch after the write commits). LLM
256
+ // profile/entity updates and memory-item actions (UPDATE / MERGE / INVALIDATE)
257
+ // count here (NIBOi).
258
+ if (result.profileUpdates.length > 0 || result.entityUpdates.length > 0) {
259
+ memoryItemMutated = true;
260
+ }
261
+
262
+ // Merge fragmented entity files
263
+ const entitiesMerged = await storage.mergeFragmentedEntities();
264
+ if (entitiesMerged > 0) {
265
+ memoryItemMutated = true;
266
+ log.info(`merged ${entitiesMerged} fragmented entity files`);
267
+ }
268
+
269
+ if (resolvePresentationCapabilities(config).entitySummary) {
270
+ try {
271
+ const synthesized = await this.deps.entitySynthesisCoordinator.processQueue(
272
+ config.defaultNamespace,
273
+ 5,
274
+ );
275
+ if (synthesized > 0) {
276
+ // Entity synthesis rewrites entity files — a durable namespace mutation,
277
+ // so record it for the catalog touch even when it is the only change in
278
+ // the pass (codex). Otherwise lastWriteAt goes stale.
279
+ memoryItemMutated = true;
280
+ log.info(`refreshed ${synthesized} entity syntheses`);
281
+ }
282
+ } catch (err) {
283
+ log.debug(`entity synthesis pass failed: ${err}`);
284
+ }
285
+ }
286
+
287
+ // Clean expired commitments
288
+ const deletedCommitments = await storage.cleanExpiredCommitments(
289
+ config.commitmentDecayDays,
290
+ );
291
+ if (deletedCommitments.length > 0) {
292
+ memoryItemMutated = true;
293
+ log.info(`cleaned ${deletedCommitments.length} expired commitments`);
294
+ if (resolveIndexingCapabilities(config).queryAwareIndexing) {
295
+ for (const m of deletedCommitments) {
296
+ deindexMemory(
297
+ config.memoryDir,
298
+ m.path,
299
+ m.frontmatter.created,
300
+ m.frontmatter.tags ?? [],
301
+ );
302
+ }
303
+ }
304
+ }
305
+
306
+ if (
307
+ resolveCreationMemoryCapabilities(config).creationMemory &&
308
+ resolveCreationMemoryCapabilities(config).commitmentLedger &&
309
+ resolveCreationMemoryCapabilities(config).commitmentLifecycle
310
+ ) {
311
+ try {
312
+ const lifecycle = await applyCommitmentLedgerLifecycle({
313
+ memoryDir: config.memoryDir,
314
+ commitmentLedgerDir: config.commitmentLedgerDir,
315
+ enabled: true,
316
+ decayDays: config.commitmentDecayDays,
317
+ });
318
+ if (
319
+ lifecycle.transitionedToExpired.length > 0 ||
320
+ lifecycle.deletedResolved.length > 0
321
+ ) {
322
+ memoryItemMutated = true;
323
+ log.info(
324
+ `commitment ledger lifecycle: expired ${lifecycle.transitionedToExpired.length}, cleaned ${lifecycle.deletedResolved.length}`,
325
+ );
326
+ }
327
+ } catch (err) {
328
+ log.debug(`commitment ledger lifecycle pass failed: ${err}`);
329
+ }
330
+ }
331
+
332
+ // Clean memories past their TTL (speculative memories auto-expire)
333
+ const deletedTTL = await storage.cleanExpiredTTL();
334
+ if (deletedTTL.length > 0) {
335
+ memoryItemMutated = true;
336
+ log.info(`cleaned ${deletedTTL.length} TTL-expired memories`);
337
+ if (resolveIndexingCapabilities(config).queryAwareIndexing) {
338
+ for (const m of deletedTTL) {
339
+ deindexMemory(
340
+ config.memoryDir,
341
+ m.path,
342
+ m.frontmatter.created,
343
+ m.frontmatter.tags ?? [],
344
+ );
345
+ }
346
+ }
347
+ }
348
+
349
+ // v8.3 Lifecycle policy pass — deterministic promotion/decay metadata
350
+ if (lifecycleCaps.lifecyclePolicy) {
351
+ try {
352
+ const lightSleepStartedAt = new Date().toISOString();
353
+ const lifecycleCorpus = await storage.readAllMemories();
354
+ // Lifecycle frontmatter writes count as durable mutations for the catalog
355
+ // touch below (codex NR-tS), even when no other consolidation step set
356
+ // memoryItemMutated.
357
+ if ((await this.deps.lifecyclePolicyCoordinator.runLifecyclePolicyPass(lifecycleCorpus, storage)) > 0) {
358
+ memoryItemMutated = true;
359
+ }
360
+ await this.recordScheduledDreamsPhaseRun(
361
+ "lightSleep",
362
+ lifecycleCorpus.length,
363
+ `scheduled lifecycle policy pass assessed ${lifecycleCorpus.length} memories`,
364
+ {
365
+ startedAt: lightSleepStartedAt,
366
+ completedAt: new Date().toISOString(),
367
+ },
368
+ );
369
+ } catch (err) {
370
+ log.warn(`lifecycle policy pass failed (ignored): ${err}`);
371
+ }
372
+ }
373
+
374
+ // v8.3 Compression guideline learning pass (default off, fail-open).
375
+ await this.deps.compressionGuidelineCoordinator.runCompressionGuidelineLearningPass();
376
+
377
+ try {
378
+ const deepSleepStartedAt = new Date().toISOString();
379
+ // Tier migrations move/rewrite memory files; count them as durable
380
+ // mutations for the catalog touch below (codex NThSW).
381
+ const tierMigration = await this.deps.tierMigrationCoordinator.runCycle(storage, "maintenance");
382
+ if (tierMigration.migrated > 0) memoryItemMutated = true;
383
+ allMemories = await storage.readAllMemories();
384
+
385
+ // Fact archival pass (v6.0) — move old, low-importance, rarely-accessed facts to archive/
386
+ if (resolveRecallEnhancementCapabilities(config).factArchival) {
387
+ const archived = await this.deps.lifecyclePolicyCoordinator.runFactArchival(allMemories);
388
+ if (archived > 0) {
389
+ memoryItemMutated = true;
390
+ log.info(`archived ${archived} old low-importance facts`);
391
+ }
392
+ }
393
+ await this.recordScheduledDreamsPhaseRun(
394
+ "deepSleep",
395
+ allMemories.length,
396
+ `scheduled deep-sleep maintenance assessed ${allMemories.length} memories`,
397
+ {
398
+ startedAt: deepSleepStartedAt,
399
+ completedAt: new Date().toISOString(),
400
+ },
401
+ );
402
+ } catch (err) {
403
+ log.warn(`deep-sleep maintenance pass failed (ignored): ${err}`);
404
+ try {
405
+ allMemories = await storage.readAllMemories();
406
+ } catch (readErr) {
407
+ log.warn(`deep-sleep maintenance recovery read failed: ${readErr}`);
408
+ throw err;
409
+ }
410
+ }
411
+
412
+ // Semantic consolidation pass — find similar memories, synthesize canonical versions
413
+ if (resolveConsolidationCapabilities(config).semanticConsolidation) {
414
+ try {
415
+ const stateFilePath = path.join(
416
+ config.memoryDir,
417
+ "state",
418
+ "semantic-consolidation-last-run.json",
419
+ );
420
+ let shouldRun = true;
421
+ try {
422
+ const stateRaw = await readFile(stateFilePath, "utf-8");
423
+ const stateData = JSON.parse(stateRaw) as { lastRunAt?: string };
424
+ if (stateData.lastRunAt) {
425
+ const lastRunMs = new Date(stateData.lastRunAt).getTime();
426
+ const intervalMs =
427
+ config.semanticConsolidationIntervalHours * 60 * 60 * 1000;
428
+ if (Date.now() - lastRunMs < intervalMs) {
429
+ shouldRun = false;
430
+ log.debug(
431
+ "[semantic-consolidation] skipping — not enough time since last run",
432
+ );
433
+ }
434
+ }
435
+ } catch {
436
+ // No state file yet — first run
437
+ }
438
+
439
+ if (shouldRun) {
440
+ const remStartedAt = new Date().toISOString();
441
+ const semResult = await this.deps.semanticConsolidationCoordinator.runSemanticConsolidation();
442
+ let remItemsProcessed = allMemories.length;
443
+ try {
444
+ allMemories = await storage.readAllMemories();
445
+ remItemsProcessed = allMemories.length;
446
+ } catch (err) {
447
+ log.warn(
448
+ `[semantic-consolidation] post-run telemetry refresh failed (non-fatal): ${err}`,
449
+ );
450
+ }
451
+ await this.recordScheduledDreamsPhaseRun(
452
+ "rem",
453
+ remItemsProcessed,
454
+ `scheduled REM consolidation found ${semResult.clustersFound} clusters`,
455
+ {
456
+ startedAt: remStartedAt,
457
+ completedAt: new Date().toISOString(),
458
+ },
459
+ );
460
+ if (semResult.memoriesArchived > 0) {
461
+ log.info(
462
+ `[semantic-consolidation] archived ${semResult.memoriesArchived} memories during maintenance`,
463
+ );
464
+ }
465
+ // Only persist last-run timestamp if the run succeeded (had no errors or made progress)
466
+ if (semResult.errors === 0 || semResult.memoriesArchived > 0) {
467
+ const stateDir = path.join(config.memoryDir, "state");
468
+ await mkdir(stateDir, { recursive: true });
469
+ await writeFile(
470
+ stateFilePath,
471
+ JSON.stringify({ lastRunAt: new Date().toISOString() }),
472
+ "utf-8",
473
+ );
474
+ }
475
+ }
476
+ } catch (err) {
477
+ log.warn(
478
+ `[semantic-consolidation] maintenance pass failed (non-fatal): ${err}`,
479
+ );
480
+ }
481
+ }
482
+
483
+ // Auto-consolidate IDENTITY.md if it's getting large
484
+ if (resolveRecallEnhancementCapabilities(config).identity) {
485
+ await this.deps.autoConsolidateIdentity();
486
+ }
487
+
488
+ // Auto-consolidate profile.md if it exceeds max lines
489
+ const profileSection = this.deps.recallSectionCoordinator.getRecallSectionEntry("profile");
490
+ const profileConsolidationTriggerLines =
491
+ typeof profileSection?.consolidateTriggerLines === "number"
492
+ ? Math.max(0, Math.floor(profileSection.consolidateTriggerLines))
493
+ : undefined;
494
+ const profileConsolidationTargetLines =
495
+ typeof profileSection?.consolidateTargetLines === "number"
496
+ ? Math.max(0, Math.floor(profileSection.consolidateTargetLines))
497
+ : 50;
498
+ if (
499
+ await storage.profileNeedsConsolidation(
500
+ profileConsolidationTriggerLines,
501
+ )
502
+ ) {
503
+ log.info("profile.md exceeds max lines — running smart consolidation");
504
+ const currentProfile = await storage.readProfile();
505
+ if (currentProfile) {
506
+ const profileResult = await this.deps.getExtraction().consolidateProfile(
507
+ currentProfile,
508
+ profileConsolidationTargetLines,
509
+ );
510
+ if (profileResult) {
511
+ await storage.writeProfile(profileResult.consolidatedProfile);
512
+ // Profile consolidation rewrites profile.md — a durable namespace
513
+ // mutation; record it for the catalog touch even when it is the only
514
+ // change in the pass (codex). Otherwise lastWriteAt goes stale.
515
+ memoryItemMutated = true;
516
+ log.info(
517
+ `profile.md consolidated: removed ${profileResult.removedCount} items — ${profileResult.summary}`,
518
+ );
519
+ }
520
+ }
521
+ }
522
+
523
+ // Memory Summarization (Phase 4A)
524
+ if (resolvePipelineProcessingCapabilities(config).summarization) {
525
+ await this.deps.lifecyclePolicyCoordinator.runSummarization(allMemories);
526
+ }
527
+
528
+ // Topic Extraction (Phase 4B)
529
+ if (resolvePipelineProcessingCapabilities(config).topicExtraction) {
530
+ await this.deps.lifecyclePolicyCoordinator.runTopicExtraction(allMemories);
531
+ }
532
+
533
+ const meta = await storage.loadMeta();
534
+ meta.lastConsolidationAt = new Date().toISOString();
535
+ await storage.saveMeta(meta);
536
+
537
+ // Temporal Memory Tree (v8.2) — rebuild nodes from all memories, fail-open
538
+ if (lifecycleCaps.temporalMemoryTree) {
539
+ try {
540
+ const tmtEntries = allMemories
541
+ .filter(
542
+ (m) =>
543
+ m.frontmatter.status !== "superseded" && m.frontmatter.status !== "archived" &&
544
+ m.frontmatter.status !== "forgotten" && m.frontmatter.status !== "pending_review", // #1576: unfaithful queue items must not feed TMT clusters
545
+ )
546
+ .map((m) => ({
547
+ path: m.path,
548
+ id: m.frontmatter.id,
549
+ created: m.frontmatter.created,
550
+ content: m.content,
551
+ }));
552
+ await this.deps.tmtBuilder.maybeRebuildNodes(
553
+ tmtEntries,
554
+ async (texts, level) => {
555
+ const prompt = `You are a memory archivist. Summarize the following ${level}-level memories into 3\u20135 sentences, preserving key facts, decisions, and preferences.\n\n${texts.map((t, i) => `[${i + 1}] ${t}`).join("\n\n")}`;
556
+ const response = await this.deps.fastChatCompletion(
557
+ [
558
+ {
559
+ role: "system",
560
+ content:
561
+ "Respond with a 3\u20135 sentence narrative summary. No JSON, just plain prose.",
562
+ },
563
+ { role: "user", content: prompt },
564
+ ],
565
+ {
566
+ temperature: 0.3,
567
+ maxTokens: config.tmtSummaryMaxTokens,
568
+ operation: "tmt_summary",
569
+ priority: "background",
570
+ },
571
+ );
572
+ return response?.content?.trim() || texts.slice(0, 3).join(" ");
573
+ },
574
+ );
575
+ } catch (err) {
576
+ log.warn(`tmt: consolidation hook failed (ignored): ${err}`);
577
+ }
578
+ }
579
+
580
+ if (this.deps.consolidationObservers.size > 0) {
581
+ const observation: ConsolidationObservation = {
582
+ runAt: new Date().toISOString(),
583
+ recentMemories: recent,
584
+ existingMemories: older.slice(-50),
585
+ profile,
586
+ result,
587
+ merged,
588
+ invalidated,
589
+ };
590
+ for (const observer of this.deps.consolidationObservers) {
591
+ try {
592
+ await observer(observation);
593
+ } catch (err) {
594
+ log.warn(`consolidation observer failed (ignored): ${err}`);
595
+ }
596
+ }
597
+ }
598
+
599
+ // Consolidated catalog write touch — belt-and-suspenders for cleanup-only
600
+ // passes that mutate the store via delete-only paths (entity merges, TTL
601
+ // cleanup) without triggering the storage chokepoint's post-write hook.
602
+ // Gated on memoryItemMutated (set by every durable mutation including cleanup-only passes)
603
+ // Best-effort and failure-tolerant.
604
+ if (memoryItemMutated) {
605
+ this.deps.getStorageRouter().recordWrite(config.defaultNamespace, storage.dir);
606
+ }
607
+
608
+ log.info("consolidation complete");
609
+ return { memoriesProcessed: allMemories.length, merged, invalidated };
610
+ }
611
+
612
+ private async recordScheduledDreamsPhaseRun(
613
+ phase: "lightSleep" | "rem" | "deepSleep",
614
+ itemsProcessed: number,
615
+ notes: string,
616
+ timing: { startedAt?: string; completedAt?: string } = {},
617
+ ): Promise<void> {
618
+ try {
619
+ await recordDreamsPhaseRun({
620
+ memoryDir: this.deps.getStorage().dir,
621
+ phase,
622
+ trigger: "scheduled",
623
+ itemsProcessed,
624
+ notes,
625
+ startedAt: timing.startedAt,
626
+ completedAt: timing.completedAt,
627
+ });
628
+ } catch (error) {
629
+ log.debug(`dreams ledger scheduled ${phase} write failed (non-fatal): ${error}`);
630
+ }
631
+ }
632
+
633
+ }