The free software movement gave us two prepositions to argue over. Free as in beer: it costs you nothing. Free as in speech: you can do what you like with it. Stallman spent decades insisting the second was the one that mattered and the first was nearly a distraction, which is why the FSF ended up maintaining a page about the word “free” that runs longer than most licences.

Somewhere around the time open source started turning up in procurement meetings, a third variant appeared: free as in puppy. The software costs nothing to take home, but now it needs feeding, walking, and trips to the vet, and someone has to look after it when you’re on holiday. It was the total-cost-of-ownership argument with fur on, and it was a useful corrective because it moved the conversation from the licence to the lifecycle. I liked it enough to give a whole talk under that title at Bath Ruby in 2018, so consider what follows me retiring my own metaphor rather than picking a fight with someone else’s.

The puppy metaphor fit the era it came from, and I think it fit the point I was making then. You’d bring in one big open source thing, a database or an application server or a CMS, and your ops team would learn its habits, read its changelogs, and generally know it by name. Run npm ls --all on a moderately sized project today and that relationship is gone. A new Rails app resolves over a hundred gems before you’ve added a line of your own, a React starter pulls in well over a thousand packages, and each of those direct dependencies arrives with its own dependencies already inside it. The date picker you actually wanted accounts for about ninety of the new lockfile entries, which is roughly the point at which I started reaching for a fourth variant: free as in tribbles.

For anyone who hasn’t seen the episode, tribbles are small purring balls of fur that a crew member brings aboard the Enterprise because one of them is pleasant to have around and obviously harmless. They are also born pregnant, and Spock does the maths at one point to get 1,771,561 tribbles from a single animal in three days given an adequate food supply. They show up in the air vents, on the captain’s chair, and finally in the grain stores, which is where they reveal that the cargo the ship was guarding has been poisoned.

Each transitive dependency is a small soft thing in much the same way, a few dozen lines of someone else’s code that you will never open. The born-pregnant property is the bit that does the real damage, because the package you add already contains the packages it needs, and those contain theirs, and that chain is how left-pad ended up in the build path of most of the JavaScript world without a single team consciously choosing it. In the episode the tribbles are also what find the poisoned grain, since the infestation is the only reason anyone goes near the cargo hold.

AI-assisted scanners are now surfacing vulnerability reports faster than maintainers can read them, let alone triage which ones describe a real problem, and while some are legitimate and plenty are slop, every one of them still lands in somebody’s queue. At the same time AI-assisted coding has dropped the cost of forking to roughly the cost of having the idea. If a library mishandles one edge case it’s a few minutes’ work to fork it, have an agent patch the offending function and draft a README, and publish the result under a new name. The original doesn’t go anywhere when that happens; both versions stay in the registry, both keep getting resolved into different trees, and occasionally into the same tree at once. Registries are filling up with near-identical organisms, each with its own release cadence and its own bug surface, and you inherit whichever one a maintainer somewhere above you in the graph happened to switch to.

The puppy framing told you to budget for care and assumed you could treat each animal individually: read the release notes, run the upgrade, maybe even recognise the maintainer. That stops being practical somewhere around the point where you open a storage compartment and they pour out onto your head. At tribble densities there’s no sensible individual to start with, so you end up managing a population instead, with rules about what’s allowed on board at all and quarantine for anything that fails a scan at the transporter. The unit you reason about stops being the package and becomes the lockfile, and after that every lockfile in the org.

Most of the tooling we have was built for the per-animal case. Dependabot files a pull request per package, advisories identify one CVE in one version range of one library on the assumption you can find it in your tree and think about it in isolation, and SBOMs enumerate every tribble on board without saying much about which compartments they’ve reached. All of that was designed for a number of dependencies you could plausibly have a relationship with, and if Dunbar’s number puts that ceiling somewhere around 150, even the simplest projects are now well past it before the first feature lands.

Kirk solved his infestation by having Scotty beam the entire population onto a Klingon ship, which is a satisfying way to close an episode and not a strategy available to the rest of us. Short of that there’s quarantine for new arrivals, lockfiles so the population is at least the same one on every machine, some discipline about what’s allowed aboard in the first place, and the usual advice about not feeding them after midnight.