superlocalmemory 3.6.23 → 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 (301) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +271 -71
  3. package/bin/slm-npm +43 -89
  4. package/ide/configs/antigravity-mcp.json +2 -2
  5. package/ide/configs/chatgpt-desktop-mcp.json +1 -1
  6. package/ide/configs/claude-desktop-mcp.json +2 -2
  7. package/ide/configs/windsurf-mcp.json +2 -2
  8. package/ide/hooks/context-hook.js +6 -2
  9. package/ide/hooks/post-recall-hook.js +7 -3
  10. package/ide/hooks/tool-event-hook.sh +2 -1
  11. package/package.json +18 -10
  12. package/plugin/.claude-plugin/plugin.json +1 -1
  13. package/plugin/_GENERATED.md +1 -1
  14. package/plugin/agents/slm-memory-advisor.md +1 -1
  15. package/plugin/requirements.txt +1 -1
  16. package/plugin/skills/slm-session/SKILL.md +1 -1
  17. package/plugin-src/rules/AGENTS.md +1 -1
  18. package/pyproject.toml +40 -8
  19. package/scripts/postinstall-interactive.js +17 -94
  20. package/scripts/postinstall.js +185 -258
  21. package/scripts/preuninstall.js +9 -50
  22. package/src/superlocalmemory/__init__.py +2 -2
  23. package/src/superlocalmemory/attribution/mathematical_dna.py +1 -1
  24. package/src/superlocalmemory/attribution/signer.py +34 -19
  25. package/src/superlocalmemory/attribution/watermark.py +1 -1
  26. package/src/superlocalmemory/cli/_lazy_init.py +3 -5
  27. package/src/superlocalmemory/cli/commands.py +453 -191
  28. package/src/superlocalmemory/cli/context_commands.py +5 -4
  29. package/src/superlocalmemory/cli/daemon.py +282 -187
  30. package/src/superlocalmemory/cli/db_migrate.py +3 -1
  31. package/src/superlocalmemory/cli/diagnostics_cmd.py +28 -0
  32. package/src/superlocalmemory/cli/evidence_cmd.py +103 -0
  33. package/src/superlocalmemory/cli/ingest_cmd.py +7 -3
  34. package/src/superlocalmemory/cli/main.py +128 -31
  35. package/src/superlocalmemory/cli/pending_store.py +54 -38
  36. package/src/superlocalmemory/cli/scale_engine_cmd.py +37 -0
  37. package/src/superlocalmemory/cli/service_installer.py +57 -52
  38. package/src/superlocalmemory/cli/setup_wizard.py +142 -88
  39. package/src/superlocalmemory/cli/version_banner.py +2 -1
  40. package/src/superlocalmemory/code_graph/config.py +3 -1
  41. package/src/superlocalmemory/core/backend_orchestrator.py +81 -21
  42. package/src/superlocalmemory/core/config.py +65 -20
  43. package/src/superlocalmemory/core/consolidation_engine.py +9 -7
  44. package/src/superlocalmemory/core/context_cache.py +56 -8
  45. package/src/superlocalmemory/core/derivation_lineage.py +246 -0
  46. package/src/superlocalmemory/core/embedding_worker.py +32 -20
  47. package/src/superlocalmemory/core/embeddings.py +54 -18
  48. package/src/superlocalmemory/core/engine.py +150 -104
  49. package/src/superlocalmemory/core/engine_ingestion.py +513 -0
  50. package/src/superlocalmemory/core/engine_wiring.py +2 -0
  51. package/src/superlocalmemory/core/evidence_bundle.py +526 -0
  52. package/src/superlocalmemory/core/fact_consolidator.py +5 -11
  53. package/src/superlocalmemory/core/graph_analyzer.py +2 -2
  54. package/src/superlocalmemory/core/health_monitor.py +4 -2
  55. package/src/superlocalmemory/core/ingestion_command.py +636 -0
  56. package/src/superlocalmemory/core/injection.py +69 -18
  57. package/src/superlocalmemory/core/lifecycle_state.py +153 -0
  58. package/src/superlocalmemory/core/maintenance.py +1 -1
  59. package/src/superlocalmemory/core/maintenance_scheduler.py +51 -35
  60. package/src/superlocalmemory/core/mutations.py +143 -0
  61. package/src/superlocalmemory/core/platform_utils.py +7 -4
  62. package/src/superlocalmemory/core/ram_lock.py +16 -5
  63. package/src/superlocalmemory/core/rate_limit.py +1 -1
  64. package/src/superlocalmemory/core/recall_pipeline.py +60 -101
  65. package/src/superlocalmemory/core/recall_worker.py +76 -59
  66. package/src/superlocalmemory/core/registry.py +1 -1
  67. package/src/superlocalmemory/core/scale_engine.py +293 -0
  68. package/src/superlocalmemory/core/score_contract.py +62 -0
  69. package/src/superlocalmemory/core/security_primitives.py +3 -1
  70. package/src/superlocalmemory/core/slm_disabled.py +3 -5
  71. package/src/superlocalmemory/core/store_pipeline.py +172 -40
  72. package/src/superlocalmemory/core/tier_manager.py +32 -20
  73. package/src/superlocalmemory/core/worker_pool.py +13 -4
  74. package/src/superlocalmemory/dynamics/activation_guided_quantization.py +1 -1
  75. package/src/superlocalmemory/dynamics/eap_scheduler.py +10 -3
  76. package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +1 -1
  77. package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +1 -1
  78. package/src/superlocalmemory/encoding/auto_linker.py +1 -1
  79. package/src/superlocalmemory/encoding/cognitive_consolidator.py +7 -16
  80. package/src/superlocalmemory/encoding/consolidator.py +22 -5
  81. package/src/superlocalmemory/encoding/fact_extractor.py +1 -1
  82. package/src/superlocalmemory/encoding/foresight.py +2 -0
  83. package/src/superlocalmemory/encoding/graph_builder.py +1 -1
  84. package/src/superlocalmemory/encoding/temporal_parser.py +2 -0
  85. package/src/superlocalmemory/evaluation/__init__.py +13 -0
  86. package/src/superlocalmemory/evaluation/calibration.py +308 -0
  87. package/src/superlocalmemory/evolution/skill_evolver.py +2 -1
  88. package/src/superlocalmemory/graph/cozo_backend.py +256 -23
  89. package/src/superlocalmemory/hooks/_outcome_common.py +21 -11
  90. package/src/superlocalmemory/hooks/antigravity_adapter.py +10 -31
  91. package/src/superlocalmemory/hooks/auto_invoker.py +25 -27
  92. package/src/superlocalmemory/hooks/auto_recall.py +31 -6
  93. package/src/superlocalmemory/hooks/auto_recall_hook.py +13 -33
  94. package/src/superlocalmemory/hooks/before_web_hook.py +9 -7
  95. package/src/superlocalmemory/hooks/claude_code_hooks.py +123 -35
  96. package/src/superlocalmemory/hooks/codex_assets.py +59 -0
  97. package/src/superlocalmemory/hooks/codex_hooks.py +186 -0
  98. package/src/superlocalmemory/hooks/context_payload.py +1 -1
  99. package/src/superlocalmemory/hooks/copilot_adapter.py +9 -24
  100. package/src/superlocalmemory/hooks/cursor_adapter.py +10 -32
  101. package/src/superlocalmemory/hooks/hook_daemon.py +4 -2
  102. package/src/superlocalmemory/hooks/hook_handlers.py +219 -32
  103. package/src/superlocalmemory/hooks/memory_protocol.py +5 -3
  104. package/src/superlocalmemory/hooks/post_tool_async_hook.py +4 -2
  105. package/src/superlocalmemory/hooks/session_registry.py +15 -8
  106. package/src/superlocalmemory/hooks/stop_outcome_hook.py +10 -6
  107. package/src/superlocalmemory/hooks/topic_shift_hook.py +42 -12
  108. package/src/superlocalmemory/hooks/user_prompt_hook.py +9 -14
  109. package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +19 -11
  110. package/src/superlocalmemory/infra/auth_middleware.py +38 -5
  111. package/src/superlocalmemory/infra/backup.py +7 -5
  112. package/src/superlocalmemory/infra/cloud_backup.py +18 -8
  113. package/src/superlocalmemory/infra/daemon_identity.py +248 -0
  114. package/src/superlocalmemory/infra/data_root.py +199 -0
  115. package/src/superlocalmemory/infra/event_bus.py +3 -1
  116. package/src/superlocalmemory/infra/local_diagnostics.py +327 -0
  117. package/src/superlocalmemory/infra/process_reaper.py +23 -0
  118. package/src/superlocalmemory/ingestion/adapter_manager.py +27 -9
  119. package/src/superlocalmemory/ingestion/base_adapter.py +25 -31
  120. package/src/superlocalmemory/ingestion/calendar_adapter.py +13 -4
  121. package/src/superlocalmemory/ingestion/credentials.py +14 -7
  122. package/src/superlocalmemory/ingestion/gmail_adapter.py +13 -4
  123. package/src/superlocalmemory/ingestion/transcript_adapter.py +7 -2
  124. package/src/superlocalmemory/learning/consolidation_quantization_worker.py +1 -1
  125. package/src/superlocalmemory/learning/ensemble.py +11 -0
  126. package/src/superlocalmemory/learning/entity_compiler.py +1 -1
  127. package/src/superlocalmemory/learning/feedback.py +1 -1
  128. package/src/superlocalmemory/learning/forgetting_scheduler.py +12 -7
  129. package/src/superlocalmemory/learning/quantization_scheduler.py +1 -1
  130. package/src/superlocalmemory/learning/ranker.py +4 -1
  131. package/src/superlocalmemory/learning/source_quality.py +1 -1
  132. package/src/superlocalmemory/learning/trigram_index.py +3 -2
  133. package/src/superlocalmemory/llm/backbone.py +1 -1
  134. package/src/superlocalmemory/math/ebbinghaus.py +1 -1
  135. package/src/superlocalmemory/math/fisher.py +1 -1
  136. package/src/superlocalmemory/math/fisher_quantized.py +1 -1
  137. package/src/superlocalmemory/math/hopfield.py +1 -1
  138. package/src/superlocalmemory/math/langevin.py +1 -1
  139. package/src/superlocalmemory/math/polar_quant.py +3 -4
  140. package/src/superlocalmemory/math/qjl.py +1 -1
  141. package/src/superlocalmemory/math/sheaf.py +1 -1
  142. package/src/superlocalmemory/math/turbo_quant.py +3 -2
  143. package/src/superlocalmemory/mcp/_daemon_proxy.py +12 -11
  144. package/src/superlocalmemory/mcp/_pool_adapter.py +27 -0
  145. package/src/superlocalmemory/mcp/http_transport.py +53 -0
  146. package/src/superlocalmemory/mcp/server.py +39 -13
  147. package/src/superlocalmemory/mcp/shared.py +69 -3
  148. package/src/superlocalmemory/mcp/tools_active.py +141 -31
  149. package/src/superlocalmemory/mcp/tools_core.py +128 -29
  150. package/src/superlocalmemory/mcp/tools_evolution.py +5 -7
  151. package/src/superlocalmemory/mcp/tools_learning.py +42 -2
  152. package/src/superlocalmemory/mcp/tools_mesh.py +7 -23
  153. package/src/superlocalmemory/mcp/tools_optimize.py +8 -1
  154. package/src/superlocalmemory/mcp/tools_v28.py +23 -2
  155. package/src/superlocalmemory/mcp/tools_v3.py +26 -1
  156. package/src/superlocalmemory/mcp/tools_v33.py +56 -17
  157. package/src/superlocalmemory/mesh/broker.py +2 -0
  158. package/src/superlocalmemory/mesh/remote_sync.py +50 -12
  159. package/src/superlocalmemory/optimize/cache/manager.py +77 -1
  160. package/src/superlocalmemory/optimize/cache/semantic.py +23 -3
  161. package/src/superlocalmemory/optimize/compress/ccr.py +4 -0
  162. package/src/superlocalmemory/optimize/compress/router.py +6 -1
  163. package/src/superlocalmemory/optimize/config/__init__.py +5 -0
  164. package/src/superlocalmemory/optimize/config/store.py +6 -4
  165. package/src/superlocalmemory/optimize/proxy/_helpers.py +15 -5
  166. package/src/superlocalmemory/optimize/proxy/capture.py +3 -2
  167. package/src/superlocalmemory/optimize/proxy/server.py +2 -2
  168. package/src/superlocalmemory/optimize/storage/db.py +12 -12
  169. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  170. package/src/superlocalmemory/retrieval/ann_index.py +1 -1
  171. package/src/superlocalmemory/retrieval/bm25_channel.py +35 -11
  172. package/src/superlocalmemory/retrieval/bridge_discovery.py +73 -8
  173. package/src/superlocalmemory/retrieval/engine.py +169 -79
  174. package/src/superlocalmemory/retrieval/entity_channel.py +289 -67
  175. package/src/superlocalmemory/retrieval/forgetting_filter.py +1 -1
  176. package/src/superlocalmemory/retrieval/fusion.py +1 -1
  177. package/src/superlocalmemory/retrieval/hopfield_channel.py +118 -30
  178. package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
  179. package/src/superlocalmemory/retrieval/quantization_aware_search.py +16 -10
  180. package/src/superlocalmemory/retrieval/reranker.py +56 -20
  181. package/src/superlocalmemory/retrieval/scope_policy.py +85 -0
  182. package/src/superlocalmemory/retrieval/semantic_channel.py +122 -14
  183. package/src/superlocalmemory/retrieval/spreading_activation.py +141 -25
  184. package/src/superlocalmemory/retrieval/strategy.py +1 -1
  185. package/src/superlocalmemory/retrieval/temporal_channel.py +30 -15
  186. package/src/superlocalmemory/retrieval/vector_store.py +1 -1
  187. package/src/superlocalmemory/server/api.py +10 -7
  188. package/src/superlocalmemory/server/bandit_loops.py +4 -2
  189. package/src/superlocalmemory/server/recall_serializer.py +24 -0
  190. package/src/superlocalmemory/server/route_mutations.py +84 -0
  191. package/src/superlocalmemory/server/routes/agents.py +8 -6
  192. package/src/superlocalmemory/server/routes/brain.py +14 -12
  193. package/src/superlocalmemory/server/routes/chat.py +29 -12
  194. package/src/superlocalmemory/server/routes/data_io.py +55 -24
  195. package/src/superlocalmemory/server/routes/helpers.py +8 -63
  196. package/src/superlocalmemory/server/routes/ingest.py +53 -36
  197. package/src/superlocalmemory/server/routes/memories.py +104 -43
  198. package/src/superlocalmemory/server/routes/mesh.py +31 -0
  199. package/src/superlocalmemory/server/routes/profiles.py +26 -4
  200. package/src/superlocalmemory/server/routes/tiers.py +43 -11
  201. package/src/superlocalmemory/server/routes/timeline.py +5 -1
  202. package/src/superlocalmemory/server/routes/v3_api.py +76 -21
  203. package/src/superlocalmemory/server/security_middleware.py +1 -1
  204. package/src/superlocalmemory/server/unified_daemon.py +680 -293
  205. package/src/superlocalmemory/server/write_identity.py +147 -0
  206. package/src/superlocalmemory/storage/access_log.py +4 -3
  207. package/src/superlocalmemory/storage/database.py +118 -25
  208. package/src/superlocalmemory/storage/migration_runner.py +84 -1
  209. package/src/superlocalmemory/storage/migration_v33.py +1 -1
  210. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +6 -60
  211. package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +120 -0
  212. package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +54 -0
  213. package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +52 -0
  214. package/src/superlocalmemory/storage/migrations/__init__.py +5 -0
  215. package/src/superlocalmemory/storage/models.py +16 -0
  216. package/src/superlocalmemory/storage/quantized_store.py +20 -3
  217. package/src/superlocalmemory/storage/v2_migrator.py +5 -3
  218. package/src/superlocalmemory/ui/favicon.svg +5 -0
  219. package/src/superlocalmemory/ui/index.html +1 -0
  220. package/src/superlocalmemory/ui/js/compliance.js +1 -1
  221. package/src/superlocalmemory/ui/js/core.js +49 -8
  222. package/src/superlocalmemory/ui/js/dashboard.js +23 -2
  223. package/src/superlocalmemory/ui/js/feedback.js +1 -1
  224. package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
  225. package/src/superlocalmemory/ui/js/graph-ui.js +1 -1
  226. package/src/superlocalmemory/ui/js/lifecycle.js +1 -1
  227. package/src/superlocalmemory/ui/js/ng-mesh.js +15 -49
  228. package/src/superlocalmemory/ui/js/settings.js +4 -2
  229. package/src/superlocalmemory/vector/lancedb_backend.py +57 -9
  230. package/bin/slm +0 -59
  231. package/bin/slm.bat +0 -77
  232. package/bin/slm.cmd +0 -5
  233. package/ide/integrations/langchain/README.md +0 -106
  234. package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +0 -9
  235. package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +0 -201
  236. package/ide/integrations/langchain/pyproject.toml +0 -38
  237. package/ide/integrations/langchain/tests/__init__.py +0 -3
  238. package/ide/integrations/langchain/tests/test_chat_message_history.py +0 -215
  239. package/ide/integrations/langchain/tests/test_security.py +0 -117
  240. package/ide/integrations/llamaindex/README.md +0 -81
  241. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +0 -9
  242. package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +0 -316
  243. package/ide/integrations/llamaindex/pyproject.toml +0 -43
  244. package/ide/integrations/llamaindex/tests/__init__.py +0 -3
  245. package/ide/integrations/llamaindex/tests/test_chat_store.py +0 -294
  246. package/ide/integrations/llamaindex/tests/test_security.py +0 -241
  247. package/plugin-src/.mcp.json +0 -12
  248. package/plugin-src/agents/slm-memory-advisor.md +0 -44
  249. package/plugin-src/agents/slm-optimize-advisor.md +0 -38
  250. package/plugin-src/hooks/.gitkeep +0 -0
  251. package/plugin-src/hooks/hooks.json +0 -23
  252. package/plugin-src/manifest.json +0 -25
  253. package/plugin-src/requirements.txt +0 -1
  254. package/plugin-src/rules/CLAUDE.md.fragment +0 -44
  255. package/plugin-src/scripts/ensure-venv.bat +0 -122
  256. package/plugin-src/scripts/ensure-venv.sh +0 -105
  257. package/plugin-src/scripts/slm-launch +0 -15
  258. package/plugin-src/scripts/slm-launch.bat +0 -17
  259. package/plugin-src/settings.json +0 -16
  260. package/plugin-src/skills/slm-cache/SKILL.md +0 -140
  261. package/plugin-src/skills/slm-compress/SKILL.md +0 -143
  262. package/plugin-src/skills/slm-graph/SKILL.md +0 -300
  263. package/plugin-src/skills/slm-recall/SKILL.md +0 -204
  264. package/plugin-src/skills/slm-remember/SKILL.md +0 -194
  265. package/plugin-src/skills/slm-session/SKILL.md +0 -207
  266. package/plugin-src/skills/slm-status/SKILL.md +0 -149
  267. package/scripts/__tests__/build-plugin.test.mjs +0 -613
  268. package/scripts/_savings_math.py +0 -270
  269. package/scripts/build-dmg.sh +0 -417
  270. package/scripts/build-plugin.js +0 -742
  271. package/scripts/build-slm-hook.ps1 +0 -40
  272. package/scripts/build-slm-hook.sh +0 -45
  273. package/scripts/build_entry.py +0 -452
  274. package/scripts/ci/stage5b_gate.sh +0 -50
  275. package/scripts/dogfood_savings.py +0 -490
  276. package/scripts/generate-thumbnails.py +0 -218
  277. package/scripts/install-skills.ps1 +0 -4
  278. package/scripts/install-skills.sh +0 -5
  279. package/scripts/install.ps1 +0 -701
  280. package/scripts/install.sh +0 -1015
  281. package/scripts/postinstall_binary.js +0 -287
  282. package/scripts/prepack.js +0 -33
  283. package/scripts/release_manifest.py +0 -273
  284. package/scripts/slm-hook.spec +0 -56
  285. package/scripts/start-dashboard.ps1 +0 -52
  286. package/scripts/start-dashboard.sh +0 -41
  287. package/scripts/sync-wiki.ps1 +0 -127
  288. package/scripts/sync-wiki.sh +0 -82
  289. package/scripts/test-dmg.sh +0 -161
  290. package/scripts/test-npm-package.ps1 +0 -252
  291. package/scripts/test-npm-package.sh +0 -207
  292. package/scripts/verify-install.ps1 +0 -294
  293. package/scripts/verify-install.sh +0 -266
  294. package/scripts/verify-v27.ps1 +0 -301
  295. package/scripts/verify-v27.sh +0 -233
  296. package/src/superlocalmemory.egg-info/PKG-INFO +0 -516
  297. package/src/superlocalmemory.egg-info/SOURCES.txt +0 -529
  298. package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
  299. package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
  300. package/src/superlocalmemory.egg-info/requires.txt +0 -71
  301. package/src/superlocalmemory.egg-info/top_level.txt +0 -1
