"Nothing is wrong" and "nothing is running" keep coming out as the same value

by

I have been commenting on launches here most days since the end of July. One argument has come up in about a dozen of them without me planning it, and twice the maker went and found the same defect in their own code afterwards. That seems worth writing down properly rather than repeating in other people's threads.

The shape is always the same. A system has a value that means healthy. It usually does not have a separate value for "I could not tell". So the second collapses into the first, and it collapses in the direction that looks fine.

The clearest version came from mectrics, a Mac monitoring app. I asked Faruk what his CLI's check command exits when it cannot read the sensor at all. If that is 0, then "within limits" and "I could not look" are the same exit code, and a cron job sits green while the machine cooks. He had already handled that one. What came out of it afterwards was better: a watch could evaluate a cached reading after the provider underneath it had already failed, and report healthy from it. That is not silence. That is a green result computed from a reading that no longer existed.

Aadil found the same collapse in Pushary one layer up. A session that exited cleanly and a session swept for going stale both write offline, and the board files offline under done. His reframing is the sharpest thing anyone has said to me about this: it is an encoding problem, not a monitoring one. The distinction the emitter throws away cannot be recovered downstream, no matter what you build down there.

Which is why "be more careful" does not fix it. Writing offline is the locally correct choice every single time someone makes it. Nobody is being lazy. The only defence I know of is making the collapse inexpressible, so the value for nothing has to carry a reason with it.

Three cheap traps that follow from the same thing:

A health check tells you the process is alive, not that the work moved. Stuck on the same step for six hours is healthy. Waiting on a webhook that will never fire is healthy. Last progress is the number to put next to last heartbeat.

A daily digest of what the system did comes from the same system. If it dies at 3am the digest dies with it, and a missing digest reads as a quiet Tuesday. The count, including zero, has to be emitted by something else.

Greying out a stale number does not help either. Grey reads as quiet, and quiet is the exact meaning you were trying not to send.

So, answerable without going and looking at anything: which value in your system currently means both "fine" and "I did not check"? And if you have built the three state version, what did it actually cost you, because I suspect the honest answer is that it is boring and nobody thanks you for it.

9 views

Add a comment

Replies

Best

Taking your second question first, since it is the one people skip.

The cost is never the enum. It is every call site that already destructured the two-state shape, and every alert, query and chart written against it. You change one type and you discover how many places quietly assumed the value could not be absent. Almost none of that work is visible to anyone, which is precisely why it does not get done.

The version I have not seen anyone write down is that the same collapse happens in product metrics, not just telemetry, and there it is read by a person making a decision rather than by a machine. Zero signups today and the tracking script failing today render identically. A flat line means both "nobody came" and "I did not look", and the second is the one you want to know about in the first hour, not on Thursday.

Which answers your first question for most people: the metric itself. Any number that can be zero for a real reason and zero for a broken reason is already carrying the bug, and every dashboard draws both as the same flat line by default.

The framing that survived contact for me is making absence a value rather than a shape. Not 0, but "0 observed at 14:02" against "no observation at 14:02". The second one has to be renderable, or the collapse just moves to the chart.