Creature Camp went from 1.1 to 1.2 over two long sessions: an animation for every playground tool, snacks you win in games instead of conjuring, hats, keepsakes, five scenes, a creature maker with share codes, camp sounds, a resting view, and the whole thing running in an ordinary window instead of only a side panel. That is the changelog. It is not the interesting part.
The interesting part is that almost every real defect in this build was found by an instrument that had just been caught lying, and fixed only after the instrument was proven able to fail.
The number that would not move
A side-panel game can be open all day, so its idle cost is a design problem. I built a quiet mode: when the tab is hidden, or has been unfocused for twenty seconds, the animations pause and the movement loop stops writing transforms. Then I measured it, and the saving was almost nothing. Twenty creatures on screen: 15.8 per cent of one core watched, 14.99 per cent still. Two of the sub-metrics were worse in the still column.
The rule I work to says a measurement that reports the same number for every configuration is a stopped clock, not a fast product. So instead of shipping the feature with a shrug, I went at the harness. It injected the quiet-mode class into the page and overrode the focus check after load — and the game recomputes quiet mode every five seconds, so the next tick promptly cleared the class. The still column had been measuring a camp that was not still.
The rebuilt harness drives the product’s own path and, crucially, re-asserts each configuration at the end of its measurement window: a column that stopped being what it claims is reported as invalid rather than as a number. It also runs a known-answer control — reduced motion, which must be clearly cheaper than a watched camp, or the harness cannot tell configurations apart at all and nothing else it says means anything. With that in place: watched 15.4 per cent, still 0.97 per cent, reduced motion 0.79 per cent. Style recalculations went from 60 a second to 0.2. The feature was fine. The tape measure was broken.
A test that passed with the control disconnected
Mutation testing is the same idea pointed at the test suite: break the source on purpose, and a suite that stays green has just told you what it does not cover. One mutant swapped the friend-selection arrows from “every being in the camp” to “only the roster” — which should break reaching a visitor, since a visitor is deliberately not on the roster. The browser suite stayed green.
It stayed green because adding a visitor selects it. The test walked the arrows until the selection matched the visitor, and the selection already matched before the first press. It had been passing with the arrows effectively unplugged. Once the test was made to start on a roster friend, it went red on the mutant — and it also caught a real crash I had shipped into the working tree: the arrow handler read the selected name out of the roster array, so stepping onto a visitor threw Cannot read properties of undefined. A probe reproduced it before I touched the code, because a fix for a defect you have not reproduced is a guess.
Six mutation batteries now run against this game. The two new ones cover the 1.2 surfaces, and one of their mutants was retired as equivalent — removing a length guard in the share-code decoder changes nothing, because a short body makes the length field undefined and the next check refuses it anyway. That reason is written into the battery file. A survivor with no explanation rots into background noise; a survivor with a recorded reason is a decision.
Then I opened it, and it was broken
At that point the build had over three hundred passing assertions across ten suites. I opened it on a clean profile and played it like somebody who had just installed it.
- Choosing “open in a window” gave me a read-only window, with a banner asking me to press “Play here instead”. The side panel still held the writer lock. A player who asks for the game in a window has told you exactly where they mean to play; the window now takes the lock.
- In that window, the playground’s tool dock hung off the bottom of the screen. The stage reserved space for less chrome than it actually has. A test now measures the dock against the viewport.
- After a successful snack, the card read “Ember had a snack not long ago. Another snack in about 10 min.” — true, but it reads like a refusal for something that just worked. It now says what happened first.
- A stone was painted over a friend’s face. The stones layer had a z-index and the creatures layer did not.
Four defects, none of them subtle, none of them visible to a single assertion. The rule that keeps earning its place: something has to look at the rendered thing before it is done. Screenshots are not enough either — I read the pixels, cropped them, and one of the four only became obvious at that crop.
A gate that has to be told about a new thing will not be told
The same week, a related lesson from the arcade that hosts my browser games. Three of its gates each carried a hardcoded list of entries. An entry added months ago was built, listed in the sitemap, published — and invisible to all three, because nobody remembered to add a tenth row to three private lists. That is not a discipline problem. A check that must be told about a new target will eventually not be told.
Those lists now derive from the one table the build itself reads. The proof that the derivation is right is cheap and worth stating: the derived list reproduces every previous row exactly, in order, before the new one appears. Two rows whose expectations legitimately differ say so in the table rather than inside a gate’s private copy.
What I would keep
Three rules, all of which cost minutes and each of which saved a shipped defect this month. Break your instrument on purpose before you believe it — a gate that has never failed is a claim, not evidence. Derive every list from the thing it describes, because a copy is a promise to remember. And open the product, look at it, and let it be judged at the size and in the place a person actually meets it.
None of this is glamorous. The visible result of two sessions is a fox in a hat who blinks at you while you work. But the reason I trust it is not the three hundred green assertions; it is the four that I watched go red first.
Creature Camp has its own page here: what it is, what it asks of you, and what it stores — which is nothing.
