superlocalmemory 4.0.8 → 4.0.9

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 (120) hide show
  1. package/CHANGELOG.md +146 -1
  2. package/README.md +6 -6
  3. package/package.json +1 -1
  4. package/plugin/.claude-plugin/plugin.json +1 -1
  5. package/plugin/CLAUDE.md +3 -3
  6. package/plugin/agents/slm-governance-advisor.md +1 -1
  7. package/plugin/agents/slm-loop-runner.md +1 -1
  8. package/plugin/agents/slm-memory-advisor.md +1 -1
  9. package/plugin/agents/slm-optimize-advisor.md +1 -1
  10. package/plugin/requirements.txt +1 -1
  11. package/plugin/scripts/ensure-venv.sh +1 -1
  12. package/plugin/skills/slm-cache/SKILL.md +1 -1
  13. package/plugin/skills/slm-compress/SKILL.md +1 -1
  14. package/plugin/skills/slm-governance/SKILL.md +1 -1
  15. package/plugin/skills/slm-graph/SKILL.md +1 -1
  16. package/plugin/skills/slm-loop/SKILL.md +1 -1
  17. package/plugin/skills/slm-mesh/SKILL.md +1 -1
  18. package/plugin/skills/slm-profile/SKILL.md +1 -1
  19. package/plugin/skills/slm-recall/SKILL.md +1 -1
  20. package/plugin/skills/slm-remember/SKILL.md +1 -1
  21. package/plugin/skills/slm-scope/SKILL.md +1 -1
  22. package/plugin/skills/slm-session/SKILL.md +1 -1
  23. package/plugin/skills/slm-status/SKILL.md +3 -3
  24. package/plugin-src/rules/AGENTS.md +1 -1
  25. package/plugin-src/skills/slm-status/SKILL.md +2 -2
  26. package/pyproject.toml +1 -1
  27. package/scripts/postinstall.js +4 -0
  28. package/src/superlocalmemory/__init__.py +1 -1
  29. package/src/superlocalmemory/cli/_lazy_init.py +1 -1
  30. package/src/superlocalmemory/cli/commands.py +119 -9
  31. package/src/superlocalmemory/cli/db_migrate.py +0 -2
  32. package/src/superlocalmemory/cli/gdpr_io.py +1 -1
  33. package/src/superlocalmemory/cli/main.py +5 -5
  34. package/src/superlocalmemory/cli/service_installer.py +2 -1
  35. package/src/superlocalmemory/cli/setup_wizard.py +1 -1
  36. package/src/superlocalmemory/core/config.py +41 -7
  37. package/src/superlocalmemory/core/context_cache.py +0 -2
  38. package/src/superlocalmemory/core/engine.py +371 -63
  39. package/src/superlocalmemory/core/evidence_bundle.py +3 -1
  40. package/src/superlocalmemory/core/install_detector.py +131 -0
  41. package/src/superlocalmemory/core/progressive_abstraction.py +1 -1
  42. package/src/superlocalmemory/core/security_primitives.py +3 -6
  43. package/src/superlocalmemory/core/store_pipeline.py +94 -26
  44. package/src/superlocalmemory/core/topic_signature.py +0 -2
  45. package/src/superlocalmemory/core/transactions/concrete_owners.py +15 -8
  46. package/src/superlocalmemory/dynamics/eap_scheduler.py +17 -6
  47. package/src/superlocalmemory/encoding/graph_builder.py +2 -2
  48. package/src/superlocalmemory/encoding/scene_builder.py +8 -2
  49. package/src/superlocalmemory/hooks/adapter_base.py +0 -2
  50. package/src/superlocalmemory/hooks/context_payload.py +0 -2
  51. package/src/superlocalmemory/hooks/portable_kit.py +8 -8
  52. package/src/superlocalmemory/hooks/post_tool_async_hook.py +0 -2
  53. package/src/superlocalmemory/hooks/prewarm_auth.py +0 -2
  54. package/src/superlocalmemory/hooks/user_prompt_hook.py +0 -2
  55. package/src/superlocalmemory/infra/backup.py +44 -8
  56. package/src/superlocalmemory/integrations/bounded_loops_mcp.py +24 -7
  57. package/src/superlocalmemory/learning/arm_catalog.py +0 -2
  58. package/src/superlocalmemory/learning/bandit.py +0 -2
  59. package/src/superlocalmemory/learning/bandit_cache.py +0 -2
  60. package/src/superlocalmemory/learning/dedup_hnsw.py +11 -11
  61. package/src/superlocalmemory/learning/ensemble.py +0 -2
  62. package/src/superlocalmemory/learning/labeler.py +0 -2
  63. package/src/superlocalmemory/learning/legacy_migration.py +0 -2
  64. package/src/superlocalmemory/learning/model_cache.py +0 -2
  65. package/src/superlocalmemory/learning/ranker.py +0 -2
  66. package/src/superlocalmemory/learning/reward_archive.py +6 -1
  67. package/src/superlocalmemory/learning/reward_proxy.py +0 -2
  68. package/src/superlocalmemory/learning/signal_worker.py +0 -2
  69. package/src/superlocalmemory/math/fisher.py +1 -1
  70. package/src/superlocalmemory/math/hopfield.py +4 -1
  71. package/src/superlocalmemory/math/langevin.py +1 -1
  72. package/src/superlocalmemory/math/sheaf.py +7 -3
  73. package/src/superlocalmemory/mcp/cli_fallback.py +1 -1
  74. package/src/superlocalmemory/mcp/profiles.py +1 -1
  75. package/src/superlocalmemory/mcp/server.py +1 -1
  76. package/src/superlocalmemory/mcp/tools_active.py +56 -0
  77. package/src/superlocalmemory/mcp/tools_core.py +1 -1
  78. package/src/superlocalmemory/optimize/cache/manager.py +2 -2
  79. package/src/superlocalmemory/optimize/compress/ccr.py +1 -1
  80. package/src/superlocalmemory/optimize/compress/router.py +1 -1
  81. package/src/superlocalmemory/optimize/proxy/_helpers.py +2 -2
  82. package/src/superlocalmemory/optimize/proxy/server.py +1 -1
  83. package/src/superlocalmemory/optimize/proxy/vertex_surface.py +2 -2
  84. package/src/superlocalmemory/optimize/storage/db.py +2 -2
  85. package/src/superlocalmemory/retrieval/agentic.py +1 -1
  86. package/src/superlocalmemory/retrieval/ann_index.py +9 -2
  87. package/src/superlocalmemory/retrieval/bm25_channel.py +2 -2
  88. package/src/superlocalmemory/retrieval/bridge_discovery.py +2 -2
  89. package/src/superlocalmemory/retrieval/engine.py +272 -43
  90. package/src/superlocalmemory/retrieval/entity_channel.py +1 -1
  91. package/src/superlocalmemory/retrieval/hopfield_channel.py +8 -2
  92. package/src/superlocalmemory/retrieval/profile_channel.py +1 -1
  93. package/src/superlocalmemory/retrieval/quantization_aware_search.py +1 -1
  94. package/src/superlocalmemory/retrieval/remote_reranker.py +2 -2
  95. package/src/superlocalmemory/retrieval/reranker.py +3 -3
  96. package/src/superlocalmemory/retrieval/semantic_channel.py +3 -3
  97. package/src/superlocalmemory/retrieval/spreading_activation.py +8 -8
  98. package/src/superlocalmemory/retrieval/strategy.py +94 -0
  99. package/src/superlocalmemory/retrieval/temporal_channel.py +167 -10
  100. package/src/superlocalmemory/retrieval/temporal_validity_filter.py +1 -1
  101. package/src/superlocalmemory/retrieval/vector_store.py +88 -10
  102. package/src/superlocalmemory/server/recall_serializer.py +10 -0
  103. package/src/superlocalmemory/server/routes/brain.py +2 -2
  104. package/src/superlocalmemory/server/routes/prewarm.py +4 -4
  105. package/src/superlocalmemory/server/unified_daemon.py +459 -7
  106. package/src/superlocalmemory/storage/_schema_version.py +46 -3
  107. package/src/superlocalmemory/storage/backup.py +531 -0
  108. package/src/superlocalmemory/storage/database.py +11 -4
  109. package/src/superlocalmemory/storage/embedding_codec.py +129 -0
  110. package/src/superlocalmemory/storage/embedding_migrator.py +5 -3
  111. package/src/superlocalmemory/storage/migration_runner.py +142 -2
  112. package/src/superlocalmemory/storage/migrations/__init__.py +1 -1
  113. package/src/superlocalmemory/storage/migrations.py +15 -1
  114. package/src/superlocalmemory/storage/models.py +7 -0
  115. package/src/superlocalmemory/storage/quantized_store.py +4 -2
  116. package/src/superlocalmemory/summaries/session_summary.py +1 -1
  117. package/src/superlocalmemory/ui/css/legacy-dashboard.css +1 -1
  118. package/src/superlocalmemory/ui/css/neural-glass.css +1 -1
  119. package/src/superlocalmemory/ui/js/core.js +1 -1
  120. package/src/superlocalmemory/ui/js/od-brain.js +1 -1
