Chapter 21. This Machine Is a Stale Mirror

An AI coding agent describes code that stopped being true when its checkout stopped being current, and a stale checkout raises no error to warn it. On 2026-06-08 the main checkout of Suede-AI-App on this machine sat 458 commits behind origin/main, on an abandoned feature branch with a paused rebase, and what an agent read out of it was that far out of date. Two computers run Suede. One of them is where I work and push; whatever it pushed to GitHub last is the truth of the estate. The other is the Mac with home directory /Users/jasoncolapietro, and it holds copies: 60 git repos under ~/code, 52 task worktrees spread across 33 sibling directories, and whatever some session parked on a branch and walked away from. The copies look like the estate. They carry none of its authority. The discipline on this box comes down to getting a fleet of agents to hold both facts at once: the code here is real, and the state here is not.

What 458 commits behind origin/main looks like

On 2026-06-08 the main checkout of Suede-AI-App sat on a feature branch named feat/nft-collectibles-gallery. It was 458 commits behind origin/main. The checkout also carried a paused REBASE_HEAD and uncommitted changes on top of the stale branch. The worktrees around it ranged from 48 to 449 commits behind, and several other checkouts on the machine were parked on dead feature branches of their own. None of this was damage. The other computer had kept pushing while this one sat still, and 458 commits is what sitting still costs at the pace the estate moves.

The number is survivable. The danger is what an agent does with a checkout like that when it treats what it sees as current. It reads stale code and reports features that no longer exist. It cuts a branch from local main and hauls hundreds of commits of drift into its diff. It re-fixes a bug the other machine fixed long since, opens a PR that resurrects a deleted file, or deploys the stale tree to production with a straight face. A stale mirror produces no error message. It answers questions with information that stopped being true the moment the other computer pushed past it.

Why this machine is a mirror and not the source

The split is deliberate: the other computer authors the estate, and this one runs agents, several at a time. Concurrent sessions are the operating condition here, not an exception. In one read-only pass taken while I drafted this chapter, pgrep -x claude | wc -l returned 6: six Claude Code processes running at once. At 18:31 that day, 3 hours 40 minutes after boot, load averages read 16.28, 11.03, 7.92. The one-minute figure sitting at double the fifteen-minute figure means the fleet had ramped up within the previous few minutes rather than idled at that level all afternoon.

Concurrency is also why a shared checkout cannot serve as a workspace. On 2026-06-10 I was editing ~/code/Suede-AI-App when my uncommitted changes vanished mid-task; two edits in, everything was gone. Another live session had switched the shared checkout from main to its own branch, feat/master-registry-consolidation, and a branch switch by any session wipes the uncommitted work of the rest with no warning. That same session had also appended its own entry, named registry-dev, to the shared ~/.claude/launch.json, which is how dev servers claim ports here: one file, many writers, unique port per task or collisions follow. A shared checkout is shared mutable state, and the collision mechanism has nothing to do with which repo it is; I treat any busy checkout on this machine the same way.

The fix became a standing convention. One worktree per task, cut in the sibling directory:

git -C ~/code/Suede-AI-App worktree add \
  ~/code/Suede-AI-App.worktrees/<task-name> -b <branch> origin/main

Then copy frontend/.env.local over from the main checkout, because it is gitignored and dev needs it. The last argument carries the whole discipline: the branch cuts from origin/main, the ref a fetch refreshed moments earlier, not from a local main that might be 458 commits in the past.

The disk shows how hard the convention gets used. ~/code holds 64 top-level directories once the worktree siblings are excluded; 60 are git repos and 4 are not (INBOX, backups, handoffs, the-signal-chain.fleet). Beside them sit 33 *.worktrees parent directories holding 52 worktrees. Suede-AI-App.worktrees alone holds 21; suede-promo.worktrees holds 8; suede-voice.worktrees holds 4. And 19 of the 33 parents are empty, shells left over from earlier cleanups. Worktrees here are disposable on purpose: cut from a fresh ref, used for one task, removed when the task lands.

The two commands that measure staleness

Before touching any repo on this machine, an agent runs two commands:

git -C ~/code/<repo> fetch origin
git -C ~/code/<repo> status --short --branch

The fetch refreshes what the mirror knows about origin. The status answers the three questions that decide what is allowed next: which branch is this checkout on, how far behind its remote has it fallen, and is there dirty work in the tree. The pair costs ten seconds. The 458-commit checkout is what skipping those ten seconds looks like, given time.

Which operations a stale mirror makes unsafe

Push, merge, and deploy are the operations a stale mirror makes unsafe, and the rest follows from the single premise that GitHub and the other computer are authoritative and this box is not.

Never push, open a PR, merge, or deploy from a base that is behind its origin/<branch>. Verify 0-behind first, and verify it fresh; a check from the morning is void by afternoon if the other computer pushed at noon. Never force-push from here. A force-push from a mirror is the copy overwriting the original.

Cut new work from a fetched origin/main into a new branch or worktree. Starting from a stale local checkout inherits the drift plus whatever abandoned branch the checkout was parked on, and on 2026-06-08 this machine had several checkouts parked that way.

