Supersedes the diagnosis in #331 for users who have configured a stop-word. The owner does have
"stop stop" configured, and reports it works sometimes — "seems like it works now, weird".
That intermittency is fully explained.
Cause: the stop-word normaliser does not strip hyphens
packages/sdk/src/voice/convo.ts:243:
function normalizeTranscript(text: string): string {
return text
.toLowerCase()
.replace(/[.,!?¿¡。,!?、]/g, "") // ← no hyphen
.replace(/\s+/g, " ")
.trim();
}
stripStopWord compares the normalised transcript against the normalised stop-word. Measured:
| Whisper output |
normalised |
matches "stop stop" |
"Stop stop." |
stop stop |
yes |
"Stop, stop." |
stop stop |
yes |
"Stop-stop." |
stop-stop |
no |
Whisper renders a repeated word as a hyphenated compound sometimes — it is a formatting choice,
not a transcription difference. So the same spoken phrase silently succeeds or fails depending on
punctuation the user cannot control or even see.
That is exactly the reported behaviour: it works, then it does not, then it works again.
Observed failing case, Coder Lead 2026-08-06 23:51:37 — transcript "Stop-stop." was sent as a
chat message instead of ending the turn, and the agent replied "Got it. Stopped." while the mic
stayed live. The silence that followed produced two phantom turns (#332).
The same file already has the answer
isNoiseTranscript in audio.ts:90 strips a much wider punctuation set, hyphens included:
.replace(/[.,!?"'’“”…·•–—:;()。,!?、:;「」『』()《》-]|\[|\]/g, " ")
So there are two normalisers in the voice package with different ideas of what punctuation is, and
the stricter one is used for the noise filter while the looser one guards the commands. That is
backwards — the command path is where a near-miss is user-visible.
Fix
Normalise hyphens (and en/em dashes) to a space in normalizeTranscript, then collapse whitespace
— which the function already does, so "stop-stop" becomes "stop stop" and matches.
Better still: have both paths share one normaliser. Two functions that must agree about punctuation
and do not is the underlying defect; the hyphen is just the instance that surfaced.
This affects every command path, not only stop-words — matchVoiceCommand and
splitTrailingCommand both run on normalizeTranscript, so any hyphenated rendering of a
multi-word command ("mute-mute", "text-mode") fails the same way.
Verification
"Stop-stop.", "Stop stop." and "Stop, stop." all end the turn identically.
- A hyphenated rendering of any configured multi-word command matches.
- Ordinary hyphenated speech is unaffected: "well-known" does not become a command, because
matching is still whole-utterance or trailing-phrase.
- A unit test pinning the three renderings above, since the failing one depends on Whisper
formatting and will not reproduce reliably by hand.
Supersedes the diagnosis in #331 for users who have configured a stop-word. The owner does have
"stop stop"configured, and reports it works sometimes — "seems like it works now, weird".That intermittency is fully explained.
Cause: the stop-word normaliser does not strip hyphens
packages/sdk/src/voice/convo.ts:243:stripStopWordcompares the normalised transcript against the normalised stop-word. Measured:"stop stop""Stop stop."stop stop"Stop, stop."stop stop"Stop-stop."stop-stopWhisper renders a repeated word as a hyphenated compound sometimes — it is a formatting choice,
not a transcription difference. So the same spoken phrase silently succeeds or fails depending on
punctuation the user cannot control or even see.
That is exactly the reported behaviour: it works, then it does not, then it works again.
Observed failing case, Coder Lead 2026-08-06 23:51:37 — transcript
"Stop-stop."was sent as achat message instead of ending the turn, and the agent replied "Got it. Stopped." while the mic
stayed live. The silence that followed produced two phantom turns (#332).
The same file already has the answer
isNoiseTranscriptinaudio.ts:90strips a much wider punctuation set, hyphens included:So there are two normalisers in the voice package with different ideas of what punctuation is, and
the stricter one is used for the noise filter while the looser one guards the commands. That is
backwards — the command path is where a near-miss is user-visible.
Fix
Normalise hyphens (and en/em dashes) to a space in
normalizeTranscript, then collapse whitespace— which the function already does, so
"stop-stop"becomes"stop stop"and matches.Better still: have both paths share one normaliser. Two functions that must agree about punctuation
and do not is the underlying defect; the hyphen is just the instance that surfaced.
This affects every command path, not only stop-words —
matchVoiceCommandandsplitTrailingCommandboth run onnormalizeTranscript, so any hyphenated rendering of amulti-word command ("mute-mute", "text-mode") fails the same way.
Verification
"Stop-stop.","Stop stop."and"Stop, stop."all end the turn identically.matching is still whole-utterance or trailing-phrase.
formatting and will not reproduce reliably by hand.