recallnest 2.6.1 → 3.0.1

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 (207) hide show
  1. package/CHANGELOG.md +292 -0
  2. package/README.md +280 -195
  3. package/README_CN.md +266 -199
  4. package/config.json.example +8 -1
  5. package/docs/api-reference.md +1 -1
  6. package/integrations/README.md +1 -1
  7. package/integrations/agy/README.md +73 -0
  8. package/integrations/agy/setup.sh +75 -0
  9. package/integrations/setup-all.sh +1 -1
  10. package/package.json +7 -5
  11. package/src/access-tracker.ts +10 -1
  12. package/src/activity-counter.ts +69 -11
  13. package/src/age-label.ts +29 -0
  14. package/src/audit-log.ts +35 -0
  15. package/src/auto-gc.ts +97 -30
  16. package/src/capture-engine.ts +26 -4
  17. package/src/cli.ts +224 -10
  18. package/src/consolidation-engine.ts +317 -123
  19. package/src/context-composer-stable.ts +5 -1
  20. package/src/data-checkup.ts +17 -3
  21. package/src/dream-pipeline.ts +90 -12
  22. package/src/embedder.ts +44 -5
  23. package/src/env-config.ts +71 -0
  24. package/src/forget-engine.ts +8 -2
  25. package/src/gateway-server.ts +272 -0
  26. package/src/ingest.ts +248 -22
  27. package/src/kg-extractor.ts +17 -0
  28. package/src/llm-client.ts +86 -25
  29. package/src/mcp-server.ts +2 -1
  30. package/src/mcp-tools-advanced.ts +7 -2
  31. package/src/mcp-tools-core.ts +11 -1
  32. package/src/mcp-tools-governance.ts +45 -3
  33. package/src/memory-evolution.ts +16 -0
  34. package/src/memory-output.ts +47 -8
  35. package/src/memory-promotion.ts +280 -0
  36. package/src/memory-store-port.ts +32 -3
  37. package/src/memory-utility.ts +314 -0
  38. package/src/pivot-apply.ts +52 -1
  39. package/src/pivot-evidence.ts +128 -0
  40. package/src/ppr-traversal.ts +25 -1
  41. package/src/recall-ledger.ts +76 -0
  42. package/src/retriever.ts +82 -9
  43. package/src/runtime-config.ts +9 -0
  44. package/src/scope-policy.ts +22 -1
  45. package/src/session-engine.ts +11 -4
  46. package/src/session-output.ts +13 -4
  47. package/src/session-store.ts +2 -3
  48. package/src/skill-promotion.ts +218 -1
  49. package/src/store.ts +231 -71
  50. package/src/synthesis-contract.ts +286 -0
  51. package/src/version-manager.ts +83 -0
  52. package/src/workflow-observation-schema.ts +26 -0
  53. package/integrations/gemini-cli/README.md +0 -57
  54. package/integrations/gemini-cli/setup.sh +0 -64
  55. package/src/__tests__/access-tracker-novelty.test.ts +0 -304
  56. package/src/__tests__/activity-counter.test.ts +0 -125
  57. package/src/__tests__/adaptive-fidelity.test.ts +0 -102
  58. package/src/__tests__/admission-control.test.ts +0 -206
  59. package/src/__tests__/anchor-generator.test.ts +0 -67
  60. package/src/__tests__/api-server-security.test.ts +0 -102
  61. package/src/__tests__/auto-consolidation.test.ts +0 -168
  62. package/src/__tests__/auto-recall.test.ts +0 -131
  63. package/src/__tests__/babel-integration.test.ts +0 -144
  64. package/src/__tests__/batch-dedup.test.ts +0 -65
  65. package/src/__tests__/belief-history.test.ts +0 -220
  66. package/src/__tests__/canary-eval.test.ts +0 -114
  67. package/src/__tests__/capture-engine.test.ts +0 -1328
  68. package/src/__tests__/capture-heuristic.test.ts +0 -171
  69. package/src/__tests__/cascade-forget.test.ts +0 -210
  70. package/src/__tests__/category-min-scores.test.ts +0 -116
  71. package/src/__tests__/cc8-cc1-essential-context.test.ts +0 -298
  72. package/src/__tests__/circuit-breaker.test.ts +0 -99
  73. package/src/__tests__/cluster-consolidation.test.ts +0 -945
  74. package/src/__tests__/confidence-metadata.test.ts +0 -125
  75. package/src/__tests__/confidence-tracker.test.ts +0 -261
  76. package/src/__tests__/conflict-advisor.test.ts +0 -206
  77. package/src/__tests__/conflict-escalation.test.ts +0 -149
  78. package/src/__tests__/conflict-lifecycle.test.ts +0 -83
  79. package/src/__tests__/conflict-output.test.ts +0 -85
  80. package/src/__tests__/conflict-store.test.ts +0 -418
  81. package/src/__tests__/connector-v1.test.ts +0 -181
  82. package/src/__tests__/consolidation-engine.test.ts +0 -430
  83. package/src/__tests__/constructive-retrieval.test.ts +0 -509
  84. package/src/__tests__/context-collapse-renderer.test.ts +0 -214
  85. package/src/__tests__/context-composer-pins.test.ts +0 -64
  86. package/src/__tests__/context-composer-task-selection.test.ts +0 -24
  87. package/src/__tests__/context-reconstructor.test.ts +0 -65
  88. package/src/__tests__/context-renderer.test.ts +0 -91
  89. package/src/__tests__/continuity-eval.test.ts +0 -275
  90. package/src/__tests__/continuity-schema.test.ts +0 -97
  91. package/src/__tests__/contracts.test.ts +0 -262
  92. package/src/__tests__/conversation-importer.test.ts +0 -692
  93. package/src/__tests__/core-recall-eval.test.ts +0 -235
  94. package/src/__tests__/core-summary.test.ts +0 -109
  95. package/src/__tests__/data-checkup.test.ts +0 -276
  96. package/src/__tests__/decay-exemption.test.ts +0 -129
  97. package/src/__tests__/dedup-actions.test.ts +0 -58
  98. package/src/__tests__/dedup-guard.test.ts +0 -39
  99. package/src/__tests__/deterministic-id.test.ts +0 -39
  100. package/src/__tests__/distill-lock.test.ts +0 -305
  101. package/src/__tests__/distill-session-argshape.test.ts +0 -79
  102. package/src/__tests__/doctor.test.ts +0 -319
  103. package/src/__tests__/dream-pipeline.test.ts +0 -780
  104. package/src/__tests__/drill-down.test.ts +0 -108
  105. package/src/__tests__/embedder.test.ts +0 -122
  106. package/src/__tests__/emotion-decay.test.ts +0 -46
  107. package/src/__tests__/emotion-detector.test.ts +0 -56
  108. package/src/__tests__/emotion-phase1-integration.test.ts +0 -153
  109. package/src/__tests__/emotion-retrieval.test.ts +0 -56
  110. package/src/__tests__/entity-resolver.test.ts +0 -58
  111. package/src/__tests__/env-config.test.ts +0 -151
  112. package/src/__tests__/error-signature-boost.test.ts +0 -87
  113. package/src/__tests__/error-signature.test.ts +0 -95
  114. package/src/__tests__/error-taxonomy.test.ts +0 -129
  115. package/src/__tests__/ethics-layer.test.ts +0 -476
  116. package/src/__tests__/event-segmenter.test.ts +0 -153
  117. package/src/__tests__/feature-flags-integration.test.ts +0 -54
  118. package/src/__tests__/frequency-tracker.test.ts +0 -113
  119. package/src/__tests__/freshness.test.ts +0 -186
  120. package/src/__tests__/graph-export.test.ts +0 -489
  121. package/src/__tests__/hotness-blend.test.ts +0 -283
  122. package/src/__tests__/ingest-chunking.test.ts +0 -44
  123. package/src/__tests__/ingest.test.ts +0 -360
  124. package/src/__tests__/interference-detector.test.ts +0 -203
  125. package/src/__tests__/kg-extractor.test.ts +0 -192
  126. package/src/__tests__/kg-store.test.ts +0 -300
  127. package/src/__tests__/llm-client-pivot.test.ts +0 -628
  128. package/src/__tests__/llm-consolidation.test.ts +0 -226
  129. package/src/__tests__/maintenance-locks.test.ts +0 -189
  130. package/src/__tests__/mcp-efficiency.test.ts +0 -288
  131. package/src/__tests__/mcp-related-scopes.test.ts +0 -151
  132. package/src/__tests__/memory-boundaries.test.ts +0 -282
  133. package/src/__tests__/memory-evolution-b2-b3-e1.test.ts +0 -345
  134. package/src/__tests__/memory-evolution.test.ts +0 -271
  135. package/src/__tests__/memory-health-rebalance.test.ts +0 -144
  136. package/src/__tests__/memory-lint.test.ts +0 -421
  137. package/src/__tests__/memory-output.test.ts +0 -215
  138. package/src/__tests__/memory-promotion.test.ts +0 -315
  139. package/src/__tests__/migrate-dedup-ids.test.ts +0 -65
  140. package/src/__tests__/multi-vector.test.ts +0 -242
  141. package/src/__tests__/narrative-architecture.test.ts +0 -456
  142. package/src/__tests__/noise-filter.test.ts +0 -205
  143. package/src/__tests__/noise-prototype-bank.test.ts +0 -280
  144. package/src/__tests__/obsidian-connector.test.ts +0 -363
  145. package/src/__tests__/omitted-reporting.test.ts +0 -98
  146. package/src/__tests__/pending-review.test.ts +0 -77
  147. package/src/__tests__/pii-redact.test.ts +0 -333
  148. package/src/__tests__/pivot-apply.test.ts +0 -373
  149. package/src/__tests__/pivot-distill-supervisor.test.ts +0 -457
  150. package/src/__tests__/pivot-distill.test.ts +0 -1178
  151. package/src/__tests__/post-retrieval-filter.test.ts +0 -178
  152. package/src/__tests__/ppr-traversal.test.ts +0 -256
  153. package/src/__tests__/prediction-engine.test.ts +0 -349
  154. package/src/__tests__/predictive-prospective-memory.test.ts +0 -416
  155. package/src/__tests__/preference-guard-smoke.test.ts +0 -211
  156. package/src/__tests__/preference-matcher.test.ts +0 -282
  157. package/src/__tests__/preference-slots.test.ts +0 -205
  158. package/src/__tests__/prospective-memory.test.ts +0 -283
  159. package/src/__tests__/pull-from-macbook-sync-only.test.ts +0 -679
  160. package/src/__tests__/query-entity-detector.test.ts +0 -171
  161. package/src/__tests__/query-expander-alias.test.ts +0 -146
  162. package/src/__tests__/query-expander.test.ts +0 -34
  163. package/src/__tests__/recall-gate.test.ts +0 -266
  164. package/src/__tests__/recall-governor.test.ts +0 -227
  165. package/src/__tests__/recall-mode.test.ts +0 -64
  166. package/src/__tests__/resolve-db-path.test.ts +0 -130
  167. package/src/__tests__/resolve-tier.test.ts +0 -64
  168. package/src/__tests__/result-synthesizer.test.ts +0 -198
  169. package/src/__tests__/resume-context.test.ts +0 -4898
  170. package/src/__tests__/retrieval-eval.test.ts +0 -163
  171. package/src/__tests__/retrieval-trace.test.ts +0 -213
  172. package/src/__tests__/retriever-boundary-weight.test.ts +0 -136
  173. package/src/__tests__/retriever-lazy-init-dispatch.test.ts +0 -123
  174. package/src/__tests__/retroactive-boost.test.ts +0 -223
  175. package/src/__tests__/salience-scoring.test.ts +0 -106
  176. package/src/__tests__/scope-inventory.test.ts +0 -200
  177. package/src/__tests__/scope-policy.test.ts +0 -69
  178. package/src/__tests__/scope-suggester.test.ts +0 -80
  179. package/src/__tests__/session-checkpoint.test.ts +0 -291
  180. package/src/__tests__/session-distiller.test.ts +0 -640
  181. package/src/__tests__/session-gc.test.ts +0 -215
  182. package/src/__tests__/skill-engine.test.ts +0 -552
  183. package/src/__tests__/skill-promotion.test.ts +0 -654
  184. package/src/__tests__/skill-verifier.test.ts +0 -122
  185. package/src/__tests__/source-heartbeat.test.ts +0 -250
  186. package/src/__tests__/stable-context-length-contract.test.ts +0 -62
  187. package/src/__tests__/store-patch-metadata.test.ts +0 -205
  188. package/src/__tests__/store-read-consistency.test.ts +0 -122
  189. package/src/__tests__/store-schema-migration.test.ts +0 -87
  190. package/src/__tests__/store-scope-audit.test.ts +0 -81
  191. package/src/__tests__/store-upsert.test.ts +0 -201
  192. package/src/__tests__/supersede-chain.test.ts +0 -154
  193. package/src/__tests__/temporal-parser.test.ts +0 -241
  194. package/src/__tests__/temporal-validity.test.ts +0 -160
  195. package/src/__tests__/term-registry-terminal-roster.test.ts +0 -127
  196. package/src/__tests__/term-registry.test.ts +0 -121
  197. package/src/__tests__/tool-error-surfacing.test.ts +0 -98
  198. package/src/__tests__/tool-output-compressor.test.ts +0 -160
  199. package/src/__tests__/topic-tag.test.ts +0 -113
  200. package/src/__tests__/trusted-memory.test.ts +0 -839
  201. package/src/__tests__/ui-server-security.test.ts +0 -93
  202. package/src/__tests__/usage-tracker.test.ts +0 -287
  203. package/src/__tests__/version-manager.test.ts +0 -213
  204. package/src/__tests__/workflow-observation-skill-outcome.test.ts +0 -352
  205. package/src/__tests__/workflow-observation.test.ts +0 -433
  206. package/src/__tests__/write-verifier.test.ts +0 -122
  207. /package/integrations/{gemini-cli/gemini-md-snippet.md → agy/agy-md-snippet.md} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,254 @@
