EngineeringDeep dive

Who watches the alerts?

On 18 October we found our Slack bot tokens had died and every alert since had gone nowhere. We rebuilt the path so it is much harder to fail quietly, then spent a week learning that an alert path can also fail loudly, by paging for things nobody could fix.

19 and 0, joined by an arrow, set large on a pale grey background beside 19 red P1 alert pills, every one struck through, above the words: P1 pages in ten days, and real emergencies among them: none
2independent paths for every alert: Slack and email
5 minbetween dead-man checks
19P1 alerts logged from 20 to 29 October
0of them met our own definition of P1

On 18 October we asked Slack whether our bot tokens still worked. Every one answered account_inactive. Our dead-man monitor’s own log showed the consequence: every DOWN alert it had tried to post had failed, and nothing had reached the alerts channel. The monitor had been doing its job. The last metre had not.

That afternoon we did the simple thing. The monitor fell back to email, Slack was retired as an alert channel, and every alert went to one shared inbox. Two days later we reversed half of that decision, for a reason worth spelling out: email alone gave us no priority, no way to tag a person, and no thread per incident. Slack is where we actually are. It just could not be the only place.

One relay, two paths

The rebuild on 20 October has one rule at its centre: every automated alert goes to Slack and to email, always both, as two paths that do not wait for or hide each other. Everything that raises an alert, from the dead-man monitor to CI to app monitors, posts to one relay. The relay does the rest.

SendersOne relayTwo paths and a pagerDead-man monitorprobes and silence checksCI and scriptsred builds, daily checksApps and vendorsmonitors, mail bridgeRelayevery alert has P1 to P4dedupe, one thread eachresolve with evidenceSlackthreads, mentions by priorityEmailevery alert, alwaysPhone pageallowlisted P1 onlyWho watches the pathEvery hourSlack token, channeland bot are checkedEvery Mondaya canary goes throughboth pathsEvery 5 minutesthe dead-man checks therelay, by direct emailEvery houra watchdog on GitHubchecks the dead-man
Senders post to one relay, which sends every alert to Slack and to email independently, and pages a phone only for a short list of P1 alerts. The bottom row is what checks the path itself.

Every alert must carry a priority, and the sender chooses it. P1 means production is down or wrong now: customers affected, data lost, a security incident, money wrong. P2 is degraded or at risk and needs action today. P3 needs a look this week and pings nobody. P4 is for the record. The relay de-duplicates by a key, so a fault that fires every five minutes is one thread with a counter, not two hundred messages, and a resolve lands in the same thread with the evidence attached.

If the Slack post fails, the email copy says so, marks itself as the primary copy, and the post is retried hourly. If the email fails, Slack says so. Neither path can silently take the other down with it.

Watching the watchers

An alert system that fails silently is worse than none, because you stop looking. So the path is checked in layers, each by something that does not depend on the layer it is checking.

The dead-man monitor does more than ping pages. Many of its targets are silence checks, which fire when something that should happen stops happening: TipBop has received no Stripe webhooks for too long, a dead-letter queue is filling, transactional email has gone quiet, the daily estate checks have not reported in 36 hours. A page that answers 200 can still be broken. A webhook that has not arrived in a day is harder to argue with.

Then the phones

With the path trustworthy, we wanted the important alerts to ring a phone. On 23 October P1 got its own channel and a push notification through ntfy. It failed on the first test. ntfy’s free service limits anonymous publishing per IP address, and Cloudflare Workers share their outbound addresses with everyone else’s Workers, so our first publish hit someone else’s quota and came back 429. ntfy itself cannot run on Workers, and publishing from them needed a paid plan.

The same day we switched to PagerDuty’s free plan: our own account in the EU region, push then phone call, and the alert key reused as the incident key, so a repeat or an escalation never opens a second incident. We also stopped repeats from shouting. A P2 that is still firing now re-posts every four hours instead of every hour, a P3 daily instead of every six hours.

Nineteen P1 alerts, three unplanned, no emergencies

Six days later we counted. Nineteen P1 alerts had been logged since 20 October. Three were unplanned. Two were ZooLog release pipelines failing, which meant a release did not ship while production carried on untouched. The third was a client’s site health check returning 503 because Cloudflare had an open D1 incident: the site itself stayed up, its form database errored, and nothing we could do would have fixed it.

P1 alerts, 20 to 29 October 2026

From 23 October every P1 paged the phones. None of the unplanned ones met our own P1 definition.

P1 alerts logged19Unplanned3Met the P1 definition0

Source: Estate decision log, 29 October 2026

None met the definition we had written ten days earlier. So the severities were wrong, and severity is the switch, so we fixed the severities: a failed release tag became P2, and that client health check became P2.

It took one more false page that afternoon, when the dead-man re-escalated the same check from a target list that had not yet been updated, for us to make the real change. Paging is now default-deny. A P1 always reaches the critical channel and the inbox, but it only rings a phone if its key is on a short allowlist (TipBop readiness, ZooLog’s app health, TipBop’s Stripe webhooks going silent, the dead-man watchdog, emergencies from the client portal) or a director raised it by hand. CI never pages. Third-party outages we cannot act on never page. Adding a key to the list means writing down the customer harm that justifies waking someone up.