<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Giulio D'Erme</title>
    <description>The latest articles on DEV Community by Giulio D'Erme (@gde03).</description>
    <link>https://dev.to/gde03</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3940212%2F5c67ea11-57fb-4c0d-af21-86b03bfcda07.jpg</url>
      <title>DEV Community: Giulio D'Erme</title>
      <link>https://dev.to/gde03</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gde03"/>
    <language>en</language>
    <item>
      <title>I Rebuilt My AI Memory Benchmark. Here Is What It Can Measure Now.</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Fri, 04 Sep 2026 10:41:16 +0000</pubDate>
      <link>https://dev.to/gde03/i-rebuilt-my-ai-memory-benchmark-here-is-what-it-can-measure-now-126e</link>
      <guid>https://dev.to/gde03/i-rebuilt-my-ai-memory-benchmark-here-is-what-it-can-measure-now-126e</guid>
      <description>&lt;p&gt;&lt;em&gt;A follow up to &lt;a href="https://dev.to/gde03/i-gave-claude-code-a-brain-then-i-measured-what-it-costs-to-ask-for-one-5351"&gt;I Gave Claude Code a Brain. Then I Measured What It Costs to Ask for One&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My last article presented a memory benchmark as a comparison between products. The comments correctly pointed out that the design was still mixing several questions together.&lt;/p&gt;

&lt;p&gt;Was the agent benefiting from memory, or from being told to search? Was the reported p value a planned test, or simply the most interesting result among several comparisons? Did the control represent a real empty memory store, or only the absence of memory tools?&lt;/p&gt;

&lt;p&gt;I rebuilt the benchmark around those questions.&lt;/p&gt;

&lt;p&gt;The result is not just a larger leaderboard. It is a more useful instrument. It can now separate several parts of the memory path, measure both help and harm, check whether the treatment was actually present, and let a reader verify the arithmetic from the published session artifacts.&lt;br&gt;
It can also produce a null. In the first official run with the improved design, the placebo scored highest and no arm had an interval that excluded zero.&lt;br&gt;
That is the result. This article is about how to read it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The measurement question
&lt;/h2&gt;

&lt;p&gt;The benchmark no longer asks only:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does a memory product improve task success?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question is too compressed. A memory system can fail because the agent never decides to search, because it asks a poor query, because retrieval returns the wrong passage, because the agent ignores a useful passage, or because the retrieved passage is stale or irrelevant.&lt;/p&gt;

&lt;p&gt;The benchmark now asks a sequence of narrower questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Does the agent complete more real coding tasks?&lt;/li&gt;
&lt;li&gt;Does memory help when the governing fact is present?&lt;/li&gt;
&lt;li&gt;Does memory make the agent worse when the corpus is stale, contradictory, unrelated, or empty?&lt;/li&gt;
&lt;li&gt;Is any change caused by retrieval, or only by extra instructions?&lt;/li&gt;
&lt;li&gt;Is the system paying for a real benefit in tokens and time?&lt;/li&gt;
&lt;li&gt;Can another person verify that the reported result follows from the sessions that produced it?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The primary endpoint remains simple. Claude Code edits a repository, and an executable checker decides whether the resulting artifact is correct. There is no LLM judge deciding whether the answer sounds good.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each arm is for
&lt;/h2&gt;

&lt;p&gt;The arms are not eight competing products. Several are controls or diagnostic tracks. Treating them all as entries in one ranking would throw away the point of the design.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Arm&lt;/th&gt;
&lt;th&gt;What it receives&lt;/th&gt;
&lt;th&gt;What it controls or tests&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bare&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No memory layer and no memory instruction&lt;/td&gt;
&lt;td&gt;The floor. What the agent does without memory or memory coaching&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude_md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The task's static project instructions&lt;/td&gt;
&lt;td&gt;The designated baseline for the current leaderboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;placebo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Neutral project shaped prose, with no task facts or memory tools&lt;/td&gt;
&lt;td&gt;Whether extra context alone changes task success&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;protocol&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The shared memory instruction, but no memory surface&lt;/td&gt;
&lt;td&gt;The cost or benefit of telling the agent to search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fs_grep&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The transcript corpus as files, searched with ordinary repository tools&lt;/td&gt;
&lt;td&gt;Whether a memory product beats a simple searchable file feed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;recall&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The RE call memory layer and its search tools&lt;/td&gt;
&lt;td&gt;Natural use: the agent decides whether to search and how to query&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mempalace&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The MemPalace integration through its published interface&lt;/td&gt;
&lt;td&gt;A product comparison under the same shared protocol&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;recall_prefetch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;RE call retrieval run by the harness using the exact task prompt&lt;/td&gt;
&lt;td&gt;Retrieval with the decision to search and query formulation removed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is also an &lt;a href="https://github.com/GiulioDER/agent-memory-bench/blob/master/docs/ORACLE_PREFETCH_DIAGNOSTIC.md" rel="noopener noreferrer"&gt;&lt;code&gt;oracle_memory&lt;/code&gt; diagnostic&lt;/a&gt; in the repository. It injects the exact relevant evidence before a session and acts as a ceiling control. It is not a product and it is not part of the official leaderboard. Its purpose is to answer a different question: can the agent use correct evidence when retrieval has already been solved?&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;bare&lt;/code&gt; is not the same as &lt;code&gt;protocol&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This distinction is central.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bare&lt;/code&gt; receives neither memory tools nor instructions about memory. It measures the agent's ordinary performance.&lt;br&gt;
&lt;code&gt;protocol&lt;/code&gt; receives the shared instruction that tells a memory enabled agent how to use memory, but it has no memory store. It measures what happens when the coaching exists without retrieval.&lt;br&gt;
The difference between &lt;code&gt;protocol&lt;/code&gt; and &lt;code&gt;bare&lt;/code&gt; is therefore the effect of the instruction. The difference between &lt;code&gt;recall&lt;/code&gt; and &lt;code&gt;protocol&lt;/code&gt; is the value of adding the memory system to that instruction.&lt;br&gt;
That is the comparison the previous article needed to make more explicit.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;placebo&lt;/code&gt; is not an empty memory store
&lt;/h3&gt;

&lt;p&gt;The placebo contains neutral project shaped prose. It does not expose a memory interface and it does not return an empty search result.&lt;br&gt;
An empty store would hold the interface constant, accept the search, return no evidence, and let the agent continue. That is a different control. The current official run does not include it.&lt;br&gt;
The new design therefore separates coaching from retrieval, but it does not yet isolate interface overhead from coaching. That remains a planned experiment, not a result I can claim today.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;recall&lt;/code&gt; and &lt;code&gt;recall_prefetch&lt;/code&gt; measure different paths
&lt;/h3&gt;

&lt;p&gt;The natural &lt;code&gt;recall&lt;/code&gt; arm asks the agent to decide when memory is worth consulting and to formulate a useful query. Its result includes the product and the agent's use of it.&lt;br&gt;
The &lt;code&gt;recall_prefetch&lt;/code&gt; arm runs retrieval in the harness using the exact task prompt, then gives the returned evidence to the agent without exposing memory tools. It removes the decision to search and most of the query formulation problem.&lt;/p&gt;

&lt;p&gt;The comparison is diagnostic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If prefetch is better than natural RE call, the agent's search decision or query is part of the bottleneck.&lt;/li&gt;
&lt;li&gt;If both are better than the baseline by a similar amount, the retrieved evidence is probably doing most of the work.&lt;/li&gt;
&lt;li&gt;If neither is better, better retrieval alone may not solve the task.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither arm should be interpreted as a general product ranking without the paired analysis and the other controls.&lt;/p&gt;

&lt;h2&gt;
  
  
  The improvements to the benchmark
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The instruction is now controlled
&lt;/h3&gt;

&lt;p&gt;In the earlier run, the memory arms carried different amounts of generic coaching. That made it possible for an apparent retrieval advantage to be an instruction advantage.&lt;br&gt;
The official run uses one shared protocol document for the memory arms. Its measured size was 3,472 bytes, identical across the arms. Each integration can add a capped result schema for its own tools, and those additions are published in the run metadata.&lt;br&gt;
In the official run, the additional material was 549 bytes for &lt;code&gt;fs_grep&lt;/code&gt;, 735 bytes for RE call, and 853 bytes for MemPalace. The earlier imbalance, where RE call carried the largest coaching surplus, was removed. The remaining differences are visible and measurable.&lt;/p&gt;

&lt;h3&gt;
  
  
  The corpus can now expose harm
&lt;/h3&gt;

&lt;p&gt;The original task suite put the governing fact in the corpus every time. It could measure help, but it was structurally weak at measuring damage.&lt;/p&gt;

&lt;p&gt;The current corpus has five conditions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;present&lt;/code&gt;: the governing fact is available and current&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;absent&lt;/code&gt;: the fact has been removed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;superseded&lt;/code&gt;: an old version sits beside a newer version&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contradictory&lt;/code&gt;: rival versions exist without an authority marker&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;adjacent&lt;/code&gt;: related information exists but does not apply to the task&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same executable checker is used in every condition. A memory system is not rewarded merely for finding text. It is evaluated on whether the completed code is correct.&lt;br&gt;
This changes the interpretation of a positive result. A system that helps on &lt;code&gt;present&lt;/code&gt; but damages work on &lt;code&gt;superseded&lt;/code&gt; has a different risk profile from one that helps on &lt;code&gt;present&lt;/code&gt; and stays neutral elsewhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  The admission gate is part of the measurement
&lt;/h3&gt;

&lt;p&gt;A cell is admitted only when every arm can demonstrate that its treatment was present and that the session was comparable. The gate checks the available tools, startup signals, sandbox identity, and treatment metadata.&lt;br&gt;
If one arm fails to start, the cell is discarded rather than scored as a task failure. The discard count is published because this rule protects the comparison but can also favour an arm that fails in a way the gate detects.&lt;br&gt;
The official run had eight arms, so it had more ways to lose a cell than the previous four arm run. It produced 2,920 sessions, 317 admitted cells, and 48 discarded cells. The admitted set is not automatically comparable with the earlier run's admitted set.&lt;/p&gt;

&lt;h3&gt;
  
  
  The artifacts are now independently checkable
&lt;/h3&gt;

&lt;p&gt;The full official run publishes session records, compressed streams, admission decisions, costs, and endpoint results. The verifier recomputes the published values from those artifacts without credentials, a database, or model calls.&lt;br&gt;
That work found defects in the benchmark itself. One older run stored its records beside the run directory under a sibling filename, so the verifier reported missing evidence even though the records existed. Another guard could not inspect compressed streams. A partition invariant assumed that every run used the same set of corpus conditions.&lt;br&gt;
Those cases are now tested explicitly. The repository documents known missing streams as failures with explanations rather than silently turning them into passes. The &lt;a href="https://github.com/GiulioDER/agent-memory-bench/blob/master/docs/REPLICATION.md" rel="noopener noreferrer"&gt;replication guide&lt;/a&gt; explains what an outside runner must report and why a replication gets standing to contradict the official run rather than entering the leaderboard as another incomparable score.&lt;/p&gt;

&lt;p&gt;The promotion and verification work is documented in &lt;a href="https://github.com/GiulioDER/agent-memory-bench/pull/70" rel="noopener noreferrer"&gt;pull request 70&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The official result
&lt;/h2&gt;

&lt;p&gt;The first official run used 26 coding tasks, five corpus conditions, five seeds, eight arms, and the &lt;code&gt;deepseek-v4-flash&lt;/code&gt; model. The leaderboard uses &lt;code&gt;claude_md&lt;/code&gt; as its designated baseline.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Arm&lt;/th&gt;
&lt;th&gt;Success rate&lt;/th&gt;
&lt;th&gt;Difference from &lt;code&gt;claude_md&lt;/code&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;placebo&lt;/td&gt;
&lt;td&gt;67.2%&lt;/td&gt;
&lt;td&gt;+9.5 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;recall&lt;/td&gt;
&lt;td&gt;65.9%&lt;/td&gt;
&lt;td&gt;+8.2 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bare&lt;/td&gt;
&lt;td&gt;65.9%&lt;/td&gt;
&lt;td&gt;+8.2 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;fs_grep&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;63.1%&lt;/td&gt;
&lt;td&gt;+5.4 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MemPalace&lt;/td&gt;
&lt;td&gt;60.6%&lt;/td&gt;
&lt;td&gt;+2.8 points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;claude_md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;57.7%&lt;/td&gt;
&lt;td&gt;baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;protocol&lt;/code&gt; and &lt;code&gt;recall_prefetch&lt;/code&gt; tracks both scored 61.2%. They are reference tracks and are not product rows.&lt;/p&gt;

&lt;p&gt;The raw numbers are in &lt;a href="https://github.com/GiulioDER/agent-memory-bench/tree/master/results/official-003" rel="noopener noreferrer"&gt;official 003&lt;/a&gt; and its &lt;a href="https://github.com/GiulioDER/agent-memory-bench/blob/master/results/official-003/leaderboard_summary.json" rel="noopener noreferrer"&gt;published summary&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to interpret those numbers
&lt;/h2&gt;

&lt;p&gt;The placebo being first does not prove that neutral prose is better than memory. It tells me that this run contains enough variance, task sensitivity, or uncontrolled influence that the ordering of the rates cannot be treated as a ranking.&lt;br&gt;
RE call's 65.9% is above the &lt;code&gt;claude_md&lt;/code&gt; baseline's 57.7%, but its interval crosses zero. The correct statement is that this configuration performed better descriptively in this run, while the run did not establish a statistically reliable product benefit.&lt;br&gt;
RE call matching the &lt;code&gt;bare&lt;/code&gt; rate is not evidence that memory and no memory are equivalent. It only says that this run did not separate them. The paired contrast and its interval are the evidence to inspect, not the order of the headline rates.&lt;br&gt;
The protocol arm gives the coaching comparison. If &lt;code&gt;protocol&lt;/code&gt; had substantially exceeded &lt;code&gt;bare&lt;/code&gt;, I would have evidence that the instruction itself changes performance. If &lt;code&gt;recall&lt;/code&gt; had then exceeded &lt;code&gt;protocol&lt;/code&gt;, I could attribute the additional difference more plausibly to the memory surface. In this run, neither diagnostic track produces a clean positive claim.&lt;br&gt;
The prefetch arm gives the retrieval comparison. A gap between prefetch and natural RE call would show that agent behaviour is limiting the benefit. A gap between prefetch and the baseline would show that the retrieval payload can help when the harness supplies it at the right time. Because the official result is a null at the product level, these tracks should be used to design the next experiment, not to rescue the leaderboard.&lt;br&gt;
The previous article's +20 cell result at p = 0.015 was exploratory. The new official comparison against the protocol arm was +15 cells at p = 0.058. The direction was similar, but the threshold did not clear. That is exactly the kind of change a better control should reveal.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it can measure now, and what it cannot
&lt;/h2&gt;

&lt;p&gt;The benchmark can now measure task success under useful and hostile memory conditions, negative transfer relative to a bare agent, the contribution of shared memory coaching, the effect of giving an agent a simple searchable feed, natural retrieval behaviour versus prompt driven retrieval, treatment wiring, discard rates, token cost, wall time, and whether the published arithmetic follows from the published sessions.&lt;br&gt;
It still cannot measure the write path. The corpus is bulk ingested before the grid and is not updated by the agent. Nothing here says whether a product extracts a good memory from a session, consolidates repeated information, forgets a correction, or preserves a decision over time.&lt;br&gt;
The task suite also favours discrete retrieval. Most tasks place one governing fact in one transcript. Cross session synthesis tasks now exist, but they have not produced a scored result.&lt;br&gt;
The run uses one model and one realization per task condition and seed. The memory arms are not budget matched, and RE call uses substantially more input tokens than the other arms. The official preregistration was committed after data collection began, so it is weaker evidence than a genuinely prospective test. Those limits are part of the result.&lt;br&gt;
The next registered change adds a paired &lt;code&gt;recall_rerank&lt;/code&gt; arm. It keeps the base arm in the same grid and changes the reranking configuration only, so it tests retrieval ordering without comparing two different runs. It is described in &lt;a href="https://github.com/GiulioDER/agent-memory-bench/pull/69" rel="noopener noreferrer"&gt;pull request 69&lt;/a&gt;, and it has no result yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benchmark is now answering better questions
&lt;/h2&gt;

&lt;p&gt;The useful improvement is not a more impressive leaderboard. It is the ability to tell apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no memory&lt;/li&gt;
&lt;li&gt;memory coaching without memory&lt;/li&gt;
&lt;li&gt;extra neutral context&lt;/li&gt;
&lt;li&gt;simple file search&lt;/li&gt;
&lt;li&gt;natural product use&lt;/li&gt;
&lt;li&gt;retrieval supplied by the harness&lt;/li&gt;
&lt;li&gt;exact evidence supplied as a ceiling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes a null more informative. When no arm wins cleanly, I know the benchmark did not merely lack a memory feature. I know which controls were present, which parts of the causal path were removed, which conditions could expose harm, and which artifacts a reader can inspect.&lt;/p&gt;

&lt;p&gt;That is what the benchmark can measure now.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>agents</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Gave Claude Code a Brain. Then I Measured What It Costs to Ask for One.</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Tue, 01 Sep 2026 15:57:06 +0000</pubDate>
      <link>https://dev.to/gde03/i-gave-claude-code-a-brain-then-i-measured-what-it-costs-to-ask-for-one-5351</link>
      <guid>https://dev.to/gde03/i-gave-claude-code-a-brain-then-i-measured-what-it-costs-to-ask-for-one-5351</guid>
      <description>&lt;p&gt;At the end of &lt;a href="https://dev.to/gde03/i-gave-claude-code-a-brain-this-time-i-let-the-tests-judge-it-5h0p"&gt;part 2&lt;/a&gt; I promised a clean competitor comparison: more than one memory system, the same admission gate, enough capacity to finish.&lt;/p&gt;

&lt;p&gt;This is that run. 1,453 agent sessions, four arms, five corpus conditions, every outcome graded by executing a checker against the code the agent actually wrote. No LLM judge anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  The corpus
&lt;/h2&gt;

&lt;p&gt;Each condition is a &lt;strong&gt;4,911 document corpus, about 27,000 embedded chunks&lt;/strong&gt;. Of those documents, &lt;strong&gt;4,902 are adversarial distractors&lt;/strong&gt; generated from the corpus's own vocabulary to be confusable, and the rest are the planted material for 36 tasks.&lt;/p&gt;

&lt;p&gt;That ratio is the point. On the small feed I used earlier, retrieval hit@10 was 1.000: everything was findable, so the benchmark could not tell "the product retrieved badly" from "the agent never searched". With the haystack, BM25 hit@1 drops from 0.485 to 0.182.&lt;/p&gt;

&lt;p&gt;The five conditions differ in what is planted, and &lt;strong&gt;four of the five are traps&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;condition&lt;/th&gt;
&lt;th&gt;what the corpus holds&lt;/th&gt;
&lt;th&gt;share of cells&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;present&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the governing fact, cleanly&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;37%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;superseded&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the fact, beside an outdated version of itself&lt;/td&gt;
&lt;td&gt;15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;adjacent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;something related and inapplicable&lt;/td&gt;
&lt;td&gt;16%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;absent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;the fact deleted, distractors left behind&lt;/td&gt;
&lt;td&gt;17%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;contradictory&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;two rival versions, no authority between them&lt;/td&gt;
&lt;td&gt;15%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Only 37 percent of cells contain a clean fact worth retrieving. In the other 63 percent the corpus is outdated, contradictory, inapplicable, or empty&lt;/strong&gt;, and a memory layer's job there is to not make things worse.&lt;/p&gt;

&lt;p&gt;I built it that way deliberately. A benchmark where memory can only help is a demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  The control that changed the question
&lt;/h2&gt;

&lt;p&gt;Two commenters asked for a placebo. Fair: if you tell an agent "you have memory, consult it before acting" and it then does better, you have not separated the memory from the telling.&lt;/p&gt;

&lt;p&gt;So I built an arm carrying &lt;strong&gt;the complete memory instruction and no memory at all&lt;/strong&gt;. Same protocol text, byte for byte, as the two real arms. Nothing behind it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;comparison&lt;/th&gt;
&lt;th&gt;wins&lt;/th&gt;
&lt;th&gt;losses&lt;/th&gt;
&lt;th&gt;net&lt;/th&gt;
&lt;th&gt;p&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;instruction only, vs bare&lt;/td&gt;
&lt;td&gt;26&lt;/td&gt;
&lt;td&gt;43&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-17&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.053&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Telling an agent to consult memory, when there is no memory, makes it measurably worse.&lt;/strong&gt; Seventeen cells of 358, borderline significance, in the direction nobody advertises.&lt;/p&gt;