@@ -1147,7 +1147,7 @@ def _cmd_context_dispatch(args: Namespace) -> None:
1147
1147
 
1148
1148
 
1149
1149
  def _agents_md_source_factory():
1150
- """Return a callable that reads the WP-05 AGENTS.md content, or None on failure.
1150
+ """Return a callable that reads the bundled AGENTS.md content, or None on failure.
1151
1151
 
1152
1152
  Source: plugin-src/rules/AGENTS.md (relative to package root).
1153
1153
  Gracefully skips if absent — never fails the MCP write.
@@ -1168,7 +1168,7 @@ def _agents_md_source_factory():
1168
1168
  if candidate.exists():
1169
1169
  return candidate.read_text(encoding="utf-8")
1170
1170
  logger.warning(
1171
- "WP-05 AGENTS.md is not bundled — skipping AGENTS.md write"
1171
+ "AGENTS.md is not bundled in this distribution — skipping AGENTS.md write"
1172
1172
  )
1173
1173
  return None
1174
1174
 
@@ -1178,15 +1178,15 @@ def _agents_md_source_factory():
1178
1178
  def cmd_connect(args: Namespace) -> None:
1179
1179
  """Configure IDE integrations.
1180
1180
 
1181
- Dispatch priority (WP-08):
1181
+ Dispatch priority:
1182
1182
  1. ``slm connect <ide>`` where ide ∈ IDE_MATRIX → portable_kit.connect_ide
1183
- (MCP-wiring + AGENTS.md; includes claude-code short-circuit to WP-06).
1183
+ (MCP-wiring + AGENTS.md; claude-code short-circuits to the plugin pointer).
1184
1184
  2. ``--cross-platform`` / ``--disable`` → LLD-05 CrossPlatformConnector.
1185
1185
  3. Bare ``slm connect`` / ``--list`` → legacy IDEConnector (markdown-rules).
1186
1186
  """
