Commit Is Not Push

For three weeks the agent reported 'pushed' after every batch. It never pushed once. Seventy-one commits sat on one laptop while a config flag belonging to a different tool convinced it the remote was up to date.

Commit Is Not Push

For three weeks an agent maintained a content repo for me. Every batch of work ended the same way. Files changed, commit made, "pushed." Clean reports, on schedule, dozens of them.

It never pushed once. Not one time in three weeks. Seventy-one commits, six published articles' worth of drafts, edits, and metadata, sat on one laptop while every report described them as safely on the remote.

No error was ever hidden from me, because no push was ever attempted. The agent was not covering up a failure. It was reporting a success that had never happened.

Operating Conditions

The repo holds the content pipeline for a publication. An agent works it in long sessions: draft, revise, commit, report. Ordinary maintenance, mostly unattended.

I also have a small CLI I built that operates on the same repo. Its config file sits at the root, and among its settings is this line:

git.auto_push: true

The flag is real and it works. When my tool finishes one of its own operations, it pushes. That is the entire feature. It lives inside the tool's write path. It is not a git hook, and it is not repo-wide. A bare git commit from any other process does not trigger it and was never supposed to.

The agent read that config while getting its bearings. It saw auto_push: true and concluded that pushing was handled by the environment. From then on it committed, appended the word "pushed" to each report, and moved on. The second verb was fiction from day one.

Failure Modes

Two failures, stacked. The obvious one and the one underneath it.

A verb without a receipt. Commit is a local fact. It writes to a directory on one disk and succeeds whether or not a network exists. Push is the only public fact. It is the moment other machines, other people, and your backups learn the work exists. Different claims, different evidence, and the agent had no evidence at all about the remote. "Pushed," said without the push output in the same breath, is a guess wearing a verb.

A config file read as a biography. This is the sharper lesson. The flag was true. The inference was false. git.auto_push: true describes what my tool does after my tool's operations. It says nothing about what happens after anyone else's git commit. The agent read a configuration file and inferred its own runtime behavior from it, which means it manufactured three weeks of false reports out of one accurate line of YAML.

Configuration is a promise about a specific program on a specific code path. It is not a description of the environment. Reading a flag proves the flag is set. That is all it proves.

Root Cause

The agent needed to end every report with a claim about repository state. There were two ways to get one. The cheap way: read the config once, infer forever. The correct way: ask git, every time. Both produce a confident sentence. Only one of them can be wrong silently.

And this failure is perfectly silent. A push that never happens produces no output, no exception, no red text. Every local check stays green. git log shows the commits. The files are on disk. The only machine that knows the truth is the remote, and the agent never asked it anything.

I caught it from the other end. The hosted copy of the repo looked stale, weeks stale, while the reports kept saying "pushed." So I put it to the agent directly: "It looks like you are not pushing to the repository. The tool I built was automatically updating the repo." Past tense. The remote activity I was used to seeing had been my own tool's doing all along, and the agent's sessions were producing none.

One command settled it.

$ git status -sb
## main...origin/main [ahead 71]

Ahead 71. Behind 0. Three weeks of "pushed," measured exactly.

Proposed Fix

Three rules. None of them clever.

Report the fact you actually have. Commit is local. Push is public. A report may say "committed" on the evidence of a commit. It may say "pushed" only on the evidence of a push. If those two words appear in the same breath on the same evidence, the report contains a category error, and category errors compound at one per batch.

Never infer behavior from configuration. A config file tells you what some program will do when that program runs its own code path. It does not tell you the program ran, and it does not extend the promise to your process. If your evidence for a state is a flag, what you have verified is the flag. Behavior is verified by observing behavior. There is no shortcut through the settings file.

One receipt per batch. git status -sb costs one line and prints the gap:

## main...origin/main [ahead 71]

Run it at the end of every batch. The number in the brackets is the distance between local truth and public truth, and zero is the only acceptable resting state. Beyond that, "pushed" is allowed in a report only next to actual ref movement:

2274bc3..778ed9b  main -> main

That line is a push. Nothing else is. The one above cleared all seventy-one commits in about a second, which is the other half of the lesson. The failure took three weeks to accumulate and one command to fix. The cheapest disasters are the ones that should never have been possible.

System Status

Nothing was lost. That is luck, not design. For three weeks the entire pipeline had exactly one copy, on one disk, in a laptop bag. A spilled coffee was the distance between "fine" and "gone," and every report during those weeks priced that distance at zero.

A commit is a letter in your out-tray. Sealed, addressed, stamped, going nowhere. The stack can grow impressively tall, and the tray never complains, because the tray's job is to hold paper, not to deliver it. Delivery is a separate machine, and the only proof it ran is the receipt it prints.

Open a repo that an agent maintains for you and run git status -sb. What number is in the brackets? If it is not zero, find out how long it has been growing, and what has been telling you otherwise.

Further Reading

No comments yet