The report was one line: the profiles topic in one of the Telegram groups showed 144 posts, and the group had about 74 members. Somebody’s profile card was still up for every person who had ever left.

The bot that runs that group already had cleanup code for exactly this: when someone leaves, delete their card, their messages, their database rows. It had run 310 times since June. So the first assumption, that the cleanup was missing, was wrong.

[“Nobody remembers the 310 times it worked.” — the cleanup code]

Measuring against the wrong thing

The obvious first step was to compare the topic against the bot’s own database. That was a trap: the database listed 141 members for a group of 73, and only 61 profiles for a topic with about 145 cards. A database that has drifted can’t be the ruler for measuring its own drift. The real ruler was Telegram itself: the live member list, and the topic’s actual messages.

Measured that way, 75 cards belonged to people who were gone, five more were old duplicates of current members, and about 2,000 chat messages were still sitting there from 130 people who had left.

[A first scan flagged almost every card as stale. That was wrong — the list it compared against was incomplete. The member count was checked against Telegram’s own before a single delete ran.]

Why the cleanup never fired

The departure handler listened for a member whose status became left or kicked. But a newcomer who is muted until they accept the rules, and then leaves, is not reported as left. Telegram reports them as restricted, with a flag saying they are no longer a member. The handler never matched, so the cleanup never ran for them. Eight of them were still in the bot’s table when I looked.

That explains part of the drift. It doesn’t prove it explains all of it: the departure log simply stops at the start of September while joins kept being recorded. So the fix has two layers: the handler now recognises the restricted-and-not-a-member case, and a nightly job asks Telegram directly about every person the bot tracks and purges anyone who is gone. It aborts if it thinks more than 80% of people have vanished, because that would mean the check itself broke.

flowchart LR
    A[Member leaves] --> B{Telegram event arrives?}
    B -->|Yes| C[Purge card, messages, rows]
    B -->|No / restricted| D[Missed]
    D --> E[Nightly check asks Telegram directly]
    E --> C

What it cost to trust the log

The bot’s log said the cleanup worked, and it did, for every case it saw. The ones it didn’t see left no trace at all, which is the whole problem with this kind of failure: nothing is red, the numbers are just quietly wrong. The group statistics command had been reporting 141 members for weeks.

[“Nothing alerted because nothing was technically failing.” — the bot]