Your agent didn't get dumber in production. It just stopped being the only thing touching the data.
In testing an agent runs alone. It reads state, thinks for a few seconds, calls a tool, and the world it read is still the world it writes to. Production puts a gap in there, and the gap is where things break. Between the read and the write a payment settles, a listing sells, an operator makes a call in the admin panel, another worker picks up the same job.
So the plan is sound, the tool call succeeds, and all of it lands against a version of reality that no longer exists. It doesn't present as a model failure. That's why teams go looking for better prompts.
I treat an agent loop the way I treat a payment flow: no action on a read that isn't proven current. Conditional writes against the version the agent carried in, never a blind update. Scope the actions so the state a decision depended on is the state it locks. And keep an explicit line between an action that can be retried and a decision that has to be re-made, because an agent that "retries" usually re-plans from fresh context instead of resuming. That is a different operation, and in anything that moves money or inventory it needs to be treated as one.
Test harnesses hide all of this: they're single-actor by construction. Nothing competes with the agent unless you build something that does. Concurrency is a condition you have to inject on purpose, the same way you inject a timeout or a malformed payload.
I've written more on where these pipelines actually break in production, over on the blog: https://polycratia.com/c/3a5d4b9d
If you're running agents against live state, you probably have a staleness window between read and act, and it's worth knowing whether anything in the system enforces it...