1
1
  # Changelog
2
2
 
3
+ <!-- Before cutting a release, run every entry past these five:
4
+ 1. before / after — a number, not an adjective. No number, no claim.
5
+ (Nothing measurable? Then one plain sentence. Do not manufacture a figure.)
6
+ 2. under what conditions was it measured — version, sample size, environment.
7
+ 3. what does this cost and who gets hit by it — state it, do not bury it.
8
+ 4. what alternative was rejected and why — the reason must be specific
9
+ enough that someone could refute it.
10
+ 5. what looks like it belongs here but deliberately does not, and on what evidence.
11
+
12
+ When condensing this file into a GitHub Release body, 2 / 4 / 5 are the first
13
+ things to go: a conclusion reads as information, a reason reads as filler.
14
+ Protect them by name. The v3.0.0 Release body dropped 11 of 11 such items in
15
+ exactly that step, while this file had every one of them. -->
16
+
17
+ ## v3.0.1 — Publication hygiene (2026-09-06)
18
+
19
+ ### Added
20
+
21
+ - **`embedding.timeoutMs` — an opt-in per-request timeout for the embedding client**
22
+ (config.json, or `RECALLNEST_EMBEDDING_TIMEOUT_MS`, which wins over the file so one
23
+ deployment can bound itself without editing a shared config). **Default behavior is
24
+ unchanged**: with neither set, no `timeout` is passed to the SDK at all and the client
25
+ keeps its own default — 600s in `openai` v7 — exactly as in every release through
26
+ v3.0.0. The knob exists because that default stacks badly: the SDK retries twice on its
27
+ own and `Embedder` retries twice more, so a black-holed endpoint issues **9 requests for
28
+ a single `embedPassage` call** (measured against a loopback endpoint that never answers),
29
+ putting the worst case at roughly 90 minutes. Lowering the default for everyone was
30
+ rejected instead of shipped — bulk embedding of long documents is legitimately slow, and
31
+ a global cut would turn working ingests into failures — so the timeout is only ever
32
+ shortened by a caller that asks. Non-finite, zero and negative values are ignored rather
33
+ than throwing, so a typo degrades to the old behavior instead of to an embedder that
34
+ aborts every request. Covered by the loopback suite (abort within the configured budget)
35
+ and by `runtime-config-embedding.test.ts` (config.json → client, env precedence, and a
36
+ whole-client comparison against the pre-change construction expression proving the unset
37
+ path is unchanged).
38
+
39
+ ### Changed
40
+
41
+ - **Publication hygiene: no machine-local identifiers in the tree, no tests in the tarball.**
42
+ Three eval scripts (`eval/ghost-scan.ts`, `eval/lengthnorm-shadow.ts`,
43
+ `eval/term-registry-shadow.ts`) imported the runtime through an absolute path that only
44
+ existed on the author's machine; they now resolve the repository root from
45
+ `RECALLNEST_ROOT`, falling back to `~/recallnest` — the identical path on the original
46
+ install, a working one everywhere else. `scripts/pivot-distill-supervisor.ts` derives its
47
+ user-level launchd labels from the current account (`com.<user>.<task>`, overridable via
48
+ `PIVOT_DISTILL_LAUNCHD_PREFIX`) instead of a hardcoded username; the supervised set is
49
+ unchanged for the original account, and the suite now asserts the derivation rule and the
50
+ override. `package.json#files` excludes `src/**/__tests__/**` — `.npmignore` alone never
51
+ could, because `files` wins — so the dry-run tarball goes from 357 files / 965.8 kB
52
+ (3.8 MB unpacked) to 189 files / 620.0 kB (2.1 MB unpacked), measured with npm 11.19.0
53
+ on this commit; `scripts/verify-package-contents.mjs` now rejects any `__tests__` directory,
54
+ so the CI gate turns red if this regresses. A new `privacy-regression.test.ts` scans
55
+ `src/`, `scripts/`, `eval/`, `bin/`, root-level `*.md` and shipped `data/*.example.*` for the
56
+ removed identifiers and for macOS home paths (obvious placeholder accounts excepted).
57
+ Rejected: relative imports in the eval scripts, because these are reproduction tools for
58
+ figures measured against the production install and must keep pointing at it even when
59
+ invoked from another checkout. Deliberately not here: the README acknowledgements are unchanged.
60
+
61
+ ## v3.0.0 — Node 22, and conclusions that can be used (2026-08-24)
62
+
63
+ Two things make this a major release: the runtime floor moves, and a synthesized
64
+ conclusion can finally reach stable memory. Everything else here is either in service of
65
+ those or was found while doing them.
66
+
67
+ ### Changed
68
+
69
+ - **`engines.node` is now `>=22`** (was `>=18.14.1`). This is the only breaking change in
70
+ the release; Bun users are unaffected.
71
+ - **`openai` migrated from `^4.0.0` to `^7.5.0`**, which removes the
72
+ `openai@4 → formdata-node@4.4.1 → node-domexception@1.0.0` deprecated chain from the
73
+ dependency tree. Every `openai` release since v5 has zero dependencies, so the chain
74
+ disappears on any upgrade — v7 was chosen because it declares `engines.node >= 22.0.0`,
75
+ making the Node floor and the dependency cleanup one decision instead of two. Verified
76
+ against the SDK rather than its migration guide: the guide documents the `httpAgent`
77
+ removal, the move to built-in `fetch`, and the Node 22 floor, but says nothing about the
78
+ three things this codebase actually depends on — `embeddings.create`, the second
79
+ `RequestOptions` argument on `chat.completions.create`, and the error classes exposed as
80
+ statics on the default export. All three hold.
81
+ - **MCP tool count is 44**, up from 43 (`promote_synthesis`, governance tier).
82
+
83
+ ### Added
84
+
85
+ - **`promote_synthesis` (MCP) and `recallnest promote-synthesis` (CLI)** — a promotion road
86
+ for dream-synthesized conclusions. `buildDerivedBoundary` marks every cluster insight and
87
+ cross-memory pattern `layer: "evidence"` on purpose, and `shouldUseStableMemoryResult`
88
+ refuses the evidence layer, so a synthesized conclusion could never take part in stable
89
+ memory regardless of how well supported it was. Eligibility comes from the conclusion's
90
+ own validated evidence set — `synthesis_contract >= 2`, at least two distinct still-active
91
+ evidence memories — rather than from repetition, because a synthesis is already a
92
+ cross-entry aggregate. It abstains when the evidence cannot be resolved, counts every
93
+ rejection reason, defaults to dry-run, never modifies the synthesized row, and writes
94
+ through the existing `promoteMemory` path so `canonicalKey` dedup makes a re-run a
95
+ revision instead of a duplicate.
96
+ - **Retrieve audit rows carry revision and provenance.** `retrieved[]` records each served
97
+ result's id, `evolution.version`, lifecycle status, and boundary layer/authority;
98
+ `retrievedTotal` appears when the capped list is shorter than the truth. Beliefs are
99
+ revised in place — the canonical id survives, the version increments, the old text
100
+ remains as a `superseded` row — so a row saying only `hits=N` could not distinguish a
101
+ current answer from a stale one after the fact.
102
+ - **HTTP contract tests for embeddings and chat completions** (`openai-contract.test.ts`).
103
+ Every prior embedder/LLM test stubbed the SDK client, so none of them touched a socket
104
+ and a transport-level regression would have passed all of them. These drive the real
105
+ `Embedder` and `LLMClient` through the real SDK against a loopback `node:http` server,
106
+ covering success, error, and timeout for the default OpenAI request shape plus the Jina
107
+ (`task`/`normalized`/`dimensions`) and Qwen-compatible profiles. No network egress, no
108
+ vendor credentials, no paid calls.
109
+ - **A repeatable regression for verbatim self-recall** (`verbatim-self-recall.test.ts`).
110
+ A long, older, rarely-read entry can fail to be recalled by words copied out of its own
111
+ body while short, fresh, frequently-read entries outrank it. The reproduction pins the
112
+ mechanism: the entry is *not* filtered — `hard_min_score`, `layer_admission` and
113
+ `noise_filter` each drop zero rows and its score clears the threshold — it is admitted
114
+ and then ranked last. The ranking fix is deliberately not in this release.
115
+ - **`scripts/tier-exemption-snapshot.ts`** — captures tier and decay-exemption distribution
116
+ so "we did not change tiers" becomes checkable later rather than asserted.
117
+
118
+ ### Added — synthesis quality (generation side)
119
+
120
+ Six changes to what `dream` produces, from a full diagnostic on 2026-08-22 whose core
121
+ finding was that **derived memories had a lower conclusion density than their own input**:
122
+ over the same 40–160 character band, with a deterministic regex and no LLM judge,
123
+ hand-written pivots scored 40.4%, raw transcripts 25.1%, insights 14.4%, patterns 12.1%.
124
+ Synthesis was subtracting.
125
+
126
+ - **`cluster_insight` no longer routes through `generateL0`.** That prompt is a chunk
127
+ summariser — it asks for a one-line summary for retrieval and explicitly preserves ports,
128
+ IPs, URLs and file paths verbatim; it never asks for a conclusion, a cause, or a decision.
129
+ The new `synthesizeClusterInsight` goes through `synthesis-contract.ts`, asks for a
130
+ reusable conclusion, and **may abstain**. The old path's `if (!insight)` only fired when
131
+ the LLM call itself failed, so "this cluster is not worth keeping" had no way to be
132
+ expressed and all 2,427 rows were episode summaries by construction.
133
+ - **`extractPattern` changed target concept and now requires evidence.** The old prompt
134
+ asked for recurring preferences, behavioural tendencies and values — a personality-profile
135
+ frame, which produced dispositional attribution in 56.1% of outputs against 1.4% in the
136
+ source material. The old prompt also claimed to want "at least 2 memories as supporting
137
+ evidence" while the implementation neither received nor checked any numbering, making the
138
+ sentence free. Two pieces of evidence is now a hard gate.
139
+ - **`validateSynthesis` runs before anything is written.** The old path checked only
140
+ `response.length < 5`, which is how 28 memories ended up holding their own system prompt
141
+ as their body. `has` must be a boolean, length must be in range, the text must not echo
142
+ the prompt, and evidence numbers must refer to real, distinct cluster members. Failures
143
+ are counted by reason instead of collapsing into one `null`.
144
+ - **Pattern and insight are decoupled.** `if (!insight) { continue; }` bound two different
145
+ target concepts to one fate: an abstaining insight meant pattern extraction never ran.
146
+ They now fail and abstain independently, and "this round produced nothing" is judged on
147
+ whether the cluster had any effect at all rather than on whether an insight existed.
148
+ - **Derived rows carry an explicit `boundary`.** All 4,749 historical derivatives had none;
149
+ the retriever's `isEvidenceLayer` fell back to scope matching, so 96.4% were classified
150
+ correctly only because they happened to sit in a `cc:`/`codex:` scope — by luck of naming,
151
+ not by design. The remaining 173 sat in `memory`/`project:*` scopes and silently held
152
+ durable authority. Derived rows are `layer: "evidence"`, `authority: "distillation"`.
153
+ - **`synthesis_contract` version stamp**, so "which code produced this output" stops being
154
+ a guess from timestamps. v2 adds a single-JSON-object constraint: v1 emitted multiple JSON
155
+ objects on 3.3% of calls (all with `finish_reason: stop`, unrelated to truncation), which
156
+ made the whole response unparsable; the same measurement after the constraint is 0.0%.
157
+
158
+ ### Added — memory utility (MemOS value backtracking)
159
+
160
+ - **Value-backtracking join key (P0).** `workflow_observe` now records `readerId` and
161
+ `recalledIds`, supplying the `(memory_id, outcome)` pairing the database never had: one
162
+ side had outcomes without participants (observations did not record memories), the other
163
+ had participants without outcomes (the access tracker recorded hits but not task success).
164
+ New `src/recall-ledger.ts` keeps process-level reader identity and a retrieval-hit ledger;
165
+ managed observations from `resume_context` / `checkpoint_session` carry it automatically.
166
+ New CLI `memory-utility <id>` reports the success rate of tasks a memory took part in.
167
+ - **`utility` column (P1).** `src/memory-utility.ts` weights outcomes (success +0.8 /
168
+ corrected +0.2 / missed −0.3 / failure −0.8) with a 30-day half-life; **it can be
169
+ negative**. It lands in `metadata.utility` and deliberately not in `importance`, which is
170
+ threshold-valued (≥0.95 grants permanent decay exemption) and already written by structured
171
+ memory. Retrieval gained `utilityWeight`, default 0 (off), feeding ranking only — not tier,
172
+ not decay exemption.
173
+ - **Cross-source criterion for promotion (P2).** `scanForPromotions` gained
174
+ `minDistinctSources` (default 2). Counting "how many similar cases" and "how many distinct
175
+ episodes" differ in dimension, not degree — hitting the same problem three times is one
176
+ experience repeated, which belongs on the failure-burst path instead. It **abstains** when
177
+ source pointers are unavailable: only 1.2% of cases across the database carry a `src:` tag,
178
+ so judging strictly would mostly punish three different problems solved on one day.
179
+
180
+ ### Fixed
181
+
182
+ - **A rate-limit reply could trigger an unbounded request storm.** Found by the new contract
183
+ tests. `embedSingle` retried a context-length error by chunking, and each chunk recursed
184
+ back into `embedSingle`, able to re-enter the same branch. Two facts made that
185
+ non-terminating: `smartChunk` returns short text unchanged, so the recursion re-embedded
186
+ the identical string and reproduced the identical error; and the gate
187
+ `/context|too long|exceed|length/i` also matches rate-limit wording — both
188
+ `"Rate limit exceeded"` and `"429 quota exceeded"` trigger chunking. Measured before the
189
+ fix: **61,724 requests in five seconds** against an endpoint asking us to slow down. The
190
+ batch path had the same shape. The missing terminating condition is now present: chunking
191
+ that cannot produce anything smaller than its input throws instead of recursing, and a
192
+ chunk's own embed call cannot re-enter the branch. After: 4 ms, one request, correct error.
193
+ - **Multiple `AccessTracker` instances in one process no longer invent separate readers.**
194
+ `createComponentResolver` caches components per profile, so one session opening two
195
+ profiles produced a phantom second reader, inflating `distinctReaderCount` and the
196
+ skill-promotion read boost. The implementation now matches what `access-tracker.ts` says
197
+ about itself ("one stdio MCP server process ≈ one CC session").
198
+
199
+ ### Documentation
200
+
201
+ - `docs/memory-boundary-contract.md` documents both promotion scans, why their eligibility
202
+ gates differ, and the abstention rule.
203
+ - `retriever.ts` records that `candidatePoolSize` above 20 has never had any effect — both
204
+ candidate legs land in `store.ts`'s `clampInt(limit, 1, 20)`. The clamp has been there
205
+ since the first commit while the 2026-07-16 tuning only touched the retriever, so that
206
+ `30` was inert from the day it landed. Left alone deliberately: raising it means widening
207
+ the candidate pool, which was measured and rejected on 2026-08-22.
208
+
209
+ ### Upgrade notes
210
+
211
+ - **Node 22 or newer is required.** This is the release's only breaking change.
212
+ - Existing LanceDB data opens in place; no export/import step.
213
+ - `promote_synthesis` defaults to dry-run and writes nothing until `dryRun=false`.
214
+ - `audit.jsonl` retrieve rows are larger now that they list what was served. The list is
215
+ capped at 10 entries with `retrievedTotal` marking truncation. Rotation is still manual;
216
+ archive it if it approaches 50 MB.
217
+ - `utilityWeight` defaults to 0 and `metadata.utility` is written only by an explicit
218
+ `memory-utility --apply` run, so the MemOS work above is **available but not yet acting on
219
+ anything**. The resident MCP server was restarted on 2026-08-24, so `readerId` is now being
220
+ written (verified end-to-end on a fresh server: a `workflow_observe` call landed an
221
+ observation carrying `readerId`); `recalledIds` only gets a value when a retrieval hit
222
+ actually occurs, and no row carries `metadata.utility` yet because `--apply` has not been
223
+ run. Real data therefore starts accumulating from this release forward, not before it.
224
+ This is the intended shadow period, not a defect.
225
+
226
+ ### Verification
227
+
228
+ - 2,324 tests pass across 165 files, 0 fail (2,281 at the 3.0 gate → +14 contract, +6 audit
229
+ revision, +8 verbatim self-recall, +15 synthesis promotion). Verified under three
230
+ feature-flag combinations, including the CI default, after CI caught one assertion
231
+ that had been reading the developer's local `.env` rather than product behaviour.
232
+ - The deprecated chain is absent from `npm ls`, `node_modules/`, `bun.lock` and
233
+ `package-lock.json`; installed `openai@7.5.0` reports zero dependencies and
234
+ `engines.node >= 22.0.0`.
235
+ - SDK compatibility was measured, not assumed: 20 sandbox probes against v7.5.0 (9 API
236
+ surface, 11 loopback-HTTP runtime) plus a `tsc --strict` check of all five call sites,
237
+ with a deliberately-broken control run to confirm the type check actually reports errors.
238
+ - `promote_synthesis` was exercised read-only against the live database: 52 contract-stamped
239
+ derivatives exist; `project:codex-self-evolution` yielded 10 candidates from 10 examined,
240
+ `project:antigravity-cli` 4 from 9 (5 below importance), `learnings` 3 from 4 (1 with too
241
+ few distinct sources). Nothing was written.
242
+ - The verbatim self-recall and synthesis-promotion suites were both reverse-verified —
243
+ removing the behaviour each asserts turns the relevant tests red and no others.
244
+
245
+ ### A note on npm history
246
+
247
+ `recallnest@2.6.1` was a maintenance release published before Trusted Publishing was
248
+ configured for this package and therefore carries no build provenance. That describes how it
249
+ was published; it is not retroactively fixable, since the same npm version cannot be
250
+ republished to add provenance.
251
+
3
252
  ## v2.6.0 — Cross-process consistency and reliable distribution (2026-08-13)
