superlocalmemory 3.6.22 → 3.7.0

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 (303) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +275 -72
  3. package/bin/slm-npm +43 -89
  4. package/docs/pi-dev-integration.md +43 -0
  5. package/ide/configs/antigravity-mcp.json +2 -2
  6. package/ide/configs/chatgpt-desktop-mcp.json +1 -1
  7. package/ide/configs/claude-desktop-mcp.json +2 -2
  8. package/ide/configs/windsurf-mcp.json +2 -2
  9. package/ide/hooks/context-hook.js +6 -2
  10. package/ide/hooks/post-recall-hook.js +7 -3
  11. package/ide/hooks/tool-event-hook.sh +2 -1
  12. package/package.json +19 -10
  13. package/plugin/.claude-plugin/plugin.json +1 -1
  14. package/plugin/_GENERATED.md +1 -1
  15. package/plugin/agents/slm-memory-advisor.md +1 -1
  16. package/plugin/requirements.txt +1 -1
  17. package/plugin/skills/slm-session/SKILL.md +1 -1
  18. package/plugin-src/rules/AGENTS.md +1 -1
  19. package/pyproject.toml +40 -8
  20. package/scripts/postinstall-interactive.js +17 -94
  21. package/scripts/postinstall.js +185 -258
  22. package/scripts/preuninstall.js +9 -50
  23. package/src/superlocalmemory/__init__.py +2 -2
  24. package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
  25. package/src/superlocalmemory/attribution/signer.py +34 -19
  26. package/src/superlocalmemory/attribution/watermark.py +1 -1
  27. package/src/superlocalmemory/cli/_lazy_init.py +3 -5
  28. package/src/superlocalmemory/cli/commands.py +490 -195
  29. package/src/superlocalmemory/cli/context_commands.py +5 -4
  30. package/src/superlocalmemory/cli/daemon.py +282 -187
  31. package/src/superlocalmemory/cli/db_migrate.py +3 -1
  32. package/src/superlocalmemory/cli/diagnostics_cmd.py +28 -0
  33. package/src/superlocalmemory/cli/evidence_cmd.py +103 -0
  34. package/src/superlocalmemory/cli/ingest_cmd.py +7 -3
  35. package/src/superlocalmemory/cli/main.py +128 -31
  36. package/src/superlocalmemory/cli/pending_store.py +54 -38
  37. package/src/superlocalmemory/cli/scale_engine_cmd.py +37 -0
  38. package/src/superlocalmemory/cli/service_installer.py +57 -52
  39. package/src/superlocalmemory/cli/setup_wizard.py +142 -88
  40. package/src/superlocalmemory/cli/version_banner.py +2 -1
  41. package/src/superlocalmemory/code_graph/config.py +3 -1
  42. package/src/superlocalmemory/core/backend_orchestrator.py +81 -21
  43. package/src/superlocalmemory/core/config.py +65 -20
  44. package/src/superlocalmemory/core/consolidation_engine.py +9 -7
  45. package/src/superlocalmemory/core/context_cache.py +56 -8
  46. package/src/superlocalmemory/core/derivation_lineage.py +246 -0
  47. package/src/superlocalmemory/core/embedding_worker.py +32 -20
  48. package/src/superlocalmemory/core/embeddings.py +54 -18
  49. package/src/superlocalmemory/core/engine.py +150 -104
  50. package/src/superlocalmemory/core/engine_ingestion.py +513 -0
  51. package/src/superlocalmemory/core/engine_wiring.py +2 -0
  52. package/src/superlocalmemory/core/evidence_bundle.py +526 -0
  53. package/src/superlocalmemory/core/fact_consolidator.py +5 -11
  54. package/src/superlocalmemory/core/graph_analyzer.py +2 -2
  55. package/src/superlocalmemory/core/health_monitor.py +4 -2
  56. package/src/superlocalmemory/core/ingestion_command.py +636 -0
  57. package/src/superlocalmemory/core/injection.py +69 -18
  58. package/src/superlocalmemory/core/lifecycle_state.py +153 -0
  59. package/src/superlocalmemory/core/maintenance.py +23 -22
  60. package/src/superlocalmemory/core/maintenance_scheduler.py +51 -35
  61. package/src/superlocalmemory/core/mutations.py +143 -0
  62. package/src/superlocalmemory/core/platform_utils.py +7 -4
  63. package/src/superlocalmemory/core/ram_lock.py +16 -5
  64. package/src/superlocalmemory/core/rate_limit.py +1 -1
  65. package/src/superlocalmemory/core/recall_pipeline.py +60 -101
  66. package/src/superlocalmemory/core/recall_worker.py +76 -59
  67. package/src/superlocalmemory/core/registry.py +1 -1
  68. package/src/superlocalmemory/core/scale_engine.py +293 -0
  69. package/src/superlocalmemory/core/score_contract.py +62 -0
  70. package/src/superlocalmemory/core/security_primitives.py +3 -1
  71. package/src/superlocalmemory/core/slm_disabled.py +3 -5
  72. package/src/superlocalmemory/core/store_pipeline.py +172 -40
  73. package/src/superlocalmemory/core/tier_manager.py +32 -20
  74. package/src/superlocalmemory/core/worker_pool.py +13 -4
  75. package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
  76. package/src/superlocalmemory/dynamics/eap_scheduler.py +10 -3
  77. package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
  78. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
  79. package/src/superlocalmemory/encoding/auto_linker.py +1 -1
  80. package/src/superlocalmemory/encoding/cognitive_consolidator.py +7 -16
  81. package/src/superlocalmemory/encoding/consolidator.py +22 -5
  82. package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
  83. package/src/superlocalmemory/encoding/foresight.py +2 -0
  84. package/src/superlocalmemory/encoding/graph_builder.py +1 -1
  85. package/src/superlocalmemory/encoding/temporal_parser.py +2 -0
  86. package/src/superlocalmemory/evaluation/__init__.py +13 -0
  87. package/src/superlocalmemory/evaluation/calibration.py +308 -0
  88. package/src/superlocalmemory/evolution/skill_evolver.py +2 -1
  89. package/src/superlocalmemory/graph/cozo_backend.py +256 -23
  90. package/src/superlocalmemory/hooks/_outcome_common.py +21 -11
  91. package/src/superlocalmemory/hooks/antigravity_adapter.py +10 -31
  92. package/src/superlocalmemory/hooks/auto_invoker.py +25 -27
  93. package/src/superlocalmemory/hooks/auto_recall.py +31 -6
  94. package/src/superlocalmemory/hooks/auto_recall_hook.py +13 -33
  95. package/src/superlocalmemory/hooks/before_web_hook.py +9 -7
  96. package/src/superlocalmemory/hooks/claude_code_hooks.py +126 -39
  97. package/src/superlocalmemory/hooks/codex_assets.py +59 -0
  98. package/src/superlocalmemory/hooks/codex_hooks.py +186 -0
  99. package/src/superlocalmemory/hooks/context_payload.py +1 -1
  100. package/src/superlocalmemory/hooks/copilot_adapter.py +9 -24
  101. package/src/superlocalmemory/hooks/cursor_adapter.py +10 -32
  102. package/src/superlocalmemory/hooks/hook_daemon.py +4 -2
  103. package/src/superlocalmemory/hooks/hook_handlers.py +241 -55
  104. package/src/superlocalmemory/hooks/memory_protocol.py +5 -3
  105. package/src/superlocalmemory/hooks/post_tool_async_hook.py +4 -2
  106. package/src/superlocalmemory/hooks/session_registry.py +15 -8
  107. package/src/superlocalmemory/hooks/stop_outcome_hook.py +10 -6
  108. package/src/superlocalmemory/hooks/topic_shift_hook.py +42 -12
  109. package/src/superlocalmemory/hooks/user_prompt_hook.py +9 -14
  110. package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +19 -11
  111. package/src/superlocalmemory/infra/auth_middleware.py +38 -5
  112. package/src/superlocalmemory/infra/backup.py +7 -5
  113. package/src/superlocalmemory/infra/cloud_backup.py +18 -8
  114. package/src/superlocalmemory/infra/daemon_identity.py +248 -0
  115. package/src/superlocalmemory/infra/data_root.py +199 -0
  116. package/src/superlocalmemory/infra/event_bus.py +3 -1
  117. package/src/superlocalmemory/infra/local_diagnostics.py +327 -0
  118. package/src/superlocalmemory/infra/process_reaper.py +23 -0
  119. package/src/superlocalmemory/ingestion/adapter_manager.py +27 -9
  120. package/src/superlocalmemory/ingestion/base_adapter.py +25 -31
  121. package/src/superlocalmemory/ingestion/calendar_adapter.py +13 -4
  122. package/src/superlocalmemory/ingestion/credentials.py +14 -7
  123. package/src/superlocalmemory/ingestion/gmail_adapter.py +13 -4
  124. package/src/superlocalmemory/ingestion/transcript_adapter.py +7 -2
  125. package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
  126. package/src/superlocalmemory/learning/ensemble.py +11 -0
  127. package/src/superlocalmemory/learning/entity_compiler.py +1 -1
  128. package/src/superlocalmemory/learning/feedback.py +1 -1
  129. package/src/superlocalmemory/learning/forgetting_scheduler.py +12 -7
  130. package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
  131. package/src/superlocalmemory/learning/ranker.py +4 -1
  132. package/src/superlocalmemory/learning/source_quality.py +1 -1
  133. package/src/superlocalmemory/learning/trigram_index.py +3 -2
  134. package/src/superlocalmemory/llm/backbone.py +13 -8
  135. package/src/superlocalmemory/math/ebbinghaus.py +1 -1
  136. package/src/superlocalmemory/math/fisher.py +1 -1
  137. package/src/superlocalmemory/math/fisher_quantized.py +1 -1
  138. package/src/superlocalmemory/math/hopfield.py +1 -1
  139. package/src/superlocalmemory/math/langevin.py +1 -1
  140. package/src/superlocalmemory/math/polar_quant.py +3 -4
  141. package/src/superlocalmemory/math/qjl.py +1 -1
  142. package/src/superlocalmemory/math/sheaf.py +1 -1
  143. package/src/superlocalmemory/math/turbo_quant.py +3 -2
  144. package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -11
  145. package/src/superlocalmemory/mcp/_pool_adapter.py +27 -0
  146. package/src/superlocalmemory/mcp/http_transport.py +53 -0
  147. package/src/superlocalmemory/mcp/server.py +39 -13
  148. package/src/superlocalmemory/mcp/shared.py +69 -3
  149. package/src/superlocalmemory/mcp/tools_active.py +141 -31
  150. package/src/superlocalmemory/mcp/tools_core.py +128 -29
  151. package/src/superlocalmemory/mcp/tools_evolution.py +5 -7
  152. package/src/superlocalmemory/mcp/tools_learning.py +42 -2
  153. package/src/superlocalmemory/mcp/tools_mesh.py +7 -23
  154. package/src/superlocalmemory/mcp/tools_optimize.py +8 -1
  155. package/src/superlocalmemory/mcp/tools_v28.py +23 -2
  156. package/src/superlocalmemory/mcp/tools_v3.py +26 -1
  157. package/src/superlocalmemory/mcp/tools_v33.py +56 -17
  158. package/src/superlocalmemory/mesh/broker.py +2 -0
  159. package/src/superlocalmemory/mesh/remote_sync.py +50 -12
  160. package/src/superlocalmemory/optimize/cache/manager.py +77 -1
  161. package/src/superlocalmemory/optimize/cache/semantic.py +23 -3
  162. package/src/superlocalmemory/optimize/compress/ccr.py +4 -0
  163. package/src/superlocalmemory/optimize/compress/router.py +6 -1
  164. package/src/superlocalmemory/optimize/config/__init__.py +5 -0
  165. package/src/superlocalmemory/optimize/config/store.py +6 -4
  166. package/src/superlocalmemory/optimize/proxy/_helpers.py +15 -5
  167. package/src/superlocalmemory/optimize/proxy/capture.py +3 -2
  168. package/src/superlocalmemory/optimize/proxy/server.py +2 -2
  169. package/src/superlocalmemory/optimize/storage/db.py +14 -13
  170. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  171. package/src/superlocalmemory/retrieval/ann_index.py +1 -1
  172. package/src/superlocalmemory/retrieval/bm25_channel.py +35 -11
  173. package/src/superlocalmemory/retrieval/bridge_discovery.py +73 -8
  174. package/src/superlocalmemory/retrieval/engine.py +169 -79
  175. package/src/superlocalmemory/retrieval/entity_channel.py +289 -67
  176. package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
  177. package/src/superlocalmemory/retrieval/fusion.py +1 -1
  178. package/src/superlocalmemory/retrieval/hopfield_channel.py +118 -30
  179. package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
  180. package/src/superlocalmemory/retrieval/quantization_aware_search.py +16 -10
  181. package/src/superlocalmemory/retrieval/reranker.py +56 -20
  182. package/src/superlocalmemory/retrieval/scope_policy.py +85 -0
  183. package/src/superlocalmemory/retrieval/semantic_channel.py +122 -14
  184. package/src/superlocalmemory/retrieval/spreading_activation.py +141 -25
  185. package/src/superlocalmemory/retrieval/strategy.py +1 -1
  186. package/src/superlocalmemory/retrieval/temporal_channel.py +30 -15
  187. package/src/superlocalmemory/retrieval/vector_store.py +1 -1
  188. package/src/superlocalmemory/server/api.py +10 -7
  189. package/src/superlocalmemory/server/bandit_loops.py +4 -2
  190. package/src/superlocalmemory/server/recall_serializer.py +24 -0
  191. package/src/superlocalmemory/server/route_mutations.py +84 -0
  192. package/src/superlocalmemory/server/routes/agents.py +8 -6
  193. package/src/superlocalmemory/server/routes/brain.py +14 -12
  194. package/src/superlocalmemory/server/routes/chat.py +29 -12
  195. package/src/superlocalmemory/server/routes/data_io.py +55 -24
  196. package/src/superlocalmemory/server/routes/helpers.py +29 -4
  197. package/src/superlocalmemory/server/routes/ingest.py +53 -36
  198. package/src/superlocalmemory/server/routes/memories.py +104 -43
  199. package/src/superlocalmemory/server/routes/mesh.py +31 -0
  200. package/src/superlocalmemory/server/routes/profiles.py +26 -4
  201. package/src/superlocalmemory/server/routes/tiers.py +43 -11
  202. package/src/superlocalmemory/server/routes/timeline.py +5 -1
  203. package/src/superlocalmemory/server/routes/v3_api.py +76 -21
  204. package/src/superlocalmemory/server/security_middleware.py +1 -1
  205. package/src/superlocalmemory/server/ui.py +6 -3
  206. package/src/superlocalmemory/server/unified_daemon.py +680 -293
  207. package/src/superlocalmemory/server/write_identity.py +147 -0
  208. package/src/superlocalmemory/storage/access_log.py +4 -3
  209. package/src/superlocalmemory/storage/database.py +118 -25
  210. package/src/superlocalmemory/storage/migration_runner.py +84 -1
  211. package/src/superlocalmemory/storage/migration_v33.py +1 -1
  212. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +6 -60
  213. package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +120 -0
  214. package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +54 -0
  215. package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +52 -0
  216. package/src/superlocalmemory/storage/migrations/__init__.py +5 -0
  217. package/src/superlocalmemory/storage/models.py +16 -0
  218. package/src/superlocalmemory/storage/quantized_store.py +20 -3
  219. package/src/superlocalmemory/storage/v2_migrator.py +5 -3
  220. package/src/superlocalmemory/ui/favicon.svg +5 -0
  221. package/src/superlocalmemory/ui/index.html +1 -0
  222. package/src/superlocalmemory/ui/js/compliance.js +1 -1
  223. package/src/superlocalmemory/ui/js/core.js +49 -8
  224. package/src/superlocalmemory/ui/js/dashboard.js +23 -2
  225. package/src/superlocalmemory/ui/js/feedback.js +1 -1
  226. package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
  227. package/src/superlocalmemory/ui/js/graph-ui.js +1 -1
  228. package/src/superlocalmemory/ui/js/lifecycle.js +1 -1
  229. package/src/superlocalmemory/ui/js/ng-mesh.js +15 -49
  230. package/src/superlocalmemory/ui/js/settings.js +4 -2
  231. package/src/superlocalmemory/vector/lancedb_backend.py +57 -9
  232. package/bin/slm +0 -59
  233. package/bin/slm.bat +0 -77
  234. package/bin/slm.cmd +0 -5
  235. package/ide/integrations/langchain/README.md +0 -106
  236. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +0 -9
  237. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +0 -201
  238. package/ide/integrations/langchain/pyproject.toml +0 -38
  239. package/ide/integrations/langchain/tests/__init__.py +0 -3
  240. package/ide/integrations/langchain/tests/test_chat_message_history.py +0 -215
  241. package/ide/integrations/langchain/tests/test_security.py +0 -117
  242. package/ide/integrations/llamaindex/README.md +0 -81
  243. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +0 -9
  244. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +0 -316
  245. package/ide/integrations/llamaindex/pyproject.toml +0 -43
  246. package/ide/integrations/llamaindex/tests/__init__.py +0 -3
  247. package/ide/integrations/llamaindex/tests/test_chat_store.py +0 -294
  248. package/ide/integrations/llamaindex/tests/test_security.py +0 -241
  249. package/plugin-src/.mcp.json +0 -12
  250. package/plugin-src/agents/slm-memory-advisor.md +0 -44
  251. package/plugin-src/agents/slm-optimize-advisor.md +0 -38
  252. package/plugin-src/hooks/.gitkeep +0 -0
  253. package/plugin-src/hooks/hooks.json +0 -23
  254. package/plugin-src/manifest.json +0 -25
  255. package/plugin-src/requirements.txt +0 -1
  256. package/plugin-src/rules/CLAUDE.md.fragment +0 -44
  257. package/plugin-src/scripts/ensure-venv.bat +0 -122
  258. package/plugin-src/scripts/ensure-venv.sh +0 -105
  259. package/plugin-src/scripts/slm-launch +0 -15
  260. package/plugin-src/scripts/slm-launch.bat +0 -17
  261. package/plugin-src/settings.json +0 -16
  262. package/plugin-src/skills/slm-cache/SKILL.md +0 -140
  263. package/plugin-src/skills/slm-compress/SKILL.md +0 -143
  264. package/plugin-src/skills/slm-graph/SKILL.md +0 -300
  265. package/plugin-src/skills/slm-recall/SKILL.md +0 -204
  266. package/plugin-src/skills/slm-remember/SKILL.md +0 -194
  267. package/plugin-src/skills/slm-session/SKILL.md +0 -207
  268. package/plugin-src/skills/slm-status/SKILL.md +0 -149
  269. package/scripts/__tests__/build-plugin.test.mjs +0 -613
  270. package/scripts/_savings_math.py +0 -270
  271. package/scripts/build-dmg.sh +0 -417
  272. package/scripts/build-plugin.js +0 -742
  273. package/scripts/build-slm-hook.ps1 +0 -40
  274. package/scripts/build-slm-hook.sh +0 -45
  275. package/scripts/build_entry.py +0 -452
  276. package/scripts/ci/stage5b_gate.sh +0 -50
  277. package/scripts/dogfood_savings.py +0 -490
  278. package/scripts/generate-thumbnails.py +0 -218
  279. package/scripts/install-skills.ps1 +0 -4
  280. package/scripts/install-skills.sh +0 -5
  281. package/scripts/install.ps1 +0 -701
  282. package/scripts/install.sh +0 -1015
  283. package/scripts/postinstall_binary.js +0 -287
  284. package/scripts/prepack.js +0 -33
  285. package/scripts/release_manifest.py +0 -273
  286. package/scripts/slm-hook.spec +0 -56
  287. package/scripts/start-dashboard.ps1 +0 -52
  288. package/scripts/start-dashboard.sh +0 -41
  289. package/scripts/sync-wiki.ps1 +0 -127
  290. package/scripts/sync-wiki.sh +0 -82
  291. package/scripts/test-dmg.sh +0 -161
  292. package/scripts/test-npm-package.ps1 +0 -252
  293. package/scripts/test-npm-package.sh +0 -207
  294. package/scripts/verify-install.ps1 +0 -294
  295. package/scripts/verify-install.sh +0 -266
  296. package/scripts/verify-v27.ps1 +0 -301
  297. package/scripts/verify-v27.sh +0 -233
  298. package/src/superlocalmemory.egg-info/PKG-INFO +0 -513
  299. package/src/superlocalmemory.egg-info/SOURCES.txt +0 -529
  300. package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
  301. package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
  302. package/src/superlocalmemory.egg-info/requires.txt +0 -71
  303. package/src/superlocalmemory.egg-info/top_level.txt +0 -1
