Kyber Cypher Plain English edition
Text size Back to the full site

How does the alarm know it is not the broken one?

What you will learn

  • How to build a watchdog where silence is the alarm, rather than noise being the alarm
  • Why a phone makes a bad timekeeper, and the fix
  • Why one watcher cannot tell "it is down" from "I cannot see it", and what I have not finished building
What happened and why it matters

I put a watchdog on a phone. It sits in my pocket, checks that my machines are answering, and tells me when they are not. A watcher that lives somewhere other than the thing it watches is a genuinely good idea, and it immediately taught me two things I did not want to know.

The first problem was time

The watchdog has a dead man's switch. It is supposed to check in on a fixed rhythm, and a missed check in is itself the alarm. For days the rhythm was wrong. Not broken, wrong. Checks that should have been minutes apart were arriving tens of minutes late, in bursts, as though the phone had been asleep and then suddenly remembered.

It had. A modern phone aggressively pauses background work to save battery. It does not tell your timer that it has been postponed. It simply postpones it. So the dead man's switch, whose entire job was to be reliable about time, was running on a device that treats time as negotiable.

The fix was to have each check hold the phone awake for the few seconds it needs, so the system keeps the processor running until the work is genuinely finished.

The idea worth taking away

A night watchman who dozes between rounds still writes the same number of entries in the book. The log looks complete. The hours it covers are not the hours you think.

The second problem is not fixed, and this guide exists mostly to say so

My phone cannot reach the house. What does that mean? It means one of two things, and from where the phone is standing they look identical. Either the house is genuinely down, or my phone has lost its own connection and everything at home is fine without me.

One watcher cannot tell these apart. This is not a harder version of the same problem. It is a different problem, and no amount of cleverness inside the phone resolves it, because the phone is the thing in doubt.

What I did instead was stop pretending. The watchdog used to report that situation as "the network is down", which was a claim it could not support. Now it has a third answer that says, in effect, "I cannot reach the house from here and I have no second opinion". That is less satisfying and considerably more true, and the difference matters, because an alert that overstates its confidence trains you to ignore alerts.

What is still open

The real answer is a second watcher, outside my building and off my connection, so two observers can disagree and the disagreement carries information. If the outside one can reach the house and I cannot, the problem is me. I have not finished building that. The candidates are a small rented machine elsewhere, a friend's spare device, or a paid service whose only job is this. Each has a tradeoff I have not resolved, and that is the honest state of it today.

The log looks complete. The hours it covers are not the hours you think.

How to do it yourself

The dead man's switch pattern, the sleep problem that makes it lie on a phone, how to describe severity honestly when you do not know, and why a second watcher is not optional. The last part is a design rather than a finished thing, and it is labelled as such.

1. Build the dead man's switch the right way round

What this does: has the watcher prove it is alive on a rhythm, and makes silence the alarm.

Why the obvious way round fails: a watcher that alerts when it notices a problem becomes permanently reassuring the moment it dies.

Three beats, not one: a single missed beat is normal wobble, and alerting on it produces noise you will eventually silence, which costs you the whole mechanism.

# the watcher writes a timestamp every N seconds
# heartbeat: { at: <timestamp>, by: <which watcher> }

# something ELSE checks how old that timestamp is
# older than 3N -> the watcher itself is the problem

2. Expect the phone to postpone you, and hold it awake

What this does: asks the system to keep the processor running while the check happens, and lets go immediately afterwards.

Why: on a phone, any timer in a background program is a suggestion rather than an instruction.

Two traps. If you forget to let go, you get a battery complaint, so put the release in the cleanup path rather than after the successful case. And keeping the processor awake does not necessarily wake the radio, so a check that needs the network may still need the phone to be properly reachable. Test on a phone that has genuinely been idle for an hour, not one you just unlocked.

# the shape: take it, do the work, ALWAYS let go
hold_awake()
try:
    do_the_check()
finally:
    let_go()

3. Measure the real gaps before trusting the fix

What this does: records when each check really happened, so you can look at the gaps between them.

What a healthy pattern looks like: the same gap every time. Long gaps followed by a burst of catching up is the sleep problem, not a fixed one.

Also: exempt the program from battery saving, and then check the setting stuck. Some systems quietly put it back.

# log every beat with its real time, then read the gaps
# healthy : N, N, N, N
# asleep  : N, N, 14N, N, 9N   <- bursts after long gaps

4. Give "I do not know" its own answer, and do not colour it like a failure

What this does: gives the watcher three possible answers instead of two.

Why this is the part most watchdogs get wrong, including mine: a missing second opinion is not evidence of anything, and code that treats "no information" as "bad" will cry wolf every time your own connection hiccups.

Write the condition out explicitly rather than letting an absent witness fall through into the failure branch.

# three answers, with honest meanings
# OK      : I reached it
# DOWN    : I could not reach it AND a second watcher agrees
# UNKNOWN : I could not reach it and I have no second opinion

# and make the code refuse to say DOWN without the witness

5. Check your own connection first, and say which leg failed

What this does: establishes whether you have a working connection at all before making any claim about the thing you are watching.

What it buys: one extra request recovers most of the ambiguity.

What it still cannot do: tell a target that is down apart from a broken path between you and the target. That leftover is what the second watcher is for, and nothing else solves it.

# the order matters
# 1. can I reach the wider internet at all?  no  -> I am offline, say so
# 2. can I reach the target?                 yes -> OK
# 3. internet yes, target no, witness says yes  -> target is DOWN
# 4. internet yes, target no, no witness        -> UNKNOWN

6. The second watcher, which I have not finished

What this is: a design, published as a design, because that is what it is.

The trap to avoid: a second watcher that shares your failures is decoration. If it rides your connection, or reports through a service your first watcher also depends on, it will go quiet at exactly the moment you need its opinion.

# requirements
# outside your building and off your connection
# checks the SAME target on its own schedule
# publishes a result your first watcher can read
# fails independently, or it is not a second opinion

# candidates, and the tradeoff of each
# a small rented machine : most control, a monthly cost, one more thing to look after
# a friend's spare       : free, depends on their power and goodwill
# a paid checking service: least work, least control, another account to manage

7. Keep the known blind spot written next to the code

What this does: records the limit in plain words where the next person will find it.

Why: until the second watcher exists, this has a known blind spot, and the worst outcome is forgetting that while trusting the output.

# watchdog.md
# KNOWN LIMIT: one watcher only. UNKNOWN means cannot-see-it-from-here,
# not down. Do not act on UNKNOWN as though it were DOWN.
# OPEN: second watcher not built yet. Candidates above.
The honest catch

The timing problem is fixed and measured. The second one is not, and this guide does not pretend otherwise. A watchdog with one vantage point is still worth having. It is just not worth believing more than it can support.

Related reading: the most dangerous alert is the one that says everything is fine is what happens when a watcher fails quietly, and prove the gauge is not the broken part is the same question one layer in.

This page in the original Kyber Cypher voice: How does the watchdog know it is not the one that is broken?