1187
1187
  ide_arg = getattr(args, "ide", None)
1188
1188
 
1189
- # WP-08: intercept known IDE_MATRIX ids before legacy branches (CRIT-1)
1189
+ # Intercept known IDE_MATRIX ids before legacy branches (critical: must run first)
1190
1190
  if ide_arg is not None:
1191
1191
  from superlocalmemory.hooks.portable_kit import (
1192
1192
  IDE_MATRIX,
@@ -1922,7 +1922,7 @@ def cmd_status(args: Namespace) -> None:
1922
1922
  ])
1923
1923
  return
1924
1924
 
1925
- # WP-02 D8: canonical key set — db_size_mb always present (0.0 if absent).
1925
+ # canonical key set — db_size_mb always present (0.0 if absent).
1926
1926
  db_size_mb = 0.0
1927
1927
  if config.db_path.exists():
1928
1928
  db_size_mb = round(config.db_path.stat().st_size / 1024 / 1024, 2)
@@ -2376,6 +2376,52 @@ def cmd_help(args: Namespace) -> None:
2376
2376
  print("Docs: https://superlocalmemory.com")
2377
2377
 
2378
2378
 
2379
+ def _migration_error_logs() -> list:
2380
+ """Return a sorted list of migration-error log files in the SLM home dir.
2381
+
2382
+ Returns an empty list when none exist or when the directory is not readable.
2383
+ """
2384
+ try:
2385
+ from superlocalmemory.core.config import SLMConfig
2386
+ from superlocalmemory.infra.data_root import canonical_data_root
2387
+ from superlocalmemory.storage.models import Mode
2388
+
2389
+ # The daemon writes this log beside the memory database it was actually
2390
+ # configured with, which is not necessarily the canonical data root —
2391
+ # any of SLM_DATA_DIR / SL_MEMORY_PATH / SLM_HOME can move it. Globbing
2392
+ # only the canonical root reported "clean" while the log sat unread in
2393
+ # the real directory. Search both, de-duplicated.
2394
+ roots = {canonical_data_root()}
2395
+ try:
2396
+ cfg = SLMConfig.for_mode(Mode.A)
2397
+ db = getattr(cfg, "memory_db_path", None) or getattr(cfg, "db_path", None)
2398
+ if db:
2399
+ roots.add(pathlib.Path(db).parent)
2400
+ except Exception:
2401
+ pass
2402
+
2403
+ found: list = []
2404
+ for root in roots:
2405
+ try:
2406
+ found.extend(root.glob("migration-error-*.log"))
2407
+ except OSError:
2408
+ continue
2409
+ return sorted(set(found))
2410
+ except Exception:
2411
+ return []
2412
+
2413
+
2414
+ def _detect_all_installs() -> list:
2415
+ """Thin shim so cmd_doctor can be tested without importing install_detector."""
2416
+ try:
2417
+ from superlocalmemory.core.install_detector import (
2418
+ _detect_all_installs as _real,
2419
+ )
2420
+ return _real()
2421
+ except Exception:
2422
+ return []
2423
+
2424
+
2379
2425
  def cmd_doctor(args: Namespace) -> None:
