memtrust-cli 0.3.0__py3-none-any.whl
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.
- memtrust/__init__.py +11 -0
- memtrust/adapters/__init__.py +62 -0
- memtrust/adapters/base.py +2020 -0
- memtrust/adapters/mem0_adapter.py +456 -0
- memtrust/adapters/mem0_direct_adapter.py +1217 -0
- memtrust/adapters/mempalace_adapter.py +1166 -0
- memtrust/adapters/openviking_adapter.py +570 -0
- memtrust/adapters/zep_graphiti_adapter.py +181 -0
- memtrust/adapters/zep_graphiti_selfhosted_adapter.py +882 -0
- memtrust/cli.py +1201 -0
- memtrust/evals/__init__.py +5 -0
- memtrust/evals/compression.py +235 -0
- memtrust/evals/contradiction.py +451 -0
- memtrust/evals/crash_recovery.py +290 -0
- memtrust/evals/embedder_cost.py +163 -0
- memtrust/evals/embedding_drift.py +273 -0
- memtrust/evals/episode_temporal_leak.py +182 -0
- memtrust/evals/extraction_quality.py +373 -0
- memtrust/evals/filter_injection.py +371 -0
- memtrust/evals/language_degradation.py +189 -0
- memtrust/evals/lock_contention.py +263 -0
- memtrust/evals/locomo.py +392 -0
- memtrust/evals/longmemeval.py +249 -0
- memtrust/evals/mempalace_metadata_scale.py +494 -0
- memtrust/evals/migration_rollback.py +276 -0
- memtrust/evals/orphan_cleanup.py +235 -0
- memtrust/evals/ranking_quality.py +303 -0
- memtrust/evals/resource_sync_safety.py +336 -0
- memtrust/evals/result_consistency.py +239 -0
- memtrust/evals/scale_fixtures.py +189 -0
- memtrust/evals/scale_stress.py +502 -0
- memtrust/evals/stats_accuracy.py +240 -0
- memtrust/evals/temporal_kg_boundary.py +281 -0
- memtrust/receipt.py +318 -0
- memtrust/scoring/__init__.py +1 -0
- memtrust/scoring/cost_tracker.py +199 -0
- memtrust/scoring/llm_judge.py +161 -0
- memtrust_cli-0.3.0.dist-info/METADATA +624 -0
- memtrust_cli-0.3.0.dist-info/RECORD +42 -0
- memtrust_cli-0.3.0.dist-info/WHEEL +4 -0
- memtrust_cli-0.3.0.dist-info/entry_points.txt +2 -0
- memtrust_cli-0.3.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: memtrust-cli
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Independent, reproducible benchmark harness for agent-memory backends
|
|
5
|
+
Project-URL: Homepage, https://github.com/RudrenduPaul/memtrust
|
|
6
|
+
Project-URL: Issues, https://github.com/RudrenduPaul/memtrust/issues
|
|
7
|
+
Project-URL: Author - Rudrendu Paul, https://github.com/RudrenduPaul
|
|
8
|
+
Project-URL: Author - Sourav Nandy, https://github.com/Sourav-nandy-ai
|
|
9
|
+
Author: Rudrendu Paul, Sourav Nandy
|
|
10
|
+
License: Apache-2.0
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: agent,benchmark,eval,evaluation,llm,memory
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Testing
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: click<9.0,>=8.1.7
|
|
23
|
+
Requires-Dist: cryptography<49.0,>=48.0.1
|
|
24
|
+
Requires-Dist: httpx<1.0,>=0.27.0
|
|
25
|
+
Requires-Dist: rich<14.0,>=13.7.1
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: mypy<2.0,>=1.10.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: pip-audit<3.0,>=2.7.3; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-cov<6.0,>=5.0.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-httpx<1.0,>=0.36.2; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest<10.0,>=9.0.3; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.5.0; extra == 'dev'
|
|
33
|
+
Provides-Extra: mem0-direct
|
|
34
|
+
Requires-Dist: boto3<2.0,>=1.34.0; extra == 'mem0-direct'
|
|
35
|
+
Requires-Dist: elasticsearch<9.0,>=8.0.0; extra == 'mem0-direct'
|
|
36
|
+
Requires-Dist: fastembed<1.0,>=0.3.1; extra == 'mem0-direct'
|
|
37
|
+
Requires-Dist: google-genai<2.0,>=1.0.0; extra == 'mem0-direct'
|
|
38
|
+
Requires-Dist: mem0ai<3.0,>=2.0.12; extra == 'mem0-direct'
|
|
39
|
+
Requires-Dist: redis<6.0,>=5.0.0; extra == 'mem0-direct'
|
|
40
|
+
Requires-Dist: redisvl<1.0,>=0.3.0; extra == 'mem0-direct'
|
|
41
|
+
Requires-Dist: valkey<7.0,>=6.0.0; extra == 'mem0-direct'
|
|
42
|
+
Provides-Extra: mempalace-direct
|
|
43
|
+
Requires-Dist: mempalace<4.0,>=3.0.0; extra == 'mempalace-direct'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# memtrust
|
|
47
|
+
|
|
48
|
+
Standardized, reproducible benchmarks for agent-memory backends, run against the vendors, not
|
|
49
|
+
published by them.
|
|
50
|
+
|
|
51
|
+
[](https://github.com/RudrenduPaul/memtrust/actions/workflows/ci.yml)
|
|
52
|
+
[](https://github.com/RudrenduPaul/memtrust/blob/main/LICENSE)
|
|
53
|
+
[](https://github.com/RudrenduPaul/memtrust/blob/main/pyproject.toml)
|
|
54
|
+
[](https://pypi.org/project/memtrust/)
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install memtrust
|
|
58
|
+
memtrust run --backends mempalace,mem0,zep,openviking --eval all
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
(For contributing to this repo instead of just running it, see [Development](#development) --
|
|
62
|
+
`pip install -e ".[dev]"` from a clone.)
|
|
63
|
+
|
|
64
|
+
**Contents:** [Why this exists](#why-this-exists) · [What it does](#what-it-does) ·
|
|
65
|
+
[Commands](#commands) · [How this differs](#how-this-differs-from-trusting-a-vendors-own-numbers) ·
|
|
66
|
+
[Contradiction detection](#the-eval-that-actually-matters-contradiction-detection) ·
|
|
67
|
+
[Compression fidelity](#the-eval-built-for-the-other-headline-overclaim-compression-fidelity) ·
|
|
68
|
+
[Temporal-KG boundary](#the-eval-built-from-mempalaces-own-bug-temporal-kg-boundary-detection) ·
|
|
69
|
+
[The landscape](#the-landscape-verified-not-benchmarked) · [Benchmarks](#benchmarks) ·
|
|
70
|
+
[GitHub Actions usage](#github-actions-usage) · [Self-host](#self-host) · [Install](#install) ·
|
|
71
|
+
[Hosted layer](#what-a-hosted-trust-layer-would-add) · [Backend coverage](#backend-coverage) ·
|
|
72
|
+
[Development](#development) · [License](#license) · [Success stories](#success-stories)
|
|
73
|
+
|
|
74
|
+
## Why this exists
|
|
75
|
+
|
|
76
|
+
If you've compared agent-memory backends recently, you've probably noticed each one leads with a
|
|
77
|
+
different accuracy number, on a different benchmark, measured a different way. MemPalace's own
|
|
78
|
+
community already flagged the problem in public. Issue [#27](https://github.com/mempalace/mempalace/issues/27)
|
|
79
|
+
on the MemPalace repository, opened April 7, 2026 and still open, documents a widely-cited 100%
|
|
80
|
+
LongMemEval score that came from hand-tuning on the failed test questions themselves. The held-out
|
|
81
|
+
score is 98.4%, not 100%. A separate 96.6% figure people cite everywhere turns out to be mostly
|
|
82
|
+
ChromaDB's default embeddings doing the work, not MemPalace's own architecture. A "lossless"
|
|
83
|
+
compression claim drops accuracy by 12.4 percentage points in practice. Two internal pull requests
|
|
84
|
+
attempting to fix the reporting problem (#433 and #729) were both closed without merging on April
|
|
85
|
+
12, 2026. As of this writing, the issue has 233 thumbs-up reactions and 39 comments.
|
|
86
|
+
|
|
87
|
+
None of that means MemPalace, or any other backend, doesn't work. It means nobody outside the
|
|
88
|
+
vendor had run the same test, the same way, against every option, and published the raw logs.
|
|
89
|
+
|
|
90
|
+
memtrust does that. It runs LongMemEval, LoCoMo, and a growing set of evals built specifically for
|
|
91
|
+
this project -- 14 of them as of this writing, registered in the CLI's `--eval` flag, plus a
|
|
92
|
+
fifteenth (temporal-KG boundary detection) that exists as a tested module but isn't wired into the
|
|
93
|
+
CLI yet. The two that matter most for understanding what this project is actually for:
|
|
94
|
+
contradiction detection, because neither LongMemEval nor LoCoMo tests the question that actually
|
|
95
|
+
matters once a memory system sits underneath a production agent -- what happens when a new fact
|
|
96
|
+
contradicts an old one? Does the backend flag the conflict? Silently overwrite the old fact with no
|
|
97
|
+
audit trail? Serve whichever version it happens to retrieve first? None of the four backends this
|
|
98
|
+
project tracks publish a number for that. And compression/round-trip fidelity, built to directly
|
|
99
|
+
test claims like the "lossless" one above: it stores content, retrieves it, and scores literal
|
|
100
|
+
reconstruction fidelity rather than semantic accuracy, per operating mode a backend exposes (see
|
|
101
|
+
`MemoryBackendAdapter.supported_modes`) -- the mechanism that would let a contributor with live
|
|
102
|
+
MemPalace credentials actually reproduce the 12.4-point compressed-mode accuracy drop
|
|
103
|
+
mempalace/mempalace#27 documents, instead of just citing it. **Neither has been run against any
|
|
104
|
+
live backend as of this writing** -- see `docs/methodology.md`. The other evals -- ranking quality,
|
|
105
|
+
crash recovery, extraction quality, embedding drift, scale/volume stress, lock contention, stats
|
|
106
|
+
accuracy, orphan cleanup, result consistency, migration rollback, filter injection, resource-sync
|
|
107
|
+
safety, and temporal-KG boundary detection -- each grew out of a specific real bug report against
|
|
108
|
+
one of the four tracked backends; see "Success stories" below for the full list.
|
|
109
|
+
|
|
110
|
+
## What it does
|
|
111
|
+
|
|
112
|
+
Every command below was actually run against this repo, with zero vendor API keys configured, to
|
|
113
|
+
produce the output shown. Nothing here is simulated.
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
$ memtrust run --backends mempalace,mem0,zep,openviking --eval all
|
|
117
|
+
memtrust 0.1.0 -- run_id=mt_2026-07-17T155402Z
|
|
118
|
+
Backends: mempalace, mem0, zep, openviking Evals: longmemeval, locomo, contradiction,
|
|
119
|
+
resource_sync_safety, compression, ranking_quality, scale_stress, embedding_drift, crash_recovery,
|
|
120
|
+
extraction_quality, migration_rollback, filter_injection, lock_contention, stats_accuracy,
|
|
121
|
+
orphan_cleanup, result_consistency
|
|
122
|
+
|
|
123
|
+
mempalace: SKIPPED (not configured) -- mempalace is not configured: environment variable
|
|
124
|
+
MEMPALACE_STORAGE_PATH is not set. Skipping this backend. See docs/methodology.md for setup
|
|
125
|
+
instructions.
|
|
126
|
+
mem0: SKIPPED (not configured) -- mem0 is not configured: environment variable MEM0_API_KEY is not
|
|
127
|
+
set. Skipping this backend. See docs/methodology.md for setup instructions.
|
|
128
|
+
zep: SKIPPED (not configured) -- zep is not configured: environment variable ZEP_API_KEY is not set.
|
|
129
|
+
Skipping this backend. See docs/methodology.md for setup instructions.
|
|
130
|
+
openviking: SKIPPED (not configured) -- openviking is not configured: environment variable
|
|
131
|
+
OPENVIKING_API_KEY is not set. Skipping this backend. See docs/methodology.md for setup
|
|
132
|
+
instructions.
|
|
133
|
+
|
|
134
|
+
Cost: $0.00 (no LLM-judged evals ran -- structural evals only, or judge not configured)
|
|
135
|
+
|
|
136
|
+
Full report: memtrust-report-2026-07-17.json
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
That's the real, reproducible behavior of a fresh clone with no credentials: every backend reports
|
|
140
|
+
SKIPPED, the command exits cleanly, and a valid JSON report is still written. `memtrust --version`
|
|
141
|
+
currently prints `0.1.0` even though the package installs as `0.2.0` on PyPI -- a stale hardcoded
|
|
142
|
+
string in `src/memtrust/__init__.py` that hasn't caught up with `pyproject.toml`, shown here exactly
|
|
143
|
+
as it actually runs rather than smoothed over. Set the relevant environment variable for any backend
|
|
144
|
+
you want to actually test (`MEM0_API_KEY`, `ZEP_API_KEY`, `OPENVIKING_API_KEY`,
|
|
145
|
+
`MEMPALACE_STORAGE_PATH`) and that backend runs for real against its live API instead of being
|
|
146
|
+
skipped.
|
|
147
|
+
|
|
148
|
+
The eval logic itself is proven offline, against the bundled synthetic fixtures and, for several
|
|
149
|
+
adapters, the real installed vendor packages with only the network boundary mocked, by the test
|
|
150
|
+
suite:
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
$ pytest --cov=memtrust --cov-report=term-missing
|
|
154
|
+
...
|
|
155
|
+
Name Stmts Miss Cover
|
|
156
|
+
-------------------------------------------------------------------------------------
|
|
157
|
+
src/memtrust/adapters/base.py 290 1 99%
|
|
158
|
+
src/memtrust/adapters/mempalace_adapter.py 265 15 94%
|
|
159
|
+
src/memtrust/adapters/mem0_adapter.py 140 12 91%
|
|
160
|
+
src/memtrust/adapters/mem0_direct_adapter.py 281 34 88%
|
|
161
|
+
src/memtrust/adapters/openviking_adapter.py 178 18 90%
|
|
162
|
+
src/memtrust/adapters/zep_graphiti_adapter.py 63 3 95%
|
|
163
|
+
src/memtrust/adapters/zep_graphiti_selfhosted_adapter.py 165 24 85%
|
|
164
|
+
src/memtrust/evals/contradiction.py 127 2 98%
|
|
165
|
+
src/memtrust/evals/compression.py 86 1 99%
|
|
166
|
+
src/memtrust/evals/temporal_kg_boundary.py 90 4 96%
|
|
167
|
+
src/memtrust/receipt.py 118 10 92%
|
|
168
|
+
-------------------------------------------------------------------------------------
|
|
169
|
+
TOTAL 4130 256 94%
|
|
170
|
+
|
|
171
|
+
580 passed, 8 skipped in 3.31s
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
580 passing tests across 33 source modules, 94% overall statement coverage, 98% on the
|
|
175
|
+
contradiction-detection eval, 99% on compression/round-trip fidelity, 96% on the new temporal-KG
|
|
176
|
+
boundary eval, 94-99% across the adapter layer. The 8 skips are live-`mempalace`-package tests that
|
|
177
|
+
only run with the optional `mempalace-direct` extra installed (`pip install -e
|
|
178
|
+
'.[dev,mempalace-direct]'`). Every test mocks its HTTP or wire
|
|
179
|
+
layer, or uses an in-memory fake backend -- none of them touch a real network, though a meaningful
|
|
180
|
+
share of the adapter tests now import and exercise *real installed vendor classes* directly
|
|
181
|
+
(`mem0ai==2.0.12`'s embedder and vector-store modules, and -- gated behind the optional
|
|
182
|
+
`mempalace-direct` extra -- the real `mempalace.mcp_server` functions), mocking only the outermost
|
|
183
|
+
network or wire-client boundary rather than the whole library. `graphiti-core` is not installed in
|
|
184
|
+
this environment, so its self-hosted adapter's tests still run against a hand-written Protocol
|
|
185
|
+
double built to match the real package's confirmed method signatures, not the real classes -- see
|
|
186
|
+
`docs/methodology.md`'s adapter confidence table for exactly which claim rests on which kind of
|
|
187
|
+
verification.
|
|
188
|
+
|
|
189
|
+
## Commands
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
$ memtrust --help
|
|
193
|
+
Usage: memtrust [OPTIONS] COMMAND [ARGS]...
|
|
194
|
+
|
|
195
|
+
memtrust: an independent, reproducible benchmark harness for agent-memory
|
|
196
|
+
backends.
|
|
197
|
+
|
|
198
|
+
Options:
|
|
199
|
+
--version Show the version and exit.
|
|
200
|
+
--help Show this message and exit.
|
|
201
|
+
|
|
202
|
+
Commands:
|
|
203
|
+
keygen Generate a new Ed25519 keypair for signing `memtrust run`...
|
|
204
|
+
report Read a prior `memtrust run` JSON report and print a formatted...
|
|
205
|
+
run Run the eval suite against the requested backends.
|
|
206
|
+
verify Verify a signed receipt produced by `memtrust run --sign`.
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
| Command | Flags | What it does |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| `memtrust run` | `--backends TEXT` comma-separated list or `all` (default `all`) · `--eval TEXT` comma-separated from `longmemeval,locomo,contradiction,resource_sync_safety,compression,ranking_quality,scale_stress,embedding_drift,crash_recovery,extraction_quality,migration_rollback,filter_injection,lock_contention,stats_accuracy,orphan_cleanup,result_consistency`, or `all` (default `all`) · `--output FILE` (defaults to `./memtrust-report-<date>.json`) · `--locomo-dataset-path FILE` points the LoCoMo eval at a real, downloaded `locomo10.json` instead of the bundled synthetic fixture (memtrust does not bundle or auto-fetch the real dataset) · `--locomo-exclude-question-ids-file FILE` excludes known-bad-ground-truth LoCoMo question IDs from scoring · `--scale-stress-n-records INTEGER` (default `500`) sets how many synthetic records the scale-stress eval stores and re-queries · `--sign FILE` writes a signed `<output>.receipt.json` alongside the report, proving it was produced by the holder of the given Ed25519 private key | Runs the eval suite against the requested backends. A backend without its credential env var set prints `SKIPPED` and the run continues -- this command never crashes on missing credentials. |
|
|
212
|
+
| `memtrust report REPORT_PATH` | positional path to a prior JSON report | Reads a report written by `memtrust run` and prints a formatted summary. |
|
|
213
|
+
| `memtrust keygen` | -- | Generates a new Ed25519 keypair for signing reports with `run --sign`. |
|
|
214
|
+
| `memtrust verify RECEIPT_PATH` | -- | Verifies a signed receipt produced by `memtrust run --sign`; a tampered or mismatched receipt fails verification. |
|
|
215
|
+
| `memtrust --version` | -- | Prints the installed version. Currently prints `0.1.0`, one release behind the `0.2.0` this package actually installs as -- see the note above. |
|
|
216
|
+
|
|
217
|
+
The temporal-KG boundary eval (`src/memtrust/evals/temporal_kg_boundary.py`,
|
|
218
|
+
`run_temporal_kg_boundary_eval()`) is not yet wired into `--eval`'s known-eval list -- it exists as
|
|
219
|
+
a tested module and a MemPalace-specific capability, callable directly, not yet a `memtrust run
|
|
220
|
+
--eval temporal_kg_boundary` option. See its own section below.
|
|
221
|
+
|
|
222
|
+
Every line above came straight from running `memtrust --help`, `memtrust run --help`, and
|
|
223
|
+
`memtrust report --help` against this repo. Nothing here is invented.
|
|
224
|
+
|
|
225
|
+
## How this differs from trusting a vendor's own numbers
|
|
226
|
+
|
|
227
|
+
Every backend memtrust tracks publishes its own benchmark numbers. None of them publish the same
|
|
228
|
+
benchmark, scored the same way, with the same held-out discipline. memtrust doesn't ask you to
|
|
229
|
+
trust it instead: it asks you to read the raw logs. Every run's methodology, prompt templates,
|
|
230
|
+
dataset versions, and scoring rubric are published in `docs/methodology.md`, versioned alongside
|
|
231
|
+
the code that produced them. If the methodology has a flaw, it's a flaw you can point to in a
|
|
232
|
+
specific file and line, not something buried in a vendor's internal eval pipeline.
|
|
233
|
+
|
|
234
|
+
General-purpose LLM eval frameworks (promptfoo, DeepEval, RAGAS, and similar tools) are mature and
|
|
235
|
+
widely used, but none of them ship a memory-backend adapter abstraction or a contradiction-
|
|
236
|
+
detection eval out of the box -- they're built for RAG quality, red-teaming, and general prompt
|
|
237
|
+
evaluation, not for comparing how different memory systems handle a fact that changes over time.
|
|
238
|
+
memtrust is narrower and more specific on purpose.
|
|
239
|
+
|
|
240
|
+
## The landscape (verified, not benchmarked)
|
|
241
|
+
|
|
242
|
+
Real, publicly checkable numbers as of this writing (`gh api repos/<org>/<repo>`), not
|
|
243
|
+
memtrust-run scores -- accuracy and contradiction-handling comparisons stay in the "Benchmarks"
|
|
244
|
+
section below until a live run actually produces them:
|
|
245
|
+
|
|
246
|
+
| Backend | GitHub stars | Self-reported description |
|
|
247
|
+
|---|---|---|
|
|
248
|
+
| [MemPalace](https://github.com/MemPalace/mempalace) | 57,268 | "The best-benchmarked open-source AI memory system. And it's free." |
|
|
249
|
+
| [Mem0](https://github.com/mem0ai/mem0) | 60,688 | "Universal memory layer for AI Agents" |
|
|
250
|
+
| [Zep / Graphiti](https://github.com/getzep/graphiti) | 28,648 | "Build Real-Time Knowledge Graphs for AI Agents" |
|
|
251
|
+
| [OpenViking](https://github.com/volcengine/OpenViking) | 26,639 | "Self-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills." |
|
|
252
|
+
|
|
253
|
+
None of these numbers say anything about which backend handles a contradicted fact correctly --
|
|
254
|
+
that's the whole reason the harness exists. Star count measures adoption, not correctness.
|
|
255
|
+
|
|
256
|
+
## The eval that actually matters: contradiction detection
|
|
257
|
+
|
|
258
|
+
LongMemEval and LoCoMo both measure recall: can the backend remember a fact you told it earlier.
|
|
259
|
+
That's necessary but not sufficient. The harder question is what a backend does when two facts
|
|
260
|
+
conflict: you tell it your meeting is at 2pm, then later say it moved to 3pm. Does it flag the
|
|
261
|
+
change? Overwrite silently? Serve whichever one it retrieves first? `memtrust`'s classifier stores
|
|
262
|
+
a fact, stores a contradicting fact, queries for it, then checks the actual retrieved content for
|
|
263
|
+
both values, rather than trusting whatever conflict signal the adapter itself reports. See
|
|
264
|
+
`src/memtrust/evals/contradiction.py` and the scoring-logic section of `docs/methodology.md` for
|
|
265
|
+
exactly how that classification works.
|
|
266
|
+
|
|
267
|
+
## The eval built for the other headline overclaim: compression fidelity
|
|
268
|
+
|
|
269
|
+
mempalace/mempalace#27 documents two separate overclaims, not one: the LongMemEval score gap
|
|
270
|
+
described above, and a "lossless" compression claim that measured 12.4 percentage points lower in
|
|
271
|
+
practice under a compressed operating mode. memtrust could not previously reproduce that second
|
|
272
|
+
number at all -- there was no way to tell an adapter "run this under mode X vs mode Y" through the
|
|
273
|
+
shared interface. `MemoryBackendAdapter.store()`/`query()` now accept an optional `mode: str |
|
|
274
|
+
None` parameter, and `MemoryBackendAdapter.supported_modes` lets an adapter declare which mode
|
|
275
|
+
strings it actually understands (`MemPalaceAdapter.supported_modes` is `("raw", "AAAK")`, the two
|
|
276
|
+
names mempalace/mempalace#27 itself uses -- see `src/memtrust/adapters/mempalace_adapter.py` for
|
|
277
|
+
the exact provenance and confidence caveat on those names). Adapters with no mode variants accept
|
|
278
|
+
and ignore the parameter, so this is a purely additive, backward-compatible interface change.
|
|
279
|
+
|
|
280
|
+
`src/memtrust/evals/compression.py` runs the same store-then-retrieve round trip once per mode a
|
|
281
|
+
backend reports, and scores each round trip with a direct, deterministic character-level
|
|
282
|
+
similarity ratio (`fidelity_ratio()`, via `difflib.SequenceMatcher` -- not an LLM judge, since a
|
|
283
|
+
"lossless" claim is a literal-reconstruction claim, not a semantic one). This is what would let a
|
|
284
|
+
contributor with live MemPalace credentials point `memtrust run --eval compression` at it and
|
|
285
|
+
reproduce a "raw vs AAAK" fidelity gap directly. **As of this writing this eval has not been run
|
|
286
|
+
against any live backend** -- see `docs/methodology.md` for the same live-credentials caveat that
|
|
287
|
+
applies to every other eval in this table.
|
|
288
|
+
|
|
289
|
+
## The eval built from MemPalace's own bug: temporal-KG boundary detection
|
|
290
|
+
|
|
291
|
+
MemPalace/mempalace#1913 (fixed by merged PR#1914, contributor ggettert) described a real,
|
|
292
|
+
concrete bug: `_temporal_filter_sql`'s `as_of` point-in-time query used a closed interval on both
|
|
293
|
+
ends, so a fact whose `valid_to` equaled the query's exact `as_of` instant still matched. Hand-roll
|
|
294
|
+
a fact change as `kg_invalidate(ended=T)` immediately followed by `kg_add(valid_from=T)` at the
|
|
295
|
+
identical boundary instant -- the exact pattern MemPalace's own pre-fix agent guidance told every
|
|
296
|
+
caller to do -- and an `as_of=T` query returns both the just-ended fact and its just-started
|
|
297
|
+
successor at once, so a single-valued fact reports two contradictory answers with no error.
|
|
298
|
+
`src/memtrust/evals/temporal_kg_boundary.py` reproduces that exact hand-rolled sequence against
|
|
299
|
+
`MemPalaceAdapter`'s `kg_add()`/`kg_invalidate()`/`kg_query()` and classifies the result with a new
|
|
300
|
+
`TemporalBoundarySignal` taxonomy, distinct from `ConflictSignal` and `RankingSignal` because it
|
|
301
|
+
concerns one narrow, structurally different failure: two facts sharing one instant, not a
|
|
302
|
+
contradiction across time or a ranking-order question.
|
|
303
|
+
|
|
304
|
+
Honest scope, stated the same way this project states it for every other eval: the real
|
|
305
|
+
`mempalace` PyPI package is not installed in this build environment, and PR#1914's fix had not
|
|
306
|
+
shipped in a released `mempalace` version as of this adapter's live-verified 3.5.0 build -- it
|
|
307
|
+
lands under the package's `[Unreleased]` changelog section. `tests/test_temporal_kg_boundary.py`
|
|
308
|
+
proves the *classification logic* is correct against two hand-written fake implementations that
|
|
309
|
+
reproduce the confirmed pre-#1914 (closed-interval) and post-#1914 (half-open-interval) SQL
|
|
310
|
+
comparison exactly. **This has not been run against a live MemPalace instance.** It also isn't
|
|
311
|
+
wired into `memtrust run --eval` yet -- call `run_temporal_kg_boundary_eval()` directly, or see the
|
|
312
|
+
test suite, until that CLI surface exists.
|
|
313
|
+
|
|
314
|
+
## Benchmarks
|
|
315
|
+
|
|
316
|
+
**Not yet measured against live backends.** This repo was built without API credentials for
|
|
317
|
+
MemPalace, Mem0, Zep, or OpenViking. Publishing a number here without actually running the harness
|
|
318
|
+
against a live backend would be exactly the kind of unverifiable claim this project exists to
|
|
319
|
+
push back on, so there isn't one.
|
|
320
|
+
|
|
321
|
+
To produce real numbers:
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
export MEM0_API_KEY=... # and/or
|
|
325
|
+
export ZEP_API_KEY=...
|
|
326
|
+
export OPENVIKING_API_KEY=...
|
|
327
|
+
export MEMPALACE_STORAGE_PATH=...
|
|
328
|
+
export MEMTRUST_JUDGE_API_KEY=... # needed for LongMemEval/LoCoMo grading; contradiction-detection doesn't need it
|
|
329
|
+
|
|
330
|
+
memtrust run --backends mempalace,mem0,zep,openviking --eval all
|
|
331
|
+
memtrust report memtrust-report-<date>.json
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
The command prints per-backend accuracy and contradiction-handling rates, writes a full JSON
|
|
335
|
+
report, and prints an estimated cost for any LLM-judged evals that ran. `MemPalaceAdapter`'s
|
|
336
|
+
drawer and knowledge-graph calls are now live-verified against a real installed instance (see
|
|
337
|
+
"Backend coverage" below), but OpenViking's memory-write/query paths, and parts of the
|
|
338
|
+
self-hosted Mem0 and Zep/Graphiti adapters, are still built against best-effort interpretations of
|
|
339
|
+
documented or source-read product concepts rather than a live-confirmed API -- see the confidence
|
|
340
|
+
table in `docs/methodology.md` before treating any adapter's output as authoritative, and consider
|
|
341
|
+
that table's gaps a standing invitation to contribute a fix.
|
|
342
|
+
|
|
343
|
+
**Labeling requirement for any future `accuracy` figure published here.** LongMemEval and LoCoMo
|
|
344
|
+
`accuracy` grades the LLM judge's verdict on raw retrieved-record content directly -- there is no
|
|
345
|
+
answer-generation step in either eval runner. This is not the same measurement as the official
|
|
346
|
+
LongMemEval/LoCoMo leaderboards' generate-then-judge QA-accuracy scores. Any `accuracy` number
|
|
347
|
+
this project publishes for those two evals must be labeled "retrieval-graded accuracy," not bare
|
|
348
|
+
"accuracy," and must not be directly compared to leaderboard figures without that caveat. See
|
|
349
|
+
`docs/methodology.md`'s "Retrieval-graded accuracy vs. generated-answer accuracy" section.
|
|
350
|
+
|
|
351
|
+
## GitHub Actions usage
|
|
352
|
+
|
|
353
|
+
Run the suite on a schedule and publish results to the leaderboard:
|
|
354
|
+
|
|
355
|
+
```yaml
|
|
356
|
+
name: memtrust-leaderboard
|
|
357
|
+
on:
|
|
358
|
+
schedule:
|
|
359
|
+
- cron: "0 9 * * 1" # weekly
|
|
360
|
+
workflow_dispatch: {}
|
|
361
|
+
|
|
362
|
+
jobs:
|
|
363
|
+
benchmark:
|
|
364
|
+
runs-on: ubuntu-latest
|
|
365
|
+
steps:
|
|
366
|
+
- uses: actions/checkout@v4
|
|
367
|
+
- uses: actions/setup-python@v5
|
|
368
|
+
with:
|
|
369
|
+
python-version: "3.12"
|
|
370
|
+
- run: pip install memtrust
|
|
371
|
+
- run: memtrust run --backends mempalace,mem0,zep,openviking --eval all --output leaderboard/data.json
|
|
372
|
+
env:
|
|
373
|
+
MEM0_API_KEY: ${{ secrets.MEM0_API_KEY }}
|
|
374
|
+
ZEP_API_KEY: ${{ secrets.ZEP_API_KEY }}
|
|
375
|
+
OPENVIKING_API_KEY: ${{ secrets.OPENVIKING_API_KEY }}
|
|
376
|
+
MEMTRUST_JUDGE_API_KEY: ${{ secrets.MEMTRUST_JUDGE_API_KEY }}
|
|
377
|
+
- run: git add leaderboard/data.json && git commit -m "Update leaderboard" && git push
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
This repo's own CI (`.github/workflows/ci.yml`) runs lint, type-check, test, and a dependency
|
|
381
|
+
security audit on every push and pull request -- no vendor credentials required, since every test
|
|
382
|
+
runs fully offline.
|
|
383
|
+
|
|
384
|
+
## Self-host
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
git clone https://github.com/RudrenduPaul/memtrust
|
|
388
|
+
cd memtrust
|
|
389
|
+
pip install -e ".[dev]"
|
|
390
|
+
export MEM0_API_KEY=...
|
|
391
|
+
memtrust run --backends mem0 --eval all
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Point an adapter at your own backend, or run the suite against your own conversation data instead
|
|
395
|
+
of the bundled synthetic fixtures (see `docs/methodology.md`'s note on swapping in the real
|
|
396
|
+
LongMemEval/LoCoMo datasets). Nothing leaves your machine unless you choose to publish it.
|
|
397
|
+
|
|
398
|
+
## Install
|
|
399
|
+
|
|
400
|
+
### npx (agent-native)
|
|
401
|
+
|
|
402
|
+
> **PyPI is live; the npm wrapper is publish-ready but not yet published.** `pip install memtrust`
|
|
403
|
+
> works today -- version 0.2.0 is on PyPI. The `memtrust-cli` npm package in `npm/memtrust-cli/` in
|
|
404
|
+
> this repo is built, tested, and passes both `npm pack --dry-run` and `npm publish --dry-run`
|
|
405
|
+
> cleanly (re-verified this session), but has not actually been pushed to the npm registry yet --
|
|
406
|
+
> `npm install memtrust-cli` still 404s as of this writing. The command below is the real,
|
|
407
|
+
> working distribution path once that publish happens; nothing about it is speculative except the
|
|
408
|
+
> "it's live on npm" part.
|
|
409
|
+
|
|
410
|
+
For CI and agent runners that have Node.js available but not necessarily a Python toolchain:
|
|
411
|
+
|
|
412
|
+
```bash
|
|
413
|
+
npx memtrust-cli run --backends mempalace,mem0,zep,openviking --eval all
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
The npm package is named `memtrust-cli` so it is unambiguous as a CLI tool at a glance (and so it
|
|
417
|
+
doesn't collide with any future `memtrust` JS library package). `npx` always resolves the package
|
|
418
|
+
name to its matching `bin` entry automatically, so `npx memtrust-cli ...` is what reliably works
|
|
419
|
+
for a zero-install first run. Once installed, the package also exposes the shorter `memtrust`
|
|
420
|
+
command as a second `bin` alias -- matching the underlying Python CLI's own command name -- so you
|
|
421
|
+
are not stuck typing `memtrust-cli` for every subsequent invocation; `memtrust run ...` works too.
|
|
422
|
+
|
|
423
|
+
This is not a zero-dependency install: `npx memtrust-cli` still fetches `memtrust` from PyPI on
|
|
424
|
+
first use. What it removes is no Python toolchain to provision by hand -- `npx memtrust-cli`
|
|
425
|
+
handles the interpreter and package fetch for you via a bundled, verified copy of Astral's
|
|
426
|
+
[`uv`](https://github.com/astral-sh/uv). Each platform package bundles a genuine, SHA-256-verified
|
|
427
|
+
copy of `uv`'s own GitHub release binary (fetched at npm package-publish time, never at end-user
|
|
428
|
+
install time), and its `bin` shim runs `uv tool run --from memtrust memtrust <args>`, which
|
|
429
|
+
transparently bootstraps a Python interpreter and installs `memtrust` from PyPI, caching it after
|
|
430
|
+
the first run.
|
|
431
|
+
|
|
432
|
+
## What a hosted trust layer would add
|
|
433
|
+
|
|
434
|
+
The harness, adapters, and leaderboard in this repo are the entire OSS surface, and they're
|
|
435
|
+
sufficient on their own to compare backends. A hosted layer on top of this -- described here, not
|
|
436
|
+
built -- would add continuous regression monitoring that re-runs the suite automatically whenever
|
|
437
|
+
a tracked backend ships a new release, private scorecards that run the same methodology against a
|
|
438
|
+
team's own data shape instead of the public sample fixtures, and a compliance-report export for
|
|
439
|
+
teams whose security or legal review needs a documented third-party artifact rather than a
|
|
440
|
+
free-text summary. None of that exists yet. If it's ever built, it stays additive to the free
|
|
441
|
+
harness, never a requirement for using it.
|
|
442
|
+
|
|
443
|
+
## Backend coverage
|
|
444
|
+
|
|
445
|
+
The MemPalace row below used to say "needs verification against a live instance" -- it needed more
|
|
446
|
+
than that. Every prior version of `MemPalaceAdapter` called a `mempalace.Palace` class
|
|
447
|
+
(`Palace(storage_path=...)` exposing `.remember()`/`.recall()`/`.invalidate()`) that never existed
|
|
448
|
+
in the real, installed package. `python3 -c "import mempalace; hasattr(mempalace, 'Palace')"`
|
|
449
|
+
returns `False`; grepping every `class` definition across the installed package turns up nothing
|
|
450
|
+
named `Palace` anywhere. Every test that appeared to pass before this rewrite was exercising a
|
|
451
|
+
hand-written fake standing in for that guess, never the real thing -- `store()`/`query()`/
|
|
452
|
+
`update()` had never actually worked against a live MemPalace install, in this project's entire
|
|
453
|
+
history, until this rewrite. `src/memtrust/adapters/mempalace_adapter.py` was rewritten from
|
|
454
|
+
scratch against the real, plain module-level functions in `mempalace.mcp_server`
|
|
455
|
+
(`tool_add_drawer`, `tool_search`, `tool_update_drawer`, `tool_delete_drawer`,
|
|
456
|
+
`tool_kg_add`/`tool_kg_invalidate`/`tool_kg_query`) -- every return shape documented in the
|
|
457
|
+
adapter's module docstring was captured by calling those functions live against a real, local
|
|
458
|
+
chromadb-backed palace, not read off a docstring and trusted. It's the kind of mistake this whole
|
|
459
|
+
project exists to catch in other people's benchmarks; finding it in memtrust's own adapter and
|
|
460
|
+
shipping the fix in the open, rather than quietly patching it, is the more useful story.
|
|
461
|
+
|
|
462
|
+
| Backend | Adapter status | Confidence (see docs/methodology.md) |
|
|
463
|
+
|---|---|---|
|
|
464
|
+
| MemPalace | Implemented -- drawer API + knowledge-graph API | High on the real `mempalace.mcp_server` functions this adapter now calls, live-verified against an installed `mempalace` 3.5.0 instance (see above). Still best-effort on compression-mode names (`"raw"`/`"AAAK"`) and on whether `degraded_retrieval` warnings are ever populated by the installed version -- see the adapter's module docstring for both caveats stated plainly. |
|
|
465
|
+
| Mem0 | Implemented -- hosted Platform API, self-hosted OSS server, and a direct in-process library adapter | High on the hosted Platform API and on what the installed `mem0ai==2.0.12` library's embedder/vector-store code actually does (confirmed by reading its real source, exercised directly in tests); medium-high on the self-hosted OSS server's route shape (confirmed from source, not run against a live server). |
|
|
466
|
+
| Zep / Graphiti | Implemented -- hosted Zep Platform API and a self-hosted `graphiti-core` adapter | Medium-high on the hosted API's documented contradiction-handling behavior; medium on the self-hosted adapter's wire-level shape (every method signature confirmed by reading `graphiti-core`'s real source, not by running it against a live Neo4j/FalkorDB instance -- the package isn't installed in this environment). |
|
|
467
|
+
| OpenViking | Implemented | Medium on architecture, low on exact memory-write/query paths -- still the adapter most likely to need correction against a live instance. |
|
|
468
|
+
|
|
469
|
+
Adding a backend adapter is the primary contribution path -- see `CONTRIBUTING.md`.
|
|
470
|
+
|
|
471
|
+
## Development
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
pip install -e ".[dev]"
|
|
475
|
+
ruff check . && ruff format --check .
|
|
476
|
+
mypy --strict src/memtrust
|
|
477
|
+
pytest --cov=memtrust --cov-report=term-missing --cov-fail-under=80
|
|
478
|
+
pip-audit
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
`.pre-commit-config.yaml` wires ruff and mypy into `pre-commit` if you'd rather run these on every
|
|
482
|
+
commit than remember to run them by hand.
|
|
483
|
+
|
|
484
|
+
## License
|
|
485
|
+
|
|
486
|
+
Apache 2.0. See `LICENSE`.
|
|
487
|
+
|
|
488
|
+
## Success stories
|
|
489
|
+
|
|
490
|
+
197 real issues/PRs filed by real contributors against MemPalace, mem0, Zep/Graphiti, and
|
|
491
|
+
OpenViking have been independently root-caused against this codebase: does the solution, as it
|
|
492
|
+
actually exists today, let you diagnose or resolve what was reported? 55 (28%) verify as a clean
|
|
493
|
+
PASS, 16 (8%) as PARTIAL (evidence captured, needs a human to
|
|
494
|
+
interpret further, or only part of the issue is covered), 42 (21%) as a genuine capability gap this
|
|
495
|
+
harness doesn't close yet, and 84 (43%) as not actually applicable (feature requests,
|
|
496
|
+
already-fixed-upstream, or genuinely out of scope). Every verdict below has been re-verified live
|
|
497
|
+
against the current codebase by a reviewer independent of whoever built the fix, not just cited
|
|
498
|
+
from a changelog. Full write-ups and validation evidence are tracked internally; the summary here
|
|
499
|
+
is for anyone deciding whether this harness would have caught their own bug.
|
|
500
|
+
|
|
501
|
+
**The headline story is about memtrust's own bug, not a vendor's.** Every version of
|
|
502
|
+
`MemPalaceAdapter` before this rewrite called a `mempalace.Palace` class -- `Palace(storage_path=
|
|
503
|
+
...)` exposing `.remember()`/`.recall()`/`.invalidate()` -- that never existed in the real,
|
|
504
|
+
installed package. `python3 -c "import mempalace; hasattr(mempalace, 'Palace')"` returns `False`;
|
|
505
|
+
nothing named `Palace` appears anywhere in the installed package's source. Every test that appeared
|
|
506
|
+
to pass was exercising a hand-written fake standing in for that guess -- `store()`/`query()`/
|
|
507
|
+
`update()` had never once worked against a live MemPalace install. `src/memtrust/adapters/
|
|
508
|
+
mempalace_adapter.py` was rewritten against the real `mempalace.mcp_server` functions, with every
|
|
509
|
+
documented return shape captured by calling them live against a real local instance. A project
|
|
510
|
+
built to catch other vendors overclaiming found the same failure mode in its own code, and the fix
|
|
511
|
+
shipped in the open rather than quietly. See "Backend coverage" above for the full account.
|
|
512
|
+
|
|
513
|
+
**MemPalace**
|
|
514
|
+
- [#1754](https://github.com/MemPalace/mempalace/pull/1754) (@rodboev): a checkpoint recovery fix
|
|
515
|
+
for silently quarantined dim-None pickles. memtrust's contradiction eval couldn't previously tell
|
|
516
|
+
"silently quarantined" apart from "no update primitive at all"; it now can
|
|
517
|
+
(`ConflictSignal.EMPTY_OR_LOST`).
|
|
518
|
+
- [#1929](https://github.com/MemPalace/mempalace/pull/1929) (@jrzmurray): a fix for NUL bytes
|
|
519
|
+
silently corrupting a ChromaDB index. memtrust's `store()` used to trust "no exception" as proof
|
|
520
|
+
of a durable write; an opt-in read-after-write verification step now catches this.
|
|
521
|
+
- [#1450](https://github.com/MemPalace/mempalace/pull/1450) (@lealbrunocalhau): a fix for an empty
|
|
522
|
+
embedding response getting scored as a wrong answer instead of flagged as infra failure. Same
|
|
523
|
+
fix as #1754 above.
|
|
524
|
+
- [#1823](https://github.com/MemPalace/mempalace/pull/1823) / [#1543](https://github.com/MemPalace/mempalace/pull/1543)
|
|
525
|
+
(@fatkobra): lock and write-integrity fixes that pointed at the same read-after-write gap #1929
|
|
526
|
+
closed.
|
|
527
|
+
- [#1913](https://github.com/MemPalace/mempalace/issues/1913) / [PR#1914](https://github.com/MemPalace/mempalace/pull/1914)
|
|
528
|
+
(@ggettert): a temporal-KG `as_of` boundary bug where a fact ending at exactly the query instant
|
|
529
|
+
still matched alongside its successor. memtrust's new temporal-KG boundary eval reproduces the
|
|
530
|
+
exact hand-rolled `kg_invalidate()`-then-`kg_add()` sequence that triggers it -- see "The eval
|
|
531
|
+
built from MemPalace's own bug" above for the honest not-yet-live-verified caveat.
|
|
532
|
+
- [PR#1890](https://github.com/MemPalace/mempalace/pull/1890) / [#1889](https://github.com/MemPalace/mempalace/issues/1889)
|
|
533
|
+
(@JosefAschauer): an `authored_at` chronology tie-break fix for `_hybrid_rank`. memtrust's ranking
|
|
534
|
+
classifier now credits a top-level `authored_at` field, not just one nested under `metadata`, as
|
|
535
|
+
a genuine ranking-driving signal.
|
|
536
|
+
- [#524](https://github.com/MemPalace/mempalace/issues/524) (@gaby): a buried-comment report that
|
|
537
|
+
"no API key required" doesn't mean "no network required" -- ChromaDB's default embedder still
|
|
538
|
+
needs to download a model on first use, which silently breaks airgapped setups. The adapter's
|
|
539
|
+
module docstring now says so explicitly.
|
|
540
|
+
|
|
541
|
+
**mem0**
|
|
542
|
+
- [#5973](https://github.com/mem0ai/mem0/pull/5973) (@abhay-codes07, superseded by
|
|
543
|
+
[#5992](https://github.com/mem0ai/mem0/pull/5992)): an empty-string entity-id filter scoping bug.
|
|
544
|
+
memtrust's mem0 adapter only reached the hosted Platform API and had no delete operation at all,
|
|
545
|
+
so it couldn't have caught this. A self-hosted adapter with tested delete/delete_many primitives
|
|
546
|
+
now can.
|
|
547
|
+
- [#4297](https://github.com/mem0ai/mem0/pull/4297) (@utkarsh240799): a dimension auto-detection
|
|
548
|
+
fix. The self-hosted adapter now routes to the right deployment, though no test yet reproduces
|
|
549
|
+
this specific bug end to end, so this one is partial, not fully caught.
|
|
550
|
+
- [#4573](https://github.com/mem0ai/mem0/issues/4573) (@jamebobob): a 32-day audit of 10,134 real
|
|
551
|
+
mem0 entries finding 97.8% junk. memtrust's new extraction-quality eval and
|
|
552
|
+
`ExtractionQualitySignal` taxonomy cover the audit's own junk categories, including its
|
|
553
|
+
808-duplicate feedback-loop case.
|
|
554
|
+
- [PR#5980](https://github.com/mem0ai/mem0/pull/5980) (@HrushiYadav): a filter-injection fix for
|
|
555
|
+
the Elasticsearch vector store. A new filter-injection eval exercises the real, installed
|
|
556
|
+
`mem0.vector_stores.elasticsearch.ElasticsearchDB._validate_filter()` directly and confirms it
|
|
557
|
+
rejects the exact malicious filter shape (`{"user_id": {"$ne": ""}}`) this PR fixed.
|
|
558
|
+
- [#4956](https://github.com/mem0ai/mem0/issues/4956) (@NDNM1408): an open proposal that mem0's
|
|
559
|
+
add-only pipeline surfaces stale, contradictory facts with no recency signal. memtrust's
|
|
560
|
+
contradiction eval now runs the same literal add-only scenario (two `store()` calls, no explicit
|
|
561
|
+
update) against this taxonomy.
|
|
562
|
+
- [#4884](https://github.com/mem0ai/mem0/issues/4884) (@wangjiawei-vegetable): a hardcoded
|
|
563
|
+
English-only tokenizer silently degrading non-Latin-script retrieval. A new
|
|
564
|
+
`LanguageDegradationSignal` and non-Latin-script fixtures now catch this shape.
|
|
565
|
+
|
|
566
|
+
**Zep / Graphiti**
|
|
567
|
+
- [#1489](https://github.com/getzep/graphiti/issues/1489) (@brentkearney): a bi-temporal
|
|
568
|
+
`invalid_at` correctness gap. memtrust's contradiction classifier used to discard Graphiti's own
|
|
569
|
+
`invalid_at` metadata and infer everything from a fixed top-5 text match, misreading a correctly
|
|
570
|
+
flagged case as a silent overwrite. It now checks the metadata first.
|
|
571
|
+
- [#1275](https://github.com/getzep/graphiti/issues/1275) (@rafaelreis-r, still open): O(n)
|
|
572
|
+
entity-resolution context growth silently dropping episodes past roughly 300 ingested. A new
|
|
573
|
+
self-hosted `graphiti-core` adapter plus a scale/volume-stress eval now tracks a fixed "anchor"
|
|
574
|
+
record's recall across ascending checkpoints against real `add_episode()` ingestion -- the same
|
|
575
|
+
shape this issue describes.
|
|
576
|
+
- [#836](https://github.com/getzep/graphiti/issues/836) (@matthiaslau) / [#920](https://github.com/getzep/graphiti/issues/920)
|
|
577
|
+
(@markwkiehl): two separate crashes in `update_communities()`/`resolve_edge_contradictions()` --
|
|
578
|
+
a too-many-values-to-unpack error and a tz-naive/aware datetime comparison error. A new
|
|
579
|
+
`CrashSignal` classification recognizes both exact shapes instead of surfacing an opaque generic
|
|
580
|
+
exception.
|
|
581
|
+
- [PR#1222](https://github.com/getzep/graphiti/pull/1222) (@david-morales) / [PR#1183](https://github.com/getzep/graphiti/pull/1183)
|
|
582
|
+
(@Milofax): FalkorDB RediSearch syntax errors from empty or unescaped fulltext queries. A new
|
|
583
|
+
`CrashSignal.QUERY_SANITIZATION_ERROR` recognizes both issues' verbatim filed error text.
|
|
584
|
+
- [#1467](https://github.com/getzep/graphiti/issues/1467) (@elimydlarz, open, zero engagement):
|
|
585
|
+
`GeminiEmbedder` silently returning the wrong vector count. A new
|
|
586
|
+
`CrashSignal.EMBEDDING_BATCH_COUNT_MISMATCH` catches this once Gemini embedder support is wired
|
|
587
|
+
into the self-hosted adapter.
|
|
588
|
+
|
|
589
|
+
**OpenViking**
|
|
590
|
+
- [#3029](https://github.com/volcengine/OpenViking/issues/3029) (@dfwgj, still open): Feishu resync
|
|
591
|
+
silently deleting user-managed files. memtrust had no way to observe this failure mode at all; a
|
|
592
|
+
dedicated resource-sync-safety eval now seeds generated and user files, triggers a resync, and
|
|
593
|
+
checks what survives.
|
|
594
|
+
- [#2850](https://github.com/volcengine/OpenViking/issues/2850) (@lg320531124, still open): BM25
|
|
595
|
+
search silently returning empty results at scale. A dedicated scale/volume-stress eval
|
|
596
|
+
(`memtrust run --eval scale_stress`) now stores a large synthetic corpus and re-queries it at
|
|
597
|
+
ascending checkpoints to reproduce the *shape* of this condition -- recall collapsing past a
|
|
598
|
+
volume threshold with no exception raised.
|
|
599
|
+
- [#1581](https://github.com/volcengine/OpenViking/issues/1581) (@0xble, fix rejected, still live
|
|
600
|
+
upstream): `v2_lock_max_retries=0` silently means unlimited retries, not zero. A new
|
|
601
|
+
lock-contention eval asserts a bounded response-time budget under concurrent-write contention.
|
|
602
|
+
- [#1255](https://github.com/volcengine/OpenViking/issues/1255) (@SeeYangZhi): a stats endpoint
|
|
603
|
+
silently returning zero despite persisted memories. A new `get_stats()`/`StatsResult` primitive
|
|
604
|
+
and dedicated stats-accuracy eval now catch this.
|
|
605
|
+
- [#2966](https://github.com/volcengine/OpenViking/issues/2966) (@lRoccoon, unaddressed upstream):
|
|
606
|
+
legacy uint16-truncated records that are permanently undeletable. A new
|
|
607
|
+
`CrashSignal.LEGACY_CORRUPT_RECORD_UNDELETABLE` now surfaces this instead of a silent no-op.
|
|
608
|
+
- [#204](https://github.com/volcengine/OpenViking/issues/204) (@ponsde, closed): non-deterministic
|
|
609
|
+
search results (Jaccard similarity 0.11 across identical queries) from a self-diagnosed dimension
|
|
610
|
+
mismatch. A new result-consistency eval computes pairwise Jaccard similarity over repeated
|
|
611
|
+
identical queries to catch this class directly.
|
|
612
|
+
|
|
613
|
+
**Cross-project**
|
|
614
|
+
- [OneNomad-LLC/przm-bench](https://github.com/OneNomad-LLC/przm-bench) (@mattstvartak): a peer
|
|
615
|
+
benchmarking project shipped cryptographic receipt signing; memtrust had none. `memtrust` now has
|
|
616
|
+
real Ed25519 signing/verification (the `cryptography` library, not a hand-rolled scheme) via
|
|
617
|
+
`memtrust keygen` / `run --sign` / `verify` -- a tampered receipt correctly fails verification,
|
|
618
|
+
a genuine one correctly passes.
|
|
619
|
+
|
|
620
|
+
Several PARTIAL and FAIL -- capability gap rows above and elsewhere in the full 197-row set remain
|
|
621
|
+
open, deliberately not counted as fixed: some point at real gaps this harness genuinely can't close
|
|
622
|
+
yet without a live vendor credential, and inflating a near-miss to PASS defeats the entire point of
|
|
623
|
+
an independently-verified benchmark. See the confidence caveats throughout this README and in
|
|
624
|
+
`docs/methodology.md` for exactly which claims rest on which kind of evidence.
|