superlocalmemory 4.0.10 → 4.1.2

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 (145) hide show
  1. package/.claude-plugin/marketplace.json +12 -2
  2. package/CHANGELOG.md +244 -0
  3. package/README.md +40 -75
  4. package/package.json +6 -3
  5. package/plugin/.claude-plugin/plugin.json +2 -2
  6. package/plugin/CLAUDE.md +3 -3
  7. package/plugin/agents/slm-governance-advisor.md +1 -1
  8. package/plugin/agents/slm-loop-runner.md +4 -4
  9. package/plugin/agents/slm-memory-advisor.md +1 -1
  10. package/plugin/agents/slm-optimize-advisor.md +1 -1
  11. package/plugin/requirements.txt +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 +2 -2
  17. package/plugin/skills/slm-mesh/SKILL.md +1 -1
  18. package/plugin/skills/slm-profile/SKILL.md +5 -5
  19. package/plugin/skills/slm-recall/SKILL.md +102 -15
  20. package/plugin/skills/slm-remember/SKILL.md +35 -3
  21. package/plugin/skills/slm-scope/SKILL.md +1 -1
  22. package/plugin/skills/slm-session/SKILL.md +29 -3
  23. package/plugin/skills/slm-status/SKILL.md +1 -1
  24. package/plugin-src/rules/AGENTS.md +16 -8
  25. package/plugin-src/skills/slm-cache/SKILL.md +1 -1
  26. package/plugin-src/skills/slm-compress/SKILL.md +1 -1
  27. package/plugin-src/skills/slm-governance/SKILL.md +1 -1
  28. package/plugin-src/skills/slm-graph/SKILL.md +1 -1
  29. package/plugin-src/skills/slm-loop/SKILL.md +2 -2
  30. package/plugin-src/skills/slm-mesh/SKILL.md +1 -1
  31. package/plugin-src/skills/slm-profile/SKILL.md +5 -5
  32. package/plugin-src/skills/slm-recall/SKILL.md +102 -15
  33. package/plugin-src/skills/slm-remember/SKILL.md +35 -3
  34. package/plugin-src/skills/slm-scope/SKILL.md +1 -1
  35. package/plugin-src/skills/slm-session/SKILL.md +29 -3
  36. package/plugin-src/skills/slm-status/SKILL.md +1 -1
  37. package/pyproject.toml +1 -1
  38. package/src/superlocalmemory/__init__.py +1 -1
  39. package/src/superlocalmemory/cli/commands.py +357 -18
  40. package/src/superlocalmemory/cli/daemon.py +30 -0
  41. package/src/superlocalmemory/cli/db_migrate.py +71 -1
  42. package/src/superlocalmemory/cli/gdpr_cmd.py +15 -2
  43. package/src/superlocalmemory/cli/main.py +24 -2
  44. package/src/superlocalmemory/code_graph/database.py +44 -0
  45. package/src/superlocalmemory/compliance/gdpr.py +449 -39
  46. package/src/superlocalmemory/core/admission.py +231 -11
  47. package/src/superlocalmemory/core/backend_orchestrator.py +190 -84
  48. package/src/superlocalmemory/core/config.py +90 -11
  49. package/src/superlocalmemory/core/consolidation_engine.py +34 -0
  50. package/src/superlocalmemory/core/engine.py +140 -11
  51. package/src/superlocalmemory/core/graph_analyzer.py +76 -112
  52. package/src/superlocalmemory/core/graph_metrics.py +597 -0
  53. package/src/superlocalmemory/core/graph_pruner.py +121 -0
  54. package/src/superlocalmemory/core/maintenance_scheduler.py +205 -0
  55. package/src/superlocalmemory/core/mode_capability.py +111 -0
  56. package/src/superlocalmemory/core/ollama_validator.py +315 -0
  57. package/src/superlocalmemory/core/projection_drain.py +380 -0
  58. package/src/superlocalmemory/core/recall_pipeline.py +390 -3
  59. package/src/superlocalmemory/core/recall_worker.py +6 -3
  60. package/src/superlocalmemory/core/scale_autopromote.py +196 -0
  61. package/src/superlocalmemory/core/scale_engine.py +16 -2
  62. package/src/superlocalmemory/core/score_contract.py +21 -1
  63. package/src/superlocalmemory/core/session_identity.py +85 -0
  64. package/src/superlocalmemory/core/status_contract.py +108 -0
  65. package/src/superlocalmemory/core/worker_pool.py +4 -4
  66. package/src/superlocalmemory/core/working_memory.py +288 -0
  67. package/src/superlocalmemory/encoding/cognitive_consolidator.py +36 -6
  68. package/src/superlocalmemory/encoding/context_generator.py +1 -1
  69. package/src/superlocalmemory/encoding/entity_resolver.py +38 -0
  70. package/src/superlocalmemory/encoding/fact_extractor.py +18 -14
  71. package/src/superlocalmemory/encoding/prospective_markers.py +262 -0
  72. package/src/superlocalmemory/encoding/type_router.py +12 -12
  73. package/src/superlocalmemory/evolution/mutation_generator.py +30 -4
  74. package/src/superlocalmemory/graph/cozo_adjacency.py +122 -0
  75. package/src/superlocalmemory/graph/cozo_backend.py +103 -138
  76. package/src/superlocalmemory/hooks/portable_kit.py +10 -2
  77. package/src/superlocalmemory/learning/bandit.py +43 -0
  78. package/src/superlocalmemory/learning/consolidation_worker.py +54 -0
  79. package/src/superlocalmemory/learning/database.py +60 -3
  80. package/src/superlocalmemory/learning/entity_compiler.py +21 -58
  81. package/src/superlocalmemory/learning/feedback.py +3 -1
  82. package/src/superlocalmemory/learning/outcomes.py +47 -16
  83. package/src/superlocalmemory/learning/pattern_miner.py +28 -3
  84. package/src/superlocalmemory/learning/pattern_miner_constants.py +43 -0
  85. package/src/superlocalmemory/learning/pcos.py +291 -0
  86. package/src/superlocalmemory/learning/reward_from_outcomes.py +365 -0
  87. package/src/superlocalmemory/learning/reward_proxy.py +100 -10
  88. package/src/superlocalmemory/learning/signal_kinds.py +79 -0
  89. package/src/superlocalmemory/mcp/profiles.py +14 -2
  90. package/src/superlocalmemory/mcp/tools_active.py +2 -1
  91. package/src/superlocalmemory/mcp/tools_core.py +31 -3
  92. package/src/superlocalmemory/mcp/tools_v28.py +20 -1
  93. package/src/superlocalmemory/parameterization/pattern_extractor.py +14 -1
  94. package/src/superlocalmemory/parameterization/soft_prompt_generator.py +98 -0
  95. package/src/superlocalmemory/retrieval/bm25_channel.py +64 -3
  96. package/src/superlocalmemory/retrieval/channel_status.py +117 -0
  97. package/src/superlocalmemory/retrieval/engine.py +106 -11
  98. package/src/superlocalmemory/retrieval/entity_channel.py +210 -256
  99. package/src/superlocalmemory/retrieval/graph_adjacency.py +219 -0
  100. package/src/superlocalmemory/retrieval/scope_policy.py +20 -0
  101. package/src/superlocalmemory/retrieval/semantic_channel.py +47 -5
  102. package/src/superlocalmemory/retrieval/spreading.py +288 -0
  103. package/src/superlocalmemory/server/api.py +24 -5
  104. package/src/superlocalmemory/server/bandit_loops.py +17 -1
  105. package/src/superlocalmemory/server/rbac_enforce.py +26 -6
  106. package/src/superlocalmemory/server/recall_health.py +87 -10
  107. package/src/superlocalmemory/server/recall_serializer.py +9 -0
  108. package/src/superlocalmemory/server/routes/behavioral.py +75 -10
  109. package/src/superlocalmemory/server/routes/compliance.py +98 -18
  110. package/src/superlocalmemory/server/routes/config_api.py +186 -4
  111. package/src/superlocalmemory/server/routes/evolution.py +178 -0
  112. package/src/superlocalmemory/server/routes/ingest.py +8 -0
  113. package/src/superlocalmemory/server/routes/learning_telemetry.py +2 -1
  114. package/src/superlocalmemory/server/routes/memories.py +49 -7
  115. package/src/superlocalmemory/server/routes/timeline.py +4 -0
  116. package/src/superlocalmemory/server/routes/v3_api.py +191 -15
  117. package/src/superlocalmemory/server/ui.py +20 -4
  118. package/src/superlocalmemory/server/unified_daemon.py +241 -7
  119. package/src/superlocalmemory/storage/_migration_internals.py +54 -2
  120. package/src/superlocalmemory/storage/_schema_version.py +24 -3
  121. package/src/superlocalmemory/storage/database.py +477 -59
  122. package/src/superlocalmemory/storage/embedding_codec.py +71 -0
  123. package/src/superlocalmemory/storage/lineage_retention.py +236 -0
  124. package/src/superlocalmemory/storage/logical_edges.py +43 -2
  125. package/src/superlocalmemory/storage/migration_runner.py +119 -0
  126. package/src/superlocalmemory/storage/migrations/M043_quarantine_display_summaries.py +60 -36
  127. package/src/superlocalmemory/storage/migrations/M044_play_carries_its_own_evidence.py +127 -0
  128. package/src/superlocalmemory/storage/migrations/M045_fact_outcome_score.py +158 -0
  129. package/src/superlocalmemory/storage/migrations/M046_prospective_memory_has_its_own_name.py +620 -0
  130. package/src/superlocalmemory/storage/migrations/M047_fisher_vectors_are_stored_like_every_other_vector.py +306 -0
  131. package/src/superlocalmemory/storage/migrations/M048_upcoming_holds_only_what_is_upcoming.py +207 -0
  132. package/src/superlocalmemory/storage/migrations/M049_a_schema_version_marker_is_one_row.py +201 -0
  133. package/src/superlocalmemory/storage/migrations.py +18 -2
  134. package/src/superlocalmemory/storage/models.py +40 -1
  135. package/src/superlocalmemory/storage/projection_outbox.py +346 -0
  136. package/src/superlocalmemory/storage/retention_policy.py +860 -0
  137. package/src/superlocalmemory/storage/schema.py +35 -1
  138. package/src/superlocalmemory/storage/write_coordinator.py +19 -2
  139. package/src/superlocalmemory/trust/scorer.py +43 -1
  140. package/src/superlocalmemory/ui/index.html +9 -18
  141. package/src/superlocalmemory/ui/js/event-delegation.js +12 -1
  142. package/src/superlocalmemory/ui/js/od-health.js +28 -6
  143. package/src/superlocalmemory/ui/js/od-memories.js +19 -0
  144. package/src/superlocalmemory/ui/js/od-settings.js +87 -1
  145. package/src/superlocalmemory/ui/js/recall-lab.js +78 -3