2380
2426
  """Comprehensive pre-flight check — verify everything works.
2381
2427
 
@@ -2728,7 +2774,7 @@ def cmd_doctor(args: Namespace) -> None:
2728
2774
  else:
2729
2775
  _check("Database", "PASS", "not yet created (will initialize on first use)")
2730
2776
 
2731
- # 11. PEP 668 advisory — WP-07: detect EXTERNALLY-MANAGED marker and
2777
+ # 11. PEP 668 advisory: detect EXTERNALLY-MANAGED marker and
2732
2778
  # recommend pipx when the system Python is managed by the OS package
2733
2779
  # manager (e.g. Homebrew, Debian/Ubuntu, Fedora 38+).
2734
2780
  try:
@@ -2782,6 +2828,70 @@ def cmd_doctor(args: Namespace) -> None:
2782
2828
  except Exception as _cr_exc:
2783
2829
  _check("Component registry", "WARN", f"probe failed: {_cr_exc}")
2784
2830
 
2831
+ # 13. Install version convergence — detect all copies of SLM on this machine
2832
+ # and warn when they are at different versions. Silent divergence is the
2833
+ # most common source of unexpected behaviour after an upgrade.
2834
+ try:
2835
+ _installs = _detect_all_installs() # shim defined above cmd_doctor
2836
+ _versions = {i["version"] for i in _installs}
2837
+ if not _installs:
2838
+ _check(
2839
+ "install_versions",
2840
+ "PASS",
2841
+ "No additional SLM installs detected on this machine",
2842
+ )
2843
+ elif len(_versions) > 1:
2844
+ _detail = "Version divergence: " + ", ".join(
2845
+ f"{i['type']}={i['version']}" for i in _installs
2846
+ )
2847
+ _check(
2848
+ "install_versions",
2849
+ "WARN",
2850
+ _detail,
2851
+ fix="Upgrade all installs: "
2852
+ "pipx upgrade superlocalmemory | "
2853
+ "pip install -U superlocalmemory (in ~/.slm-venv) | "
2854
+ "npm install -g superlocalmemory@latest",
2855
+ )
2856
+ else:
2857
+ _unified = next(iter(_versions))
2858
+ _types = ", ".join(i["type"] for i in _installs)
2859
+ _check(
2860
+ "install_versions",
2861
+ "PASS",
2862
+ f"All installs at {_unified} ({_types})",
2863
+ )
2864
+ except Exception as _inst_exc: # noqa: BLE001 — never break doctor
2865
+ _check("install_versions", "WARN", f"could not probe installs: {_inst_exc}")
2866
+
2867
+ # 14. Migration error logs — surface any unresolved failure from a previous
2868
+ # upgrade attempt. The daemon writes these and they persist until the
2869
+ # user takes action; doctor is the right place to surface them.
2870
+ try:
2871
+ _err_logs = _migration_error_logs()
2872
+ if _err_logs:
2873
+ _latest = _err_logs[-1]
2874
+ _check(
2875
+ "migration_errors",
2876
+ "FAIL",
2877
+ f"Unresolved migration failure: {_latest.name}",
2878
+ # `--fix` heals models, sqlite-vec and stale locks. It does NOT
2879
+ # re-run a migration or restore a snapshot, so pointing here at
2880
+ # `--fix` sent the user round a loop that could never clear this
2881
+ # check. The log itself carries the restore command.
2882
+ fix=(
2883
+ f"Read {_latest} — it names what failed and, if a snapshot "
2884
+ f"was taken, the exact command to restore it. Restart the "
2885
+ f"daemon to retry the upgrade. Delete the log once resolved."
2886
+ ),
2887
+ )
2888
+ else:
2889
+ # Reporting nothing when clean made "no failures" and "the check
2890
+ # never ran" look identical in the output.
2891
+ _check("migration_errors", "PASS", "no unresolved migration failures")
2892
+ except Exception as _mel_exc: # noqa: BLE001 — never break doctor
2893
+ _check("migration_errors", "WARN", f"could not check error logs: {_mel_exc}")
2894
+
2785
2895
  # 12. Optimize (Surface B) — reads daemon-persisted metrics (≤60s stale).
2786
2896
  info = _gather_optimize_surface_b()
2787
2897
  _enabled = info["enabled"]
@@ -3332,7 +3442,7 @@ def _cmd_init_auto(
3332
3442
  config_exists: bool,
3333
3443
  force: bool,
3334
3444
  ) -> None:
3335
- """WP-07: non-interactive --auto branch for slm init.
3445
+ """Non-interactive --auto branch for slm init.
3336
3446
 
3337
3447
  Best-effort at every step; only exits non-zero when config save fails.
3338
3448
  No TTY required. Does NOT run IDE connect (AC6).
@@ -3394,7 +3504,7 @@ def cmd_init(args: Namespace) -> None:
3394
3504
  slm_data_dir = slm_home()
3395
3505
  config_exists = (slm_data_dir / "config.json").exists()
3396
3506
 
3397
- # WP-07: --auto branch — fully non-interactive, no TTY required (AC6).
3507
+ # --auto branch — fully non-interactive, no TTY required.
3398
3508
  if auto:
3399
3509
  os.environ["SLM_NON_INTERACTIVE"] = "1"
3400
3510
  _cmd_init_auto(args, slm_data_dir, config_exists, force)
@@ -4,8 +4,6 @@
4
4
 
5
5
  """CLI handler for ``slm db migrate``.