@@ -15,7 +15,7 @@ Design decisions:
15
15
  - Mode C: LLM sufficiency judgment with 3-way classification
16
16
 
17
17
  Part of Qualixar | Author: Varun Pratap Bhardwaj
18
- License: Elastic-2.0
18
+ License: AGPL-3.0-or-later
19
19
  """
20
20
  from __future__ import annotations
21
21
 
@@ -12,7 +12,7 @@ scale we target (up to 100K facts). At that scale, a single cosine
12
12
  scan takes ~5ms on CPU which is well within our latency budget.
13
13
 
14
14
  Part of Qualixar | Author: Varun Pratap Bhardwaj
15
- License: Elastic-2.0
15
+ License: AGPL-3.0-or-later
16
16
  """
17
17
 
18
18
  from __future__ import annotations
@@ -12,7 +12,7 @@ the entire index. This version persists tokens to the DB via
12
12
  store_bm25_tokens / get_all_bm25_tokens and cold-loads on init.
13
13
 
14
14
  Part of Qualixar | Author: Varun Pratap Bhardwaj
15
- License: Elastic-2.0
15
+ License: AGPL-3.0-or-later
16
16
  """
17
17
 
18
18
  from __future__ import annotations
@@ -23,6 +23,8 @@ from typing import TYPE_CHECKING
23
23
 
24
24
  from rank_bm25 import BM25Plus
25
25
 
26
+ from superlocalmemory.storage.database import _scope_where
27
+
26
28
  if TYPE_CHECKING:
27
29
  from superlocalmemory.storage.database import DatabaseManager
28
30
 
@@ -72,6 +74,7 @@ class BM25Channel:
72
74
  self._bm25: BM25Plus | None = None
73
75
  self._dirty: bool = False
74
76
  self._loaded_profiles: set[str] = set()
77
+ self._loaded_scope_key: tuple[str, bool, bool] | None = None
75
78
 
76
79
  @property
77
80
  def document_count(self) -> int:
@@ -82,18 +85,31 @@ class BM25Channel:
82
85
 
83
86
  Idempotent: subsequent calls for the same profile are no-ops.
84
87
  """
