superlocalmemory 4.1.4 → 4.1.6

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 (48) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +68 -0
  3. package/README.md +3 -3
  4. package/package.json +1 -1
  5. package/plugin/.claude-plugin/plugin.json +1 -1
  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 +1 -1
  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 +1 -1
  17. package/plugin/skills/slm-mesh/SKILL.md +2 -2
  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 +2 -2
  23. package/plugin/skills/slm-status/SKILL.md +1 -1
  24. package/plugin-src/rules/AGENTS.md +1 -1
  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 +1 -1
  30. package/plugin-src/skills/slm-mesh/SKILL.md +2 -2
  31. package/plugin-src/skills/slm-profile/SKILL.md +1 -1
  32. package/plugin-src/skills/slm-recall/SKILL.md +1 -1
  33. package/plugin-src/skills/slm-remember/SKILL.md +1 -1
  34. package/plugin-src/skills/slm-scope/SKILL.md +1 -1
  35. package/plugin-src/skills/slm-session/SKILL.md +2 -2
  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/diagnostics_cmd.py +74 -1
  40. package/src/superlocalmemory/cli/main.py +12 -0
  41. package/src/superlocalmemory/core/maintenance_scheduler.py +36 -0
  42. package/src/superlocalmemory/core/remember_runtime.py +12 -1
  43. package/src/superlocalmemory/encoding/fact_extractor.py +7 -3
  44. package/src/superlocalmemory/mcp/session_binding.py +7 -1
  45. package/src/superlocalmemory/reliability/__init__.py +45 -0
  46. package/src/superlocalmemory/reliability/join_liveness.py +301 -0
  47. package/src/superlocalmemory/reliability/prior_distance.py +243 -0
  48. package/src/superlocalmemory/server/routes/backup.py +1 -1
@@ -21,7 +21,7 @@
21
21
  "license": "AGPL-3.0-or-later",
22
22
  "name": "superlocalmemory",
23
23
  "source": "./plugin",
24
- "version": "4.1.4"
24
+ "version": "4.1.6"
25
25
  },
26
26
  {
27
27
  "author": {
@@ -39,7 +39,7 @@
39
39
  "license": "AGPL-3.0-or-later",
40
40
  "name": "superlocalmemory-codex",
41
41
  "source": "./codex-plugin",
42
- "version": "4.1.4"
42
+ "version": "4.1.6"
43
43
  }
44
44
  ]
45
45
  }
