@remnic/core 9.3.734 → 9.3.736

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 (256) hide show
  1. package/dist/access-boundary.d.ts +8 -6
  2. package/dist/access-boundary.js +9 -9
  3. package/dist/access-cli.js +24 -24
  4. package/dist/access-http.d.ts +8 -6
  5. package/dist/access-http.js +14 -14
  6. package/dist/access-mcp.d.ts +8 -6
  7. package/dist/access-mcp.js +13 -13
  8. package/dist/access-operations-batch.js +11 -11
  9. package/dist/access-operations.d.ts +8 -6
  10. package/dist/access-operations.js +12 -12
  11. package/dist/{access-service-rjFfmfKB.d.ts → access-service-CdC0q4pr.d.ts} +3 -3
  12. package/dist/access-service.d.ts +8 -6
  13. package/dist/access-service.js +8 -8
  14. package/dist/access-surface-catalog.d.ts +8 -6
  15. package/dist/action-confidence.d.ts +1 -1
  16. package/dist/active-memory-bridge.d.ts +1 -1
  17. package/dist/active-memory-bridge.js +3 -3
  18. package/dist/active-recall.d.ts +1 -1
  19. package/dist/behavior-learner.d.ts +1 -1
  20. package/dist/behavior-signals.d.ts +1 -1
  21. package/dist/bootstrap.d.ts +7 -5
  22. package/dist/briefing.d.ts +1 -1
  23. package/dist/buffer-surprise-report.d.ts +1 -1
  24. package/dist/buffer.d.ts +1 -1
  25. package/dist/calibration.d.ts +1 -1
  26. package/dist/capabilities.d.ts +101 -2
  27. package/dist/capabilities.js +13 -3
  28. package/dist/{catalog-DHYXzM4-.d.ts → catalog-D2NLDg4S.d.ts} +1 -1
  29. package/dist/causal-behavior.d.ts +1 -1
  30. package/dist/causal-consolidation.d.ts +1 -1
  31. package/dist/causal-trajectory-graph.d.ts +1 -1
  32. package/dist/{chunk-IWMGBNXY.js → chunk-2T2N7ISV.js} +3 -3
  33. package/dist/{chunk-K7PAILHO.js → chunk-5BOQNB2K.js} +3 -3
  34. package/dist/{chunk-Q5LGXWNG.js → chunk-AAIHDIMD.js} +6 -6
  35. package/dist/{chunk-WHQ2JB35.js → chunk-AB2E5DCN.js} +2 -2
  36. package/dist/{chunk-Z7J3OAPR.js → chunk-AE2HPUP7.js} +726 -645
  37. package/dist/chunk-AE2HPUP7.js.map +1 -0
  38. package/dist/{chunk-FAGERSH2.js → chunk-AE7NTZ75.js} +3 -3
  39. package/dist/{chunk-V5OVSGB6.js → chunk-AESC5OQJ.js} +2 -2
  40. package/dist/{chunk-7FPJFCXL.js → chunk-BXPG5AVX.js} +4 -4
  41. package/dist/{chunk-UH3NYOHN.js → chunk-CHJIWG2H.js} +2 -2
  42. package/dist/{chunk-IDIXGGDN.js → chunk-E4LYJ7PY.js} +6 -6
  43. package/dist/{chunk-WTTVFSCO.js → chunk-FF36YNKY.js} +3 -3
  44. package/dist/{chunk-TJSQHO4Q.js → chunk-FLPKEMSO.js} +2 -2
  45. package/dist/{chunk-UF3N7IRP.js → chunk-G54IDCD3.js} +45 -41
  46. package/dist/chunk-G54IDCD3.js.map +1 -0
  47. package/dist/{chunk-UK6U5C3N.js → chunk-GB2FZOWB.js} +3 -3
  48. package/dist/{chunk-5OYHJIJN.js → chunk-GYICIICQ.js} +3 -3
  49. package/dist/{chunk-PEF2XOIV.js → chunk-HFXZIF3V.js} +3 -3
  50. package/dist/{chunk-PKO5NJ65.js → chunk-HLPYL6LC.js} +27 -24
  51. package/dist/chunk-HLPYL6LC.js.map +1 -0
  52. package/dist/{chunk-ET5HXSQL.js → chunk-IPI45Q4S.js} +2 -2
  53. package/dist/{chunk-2L5RTVMO.js → chunk-IX4L7E5G.js} +2 -2
  54. package/dist/{chunk-SYX73XD7.js → chunk-IXGXALRV.js} +10 -7
  55. package/dist/chunk-IXGXALRV.js.map +1 -0
  56. package/dist/{chunk-SHJGBAIW.js → chunk-JWDE7OVJ.js} +44 -2
  57. package/dist/{chunk-SHJGBAIW.js.map → chunk-JWDE7OVJ.js.map} +1 -1
  58. package/dist/{chunk-IZLTOS5L.js → chunk-K3Y2SJTN.js} +4 -4
  59. package/dist/{chunk-CILX2XW7.js → chunk-NDKW67ER.js} +2 -2
  60. package/dist/{chunk-54RCE5Z3.js → chunk-NNJKEAP2.js} +2 -2
  61. package/dist/{chunk-LV32K4OP.js → chunk-OYHYBHHI.js} +2 -2
  62. package/dist/{chunk-5DIKZKOD.js → chunk-P6VLG7KE.js} +2 -2
  63. package/dist/{chunk-T7CGPTFU.js → chunk-QNTLWH3T.js} +3 -3
  64. package/dist/{chunk-6U7TES2M.js → chunk-UO6MPN77.js} +13 -12
  65. package/dist/chunk-UO6MPN77.js.map +1 -0
  66. package/dist/{chunk-NDYQIN6C.js → chunk-VOEVVIP3.js} +3 -3
  67. package/dist/{chunk-3QETM5NG.js → chunk-ZBZ4XULO.js} +3 -3
  68. package/dist/{cli-XVpmSoQs.d.ts → cli-BHy6Bo6u.d.ts} +3 -3
  69. package/dist/cli.d.ts +9 -7
  70. package/dist/cli.js +20 -20
  71. package/dist/compounding/engine.d.ts +1 -1
  72. package/dist/compounding/engine.js +2 -2
  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.d.ts +1 -1
  78. package/dist/connectors/index.d.ts +1 -1
  79. package/dist/consolidation-provenance-check.d.ts +1 -1
  80. package/dist/consolidation-undo.d.ts +1 -1
  81. package/dist/contradiction/index.d.ts +1 -1
  82. package/dist/contradiction/index.js +2 -2
  83. package/dist/{contradiction-scan-OUHMCUBT.js → contradiction-scan-2B4AE4TI.js} +3 -3
  84. package/dist/conversation-index/backend.d.ts +1 -1
  85. package/dist/conversation-index/chunker.d.ts +1 -1
  86. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  87. package/dist/conversation-index/indexer.d.ts +1 -1
  88. package/dist/conversation-index/search.d.ts +1 -1
  89. package/dist/day-summary.d.ts +1 -1
  90. package/dist/delinearize.d.ts +1 -1
  91. package/dist/direct-answer-wiring.d.ts +1 -1
  92. package/dist/direct-answer.d.ts +1 -1
  93. package/dist/embedding-fallback.d.ts +1 -1
  94. package/dist/embedding-fallback.js +2 -2
  95. package/dist/enrichment/index.d.ts +1 -1
  96. package/dist/entity-retrieval.d.ts +1 -1
  97. package/dist/entity-retrieval.js +2 -2
  98. package/dist/entity-schema.d.ts +1 -1
  99. package/dist/explicit-capture.d.ts +7 -5
  100. package/dist/explicit-capture.js +2 -2
  101. package/dist/extraction-faithfulness.d.ts +1 -1
  102. package/dist/extraction-judge-telemetry.d.ts +1 -1
  103. package/dist/extraction-judge-training.d.ts +1 -1
  104. package/dist/extraction-judge.d.ts +1 -1
  105. package/dist/extraction.d.ts +1 -1
  106. package/dist/extraction.js +3 -3
  107. package/dist/fallback-llm.d.ts +1 -1
  108. package/dist/{first-start-migration-W4U6XDKI.js → first-start-migration-2RQYDIZ7.js} +6 -5
  109. package/dist/first-start-migration-2RQYDIZ7.js.map +1 -0
  110. package/dist/graph-dashboard-diff.d.ts +1 -1
  111. package/dist/graph-dashboard-key.d.ts +1 -1
  112. package/dist/graph-dashboard-parser.d.ts +1 -1
  113. package/dist/graph-edge-reinforcement.d.ts +1 -1
  114. package/dist/graph-snapshot.d.ts +1 -1
  115. package/dist/graph.d.ts +1 -1
  116. package/dist/identity-continuity.d.ts +1 -1
  117. package/dist/importance.d.ts +1 -1
  118. package/dist/index.d.ts +9 -9
  119. package/dist/index.js +30 -30
  120. package/dist/intent.d.ts +1 -1
  121. package/dist/lcm/engine.d.ts +1 -1
  122. package/dist/lcm/index.d.ts +1 -1
  123. package/dist/lcm/tools.d.ts +1 -1
  124. package/dist/lifecycle.d.ts +1 -1
  125. package/dist/live-connectors-runner.d.ts +1 -1
  126. package/dist/local-llm.d.ts +1 -1
  127. package/dist/local-llm.js +2 -2
  128. package/dist/local-model-endpoint.d.ts +1 -1
  129. package/dist/maintenance/memory-governance.d.ts +1 -1
  130. package/dist/mcp-memory-inspector-app.d.ts +8 -6
  131. package/dist/memory-action-policy.d.ts +1 -1
  132. package/dist/memory-cache.d.ts +1 -1
  133. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  134. package/dist/memory-projection-store.d.ts +1 -1
  135. package/dist/memory-provenance.d.ts +1 -1
  136. package/dist/memory-worth-outcomes.d.ts +1 -1
  137. package/dist/models-json.d.ts +1 -1
  138. package/dist/namespaces/migrate.d.ts +2 -2
  139. package/dist/namespaces/migrate.js +6 -6
  140. package/dist/namespaces/principal.d.ts +1 -1
  141. package/dist/namespaces/principal.js +2 -2
  142. package/dist/namespaces/search.d.ts +1 -1
  143. package/dist/namespaces/search.js +4 -4
  144. package/dist/namespaces/storage.d.ts +2 -2
  145. package/dist/namespaces/storage.js +2 -2
  146. package/dist/native-knowledge.d.ts +1 -1
  147. package/dist/operator-toolkit.d.ts +1 -1
  148. package/dist/operator-toolkit.js +11 -11
  149. package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
  150. package/dist/orchestration/compression-guideline-coordinator.js +2 -1
  151. package/dist/orchestration/maintenance.d.ts +2 -2
  152. package/dist/orchestration/maintenance.js +6 -6
  153. package/dist/{orchestrator-BXi-gadS.d.ts → orchestrator-C-xp_rtZ.d.ts} +141 -18
  154. package/dist/orchestrator.d.ts +7 -5
  155. package/dist/orchestrator.js +19 -21
  156. package/dist/patterns-cli.d.ts +1 -1
  157. package/dist/policy-runtime.d.ts +1 -1
  158. package/dist/provenance.d.ts +1 -1
  159. package/dist/qmd-recall-cache.d.ts +1 -1
  160. package/dist/qmd.d.ts +1 -1
  161. package/dist/recall-disclosure-escalation.d.ts +1 -1
  162. package/dist/recall-explain-renderer.d.ts +1 -1
  163. package/dist/recall-planner-llm.d.ts +1 -1
  164. package/dist/recall-state.d.ts +1 -1
  165. package/dist/recall-tag-filter.d.ts +1 -1
  166. package/dist/recall-xray-cli.d.ts +1 -1
  167. package/dist/recall-xray-renderer.d.ts +1 -1
  168. package/dist/recall-xray.d.ts +1 -1
  169. package/dist/resolve-auth-token.d.ts +1 -1
  170. package/dist/retrieval-agents.d.ts +1 -1
  171. package/dist/retrieval-tiers.d.ts +1 -1
  172. package/dist/routing/engine.d.ts +1 -1
  173. package/dist/routing/store.d.ts +1 -1
  174. package/dist/search/embed-helper.d.ts +1 -1
  175. package/dist/search/embed-helper.js +2 -2
  176. package/dist/search/factory.d.ts +1 -1
  177. package/dist/search/factory.js +3 -3
  178. package/dist/search/index.d.ts +1 -1
  179. package/dist/search/index.js +3 -3
  180. package/dist/search/lancedb-backend.d.ts +1 -1
  181. package/dist/search/meilisearch-backend.d.ts +1 -1
  182. package/dist/search/noop-backend.d.ts +1 -1
  183. package/dist/search/orama-backend.d.ts +1 -1
  184. package/dist/search/port.d.ts +1 -1
  185. package/dist/search/remote-backend.d.ts +1 -1
  186. package/dist/{semantic-consolidation-DeL5grLx.d.ts → semantic-consolidation-COdwU-me.d.ts} +1 -1
  187. package/dist/semantic-consolidation.d.ts +2 -2
  188. package/dist/semantic-rule-verifier.d.ts +1 -1
  189. package/dist/session-observer-bands.d.ts +1 -1
  190. package/dist/session-observer-state.d.ts +1 -1
  191. package/dist/shared-context/manager.d.ts +1 -1
  192. package/dist/signal.d.ts +1 -1
  193. package/dist/storage.d.ts +1 -1
  194. package/dist/summarizer.d.ts +1 -1
  195. package/dist/summarizer.js +3 -3
  196. package/dist/summary-snapshot.d.ts +1 -1
  197. package/dist/temporal-supersession.d.ts +1 -1
  198. package/dist/temporal-validity.d.ts +1 -1
  199. package/dist/threading.d.ts +1 -1
  200. package/dist/tier-migration.d.ts +1 -1
  201. package/dist/tier-routing.d.ts +1 -1
  202. package/dist/{tier-stats-LSM35HZY.js → tier-stats-KPDIISG7.js} +6 -5
  203. package/dist/tier-stats-KPDIISG7.js.map +1 -0
  204. package/dist/topics.d.ts +1 -1
  205. package/dist/transcript.d.ts +1 -1
  206. package/dist/trust-score-stage.d.ts +1 -1
  207. package/dist/trust-score.d.ts +1 -1
  208. package/dist/{types-CpFz51Pv.d.ts → types-w3Y232yi.d.ts} +1 -1
  209. package/dist/types.d.ts +1 -1
  210. package/dist/utility-runtime.d.ts +1 -1
  211. package/package.json +2 -2
  212. package/src/access-service.ts +20 -20
  213. package/src/capabilities.test.ts +197 -0
  214. package/src/capabilities.ts +206 -0
  215. package/src/cli/creation-ledger-commands.ts +2 -2
  216. package/src/cli/research-status-commands.ts +13 -13
  217. package/src/cli.ts +17 -17
  218. package/src/maintenance/first-start-migration.ts +3 -3
  219. package/src/maintenance/tier-stats.ts +3 -3
  220. package/src/operator-toolkit.ts +8 -8
  221. package/src/orchestration/compression-guideline-coordinator.ts +7 -6
  222. package/src/orchestration/entity-synthesis-coordinator.ts +319 -0
  223. package/src/orchestration/lifecycle-policy-coordinator.ts +504 -0
  224. package/src/orchestrator.ts +40 -618
  225. package/dist/chunk-6U7TES2M.js.map +0 -1
  226. package/dist/chunk-PKO5NJ65.js.map +0 -1
  227. package/dist/chunk-SYX73XD7.js.map +0 -1
  228. package/dist/chunk-UF3N7IRP.js.map +0 -1
  229. package/dist/chunk-Z7J3OAPR.js.map +0 -1
  230. package/dist/first-start-migration-W4U6XDKI.js.map +0 -1
  231. package/dist/tier-stats-LSM35HZY.js.map +0 -1
  232. /package/dist/{chunk-IWMGBNXY.js.map → chunk-2T2N7ISV.js.map} +0 -0
  233. /package/dist/{chunk-K7PAILHO.js.map → chunk-5BOQNB2K.js.map} +0 -0
  234. /package/dist/{chunk-Q5LGXWNG.js.map → chunk-AAIHDIMD.js.map} +0 -0
  235. /package/dist/{chunk-WHQ2JB35.js.map → chunk-AB2E5DCN.js.map} +0 -0
  236. /package/dist/{chunk-FAGERSH2.js.map → chunk-AE7NTZ75.js.map} +0 -0
  237. /package/dist/{chunk-V5OVSGB6.js.map → chunk-AESC5OQJ.js.map} +0 -0
  238. /package/dist/{chunk-7FPJFCXL.js.map → chunk-BXPG5AVX.js.map} +0 -0
  239. /package/dist/{chunk-UH3NYOHN.js.map → chunk-CHJIWG2H.js.map} +0 -0
  240. /package/dist/{chunk-IDIXGGDN.js.map → chunk-E4LYJ7PY.js.map} +0 -0
  241. /package/dist/{chunk-WTTVFSCO.js.map → chunk-FF36YNKY.js.map} +0 -0
  242. /package/dist/{chunk-TJSQHO4Q.js.map → chunk-FLPKEMSO.js.map} +0 -0
  243. /package/dist/{chunk-UK6U5C3N.js.map → chunk-GB2FZOWB.js.map} +0 -0
  244. /package/dist/{chunk-5OYHJIJN.js.map → chunk-GYICIICQ.js.map} +0 -0
  245. /package/dist/{chunk-PEF2XOIV.js.map → chunk-HFXZIF3V.js.map} +0 -0
  246. /package/dist/{chunk-ET5HXSQL.js.map → chunk-IPI45Q4S.js.map} +0 -0
  247. /package/dist/{chunk-2L5RTVMO.js.map → chunk-IX4L7E5G.js.map} +0 -0
  248. /package/dist/{chunk-IZLTOS5L.js.map → chunk-K3Y2SJTN.js.map} +0 -0
  249. /package/dist/{chunk-CILX2XW7.js.map → chunk-NDKW67ER.js.map} +0 -0
  250. /package/dist/{chunk-54RCE5Z3.js.map → chunk-NNJKEAP2.js.map} +0 -0
  251. /package/dist/{chunk-LV32K4OP.js.map → chunk-OYHYBHHI.js.map} +0 -0
  252. /package/dist/{chunk-5DIKZKOD.js.map → chunk-P6VLG7KE.js.map} +0 -0
  253. /package/dist/{chunk-T7CGPTFU.js.map → chunk-QNTLWH3T.js.map} +0 -0
  254. /package/dist/{chunk-NDYQIN6C.js.map → chunk-VOEVVIP3.js.map} +0 -0
  255. /package/dist/{chunk-3QETM5NG.js.map → chunk-ZBZ4XULO.js.map} +0 -0
  256. /package/dist/{contradiction-scan-OUHMCUBT.js.map → contradiction-scan-2B4AE4TI.js.map} +0 -0
