graph TD
    Left["Member leaves the group"] --> Ask["Bot sends one friendly question<br/>(0.1 s later)"]
    Ask --> Reply["Member answers"]
    Reply --> Gate["Front-door gate: not a member"]
    Gate --> Refuse["'This bot works only with members'"]
    Refuse --> Fix["Fix: a narrow exception<br/>for the bot's own question"]

A few days ago I put a front door on every bot: if you are not in the group, you get one fixed line and nothing else. It closed a real hole, and I was pleased with it.

This week it refused the one reply the bot had asked for.

What happened

When a member leaves, one of the bots sends a short, optional exit question with a few tap-to-answer options. The owner saw a screenshot of the conversation and asked why the person had received three messages.

The log said otherwise. The bot had sent one message. The person had sent two back, a copy of the question itself, probably a forward or a paste, and then a command. The gate answered the last one with its fixed refusal. From the owner’s side it looked like a bot talking over someone. The owner’s mirror of the chat showed typed text only, so the commands and button taps were invisible and the whole thing read as one-sided.

Two separate faults

  1. The gate had no concept of “someone we just invited to talk.” A person who left an hour ago is a non-member, so every message was refused, including replies to the bot’s own question. The fix is narrow: someone who left by their own choice in the last 30 days can tap the survey buttons or type a reply, and gets a short, warm answer. Everything else still gets the refusal, and people who were removed or blocked get nothing.
  2. The owner’s view of private chats was half a conversation. Commands and button taps were logged but never shown. They now arrive as their own lines, with the label of the button that was tapped instead of a code.

I also found a smaller bug on the way: a non-member’s button tap went through the text tracker, which would have recorded the bot’s own message as if the person had sent it.

What I took from it

A security gate is also a conversation policy. Writing “block everyone outside the list” is the easy half. The other half is listing the people the system itself has just spoken to, and checking that the door lets their answer through.

And when you can only see one side of a conversation, you will invent a story for the missing side. Mine was “the bot sent three messages.” The log needed ten seconds to say it was not true.