4
253
 
5
254
  ### Added
@@ -136,6 +385,49 @@ P0 反馈闭环:让 skill 的 `successCount` / `failureCount` 真有真实使
136
385
 
137
386
  - 基线 1486 → 1520 / 0 fail(+13 新 case 覆盖 outcome 映射 + 错误路径 + 元数据完整性 + 时间戳;+1 顺手修 workflow-observation.test.ts dashboard 漏传 now 参数 pre-existing bug)
138
387
 
388
+ ## v2.3 — Connector ecosystem + source health
389
+
390
+ > Migrated out of README on 2026-08-28. These three entries lived in the README as
391
+ > "New in vX" sections and were never in this file; release dates were not recorded at
392
+ > the time, so none is stated here rather than guessed. They sit between v2.5.0-pre
393
+ > (2026-05-27) and v1.3.1 (2026-03-12) by position in the sequence.
394
+
395
+ v2.2 hardened retrieval quality; v2.3 opens RecallNest to external data sources with a standard connector framework and operational health monitoring.
396
+
397
+ - **Connector-v1 Standard** *(GB-2)* — A JSON format (`ConnectorOutputV1`) that any external script can produce. Obsidian vaults, emails, RSS feeds, log files — normalize once, ingest through the full dedup/embed/extract pipeline. See [`docs/connector-spec.md`](docs/connector-spec.md) for the specification and [`connectors/examples/`](connectors/examples/) for adapter skeletons (email, logs, RSS).
398
+
399
+ - **Obsidian Vault Ingestion** *(GB-1)* — First-party Obsidian connector: scans `.md` files, extracts frontmatter + wikilinks, maps folder structure to tags. One command: `lm ingest --obsidian /path/to/vault`.
400
+
401
+ - **Source Health Monitoring** *(GB-3)* — Every connector ingest writes a heartbeat to `data/source-heartbeat.json`. `data_checkup` flags stale sources (>7d warning, >30d error). `doctor --ci` shows a per-source heartbeat summary with human-readable age.
402
+
403
+ ## v2.2 — Retrieval quality hardening
404
+
405
+ v2.1 added philosophy-informed behavior; v2.2 closes the last three engine-layer gaps identified by a frontier research scan (ACC, PI-LLM, TSM).
406
+
407
+ - **Memory Confidence Meta-tags** *(ACC / Dual-Process UQ)* — Each memory now carries structured `ConfidenceMetadata` (score, reliability tier: `direct` / `inferred` / `hearsay`). Auto-assigned from source on write (`manual` = 0.9, `agent` = 0.7, `conversation_import` = 0.5). Retrieval scores are weighted by confidence. `resume_context` tags low-confidence items with `[低置信]`.
408
+
409
+ - **Interference Detection + Active Forgetting Gate** *(PI-LLM / SleepGate)* — Semantic cluster detection identifies groups of near-duplicate memories competing for retrieval. Enhanced RIF keeps only top-K (default 3) per cluster; extras are demoted 50% instead of removed. Write-time pre-warning: when a scope accumulates ≥5 high-similarity active memories, the weakest is flagged `pending_review`. `data_checkup` reports interference density.
410
+
411
+ - **Temporal Validity Windows** *(TSM / TiMem / Zep)* — `store_memory` accepts `validUntil` (expiration) and `eventTime` (when the event actually happened). `search_memory` supports `validAt` (point-in-time query) and `includeExpired` (demote 80% instead of hide). Auto-GC applies 2× decay acceleration to expired memories.
412
+
413
+ - **Usage-Adjusted Auto-GC** *(off by default)* — `RECALLNEST_USAGE_DECAY=true` enables a GC-only cold-memory penalty when constructive retrieval is also active. Cold memories discount the frequency component instead of changing online retrieval ranking.
414
+
415
+ ## v2.1 — Philosophy-informed memory
416
+
417
+ v2.0 built the operational memory platform; v2.1 added philosophy-informed memory behavior.
418
+
419
+ Five upgrades derived from 9 research dimensions in philosophy of memory, each mapped to concrete engineering:
420
+
421
+ - **Emotion-Aware Decay** *(Affective Memory Theory)* — Memories with strong emotional content decay 20-30% slower. Keyword-based emotion detection computes `salience` (mnemonic significance), which feeds into the Weibull half-life formula and a rebalanced 4-factor evolution score. Zero LLM cost.
422
+
423
+ - **Memory Ethics Layer** *(Right to Be Forgotten / GDPR Art. 17)* — Four privacy tiers (`ephemeral` / `private` / `durable` / `shared`). Cascade forgetting engine that propagates deletion through KG triples, evolution chains, pin assets, and briefs. Full audit trail. `forget_memory` MCP tool for agent-driven deletion.
424
+
425
+ - **Autobiographical Narrative** *(Narrative Identity Theory / Conway's 3-layer model)* — Memories are tagged with `lifePeriod → generalEvent → specificEvent` hierarchy, orthogonal to existing 6 categories. Retrieval pulls narrative siblings. Context rendering groups by life period. Rule-based tagger with EN+CN support.
426
+
427
+ - **Constructive Retrieval** *(Simulation Theory / Michaelian)* — Instead of returning raw stored text, RecallNest now reconstructs context from an expanded candidate set: KG neighbors + evolution chains + cluster members + narrative siblings. Source-map grounded coverage replaces lexical overlap. Contradictions are detected and flagged.
428
+
429
+ - **Predictive Prospective Memory** *(Mental Time Travel / Tulving)* — Heuristic prediction engine that surfaces "you might need this" reminders from behavioral signals: stale checkpoint open loops, corrected workflow observations, high-frequency dormant memories, and uncovered query topics. Zero LLM cost. Auto-expire in 7 days if unaccepted.
430
+
139
431
  ## v1.3.1 — Upstream Sync (2026-03-12)
140
432
 
141
433
  Synced with [CortexReach/memory-lancedb-pro](https://github.com/CortexReach/memory-lancedb-pro) master (v1.1.0-beta.6+).