nexusmem 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -9,6 +9,59 @@ built from, matched by publish timestamp: `v0.1.0` → `67a4776`, `v0.1.1` → `
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ No unreleased changes yet.
13
+
14
+ ## [0.8.0] — 2026-08-22
15
+
16
+ ### Added
17
+
18
+ - Provenance widened from 2 tiers to a 4-tier trust hierarchy: `observed` (commits, diffs, shell
19
+ exit codes) > `authored` (doc sections — human-written claims) > `recorded` (conversation turns —
20
+ verbatim discourse) > `derived` (session summaries — a model's distillation). Schema V7 backfills
21
+ existing databases by kind. The ranker decays each tier at its own rate (lower trust fades
22
+ faster); the ordering is the design claim, the exact ratios are documented judgment calls.
23
+ - Contradiction checking now runs automatically during `sync`: at most 3 new SLM judgments per run
24
+ (`contradictions.maxPerSync`; `contradictions.autoCheck: false` turns it off), gated on the
25
+ embedding provider already being reachable. Every judgment — either verdict — is memoized in a new
26
+ `contradiction_checks` table (schema V8), so a judged pair is never sent to the model again and
27
+ repeat syncs converge to zero model calls. Measured live against this repo's own database: 5.4s
28
+ for the first 10 judgments, 0.5s for the identical re-run. Still suggest-only: nothing ever writes
29
+ `supersedes` automatically.
30
+ - Standing suggestions now surface everywhere without a model in the loop: plain `nexusmem stale`
31
+ decorates flagged candidates from the memoized judgments (instant, offline), `nexusmem status`
32
+ gains a `flagged` line, and the sync summary reports new/open suggestion counts.
33
+ - `stale --check-contradictions` reuses each candidate's stored embedding instead of re-embedding
34
+ it, and stops after two consecutive null SLM replies so a down provider costs at most two timeouts
35
+ rather than one per candidate.
36
+
37
+ ## [0.7.0] — 2026-08-21
38
+
39
+ ### Added
40
+
41
+ - `nexusmem stale --check-contradictions`: for each stale candidate, finds the most similar newer
42
+ node (local embedding search) and asks a local SLM (Ollama, `qwen2.5:3b` by default) whether it
43
+ actually contradicts the older one, instead of only surfacing by age. Suggest-only — nothing is
44
+ written, same as plain `stale`. Live-dogfooded against this repo's own real database and Ollama
45
+ instance; found and fixed a real gap along the way (below) before the feature surfaced anything
46
+ useful.
47
+ - Import graph: bare Python imports with no leading dot (`import foo`, `from foo import bar`)
48
+ now resolve to a same-directory sibling file too, alongside the existing relative-dot support.
49
+ Found dogfooding two real local projects: neither used a single PEP 328 relative import, both
50
+ relied entirely on this flat-script style. Guarded by a static list of stdlib module names so a
51
+ bare `import os`/`import queue`/etc. is never mistaken for a same-named local file.
52
+
53
+ ### Fixed
54
+
55
+ - Import graph: a Java wildcard import (`import a.b.*;`) no longer merges files from two
56
+ unrelated packages that happen to share a directory-name suffix (e.g. two Gradle/Maven modules
57
+ each with their own `.../foo`) — it now refuses to guess, same as the single-class-import case.
58
+ - `stale --check-contradictions`'s neighbor search now looks past same-timestamp sibling nodes
59
+ (e.g. the many chunks one long conversation gets split into) to reach genuinely newer content.
60
+ Found live-dogfooding against this repo's own database: the first real candidate's closest 15
61
+ neighbors were all same-conversation siblings sharing its exact timestamp, so the original
62
+ 5-neighbor default silently found zero suggestions for every candidate, regardless of what the
63
+ SLM would have said.
64
+
12
65
  ## [0.6.0] — 2026-08-20
13
66
 
14
67
  ### Added
@@ -451,7 +504,9 @@ First public release.
451
504
  there is no local-model summarization pass, and the conversation collector has never been audited
452
505
  for the stale-node bug that was found and fixed in the docs collector.
453
506
 
454
- [Unreleased]: https://github.com/yaminbkk/NexusMem/compare/v0.6.0...HEAD
507
+ [Unreleased]: https://github.com/yaminbkk/NexusMem/compare/v0.8.0...HEAD
508
+ [0.8.0]: https://github.com/yaminbkk/NexusMem/compare/v0.7.0...v0.8.0
509
+ [0.7.0]: https://github.com/yaminbkk/NexusMem/compare/v0.6.0...v0.7.0
455
510
  [0.6.0]: https://github.com/yaminbkk/NexusMem/compare/v0.5.4...v0.6.0
456
511
  [0.5.4]: https://github.com/yaminbkk/NexusMem/compare/v0.5.3...v0.5.4
457
512
  [0.5.3]: https://github.com/yaminbkk/NexusMem/compare/v0.5.2...v0.5.3
package/README.md CHANGED
@@ -24,7 +24,7 @@ exists nowhere else, and it disappears when your terminal scrollback rolls over.
24
24
  **Contents:** [Try it](#try-it) · [Exact shell capture](#optional-exact-shell-capture) ·
25
25
  [Failure → fix chains](#failure--fix-chains-opt-in) · [How retrieval works](#how-retrieval-works) ·
26
26
  [Session summaries](#session-summaries-optional-local-model) · [Use it from an agent](#use-it-from-an-agent)
27
- · [What it costs you](#what-it-costs-you) · [Manual staleness & provenance](#manual-staleness--provenance) ·
27
+ · [What it costs you](#what-it-costs-you) · [Staleness & provenance](#staleness--provenance) ·
28
28
  [Where it breaks](#where-it-breaks) · [Commands](#commands) · [Cross-project recall](#recall-across-projects)
29
29
  · [On disk](#on-disk) · [Development](#development)
30
30
 
@@ -48,11 +48,11 @@ Relevant history for: windows spawn failure
48
48
  readRepoInfo collapsed three unrelated failures into one error: git running and reporting
49
49
  the path is not a work tree, git not being installed, and the process failing to spawn at
50
50
  all. Dogfooding hit the third case in two separate sessions...
51
- - 2026-08-09 [inferred] README.md — Before a tagged release
51
+ - 2026-08-09 [authored] README.md — Before a tagged release
52
52
  - [ ] Retry on transient process-spawn failures on Windows
53
53
  ```
