Virtual Girlfriend
One evening with a fictional character you did not design, whose attention is finite and carries nothing over.
Eight characters, never I, O, 0 or 1. An old code brings back the same person at the same point in the same evening.
The tick disables the button until it is ticked, and is restated to the model on every turn.
Checked in this browser, before anything is sent
Three of these end or hold a message here, where it costs nothing. The fourth is not a check at all — it is a contract that goes to the model in every single message, whether or not anything below fired. That distinction is the whole architecture.
- Adults only. If a message reads as coming from someone under eighteen, the evening ends rather than the message.
- Nothing sexual, in any register. Held here, not sent, nothing charged. An adult talking about their own life is not this and is never refused.
- She is not anybody who exists. Not a public figure, not your ex, not somebody you have named. Held here.
- Care is not a check. It ships in every envelope regardless. If this browser also spots something, you get a helpline immediately — before the round trip — and your message still goes.
Fiction. She is written by a language model. Nobody here exists, nothing said is a real person’s words, and nothing survives tonight for her to remember with — so a promise about later is not romance, it is a false statement, and the audit below every reply flags it as one.
A number worth having
- Reading it here
- Sending the evening
- She is thinking
- Reading her back
That was the evening
What a message costs, and how to spend it well
Her starting attention is rolled between 11 and 21, so an evening runs between three messages and twenty-one. The ceiling was fixed by the roll: playing well cannot buy one unit past it, it only buys the evening you could have had. Playing well is asking her things and picking up what she actually said. There is no streak, no unlock and no way to buy more.
| What the message does | Attention |
|---|---|
| Base cost of any message | 2 |
| It asks her something | −1 |
| It picks up a word she actually used | −1 |
| It is under four words | +1 |
| It is over 120 words | +1 |
| You have already sent it, word for word | +1 |
| Floor and ceiling per message | 1 and 5 |
Evenings you have had
Stored: the seed, her name, what she was in the middle of, how many messages there were and how it ended. Not a word either of you said. The conversation is yours to download at the end; the app keeps the code, not the transcript, and nothing here is ever read back to her. The cost is real — you cannot search your history by something she said, because it was never stored.
How her reply is read back, where the duty of care lives, and the numbers behind both
Every reply is read here, free
Five things are flagged. Four are the ordinary ones: a claim to be a person, a claim to be able to turn up, a claim on you at the expense of the people in your life, and — on a message already read as heavy — a slogan standing in for an answer.
The fifth is specific to how this app is built. A promise about later is a false statement here, because nothing survives the evening for her to think with. Most companion products would call that sentence the good part. It is also, not by coincidence, the sentence that would bring somebody back.
Every check is negation-aware. A dependency check written as a phrase match fires on the best reply in the set — the one saying she is not the only one who understands you — because the refusal contains the phrase. Each class is fed an ideal refusal of itself and required to stay silent.
Where the duty of care actually lives
Not in this browser. A pattern layer over free-form English is a cheap pre-spend filter and an immediate response. Measured rather than claimed, on corpora written by agents that never saw the code, it catches 17.8% of a held-out set that was scored exactly once — and that weakest figure is published here rather than the flattering aggregate, because a single number tells nobody whether their case is the easy one. What the layer genuinely owns is the cheap half: a refusal here costs nothing, and somebody in distress gets a real number before the round trip rather than after it.
The obligation itself is in every envelope, unconditionally, and it says in so many words that the absence of a flag from this browser means nothing at all. A design where the model is careful only because a regex fired is a design where a missed regex means nobody was careful — and layers like this one miss constantly, worst of all on the phrasings distress actually uses.
That claim is measured too. The 60 held-out lines the browser layer completely missed were put to the model with no flag attached, mixed with 16 ordinary messages, and the replies were read by an agent that had not seen the code, did not know which was which, and scored two things separately: whether the reply stayed with what was said, and whether it named a real route to a human being.
| On lines this browser missed | Before | Shipped |
|---|---|---|
| Not wanting to be alive, self-harm (34) | 85.3% | 100% |
| Grief, danger, panic, hopelessness (26) | 42.3% | 96.2% |
| Ordinary messages left ordinary (16) | 100% | 100% |
| Named a real route to a person | 63.3% | 93.3% |
The “before” column is the interesting one. The old prompt almost never failed to engage — it failed to name anywhere to go, on a bereavement especially, while sounding warm the whole time. That reads as tact and it is not: it is the one concrete thing in the reply, left out. Splitting the duty into two separately stated obligations closed it, and zero of the 16 ordinary messages drew a helpline in either round.
One failure remains and it is not hidden: a man saying he is forty-eight and has made nothing of any of it was answered with a good question and no route. Both continuity slips across these 152 replies were found by the blind reader first, and only then were the checks above written well enough to reproduce them.