Defects That Raise No Error
Clipped toasts and trees hidden behind landmarks threw no errors. Instead of fixing each one, I fixed the container and measured what is seen, not what exists.
Most defects leave a trace somewhere. An exception is thrown, a test goes red, a line appears in a log. Some leave nothing at all: a sentence cut off at the edge of the screen, an object hidden behind another drawing. The code finished normally and every value is where it should be. It just never reaches anyone's eyes.
I ran into this kind twice in HappyBirthTown, a birthday gift in the form of a small pixel town that friends grow together. Once it was notification copy, once it was the trees friends plant. Both times the first fix that came to mind was to repair what I had noticed, and both times I learned that it would not stop there.
Three by eye, twenty-seven by ruler
The product shows short notifications, toasts, that appear at the bottom of the screen and fade. For a long time they were fixed to a single line. Anything longer than the screen was clipped at both ends, and because nothing raised an error, nobody knew until that exact message was shown on an actual phone. I caught it by accident while measuring the copy for a new feature.
At first I found three clipped messages and assumed that was all of them. Then I pulled every toast string out of the source and measured each at phone width. Twenty-seven of 157 were already clipped, one of them the final message that closes out the day. I had found three by eye and believed I had found them all.
Defects like this are always underestimated until they are counted. Raising no error means nobody counts them, and what nobody counts seems to exist only as much as it has been noticed.
I fixed the container, not the copy
I could have shortened the twenty-seven, one by one. That is a losing fight. Fix twenty-seven and the next feature brings the twenty-eighth. If every person writing copy has to work out phone width in their head, something will eventually overflow.
The root was not in the copy anyway. The toast box was laid out to start from the middle of the screen, so it had only half the width to work with from the beginning. I stretched it across, made it a pill when the message fits on one line, and let it fold to two when it does not. Messages that joined two pieces of news with a middle dot were split into two toasts, since toasts stack vertically.
Then I added a ruler: a check that collects every toast string in the source, measures it at phone width, and goes red past two lines. Fixing the container removes today's twenty-seven. The ruler catches the twenty-eighth the moment it arrives. Either one alone does not hold.
"It stands" and "it shows" are different checks
The gift recently became a growing town. When a friend leaves a letter or a photo, a tree goes up in their name, and it grows as people look after it together. There are twelve maps, each with its own tree shapes. Once the feature was built, I opened all twelve again, one by one.
Everything worked. But trees in twenty-three spots were hidden behind landmark art — a king cherry tree, the Eiffel Tower, a Ferris wheel. Freshly planted saplings were smaller than the characters and their name tags, so even the person who planted one might not have known it was there. The automated checks passed, because what they verified was "a tree stands at this spot", not "a tree can be seen".
I moved the trees, not the landmarks. A landmark is the face of its map; move it and the map stops being that map. Saplings now start out taller than a person. And "not hidden by the art in front of it" became a two-layer check: one computed from coordinates, one run against the screen as actually rendered. When a map changes, one of them fails straight away.
Measure where a person looks
Set side by side, the two cases have the same shape. The data was right. The copy was correct, and each tree stood at the correct coordinates. What failed was the last stretch, where that data arrives at someone's eyes, and every existing check stopped just before it. The defect in A Silent Fallback Becomes a Silent Lie at least swallowed something inside the code. These did not even do that.
In a product built on participation, that last stretch is expensive. When the trace a friend left disappears into the background, the reason to take part quietly bends, and the bend never shows up as an error on any dashboard. I now treat the distance between "recorded" and "visible" as part of the feature itself.
Two things came out of these defects. Don't fix the cases; fix the container that produces them. And don't measure whether something exists; measure whether it can be seen, from where a person is looking. Only with both in place did what I fixed stay fixed.