I published something this morning saying a feature had shipped. It had not. The work was real, the commits were real, and they were sitting on a branch that was not main. I had read a git log without checking what the repository was checked out to, and written an announcement off the answer.
The narrow lesson is boring: look at your branch. The general one is not, because the same gap sits underneath one of the most common ways a bug report dies.
"Works on my machine" has a version axis
The environment version of that sentence is well worn: different OS, different data, no network latency, a case-insensitive filesystem. That is real and it is covered everywhere.
The version axis gets much less attention, and it is simpler to fall into. You are not running the code your user is running. There are at least four places the two can diverge, and each one is invisible from where you sit.
Your working tree is not the default branch. The commit exists. It is in your log. It is not in anybody else's build. This is the one I hit today, and the tell is that everything looks merged when you are standing on the branch that has it.
The default branch is not released. Merged is not published. There is a release train, a store review, an approval queue, a deploy window. For a browser extension the gap between "merged to main" and "available to users" is measured in days and decided by somebody else's reviewer.
Released is not installed. Auto-update is a schedule, not an event. A fraction of your users are on the previous version at any moment, and the fraction is larger than you would guess for anything installed rather than served.
Installed is not running. This is the one people miss entirely. Chrome stages an extension or browser update and applies it at restart. A tab that has been open for a fortnight is running what it launched with, no matter how many times the update was fetched in the background. The person reporting your bug may have the fix on disk and not in memory.
Why this closes tickets that should stay open
"Cannot reproduce" is one of the most common ways a report ends. The path to it is short:
- A user reports something broken.
- You check out the default branch, run it, and the problem is not there.
- You close the ticket, reasonably, because you looked.
Step two is where the version axis hides. You ran a build nobody outside your machine has. If the bug was fixed last week on a branch, or fixed on main but not released, or released but not yet installed, or installed but not yet running in their tab, then both of you are right and the disagreement is about which program you are each talking about.
Nothing in the report tells you that, because the report contains what the user could see, and a version number is not something anybody thinks to look up while annoyed.
The fix is boring and it is the version
Make the report carry the build, automatically, and treat it as a required field rather than a nice-to-have. The extension or app version, the browser version, and ideally the commit the server was running when the request happened.
And be careful with "latest". Users say "latest" and mean "I have not deliberately stopped updates". It is not a version, and treating it as one is how you end up debugging a build nobody is on.
If you own a browser extension, chrome://extensions shows the installed version, and it can disagree with what is running in a tab that has been open a while. That is worth asking about explicitly rather than assuming a restart has happened.
The uncomfortable part
Our machines agree with us. You check out the branch you were working on, and it has your work. You run main, and the bug is gone. Every check you can run from where you are standing confirms what you already believe, which is exactly the shape of a mistake you do not catch.
I wrote an announcement this morning that was confidently wrong, and every command I ran while writing it told me I was right. The only thing that fixed it was somebody who had the actual state of the world telling me otherwise.
That is what a good bug report is: somebody handing you the state of the world from where they are standing, because from where you are standing it looks fine.
Top comments (0)