Give a coding agent a bounded task and it does fine. Give it a four-hour refactor and something strange happens around the two-thirds mark: the output stays fluent, the commits keep landing, the tests still pass — and the work has drifted somewhere you never asked it to go.
We have watched this happen enough times on Swarm Orchestrator to stop treating it as a model problem. It is a control problem, and it has structure.
The failure is not hallucination
The intuitive story is that the model starts making things up. That is not what we see. Individual actions stay locally correct almost to the end. What decays is the relationship between the actions and the original goal.
A representative run: the agent is asked to migrate a module off a deprecated interface. For the first ninety minutes it does exactly that. Then it encounters a test that fails for an unrelated reason. It fixes the test. The fix touches a helper. The helper is used elsewhere, so it updates those call sites. Two hours later it is deep in a refactor of the logging layer, every individual step defensible, and the deprecated interface is still there.
Every step was reasonable. The trajectory was not. No single decision was wrong enough to catch.
This is goal drift, and it is what makes long-horizon agents hard in a way that short ones are not. Short tasks fail loudly. Long tasks fail by degrees.
Three mechanisms we can actually name
1. The goal falls out of the effective context
Even with a large window, the original instruction competes with thousands of tokens of tool output, diffs and error text. It is still technically present. It is no longer load-bearing. The nearest error message becomes the de facto objective because it is the most recent, most concrete thing in view.
2. Self-verification collapses into self-agreement
An agent asked to check its own work against its own plan will almost always approve it. Both sides of that check come from the same context, so they share the same drift. Verification that shares state with execution is not verification.
3. Sunk-cost momentum
Once an agent has produced a hundred edits, proposals to discard them score badly against proposals to continue. Nothing in the loop rewards abandoning work. We have watched agents rationalize their way forward through three consecutive failed approaches rather than reset.
What actually helped
We tried longer context, better prompts and more capable models. All three helped a little. The changes that moved the number were structural.
Re-anchor on a schedule. Every N steps, drop the working context and restate the task from the original brief plus a compact state summary. Not a reminder appended to a growing transcript — a genuine reset. This alone cut drift-related failures by roughly half in our runs.
Verify from a cold context. The checker gets the original task and the final diff. It does not get the execution transcript, the reasoning, or the agent's own account of what it did. It has no way to inherit the drift.
result = agent.run(task, budget=steps)
verdict = verify(task, result.diff) # cold: no transcript, no plan
if not verdict.on_target:
result = agent.run(task, seed=result.diff, budget=steps)
Make abandonment cheap. Checkpoint aggressively and treat a reset as a normal outcome rather than a failure. An agent that can throw away two hours without ceremony will do it; one that cannot will rationalize instead.
Bound the blast radius. Declare the files a task may touch up front. When the agent wants to go outside that set, it has to stop and ask. Most drift announces itself as a request to edit something nobody mentioned.
The uncomfortable part
None of this fixes the underlying issue. It contains it. An agent with a re-anchor loop and a cold verifier still drifts — it just gets caught within a bounded window instead of four hours later.
We suspect the real fix is not a bigger model but an architecture where the goal is held somewhere the execution loop cannot overwrite. That is the direction Track 01 is heading. We will write up what breaks.