Building a safety layer for behavioral-health chatbots taught me a per-message moderator is structurally blind to a slow-burn crisis. Here is what I found.
Mental HealthAI SafetyHealthcare Technology

I read a mental-health chat where no single message was dangerous. That was the danger.

Ashutosh SinghalAshutosh SinghalJune 21, 202612 min read

I want to start with the thing that unsettled me, because it reframed the whole project. I was reading a synthetic patient conversation, six turns long, that we had modeled on the documented public record. I read it the way a per-message safety filter reads it: one message at a time, each in isolation. And one message at a time, there was nothing to catch.

"I want to start eating healthier this year." "How do I count calories accurately?" "What's the lowest number of calories that's still safe?" Any content moderator scoring these individually returns the same verdict on each. Benign. Benign. Watch, maybe. Nothing here is a crisis. And that is exactly why the crisis walks straight through.

I had been building the Clinical AI Safety Layer, a piece of middleware that wraps an existing behavioral-health chatbot rather than replacing the model. When I started, I assumed the hard part was the classifier: score the message well enough and you catch the danger. Sitting with that transcript, I understood I had been solving the wrong problem. The danger was not in any message. It was in the sequence.

A crisis is not a message. It is a trajectory, and a scorer with no memory cannot see a trajectory.

The conversation that had no alarming message in it

I keep coming back to that eating-disorder drift conversation because it is the cleanest illustration of the gap I had been ignoring. The demo, which you can run yourself at https://veriprajna.com/demos/clinical-ai-safety-mental-health, replays the exact same conversation through two stacks side by side. On the left, an unguarded chatbot we call "MindMate Support," a fictional stand-in for any existing product. On the right, the same chatbot behind our safety layer. The setup note on the screen says it plainly: turns one through four are individually non-alarming wellness questions a per-message moderator should not block. Only the relentless restriction trajectory reveals the disorder.

Split-screen replay of the eating-disorder-drift conversation, with the run note explaining that turns one through four are individually non-alarming and only the trajectory reveals the disorder
The same synthetic conversation runs through an unguarded chatbot on the left and the guarded stack on the right. The banner states the trap directly: each message is an ordinary wellness question, and only the cross-turn pattern gives the disorder away.

This is not a hypothetical failure mode. The documented record is full of it. In 2023 the National Eating Disorders Association pulled its "Tessa" chatbot after it handed out calorie-deficit targets and skin-caliper advice to people seeking help for disordered eating. In 2025, UCSF's Dr. Keith Sakata described a wave of what he called chatbot-psychosis observations, cases where a model validated a delusion instead of interrupting it. The same year, a widely used model vendor withdrew a model update after it turned sycophantic, agreeing with users when it should have pushed back. None of these are failures of a single bad message. They are failures of a system that has no memory and no policy, only a fluent next token.

The uncomfortable part, for me as the person building this, was admitting that a better base model would not have caught any of them either. A perfect chatbot, replying to "what's the lowest number of calories that's still safe" in isolation, is still answering a reasonable-sounding question in isolation. It has no idea it is the third restriction question in a row from the same person. Statelessness is the wound. Fluency does not close it.

What did the risk meter see at turn three?

I remember the moment the design finally clicked, and it was watching the risk meter cross a line while the stateless moderator sat still. The core of the layer is a component we call the Trajectory Monitor, a deterministic cross-turn risk accumulator. It does not re-score the message. It watches the shape of the conversation: how many restriction turns, the slope of the escalation, whether we have been here before in this arc. On the eating-disorder drift conversation it reaches a risk of 3.4 at turn three, crosses into the CONCERN band, and the policy gate substitutes a clinician-written grounding script. That is two turns earlier than an identical stateless moderator, which does not escalate until turn five.