package/CHANGELOG.md CHANGED
@@ -5,6 +5,74 @@ All notable changes to SuperLocalMemory will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.1.6] — A learning loop that never learns looks identical to one that works
9
+
10
+ ### Fixed
11
+ - **The engagement-learning loop settled every outcome at neutral, regardless of
12
+ real usage.** `SESSION_ENV_VARS` checked `SLM_SESSION_ID` and `CLAUDE_SESSION_ID`
13
+ but not `CLAUDE_CODE_SESSION_ID` — the variable Claude Code's own MCP subprocess
14
+ actually sets. Every recall from Claude Code fell through to the synthetic
15
+ `mcp:<agent_id>` id, which step 4 of the resolution ladder deliberately excludes
16
+ from ever matching a pending outcome, by design — a real session should never be
17
+ confused with a placeholder. The result: measured on a live store, 6,013 of 6,039
18
+ settled outcomes carried exactly `reward=0.5`, and all 414 bandit arms held
19
+ `alpha == beta` at every play count. Adding the missing name is what closes the
20
+ loop; two test files that had never isolated session resolution from the ambient
21
+ environment were also hardened, since a live Claude Code session now genuinely
22
+ satisfies the check they'd only ever run without.
23
+ - **Auto-captured facts could assert a date nothing in the source text contained.**
24
+ The fact-extraction system prompt taught relative-date resolution with a fixed
25
+ worked example — `'Yesterday' with session date 2024-01-15 becomes '2024-01-14'`
26
+ — sent identically on every extraction call. A smaller local model under
27
+ uncertainty would echo that literal example date back as if it were extracted
28
+ content, rather than resolving against the real conversation date already present
29
+ in the same prompt. Reproduced live and fixed by removing the concrete date from
30
+ the instruction entirely, teaching the same rule without anything to leak.
31
+ Several existing memories carrying this exact signature — including one date
32
+ claim accessed 28 times — were identified and quarantined.
33
+ - **A store that drifted from M048's classification rule stayed unready for up to a
34
+ full maintenance interval (6 hours) after every restart.** The migration itself
35
+ is idempotent and safe to replay — its own `verify()` docstring says so — but the
36
+ migration runner never replays a completed migration, and the periodic
37
+ maintenance cycle that's supposed to reconcile it only runs once every
38
+ `scheduler_interval_minutes`. A restart landing between cycles reported
39
+ `ready=false, migrations=false` with "automatic replay is disabled" and stayed
40
+ that way until the next scheduled tick. A third staggered one-shot startup timer,
41
+ matching the two that already exist for the same reason (cache GC, graph
42
+ metrics), now runs the same reconciliation pass within seconds of boot instead.
43
+
44
+ ## [4.1.5] — Ask whether a feature is working, not whether it is present
45
+
46
+ ### Added
47
+ - **`slm diagnostics reliability`** — two read-only checks that answer a question
48
+ neither a code search nor a call trace can: is a wired feature actually taking
49
+ effect on *your* store?
50
+ - The first asks whether the retrieval learner's posteriors have moved away from
51
+ where they started. A learner that records activity and never shifts its
52
+ distribution looks healthy from every counter it keeps; this reports it plainly.
53
+ - The second asks whether a feature gated on a table or column can run here at
54
+ all, and when it cannot, searches the rest of the store for the data it needs
55
+ and tells you where it is, how much of what is needed it covers, and whether
56
+ connecting it would need a backfill.
57
+ Both are read-only, run in a second, and print what they found in plain language.
58
+ Run it on your own store: it may tell you something you assumed was on is not.
59
+
60
+ ### Fixed
61
+ - **A refused write said only "temporarily unavailable."** Three unrelated causes
62
+ produced that one message — a busy write journal, another process holding the
63
+ writer, and a rejected stale write. They call for different responses, and one of
64
+ them is not a fault at all. The cause is now named, so a log line says which
65
+ happened instead of leaving you to guess.
66
+ - **The Codex and Antigravity plugins still advertised 4.1.3 after 4.1.4 shipped.**
67
+ Their manifests are generated from a shared source and were not regenerated during
68
+ that release, so both surfaces reported a version they were not. All four editor
69
+ surfaces are regenerated and checked against the package version on every release.
70
+ - **The benchmark instructions could not be followed.** The documented command named
71
+ a directory that does not exist and an interpreter path pointing outside the
72
+ project, and the environment it suggested carries an older release — so anyone
73
+ following it measured the wrong code. Corrected, with a check that the interpreter
74
+ you choose has the version you mean to test.
75
+
8
76
  ## [4.1.4] — A busy daemon is not a dead daemon
9
77
 
10
78
  ### Fixed
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  </picture>
6
6
  </p>
7
7
 
8
- <h1 align="center">SuperLocalMemory V4.1.4</h1>
8
+ <h1 align="center">SuperLocalMemory V4.1.6</h1>
9
9
 
10
10
  <h2 align="center">Rent the LLM. Own the memory.</h2>
11
11
 
@@ -27,12 +27,12 @@ guarantee here is stated as a falsifiable invariant, tested under an adversarial
27
27
  negative control, and shipped with the harness that regenerates the evidence:
28
28
  <code>python benchmark/run_all.py --trials 200 --output-dir results/</code>. What each experiment
29
29
  does <em>not</em> exercise is stated too.</p>
30
- <p align="center"><code>v4.1.4</code> — one control plane: <strong>SLM-Mesh</strong> peer coordination · multi-scope memory (personal / shared / global) · profiles · Cache · Compress · 7-layer retrieval · code graph · Entity Explorer · skill evolution · Modes A/B/C · GDPR retention &amp; audit chain · bounded loops — across CLI, MCP, dashboard, the <strong>Claude plugin</strong>, the <strong>Codex add-on</strong>, and documented IDE integrations.<br/>
30
+ <p align="center"><code>v4.1.6</code> — one control plane: <strong>SLM-Mesh</strong> peer coordination · multi-scope memory (personal / shared / global) · profiles · Cache · Compress · 7-layer retrieval · code graph · Entity Explorer · skill evolution · Modes A/B/C · GDPR retention &amp; audit chain · bounded loops — across CLI, MCP, dashboard, the <strong>Claude plugin</strong>, the <strong>Codex add-on</strong>, and documented IDE integrations.<br/>
31
31
  Proxy: <code>slm wrap claude</code> &nbsp;·&nbsp; MCP: add <code>slm_compress</code> to your config &nbsp;·&nbsp; Skill: zero-config</p>