@@ -79,12 +79,9 @@ import {
79
79
  } from "./search/factory.js";
80
80
  import { NoopSearchBackend } from "./search/noop-backend.js";
81
81
  import {
82
- compareEntityTimestamps,
83
82
  StorageManager,
84
83
  ContentHashIndex,
85
- fingerprintEntityStructuredFacts,
86
84
  normalizeAttributePairs,
87
- parseEntityFile,
88
85
  } from "./storage.js";
89
86
  import { sanitizeMemoryContent } from "./sanitize.js";
90
87
  import { ThreadingManager } from "./threading.js";
@@ -102,6 +99,8 @@ import { TierMigrationCoordinator } from "./orchestration/tier-migration-coordin
102
99
  import { ExtractionQueueCoordinator } from "./orchestration/extraction-queue-coordinator.js";
103
100
  import { CompressionGuidelineCoordinator } from "./orchestration/compression-guideline-coordinator.js";
104
101
  import { SemanticConsolidationCoordinator } from "./orchestration/semantic-consolidation-coordinator.js";
102
+ import { LifecyclePolicyCoordinator } from "./orchestration/lifecycle-policy-coordinator.js";
103
+ import { EntitySynthesisCoordinator } from "./orchestration/entity-synthesis-coordinator.js";
105
104
  import {
106
105
  runLiveConnectorsOnce,
107
106
  type LiveConnectorsRunSummary,
@@ -281,7 +280,7 @@ import {
281
280
  resolveQmdCapabilities,
282
281
  resolveIdentityContinuityCapabilities,
283
282
  resolveLocalLlmCapabilities,
284
- } from "./capabilities.js";
283
+ resolveSecurityCapabilities, resolveEvalCapabilities, resolveUtilityLearningCapabilities, resolveObjectiveStateCapabilities, resolveCompressionCapabilities} from "./capabilities.js";
285
284
  import { DEFAULT_TAXONOMY } from "./taxonomy/index.js";
