Repository navigation
@W-24333476 - Fix welcome-leak race via position-based classifier - #16
Open
sf-samarth-urs wants to merge 1 commit into
Open
sf-samarth-urs wants to merge 1 commit into
sf-samarth-urs wants to merge 1 commit into
Conversation
The timing-based welcome-tracker (hasUserSent + welcomeDropped + 5s gate) failed on answer-before-welcome. When the handshake exceeded the gate's 5s timeout, the user POST went out, hasUserSent flipped on sendMessage() resolve, and if the real answer arrived before the welcome it got labelled "late welcome" and dropped — while the actual welcome then rendered as the answer. Reproduced via opener-pill click on PDP (see screenshot in W-24333476). Replace with a position-based classifier anchored on the server's EndUser-echo timestamp: - SDK emits a new user_echo event when SCRT2 echoes an EndUser CONVERSATION_MESSAGE, carrying entry.identifier + transcriptedTimestamp. Previously these entries were silently dropped. - WidgetProvider holds echoCutoffRef (ISO-8601 server timestamp) and a pre-echo message buffer. Chatbot entries arriving before the echo are buffered, not dropped. On echo arrival the buffer drains through the classifier. - Chatbot timestamp <= echo cutoff → welcome (drop). - Chatbot timestamp > echo cutoff → answer (render). - Server-generated timestamps, so no clock skew; ISO-8601 UTC strings sort lexicographically. Removed: - welcome-gate.ts (and its test file) — the send-side await is no longer needed; correctness is on the receive side. - hasUserSentRef, welcomeDroppedRef, welcomeTimeoutRef — subsumed by echoCutoffRef. Kept: - A 5s UI-liveness fallback that re-enables Send on silent agents. Independent of correctness. sendMessage() now returns the client-generated message id so callers can correlate a specific send with its user_echo event if they need to. Tests: 175 passing; welcome-tracker.test.ts rewritten for the position model with an explicit regression test for the answer-before-welcome window.
sf-samarth-urs
force-pushed
the
feature/w-24333476-welcome-race-fix
branch
from
October 8, 2026 19:58
a88c75e to
88bd8ee
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the race where the agent's auto-welcome greeting (
"Welcome to NTO! I'm your AI shopping assistant...") leaks into the widget as if it were the answer to the shopper's question — visible in the opener-pill flow onzyss-001PDPs.Root cause
The previous timing-based classifier (
hasUserSent+welcomeDropped+ 5s gate) failed on answer-before-welcome:sendMessage()starts the handshake, opens the 5s welcome-gate.hasUserSentflipstrueonsendMessage()resolve.hasUserSent=true, welcomeDropped=false→drop-welcome(post-send late-welcome branch) → answer swallowed.welcomeDropped=true→render-answer→ welcome renders as the answer.That matches the W-24333476 repro screenshot exactly: shopper clicked "Can I machine wash this?" → saw the greeting as the response.
Fix — position-based classifier
Replace timing + ordering heuristics with a server-authoritative cutoff: the EndUser echo's
transcriptedTimestamp.sdk/client.ts) — stop silently dropping EndUserCONVERSATION_MESSAGEentries. Emit a newuser_echoevent carrying{ messageId, timestamp }.sendMessage()now returns the client-generated message id for correlation.WidgetProvider.tsx) — holdechoCutoffRef(ISO-8601) + a pre-echo message buffer. Chatbot entries arriving before the echo are buffered, not dropped. On echo, buffer drains through the classifier.welcome-tracker.ts) — pure classifier: Chatbot timestamp ≤ cutoff → welcome (drop); > cutoff → answer (render). Server timestamps, so no clock skew; ISO-8601 UTC strings sort lexicographically.What's deleted
src/provider/welcome-gate.ts+ its test — the send-side await is no longer needed. Correctness is now entirely on the receive side.hasUserSentRef,welcomeDroppedRef,welcomeTimeoutRefstate — subsumed byechoCutoffRef.What's kept
0000-01-01T00:00:00.000Zso replayed historical entries render as answers.Diff shape
Net: -431 lines, same guarantees.
Test plan
npm test -- --run→ 175 tests pass, 12 filesnpx tsc --noEmit→ cleanwelcome-tracker.test.tscovers the answer-before-welcome window explicitlyzyss-001after cartridge rebuild — pill-click flow renders the real answer, no welcome bubble appearsRelated
/Users/surs/pwa-kit/.agents/artifacts/Unexpected-WelcomeMessage-SFRA.png