The comparative report says what each system does. This page answers the other question — which systems actually have X — for the seven mechanisms whose absence causes a failure the system cannot detect.
Marks come from each report's frontmatter, so this table cannot disagree with what a report declares. It cannot independently confirm what a report declares: the frontmatter is the reviewer's assertion, and while a growing share of marks carry an evidence record naming the file and symbol they rest on, the rest are checked for shape rather than re-derived from the tree. A tick means the mechanism was found in code at that report's pinned commit; a dash means it was not found, which is different from impossible, planned, or badly built. The definitions, the evidence threshold, and why these seven rather than others are on the atlas rubric.
Read the of 7 column as a shape, not a
score. Around half of the systems here carry none or one — the
exact share is computed per report and printed in the strip at the top
of each one — so a low number is the ordinary case rather than a poor
one, and most of these columns are outside what most of these systems
set out to do. A local coding agent that never claimed to arbitrate
truth is not failing by carrying one mark. The column is worth sorting
on only when you already know which mechanism you need.
Filters combine with and — "tombstone and scope enforced" is the question worth asking, and it is the one a per-column view cannot answer.
Which one you need depends on where your memory breaks, and the seven do not intervene at the same place. Three of them guard the write, two describe what the store is able to say, one guards the read, and one is the test that keeps the other six honest. Read as a row of seven equal boxes they look like a scorecard; read against the path a memory takes they are seven different answers to seven different questions:
Diagram source
%% caption: where each of the seven marks sits on the write, store and read path — three guard what enters, two what the store can say about it, and two what comes back
flowchart TD
EV["Evidence<br/>messages, files, tool output"] --> WR{"Write path"}
WR --> ST[("Store")]
ST --> RD{"Read path"}
RD --> CX["Context<br/>what the model sees this turn"]
CX -.->|"that is wrong, forget it"| CO["Correction"]
CO --> WR
T["Rejected-value tombstone<br/>refuses the value, not the row"] -.-> WR
H["Human review surface<br/>a person adjudicates, not just views"] -.-> WR
A["Append-only mutation audit<br/>what changed, in the system's own store"] -.-> WR
TS["Explicit trust state<br/>may this be acted on"] -.-> ST
BT["Bi-temporal validity<br/>true-when, apart from recorded-when"] -.-> ST
SC["Scope enforced in retrieval<br/>the filter that is actually applied"] -.-> RD
NE["Negative retrieval assertion<br/>a committed test that this must not come back"] -.-> RDThe loop is the part worth staring at. A correction re-enters through the same write path that created the belief, which is why a mark on the write side is worth more than it looks: it is the only place that sees both the original claim and the attempt to reassert it after you thought it was gone.
Reading the counts
A system with six ticks is not better than one with two. It is differently shaped. Memory Engine governs access more thoroughly than anything else here and knows nothing about whether a memory is true; OptMem carries one mark and is among the most carefully reasoned designs in the corpus. Several systems carry a dash on a capability their design deliberately does not need.
Three things the counts show that the reports individually do not:
Read-path scoping is common; correction is not. Over half the atlas applies a scope key when retrieving. 51 systems of 555 carry a value-level tombstone. That gap is the atlas's central finding, and it is visible here in one column pair.
Trust is usually a number, not a state. Most systems collapse "how sure am I" into "how findable is this" — see decay and reinforcement.
Negative evidence is almost never tested. 275 repositories of 555 assert that particular material must not appear — the assertion every scope, deletion and correction claim in this atlas ultimately rests on. Read together rather than one at a time, they split cleanly, and the split says more than the count. A full re-score on 2026-08-08 found 27 of the 37 assert about a read path — 20 about a particular value, 7 about a scope boundary — while ten assert about a projection, a preamble, a summarization, a file or a write. All ten are real committed tests. Only the 27 are negative retrieval assertions.
Seven asserted a boundary at that reading: that a
principal cannot retrieve another principal's material. Five are worth
describing. MIRIX's
test_filter_tags_db.py creates a memory under one scope,
searches under another, and asserts the id is absent. Aukora Kernel does it better — an
unrelated principal reads ok: false, a subject whose
delegation manifest was revoked reads ok: false, and the
owner reads "the secret" in the same block, so the denial
is proved targeted rather than a blanket failure. EverOS does it at the endpoint: two
owners, the same query string,
assert c_ids.isdisjoint(m_ids) plus a positive control on
each side, repeated for two agent owners sharing a keyword. CrewAI does it over a path hierarchy:
three records under /other/scope,
/crew/crew-a/inner and /crew/crew-b/inner, a
Memory opened with root_scope="/crew/crew-a",
and an assertion that recall returns exactly one result and it is the
rooted one. CSM asserts the degenerate
case the other four leave implicit: searchMemories called
in project mode with no project id must return [],
with the assertion message spelling out the intent — "project mode
without a project ID must fail closed".
All five also hold scope_enforced. Their negative suites
are therefore tests of a capability the same system already
claims — which is worth having, and is not evidence about
deletion or correction.
Twenty asserted about content at that reading: that
particular material must not surface to anyone entitled to search,
regardless of who is asking. Eight show the range. open-cowork's service tests assert
that a session deleted while its extraction is queued leaves nothing
searchable; its forbiddenHits eval field, which would name
what a query must not return, is populated by no committed case. Verel's
tests/test_memory_negative_eval.py asserts a REJECTED fact
is invisible to every recall path — a suite built from the red-team
finding that produced its tombstone. Project
N.E.K.O.'s test_hard_filter_drops_negative_score
asserts that an entry the user disputed is dropped before the
rerank, the docstring giving the reason: "Stage-2 would either
reinforce the dispute or, worse, cancel it." Helm is the weakest of them: its supersede
case asserts recall returns exactly one active row and
fails with "recall returned old value" if the replaced one appears. The
value is still in the table and still readable through
history, so this is a genuine read-path exclusion — but it
covers replacement only. Helm's other two exits,
forget and the confidence-floor prune, are hard deletes
with nothing asserted about them, which is the case where a
re-derivation would actually reinstate the value. agent-afk's
it('excludes superseded facts from search') asserts the
same about its FTS path, and Agno is the
same shape against a judged verdict — a retired fact absent from
live_facts() while both rows remain in the record. The Pydantic AI Harness asserts
it about the prompt rather than the store:
test_delete_existing_is_content_free requires a deleted
body to be absent from the tool result, a search test requires
all('secret' not in repr(match)) under a character budget,
and two injection tests require a superseded line and a stale fact not
to appear in the captured model context. Graphify adds the cheapest version of
the shape and one nobody else has:
test_negative_only_node_absent_from_sources asserts that a
source cited only by answers marked dead_end appears in
none of the three lesson lists — a source that failed rather
than a value that was rejected.
Only the content kind probes the question the atlas is actually asking. A boundary test proves the filter works; a content test proves a value that was rejected, disputed or forbidden stays gone. Within that kind the sharpest cases raise a distinction the rest do not: a test that a superseded value stays hidden is cheap, because the row is still there to be filtered on. The expensive assertion is that a value the system destroyed does not come back — which requires something durable to check against, and is why the tombstone column and this one keep appearing together.
Two further things the joint reading shows. The positive control — asserting that the denial is targeted rather than an empty result — appears in Aukora and EverOS and is absent from the rest, and a negative test without one passes just as well when retrieval is broken. And the assertion shape is reachable from ordinary engineering practice: every boundary case above is an access-control test that happens to assert about recall rather than a result of memory research, and N.E.K.O. reached the content form from a companion app, where re-raising something the user asked you to drop is a product failure rather than a data-quality one.
Near-misses
Strictness is what makes the counts mean anything, and it hides the interesting cases. The ones worth knowing:
- claude-mem has "tombstones" that synchronize row deletion across stores — not a rejected-value tombstone.
- Mercury grades confidence three ways and has no discrete state.
- Most trust-state systems stop short of the state that matters. Verel, RainBox, Gini and memsem carry an explicitly
rejected state; Magic
Context qualifies on
staleandflagged. - RainBox's
RetrievalEventand Atomic Agent'svote_eventsare append-only logs of use and feedback, not of mutation. - ai-memory, nanobot and Basic Memory get an audit trail from git, which is a real mechanism and a different one.
- Memanto resolves conflicts with a human and then deletes without a tombstone — the most carefully reasoned correction in the atlas, and the next extraction pass may undo it.
- Daimon is the weakest of the tombstones, and the flag is granted on mechanism rather than on hardening: it suppresses on the read path rather than refusing the write, and its key is a hash of the item's exact text, so a paraphrase defeats it where Verel's normalized key would not. It is also the only holder with no test that re-asserts a forgotten value.
- memsem is the near-miss in the other direction: its suppression table refuses the write and is keyed on the normalised value, and nothing but a human rejecting a candidate ever writes a row into it, so its own automatic supersession path reaches the store ungated.
What these systems are built on
The seven marks above are about mechanisms. This is the other question: what these systems store memory in, and which retrieval channels they run. Both come from each report's frontmatter, so the table cannot drift from the reviews.
It is a census, not a recommendation. It says what the corpus contains and nothing about what works: the largest row is a plurality of under half, and no row here has been shown to retrieve better than another. Choosing an engine from a distribution is the mistake this table is most likely to cause.
Two rows need reading before the big ones. Delegated to the
adopter is a system whose storage is an adapter its user binds
— a framework's BaseStore, an ORM, "application-chosen" —
so it has no engine of its own to count. No arm named
is a review whose retrieval summary named neither a lexical, vector nor
graph channel; that is a gap in the review, not a system without
retrieval.
| Stored in | Systems | Read off code | Retrieval arm | Systems | Read off code | |
|---|---|---|---|---|---|---|
| SQLite | 263 | 177 | Lexical | 368 | 278 | |
| Files on disk | 263 | 188 | Vector | 340 | 228 | |
| Postgres | 99 | 62 | Graph | 150 | 110 | |
| Delegated to the adopter | 46 | 25 | No arm named in the review | 90 | 40 | |
| Graph database | 33 | 23 | ||||
| In-process only | 27 | 11 | ||||
| Chroma | 25 | 11 | ||||
| Qdrant | 20 | 10 | ||||
| LanceDB | 15 | 8 | ||||
| Redis | 14 | 5 | ||||
| Embedded key-value | 14 | 9 | ||||
| Milvus | 9 | 6 | ||||
| FAISS | 8 | 5 | ||||
| MongoDB | 6 | 4 | ||||
| DuckDB | 4 | 3 | ||||
| Pinecone | 2 | 1 | ||||
| Elasticsearch | 2 | 1 | ||||
| TepinDB | 1 | 1 |
Counted across 555 reports, each of which may name more than one
store. The Read off code column is the part of each row
confirmed against the tree at the pinned commit: 365 of 555 reports have
been read that way, and the other 190 were derived from the review's own
summary lines and are labelled seeded rather than
reviewed. Read the first number as what the corpus says
about itself and the second as what has been checked.