@@ -18,6 +18,7 @@ Part of Qualixar | Author: Varun Pratap Bhardwaj
18
18
  from __future__ import annotations
19
19
 
20
20
  import logging
21
+ from pathlib import Path
21
22
  from typing import Any
22
23
 
23
24
  from superlocalmemory.core.config import CANONICAL_RECALL_LIMIT, SLMConfig
@@ -32,6 +33,19 @@ logger = logging.getLogger(__name__)
32
33
  from superlocalmemory.core.hooks import HookRegistry
33
34
 
34
35
 
36
+ def _verify_ingestion_schema(memory_db: Path) -> bool:
37
+ """Verify M018 using an explicitly owned SQLite connection."""
38
+ import sqlite3
39
+
40
+ from superlocalmemory.storage.migrations import M018_ingestion_operations
41
+
42
+ connection = sqlite3.connect(str(memory_db))
43
+ try:
44
+ return bool(M018_ingestion_operations.verify(connection))
45
+ finally:
46
+ connection.close()
47
+
48
+
35
49
  class MemoryEngine:
36
50
  """Main orchestrator for the SuperLocalMemory V3 memory system.
37
51
 
@@ -170,7 +184,9 @@ class MemoryEngine:
170
184
  # Previously only the daemon lifespan ran apply_deferred, so an existing
171
185
  # pre-3.6.15 database used WITHOUT the daemon hit
172
186
  # "table memories has no column named scope" on the first scoped write.
173
- # Idempotent (skips applied migrations) + non-fatal; mirrors the daemon.
187
+ # Idempotent (skips applied migrations). M018 is now a hard runtime
188
+ # prerequisite: allowing initialization to continue without it would
189
+ # make every advertised write path fail after startup.
174
190
  try:
175
191
  from superlocalmemory.storage.migration_runner import (
176
192
  apply_all, apply_deferred,
@@ -178,10 +194,22 @@ class MemoryEngine:
178
194
  _base = self._config.base_dir
179
195
  _learning_db = _base / "learning.db"
180
196
  _memory_db = self._db.db_path
197
+ # Forward migrations extend the historical learning schema. A
198
+ # fresh explicit data root has no learning.db yet, so bootstrap
199
+ # those base tables before applying M001/M002/M009.
200
+ from superlocalmemory.learning.database import LearningDatabase
201
+ LearningDatabase(_learning_db)
181
202
  apply_all(_learning_db, _memory_db)
182
203
  apply_deferred(_learning_db, _memory_db)
204
+ if not _verify_ingestion_schema(_memory_db):
205
+ raise RuntimeError(
206
+ "required M018 canonical-ingestion schema is unavailable"
207
+ )
183
208
  except Exception as exc:
184
- logger.warning("v3.6.15 deferred migration apply failed: %s", exc)
209
+ raise RuntimeError(
210
+ "MemoryEngine initialization stopped because the required "
211
+ f"ingestion migration failed: {exc}"
212
+ ) from exc
185
213
 
186
214
  # V3.4.7: Apply "Learning Brain" schema (tool_events, behavioral_assertions)
187
215
  try:
@@ -364,11 +392,30 @@ class MemoryEngine:
364
392
  meta = {}
365
393
  if not isinstance(meta, dict):
366
394
  meta = {}
367
- _scope = meta.get("scope") or "personal"
368
- _shared = meta.get("shared_with")
369
- self.store(
370
- item["content"], metadata=meta or None,
371
- scope=_scope, shared_with=_shared,
395
+ _scope = meta.pop("scope", None) or "personal"
396
+ _shared = meta.pop("shared_with", None)
397
+ _source_type = str(
398
+ meta.pop("_slm_source_type", "legacy-pending")
399
+ )
400
+ _idempotency_key = str(
401
+ meta.pop("_slm_idempotency_key", f"pending:{item['id']}")
402
+ )
403
+ if item.get("tags"):
404
+ meta.setdefault("tags", item["tags"])
405
+ from superlocalmemory.core.engine_ingestion import (
406
+ canonical_store,
407
+ local_trusted_actor_id,
408
+ )
409
+ canonical_store(
410
+ self,
411
+ item["content"],
412
+ source_type=_source_type,
413
+ trusted_actor_id=local_trusted_actor_id("engine-startup"),
414
+ metadata=meta or None,
415
+ scope=_scope,
416
+ shared_with=_shared,
417
+ session_id=str(meta.get("session_id") or ""),
418
+ idempotency_key=_idempotency_key,
372
419
  )
373
420
  mark_done(item["id"], base_dir)
374
421
  except Exception as exc:
@@ -397,54 +444,45 @@ class MemoryEngine:
397
444
  self._require_full("store")
398
445
  self._ensure_init()
399
446
 
400
- from superlocalmemory.core.store_pipeline import run_store
401
- return run_store(
402
- content, self._profile_id,
403
- session_id=session_id, session_date=session_date,
404
- speaker=speaker, role=role, metadata=metadata,
405
- scope=scope, shared_with=shared_with,
406
- config=self._config, db=self._db,
407
- embedder=self._embedder,
408
- fact_extractor=self._fact_extractor,
409
- entity_resolver=self._entity_resolver,
410
- temporal_parser=self._temporal_parser,
411
- type_router=self._type_router,
412
- graph_builder=self._graph_builder,
413
- consolidator=self._consolidator,
414
- observation_builder=self._observation_builder,
415
- scene_builder=self._scene_builder,
416
- entropy_gate=self._entropy_gate,
417
- ann_index=self._ann_index,
418
- sheaf_checker=self._sheaf_checker,
419
- retrieval_engine=self._retrieval_engine,
420
- provenance=self._provenance,
421
- hooks=self._hooks,
422
- vector_store=self._vector_store,
423
- context_generator=self._context_generator,
424
- temporal_validator=self._temporal_validator,
425
- auto_linker=self._auto_linker,
426
- consolidation_engine=self._consolidation_engine,
447
+ from superlocalmemory.core.engine_ingestion import (
448
+ canonical_store,
449
+ local_trusted_actor_id,
450
+ )
451
+ return canonical_store(
452
+ self,
453
+ content,
454
+ source_type="python-api",
455
+ trusted_actor_id=local_trusted_actor_id("python-api"),
456
+ metadata=metadata,
457
+ scope=scope,
458
+ shared_with=shared_with,
459
+ session_id=session_id,
460
+ session_date=session_date,
461
+ speaker=speaker,
462
+ role=role,
463
+ require_complete=False,
427
464
  )
428
465
 
429
466
  def store_fact_direct(self, fact: AtomicFact) -> str:
430
- """Store a pre-built fact with full enrichment."""
467
+ """Durably store a pre-built fact with full enrichment."""
431
468
  self._require_full("store_fact_direct")
432
469
  self._ensure_init()
433
470
 
434
- from superlocalmemory.core.store_pipeline import run_store_fact_direct
435
- return run_store_fact_direct(
436
- fact, self._profile_id,
437
- db=self._db, embedder=self._embedder,
438
- entity_resolver=self._entity_resolver,
439
- ann_index=self._ann_index,
440
- graph_builder=self._graph_builder,
441
- retrieval_engine=self._retrieval_engine,
442
- vector_store=self._vector_store,
471
+ from superlocalmemory.core.engine_ingestion import (
472
+ canonical_store_fact,
473
+ local_trusted_actor_id,
474
+ )
475
+ return canonical_store_fact(
476
+ self,
477
+ fact,
478
+ trusted_actor_id=local_trusted_actor_id("python-api-prebuilt"),
443
479
  )
444
480
 
445
481
  def store_fast(
446
482
  self, content: str, metadata: dict[str, Any] | None = None,
447
483
  *, scope: str = "personal", shared_with: list[str] | None = None,
484
+ session_date: str | None = None, speaker: str = "", role: str = "user",
485
+ index_external: bool = True,
448
486
  ) -> list[str]:
449
487
  """v3.5.5 WRITE-THROUGH: synchronous verbatim insert for IMMEDIATE recall.
