superlocalmemory 4.1.13 → 4.1.14
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.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +48 -0
- package/README.md +3 -3
- package/package.json +1 -8
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/CLAUDE.md +3 -3
- package/plugin/agents/slm-governance-advisor.md +1 -1
- package/plugin/agents/slm-loop-runner.md +1 -1
- package/plugin/agents/slm-memory-advisor.md +1 -1
- package/plugin/agents/slm-optimize-advisor.md +1 -1
- package/plugin/requirements.txt +1 -1
- package/plugin/skills/slm-cache/SKILL.md +1 -1
- package/plugin/skills/slm-compress/SKILL.md +1 -1
- package/plugin/skills/slm-governance/SKILL.md +1 -1
- package/plugin/skills/slm-graph/SKILL.md +1 -1
- package/plugin/skills/slm-loop/SKILL.md +1 -1
- package/plugin/skills/slm-mesh/SKILL.md +1 -1
- package/plugin/skills/slm-profile/SKILL.md +1 -1
- package/plugin/skills/slm-recall/SKILL.md +1 -1
- package/plugin/skills/slm-remember/SKILL.md +1 -1
- package/plugin/skills/slm-scope/SKILL.md +1 -1
- package/plugin/skills/slm-session/SKILL.md +1 -1
- package/plugin/skills/slm-status/SKILL.md +1 -1
- package/plugin-src/agents/slm-memory-advisor.md +1 -1
- package/plugin-src/agents/slm-optimize-advisor.md +1 -1
- package/plugin-src/rules/AGENTS.md +1 -1
- package/plugin-src/skills/slm-cache/SKILL.md +1 -1
- package/plugin-src/skills/slm-compress/SKILL.md +1 -1
- package/plugin-src/skills/slm-governance/SKILL.md +1 -1
- package/plugin-src/skills/slm-graph/SKILL.md +1 -1
- package/plugin-src/skills/slm-loop/SKILL.md +1 -1
- package/plugin-src/skills/slm-mesh/SKILL.md +1 -1
- package/plugin-src/skills/slm-profile/SKILL.md +1 -1
- package/plugin-src/skills/slm-recall/SKILL.md +1 -1
- package/plugin-src/skills/slm-remember/SKILL.md +1 -1
- package/plugin-src/skills/slm-scope/SKILL.md +1 -1
- package/plugin-src/skills/slm-session/SKILL.md +1 -1
- package/plugin-src/skills/slm-status/SKILL.md +1 -1
- package/scripts/postinstall.js +71 -2
- package/pyproject.toml +0 -250
- package/src/superlocalmemory/__init__.py +0 -82
- package/src/superlocalmemory/access/__init__.py +0 -3
- package/src/superlocalmemory/access/rbac.py +0 -575
- package/src/superlocalmemory/attribution/__init__.py +0 -9
- package/src/superlocalmemory/attribution/signer.py +0 -173
- package/src/superlocalmemory/attribution/watermark.py +0 -189
- package/src/superlocalmemory/brain/__init__.py +0 -5
- package/src/superlocalmemory/brain/truth.py +0 -418
- package/src/superlocalmemory/cli/__init__.py +0 -5
- package/src/superlocalmemory/cli/__main__.py +0 -17
- package/src/superlocalmemory/cli/_lazy_init.py +0 -115
- package/src/superlocalmemory/cli/cache_cmd.py +0 -198
- package/src/superlocalmemory/cli/commands.py +0 -4710
- package/src/superlocalmemory/cli/compress_cmd.py +0 -151
- package/src/superlocalmemory/cli/context_commands.py +0 -193
- package/src/superlocalmemory/cli/daemon.py +0 -909
- package/src/superlocalmemory/cli/db_migrate.py +0 -150
- package/src/superlocalmemory/cli/diagnostics_cmd.py +0 -101
- package/src/superlocalmemory/cli/escape_hatch.py +0 -220
- package/src/superlocalmemory/cli/evidence_cmd.py +0 -103
- package/src/superlocalmemory/cli/gdpr_cmd.py +0 -792
- package/src/superlocalmemory/cli/gdpr_io.py +0 -109
- package/src/superlocalmemory/cli/help_cmd.py +0 -197
- package/src/superlocalmemory/cli/host_upgrades.py +0 -189
- package/src/superlocalmemory/cli/ingest_cmd.py +0 -327
- package/src/superlocalmemory/cli/json_output.py +0 -81
- package/src/superlocalmemory/cli/loop_cmd.py +0 -187
- package/src/superlocalmemory/cli/main.py +0 -1145
- package/src/superlocalmemory/cli/mesh_cmd.py +0 -38
- package/src/superlocalmemory/cli/migrate_cmd.py +0 -55
- package/src/superlocalmemory/cli/ops_cmd.py +0 -281
- package/src/superlocalmemory/cli/optimize_cmd.py +0 -179
- package/src/superlocalmemory/cli/optimize_constants.py +0 -31
- package/src/superlocalmemory/cli/pending_store.py +0 -296
- package/src/superlocalmemory/cli/proxy_cmd.py +0 -108
- package/src/superlocalmemory/cli/scale_engine_cmd.py +0 -56
- package/src/superlocalmemory/cli/service_installer.py +0 -373
- package/src/superlocalmemory/cli/setup_wizard.py +0 -1162
- package/src/superlocalmemory/cli/summary_cmd.py +0 -215
- package/src/superlocalmemory/cli/version_banner.py +0 -202
- package/src/superlocalmemory/cli/wizard_v3426_options.py +0 -129
- package/src/superlocalmemory/code_graph/__init__.py +0 -46
- package/src/superlocalmemory/code_graph/blast_radius.py +0 -177
- package/src/superlocalmemory/code_graph/bridge/__init__.py +0 -36
- package/src/superlocalmemory/code_graph/bridge/entity_resolver.py +0 -490
- package/src/superlocalmemory/code_graph/bridge/event_listeners.py +0 -206
- package/src/superlocalmemory/code_graph/bridge/fact_enricher.py +0 -159
- package/src/superlocalmemory/code_graph/bridge/hebbian_linker.py +0 -170
- package/src/superlocalmemory/code_graph/bridge/maintenance.py +0 -220
- package/src/superlocalmemory/code_graph/bridge/temporal_checker.py +0 -152
- package/src/superlocalmemory/code_graph/changes.py +0 -363
- package/src/superlocalmemory/code_graph/communities.py +0 -299
- package/src/superlocalmemory/code_graph/config.py +0 -154
- package/src/superlocalmemory/code_graph/database.py +0 -526
- package/src/superlocalmemory/code_graph/extractors/__init__.py +0 -95
- package/src/superlocalmemory/code_graph/extractors/python.py +0 -413
- package/src/superlocalmemory/code_graph/extractors/typescript.py +0 -556
- package/src/superlocalmemory/code_graph/flows.py +0 -350
- package/src/superlocalmemory/code_graph/git_hooks.py +0 -226
- package/src/superlocalmemory/code_graph/graph_engine.py +0 -295
- package/src/superlocalmemory/code_graph/graph_store.py +0 -335
- package/src/superlocalmemory/code_graph/incremental.py +0 -200
- package/src/superlocalmemory/code_graph/models.py +0 -130
- package/src/superlocalmemory/code_graph/parser.py +0 -687
- package/src/superlocalmemory/code_graph/resolver.py +0 -321
- package/src/superlocalmemory/code_graph/search.py +0 -460
- package/src/superlocalmemory/code_graph/service.py +0 -95
- package/src/superlocalmemory/code_graph/watcher.py +0 -207
- package/src/superlocalmemory/compliance/__init__.py +0 -0
- package/src/superlocalmemory/compliance/abac.py +0 -204
- package/src/superlocalmemory/compliance/audit.py +0 -385
- package/src/superlocalmemory/compliance/eu_ai_act.py +0 -101
- package/src/superlocalmemory/compliance/gdpr.py +0 -1479
- package/src/superlocalmemory/compliance/lifecycle.py +0 -158
- package/src/superlocalmemory/compliance/retention.py +0 -415
- package/src/superlocalmemory/compliance/scheduler.py +0 -217
- package/src/superlocalmemory/contracts/__init__.py +0 -1
- package/src/superlocalmemory/contracts/schemas/agent-experience-v1.schema.json +0 -92
- package/src/superlocalmemory/contracts/schemas/agent-integration-contract-v2.schema.json +0 -46
- package/src/superlocalmemory/contracts/schemas/cognitive-turn-receipt-v1.schema.json +0 -59
- package/src/superlocalmemory/contracts/v402.py +0 -62
- package/src/superlocalmemory/core/__init__.py +0 -0
- package/src/superlocalmemory/core/actor_context.py +0 -166
- package/src/superlocalmemory/core/admission.py +0 -769
- package/src/superlocalmemory/core/backend_orchestrator.py +0 -637
- package/src/superlocalmemory/core/block_hygiene.py +0 -147
- package/src/superlocalmemory/core/community_summary.py +0 -267
- package/src/superlocalmemory/core/component_healer.py +0 -144
- package/src/superlocalmemory/core/component_registry.py +0 -514
- package/src/superlocalmemory/core/config.py +0 -2204
- package/src/superlocalmemory/core/consolidation_engine.py +0 -983
- package/src/superlocalmemory/core/context_cache.py +0 -574
- package/src/superlocalmemory/core/derivation_lineage.py +0 -246
- package/src/superlocalmemory/core/embedding_worker.py +0 -208
- package/src/superlocalmemory/core/embeddings.py +0 -1052
- package/src/superlocalmemory/core/engine.py +0 -1395
- package/src/superlocalmemory/core/engine_capabilities.py +0 -24
- package/src/superlocalmemory/core/engine_ingestion.py +0 -983
- package/src/superlocalmemory/core/engine_lock.py +0 -75
- package/src/superlocalmemory/core/engine_wiring.py +0 -776
- package/src/superlocalmemory/core/entity_community.py +0 -178
- package/src/superlocalmemory/core/error_envelope.py +0 -60
- package/src/superlocalmemory/core/evidence_bundle.py +0 -528
- package/src/superlocalmemory/core/fact_consolidator.py +0 -812
- package/src/superlocalmemory/core/file_lock.py +0 -92
- package/src/superlocalmemory/core/graph_analyzer.py +0 -456
- package/src/superlocalmemory/core/graph_metrics.py +0 -597
- package/src/superlocalmemory/core/graph_pruner.py +0 -939
- package/src/superlocalmemory/core/health_monitor.py +0 -338
- package/src/superlocalmemory/core/hooks.py +0 -65
- package/src/superlocalmemory/core/ingest_gate.py +0 -133
- package/src/superlocalmemory/core/ingest_policy.py +0 -38
- package/src/superlocalmemory/core/ingestion_command.py +0 -1042
- package/src/superlocalmemory/core/injection.py +0 -434
- package/src/superlocalmemory/core/install_detector.py +0 -131
- package/src/superlocalmemory/core/key_expander.py +0 -138
- package/src/superlocalmemory/core/lifecycle_state.py +0 -153
- package/src/superlocalmemory/core/maintenance.py +0 -777
- package/src/superlocalmemory/core/maintenance_scheduler.py +0 -507
- package/src/superlocalmemory/core/materialization_control.py +0 -20
- package/src/superlocalmemory/core/mcp_embedder_proxy.py +0 -89
- package/src/superlocalmemory/core/memory_health.py +0 -266
- package/src/superlocalmemory/core/mode_capability.py +0 -111
- package/src/superlocalmemory/core/modes.py +0 -168
- package/src/superlocalmemory/core/mutations.py +0 -688
- package/src/superlocalmemory/core/ollama_embedder.py +0 -266
- package/src/superlocalmemory/core/ollama_validator.py +0 -315
- package/src/superlocalmemory/core/operation_policy.py +0 -92
- package/src/superlocalmemory/core/operation_policy_registry.py +0 -542
- package/src/superlocalmemory/core/operation_request.py +0 -127
- package/src/superlocalmemory/core/ops_remediation.py +0 -542
- package/src/superlocalmemory/core/pii.py +0 -105
- package/src/superlocalmemory/core/platform_utils.py +0 -138
- package/src/superlocalmemory/core/profiles.py +0 -234
- package/src/superlocalmemory/core/progressive_abstraction.py +0 -208
- package/src/superlocalmemory/core/projection_drain.py +0 -380
- package/src/superlocalmemory/core/queue_consumer.py +0 -168
- package/src/superlocalmemory/core/ram_lock.py +0 -160
- package/src/superlocalmemory/core/rate_limit.py +0 -151
- package/src/superlocalmemory/core/recall_gate.py +0 -95
- package/src/superlocalmemory/core/recall_pipeline.py +0 -1337
- package/src/superlocalmemory/core/recall_queue.py +0 -377
- package/src/superlocalmemory/core/recall_worker.py +0 -414
- package/src/superlocalmemory/core/registry.py +0 -121
- package/src/superlocalmemory/core/remember_admission.py +0 -161
- package/src/superlocalmemory/core/remember_runtime.py +0 -1190
- package/src/superlocalmemory/core/remote_mode.py +0 -214
- package/src/superlocalmemory/core/reranker_worker.py +0 -338
- package/src/superlocalmemory/core/safe_fs.py +0 -108
- package/src/superlocalmemory/core/scale_autopromote.py +0 -196
- package/src/superlocalmemory/core/scale_engine.py +0 -915
- package/src/superlocalmemory/core/score_contract.py +0 -82
- package/src/superlocalmemory/core/security_primitives.py +0 -672
- package/src/superlocalmemory/core/session_identity.py +0 -98
- package/src/superlocalmemory/core/shadow_router.py +0 -319
- package/src/superlocalmemory/core/slm_disabled.py +0 -85
- package/src/superlocalmemory/core/status_contract.py +0 -108
- package/src/superlocalmemory/core/store_pipeline.py +0 -1404
- package/src/superlocalmemory/core/summarizer.py +0 -200
- package/src/superlocalmemory/core/tier_manager.py +0 -461
- package/src/superlocalmemory/core/topic_signature.py +0 -156
- package/src/superlocalmemory/core/transactions/__init__.py +0 -78
- package/src/superlocalmemory/core/transactions/concrete_owners.py +0 -604
- package/src/superlocalmemory/core/transactions/erasure.py +0 -825
- package/src/superlocalmemory/core/transactions/manifest.py +0 -255
- package/src/superlocalmemory/core/transactions/manifest_key.py +0 -155
- package/src/superlocalmemory/core/transactions/obligations.py +0 -272
- package/src/superlocalmemory/core/transactions/owners.py +0 -114
- package/src/superlocalmemory/core/transactions/reconciler.py +0 -285
- package/src/superlocalmemory/core/transactions/service.py +0 -330
- package/src/superlocalmemory/core/worker_pool.py +0 -377
- package/src/superlocalmemory/core/working_memory.py +0 -288
- package/src/superlocalmemory/dynamics/__init__.py +0 -0
- package/src/superlocalmemory/dynamics/activation_guided_quantization.py +0 -374
- package/src/superlocalmemory/dynamics/eap_scheduler.py +0 -294
- package/src/superlocalmemory/dynamics/ebbinghaus_langevin_coupling.py +0 -171
- package/src/superlocalmemory/dynamics/fisher_langevin_coupling.py +0 -227
- package/src/superlocalmemory/encoding/__init__.py +0 -0
- package/src/superlocalmemory/encoding/auto_linker.py +0 -308
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +0 -899
- package/src/superlocalmemory/encoding/consolidator.py +0 -472
- package/src/superlocalmemory/encoding/context_generator.py +0 -175
- package/src/superlocalmemory/encoding/emotional.py +0 -189
- package/src/superlocalmemory/encoding/entity_reflexion.py +0 -200
- package/src/superlocalmemory/encoding/entity_resolver.py +0 -687
- package/src/superlocalmemory/encoding/entropy_gate.py +0 -101
- package/src/superlocalmemory/encoding/fact_extractor.py +0 -877
- package/src/superlocalmemory/encoding/foresight.py +0 -93
- package/src/superlocalmemory/encoding/graph_builder.py +0 -346
- package/src/superlocalmemory/encoding/observation_builder.py +0 -177
- package/src/superlocalmemory/encoding/prospective_markers.py +0 -262
- package/src/superlocalmemory/encoding/scene_builder.py +0 -410
- package/src/superlocalmemory/encoding/signal_inference.py +0 -90
- package/src/superlocalmemory/encoding/temporal_parser.py +0 -432
- package/src/superlocalmemory/encoding/temporal_validator.py +0 -572
- package/src/superlocalmemory/encoding/type_router.py +0 -237
- package/src/superlocalmemory/evaluation/__init__.py +0 -13
- package/src/superlocalmemory/evaluation/calibration.py +0 -308
- package/src/superlocalmemory/evolution/__init__.py +0 -29
- package/src/superlocalmemory/evolution/blind_verifier.py +0 -122
- package/src/superlocalmemory/evolution/budget.py +0 -356
- package/src/superlocalmemory/evolution/evolution_store.py +0 -619
- package/src/superlocalmemory/evolution/llm_dispatch.py +0 -559
- package/src/superlocalmemory/evolution/model_selection.py +0 -175
- package/src/superlocalmemory/evolution/mutation_generator.py +0 -226
- package/src/superlocalmemory/evolution/skill_activator.py +0 -270
- package/src/superlocalmemory/evolution/skill_evolver.py +0 -928
- package/src/superlocalmemory/evolution/triggers.py +0 -376
- package/src/superlocalmemory/evolution/types.py +0 -114
- package/src/superlocalmemory/graph/__init__.py +0 -9
- package/src/superlocalmemory/graph/cozo_adjacency.py +0 -122
- package/src/superlocalmemory/graph/cozo_backend.py +0 -751
- package/src/superlocalmemory/hooks/__init__.py +0 -3
- package/src/superlocalmemory/hooks/_outcome_common.py +0 -523
- package/src/superlocalmemory/hooks/adapter_base.py +0 -347
- package/src/superlocalmemory/hooks/antigravity_adapter.py +0 -171
- package/src/superlocalmemory/hooks/auto_capture.py +0 -133
- package/src/superlocalmemory/hooks/auto_invoker.py +0 -521
- package/src/superlocalmemory/hooks/auto_parameterize.py +0 -147
- package/src/superlocalmemory/hooks/auto_recall.py +0 -191
- package/src/superlocalmemory/hooks/auto_recall_hook.py +0 -251
- package/src/superlocalmemory/hooks/before_web_hook.py +0 -131
- package/src/superlocalmemory/hooks/claude_code_hooks.py +0 -637
- package/src/superlocalmemory/hooks/codex_assets.py +0 -251
- package/src/superlocalmemory/hooks/codex_hooks.py +0 -186
- package/src/superlocalmemory/hooks/context_payload.py +0 -311
- package/src/superlocalmemory/hooks/copilot_adapter.py +0 -208
- package/src/superlocalmemory/hooks/cross_platform_connector.py +0 -90
- package/src/superlocalmemory/hooks/cursor_adapter.py +0 -173
- package/src/superlocalmemory/hooks/hook_daemon.py +0 -295
- package/src/superlocalmemory/hooks/hook_handlers.py +0 -822
- package/src/superlocalmemory/hooks/ide_connector.py +0 -246
- package/src/superlocalmemory/hooks/memory_protocol.py +0 -158
- package/src/superlocalmemory/hooks/portable_kit.py +0 -755
- package/src/superlocalmemory/hooks/post_tool_async_hook.py +0 -183
- package/src/superlocalmemory/hooks/post_tool_outcome_hook.py +0 -351
- package/src/superlocalmemory/hooks/prewarm_auth.py +0 -187
- package/src/superlocalmemory/hooks/rules_engine.py +0 -99
- package/src/superlocalmemory/hooks/session_registry.py +0 -330
- package/src/superlocalmemory/hooks/stop_outcome_hook.py +0 -138
- package/src/superlocalmemory/hooks/sync_loop.py +0 -114
- package/src/superlocalmemory/hooks/topic_shift_hook.py +0 -302
- package/src/superlocalmemory/hooks/user_prompt_hook.py +0 -131
- package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +0 -210
- package/src/superlocalmemory/infra/__init__.py +0 -3
- package/src/superlocalmemory/infra/auth_middleware.py +0 -145
- package/src/superlocalmemory/infra/backup.py +0 -974
- package/src/superlocalmemory/infra/backup_obligations.py +0 -423
- package/src/superlocalmemory/infra/cache_manager.py +0 -267
- package/src/superlocalmemory/infra/cloud_backup.py +0 -788
- package/src/superlocalmemory/infra/daemon_identity.py +0 -300
- package/src/superlocalmemory/infra/data_root.py +0 -238
- package/src/superlocalmemory/infra/event_bus.py +0 -637
- package/src/superlocalmemory/infra/local_diagnostics.py +0 -327
- package/src/superlocalmemory/infra/pid_manager.py +0 -193
- package/src/superlocalmemory/infra/process_identity.py +0 -180
- package/src/superlocalmemory/infra/process_reaper.py +0 -624
- package/src/superlocalmemory/infra/rate_limiter.py +0 -228
- package/src/superlocalmemory/infra/self_heal.py +0 -401
- package/src/superlocalmemory/infra/version_integrity.py +0 -229
- package/src/superlocalmemory/ingestion/__init__.py +0 -13
- package/src/superlocalmemory/ingestion/adapter_manager.py +0 -255
- package/src/superlocalmemory/ingestion/base_adapter.py +0 -171
- package/src/superlocalmemory/ingestion/calendar_adapter.py +0 -349
- package/src/superlocalmemory/ingestion/credentials.py +0 -125
- package/src/superlocalmemory/ingestion/gmail_adapter.py +0 -378
- package/src/superlocalmemory/ingestion/parsers.py +0 -100
- package/src/superlocalmemory/ingestion/transcript_adapter.py +0 -161
- package/src/superlocalmemory/integrations/__init__.py +0 -1
- package/src/superlocalmemory/integrations/bounded_loops_mcp.py +0 -431
- package/src/superlocalmemory/integrations/bounded_loops_v051.py +0 -236
- package/src/superlocalmemory/learning/__init__.py +0 -0
- package/src/superlocalmemory/learning/adaptive.py +0 -172
- package/src/superlocalmemory/learning/arm_catalog.py +0 -97
- package/src/superlocalmemory/learning/assertion_miner.py +0 -403
- package/src/superlocalmemory/learning/bandit.py +0 -654
- package/src/superlocalmemory/learning/bandit_cache.py +0 -131
- package/src/superlocalmemory/learning/behavioral.py +0 -542
- package/src/superlocalmemory/learning/bootstrap.py +0 -298
- package/src/superlocalmemory/learning/consolidation_cycle.py +0 -398
- package/src/superlocalmemory/learning/consolidation_quantization_worker.py +0 -115
- package/src/superlocalmemory/learning/consolidation_worker.py +0 -261
- package/src/superlocalmemory/learning/cross_project.py +0 -408
- package/src/superlocalmemory/learning/database.py +0 -698
- package/src/superlocalmemory/learning/dedup_hnsw.py +0 -413
- package/src/superlocalmemory/learning/engagement.py +0 -487
- package/src/superlocalmemory/learning/engagement_features.py +0 -279
- package/src/superlocalmemory/learning/ensemble.py +0 -309
- package/src/superlocalmemory/learning/entity_compiler.py +0 -356
- package/src/superlocalmemory/learning/fact_outcome_joins.py +0 -207
- package/src/superlocalmemory/learning/features.py +0 -138
- package/src/superlocalmemory/learning/feedback.py +0 -724
- package/src/superlocalmemory/learning/forgetting_scheduler.py +0 -375
- package/src/superlocalmemory/learning/hnsw_dedup.py +0 -69
- package/src/superlocalmemory/learning/labeler.py +0 -85
- package/src/superlocalmemory/learning/legacy_migration.py +0 -316
- package/src/superlocalmemory/learning/lightgbm_subprocess.py +0 -236
- package/src/superlocalmemory/learning/memory_merge.py +0 -175
- package/src/superlocalmemory/learning/model_cache.py +0 -267
- package/src/superlocalmemory/learning/model_rollback.py +0 -281
- package/src/superlocalmemory/learning/outcome_queue.py +0 -306
- package/src/superlocalmemory/learning/outcomes.py +0 -286
- package/src/superlocalmemory/learning/pattern_miner.py +0 -465
- package/src/superlocalmemory/learning/pattern_miner_constants.py +0 -90
- package/src/superlocalmemory/learning/pcos.py +0 -291
- package/src/superlocalmemory/learning/project_context.py +0 -366
- package/src/superlocalmemory/learning/propensity.py +0 -131
- package/src/superlocalmemory/learning/ranker.py +0 -300
- package/src/superlocalmemory/learning/ranker_common.py +0 -163
- package/src/superlocalmemory/learning/ranker_retrain_legacy.py +0 -210
- package/src/superlocalmemory/learning/ranker_retrain_online.py +0 -423
- package/src/superlocalmemory/learning/reward.py +0 -888
- package/src/superlocalmemory/learning/reward_archive.py +0 -223
- package/src/superlocalmemory/learning/reward_boost.py +0 -211
- package/src/superlocalmemory/learning/reward_from_outcomes.py +0 -365
- package/src/superlocalmemory/learning/reward_model.py +0 -144
- package/src/superlocalmemory/learning/reward_proxy.py +0 -578
- package/src/superlocalmemory/learning/shadow_test.py +0 -524
- package/src/superlocalmemory/learning/signal_kinds.py +0 -79
- package/src/superlocalmemory/learning/signal_worker.py +0 -268
- package/src/superlocalmemory/learning/signals.py +0 -646
- package/src/superlocalmemory/learning/skill_performance_miner.py +0 -422
- package/src/superlocalmemory/learning/source_quality.py +0 -828
- package/src/superlocalmemory/learning/trigram_index.py +0 -548
- package/src/superlocalmemory/learning/workflows.py +0 -309
- package/src/superlocalmemory/llm/__init__.py +0 -0
- package/src/superlocalmemory/llm/backbone.py +0 -364
- package/src/superlocalmemory/loops/__init__.py +0 -58
- package/src/superlocalmemory/loops/budget.py +0 -58
- package/src/superlocalmemory/loops/engine.py +0 -174
- package/src/superlocalmemory/loops/ledger.py +0 -298
- package/src/superlocalmemory/loops/models.py +0 -152
- package/src/superlocalmemory/loops/rules.py +0 -52
- package/src/superlocalmemory/math/__init__.py +0 -0
- package/src/superlocalmemory/math/ebbinghaus.py +0 -352
- package/src/superlocalmemory/math/fisher.py +0 -356
- package/src/superlocalmemory/math/fisher_quantized.py +0 -255
- package/src/superlocalmemory/math/hopfield.py +0 -282
- package/src/superlocalmemory/math/langevin.py +0 -411
- package/src/superlocalmemory/math/polar_quant.py +0 -414
- package/src/superlocalmemory/math/qjl.py +0 -115
- package/src/superlocalmemory/math/sheaf.py +0 -261
- package/src/superlocalmemory/math/turbo_quant.py +0 -318
- package/src/superlocalmemory/mcp/__init__.py +0 -0
- package/src/superlocalmemory/mcp/_daemon_proxy.py +0 -203
- package/src/superlocalmemory/mcp/_pool_adapter.py +0 -181
- package/src/superlocalmemory/mcp/_stdin_guard.py +0 -60
- package/src/superlocalmemory/mcp/agent_context.py +0 -115
- package/src/superlocalmemory/mcp/cli_fallback.py +0 -602
- package/src/superlocalmemory/mcp/http_transport.py +0 -85
- package/src/superlocalmemory/mcp/profiles.py +0 -154
- package/src/superlocalmemory/mcp/resources.py +0 -281
- package/src/superlocalmemory/mcp/server.py +0 -480
- package/src/superlocalmemory/mcp/session_binding.py +0 -98
- package/src/superlocalmemory/mcp/shared.py +0 -112
- package/src/superlocalmemory/mcp/tools.py +0 -18
- package/src/superlocalmemory/mcp/tools_active.py +0 -958
- package/src/superlocalmemory/mcp/tools_brain.py +0 -298
- package/src/superlocalmemory/mcp/tools_code_graph.py +0 -1717
- package/src/superlocalmemory/mcp/tools_context.py +0 -239
- package/src/superlocalmemory/mcp/tools_core.py +0 -1112
- package/src/superlocalmemory/mcp/tools_evolution.py +0 -343
- package/src/superlocalmemory/mcp/tools_learning.py +0 -393
- package/src/superlocalmemory/mcp/tools_loops.py +0 -345
- package/src/superlocalmemory/mcp/tools_mesh.py +0 -429
- package/src/superlocalmemory/mcp/tools_ops.py +0 -115
- package/src/superlocalmemory/mcp/tools_optimize.py +0 -322
- package/src/superlocalmemory/mcp/tools_summaries.py +0 -147
- package/src/superlocalmemory/mcp/tools_v28.py +0 -292
- package/src/superlocalmemory/mcp/tools_v3.py +0 -398
- package/src/superlocalmemory/mcp/tools_v33.py +0 -507
- package/src/superlocalmemory/mesh/__init__.py +0 -12
- package/src/superlocalmemory/mesh/broker.py +0 -812
- package/src/superlocalmemory/mesh/broker_security.py +0 -470
- package/src/superlocalmemory/mesh/discovery.py +0 -365
- package/src/superlocalmemory/mesh/lock_protocol.py +0 -313
- package/src/superlocalmemory/mesh/node_identity.py +0 -97
- package/src/superlocalmemory/mesh/outbox_remote.py +0 -429
- package/src/superlocalmemory/mesh/remote_sync.py +0 -829
- package/src/superlocalmemory/mesh/state_sync.py +0 -286
- package/src/superlocalmemory/migrations/__init__.py +0 -5
- package/src/superlocalmemory/migrations/v3_4_25_to_v3_4_26.py +0 -144
- package/src/superlocalmemory/optimize/NOTICE +0 -6
- package/src/superlocalmemory/optimize/__init__.py +0 -0
- package/src/superlocalmemory/optimize/adapters/__init__.py +0 -68
- package/src/superlocalmemory/optimize/adapters/_agent_registry.py +0 -120
- package/src/superlocalmemory/optimize/adapters/anthropic_adapter.py +0 -112
- package/src/superlocalmemory/optimize/adapters/openai_adapter.py +0 -122
- package/src/superlocalmemory/optimize/adapters/wrap.py +0 -228
- package/src/superlocalmemory/optimize/cache/__init__.py +0 -31
- package/src/superlocalmemory/optimize/cache/boundary_store.py +0 -488
- package/src/superlocalmemory/optimize/cache/centroid_store.py +0 -199
- package/src/superlocalmemory/optimize/cache/context_key.py +0 -67
- package/src/superlocalmemory/optimize/cache/exact.py +0 -88
- package/src/superlocalmemory/optimize/cache/invalidation.py +0 -36
- package/src/superlocalmemory/optimize/cache/key_builder.py +0 -111
- package/src/superlocalmemory/optimize/cache/manager.py +0 -737
- package/src/superlocalmemory/optimize/cache/semantic.py +0 -637
- package/src/superlocalmemory/optimize/cache/stampede.py +0 -50
- package/src/superlocalmemory/optimize/compress/__init__.py +0 -17
- package/src/superlocalmemory/optimize/compress/align.py +0 -159
- package/src/superlocalmemory/optimize/compress/ccr.py +0 -116
- package/src/superlocalmemory/optimize/compress/prose_llmlingua.py +0 -71
- package/src/superlocalmemory/optimize/compress/router.py +0 -667
- package/src/superlocalmemory/optimize/config/__init__.py +0 -56
- package/src/superlocalmemory/optimize/config/defaults.py +0 -43
- package/src/superlocalmemory/optimize/config/schema.py +0 -327
- package/src/superlocalmemory/optimize/config/store.py +0 -270
- package/src/superlocalmemory/optimize/metrics/__init__.py +0 -8
- package/src/superlocalmemory/optimize/metrics/counters.py +0 -155
- package/src/superlocalmemory/optimize/metrics/estimator.py +0 -87
- package/src/superlocalmemory/optimize/metrics/exporters.py +0 -77
- package/src/superlocalmemory/optimize/metrics/persistence.py +0 -115
- package/src/superlocalmemory/optimize/proxy/__init__.py +0 -28
- package/src/superlocalmemory/optimize/proxy/_helpers.py +0 -730
- package/src/superlocalmemory/optimize/proxy/anthropic_surface.py +0 -375
- package/src/superlocalmemory/optimize/proxy/capture.py +0 -550
- package/src/superlocalmemory/optimize/proxy/gemini_surface.py +0 -528
- package/src/superlocalmemory/optimize/proxy/lifecycle.py +0 -126
- package/src/superlocalmemory/optimize/proxy/openai_surface.py +0 -465
- package/src/superlocalmemory/optimize/proxy/server.py +0 -199
- package/src/superlocalmemory/optimize/proxy/vertex_surface.py +0 -246
- package/src/superlocalmemory/optimize/storage/__init__.py +0 -0
- package/src/superlocalmemory/optimize/storage/db.py +0 -1185
- package/src/superlocalmemory/optimize/storage/schema.py +0 -205
- package/src/superlocalmemory/parameterization/__init__.py +0 -47
- package/src/superlocalmemory/parameterization/cross_project.py +0 -12
- package/src/superlocalmemory/parameterization/pattern_extractor.py +0 -584
- package/src/superlocalmemory/parameterization/pii_filter.py +0 -106
- package/src/superlocalmemory/parameterization/prompt_injector.py +0 -219
- package/src/superlocalmemory/parameterization/prompt_lifecycle.py +0 -281
- package/src/superlocalmemory/parameterization/soft_prompt_generator.py +0 -542
- package/src/superlocalmemory/parameterization/workflow_miner.py +0 -17
- package/src/superlocalmemory/reliability/__init__.py +0 -45
- package/src/superlocalmemory/reliability/join_liveness.py +0 -301
- package/src/superlocalmemory/reliability/prior_distance.py +0 -243
- package/src/superlocalmemory/retrieval/__init__.py +0 -0
- package/src/superlocalmemory/retrieval/agentic.py +0 -367
- package/src/superlocalmemory/retrieval/ann_index.py +0 -235
- package/src/superlocalmemory/retrieval/bm25_channel.py +0 -451
- package/src/superlocalmemory/retrieval/bridge_discovery.py +0 -253
- package/src/superlocalmemory/retrieval/channel_registry.py +0 -154
- package/src/superlocalmemory/retrieval/channel_status.py +0 -117
- package/src/superlocalmemory/retrieval/engine.py +0 -1615
- package/src/superlocalmemory/retrieval/entity_channel.py +0 -994
- package/src/superlocalmemory/retrieval/forgetting_filter.py +0 -160
- package/src/superlocalmemory/retrieval/fusion.py +0 -81
- package/src/superlocalmemory/retrieval/graph_adjacency.py +0 -219
- package/src/superlocalmemory/retrieval/hopfield_channel.py +0 -465
- package/src/superlocalmemory/retrieval/profile_channel.py +0 -105
- package/src/superlocalmemory/retrieval/quantization_aware_search.py +0 -147
- package/src/superlocalmemory/retrieval/remote_reranker.py +0 -758
- package/src/superlocalmemory/retrieval/reranker.py +0 -674
- package/src/superlocalmemory/retrieval/scope_policy.py +0 -126
- package/src/superlocalmemory/retrieval/semantic_channel.py +0 -638
- package/src/superlocalmemory/retrieval/spreading.py +0 -288
- package/src/superlocalmemory/retrieval/spreading_activation.py +0 -616
- package/src/superlocalmemory/retrieval/strategy.py +0 -248
- package/src/superlocalmemory/retrieval/temporal_channel.py +0 -433
- package/src/superlocalmemory/retrieval/temporal_frame.py +0 -102
- package/src/superlocalmemory/retrieval/temporal_utils.py +0 -122
- package/src/superlocalmemory/retrieval/temporal_validity_filter.py +0 -499
- package/src/superlocalmemory/retrieval/time_window.py +0 -181
- package/src/superlocalmemory/retrieval/vector_store.py +0 -863
- package/src/superlocalmemory/server/__init__.py +0 -1
- package/src/superlocalmemory/server/api.py +0 -310
- package/src/superlocalmemory/server/asset_versions.py +0 -171
- package/src/superlocalmemory/server/bandit_loops.py +0 -158
- package/src/superlocalmemory/server/config_file.py +0 -90
- package/src/superlocalmemory/server/consolidation_runner.py +0 -140
- package/src/superlocalmemory/server/egress_policy.py +0 -258
- package/src/superlocalmemory/server/loopback.py +0 -85
- package/src/superlocalmemory/server/middleware/__init__.py +0 -11
- package/src/superlocalmemory/server/middleware/security_headers.py +0 -144
- package/src/superlocalmemory/server/origin.py +0 -55
- package/src/superlocalmemory/server/profile_runtime.py +0 -515
- package/src/superlocalmemory/server/rbac_enforce.py +0 -194
- package/src/superlocalmemory/server/recall_health.py +0 -343
- package/src/superlocalmemory/server/recall_serializer.py +0 -320
- package/src/superlocalmemory/server/route_mutations.py +0 -104
- package/src/superlocalmemory/server/routes/__init__.py +0 -4
- package/src/superlocalmemory/server/routes/abstraction.py +0 -314
- package/src/superlocalmemory/server/routes/adapters.py +0 -63
- package/src/superlocalmemory/server/routes/agents.py +0 -303
- package/src/superlocalmemory/server/routes/backup.py +0 -869
- package/src/superlocalmemory/server/routes/behavioral.py +0 -659
- package/src/superlocalmemory/server/routes/brain.py +0 -1892
- package/src/superlocalmemory/server/routes/chat.py +0 -393
- package/src/superlocalmemory/server/routes/compliance.py +0 -533
- package/src/superlocalmemory/server/routes/config_api.py +0 -703
- package/src/superlocalmemory/server/routes/data_io.py +0 -329
- package/src/superlocalmemory/server/routes/entity.py +0 -237
- package/src/superlocalmemory/server/routes/events.py +0 -214
- package/src/superlocalmemory/server/routes/evolution.py +0 -510
- package/src/superlocalmemory/server/routes/helpers.py +0 -499
- package/src/superlocalmemory/server/routes/ingest.py +0 -137
- package/src/superlocalmemory/server/routes/insights.py +0 -366
- package/src/superlocalmemory/server/routes/learning.py +0 -834
- package/src/superlocalmemory/server/routes/learning_telemetry.py +0 -154
- package/src/superlocalmemory/server/routes/lifecycle.py +0 -184
- package/src/superlocalmemory/server/routes/memories.py +0 -1661
- package/src/superlocalmemory/server/routes/mesh.py +0 -517
- package/src/superlocalmemory/server/routes/mesh_lock.py +0 -54
- package/src/superlocalmemory/server/routes/mesh_state.py +0 -63
- package/src/superlocalmemory/server/routes/optimize.py +0 -197
- package/src/superlocalmemory/server/routes/prewarm.py +0 -173
- package/src/superlocalmemory/server/routes/profiles.py +0 -292
- package/src/superlocalmemory/server/routes/ratelimit.py +0 -132
- package/src/superlocalmemory/server/routes/rbac.py +0 -366
- package/src/superlocalmemory/server/routes/stats.py +0 -385
- package/src/superlocalmemory/server/routes/tiers.py +0 -222
- package/src/superlocalmemory/server/routes/timeline.py +0 -258
- package/src/superlocalmemory/server/routes/token.py +0 -90
- package/src/superlocalmemory/server/routes/v3_api.py +0 -3023
- package/src/superlocalmemory/server/routes/ws.py +0 -171
- package/src/superlocalmemory/server/security_middleware.py +0 -89
- package/src/superlocalmemory/server/ui.py +0 -354
- package/src/superlocalmemory/server/unified_daemon.py +0 -6326
- package/src/superlocalmemory/server/write_identity.py +0 -195
- package/src/superlocalmemory/storage/__init__.py +0 -0
- package/src/superlocalmemory/storage/_migration_internals.py +0 -638
- package/src/superlocalmemory/storage/_schema_version.py +0 -174
- package/src/superlocalmemory/storage/access_log.py +0 -170
- package/src/superlocalmemory/storage/admission_codec.py +0 -129
- package/src/superlocalmemory/storage/admission_journal.py +0 -843
- package/src/superlocalmemory/storage/agent_experience.py +0 -546
- package/src/superlocalmemory/storage/backup.py +0 -531
- package/src/superlocalmemory/storage/correction_cases.py +0 -670
- package/src/superlocalmemory/storage/database.py +0 -3180
- package/src/superlocalmemory/storage/deferred_writes.py +0 -209
- package/src/superlocalmemory/storage/embedding_codec.py +0 -200
- package/src/superlocalmemory/storage/embedding_migrator.py +0 -672
- package/src/superlocalmemory/storage/erasure_fence.py +0 -45
- package/src/superlocalmemory/storage/execution_learning.py +0 -285
- package/src/superlocalmemory/storage/external_evidence.py +0 -359
- package/src/superlocalmemory/storage/generation_fence.py +0 -63
- package/src/superlocalmemory/storage/lineage_retention.py +0 -236
- package/src/superlocalmemory/storage/logical_edges.py +0 -86
- package/src/superlocalmemory/storage/memory_write.py +0 -115
- package/src/superlocalmemory/storage/migration_runner.py +0 -895
- package/src/superlocalmemory/storage/migration_v33.py +0 -140
- package/src/superlocalmemory/storage/migrations/M001_add_signal_features_columns.py +0 -67
- package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +0 -107
- package/src/superlocalmemory/storage/migrations/M003_migration_log.py +0 -38
- package/src/superlocalmemory/storage/migrations/M004_cross_platform_sync_log.py +0 -46
- package/src/superlocalmemory/storage/migrations/M005_bandit_tables.py +0 -75
- package/src/superlocalmemory/storage/migrations/M006_action_outcomes_reward.py +0 -75
- package/src/superlocalmemory/storage/migrations/M007_pending_outcomes.py +0 -63
- package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +0 -94
- package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +0 -80
- package/src/superlocalmemory/storage/migrations/M011_archive_and_merge.py +0 -87
- package/src/superlocalmemory/storage/migrations/M012_shadow_observations.py +0 -72
- package/src/superlocalmemory/storage/migrations/M013_bi_temporal_columns.py +0 -55
- package/src/superlocalmemory/storage/migrations/M014_v345_scale_ready.py +0 -45
- package/src/superlocalmemory/storage/migrations/M015_add_pinned_column.py +0 -58
- package/src/superlocalmemory/storage/migrations/M016_add_scope_support.py +0 -120
- package/src/superlocalmemory/storage/migrations/M017_ccq_scope_column.py +0 -79
- package/src/superlocalmemory/storage/migrations/M018_ingestion_operations.py +0 -120
- package/src/superlocalmemory/storage/migrations/M019_derivation_lineage.py +0 -54
- package/src/superlocalmemory/storage/migrations/M020_model_state_integrity.py +0 -52
- package/src/superlocalmemory/storage/migrations/M021_ingestion_log_profile.py +0 -108
- package/src/superlocalmemory/storage/migrations/M022_entity_aliases_profile.py +0 -86
- package/src/superlocalmemory/storage/migrations/M023_mesh_profile_isolation.py +0 -194
- package/src/superlocalmemory/storage/migrations/M024_rbac_users_roles.py +0 -87
- package/src/superlocalmemory/storage/migrations/M025_perf_indexes.py +0 -90
- package/src/superlocalmemory/storage/migrations/M026_rbac_memberships_fk.py +0 -136
- package/src/superlocalmemory/storage/migrations/M027_transferable_patterns_profile.py +0 -163
- package/src/superlocalmemory/storage/migrations/M028_fact_entity_associations.py +0 -305
- package/src/superlocalmemory/storage/migrations/M029_behavioral_history_indexes.py +0 -137
- package/src/superlocalmemory/storage/migrations/M030_entity_explorer_indexes.py +0 -93
- package/src/superlocalmemory/storage/migrations/M031_dead_letter_operations.py +0 -80
- package/src/superlocalmemory/storage/migrations/M032_write_coordinator_admission.py +0 -188
- package/src/superlocalmemory/storage/migrations/M033_projection_transactions.py +0 -148
- package/src/superlocalmemory/storage/migrations/M034_obligation_integrity.py +0 -58
- package/src/superlocalmemory/storage/migrations/M035_erasure_receipts.py +0 -113
- package/src/superlocalmemory/storage/migrations/M036_vector_row_map.py +0 -107
- package/src/superlocalmemory/storage/migrations/M037_manifest_hmac_version.py +0 -162
- package/src/superlocalmemory/storage/migrations/M038_learning_feedback_channel.py +0 -77
- package/src/superlocalmemory/storage/migrations/M039_scene_fact_members.py +0 -137
- package/src/superlocalmemory/storage/migrations/M040_agent_experience_receipts.py +0 -254
- package/src/superlocalmemory/storage/migrations/M041_external_evidence_receipts.py +0 -189
- package/src/superlocalmemory/storage/migrations/M042_correction_case_ledger.py +0 -245
- package/src/superlocalmemory/storage/migrations/M043_quarantine_display_summaries.py +0 -512
- package/src/superlocalmemory/storage/migrations/M044_play_carries_its_own_evidence.py +0 -127
- package/src/superlocalmemory/storage/migrations/M045_fact_outcome_score.py +0 -158
- package/src/superlocalmemory/storage/migrations/M046_prospective_memory_has_its_own_name.py +0 -620
- package/src/superlocalmemory/storage/migrations/M047_fisher_vectors_are_stored_like_every_other_vector.py +0 -306
- package/src/superlocalmemory/storage/migrations/M048_upcoming_holds_only_what_is_upcoming.py +0 -229
- package/src/superlocalmemory/storage/migrations/M049_a_schema_version_marker_is_one_row.py +0 -201
- package/src/superlocalmemory/storage/migrations/M050_execution_learning_v2.py +0 -70
- package/src/superlocalmemory/storage/migrations/__init__.py +0 -103
- package/src/superlocalmemory/storage/migrations.py +0 -333
- package/src/superlocalmemory/storage/models.py +0 -500
- package/src/superlocalmemory/storage/projection_outbox.py +0 -346
- package/src/superlocalmemory/storage/quantized_store.py +0 -280
- package/src/superlocalmemory/storage/read_connection.py +0 -115
- package/src/superlocalmemory/storage/retention_policy.py +0 -860
- package/src/superlocalmemory/storage/schema.py +0 -1108
- package/src/superlocalmemory/storage/schema_code_graph.py +0 -282
- package/src/superlocalmemory/storage/schema_v32.py +0 -382
- package/src/superlocalmemory/storage/schema_v3410.py +0 -159
- package/src/superlocalmemory/storage/schema_v3411.py +0 -149
- package/src/superlocalmemory/storage/schema_v343.py +0 -315
- package/src/superlocalmemory/storage/schema_v345.py +0 -109
- package/src/superlocalmemory/storage/schema_v347.py +0 -140
- package/src/superlocalmemory/storage/sqlite_vectors.py +0 -169
- package/src/superlocalmemory/storage/v2_migrator.py +0 -466
- package/src/superlocalmemory/storage/write_coordinator.py +0 -949
- package/src/superlocalmemory/storage/write_lock.py +0 -88
- package/src/superlocalmemory/summaries/__init__.py +0 -37
- package/src/superlocalmemory/summaries/base.py +0 -267
- package/src/superlocalmemory/summaries/daily_reflection.py +0 -340
- package/src/superlocalmemory/summaries/non_answer.py +0 -223
- package/src/superlocalmemory/summaries/project_work_log.py +0 -440
- package/src/superlocalmemory/summaries/session_summary.py +0 -311
- package/src/superlocalmemory/trust/__init__.py +0 -0
- package/src/superlocalmemory/trust/gate.py +0 -171
- package/src/superlocalmemory/trust/provenance.py +0 -124
- package/src/superlocalmemory/trust/scorer.py +0 -413
- package/src/superlocalmemory/trust/signals.py +0 -153
- package/src/superlocalmemory/ui/assets/slm-icon-white.svg +0 -64
- package/src/superlocalmemory/ui/assets/slm-icon.svg +0 -36
- package/src/superlocalmemory/ui/css/brain.css +0 -409
- package/src/superlocalmemory/ui/css/design-system.css +0 -696
- package/src/superlocalmemory/ui/css/legacy-dashboard.css +0 -663
- package/src/superlocalmemory/ui/css/neural-glass.css +0 -1599
- package/src/superlocalmemory/ui/css/od-bridge.css +0 -158
- package/src/superlocalmemory/ui/favicon.svg +0 -36
- package/src/superlocalmemory/ui/index.html +0 -1638
- package/src/superlocalmemory/ui/js/agents.js +0 -192
- package/src/superlocalmemory/ui/js/auto-settings.js +0 -624
- package/src/superlocalmemory/ui/js/brain.js +0 -1400
- package/src/superlocalmemory/ui/js/clusters.js +0 -326
- package/src/superlocalmemory/ui/js/compliance.js +0 -307
- package/src/superlocalmemory/ui/js/core.js +0 -566
- package/src/superlocalmemory/ui/js/dashboard.js +0 -503
- package/src/superlocalmemory/ui/js/event-delegation.js +0 -113
- package/src/superlocalmemory/ui/js/events.js +0 -178
- package/src/superlocalmemory/ui/js/fact-detail.js +0 -142
- package/src/superlocalmemory/ui/js/feedback.js +0 -339
- package/src/superlocalmemory/ui/js/graph-event-bus.js +0 -83
- package/src/superlocalmemory/ui/js/graph-filters.js +0 -220
- package/src/superlocalmemory/ui/js/graph-ui.js +0 -214
- package/src/superlocalmemory/ui/js/ide-status.js +0 -115
- package/src/superlocalmemory/ui/js/init.js +0 -54
- package/src/superlocalmemory/ui/js/knowledge-graph.js +0 -945
- package/src/superlocalmemory/ui/js/lifecycle.js +0 -387
- package/src/superlocalmemory/ui/js/math-health.js +0 -114
- package/src/superlocalmemory/ui/js/memories.js +0 -394
- package/src/superlocalmemory/ui/js/memory-chat.js +0 -371
- package/src/superlocalmemory/ui/js/memory-timeline.js +0 -265
- package/src/superlocalmemory/ui/js/modal.js +0 -733
- package/src/superlocalmemory/ui/js/ng-entities.js +0 -298
- package/src/superlocalmemory/ui/js/ng-health.js +0 -208
- package/src/superlocalmemory/ui/js/ng-ingestion.js +0 -203
- package/src/superlocalmemory/ui/js/ng-mesh.js +0 -374
- package/src/superlocalmemory/ui/js/ng-shell.js +0 -524
- package/src/superlocalmemory/ui/js/ng-skills.js +0 -663
- package/src/superlocalmemory/ui/js/od-agents.js +0 -588
- package/src/superlocalmemory/ui/js/od-auth-gate.js +0 -257
- package/src/superlocalmemory/ui/js/od-backup.js +0 -878
- package/src/superlocalmemory/ui/js/od-boundedloops.js +0 -324
- package/src/superlocalmemory/ui/js/od-brain.js +0 -1095
- package/src/superlocalmemory/ui/js/od-compliance-ext.js +0 -301
- package/src/superlocalmemory/ui/js/od-components.js +0 -147
- package/src/superlocalmemory/ui/js/od-entities.js +0 -622
- package/src/superlocalmemory/ui/js/od-graph.js +0 -776
- package/src/superlocalmemory/ui/js/od-health.js +0 -579
- package/src/superlocalmemory/ui/js/od-mcp.js +0 -508
- package/src/superlocalmemory/ui/js/od-memories.js +0 -1499
- package/src/superlocalmemory/ui/js/od-mesh.js +0 -645
- package/src/superlocalmemory/ui/js/od-operations.js +0 -1268
- package/src/superlocalmemory/ui/js/od-ops-health.js +0 -417
- package/src/superlocalmemory/ui/js/od-optimize.js +0 -828
- package/src/superlocalmemory/ui/js/od-settings.js +0 -1275
- package/src/superlocalmemory/ui/js/od-shell.js +0 -819
- package/src/superlocalmemory/ui/js/od-skills.js +0 -600
- package/src/superlocalmemory/ui/js/od-team.js +0 -265
- package/src/superlocalmemory/ui/js/optimize.js +0 -191
- package/src/superlocalmemory/ui/js/profiles.js +0 -362
- package/src/superlocalmemory/ui/js/quick-actions.js +0 -334
- package/src/superlocalmemory/ui/js/recall-lab.js +0 -373
- package/src/superlocalmemory/ui/js/search.js +0 -86
- package/src/superlocalmemory/ui/js/settings.js +0 -556
- package/src/superlocalmemory/ui/js/timeline.js +0 -62
- package/src/superlocalmemory/ui/js/trust-dashboard.js +0 -225
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/bootstrap-icons.css +0 -2018
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap.bundle.min.js +0 -7
- package/src/superlocalmemory/ui/vendor/bootstrap.min.css +0 -6
- package/src/superlocalmemory/ui/vendor/d3.v7.min.js +0 -2
- package/src/superlocalmemory/ui/vendor/graphology-library.min.js +0 -2
- package/src/superlocalmemory/ui/vendor/graphology.umd.min.js +0 -2
- package/src/superlocalmemory/ui/vendor/inter-ui/inter-variable.min.css +0 -8
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable-Italic.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/sigma.min.js +0 -1
- package/src/superlocalmemory/vector/__init__.py +0 -9
- package/src/superlocalmemory/vector/lancedb_backend.py +0 -366
|
@@ -1,994 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2026 Varun Pratap Bhardwaj / Qualixar
|
|
2
|
-
# Licensed under AGPL-3.0-or-later - see LICENSE file
|
|
3
|
-
# Part of SuperLocalMemory V3 | https://qualixar.com | https://varunpratap.com
|
|
4
|
-
|
|
5
|
-
"""SuperLocalMemory V3 — Entity Graph Channel with Spreading Activation.
|
|
6
|
-
|
|
7
|
-
SA-RAG pattern: entities from query -> canonical lookup -> graph traversal
|
|
8
|
-
with decay. Handles BOTH uppercase and lowercase entity mentions.
|
|
9
|
-
|
|
10
|
-
Part of Qualixar | Author: Varun Pratap Bhardwaj
|
|
11
|
-
License: AGPL-3.0-or-later
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
import json
|
|
17
|
-
import logging
|
|
18
|
-
import os
|
|
19
|
-
import re
|
|
20
|
-
import threading
|
|
21
|
-
from collections import defaultdict
|
|
22
|
-
from typing import TYPE_CHECKING, Any
|
|
23
|
-
|
|
24
|
-
from superlocalmemory.retrieval import spreading
|
|
25
|
-
from superlocalmemory.retrieval.scope_policy import (
|
|
26
|
-
authorized_fact_ids,
|
|
27
|
-
filter_authorized_results,
|
|
28
|
-
)
|
|
29
|
-
from superlocalmemory.storage.database import (
|
|
30
|
-
_scope_where,
|
|
31
|
-
_unbounded_facts_ceiling,
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
if TYPE_CHECKING:
|
|
35
|
-
from superlocalmemory.encoding.entity_resolver import EntityResolver
|
|
36
|
-
from superlocalmemory.storage.database import DatabaseManager
|
|
37
|
-
|
|
38
|
-
logger = logging.getLogger(__name__)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
def _adj_ttl_seconds() -> float:
|
|
42
|
-
"""In-memory adjacency-cache TTL (seconds), env-overridable.
|
|
43
|
-
|
|
44
|
-
v3.8.5: raised from a hard-coded 300s to 3600s. The TTL only exists to
|
|
45
|
-
catch edge-WEIGHT mutations (pruning / MAX-merge) that leave the edge COUNT
|
|
46
|
-
unchanged — new memories already force a reload via the count check. At 300s
|
|
47
|
-
a 208K-edge graph rebuilt on the recall hot path every 5 idle minutes,
|
|
48
|
-
causing a recurring multi-second latency spike. Weight drift is a minor
|
|
49
|
-
ranking refinement, so a longer TTL trades negligible staleness for a big
|
|
50
|
-
latency win. Set SLM_ENTITY_ADJ_TTL_S to tune (0 disables time-based reload;
|
|
51
|
-
the count-based correctness reload always remains).
|
|
52
|
-
"""
|
|
53
|
-
try:
|
|
54
|
-
return max(0.0, float(os.environ.get("SLM_ENTITY_ADJ_TTL_S", "3600")))
|
|
55
|
-
except (TypeError, ValueError):
|
|
56
|
-
return 3600.0
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
_PROPER_NOUN_RE = re.compile(r"\b[A-Z][a-z]{1,}\b")
|
|
60
|
-
|
|
61
|
-
_ENTITY_STOP: frozenset[str] = frozenset(
|
|
62
|
-
{
|
|
63
|
-
# Expanded stop list for query entity extraction
|
|
64
|
-
"what",
|
|
65
|
-
"when",
|
|
66
|
-
"where",
|
|
67
|
-
"who",
|
|
68
|
-
"which",
|
|
69
|
-
"how",
|
|
70
|
-
"does",
|
|
71
|
-
"did",
|
|
72
|
-
"the",
|
|
73
|
-
"that",
|
|
74
|
-
"this",
|
|
75
|
-
"there",
|
|
76
|
-
"then",
|
|
77
|
-
"than",
|
|
78
|
-
"they",
|
|
79
|
-
"them",
|
|
80
|
-
"have",
|
|
81
|
-
"has",
|
|
82
|
-
"had",
|
|
83
|
-
"been",
|
|
84
|
-
"being",
|
|
85
|
-
"about",
|
|
86
|
-
"after",
|
|
87
|
-
"before",
|
|
88
|
-
"from",
|
|
89
|
-
"into",
|
|
90
|
-
"with",
|
|
91
|
-
"some",
|
|
92
|
-
"other",
|
|
93
|
-
"would",
|
|
94
|
-
"could",
|
|
95
|
-
"should",
|
|
96
|
-
"will",
|
|
97
|
-
"because",
|
|
98
|
-
"also",
|
|
99
|
-
"just",
|
|
100
|
-
"like",
|
|
101
|
-
"know",
|
|
102
|
-
"think",
|
|
103
|
-
"feel",
|
|
104
|
-
"want",
|
|
105
|
-
"need",
|
|
106
|
-
"make",
|
|
107
|
-
"take",
|
|
108
|
-
"give",
|
|
109
|
-
"tell",
|
|
110
|
-
"said",
|
|
111
|
-
"wow",
|
|
112
|
-
"gonna",
|
|
113
|
-
"got",
|
|
114
|
-
"by",
|
|
115
|
-
"thanks",
|
|
116
|
-
"thank",
|
|
117
|
-
"hey",
|
|
118
|
-
"hi",
|
|
119
|
-
"hello",
|
|
120
|
-
"bye",
|
|
121
|
-
"good",
|
|
122
|
-
"great",
|
|
123
|
-
"nice",
|
|
124
|
-
"cool",
|
|
125
|
-
"right",
|
|
126
|
-
"let",
|
|
127
|
-
"can",
|
|
128
|
-
"might",
|
|
129
|
-
"much",
|
|
130
|
-
"many",
|
|
131
|
-
"more",
|
|
132
|
-
"most",
|
|
133
|
-
"something",
|
|
134
|
-
"anything",
|
|
135
|
-
"everything",
|
|
136
|
-
"nothing",
|
|
137
|
-
"someone",
|
|
138
|
-
"it",
|
|
139
|
-
"my",
|
|
140
|
-
"your",
|
|
141
|
-
"our",
|
|
142
|
-
"their",
|
|
143
|
-
"me",
|
|
144
|
-
"you",
|
|
145
|
-
"we",
|
|
146
|
-
"us",
|
|
147
|
-
"do",
|
|
148
|
-
"if",
|
|
149
|
-
"or",
|
|
150
|
-
"no",
|
|
151
|
-
"to",
|
|
152
|
-
"at",
|
|
153
|
-
"on",
|
|
154
|
-
"in",
|
|
155
|
-
"so",
|
|
156
|
-
"go",
|
|
157
|
-
"come",
|
|
158
|
-
"see",
|
|
159
|
-
"look",
|
|
160
|
-
"say",
|
|
161
|
-
"ask",
|
|
162
|
-
"try",
|
|
163
|
-
"keep",
|
|
164
|
-
"yes",
|
|
165
|
-
"yeah",
|
|
166
|
-
"sure",
|
|
167
|
-
"okay",
|
|
168
|
-
"ok",
|
|
169
|
-
"really",
|
|
170
|
-
"actually",
|
|
171
|
-
"maybe",
|
|
172
|
-
"well",
|
|
173
|
-
"still",
|
|
174
|
-
"even",
|
|
175
|
-
"very",
|
|
176
|
-
}
|
|
177
|
-
)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
def extract_query_entities(query: str) -> list[str]:
|
|
181
|
-
"""Extract entity candidates from query (handles both cases).
|
|
182
|
-
|
|
183
|
-
Strategy: find proper nouns in original + title-cased text,
|
|
184
|
-
plus quoted phrases. Deduplicates case-insensitively.
|
|
185
|
-
"""
|
|
186
|
-
candidates: list[str] = []
|
|
187
|
-
seen: set[str] = set()
|
|
188
|
-
|
|
189
|
-
def _add(name: str) -> None:
|
|
190
|
-
lo = name.lower()
|
|
191
|
-
if lo not in seen and lo not in _ENTITY_STOP and len(name) >= 2:
|
|
192
|
-
seen.add(lo)
|
|
193
|
-
candidates.append(name)
|
|
194
|
-
|
|
195
|
-
for m in _PROPER_NOUN_RE.finditer(query):
|
|
196
|
-
_add(m.group(0))
|
|
197
|
-
for m in _PROPER_NOUN_RE.finditer(query.title()):
|
|
198
|
-
_add(m.group(0))
|
|
199
|
-
for m in re.finditer(r'"([^"]+)"', query):
|
|
200
|
-
_add(m.group(1).strip())
|
|
201
|
-
# Also extract multi-word capitalized sequences (e.g. "New York", "San Francisco")
|
|
202
|
-
for m in re.finditer(r"\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)\b", query):
|
|
203
|
-
_add(m.group(1))
|
|
204
|
-
# Extract all-caps abbreviations (e.g. NYU, MIT, UCLA) — min 2 chars
|
|
205
|
-
for m in re.finditer(r"\b([A-Z]{2,})\b", query):
|
|
206
|
-
_add(m.group(1))
|
|
207
|
-
|
|
208
|
-
return candidates
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
class EntityGraphChannel:
|
|
212
|
-
"""Entity-based retrieval with spreading activation (SA-RAG).
|
|
213
|
-
|
|
214
|
-
V3.3.9: In-memory adjacency cache for O(1) edge lookup.
|
|
215
|
-
Replaces per-node SQLite queries (23ms each) with dict lookup (<0.001ms).
|
|
216
|
-
The cache is loaded once per profile and invalidated on store/edge changes.
|
|
217
|
-
Memory cost: ~18 MB for 232K edges. Zero quality change — same algorithm.
|
|
218
|
-
"""
|
|
219
|
-
|
|
220
|
-
def __init__(
|
|
221
|
-
self,
|
|
222
|
-
db: DatabaseManager,
|
|
223
|
-
entity_resolver: EntityResolver | None = None,
|
|
224
|
-
decay: float = 0.7,
|
|
225
|
-
activation_threshold: float = 0.05,
|
|
226
|
-
max_hops: int = 4,
|
|
227
|
-
graph_metrics: dict[str, dict] | None = None,
|
|
228
|
-
cozo_backend: Any = None, # v3.4.5: optional CozoDB backend
|
|
229
|
-
) -> None:
|
|
230
|
-
self._db = db
|
|
231
|
-
self._resolver = entity_resolver
|
|
232
|
-
self._decay = decay
|
|
233
|
-
self._threshold = activation_threshold
|
|
234
|
-
self._max_hops = max_hops
|
|
235
|
-
# v3.4.5: Optional CozoDB graph backend (Sprint 2)
|
|
236
|
-
self._cozo = cozo_backend
|
|
237
|
-
self._cache_lock = threading.RLock()
|
|
238
|
-
# In-memory adjacency: {node_id -> [(neighbor_id, weight), ...]}
|
|
239
|
-
self._adj: dict[str, list[tuple[str, float]]] = {}
|
|
240
|
-
self._adj_profile: str = "" # Track which profile is loaded
|
|
241
|
-
self._adj_scope_key: tuple[str, bool, bool] | None = None
|
|
242
|
-
self._adj_edge_count: int = 0 # Track edge count for staleness detection
|
|
243
|
-
self._adj_fact_count: int = 0
|
|
244
|
-
self._entity_to_facts: dict[str, list[str]] = defaultdict(list)
|
|
245
|
-
self._fact_to_entities: dict[str, list[str]] = defaultdict(list)
|
|
246
|
-
self._visible_fact_ids: set[str] = set()
|
|
247
|
-
# v3.4.1: Graph intelligence metrics (loaded from fact_importance)
|
|
248
|
-
self._graph_metrics: dict[str, dict] = graph_metrics or {}
|
|
249
|
-
self._graph_metrics_profile: str = ""
|
|
250
|
-
|
|
251
|
-
def _ensure_adjacency(
|
|
252
|
-
self,
|
|
253
|
-
profile_id: str,
|
|
254
|
-
*,
|
|
255
|
-
include_global: bool = False,
|
|
256
|
-
include_shared: bool = False,
|
|
257
|
-
) -> None:
|
|
258
|
-
"""Load graph adjacency into memory for fast spreading activation.
|
|
259
|
-
|
|
260
|
-
Loads ALL edges for a profile into a bidirectional dict.
|
|
261
|
-
Called once per profile switch or when edge count changes (new store).
|
|
262
|
-
Cost: ~1s for 232K edges, ~18 MB RAM.
|
|
263
|
-
"""
|
|
264
|
-
# Check staleness: profile changed or new edges added since last load
|
|
265
|
-
scope_key = (profile_id, bool(include_global), bool(include_shared))
|
|
266
|
-
current_count = self._get_edge_count(
|
|
267
|
-
profile_id,
|
|
268
|
-
include_global=include_global,
|
|
269
|
-
include_shared=include_shared,
|
|
270
|
-
)
|
|
271
|
-
try:
|
|
272
|
-
current_fact_count = self._db.get_fact_count(
|
|
273
|
-
profile_id,
|
|
274
|
-
include_global=include_global,
|
|
275
|
-
include_shared=include_shared,
|
|
276
|
-
)
|
|
277
|
-
except Exception:
|
|
278
|
-
current_fact_count = -1
|
|
279
|
-
# memory-bounding-01: also reload if the cache is older than the TTL,
|
|
280
|
-
# even when the edge COUNT is unchanged. Edge weights/pruning can mutate
|
|
281
|
-
# the graph without changing the count (e.g. store_edge MAX-merge), and a
|
|
282
|
-
# count-stable window would otherwise serve a stale adjacency map.
|
|
283
|
-
import time as _t_ec
|
|
284
|
-
|
|
285
|
-
_now_ec = _t_ec.monotonic()
|
|
286
|
-
_ttl = _adj_ttl_seconds()
|
|
287
|
-
# TTL=0 disables the time-based reload entirely (count-based correctness
|
|
288
|
-
# reload still applies); otherwise the cache is fresh within the TTL.
|
|
289
|
-
_fresh = _ttl <= 0.0 or ((_now_ec - getattr(self, "_adj_loaded_at", 0.0)) < _ttl)
|
|
290
|
-
if (
|
|
291
|
-
self._adj_scope_key == scope_key
|
|
292
|
-
and (self._adj or self._visible_fact_ids)
|
|
293
|
-
and self._adj_edge_count == current_count
|
|
294
|
-
and self._adj_fact_count == current_fact_count
|
|
295
|
-
and _fresh
|
|
296
|
-
):
|
|
297
|
-
return
|
|
298
|
-
adj: dict[str, list[tuple[str, float]]] = defaultdict(list)
|
|
299
|
-
# The graph projection, when there is one, answers this in 395 ms where
|
|
300
|
-
# SQLite takes 2,477 ms on the same 208k-edge store (hand-measured, see
|
|
301
|
-
# graph/cozo_adjacency for the run; no test reproduces it) -- and this rebuild
|
|
302
|
-
# sits on the recall path, triggered by any edge-count change or a TTL
|
|
303
|
-
# expiry. It declines global and shared scope, because it stores one
|
|
304
|
-
# profile per edge and a short answer here would silently shrink the
|
|
305
|
-
# graph around a candidate. That decline is correct, not a degradation.
|
|
306
|
-
#
|
|
307
|
-
# This is the projection's only reader. Before it, the projection was
|
|
308
|
-
# maintained by the outbox, held at parity, purged on erasure, and
|
|
309
|
-
# queried by nothing.
|
|
310
|
-
triples: list[tuple[str, str, float]] | None = None
|
|
311
|
-
source_name = "sqlite"
|
|
312
|
-
try:
|
|
313
|
-
from superlocalmemory.graph.cozo_adjacency import adjacency_source
|
|
314
|
-
|
|
315
|
-
projection = (
|
|
316
|
-
adjacency_source() if self._projection_is_caught_up(profile_id) else None
|
|
317
|
-
)
|
|
318
|
-
if projection is not None:
|
|
319
|
-
triples = projection.edges(
|
|
320
|
-
profile_id,
|
|
321
|
-
include_global=include_global,
|
|
322
|
-
include_shared=include_shared,
|
|
323
|
-
)
|
|
324
|
-
if triples is not None:
|
|
325
|
-
source_name = projection.name
|
|
326
|
-
except Exception: # noqa: BLE001 -- SQLite answers this unconditionally
|
|
327
|
-
triples = None
|
|
328
|
-
if triples is None:
|
|
329
|
-
try:
|
|
330
|
-
where, params = _scope_where(
|
|
331
|
-
profile_id,
|
|
332
|
-
include_global=include_global,
|
|
333
|
-
include_shared=include_shared,
|
|
334
|
-
)
|
|
335
|
-
rows = self._db.execute(
|
|
336
|
-
f"SELECT source_id, target_id, weight FROM graph_edges WHERE {where}",
|
|
337
|
-
(*params,),
|
|
338
|
-
)
|
|
339
|
-
except Exception:
|
|
340
|
-
rows = []
|
|
341
|
-
triples = []
|
|
342
|
-
for r in rows:
|
|
343
|
-
d = dict(r)
|
|
344
|
-
triples.append(
|
|
345
|
-
(d["source_id"], d["target_id"], float(d["weight"])),
|
|
346
|
-
)
|
|
347
|
-
self._adjacency_source_name = source_name
|
|
348
|
-
for edge_source, edge_target, edge_weight in triples:
|
|
349
|
-
adj[edge_source].append((edge_target, edge_weight))
|
|
350
|
-
adj[edge_target].append((edge_source, edge_weight))
|
|
351
|
-
# Also load entity maps (same staleness lifecycle)
|
|
352
|
-
self._load_entity_maps(
|
|
353
|
-
profile_id,
|
|
354
|
-
include_global=include_global,
|
|
355
|
-
include_shared=include_shared,
|
|
356
|
-
)
|
|
357
|
-
# Edge scope alone cannot authorize an endpoint. Prune both endpoints
|
|
358
|
-
# against the visible fact corpus so denied facts cannot influence an
|
|
359
|
-
# allowed candidate indirectly through propagation.
|
|
360
|
-
self._adj = {
|
|
361
|
-
node_id: [
|
|
362
|
-
(neighbor_id, weight)
|
|
363
|
-
for neighbor_id, weight in neighbors
|
|
364
|
-
if neighbor_id in self._visible_fact_ids
|
|
365
|
-
]
|
|
366
|
-
for node_id, neighbors in adj.items()
|
|
367
|
-
if node_id in self._visible_fact_ids
|
|
368
|
-
}
|
|
369
|
-
self._adj_profile = profile_id
|
|
370
|
-
self._adj_scope_key = scope_key
|
|
371
|
-
self._adj_edge_count = current_count
|
|
372
|
-
self._adj_fact_count = current_fact_count
|
|
373
|
-
self._adj_loaded_at = _now_ec # memory-bounding-01: TTL reference
|
|
374
|
-
# v3.4.1: Load graph intelligence metrics (P0)
|
|
375
|
-
self._load_graph_metrics(profile_id)
|
|
376
|
-
|
|
377
|
-
# One array-shaped view of the same graph, for the walk to run over.
|
|
378
|
-
# Built here rather than per query because it is derived entirely from
|
|
379
|
-
# the maps above and shares their staleness lifecycle exactly.
|
|
380
|
-
from superlocalmemory.retrieval.graph_adjacency import snapshot_from_maps
|
|
381
|
-
|
|
382
|
-
self._snapshot = snapshot_from_maps(
|
|
383
|
-
self._adj,
|
|
384
|
-
self._entity_to_facts,
|
|
385
|
-
self._fact_to_entities,
|
|
386
|
-
self._graph_metrics,
|
|
387
|
-
source=getattr(self, "_adjacency_source_name", "sqlite"),
|
|
388
|
-
profile_id=profile_id,
|
|
389
|
-
# Every visible fact is a node, including the ones with no edges
|
|
390
|
-
# yet. Ingestion is queryable-first, so a memory stored a moment ago
|
|
391
|
-
# has entities and no edges, and it must still be reachable.
|
|
392
|
-
nodes=self._visible_fact_ids,
|
|
393
|
-
# Only a real count. The staleness check above compares this value
|
|
394
|
-
# with ``==``, which a MagicMock tolerates; an ordering comparison
|
|
395
|
-
# does not, and the mock DBs in the test suite reach here.
|
|
396
|
-
fact_count=(
|
|
397
|
-
current_fact_count
|
|
398
|
-
if isinstance(current_fact_count, int) and current_fact_count >= 0
|
|
399
|
-
else 0
|
|
400
|
-
),
|
|
401
|
-
)
|
|
402
|
-
|
|
403
|
-
logger.info(
|
|
404
|
-
"Loaded adjacency cache: %d nodes, %d edges, %d entity mappings for profile %s",
|
|
405
|
-
len(self._adj),
|
|
406
|
-
sum(len(v) for v in self._adj.values()) // 2,
|
|
407
|
-
len(self._entity_to_facts),
|
|
408
|
-
profile_id,
|
|
409
|
-
)
|
|
410
|
-
|
|
411
|
-
def _projection_is_caught_up(self, profile_id: str) -> bool:
|
|
412
|
-
"""Whether the second graph store has seen every change SQLite has.
|
|
413
|
-
|
|
414
|
-
The graph lives in two stores and no transaction spans them, so the
|
|
415
|
-
durable record of "this fact still needs projecting" is a queue row
|
|
416
|
-
written in the same transaction as the change. A row outstanding for
|
|
417
|
-
this profile is that store telling us, in its own words, that it is
|
|
418
|
-
behind -- and reading a graph that is behind means walking a link the
|
|
419
|
-
store has already removed.
|
|
420
|
-
|
|
421
|
-
This is a primary-key count on a table whose steady state is empty and
|
|
422
|
-
whose size is bounded by the fact count, so it is microseconds. The
|
|
423
|
-
alternative -- comparing the two edge sets -- costs 1.9 s on the
|
|
424
|
-
author's store and 7.7 s on the larger one, which is the whole recall
|
|
425
|
-
budget spent proving a cache is warm.
|
|
426
|
-
"""
|
|
427
|
-
try:
|
|
428
|
-
from superlocalmemory.storage import projection_outbox
|
|
429
|
-
|
|
430
|
-
if not projection_outbox.is_available(self._db):
|
|
431
|
-
return True
|
|
432
|
-
rows = self._db.execute(
|
|
433
|
-
"SELECT COUNT(*) AS cnt FROM projection_outbox WHERE profile_id = ?",
|
|
434
|
-
(profile_id,),
|
|
435
|
-
)
|
|
436
|
-
pending = int(dict(rows[0]).get("cnt", 0)) if rows else 0
|
|
437
|
-
except Exception: # noqa: BLE001 -- an unreadable queue means read SQLite
|
|
438
|
-
return False
|
|
439
|
-
if pending:
|
|
440
|
-
logger.debug(
|
|
441
|
-
"adjacency: %d change(s) not yet in the graph projection for "
|
|
442
|
-
"profile %s; reading the store directly", pending, profile_id,
|
|
443
|
-
)
|
|
444
|
-
return False
|
|
445
|
-
return True
|
|
446
|
-
|
|
447
|
-
def _get_edge_count(
|
|
448
|
-
self,
|
|
449
|
-
profile_id: str,
|
|
450
|
-
*,
|
|
451
|
-
include_global: bool = False,
|
|
452
|
-
include_shared: bool = False,
|
|
453
|
-
) -> int:
|
|
454
|
-
"""Fast edge count for staleness check (~1ms)."""
|
|
455
|
-
try:
|
|
456
|
-
where, params = _scope_where(
|
|
457
|
-
profile_id,
|
|
458
|
-
include_global=include_global,
|
|
459
|
-
include_shared=include_shared,
|
|
460
|
-
)
|
|
461
|
-
rows = self._db.execute(
|
|
462
|
-
f"SELECT COUNT(*) as cnt FROM graph_edges WHERE {where}",
|
|
463
|
-
(*params,),
|
|
464
|
-
)
|
|
465
|
-
if rows:
|
|
466
|
-
return int(dict(rows[0]).get("cnt", 0))
|
|
467
|
-
except Exception:
|
|
468
|
-
pass
|
|
469
|
-
return 0
|
|
470
|
-
|
|
471
|
-
def _load_entity_maps(
|
|
472
|
-
self,
|
|
473
|
-
profile_id: str,
|
|
474
|
-
*,
|
|
475
|
-
include_global: bool = False,
|
|
476
|
-
include_shared: bool = False,
|
|
477
|
-
) -> None:
|
|
478
|
-
"""Pre-load entity→fact and fact→entity maps into memory.
|
|
479
|
-
|
|
480
|
-
Eliminates per-entity and per-fact SQL in the spreading activation loop.
|
|
481
|
-
Fetch only the two columns this index consumes. Loading full AtomicFact
|
|
482
|
-
objects also deserializes every 768-d embedding and Fisher vector; on a
|
|
483
|
-
mature database that turned one new fact into a 5-second recall stall.
|
|
484
|
-
The scope predicate and configurable 50k safety ceiling are identical
|
|
485
|
-
to ``get_all_facts``; only heavyweight unused columns are omitted.
|
|
486
|
-
"""
|
|
487
|
-
# entity_id -> [fact_id, ...]
|
|
488
|
-
self._entity_to_facts: dict[str, list[str]] = defaultdict(list)
|
|
489
|
-
# fact_id -> [entity_id, ...]
|
|
490
|
-
self._fact_to_entities: dict[str, list[str]] = defaultdict(list)
|
|
491
|
-
self._visible_fact_ids = set()
|
|
492
|
-
|
|
493
|
-
try:
|
|
494
|
-
where, params = _scope_where(
|
|
495
|
-
profile_id,
|
|
496
|
-
include_global=include_global,
|
|
497
|
-
include_shared=include_shared,
|
|
498
|
-
)
|
|
499
|
-
# Withheld rows must not enter the entity map at all. They carry
|
|
500
|
-
# their whole cluster's pooled entity list, which is exactly why
|
|
501
|
-
# they out-ranked real memories here in the first place — leaving
|
|
502
|
-
# them in the map would keep spending this channel's budget on
|
|
503
|
-
# candidates that hydration then discards.
|
|
504
|
-
rows = self._db.execute(
|
|
505
|
-
"SELECT fact_id, canonical_entities_json "
|
|
506
|
-
f"FROM atomic_facts WHERE {where}"
|
|
507
|
-
f"{self._db.visible_fact_clause()} "
|
|
508
|
-
"ORDER BY created_at DESC LIMIT ?",
|
|
509
|
-
(*params, _unbounded_facts_ceiling()),
|
|
510
|
-
)
|
|
511
|
-
except Exception:
|
|
512
|
-
rows = []
|
|
513
|
-
for row in rows:
|
|
514
|
-
data = dict(row)
|
|
515
|
-
fact_id = str(data.get("fact_id") or "")
|
|
516
|
-
if not fact_id:
|
|
517
|
-
continue
|
|
518
|
-
self._visible_fact_ids.add(fact_id)
|
|
519
|
-
try:
|
|
520
|
-
entity_ids = json.loads(
|
|
521
|
-
data.get("canonical_entities_json") or "[]",
|
|
522
|
-
)
|
|
523
|
-
except (TypeError, ValueError):
|
|
524
|
-
entity_ids = []
|
|
525
|
-
for entity_id in entity_ids:
|
|
526
|
-
if not isinstance(entity_id, str) or not entity_id:
|
|
527
|
-
continue
|
|
528
|
-
self._entity_to_facts[entity_id].append(fact_id)
|
|
529
|
-
self._fact_to_entities[fact_id].append(entity_id)
|
|
530
|
-
|
|
531
|
-
logger.info(
|
|
532
|
-
"Loaded entity maps: %d entities, %d facts with entities",
|
|
533
|
-
len(self._entity_to_facts),
|
|
534
|
-
len(self._fact_to_entities),
|
|
535
|
-
)
|
|
536
|
-
|
|
537
|
-
def _load_graph_metrics(self, profile_id: str) -> None:
|
|
538
|
-
"""Load PageRank, community_id, degree_centrality from fact_importance.
|
|
539
|
-
|
|
540
|
-
v3.4.1: Enables graph-enhanced retrieval (P0).
|
|
541
|
-
Called alongside adjacency loading. Same staleness lifecycle.
|
|
542
|
-
"""
|
|
543
|
-
if self._graph_metrics_profile == profile_id and self._graph_metrics:
|
|
544
|
-
return
|
|
545
|
-
self._graph_metrics = {}
|
|
546
|
-
self._graph_metrics_profile = profile_id
|
|
547
|
-
try:
|
|
548
|
-
rows = self._db.execute(
|
|
549
|
-
"SELECT fact_id, pagerank_score, community_id, degree_centrality "
|
|
550
|
-
"FROM fact_importance WHERE profile_id = ?",
|
|
551
|
-
(profile_id,),
|
|
552
|
-
)
|
|
553
|
-
for r in rows:
|
|
554
|
-
d = dict(r)
|
|
555
|
-
self._graph_metrics[d["fact_id"]] = {
|
|
556
|
-
"pagerank_score": float(d.get("pagerank_score", 0) or 0),
|
|
557
|
-
"community_id": d.get("community_id"),
|
|
558
|
-
"degree_centrality": float(d.get("degree_centrality", 0) or 0),
|
|
559
|
-
}
|
|
560
|
-
logger.info(
|
|
561
|
-
"Loaded graph metrics: %d facts for profile %s",
|
|
562
|
-
len(self._graph_metrics),
|
|
563
|
-
profile_id,
|
|
564
|
-
)
|
|
565
|
-
except Exception as exc:
|
|
566
|
-
logger.debug("Graph metrics load failed (graceful degradation): %s", exc)
|
|
567
|
-
self._graph_metrics = {}
|
|
568
|
-
|
|
569
|
-
def invalidate_cache(self) -> None:
|
|
570
|
-
"""Clear all caches. Call after adding/removing edges or facts."""
|
|
571
|
-
self._adj.clear()
|
|
572
|
-
self._adj_profile = ""
|
|
573
|
-
self._adj_scope_key = None
|
|
574
|
-
self._adj_edge_count = 0
|
|
575
|
-
self._adj_fact_count = 0
|
|
576
|
-
self._entity_to_facts = defaultdict(list)
|
|
577
|
-
self._fact_to_entities = defaultdict(list)
|
|
578
|
-
self._visible_fact_ids.clear()
|
|
579
|
-
self._graph_metrics.clear()
|
|
580
|
-
self._graph_metrics_profile = ""
|
|
581
|
-
|
|
582
|
-
def search(self, query: str, profile_id: str, top_k: int = 50) -> list[tuple[str, float]]:
|
|
583
|
-
"""Serialize access to the scope-keyed graph/entity cache."""
|
|
584
|
-
with self._cache_lock:
|
|
585
|
-
return self._search_locked(query, profile_id, top_k)
|
|
586
|
-
|
|
587
|
-
def _search_locked(
|
|
588
|
-
self,
|
|
589
|
-
query: str,
|
|
590
|
-
profile_id: str,
|
|
591
|
-
top_k: int = 50,
|
|
592
|
-
) -> list[tuple[str, float]]:
|
|
593
|
-
"""Search via entity graph with spreading activation.
|
|
594
|
-
|
|
595
|
-
V3.3.9: Uses in-memory adjacency for O(1) edge lookups.
|
|
596
|
-
V3.4.5: Routes to CozoDB if backend is active (Sprint 2).
|
|
597
|
-
"""
|
|
598
|
-
include_global = bool(getattr(self, "include_global", False))
|
|
599
|
-
include_shared = bool(getattr(self, "include_shared", False))
|
|
600
|
-
raw_entities = extract_query_entities(query)
|
|
601
|
-
|
|
602
|
-
if not raw_entities:
|
|
603
|
-
return []
|
|
604
|
-
|
|
605
|
-
# Load the visible fact/entity map before resolution. Canonical entity
|
|
606
|
-
# IDs are profile-local UUIDs, so the same name may have a different ID
|
|
607
|
-
# in an opted-in global/shared owner's partition.
|
|
608
|
-
self._ensure_adjacency(
|
|
609
|
-
profile_id,
|
|
610
|
-
include_global=include_global,
|
|
611
|
-
include_shared=include_shared,
|
|
612
|
-
)
|
|
613
|
-
|
|
614
|
-
canonical_ids = self._resolve_entities(raw_entities, profile_id)
|
|
615
|
-
if not canonical_ids:
|
|
616
|
-
return []
|
|
617
|
-
|
|
618
|
-
# One walk, over the array-shaped snapshot when there is one. The
|
|
619
|
-
# dict form below is kept for the mock/lightweight DBs that never build
|
|
620
|
-
# an adjacency cache, and it is the only path that still pays a Python
|
|
621
|
-
# loop per edge.
|
|
622
|
-
snapshot = getattr(self, "_snapshot", None)
|
|
623
|
-
if snapshot is not None and snapshot.node_count:
|
|
624
|
-
activation_result = spreading.activate(
|
|
625
|
-
snapshot,
|
|
626
|
-
canonical_ids,
|
|
627
|
-
decay=self._decay,
|
|
628
|
-
threshold=self._threshold,
|
|
629
|
-
max_hops=self._max_hops,
|
|
630
|
-
)
|
|
631
|
-
spreading.apply_community_bias(
|
|
632
|
-
activation_result.scores, snapshot, canonical_ids,
|
|
633
|
-
)
|
|
634
|
-
activation = activation_result.as_mapping(snapshot, threshold=-1.0)
|
|
635
|
-
if activation:
|
|
636
|
-
self._suppress_contradictions(activation, profile_id)
|
|
637
|
-
results = [
|
|
638
|
-
(fid, sc) for fid, sc in activation.items() if sc >= self._threshold
|
|
639
|
-
]
|
|
640
|
-
if not results:
|
|
641
|
-
return []
|
|
642
|
-
max_score = max(sc for _, sc in results)
|
|
643
|
-
if max_score > 0:
|
|
644
|
-
results = [(fid, sc / max_score) for fid, sc in results]
|
|
645
|
-
results.sort(key=lambda x: (-x[1], x[0]))
|
|
646
|
-
return filter_authorized_results(
|
|
647
|
-
self._db,
|
|
648
|
-
results,
|
|
649
|
-
profile_id,
|
|
650
|
-
include_global=include_global,
|
|
651
|
-
include_shared=include_shared,
|
|
652
|
-
)[:top_k]
|
|
653
|
-
|
|
654
|
-
# Seed activation from direct entity-linked facts (no adjacency cache:
|
|
655
|
-
# mock and lightweight DBs only). Graph intelligence is unavailable on
|
|
656
|
-
# this path by design -- see Phase 7 LLD H-01.
|
|
657
|
-
activation: dict[str, float] = defaultdict(float)
|
|
658
|
-
visited_entities: set[str] = set(canonical_ids)
|
|
659
|
-
use_cache = False
|
|
660
|
-
for eid in canonical_ids:
|
|
661
|
-
for fact in self._db.get_facts_by_entity(
|
|
662
|
-
eid,
|
|
663
|
-
profile_id,
|
|
664
|
-
include_global=include_global,
|
|
665
|
-
include_shared=include_shared,
|
|
666
|
-
):
|
|
667
|
-
activation[fact.fact_id] = max(activation[fact.fact_id], 1.0)
|
|
668
|
-
|
|
669
|
-
frontier = set(activation.keys())
|
|
670
|
-
for hop in range(1, self._max_hops):
|
|
671
|
-
hop_decay = self._decay**hop
|
|
672
|
-
if hop_decay < self._threshold:
|
|
673
|
-
break
|
|
674
|
-
next_frontier: set[str] = set()
|
|
675
|
-
for fid in frontier:
|
|
676
|
-
for edge in self._db.get_edges_for_node(
|
|
677
|
-
fid,
|
|
678
|
-
profile_id,
|
|
679
|
-
include_global=include_global,
|
|
680
|
-
include_shared=include_shared,
|
|
681
|
-
):
|
|
682
|
-
neighbor = edge.target_id if edge.source_id == fid else edge.source_id
|
|
683
|
-
propagated = activation[fid] * self._decay
|
|
684
|
-
if propagated >= self._threshold and propagated > activation.get(
|
|
685
|
-
neighbor, 0.0
|
|
686
|
-
):
|
|
687
|
-
activation[neighbor] = propagated
|
|
688
|
-
next_frontier.add(neighbor)
|
|
689
|
-
new_eids_sql = self._discover_entities(frontier, profile_id, visited_entities)
|
|
690
|
-
for eid in new_eids_sql:
|
|
691
|
-
visited_entities.add(eid)
|
|
692
|
-
for fact in self._db.get_facts_by_entity(
|
|
693
|
-
eid,
|
|
694
|
-
profile_id,
|
|
695
|
-
include_global=include_global,
|
|
696
|
-
include_shared=include_shared,
|
|
697
|
-
):
|
|
698
|
-
if hop_decay > activation.get(fact.fact_id, 0.0):
|
|
699
|
-
activation[fact.fact_id] = hop_decay
|
|
700
|
-
next_frontier.add(fact.fact_id)
|
|
701
|
-
frontier = next_frontier
|
|
702
|
-
if not frontier:
|
|
703
|
-
break
|
|
704
|
-
|
|
705
|
-
# v3.4.1 P2: Community-aware boosting
|
|
706
|
-
if self._graph_metrics and use_cache:
|
|
707
|
-
from collections import Counter as _Counter
|
|
708
|
-
|
|
709
|
-
seed_communities: _Counter = _Counter()
|
|
710
|
-
for eid in canonical_ids:
|
|
711
|
-
for fid in self._entity_to_facts.get(eid, ()):
|
|
712
|
-
m = self._graph_metrics.get(fid, {})
|
|
713
|
-
comm = m.get("community_id")
|
|
714
|
-
if comm is not None:
|
|
715
|
-
seed_communities[comm] += 1
|
|
716
|
-
if seed_communities:
|
|
717
|
-
total_seeds = sum(seed_communities.values())
|
|
718
|
-
for fid in list(activation.keys()):
|
|
719
|
-
m = self._graph_metrics.get(fid, {})
|
|
720
|
-
fact_comm = m.get("community_id")
|
|
721
|
-
if fact_comm is not None and fact_comm in seed_communities:
|
|
722
|
-
boost = min(1.0 + 0.15 * (seed_communities[fact_comm] / total_seeds), 1.3)
|
|
723
|
-
activation[fid] *= boost
|
|
724
|
-
elif fact_comm is not None and fact_comm not in seed_communities:
|
|
725
|
-
activation[fid] *= 0.9 # Mild penalty for unrelated communities
|
|
726
|
-
|
|
727
|
-
# v3.4.1 P3: Contradiction suppression via graph_edges
|
|
728
|
-
if use_cache and activation:
|
|
729
|
-
self._suppress_contradictions(activation, profile_id)
|
|
730
|
-
|
|
731
|
-
# v3.4.1: Score normalization to [0, 1]
|
|
732
|
-
results = [(fid, sc) for fid, sc in activation.items() if sc >= self._threshold]
|
|
733
|
-
if not results:
|
|
734
|
-
return []
|
|
735
|
-
max_score = max(sc for _, sc in results)
|
|
736
|
-
if max_score > 0:
|
|
737
|
-
results = [(fid, sc / max_score) for fid, sc in results]
|
|
738
|
-
results.sort(key=lambda x: (-x[1], x[0]))
|
|
739
|
-
return filter_authorized_results(
|
|
740
|
-
self._db,
|
|
741
|
-
results,
|
|
742
|
-
profile_id,
|
|
743
|
-
include_global=include_global,
|
|
744
|
-
include_shared=include_shared,
|
|
745
|
-
)[:top_k]
|
|
746
|
-
|
|
747
|
-
def score_candidates(
|
|
748
|
-
self,
|
|
749
|
-
query: str,
|
|
750
|
-
candidate_fact_ids: list[str],
|
|
751
|
-
profile_id: str,
|
|
752
|
-
*,
|
|
753
|
-
include_global: bool | None = None,
|
|
754
|
-
include_shared: bool | None = None,
|
|
755
|
-
) -> dict[str, float]:
|
|
756
|
-
"""Serialize access to the scope-keyed graph/entity cache."""
|
|
757
|
-
with self._cache_lock:
|
|
758
|
-
return self._score_candidates_locked(
|
|
759
|
-
query,
|
|
760
|
-
candidate_fact_ids,
|
|
761
|
-
profile_id,
|
|
762
|
-
include_global=include_global,
|
|
763
|
-
include_shared=include_shared,
|
|
764
|
-
)
|
|
765
|
-
|
|
766
|
-
def _score_candidates_locked(
|
|
767
|
-
self,
|
|
768
|
-
query: str,
|
|
769
|
-
candidate_fact_ids: list[str],
|
|
770
|
-
profile_id: str,
|
|
771
|
-
*,
|
|
772
|
-
include_global: bool | None = None,
|
|
773
|
-
include_shared: bool | None = None,
|
|
774
|
-
) -> dict[str, float]:
|
|
775
|
-
"""Score candidate facts by their entity-graph proximity to query entities.
|
|
776
|
-
|
|
777
|
-
V3.4.11 "Signal Enhancer" architecture: instead of returning its own
|
|
778
|
-
independent set of fact_ids (which get outranked by multi-channel facts
|
|
779
|
-
in RRF), this method scores EXISTING candidates from semantic/BM25
|
|
780
|
-
by their graph connectivity to query entities.
|
|
781
|
-
|
|
782
|
-
Research basis: Microsoft GraphRAG DRIFT Search, HippoRAG, Pistis-RAG
|
|
783
|
-
cascaded architecture. Graph signals act as post-retrieval boosters,
|
|
784
|
-
not independent retrievers. Avoids the "weakest link" phenomenon where
|
|
785
|
-
non-overlapping result sets cause rank collapse in RRF fusion.
|
|
786
|
-
|
|
787
|
-
Args:
|
|
788
|
-
query: The user's query string.
|
|
789
|
-
candidate_fact_ids: Fact IDs from semantic/BM25/other channels.
|
|
790
|
-
profile_id: User profile.
|
|
791
|
-
|
|
792
|
-
Returns:
|
|
793
|
-
Dict mapping fact_id → entity_graph score [0, 1].
|
|
794
|
-
Facts with no entity connection return 0.
|
|
795
|
-
Facts directly linked to query entities score ~1.0.
|
|
796
|
-
Facts 1-hop away score ~0.7 (decay factor).
|
|
797
|
-
"""
|
|
798
|
-
if not candidate_fact_ids:
|
|
799
|
-
return {}
|
|
800
|
-
|
|
801
|
-
if include_global is None:
|
|
802
|
-
include_global = bool(getattr(self, "include_global", False))
|
|
803
|
-
if include_shared is None:
|
|
804
|
-
include_shared = bool(getattr(self, "include_shared", False))
|
|
805
|
-
allowed_candidates = authorized_fact_ids(
|
|
806
|
-
self._db,
|
|
807
|
-
candidate_fact_ids,
|
|
808
|
-
profile_id,
|
|
809
|
-
include_global=include_global,
|
|
810
|
-
include_shared=include_shared,
|
|
811
|
-
)
|
|
812
|
-
if not allowed_candidates:
|
|
813
|
-
return {}
|
|
814
|
-
|
|
815
|
-
raw_entities = extract_query_entities(query)
|
|
816
|
-
if not raw_entities:
|
|
817
|
-
return {}
|
|
818
|
-
|
|
819
|
-
self._ensure_adjacency(
|
|
820
|
-
profile_id,
|
|
821
|
-
include_global=include_global,
|
|
822
|
-
include_shared=include_shared,
|
|
823
|
-
)
|
|
824
|
-
canonical_ids = self._resolve_entities(raw_entities, profile_id)
|
|
825
|
-
if not canonical_ids:
|
|
826
|
-
return {}
|
|
827
|
-
|
|
828
|
-
# The same walk as search(), over the same snapshot. This method used
|
|
829
|
-
# to carry its own copy of the loop, which is how the two drifted: the
|
|
830
|
-
# community bias here has never applied search()'s outsider penalty, and
|
|
831
|
-
# the only record of that was the absence of six lines.
|
|
832
|
-
snapshot = getattr(self, "_snapshot", None)
|
|
833
|
-
if snapshot is None or not snapshot.node_count:
|
|
834
|
-
return {}
|
|
835
|
-
activation_result = spreading.activate(
|
|
836
|
-
snapshot,
|
|
837
|
-
canonical_ids,
|
|
838
|
-
decay=self._decay,
|
|
839
|
-
threshold=self._threshold,
|
|
840
|
-
max_hops=self._max_hops,
|
|
841
|
-
)
|
|
842
|
-
spreading.apply_community_bias(
|
|
843
|
-
activation_result.scores,
|
|
844
|
-
snapshot,
|
|
845
|
-
canonical_ids,
|
|
846
|
-
# Re-scoring another channel's candidates, so a fact outside every
|
|
847
|
-
# seed community is not damped -- see apply_community_bias.
|
|
848
|
-
penalise_outsiders=False,
|
|
849
|
-
)
|
|
850
|
-
activation = {
|
|
851
|
-
fid: float(activation_result.scores[idx])
|
|
852
|
-
for fid, idx in snapshot.node_index.items()
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
# Extract scores ONLY for the candidate set, normalize to [0, 1]
|
|
856
|
-
candidate_set = allowed_candidates
|
|
857
|
-
scored = {fid: activation.get(fid, 0.0) for fid in candidate_set}
|
|
858
|
-
|
|
859
|
-
max_score = max(scored.values()) if scored else 0
|
|
860
|
-
if max_score > 0:
|
|
861
|
-
scored = {fid: sc / max_score for fid, sc in scored.items()}
|
|
862
|
-
|
|
863
|
-
return scored
|
|
864
|
-
|
|
865
|
-
def _suppress_contradictions(
|
|
866
|
-
self,
|
|
867
|
-
activation: dict[str, float],
|
|
868
|
-
profile_id: str,
|
|
869
|
-
) -> None:
|
|
870
|
-
"""P3: Penalize older fact in contradiction pairs, heavy-penalize superseded.
|
|
871
|
-
|
|
872
|
-
Uses graph_edges (edge_type CHECK includes 'contradiction', 'supersedes').
|
|
873
|
-
"""
|
|
874
|
-
candidate_ids = list(activation.keys())
|
|
875
|
-
if not candidate_ids:
|
|
876
|
-
return
|
|
877
|
-
try:
|
|
878
|
-
placeholders = ",".join("?" * len(candidate_ids))
|
|
879
|
-
sql = (
|
|
880
|
-
"SELECT source_id, target_id, edge_type FROM graph_edges "
|
|
881
|
-
"WHERE profile_id = ? AND edge_type IN ('contradiction', 'supersedes') "
|
|
882
|
-
"AND (source_id IN (" + placeholders + ") "
|
|
883
|
-
"OR target_id IN (" + placeholders + "))"
|
|
884
|
-
)
|
|
885
|
-
rows = self._db.execute(sql, (profile_id, *candidate_ids, *candidate_ids))
|
|
886
|
-
edges = [dict(r) for r in rows]
|
|
887
|
-
if not edges:
|
|
888
|
-
return
|
|
889
|
-
|
|
890
|
-
# Batch load created_at for involved facts
|
|
891
|
-
involved = set()
|
|
892
|
-
for e in edges:
|
|
893
|
-
involved.add(e["source_id"])
|
|
894
|
-
involved.add(e["target_id"])
|
|
895
|
-
involved = involved & set(candidate_ids)
|
|
896
|
-
if not involved:
|
|
897
|
-
return
|
|
898
|
-
ph2 = ",".join("?" * len(involved))
|
|
899
|
-
ts_rows = self._db.execute(
|
|
900
|
-
"SELECT fact_id, created_at FROM atomic_facts "
|
|
901
|
-
"WHERE fact_id IN (" + ph2 + ") AND profile_id = ?",
|
|
902
|
-
(*involved, profile_id),
|
|
903
|
-
)
|
|
904
|
-
ts_map = {dict(r)["fact_id"]: dict(r).get("created_at", "") for r in ts_rows}
|
|
905
|
-
|
|
906
|
-
for e in edges:
|
|
907
|
-
src, tgt, etype = e["source_id"], e["target_id"], e["edge_type"]
|
|
908
|
-
if etype == "supersedes" and src in activation:
|
|
909
|
-
activation[src] *= 0.3 # Heavy penalty: this fact was replaced
|
|
910
|
-
elif etype == "contradiction":
|
|
911
|
-
src_ts = ts_map.get(src, "")
|
|
912
|
-
tgt_ts = ts_map.get(tgt, "")
|
|
913
|
-
if src_ts and tgt_ts:
|
|
914
|
-
older = src if src_ts < tgt_ts else tgt
|
|
915
|
-
if older in activation:
|
|
916
|
-
activation[older] *= 0.5
|
|
917
|
-
except Exception as exc:
|
|
918
|
-
logger.debug("Contradiction suppression failed: %s", exc)
|
|
919
|
-
|
|
920
|
-
def _resolve_entities(self, raw: list[str], profile_id: str) -> list[str]:
|
|
921
|
-
"""Resolve local and visible cross-profile canonical entity IDs."""
|
|
922
|
-
ids: list[str] = []
|
|
923
|
-
seen: set[str] = set()
|
|
924
|
-
if self._resolver is not None:
|
|
925
|
-
for eid in self._resolver.resolve(raw, profile_id).values():
|
|
926
|
-
if eid not in seen:
|
|
927
|
-
seen.add(eid)
|
|
928
|
-
ids.append(eid)
|
|
929
|
-
else:
|
|
930
|
-
for name in raw:
|
|
931
|
-
ent = self._db.get_entity_by_name(name, profile_id)
|
|
932
|
-
if ent and ent.entity_id not in seen:
|
|
933
|
-
seen.add(ent.entity_id)
|
|
934
|
-
ids.append(ent.entity_id)
|
|
935
|
-
|
|
936
|
-
# Entity UUIDs are profile-local. Supplement local resolution with
|
|
937
|
-
# same-name/alias IDs that are actually referenced by visible facts.
|
|
938
|
-
names = [name.strip().lower() for name in raw if name.strip()]
|
|
939
|
-
if names and self._visible_fact_ids and self._entity_to_facts:
|
|
940
|
-
placeholders = ",".join("?" for _ in names)
|
|
941
|
-
try:
|
|
942
|
-
rows = self._db.execute(
|
|
943
|
-
"SELECT entity_id FROM canonical_entities "
|
|
944
|
-
f"WHERE LOWER(canonical_name) IN ({placeholders}) "
|
|
945
|
-
"UNION SELECT entity_id FROM entity_aliases "
|
|
946
|
-
f"WHERE LOWER(alias) IN ({placeholders})",
|
|
947
|
-
(*names, *names),
|
|
948
|
-
)
|
|
949
|
-
except Exception:
|
|
950
|
-
rows = []
|
|
951
|
-
visible_entity_ids = set(self._entity_to_facts)
|
|
952
|
-
for row in rows:
|
|
953
|
-
entity_id = str(dict(row)["entity_id"])
|
|
954
|
-
if entity_id in visible_entity_ids and entity_id not in seen:
|
|
955
|
-
seen.add(entity_id)
|
|
956
|
-
ids.append(entity_id)
|
|
957
|
-
return ids
|
|
958
|
-
|
|
959
|
-
def _discover_entities(
|
|
960
|
-
self,
|
|
961
|
-
fact_ids: set[str],
|
|
962
|
-
profile_id: str,
|
|
963
|
-
visited: set[str],
|
|
964
|
-
) -> list[str]:
|
|
965
|
-
"""Find new canonical entity IDs referenced by a set of facts."""
|
|
966
|
-
new: list[str] = []
|
|
967
|
-
seen = set(visited)
|
|
968
|
-
allowed_fact_ids = authorized_fact_ids(
|
|
969
|
-
self._db,
|
|
970
|
-
fact_ids,
|
|
971
|
-
profile_id,
|
|
972
|
-
include_global=bool(getattr(self, "include_global", False)),
|
|
973
|
-
include_shared=bool(getattr(self, "include_shared", False)),
|
|
974
|
-
)
|
|
975
|
-
for fid in allowed_fact_ids:
|
|
976
|
-
rows = self._db.execute(
|
|
977
|
-
"SELECT canonical_entities_json FROM atomic_facts WHERE fact_id = ?",
|
|
978
|
-
(fid,),
|
|
979
|
-
)
|
|
980
|
-
if not rows:
|
|
981
|
-
continue
|
|
982
|
-
raw = dict(rows[0]).get("canonical_entities_json")
|
|
983
|
-
if not raw:
|
|
984
|
-
continue
|
|
985
|
-
try:
|
|
986
|
-
for eid in json.loads(raw):
|
|
987
|
-
if eid not in seen:
|
|
988
|
-
seen.add(eid)
|
|
989
|
-
new.append(eid)
|
|
990
|
-
except (ValueError, TypeError):
|
|
991
|
-
continue
|
|
992
|
-
return new
|
|
993
|
-
|
|
994
|
-
# v3.4.5: CozoDB-backed search (Sprint 2)
|