Chạy bằng npm test (Vitest), dùng provider giả lập (fakeProvider) tự trả về JSON đã ghi sẵn — kiểm tra code xử lý đúng logic không. Không gọi model AI thật, nên không kiểm tra được model có hiểu đúng câu khách không — việc đó thuộc phần 2 và 3.
Run via npm test (Vitest), using a mocked provider (fakeProvider) that returns pre-written JSON — checks whether the code's own logic is correct. No real AI model is called, so this cannot verify whether a model actually understood a guest's message — that's Parts 2 and 3.
| FileFile | Số testTests | Kiểm tra gìWhat it checks |
|---|---|---|
robustness.test.ts | 48 | 200 payload giả lập ngẫu nhiên (fuzz) — extract() luôn resolve/reject đúng cách, không crash200 randomly generated (fuzz) payloads — extract() always resolves/rejects correctly, never crashes |
whatsapp.test.ts | 38 | Chữ ký HMAC, dedupe wamid, claim/release, xin lỗi khi lỗi, handoff, lệnh resetHMAC signature, wamid dedupe, claim/release, apology on failure, handoff, reset command |
dates.test.ts | 31 | Phân giải ngày tuyệt đối/tương đối 3 ngôn ngữ, mốc TODAY cố địnhAbsolute/relative date parsing in 3 languages, fixed TODAY anchor |
extract.test.ts | 20 | Retry-once, phân loại lỗi transport/validation, enforceVerbatimEvidence, postProcessRetry-once, transport-vs-validation error classification, enforceVerbatimEvidence, postProcess |
questions.test.ts | 16 | 3 loại reply (greeting/questions/summary), nhãn (assumed), câu hỏi theo ngôn ngữ3 reply kinds (greeting/questions/summary), the (assumed) label, per-language questions |
counts.test.ts | 14 | Đối chiếu số khách/đêm/phòng với văn bản gốcCorroborates guests/nights/rooms counts against the source text |
evalReplay.test.ts | 12 | Bộ chấm điểm eval offline khớp đúng logic scorerOffline eval replay matches the scorer's own logic |
conversationStore.test.ts | 9 | Split TTL, fencing token, pause/resume/handoffSplit TTL, fencing token, pause/resume/handoff |
normalize.test.ts | 7 | Nhận diện ngôn ngữ, che PII khi logLanguage detection, PII masking for logs |
converse.test.ts | 6 | Giới hạn transcript, luồng hội thoại nhiều lượtTranscript cap, multi-turn conversation flow |
providers/providerFromEnv.test.ts | 4 | Chọn đúng provider theo env var, wrapper resilient fallbackCorrect provider selection by env var, resilient fallback wrapper |
bff.test.ts | 3 | Route cơ bản của BFFBasic BFF routes |
providers/gemini.test.ts, deepseek.test.ts | 4 | Timeout, prompt transport có đủ rule 2 ngôn ngữTimeout, transport prompt carries both languages' rules |
dataset.test.ts | 1 | File dataset eval là JSON hợp lệEval dataset file is valid JSON |
Chạy qua eval/runner.mjs, gọi thật /v1/extract trên production. 14 case gồm 10 case gốc (đa ngôn ngữ, có bẫy bịa đặt) + 4 case en-06..en-09 thêm hôm 20/09 sau khi phát hiện bug guests.
Run via eval/runner.mjs, calling real /v1/extract on production. 14 cases: 10 original (multilingual, with fabrication traps) + 4 cases en-06..en-09 added 20/09 after the guests bug was found.
| Thời điểmWhen | Provider | Required fieldsRequired fields | Fabrication | Evidence | p95 latencyp95 latency |
|---|---|---|---|---|---|
| 20/09, trước khi sửa bug20/09, before the bug fix | google:gemini-3.1-flash-lite | 31/35 (89%) | 0 | 100% | 6.5s |
21/09, Gemini sau fix guests+diveTo21/09, Gemini after the guests+diveTo fix | google:gemini-3.1-flash-lite | 34-35/35 (97-100%) | 0 | 100% | ~4s |
| 21/09, DeepSeek ngay khi gateway sống lại (chưa qua wrapper)21/09, DeepSeek right after the gateway came back (bare, no wrapper) | deepseek-gateway:deepseek-flash | 34/35 (97%) | 0 | 100% | 5.2s |
| 21/09, DeepSeek vừa lên provider chính (bug wrapper)21/09, DeepSeek just switched to primary (wrapper bug active) | deepseek-gateway:deepseek-flash | 32/35 (91%) | 0 | 100% | 5.0s |
| 21/09, DeepSeek sau khi sửa hết (wrapper + checkIn cô lập)21/09, DeepSeek after every fix (wrapper + isolated checkIn) | deepseek-gateway:deepseek-flash | 35/35 (100%) | 0 | 100% | 5.7s |
Không có số liệu lặp lại được, không chạy tự động, không có tiêu chí pass/fail cố định — đây là hội thoại thật/gần thật do người gõ tay, mỗi lần đổi 1 chi tiết để dò lỗi. Giá trị: tìm ra phần lớn bug thật trong ngày, những bug mà unit test (giả lập) và eval (câu ngắn) không chạm tới. No repeatable score, not automated, no fixed pass/fail bar — these are real/near-real conversations typed by hand, changing one detail each time to probe for issues. Value: found most of today's real bugs, ones unit tests (mocked) and eval (short messages) never touched.
| Kịch bảnScenario | KênhChannel | Kết quảResult |
|---|---|---|
| Hội thoại 4 lượt tiếng Việt (chào → trả lời dồn → lặn → tóm tắt)4-turn Vietnamese conversation (greeting → dense answer → dive → summary) | API (/v1/converse) | OK |
| Booking thật "Alex" — cửa sổ lặn hẹp hơn cả kỳ nghỉReal "Alex" booking — dive window narrower than the whole stay | WhatsApp sandbox | OK — phân biệt đúng, No-Fly advisory bắn đúngcorrectly distinguished, No-Fly advisory fired correctly |
| Test độ trễ 7 phút giữa 2 tin (rủi ro lớn nhất cho demo)7-minute gap test between two messages (top demo-day risk) | WhatsApp sandbox | OK — nhớ đúng contextcontext retained correctly |
| Thread "Michael" — hỏi về baby/thêm người sau khi đã cho số khách"Michael" thread — asked about a baby/extra person after guests was already given | WhatsApp sandbox | Tìm ra 2 bugFound 2 bugs — nhãn (assumed) mất, guests bị xoá về missing(assumed) tag lost, guests wiped to missing |
| Email dài kiểu gia đình có con (Jennifer) — số tổng + chi tiết lặn của 1 ngườiLong family-style email (Jennifer) — a stated total plus one person's diving detail | API + WhatsApp sandbox | Tìm ra 2 bugFound 2 bugs — guests, diveTo (cả hai đã sửaboth since fixed) |
| Bug | Nguyên nhânRoot cause | Cách sửaFix | Trạng tháiStatus |
|---|---|---|---|
guests bị bỏ vềwiped to missing | Model quá tải khi phân loại nhiều field cùng lúc trong 1 promptModel overloaded classifying many fields at once in one prompt | Cô lập guests ra 1 cuộc gọi riêng, chạy song songIsolated guests into its own call, run in parallel | Đã sửaFixed |
diveTo bỏ sót ngày thứ 2 ("16th and 17th")missed the second date ("16th and 17th") | Thiếu rule cho cú pháp "ngày X and ngày Y"Missing rule for the "date X and date Y" pattern | Thêm rule + ví dụ vào prompt chínhAdded rule + example to the main prompt | Đã sửaFixed |
extractGuests không chạy trên productiondidn't run in production | Wrapper resilient (Gemini↔DeepSeek fallback) không forward optional methodResilient (Gemini↔DeepSeek fallback) wrapper didn't forward the optional method | Sửa wrapper forward đúngFixed the wrapper to forward extractGuests/extractCheckIn | Đã sửaFixed |
checkIn ngày tương đối tiếng Anh không ổn định trên DeepSeekEnglish relative-date unstable on DeepSeek | Cùng cơ chế quá tải như bug guestsSame overload mechanism as the guests bug | Cô lập checkIn ra 1 cuộc gọi riêngIsolated checkIn into its own call | Đã sửaFixed |
| Fabrication ngày ("cuối tháng này" → bịa ngày cụ thể)Date fabrication ("end of this month" → invented a specific day) | Phát sinh khi viết prompt cô lập lần đầu, chưa dạy tôn trọng "chưa chốt ngày"Introduced while first writing the isolated prompt, which hadn't yet been taught to respect "not decided yet" | Bắt được trước khi deploy, sửa prompt trước khi lên productionCaught before deploying, fixed the prompt before it reached production | Đã sửa, chưa từng lên productionFixed, never reached production |