6
6
 
7
- LLD reference: ``.backup/active-brain/lld/LLD-06-windows-binary-and-legacy-migration.md``
8
- Section 7.2 (slm db migrate CLI).
9
7
 
10
8
  Thin wrapper over the canonical runner in
11
9
  ``superlocalmemory.storage.migration_runner``. This module owns only
@@ -73,7 +73,7 @@ def _audit_chain_path() -> Path:
73
73
  # ─────────────────────────────────────────────────────────────────────────────
74
74
 
75
75
  # Known gaps in this release — reported honestly so a DPO can plan remediation.
76
- # Gaps C1 and C2 are tracked as open items in the Wave 3 backlog.
76
+ # Gaps C1 and C2 (cross-device erase verification and audit-log replay) remain open.
77
77
  KNOWN_GAPS = [
78
78
  {
79
79
  "ref": "C1",
@@ -134,7 +134,7 @@ def main() -> None:
134
134
  and "--apply" not in sys.argv[2:]
135
135
  )
136
136
 
137
- # WP-07: lazy first-run init — runs after hook/mcp fast-paths so stdout
137
+ # lazy first-run init — runs after hook/mcp fast-paths so stdout
138
138
  # is never polluted on those paths (CRIT-3, MCP JSON-RPC purity).
139
139
  # Guarded: any failure must not crash the CLI (AC4).
140
140
  _is_mcp_cmd = len(sys.argv) >= 2 and sys.argv[1] == "mcp"
@@ -169,7 +169,7 @@ def main() -> None:
169
169
  from superlocalmemory.migrations.v3_4_25_to_v3_4_26 import (
170
170
  migrate_if_safe as _migrate_if_safe,
171
171
  )
172
- # WP-07: route through slm_home() so all 3 env aliases are honoured.
172
+ # route through slm_home() so all 3 env aliases are honoured.
173
173
  from superlocalmemory.cli._lazy_init import slm_home as _slm_home
174
174
  _data = _slm_home()
175
175
  _res = _migrate_if_safe(_data)
@@ -209,7 +209,7 @@ def main() -> None:
209
209
  "--gate", action="store_true",
210
210
  help="Enable PreToolUse gate (experimental — blocks tools until session_init)",
211
211
  )