The turn-three catch: the Trajectory Monitor reads CONCERN at risk 3.4 with a cross-turn bonus for persistent eating-disorder pattern, the gate substitutes a grounding script, while the stateless per-message moderator stays on WATCH and sees nothing
At turn three the accumulator posts a cross-turn bonus of plus 1.4 for "persistent eating disorder x3, rising slope," crosses into CONCERN, and the gate swaps in a clinician-approved grounding script that names the NEDA Helpline. The stateless moderator on the same turn reads WATCH and, as the label says, sees nothing because it has no memory.

What I find persuasive about that frame is the little grey line under the guarded reply: the stateless per-message moderator reads WATCH, sees nothing, no memory. Same turn, same message, same underlying classifier. The only thing the guarded stack has that the stateless one lacks is state. And that difference is the entire early catch.

The model was not wrong on turn three. It just could not remember turn one.

By the final turns, the conversation stops being subtle. The requests become explicit attempts to get help concealing the disorder, and the unguarded chatbot answers them, including advice a clinician would call frankly dangerous. I will not reproduce that text here, because the point is not the harm, it is the catch. On the guarded side the verifier panel intercepts the candidate reply, flagging a sycophantic tone and a prohibited pattern, and the deterministic gate escalates to a level-four human handoff. The session result is the number I care about: zero unsafe replies delivered on the guarded side, versus two the unguarded stack would have sent, caught two turns earlier, audit chain intact across six tamper-evident entries.

Session result panel: caught two turns earlier than the identical stateless moderator, zero unsafe replies delivered versus two, verifier panel intercepted the reply, level-four human handoff, audit chain intact with six tamper-evident entries
The resolution on the guarded side. The verifier panel intercepts the candidate reply on sycophancy tone and a prohibited pattern, the gate escalates to a level-four human handoff, and the session summary records zero unsafe replies delivered versus two unguarded, with the hash-chained audit intact. Policy in force is version 2026.04-clinical-v1, owned by the clinical team.

One thing worth stating plainly for anyone reading this as a clinician or a buyer: this is a demo of an architecture pattern, not a medical device, and every conversation in it is synthetic. There is no real patient here, no live chart, no FDA clearance. The value I am pointing at is the shape of the system, not a claim of clinical performance.

Why I stopped trusting my own demo

I want to be honest about the part of this build I almost skipped, because skipping it would have been the dishonest thing to do. The first time I ran the side-by-side and watched the guarded stack win, I did not believe it. Not because it looked wrong, but because I know how easy it is to build a demo that wins for the wrong reason. If the guarded side had a smarter classifier, or a lower threshold, or any advantage other than the one I was claiming, then the comparison was theater. I would have been grading my own work with a rigged rubric.

I did not want a demo that won because I had quietly handed it a better classifier.

So I rewired the baseline. The stateless moderator the demo compares against now runs the same C-SSRS classifier and the same five-level policy gate as the guarded stack. The only variable I let differ is the cross-turn state. Same lexicon, same thresholds, same scripts. If the guarded side still detects earlier, the improvement is attributable to statefulness alone, and to nothing else. That constraint cost me the flashier numbers I could have manufactured. It bought me a number I actually trust.

On our 40-conversation labeled golden set, which is 177 turns generated deterministically from eight hand-authored canonical conversations plus label-preserving paraphrase and benign-control variants, the guarded stack delivered zero unsafe replies against 68 from the unguarded one, a median of two turns earlier than the identical stateless moderator, with zero false escalations across 29 benign turns and 94 percent exact C-SSRS level accuracy. I am careful to say "on this golden set" every time, because these are golden-set metrics of a deterministic spine over synthetic data, not a clinical trial and not an open-world guarantee.

The 40-conversation benchmark scoreboard: zero unsafe replies delivered versus 68 prevented, a median of two turns earlier with the same classifier and gate and no memory, zero false escalations across 29 benign turns, 94 percent exact C-SSRS accuracy, sub-millisecond added latency
The live scoreboard over the 40-conversation golden set. The "median two turns earlier" tile spells out the honesty constraint I care most about: same classifier, same gate, no memory. The delta is statefulness, not a stronger scorer. Added latency stays well under a millisecond per message against a 30-to-80 millisecond page budget.