450
488
 
@@ -470,14 +508,9 @@ class MemoryEngine:
470
508
  from superlocalmemory.storage.models import (
471
509
  AtomicFact, FactType, MemoryRecord,
472
510
  )
473
- if not content or not content.strip():
511
+ from superlocalmemory.core.engine_ingestion import content_passes_admission
512
+ if not content_passes_admission(content):
474
513
  return []
475
- try:
476
- from superlocalmemory.core.injection import is_low_quality
477
- if is_low_quality(content):
478
- return []
479
- except Exception:
480
- pass
481
514
  # v3.6.6 ingest gate: reject 1MB monsters + prompt-template pollution;
482
515
  # clamp the searchable FACT copy (head+tail) while the memories row keeps
483
516
  # the FULL original. Embedding/BM25 use the clamped copy so a 167KB paste
@@ -500,8 +533,10 @@ class MemoryEngine:
500
533
  now = datetime.now(timezone.utc).isoformat()
501
534
  record = MemoryRecord(
502
535
  profile_id=self._profile_id, content=content,
503
- session_date=now[:10],
536
+ session_date=session_date or now[:10],
504
537
  session_id=(metadata or {}).get("session_id", ""),
538
+ speaker=speaker,
539
+ role=role,
505
540
  metadata=metadata or {},
506
541
  scope=scope, shared_with=shared_with,
507
542
  )
