Agents Never Remember What Isn't There
Every memory system stores what an agent found. The expensive half of any session is what it looked for and did not find, and the falsification conditions of that finding run backwards. Closing the gap needs a primitive that does not exist yet.
Most agent memory systems have a small operation table. Write a note. Read it back. Supersede it with a newer value. Delete it. The store is a record of what an agent found: a definition, a call site, a config value, a decision, a gotcha. Every design decision in the system assumes the note names something that exists.
Almost none of these systems can store the other kind of finding: that something does not exist.
There is no retry configuration in this service. Nothing calls this function. This repository has no integration test layer. That flag was never wired up. Each of those is a real finding, each is expensive to establish, and each is thrown away at the end of the session that established it. The next session pays for it again from zero.
The argument of this post is that the gap is structural. An absence cannot be stored the way a presence is stored, because its truth conditions are inverted in a way that breaks every mechanism a memory system uses to keep notes honest. Closing the gap requires a primitive nobody has built, and the rest of the post is about what that primitive would have to look like, why three reasonable alternatives fail, and what has to be true of the layer below the memory system for the primitive to work at all.
The closest neighbour in argument is a recent post that observed the first search an agent runs is a write to memory and every repeat is a read. That post treats search as memory's write path. This post is about the one result that write path cannot carry, which is the empty result. A search that comes back empty names no artifact, has no anchor, and produces nothing the memory layer can record. The two arguments are complementary rather than overlapping. Where the first one talked about what gets written, this one is about what the writing system is structurally blind to.
Absence Is the Most Expensive Thing an Agent Establishes
Start with the cost, because the asymmetry is stark and almost never stated.
A search for something that exists terminates the moment it is found. The agent greps, gets a hit on the third file, reads it, and moves on. The cost is bounded by luck and by how good the first guess was.
A search that establishes absence cannot terminate early. It terminates only on exhaustion. To conclude that there is no retry configuration, the agent has to look under every name the thing might have (retry, retries, backoff, max_attempts, RetryPolicy), in every place it might live (config files, environment defaults, a client wrapper, a decorator, a base class), and in every form it might take (a literal, a constant, a setting read from an env var, a library default that was never overridden). Absence is always the full sweep. There is no lucky third file.
So the expensive result is the one that gets discarded, and the cheap result is the one that gets written down. That is exactly backwards from what a cost-aware system would do.
A memory system that stores only findings stores only the cheap half of what a session learned. The expensive half, the exhaustive searches that came back empty, evaporates at the session boundary and is re-run at a discount that makes it progressively less trustworthy.
It gets worse when you count repetition. Presence facts tend to be written down because they are immediately useful: an agent that found the lock function needs the file and line right now. Absence facts feel like non-results at the moment they are established, so nothing prompts anyone to record them, and the same sweep runs again next week under a slightly different query.
There is a second-order effect worth naming. An agent that cannot recall a previous absence does not merely repeat the search. It repeats the search less thoroughly, because the session's budget is already partly spent on the actual task. A sweep that produced nothing last time produces nothing this time in less depth. The second pass is cheaper and weaker, which means the conclusion is less reliable each time it is re-derived. Re-derivation is not a fixed tax. It degrades.
The visualization below makes the asymmetry concrete. Set the number of distinct findings a session makes, then watch how the cost picture shifts as you decide which of those findings the memory layer keeps.
What a Memory Layer Actually Keeps
A session makes a number of distinct findings, and each has a different cost. Drag the slider and watch the share of total work that survives the session boundary. The bar is the part of the session's discovery work the memory layer can carry over. The longer it is, the smaller the re-derivation cost the next session has to pay.
Pick the right configuration and the bar shrinks dramatically. Pick the wrong one, skewed findings and a memory layer that captures only presence, and the discarded share turns out to carry the larger fraction of the session's total work. That is the practical cost of the gap. The next section explains why the gap is not just a matter of which findings the memory layer chooses to keep.
An Absence Is a Claim About a Search, Not About the World
Here is the first thing that makes absence hard to store, and it is not obvious until you try to write the note.
There is no retry config is not a proposition about the repository. It is shorthand for a much longer proposition about a search: I looked in these locations, under these names, using this method, at this revision, and found nothing. Strip away the search and what remains is a bare assertion with no way to tell whether it was established by a thorough sweep or by one hasty grep against one spelling.
This matters because the two are indistinguishable in the note and radically different in value. A thorough absence is a real finding. A hasty absence is a guess wearing a finding's clothes.
And the failure mode of a wrong absence is the worst one in this whole area. An agent that reads "there is no retry config" does not look for a retry config. The note forecloses the search that would refute it. That is the self-sealing shape: a false negative removes the action that generates the contradicting evidence, so the error is stable and silent, and no amount of subsequent capability fixes it because the model is reasoning correctly from a premise it has no route to re-examine.
A presence-memory can be a bare fact and still be useful, because acting on it produces immediate feedback when it is wrong. An absence-memory acted on produces no feedback at all. So the scope is not metadata attached to the finding. The scope is the finding, and a note that omits it is not a compressed version of the finding. It is a different and less defensible claim.
The trade-off is described formally in knowledge-base research under the closed-world assumption and negation-as-failure: a system that cannot prove a predicate concludes the predicate is false, and the cost of that shortcut is that the conclusion tracks the search rather than the world. The closed-world machinery was built for a fixed knowledge base whose contents the system could exhaustively enumerate. A code repository is not a closed world, and the agent is not enumerating it. It is sampling it, under a query, and the absence of a hit is a fact about the sample, not a fact about the repository.
That distinction collapses the moment a note drops the scope of its search. A bare "no retry config" promises more than the search that produced it could deliver, and a memory system that stores the bare form makes the promise on the note's behalf.
The Self-Sealing Failure
The shape in Section 02 has a name in the agent-memory literature, and the name matters because the literature has spent real effort on it.
Recent work on memory for autonomous agents characterizes the failure as self-reinforcing error. The mechanism is plain once you see it: an agent holds a false belief, the belief shapes the actions it takes, the actions generate observations that confirm the belief, and the loop closes. The next session re-derives the same belief from the same durable inputs and writes it down again as if it were a fresh discovery.
The same shape shows up under a related name in the spurious-correlation framing of memory bias. A short empirical study on this exact pattern appears in When Memories Become Liabilities (arXiv:2603.04664), which finds that an agent's prior answers bias its later steps and the bias compounds across turns, with the gap between agents that have such memory and agents that do not widening as the task lengthens.
Sequential decision theory met this structure decades ago. In a multi-armed bandit, an agent that always pulls the best-known arm and is given a false negative belief about one arm's value will never update that arm's posterior, because updates require pulls. The cure is forced exploration, a mechanism that occasionally takes the action the current posterior says is worthless, specifically to keep the posterior honest. Agent memory has no analogue of forced exploration. There is no mechanism that periodically resurfaces a discarded belief for re-testing. The belief is either held, in which case it gates the action, or gone, in which case Section 04 shows something worse happens.
This is a direct extension of the previous post's argument about the missing reinstate operation. That post argued that deletion cannot break the self-reinforcing loop, because the durable inputs that produced the false belief remain in the workspace and keep regenerating it. This post argues that the same loop, running on absence rather than presence, is harder to detect in the first place, and that the obvious mitigations either do not exist or do not work.
Falsification Conditions Run Backwards
This is the core of the argument, and it is what makes absence a distinct primitive rather than a special case of an ordinary note.
Consider how a presence-memory is kept honest. The note names a thing: a function, a file, a constant. The store anchors the note to the artifact that contains it and hashes that artifact's content. On the next check, if the hash changed, the note is flagged as possibly drifted. The mechanism works because the note has a referent, the referent has a location, and the location has content that can be watched.
Now try the same thing for an absence. There is no referent. The note says nothing exists at any location, so there is no location to anchor to and no content to hash. The entire staleness apparatus is built on a structure that an absence-memory does not have.
Worse, the direction of falsification inverts.
- A presence-memory is falsified by a change to the named thing. The function moved, the constant was renamed, the signature changed. The set of events that can falsify it is small, local, and watchable.
- An absence-memory is falsified by an addition anywhere inside the search's scope. Someone adds a retry decorator in a file nobody touched last month, and the note is now false, with no signal reaching the note at all.
The consequence is that presence and absence need opposite watch strategies. Presence watches a point. Absence watches a region, and the region is defined by a query rather than by a path.
There is a compensating asymmetry, and it is the thing that makes this tractable rather than hopeless. A deletion can never falsify an absence. If the note says nothing exists and someone removes code, the note is still true. Neither can a modification of existing code that does not introduce a new instance. Only additions matter.
Presence-memory anchors to a location and is invalidated by change. Absence-memory anchors to a query and is invalidated only by addition. That single asymmetry is what makes an absence cheap to re-verify despite being expensive to establish, and it is available to any system willing to treat a query as a first-class anchor.
Checking an absence-memory does not require re-running the original exhaustive sweep against the whole corpus. It requires running the original query against only what was added since the note was written. The check is bounded by the diff, not by the repository, and it is monotone: absences accumulate evidence in one direction and can only be broken by growth. An absence written a year ago in a repository with a hundred commits since is checkable at the cost of scanning those hundred commits' additions, not at the cost of the original sweep.
Watch the mechanism in the interactive below. Pick a window since the note was written, run the recorded query against just that window, and see what fires the absence and what does not.
Re-Checking an Absence Against the Diff
An absence note records a query: "is there a retry configuration anywhere?" Set the window of additions since the note was written, and the simulator runs the recorded query against just that window, in the order the additions arrived. Watch what fires the absence and what does not, and notice the only event that can.
retry, retries, backoff, max_attempts, RetryPolicy. Modifications and deletions never break an absence. The full-sweep mode re-runs the query against the entire corpus every check, which is what a presence-style store would force you to do; the additions-only mode is the cost of the primitive. Seeded per replay so the same window replays identically.Three Reasonable Fixes, Three Different Failures
Three responses come up immediately. Each is reasonable and each fails for a different reason, which is a good sign that the gap is real.
"Just write the negative result as an ordinary note"
You can. Nothing stops an agent from storing "there is no retry config" as a normal finding today. The problem is what happens next: it enters a store whose ranking, staleness, and trust machinery were all designed for referents, so it sits there as an unanchored, unverifiable assertion that no mechanism will ever revisit. It cannot go stale, because staleness is defined by drift at an anchor and it has no anchor. It therefore ages into a permanent, unchallengeable claim, which is precisely the property you least want on the class of note that forecloses its own re-examination.
An absence note in a presence store is not a partial solution. It is the failure mode with extra steps.
"Re-run the search when the note is recalled"
Closer, and this is where the real design lives, but two things break a naive version.
First, the query has to have been recorded verbatim, along with the method. "I searched for retry" is not enough to reproduce anything. Was it lexical or semantic? Case sensitive? Did it cover the vendored directory? A re-run that differs from the original in any of these is not a re-check, it is a new search whose disagreement with the note tells you nothing about whether the world changed.
Second, and this one is specific to semantic retrieval: the same query does not mean the same thing over time. Re-embed a query after a model change, an index rebuild, or a chunking change, and it returns a different neighborhood over an unchanged corpus. A semantic absence is a claim about a corpus, a query, and an embedding, and only the first of those is expected to change. A re-run that silently varies the other two produces false reinstatements of a search that was never actually invalidated. Any absence primitive built on semantic retrieval has to pin the retrieval configuration as part of the note, which no store currently does. (A worked example of the embedding-mismatch hazard appears in the public write-up of the embedding-drift problem: a corpus re-embedded under a new model returns results whose ranking inverts with no signal at the similarity layer, the same shape this section describes.)
"Hash the whole corpus"
Too coarse to be useful. Any commit anywhere invalidates every absence in the store, and a mechanism that flags everything flags nothing, because the flag stops carrying information and gets ignored. The same alarm-fatigue pattern is well documented in clinical monitoring: alarm fatigue in ICU monitoring, for example, arises when overwarning degrades response to every warning, the same mechanism that makes a coarse staleness flag useless for distinguishing what actually changed. The addition-only check from Section 04 is what rescues this: the correct granularity is not the corpus and not the file, it is the set of additions since the note, filtered by the note's own query.
What an Absence-Memory Has to Carry
Working backwards from the failures above, the shape is determined rather than chosen.
An absence-memory has to record the verdict (nothing found), the query in the exact form that was executed, the method (lexical, semantic, symbol-graph lookup, or a combination, since a serious sweep uses several and an absence established by only one of them is weaker), the scope that was actually covered including what was excluded, and the corpus revision at which it held.
The check is then a re-run of the recorded query, restricted to additions since the recorded revision, with the recorded method and configuration.
Three properties follow, and all three are improvements on how presence-memory behaves today.
The cost of re-checking an absence at revision r_n over an original sweep S against a corpus with additions A_n since the note was written:
The check scales with the diff, not with the corpus. An old absence is not more expensive to verify than a new one, which is unusual: most staleness mechanisms degrade as the anchored artifact drifts further from its recorded state. Here the work is monotone in additions, never in the original sweep, so cost stays bounded as the repository ages.
The check is cheap and gets no more expensive with age. A year-old absence in a thousand-commit repository is checkable in the cost of scanning those thousand commits' additions, not in the cost of the original sweep. That is the structural payoff of the addition-only watch.
The check has a definite answer. Unlike a content-hash drift signal, which says only that something changed and leaves interpretation to the reader, an absence check either finds a new instance or does not. It produces a verdict, not a caveat.
A broken absence is highly informative. When the check fires, it does not merely invalidate the note. It hands over the exact thing that was added and the exact query it matched, which is usually the answer the agent needed. The invalidation and the discovery are the same event.
There is also a strong claim available about what should happen to a verified absence, and it deserves stating rather than assuming. An absence that has been re-checked across many revisions and held every time is not merely still true. It is evidence about the shape of the system, and it should be delivered differently from a fresh one. No retry configuration has existed here across the last four hundred commits is a stronger and more useful statement than no retry configuration found, and only a store that keeps the check history can say it.
Retrieval Has to Be Honest First
There is a layer below the memory system that has to cooperate, and today it usually cannot.
For an agent to record an absence at all, its search tool has to be able to distinguish two states that most tools conflate: nothing exists and I did not find it. A retrieval system that returns its best matches regardless of quality never says the first one. It always returns something, so the agent never receives the signal that would prompt an absence to be recorded, and instead receives a list of near-misses that it must judge for itself.
That judgment is where false absences come from. An agent that receives five irrelevant results and concludes "not present" has made an inference the retrieval layer never licensed. An agent that receives an explicit empty result with a stated scope has received a finding.
An absence primitive is not purely a memory feature. It requires the search layer to be honest about coverage: to distinguish an empty result from a weak one, to report what it searched rather than only what it returned, and to be willing to say nothing at all. That property is worth having for its own sake, and it is a precondition for anything in Part 5.
This is the same boundary as the argument that search and memory are two phases of one system rather than two systems. An absence is the clearest case: it is produced by retrieval, consumed by memory, and meaningless if either half is unaware of the other.
What This Is and Is Not
No measurement is offered here. The argument is structural. It identifies a class of finding that is expensive to establish, systematically discarded, and unstorable under existing designs, shows that the standard staleness mechanism cannot apply to it, and derives the shape of a primitive that could. That is an argument, not a result, and it should not be read as more.
The experiment is specifiable, which is the part worth doing next. Take tasks whose solution requires establishing that something does not exist, which is common in real codebase work: confirming there is no existing implementation before writing one, confirming a config is unset before adding it, confirming nothing calls a function before deleting it. Run them across repeated sessions on an evolving repository. Measure the cost of the negative determination each time, measure whether the second and later determinations are less thorough than the first, and measure how often a false absence survives. Then compare against a condition with recorded absences and diff-scoped re-checks. The re-derivation-cost framing is the right one, and the degradation effect from Part 1 is the most interesting thing to look for, because if it is real it means the current situation is worse than a simple repeated-cost model suggests.
This does not make an agent's negative conclusions correct. A recorded absence is exactly as good as the sweep that produced it, and the primitive proposed here makes the sweep's scope visible rather than making it better. That is the point. It converts an unfalsifiable assertion into a checkable one. A thorough absence becomes durable, and a hasty one becomes visibly hasty.
Nothing here is a security mechanism. An absence record is a cost-saving and error-preventing device against ordinary repetition, not a control against an adversary who can write to the store. A poisoned absence would be a particularly effective attack precisely because of the foreclosure property in Section 02. That is worth naming as a risk of the design rather than hiding.
Every memory system stores what an agent found. The expensive half of what a session learns is what it looked for and did not find, and that half is discarded at the session boundary, re-derived more cheaply and less reliably every time.
An absence is a claim about a search, not about the world. It cannot be anchored to a file, because it names no file. It can only be anchored to the query that established it, and once it is, it becomes the cheapest note in the store to keep honest, because nothing but an addition can ever make it false.
Sources
Where claims touch published work, the source is verifiable. Where a claim comes from building the system, it is stated as such.
- Hu, Z. and others. When Memories Become Liabilities: Leveraging Spurious Correlations in Self-Reinforcing Memory.
- Poole, D. Artificial Intelligence: Foundations of Computational Agents, 3rd ed., Chapter 5.7: Complete Knowledge and Negation as Failure.
- Wikipedia contributors. Closed-World Assumption.
- multigrid. Why You Have to Re-Embed When You Change Embedding Models.
- speed_engineer. Upgrading Your Embedding Model Doesn't Break RAG Loudly. It Breaks It Quietly..
- Patient Safety Network, Agency for Healthcare Research and Quality. Alert Fatigue.
- vectr source: the absence and re-check mechanism discussed in this post is sketched in the working-memory layer's public docs; the reversible revocation machinery that an absence primitive composes with is described in the vectr source under
agent/working_context_store/_events.pyand discussed in Reinstatement Is the Missing Primitive in Agent Memory.