54
54
 
55
- `[observed]`/`[inferred]` is the provenance tag (see [Manual staleness & provenance](#manual-staleness--provenance))
55
+ `[observed]`/`[authored]` is the provenance tag (see [Staleness & provenance](#staleness--provenance))
56
56
  — a commit is a directly observed event, a doc section is a written claim that could go stale.
57
57
 
58
58
  A commit and a docs section, ranked against each other, inside whatever token budget you gave it.
@@ -269,19 +269,23 @@ Two things a memory layer needs and this one only partly has: a way to tell an o
269
269
  guess, and a way to retire a conclusion once something contradicts it. This section is what exists
270
270
  and what doesn't.
271
271
 
272
- Every node carries a `provenance`: `observed` (a commit that landed, a shell command's real exit
273
- code) or `inferred` (a conversation turn, a session summary, a doc section all readable as claims
274
- that could be wrong or go stale). Set once per collector at ingest time, shown as a `[observed]` /
275
- `[inferred]` tag on every query result, and now used to decay retrieval weight too `inferred` nodes
276
- fade from ranking twice as fast as `observed` ones as they age.
272
+ Every node carries a `provenance`, a four-tier trust hierarchy set once per collector at ingest
273
+ time: `observed` (a commit that landed, a shell command's real exit code) > `authored` (a doc
274
+ section a human's own written claim) > `recorded` (a conversation turn verbatim, but talk about
275
+ events rather than the events) > `derived` (a session summary a model's distillation). The tier is
276
+ shown as a tag on every query result and decays retrieval weight — the lower the trust, the faster a
277
+ node fades from ranking as it ages. The ordering is the design claim; the exact decay ratios are
278
+ judgment calls, not measured optima.
277
279
 
278
280
  ```bash
279
281
  nexusmem stale
280
282
  ```
281
283
 
282
- Lists `inferred` nodes old enough (45+ days by default) that nothing has confirmed they still hold —
283
- a heuristic on age and provenance, not on content. It writes nothing; you decide which candidates are
284
- actually wrong.
284
+ Lists non-`observed` nodes old enough (45+ days by default) that nothing has confirmed they still
285
+ hold — a heuristic on age and provenance, not on content. It writes nothing; you decide which
286
+ candidates are actually wrong. Any candidate the SLM has already flagged (see below) is decorated
287
+ with its standing `likely superseded by` suggestion — reading those costs nothing, so the plain
288
+ command stays instant and offline.
285
289
 
286
290
  ```bash
287
291
  nexusmem mark-stale <oldNodeId> --supersedes <newNodeId>
@@ -290,10 +294,27 @@ nexusmem mark-stale <oldNodeId> --supersedes <newNodeId>
290
294
  Links `newNodeId` as the replacement for `oldNodeId`. The ranker down-weights the old node from then
291
295
  on (it stays queryable, just usually loses to its replacement) — nothing is deleted, unlike `forget`.
292
296
 
293
- **What this doesn't do:** nothing here reads content to detect a real contradiction. If a later commit
294
- contradicts an earlier doc section, `nexusmem stale` won't know that specifically — it only knows the
295
- doc section is old and inferred. Actual contradiction detection (comparing what two nodes claim, not
296
- just how old one is) is still an open problem.
297
+ ```bash
298
+ nexusmem stale --check-contradictions
299
+ ```
300
+
301
+ For each candidate, finds the most similar newer node (local embedding search) and asks a local SLM
302
+ (Ollama, `qwen2.5:3b` by default) whether it actually contradicts the older one — real content
303
+ comparison, not just age. A match is printed as `likely superseded by <id> <title> -- <reason>`
304
+ under the candidate. Every judgment (either verdict) is memoized, so a judged pair is never sent to
305
+ the model again; nothing else is written — `supersedes` stays yours to set via `mark-stale`.
306
+
307
+ **This also runs automatically during `sync`** — at most 3 new judgments per run (configurable via
308
+ the `contradictions` block in `.nexusmem/config.json`; set `autoCheck: false` to turn it off), only
309
+ when the embedding provider was reachable anyway, and free on repeat syncs thanks to the
310
+ memoization. New and open suggestions show up in the sync summary, `nexusmem status` (a `flagged`
311
+ line), and plain `nexusmem stale`.
312
+
313
+ **What this doesn't do:** it is one small model's yes/no judgment on one older/newer pair, not a
314
+ verified fact — treat a match as a lead to check, not a conclusion. It also only ever compares a
315
+ candidate against nodes *found by embedding similarity*; a contradiction from an unrelated-sounding
316
+ node would never surface. Comprehensive contradiction detection (not just for the pair the vector
317
+ search happens to surface) is still an open problem, and nothing here supersedes a node on its own.
297
318
 
298
319
  ## Where it breaks
299
320
 
@@ -361,8 +382,9 @@ just how old one is) is still an open problem.
361
382
  ## Commands
362
383
 
363
384
  `init`, `sync`, `query <text>`, `status` (add `--share` for a plain-text summary worth pasting
364
- somewhere), `projects`, `mcp`, `forget <value>`, `stale`,
365
- `mark-stale <nodeId> --supersedes <newNodeId>`, and `hook install|remove|status`.
385
+ somewhere), `projects`, `mcp`, `forget <value>`, `stale` (add `--check-contradictions` for a local-SLM
386
+ content check, see above), `mark-stale <nodeId> --supersedes <newNodeId>`, and
387
+ `hook install|remove|status`.
366
388
 
367
389
  There are also five dry-run previews (`scan-git`, `scan-diff`, `scan-shell`, `scan-docs`,
368
390
  `scan-conversation`)