Picture a shop with one of those signs in the window that flips itself to OPEN on a timer. It's a tidy idea. Nobody has to remember to turn it over each morning; the clock does it. The staff arrive, the lights come on, the first customers wander in, and the sign out front announces the place is open for business. Nobody has to touch it.
Now move the shop's opening time an hour earlier and forget to tell the timer. The staff are inside. The lights are on. The till is ringing. And the sign in the window still says CLOSED, because the only thing it knows about is the old schedule. Passers-by glance at the sign, take it at its word, and keep walking, past a shop that is very much open.
That sign was a church's website, one Sunday morning.
What the church asked for
We build for a church that streams its Sunday service online. Plenty of the congregation watch from home, or from another town, or from another country. So the brief was simple and reasonable: when the service starts, the "watch live" page on the website should switch itself on. No volunteer logging in to flip a switch at the exact right minute, no dead embed sitting there an hour early, no scramble if the person who usually does it is away. The page should just know.
We built exactly that. When the stream goes live, the page notices on its own and starts showing it. For weeks it worked the way it should.
The Sunday it stayed dark
Then one Sunday the service time moved. It had been running later in the day; the church brought it forward by an hour. An ordinary change, the kind any congregation makes.
The service started at its new time. The stream went out. People at home opened the website to watch.
The page said nothing was live.
Everything that mattered was actually working. The camera was rolling, the stream was up, the broadcast was genuinely happening and anyone with the direct link to the stream could see it. The one thing that failed was the one thing the congregation actually used: the page that was supposed to flip itself on stayed dark, right through the service.
The time was written in two places
Here is what had gone wrong, in plain terms.
The page didn't decide to go live by watching the clock against the service schedule. It went live inside a separate "expect a stream around now" window: a second note, kept apart from the service times, that effectively said the service is roughly between these hours, so a stream is allowed. While that window matched the real service time, everything lined up and the page behaved perfectly.
When the service moved an hour earlier, the service schedule got updated. The window did not. So at the new start time, the page checked its window, saw that "now" fell outside the hours it had been told to expect a stream, and did precisely what it was built to do: it left the page off.
The system wasn't broken. It was obedient. It had two records of the same fact (when the service happens) and we had only changed one of them. The page trusted the one we forgot.
When one fact lives in two places, you don't have a backup. You have two things that are about to disagree, and a quiet morning when they finally do.
The fix, and the fix behind the fix
The immediate fix took a minute: correct the window so it covered the new time. The page came to life on the next check, and the next service ran without a hitch.
But the minute-long fix isn't the lesson, because it leaves the trap fully armed. The time still lived in two places. The next schedule change (and churches change their schedule) would walk straight into the same wall, and we'd be back correcting the same second record by hand, hoping we remembered.
The real fix is to delete the second copy. The service schedule should be the single place the time is written, and the "go live" window should be worked out from it automatically. Change the service to an earlier hour in one place, and the window that drives the live page moves with it, because it was never a separate fact to begin with. It was the same fact, read twice.
What travels out of this
None of this is specific to a church, or to video.
If a fact lives in two places, one of them is wrong and you don't know which yet. The service time, the price, the deadline, the address: the moment the same thing is typed into two systems, you've signed up to keep them in sync by memory. Memory loses.
An automatic switch is only as good as what it reads. "It turns itself on" sounds like one less thing to worry about. It's really one more thing pointed at a record you now have to keep honest. When it's wrong, it's wrong silently, because the whole point was that nobody was watching it.
The dangerous failures are the ones where nothing breaks. No error, no alarm, no red light. Every part did its job correctly against the information it was given. The fault was in the shape of the information, not the working of the machine. That kind of fault hides from every health check you own.
The honest opinion underneath it: "it'll switch itself on automatically" is a feature you should be slightly suspicious of, including when we build it. Automation doesn't remove the work of keeping a fact true in one place — it just moves that work somewhere you can't see it until the morning it bites. The win isn't the clever switch. The win is having one clock that everything else obeys.
For the technical reader
The watch page is a static site (Next.js, exported and served from Cloudflare Pages). It reads its live state from a single row in the database (Supabase / Postgres) rather than anything baked into the build. At build time, the site bakes in the database's public URL and anon key, so the browser reads the live state directly on each visit.
A small poller runs server-side every couple of minutes. It calls the streaming platform's API (the YouTube Data API) to ask whether the channel is live and, if so, for the current video id, and it writes that answer into the live-state row the page reads. That's the mechanism behind "the page notices on its own."
The guard that bit us is deliberate and worth keeping: the poller only acts inside a scheduled broadcast window, and it will revert a manual flip made outside that window. Without it, a "live" state set by hand (or left over from a previous stream) would stick on the page indefinitely. The window stops a stale signal lingering for days. The cost of that safety is that the window has to be correct, and the window was maintained as its own record, separate from the session schedule. Move the service from one hour to another in the schedule, leave the window pointing at the old hour, and "now" falls outside the window: the poller correctly declines to go live. No error is raised, because nothing erred.
Remediation was to correct the window. The durable fix is to derive the window from the session schedule so there is exactly one source of truth for the service time; a hand-maintained window is a second copy waiting to drift.
There's a second instance of the same anti-pattern in the same system, which is what made the lesson land. The displayed schedule is a merge: a static bundled sessions file overlaid with the live database row, matched on start-time. The live row supplies the timing and state; the static file supplies titles and speakers. Edit the time in only one of the two and you don't get an error either. You get a mismatch, or a duplicate card, because the matcher no longer pairs them up. Same disease, same module: one fact, two homes, no warning when they part ways. The cure is the same in both places: make one record authoritative and have the other read from it, rather than asking two records to stay polite.