Why Clara wouldn't stop replying
What caused the thread that embarrassed us, how common it is, what we fixed overnight, and the handful of things that need your call this morning.
2026-08-29 · overnight program · every number below comes from real production data or is labelled an estimate
The strategy in one paragraph
The embarrassing thread wasn't one bug — it was a missing concept. Clara has no idea of "this conversation doesn't need a reply": prospects literally cannot receive silence, nothing compares what she's about to send with what she already sent, and her follow-up timers never look at what's happening in the conversation. Overnight we proved all of that with real production data, fixed every confirmed defect that fed the incident, built the measurement rig that grades "would a coworker have sent this at all", and built person-level mute as one first-class switch. What remains for you this morning are the design picks, not the bleeding.
1 · What causes it (verified, not guessed)
- Prospects can't receive silence. The "end conversation" ability exists but is only granted to residents; a prospect's every text structurally spawns a reply. If the model produces nothing, the code manufactures an apology and sends that instead. The written default is literally "when in doubt: respond."
- She repeats because nothing checks. There is no comparison anywhere between an outgoing message and her own recent sends. The "repeat" in the incident was the prospect texting an identical "Thank you" twice — each one got its own full reply.
- The repeated "I'll follow up tomorrow either way" comes from the escalation machinery. The open-question prompt block instructs her to say that exact sentence, and the same block made her hedge on the voucher answer even after the correct fact was on file — proven by simulation (7 out of 7 hedges with the question open, clean answers with it closed), then confirmed live.
- The one brake we have can't fire. The goodbye-loop breaker counts "tomorrow" and any digit as content, so her own sign-offs never qualify as empty.
2 · How widespread (real rows, honest denominators)
- Across 174 real human text and email conversations — all of them, 7,619 messages — people sent 29 plain goodbyes and Clara replied to 25 (86%). Both thumbs-up reactions we have ever received got replies; one reply was "👍".
- This is original behaviour, not the new model. Reply-to-goodbye ran 80% / 71% / 94% across June / July / August, and the model switch boundary shows 83% before, 83% after. The "previous model was better" hypothesis is refuted with dates.
- The repeat shape is new, and it is tied to the escalation machinery. The only repeated status-line cluster in the whole corpus is this thread's, and its escalation record was created 55 seconds before the first one.
- Sibling problems found in the same sweep: 31% of "I'll get back to you by [time]" promises were never kept — one prospect promised a Monday tour went 43.5 days in silence — and 3 of 11 open escalations sat past their promised deadline with nobody chasing.
- It reproduced live while we were investigating. Five minutes after the correct voucher answer went out, he texted "Thank you so much", Clara replied again, mirrored his smiley, and he wrote "I need humans to come back." That sequence is the closing exhibit on the decision page.
3 · The yellow dot — straight answer
It means a safety check changed what Clara said before sending. A rewrite lights the same dot as a block. On the two dotted messages (4:34 and 4:43 PM Mountain), the promise-backing check swapped his sentences down to "I don't have that answer on file right now" — the exact robot-speak he called out. So your reading was half right: the check did catch something and a message did go out, but what went out was the corrected version, not the caught draft. That check's two real holes — blindness to a dash, and never reading the open-question table — are both fixed and merged.
4 · Shipped overnight — nine changes, all merged
- Answered questions stay answered — a new message can no longer wipe a settled answer (the 2:31 AM overwrite was the failing case).
- Follow-up timers park on human-owned threads instead of blindly spending their turn — your "aware of what's happening" ruling, implemented.
- Promises split by a dash are now detected. Replayed over 30 days and 850 real turns: exactly two additional catches, both this incident's own missed promises.
- "Backed" now reads the actual open question, not the racy thread status.
- A takeover hands the thread back when the answer settles, not at send — the 79-millisecond flip that re-armed the loop mid-conversation is gone.
- The escalation relay follows the person's address — an email-side question can no longer silently fail to text an SMS prospect. Found live while closing his question.
- A refused manual send now explains itself — "this person is muted or opted out, here's how to proceed" — instead of failing silently.
- The measurement lane. It replays real threads through the real loop with outbound suppressed and grades every reply against "would a coworker have sent this?" Red run committed: 100% of graded replies on the incident thread fail the coworker standard — twice. This is the ruler every fix gets measured against.
- Mute v1 merged — all checks green, both reviewers. See the next section for what that does and does not mean.
5 · Mute — merged, and dormant until you say otherwise
Your invariant, shipped: a muted person hears nothing and triggers nothing, until unmuted — except what a human deliberately sends, and emergency or safety notices. It is one new "muted" level on the existing opt-out table — one column, every lane at once, including the five paths that bypass the usual gate and the routine operational replies nothing else stops.
Proven on the test property: 6 out of 6, twice. Silence in both directions, zero team notices, takeover-as-Clara still works with the mute staying on, and an opt-out can never be overridden. On voice, the webhook half is proven and the live call leg ships through the agent-config pipeline behind two scored simulation scenarios — the direct-edit path is correctly blocked by our own CI guard. The pane switch, the list badge and the productized "reply as Clara" composer are day-2; the API underneath already exists.
6 · The prospect — final state
- Voucher question resolved, answer on record (JP&Co team decision, 2026-08-28): housing choice vouchers are accepted as a source of income; screening and qualification details route to the leasing team. He received it at 8:26 PM Mountain, from Camellia's line.
- The raw wording we got back contained screening clauses that are unlawful for voucher holders under Colorado SB23-184. It was kept out of our records and out of anything Clara can learn from — it lives only in the mailbox.
- His "I need humans" request is recorded as its own item and closed with your judgement note, at the real timestamps.
- Fully muted — phone and email, gate-verified. All three application-reminder timers cancelled at the source and verified: zero sends fired. Thread human-owned, staff nagging dead at the query level.
7 · Your morning picks
Two are live decisions blocking work that is otherwise finished:
- Activate mute v1 — the code is merged and dormant; the Willows demo is ready, with proofs at 6 out of 6 and then 8 out of 8.
- Un-gate the "don't reply to a bare thank-you" skip — built, conservative, held in draft for exactly this decision.
The rest, all on the decision page as multiple choice with a recommendation:
- Office-hours-aware promise clocks (today a 5 PM Friday escalation promises Saturday).
- Escalation silence scoped to the topic or to the whole thread.
- Per-turn-type model effort — a cost lever only; the "the model caused it" hypothesis was refuted.
- Mute day-2 surfaces: the badge, the pane switch, the composer.
- One process item: auto-merge-on-green outran the review bot once tonight. The fix shipped 11 minutes later, but the window is real.
Honesty ledger — what went wrong on our side
Caught by us, disclosed
- The review bots caught a real-name leak in a file that asserted it had no names, and a false-green flaw in the very harness built to catch this bug — both were the exact failure classes those artifacts claimed to prevent. Fixed at the root: a name fence with a positive control, and silence now requires a positive signal from the guard itself.
- One mute write initially landed in a local store instead of production (an environment default). Caught by self-review and re-executed against production. An earlier "zero suppression records" claim used the wrong key and was corrected.
- The escalation-relay bug meant our "proper path" close did not actually deliver; the delivery was completed through the hardened manual rail, and the bug became fix number 6.
- Four phases of a Willows test harness had been silently dead for 11 days (a subject-format drift). Found and repaired in passing.
Caught by the review lane — two that would have shipped broken
- The voice mute would have been dead text. A reviewer caught that the change was written into a part of the voice prompt that never gets rendered — it would have read correctly in the pull request, passed review by eye, and done absolutely nothing on a real call. A muted person would have been answered by Clara as normal.
- An unmute would have destroyed a real opt-out. As first written, unmuting someone would have cleared the underlying record — including a genuine STOP, which is a legal boundary we are never allowed to lift. Caught before merge.
Full evidence trail, including every query and file reference, is in the session reports; the decision page carries the sourcing for every number above.