32
32
  <p align="center"><strong>Four public arXiv preprints</strong> · V4: <a href="https://arxiv.org/abs/2608.08253">arXiv:2608.08253</a> · companion archive: <a href="https://zenodo.org/records/21853302">Zenodo 21853302</a> (<a href="https://doi.org/10.5281/zenodo.21853302">DOI 10.5281/zenodo.21853302</a>) · prior preprints: <a href="https://arxiv.org/abs/2603.02240">2603.02240</a> · <a href="https://arxiv.org/abs/2603.14588">2603.14588</a> · <a href="https://arxiv.org/abs/2604.04514">2604.04514</a>.</p>
33
33
 
34
34
  <p align="center">
35
- <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/v4.1.4-Current_Release-2ea44f?style=for-the-badge&logo=checkmarx&logoColor=white" alt="v4.1.4 — Current Release"/></a>
35
+ <a href="CHANGELOG.md"><img src="https://img.shields.io/badge/v4.1.6-Current_Release-2ea44f?style=for-the-badge&logo=checkmarx&logoColor=white" alt="v4.1.6 — Current Release"/></a>
36
36
  <a href="https://arxiv.org/abs/2608.08253"><img src="https://img.shields.io/badge/arXiv-2608.08253-b31b1b?style=for-the-badge&logo=arxiv&logoColor=white" alt="SuperLocalMemory 4.0 paper on arXiv:2608.08253"/></a>
37
37
  <a href="https://zenodo.org/records/21853302"><img src="https://img.shields.io/badge/Zenodo-10.5281%2Fzenodo.21853302-1682D4?style=for-the-badge&logo=zenodo&logoColor=white" alt="V4 paper on Zenodo: 10.5281/zenodo.21853302"/></a>
38
38
  <a href="https://arxiv.org/abs/2603.14588"><img src="https://img.shields.io/badge/arXiv-2603.14588-b31b1b?style=for-the-badge&logo=arxiv&logoColor=white" alt="arXiv Paper"/></a>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "superlocalmemory",
3
- "version": "4.1.4",
3
+ "version": "4.1.6",
4
4
  "description": "Local-first agent memory with MCP and an agent-native CLI. Documented clients include Claude Code, Cursor, and Windsurf.",
5
5
  "keywords": [
6
6
  "ai-memory",
@@ -15,5 +15,5 @@
15
15
  "mcpServers": "./.mcp.json",
16
16
  "name": "superlocalmemory",
17
17
  "repository": "https://github.com/qualixar/superlocalmemory",
18
- "version": "4.1.4"
18
+ "version": "4.1.6"
19
19
  }
package/plugin/CLAUDE.md CHANGED
@@ -1,4 +1,4 @@
1
- <!-- BEGIN SuperLocalMemory v4.1.4 -->
1
+ <!-- BEGIN SuperLocalMemory v4.1.6 -->
2
2
 
3
3
  ## SuperLocalMemory (SLM) — Agent Rules
4
4
 
@@ -39,6 +39,6 @@ slm-recall · slm-remember · slm-session · slm-status · slm-cache · slm-comp
39
39
  ### Subagents
40
40
  slm-memory-advisor (memory decisions, session hygiene, scope/profile guidance) · slm-optimize-advisor (context compression + KV cache) · slm-governance-advisor (scope/roles/compliance/GDPR)
41
41
 
42
- <!-- END SuperLocalMemory v4.1.4 -->
42
+ <!-- END SuperLocalMemory v4.1.6 -->
43
43
 
44
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
44
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -77,4 +77,4 @@ slm-scope · slm-governance · slm-profile · slm-remember · slm-recall
77
77
  # What NOT to do
78
78
  Never session_init twice; never forget without dry-run preview; never store secrets; never bypass role checks; never claim an erasure succeeded without verifying via recall.
79
79
 
80
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
80
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -68,4 +68,4 @@ assessment. The gate is the authority.
68
68
 
69
69
  ---
70
70
 
71
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
71
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -46,4 +46,4 @@ slm-recall · slm-remember · slm-session · slm-scope · slm-profile · slm-gov
46
46
  # What NOT to do
