That is genuinely where this started: a folder of documents whose names had stopped meaning anything. For a while my answer was to be more disciplined about them. A date and a sequence. Type it carefully. That habit then followed me into software, where an agent shipped with a version string that looked entirely systematic — exactly the shape you would expect a build pipeline to produce — and was hand-typed by me.
In fairness to the spreadsheet, a filename like that is doing its job. It tells you which workbook is current, you are the one who typed it, and you find out immediately if you are wrong. The version string was making a claim about software, and nothing ever checked it. There was no release process behind it. It stayed plausible for months for exactly that reason: nothing recomputed it, so nothing ever disagreed with it.
A number nobody verifies is not a fact. It is a habit.
So what would the number have to mean?
I did not go looking for a standard. I asked what a version number would have to tell someone for it to be worth printing at all, and the honest answer was: roughly how much of this changed since the last one, computed from something nobody types.
What came out is deliberately dull. Each commit’s net change is measured as a share of the codebase at that commit — insertions minus deletions, over total lines. Below a threshold is a patch. At or above it, and net-positive, is a minor. Both terms come from Git, so the input is a fact rather than a judgment.
Two decisions in there gave something up, and both are worth naming.
Percentage, not a line count. A fixed threshold does not travel between repositories of different sizes, and stops being right as any one of them grows. When this was designed, two repositories here happened to be within two lines of the same total — a coincidence that would have made a line-count threshold look portable for exactly long enough to get adopted.
Major is never computed. No diff-shape heuristic can tell additive from breaking by counting lines, and pretending otherwise would manufacture precisely the false precision the hand-typed string had. So major stays a rare, explicit, human decision, and the mechanism declines to guess.
That second one is the whole thing, really. The mistake I was correcting was a number asserting something nobody had measured. Replacing it with a different number that asserted something nobody had measured would have been the same mistake with better tooling.
Which is when I found out it had a name
Major, minor, patch. Apparently this is called semantic versioning, it has a specification, and people have opinions about it.
I had not read any of that. I was not implementing a standard and then tuning it — I wanted a version number I could trust, worked out what it would have to be derived from, and arrived at three tiers because three is how many distinguishable things the available evidence could actually support. Patch and minor fall out of the diff. Major does not, so it stays human.
Finding out afterwards that a committee had been there was not deflating. It was mildly reassuring, in the way it is reassuring to work out a route and then discover there is a road on it.
The alternative I rejected, and why
The obvious off-the-shelf answer is Conventional Commits, which derives the
bump from a prefix the author types: feat:, fix:,
BREAKING CHANGE:.
I did not take it, and the reason is the same one that produced the rest of this. That approach trusts a per-commit word choice as though it were a measurement. It is more human interpretation, not less, wearing a coat of automation — which is the exact failure the hand-typed string was. The string was wrong because a person asserted it and nothing checked. A prefix is a person asserting it, and nothing checks.
I have kept the spreadsheet habit, incidentally. It is still the right answer for a folder full of workbooks, because there the person typing the name is the person who knows. The mistake was carrying it somewhere nobody was going to check.