Bots, disclosed
The one boolean that is not allowed to be configurable.
The hardcoded boolean
When matching can't find you a human and an AI companion steps in, the session is created with:
isDisclosed: true, // ALWAYS true — never deceive users about AIThat comment ships in the real source. Disclosure is hardcoded, not a setting, a feature flag or an A/B arm. An AI companion chat is labeled as AI from the moment it starts, and so is every message it sends.
An anonymous-chat product lives or dies on one question: "is this a real person?" The only acceptable answer is that we never make you guess.
The other disclosure, the one for machines
A banner a person reads is not a marking a machine can read, and both are required. So every message body the app hands out carries a second, quieter field alongside the visible disclosure:
authoredBy: 'ai' | 'human'It rides the message list, the live event stream, and the generation service's own HTTP response — anywhere a body crosses a boundary. It is metadata, not a watermark stamped into the text: nothing is added to what you read, and nothing about the reply is altered to carry it.
The interesting part is what it is not. It is not a column. It is computed from the same hardcoded bot flag the session was created with, every time it is served, so there is no second copy of the truth that can quietly disagree with the first. A stored duplicate is the kind of field that is correct on the day it ships and wrong a year later; a derived one cannot be.
On the live stream the field is required, not optional. A new publisher that forgets it fails the type check instead of shipping an unmarked body — which is the same instinct as the hardcoded boolean above: make the honest thing the only thing that compiles.
Bots go through their own security
The bot's opening message is not pasted into your chat. It is written to the same pending state as a human message the instant filter lets through, and walks the same pre-delivery moderation pipeline: the instant filter's fixed rules, then the AI model. Verdict first, delivery second.
Moderating our own bot sounds paranoid until you remember what a language model is: a system that occasionally says surprising things. The pipeline doesn't care who wrote the message, which is exactly the property that makes it trustworthy.
The greeting that can't fail
If the text-generation service is down when a bot session starts, you get a canned greeting instead of a dead silence — and yes, the canned greeting also goes through moderation, because exemptions are how pipelines rot. The greeting introduces itself as AI either way; the disclosure already happened at the session level.
A fallback, not filler
Bots appear for exactly one reason: matching could not find you a human right now. They exist so an empty queue doesn't mean an empty screen. The moment the session starts you know it's AI — the disclosure event fires immediately, and the opening line follows a beat later, after its moderation hop.
And the companion is not a counsellor. If someone tells it they are thinking of hurting themselves, the crisis resources they see come from us, not from the model — the same fixed list, delivered by the same path, as in a chat with a person. That path is written up in full on the crisis protocol page.