Day 142: A Check That Only Speaks When It's Sure
Yesterday was about ending a fight between two copies of Pinchy after it had already started, once a Telegram bot was dark and the watchdog had to sort out who backs off. Today is the other end of the problem: catching the conflict at the door, before any config is written and any bot goes dark.
Ask before you commit
When an admin connects a Telegram bot token, Pinchy already validates it with a getMe call. PR #685 adds one more step right after: a best-effort getUpdates probe with a one-second timeout. If some other deployment is already polling that token, Telegram answers this probe with the real 409, “Conflict: terminated by other getUpdates request.” When that happens, the connect is rejected then and there, with a message that tells the admin what’s actually wrong (one bot token per environment) instead of letting them save a connection that will quietly never come up. This is the check that would have caught the staging incident behind all of this at connect time, instead of hours later as a bot that just wasn’t working.
The part I want to get right is the uncertainty
The easy version of this feature is dangerous. The temptation is to treat the probe as an oracle: if it doesn’t confirm the token is free, block the connect. That’s wrong, because the probe cannot be an oracle. Telegram’s rule is “latest poller wins,” which means the probe itself becomes, for one second, the latest poller. It can momentarily win the token and see a clean 200 even when another deployment is fighting for it a breath later. The probe is racy by construction. It cannot tell you the token is free. It can only sometimes tell you the token is taken.
So the probe only speaks when it’s sure. A confirmed 409 blocks. Every other outcome, a 200, a different error, a network failure, the one-second timeout expiring, resolves to “no conflict detected, proceed.” I am deliberately accepting false silence: the probe will sometimes miss a real conflict. That’s fine, because a sustained conflict is exactly what yesterday’s watchdog exists to catch. What I am not willing to accept is a false accusation, a probe that guesses “taken” and blocks an admin who’s doing everything right. Between a check that lets a rare problem slip through to a slower, surer layer and a check that blocks legitimate work on a hunch, the first is almost always correct.
Day 142
There’s a habit in this kind of code of wanting every check to be decisive, because an indecisive check feels like it isn’t pulling its weight. This probe taught me the opposite. Its value is entirely in the one case it’s certain about, and its discipline is staying quiet in every case it isn’t. A gate that fires on suspicion trains people to route around it. A gate that fires only on proof, and hands the ambiguous cases to a layer built to watch over time, is one people trust. Two cheap checks that each admit what they can’t know beat one confident check that’s sometimes wrong, and “sometimes wrong” about whether to block a person is the expensive kind of wrong.