@@ -513,44 +548,42 @@ class MemoryEngine:
513
548
  r"\b([A-Z][a-z]+(?:\s[A-Z][a-z]+){0,3})\b", fact_text)}
514
549
  | {m.group(1) for m in _re.finditer(r"\b([A-Z]{2,})\b", fact_text)}
515
550
  )
516
- # v3.5.5: compute the embedding SYNCHRONOUSLY. A single warm embed is
517
- # ~22ms (the 30-180s of full store() was LLM fact-extraction + graph,
518
- # NOT embedding). With the embedding present, the semantic channel
519
- # scores this fact correctly so it ranks properly IMMEDIATELY — not
520
- # just keyword-findable but top-ranked. Graph/entity enrichment stays
521
- # async. Embed failure fact still inserted (keyword-recallable).
551
+ # Queryable admission must never acquire the embedding worker lock.
552
+ # On a warm daemon that looked cheap, but on a clean Mode A install the
553
+ # background model load owns that lock for up to 180s and turned the
554
+ # receipt-first path into a hidden synchronous wait. The canonical
555
+ # materializer below runs the complete pipeline and promotes this same
556
+ # fact with its embedding, Fisher parameters, entities and graph edges.
557
+ # Until then it is deliberately BM25/entity/date recallable.
522
558
  emb = None
