A deployment file names a version for the thing it deploys. The thing actually running can stop matching that name at any point, by any means the file itself has no visibility into, and by default, nothing checks whether the two still agree. The file only gets consulted again the next time something forces a recreate, and at that moment it always wins, silently, in whichever direction it happens to be stale.

The gap ordinary tooling doesn’t cover

Tooling built to manage this kind of drift almost always looks in one direction only: forward, for available upgrades. That answers “is there something newer I could move to,” not “does the file already disagree with what’s running right now.” A service can be changed out from under its own file by a manual fix, a one-off maintenance step, or anything else that touches the running thing without also touching the file describing it, and nothing surfaces that gap until a later, unrelated event causes a recreate. The recreate reads the file, not the running state, so it reproduces whatever the file says, correct or not.

The drift runs both directions, and both are dangerous

It’s tempting to assume the risk only runs one way: a stale file rolling something forward to a version nobody’s tested. It runs the other way just as easily: a stale file can just as well roll a service backward, undoing days of state the newer, untracked version had already produced, with no warning that anything was about to change at all. Both directions have been observed independently on the same estate, within the same tool’s first real run: one file had gone stale pointing backward, the other pointing forward. Nothing about the file itself distinguishes the two cases, because the file was never checked against reality in either one.

What closes the gap

The fix isn’t checking more often for upgrades. It’s asking a different question: does the file’s own reference already match what’s actually running, regardless of which direction a mismatch would run. That comparison has to use identity that can’t shift out from under it. A name given to a version is not reliable for this, because a registry can silently reassign what a name points to later, without the thing already running having changed at all. Confirming what’s actually running has to rely on a comparison of the actual content, not the label attached to it at some earlier moment. A checker built this way also has to keep a third outcome available, distinct from “matches” and “diverged”: genuinely unable to tell. Collapsing “couldn’t tell” into “fine” defeats the point of building the check at all.

Where the claim stops

A check like this only closes the gap on the path that actually runs it. Any way of triggering a change that doesn’t go through the check first reopens the identical blind spot, even with the check fully built and working elsewhere. A manual, run-before-you-act version of the check is not the same guarantee as one wired into every path capable of causing a recreate. It depends on someone remembering to run it, which is exactly the dependency the check exists to remove.

The night this was learned the hard way, a network change, a secrets store that came back several days out of date, and the tool built afterward, is told in Act 65.