212
- # WP-07: non-interactive auto setup (pip post-install, CI, scripts).
212
+ # non-interactive auto setup (pip post-install, CI, scripts).
213
213
  init_p.add_argument(
214
214
  "--auto", action="store_true",
215
215
  help="Non-interactive setup: mode A + hooks (no TTY required, for CI/scripts)",
@@ -243,7 +243,7 @@ def main() -> None:
243
243
  "--list", action="store_true", help="List all supported IDEs",
244
244
  )
245
245
  connect_p.add_argument("--json", action="store_true", help="Output structured JSON (agent-native)")
246
- # WP-08 CRIT-1: declare missing flags so cmd_connect can read them without getattr fallback
246
+ # declare missing flags so cmd_connect can read them without getattr fallback
247
247
  connect_p.add_argument(
248
248
  "--here", action="store_true", default=False,
249
249
  help="Write config relative to current working directory (project scope)",
@@ -258,7 +258,7 @@ def main() -> None:
258
258
  )
259
259
  connect_p.add_argument(
260
260
  "--profile", metavar="PROFILE", default=None,
261
- help="Inject SLM_MCP_PROFILE env var into the MCP server block (WP-01)",
261
+ help="Inject SLM_MCP_PROFILE env var into the MCP server block (named profile selection)",
262
262
  )
263
263
  connect_p.add_argument(
264
264
  "--dry-run", action="store_true", dest="dry_run", default=False,
@@ -19,7 +19,6 @@ from __future__ import annotations
19
19
 
20
20
  import logging
21
21
  import os
22
- import plistlib
23
22
  import subprocess
24
23
  import sys
25
24
  from pathlib import Path
@@ -56,6 +55,8 @@ def _macos_plist_path() -> Path:
56
55
 
57
56
 
58
57
  def _macos_plist_content() -> str:
58
+ import plistlib # macOS-only stdlib module; deferred so non-macOS platforms can import this module safely
59
+
59
60
  python = get_python_path()
60
61
  log = get_log_path()
61
62
  err_log = get_error_log_path()
@@ -29,7 +29,7 @@ from typing import Any
29
29
  # Constants
30
30
  # ---------------------------------------------------------------------------
31
31
 
32
- # WP-07: resolve via slm_home() so all 3 env aliases are honoured.
32
+ # resolve via slm_home() so all 3 env aliases are honoured.
33
33
  # Fallback keeps stdlib-only path if the import fails during early bootstrap.
34
34
  def _resolve_slm_home() -> Path:
35
35
  from superlocalmemory.infra.data_root import canonical_data_root
@@ -23,7 +23,7 @@ logger = logging.getLogger(__name__)
23
23
 
24
24
 
25
25
  # ---------------------------------------------------------------------------
26
- # Canonical limits (WP-02 — single source of truth across all surfaces)
26
+ # Canonical limits — single source of truth across all surfaces
27
27
  # ---------------------------------------------------------------------------
28
28
 
29
29
  #: Default number of results returned by recall across MCP, CLI, daemon, and
@@ -387,6 +387,21 @@ class RetrievalConfig:
387
387
  # fail-open — never a per-query LLM call. Kill-switch for tuning.
388
388
  enable_community_context: bool = True
389
389
 
390
+ # Recency query strategy.
391
+ # When False, queries matching present-activity phrases fall through to
392
+ # factual routing — one-line rollback without touching strategy.py.
393
+ enable_recency_strategy: bool = True
394
+ # Strength of the recency prior applied during final-score fusion.
395
+ # 0.0 = no recency bias (restores previous ranking exactly).
396
+ # Consumed by a separate ranking stage; this field makes the knob
397
+ # configurable without further edits to this class.
398
+ recency_prior_strength: float = 0.5
399
+ # A fact written moments ago has no embedding yet, so it scores zero on the
400
+ # semantic channel — the same score a genuinely unrelated fact gets. Inside
401
+ # this window that zero is read as "not computed yet", not as "unrelated".
402
+ write_recency_floor_enabled: bool = True
403
+ write_recency_floor_minutes: float = 60.0
404
+
390
405
 
391
406
  # ---------------------------------------------------------------------------
392
407
  # Math Config
@@ -564,7 +579,26 @@ class HopfieldConfig:
564
579
  max_iterations: int = 1
565
580
  convergence_epsilon: float = 1e-6
566
581
  prefilter_threshold: int = 10_000
567
- prefilter_candidates: int = 1000
582
+ # How many candidates the index hands to this stage. This stage decides final
583
+ # membership, so a fact ranked past this number by the index never reaches it
584
+ # and can never be returned — the size of this pool is a direct limit on which
585
+ # memories are reachable at all.
586
+ #
587
+ #
588
+ # Chosen by measurement against the 2 s recall ceiling, on a 517 MB store:
589
+ # 150 -> p95 998 ms, 0 channel timeouts
590
+ # 300 -> p95 1054 ms, 0
591
+ # 500 -> p95 1140 ms, 0 <- here: 3.3x the reachability of 150 for +142 ms
592
+ # 750 -> p95 1278 ms, 0
593
+ # 1000 -> p95 1947-2737 ms, 2-25 timeouts
594
+ #
595
+ # 1000 is excluded twice over: it breaches the ceiling, and a channel that
596
+ # misses its deadline contributes nothing to fusion — so whether it lands
597
+ # varies with machine load and the same question stops returning the same
598
+ # answer. 500 keeps ~860 ms of headroom, which is several times the observed
599
+ # run-to-run variance, and stays clear of the region where the cost curve
600
+ # turned non-linear for reasons that were never explained.
601
+ prefilter_candidates: int = 500
568
602
  skip_threshold: int = 100_000
569
603
  cache_ttl_seconds: float = 60.0
570
604
 
@@ -1727,7 +1761,7 @@ class SLMConfig:
1727
1761
  embedding_dimension: int = 0,
1728
1762
  ) -> SLMConfig:
