The Code Was Updated. The Python Process Wasn't.
A mixed-generation import failure in local agent tooling, and why a healthy fresh interpreter didn't disprove the error in a running session.
Work period: September 21–22, 2026.
The constant was in the source file. A fresh Python interpreter could import it. The running application still reported that it couldn’t import the name.
That was the shape of a failure in my local agent tooling in September. The apparent contradiction made sense once the investigation separated the code on disk from the modules already loaded into the process.
Two generations in one process
The checkout had changed while long-lived terminal sessions remained active. One session could still hold an older error-classifier module in memory. Later, it could load a newer fallback module that expected a constant the older classifier didn’t have.
Python had enough of the old generation loaded to break an import from the new one. Looking at the current file showed the constant. Starting a clean interpreter loaded compatible versions and succeeded. Both observations were accurate, but neither described the failing process’s complete state.
The process timeline supported that explanation: the long-lived sessions predated the source update. The question was no longer whether the name existed somewhere in the checkout. It was whether the module supplying it inside that process belonged to the same generation as the module asking for it.
Reproduce the mismatch
The regression test recreated the relevant relationship. It left the classifier without the marker and loaded the fallback path that depended on it. Before the fix, that produced the expected import failure.
That test was more useful than repeating a fresh import. A fresh interpreter had already passed. The regression needed to represent the stale-peer condition that made the running session different.
The repair moved the shared marker into a small dependency-free module. Both the classifier and the fallback code imported it from that owner. The classifier kept its public attribute for compatibility, while the fallback stopped relying on the potentially stale peer module to supply it.
The change was narrow. It removed the dependency involved in this particular failure. It didn’t make arbitrary source replacement safe inside a running Python application.
Source checks and runtime checks answer different questions
The focused verification recorded 198 passing tests with no failures. Lint, compilation, and fresh import-identity checks also passed. Those results covered the changed behavior and its nearby classifier and fallback paths; they weren’t a full-repository test result.
There was still an activation question. A patch on disk doesn’t tell you which modules an existing terminal session is using.
The repair was checked in a newly started terminal interface, which completed a normal model request without the reported import error. That provided runtime evidence for the repaired path. One older session remained outside the operation, and the gateway was not restarted. Those limits stayed in the closeout instead of being rounded up into “everything is fixed.”
Keep the process in the picture
This is a useful debugging habit for any long-lived tool that can outlast a source update. Record when the process started, when the checkout changed, and which test actually reproduced the failure. Keep a successful clean-process check in its proper place: it tells you about the clean process.
The same care applies to the result. A regression can prove the specific dependency was repaired. A fresh session can show that the repaired path runs. Neither observation grants a permanent guarantee across later updates.
I want the failure report and the successful test to describe the same conditions closely enough that the result means something. In this case, the missing piece was sitting in memory while we were looking at the file.