523
559
  fmean = fvar = None
524
- try:
525
- emb = self._embedder.embed(fact_text) if self._embedder else None
526
- if emb:
527
- fmean, fvar = self._embedder.compute_fisher_params(emb)
528
- except Exception:
529
- emb = None
530
560
  fact = AtomicFact(
531
561
  fact_id=_uuid.uuid4().hex[:16], memory_id=record.memory_id,
532
562
  profile_id=self._profile_id, content=fact_text,
533
563
  fact_type=FactType.EPISODIC, entities=ents,
534
- observation_date=now[:10], confidence=0.7, importance=0.5,
564
+ observation_date=session_date or now[:10],
565
+ confidence=0.7, importance=0.5,
535
566
  embedding=emb, fisher_mean=fmean, fisher_variance=fvar,
536
567
  created_at=now,
537
568
  scope=scope, shared_with=shared_with,
538
569
  )
539
570
  self._db.store_fact(fact) # FTS5 trigger → immediately BM25-recallable
540
571
  # Upsert to vector store so the semantic channel finds it now.
541
- try:
542
- vs = getattr(self, "_vector_store", None)
543
- if emb and vs and getattr(vs, "available", False):
544
- vs.upsert(fact.fact_id, self._profile_id, emb)
545
- except Exception:
546
- pass
572
+ if index_external:
573
+ try:
574
+ vs = getattr(self, "_vector_store", None)
575
+ if emb and vs and getattr(vs, "available", False):
576
+ vs.upsert(fact.fact_id, self._profile_id, emb)
577
+ except Exception:
578
+ pass
547
579
  # Persist BM25 tokens too (covers the in-memory rank_bm25 fallback path).
