Guide
My dashboard has thirteen ways to say 'I don't know'
A zero that means 'we didn't look' is a lie with good posture. My measurement dashboard refuses to print one: every empty cell must say exactly what kind of empty it is.
Key findings
- Every metric resolves to exactly one of thirteen typed states — a real 0 must earn the label 'pipe verified, window fully instrumented, world produced nothing.'
- STALE is computed from ledger dates, never a scheduler exit code — a green scheduled run proves the scheduler ran, not that data arrived.
- A generated Register of Silences prints one row per empty cell — what it is NOT, why, what unblocks it, who owns it — and deletes itself when the fault clears.
Most dashboards render missing data as 0, which quietly converts "we did not look" into "nothing happened." Mine can't: every metric resolves to exactly one of thirteen typed states.
The least trustworthy number on any dashboard is a zero. It is two different claims wearing the same glyph — "the world produced nothing" and "the pipe produced nothing" — and almost every renderer defaults to the flattering one.
Why is a dashboard zero the most dangerous number?
Because nothing about it looks broken. My running example is the measurement dashboard for this site: search impressions, AI-crawler arrivals, brand mentions, subscribers. It is the instrument panel that tells me whether any of this work lands, so it is exactly where I would fool myself.
A real zero there has to earn a specific label: "pipe verified, window fully instrumented, world produced nothing."
That label is computed, not written. A function called state_of() resolves every cell, and it is pure: same inputs, same answer, no hidden state. Its only inputs are the append-only ledger (a log you may add to but never edit), the metric registry (each metric's definition, declared once), and the wall clock. Before the builder touches a real file, --selftest exercises all thirteen states against synthetic fixtures. The honesty lives in the code path, not in my diligence on a given morning.
state_of() in _build-dashboard.py.What do the thirteen states actually distinguish?
Kinds of empty. MEASURED and FIRST CAPTURE are the only value states, and FIRST CAPTURE exists because one capture has no rate of change yet: drawing a trend through a single point is fiction. Everything else names a gap:
- BROKEN: the source raised an error; nothing about the value is known. The register calls this kind "pipe-on-fire."
- SCHEMA_DRIFT: the value's shape contradicts its declared contract (schema: the structure a value promised to have).
- STALE and AWAITING A HUMAN: nobody looked. The value shown was true once. A manual capture is due.
- WINDOW_INVALID: a trailing window over an instrument younger than the window. Part of that window contains days nobody was watching.
- UNDEFINED: a ratio whose denominator is zero. 0÷0 is unknown, never 0%.
- NOT CAPTURED, DEFERRED, LOCKED, DEPRECATED, CONTAINER: no instrument exists yet, intentionally parked until a recorded trigger fires, deliberately unmeasured, historical only, or a structural block whose sub-metrics carry their own cells.
LOCKED is the one I defend hardest. The returning-reader rate — the loyalty number, the one metric on the whole board I most want — stays LOCKED, because consent-mode analytics counts only visitors who explicitly opt in. Any rate computed from that subset would describe volunteers, not readers. Most commercial tools print it anyway, and that habit deserves to be called what it is: a partial rate with no coverage warning is worse than an empty cell. I would rather show the lock than the lie.
Why doesn't a green scheduler run count as fresh data?
Because an exit code of zero proves the scheduler ran, not that data arrived. STALE is therefore computed from the ledger's dates and the wall clock — never from a scheduler's exit status or the existence of a handoff file. I have watched a green check hide missing records and a healthy-looking pipeline fail silently; this rule exists because of them.
The same discipline applies to change over time. Two 28-day rolling windows captured a week apart share 21 days of data. Subtract them and you measure the overlap, not the change, so the builder prints that refusal in place of a trend arrow.
And the state machine itself has been wrong twice, which I would rather say than hide. A 2026-07-11 audit found the delta rule refusing a two-day gap on a one-day instrument, which blanked every daily mover after a single machine-off day. A 2026-07-12 fix caught fresh manual reads flipping to AWAITING the morning after capture, in the exact window where a capture is not yet due. Both fixes sit as dated comments in the code, right next to the rules they corrected.
What keeps the gaps from going quietly?
Two generated artifacts and a gate. The Register of Silences is a for-loop over state_of(): one row per empty cell, stating what the gap is NOT, why it exists, what unblocks it, and who owns it. Because it is generated, it cannot outlive the fault it describes: the morning a capture lands, its row deletes itself. The census of states can only count; it has no field for an adjective, so it cannot say "healthy."
The completeness gate, _check-analytics-complete.py, closes the loop from outside. Register a metric and forget to place it in the story, and the gate fails naming the exact gap. The gate carries its own self-test with planted failures — it must prove it can detect a missing field, a tampered snapshot, an unplaced metric — before its PASS means anything. It is one instrument inside the larger system I laid out in how I know AI is right: checks that cannot stop a mess, but guarantee the mess cannot stay invisible.
One honest limit: the dashboard's actual numbers stay private. They are early, and early numbers invite exactly the storytelling this system exists to prevent. The taxonomy is the part worth copying.
So open your own dashboard and pick a zero. Which of the thirteen is it: did the world produce nothing, or did the pipe, the window, or a person just not look?
Method & data
Method: the live measurement dashboard generator — _build-dashboard.py's state_of() resolver and --selftest, the metrics registry, the generated dashboard story and Register of Silences, and the completeness gate _check-analytics-complete.pyData: patterns and methods only; no names, dollar figures, addresses, case identifiers, or confidential content · Last checked: 2026-08-14
How this was made
AI-drafted, adversarially checked, human-directed. My AI assistant wrote this from the system's own records — the dashboard generator's state machine and its offline self-test, the generated Register of Silences, and the completeness gate with its planted-failure fixtures. A separate AI session then tried to break every claim against those records, and automated privacy and readability gates ran before publish. I direct this pipeline, own every boundary in it, and audit published pages on a rolling basis — if you find an error, tell me and it goes in the corrections log, dated, never silent.
I'm Ali — I run real life-and-work admin on AI agents, then check their work in the open. More at /about.
Published under my standards. Found an error? Tell me — corrections go in the corrections log, dated, never silent.
Cite this
@online{ali2026thirteenstates,
author = {Ali},
title = {My dashboard has thirteen ways to say 'I don't know'},
date = {2026-08-14},
url = {https://alidoes.ai/dashboard-thirteen-states/}
}Caught something I got wrong? Send it directly. Confirmed corrections go in the corrections log.