The False Resolution Detector of a Support ChatBot (Part 1: The Diagnosis)
Chatbots are not my favorite. Especially when there’s no other way to reach a human. I won’t say all of them are stupid — even the…

Illustration by Alghozy on Unsplash
The False Resolution Detector of a Support ChatBot (Part 1: The Diagnosis)
Chatbots are not my favorite. Especially when there’s no other way to reach a human. I won’t say all of them are stupid — even the AI-powered ones — but in the majority of cases, honestly, they are. The scenario tends to repeat itself. I go to a website looking for a contact email (God forbid a phone number — I’m a millennial, I have zero desire to sit on hold for an hour), and there’s no email, no support line, nothing. Okay. What’s left? Chatbot. Fine, let’s try this. My experience with chatbots is usually far from satisfactory, which might be exactly why every airline and financial company on earth has one. Three things happen at once: I’m trying to phrase my question so the bot actually understands it, I’m calculating my odds of getting a real answer (low), and I’m wondering when I can get to a human to actually fix this. Sometimes a human isn’t even an option. I ask, I get nothing resembling an answer, and I quietly leave the website. Am I happy? Is my issue resolved? Would I recommend this company to a friend? I will absolutely tell every friend and family member how bad that experience was. So the real question is: how many customers go through this exact loop — ask, get nothing, leave silently — while the company’s dashboard still logs it as resolved?
I. Chapter: The Problem, Stated Precisely
False resolution is simple to define and easy to miss: a bot marks a conversation “resolved” without the customer’s actual problem being fixed and without anyone checking whether it was. Here’s what that looks like in practice:
Customer: My payment keeps failing when I try to update my card. Bot: I’ve refreshed your payment settings. You should be able to add a new card now. Customer: ok [Conversation ends. Status: Resolved.]
Nothing in that exchange confirms the customer’s card was actually accepted. “Ok” isn’t a confirmation; it’s the sound of someone deciding this isn’t worth pursuing further. Maybe they tried again, and it worked. Maybe they gave up and called their bank instead. Maybe they’re now looking for a competitor. The transcript doesn’t say. The dashboard doesn’t care. It just says: resolved.
That’s the gap this piece is about, not bad answers, necessarily, but unverified ones, logged as if they were verified.
II. Chapter: Why I Didn’t Start With Code
Before I wrote a single line of the evaluator, I stopped and did what I’d do with any operational failure: root-cause analysis, on paper, before touching a tool.
It would have been easy to skip this. Sit down, guess at a few signals that seem like they’d indicate a fake resolution — short conversation, flat reply, no follow-up question — and start building. But that’s exactly the move I’m trying to catch the bot making: taking a shortcut, calling it good enough, and reporting the result as solid.
So I used the tools I already trust for this kind of problem — a fishbone diagram first, then 5 Whys on a specific case — before deciding what the evaluator should actually look for. Operator first, builder second. If I got the diagnosis wrong here, no amount of clever code downstream was going to fix that.
III. Chapter: Fishbone: Mapping the Causes
Before touching any code, I mapped the problem the way I’d map any operational failure: a fishbone diagram, problem at the head, causes on the bones.