Preserve dirty work and paused rebases as found. The paused REBASE_HEAD on feat/nft-collectibles-gallery was not aborted, resolved, or stashed; I left it where it sat. Uncommitted state on this machine can belong to another session, or to intent the other machine never finished expressing. Not being able to identify the owner is the reason to leave it alone, not a license to tidy it.

Don’t run vercel deploy --prod from a local checkout. The GitHub-to-Vercel integration ships what the authoritative side pushed; a CLI deploy from here ships whatever this mirror happens to contain and labels it current. When a manual deploy is unavoidable, it comes from a worktree cut from origin/main moments before.

The sandbox framing also settles where answers come from. When the question is what a feature does in production, the answer lives at the live URL or on GitHub, not in ~/code. A local tree can tell you how something is built; it cannot tell you what is deployed. Agents here quote the mirror for structure and the live surface for behavior, and a claim about production backed by a local file read is treated as no claim at all.

And the line that keeps the caution from freezing all work: local build, test, and read are fine. Push, merge, and deploy are the operations that can affect “current,” and they are the whole list. An agent can compile, run suites, and read code here all day at zero risk. The blast radius starts where bytes leave the box.

Why a one-time pull-all does not fix the problem

On 2026-06-10 I ran a pull-all that made this mirror current without making it authoritative: I fetched and fast-forward pulled about 50 repos, everything then in ~/code. The fast-forward constraint was the point, not a convenience. A fast-forward can restate what origin says and nothing else; a merge pull would have had this mirror manufacturing commits the authoritative side never wrote, which is the one thing a mirror must not do even while catching up. Suede-AI-App came out clean on current main. No paused rebases remained in any main checkout. The sweep left the 4 broken-remote snapshots under ~/from-jasons-macbook untouched. For a moment the mirror agreed with the source.

The rule did not relax, because the rule is about the process that produces drift, not about any one measurement of it. This box falls behind again the moment the other computer pushes. A sync makes a mirror current; it does not make it authoritative. Re-verification is per-action: prove 0-behind before this push, then prove it again before the next one. The estate keeps growing under the mirror’s feet too; the directory that held about 50 repos on 2026-06-10 holds 60 as I write this.

Why synced is the wrong word for a fetch

“Synced” is a status claim on this machine, an assertion that local now represents current, and a fetch earns no such claim. A routine git fetch once ran here and alarmed me, and I stand by the alarm. On semantics I had no case: fetch mutates nothing remote, and it is the first command in this chapter’s own procedure. The framing was the problem, because the agent presented the operation as syncing. The instruction I gave the fleet afterward: “make sure work we do on this computer doesn’t affect anything as if it were current.”

The fetch stayed; the word went. Agents here report the operation as what it is: refreshed remote refs, read-only, nothing pushed. I make push and deploy decisions off the verbs in an agent’s report, so on a box whose defining property is that it does not represent current state, the verbs are load-bearing. A report that says “synced” when it means “fetched” is not wrong about the git objects. It is wrong about what I am now entitled to believe.

Three checkouts as found, and what each one proves

While drafting this chapter I took a read-only snapshot of three active repos on this machine. No fetch ran as part of it.

Repo Last local commit Branch Working tree
Suede-AI-App 965ba6e1, 2026-07-26T17:46:33-04:00, “feat(social): hand the saved rig off to the Registry (#796)” main dirty, 10 entries
suede-agent-studio badcd29, 2026-07-24T01:09:58-04:00, “copy: finish the payout-promise sweep on non-pricing surfaces (#151)” detached HEAD dirty, 2 entries
strumly b70714d, 2026-07-26T00:23:48-04:00, “fix(tools): lead with the interactive trainer, not the reference tables” main clean

Each row exercises a different clause of the discipline.

Suede-AI-App sits on main with a commit dated 2026-07-26 and ten dirty entries: two modified App Store metadata files under ios-app/fastlane/metadata/en-US/, and eight untracked paths including a CLAUDE.md, fastlane metadata directories, and product docs plus two images under suede-home/. The fresh commit date proves the mirror was touched that day; it proves nothing about distance from origin. The dirty entries are some session’s work in flight, so the preserve rule applies, and nothing gets stashed or cleaned on its behalf.

suede-agent-studio is the instructive row. Detached HEAD, no branch at all, with a modified src/app/landing.css and an untracked fastlane/ directory sitting on top. Dirty work with no branch anchor is one careless git checkout away from being hard to find again. An agent arriving here to start a task has one correct move: leave this checkout as it stands and cut a worktree from origin/main beside it.

strumly is the tempting row. Clean tree, default branch, a commit from 2026-07-26. It looks safe, and the appearance is worth nothing, because the snapshot ran without a fetch and the timestamps describe the local copies and nothing beyond them. The distance from this main to origin/main was unmeasured at the moment of the snapshot, and unmeasured means assumed behind. On this machine a clean checkout is not a green light. It is a checkout whose staleness has not been measured yet.

The discipline in one paragraph

GitHub and the live URLs hold the truth of the estate; the other computer writes it; this machine keeps copies for agents to build and test against. Fetch and read status before touching any repo. Prove 0-behind before any push, merge, or deploy, and prove it again for the next one. Cut branches from origin/main, not from a local main nobody has measured. Leave dirty trees and paused rebases as found. Two commands and ten seconds per repo buy all of it, and the 458-commit checkout with the paused rebase is the standing exhibit of what accumulates when they get skipped.