A follow up to I Gave Claude Code a Brain. Then I Measured What It Costs to Ask for One
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.
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?
I rebuilt the benchmark around those questions.
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.
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.
That is the result. This article is about how to read it.
The measurement question
The benchmark no longer asks only:
Does a memory product improve task success?
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.
The benchmark now asks a sequence of narrower questions:
- Does the agent complete more real coding tasks?
- Does memory help when the governing fact is present?
- Does memory make the agent worse when the corpus is stale, contradictory, unrelated, or empty?
- Is any change caused by retrieval, or only by extra instructions?
- Is the system paying for a real benefit in tokens and time?
- Can another person verify that the reported result follows from the sessions that produced it?
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.
What each arm is for
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.
| Arm | What it receives | What it controls or tests |
|---|---|---|
bare |
No memory layer and no memory instruction | The floor. What the agent does without memory or memory coaching |
claude_md |
The task's static project instructions | The designated baseline for the current leaderboard |
placebo |
Neutral project shaped prose, with no task facts or memory tools | Whether extra context alone changes task success |
protocol |
The shared memory instruction, but no memory surface | The cost or benefit of telling the agent to search |
fs_grep |
The transcript corpus as files, searched with ordinary repository tools | Whether a memory product beats a simple searchable file feed |
recall |
The RE call memory layer and its search tools | Natural use: the agent decides whether to search and how to query |
mempalace |
The MemPalace integration through its published interface | A product comparison under the same shared protocol |
recall_prefetch |
RE call retrieval run by the harness using the exact task prompt | Retrieval with the decision to search and query formulation removed |
There is also an oracle_memory diagnostic 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?
bare is not the same as protocol
This distinction is central.
bare receives neither memory tools nor instructions about memory. It measures the agent's ordinary performance.
protocol 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.
The difference between protocol and bare is therefore the effect of the instruction. The difference between recall and protocol is the value of adding the memory system to that instruction.
That is the comparison the previous article needed to make more explicit.
placebo is not an empty memory store
The placebo contains neutral project shaped prose. It does not expose a memory interface and it does not return an empty search result.
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.
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.
recall and recall_prefetch measure different paths
The natural recall 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.
The recall_prefetch 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.
The comparison is diagnostic:
- If prefetch is better than natural RE call, the agent's search decision or query is part of the bottleneck.
- If both are better than the baseline by a similar amount, the retrieved evidence is probably doing most of the work.
- If neither is better, better retrieval alone may not solve the task.
Neither arm should be interpreted as a general product ranking without the paired analysis and the other controls.
The improvements to the benchmark
The instruction is now controlled
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.
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.
In the official run, the additional material was 549 bytes for fs_grep, 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.
The corpus can now expose harm
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.
The current corpus has five conditions:
-
present: the governing fact is available and current -
absent: the fact has been removed -
superseded: an old version sits beside a newer version -
contradictory: rival versions exist without an authority marker -
adjacent: related information exists but does not apply to the task
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.
This changes the interpretation of a positive result. A system that helps on present but damages work on superseded has a different risk profile from one that helps on present and stays neutral elsewhere.
The admission gate is part of the measurement
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.
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.
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.
The artifacts are now independently checkable
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.
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.
Those cases are now tested explicitly. The repository documents known missing streams as failures with explanations rather than silently turning them into passes. The replication guide 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.
The promotion and verification work is documented in pull request 70.
The official result
The first official run used 26 coding tasks, five corpus conditions, five seeds, eight arms, and the deepseek-v4-flash model. The leaderboard uses claude_md as its designated baseline.
| Arm | Success rate | Difference from claude_md
|
|---|---|---|
| placebo | 67.2% | +9.5 points |
| recall | 65.9% | +8.2 points |
| bare | 65.9% | +8.2 points |
fs_grep |
63.1% | +5.4 points |
| MemPalace | 60.6% | +2.8 points |
claude_md |
57.7% | baseline |
The protocol and recall_prefetch tracks both scored 61.2%. They are reference tracks and are not product rows.
The raw numbers are in official 003 and its published summary.
How to interpret those numbers
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.
RE call's 65.9% is above the claude_md 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.
RE call matching the bare 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.
The protocol arm gives the coaching comparison. If protocol had substantially exceeded bare, I would have evidence that the instruction itself changes performance. If recall had then exceeded protocol, I could attribute the additional difference more plausibly to the memory surface. In this run, neither diagnostic track produces a clean positive claim.
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.
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.
What it can measure now, and what it cannot
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.
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.
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.
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.
The next registered change adds a paired recall_rerank 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 pull request 69, and it has no result yet.
The benchmark is now answering better questions
The useful improvement is not a more impressive leaderboard. It is the ability to tell apart:
- no memory
- memory coaching without memory
- extra neutral context
- simple file search
- natural product use
- retrieval supplied by the harness
- exact evidence supplied as a ceiling
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.
That is what the benchmark can measure now.
Top comments (6)
The corpus conditions are where I would push. "Superseded" and "contradictory" are the two states a memory layer is supposed to absorb before the agent sees anything: the older fact's validity window closes, retrieval stops returning it, and the agent never has to be clever about it. In your setup the memory arm receives a corpus that still contains both versions, so the measurement is whether the model copes with a bad store, not whether a store prevents the condition. Both are worth measuring. They are different claims, and the second one is what a memory layer should be judged on.
That would need one more arm where the store is responsible: same corpus, but the layer marks the superseded item and is allowed to withhold it. If the harm disappears there and persists in your current arm, you have separated "the model handled it" from "the layer handled it".
On the write path you say you cannot measure yet: the cheapest split we know is to hold retrieval fixed, vary only what was written, and score two things separately â whether the fact is in the assembled bundle at all, and whether the answer used it. Most of our own failures live in the first one, and a read-path-only benchmark records them as reasoning failures, which sends you looking in the wrong place.
You are right about the distinction, and the official run measures the first claim, not the second. Every arm gets the same corpus with both versions in it. So a good superseded score there says the agent coped. It does not say the store prevented anything.
I ran something close to your extra arm on 2026-09-01, after this article was written. It started from a harness defect. The corpus was rendered with no frontmatter, and frontmatter is the only place RE-call reads validity windows and successor pointers. So its supersession layer could not be reached at all, and the benchmark had been reporting a disabled feature as a product weakness. Fixing that produced three renderings of the same corpus:
no lineage (the control);
timestamps only: a valid_from on every document, and no new information;
declared lineage: the stale plant gets a valid_until and the current one a supersedes pointer. The store then marks the old item and ranks it below its successor (it demotes; it does not withhold).
The damage rate on superseded fell from 5/30 to 2/30 to 1/30. That looks like your hypothesis confirmed, but most of it is not the layer. Three quarters of the drop came from the timestamps tier, which declares no lineage at all: writing a field into all 4,911 documents changed every embedding, and therefore retrieval itself. The supersession verdict on its own was worth one cell in thirty. None of it was significant (Fisher p = 0.19, control against declared lineage), and it covers one product, one model and 30 paired cells. The declared tier is also circular by design, because the harness tells the store which document wins. It is a ceiling for the layer, not a measurement of detection.
The larger lesson matches your second paragraph closely. In an earlier run I split the same condition by what retrieval actually returned:
sessions that got only the current fact solved 19 of 19;
sessions that got both versions solved 56%;
in 45% of sessions, neither version came back at all.
So the main failure was not lineage. It was the fact never reaching the bundle, and a score taken only on the final result files that under the model.
contradictory plants carry no authority marker by design, so a store has nothing to resolve from. The most a layer can do there is detect the conflict and surface it, which is a third claim again.
Your write path split is the right design: hold retrieval fixed, vary only what was written, and score bundle presence and use separately. I do not have it yet. The record for the lineage tiers, including the predictions it got wrong, is preregistration 023 in the repository.
The harness defect is the most useful thing in this reply, and it generalises: the benchmark was reporting a disabled feature as a product weakness. We had the same shape last month somewhere else â our MCP connector never asked the server to emit a receipt, so the audit trail the product does produce was simply absent on the path most people actually use. Both are "the feature was never reached", and both only surface when someone checks the plumbing instead of the result.
On the tiers, the confound you found is the thing I would design around. Writing valid_from into 4,911 documents changes every embedding, so the timestamps tier moves retrieval and resolution at the same time. The way out is to keep lineage out of the text entirely: validity and successor as row state the embedder never sees. Then the tiers differ in what the store knows rather than in what the index contains, and the comparison is about resolution again.
The circularity is the other half of it. If the harness declares the winner, you measure a ceiling. The detection variant is to declare nothing, let the layer decide by its own rule, and score that decision separately from the task outcome. Ours fires on word overlap or a registered claim key, and it fails in both directions: a reworded contradiction slips through, and a later, more general restatement can supersede a specific one. The second is an open bug on our side. A benchmark that scored the decision itself would have found it before a code review did.
And the 45% of sessions where neither version came back is the number I would lead with next time. That is not a lineage result, it is a coverage result, and it caps everything downstream.
A correction to my last reply. I said the timestamps tier moved results because writing valid_from into every document changed every embedding. That is wrong. RE-call removes Markdown frontmatter before chunking and keeps it as chunk metadata, which is the row state you describe. I checked the run records: the same query, issued in the control and in the declared tier, returned the same documents with the same scores. What differed was the agent: of 76 distinct queries in the control, not one recurred verbatim in the timestamps tier. So the three cell move between those tiers is most plausibly run variance at n = 30. The honest summary is four cells from control to declared lineage, not significant, and nothing I can attribute them to. My explanation was an inference I never checked against the code, which is your plumbing lesson turned on me.
That correction is worth more than the original result, and the lesson is mutual: I took your explanation at face value too, which is the same mistake in the other direction.
The number I would now build on is the one you found while checking: of 76 distinct queries, not one recurred verbatim across the tiers. That means the component varying between arms was not the store, it was query formulation. Retrieval was never being held fixed, so a three cell move at n = 30 has nowhere to come from except the agent.
Which suggests the same split we have been drawing all along, applied one level up: capture a query log once and replay it identically across arms, and you are measuring the store. Let the agent form its own queries, and you are measuring the pair. Different claims, different noise floors. The first should make thirty cells say something; the second is what a user actually gets, and it will keep producing movement you cannot attribute.
With the queries fixed, your 45% where neither version came back also becomes attributable, instead of being partly a property of whatever the agent happened to ask that run.
do you wanna try my websiteïžapi gatewayïži wanna improve it.Can you give some advices to meïžthank you