Problem
Every ASR final on the interviewer channel (ch_0) fires a full live-suggestion request, regardless of whether the turn was a real question or pure backchannel ("mhm", "yeah", "okay", "got it"). The only mechanism for "no answer needed" is the backend emitting a NO_SUGGESTION_NEEDED sentinel inside the answer stream itself, after the client has already:
- uploaded the full profile + context + up to 60 transcripts
- started a model generation
- rendered a
Pending card that then has to be retracted
Three concrete failure modes:
- Cost/latency paid before the decision. The cheapest, most certain signal ("this is filler") runs last, not first.
- In-band control signal. The decision travels inside the prose stream it's supposed to gate. It already broke once - professional mode's bold headline made the model emit
**NO_SUGGESTION_NEEDED**, requiring a markdown-stripping regex in suggestion-sentinel.ts to keep matching.
- Wrong trigger boundary. An ASR final is an acoustic endpoint, not a finished thought - a question split by a thinking pause ("So tell me about..." / "...your Kafka work") fires two requests, and the second aborts the first mid-render.
- Show-then-retract UI. The panel renders a spinner immediately and pulls it back on every "okay, got it", which reads as a bug even when working as designed.
Fix
A cascade, cheapest and most certain signal first:
- Stage 0/1 (client, deterministic) -
classifyInterviewerTurn() runs in-process on the merged interviewer turn and returns Skip / Answer / Uncertain. Skip drops the turn with no request and no card. Answer (a completed question or directive) generates immediately. Uncertain parks on a short settle timer that a continuation re-arms, so a split question is judged whole.
- Stage 2 (backend, speculative) - for
Uncertain turns, a cheap one-word classifier (no profile, no context, free-tier model) runs beside the real generation as a background task rather than in front of it, so a real question pays zero added latency. A SKIP verdict cancels the generation and yields the sentinel; every gate failure falls open to answering.
- The client no longer renders a
Pending card on request start - it holds briefly so a turn the backend gate suppresses produces no card at all instead of one that flashes and disappears.
The NO_SUGGESTION_NEEDED sentinel remains as the last-resort fallback for turns neither stage can settle.
PRs
Problem
Every ASR final on the interviewer channel (
ch_0) fires a full live-suggestion request, regardless of whether the turn was a real question or pure backchannel ("mhm", "yeah", "okay", "got it"). The only mechanism for "no answer needed" is the backend emitting aNO_SUGGESTION_NEEDEDsentinel inside the answer stream itself, after the client has already:Pendingcard that then has to be retractedThree concrete failure modes:
**NO_SUGGESTION_NEEDED**, requiring a markdown-stripping regex insuggestion-sentinel.tsto keep matching.Fix
A cascade, cheapest and most certain signal first:
classifyInterviewerTurn()runs in-process on the merged interviewer turn and returnsSkip/Answer/Uncertain.Skipdrops the turn with no request and no card.Answer(a completed question or directive) generates immediately.Uncertainparks on a short settle timer that a continuation re-arms, so a split question is judged whole.Uncertainturns, a cheap one-word classifier (no profile, no context, free-tier model) runs beside the real generation as a background task rather than in front of it, so a real question pays zero added latency. ASKIPverdict cancels the generation and yields the sentinel; every gate failure falls open to answering.Pendingcard on request start - it holds briefly so a turn the backend gate suppresses produces no card at all instead of one that flashes and disappears.The
NO_SUGGESTION_NEEDEDsentinel remains as the last-resort fallback for turns neither stage can settle.PRs