&lt;p&gt;That reframes everything. "Does memory beat no memory" is not directly answerable, because every memory product requires that instruction. The answerable question is: &lt;strong&gt;does the product earn back the cost of asking for it?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt; &lt;code&gt;0.11.0&lt;/code&gt; is mine, so read accordingly. &lt;a href="https://pypi.org/project/mempalace/" rel="noopener noreferrer"&gt;MemPalace&lt;/a&gt; &lt;code&gt;3.8.0&lt;/code&gt; is the better known of the two. Both received the same instruction and the same gate. Every write tool was withheld from every arm.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;comparison&lt;/th&gt;
&lt;th&gt;wins&lt;/th&gt;
&lt;th&gt;losses&lt;/th&gt;
&lt;th&gt;net&lt;/th&gt;
&lt;th&gt;p&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RE-call vs instruction only&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;41&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+20&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.015&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MemPalace vs instruction only&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;23&lt;/td&gt;
&lt;td&gt;+2&lt;/td&gt;
&lt;td&gt;0.885&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RE-call vs MemPalace&lt;/td&gt;
&lt;td&gt;48&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;+18&lt;/td&gt;
&lt;td&gt;0.054&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RE-call vs bare&lt;/td&gt;
&lt;td&gt;47&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;td&gt;+3&lt;/td&gt;
&lt;td&gt;0.834&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MemPalace vs bare&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;53&lt;/td&gt;
&lt;td&gt;-15&lt;/td&gt;
&lt;td&gt;0.142&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;McNemar exact on discordant pairs. &lt;strong&gt;The only comparison clearing p &amp;lt; 0.05 is RE-call against the instruction-only control.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Note the fourth row before anyone else does. &lt;strong&gt;Against a bare agent, RE-call is +3 cells at p = 0.834, which is nothing.&lt;/strong&gt; The win is real against the instruction the product requires and invisible against an agent you never asked. A sceptic will quote that row and is entitled to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Arm by arm
&lt;/h2&gt;

&lt;p&gt;Tasks solved out of cells, admitted only where all four arms produced a record. Ordered by how much RE-call gains over the instruction-only arm, which is the comparison that isolates the product from the coaching.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;condition&lt;/th&gt;
&lt;th&gt;cells&lt;/th&gt;
&lt;th&gt;bare&lt;/th&gt;
&lt;th&gt;instruction&lt;/th&gt;
&lt;th&gt;RE-call&lt;/th&gt;
&lt;th&gt;MemPalace&lt;/th&gt;
&lt;th&gt;RE-call gain&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;present&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;134&lt;/td&gt;
&lt;td&gt;52/134 · 0.388&lt;/td&gt;
&lt;td&gt;53/134 · 0.396&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;67/134 · 0.500&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;56/134 · 0.418&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+14&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;superseded&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;td&gt;38/52 · 0.731&lt;/td&gt;
&lt;td&gt;34/52 · 0.654&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;41/52 · 0.788&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;35/52 · 0.673&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+7&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;absent&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;49/60 · 0.817&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;41/60 · 0.683&lt;/td&gt;
&lt;td&gt;44/60 · 0.733&lt;/td&gt;
&lt;td&gt;37/60 · 0.617&lt;/td&gt;
&lt;td&gt;+3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;contradictory&lt;/td&gt;
&lt;td&gt;54&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;44/54 · 0.815&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;41/54 · 0.759&lt;/td&gt;
&lt;td&gt;39/54 · 0.722&lt;/td&gt;
&lt;td&gt;42/54 · 0.778&lt;/td&gt;
&lt;td&gt;-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;adjacent&lt;/td&gt;
&lt;td&gt;58&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;42/58 · 0.724&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;39/58 · 0.672&lt;/td&gt;
&lt;td&gt;37/58 · 0.638&lt;/td&gt;
&lt;td&gt;40/58 · 0.690&lt;/td&gt;
&lt;td&gt;-2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;all&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;358&lt;/td&gt;
&lt;td&gt;225/358 · 0.628&lt;/td&gt;
&lt;td&gt;208/358 · 0.581&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;228/358 · 0.637&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;210/358 · 0.587&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+20&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;RE-call is the only arm that beats doing nothing, by 0.9 points overall.&lt;/strong&gt; MemPalace at 210/358 sits below the no-memory baseline and barely above instruction-only. MemPalace's gains against the same control are +3, +1, -4, +1, +1, totalling &lt;strong&gt;+2&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The shape of that table matters more than the total. &lt;strong&gt;Memory pays where there is something to recall and costs where there is not.&lt;/strong&gt; On &lt;code&gt;present&lt;/code&gt; RE-call converts 67 of 134 against bare's 52. On the three conditions built to punish retrieval it is flat or slightly negative, because surfacing something inapplicable is worse than surfacing nothing.&lt;/p&gt;

&lt;h3&gt;
  
  
  This is close to a worst case, and that is the point
&lt;/h3&gt;

&lt;p&gt;Go back to the composition. &lt;strong&gt;Sixty-three percent of these cells are conditions built to punish a memory layer&lt;/strong&gt;, where the corpus is outdated, contradictory, inapplicable, or empty and the best available outcome is to waste nothing. Only 37 percent contain a clean fact worth retrieving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RE-call is still the only arm that finishes above the no-memory baseline.&lt;/strong&gt; It does that while spending nearly two thirds of its cells in terrain designed to make retrieval a liability, and while paying the -17 cell entry fee that the instruction alone costs.&lt;/p&gt;

&lt;p&gt;That is the number I would defend hardest, because it is the unflattering way to measure my own product and it still comes out positive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the composition is a choice I made, not a fact about anyone's repository.&lt;/strong&gt; Real memory does not sit still at that ratio. How much of it is current, governing and correctly superseded is a property of how the layer writes and maintains notes over time, which &lt;strong&gt;this benchmark does not measure at all&lt;/strong&gt;. It fixes the corpus and varies the product.&lt;/p&gt;

&lt;p&gt;So read the table as a floor rather than a forecast. On the condition a well maintained corpus is mostly made of, RE-call is +14 of its +20. What that becomes at a healthier ratio I have not measured, and I am not going to put a number on it.&lt;/p&gt;

&lt;p&gt;I would rather someone else did. A composition sweep, holding the product constant and varying the mix, is the obvious next experiment and it is not run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number I find most telling
&lt;/h2&gt;

&lt;p&gt;For each product, the solved rate when it searched minus when it did not:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;condition&lt;/th&gt;
&lt;th&gt;RE-call&lt;/th&gt;
&lt;th&gt;MemPalace&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;present&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+0.181&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;+0.019&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;adjacent&lt;/td&gt;
&lt;td&gt;+0.147&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-0.032&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;contradictory&lt;/td&gt;
&lt;td&gt;+0.079&lt;/td&gt;
&lt;td&gt;+0.085&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;absent&lt;/td&gt;
&lt;td&gt;+0.031&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+0.264&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;superseded&lt;/td&gt;
&lt;td&gt;+0.006&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-0.094&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;When RE-call searches it helps in five conditions of five. When MemPalace searches it hurts in two&lt;/strong&gt;, while searching more often (0.58 to 0.69 against 0.46 to 0.56).&lt;/p&gt;

&lt;p&gt;On &lt;code&gt;present&lt;/code&gt;, the condition built so the answer &lt;em&gt;is&lt;/em&gt; in memory, searching is worth &lt;strong&gt;+0.181 to RE-call and +0.019 to MemPalace&lt;/strong&gt;. That is the cell both products exist for.&lt;/p&gt;

&lt;p&gt;Cost, median beside mean because these distributions are skewed enough that on an earlier run of mine the two disagreed in sign: RE-call 65.9 s and 56,476 input tokens per session, MemPalace 68.6 s and 90,706, bare 44.7 s and 14,085. &lt;strong&gt;RE-call is faster and uses 38 percent fewer tokens than MemPalace while delivering ten times the net benefit.&lt;/strong&gt; Both are materially heavier than no memory, which is the honest cost of the idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I had to publish against myself
&lt;/h2&gt;

&lt;p&gt;The previous run said something different, and I want to be the one who says why.&lt;/p&gt;

&lt;p&gt;In it, RE-call looked like &lt;strong&gt;the most damaging arm of seven&lt;/strong&gt;, worst on three of four adversarial conditions. I had written that up as a genuine weakness of my own product.&lt;/p&gt;

&lt;p&gt;It was my harness. That run gave RE-call &lt;strong&gt;1,958 bytes of coaching over the shared protocol against MemPalace's 853&lt;/strong&gt;, and most of the surplus was not about RE-call at all: search before your first write, search by symptom rather than goal. Generic advice that helps any retrieval system, handed to one of them. Worse, the flag selecting the fair variant was &lt;strong&gt;hardcoded in my launcher with no override&lt;/strong&gt;, so no run I had ever done could have been matched, and I had not noticed.&lt;/p&gt;

&lt;p&gt;Under the corrected instruction the finding evaporates. RE-call's damage-only net harm falls from +0.073 to +0.0122, &lt;strong&gt;identical to MemPalace's&lt;/strong&gt;, and its &lt;code&gt;superseded&lt;/code&gt; damage from 0.179 to 0.036. Its usefulness score also fell, 0.377 to 0.281, while MemPalace's did not move at all, because MemPalace had been on the shared protocol all along. My product's advantage narrowed from 1.8x to 1.35x once I stopped giving it a bigger prompt.&lt;/p&gt;

&lt;p&gt;Both corrections point the same way. I had been generous to myself and unfair to the competitor, and it produced one flattering finding and one damning one, both wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this benchmark cannot see
&lt;/h2&gt;

&lt;p&gt;RE-call has a reasoning-graph layer. Across 2,181 sessions of the earlier run its four graph tools were called &lt;strong&gt;zero times&lt;/strong&gt;. Read alone, damning.&lt;/p&gt;

&lt;p&gt;It builds that graph from &lt;strong&gt;authored cross-references&lt;/strong&gt;, the way a wiki links notes. Its own memory store has 44,364 of them. This benchmark's corpus is rendered agent transcripts: conversation turns, no cross-references. The graph gets entities and no edges. It is a node set, not a graph.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So graph reasoning needs an authored, cross-referenced corpus and this benchmark deliberately measures raw transcripts.&lt;/strong&gt; Different corpus classes, not a weakness. Manufacturing cross-references in to make the feature look good would be assuming the answer. I established that with ten read-only queries rather than the 220 sessions the experiment would have cost, after a reviewer pointed out my draft design would have measured a language model reading trusted evidence and published it as a graph result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Come and break it
&lt;/h2&gt;

&lt;p&gt;Two systems is a comparison, not a field, and one of them is mine. The harness is public: &lt;a href="https://github.com/GiulioDER/agent-memory-bench" rel="noopener noreferrer"&gt;github.com/GiulioDER/agent-memory-bench&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you build a memory layer for coding agents, I would rather measure yours than have you take my word for this.&lt;/strong&gt; Every adapter is hash-pinned and every vendor is invited to review their own config before a measured run, which is what &lt;code&gt;adapters/&amp;lt;name&amp;gt;/VENDOR_REVIEW.md&lt;/code&gt; is for. Open an issue and I will help wire it up.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And if you just want to check my arithmetic&lt;/strong&gt;, the README has a section on verifying a published run with no credentials and no money. The preregistrations are in the repo, including the ones whose predictions I got wrong, and the raw records are published with each run.&lt;/p&gt;

&lt;p&gt;If you take one number from this, take that one: &lt;strong&gt;63 percent of the cells were built to make memory a liability, and the memory layer still finished ahead of not having one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One thing I would most like broken: the 45 percent. On &lt;code&gt;superseded&lt;/code&gt;, the largest single loss is that in 45 percent of sessions &lt;strong&gt;neither&lt;/strong&gt; planted document is retrieved at all. That is worth roughly three times more than anything I have measured on the ranking side, it is a query-formulation problem rather than a retrieval-quality one, and it is already preregistered. If someone has a better idea than mine, I would like to lose that one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The method, the leaderboard and the submission rules now live at&lt;/strong&gt; &lt;a href="https://giulioder.github.io/agent-memory-bench/" rel="noopener noreferrer"&gt;giulioder.github.io/agent-memory-bench&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://huggingface.co/spaces/Gde05/agent-memory-bench" rel="noopener noreferrer"&gt;ghttps://huggingface.co/spaces/Gde05/agent-memory-bench&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>The #1 row on this AI memory leaderboard is not a measurement</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Sat, 29 Aug 2026 15:00:01 +0000</pubDate>
      <link>https://dev.to/gde03/the-1-row-on-this-ai-memory-leaderboard-is-not-a-measurement-3mhc</link>
      <guid>https://dev.to/gde03/the-1-row-on-this-ai-memory-leaderboard-is-not-a-measurement-3mhc</guid>
      <description>&lt;p&gt;Bench'd (benchd.ai) calls itself the neutral benchmark authority for AI memory, and sells vendors a verification badge from $299 to $3,999.99 a month.&lt;/p&gt;

&lt;p&gt;I ran my memory system through their harness. Then I checked their board. Every number below is from their own site and repository, read on 2026-08-29, and every one takes seconds to verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers are fake
&lt;/h2&gt;

&lt;p&gt;Their three track leaders, recomputed against the harness's own aggregation rule:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Track&lt;/th&gt;
&lt;th&gt;#1&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;th&gt;What its own dimensions say&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Knowledge Brain&lt;/td&gt;
&lt;td&gt;gbrain&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;100.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;perfect recall, reliability score 4.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent Memory&lt;/td&gt;
&lt;td&gt;Letta&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;80.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;own dimensions average &lt;strong&gt;26.7&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Conversational Memory&lt;/td&gt;
&lt;td&gt;LangMem&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;60.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;dimensions are &lt;strong&gt;all zero&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A 100.0 beside a reliability score of 4.0 is the signature of an adapter echoing expected answers. An 80.0 built from dimensions averaging 26.7 is an aggregation bug. A 60.0 from all-zero dimensions is not a number.&lt;/p&gt;

&lt;p&gt;None of the three has a manifest anyone can download. And per Bench'd's own methodology page, rows marked Community-Verified are "independently run" by Bench'd. &lt;strong&gt;All three are.&lt;/strong&gt; So these are not vendor claims. Letta did not submit an 80.0. gbrain did not submit a 100.0. The vendors named in those rows are being misrepresented by the harness, not caught by it.&lt;/p&gt;

