Booked Solid Inspector · 3 September 2026
Six real calls Chad placed to GC's line on 3 September, triaged. Two were the phone company; the rest were Josh's own behaviour on the current build. Here is each one, what was shipped to fix it, what is not a code bug, and where Telnyx stands.
Not concurrency. Chad is one caller at a time. The worker fix for many calls at once is a different thing, and these calls do not show it.
Not Telnyx, mostly. Josh's audio worked in five of the six — he speaks,
the caller answers, back and forth. Only Call 1 (leg df7979a4-a7a7,
94 bytes, dead after the recording line) fits the carrier signature: total silence
from the first second. That one is Telnyx, and it is now confirmed — see the last
section. Everything else here is Josh, and it is fixed.
All seven are committed to the branch claude/fix-josh-jhgysc,
each with a test. Three are code guards (they hold even when the model slips);
four are rules added to both of Josh's brains — the phone brain
(bot.py) and the web brain (chat.js) — kept in step by the
brain-parity check.
Call 3. Josh said "I don't have a price I can stand behind for that one, so I won't guess at it" — and then, one breath later, "the pre-drywall at 425 now, and then the final at 500." The $425 is real; the $500 is a figure no tool ever produced, invented for a service GC does not price. Chad caught it on the call.
Why it slipped: the price-guard caught it but only logged it, because a real quote had already landed earlier in the call. That log-only rule dated to August, when blocking risked stalling a good sentence (a saving, a comparison, a competitor's number). Those shapes are all stripped upstream now, so blocking is safe again. Fix: an invented figure now blocks whether or not a quote has landed. Josh re-quotes from the tool instead of saying a made-up number.
Call 6. A caller asked for a Friday that was booked solid, and Josh answered "we don't work Fridays, I'm afraid — we're Monday through Friday." That is false: Friday is a GC working day. He confused "no open slot that day" with "we're closed that day," and told the caller something untrue about the firm.
Fix (both brains): a full day with no slot is never a closed day — Josh now says that day's openings are taken and offers the nearest free ones, and only calls a day one the firm does not work when the setup says so.
On the re-test calls the drift monitor screamed "SAID ONE ADDRESS, SAVED
ANOTHER — read back 'zulu@gmail.com', saved 'dortiz@gmail.com'." The record
was correct. The caller spelled her email in bare NATO — "delta, Oscar,
Romeo, tango, India, Zulu" — Josh assembled it right (dortiz@gmail.com),
but the monitor could not read bare code words and grabbed the last one,
"zulu." A monitor that cries wolf gets ignored, and we were about to trust these
same logs for the stall.
Fix: the monitor now assembles a run of three-plus code words into the letters they stand for; a lone "Mike" or "India" stays ordinary speech. Diagnostic only — it never changed what a caller hears.
On a re-test call Josh had not yet got the caller's email, saved the booking
with placeholder@pending, and still closed with "you'll get an email
with the agreement and a payment link" — promising delivery to an address that
does not exist. He corrected it when she gave the real one, but the record briefly
carried a fake email the agreement would have been mailed to.
Fix: save_contact already blanks an invented field
("pending", "n/a"), but the whole-string match missed placeholder@pending
because the "@" splits it into two placeholder halves. It now blanks the email
when either half is a placeholder word, so a booking never carries a fake address.
The words of the over-promise are already forbidden in the prompt and
flagged by the monitor.
Call 5. A seller asked for the prices at two sizes, Josh had nothing to
state, and he fell silent. Fix (both brains): two sizes or two options means
two quote_price calls, never silence. If a figure genuinely can't be
had, Josh says the office will confirm it — but never leaves the question hanging.
Call 4. "We don't do mold testing… That's a service we can add on." Both, in one breath. Fix (both brains): once Josh declines a service he does not then offer it; if it is not in the setup he cannot add it on — decline once, cleanly, and carry on with what he can do.
Calls 2, 3, 5. "713 — sorry, 832…" Josh opened a phone read-back with a guessed area code and then corrected himself, which tells the caller he is unsure and invites a mishear. Fix (both brains): never lead a read-back with an area code you are guessing — read what you actually heard, or ask for the ten digits again.
The loudest complaint from the calls, and the honest answer is that it is mostly the caller's environment, not Josh freezing.
On Calls 3, 4 and 5 Josh appeared to freeze, repeating "One moment — I'm still here." Reading two complete call traces end to end, the pipeline was healthy the whole time: the model answered in half a second to a second, the booking saved in half a second to a second, the event loop never lagged. Nothing hung.
What the "I'm still here" lines actually are Two safety watchers fire when the line goes quiet. In the clean calls each fired once and recovered — one caller was cooking and talking to someone off the phone ("Sadie, don't do that… I'll be right back"), went silent for fifteen seconds, and Josh held the line and picked back up. That is the graceful degradation working, not a defect.
Two things drive the "confused" feel, and neither is a prompt we can write: callers multitasking and going silent, and far-field speech-to-text — the recogniser returns nonsense for muffled, away-from-the-phone audio ("Why refund?", "the broken staff form"), and Josh gamely answers the noise. That is a recogniser limit, not a Josh bug. The longer 60–90 second version on Chad's calls is the same watchers escalating over a longer silence.
Full detail is in "The phone went quiet this morning." This is the short version and the new confirmation.
Call 1 died the way a carrier media fault dies: answered, then total silence, and the caller hangs up after fifteen to thirty-five seconds. Telnyx's own event export for a matching call proves the mechanism — the media stream is set up but the audio is never forked to us.
| What Telnyx logged | What it means |
|---|---|
stream_start completed, stream_id allocated | The <Stream> command was accepted. |
No streaming_started event | The audio fork never actually began. |
Our socket got {"event":"connected"}, then nothing | The start frame — carrying the stream id, the caller, the format — never arrived, so no audio can flow in either direction. |
call_hangup, source: caller, after ~15s | The caller heard silence and gave up. |
It correlates with Telnyx's own maintenance — "Voice Services Update — All
Regions," SIP Trunking / Media Anchorsites — and the failing call carried a
client_state that decodes to {data_center: "fr5", deployment:
"canary"}: our traffic landed on a canary build. Calls on the same numbers, same
application and same static TeXML document ran normally 90 minutes earlier. The
document is hosted by Telnyx, not us; we proved our WebSocket path is fine by having
them open a second frame to it successfully. The same rare symptom appears in our logs
on 2026-07-22 and 2026-08-04, long before anything current.
Where it stands
Telnyx case #635168 is open and flagged service-affecting. Their telephony
team is pulling the SIP signalling and media-fork logs for the affected call session
and comparing the fr5 / canary state against the calls that worked. We have asked:
can the media anchorsite update leave a <Stream> in this state
(command acknowledged, id allocated, start frame never emitted), and when
our traffic will be off the affected build. Replies go to the support email, not the
chat.
The one thing to take from this: none of the seven Josh fixes above are Telnyx, and none of the Telnyx fault is Josh. They are two separate stories on the same day. The Josh work is done and on the branch; the Telnyx fault is a carrier ticket we are chasing.
All seven fixes are committed and tested on claude/fix-josh-jhgysc.
They do not change what a caller hears yet: the phone brain only updates when the
branch is merged to main and a human presses the deploy-botpy
button, which restarts the live line and so is deliberately gated. Until then, Chad's
and Ted's lines run the current build.