1729
1763
  """Create config with mode-appropriate defaults."""
1730
- # WP-07: resolve base dir via slm_home() at call time when not explicit.
1764
+ # resolve base dir via slm_home() at call time when base_dir is not explicit.
1731
1765
  if base_dir is None:
1732
1766
  try:
1733
1767
  from superlocalmemory.cli._lazy_init import slm_home as _slm_home
@@ -1895,7 +1929,7 @@ class SLMConfig:
1895
1929
 
1896
1930
  Returns ``\"b\"`` (the default) if the file doesn't exist.
1897
1931
  """
1898
- # WP-07: resolve via slm_home() at call time when base_dir not explicit.
1932
+ # resolve via slm_home() at call time when base_dir is not explicit.
1899
1933
  if base_dir is None:
1900
1934
  try:
1901
1935
  from superlocalmemory.cli._lazy_init import slm_home as _slm_home
@@ -1913,7 +1947,7 @@ class SLMConfig:
1913
1947
  @staticmethod
1914
1948
  def write_current_mode(mode: str, base_dir: Path | None = None) -> None:
1915
1949
  """Write the current mode letter to ``current_mode``."""
1916
- # WP-07: resolve via slm_home() at call time when base_dir not explicit.
1950
+ # resolve via slm_home() at call time when base_dir is not explicit.
1917
1951
  if base_dir is None:
1918
1952
  try:
1919
1953
  from superlocalmemory.cli._lazy_init import slm_home as _slm_home
@@ -1956,7 +1990,7 @@ class SLMConfig:
1956
1990
  import dataclasses
1957
1991
 
1958
1992
  from superlocalmemory.storage.models import Mode as _M
1959
- # WP-07: resolve via slm_home() at call time when base_dir not explicit.
1993
+ # resolve via slm_home() at call time when base_dir is not explicit.
1960
1994
  if base_dir is None:
1961
1995
  try:
1962
1996
  from superlocalmemory.cli._lazy_init import slm_home as _slm_home
@@ -2031,7 +2065,7 @@ class SLMConfig:
2031
2065
  Called on daemon boot. Idempotent — if ``current_mode`` already
2032
2066
  exists, this is a no-op. Returns True if migration was performed.
2033
2067
  """
2034
- # WP-07: resolve via slm_home() at call time when base_dir not explicit.
2068
+ # resolve via slm_home() at call time when base_dir is not explicit.
2035
2069
  if base_dir is None:
2036
2070
  try:
2037
2071
  from superlocalmemory.cli._lazy_init import slm_home as _slm_home
@@ -4,8 +4,6 @@
4
4
 
5
5
  """Context cache — separate SQLite WAL DB, read-path <10 ms.
6
6
 
7
- LLD reference: `.backup/active-brain/lld/LLD-01-context-cache-and-hot-path-hooks.md`
8
- Section 4.1.
9
7
 
10
8
  Two concerns in one module:
11
9
  - Writer (``ContextCache``) — used by the daemon only. Owns pragmas,