The Fix Was Committed. The Old Value Kept Running.

2026年8月15日2 次浏览来源:Dev.to阅读原文

Originally published on hexisteme notes.

I deleted three ambient API keys from my shell profile.

Then I ran the standard clean-room check — spawn a shell with no inherited environment at all, , and read back for all three.

That command doesn't lie: a shell started with an empty environment can only see what the current profile puts there, so if it reports the variable missing, the profile is clean.

I closed the loop, reconnected my tools, and moved on.

Minutes later I reconnected a review tool I run for cross-vendor sanity checks, and it came back healthy — with eight providers registered, one of them authenticated with a key I had just deleted.

Not a cached credential from an old response.

A live, working authentication, using a value that no longer existed anywhere on disk.

The fix was committed.

The old value kept running.

Two different questions that sound like one "Did I fix the config?" and "Is the fix in effect?" collapse into a single question in your head, because in the common case they're the same event: you edit a file, the next thing that reads the file gets the new value, done. answers the first question perfectly.

It says nothing about the second, because it doesn't test any process that already exists — it only tests a brand-new one, freshly spawned, that has no choice but to read the current profile because it has no environment of its own yet.

Every process that was already running before you made the edit is a different story.

It read the profile once, at its own startup, copied whatever it found into its own memory, and has not looked at the file since.

From that point forward it is not a reader of your shell profile — it is a cache of it.

And caches don't invalidate themselves.

Finding the actual culprit The process holding the stale value here was the editor I was working in — the same long-lived process that hosts my coding sessions and manages tool connections through MCP.

I compared two timestamps: when that process had started, and when I had last modified the profile.

The process had started days before the edit.

The profile edit landed after midnight on a night when the process itself had already been running since the afternoon several days earlier — the gap was the better part of a week.

It didn't matter that the file on disk was correct.

The parent process had frozen its own copy of the environment back when it launched, and it had been silently reinjecting that frozen copy into every child it spawned ever since — including, on reconnect, the review tool that came back with eight providers wired to a key I no longer had.

That's the mechanism in full: a long-lived parent — an editor, an IDE, a scheduler daemon, an old shell or terminal multiplexer session, anything that starts once and lives a long time — freezes environment variables at boot and hands that frozen snapshot to every process it spawns afterward, no matter how long ago the profile changed.

Reconnecting a tool through that parent doesn't re-read the profile.

It re-reads the parent's memory.

Three layers, not one The fix wasn't a better command.

It was accepting that "did this take effect" is not a single yes/no question but three separate ones, and that passing the first tells you nothing about the other two: The profile, on disk.

What will a brand-new process see?

This is what actually checks.

The live parent process.

What did this specific already-running process freeze at its own startup, and when did that startup happen relative to your edit?

A parent whose start time predates your edit is guaranteed to be carrying the old value, no matter what the file now says.

The child, in practice.

What does the thing that actually consumes the value receive when it's spawned right now?

This is the only layer that tells you what's really happening, and it's downstream of both of the others.

Checking layer 1 and reporting "fixed" is reporting one-third of the answer as if it were the whole thing.

The honest report, until you've checked all thr

分享