47
47
  Never session_init twice; never forget dry_run=False without reporting preview; never dump a whole file into remember; never invent a memory; never claim "saved" without success:true / clean CLI exit; never bypass scope or governance restrictions.
48
48
 
49
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
49
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -41,4 +41,4 @@ slm-compress · slm-cache · slm-status · slm-profile
41
41
  # What NOT to do
42
42
  Never compress code-for-edit/JSON-to-parse/<500 chars; never store secrets/ccr_ids; never let optimize failure block/alter the task; never claim a specific savings %; never carry ccr_ids across profile switches.
43
43
 
44
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
44
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -1 +1 @@
1
- superlocalmemory==4.1.4
1
+ superlocalmemory==4.1.6
@@ -145,4 +145,4 @@ These subcommands control daemon-level cache settings. They do not read or write
145
145
 
146
146
  ---
147
147
 
148
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
148
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -147,4 +147,4 @@ Content over 1 MB (1 000 000 bytes UTF-8) is processed but `reversible` is force
147
147
 
148
148
  ---
149
149
 
150
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
150
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -245,4 +245,4 @@ Before running any destructive operation (`forget`, `compact_memories`):
245
245
 
246
246
  ---
247
247
 
248
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
248
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -312,4 +312,4 @@ profile. See `slm-profile` for the full profile switching workflow.
312
312
 
313
313
  ---
314
314
 
315
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
315
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -96,4 +96,4 @@ paused, name the approval needed; when errored, quote the short detail.
96
96
 
97
97
  ---
98
98
 