548
- try:
549
- bm25 = getattr(self._retrieval_engine, "_bm25", None)
550
- if bm25:
551
- bm25.add(fact.fact_id, fact_text, self._profile_id)
552
- except Exception:
553
- pass
580
+ if index_external:
581
+ try:
582
+ bm25 = getattr(self._retrieval_engine, "_bm25", None)
583
+ if bm25:
584
+ bm25.add(fact.fact_id, fact_text, self._profile_id)
585
+ except Exception:
586
+ pass
554
587
  return [fact.fact_id]
555
588
 
556
589
  # -- Recall operations --------------------------------------------------
@@ -574,11 +607,10 @@ class MemoryEngine:
574
607
  ``put_nowait`` and the actual ``pending_outcomes`` INSERT runs
575
608
  on a background worker.
576
609
 
577
- V3.4.40 (2026-05-09): ``fast=True`` skips the SpreadingActivation
578
- channel. Deprecated in v3.6.9 SA now completes in ~36ms after the
579
- neighbor-cache fix; fast=True is slower than fast=False and reduces
580
- recall quality. The parameter is accepted for backward compatibility
581
- but is silently treated as False.
610
+ ``fast=True`` is the latency-bounded path: it skips spreading
611
+ activation and remote agentic verification while retaining semantic,
612
+ lexical, graph, temporal, and Hopfield retrieval. Use full recall when
613
+ maximum multi-round quality matters more than response time.
582
614
 
