Why a twin, and not a switch
I built the CFU Calculator first, for bacteria. Then I went back to the bench, counted plaques instead of colonies, and reached for it out of habit — and it worked. Of course it worked. A plaque and a colony are both one countable thing on a plate. The arithmetic has no idea which one you are looking at.
So the obvious move was a toggle. One tool, a little switch marked CFU/PFU, and the labels change. I sat with that for about a day, and then I built a separate tool instead, which deserves an explanation because on paper it is the worse engineering decision — two files that could drift apart, when one would do.
The reason is that they are not the same job at the bench, even though they are the same sum. Phage titration has the spot assay, which brings its own countable window and its own plating volume, and which the bacterial version has no business defaulting to. When you open a tool to type in plaque counts, every default should already be a phage default. A toggle means the tool is briefly wrong every time you open it, and you have to remember to correct it — which is precisely the class of small habitual error the tool exists to remove.
A toggle is a question. A separate tool is an answer.
What I did do is refuse to let the arithmetic fork. The function that turns a count into a titer is character-identical across the CFU Calculator, this one, and the titering module inside Dilution Designer. Same expression, same guard clauses, same treatment of zero. If I ever find a bug in it, I want the fix to be the same edit in three places rather than three different judgement calls made months apart. The export schema is shared for the same reason: whatever you point at the resulting spreadsheet does not need to know which assay produced it.
And this tool stops early, deliberately. It gives you a titer, a mean and a spread. It does not do efficiency of plating, it does not compare a permissive host against a restrictive one, and it does not run a statistical test — all of which are real phage questions, and all of which already live in Dilution Designer's Titering & EOP module, where an experiment can hold host conditions and a switchable reference. This is the thing you open with a stack of plates and five minutes. That one is the thing you open when the experiment is the point.
As with the others: the science and the design calls are mine, the engineering I did alongside Claude. I am a scientist who has gotten good at building tools with AI, not a career software engineer, and saying so plainly costs me nothing. It also means the honest failure modes get written down — the CFU write-up carries a post-mortem on a unit-display bug that turned microlitres into millilitres in every table I had built, which is the kind of thing you only catch by looking at what actually rendered.