@@ -156,6 +156,16 @@ from superlocalmemory.storage.migrations import (
156
156
  from superlocalmemory.storage.migrations import (
157
157
  M043_quarantine_display_summaries as _M043,
158
158
  )
159
+ from superlocalmemory.storage.migrations import (
160
+ M044_play_carries_its_own_evidence as _M044,
161
+ )
162
+ from superlocalmemory.storage.migrations import (
163
+ M045_fact_outcome_score as _M045,
164
+ M046_prospective_memory_has_its_own_name as _M046,
165
+ M047_fisher_vectors_are_stored_like_every_other_vector as _M047,
166
+ M048_upcoming_holds_only_what_is_upcoming as _M048,
167
+ M049_a_schema_version_marker_is_one_row as _M049,
168
+ )
159
169
 
160
170
  # Emit under the runner's logger name so operational log filters that key on
161
171
  # "superlocalmemory.storage.migration_runner" keep matching after this split.
@@ -207,6 +217,12 @@ _MODULES = {
207
217
  _M041.NAME: _M041,
208
218
  _M042.NAME: _M042,
209
219
  _M043.NAME: _M043,
220
+ _M044.NAME: _M044,
221
+ _M045.NAME: _M045,
222
+ _M046.NAME: _M046,
223
+ _M047.NAME: _M047,
224
+ _M048.NAME: _M048,
225
+ _M049.NAME: _M049,
210
226
  }
211
227
 
212
228
  # Exact historical DDL fingerprints whose resulting schema is intentionally
@@ -245,9 +261,24 @@ def _ddl_hash(ddl: str) -> str:
245
261
  return hashlib.sha256(ddl.encode("utf-8")).hexdigest()
246
262
 
247
263
 
264
+ #: How long a migration waits for a database another process is holding.
265
+ #:
266
+ #: Without this, SQLite raises SQLITE_BUSY the instant a write lock is taken,
267
+ #: and a migration that runs while the daemon happens to be writing is recorded
268
+ #: as failed rather than retried. A migration that rebuilds a table takes an
269
+ #: exclusive lock, so it is exactly the one most likely to collide — and its
270
+ #: failure leaves an upgrade wedged until someone notices.
271
+ #:
272
+ #: Fifteen seconds is longer than any single write this codebase performs and
273
+ #: short enough that a genuinely stuck lock still surfaces as a failure rather
274
+ #: than a hang.
275
+ _MIGRATION_BUSY_TIMEOUT_MS = 15_000
276
+
277
+
248
278
  def _connect(db_path: Path) -> sqlite3.Connection:
249
279
  # isolation_level=None → we manage transactions explicitly via DDL.
250
280
  conn = sqlite3.connect(db_path, isolation_level=None)
281
+ conn.execute(f"PRAGMA busy_timeout = {_MIGRATION_BUSY_TIMEOUT_MS};")
251
282
  conn.execute("PRAGMA foreign_keys = OFF;")
252
283
  return conn
253
284
 
@@ -301,6 +332,22 @@ def _delete_log(conn: sqlite3.Connection, name: str) -> None:
301
332
  conn.execute("DELETE FROM migration_log WHERE name = ?", (name,))
302
333
 
303
334
 
335
+ def _why_unmet(mod, conn) -> str:
336
+ """The migration's own account of which check does not hold.
337
+
338
+ A migration may expose ``unmet(conn)`` returning a sentence. Most do not,
339
+ and for those the caller keeps its generic wording. Never raises: this runs
340
+ while reporting a failure and must not become a second one.
341
+ """
342
+ fn = getattr(mod, "unmet", None)
343
+ if not callable(fn):
344
+ return ""
345
+ try:
346
+ return str(fn(conn) or "")
347
+ except Exception: # noqa: BLE001 - a detail string is not worth a crash
348
+ return ""
349
+
350
+
304
351
  def _apply_single(
305
352
  conn: sqlite3.Connection,
306
353
  migration: Migration,
@@ -383,9 +430,12 @@ def _apply_single(
383
430
  try:
384
431
  repair_fn(conn)
385
432
  if not bool(verify_fn(conn)):
433
+ _why = _why_unmet(mod, conn)
386
434
  return (
387
435
  "failed",
388
- f"safe repair did not restore {migration.name}",
436
+ f"safe repair did not restore "
437
+ f"{migration.name}"
438
+ + (f": {_why}" if _why else ""),
389
439
  )
390
440
  _upsert_log(conn, migration.name, ddl_hash, "complete")
391
441
  return (
@@ -451,9 +501,11 @@ def _apply_single(
451
501
  )
452
502
  try:
453
503
  if not bool(verify_fn(conn)):
504
+ _why = _why_unmet(mod, conn)
454
505
  return (
455
506
  "failed",
456
- f"safe repair did not restore {migration.name}",
507
+ f"safe repair did not restore {migration.name}"
508
+ + (f": {_why}" if _why else ""),
457
509
  )
458
510
  except sqlite3.Error as exc:
459
511
  return (
@@ -20,10 +20,31 @@ from __future__ import annotations
20
20
  import sqlite3
21
21
  from pathlib import Path
22
22
 
23
- #: Highest schema_version this runner can write. Matches the trailing serial
24
- #: of the latest migration (M042). Increment when adding new migrations or
23
+ #: Highest schema_version this runner can write. Matches the trailing serial of
24
+ #: the latest migration (M049). Increment when adding new migrations or
25
25
  #: table-level breaking changes.
26
- SUPPORTED_SCHEMA_VERSION: int = 42
26
+ #:
27
+ #: This sat at 42 while M043, M044 and M045 shipped, so for three migrations the
28
+ #: ceiling did not move and nothing prevented an older build from opening a
29
+ #: newer store. That was tolerable only because those three were additive: a
30
+ #: build that did not know about a new column or table simply never read it.
31
+ #:
32
+ #: M046 is not additive. It rebuilds ``atomic_facts`` with a constraint that
33
+ #: rejects the value an older build classifies planned events as, so an older
34
+ #: writer against a migrated store fails its INSERT. The ceiling is what turns
35
+ #: that from a lost memory into a refusal to start, which is why it moves here
36
+ #: and why it moves to the trailing serial rather than to 43.
37
+ #:
38
+ #: M049 is additive — a unique index on ``schema_version`` plus the removal of
39
+ #: the duplicate rows that index could not otherwise be created over — so an
40
+ #: older build could in principle read a store it has touched. The ceiling
41
+ #: still moves, because the convention is "trailing serial, always": the cost of
42
+ #: moving it for an additive migration is an older build declining a store it
43
+ #: could have read, and the cost of NOT moving it for one that turns out not to
44
+ #: be additive is a silent bad write. Those are not comparable, and judging
45
+ #: additivity per migration is exactly the judgement that let it fall three
46
+ #: behind.
47
+ SUPPORTED_SCHEMA_VERSION: int = 49
27
48
 
28
49
 
29
50
  class SchemaVersionError(RuntimeError):