99
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
99
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -97,7 +97,7 @@ mesh_send(to=target_id, message="I'm starting work on auth/handler.py — please
97
97
  mesh_send(to="broadcast", message="Deploying to staging in 5 minutes")
98
98
 
99
99
  # Message all sessions working in the same project
100
- mesh_send(to="project:/Users/me/myproject", message="Tests are green on main")
100
+ mesh_send(to="project:~/myproject", message="Tests are green on main")
101
101
  ```
102
102
 
103
103
  **4 KB message cap.** For large payloads (diffs, file contents), write to a file
@@ -279,4 +279,4 @@ mesh availability.
279
279
 
280
280
  ---
281
281
 
282
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
282
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -146,4 +146,4 @@ Name them differently in your MCP config (e.g. `superlocalmemory-personal` and
146
146
 
147
147
  ---
148
148
 
149
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
149
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -323,4 +323,4 @@ before recalling, then switch back. See `slm-profile` for workspace switching.
323
323
 
324
324
  ---
325
325
 
326
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
326
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -270,4 +270,4 @@ different workspace, use `switch_profile` first. See `slm-profile`.
270
270
 
271
271
  ---
272
272
 
273
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
273
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -173,4 +173,4 @@ to review the impact. See `slm-remember` for the full deletion discipline.
173
173
 
174
174
  ---
175
175
 
176
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
176
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -52,7 +52,7 @@ recalls or remembers in that session.
52
52
 
53
53
  ```
54
54
  session_init(
55
- project_path: str = "", # working directory path, e.g. "/Users/me/projects/foo"
55
+ project_path: str = "", # working directory path, e.g. "~/projects/foo"
56
56
  query: str = "", # topic override; if omitted, derived from project_path
57
57
  max_results: int = 10, # max memories to return (default: 10)
58
58
  max_age_days: int = 30, # suppress memories older than N days unless score >= 0.7
@@ -253,4 +253,4 @@ explicitly and call `recall` with `include_global`/`include_shared` after
253
253
 
254
254
  ---
255
255
 
256
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
256
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -163,4 +163,4 @@ multi-profile setup. To switch the active profile, see `slm-profile`.
163
163
 
164
164
  ---
165
165
 
166
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
166
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -137,4 +137,4 @@ When the SLM MCP server is unavailable, use these CLI equivalents:
137
137
  - **slm-optimize-advisor** — context compression and KV cache
138
138
  - **slm-governance-advisor** — scope/role compliance, retention policies, GDPR
139
139
 
140
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
140
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -145,4 +145,4 @@ These subcommands control daemon-level cache settings. They do not read or write
145
145
 
146
146
  ---
147
147
 
148
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
148
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -147,4 +147,4 @@ Content over 1 MB (1 000 000 bytes UTF-8) is processed but `reversible` is force
147
147
 
148
148
  ---
149
149
 
150
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
150
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -245,4 +245,4 @@ Before running any destructive operation (`forget`, `compact_memories`):
245
245
 
246
246
  ---
247
247
 
248
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
248
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -312,4 +312,4 @@ profile. See `slm-profile` for the full profile switching workflow.
312
312
 
313
313
  ---
314
314
 
315
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
315
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -96,4 +96,4 @@ paused, name the approval needed; when errored, quote the short detail.
96
96
 
97
97
  ---
98
98
 
99
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
99
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
@@ -97,7 +97,7 @@ mesh_send(to=target_id, message="I'm starting work on auth/handler.py — please
97
97
  mesh_send(to="broadcast", message="Deploying to staging in 5 minutes")
98
98
 
99
99
  # Message all sessions working in the same project
100
- mesh_send(to="project:/Users/me/myproject", message="Tests are green on main")
100
+ mesh_send(to="project:~/myproject", message="Tests are green on main")
101
101
  ```
102
102
 
103
103
  **4 KB message cap.** For large payloads (diffs, file contents), write to a file
@@ -279,4 +279,4 @@ mesh availability.
279
279
 
280
280
  ---
281
281
 
282
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
282
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -146,4 +146,4 @@ Name them differently in your MCP config (e.g. `superlocalmemory-personal` and
146
146
 
147
147
  ---
148
148
 
149
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
149
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -323,4 +323,4 @@ before recalling, then switch back. See `slm-profile` for workspace switching.
323
323
 
324
324
  ---
325
325
 
326
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
326
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -270,4 +270,4 @@ different workspace, use `switch_profile` first. See `slm-profile`.
270
270
 
271
271
  ---
272
272
 
273
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
273
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -173,4 +173,4 @@ to review the impact. See `slm-remember` for the full deletion discipline.
173
173
 
174
174
  ---
175
175
 
176
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
176
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -52,7 +52,7 @@ recalls or remembers in that session.
52
52
 
53
53
  ```
54
54
  session_init(
55
- project_path: str = "", # working directory path, e.g. "/Users/me/projects/foo"
55
+ project_path: str = "", # working directory path, e.g. "~/projects/foo"
56
56
  query: str = "", # topic override; if omitted, derived from project_path
57
57
  max_results: int = 10, # max memories to return (default: 10)
58
58
  max_age_days: int = 30, # suppress memories older than N days unless score >= 0.7
@@ -253,4 +253,4 @@ explicitly and call `recall` with `include_global`/`include_shared` after
253
253
 
254
254
  ---
255
255
 
256
- *SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later*
256
+ *SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later*
@@ -163,4 +163,4 @@ multi-profile setup. To switch the active profile, see `slm-profile`.
163
163
 
164
164
  ---
165
165
 
166
- SuperLocalMemory v4.1.4 · Qualixar · AGPL-3.0-or-later
166
+ SuperLocalMemory v4.1.6 · Qualixar · AGPL-3.0-or-later
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "superlocalmemory"
3
- version = "4.1.4"
3
+ version = "4.1.6"
4
4
  description = "Local-first agent memory with auditable hybrid retrieval"
5
5
  readme = "README.md"
6
6
  license = "AGPL-3.0-or-later"
@@ -32,7 +32,7 @@ if "OMP_NUM_THREADS" not in os.environ:
32
32
  os.environ["OMP_NUM_THREADS"] = "2"
33
33
  # ---------------------------------------------------------------------------
34
34
 
35
- __version__ = "4.1.4"
35
+ __version__ = "4.1.6"
36
36
 
37
37
  _REQUIRED_VERSIONS = {
38
38
  "sentence_transformers": "5.3.0",
@@ -10,8 +10,11 @@ from argparse import Namespace
10
10
 
11
11
  def cmd_diagnostics(args: Namespace) -> None:
12
12
  action = getattr(args, "diagnostics_command", None)
13
+ if action == "reliability":
14
+ _cmd_reliability(args)
15
+ return
13
16
  if action != "export":
14
- raise SystemExit("choose a diagnostics subcommand: export")
17
+ raise SystemExit("choose a diagnostics subcommand: export, reliability")
15
18
 
16
19
  from superlocalmemory.cli.json_output import json_print
17
20
  from superlocalmemory.infra.local_diagnostics import default_diagnostics
@@ -25,4 +28,74 @@ def cmd_diagnostics(args: Namespace) -> None:
25
28
  print("No automatic reporting was enabled.")
26
29
 
27
30
 
31
+ def _cmd_reliability(args: Namespace) -> None:
32
+ """Report whether wired mechanisms are effective, not merely present.
33
+
34
+ ``implemented``, ``reachable`` and ``effective`` are three different
35
+ questions. A grep answers the first and an import answers the second; only
36
+ querying this store answers the third. Both checks are read-only.
37
+ """
38
+ from superlocalmemory.cli.json_output import json_print
39
+ from superlocalmemory.infra.data_root import state_path
40
+ from superlocalmemory.reliability import (
41
+ DEFAULT_MIN_OBSERVATIONS,
42
+ check_beta_learners,
43
+ check_schema_guards,
44
+ )
45
+
46
+ floor = getattr(args, "min_observations", None) or DEFAULT_MIN_OBSERVATIONS
47
+ learners = check_beta_learners(state_path("learning.db"), min_observations=floor)
48
+ guards = check_schema_guards(state_path("memory.db"))
49
+
50
+ payload = {
51
+ "learners": [
52
+ {
53
+ "table": v.table,
54
+ "verdict": v.verdict,
55
+ "units": v.units,
56
+ "units_at_prior_mean": v.units_at_prior_mean,
57
+ "units_matching_neutral_identity": v.units_matching_neutral_identity,
58
+ "observations": v.observations,
59
+ "detail": v.detail,
60
+ }
61
+ for v in learners
62
+ ],
63
+ "schema_guards": [
64
+ {
65
+ "name": g.name,
66
+ "verdict": g.verdict,
67
+ "missing": list(g.missing),
68
+ "found_elsewhere": [
69
+ {
70
+ "table": tbl,
71
+ "column": col,
72
+ "populated_rows": n,
73
+ # -1 when coverage over the guarded table could not be
74
+ # measured. Populated rows alone overstate the remedy.
75
+ "coverage_pct_of_guarded_table": cov,
76
+ }
77
+ for tbl, col, n, cov in g.found_elsewhere
78
+ ],
79
+ "detail": g.detail,
80
+ }
81
+ for g in guards
82
+ ],
83
+ }
84
+
85
+ if bool(getattr(args, "json", False)):
86
+ json_print("diagnostics-reliability", data=payload)
87
+ return
88
+
89
+ if not learners and not guards:
90
+ print("No Bayesian learners or schema-guarded paths found in this store.")
91
+ return
92
+
93
+ for v in learners:
94
+ print(f"[{v.verdict}] {v.table}")
95
+ print(f" {v.detail}")
96
+ for g in guards:
97
+ print(f"[{g.verdict}] {g.name}")
98
+ print(f" {g.detail}")
99
+
100
+
28
101
  __all__ = ["cmd_diagnostics"]
@@ -875,6 +875,18 @@ def main() -> None:
875
875
  "export", help="Write a deterministic content-free JSON report",
876
876
  )
877
877
  diagnostics_export.add_argument("destination")
878
+ diagnostics_reliability = diagnostics_sub.add_parser(
879
+ "reliability",
880
+ help=(
881
+ "Ask whether wired mechanisms are actually effective: has each "
882
+ "Bayesian learner moved off its prior, and has each schema-guarded "
883
+ "path ever executed against this store"
884
+ ),
885
+ )
886
+ diagnostics_reliability.add_argument(
887
+ "--min-observations", type=int, default=None,
888
+ help="Observation floor below which an unmoved posterior is not reported",
889
+ )
878
890
  diagnostics_export.add_argument(
879
891
  "--json", action="store_true", help="Output structured JSON",
880
892
  )
@@ -77,11 +77,43 @@ class MaintenanceScheduler:
77
77
  )
78
78
  self._initial_metrics_timer.daemon = True
79
79
  self._initial_metrics_timer.start()
80
+ # M048's re-read pass is idempotent and safe to replay (see its
81
+ # verify() docstring), but the migration runner never replays a
82
+ # completed migration and the cycle above only reaches it every
83
+ # ``scheduler_interval_minutes`` (360 by default). A store that
84
+ # drifted since the last cycle stays blocking — ready=false,
85
+ # migrations=false — for up to that whole interval after every
86
+ # restart, not because the fix is slow, but because nothing asks
87
+ # for it sooner. Staggered behind the other two so none of the
88
+ # three one-shots contend for the write lock.
89
+ self._initial_reclassify_timer = threading.Timer(
90
+ 210.0, self._initial_reclassify_upcoming,
91
+ )
92
+ self._initial_reclassify_timer.daemon = True
93
+ self._initial_reclassify_timer.start()
80
94
  logger.info(
81
95
  "Maintenance scheduler started (interval=%dm)",
82
96
  self._config.forgetting.scheduler_interval_minutes,
83
97
  )
84
98
 
99
+ def _initial_reclassify_upcoming(self) -> None:
100
+ """Best-effort one-shot M048 re-read shortly after boot.
101
+
102
+ Runs the same pass the periodic cycle already runs (see below) so a
103
+ store that drifted before this restart converges within seconds
104
+ instead of waiting up to a full maintenance interval with the
105
+ daemon reporting itself not ready.
106
+ """
107
+ if not self._running:
108
+ return
109
+ try:
110
+ from superlocalmemory.storage.migrations import (
111
+ M048_upcoming_holds_only_what_is_upcoming as _reclassify,
112
+ )
113
+ _reclassify.apply(open_connection=self._db.raw_connection)
114
+ except Exception as exc:
115
+ logger.debug("Startup plan re-read skipped: %s", exc)
116
+
85
117
  def _initial_cache_gc(self) -> None:
86
118
  """Best-effort one-shot activation-cache GC shortly after boot."""
87
119
  if not self._running:
@@ -133,6 +165,10 @@ class MaintenanceScheduler:
133
165
  if _metrics_timer is not None:
134
166
  _metrics_timer.cancel()
135
167
  self._initial_metrics_timer = None
168
+ _reclassify_timer = getattr(self, "_initial_reclassify_timer", None)
169
+ if _reclassify_timer is not None:
170
+ _reclassify_timer.cancel()
171
+ self._initial_reclassify_timer = None
136
172
  logger.info("Maintenance scheduler stopped")
137
173
 
138
174
  def _schedule_next(self) -> None:
@@ -419,8 +419,19 @@ class CanonicalRememberRuntime:
419
419
  OwnershipRequiredError,
420
420
  WriteCoordinatorError,
421
421
  ) as exc:
422
+ # Name which of the three it was. They are not interchangeable and
423
+ # they call for different responses: an unavailable journal is I/O
424
+ # or lock contention and worth retrying, lost ownership means
425
+ # another writer holds the lease, and a coordinator error is the
426
+ # same type the generation fence raises to reject a stale epoch.
427
+ # Collapsing all three into one string makes a spurious fence
428
+ # rejection indistinguishable from a transient disk stall, for the
429
+ # operator reading a log and for a caller deciding whether to
430
+ # retry. Only the class name is included: it is the whole of the
431
+ # discriminating information and carries no request content.
422
432
  raise CanonicalRememberUnavailable(
423
- "canonical remember is temporarily unavailable"
433
+ "canonical remember is temporarily unavailable "
434
+ f"({type(exc).__name__})"
424
435
  ) from exc
425
436
  finally:
426
437
  clear_admission_epoch(request.profile_id, request.idempotency_key)
@@ -134,9 +134,13 @@ _SYSTEM_PROMPT = (
134
134
  "must name the subject explicitly.\n"
135
135
  "2. Each fact must be a COMPLETE, STANDALONE statement understandable "
136
136
  "without the original conversation.\n"
137
- "3. Convert ALL relative time to ABSOLUTE dates when possible. "
138
- "'Yesterday' with session date 2024-01-15 becomes '2024-01-14'. "
139
- "'Next month' becomes the actual month and year.\n"
137
+ "3. Convert ALL relative time to ABSOLUTE dates when possible, using "
138
+ "ONLY the conversation date given in the user message below as your "
139
+ "reference point never invent or assume a date. 'Yesterday' resolves "
140
+ "to one calendar day before that conversation date; 'next month' "
141
+ "resolves to the following calendar month of that same date. If no "
142
+ "conversation date is given, leave the date unresolved rather than "
143
+ "guessing one.\n"
140
144
  "4. Resolve ALL coreferences. 'He went there' must become "
141
145
  "'[Person name] went to [Place name]'.\n"
142
146
  "5. Extract relationships between people when mentioned.\n"