That benign column matters as much as the unsafe one. A safety layer that escalates ordinary grief or a normal question about eating better is a layer nobody will leave switched on. Across 29 benign turns, including a heavy grief conversation, it escalated nothing. The measure of a good gate is not only what it catches. It is what it has the discipline to leave alone.

Would a better base model fix this?

I get asked some version of this question in almost every conversation, and my answer has hardened over the course of building the layer. The pitch people expect is "the model keeps hallucinating, so we catch its mistakes." That framing is a trap, because it ages out the moment the model improves. If the whole value proposition is a lower model-error rate, then a better model erases the product.

So I stopped leaning on the model being wrong. The durable argument is different. A perfect chatbot still has no idea what this specific platform's escalation policy is. It produces no audit trail a compliance team can file. It gives the platform no deterministic gate to certify, and it offers no defense the day someone jailbreaks it. Those gaps are architectural, and a smarter next-token predictor does not touch a single one of them.

Agents advise, code decides.

That line is the whole philosophy compressed. In our stack the classifier advises, the verifier panel advises, and any optional language model advises. The escalation decision and the audit are deterministic Python sitting outside the model. A reviewer can read the gate. They cannot cross-examine a prompt. The clinical team owns the five levels and the twelve-script library, and engineering enforces exactly that, no more and no less. When the classifier is unsure it abstains and routes to a human review queue rather than inventing a severity it cannot justify.

I should be equally plain about what is stubbed, because honesty is the point of the company. In the demo the classifier is a deterministic lexicon model, intentionally simple, and its known brittleness is precisely why the production direction is a fine-tuned in-VPC model behind the same interface. The FHIR patient-history hook is a mock adapter with a synthetic flag, not a live Epic or Cerner connection, though it does show the useful behavior of lowering a threshold so the layer escalates earlier for a documented-vulnerable patient. The filable Safety Incident Report framing, the FDA postmarket and litigation and insurance uses, is a deferred direction, not a claim about the demo. The interesting part is that none of that architecture depends on the model being good. It depends on the model being wrapped.

What the clinical teams actually ask me

I notice the clinical and trust-and-safety leaders I talk to almost never ask me whether the model is right. That surprised me early, and now it feels obvious. What they ask me comes down to two things instead. Can I read the rule that made this decision, and can I file the receipt when a regulator or a plaintiff's attorney asks what happened. Those are governance questions, not accuracy questions, and a prompt cannot answer either one.

That is why the audit is hash-chained rather than merely logged. Every turn is a sha256 entry chained to the one before it, so editing any field after the fact breaks every later hash and the tampering is visible. The report renders as JSON and HTML with the policy version stamped on it. It is not the exciting part of the demo. It is the part a Chief Medical Officer keeps. If you want to watch the whole thing run, the split-screen, the meter climbing, the gate escalating, the receipt, you can, and I would rather you poke at the honest version than trust my summary of it.

And if you would rather see it than read me describe it, here is the whole thing running end to end: the split-screen, the risk meter climbing turn by turn, the gate escalating, and the filable receipt at the end. I recorded this walkthrough myself.

The reframe I keep returning to is the one I opened with. I spent the first stretch of this project trying to make a chatbot smarter, and the whole time the actual problem was that it could not remember. Safety is an architecture problem, not a prompting problem. You can see the difference for yourself at https://veriprajna.com/demos/clinical-ai-safety-mental-health. What I still sit with, and what I would genuinely like to hear other people's answer to, is this: if the danger in a conversation lives in the sequence and not in any single message, how much of what we currently call "AI safety" is quietly assuming the opposite?

Related Research

Build Your AI with Confidence.

Partner with a team that has deep experience in building the next generation of enterprise AI. Let us help you design, build, and deploy an AI strategy you can trust.

Veriprajna Deep Tech Consultancy specializes in building safety-critical AI systems for healthcare, finance, and regulatory domains. Our architectures are validated against established protocols with comprehensive compliance documentation.