85
- if profile_id in self._loaded_profiles:
88
+ include_global = bool(getattr(self, "include_global", False))
89
+ include_shared = bool(getattr(self, "include_shared", False))
90
+ scope_key = (profile_id, include_global, include_shared)
91
+ if scope_key == self._loaded_scope_key:
86
92
  return
87
93
 
88
- token_map = self._db.get_all_bm25_tokens(profile_id)
89
- _inc_global = getattr(self, 'include_global', False)
90
- _inc_shared = getattr(self, 'include_shared', False)
94
+ # A legacy in-memory index is a visibility-specific view. Reusing a
95
+ # corpus warmed under another profile/scope leaks private documents or
96
+ # omits newly enabled global/shared documents.
97
+ self._corpus = []
98
+ self._fact_ids = []
99
+ self._fact_id_set = set()
100
+ self._raw_texts = []
101
+ self._bm25 = None
102
+ token_map = self._db.get_all_bm25_tokens(
103
+ profile_id,
104
+ include_global=include_global,
105
+ include_shared=include_shared,
106
+ )
91
107
  if not token_map:
92
108
  # Fallback: tokenize facts directly if no pre-stored tokens
93
109
  facts = self._db.get_all_facts(
94
110
  profile_id,
95
- include_global=_inc_global,
96
- include_shared=_inc_shared,
111
+ include_global=include_global,
112
+ include_shared=include_shared,
97
113
  )
