An agent opens a pull request against a file it edited the day before, and the diff quietly renames a function that three other services still call. Nobody told it to break that contract. It simply did not know the contract existed, because nothing it read this session mentioned it, and the session before this one, the one where a teammate explained exactly why that function's name matters, is gone. Ask the same agent to describe the authentication flow twice in the same week and you can get two different descriptions, neither one exactly wrong, neither one quite the architecture as it actually stands. This is not a story about a weak model. It is a story about an agent with no persistent, structural understanding of the codebase it is working in, reconstructing that understanding from whatever fits in the window this run, and quietly guessing at the rest.
The standard response to a forgetful agent is to hand it more room: a bigger context window, a retrieval layer that fetches relevant snippets, a newer model with a longer memory of the conversation. None of these reach the actual defect, because the defect was never capacity. A window that could hold the whole repository still empties at the end of the session. A retrieval system that finds text similar to your question still cannot say what a function actually depends on, because resemblance and dependency are different relationships, and one does not imply the other. A model, however capable, is still producing its best guess about your code from whatever it can currently see, and that guess is exactly what shows up in production as a hallucinated file path, a duplicated helper function, or an edit that quietly breaks callers nobody mentioned.
What actually closes the gap is not a bigger container for text or a fuzzier search over it. It is a deterministic context graph: a structural map of the codebase, files, dependencies, call relationships, ownership, built the same way every time from the same source, so an agent can be handed verified facts about the project instead of being asked to remember or infer them. This piece works through what that phrase actually means, why the two default fixes do not reach the problem, what the failure looks like when a team hits it in production, and why the fix looks more like how a compiler treats source code than how a model treats a conversation.
Origin: what an agent has instead of memory
Start with the honest inventory of what a coding agent has available to it when a session begins, because it is short. It has a system prompt. It has whatever files it chooses to open and read this run, inside a token budget. It has, if the tooling supports it, a retrieval step that can fetch snippets resembling the current question. And it has the model's training data, frozen at some past date, which knows programming in general and nothing about the branch that was pushed an hour ago. None of that persists. Close the session and the next one starts from the same short list, not from anything the agent worked out about your project last time.
This is the same gap covered in how agent memory works for AI systems generally: the context window is not storage, it is a buffer that gets discarded, and a model's weights do not update from a conversation. Applied to a codebase specifically, the gap is sharper, because a codebase is not a set of facts a person could plausibly reconstruct from general knowledge. It is thousands of specific, arbitrary decisions, this file imports that one, this function is called from six places, this module is owned by a team that renamed it eight months ago, and almost none of that can be derived. It has to be looked up fresh, or already known.
Two fixes get reached for first, and it is worth being specific about why each one misses. The first is a bigger window. The logic is intuitive: if the agent forgot something, give it more room to hold. But holding more text is not the same as comprehending more of it. Lost in the Middle, the study that first measured this carefully, found language models recall information from the start and end of a long context far better than the middle, and later testing from Chroma ran eighteen frontier models and found accuracy degrading steadily as input grows, often well before the advertised limit is close to full. A bigger window changes how much a session can hold before it overflows. It does not change how reliably the agent uses what is already there, and it does nothing for the fact that the window empties again next session regardless of size. Capacity was never the constraint.
The second fix is retrieval: turn the codebase into embeddings, and when the agent needs context, fetch the chunks whose vectors sit closest to the question. This is a genuine improvement over reading files at random, and it is the same technique that grounds a model in any private corpus. It is also the wrong primitive for a specific, structural reason. Vector similarity measures how much two pieces of text resemble each other. It says nothing about whether one actually depends on the other. A checkout handler and the tax-calculation function it calls on every request might share almost no vocabulary, the handler deals in routing and validation, the tax function in rates and rounding, so nothing in embedding space points from one to the other, even though changing the tax function will break the handler with certainty. Meanwhile two unrelated files that both happen to handle user records can sit right next to each other in that same space, resembling each other while depending on nothing in common. Resemblance is a real signal. It is not the same fact as a dependency, and shipping code safely runs on dependencies, not resemblance.
Present: what a deterministic context graph actually is
Set AI aside for a moment, because the underlying idea is not new. A compiler builds a structural representation of a program, an abstract syntax tree, before it does anything else, because it needs to reason about what the code does, not just what the text looks like. A linker resolves symbols into a dependency graph before it can produce a working binary. Static analysis tools have walked call graphs and import graphs for decades to answer exactly the questions a coding agent now needs answered: what calls this function, what breaks if this file changes, who owns this module. None of that machinery involves guessing. It involves parsing, a mechanical, rule-based process that reads source and produces a structural output, the same output every time, for the same input.
A deterministic context graph applies that idea to giving an AI agent the same structural ground truth. The nodes are the real units of a codebase: files, functions, classes, modules, packages, sometimes the people or teams who own a given piece. The edges are the real relationships between those units: imports, calls, inherits, is tested by, is owned by. The graph is built by parsing the source, not by asking a model to summarize it, and that distinction is the entire point. Parsing is deterministic in the precise engineering sense of the word: a fixed procedure applied to a fixed input produces a fixed output, verifiably, on any machine, every time it runs. Parse the same commit twice and you get the same graph twice, not a graph that drifts because a language model sampled a different token somewhere in the middle of describing your architecture.
Put a question to a system like this and the difference from a text search is immediate. Ask what depends on a given function and a vector search returns passages that talk about similar things, which may or may not be the actual callers. A graph walks the real call edges outward from that function's node and returns the actual callers, all of them, or reports honestly that there are none. One is an approximation dressed up as an answer. The other is a lookup. The graph also has to stay current to be worth anything: source changes constantly, so a useful version of this idea recomputes on every meaningful change rather than aging into a stale, confidently wrong map, which is worse than no map at all.
It is worth separating this from a nearby idea it sometimes gets confused with. GraphRAG also builds a graph, but it extracts entities and relationships from prose using a language model, a judgment call useful for summarizing themes across documents where no ground truth exists to parse. A codebase is a different kind of object: it already has an exact, mechanical structure, because a computer has to execute it, so a code graph does not need a model to infer relationships a parser can simply read off the source. The two ideas share a shape and solve different problems.
None of this replaces the disciplines already built around making a model useful. Context engineering is still the job of deciding, turn by turn, what belongs in the window. Retrieval is still how a system reaches past the window for something specific. What a structural graph changes is the material those disciplines have to work with. Deciding what to include is a different and easier problem when the candidate set is the files a verified edge actually connects to this change, instead of the files whose text happened to sound closest to it. A graph is the substrate. Context engineering and retrieval are what get built on top of it.
Present: the failure mode this actually fixes in production
None of this would matter much if the gap were theoretical. It is not, and four independently gathered numbers describe the same failure from four angles: forced to act without a structural memory of the project, an agent, or a developer leaning on one, does not pause to say so. It produces the most plausible available answer, and a plausible wrong answer costs more than an obviously broken one, because it passes a skim.
Start with raw productivity, measured under unusually careful conditions. In 2025 the research group METR ran a randomized controlled trial with sixteen experienced open-source developers working on repositories they already knew well, using the AI coding tools available at the time. The developers were not novices and the repositories were not toy problems. Before the study, they predicted AI assistance would make them about 24 percent faster. The measured result was the opposite: completing real tasks took them 19 percent longer with the tools than without. Afterward, having just been timed at 19 percent slower, the same developers still estimated the AI had sped them up by 20 percent. That gap between felt speed and measured speed is not a story about generation quality. These were capable tools used by people who already knew the code. What likely ate the time is the part that never shows up in a demo: reading output that looked right, checking it against a codebase the model could not see, and fixing what did not fit.
The guessing shows up most starkly when a model has to name something specific that may or may not exist. A study presented at USENIX Security 2025 tested sixteen popular code-generating models across 576,000 samples in Python and JavaScript, checking every package import against the real package registries. At least 5.2 percent of commercial-model outputs and 21.7 percent of open-source-model outputs referenced a package that does not exist, more than 205,000 distinct invented package names across the study. The model is not being careless. It is doing precisely what a language model does under uncertainty: producing the name that best fits the statistical pattern of a real package name in this ecosystem, whether or not one exists. Point that same mechanism inward, at a private codebase instead of a public registry, and the failure is identical in shape: an agent unsure whether a helper already exists somewhere in a utilities folder, or whether a file it is about to edit is still imported anywhere, has no more reason to check than it did to check the npm registry, and every reason to produce a confident, plausible answer instead.
The habit of guessing instead of checking leaves a visible trace in the code itself. GitClear's 2025 analysis of 211 million lines of code changes from 2020 through 2024 found that the share of new code copy-pasted from elsewhere, rather than reused through a shared function, rose from 8.3 percent to 12.3 percent over that period, while the share of changes that were genuine refactoring fell from 24.1 percent to 9.5 percent. 2024 was the first year on record where duplicated code outpaced refactoring. That is what it looks like when "does something like this already exist, and who else depends on it" is a question nobody, human or agent, has a fast and reliable way to answer. The path of least resistance is to write it again, and writing it again is indistinguishable, in the moment, from real progress.
The frustration this produces is not a niche complaint. Stack Overflow's 2025 developer survey, built on tens of thousands of responses, found trust in AI accuracy sitting at 32.7 percent against 45.7 percent distrust, and the single most-cited frustration, named by 66 percent of developers, was AI output that is almost right, but not quite, ahead of the time cost of debugging it at 45 percent. Trust was lowest, and distrust highest, among the developers with the most experience, the group best positioned to notice exactly where an answer quietly diverges from how the codebase actually works. That is the whole pattern compressed into one statistic: the people who know the ground truth trust the tool least, because they are the ones who keep catching it guessing.
Present: why a bigger window or a smarter model does not fix it
The two obvious responses, more context or a better model, keep getting tried, so it is worth being precise about why neither one closes this particular gap.
A bigger window addresses capacity, and capacity was never the binding constraint. Even a session with room to spare degrades before it fills: the same context rot that erodes recall in a long conversation erodes recall in a long, file-stuffed coding session, often well before half the window is used. And capacity does nothing about persistence. A ten-million-token window emptied at the end of the session holds exactly as much of the codebase next Monday as a four-thousand-token one: none. Quoting window size as if it were a memory feature conflates two different properties, how much a session can momentarily hold and whether anything survives the session, and only the second one is the actual problem a forgetful agent has.
A more capable model addresses fluency, and fluency was not the shortfall either. Every generation of frontier model writes more plausible code than the last. None of that changes what the model is mechanically doing at inference time: predicting the next most likely token given whatever is currently in front of it. A better model is a better predictor, and it is still predicting: at the exact moments where the true answer is not visible in its context, it still produces its best guess rather than a checked fact. Determinism is not a matter of degree you approach by scaling a probabilistic process harder. A guess that is right slightly more often is still a guess, and the file paths, packages, and callers it gets wrong cluster exactly where a codebase diverges from what a general-purpose model would expect, in the specific decisions that make a project what it actually is.
This is also where reliability math compounds against a guess-and-hope approach. Chain enough steps together, each depending on the last, and even a high per-step success rate collapses over a real multi-step change, a dynamic covered in more depth in why agents that work in the demo die in production. A hallucinated dependency or an edit that misses a caller is rarely the whole failure by itself. It is the bad foundation three steps upstream that a later step confidently builds on. Grounding each step in a verified structural fact, instead of an inferred one, is one of the few places in that chain where a failure mode can be removed outright rather than merely caught later with more review.
None of this argues for a smaller window or a weaker model, only that both answer a different question than the one a forgetful agent is actually asking. The real question is not how much a session can hold or how fluently it can guess. It is what is actually true about this codebase right now, and whether that fact can be retrieved without re-deriving or inventing it. A window cannot answer that no matter its size, because it holds text, not verified structure. A model cannot answer it from weights alone, because the weights were never trained on your codebase. Something has to compute the fact once, correctly, and make it available again without asking the model to remember or guess.
Future and impact: a graph as the substrate, not a replacement
None of this makes a deterministic context graph a rival to the disciplines already built around getting good work out of a model. It sits underneath them. Context engineering is still the practice of deciding, turn by turn, what belongs in the window. Retrieval is still how a system reaches past the window for something specific. A graph does not replace either. It changes what they get to work with, so that curating context becomes the easier job of asking what a verified edge actually connects to a change, instead of the harder job of approximating an answer from which text sounds closest to it.
Where this goes next is not hard to sketch in outline, even if the specifics stay unsettled. As agents are trusted with longer chains of autonomous change across real production codebases, whether a model can write plausible code stops being the interesting question. That part is largely solved already. The open question becomes whether the system around the model can tell a true structural fact from a merely plausible one, every session, without paying the cost of re-deriving it or the risk of guessing it. That looks more like an infrastructure problem than a modeling one: something computed once per change and reused, the way a build system reuses a dependency graph instead of re-resolving every import by hand on every compile.
Spiderbrain, built by Perform Digital, is one working implementation of this idea. It parses a codebase locally into a deterministic, source-free graph of files, dependencies, and call relationships, backed by roughly 350 automated checks that verify the same source produces the same graph on every release, and it hands that graph to coding agents over MCP so a new session can start from structural ground truth instead of an empty window.
The habit worth taking from all of this is not "add a graph" as a checklist item. It is a sharper question to ask of any coding agent before trusting it with real work: when it is not sure something is true about the codebase, does it check, or does it guess. A bigger window will not change the answer. A better model will not change it either, not by itself. Only something that computed the fact once and can hand it back the same way every time actually will.
Council summary
This post argues that a coding agent's forgetfulness is not a model-quality problem but a missing-layer problem: without a persistent, structural map of the codebase, an agent re-derives the project from whatever fits in its window each session and guesses at the rest, and neither a bigger context window nor a more capable model reaches that gap, since neither is built to persist across sessions or to distinguish structural fact from plausible text. It defines a deterministic context graph precisely: a graph of files, dependencies, and relationships built by parsing rather than inference, so the same source produces the same graph every time, and it draws a clear line between that graph and the context window, vector retrieval, and LLM summarization it is meant to sit underneath. The claim is backed by four independently sourced numbers: METR's randomized trial showing experienced developers 19 percent slower despite feeling faster, a USENIX Security 2025 study finding open-source models hallucinate a nonexistent package in 21.7 percent of outputs, GitClear's finding that duplicated code overtook refactoring for the first time in 2024, and Stack Overflow's 2025 survey showing the most experienced developers trust AI output the least. The reader's takeaway is a diagnostic question to carry into any evaluation of a coding agent: when it is unsure whether something is true about the codebase, does it check a fact or produce a guess. The post is honest that a graph is a substrate for context engineering and retrieval to build on, not a replacement for either.
Comments