583
615
  Multi-scope: ``include_global`` / ``include_shared`` control which
584
616
  scopes participate in retrieval. ``None`` (the default) means "use the
@@ -599,31 +631,33 @@ class MemoryEngine:
599
631
  if include_shared is None:
600
632
  include_shared = bool(getattr(_scope_cfg, "recall_include_shared", False))
601
633
 
602
- if fast:
603
- logger.warning(
604
- "fast=True is deprecated (v3.6.9): SpreadingActivation now "
605
- "completes in ~36ms; fast mode is slower and reduces quality. "
606
- "Pass fast=False (the default) to silence this warning."
607
- )
608
- fast = False
609
-
610
634
  pid = profile_id or self._profile_id
611
635
 
612
636
  from superlocalmemory.core.recall_pipeline import run_recall
613
- response = run_recall(
614
- query, pid, mode=mode, limit=limit, agent_id=agent_id,
615
- config=self._config,
616
- retrieval_engine=self._retrieval_engine,
617
- trust_scorer=self._trust_scorer,
618
- embedder=self._embedder,
619
- db=self._db, llm=self._llm,
620
- hooks=self._hooks,
621
- access_log=self._access_log,
622
- auto_linker=self._auto_linker,
623
- fast=fast,
624
- include_global=include_global,
625
- include_shared=include_shared,
626
- )
637
+ try:
638
+ response = run_recall(
639
+ query, pid, mode=mode, limit=limit, agent_id=agent_id,
640
+ config=self._config,
641
+ retrieval_engine=self._retrieval_engine,
642
+ trust_scorer=self._trust_scorer,
643
+ embedder=self._embedder,
644
+ db=self._db, llm=self._llm,
645
+ hooks=self._hooks,
646
+ access_log=self._access_log,
647
+ auto_linker=self._auto_linker,
648
+ fast=fast,
649
+ include_global=include_global,
650
+ include_shared=include_shared,
651
+ )
652
+ except Exception as exc:
653
+ from superlocalmemory.infra.local_diagnostics import record_operation
654
+
655
+ record_operation("recall", client=agent_id, error=exc)
656
+ raise
657
+
658
+ from superlocalmemory.infra.local_diagnostics import record_recall
659
+
660
+ record_recall(self._db, response, client=agent_id)
627
661
 
628
662
  # S9-DASH-02: enqueue for pending_outcomes. Non-blocking; errors
629
663
  # swallowed because signal capture is never load-bearing on
@@ -685,7 +719,19 @@ class MemoryEngine:
685
719
  def close(self) -> None:
686
720
  if self._maintenance_scheduler is not None:
687
721
  self._maintenance_scheduler.stop()
722
+ if self._retrieval_engine is not None:
723
+ try:
724
+ self._retrieval_engine.close()
725
+ except Exception:
726
+ pass
688
727
  if self._db is not None:
728
+ try:
729
+ from superlocalmemory.core.recall_pipeline import (
730
+ release_recall_resources,
731
+ )
732
+ release_recall_resources(self._db)
733
+ except Exception:
734
+ pass
689
735
  try:
690
736
  self._db.close()
691
737
  except Exception: