Volume II · Chapter 6
Context Drift
Divergence between what the agent believes and what's true — files edited outside the session, stale references, the rot-by-external-edit problem.2026-07-12 · 9 min read
An agent opens a session, reads a config file to understand how a service is wired, and forms an understanding of it that will govern every edit for the next hour. Twenty minutes in, a teammate pushes a small fix to that same file — a default value corrected, a flag renamed — and moves on, unaware that a session on the other side of the repository has already read the old version into its working understanding. Nothing tells the agent this happened. No error fires, no diff appears in its context, no line of the transcript marks the moment the world underneath it changed. The agent simply keeps going, reasoning from a file that no longer exists in the form it remembers, proposing edits calibrated to a default value nobody is using anymore.
This is not a rare accident. It is the default condition of any session that runs longer than a few minutes in a codebase anyone else can touch — a teammate committing in parallel, a second AI session working a different ticket in the same repository, a deploy that rotates a config value nobody thought to mention. The session’s context was accurate when it was formed. It is not accurate now. And unlike most failures an engineer learns to watch for, there is no local symptom: the agent is not confused, not stuck, not producing malformed output. It is fluent, confident, and wrong about something specific and checkable, in a way that looks from the outside exactly like being right.
Rot from within, drift from without
It is worth being precise about the difference between this failure and the one the previous chapter named, because the two are easy to fold into a single vague complaint about “context problems” and they call for entirely different responses. Context rot, per Chroma Research’s evaluation, is a capacity-and-attention problem inside a static context: models do not use their context uniformly, and reliability degrades unevenly as input length grows, even when every token in the window is accurate and none of it has changed since it was written. Rot is what happens to true information that a session simply has too much of, or has arranged badly.
Drift is a different axis entirely. A session can be nowhere near its context limit, carrying a small, cleanly curated set of files, well inside the band where rot has no measurable effect — and still be wrong, because one of those files stopped matching reality after the session read it. Rot degrades a session’s grip on information that is still true. Drift keeps the grip firm on information that has quietly become false. A well-curated context is not protected against drift; if anything, a lean context makes an agent more confident in what little it is holding, and confidence is exactly the wrong instinct to have about a fact nobody has re-checked.
A clean bill of health, silently wrong
Chapter 3 gave this volume a way to score a session’s context health — a number, a band, and a named reason for what dragged the number down — and one of its four scoring factors already reaches directly for this problem: a stale-reference check comparing what a session read against what has since changed. That is real coverage, not a gap this chapter is discovering. It is also conditional on something worth stating plainly: the check works only when a harness is actually watching the right things — file modification times, a git log, some change-detection signal wired into the score’s inputs in the first place. A healthy stale-reference factor is a property of a well-built harness, not something every session gets automatically the moment someone calls its context “healthy.”
The residual gap is narrower than “the score cannot see drift at all,” and it is worth being precise about where it actually sits, because the imprecise version is easy to overclaim. A stale-reference check built on file state can only flag a change that shows up as a file changing. A dependency version bumped in a registry, a config value rotated by a deploy, a feature flag flipped in an admin panel — none of those necessarily touch a file the session’s tooling has any reason to be watching, so there is nothing local for a file-based check to diff against. A session can sit in the healthy band, stale-reference factor included, while reasoning confidently from a fact that changed somewhere the score’s watcher was never pointed.
A health score can catch a file that changed underneath it. It has no channel for a fact that changed without ever touching a file at all.
On the residual blind spot a file-based staleness check cannot close
Three ways the ground moves
Drift has a small number of recurring sources, and they are worth separating because they differ sharply in how detectable they are.
- Concurrent human edits. A teammate changes a file the session already read — a refactor, a bug fix, a rename — through the ordinary, unremarkable act of doing their own work in the same repository.
- Concurrent AI sessions. A second agent, working a different task in the same codebase, touches a file the first session is holding in context — increasingly the normal case rather than the exception, as teams move from running one agent at a time to running several (a pattern this Library covers in depth in Volume VI).
- External system state changing. A dependency gets bumped, a deploy rotates a config value, a feature flag flips, a database migration runs — none of it necessarily touching a file the session has open, all of it changing facts the session is reasoning from.
The first two share a shape: a file the session already has visibility into gets changed by another actor. That shape is exactly what a file-based staleness check — Chapter 3’s stale-reference factor, or the simpler mtime comparison later in this chapter — is built to catch, given a harness that is actually watching. The third source is a different shape entirely. Nothing about a dependency bump or a rotated config value requires touching a file at all, so there is nothing local for any file-based check, however well built, to notice.
The industry’s response to the second source has, so far, mostly been architectural rather than diagnostic: isolate the sessions so they cannot collide in the first place. Running each concurrent agent in its own git worktree — a separate working directory sharing one repository history — keeps two sessions’ edits from landing on top of each other in real time, deferring any real conflict to an ordinary merge instead of a silent overwrite. GitHub’s own 2025 push toward a unified “mission control” for running multiple agents against one codebase is a signal of how normal this pattern has become, not an outlier case worth dismissing. Isolation solves the collision. It does not solve drift — a session in its own worktree can still be reasoning from a stale copy of a shared file the moment that worktree is synced against a moving base branch.
Cheap signals, real limits
The single cheapest mechanical signal available is a timestamp comparison: has this file’s modification time changed since the session last read it? It costs a filesystem stat call, requires no new infrastructure, and catches the single most common case — a file edited after the session formed its understanding of it. It is also, deliberately, a heuristic rather than a guarantee. A rename or a move changes the path without necessarily updating the mtime a check is comparing against; a tool that touches a file without meaningfully altering its content can trip a false positive; filesystem timestamp resolution is coarser than people assume. The check is worth having precisely because it is cheap, not because it is complete.
The second lever is a discipline, not a mechanism: re-read a file before trusting it, particularly right before an edit that depends on its current state. This is where the honest tradeoff sits, and it is worth naming rather than glossing over. Re-reading everything before every action would eliminate a meaningful share of drift and simultaneously defeat the entire discipline the rest of this volume argues for — a context window is a finite resource, and refreshing every file on every turn is a curation failure by the same standard Chapter 2 used to describe over-loading. Anthropic’s framing of context as something to load deliberately, not reflexively, cuts both ways here: the same restraint that prevents rot is what makes a session vulnerable to drift, because restraint means trusting what was read earlier instead of re-checking it now.
It helps to name the general shape of this problem, because it is not new and it does not belong uniquely to AI sessions. Distributed systems have run into the identical tension for decades under the name of staleness and consistency: a cached copy of a fact is accurate at the moment it is fetched and only probabilistically accurate afterward, and the choice to trust the cache instead of re-fetching on every read is a deliberate tradeoff between latency and correctness, not an oversight. Infrastructure teams gave their version of the same problem a name that maps almost exactly onto this chapter’s: drift, the divergence between a system’s declared state and its real one, detected by diffing the two rather than assuming they still match. A session’s in-context understanding of a file is a cache. The file on disk is the source of truth. The question is never whether the cache can go stale — it always can — but how cheaply staleness can be detected before it is acted on.
| Drift source | Cheapest available signal | What still gets missed |
|---|---|---|
| Concurrent human edit | File mtime newer than the session’s last read of it | A rename or move that changes the path without a corresponding mtime the check is watching |
| Concurrent AI session, same repo | Mtime check, plus worktree isolation to prevent live collision | Two sessions sharing one worktree by design, or a stale sync against a moving base branch |
| External system state (dependency, config, deploy) | None intrinsic — requires an explicit, task-specific check against the live system | Anything the session had no prior reason to suspect had changed at all |
The honest limit
The table’s third row is the point this chapter has been building toward, and it deserves to be stated without softening: some drift cannot be caught from inside a session, no matter how disciplined that session is about re-reading and timestamp checks. An agent cannot suspect a fact it has no reason to suspect. It cannot re-check a dependency version it does not know was bumped, or a config value it does not know a deploy just rotated, because re-checking requires first knowing that something might be worth re-checking — and that knowledge, by construction, comes from outside the session or not at all.
This is not a discipline problem to be solved by trying harder, and treating it as one is exactly the mistake this chapter is arguing against. It is a structural gap, and structural gaps get closed structurally: by a harness that can observe the world the session cannot — a file watcher that pushes a “this changed since you read it” signal into the session rather than waiting for the agent to guess when to ask, the same pattern infrastructure teams already run when they diff declared state against real state on a schedule instead of trusting that nothing moved. An individual session cannot build this for itself mid-task. The tooling layer around it can, and whether it does is a design decision, not a fact about how capable any particular agent happens to be.
What the telemetry should show
Operon does not yet have a large enough fleet of drift-specific incidents to publish a real distribution, and this chapter will not manufacture one. What follows is the shape of the check worth running, offered as a starting instrument rather than a finding.
None of this argues for paranoia — a session that re-verifies everything before every action has simply traded drift for rot, which is not a trade worth making. It argues for treating staleness the way the rest of this volume treats every other scarce-context problem: as something to check cheaply and often where checking is cheap, and to hand off structurally where it is not. The next chapter turns to the memory ladder that carries context across sessions in the first place — and a session that cannot trust what it is holding within its own lifetime has little chance of trusting what a prior session handed it across a gap far wider than twenty minutes.
For Discussion
- Of the shared or high-traffic files your AI sessions touch in a typical week, is there any mechanism that would catch one changing mid-session — or does every session implicitly assume nothing moved?
- If two AI sessions, or an AI session and a teammate, are editing the same file today, what actually happens when their changes meet — a merge conflict a human resolves, or a silent overwrite nobody notices until later?
- Where in your workflow does drift do the most damage: a stale file read, a stale dependency version, or a stale assumption about deployed configuration — and does your tooling treat those three as the same problem or three different ones?
References
- establishedEffective context engineering for AI agents — context as a finite, curated resourceAnthropic engineering · 2025-09-29
- establishedContext Rot: how models use context, evaluated across 18 modelsChroma Research · 2025-07
- establishedEffective harnesses for long-running agents — cross-session state and structured handoffAnthropic engineering · 2025-11-26
- establishedRun parallel sessions with worktrees — isolating concurrent agent sessions in one repositoryClaude Code documentation · 2026
- establishedIntroducing Agent HQ: a unified control plane for running multiple coding agents against one codebaseGitHub Blog · 2025-10-28
- establishedEventually Consistent — staleness and consistency tradeoffs between a cache and its source of truthWerner Vogels, ACM Queue · 2008-10
- establishedDetecting and Managing Drift with Terraform — the infrastructure-world precedent for diffing declared vs. real stateHashiCorp · 2024