The problem statement at the head: the bot reports a resolution rate that doesn’t match what customers actually experienced. Six branches, adapted from the classic 6 Ms to fit a conversation instead of a factory floor.
1method — the bot’s resolution logic. This branch covers how the bot itself decides a conversation is over. The specific failure: a pause in messages triggers closure just as reliably as an explicit “yes, that fixed it.” The bot has no way to tell the difference between a customer who’s satisfied and a customer who’s stopped replying.
2measurement — how resolution gets logged and reported. This branch covers what happens to that closure event once it leaves the conversation. The specific failure: the number that reaches a dashboard is whatever the bot reported about itself, with no human ever sampling a batch of “resolved” tickets to check if that’s true.
3machine — the underlying model’s tendencies. This branch covers what the model does by default, independent of any explicit rule. The specific failure: faced with an ambiguous reply, the model doesn’t ask a clarifying question; it moves toward closing, because nothing about how it was tuned rewards it for slowing down.
4material — the knowledge base behind the bot’s answers. This branch covers the content the bot is actually drawing from. The specific failure: on topics where the knowledge base has no good answer, the bot still gives a confident one — no signal in its response distinguishes a well-supported answer from a guess.
5milieu — the context surrounding the conversation. This branch covers everything outside the bot itself: channel, timing, and who’s asking. The specific failure: a sensitive or urgent issue changes what “ok” means at the end of a conversation, and the bot treats every “ok” identically, regardless of what came before it.
6manpower — the human decisions upstream. This branch covers what the team was actually optimizing for when building and tuning the bot. The specific failure: resolution rate, response time, and deflection rate were the numbers used to tune the system, and nothing about “was the customer actually helped” was ever part of that loop.
Here’s the full version — same prose-first approach (no table, since Medium can’t render one), but now listing all six causes with their scores made explicit, formatted as a clean list rather than buried in narrative:
Six candidates then went into the scoring pass, each rated on two questions: how severe is this cause if left unfixed, and how often would it actually fire in real conversations. A third check — would a support ops leader recognize this instantly?
Pause/silence triggers closure: severity 5, frequency 5, instant ops nod. The only cause rated a full 5 on both counts.
No clarifying questions after an ambiguous reply: got severity 3, frequency 4, instant ops nod. A strong second, but not close to the winner.
Model tuned for faster resolution: severity 3, frequency 3, no ops nod. Real, but harder for a support lead to point to without seeing the model’s internals.
Topics with no good answer in the knowledge base: severity 3, frequency 3, no ops nod. Plausible, but not what anyone’s first instinct lands on.
Bot not asking “did I resolve this?”: severity 2, frequency 3, instant ops nod. Recognizable, but scored as less severe — this is the “fails to do” framing, not the “does wrong” framing.
No human overview of resolved tickets: severity 2, frequency 1, instant ops nod. The one absence-flavored cause on the list, and the lowest score of all six.
Pause/silence triggering closure won by a wide margin, not close. It’s the only cause I rated 5/5, and the one every ops instinct nodded at immediately. That’s the tail.
It’s worth noting why this makes sense as the winner, because it isn’t really competing with “the bot doesn’t ask if the issue was resolved”, those are the same gap, viewed from two directions. One is what the bot fails to do. The other is what the bot does instead: it treats the absence of a reply as confirmation. My own scoring caught that difference without me planning it; I rated the “does wrong” framing far more severe than the “fails to do” framing. That’s worth saying plainly: the problem isn’t a missing question. It’s an active misreading of silence as agreement.
That also settled something I’d been circling since the fishbone: is this a story about bad bot design, or a story about a missing audit? My top four scores were all mechanism-flavored — pause/silence, no clarifying questions, model tuning toward faster closes. The one absence-flavored cause, no human review of resolved tickets, scored lowest. So this was heading toward bad design, with the missing audit as a contributing factor, not the main one.
The first Why, stated as cleanly as I could manage:
Why does the bot treat silence the same as confirmation?
IV: Chapter 4–5 Whys: One Case, All the Way Down
Here’s the case I picked to drill into — a composite, built from the kind of exchange that shows up constantly and gets logged as a clean win every time:
Customer: My payment keeps failing when I try to update my card. Bot: I’ve refreshed your payment settings. You should be able to add a new card now. Customer: ok [14 seconds pass. No further messages. Conversation closed. Status: Resolved.]
Nothing here confirms the card was actually accepted. I wanted to know why the system was so confident it had.
Why does the bot treat silence the same as confirmation? Because it's a closed-trigger, it only checks for the absence of a negative signal: no complaint, no follow-up question. It never checks for the presence of a positive one.
Why does the close-trigger work that way — checking for absence-of-complaint instead of presence-of-confirmation? Because the absence of complaint is easy to detect mechanically. A timer. A lack of new messages. The presence of confirmation requires either asking a direct question or interpreting open-ended language — both are harder to build reliably.
Why was the easier-to-detect signal chosen as the definition of resolution? Because the metric this system was accountable for was resolution rate — a number that climbs every time a conversation closes without a complaint. Nothing in that metric distinguishes a closed conversation from a confirmed one. There was never a design requirement to build the harder signal, because the easier one already satisfied what was being measured.
Why did testing not catch that this breaks down on ambiguous or abandoned conversations? Because testing validates against the metric being optimized for, not against a metric that doesn’t exist yet. If “confirmed resolution” was never something being measured, there was no test built to check for it either.
Why was resolution defined this way in the first place — as closure rather than a confirmed outcome? Because closure is something the system can report on its own, immediately, with no external input. Confirmed outcome would require either the customer to actively confirm or a human to audit a sample of conversations — both slower, both costing something to build. Neither made it into the metric’s original definition, because neither was accounted for as necessary.
Five whys down, and I’d stopped talking about the bot entirely. I was talking about a decision made long before any conversation happened — a decision about what counts.
Resolution was defined as whatever the system could report about itself, not as what the customer actually experienced — so the metric was never capable of catching the gap it’s now hiding.
I picked this case because the failure was the most visible one on the fishbone — a bot mishandling silence. Five steps down, it turned out to be a measurement problem all along.
That’s a claim, not a conclusion. Root-cause analysis tells you what’s probably true. It doesn’t test it. So I built something to find out if it actually was — a heuristic evaluator and an LLM judge, both designed to catch exactly the failure I’d just traced back five steps. That’s Part 2.
메타데이터
- post_id
- c91c01ca95b9
- slug
- the-false-resolution-detector-of-a-support-chatbot-part-1-the-diagnosis-c91c01ca95b9
- url
- https://medium.com/@kathrine.yanchenko/the-false-resolution-detector-of-a-support-chatbot-part-1-the-diagnosis-c91c01ca95b9
- canonical_url
- https://medium.com/@kathrine.yanchenko/the-false-resolution-detector-of-a-support-chatbot-part-1-the-diagnosis-c91c01ca95b9
- author_url
- https://medium.com/@kathrine.yanchenko
- status
- ok
- fetched_at
- 2026-08-21 12:13:25