98
114
  for fact in facts:
99
115
  if fact.fact_id in self._fact_id_set:
@@ -112,8 +128,8 @@ class BM25Channel:
112
128
  try:
113
129
  facts = self._db.get_all_facts(
114
130
  profile_id,
115
- include_global=_inc_global,
116
- include_shared=_inc_shared,
131
+ include_global=include_global,
132
+ include_shared=include_shared,
117
133
  )
118
134
  fact_content_map = {f.fact_id: f.content for f in facts}
119
135
  except Exception:
@@ -128,6 +144,7 @@ class BM25Channel:
128
144
 
129
145
  self._dirty = True
130
146
  self._loaded_profiles.add(profile_id)
147
+ self._loaded_scope_key = scope_key
131
148
  logger.debug(
132
149
  "BM25 cold-loaded %d documents for profile=%s",
133
150
  len(token_map) if token_map else 0, profile_id,
@@ -176,14 +193,20 @@ class BM25Channel:
176
193
  # Quote each token so query punctuation can't break FTS5 MATCH syntax;
177
194
  # OR-join for high recall (any token may match).
178
195
  match_expr = " OR ".join('"' + t.replace('"', "") + '"' for t in tokens)
196
+ where, params = _scope_where(
197
+ profile_id,
198
+ include_global=bool(getattr(self, "include_global", False)),
199
+ include_shared=bool(getattr(self, "include_shared", False)),
200
+ prefix="af",
201
+ )
179
202
  sql = (
180
203
  "SELECT af.fact_id AS fact_id, bm25(atomic_facts_fts) AS rank "
181
204
  "FROM atomic_facts_fts "
182
205
  "JOIN atomic_facts af ON af.rowid = atomic_facts_fts.rowid "
183
- "WHERE atomic_facts_fts MATCH ? AND af.profile_id = ? "
206
+ f"WHERE atomic_facts_fts MATCH ? AND {where} "
184
207
  "ORDER BY rank LIMIT ?"
185
208
  )
186
- rows = self._db.execute(sql, (match_expr, profile_id, int(top_k)))
209
+ rows = self._db.execute(sql, (match_expr, *params, int(top_k)))
187
210
  out: list[tuple[str, float]] = []
188
211
  for r in rows:
189
212
  d = dict(r)
@@ -263,3 +286,4 @@ class BM25Channel:
263
286
  self._bm25 = None
264
287
  self._dirty = False
265
288
  self._loaded_profiles = set()
289
+ self._loaded_scope_key = None
@@ -22,14 +22,18 @@ Parameters:
22
22
  - typed mu: entity=1.2, causal=1.3, semantic=0.8, temporal=0.9
23
23
 
24
24
  Part of Qualixar | Author: Varun Pratap Bhardwaj
25
- License: Elastic-2.0
25
+ License: AGPL-3.0-or-later
26
26
  """
27
27
  from __future__ import annotations
28
28
 
29
29
  import logging
30
- import re
31
30
  from typing import TYPE_CHECKING
32
31
 
32
+ from superlocalmemory.retrieval.scope_policy import (
33
+ authorized_fact_ids,
34
+ filter_authorized_results,
35
+ )
36
+
33
37
  if TYPE_CHECKING:
34
38
  from superlocalmemory.storage.database import DatabaseManager
35
39
 
@@ -64,6 +68,9 @@ class BridgeDiscovery:
64
68
  seed_ids: list[str],
65
69
  profile_id: str,
66
70
  max_bridges: int = 10,
71
+ *,
72
+ include_global: bool = False,
73
+ include_shared: bool = False,
67
74
  ) -> list[tuple[str, float]]:
68
75
  """Find bridge facts connecting seed results.
69
76
 
@@ -78,13 +85,36 @@ class BridgeDiscovery:
78
85
  if len(seed_ids) < 2:
79
86
  return []
80
87
 
88
+ allowed_seeds = authorized_fact_ids(
89
+ self._db,
90
+ seed_ids,
91
+ profile_id,
92
+ include_global=include_global,
93
+ include_shared=include_shared,
94
+ )
95
+ if any(seed_id not in allowed_seeds for seed_id in seed_ids):
96
+ return []
97
+
98
+ try:
99
+ visible_seed_facts = self._db.get_facts_by_ids(
100
+ seed_ids,
101
+ profile_id,
102
+ include_global=include_global,
103
+ include_shared=include_shared,
104
+ )
105
+ except Exception:
106
+ return []
107
+ seed_facts = {fact.fact_id: fact for fact in visible_seed_facts}
108
+ if any(seed_id not in seed_facts for seed_id in seed_ids):
109
+ return []
110
+
81
111
  bridges: list[tuple[str, float]] = []
82
112
  seen = set(seed_ids)
83
113
 
84
114
  # Check consecutive pairs for entity overlap
85
115
  for i in range(len(seed_ids) - 1):
86
- fact_a = self._db.get_fact(seed_ids[i])
87
- fact_b = self._db.get_fact(seed_ids[i + 1])
116
+ fact_a = seed_facts.get(seed_ids[i])
117
+ fact_b = seed_facts.get(seed_ids[i + 1])
88
118
  if not fact_a or not fact_b:
89
119
  continue
90
120
 
@@ -98,7 +128,12 @@ class BridgeDiscovery:
98
128
  # Strategy 1: Entity bridge (union minus intersection)
99
129
  bridge_entities = (entities_a | entities_b) - (entities_a & entities_b)
100
130
  for eid in bridge_entities:
101
- entity_facts = self._db.get_facts_by_entity(eid, profile_id)
131
+ entity_facts = self._db.get_facts_by_entity(
132
+ eid,
133
+ profile_id,
134
+ include_global=include_global,
135
+ include_shared=include_shared,
136
+ )
102
137
  for f in entity_facts[:5]:
103
138
  if f.fact_id not in seen:
104
139
  seen.add(f.fact_id)
@@ -112,7 +147,13 @@ class BridgeDiscovery:
112
147
  break
113
148
 
114
149
  bridges.sort(key=lambda x: x[1], reverse=True)
115
- return bridges[:max_bridges]
150
+ return filter_authorized_results(
151
+ self._db,
152
+ bridges,
153
+ profile_id,
154
+ include_global=include_global,
155
+ include_shared=include_shared,
156
+ )[:max_bridges]
116
157
 
117
158
  def spreading_activation(
118
159
  self,
@@ -120,6 +161,9 @@ class BridgeDiscovery:
120
161
  profile_id: str,
121
162
  max_depth: int = _MAX_DEPTH,
122
163
  budget: int = _NODE_BUDGET,
164
+ *,
165
+ include_global: bool = False,
166
+ include_shared: bool = False,
123
167
  ) -> list[tuple[str, float]]:
124
168
  """Spreading activation from seed facts through the graph.
125
169
 
@@ -135,6 +179,16 @@ class BridgeDiscovery:
135
179
  Returns:
136
180
  List of (fact_id, activation_score) for activated facts.
137
181
  """
182
+ allowed_seeds = authorized_fact_ids(
183
+ self._db,
184
+ seed_ids,
185
+ profile_id,
186
+ include_global=include_global,
187
+ include_shared=include_shared,
188
+ )
189
+ if any(seed_id not in allowed_seeds for seed_id in seed_ids):
190
+ return []
191
+
138
192
  activations: dict[str, float] = {fid: 1.0 for fid in seed_ids}
139
193
  frontier = list(seed_ids)
140
194
 
@@ -145,7 +199,12 @@ class BridgeDiscovery:
145
199
  if current_activation < 0.01:
146
200
  continue
147
201
 
148
- edges = self._db.get_edges_for_node(fid, profile_id)
202
+ edges = self._db.get_edges_for_node(
203
+ fid,
204
+ profile_id,
205
+ include_global=include_global,
206
+ include_shared=include_shared,
207
+ )
149
208
  for edge in edges:
150
209
  other_id = (
151
210
  edge.target_id
@@ -171,4 +230,10 @@ class BridgeDiscovery:
171
230
  if fid not in set(seed_ids) and score > 0.01
172
231
  ]
173
232
  results.sort(key=lambda x: x[1], reverse=True)
174
- return results[:budget]
233
+ return filter_authorized_results(
234
+ self._db,
235
+ results,
236
+ profile_id,
237
+ include_global=include_global,
238
+ include_shared=include_shared,
239
+ )[:budget]