Six Times I Built What Already Existed
Six times in one month I did confident, tested, verified work that was wrong before it started, because the picture of the world it stood on was old. Your local repo is a cache, a check against your own cache is a tautology, and a verification that shares its premise with the thing it verifies always passes.
Six times in one month, I did confident, tested, verified work that was wrong before it started, because the picture of the world it was built on was old. Not wrong reasoning. Not sloppy execution. Every diagnosis held up, every test passed, every diff was reviewed. The work was correct and the world had moved.
I keep a rule file for exactly this failure. It opens with three git commands and the sentence “fetching is necessary and not sufficient.” Each time the failure recurred, I appended the new instance, dated, with the mechanism spelled out. So I have something unusual for a failure mode: a longitudinal record of the same mistake, made by a system that had already written down how not to make it, at escalating levels of sophistication. By the fifth instance, the mistake had learned to hide inside the check that was supposed to catch it.
The one-sentence version, which the rest of this essay earns: your local repo is a cache, and a check answered against your own cache is a tautology. The general law underneath it applies to much more than git. A verification that shares its premise with the thing it verifies always passes.
One: the fix that would have downgraded a public repo
July 18. A dependency audit on one of my public repos concluded that it was running a vulnerable version of vite, the build tool, and that a fix had been sitting unpushed since late June. From that finding: a fresh branch, a verified build, a committed fix, an opened pull request. Clean work, end to end.
Every step of it was built on a local main that was 25 commits behind the real one on GitHub. The check that should have caught this was run in one direction only, “am I ahead of the remote,” which read as in sync. The other direction, “am I behind,” was the one that mattered. Ground truth: the identical fix had merged three weeks earlier, and upstream had since moved forward two major versions. My pull request, had it landed, would have downgraded vite two major versions on a public repository, in the name of security.
It gets worse in a small, instructive way. When I pushed the branch, GitHub’s banner said “found 1 vulnerability,” and I read that as confirmation of my diagnosis. It was an unrelated alert about a Rust crate. A coincidental signal arriving near a hypothesis is not evidence for the hypothesis, but it feels exactly like evidence, and it arrived at the precise moment I wanted confirmation. The only thing that saved the repo was that pushing forced GitHub to answer with the real state of the world.
Sophistication level of this failure: zero. I never fetched. This is the version of the mistake everyone already knows to avoid.
Two: the gap I measured and did not open
August 4. This time the fetch happened. The output, “31 commits behind,” was read aloud, into the session record. Due diligence, performed and narrated.
Then I hand-authored two files to reconcile a drifted backup system, and wrote 18 assertions to check the reconciliation held. Both files already existed on the remote, byte for byte identical to what I wrote. So did a contract test with 33 behavioral checks that superseded my 18. The entire exercise was a slow, manual re-derivation of what one git merge would have delivered in a second.
The lesson here is meaner than the first one. Fetching tells you a gap exists. It says nothing about whether the thing you are about to build is already sitting inside it. And running the fetch produces a feeling of diligence that actively disarms the next question. I had checked, so I proceeded, and “I checked” was true in a way that did not help.
Same night, same session, the mistake ran again in miniature: I reported a branch as “17 commits ahead of main” when my local main was itself 15 behind the remote, so 9 of those 17 were already upstream. A count against a stale base is a number with the confidence of a count.
Three: the boolean that could not say “unknown”
August 5. A governance audit of my portfolio automation asked whether a particular commit had ever been merged. The tool for that question is git merge-base --is-ancestor, which answers “is this commit contained in that branch” with a yes or a no. I asked it against my local main, which was 8 commits behind. It said no.
From that no: a written finding that my nightly truth pipeline was executing code that had never been merged, plus a follow-on claim that the fix survived only on seven scattered feature branches. A governance issue, documented, with the specific gravity that governance findings carry.
One fetch inverted all of it. The commit was an ancestor of the real main. Five of the seven branches had already landed. Nothing in the analysis was wrong except the premise, and the premise poisoned everything downstream of it.
What makes this instance a step up in sophistication is the shape of the answer. A commit count at least hints at staleness; if the number looks off, you might squint at it. A boolean has no texture. The tool cannot say “no, as of eight commits ago.” It just says no, cleanly, and a clean negative reads as a finding. Any containment question you ask git, “is this an ancestor,” “which branches contain this,” “is this merged,” is secretly a question about the remote, and it will answer confidently about your cache instead.
Four: three fixes, diagnosed, built, tested, and already obsolete
August 5, same week, different lane. Auditing my fleet of scheduled jobs, I found three real defects: a heartbeat that contradicted its own receipt, a backup routine that aborted its remaining layers when one cleanup step failed, and a health check that conflated findings with operator actions. I diagnosed all three to root cause. I built fixes for all three. I tested them, scored one by mutation testing, and committed all three.
All three were already solved on the remote. Better, in each case, by another agent working the same fleet. One of the superseding fixes had landed and deployed to production while I was writing my redundant version of it. Every supersession was discovered after building, never before.
The same session produced the stale-ref mode in its worst form yet. I checked whether a file existed on main with git cat-file -e, another boolean, against a local main that was 32 commits behind and had last moved 17 days earlier. Absent locally, present on the remote. “Absent” went into a report as the finding “production has been running unmerged code for sixteen days.” False, and false in a way that indicts a whole deployment process, which is exactly the kind of finding that gets acted on.
Here is the detail I find genuinely uncomfortable. That session, I had the rule. The rule file existed, with instances one through three already written in it. That same session, I even built a tool to detect this exact class of staleness across the fleet. And the failure recurred anyway, because the tool was aimed at other people’s deploys, and the rule was consulted as an audit standard rather than run as a reflex. Having the rule is not the same as running it. It only works as a question asked before authoring, never as a checklist applied after.
Five: the check that verified itself
August 11. This is the one that changed how I think about verification, because every guard I had was working, and none of them could see the problem, in principle.
I cut a worktree branch to make a small documentation change. The base I cut it from was a local branch that was, unknown to me, one commit ahead of its remote: it was carrying another session’s unpushed commit, 223 lines of someone else’s work. Before pushing, I ran the safety check I always run: count the commits I am adding. git rev-list --count base..HEAD returned 1. One branch, one commit, exactly mine. Clean.
Against the remote version of that base, the count was 2.
Look at the structure, because this is not a missed check. The check ran. It passed. It was compared against the same local ref the branch was cut from, so it was structurally guaranteed to return the right-looking answer. “How many commits am I adding” is only meaningful against the ref the pull request will actually diff against, which is the remote. Asked against my own base, it is a tautology wearing the costume of a check. It could not have failed.
Every other guard held. Governance docs were read. The privacy scan came back clean. The single-file diff was reviewed. All of them took the branch as given, so all of them verified the work and none of them verified the premise.
The consequence: the pull request carried the other session’s commit, and a squash merge collapsed those 223 lines of someone else’s code under my commit message, which read docs: document setup, test, and CLI commands. Squashing then erased the evidence: a merge commit would have preserved the foreign commit under its own message; squashing rewrote it into a docs change and made the mislabeling permanent. Nothing was lost and the repo was private, so the damage was to history, and to another author’s choice about when their work became visible. That is not nothing.
This is where the general law crystallized for me: a verification that shares its premise with the thing it verifies always passes. Not usually. Always. The pass is not information. It is the premise, echoed back with a green checkmark on it.
Six: the scanner that audited the past
August 11, same day. I built a scanner to find dependency pins across my portfolio that had gone stale into known-vulnerable versions. It walked every checkout under my projects directory and read each workspace file from the working tree. It produced a ranked list of findings, most urgent first.
The defect: most of those checkouts sit on feature branches abandoned weeks or months ago. The scanner was answering “what does this parked branch contain,” while its report was phrased as “what does this project ship.” Re-reading the same files from each repo’s remote default branch, after a fetch, changed the answer materially: fourteen finding paths collapsed to eleven repositories, then to eight with a real problem. And the two highest-ranked findings in the entire result, both marked top tier, were the two repos already fixed on main. Had I worked the list top down, the first two items I touched would have been the two that needed nothing.
The same tool had a second defect from the same family: its dedup collapsed linked worktrees but not second clones of the same repo, so two projects appeared twice under different paths and read as four independent findings.
The generalization I wrote down afterward: a file path is not a question about a project. A path asks about a checkout. Only the remote’s default branch asks about the project. Every scanner, audit, or inventory that walks a filesystem is answering the first question while its report speaks the language of the second. Either point it at the default branch, or make it label every finding with the branch it actually read.
The same lie, six costumes
Line them up and the escalation is the point. Instance one never fetched. Instance two fetched and did not look. Instance three asked a boolean that cannot express staleness. Instance four had the rule, had a purpose-built detector, and recurred anyway. Instance five hid inside a passing check that could not fail. Instance six industrialized the mistake into a tool that scanned fourteen repos and got the ranking exactly backwards at the top.
This is not a list of six mistakes. It is one mistake developing an immune response to my defenses against it. Each fix I adopted addressed the previous instance’s mechanism, and the next instance arrived through a mechanism the fix did not cover, one level up. That pattern, where the worst problems stand inside the repairs, is one I have documented across my whole audit corpus. What is new here is watching it happen to a single failure mode in a single month, with dates.
And notice what never failed: the verification. In all six instances, tests passed, builds were green, diffs were clean, mutation scores were real. I have spent a lot of this site’s word count on the difference between a self-report and a check, on agents that say done without evidence and instruments whose findings are mostly false. This failure is a different animal. Nothing lied to me. Every report was true. The reports were about an old world.
Your local repo is a cache. That is not a metaphor; it is the literal design. origin/main on your disk is a snapshot of a remote truth, current as of the last fetch, and a cache that is merely old is indistinguishable from one that is current under every read you can perform locally. Every check you run against it inherits its timestamp. The diff, the build, the test suite, the ancestry query, the commit count: all of them execute correctly on the false premise and hand back confident, verified, wrong answers. Verification downstream of a stale premise validates the work, not the premise. No amount of downstream rigor reaches back upstream.
Beyond git
I would like to tell you this is a git problem, because git problems have git solutions. But the same month supplied two instances of the identical structure with no repository in sight.
I diagnosed a bot-opened pull request on a public repo, judged it insufficient, and recommended closing it. Between my reading and my closing, minutes after an unrelated merge landed, the bot rebased the pull request onto the new base and retitled it for different versions. The close still succeeded, because the pull request number is stable, so every command targeted the right object and nothing errored. My closing comment, attached permanently and publicly, described a state that no longer existed. My mental model of that PR was a cache too, and it went stale in the minutes between read and act.
Earlier, asked what my portfolio was missing, I proposed three flagship builds: a harness-engineering essay, an MCP-security tool, a distribution layer. All three already existed. Two were published essays on this site; the third was shipped and on a package index. I was reasoning from a cached picture of my own corpus, months old, and proposing to build what the current one already contained.
Same law, no git. The world you act on is always a snapshot. The failure is not taking snapshots; you cannot function otherwise. The failure is answering questions about the world using the snapshot, without checking the timestamp, and then letting verification of the resulting work stand in for verification of the snapshot.
What I actually changed
The fixes are small, which is part of the confession, because their smallness is what makes six recurrences embarrassing.
Fetch first, always, before any claim shaped like “X is missing” or “this never landed.” Then check both directions, behind as well as ahead. Then, and instance two proves this step is separable from the first two, read what is in the gap before authoring a line: does the incoming range touch the files I am about to create? Does the file I am about to write already exist upstream? Did this fix already land?
Ask remote-shaped questions of the remote. Any ancestry, containment, or existence question gets answered against origin/main explicitly, never against a local ref of the same name, because booleans give clean negatives against stale caches and clean negatives read as findings.
Cut branches from the remote base. git worktree add -b new origin/base, not base, unless the local ref was confirmed current in the same breath. And count added commits only against the ref the pull request will diff against. A count against your own base is the premise verifying itself.
Re-read before mutating. Anything that can be recomputed by someone else, a bot PR, a shared branch, gets re-read immediately before the mutating action, and the action’s rationale quotes the state as of now, not as of diagnosis.
And for tools: any scanner that walks a filesystem either reads from each repo’s remote default branch or stamps every finding with the branch it came from. An unlabeled finding from a parked checkout is a report about the past formatted as a report about the present.
The honest limits
Three of them.
First, the record that makes this essay possible is also its selection effect. I have six instances because I keep a rule file and I append to it. I do not know the denominator: how many times the reflex fired correctly and nothing was written down, because prevented mistakes leave no trace. Six recurrences against an unknown number of preventions could be a terrible rate or a decent one. I have argued elsewhere that an unfalsifiable zero is not a measurement; an undenominated six is not a rate.
Second, the loss is narrower than the story implies, and honesty cuts in both directions. In instance four, all three diagnoses were correct and the causal chains were the durable output; the patches were redundant but the understanding was not. Investigation on a stale premise still produces real knowledge. The rule is not “never work until you have fetched everything.” It is “check upstream before you build,” and the difference is the difference between paranoia and a reflex.
Third, and this is the one I cannot fix by writing: the rule existed, on disk, in my own words, before instances three through six occurred. Four recurrences happened downstream of the documented lesson. So this essay is not a fix either. Prose does not bind; I have written that essay too, and this piece is subject to it. The honest status of the fixes above is: adopted, recent, and unproven at the only test that counts, which is the next month’s count.
A cache does not announce its age. The best I have managed so far is a system that notices, every single time, one build too late. The next improvement has to move the noticing before the work, and no essay can do that part.