An agent that passes in testing and fails in production is rarely reasoning worse. It is acting on a world that stopped standing still between the plan and the write.
The loop goes like this: read state, decide a sequence of steps, then execute them one tool call at a time. In a test run nothing else writes. The state the agent read at step one is still true at step five. That property belongs to the test harness, not to the system.
In production a moderator approves, a webhook settles, a cron reprices, a human edits the same record, all of it between step two and step four. Each tool call is its own transaction. The agent holds no lock and carries no version of what it read. So the plan is correct for a state that no longer exists, and the write still succeeds. Nothing throws. What you get is a plausible action applied to stale facts, and that is much harder to find than a crash.
The fix I keep landing on is unglamorous: every mutating tool takes the version of the state the decision was based on, and refuses the write on mismatch instead of accepting it. Then the agent re-reads and re-decides. The model plans over a snapshot; it does not own the record.
This is the same discipline as ledgering money. Optimistic concurrency, explicit conflict, no silent overwrite.
I would start by asking where your agent's plan crosses a state boundary it has no way to detect...