286
285
  import {
287
286
  searchHarmonicRetrieval,
@@ -450,8 +449,6 @@ import type {
450
449
  RecallPlanMode,
451
450
  RecallSectionConfig,
452
451
  RecallTierExplain,
453
- EntityStructuredSection,
454
- EntityTimelineEntry,
455
452
  } from "./types.js";
456
453
  import { disposeDefaultArchiveScoring, getDefaultArchiveScoring, memoryFileToScoreItem } from "./recall/archive-scoring.js";
457
454
 
@@ -491,92 +488,6 @@ interface ExtractionRunResult {
491
488
  postPersistMetadataFailed?: boolean;
492
489
  }
493
490
 
494
- export function dedupeEntitySynthesisEvidenceEntries(
495
- entries: EntityTimelineEntry[],
496
- ): EntityTimelineEntry[] {
497
- const dedupedEvidenceEntries: EntityTimelineEntry[] = [];
498
- const evidenceByFact = new Map<string, {
499
- newest: EntityTimelineEntry;
500
- oldest: EntityTimelineEntry;
501
- }>();
502
-
503
- for (const entry of entries) {
504
- const normalizedFact = entry.text.trim();
505
- if (!normalizedFact) continue;
506
- const existing = evidenceByFact.get(normalizedFact);
507
- if (!existing) {
508
- evidenceByFact.set(normalizedFact, { newest: entry, oldest: entry });
509
- continue;
510
- }
511
- if (compareEntityTimestamps(entry.timestamp, existing.newest.timestamp) > 0) {
512
- existing.newest = entry;
513
- }
514
- if (compareEntityTimestamps(entry.timestamp, existing.oldest.timestamp) < 0) {
515
- existing.oldest = entry;
516
- }
517
- }
518
-
519
- for (const { newest, oldest } of evidenceByFact.values()) {
520
- dedupedEvidenceEntries.push(newest);
521
- const newestKey = [
522
- newest.timestamp,
523
- newest.source ?? "",
524
- newest.sessionKey ?? "",
525
- newest.principal ?? "",
526
- newest.text,
527
- ].join("\u0000");
528
- const oldestKey = [
529
- oldest.timestamp,
530
- oldest.source ?? "",
531
- oldest.sessionKey ?? "",
532
- oldest.principal ?? "",
533
- oldest.text,
534
- ].join("\u0000");
535
- if (oldestKey !== newestKey) {
536
- dedupedEvidenceEntries.push(oldest);
537
- }
538
- }
539
-
540
- return dedupedEvidenceEntries;
541
- }
542
-
543
- function flattenStructuredSectionEvidence(
544
- sections: EntityStructuredSection[] | undefined,
545
- ): EntityTimelineEntry[] {
546
- return (sections ?? []).flatMap((section) =>
547
- section.facts
548
- .map((fact) => fact.trim())
549
- .filter((fact) => fact.length > 0)
550
- .map((fact) => ({
551
- timestamp: "",
552
- text: fact,
553
- source: `section:${section.title}`,
554
- })),
555
- );
556
- }
557
-
558
- function fingerprintEntitySynthesisEvidence(entity: {
559
- timeline: EntityTimelineEntry[];
560
- structuredSections?: EntityStructuredSection[];
561
- }): string {
562
- const fingerprint = createHash("sha256");
563
- const timelineEntries = entity.timeline
564
- .map((entry) => [
565
- entry.timestamp,
566
- entry.source ?? "",
567
- entry.sessionKey ?? "",
568
- entry.principal ?? "",
569
- entry.text,
570
- ].join("\u0000"))
571
- .sort();
572
- const timelineEntrySeparator = String.fromCharCode(1);
573
- const structuredFactsSeparator = String.fromCharCode(2);
574
- fingerprint.update(timelineEntries.join(timelineEntrySeparator));
575
- fingerprint.update(structuredFactsSeparator);
576
- fingerprint.update(fingerprintEntityStructuredFacts(entity) ?? "");
577
- return fingerprint.digest("hex");
578
- }
579
-
580
491
  export interface GraphRecallSnapshot {
581
492
  recordedAt: string;
582
493
  mode: RecallPlanMode | string;
@@ -1902,6 +1813,8 @@ export class Orchestrator {
1902
1813
  readonly tierMigrationCoordinator: TierMigrationCoordinator;
1903
1814
  readonly compressionGuidelineCoordinator: CompressionGuidelineCoordinator;
1904
1815
  readonly semanticConsolidationCoordinator: SemanticConsolidationCoordinator;
1816
+ readonly lifecyclePolicyCoordinator: LifecyclePolicyCoordinator;
1817
+ readonly entitySynthesisCoordinator: EntitySynthesisCoordinator;
1905
1818
  /**
1906
1819
  * In-memory X-ray snapshot from the most recent `recall()` call that
1907
1820
  * was invoked with `xrayCapture: true` (issue #570 PR 1). Scope is
@@ -3025,6 +2938,12 @@ export class Orchestrator {
3025
2938
  fastChatCompletion: (messages, options) =>
3026
2939
  this.fastChatCompletion(messages, options),
3027
2940
  });
2941
+ this.entitySynthesisCoordinator = new EntitySynthesisCoordinator({
2942
+ config,
2943
+ getStorage: (namespace) => this.getStorage(namespace),
2944
+ fastChatCompletion: (messages, options) =>
2945
+ this.fastChatCompletion(messages, options),
2946
+ });
3028
2947
 
3029
2948
  this.sessionObserver = new SessionObserverState({
3030
2949
  memoryDir: config.memoryDir,
@@ -3098,6 +3017,16 @@ export class Orchestrator {
3098
3017
  config.gatewayConfig,
3099
3018
  this.modelRegistry,
3100
3019
  );
3020
+ this.lifecyclePolicyCoordinator = new LifecyclePolicyCoordinator({
3021
+ config,
3022
+ getStorage: () => this.storage,
3023
+ extraction: this.extraction,
3024
+ embeddingFallback: this.embeddingFallback,
3025
+ getEffectiveLifecycleThresholds: () => this.effectiveLifecycleThresholds(),
3026
+ removeContentHashForMemory: (targetStorage, memory, context) =>
3027
+ this.removeContentHashForMemory(targetStorage, memory, context),
3028
+ saveContentHashIndexes: () => this.saveContentHashIndexes(),
3029
+ });
3101
3030
  this.threading = new ThreadingManager(
3102
3031
  path.join(config.memoryDir, "threads"),
3103
3032
  config.threadingGapMinutes,
@@ -3510,8 +3439,8 @@ export class Orchestrator {
3510
3439
  this.runtimePolicyValues = await this.policyRuntime.loadRuntimeValues();
3511
3440
  this.utilityRuntimeValues = await loadUtilityRuntimeValues({
3512
3441
  memoryDir: this.config.memoryDir,
3513
- memoryUtilityLearningEnabled: this.config.memoryUtilityLearningEnabled,
3514
- promotionByOutcomeEnabled: this.config.promotionByOutcomeEnabled,
3442
+ memoryUtilityLearningEnabled: resolveUtilityLearningCapabilities(this.config).memoryUtilityLearning,
3443
+ promotionByOutcomeEnabled: resolveUtilityLearningCapabilities(this.config).promotionByOutcome,
3515
3444
  });
3516
3445
 
3517
3446
  // Initialize content-hash dedup index
@@ -4432,150 +4361,10 @@ export class Orchestrator {
4432
4361
  namespace?: string,
4433
4362
  maxEntities: number = 5,
4434
4363
  ): Promise<number> {
4435
- if (
4436
- !this.config.entitySummaryEnabled
4437
- || maxEntities <= 0
4438
- || this.config.entitySynthesisMaxTokens <= 0
4439
- ) return 0;
4440
- const storage = await this.getStorage(namespace);
4441
- const queued = await storage.refreshEntitySynthesisQueue();
4442
- let processed = 0;
4443
- let attempted = 0;
4444
-
4445
- for (const entityName of queued) {
4446
- if (attempted >= maxEntities) break;
4447
- attempted += 1;
4448
- try {
4449
- const raw = await storage.readEntity(entityName);
4450
- if (!raw) continue;
4451
- const entity = parseEntityFile(raw, this.config.entitySchemas);
4452
- const previousSynthesis = entity.synthesis || entity.summary || "";
4453
- const sortedTimelineEntries = entity.timeline
4454
- .slice()
4455
- .sort((left, right) => compareEntityTimestamps(right.timestamp, left.timestamp));
4456
- const newerTimelineEntries = sortedTimelineEntries.filter(
4457
- (entry) =>
4458
- !entity.synthesisUpdatedAt
4459
- || compareEntityTimestamps(entry.timestamp, entity.synthesisUpdatedAt) > 0,
4460
- );
4461
- const appendedTimelineEntries = entity.synthesisTimelineCount === undefined
4462
- ? []
4463
- : entity.timeline.slice(Math.max(0, entity.synthesisTimelineCount));
4464
- const structuredEvidenceEntries = flattenStructuredSectionEvidence(entity.structuredSections);
4465
- const structuredEvidenceCount = structuredEvidenceEntries.length;
4466
- const structuredEvidenceDigest = fingerprintEntityStructuredFacts(entity);
4467
- const structuredEvidenceDrifted = structuredEvidenceDigest !== (entity.synthesisStructuredFactDigest?.trim() || undefined);
4468
- const appendedStructuredEvidenceEntries = entity.synthesisStructuredFactCount === undefined
4469
- || structuredEvidenceDrifted
4470
- ? structuredEvidenceEntries
4471
- : structuredEvidenceEntries.slice(Math.max(0, entity.synthesisStructuredFactCount));
4472
- const candidateEvidenceEntries = [
4473
- ...newerTimelineEntries,
4474
- ...appendedTimelineEntries,
4475
- ...appendedStructuredEvidenceEntries,
4476
- ]
4477
- .slice()
4478
- .sort((left, right) => compareEntityTimestamps(right.timestamp, left.timestamp));
4479
- const dedupedEvidenceEntries = dedupeEntitySynthesisEvidenceEntries(
4480
- candidateEvidenceEntries.length > 0
4481
- ? candidateEvidenceEntries
4482
- : [...sortedTimelineEntries, ...structuredEvidenceEntries],
4483
- );
4484
- const chronologicalEvidenceEntries = dedupedEvidenceEntries
4485
- .slice()
4486
- .sort((left, right) => compareEntityTimestamps(left.timestamp, right.timestamp));
4487
- if (chronologicalEvidenceEntries.length === 0) continue;
4488
- const latestEvidenceTimestamp = chronologicalEvidenceEntries
4489
- .slice()
4490
- .reverse()
4491
- .map((entry) => entry.timestamp?.trim() || undefined)
4492
- .find((timestamp) => Boolean(timestamp));
4493
- const previousSynthesisUpdatedAt = entity.synthesisUpdatedAt?.trim() || undefined;
4494
- const nextSynthesisUpdatedAt = compareEntityTimestamps(
4495
- latestEvidenceTimestamp,
4496
- previousSynthesisUpdatedAt,
4497
- ) >= 0
4498
- ? latestEvidenceTimestamp
4499
- : previousSynthesisUpdatedAt;
4500
- const evidenceBatches: typeof chronologicalEvidenceEntries[] = [];
4501
- for (let index = 0; index < chronologicalEvidenceEntries.length; index += 8) {
4502
- evidenceBatches.push(chronologicalEvidenceEntries.slice(index, index + 8));
4503
- }
4504
-
4505
- let nextSynthesis = previousSynthesis;
4506
- let batchFailed = false;
4507
- for (const evidenceEntries of evidenceBatches) {
4508
- const evidenceText = evidenceEntries
4509
- .map((entry) => {
4510
- const sectionTitle = entry.source?.startsWith("section:")
4511
- ? entry.source.slice("section:".length)
4512
- : "";
4513
- const metadata = [
4514
- `timestamp=${entry.timestamp}`,
4515
- sectionTitle ? `section=${sectionTitle}` : entry.source ? `source=${entry.source}` : "",
4516
- entry.sessionKey ? `session=${entry.sessionKey}` : "",
4517
- entry.principal ? `principal=${entry.principal}` : "",
4518
- ]
4519
- .filter(Boolean)
4520
- .join(", ");
4521
- return `- ${metadata}: ${entry.text}`;
4522
- })
4523
- .join("\n");
4524
- const response = await this.fastChatCompletion(
4525
- [
4526
- {
4527
- role: "system",
4528
- content:
4529
- "Rewrite the entity synthesis as compact current truth. Preserve uncertainty when evidence conflicts. Return plain text only.",
4530
- },
4531
- {
4532
- role: "user",
4533
- content: [
4534
- `Entity: ${entity.name} (${entity.type})`,
4535
- nextSynthesis ? `Previous synthesis:\n${nextSynthesis}` : "Previous synthesis: none",
4536
- `New evidence:\n${evidenceText}`,
4537
- ].join("\n\n"),
4538
- },
4539
- ],
4540
- {
4541
- temperature: 0.2,
4542
- maxTokens: this.config.entitySynthesisMaxTokens,
4543
- operation: "entity_summary",
4544
- priority: "background",
4545
- },
4546
- );
4547
- const synthesis = response?.content?.trim().replace(/^["']|["']$/g, "");
4548
- const maxSynthesisChars = Math.max(2_000, this.config.entitySynthesisMaxTokens * 8);
4549
- if (!synthesis || synthesis.length < 10 || synthesis.length > maxSynthesisChars) {
4550
- batchFailed = true;
4551
- break;
4552
- }
4553
- nextSynthesis = synthesis;
4554
- }
4555
- if (batchFailed || nextSynthesis.length === 0) continue;
4556
- const latestRaw = await storage.readEntity(entityName);
4557
- if (!latestRaw) continue;
4558
- const latestEntity = parseEntityFile(latestRaw, this.config.entitySchemas);
4559
- if (
4560
- fingerprintEntitySynthesisEvidence(latestEntity)
4561
- !== fingerprintEntitySynthesisEvidence(entity)
4562
- ) {
4563
- continue;
4564
- }
4565
- await storage.updateEntitySynthesis(entityName, nextSynthesis, {
4566
- entityUpdatedAt: new Date().toISOString(),
4567
- synthesisStructuredFactDigest: structuredEvidenceDigest,
4568
- synthesisStructuredFactCount: structuredEvidenceCount,
4569
- synthesisTimelineCount: entity.timeline.length,
4570
- updatedAt: nextSynthesisUpdatedAt,
4571
- });
4572
- processed += 1;
4573
- } catch (err) {
4574
- log.debug(`entity synthesis refresh failed for ${entityName}: ${err}`);
4575
- }
4576
- }
4577
-
4578
- return processed;
4364
+ // Issue #1526: entity synthesis lifecycle moved to EntitySynthesisCoordinator.
4365
+ // Thin delegation keeps all call sites (consolidation pass, access-service)
4366
+ // and tests that exercise the public API working unchanged.
4367
+ return this.entitySynthesisCoordinator.processQueue(namespace, maxEntities);
4579
4368
  }
4580
4369
 
4581
4370
  async generateDaySummary(
@@ -4805,7 +4594,7 @@ export class Orchestrator {
4805
4594
  action: event.action,
4806
4595
  eligibility,
4807
4596
  options: {
4808
- actionsEnabled: this.config.contextCompressionActionsEnabled,
4597
+ actionsEnabled: resolveCompressionCapabilities(this.config).contextCompressionActions,
4809
4598
  maxCompressionTokensPerHour: this.config.maxCompressionTokensPerHour,
4810
4599
  },
4811
4600
  });
@@ -8305,11 +8094,11 @@ export class Orchestrator {
8305
8094
  const objectiveStatePromise = (async (): Promise<string | null> => {
8306
8095
  const t0 = Date.now();
8307
8096
  if (
8308
- !this.config.objectiveStateMemoryEnabled ||
8309
- !this.config.objectiveStateRecallEnabled ||
8097
+ !resolveObjectiveStateCapabilities(this.config).objectiveStateMemory ||
8098
+ !resolveObjectiveStateCapabilities(this.config).objectiveStateRecall ||
8310
8099
  !this.isRecallSectionEnabled(
8311
8100
  "objective-state",
8312
- this.config.objectiveStateRecallEnabled === true,
8101
+ resolveObjectiveStateCapabilities(this.config).objectiveStateRecall === true,
8313
8102
  )
8314
8103
  ) {
8315
8104
  recordRecallSectionMetric({
@@ -8562,11 +8351,11 @@ export class Orchestrator {
8562
8351
  const trustZonePromise = (async (): Promise<string | null> => {
8563
8352
  const t0 = Date.now();
8564
8353
  if (
8565
- !this.config.trustZonesEnabled ||
8566
- !this.config.trustZoneRecallEnabled ||
8354
+ !resolveSecurityCapabilities(this.config).trustZones ||
8355
+ !resolveSecurityCapabilities(this.config).trustZoneRecall ||
8567
8356
  !this.isRecallSectionEnabled(
8568
8357
  "trust-zones",
8569
- this.config.trustZoneRecallEnabled === true,
8358
+ resolveSecurityCapabilities(this.config).trustZoneRecall === true,
8570
8359
  )
8571
8360
  ) {
8572
8361
  recordRecallSectionMetric({
@@ -11735,7 +11524,7 @@ export class Orchestrator {
11735
11524
  if (
11736
11525
  this.isRecallSectionEnabled(
11737
11526
  "compression-guidelines",
11738
- this.config.compressionGuidelineLearningEnabled === true,
11527
+ resolveCompressionCapabilities(this.config).compressionGuidelineLearning === true,
11739
11528
  )
11740
11529
  ) {
11741
11530
  const compressionGuidelineSection =
@@ -17017,81 +16806,6 @@ export class Orchestrator {
17017
16806
  return this.compressionGuidelineCoordinator.buildCompressionGuidelineRecallSection();
17018
16807
  }
17019
16808
 
17020
- private actionOutcomePriorDelta(event: MemoryActionEvent): number {
17021
- if (event.outcome === "failed") return -0.3;
17022
- if (event.policyDecision === "deny") return -0.22;
17023
- if (event.policyDecision === "defer") return -0.14;
17024
- if (event.outcome === "skipped") return -0.1;
17025
-
17026
- if (event.outcome !== "applied") return 0;
17027
- switch (event.action) {
17028
- case "store_episode":
17029
- case "store_note":
17030
- case "update_note":
17031
- return 0.08;
17032
- case "create_artifact":
17033
- case "summarize_node":
17034
- case "link_graph":
17035
- return 0.04;
17036
- case "discard":
17037
- return -0.03;
17038
- default:
17039
- return 0;
17040
- }
17041
- }
17042
-
17043
- private async buildLifecycleActionPriors(
17044
- storage: StorageManager = this.storage,
17045
- ): Promise<Map<string, number>> {
17046
- const events = await storage.readMemoryActionEvents(1200);
17047
- if (events.length === 0) return new Map<string, number>();
17048
-
17049
- const nowMs = Date.now();
17050
- const windowMs = 14 * 24 * 60 * 60 * 1000;
17051
- const byMemory = new Map<
17052
- string,
17053
- Array<{ weightedDelta: number; weight: number }>
17054
- >();
17055
-
17056
- for (const event of events) {
17057
- if (
17058
- typeof event.memoryId !== "string" ||
17059
- event.memoryId.trim().length === 0
17060
- )
17061
- continue;
17062
- const ts = Date.parse(event.timestamp);
17063
- if (!Number.isFinite(ts)) continue;
17064
- const ageMs = nowMs - ts;
17065
- if (ageMs < 0 || ageMs > windowMs) continue;
17066
-
17067
- const delta = this.actionOutcomePriorDelta(event);
17068
- if (delta === 0) continue;
17069
-
17070
- const recencyWeight = Math.max(0.2, 1 - ageMs / windowMs);
17071
- const list = byMemory.get(event.memoryId) ?? [];
17072
- if (list.length >= 8) list.shift();
17073
- list.push({
17074
- weightedDelta: delta * recencyWeight,
17075
- weight: recencyWeight,
17076
- });
17077
- byMemory.set(event.memoryId, list);
17078
- }
17079
-
17080
- const out = new Map<string, number>();
17081
- for (const [memoryId, deltas] of byMemory.entries()) {
17082
- if (deltas.length === 0) continue;
17083
- const weightedSum = deltas.reduce(
17084
- (sum, item) => sum + item.weightedDelta,
17085
- 0,
17086
- );
17087
- const weightTotal = deltas.reduce((sum, item) => sum + item.weight, 0);
17088
- if (weightTotal <= 0) continue;
17089
- const score = weightedSum / weightTotal;
17090
- out.set(memoryId, Math.max(-0.25, Math.min(0.15, score)));
17091
- }
17092
- return out;
17093
- }
17094
-
17095
16809
  private async recordScheduledDreamsPhaseRun(
17096
16810
  phase: "lightSleep" | "rem" | "deepSleep",
17097
16811
  itemsProcessed: number,
@@ -17126,315 +16840,23 @@ export class Orchestrator {
17126
16840
  allMemories: MemoryFile[],
17127
16841
  storage: StorageManager = this.storage,
17128
16842
  ): Promise<number> {
17129
- const now = new Date();
17130
- const nowIso = now.toISOString();
17131
- const countsByState: Record<LifecycleState, number> = {
17132
- candidate: 0,
17133
- validated: 0,
17134
- active: 0,
17135
- stale: 0,
17136
- archived: 0,
17137
- };
17138
- const transitionCounts: Record<string, number> = {};
17139
- let updatedCount = 0;
17140
- let disputedCount = 0;
17141
- let evaluatedCount = 0;
17142
- const lifecycleCaps = resolveMemoryLifecycleCapabilities(this.config);
17143
-
17144
- const thresholds = this.effectiveLifecycleThresholds();
17145
- const policy = {
17146
- promoteHeatThreshold: thresholds.promoteHeatThreshold,
17147
- staleDecayThreshold: thresholds.staleDecayThreshold,
17148
- archiveDecayThreshold: thresholds.archiveDecayThreshold,
17149
- protectedCategories: this.config.lifecycleProtectedCategories,
17150
- };
17151
- const actionPriors = await this.buildLifecycleActionPriors(storage);
17152
-
17153
- for (const memory of allMemories) {
17154
- if (
17155
- memory.frontmatter.status === "superseded" ||
17156
- memory.frontmatter.status === "forgotten"
17157
- ) {
17158
- continue;
17159
- }
17160
- evaluatedCount += 1;
17161
- const currentState = resolveLifecycleState(memory.frontmatter);
17162
- const actionPriorScore = actionPriors.get(memory.frontmatter.id);
17163
- const signals: LifecycleSignals | undefined =
17164
- typeof actionPriorScore === "number" &&
17165
- Number.isFinite(actionPriorScore)
17166
- ? { actionPriorScore }
17167
- : undefined;
17168
- const decision = decideLifecycleTransition(memory, policy, now, signals);
17169
- const nextState: LifecycleState =
17170
- memory.frontmatter.status === "archived"
17171
- ? "archived"
17172
- : decision.nextState;
17173
-
17174
- countsByState[nextState] += 1;
17175
- if (memory.frontmatter.verificationState === "disputed") {
17176
- disputedCount += 1;
17177
- }
17178
- if (nextState !== currentState) {
17179
- const key = `${currentState}->${nextState}`;
17180
- transitionCounts[key] = (transitionCounts[key] ?? 0) + 1;
17181
- }
17182
-
17183
- const prevHeat = memory.frontmatter.heatScore;
17184
- const prevDecay = memory.frontmatter.decayScore;
17185
- const scoreDelta =
17186
- Math.abs((prevHeat ?? -1) - decision.heatScore) +
17187
- Math.abs((prevDecay ?? -1) - decision.decayScore);
17188
- const shouldPersist =
17189
- memory.frontmatter.lifecycleState !== nextState ||
17190
- memory.frontmatter.heatScore === undefined ||
17191
- memory.frontmatter.decayScore === undefined ||
17192
- memory.frontmatter.lastValidatedAt === undefined ||
17193
- scoreDelta >= 0.01;
17194
-
17195
- if (!shouldPersist) continue;
17196
-
17197
- const wrote = await storage.writeMemoryFrontmatter(memory, {
17198
- lifecycleState: nextState,
17199
- heatScore: decision.heatScore,
17200
- decayScore: decision.decayScore,
17201
- lastValidatedAt: nowIso,
17202
- });
17203
- if (wrote) updatedCount += 1;
17204
- }
17205
-
17206
- // Report how many memories had frontmatter rewritten so callers can record a
17207
- // catalog write touch for lifecycle-only passes (codex NR-tS).
17208
- if (!lifecycleCaps.lifecycleMetrics) return updatedCount;
17209
-
17210
- const total = evaluatedCount;
17211
- const metrics = {
17212
- generatedAt: nowIso,
17213
- memoriesEvaluated: total,
17214
- memoriesUpdated: updatedCount,
17215
- countsByLifecycleState: countsByState,
17216
- transitionCounts,
17217
- staleRatio: total > 0 ? countsByState.stale / total : 0,
17218
- disputedRatio: total > 0 ? disputedCount / total : 0,
17219
- policy: {
17220
- promoteHeatThreshold: thresholds.promoteHeatThreshold,
17221
- staleDecayThreshold: thresholds.staleDecayThreshold,
17222
- archiveDecayThreshold: thresholds.archiveDecayThreshold,
17223
- protectedCategories: this.config.lifecycleProtectedCategories,
17224
- },
17225
- };
17226
- const metricsPath = path.join(
17227
- storage.dir,
17228
- "state",
17229
- "lifecycle-metrics.json",
17230
- );
17231
- await mkdir(path.dirname(metricsPath), { recursive: true });
17232
- await writeFile(metricsPath, JSON.stringify(metrics, null, 2), "utf-8");
17233
- return updatedCount;
16843
+ return this.lifecyclePolicyCoordinator.runLifecyclePolicyPass(allMemories, storage);
17234
16844
  }
17235
-
17236
- /**
17237
- * Archive old, low-importance, rarely-accessed facts (v6.0).
17238
- * Moves eligible facts from facts/ to archive/YYYY-MM-DD/.
17239
- * Returns the number of archived facts.
17240
- */
17241
16845
  private async runFactArchival(
17242
16846
  allMemories: import("./types.js").MemoryFile[],
17243
16847
  ): Promise<number> {
17244
- const now = Date.now();
17245
- const ageCutoffMs = this.config.factArchivalAgeDays * 24 * 60 * 60 * 1000;
17246
- const protectedCategories = new Set(
17247
- this.config.factArchivalProtectedCategories,
17248
- );
17249
- let archivedCount = 0;
17250
-
17251
- for (const memory of allMemories) {
17252
- const fm = memory.frontmatter;
17253
-
17254
- // Skip already-archived or superseded
17255
- if (fm.status && fm.status !== "active") continue;
17256
-
17257
- // Skip protected categories
17258
- if (protectedCategories.has(fm.category)) continue;
17259
-
17260
- // Skip corrections (always keep)
17261
- if (fm.category === "correction") continue;
17262
-
17263
- // Check age requirement
17264
- const createdMs = new Date(fm.created).getTime();
17265
- if (now - createdMs < ageCutoffMs) continue;
17266
-
17267
- // Check importance (only archive low-importance facts)
17268
- const importanceScore = fm.importance?.score ?? 0.5;
17269
- if (importanceScore >= this.config.factArchivalMaxImportance) continue;
17270
-
17271
- // Check access count
17272
- const accessCount = fm.accessCount ?? 0;
17273
- if (accessCount > this.config.factArchivalMaxAccessCount) continue;
17274
-
17275
- // All criteria met — archive
17276
- const result = await this.storage.archiveMemory(memory);
17277
- if (result) {
17278
- // Remove from the same storage-scoped content-hash index since it is
17279
- // no longer in hot search.
17280
- await this.removeContentHashForMemory(
17281
- this.storage,
17282
- memory,
17283
- "fact-archival",
17284
- );
17285
- await this.embeddingFallback.removeFromIndex(memory.frontmatter.id);
17286
- if (
17287
- resolveIndexingCapabilities(this.config).queryAwareIndexing &&
17288
- memory.path &&
17289
- memory.frontmatter?.created
17290
- ) {
17291
- deindexMemory(
17292
- this.config.memoryDir,
17293
- memory.path,
17294
- memory.frontmatter.created,
17295
- memory.frontmatter.tags ?? [],
17296
- );
17297
- }
17298
- archivedCount++;
17299
- }
17300
- }
17301
-
17302
- // Save hash indexes if we removed any entries.
17303
- if (archivedCount > 0) {
17304
- await this.saveContentHashIndexes().catch((err) =>
17305
- log.warn(`content-hash index save failed during archival: ${err}`),
17306
- );
17307
- }
17308
-
17309
- return archivedCount;
16848
+ return this.lifecyclePolicyCoordinator.runFactArchival(allMemories);
17310
16849
  }
17311
-
17312
- /**
17313
- * Run memory summarization if memory count exceeds threshold (Phase 4A).
17314
- */
17315
16850
  private async runSummarization(
17316
16851
  allMemories: import("./types.js").MemoryFile[],
17317
16852
  ): Promise<void> {
17318
- // Only active memories count toward the threshold
17319
- const activeMemories = allMemories.filter(
17320
- (m) => isActiveMemoryStatus(m.frontmatter.status),
17321
- );
17322
-
17323
- if (activeMemories.length < this.config.summarizationTriggerCount) {
17324
- return;
17325
- }
17326
-
17327
- log.info(
17328
- `memory count (${activeMemories.length}) exceeds threshold (${this.config.summarizationTriggerCount}) — running summarization`,
17329
- );
17330
-
17331
- // Sort by creation date, oldest first
17332
- const sorted = activeMemories.sort(
17333
- (a, b) =>
17334
- new Date(a.frontmatter.created).getTime() -
17335
- new Date(b.frontmatter.created).getTime(),
17336
- );
17337
-
17338
- // Keep recent memories, with explicit zero handling so `slice(-0)` does not
17339
- // accidentally keep every memory out of the summarization candidate set.
17340
- const recentToKeep = Math.max(0, this.config.summarizationRecentToKeep);
17341
- const toSummarize = recentToKeep > 0 ? sorted.slice(0, -recentToKeep) : sorted;
17342
-
17343
- // Filter candidates for summarization
17344
- const candidates = toSummarize.filter((m) => {
17345
- // Skip if protected by entity reference
17346
- if (m.frontmatter.entityRef) return false;
17347
-
17348
- // Skip if protected by tag
17349
- const protectedTags = this.config.summarizationProtectedTags;
17350
- if (m.frontmatter.tags.some((t) => protectedTags.includes(t)))
17351
- return false;
17352
-
17353
- // Skip if importance is above threshold
17354
- const importance = m.frontmatter.importance?.score ?? 0.5;
17355
- if (importance >= this.config.summarizationImportanceThreshold)
17356
- return false;
17357
-
17358
- return true;
17359
- });
17360
-
17361
- if (candidates.length < 50) {
17362
- log.debug(
17363
- `only ${candidates.length} candidates for summarization — skipping`,
17364
- );
17365
- return;
17366
- }
17367
-
17368
- // Summarize in batches of 50
17369
- const batchSize = 50;
17370
- for (let i = 0; i < candidates.length; i += batchSize) {
17371
- const batch = candidates.slice(i, i + batchSize);
17372
- const batchData = batch.map((m) => ({
17373
- id: m.frontmatter.id,
17374
- content: m.content,
17375
- category: m.frontmatter.category,
17376
- created: m.frontmatter.created,
17377
- }));
17378
-
17379
- const result = await this.extraction.summarizeMemories(batchData);
17380
- if (!result) continue;
17381
-
17382
- // Create summary
17383
- const summary: MemorySummary = {
17384
- id: `summary-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
17385
- createdAt: new Date().toISOString(),
17386
- timeRangeStart: batch[0].frontmatter.created,
17387
- timeRangeEnd: batch[batch.length - 1].frontmatter.created,
17388
- summaryText: result.summaryText,
17389
- keyFacts: result.keyFacts,
17390
- keyEntities: result.keyEntities,
17391
- sourceEpisodeIds: batch.map((m) => m.frontmatter.id),
17392
- };
17393
-
17394
- await this.storage.writeSummary(summary);
17395
-
17396
- // Archive source memories
17397
- const archived = await this.storage.archiveMemories(
17398
- batch.map((m) => m.frontmatter.id),
17399
- summary.id,
17400
- );
17401
-
17402
- // Catalog write touch (issue #1499 sweep): summarization writes a durable
17403
- // summary and then rewrites source-memory archive status, bypassing the
17404
- // extraction write path. Record the touch after both mutations complete so
17405
- // `lastWriteAt` covers the final archived-state write.
17406
- // #1522: catalog touch handled at the storage chokepoint.
17407
-
17408
- log.info(
17409
- `created summary ${summary.id} from ${batch.length} memories, archived ${archived}`,
17410
- );
17411
- }
16853
+ return this.lifecyclePolicyCoordinator.runSummarization(allMemories);
17412
16854
  }
17413
-
17414
- /**
17415
- * Run topic extraction on all memories (Phase 4B).
17416
- */
17417
16855
  private async runTopicExtraction(
17418
16856
  allMemories: import("./types.js").MemoryFile[],
17419
16857
  ): Promise<void> {
17420
- // Only extract from active memories
17421
- const activeMemories = allMemories.filter(
17422
- (m) => isActiveMemoryStatus(m.frontmatter.status),
17423
- );
17424
-
17425
- if (activeMemories.length === 0) return;
17426
-
17427
- const topics = extractTopics(
17428
- activeMemories,
17429
- this.config.topicExtractionTopN,
17430
- );
17431
- await this.storage.saveTopics(topics);
17432
-
17433
- log.debug(
17434
- `extracted ${topics.length} topics from ${activeMemories.length} memories`,
17435
- );
16858
+ return this.lifecyclePolicyCoordinator.runTopicExtraction(allMemories);
17436
16859
  }
17437
-
17438
16860
  /** Threshold (bytes) at which IDENTITY.md reflections get auto-consolidated */
17439
16861
  private static readonly IDENTITY_CONSOLIDATE_THRESHOLD = 8_000;
17440
16862
 
@@ -17888,7 +17310,7 @@ export class Orchestrator {
17888
17310
  private queueEvalShadowRecall(
17889
17311
  record: Omit<EvalShadowRecallRecord, "schemaVersion">,
17890
17312
  ): void {
17891
- if (!this.config.evalHarnessEnabled || !this.config.evalShadowModeEnabled)
17313
+ if (!resolveEvalCapabilities(this.config).evalHarness || !resolveEvalCapabilities(this.config).evalShadowMode)
17892
17314
  return;
17893
17315
  this.evalShadowWriteChain = this.evalShadowWriteChain
17894
17316
  .catch(() => undefined)