&lt;p&gt;Filed as [issue #5 (&lt;a href="https://github.com/benchdai/harness/issues/5" rel="noopener noreferrer"&gt;https://github.com/benchdai/harness/issues/5&lt;/a&gt;) on 2026 08-23. Still on the board.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trust is fake
&lt;/h2&gt;

&lt;p&gt;Their methodology page has a section headed &lt;strong&gt;Verify a Receipt Yourself&lt;/strong&gt;: &lt;em&gt;"You don't need to trust us. Every receipt can be independently verified."&lt;/em&gt; It gives you this:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;```bash curl -sL &lt;a href="https://benchd.dev/api/receipt/run_abc123.json" rel="noopener noreferrer"&gt;https://benchd.dev/api/receipt/run_abc123.json&lt;/a&gt; -o receipt.json&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


`benchd.dev` does not exist. NXDOMAIN against 1.1.1.1, against 8.8.8.8, and against my local resolver. `benchd.ai` resolves fine.



```console $ nslookup benchd.dev 1.1.1.1 *** one.one.one.one can't find benchd.dev: Non-existent domain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entire independent-verification story terminates at a domain that has never existed. Nobody has ever verified a Bench'd receipt using Bench'd's published method, because there has never been a host to fetch one from. That check took four seconds.&lt;/p&gt;

&lt;p&gt;Two more, quickly. Their trust page defines authenticity as a signature from "a key published on this page"; the key signing their own shipped manifests matches neither published fingerprint. And their trust page promises they take no payment from vendors on the leaderboard, while their pricing page sells those vendors a leaderboard badge. An organisation that ranks vendors cannot also invoice them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nobody is home
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The harness repo, the entire basis of the "independent, reproducible, open" claim: &lt;strong&gt;no commit
since 2026-06-06&lt;/strong&gt;. Eighty-four days.&lt;/li&gt;
&lt;li&gt;Five open issues, from two different vendors. &lt;strong&gt;Every comment on all five is from the person who filed it.&lt;/strong&gt; Dustin-a11y has been waiting since 14 July.&lt;/li&gt;
&lt;li&gt;Their submission endpoint caps uploads at ~4.5 MB, so no full trace manifest fits. &lt;strong&gt;Not even their own 16 MB manifests fit.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Submit real traces, get rejected by an unmaintained upload cap. Submit nothing, be Community-Verified at 100.0.&lt;/p&gt;

&lt;p&gt;Meanwhile the board publishes receipts dated two days ago, and the pricing page keeps selling.&lt;/p&gt;

&lt;h2&gt;
  
  
  The control finished third
&lt;/h2&gt;

&lt;p&gt;Bench'd runs a control: GPT-4o-mini with no memory attached. Conversational Memory track, 2026-08-29:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;LangMem&lt;/td&gt;
&lt;td&gt;60.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;LlamaIndex Memory&lt;/td&gt;
&lt;td&gt;59.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;no memory at all&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;57.6&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;LangChain Memory&lt;/td&gt;
&lt;td&gt;34.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Mem0&lt;/td&gt;
&lt;td&gt;32.4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A benchmark whose control finishes third is not measuring the thing it is named after.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is the industry, not one website
&lt;/h2&gt;

&lt;p&gt;Bench'd is downstream of a worse problem: the numbers it aggregates come from READMEs, and the READMEs do not survive checking.&lt;/p&gt;

&lt;p&gt;Over the past months I have checked the benchmark claims of several memory projects and have not yet found one that held up. A published 96.6% recall that becomes &lt;strong&gt;87.0%&lt;/strong&gt; when rescored with the benchmark's own scorer, because the field reports &lt;code&gt;recall_any&lt;/code&gt; where the benchmark specifies &lt;code&gt;recall_all&lt;/code&gt;. A "clean held-out" set built &lt;em&gt;after&lt;/em&gt; the tuning it was meant to hold out. LoCoMo ground truth with roughly 99 wrong or misattributed answers, per &lt;a href="https://github.com/dial481/locomo%20audit" rel="noopener noreferrer"&gt;@dial481's audit&lt;/a&gt;, and a judge accepting ~63% of deliberately wrong answers. Session-level LoCoMo recall quoted without mentioning that a &lt;strong&gt;random ranker scores 0.371&lt;/strong&gt; at the depths everyone reports.&lt;/p&gt;

&lt;p&gt;None of that is fraud. It is a field where the number goes in the README, the arithmetic goes nowhere, and nobody is expected to check. Every project that publishes a soft metric under a hard name makes it more rational for the next one to do the same. The honest ones lose ground for being honest, which is the part that actually disrupts the market.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I measured, briefly
&lt;/h2&gt;

&lt;p&gt;RE-call, through their harness, unmodified scoring path, on 2026-08-23: &lt;strong&gt;69.0 LongMemEval, 71.6 LoCoMo&lt;/strong&gt;, $6.64 total spend. The no-memory control is 57.6, so the number that means anything is &lt;strong&gt;+11.4 over having no memory&lt;/strong&gt;. I am giving you the control so you can compute that instead of trusting a ranking.&lt;/p&gt;

&lt;p&gt;Two disclosures, since I am demanding them from everyone else. I set RE-call's abstention threshold to zero: every question is answerable by construction and the judge scores "insufficient information" as wrong, so honest abstention forfeits 26.7 points, and refusing when nothing clears the threshold is the whole premise of my product. And I compare only within the Conversational Memory track.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;benchd-harness
benchd verify longmemeval-v1.manifest.signed.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Signed manifests, run records and SHA256SUMS: &lt;a href="https://github.com/GiulioDER/RE-call/releases/tag/benchd-official-2026-08-23" rel="noopener noreferrer"&gt;benchd official-2026-08-23&lt;/a&gt;.&lt;br&gt;
Pre-registered before measurement, wrong predictions left standing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Over to you
&lt;/h2&gt;

&lt;p&gt;Every check above took minutes. The DNS one took four seconds. If the checks are that cheap and keep coming back positive, the problem is not difficulty, it is that nobody is expected to look.&lt;/p&gt;

&lt;p&gt;Three questions, and I will answer every reply:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Is this just normal now?&lt;/strong&gt; Have you ever gone to verify a benchmark number in a README and found it did not hold? I want to know whether my hit rate is bad luck or the base rate, because from where I am standing it looks like the base rate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What do you do when it is your project on the losing end?&lt;/strong&gt; You ship a real number. Someone ships a bigger one that nobody checks, and takes the users, the stars and the funding with it. Do you match them and publish your softest metric, spend your time auditing theirs, or eat it and keep building? I have picked one of those three and I am not sure it was right.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What actually gets an unreal number corrected?&lt;/strong&gt; This is the one I most want answers to. A filed issue gets ignored. A polite email gets ignored. A public writeup costs you a week and makes you look like a competitor with an axe. What has worked for you: reproduction repos, pressure from the benchmark's own authors, a shared audit registry, something I have not thought of? Not how to attack anyone, how to make the correction actually land, because everything I have tried so far has mostly not.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If any line here is wrong, name it and I will correct it publicly, same prominence, same day. I put that offer in their issue tracker before publishing rather than after.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>ai</category>
      <category>opensource</category>
      <category>llm</category>
    </item>
    <item>
      <title>I Gave Claude Code a Brain. This Time I Let the Tests Judge It.</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Mon, 24 Aug 2026 16:06:44 +0000</pubDate>
      <link>https://dev.to/gde03/i-gave-claude-code-a-brain-this-time-i-let-the-tests-judge-it-5h0p</link>
      <guid>https://dev.to/gde03/i-gave-claude-code-a-brain-this-time-i-let-the-tests-judge-it-5h0p</guid>
      <description>&lt;p&gt;&lt;em&gt;The first experiment measured whether Claude Code knew the right answer. This one measured whether the work actually succeeded.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In my &lt;a href="https://dev.to/gde03/i-gave-claude-code-a-brain-its-mistake-rate-went-to-zero-3d8l"&gt;previous experiment&lt;/a&gt;, I tested whether a memory layer could stop Claude Code from confidently repeating project-specific mistakes.&lt;/p&gt;

&lt;p&gt;It did.&lt;/p&gt;

&lt;p&gt;But there was an obvious limitation.&lt;/p&gt;

&lt;p&gt;The tasks measured whether the answer was correct. They did not ask the agent to modify a repository, run the result, and pass a deterministic test.&lt;/p&gt;

&lt;p&gt;So I ran the harder version.&lt;/p&gt;

&lt;p&gt;This time, the agent had to do real work in a temporary repository. A checker decided whether the result was correct. No judge model. No subjective scoring. The task either passed or it did not.&lt;/p&gt;

&lt;p&gt;Here is the result from the complete run:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Successful runs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code without memory&lt;/td&gt;
&lt;td&gt;50.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code with &lt;code&gt;CLAUDE.md&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;36.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Claude Code with RE-call&lt;/td&gt;
&lt;td&gt;58.3%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;RE-call improved success over the &lt;code&gt;CLAUDE.md&lt;/code&gt; baseline by 22.2 percentage points.&lt;/p&gt;

&lt;p&gt;The 95% confidence interval was +11.1 to +33.3 points.&lt;/p&gt;

&lt;p&gt;The paired McNemar test gave a p-value of 0.000145.&lt;/p&gt;

&lt;p&gt;This was not one lucky demonstration. It was 72 paired comparisons across 24 tasks and three seeds, with zero discarded cells.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed from the first experiment?
&lt;/h2&gt;

&lt;p&gt;Each task asked Claude Code to create or modify files in a repository and run the result.&lt;/p&gt;

&lt;p&gt;The benchmark included tasks involving things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deterministic file ordering&lt;/li&gt;
&lt;li&gt;Unicode normalization&lt;/li&gt;
&lt;li&gt;migration naming&lt;/li&gt;
&lt;li&gt;shell quoting&lt;/li&gt;
&lt;li&gt;money rounding&lt;/li&gt;
&lt;li&gt;stable sorting&lt;/li&gt;
&lt;li&gt;line ending handling&lt;/li&gt;
&lt;li&gt;generated files and golden outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important detail is that every task had a deterministic checker.&lt;/p&gt;

&lt;p&gt;The agent could say "done" all it wanted. The checker only cared whether the repository ended up in the correct state.&lt;/p&gt;

&lt;p&gt;I ran every task through three configurations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bare Claude Code&lt;/li&gt;
&lt;li&gt;Claude Code with the project's &lt;code&gt;CLAUDE.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Claude Code with the same environment plus RE-call memory&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The harness also verified that the memory tools were actually available before counting a session. If the memory layer was missing, the entire paired cell was discarded.&lt;/p&gt;

&lt;p&gt;That happened zero times in the DeepSeek run.&lt;/p&gt;

&lt;h2&gt;
  
  
  RE-call helped where project memory mattered
&lt;/h2&gt;

&lt;p&gt;The most useful comparison is RE-call versus the static &lt;code&gt;CLAUDE.md&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The static file produced a 36.1% success rate.&lt;/p&gt;

&lt;p&gt;RE-call produced 58.3%.&lt;/p&gt;

&lt;p&gt;That is a 22.2 point improvement.&lt;/p&gt;

&lt;p&gt;The paired results were even more revealing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RE-call won 17 comparisons that &lt;code&gt;CLAUDE.md&lt;/code&gt; lost&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CLAUDE.md&lt;/code&gt; won only 1 comparison that RE-call lost&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The effect was strongest on the tasks classified as memory-sensitive. Across those eight tasks, RE-call improved success by 45.8 percentage points.&lt;/p&gt;

&lt;p&gt;That is the pattern I was looking for.&lt;/p&gt;

&lt;p&gt;Memory did not make every task easier. It helped when the task depended on a project decision, convention, or failure mode that was not fully present in the immediate prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  The surprising result was &lt;code&gt;CLAUDE.md&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The static &lt;code&gt;CLAUDE.md&lt;/code&gt; configuration performed worse than the bare configuration:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Successful runs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bare&lt;/td&gt;
&lt;td&gt;50.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;36.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The bare configuration won by 13.9 percentage points.&lt;/p&gt;

&lt;p&gt;This is not what I expected.&lt;/p&gt;

&lt;p&gt;It suggests that a static instruction file is not automatically a memory system. It can add useful guidance, but it can also add noise, constraints, or instructions that compete with the task.&lt;/p&gt;

&lt;p&gt;RE-call is doing something different.&lt;/p&gt;

&lt;p&gt;Instead of putting every historical fact into the permanent prompt, it gives the agent a way to retrieve relevant project history when the current task needs it.&lt;/p&gt;

&lt;p&gt;That distinction matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory did not just improve the final score
&lt;/h2&gt;

&lt;p&gt;The benchmark also measured what happened inside the memory mechanism.&lt;/p&gt;

&lt;p&gt;In the DeepSeek run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The agent searched memory in 83.3% of eligible sessions.&lt;/li&gt;
&lt;li&gt;When it searched, it reached useful context 85.0% of the time.&lt;/li&gt;
&lt;li&gt;Overall, useful project context was reached in 70.8% of sessions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the result is not simply that "the model had more tokens."&lt;/p&gt;

&lt;p&gt;The memory layer was being consulted, and in most cases where it was consulted, it reached something useful.&lt;/p&gt;

&lt;p&gt;There is still room to improve retrieval. A search is not automatically a good search. The model needs to find the right historical decision, not merely retrieve something related to the words in the prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  The cost
&lt;/h2&gt;

&lt;p&gt;The complete DeepSeek run cost an estimated $0.4964 at the captured API prices.&lt;/p&gt;

&lt;p&gt;The three arms cost:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Estimated cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bare&lt;/td&gt;
&lt;td&gt;$0.0824&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$0.0863&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RE-call&lt;/td&gt;
&lt;td&gt;$0.3277&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;RE-call used about four times as many total tokens as the static prompt configuration.&lt;/p&gt;

&lt;p&gt;That is the tradeoff.&lt;/p&gt;

&lt;p&gt;The memory layer costs more on every task, including tasks where memory is unnecessary. In exchange, it can prevent the much more expensive failure mode where an agent confidently follows an outdated convention, repeats a known mistake, or spends several minutes debugging a problem the team already solved.&lt;/p&gt;

&lt;p&gt;The next engineering question is not whether memory helps.&lt;/p&gt;

&lt;p&gt;It is how to make the retrieval smaller, faster, and more selective.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about GPT-5.3 Codex?
&lt;/h2&gt;

&lt;p&gt;I also started the same model-freeze run with GPT-5.3 Codex.&lt;/p&gt;

&lt;p&gt;That run is not a negative result for GPT.&lt;/p&gt;

&lt;p&gt;The provider hit a credit and in-flight request limit while the benchmark was running. The harness correctly discarded the affected paired cells instead of treating missing sessions as failed model attempts.&lt;/p&gt;

&lt;p&gt;Only 40 of the 72 paired cells were admissible, so I am not using that run to claim that GPT-5.3 Codex is better or worse.&lt;/p&gt;

&lt;p&gt;The descriptive numbers pointed in the same direction:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Configuration&lt;/th&gt;
&lt;th&gt;Successful runs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bare&lt;/td&gt;
&lt;td&gt;47.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CLAUDE.md&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RE-call&lt;/td&gt;
&lt;td&gt;50.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;But the run needs to be repeated with the provider capacity issue fixed before it becomes a valid model comparison.&lt;/p&gt;

&lt;p&gt;That is an operational failure, not a model conclusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this proves
&lt;/h2&gt;

&lt;p&gt;This experiment does not show that memory makes an agent generally smarter.&lt;/p&gt;

&lt;p&gt;It shows something narrower and more useful:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A production memory layer can improve the probability that an agent completes a real repository task correctly.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this run, RE-call improved success by 22.2 percentage points over the static project file.&lt;/p&gt;

&lt;p&gt;It also improved success over the bare configuration, although that gain was smaller at 8.3 points. That difference is important. The main value is not simply adding more instructions. The value is retrieving the right project-specific context when it matters.&lt;/p&gt;

&lt;p&gt;The first experiment showed that memory can make answers more correct.&lt;/p&gt;

&lt;p&gt;This experiment showed that the improvement survives contact with the repository.&lt;/p&gt;

&lt;p&gt;That is the result I was actually waiting for.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;The next step is a clean competitor comparison:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rerun GPT-5.3 Codex with sufficient provider capacity&lt;/li&gt;
&lt;li&gt;compare RE-call against other memory systems&lt;/li&gt;
&lt;li&gt;keep the same tasks, seeds, checkers, and admission gate&lt;/li&gt;
&lt;li&gt;publish discarded cells and operational failures alongside the scores&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is not to produce another flattering demo.&lt;/p&gt;

&lt;p&gt;The goal is to find out whether a memory layer remains useful when the models, vendors, and retrieval systems change.&lt;/p&gt;

&lt;p&gt;That is the benchmark I want to run next.&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/GiulioDER" rel="noopener noreferrer"&gt;
        GiulioDER
      &lt;/a&gt; / &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;
        RE-call
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Memory that abstains instead of guessing: agent memory on your own Postgres with a verdict, confidence and provenance on every hit, and a calibrated refusal when nothing clears the threshold.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/GiulioDER/RE-call/master/docs/banner.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FGiulioDER%2FRE-call%2Fmaster%2Fdocs%2Fbanner.png" alt="RE-call: memory that knows when not to guess" width="900"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;b&gt;Memory that abstains instead of guessing.&lt;/b&gt;&lt;br&gt;
  RE-call is agent memory on your own PostgreSQL with pgvector: every hit carries a verdict
  confidence and provenance, a retracted claim comes back marked &lt;code&gt;superseded&lt;/code&gt;, and a
  question the corpus cannot answer is refused rather than answered from the nearest neighbour
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://github.com/GiulioDER/RE-call/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/GiulioDER/RE-call/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt;
  &lt;a href="https://pypi.org/project/recall-rag/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1f8539ee4aa2c08fc6fc0bfe7c3b1d733321ddad64d9786f4b3ac0d6635b77cb/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f726563616c6c2d726167" alt="PyPI version"&gt;&lt;/a&gt;
  &lt;a href="https://pypi.org/project/recall-rag/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/8de1c54930a85380f03670b6a5dabf403928f87e9bbd0dbcd6c7856793168fe2/68747470733a2f2f696d672e736869656c64732e696f2f707970692f646d2f726563616c6c2d726167" alt="PyPI downloads"&gt;&lt;/a&gt;
  &lt;a href="https://github.com/GiulioDER/RE-call/blob/master/LICENSE" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/a549a7a30bacba7bfceebdc207a8e86c3f2c02995a2527640dca30048fd2b64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d417061636865253230322e302d626c75652e737667" alt="License: Apache 2.0"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565"&gt;&lt;img src="https://camo.githubusercontent.com/96abf9b704f80578ea56dd10cab0d911c56d46dbec347f431ece9cf60ac175ad/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f707974686f6e2d332e31312532422d626c7565" alt="Python 3.11+"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer" href="https://github.com/GiulioDER/RE-call/docs/postgresql-badge.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FGiulioDER%2FRE-call%2FHEAD%2Fdocs%2Fpostgresql-badge.svg" alt="PostgreSQL + pgvector"&gt;&lt;/a&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/ac0f8629636aee4176e42c623d8572fb7c475e348416842205d43b4ba56da394/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f43492d7265616c2532307067766563746f72253230c2b72532307479706573253230c2b725323061756469742d627269676874677265656e"&gt;&lt;img src="https://camo.githubusercontent.com/ac0f8629636aee4176e42c623d8572fb7c475e348416842205d43b4ba56da394/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f43492d7265616c2532307067766563746f72253230c2b72532307479706573253230c2b725323061756469742d627269676874677265656e" alt="CI: real pgvector, types, audit"&gt;&lt;/a&gt;
  &lt;a href="https://glama.ai/mcp/servers/GiulioDER/RE-call" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9a2ac13602ba1ce75a3eec396da85f3d32fc65505b6b2dfaef31893ac719cff3/68747470733a2f2f676c616d612e61692f6d63702f736572766572732f4769756c696f4445522f52452d63616c6c2f6261646765732f73636f72652e737667" alt="RE-call MCP server"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a rel="noopener noreferrer nofollow" href="https://raw.githubusercontent.com/GiulioDER/RE-call/master/launch/terminal-video/out/re-call-terminal-demo-preview.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FGiulioDER%2FRE-call%2Fmaster%2Flaunch%2Fterminal-video%2Fout%2Fre-call-terminal-demo-preview.gif" alt="Terminal demo: a stale rate-limit memo outranks its correction on cosine, RE-call marks it superseded, and an unanswerable query is refused" width="720"&gt;&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  ATM-Bench Recall@10 &lt;b&gt;92.8924&lt;/b&gt; 
  against 79.09 
  for the best published row (&lt;a href="https://github.com/GiulioDER/RE-call/blob/master/docs/ATM_BENCH.md" rel="noopener noreferrer"&gt;limits&lt;/a&gt;)
  &amp;nbsp;·&amp;nbsp;
  second of ten on MTRAG correct refusals (&lt;a href="https://github.com/GiulioDER/RE-call/blob/master/docs/MTRAG_BENCHMARK.md" rel="noopener noreferrer"&gt;limits&lt;/a&gt;)
  &amp;nbsp;·&amp;nbsp;
  zero memory-layer LLM calls to build memory, where Mem0 pays one per session (&lt;a href="https://github.com/GiulioDER/RE-call/blob/master/benchmarks/REVIEW.md" rel="noopener noreferrer"&gt;limits&lt;/a&gt;)
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://github.com/GiulioDER/RE-call#why-re-call" rel="noopener noreferrer"&gt;Why RE-call&lt;/a&gt;
  &amp;nbsp;·&amp;nbsp;
  &lt;a href="https://github.com/GiulioDER/RE-call#quickstart" rel="noopener noreferrer"&gt;Quickstart&lt;/a&gt;
  &amp;nbsp;·&amp;nbsp;
  &lt;a href="https://github.com/GiulioDER/RE-call#how-it-works" rel="noopener noreferrer"&gt;How it works&lt;/a&gt;
  &amp;nbsp;·&amp;nbsp;
  &lt;a href="https://github.com/GiulioDER/RE-call#product-surface" rel="noopener noreferrer"&gt;Product surface&lt;/a&gt;
  &amp;nbsp;·&amp;nbsp;
  &lt;a href="https://github.com/GiulioDER/RE-call#documentation" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;
  &amp;nbsp;·&amp;nbsp;
  &lt;a href="https://github.com/GiulioDER/RE-call#evidence" rel="noopener noreferrer"&gt;Evidence&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;a href="https://giulioder.github.io/RE-call/" rel="nofollow noopener noreferrer"&gt;Setup guide: install, configure and run RE-call&lt;/a&gt;
  &amp;nbsp;·&amp;nbsp;
  &lt;a href="https://github.com/GiulioDER/validity-frontmatter" rel="noopener noreferrer"&gt;Validity Frontmatter: the open spec RE-call implements&lt;/a&gt;
&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why RE-call&lt;/h2&gt;

&lt;/div&gt;

&lt;p&gt;Nearest-match retrieval cannot tell the difference between what is true and what merely reads like
it. When a corpus keeps its history, and real agent memory does, the retracted…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


</description>
      <category>ai</category>
      <category>agents</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Gave Claude Code a Brain. Its Mistake Rate Went to Zero.</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Fri, 21 Aug 2026 20:43:21 +0000</pubDate>
      <link>https://dev.to/gde03/i-gave-claude-code-a-brain-its-mistake-rate-went-to-zero-3d8l</link>
      <guid>https://dev.to/gde03/i-gave-claude-code-a-brain-its-mistake-rate-went-to-zero-3d8l</guid>
      <description>&lt;p&gt;&lt;strong&gt;40 tasks. Without memory it got them wrong 52.5% of the time. With memory: 0%.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not "fewer mistakes". Not "improved by 30%". Zero. Forty out of forty.&lt;/p&gt;

&lt;p&gt;Here is the entire result before I explain anything:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Claude Code&lt;/th&gt;
&lt;th&gt;Claude Code &lt;strong&gt;+ RE-call&lt;/strong&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Got it wrong&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;52.5%&lt;/strong&gt; of runs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Answer correctness&lt;/td&gt;
&lt;td&gt;0.144&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.358&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Factual correctness&lt;/td&gt;
&lt;td&gt;0.288&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.559&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Times memory made things worse&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 out of 40&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Correctness doubled. Factual accuracy doubled. And across 40 head to head runs, the version with memory never once lost a round the other one won.&lt;/p&gt;

&lt;p&gt;The p values are 0.0003 and below. In plain language: this is not luck.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that actually buys you
&lt;/h2&gt;

&lt;p&gt;Numbers are nice. Here is what they mean on a Tuesday afternoon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your agent stops confidently recommending commands that do not work.&lt;/strong&gt; Not commands that error out, because you would catch those. Commands that succeed, print something reassuring, and do nothing at all. Those are the expensive ones, precisely because you believe them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your agent knows the decisions your team already made.&lt;/strong&gt; Why that library version is pinned. Why that directory is gitignored. Which flag broke production in March. The knowledge that lives in people's heads, old pull requests, and nowhere the model can see.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answers about your repository get twice as correct.&lt;/strong&gt; Not longer, not vaguer. More right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It never makes anything worse.&lt;/strong&gt; Zero regressions across 40 paired runs. That is the number I would want to see before letting anything near my workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I did not just publish another benchmark
&lt;/h2&gt;

&lt;p&gt;I have run RE-call through plenty of them. Retrieval benchmarks, long context benchmarks, answer quality benchmarks. They are genuinely useful and I keep running them, because a benchmark tells you where your system is weak, which knob actually matters, and whether last week's idea was clever or merely expensive.&lt;/p&gt;

&lt;p&gt;But a retrieval benchmark proves your retriever retrieves. It does not prove anyone is better off.&lt;/p&gt;

&lt;p&gt;You can top a leaderboard and change nothing about a single developer's day. That gap bothered me enough to go and measure the day instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the test was built
&lt;/h2&gt;

&lt;p&gt;The whole design fits in one sentence: run the same task through two Claude Code sessions that differ by exactly one thing, and count what happens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The two sessions.&lt;/strong&gt; Both ran the same model. Both got the same tasks. Both loaded the same &lt;code&gt;CLAUDE.md&lt;/code&gt; project file, byte for byte, and I made the harness verify that at the start of every run rather than take my word for it. Both ran with hooks, plugins and auto loaded context switched off, so nothing could sneak in a hidden advantage. The only difference: one session could also search a curated memory of the project, and the other could not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tasks.&lt;/strong&gt; Ten tasks, each hiding a hazard this project ran into once, paid for, and wrote down. A CPU cap that reports success and caps nothing. An image renderer that does not exist on this machine. A library install that quietly breaks the environment. Ordinary requests, each with a booby trap that only bites if you do not know the history.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The scoring for hazards.&lt;/strong&gt; Each hazard has a deterministic checker that reads the session transcript and decides whether the agent walked into it. A pattern, not an opinion. No model gets a vote on this part.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The repetitions.&lt;/strong&gt; Each hazard task ran ten times per arm, because agents are not deterministic and one run of anything proves nothing. Sixty paired runs in total.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The honesty gate.&lt;/strong&gt; Before any pair counts, the harness checks that the memory tools were actually present in the memory session and actually absent in the other one. If either is wrong, the pair is thrown away rather than scored.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The predictions.&lt;/strong&gt; I wrote down what I expected before running anything, and committed it with a timestamp. That is the only reason I can tell you honestly which results surprised me, rather than building a story around whatever came out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The statistics.&lt;/strong&gt; Every comparison is paired, same task through both arms, so the test is on the difference within each pair rather than two independent piles of numbers. Hazards get an exact McNemar test, which looks only at pairs where the two arms disagreed. Costs get a Wilcoxon signed rank test, which does not assume the data is nicely shaped, because agent token counts absolutely are not.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I measured answer quality, with Ragas
&lt;/h2&gt;

&lt;p&gt;Counting hazards is the easy half. "Was the answer actually any good" is where most demos quietly stop and switch to screenshots.&lt;/p&gt;

&lt;p&gt;For that I used &lt;strong&gt;&lt;a href="https://github.com/vibrantlabsai/ragas" rel="noopener noreferrer"&gt;Ragas&lt;/a&gt;&lt;/strong&gt;, an open source evaluation toolkit for LLM applications. It exists to turn "that looks about right" into a number, which is exactly the problem I had.&lt;/p&gt;

&lt;p&gt;The way it works is refreshingly boring. You write down the correct answer in advance. Ragas then breaks the agent's actual response into individual claims and checks each one against your reference, so you find out how much of what it said was right, and how much was confidently wrong.&lt;/p&gt;

&lt;p&gt;Two metrics from their library did the work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AnswerCorrectness&lt;/code&gt;&lt;/strong&gt;, which scores how much of the reference answer the response actually got right. I configured it with &lt;code&gt;weights=[1.0, 0.0]&lt;/code&gt;, which turns off the embedding similarity half. That half rewards an answer for &lt;em&gt;sounding&lt;/em&gt; like the reference, and I did not want to reward paraphrasing. Only factual overlap counts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;FactualCorrectness&lt;/code&gt;&lt;/strong&gt;, which compares the claims in the response against the claims in the reference and scores the agreement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three things kept it honest:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The judge is a different model family from the agent under test.&lt;/strong&gt; Claude Code did the work; a GPT model did the grading. Nothing marked its own homework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every reference answer was written before the runs.&lt;/strong&gt; Nobody got to decide what "correct" meant after seeing the output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every failed judge call is recorded, not dropped.&lt;/strong&gt; That matters more than it sounds. On my first attempt, five of six scores silently failed because the judge hit a token limit while decomposing long answers. Because failures were recorded rather than skipped, I caught it. Had they been skipped, I would have published a quality number computed from one sixth of the run with a perfectly plausible figure on top.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Final tally: 120 responses scored, zero failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  The control that makes the rest believable
&lt;/h2&gt;

&lt;p&gt;This is the part product demos skip, and the part I would look for first as a reader.&lt;/p&gt;

&lt;p&gt;I also ran tasks where the answer was already sitting in &lt;code&gt;CLAUDE.md&lt;/code&gt;. Both agents had that file. So memory should add precisely nothing.&lt;/p&gt;

&lt;p&gt;Result: &lt;strong&gt;0.083 against 0.083. A difference of exactly zero. p = 1.0.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If memory had "won" there too, my experiment would be broken and this article would not exist. The gain appears exactly where memory holds something the file does not, and vanishes everywhere else. That is what a real effect looks like, as opposed to a flattering one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The finding I did not expect
&lt;/h2&gt;

&lt;p&gt;The first time I ran this, I did the clever thing. I gave the agent RE call &lt;strong&gt;instead of&lt;/strong&gt; &lt;code&gt;CLAUDE.md&lt;/code&gt;. Retrieval replaces your documentation. That is the entire pitch of RAG.Answer quality improved by 0.044, with a p value of 0.43. Translation: nothing happened.Then I ran it the way an actual developer would set it up. Keep your &lt;code&gt;CLAUDE.md&lt;/code&gt;. Add memory on top.&lt;/p&gt;

&lt;p&gt;Quality nearly doubled.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replacing your documentation with retrieval does nothing. Adding retrieval to it changes everything.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I had written down the opposite prediction before running a single session, which is the only reason I can prove I was surprised rather than inventing the narrative afterwards.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs
&lt;/h2&gt;

&lt;p&gt;About 15,000 extra input tokens per session, and a couple of seconds. On tasks where memory cannot possibly help, it runs slightly slower, because it goes and looks something up and finds nothing useful.&lt;/p&gt;

&lt;p&gt;That is the trade: pay a little on every task, stop paying enormously on the ones that would have gone wrong. Roughly once in twenty runs, the agent without memory disappeared down a hole for seven minutes chasing something that had been written down all along.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not prove yet
&lt;/h2&gt;

&lt;p&gt;I would rather say this myself than have someone say it for me.&lt;/p&gt;

&lt;p&gt;This shows memory eliminates a specific, expensive class of mistake and makes answers about your project substantially more correct. It does not show memory makes an agent generally smarter. Where memory has nothing to add, it adds nothing, and I have the control numbers proving both halves.&lt;/p&gt;

&lt;p&gt;It also does not yet show that the &lt;strong&gt;work&lt;/strong&gt; succeeds more often. Every task here asks for a recommendation and scores whether that recommendation is right. None of them writes code, runs a test suite, or ships anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2 coming soon
&lt;/h2&gt;

&lt;p&gt;The next round is already running, and it asks the harder question: does the work actually succeed?&lt;/p&gt;

&lt;p&gt;Real tasks, in a real repository, where a test suite decides the outcome. No judge, no reference answer, no interpretation. It passes or it does not. Alongside it, more measurements on where the gains come from: how often memory gets consulted, how often it returns the fact that matters, and which kinds of task benefit most.&lt;/p&gt;

&lt;p&gt;That is the number I actually want, and I will publish it whichever way it falls.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Part 2 coming soon.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>productivity</category>
      <category>agents</category>
    </item>
    <item>
      <title>The RAG benchmark that pays you for saying "I don't know", and what it exposed</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Sun, 09 Aug 2026 11:33:16 +0000</pubDate>
      <link>https://dev.to/gde03/the-rag-benchmark-that-pays-you-for-saying-i-dont-know-and-what-it-exposed-4411</link>
      <guid>https://dev.to/gde03/the-rag-benchmark-that-pays-you-for-saying-i-dont-know-and-what-it-exposed-4411</guid>
      <description>&lt;p&gt;Nine published systems. One of them refuses 2.3× more often than &lt;code&gt;gpt-4o&lt;/code&gt; and still finishes 4th on answer quality. It calls no LLM.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Part 5 of &lt;strong&gt;The Answerability Problem&lt;/strong&gt;. Parts 1 to 4 argued the field measures accuracy on questions that have answers. This one is about the benchmark that doesn't. Code: &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt; (Apache 2.0).&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/IBM/mt-rag-benchmark" rel="noopener noreferrer"&gt;MTRAG&lt;/a&gt;&lt;/strong&gt; (IBM, TACL 2025) is 842 human-written multi-turn tasks with an official &lt;code&gt;gpt-4o-mini&lt;/code&gt; judge that pays a &lt;strong&gt;full 1.0 on every metric&lt;/strong&gt; for correctly saying &lt;em&gt;"I do not have that information."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Almost no other benchmark scores a refusal as anything but a miss. So this is the one board where the thing my system is built for is actually worth points.&lt;/p&gt;

&lt;p&gt;Here is what nine published systems do with that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nobody is collecting the free money
&lt;/h2&gt;

&lt;p&gt;Correct refusals on the 55 unanswerable tasks. Same judge, same tasks, every system:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;system&lt;/th&gt;
&lt;th&gt;correct refusals&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;llama-3.1-8b&lt;/td&gt;
&lt;td&gt;18/55&lt;/td&gt;
&lt;td&gt;32.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;🔹 &lt;code&gt;gpt-4o&lt;/code&gt; + RE-call&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;16/55&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;29.1%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;llama-3.1-70b&lt;/td&gt;
&lt;td&gt;16/55&lt;/td&gt;
&lt;td&gt;29.1%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;gpt-4o-mini&lt;/td&gt;
&lt;td&gt;13/55&lt;/td&gt;
&lt;td&gt;23.6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;gpt-4o &lt;em&gt;(benchmark's own retrieval)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;7/55&lt;/td&gt;
&lt;td&gt;12.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;llama-3.1-405b&lt;/td&gt;
&lt;td&gt;3/55&lt;/td&gt;
&lt;td&gt;5.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;qwen-2.5-72b&lt;/td&gt;
&lt;td&gt;1/55&lt;/td&gt;
&lt;td&gt;1.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;mixtral-8x22b&lt;/td&gt;
&lt;td&gt;0/55&lt;/td&gt;
&lt;td&gt;0.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Two rows in that table read the same document set with the same model.&lt;/strong&gt; Row 6 is &lt;code&gt;gpt-4o&lt;/code&gt; on the benchmark's own retrieval. Row 2 is &lt;code&gt;gpt-4o&lt;/code&gt; on RE-call's. Same reader, same prompt, same judge, only the contexts differ, and the refusal rate goes from 7 to 16 out of 55.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then read the rank order. It is close to inverted against model size.&lt;/strong&gt; The 8B model refuses best. The 405B model refuses 5.5% of the time. One model refuses nothing at all. Scale does not buy this, and on this evidence it costs it.&lt;/p&gt;

&lt;p&gt;RE-call is &lt;strong&gt;second of ten&lt;/strong&gt;, tied exactly with &lt;code&gt;llama-3.1-70b&lt;/code&gt; at 16 of 55, and it refuses &lt;strong&gt;2.3× more often than &lt;code&gt;gpt-4o&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;16× more often than &lt;code&gt;qwen-2.5-72b&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The usual objection, answered
&lt;/h2&gt;

&lt;p&gt;Abstention is cheap if you don't care about answering. So here is what it cost, on the same 842 tasks:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;system&lt;/th&gt;
&lt;th&gt;answer quality&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;llama-3.1-405b&lt;/td&gt;
&lt;td&gt;0.5691&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;qwen-2.5-72b&lt;/td&gt;
&lt;td&gt;0.5625&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;gpt-4o &lt;em&gt;(benchmark's own retrieval)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;0.5591&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;🔹 &lt;code&gt;gpt-4o&lt;/code&gt; + RE-call&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.5527&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;c4ai-command-r-plus&lt;/td&gt;
&lt;td&gt;0.5502&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;RE-call is the only system in that top four that is also top two on abstention.&lt;/strong&gt; The three above it refuse 5.5%, 1.8% and 12.7%. The gap to &lt;code&gt;gpt-4o&lt;/code&gt; is &lt;strong&gt;0.0064&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is the whole claim, and it is a narrow one: not "best", but &lt;strong&gt;the only one on the board that is near the top of both columns at once&lt;/strong&gt;. Everyone else picked a column.&lt;/p&gt;

&lt;p&gt;Same two rows again, 3 and 4, same reader. Swapping the benchmark's own retrieval for RE-call's costs &lt;strong&gt;0.0064&lt;/strong&gt; on answer quality and more than doubles what the system correctly refuses. That is the trade, priced.&lt;/p&gt;

&lt;p&gt;And against the benchmark's own retrieval directly, identical generator, prompt and judge, only the contexts swapped, RE-call is ahead: &lt;strong&gt;0.5527 against 0.5516&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Small. Positive under both prompts I tested. I am not going to inflate it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Every row above is scored by MTRAG's official &lt;code&gt;gpt-4o-mini-2024-07-18&lt;/code&gt; judge, hard-coded by the benchmark and applied identically to my rows and theirs. The reader on my rows is &lt;code&gt;gpt-4o&lt;/code&gt;, the same model as the row I am compared against.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One engine, whatever you can afford
&lt;/h2&gt;

&lt;p&gt;The other half of this. The same pipeline runs at both ends of the price range, and every rung is a named flag with a measured price, not a tier you buy.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;configuration&lt;/th&gt;
&lt;th&gt;nDCG@5&lt;/th&gt;
&lt;th&gt;cost&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;🔹 SPLADE learned sparse &lt;em&gt;(the free default)&lt;/em&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.3573&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;local, $0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+ Voyage rerank &lt;em&gt;(one flag)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;0.4342&lt;/td&gt;
&lt;td&gt;paid API&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;A 48% relative span between two flags&lt;/strong&gt;, measured on 777 judged queries.&lt;/p&gt;

&lt;p&gt;The reranker is worth &lt;strong&gt;+0.0769 nDCG@5&lt;/strong&gt; and is &lt;strong&gt;worse on 162 of the 777&lt;/strong&gt;. That is exactly why it is off by default. I would rather ship a flag with two published numbers than a default with a marketing claim.&lt;/p&gt;

&lt;p&gt;Everything dashed and amber below is opt-in and switched on by name. The solid path is what runs if you change nothing, and it costs &lt;strong&gt;$0 at any scale&lt;/strong&gt;, because there is no LLM anywhere in it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3t7fmf1sxpq24pd7k1qq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3t7fmf1sxpq24pd7k1qq.png" alt="The RE-call pipeline. Write path: memo with supersession and validity frontmatter, chunk, embed locally with no API call. Query path: embed the query. Both meet in one PostgreSQL and pgvector database holding vectors and full text. Dense cosine and sparse full-text retrieval feed Reciprocal Rank Fusion, with an optional cross-encoder rerank shown dashed and amber. Then a gap check against a calibrated threshold, then the trust layer enforcing supersession, validity and confidence, fed by a calibration fitted per embedder and corpus. Output is a verdict with confidence and provenance, or ABSTAIN with a reason." width="800" height="1355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Writing a memory is a local embedding.&lt;/strong&gt; No LLM call, so the marginal cost of a memory is $0 and stays $0 at any scale, on any model, forever. There is no upstream pricing change that can alter that.&lt;/p&gt;

&lt;p&gt;Air-gapped and fully local, or cloud embedder and reranker when a jargon-heavy corpus makes it worth paying. Same engine, same guarantee at every setting: superseded or expired memories are demoted rather than served, and the confidence threshold is &lt;strong&gt;fitted per embedder and corpus at install time, never a shipped constant.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The number I nearly published
&lt;/h2&gt;

&lt;p&gt;One thing before you trust any of the above.&lt;/p&gt;

&lt;p&gt;An earlier version of this run had RE-call &lt;strong&gt;beating every baseline, including llama-3.1-405b&lt;/strong&gt;. It was an artifact and it was one edit away from going out.&lt;/p&gt;

&lt;p&gt;The official scorer reads the answerability label in lower case. The release files ship it capitalised. So the conditioning that pays 1.0 for a correct refusal silently never ran on my data: 2,526 lookups, &lt;strong&gt;zero label matches&lt;/strong&gt;. My metrics were raw, the published baselines' were conditioned, and I was comparing two different quantities in exactly the place where my system is strongest.&lt;/p&gt;

&lt;p&gt;Both sides were individually correct. &lt;strong&gt;The error lived entirely in the join.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two signals should have caught it earlier and I explained both away. I had even written the memo describing the two-key problem, that same day, and never connected it. Having the fact is not the same as applying it.&lt;/p&gt;

&lt;p&gt;Corrected, the honest reading is: RE-call at &lt;strong&gt;0.5527 against gpt-4o's 0.5591, so −0.0064&lt;/strong&gt;. Fourth, not first. The abstention result survives intact, because it was measured by the official judge rather than by the string-matching detector that had earlier inflated it from 29% to 43.6%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The anomaly you can explain is still an anomaly, and the one that flatters you is the one to chase hardest.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So which rung is yours
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Take the free default&lt;/strong&gt; if the marginal cost of a memory has to be zero, your data cannot leave, or you need it to work offline. 0.3573, local, $0, no API key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add the reranker&lt;/strong&gt; when a human is waiting. One second is invisible next to the generator call that follows it, and it is the largest single gain in the project. Check it on your corpus first: it lost on 162 of 777 queries here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use something else&lt;/strong&gt; if abstention is worth nothing to you and you only need the top of one column. Three systems beat me on answer quality. All three of them will confidently answer a question whose answer is not in the corpus, between 87% and 98% of the time.&lt;/p&gt;

&lt;p&gt;That is the trade. A system that invents a plausible answer and one that says nothing are not two points on one scale.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Every number, the six generation runs behind them, the correction in full, and the scoring bug I reported upstream: &lt;strong&gt;&lt;a href="https://github.com/GiulioDER/RE-call/blob/master/docs/MTRAG_BENCHMARK.md" rel="noopener noreferrer"&gt;docs/MTRAG_BENCHMARK.md&lt;/a&gt;&lt;/strong&gt;. &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt; is Apache 2.0, &lt;code&gt;pip install recall-rag&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ai</category>
      <category>opensource</category>
      <category>benchmarking</category>
    </item>
    <item>
      <title>Make your AI assistant predict the result before it runs it</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Sun, 02 Aug 2026 14:20:27 +0000</pubDate>
      <link>https://dev.to/gde03/make-your-ai-assistant-predict-the-result-before-it-runs-it-2abo</link>
      <guid>https://dev.to/gde03/make-your-ai-assistant-predict-the-result-before-it-runs-it-2abo</guid>
      <description>&lt;p&gt;&lt;em&gt;Less technical than my usual posts. Nothing to install, nothing to pay for, and it works the same whether you're using an AI assistant for code, spreadsheets, research or writing.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Here is the shape of the problem I want to describe. See if you recognise it.&lt;/p&gt;

&lt;p&gt;You ask your assistant to do something that produces a result. It does. A number, a summary, a status, an answer comes back. It's plausible. You ask why, and you get a clear, confident explanation that makes complete sense of it. So you believe it, you write it down, and you build your next three decisions on top of it.&lt;/p&gt;

&lt;p&gt;A week later you find out the whole thing was wrong. Not wrong in an obvious way. Wrong because the tool was measuring something you didn't ask about, or reading a file that was empty, or answering a slightly different question than the one in your head.&lt;/p&gt;

&lt;p&gt;Notice what didn't happen there. Nothing was invented. No fake citation, no made-up fact, none of the failures people mean when they say "hallucination". The failure was structural: &lt;strong&gt;nobody committed to what the answer should be while it was still possible to be wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The habit
&lt;/h2&gt;

&lt;p&gt;Before your assistant runs anything that produces a result, make it answer two questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. What do you expect the result to be, and why?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. How would you know if this were broken?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the whole technique. Two sentences before the work instead of a paragraph of explanation after it. It works on the free tier. It works on any model. It costs a few seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the first question works
&lt;/h2&gt;

&lt;p&gt;This isn't about "thinking harder", and it isn't a motivational trick. It changes the kind of problem your assistant is solving.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explaining a result you've already seen is an open-ended task.&lt;/strong&gt; There are a huge number of stories that fit any given outcome, and a language model is exceptionally good at finding one of them. That's not a flaw, it's the thing it's built to do. The problem is that a fluent explanation tells you nothing about whether the result is correct. It reads identical either way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Predicting a result you haven't seen is a closed task.&lt;/strong&gt; Everything the assistant believes about your data, your files and your request has to collapse into one statement that can turn out to be wrong. And when the real output disagrees with the prediction, you get a signal that could not have been manufactured after the fact, because the prediction is already sitting there on the screen.&lt;/p&gt;

&lt;p&gt;That gap between expected and actual is the entire product. It's cheap to produce and impossible to fake in hindsight.&lt;/p&gt;

&lt;p&gt;There's a bonus effect, and it's the reason results feel steadier once you do this. Predicting first pins down the standard of success &lt;strong&gt;before&lt;/strong&gt; the data arrives. Most of the wobble between one run and the next isn't the model changing its mind, it's the standard quietly moving to fit whatever showed up.&lt;/p&gt;

&lt;p&gt;Science has a name for this and an entire apparatus around it: pre-registration. Nobody needed to invent it for AI. We just forgot to apply it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the second question matters more
&lt;/h2&gt;

&lt;p&gt;I learned this one the expensive way.&lt;/p&gt;

&lt;p&gt;I had a system meant to answer time-sensitive questions: which of these documents was true &lt;em&gt;as of&lt;/em&gt; a particular date. It scored badly. I had predicted it would score badly, because the task is genuinely hard. Prediction matched result. I nodded, wrote the number down, and moved on.&lt;/p&gt;

&lt;p&gt;The prediction was right and the measurement was worthless.&lt;/p&gt;

&lt;p&gt;None of the documents had dates attached to them. Not one, out of four hundred and twenty. The system was being asked a question about time using material that had no time in it. When I fixed that, with exactly the same documents, the score went from 0.19 to 0.98.&lt;/p&gt;

&lt;p&gt;I want to be careful with that number, because it's the kind of number people quote badly, including the person who produced it. &lt;strong&gt;That is not an improvement.&lt;/strong&gt; Nothing got smarter. That's what it looks like from the outside when a broken instrument gets repaired, and if I'd published it as a win I'd have been telling a lie with correct arithmetic in it.&lt;/p&gt;

&lt;p&gt;Here's the general rule, and it's the part almost everyone skips:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Predicting the answer will not tell you the question was never asked.&lt;/strong&gt; If the setup is broken, your prediction and your result can be wrong in the same direction, agree with each other perfectly, and confirm nothing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which is exactly what the second question is for. "How would I know if this were broken?" forces something different out of the assistant: not a guess at the answer, but a statement about the machinery, one that has to hold true &lt;em&gt;whatever the answer turns out to be&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Expectation: "the score will be low, this is a hard problem."&lt;/li&gt;
&lt;li&gt;Broken-check: "if the documents don't have dates on them, the question isn't being asked at all."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first one was right and taught me nothing. The second one would have gone off on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Done is not the same as proved
&lt;/h2&gt;

&lt;p&gt;That second question generalises into something I now say out loud several times a week.&lt;/p&gt;

&lt;p&gt;When a task reports success, what you have learned is that a task reported success. You have not learned that a file was written, that the file has anything in it, that the numbers cover the dates you asked for, or that the check you requested was actually performed.&lt;/p&gt;

&lt;p&gt;My favourite example is small and stupid. I once wrote a rule-checker to catch a specific kind of mistake in my own work. It ran clean for weeks. It ran clean because of a settings mismatch that meant the rule I cared about was never switched on. The checker was structurally incapable of finding anything. Nothing was broken, nothing errored, everything was green, and the green meant nothing at all.&lt;/p&gt;

&lt;p&gt;The first test I wrote to fix that read the settings file to confirm the settings file. It passed. Two separate reviews walked straight past it. The thing that finally caught anything was running the checker against a deliberately bad example and watching it complain.&lt;/p&gt;

&lt;p&gt;So: ask for the output, not the status. Show me the rows. Show me the file. Show me it catching one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Anything that's supposed to warn you, make it warn you once
&lt;/h2&gt;

&lt;p&gt;Same idea, pointed somewhere useful.&lt;/p&gt;

&lt;p&gt;A safety net you have never seen catch anything is not a safety net. It's a guess in the shape of one. This applies to far more than code: the alert that's supposed to email you when a number goes out of range, the filter that's supposed to catch the bad rows, the check that's supposed to stop the bad export.&lt;/p&gt;

&lt;p&gt;So test it deliberately. Feed it the bad thing on purpose, once, and watch it fire.&lt;/p&gt;

&lt;p&gt;I ran that exercise across a system I'd been maintaining for months. It found twelve warnings that could never have gone off under any circumstances. One of them was the reason a cost had been quietly running for about two months before anyone noticed. Every one of those twelve had been read and approved by someone, including me. Reading them was never going to work, because they &lt;em&gt;read correctly&lt;/em&gt;. That's precisely what makes them dangerous.&lt;/p&gt;

&lt;p&gt;Two things I got wrong before I got them right, and they generalise:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Breaking it on purpose only proves whatever you actually broke.&lt;/strong&gt; I once "confirmed" that two checks happened in the right order by deleting one of them entirely. All that proved was that a check existed. The ordering, which was the actual thing I cared about, stayed untested.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A check that can't pass is as useless as one that can't fail.&lt;/strong&gt; I hit five in a row where the thing also refused to go green on a known-good input, and each one had been introduced while fixing the previous one. Identical behaviour on the good case and the bad case means it's measuring nothing, in either direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Look it up, don't remember it
&lt;/h2&gt;

&lt;p&gt;One more, cheaper than everything above. When the assistant needs a fact it could go and check, make it go and check. A confident wrong value is worse than an admitted blank, because a blank is honest and gets dealt with, while a wrong value slides silently into everything downstream.&lt;/p&gt;

&lt;p&gt;And the part that took me embarrassingly long to accept: &lt;strong&gt;"it isn't there" is a complete answer.&lt;/strong&gt; It does not need to be improved into something that looks more like information.&lt;/p&gt;

&lt;h2&gt;
  
  
  The version you can paste in right now
&lt;/h2&gt;

&lt;p&gt;All of it collapses into five lines. Put them in your assistant's instructions file, your saved prompt, your project settings, wherever your tool keeps standing rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; Before running anything that produces a result: say what you expect
  and why, in one or two sentences. Then run it.
&lt;span class="p"&gt;-&lt;/span&gt; Also say how I'd know if this were broken, and check that first.
&lt;span class="p"&gt;-&lt;/span&gt; "Done" is not a result. Show me the output: the file, the rows, the value.
&lt;span class="p"&gt;-&lt;/span&gt; Anything meant to warn me gets tested once by making it warn me.
&lt;span class="p"&gt;-&lt;/span&gt; Look facts up instead of recalling them. "Not there" is a valid answer.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If five lines is four too many, keep the second one. It's the one that has paid for itself the most times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Can you actually prove this helps?
&lt;/h2&gt;

&lt;p&gt;Not the way I'd like to. I can't show you that it produces fewer invented facts, because I haven't run that experiment and I'm not going to claim a result I don't have.&lt;/p&gt;

&lt;p&gt;But that isn't really the thing that hurts, is it. What hurts is the week you spend building on top of an answer that was wrong from the start. And &lt;strong&gt;that one is measurable, by you, this month, for free.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keep a tally. Every time you have to walk something back, throw work away, or redo a decision because the result underneath it turned out to be wrong, put a mark down. One line, one date, one sentence on what the wrong thing was.&lt;/p&gt;

&lt;p&gt;Do that for two weeks as you work now. Then add the two questions and do it for two more.&lt;/p&gt;

&lt;p&gt;You're not counting how often the assistant sounds right, which is close to always and tells you nothing. You're counting how often it &lt;em&gt;stayed&lt;/em&gt; right long enough to build on. That's the number that maps onto your actual time, and unlike a benchmark score it's yours, it's specific to your work, and nobody can argue with it.&lt;/p&gt;

&lt;p&gt;My honest position: I have a mechanism I find convincing and an incident log where the disasters cluster hard on the occasions when nobody committed to anything in advance. That's evidence. It isn't a measurement, and I'd be doing the exact thing this post argues against if I dressed it up as one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it doesn't help
&lt;/h2&gt;

&lt;p&gt;Three limits, because I'd rather say them than have them said back to me.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It needs something checkable.&lt;/strong&gt; If there's no observable outcome, "predict the result" turns into a confident-sounding preamble that flatters whatever comes next. When there's nothing to be wrong about, skip it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A confident prediction can pull you toward it.&lt;/strong&gt; Say a number out loud beforehand and there's pressure, on a model as much as on a person, to read the result as agreeing with it. The fix is to predict the &lt;strong&gt;observable&lt;/strong&gt;, not the conclusion. "There should be roughly 400 rows, all dated after June" pulls much less than "this should confirm my theory."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It slows you down slightly.&lt;/strong&gt; A few seconds per task. You get them back the first time it catches something, and you'll know exactly when that happens, because the prediction will be sitting right there next to the result, disagreeing with it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you try the five lines, I'd like to know which ones earn their place and which are cargo cult. I'm fairly sure at least one of them is.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>discuss</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The memory layer that never calls an LLM: what that buys, and what it costs</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Thu, 30 Jul 2026 20:43:23 +0000</pubDate>
      <link>https://dev.to/gde03/the-memory-layer-that-never-calls-an-llm-what-that-buys-and-what-it-costs-12ch</link>
      <guid>https://dev.to/gde03/the-memory-layer-that-never-calls-an-llm-what-that-buys-and-what-it-costs-12ch</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 4 of **The Answerability Problem&lt;/em&gt;&lt;em&gt;, and the one that isn't about abstention. &lt;a href="https://dev.to/gde03/the-ai-memory-benchmark-everyone-quotes-forbids-saying-i-dont-know-o1n"&gt;Parts 1–3&lt;/a&gt; argued that the field measures the wrong half and that my own system hits a wall on the right half. This part is the ledger: what RE-call is, what it loses at, and why you might still want the thing that loses. Code: &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt; (MIT).&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Three parts of "here is what doesn't work" earn one part of "here is what this is for."&lt;/p&gt;

&lt;p&gt;So, plainly: &lt;strong&gt;on BEAM's 1M-token bucket, Mem0 scores better than RE-call on categories I care about.&lt;/strong&gt; I'm not going to bury that, and I'm not going to explain it away. I'm going to tell you exactly why it happens, what that accuracy costs, and let you decide which side of the trade you want, because for a lot of people the answer is not the obvious one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mechanism, in one sentence
&lt;/h2&gt;

&lt;p&gt;Mem0 calls an LLM when you &lt;em&gt;write&lt;/em&gt; a memory, and stores the distilled result. RE-call calls no LLM ever, and stores your raw turns.&lt;/p&gt;

&lt;p&gt;That single decision explains everything downstream: the wins, the losses, the bill, and where your data goes.&lt;/p&gt;

&lt;p&gt;The clearest place to see it is &lt;code&gt;temporal_reasoning&lt;/code&gt;, my second-worst BEAM category: &lt;strong&gt;0.408 against Mem0's 0.567.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One disclosure before that number goes anywhere, because it changes what it means: &lt;strong&gt;that cell was measured with reranking off.&lt;/strong&gt; The BEAM harness takes a &lt;code&gt;--reranker&lt;/code&gt; flag and defaults it to &lt;code&gt;none&lt;/code&gt;, and the run didn't pass it. Reranking is the largest retrieval gain in this project. &lt;a href="https://dev.to/gde03/relevance-is-not-answerability-six-signals-and-none-of-them-beat-plain-cosine-2f14"&gt;Part 2&lt;/a&gt; measures it at hit@5 0.671 → 0.777 on LOCOMO, improving &lt;em&gt;every&lt;/em&gt; category including the multi-hop floor I'd predicted it wouldn't touch. So 0.408 is my &lt;strong&gt;shipped default&lt;/strong&gt;, not my best configuration, and the reranked cell is &lt;strong&gt;unmeasured&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'm not going to tell you which way that would go. The last time I predicted a category wouldn't benefit from reranking I was wrong, and guessing here would be the same error with a bigger number attached.&lt;/p&gt;

&lt;p&gt;What I &lt;em&gt;can&lt;/em&gt; say is that reranking is unlikely to be the whole story, because the diagnosis isn't a ranking failure. Of seven badly-lost questions only one had empty retrieval; five were answered confidently and wrongly. They are all the same shape, "how many days between A and B", and in the five it answered, my system used the wrong &lt;em&gt;instance&lt;/em&gt; of a date, while getting the arithmetic on those wrong dates right every single time. That is what makes this a selection problem and not a reasoning one:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;gold&lt;/th&gt;
&lt;th&gt;our answer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;25 Mar → 1 Apr = 7 days&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;14 days&lt;/strong&gt;, using the &lt;em&gt;updated&lt;/em&gt; deadline of 15 Apr&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25 Mar → 10 Apr = 16 days&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;26 days&lt;/strong&gt;, using a &lt;em&gt;different&lt;/em&gt; viewing on 15 Mar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;15 Feb → 20 Feb = 5 days&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;0 days&lt;/strong&gt;, using 10 Jan, the date the deadline was &lt;em&gt;set&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mem0 gets these right because its stored memory is one distilled line, &lt;em&gt;"Sprint 1 deadline: February 15, 2024"&lt;/em&gt;. Mine is the same date scattered across many raw turns in different roles: when it was set, when it was revised, when someone mentioned it in passing.&lt;/p&gt;

&lt;p&gt;&lt;del&gt;&lt;strong&gt;This is the one category where LLM distillation at ingest is genuinely the better architecture&lt;/strong&gt;, and no retrieval-side change I can afford replicates it. It's recorded in the repo as a known limit, not an open task.&lt;/del&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Correction, added after publication.&lt;/strong&gt; That paragraph claimed more than I had measured, and a reader's comment exposed it. The cell was measured with my own temporal layer structurally unable to fire, which is not the same as having tried it, and "recency is falsified" rules out one family of fix, not all of them. The obvious successor is unsound too, for a reason I did not expect: a validity window records when a turn was &lt;em&gt;said&lt;/em&gt;, not when the event &lt;em&gt;happened&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So I enumerated the seven questions instead of describing them; they are a fixture in the repo now. Of the five my system answered, the mechanisms are &lt;strong&gt;two&lt;/strong&gt; wrong instances of a similar event, &lt;strong&gt;one&lt;/strong&gt; genuine revision, &lt;strong&gt;one&lt;/strong&gt; field &lt;em&gt;value&lt;/em&gt; confused with the time it was &lt;em&gt;asserted&lt;/em&gt;, and &lt;strong&gt;one&lt;/strong&gt; event time confused with mention time. Supersession therefore reaches &lt;strong&gt;one of five&lt;/strong&gt;: four problems wearing one category name, none of them solved. Stated as narrowly as it was made, that is a hand reading of five answers from the run artifact alone, and five items is a list, not a rate.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So: they're better at this, for a real reason. Whether it is cheaply fixable is now an open question rather than a closed one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What that accuracy costs
&lt;/h2&gt;

&lt;p&gt;Here's the other side of the same decision, measured on the identical benchmark workload:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;RE-call&lt;/th&gt;
&lt;th&gt;Mem0&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LLM calls to build the memory&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;272&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tokens&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.6 M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;cost&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$7.29&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ingest wall clock&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;67 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;288 s (&lt;strong&gt;~4.3× slower&lt;/strong&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;where your documents go&lt;/td&gt;
&lt;td&gt;your Postgres&lt;/td&gt;
&lt;td&gt;an LLM provider, once per memory written&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That $7.29 is for &lt;em&gt;one&lt;/em&gt; benchmark's memory. It is not a subscription. It is a per-memory marginal cost that scales with everything you ever write. RE-call's write path calls no model, so its marginal cost is &lt;strong&gt;$0 at any scale, on any model, forever&lt;/strong&gt;. There is no pricing change upstream that can alter that number.&lt;/p&gt;

&lt;p&gt;The ingest gap is the same fact wearing a stopwatch: an extraction call per session is a network round-trip per session.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Retrieve latency, 77 ms against 104 ms, I report as **directional only&lt;/em&gt;&lt;em&gt;. The repeated-query bootstrap CI is optimistic and the two backends differ, so I won't lean on it.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The part that isn't a number
&lt;/h2&gt;

&lt;p&gt;Your data never leaves your infrastructure. Local embeddings, the PostgreSQL you already run, and it works &lt;strong&gt;offline&lt;/strong&gt;: on an air-gapped box, in a privacy-bound environment, under a DPA that doesn't have room for another subprocessor.&lt;/p&gt;

&lt;p&gt;A memory layer that calls an LLM per write cannot offer that, structurally. Not because anyone is careless, but because the architecture requires sending the content out to distil it.&lt;/p&gt;

&lt;p&gt;If you're a solo developer, that's a cost story. If you're a company holding customer conversations, it's a procurement story, and it's usually the one that decides the question before accuracy is ever discussed.&lt;/p&gt;

&lt;p&gt;The cloud embedder is available as a &lt;strong&gt;measured option&lt;/strong&gt; rather than a default, and the repo prices it honestly: it wins on 16 of 17 held-out corpora, median +0.059 hit@5, and it means every document and every query leaves your machine, at 246 ms p50 against 45 ms local. You get the numbers and you choose. That's the pattern for everything here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything is a switch, and both settings are measured
&lt;/h2&gt;

&lt;p&gt;This is the part I undersold for five articles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Embedder&lt;/strong&gt;: a hashing model that needs no download, &lt;code&gt;bge-small&lt;/code&gt;, &lt;code&gt;bge-large&lt;/code&gt;, Voyage, or anything OpenAI-compatible. Measured across 17 corpora, with the rule for when paying is worth it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reranking&lt;/strong&gt;: off by default, one flag on. It's the largest retrieval gain in the project (&lt;strong&gt;hit@5 0.671 → 0.777&lt;/strong&gt;) and it costs ~1,050 ms/query, about 4× wall clock. Both halves are published, and the decision is yours: answering a human, ~1 s is invisible next to the LLM call that follows; serving high-volume automated retrieval, it dominates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entailment abstention&lt;/strong&gt;: off by default, and &lt;a href="https://dev.to/gde03/relevance-is-not-answerability-six-signals-and-none-of-them-beat-plain-cosine-2f14"&gt;Part 2&lt;/a&gt; is 2,000 words on why it doesn't rescue the hard case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The whole stack&lt;/strong&gt;: Postgres and pgvector. No separate vector database, no queue, no second store to keep consistent.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd rather ship a flag with two measured settings than a default with a marketing claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  And the risk that doesn't show up in an accuracy column
&lt;/h2&gt;

&lt;p&gt;BEAM has an &lt;code&gt;abstention&lt;/code&gt; category, questions whose correct answer is "that isn't in here." I scored &lt;strong&gt;Mem0's own published answers&lt;/strong&gt; on it, with &lt;strong&gt;Mem0's own judge&lt;/strong&gt;. n=70:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mem0 did&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;mean score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;abstained&lt;/td&gt;
&lt;td&gt;38&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.974&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;answered anyway&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.016&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The category is near-perfectly binary, and it is testing exactly one thing: does the system invent an answer when the evidence isn't there. &lt;strong&gt;It invents one 46% of the time.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One real example: asked about user feedback that was never recorded, it answered &lt;em&gt;"User testing showed a positive response: the dynamic language switching feature achieved a 90% satisfaction rate."&lt;/em&gt; The corpus does contain &lt;em&gt;"achieving a 90% satisfaction rate is a strong start"&lt;/em&gt;, the &lt;strong&gt;assistant&lt;/strong&gt; speculating, which retrieval surfaced and the answerer read as fact.&lt;/p&gt;

&lt;p&gt;I want to be precise about what I'm claiming, because this is where it would be easy to overreach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Their published score is &lt;strong&gt;honest&lt;/strong&gt;. I reproduced their BEAM cell to &lt;strong&gt;0.0005&lt;/strong&gt; (0.6414 against 0.6409). Nothing is being faked.&lt;/li&gt;
&lt;li&gt;The benchmark is &lt;strong&gt;not&lt;/strong&gt; backfitted to them. A benchmark tuned to flatter a vendor would not expose a 46% fabrication rate on that vendor.&lt;/li&gt;
&lt;li&gt;And my own number here is not a triumph. On the same category my shipped policy abstains correctly &lt;strong&gt;23.3%&lt;/strong&gt; of the time at a &lt;strong&gt;9.3%&lt;/strong&gt; false-abstain cost, measured on 30 unanswerable and 270 answerable questions across conversations 0–14, at &lt;strong&gt;$0&lt;/strong&gt;, because that probe needs no LLM. Same configuration caveat as above: reranker off. I tested four stricter policies and &lt;strong&gt;every one of them nets worse&lt;/strong&gt; on BEAM's 9:1 answerable-to-unanswerable mix. The shipped policy is already the best of the five, which is the opposite of what I predicted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So neither of us solves this. The difference is the shape of the failure: a system that fabricates a plausible satisfaction rate is a different kind of liability from one that returns nothing. Depending on what you're building, "slightly less accurate" and "confidently invents a statistic" are not two points on one scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two things wrong with the benchmark itself
&lt;/h2&gt;

&lt;p&gt;Worth saying because they cut against my own story as much as anyone's.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BEAM's unanswerable questions score &lt;em&gt;higher&lt;/em&gt; than its answerable ones&lt;/strong&gt;: median top-1 cosine &lt;strong&gt;0.676&lt;/strong&gt; against &lt;strong&gt;0.641&lt;/strong&gt;. They're adversarially constructed, and a lexical-coverage signal sharing no mathematics with cosine inverts in the same direction. So &lt;strong&gt;every BEAM figure, theirs and mine, is an upper bound on difficulty, not an estimate of deployed behaviour.&lt;/strong&gt; On an ordinary corpus, where unanswerable means genuinely absent, plain cosine separates at AUC 0.780.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The scoring is 9:1 against withholding.&lt;/strong&gt; Abstention is ~10% of BEAM, so a policy that abstains more gains on 30 questions and loses on 270. That is not a complaint about the benchmark. Its abstention category is well built. It means &lt;strong&gt;an abstention claim cannot be made through BEAM's aggregate&lt;/strong&gt;, no matter how good the policy gets. The field needs a metric that prices a false answer against a withheld one, and this isn't it.&lt;/p&gt;

&lt;p&gt;Two smaller corrections that arm produced: BEAM's harness pins &lt;strong&gt;gpt-5&lt;/strong&gt; as answerer and judge (not gpt-4o), and the published &lt;strong&gt;64.1 is a mean rubric-nugget score, not a pass rate&lt;/strong&gt;: the pass rate for the same run is 70.14%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I'm not reporting: a paired BEAM aggregate.&lt;/strong&gt; I have per-category cells and the abstention probe; I do not have a like-for-like total, so there isn't one in the repo and there isn't one here. An earlier draft of this project did fuse two unrelated BEAM numbers into a headline that read well and did not exist. Once burned.&lt;/p&gt;

&lt;h2&gt;
  
  
  So which one should you use?
&lt;/h2&gt;

&lt;p&gt;Genuinely depends, and I'll say it against my own interest:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use the LLM-distilling architecture&lt;/strong&gt; if your questions are heavy on temporal and multi-hop reasoning over dense material, a strong reader is doing the answering, per-memory cost is not a constraint, and sending content to a model provider is fine for you. It is better at that, measurably, and I've shown you the category where it beats me and why.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use this one&lt;/strong&gt; if the marginal cost of a memory has to be zero, your data can't leave, you need it to work offline, you want the retrieval path to be inspectable and switchable rather than a model's opinion, or if a system that confidently invents a satisfaction rate is a worse outcome for you than one that says nothing.&lt;/p&gt;

&lt;p&gt;That's the trade. It isn't "we're better." It's that an LLM in the write path buys a better representation and charges you money, latency, and your data for it, and for a large number of real deployments that's the wrong purchase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the series ends up
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/gde03/the-ai-memory-benchmark-everyone-quotes-forbids-saying-i-dont-know-o1n"&gt;Parts 1–3&lt;/a&gt; said the field measures accuracy on questions that have answers, that the standard harness for the most-quoted benchmark &lt;em&gt;forbids&lt;/em&gt; abstaining, that when I built the missing metric my own system scored zero, and finally that the two public benchmarks disagree because each samples one point of a hidden axis, which turns a yes/no question into a coordinate.&lt;/p&gt;

&lt;p&gt;This part says the rest of it: that the same design which loses &lt;code&gt;temporal_reasoning&lt;/code&gt; is the one that costs $0, ingests 4.3× faster, and never sends a document anywhere, and that the incumbent's better aggregate comes with a 46% fabrication rate on the questions where the honest answer is silence.&lt;/p&gt;

&lt;p&gt;Both of those are true at once. Publishing only the flattering half is the thing this whole series is against.&lt;/p&gt;

&lt;h2&gt;
  
  
  For completeness: the paired contest
&lt;/h2&gt;

&lt;p&gt;On LOCOMO, same questions, same generator, same judge, only the memory differs. Paired McNemar over per-question outcomes, n=1,540:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;generator&lt;/th&gt;
&lt;th&gt;judge&lt;/th&gt;
&lt;th&gt;RE-call&lt;/th&gt;
&lt;th&gt;Mem0&lt;/th&gt;
&lt;th&gt;paired p&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4o-mini&lt;/td&gt;
&lt;td&gt;gpt-4o-mini&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.416&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.378&lt;/td&gt;
&lt;td&gt;0.0059&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4o-mini&lt;/td&gt;
&lt;td&gt;gpt-4o&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.466&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.412&lt;/td&gt;
&lt;td&gt;0.00018&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gpt-4o&lt;/td&gt;
&lt;td&gt;gpt-4o&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.484&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.444&lt;/td&gt;
&lt;td&gt;0.0065&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Holm–Bonferroni across all five cells run (largest adjusted p = 0.012), and it holds on the 1,369 questions where both judges agree (0.440 vs 0.399, p = 0.006).&lt;/p&gt;

&lt;p&gt;Two things I'll say louder than the result. &lt;strong&gt;The lead is a property of the reader, not a universal fact&lt;/strong&gt;. The margin shrinks as the generator strengthens and &lt;em&gt;reverses on Claude Sonnet&lt;/em&gt; (0.565 vs 0.608, n=584, a generator run after pre-registration and labelled as such). And &lt;strong&gt;note the absolute numbers&lt;/strong&gt;: 0.416–0.484, nothing like the 92.5 in the headlines, because a paired protocol with a strict judge and a matched retrieval budget measures something the leniency stack in &lt;a href="https://dev.to/gde03/the-ai-memory-benchmark-everyone-quotes-forbids-saying-i-dont-know-o1n"&gt;Part 1&lt;/a&gt; does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  One more thing, and it's the reason any of this is checkable
&lt;/h2&gt;

&lt;p&gt;Everything above is a number I produced about my own system. You have no way to recompute it without buying inference.&lt;/p&gt;

&lt;p&gt;That bothered me enough to build the fix: a benchmark where &lt;strong&gt;every number is recomputable by a hostile party for $0, with no model in the loop&lt;/strong&gt;: no judge, no paid generator, git as the database, and disputing a result is a pull request. It has RE-call on its board with an unflattering score, and a deliberately fabricated submission committed as a fixture because it passes five of the six mechanical checks.&lt;/p&gt;

&lt;p&gt;That's its own post, coming next, and it's the one I'd most like you to act on.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Every figure: &lt;a href="https://github.com/GiulioDER/RE-call/blob/master/results/FINDINGS.md" rel="noopener noreferrer"&gt;&lt;code&gt;results/FINDINGS.md&lt;/code&gt;&lt;/a&gt; §9d–§9p, &lt;a href="https://github.com/GiulioDER/RE-call/blob/master/results/RESULTS.md" rel="noopener noreferrer"&gt;&lt;code&gt;results/RESULTS.md&lt;/code&gt;&lt;/a&gt; §9–§11. &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt; is MIT, &lt;code&gt;pip install recall-rag&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>“Does your agent know what it doesn’t know?” has no answer. It has a coordinate.</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Thu, 30 Jul 2026 20:33:21 +0000</pubDate>
      <link>https://dev.to/gde03/does-your-agent-know-what-it-doesnt-know-has-no-answer-it-has-a-coordinate-1p4f</link>
      <guid>https://dev.to/gde03/does-your-agent-know-what-it-doesnt-know-has-no-answer-it-has-a-coordinate-1p4f</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 3 of **The Answerability Problem&lt;/em&gt;&lt;em&gt;. &lt;a href="https://dev.to/gde03/the-ai-memory-benchmark-everyone-quotes-forbids-saying-i-dont-know-o1n"&gt;Part 1&lt;/a&gt; showed the standard harness excluding the questions that test refusal, and my own system scoring 0.000 on them. &lt;a href="https://dev.to/gde03/relevance-is-not-answerability-six-signals-and-none-of-them-beat-plain-cosine-2f14"&gt;Part 2&lt;/a&gt; measured six candidate signals and found none that beat plain cosine. This part explains why both were asking a question that has no answer. Code and every number: &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt; (MIT).&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Two public benchmarks disagree about whether memory systems can abstain.&lt;/p&gt;

&lt;p&gt;On LOCOMO's adversarial category my system scores &lt;strong&gt;0.000&lt;/strong&gt; out of 446, and every lever I ship reaches a usable catch rate only by refusing 60% of legitimate questions. On BEAM's abstention category the same class of system does something, and the incumbent's own published answers abstain correctly 38 times out of 70.&lt;/p&gt;

&lt;p&gt;For weeks I treated that as two data points about one capability and tried to reconcile them. It is not two data points. It is two samples of a hidden variable, each reported as a scalar.&lt;/p&gt;

&lt;p&gt;Name the variable and the disagreement dissolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The variable is how far the question sits from what the corpus contains
&lt;/h2&gt;

&lt;p&gt;Ask a conversation log what Caroline realised, when it was Melanie who realised something and Caroline is right there discussing something else. The answer is absent by inches. Now ask the same corpus about restaurant reservations, when it contains none at all. Also absent, by a mile.&lt;/p&gt;

&lt;p&gt;Both are "unanswerable." Reporting one number for both is like reporting one number for "can it see" without saying how far away you put the object.&lt;/p&gt;

&lt;p&gt;So we built a benchmark whose x-axis is that distance. Questions are generated at controlled &lt;strong&gt;excision distances&lt;/strong&gt; from their own gold evidence: at &lt;code&gt;r=0.00&lt;/code&gt; only the single supporting turn is removed, at &lt;code&gt;r=1.00&lt;/code&gt; the whole surrounding topic is gone, with rungs in between. The document-id lists are frozen into the released manifest, so a system under test never computes its own distances. It just answers, and the harness already knows where each question sits.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result is a curve, and the shape is the finding
&lt;/h2&gt;

&lt;p&gt;Discrimination between answerable and unanswerable questions, by rung. AUC, n=200 per rung:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rung&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=0.00&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=0.25&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=0.50&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=0.75&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=1.00&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AUC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.567&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.784&lt;/td&gt;
&lt;td&gt;0.841&lt;/td&gt;
&lt;td&gt;0.921&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.968&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;At the far rung it is nearly perfect. At the near rung it is &lt;strong&gt;barely above chance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So "does your memory know when it doesn't know?" has no answer. The honest reply is a question back: &lt;em&gt;how far away?&lt;/em&gt; A usable gate needs roughly 0.90, and this system crosses that between &lt;code&gt;r=0.50&lt;/code&gt; and &lt;code&gt;r=0.75&lt;/code&gt;, which is to say only once &lt;strong&gt;half to three-quarters of the topic has been deleted&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That curve also explains the benchmark disagreement. LOCOMO's adversarials are built by misattribution, right event and wrong speaker, so they sit near &lt;code&gt;r=0.00&lt;/code&gt;. BEAM's are adversarially constructed too and sit near zero as well; its unanswerable questions actually score &lt;em&gt;higher&lt;/em&gt; similarity than its answerable ones. Corpora where abstention appears to "work", bounded technical documents where the miss is a different subject entirely, sit at the far end. Nobody was wrong. Everybody was reporting one point and calling it a capability.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mechanism, and it is not a threshold problem
&lt;/h2&gt;

&lt;p&gt;Here is the part I did not expect, and the reason I no longer think this is fixable by tuning.&lt;/p&gt;

&lt;p&gt;Take each answerable question, delete its gold evidence, and measure how far the top retrieval score moves. Paired, same question, n=200. Mean change: &lt;strong&gt;−0.0111&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The mean is not the story. The distribution is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;130 of 200 questions: exactly zero change.&lt;/strong&gt; Deleting the answer moved the score not at all.&lt;/li&gt;
&lt;li&gt;64 decreased.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;6 increased.&lt;/strong&gt; Removing the evidence made the corpus look &lt;em&gt;more&lt;/em&gt; relevant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For roughly two thirds of these questions the top hit was never the gold evidence to begin with. The number a threshold gates on was not reading the answer. It was reading something else nearby, and it went on reading it after the answer was gone.&lt;/p&gt;

&lt;p&gt;You cannot threshold your way out of that. A threshold is a monotone rule on a score, and the score is not a measurement of the thing you want to decide about. That is why &lt;a href="https://dev.to/gde03/relevance-is-not-answerability-six-signals-and-none-of-them-beat-plain-cosine-2f14"&gt;Part 2's&lt;/a&gt; six signals clustered and all failed: they were six ways of reading the same wrong quantity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then we checked whether any of it was an artifact
&lt;/h2&gt;

&lt;p&gt;A curve measured on one embedder is a property of that embedder until shown otherwise. So the whole thing was re-run on &lt;code&gt;gte-base&lt;/code&gt;: different model family, 768 dimensions against 384, and a cosine range that does not overlap the first one at all (0.7620–0.9332 against 0.4945–0.8238).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;rung&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=0.00&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=0.25&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=0.50&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=0.75&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;r=1.00&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;bge-small, 384d&lt;/td&gt;
&lt;td&gt;0.567&lt;/td&gt;
&lt;td&gt;0.784&lt;/td&gt;
&lt;td&gt;0.841&lt;/td&gt;
&lt;td&gt;0.921&lt;/td&gt;
&lt;td&gt;0.968&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gte-base, 768d&lt;/td&gt;
&lt;td&gt;0.570&lt;/td&gt;
&lt;td&gt;0.794&lt;/td&gt;
&lt;td&gt;0.841&lt;/td&gt;
&lt;td&gt;0.925&lt;/td&gt;
&lt;td&gt;0.976&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Within 0.010 at every rung, identical at &lt;code&gt;r=0.50&lt;/code&gt;, and the 0.90 crossing falls in the same interval on both. The &lt;em&gt;shape&lt;/em&gt; survives a change of family, size and scale. The &lt;strong&gt;magnitudes do not&lt;/strong&gt;: the within-unanswerable deltas run about 2.1× smaller on &lt;code&gt;gte-base&lt;/code&gt;. That is exactly why the predictions were registered on sign, monotonicity and ordering rather than on size. Had the pre-registration said "reproduces −0.1100", a real effect would now be reading as a failure.&lt;/p&gt;

&lt;p&gt;One detail I checked rather than reported: both arms have 173 of 200 questions monotone, and that identical count is coincidence. The two sets are not the same questions, overlapping on 156. What is substantive is that &lt;strong&gt;90% of the questions monotone under one embedder are monotone under the other&lt;/strong&gt;, which is agreement per question rather than in aggregate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two admissions, because they are the useful part
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The first version of this benchmark passed, and the pass was garbage.&lt;/strong&gt; v1 reported a perfect +1.000 discrimination across the board, which I came close to publishing. At the largest excision the removal took out the entire conversation, and the slice under test &lt;em&gt;was&lt;/em&gt; that conversation, so the index was empty. It scored a perfect ability to detect that nothing was there, on nothing being there. Every non-empty contrast in that arm was flat, at most +0.003.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And I predicted the wrong shape.&lt;/strong&gt; My registered prediction was a step: some distance at which the system flips from confident to uncertain. It is a gradient, smooth and monotone, and the shipped binary abstention decision is blind to every bit of it.&lt;/p&gt;

&lt;p&gt;A third admission belongs to the pre-registration rather than to me, and it is the honest reading of the whole arm. Before running, it recorded: &lt;em&gt;if the gradient holds, the most likely reading is mundane, since any dense retriever's top-1 similarity falls as you delete the relevant documents.&lt;/em&gt; That is what happened. The mechanism is almost certainly generic to dense retrieval rather than a property of my system. The interesting content is not that the gradient exists. It is that &lt;strong&gt;a graded signal sits underneath a binary decision that cannot express it&lt;/strong&gt;, and that at the boundary itself the signal is worth almost nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The guard that cannot fire
&lt;/h2&gt;

&lt;p&gt;While measuring the above, the shipped abstention floor turned out to be inert.&lt;/p&gt;

&lt;p&gt;The default constant is a cosine of 0.50. On &lt;code&gt;bge-small&lt;/code&gt; the observed scores span [0.4945, 0.8238], so &lt;strong&gt;1 response in 1200&lt;/strong&gt; falls below it. On &lt;code&gt;gte-base&lt;/code&gt; the entire distribution sits above 0.76, and the answer is &lt;strong&gt;0 of 1200&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The guard my library ships, whose job is to withhold an answer, could not fire on either embedder. Not "fired rarely". Could not fire, because the constant sits below the whole distribution it is compared against.&lt;/p&gt;

&lt;p&gt;That is the fifth instance of this pattern I have found in a month, and the first one located in the shipped library rather than in a benchmark harness. It is embedder-specific in both directions: on a paid API embedder the same constant does the opposite, starving 23.3% of legitimate queries. One number, three behaviours, depending on a model choice it knows nothing about.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not establish
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Not a quality comparison.&lt;/strong&gt; Nothing here says one embedder retrieves better than the other. Only the shape of the distance response was measured.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Two families is not "embedder-independent".&lt;/strong&gt; It raises confidence, and says nothing about API embedders, where the same constant fails in the opposite direction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not a single-variable change.&lt;/strong&gt; Family, size and dimensionality moved together, so the agreement cannot be attributed to any one of them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Same corpus, no judge.&lt;/strong&gt; A shared-corpus artifact would reproduce here rather than be caught, and answer &lt;em&gt;correctness&lt;/em&gt; is unmeasured throughout.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I would like argued with
&lt;/h2&gt;

&lt;p&gt;The claim I am least sure of is the strong one: that &lt;strong&gt;abstention is not a property a memory system has, but a function of distance that has to be measured against an axis&lt;/strong&gt;, and that any single-number abstention score is therefore a category error, including the ones I published earlier in this series.&lt;/p&gt;

&lt;p&gt;If that is right, "does it know what it doesn't know?" should stop being asked, and every benchmark reporting one abstention number should report a curve instead.&lt;/p&gt;

&lt;p&gt;If it is wrong, the cheapest way to show me is a signal that separates at &lt;code&gt;r=0.00&lt;/code&gt;, where mine sits at 0.567 on two independent embedder families. The manifest is frozen and public, the harness is one command, and it costs nothing to run.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/gde03/the-memory-layer-that-never-calls-an-llm-what-that-buys-and-what-it-costs-12ch"&gt;Part 4&lt;/a&gt; is the ledger: what this architecture buys, what it costs, and where it loses on purpose.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The ladder, its pre-registrations and every artifact: &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt;, &lt;code&gt;benchmarks/ladder/&lt;/code&gt; and &lt;code&gt;results/ladder/&lt;/code&gt;. Both verdicts, including the retracted v1, are committed rather than summarised.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>llm</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Relevance is not answerability: six signals, and none of them beat plain cosine</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Thu, 30 Jul 2026 20:31:08 +0000</pubDate>
      <link>https://dev.to/gde03/relevance-is-not-answerability-six-signals-and-none-of-them-beat-plain-cosine-2f14</link>
      <guid>https://dev.to/gde03/relevance-is-not-answerability-six-signals-and-none-of-them-beat-plain-cosine-2f14</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 2 of **The Answerability Problem&lt;/em&gt;&lt;em&gt;. &lt;a href="https://dev.to/gde03/the-ai-memory-benchmark-everyone-quotes-forbids-saying-i-dont-know-o1n"&gt;Part 1&lt;/a&gt; showed the standard harness excluding the questions that test refusal, my own system scoring 0.000, and every lever I ship failing. It asked whether any cheap signal can separate "relevant" from "answerable." This is the bake-off. Code: &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;LongMemEval is the other public benchmark in this space, and unlike LOCOMO it names abstention as a first-class question type. 500 questions over a synthetic user's chat history: 470 answerable, &lt;strong&gt;30 whose answer was never mentioned&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My retrieval does well on it. The right session is in the returned set &lt;strong&gt;97%&lt;/strong&gt; of the time.&lt;/p&gt;

&lt;p&gt;Then the trust layer refuses to answer &lt;strong&gt;48% of those&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sit with the shape of that. The system finds the answer, holds it, and declines to use it, in nearly half of the cases where it succeeded. As a product that is worse than having no abstention layer at all: you have paid for retrieval quality and then thrown it away at the last gate.&lt;/p&gt;

&lt;p&gt;And it gets stranger. False-abstain &lt;strong&gt;rises as the problem gets easier&lt;/strong&gt;: 0.328 → 0.409 → 0.481 as I narrow the haystack, while the fitted threshold &lt;em&gt;falls&lt;/em&gt; (0.752 → 0.723 → 0.713). A smaller haystack means a better top hit means higher cosines all round, and every one of those higher cosines belongs to an unanswerable question too.&lt;/p&gt;

&lt;h2&gt;
  
  
  The obvious diagnosis, tested first, and wrong
&lt;/h2&gt;

&lt;p&gt;Every engineer's first instinct here, mine included, is &lt;em&gt;the threshold is in the wrong place&lt;/em&gt;. So I measured the two distributions directly. Top-1 cosine over all 500 questions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;answerable (n=470)&lt;/th&gt;
&lt;th&gt;unanswerable (n=30)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;q05 / q25&lt;/td&gt;
&lt;td&gt;0.612 / 0.671&lt;/td&gt;
&lt;td&gt;n/a / 0.620&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;median&lt;/td&gt;
&lt;td&gt;0.723&lt;/td&gt;
&lt;td&gt;0.647&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;q75 / max&lt;/td&gt;
&lt;td&gt;0.774 / 0.938&lt;/td&gt;
&lt;td&gt;0.689 / 0.811&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;AUC 0.753.&lt;/strong&gt; The unanswerable range sits almost entirely &lt;em&gt;inside&lt;/em&gt; the answerable range.&lt;/p&gt;

&lt;p&gt;There is no threshold. The best one obtainable on these very samples scores balanced error &lt;strong&gt;0.285&lt;/strong&gt; against the shipped rule's &lt;strong&gt;0.305&lt;/strong&gt;, a 0.02 improvement, and that 0.285 is an &lt;em&gt;in-sample&lt;/em&gt; ceiling, so held-out the gap is smaller still. If you want false-abstain down to a shippable 0.05, you pay about &lt;strong&gt;0.78 false-confidence&lt;/strong&gt; for it.&lt;/p&gt;

&lt;p&gt;Recalibration was ruled out by measurement, not by argument. That distinction matters to me: "I thought about it and it wouldn't work" is how you end up wrong the way I was in Part 1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Six signals, one measurement
&lt;/h2&gt;

&lt;p&gt;If the threshold isn't the problem and the &lt;em&gt;signal&lt;/em&gt; is, then swap the signal. I measured six candidates on the same 500 questions and the same haystacks, differing in nothing but which quantity the gate reads:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;signal&lt;/th&gt;
&lt;th&gt;family&lt;/th&gt;
&lt;th&gt;AUC&lt;/th&gt;
&lt;th&gt;95% CI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;dense_top1&lt;/code&gt; &lt;em&gt;(shipped)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;relevance, bi-encoder&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.753&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;[0.680, 0.826]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;rerank_top1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;relevance, cross-encoder&lt;/td&gt;
&lt;td&gt;0.742&lt;/td&gt;
&lt;td&gt;[0.666, 0.818]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hybrid_top1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;relevance, RRF&lt;/td&gt;
&lt;td&gt;0.739&lt;/td&gt;
&lt;td&gt;[0.663, 0.815]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;entail_max&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;answerability, QNLI&lt;/td&gt;
&lt;td&gt;0.648&lt;/td&gt;
&lt;td&gt;[0.557, 0.739]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;margin_1_5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;distributional&lt;/td&gt;
&lt;td&gt;0.579&lt;/td&gt;
&lt;td&gt;[0.479, 0.679]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ratio_1_5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;distributional&lt;/td&gt;
&lt;td&gt;0.545&lt;/td&gt;
&lt;td&gt;[0.442, 0.648]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Nothing beat the signal already shipping.&lt;/strong&gt; And the two informative rows are not the top one.&lt;/p&gt;

&lt;h3&gt;
  
  
  The cross-encoder is the finding
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;rerank_top1&lt;/code&gt; is a cross-encoder. It does not embed the query and the document separately and compare vectors. It reads them &lt;strong&gt;jointly&lt;/strong&gt;, with full attention between them, which is exactly the architecture you'd reach for if you wanted a model that could tell "this passage answers this question" from "this passage is about this topic."&lt;/p&gt;

&lt;p&gt;It ranks superbly. Below, it delivers the single largest retrieval gain I've measured; on this benchmark it reaches hit@5 &lt;strong&gt;0.970&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And it scores a topically-related session that does &lt;em&gt;not&lt;/em&gt; contain the answer just as highly as one that does.&lt;/p&gt;

&lt;p&gt;That's the result that reorganised my mental model. The cross-encoder isn't failing because it's small or badly trained. It's failing because it was trained for &lt;strong&gt;relevance&lt;/strong&gt;, and it is &lt;em&gt;excellent&lt;/em&gt; at relevance, and relevance is a different quantity from answerability. A session where the user discusses their job search at length is maximally relevant to "what company did the user say they were joining?" whether or not they ever named the company.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Relevance asks &lt;em&gt;is this about the same thing?&lt;/em&gt; Answerability asks &lt;em&gt;is the specific fact in here?&lt;/em&gt; Nothing in a relevance objective ever requires a model to learn the second one.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  And the answerability model came in below plain cosine
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;entail_max&lt;/code&gt; is the QNLI judge, the one built-in that's actually trained on "does this answer this question," the one that came out of &lt;a href="https://dev.to/gde03/retrieval-augmented-self-recall-what-the-comments-taught-me-re-call-v03-42c1"&gt;reader comments on the last series&lt;/a&gt; and that I was pleased to ship.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0.648.&lt;/strong&gt; Below cosine. At its own untuned boundary it scores false-confidence &lt;strong&gt;0.533&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And here's the part that makes it a real finding instead of a bad day: months earlier, on a completely different corpus the judge had never seen, I measured its residual near-miss false-confidence at &lt;strong&gt;0.50&lt;/strong&gt;. The bound transferred &lt;em&gt;exactly&lt;/em&gt;. It was never good enough for this workload; it was simply never tested against a workload that made that visible.&lt;/p&gt;

&lt;p&gt;Stacking it behind a lowered gate doesn't rescue it either:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;configuration&lt;/th&gt;
&lt;th&gt;false-abstain&lt;/th&gt;
&lt;th&gt;false-confident&lt;/th&gt;
&lt;th&gt;balanced&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;shipped cosine @0.713&lt;/td&gt;
&lt;td&gt;0.443&lt;/td&gt;
&lt;td&gt;0.167&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.305&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;judge alone @0.5&lt;/td&gt;
&lt;td&gt;0.321&lt;/td&gt;
&lt;td&gt;0.533&lt;/td&gt;
&lt;td&gt;0.427&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gate 0.600 + judge&lt;/td&gt;
&lt;td&gt;0.332&lt;/td&gt;
&lt;td&gt;0.433&lt;/td&gt;
&lt;td&gt;0.383&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gate 0.650 + judge&lt;/td&gt;
&lt;td&gt;0.381&lt;/td&gt;
&lt;td&gt;0.233&lt;/td&gt;
&lt;td&gt;0.307&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The best stack ties the plain threshold and costs you a model pass per query.&lt;/p&gt;

&lt;h2&gt;
  
  
  The error bar that nearly buried all of it
&lt;/h2&gt;

&lt;p&gt;Now the methodological part, which is the one I'd actually want to read.&lt;/p&gt;

&lt;p&gt;There are &lt;strong&gt;30&lt;/strong&gt; unanswerable questions. That's the benchmark's own class size, not a sampling choice, and I can't re-run it larger. Small-n results deserve suspicion, so I put an interval on the AUC.&lt;/p&gt;

&lt;p&gt;The first version used &lt;code&gt;sqrt(A(1-A)/n_min)&lt;/code&gt;, roughly &lt;strong&gt;0.08&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That's wrong, and wrong in the direction that feels responsible. It uses only the smaller class and throws away the 470-sample one entirely, and it is not the standard error of an AUC in the first place. The Hanley &amp;amp; McNeil (1982) estimator, which accounts for both classes, gives &lt;strong&gt;0.037&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;My error bar was &lt;strong&gt;2.1× too wide.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The consequence wasn't cosmetic. At ±0.08, the 0.90 usability bar falls back &lt;em&gt;inside&lt;/em&gt; the interval of the best signal, and the finding degrades from "measured exclusion" to "inconclusive, needs more data." I would have published a shrug. With the correct estimator, the best signal's interval tops out at &lt;strong&gt;0.826&lt;/strong&gt; and the bar sits &lt;strong&gt;outside&lt;/strong&gt; it.&lt;/p&gt;

&lt;p&gt;That's the difference between &lt;em&gt;"I couldn't tell"&lt;/em&gt; and &lt;em&gt;"none of these signals is good enough, and here's the proof."&lt;/em&gt; Same data. The entire finding lived in the variance estimator.&lt;/p&gt;

&lt;p&gt;Two things came out of that, and both ship:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The estimator is now a library function, &lt;code&gt;recall.calibration.separability_interval&lt;/code&gt;, pinned by a test, so the published table and the library's own runtime certification read from &lt;strong&gt;one&lt;/strong&gt; implementation and cannot drift apart.&lt;/li&gt;
&lt;li&gt;Certification tests the interval's &lt;strong&gt;lower bound&lt;/strong&gt;, not the point estimate. At the 20-samples-per-class minimum the module accepts, a measured AUC of 0.95 carries a lower bound of 0.879: it clears the bar on the point and &lt;em&gt;has not established it&lt;/em&gt;. Certifying on the point would readmit, through small-sample noise, exactly the silent failure this whole exercise exists to expose.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm equally clear on what n=30 does &lt;strong&gt;not&lt;/strong&gt; buy me. The three relevance signals at 0.74–0.75 are &lt;strong&gt;not distinguishable from one another&lt;/strong&gt;. Their intervals overlap almost entirely, the ordering among them is noise, and no claim here rests on it. Anyone who reads that table as "dense beats rerank for abstention" is reading further than the data goes. The only conclusion the sample supports is the one I'm drawing: &lt;strong&gt;none of them reaches the ~0.90 a usable gate needs.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So what is the actual shape of the problem?
&lt;/h2&gt;

&lt;p&gt;Three structurally different relevance signals cluster at 0.74–0.75. The one model in the lineup trained on answerability lands below all of them. Two distributional signals land below that. A stronger judge, tested separately, moves along the curve without lifting it.&lt;/p&gt;

&lt;p&gt;The conclusion I'd have drawn a week ago is the tempting one: &lt;em&gt;answerability is not recoverable from the retrieval geometry at all.&lt;/em&gt; I'm not drawing it, because I ran the control that tests it and it came back the other way.&lt;/p&gt;

&lt;p&gt;Build an &lt;strong&gt;ordinary&lt;/strong&gt; unanswerable set instead of an adversarial one, mechanically and with no labelling. Take a 787-document corpus, index 657 of them, hold 120 out, and use each document's own summary line as a query. Queries for indexed documents are answerable; queries for held-out documents are unanswerable because the document is genuinely absent. On that set, plain cosine separates at &lt;strong&gt;AUC 0.780&lt;/strong&gt;, and you can abstain on half the unanswerable questions for a &lt;strong&gt;13.7%&lt;/strong&gt; false-abstain cost. That is not a usable gate by the 0.90 standard, but it is nothing like the coin flip the benchmarks produce.&lt;/p&gt;

&lt;p&gt;So the honest statement is narrower and more useful:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Similarity separates answerable from unanswerable when the unanswerable question is about something genuinely absent. It fails, and inverts, when the unanswerable question is &lt;em&gt;constructed&lt;/em&gt; to be adjacent.&lt;/strong&gt; LOCOMO's cat5, LongMemEval's unanswerable class and BEAM's abstention split are all the second kind, by design.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The inversion is the part worth staring at. On BEAM the unanswerable questions score &lt;strong&gt;higher&lt;/strong&gt; than the answerable ones, and a lexical-coverage signal sharing no mathematics with cosine inverts in the &lt;em&gt;same&lt;/em&gt; direction (0.741 unanswerable against 0.717 answerable). Two unrelated signals failing identically points at the questions, not the retriever.&lt;/p&gt;

&lt;p&gt;Which reframes what those benchmarks measure. &lt;strong&gt;They are upper bounds on difficulty, not estimates of deployed behaviour&lt;/strong&gt;, and reporting an adversarial abstention score as if it described production is its own kind of over-claim, one I was two paragraphs away from making.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/gde03/does-your-agent-know-what-it-doesnt-know-has-no-answer-it-has-a-coordinate-1p4f"&gt;Part 3&lt;/a&gt; is where that boundary gets located properly, on a continuous axis and with a coordinate, and where the real defect turns out to live: not in the signal, and not in the threshold, but in what the score reads.&lt;/p&gt;

&lt;h3&gt;
  
  
  The counterweight, folded in
&lt;/h3&gt;

&lt;p&gt;The obvious objection is that these signals are all weak because &lt;em&gt;retrieval&lt;/em&gt; is weak. It isn't, and I can price that precisely: turning on the cross-encoder reranker moves hit@5 from &lt;strong&gt;0.671 to 0.777&lt;/strong&gt; at n=1,536, roughly twice the largest embedder effect in this project, with intervals disjoint from baseline through k=10. Three checks say the gain is real: hit@20 barely moves (0.855 → 0.870), as reordering a fixed pool requires; the gain decays with depth exactly as the mechanism predicts (+0.155 at k=1 → +0.016 at k=20); and an unrelated cross-encoder with 12× the parameters lands &lt;em&gt;within noise&lt;/em&gt; at 6.3× the cost, so the effect belongs to &lt;strong&gt;reranking&lt;/strong&gt;, not to a model.&lt;/p&gt;

&lt;p&gt;Abstention across all three rerank arms: &lt;strong&gt;0.00, 0.00, 0.00.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The best retrieval work in the project moved honesty by nothing. Reranking reorders what retrieval returned; it never touches whether what came back contains an answer. &lt;strong&gt;Your retrieval-quality metric and your honesty metric are not correlated, and improving the first will feel like improving the second.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/gde03/does-your-agent-know-what-it-doesnt-know-has-no-answer-it-has-a-coordinate-1p4f"&gt;Part 3&lt;/a&gt; is where this stops being a wall and becomes a measurement: the two public benchmarks disagree about abstention for a reason, and naming it turns a yes/no question into a coordinate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question for the comments:&lt;/strong&gt; if you've built a production RAG gate that decides &lt;em&gt;"the answer isn't in what I retrieved"&lt;/em&gt;, what does it read, and &lt;strong&gt;have you measured it on unanswerable questions that aren't adversarial?&lt;/strong&gt; That distinction turned out to be the whole ballgame here, and I nearly published the stronger claim without it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Full tables, intervals, and the six-signal comparison: &lt;a href="https://github.com/GiulioDER/RE-call/blob/master/results/FINDINGS.md" rel="noopener noreferrer"&gt;&lt;code&gt;FINDINGS.md&lt;/code&gt; §10b&lt;/a&gt;, &lt;a href="https://github.com/GiulioDER/RE-call/blob/master/results/RESULTS.md" rel="noopener noreferrer"&gt;&lt;code&gt;RESULTS.md&lt;/code&gt; §8&lt;/a&gt;. The LongMemEval arm is flagged in-repo as the weakest evidence in the file, and why: it was measured pre-fix, so its retrieval rows are a dense-only lower bound. The abstention conclusion does not depend on that.&lt;/em&gt; Next: &lt;strong&gt;Part 3, "Does your agent know what it doesn't know?" has no answer. It has a coordinate.&lt;/strong&gt;*&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>machinelearning</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The AI-memory benchmark everyone quotes forbids saying “I don't know”</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Thu, 30 Jul 2026 20:14:27 +0000</pubDate>
      <link>https://dev.to/gde03/the-ai-memory-benchmark-everyone-quotes-forbids-saying-i-dont-know-o1n</link>
      <guid>https://dev.to/gde03/the-ai-memory-benchmark-everyone-quotes-forbids-saying-i-dont-know-o1n</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 1 of **The Answerability Problem&lt;/em&gt;&lt;em&gt;. A follow-on from &lt;a href="https://dev.to/gde03/retrieval-augmented-self-recall-the-rag-problem-nobody-talks-about-2n0n"&gt;Retrieval-Augmented Self-Recall&lt;/a&gt;. That series argued agent memory needs calibrated abstention. This one is what happened when I actually tried to measure it. Code and every number: &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt; (MIT).&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;There's a benchmark war going on in AI memory, and it's a healthy one.&lt;/p&gt;

&lt;p&gt;Mem0's paper (arXiv:2504.19413, Table 2) reports an LLM-as-judge score of &lt;strong&gt;J=66.88&lt;/strong&gt; for itself against &lt;strong&gt;65.99&lt;/strong&gt; for a competitor, Zep. Zep published a rebuttal disputing the methodology and the scores attributed to it. Mem0's later announcement of a new algorithm puts it at &lt;strong&gt;92.5&lt;/strong&gt; on LOCOMO and &lt;strong&gt;94.4&lt;/strong&gt; on LongMemEval. People argued about all of it. That's how you know the numbers matter to someone.&lt;/p&gt;

&lt;p&gt;But both sides are fighting over the same axis: &lt;strong&gt;of the questions the memory can answer, how many does it get right?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;LOCOMO has five question categories. Four of them are that axis. The fifth is 446 questions, &lt;strong&gt;22.5% of the benchmark&lt;/strong&gt;, that look answerable and aren't. They name a real person and a real topic from the conversation, then ask about something that person never said. Right event, wrong speaker. The correct answer is &lt;em&gt;"that isn't in here."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I wanted to know how the incumbents score on those 446. So I went and read the harness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two lines of code
&lt;/h2&gt;

&lt;p&gt;Mem0's published benchmark harness (&lt;code&gt;mem0ai/memory-benchmarks&lt;/code&gt;) contains this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;CATEGORIES_TO_EVALUATE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Category 5, all 446 adversarial questions, is excluded from scoring entirely.&lt;/p&gt;

&lt;p&gt;And the answer prompt contains this instruction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NEVER say "not specified" … COMMIT AND ANSWER&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So it isn't that abstention goes unmeasured. The harness removes the questions that would test it, and then instructs the model not to do it on the ones that remain.&lt;/p&gt;

&lt;p&gt;I want to be careful here, because there's a cheap version of this observation and I'm not making it. Excluding cat5 is a &lt;em&gt;defensible&lt;/em&gt; choice if what you're measuring is answer quality: a refusal scores zero on an answerable question either way, and mixing the classes muddies the metric. The "COMMIT AND ANSWER" instruction reduces variance from a model that hedges. Neither line is a scandal.&lt;/p&gt;

&lt;p&gt;What they are, together, is a &lt;strong&gt;scope&lt;/strong&gt;. The number that comes out the other end is answer accuracy on questions that have answers, and it is structurally incapable of telling you anything about what the system does when the answer isn't there. That's fine, as long as everyone reads it that way. In practice it gets read as "how good is this memory."&lt;/p&gt;

&lt;h2&gt;
  
  
  The leniency stack underneath
&lt;/h2&gt;

&lt;p&gt;Once I was in the harness I kept reading, and the abstention exclusion turns out to be the &lt;em&gt;fourth&lt;/em&gt;-most interesting thing in it. The judge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;marks an answer &lt;strong&gt;CORRECT&lt;/strong&gt; if it matches &lt;strong&gt;one&lt;/strong&gt; item out of an N-item gold list;&lt;/li&gt;
&lt;li&gt;tolerates &lt;strong&gt;±14 days&lt;/strong&gt; on dates and &lt;strong&gt;±50%&lt;/strong&gt; on durations;&lt;/li&gt;
&lt;li&gt;is instructed to use the evidence &lt;strong&gt;"only to ACCEPT answers, never to reject them."&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;and hands the reader up to &lt;strong&gt;200 memories per question&lt;/strong&gt;, roughly 7k tokens, with no retrieval budget.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An independent audit (&lt;code&gt;dial481/locomo-audit&lt;/code&gt;) measured that judge &lt;strong&gt;over-accepting 62.8% of deliberately wrong answers&lt;/strong&gt;. The same audit found LOCOMO's answer key is partly corrupted, which caps the honest achievable ceiling somewhere near &lt;strong&gt;93.6&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Sit with that for a second. A published &lt;strong&gt;92.5&lt;/strong&gt; is not "nearly perfect." It is &lt;em&gt;at the ceiling of a benchmark whose ceiling is a data-quality artifact&lt;/em&gt;, produced by a judge that accepts nearly two thirds of answers known to be wrong, on the 77.5% of questions that were kept.&lt;/p&gt;

&lt;p&gt;I am not claiming anyone cheated. I'm claiming the number is load-bearing for a conclusion it cannot support, and that this is true of every published figure on this benchmark, including any I might publish.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would a metric that sees abstention even look like?
&lt;/h2&gt;

&lt;p&gt;Here's the part that took me longest, and it's the part I'd most like pushback on.&lt;/p&gt;

&lt;p&gt;The obvious metric is "how often does it correctly refuse?", which I will call &lt;strong&gt;adversarial-abstain&lt;/strong&gt;. It is completely useless on its own, because I can score &lt;strong&gt;1.00&lt;/strong&gt; on it in one line: refuse everything. A memory that always says "I don't know" is perfectly honest and perfectly worthless.&lt;/p&gt;

&lt;p&gt;The mirror metric is &lt;strong&gt;false-abstain&lt;/strong&gt;: how often it refuses a question it could have answered. Also gameable on its own, in the opposite direction: never abstain and you score a perfect 0.000. Which, as it happens, is exactly what "COMMIT AND ANSWER" instructs.&lt;/p&gt;

&lt;p&gt;So neither column means anything alone. The quantity that can't be gamed by a degenerate policy is the &lt;strong&gt;difference&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;discrimination = adversarial-abstain − false-abstain&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Refuse everything: 1.00 − 1.00 = 0. Refuse nothing: 0.00 − 0.00 = 0. You only score above zero by &lt;em&gt;telling the two classes apart&lt;/em&gt;, which is the actual capability in question. It's the same shape as a balanced-accuracy or Youden's J, and I make no claim to having invented it; the claim is that nobody in this space is reporting it, and it is cheap to report.&lt;/p&gt;

&lt;p&gt;So I built the harness. It's a couple of hundred lines, it runs on the public LOCOMO file, and it ships in the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sLO&lt;/span&gt; https://raw.githubusercontent.com/snap-research/locomo/main/data/locomo10.json
python &lt;span class="nt"&gt;-m&lt;/span&gt; recall.eval.locomo_abstention &lt;span class="nt"&gt;--data&lt;/span&gt; locomo10.json &lt;span class="nt"&gt;--answerable-sample&lt;/span&gt; 40
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I ran it against my own system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zero
&lt;/h2&gt;

&lt;p&gt;RE-call, default configuration, on all 446 adversarial questions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Adversarial abstain ↑&lt;/th&gt;
&lt;th&gt;Answerable false-abstain ↓&lt;/th&gt;
&lt;th&gt;discrimination&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;default&lt;/td&gt;
&lt;td&gt;0.000 [0.00, 0.01]&lt;/td&gt;
&lt;td&gt;0.000 [0.00, 0.01]&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Zero out of 446. Not "worse than I hoped". It is &lt;strong&gt;the exact score of a system with no abstention mechanism at all&lt;/strong&gt;, achieved by a system whose entire published thesis is calibrated abstention. I have spent months writing about this. I have a trust layer, a calibrated cosine threshold, and an entailment judge, and on the hardest public instance of the problem they collectively did nothing.&lt;/p&gt;

&lt;p&gt;I'd planned a different article. The draft that sat in this folder for two weeks was called &lt;em&gt;"The one question every AI-memory benchmark skips"&lt;/em&gt; and its argument was: they don't measure this, I do, here's my score. I killed it, because the honest version of the finding is not that I found a gap in the field. It's that &lt;strong&gt;I found a gap in the field and then fell straight into it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That is a much more interesting result, and it's what the rest of the series is about.&lt;/p&gt;

&lt;h3&gt;
  
  
  And every lever I ship fails the same way
&lt;/h3&gt;

&lt;p&gt;Before going further, the short version of what I tried. Four modes, each measured &lt;em&gt;against its cost to answerable questions&lt;/em&gt;, because a system that abstains on everything scores 1.00 and is useless:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Adversarial abstain ↑&lt;/th&gt;
&lt;th&gt;Answerable false-abstain ↓&lt;/th&gt;
&lt;th&gt;discrimination&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;default&lt;/td&gt;
&lt;td&gt;0.000&lt;/td&gt;
&lt;td&gt;0.000&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;calibrated &lt;em&gt;(in-sample, an upper bound)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;0.574&lt;/td&gt;
&lt;td&gt;0.420&lt;/td&gt;
&lt;td&gt;0.154&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;entailment judge&lt;/td&gt;
&lt;td&gt;0.347&lt;/td&gt;
&lt;td&gt;0.290&lt;/td&gt;
&lt;td&gt;0.057&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;both&lt;/td&gt;
&lt;td&gt;0.796&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.603&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0.193&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The best absolute catch is the worst trade: it refuses &lt;strong&gt;60.3% of the questions your users actually wanted answered&lt;/strong&gt;. There is no row here anyone ships.&lt;/p&gt;

&lt;p&gt;And when I later fixed two real retrieval bugs, discrimination went from 0.157 to &lt;strong&gt;0.154&lt;/strong&gt;, which is unchanged. Both columns rose together. &lt;em&gt;A retrieval improvement cannot improve an answerability judgement, because a better-retrieved on-topic-but-wrong passage scores **higher&lt;/em&gt;&lt;em&gt;, not lower.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where the series goes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Part 2&lt;/strong&gt;: six candidate signals measured head to head, including a cross-encoder that reads query and document jointly and still can't tell. Relevance is not answerability. Plus the largest retrieval gain I've measured (+0.106 hit@5) moving abstention by exactly nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 3&lt;/strong&gt;: the payoff. why this benchmark and BEAM &lt;em&gt;disagree&lt;/em&gt;, and the hidden variable that dissolves it. Discrimination isn't a property, it's a curve, and I can now tell you the coordinate where it crosses usable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Part 4&lt;/strong&gt;: the trade this design implies. what a memory layer that never calls an LLM costs you, and what it saves.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I'm writing it this way
&lt;/h2&gt;

&lt;p&gt;The last time I published a design in this space, the comments were better than the post. Not&lt;br&gt;
vague encouragement, but people naming the failure mode precisely and describing what would fix it.&lt;br&gt;
I turned those into experiments and shipped what survived. One of them produced a real improvement&lt;br&gt;
that &lt;strong&gt;Part 2 then shows landing below plain cosine&lt;/strong&gt; on this workload, which is exactly why it was&lt;br&gt;
worth publishing: a design you keep in a drawer accumulates conviction, a design you publish&lt;br&gt;
accumulates objections, and objections are the cheapest high-quality signal available to anyone&lt;br&gt;
building this stuff.&lt;/p&gt;

&lt;p&gt;So if you build or evaluate retrieval-backed agents, the comment section is the point of this,&lt;br&gt;
not a formality. Tell me where the measurement is wrong.&lt;/p&gt;

&lt;p&gt;One thing worth saying because it cuts against my own framing: the field is already moving. Mem0's&lt;br&gt;
newer &lt;strong&gt;BEAM&lt;/strong&gt; benchmark ships an abstention category. Whatever you make of the rest of it, someone&lt;br&gt;
over there reached the same conclusion I did and did something about it. I'd rather be early to a&lt;br&gt;
fixed problem than right about a permanent one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question
&lt;/h2&gt;

&lt;p&gt;If you build or evaluate retrieval-backed agents, I'd genuinely like to know:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you measure what your system does when the answer isn't in the corpus, and if you do, what number do you report?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not "does it hallucinate less." A number, on a fixed set of questions you know are unanswerable, alongside the cost in refused-but-answerable questions. If you have one, I want to see it. If you tried and it came out like mine, that's more useful still.&lt;/p&gt;

&lt;p&gt;And if you think &lt;code&gt;discrimination&lt;/code&gt; is the wrong summary statistic, say so. I would rather find that out in a comment section than after building four more articles on top of it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Every figure here is measured and reproducible: &lt;a href="https://github.com/GiulioDER/RE-call/blob/master/results/RESULTS.md" rel="noopener noreferrer"&gt;&lt;code&gt;results/RESULTS.md&lt;/code&gt; §7b&lt;/a&gt; and &lt;a href="https://github.com/GiulioDER/RE-call/blob/master/results/FINDINGS.md" rel="noopener noreferrer"&gt;&lt;code&gt;results/FINDINGS.md&lt;/code&gt; §9b&lt;/a&gt;. The harness is in the repo. Next: *&lt;/em&gt;&lt;a href="https://dev.to/gde03/relevance-is-not-answerability-six-signals-and-none-of-them-beat-plain-cosine-2f14"&gt;Part 2, Relevance is not answerability: six signals, and none of them beat plain cosine&lt;/a&gt;.***&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Retrieval-Augmented Self-Recall — What the Comments Taught Me (RE-call v0.3)</title>
      <dc:creator>Giulio D'Erme</dc:creator>
      <pubDate>Sat, 18 Jul 2026 12:07:45 +0000</pubDate>
      <link>https://dev.to/gde03/retrieval-augmented-self-recall-what-the-comments-taught-me-re-call-v03-42c1</link>
      <guid>https://dev.to/gde03/retrieval-augmented-self-recall-what-the-comments-taught-me-re-call-v03-42c1</guid>
      <description>&lt;p&gt;&lt;em&gt;A follow-up to &lt;a href="https://dev.to/gde03/retrieval-augmented-self-recall-the-rag-problem-nobody-talks-about-2n0n"&gt;Part 1: the self-recall thesis&lt;/a&gt; — the series runs through &lt;a href="https://dev.to/gde03/retrieval-augmented-self-recall-part-6-the-fine-tune-that-did-nothing-and-shipping-it-as-an-mcp-240m"&gt;Part 6&lt;/a&gt;. Code: &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt; — everything below is measured and reproducible (&lt;code&gt;make eval&lt;/code&gt;), full study in &lt;a href="https://github.com/GiulioDER/RE-call/blob/master/docs/ENTAILMENT_SUPERSESSION_STUDY.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/ENTAILMENT_SUPERSESSION_STUDY.md&lt;/code&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I published a thesis post about agent memory and got five comments that were better than the post.&lt;/p&gt;

&lt;p&gt;Two of them didn't just critique the design — they described, precisely, why it would fail and what would fix it. So I did the only reasonable thing: I turned both into experiments, ran them on the same eval harness the series is built on, and shipped what survived. That's &lt;strong&gt;RE-call v0.3&lt;/strong&gt;, and this post is the receipt.&lt;/p&gt;

&lt;p&gt;I want to be explicit about why I'm writing it this way. The point of publishing this series was never broadcast — it was &lt;strong&gt;error-correction&lt;/strong&gt;. A design you keep in a drawer accumulates conviction; a design you publish accumulates &lt;em&gt;objections&lt;/em&gt;, and objections are the cheapest high-quality signal you will ever get. The comment section of Part 1 did more for this codebase than any week of solo iteration. This post exists to pay that back with the thing commenters almost never receive: evidence that someone listened, measured, and changed the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comment 1: "A similarity score is not a confidence score"
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/vinimabreu"&gt;Vinicius Pereira&lt;/a&gt; put it in one line I've been quoting since:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Proximity is a candidate; entailment is the evidence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;His argument: the near-misses that hurt most are &lt;strong&gt;high-similarity and wrong&lt;/strong&gt; — memos semantically adjacent to the query that don't answer it. A threshold-based &lt;code&gt;gap_warning&lt;/code&gt; (Part 3, Part 5) waves them straight through &lt;em&gt;by construction&lt;/em&gt;, because their similarity clears any threshold you could calibrate. The abstention signal cannot be the retriever's own score. You need a separate check that the retrieved memo actually &lt;strong&gt;entails&lt;/strong&gt; an answer.&lt;/p&gt;

&lt;p&gt;He was right, and measurably so. I built a held-out challenge set of 10 near-miss queries — each names a strongly on-topic memo that does &lt;em&gt;not&lt;/em&gt; contain the asked-for fact ("how much did the cache reduce &lt;strong&gt;memory usage&lt;/strong&gt;" against a memo that measures &lt;em&gt;latency&lt;/em&gt;). Baseline, with the calibrated threshold from Part 5 doing its best:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Embedder&lt;/th&gt;
&lt;th&gt;Near-miss FCR @ calibrated threshold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hashing-64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bge-small&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;voyage-3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.40&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The threshold that scores a perfect 0.00 on far-gap queries passes 40–100% of near-misses. There is no threshold to fix. The distractor's cosine is &lt;em&gt;genuinely high&lt;/em&gt; — that's what makes it a near-miss.&lt;/p&gt;

&lt;p&gt;So v0.3 adds an opt-in &lt;strong&gt;entailment stage&lt;/strong&gt;: a small QNLI cross-encoder ("does this sentence answer this question?") judges the trusted hits, and a hit that doesn't entail the query is demoted to a new verdict, &lt;code&gt;not_entailed&lt;/code&gt;. The key property is exactly the one Vinicius predicted: it emits a &lt;strong&gt;decision at the judge's own trained boundary&lt;/strong&gt;, not another score — so there is no per-embedder constant left to recalibrate. And that transfer claim held: the &lt;em&gt;identical&lt;/em&gt; judge, zero tuning, on every embedder:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Embedder&lt;/th&gt;
&lt;th&gt;Near-miss FCR: threshold → +entailment&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hashing-64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.00 → &lt;strong&gt;0.60&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bge-small&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.80 → &lt;strong&gt;0.50&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;voyage-3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.40 → 0.40&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Where the comment needed a refinement — which is the point of measuring
&lt;/h3&gt;

&lt;p&gt;The ablation was the honest surprise. Running the judge &lt;em&gt;alone&lt;/em&gt;, without the threshold, &lt;strong&gt;degrades far-gap detection&lt;/strong&gt; (gap FCR 0.00 → 0.40 on both semantic embedders): fed nearest-noise from a topic the corpus doesn't cover, the QNLI model sometimes calls it an answer. So entailment does not &lt;em&gt;replace&lt;/em&gt; the calibrated threshold — the two guard &lt;strong&gt;different failure classes&lt;/strong&gt; and must be stacked. Threshold catches far gaps; judge catches near-misses.&lt;/p&gt;

&lt;p&gt;And the costs are real, and published: ~0.1–1.0 s of judge time per query on CPU, one legitimately answerable query wrongly rejected on both semantic embedders (its gold memo answers by &lt;em&gt;negation&lt;/em&gt; — "do we retry on 4xx?" → "we do &lt;strong&gt;not&lt;/strong&gt; retry" — and the judge reads that as not-answering), MRR on answerable queries dips 1.000 → 0.929. The residual near-miss FCR (0.40–0.60) is the judge's own quality bound — Part 5's law, one layer up: gap detection is bounded by the embedder, and &lt;strong&gt;abstention-by-entailment is bounded by the judge&lt;/strong&gt;. Ships OFF by default for exactly these reasons; you opt in with your eyes open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comment 2: "Supersession is a relation, not a property"
&lt;/h2&gt;

&lt;p&gt;The same comment carried a second thesis, on the guard I'd already confessed was weakest (freshness):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are trying to infer a relation between two memos at read time, when both look valid in isolation. That inference is a losing game. Bind the truth when it is created.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And &lt;a href="https://dev.to/mateo_ruiz_6992b1fce47843"&gt;Mateo Ruiz&lt;/a&gt; had independently named the target shape:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Retrieval should return confidence + provenance + validity, not just relevance.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That sentence is now, almost verbatim, how RE-call's trust layer describes itself. Every hit returns a verdict (&lt;code&gt;ok / superseded / expired / …&lt;/code&gt;), a calibrated confidence, and provenance; a memo declares &lt;code&gt;supersedes: old-memo.md&lt;/code&gt; in its frontmatter &lt;em&gt;at write time&lt;/em&gt;, and retrieval returns the current head of the chain instead of a resolved-but-still-embedded old decision.&lt;/p&gt;

&lt;p&gt;For v0.3 I added the experiment that closes the "why not just timestamps?" question — against the &lt;strong&gt;steelman&lt;/strong&gt;, not a strawman: "among the confidently-relevant hits, trust the newest", with the stale docs re-touched after their successors, the way any living corpus re-syncs constantly. Superseded-trust rate (how often the stale memo is handed back as the answer — lower is better):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Embedder&lt;/th&gt;
&lt;th&gt;Plain search&lt;/th&gt;
&lt;th&gt;Recency (steelman)&lt;/th&gt;
&lt;th&gt;Declared &lt;code&gt;supersedes:&lt;/code&gt;
&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hashing-64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;0.83&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;bge-small&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;0.83&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;voyage-3&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.00&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Look at the &lt;code&gt;bge-small&lt;/code&gt; row: the timestamp heuristic is &lt;em&gt;worse than plain relevance ranking&lt;/em&gt; — the tie-break actively promotes the freshly-re-synced stale memo in the one case where ranking had preferred the successor. A per-document timestamp cannot see a two-document relation, and making the timestamp "smarter" makes it more confidently wrong. The declared relation holds at 0.00 in the same runs.&lt;/p&gt;

&lt;p&gt;Vinicius also called the residual failure mode in advance: write-time binding is only as good as the author's discipline — a forgotten link is an orphan memo that looks valid forever. But, as I replied then: &lt;em&gt;impossible to infer&lt;/em&gt; becomes &lt;em&gt;possible to enforce&lt;/em&gt;. So v0.3 ships &lt;code&gt;recall lint&lt;/code&gt; — dangling &lt;code&gt;supersedes:&lt;/code&gt; references, cycles, ambiguous successors, versioned siblings with no declared edge, closures declared only in prose. No DB, exit 1 on errors, drops into CI in one line. (It paid for itself before it shipped: writing its tests uncovered a real parser bug where a scalar &lt;code&gt;[[wikilink]]&lt;/code&gt; was read as a YAML list, producing an edge that silently never resolved.)&lt;/p&gt;

&lt;h2&gt;
  
  
  The experiment I still owe
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/nazar-boyko"&gt;Nazar Boyko&lt;/a&gt; asked, before Part 5 was even published, whether the gap threshold should be &lt;em&gt;relative&lt;/em&gt; — top hit versus the rest of the batch — rather than an absolute cutoff re-tuned per embedder. It's a good idea with a suspected hole (a spread-based check is blind to the single confident distractor — which is precisely the near-miss class above), but suspicion is not measurement. It's on the list, and the harness is now shaped to answer it.&lt;/p&gt;

&lt;p&gt;And &lt;a href="https://dev.to/hannune"&gt;Tae Kim&lt;/a&gt;'s point — a typed &lt;code&gt;coverage_check&lt;/code&gt; slot so the "no real match" signal can't be silently dropped — sharpened a design rule that now runs through the whole stack: &lt;strong&gt;the retriever computes the signal, the schema carries it.&lt;/strong&gt; Computed, it's a measurement; self-reported by the model, it's a declaration. Those fail very differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm actually arguing for
&lt;/h2&gt;

&lt;p&gt;Five people I've never met read a post about a niche RAG problem and, between them, produced: a falsifiable critique of my abstention mechanism, the correct architecture for supersession, a proposed alternative worth benchmarking, and a schema-design principle. Total cost to me: publishing something concrete enough to be wrong about, and taking the replies seriously enough to run them.&lt;/p&gt;

&lt;p&gt;That's the whole model. Not "content", not reach — &lt;strong&gt;working in public as a form of peer review&lt;/strong&gt;. The asymmetry is absurdly favorable: you contribute one design and get back the failure modes it would have taken you months to hit alone. The only price is that you have to be willing to write "I was wrong, here's the measurement" — which, in a series whose thesis is &lt;em&gt;calibrated honesty&lt;/em&gt;, is not a price at all. It's the product.&lt;/p&gt;

&lt;p&gt;So: thank you Vinicius, Mateo, Nazar, Tae — and &lt;a href="https://dev.to/amin_parva_ab01ff398fd341"&gt;Amin&lt;/a&gt;, whose memory-compaction angle (keep the gist graph, not every turn) is a different axis of the same problem and deserves its own experiment. v0.3 has your fingerprints on it.&lt;/p&gt;

&lt;p&gt;If you're reading this and see the next hole — the negation-blind judge, the owed relative-threshold benchmark, a stronger entailment model, something I haven't imagined — the comment section is open and the harness is public. Evidently, it works.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Code: &lt;a href="https://github.com/GiulioDER/RE-call" rel="noopener noreferrer"&gt;RE-call&lt;/a&gt; (MIT). The full v0.3 study with every table: &lt;a href="https://github.com/GiulioDER/RE-call/blob/master/docs/ENTAILMENT_SUPERSESSION_STUDY.md" rel="noopener noreferrer"&gt;&lt;code&gt;docs/ENTAILMENT_SUPERSESSION_STUDY.md&lt;/code&gt;&lt;/a&gt;. Series index: &lt;a href="https://dev.to/gde03/retrieval-augmented-self-recall-the-rag-problem-nobody-talks-about-2n0n"&gt;Part 1&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>opensource</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
