Note · operations
The Job That Paged a Human to Say It Had Nothing to Say
A cron job that forgot to write its own outcome file paged a human to announce it had nothing to report. That forced a rule: only what a human can act on reaches Slack, and exactly one line of code is allowed to decide.
- Written by
- Corey
- Published
- 07/09/2026
You already have a channel like this.
A Slack channel, an inbox filter, a PagerDuty rotation. It used to matter. Now you have it muted, or set to notify without sound, or you just check the dashboard directly when something feels off and let the channel scroll past unread. Nobody built it to be ignorable. It got that way one reasonable message at a time.
Every notification system starts useful and ends up ignored, and it always happens the same way: by asking a human to read something they cannot do anything about.
We built one of these on purpose, over months, one small automation at a time, and it worked exactly as designed right up until it didn’t.
Every job we run posts to Slack when it finishes. What it did, what it found, what it fixed. That sounds responsible. After enough months it reads as noise with excellent production values.
What actually happened
Each job wrote a small file when it finished: closed, filed, failed, blocked. A separate script read that file and turned it into a line in Slack. Sensible split. One job does the work, one reports it, and you can add a hundred more jobs without teaching each one how to talk to Slack directly.
The failure wasn’t in any single message. It was in what a healthy day looked like: dozens of cheerful green lines, “closed 3 issues”, “filed 2 tickets”, “scanned 14 repos, nothing to do”. All true. All harmless. All completely indistinguishable, at a glance, from the one line that actually needed a person.
Then a job forgot to write its file. Not a loud failure. It just skipped that one piece of bookkeeping on the way out. The reporting script read nothing, decided that meant nothing had happened, and posted “ran and declared nothing” into a channel a human reads.
A script paged a person to announce its own confusion. That is the whole incident. Nobody’s data was wrong. Nobody’s job actually failed. A filing error rang a bell that was supposed to be reserved for things only a person could fix.
The rule, stated plainly
The instruction that ended it was one sentence: “I should only be notified of outcomes or fails that need me to fix something. If you can fix it, you fix it.”
Read that twice, because the obvious half isn’t the useful half. “Only tell me what needs me” is what everyone already believes about their own alerts. The useful half is what it rules out. Success isn’t news. Failure isn’t news either, unless the fix genuinely requires a human hand. A job that fails and gets auto-repaired, or auto-filed as a tracked ticket, has nothing to say to a person. Silence is the correct report.
We made that binary, on purpose. Every outcome now falls into exactly one of two buckets. Something only a human can act on - a login only they hold, an identity check, a decision that commits someone’s name to something - and it reaches Slack. Or the system already handled it, in which case it’s written down somewhere a person can look when they choose to, and nothing pages anyone.
Where the discipline actually has to live
The part we got wrong first was assuming a rule like that could live in each job’s own judgement. It can’t, for the same reason a speed limit can’t live in each driver’s judgement. Every script that’s allowed to post to Slack directly is a place the rule can be followed correctly for months and then quietly broken by whoever writes the next one without reading how the first forty behaved.
So the rule doesn’t live in judgement any more. It lives in one function. Every job writes its outcome to a file, full stop, no exceptions. Exactly one script is allowed to touch the notification API, and it fires on precisely two conditions: a declared human-only blocker, or an explicit flag a job sets when it genuinely can’t decide something itself. A test asserts that count stays at one code path in. The next script that wants to shout at a person has to go through the same gate rather than invent its own.
The channel went from a wall of green ticks to something close to actual quiet, most days. That’s the whole point of the fix. A channel that says nothing actionable is exactly as broken as a channel that never stops talking, and it breaks the same way: it trains the reader to stop opening it, right up until the day something in it genuinely mattered.
What to check in yours
The test isn’t “was this message accurate.” Every line in our old channel was accurate. The test is: could the person reading this exact line do anything different in the next five minutes? If the honest answer is no for most of what your channel says, you already have the failure we had.
You just haven’t yet had the job that forgets to write its own file and pages someone to announce it.
Where this stops working
- It assumes every outcome can be sorted into 'a human can fix this' or 'the system already handled it' at the moment it happens. Some failures are genuinely ambiguous, and a policy that defaults ambiguous cases to silence risks quietly under-alerting a new failure mode nobody has seen yet.
- It only works because one script is the sole path to the notification channel. The moment a second script gets its own direct line out - a webhook added under deadline, a one-off debugging alert someone forgets to remove - the same noise comes back through the side door.
- It does not make a bad failure message good. A human-only alert that fires correctly but reads like a stack trace still fails the reader; the binary rule stops the wrong messages arriving, it does not write the right ones for you.
More notes
- Every fault got its own ticket. That was the fault.A machine-detected fault used to become a GitHub issue the moment it happened, which scattered one recurring problem across dozens of tickets and made it impossible to tell what was actually recurring. Now a fault has to happen on three separate days before it earns one.
- Your About Page Describes A Company You Have Already LeftThe public pages nobody touches keep describing the company you were when you last wrote them. Here is the ten-minute check that finds the gap, and what we found when we ran it on ourselves.