← technext-edge
technext-edge · Extractor pod

Roadmap — 18/09 (thay bản 17/09)

Bản 17/09 vẫn đúng về hướng nhưng đã lệch thực tế sau một ngày: nó không hề nhắc tới trục WhatsApp/state — nơi toàn bộ rủi ro demo đang nằm — và 2 việc đã xong sau đó không có trong nó. Bản này giữ 3 nhóm cũ, thêm 2 làn mà bản cũ thiếu (L0 đóng băng & ship, L1 chống tái phát), và bổ sung 3 thứ bản cũ không có: Definition of Done, danh sách việc phải nói không, và lịch theo ngày.

0 · Vì sao phải viết lại roadmap

bằng chứng 18/09

Vấn đề không nằm ở kế hoạch, mà ở chỗ kế hoạch không có gì kiểm chứng tự động. Ba bằng chứng trong hôm nay:

Cây nguồn từng hỏng mà không ai biếtpackages/extractor/src/dates.ts:96 có một dấu } thừa → 5 trong 10 file test không compile được, chỉ 16 test chạy. Phát hiện lúc 18/09 16:26 khi bắt đầu bật typecheck; đã sửa.
đã sửa
Không có CI, không có lệnh typecheck ở rootPlaybook yêu cầu CI cho repo Edge; thực tế không có .github/, và package.json root chỉ có test (chạy mỗi extractor). Đây là lý do trực tiếp của lỗi trên.
đã bổ sung
Hai file log PII untracked mà .gitignore không chặnLuật cũ chỉ khớp results.*.json, không khớp results-deepseek.log / results-gemini.log — hai file này có thể chứa nguyên văn tin của khách. Đã chặn và kiểm chứng bằng git check-ignore -v.
đã sửa
ADR-006 tự khai "accepted" nhưng chưa từng được commitgit grep ADR-006 (không file code nào nhắc) cho 0 kết quả; conversationStore.ts và whatsapp.ts vẫn ghi "no ADR yet". Tài liệu không có trong git thì không tồn tại — và nó còn đảo ngược ADR-005a mà không có dòng Supersedes.
chờ quyết

L0 · Đóng băng & ship

hôm nay, không hoãn được

Không thể lập kế hoạch trên một cây nguồn chưa đóng băng. Hiện có 16 file modified + 5 file test mới chưa commit; main còn ahead 2 chưa push.

Commit dòng WIP theo 4 chủ đề, không gộp 1 commit khổng lồ① store + WhatsApp handler · ② converse + questions (đa ngôn ngữ) · ③ extract + dates + schema (5 field optional mới) · ④ provider + eval + test mới. Mỗi commit phải qua npm run verify.
người quyết
Push main + deploy rồi test 1 tin thậtDeploy là CLI từ repo root (vercel build → vercel deploy --prebuilt --prod), không phải push-to-deploy. Phải xác nhận webhook hết 404 và prod đã có WHATSAPP_*.
người quyết
Bổ sung 2 env var còn thiếu vào §6 team guideWHATSAPP_TURN_TIMEOUT_MS và WHATSAPP_TIMEOUT_MS đã dùng trong code nhưng chưa có trong tài liệu bàn giao.
code
Xoay App Secret + API key đã lộ trong chatTiền đề cho mọi thứ phía sau: khoá đã lộ thì mọi số đo hiệu năng/chi phí đều dựa trên tài khoản có thể bị người khác dùng.
người quyết

L1 · Chống tái phát

1 ngày · làn rẻ nhất, chặn nhiều thứ nhất

Làn này không thêm tính năng nào cho khách. Nó tồn tại để sự việc ở mục 0 không lặp lại. Trạng thái 18/09: 3/5 việc đã xong.

CI: typecheck + test trên mỗi pushXong: .github/workflows/ci.yml — npm ci rồi npm run verify, Node 20, cancel-in-progress. Còn phải kiểm chứng bằng một lần push thật.
xong 18/09
Lệnh typecheck ở rootXong: npm run typecheck chạy cả 2 workspace (--workspaces --if-present); npm run verify = typecheck + test. Bằng chứng: npm run verify exit 0, 11/11 file test pass (78 test) sau khi thêm test/questions.test.ts.
xong 18/09
.gitignore chặn log eval có thể chứa văn bản kháchXong: thêm results*.log và results-*.json. Kiểm chứng: git check-ignore -v trỏ đúng về dòng 13 của .gitignore.
xong 18/09
Test file cũng phải được typecheckHiện tsconfig.json của extractor chỉ include ["src"] — 5 file test mới không được kiểm kiểu. Đây là lỗ hổng còn lại của L1.
code
Quyết định số phận .agents/Đang untracked nhưng chứa skill dùng chung (browser-skill, technext-status-report). Hoặc commit, hoặc ghi vào .gitignore — không để nó hiện mãi trong mỗi lần git status.
người quyết

L2 · Cứng hoá kênh & state

1–2 ngày · chặn rủi ro demo lớn nhất

Ba lỗi trong làn này nằm trong code đang chạy, không phải nâng cấp: chúng đã có mặt trên main hôm nay.

Claim TTL đang là 24 giờ, không phải 60 giâyconversationStore.ts dùng ttlMs = THREAD_TTL_MS cho khoá claim của wamid. Nếu function bị kill sau khi claim mà trước khi releaseMessage, tin đó bị khoá 24 giờ — khách im lặng mất một ngày. Cần: claim in-flight ~60s + một "done marker" riêng có TTL dài.
code
releaseMessage không có token → double replyHiện release chỉ theo id, nên một lượt retry cũ có thể nhả claim của lượt mới. Cần claimMessage → {fenceToken} và releaseMessage(id, token) kiểm token. Bằng chứng phải là test: 3 lần giao cùng một wamid ⇒ đúng 1 reply.
code
Không có khoá theo thread → mất lượt khi khách nhắn liên tiếpHai tin cách nhau 1 giây có thể chạy song song và ghi đè state của nhau. Cần thread-lock:<phone> + gộp tin trong 2–3 giây thành một lượt. Cập nhật 19/09: đúng ca này đã xảy ra trong lần chạy thật — khách gửi tin thứ hai (“hi”) cách tin đầu 1 giây và nhận một câu trả lời riêng, lặp lại nội dung tin trước. Chưa sửa. Cập nhật 20/09: truy lại đúng race trong code — app.ts xử lý mỗi webhook độc lập (store.append → store.history → converse(), mất 3–6s), không có mutex/queue theo số điện thoại nào cả (grep lock/mutex/debounce/queue trong apps/casa-bff/src: không có kết quả). Kịch bản cụ thể: webhook A đọc history lúc chỉ có tin 1, đang "nghĩ"; tin 2 đến, webhook B ghi vào rồi đọc history đủ cả hai; A trả lời xong trước dựa trên history thiếu tin 2 → hỏi lại đúng thứ khách vừa nói ở tin 2 → khách nhận 2 tin, tin đầu hỏi thừa. Đề xuất rẻ nhất: debounce ~1.5–2s theo từng số điện thoại trước khi gọi converse() — nếu có tin mới đến trong cửa sổ đó thì gộp vào cùng một lượt thay vì gọi model riêng. Chưa làm — cần xác nhận trước vì đổi timing đua với cửa sổ redelivery 20s của Meta.
code
Không bao giờ im lặngXong 18/09: fallbackReply("apology", lang) trong questions.ts — provider lỗi/quá hạn thì khách nhận một câu xin lỗi tĩnh (en/vi/zh theo chính lời khách) và thread được đánh dấu cần người thật. Claim được giữ lại vì khách đã nghe được gì đó, nên redelivery của Meta là duplicates: 1 chứ không thành tin thứ hai. Bằng chứng: whatsapp.test.ts — "apologizes rather than falling silent…" (gateway 500 hai lần ⇒ replied: 1, failed: 1, handoffs: 1, history có câu xin lỗi) và test deadline (turn quá hạn ⇒ vẫn đúng 1 tin gửi đi).
xong 18/09
Handoff tối thiểuXong 18/09: cờ paused + wantsHuman() + ASK_LIMIT=8 được đọc trước khi gọi model (app.ts), lưu trong conversationStore (pause/resume/needsTelling/markTold). Khách được nói một lần, không lặp lại câu giữ chỗ ở mỗi tin tiếp theo (HOLD_REPEAT_MS = 10'). Lễ tân đọc và trả thread bằng npm run whatsapp:threads, hoặc GET /v1/channels/whatsapp/threads + POST /v1/channels/whatsapp/threads/:phone/resume (khoá bằng x-verify-token). Test: thread đã pause ⇒ provider.call không tăng; từ khoá escalate tiếng Việt ⇒ 1 tin giữ chỗ tiếng Việt, 0 lần gọi model; quá hạn mức hỏi ⇒ reason: asking_limit.
xong 18/09
Store cho production + contract test dùng chungXong 24/09 (phần contract test): packages/extractor/test/conversationStore.contract.test.ts — một spec 16 test chạy trên cả hai adapter (in-memory + Redis REST) qua bảng ADAPTERS, thêm adapter mới chỉ cần một dòng. Bao phủ thứ tự lượt, cap MAX_TURNS, claim NX + fenceToken, hết hạn in-flight 60s nhưng "done" giữ 24h, park/list/resume, needsTelling theo cửa sổ lặp, clear(), phone lock (kể cả khi work ném lỗi), TTL thread 24h. Lỗi thật tìm được khi viết spec: mock KV cũ trong redisStore.test.ts trả "OK" cho mọi lệnh nó không biết và không xử lý SADD/SMEMBERS/SREM — nên đường pause/resume/giữ chỗ chưa từng được test trên Redis, đúng loại lệch chỉ hiện ở production. Mock mới ném lỗi khi gặp lệnh lạ. Còn lại: chốt backend chính thức (Upstash/Vercel KV hay Postgres) — hiện chọn theo env KV_REST_API_URL, production chưa cấu hình nên vẫn in-memory.
xong 24/09
ADR-006: commit file quyết định contract trả lờiXong 18/09: docs/adr/ADR-006-reply-contract.md, status proposed (chờ Anthony ký), có dòng Supersedes ghi rõ clause cap 8 lượt của ADR-005a đã bị thay bằng cap theo kích thước. Nội dung: một tin mỗi lượt do code viết, 3 loại reply, house-norm chỉ hiện chứ không hỏi, không suy diễn field ảnh hưởng tiền, evidence + language chỉ đọc lời khách.
xong 18/09

L3 · Hợp đồng & nội dung

2 ngày · làm được mà không chờ ai

Sau L2, kênh đã "cứng". L3 làm cho câu trả lời đúng và tất định — phần duy nhất khách thực sự nhìn thấy.

Hợp đồng hoàn tất: tách READY_FIELDS khỏi danh sách hỏidone = questions.length === 0 chỉ phủ 7 field trong PRIORITY. WIP vừa thêm 5 field optional (transportType, diver, guestType, diveFrom, diveTo) mà không field nào được hỏi ⇒ done:true vẫn có thể xảy ra khi chưa biết roundtrip. Điều kiện bàn giao phải tách khỏi điều kiện hỏi. Cập nhật 18/09: diveFrom, diveTo và transportType nay được hỏi khi áp dụng được ⇒ lỗ "chưa biết roundtrip mà vẫn done:true" đã hẹp lại. Cập nhật 18/09 (lần 2): diver nay đã nằm trong danh sách hỏi (rule mới trong questions.ts, không còn suy từ regex), nên chỉ còn guestType là field optional không bao giờ được hỏi — READY_FIELDS vẫn phải tách. Cập nhật 24/09: đã tách. questions.ts có HANDOFF_REQUIRED_FIELDS (13 field), NEVER_ASKED_FIELDS (kèm nguồn giá trị: checkOut do code suy ra, guestType do người thật xác nhận) và isReadyForHandoff(trip); converse.ts dùng nó cho done. Danh sách hỏi và điều kiện bàn giao cùng đọc từ một hàm openRules() nên không thể mâu thuẫn. Lỗi thật đã mắc và bị test bắt: bản đầu coi 3 field lặn là bắt buộc vô điều kiện, trong khi rule của chúng bị gate bởi diver === true và diveNotes vắng mặt — nên mọi khách không lặn và mọi ca lịch lặn chia ngày (đúng ca mà NEVER-RE-ASK sinh ra để phục vụ) không bao giờ bàn giao được. Sửa: field bắt buộc chỉ bị kiểm khi rule của nó áp dụng cho chuyến này. Test: 4 test mới trong questions.test.ts, gồm test bất biến "mọi field bắt buộc phải được hỏi, hoặc do code điền, hoặc có lý do never-ask".
xong 24/09
Sửa lỗi tiền: transportType đang bị suy diễnextract.ts tự suy roundtrip từ dữ liệu khác trong khi giá phụ thuộc vào nó. ADR-006 Decision 4 (mơ hồ ⇒ missing và hỏi lại) là cách sửa đúng — phải làm trước demo. Cập nhật 18/09: phần diver của lỗi tiền đã sửa — regex isDiving và dive window suy diễn đã bị xoá, diver nay là câu hỏi và cửa sổ lặn chỉ hỏi sau khi khách xác nhận. Riêng transportType vẫn còn derived + hỏi lại khách, tức là chữa triệu chứng — giá vẫn đang phụ thuộc một giá trị do code tự đoán. Cập nhật 19/09 (chạy thật trên điện thoại): provider có lúc bỏ hẳn key diver khỏi tool arguments — cùng một tin của khách mà lượt này hỏi “có lặn không”, lượt sau không hỏi nữa, không lỗi, không log. Đã sửa ở extract.ts: key vắng mặt, cũng như state chỉ code được đặt (default/derived), bị quy về missing ⇒ thành câu hỏi; riêng 3 field lặn chỉ stated mới sống sót. Bằng chứng: extract.test.ts 3 test mới + questions.test.ts 1 test cho key vắng mặt (npm run verify 108/108). Cập nhật 24/09: hết suy diễn. postProcess không còn ghi roundtrip. Chỉ còn một trường hợp code được phép điền: khách từ chối transfer ⇒ none, derived (không cần hỏi gì). Khách cần transfer mà chưa nói một chiều hay khứ hồi ⇒ để {value:null, state:"missing"}, câu hỏi trong questions.ts nổ ra, và giá lấy từ câu trả lời của khách. Test: extract.test.ts 2 test viết lại, questions.test.ts 1 test viết lại, evalReplay cập nhật theo hành vi mới.
xong 24/09
Trạng thái assumed cho default ảnh hưởng tiềnguestType mặc định retail và transportType hiện là default im lặng — nhưng agent được giảm 30%, nên một default sai là một báo giá sai. Phải hiển thị cho người thật, không nói với khách.
code
Một tin mỗi lượt: chào → xác nhận + hỏi tiếp → tóm tắtXong 18/09 theo yêu cầu lead: converse.ts không còn gửi questions[0]; renderFormMessage() đã được thay bằng renderReply() với ba câu tất định (ADR-006). Khách chưa nói gì ⇒ greeting (giới thiệu Casa, xin ngày nhận phòng / số đêm / số khách / tên). Đã hiểu một phần ⇒ xác nhận đúng những gì khách nói rồi hỏi nốt theo thứ tự ưu tiên. Hết mục cần hỏi ⇒ summary in ra từng giá trị để khách kiểm. House-norm (phòng / bữa ăn / đưa đón) không còn bị hỏi (BASELINE = ["missing"]) mà hiện trong summary kèm nhãn (assumed). PRIORITY đổi thành RULES có điều kiện when: diveFrom/diveTo chỉ hỏi khi khách có lặn, transportType chỉ hỏi khi khách cần đưa đón. Bằng chứng: questions.test.ts (9 test: 3 loại reply, cờ (assumed), ngày theo en/vi/zh) + converse.test.ts (6 test) + whatsapp.test.ts (1 tin khách ⇒ 1 tin WhatsApp) + normalize.test.ts (7 test) · npm run verify 12/12 file, 91/91 test. Đã bù 18/09 (L2): câu xin lỗi tĩnh + cờ paused — khách không còn nhận không gì cả.
xong 18/09
Renderer tất định cho câu hỏi và câu xác nhậnXong 18/09 — ADR-006 đã được viết: docs/adr/ADR-006-reply-contract.md. Model không viết câu nào cho khách; renderReply() trong questions.ts chọn một trong ba câu tất định (greeting / questions / summary) và trả kèm replyKind cho BFF. Vì không có model nào viết câu trả lời nên nó không thể cam kết giá/phòng: câu cuối nói rõ “nothing is booked yet” rồi mời người thật xác nhận. Bằng chứng: test/questions.test.ts (9 test: 3 loại reply, nhãn (assumed), ngày theo en/vi/zh).
xong 18/09
Bổ sung ngày trong tuần còn thiếuXong 18/09: WEEKDAYS trong dates.ts có đủ dạng số (thứ 2…thứ 7 và thu 2…thu 7) bên cạnh dạng chữ. Đây là lỗi thật: khách trả lời “thứ 7 tuần sau” trước đó resolve ra null ⇒ mất ngày nhận phòng. Test dùng TODAY cố định 2026-09-15, không dùng ngày thật: dates.test.ts (10 test) — “thứ 7 tuần sau” ⇒ 2026-09-26.
xong 18/09
Biến kịch bản Anh Minh thành golden test + case evalXác nhận 18/07 vs 25/07, nhóm 1+1, transport mơ hồ. Case này phải được thêm vào dataset eval để ngưỡng "fabricated = 0" bắt được hồi quy — đây là cơ chế khiến lỗi tiền không quay lại.
code
Đo latency turn 1 vs turn 12 trước khi bàn window + anchorADR-005a phê duyệt p95 ≤ 8s; con số "1.8s → 4–6s" trong ADR-006 không có phép đo nào trong repo. Không đo thì không có cơ sở đảo ngược ADR-005a.
cần số đo

L4 · Chờ người khác → mới được làm

theo lịch của người khác

Không việc nào dưới đây làm được trước khi có đầu vào tương ứng. Danh sách này thay cho các mục "Open Items" đã lỗi thời trong sprint tracker.

Anthropic API key (Anthony)Đường chính thức cho extractor ở cả preview/staging/production theo Delivery Plan 16/09. Viết adapter được (test bằng fetch giả) nhưng kiểm chứng thật thì phải có key. Ghi chú: mục "bật billing Gemini" trong tracker đã lỗi thời.
chờ key
Freeze schema của Phillipschema.ts tự ghi là PLACEHOLDER. Mọi endpoint mới dựa trên nó — xây trên placeholder là xây trên cát.
chờ Phillip
House-norm thật + giá trị mặc định (Jett / Eloa)Đoán sai mặc định đọc lên thành bịa trong eval — trùng đúng trục rủi ro của L3.
chờ norm
30 tin thật đã che tên (Eloa)Đây mới là dataset bake-off thật. Sau khi có: LLM-judge cho tiêu chí "câu hỏi đúng trọng tâm" → chạy leaderboard → ADR-005b.
chặn ADR-005b
Quyết định mask PII trước khi gửi hay chỉ trước khi log (Anthony / Sky)Nếu mask trước khi gửi thì lý do loại DeepSeek vì data-residency cần xem lại — tức là thay đổi Gate A của ADR-005a.
chờ quyết
Mốc cuối, giữ nguyên từ bản 17/09: nối Extractor vào form Estimator UI thật, demo 20 phút với Evane. Chuỗi phụ thuộc: key → adapter → 30 tin thật → ADR-005b → nối UI. Không nhảy cóc.

Definition of Done — thứ bản 17/09 không có

áp cho mọi việc ở trên

Bản 17/09 liệt kê việc nhưng không nói thế nào là xong, nên "xong" trôi theo trí nhớ. Một việc chỉ được coi là Done khi có cả 4:

① Một commit trên mainKhông phải "đã viết trong working tree". Nếu chưa commit, nó không tồn tại với người còn lại.
commit
② Một test hoặc phép đo chứng minh"Đã review", "trông ổn", "chắc là chạy" không tính. Ví dụ ở L1: npm run verify exit 0 + 10/10 test file pass.
test
③ Một dòng trong sprint trackerTracker là nguồn sự thật duy nhất. Lưu ý: sheet "Status Summary" đang đếm cứng D5:D15 ⇒ thêm dòng mới sẽ không được đếm, phải sửa formula trước.
tracker
④ Env/tài liệu liên quan cập nhật trong cùng commitKhông có env var mới nào được dùng trong code mà chưa có trong §6. Đây chính là thứ đã lệch ở L0.
doc
Luật viết: không có số đo thì không được ghi sốADR-005a sống bằng luật này. ADR-006 đang vi phạm với "1.8s → 4–6s" và "dưới 2.0s ở lượt 15" — cả hai đều không có phép đo trong repo, và con số thứ hai còn bất khả thi so với Gate B p95 ≤ 8s của ADR-005a.
luật

Roadmap phải nói KHÔNG với gì

quan trọng ngang việc nói có

Roadmap cũ chỉ liệt kê việc sẽ làm, nên không ai thấy việc gì đang bị hoãn ầm thầm. Ghi rõ ra:

Không làm sliding window + state anchor ngayADR-006 §5 đảo ngược quyết định 5 của ADR-005a mà không có dòng Supersedes. "Anchor" nghĩa là merge state — một bề mặt lỗi mới cho trục zero-hallucination. Code hiện tại (MAX_TRANSCRIPT_CHARS = 60_000, giữ đầu + đuôi) vẫn giữ được dữ kiện. Chỉ làm sau khi có số đo ở L3.
hoãn
Không xây endpoint mới / Odoo client trên schema placeholder/v1/estimate/compute, /v1/booking/submit, draft store… đều chờ Phillip freeze schema. Xây trước là tự tạo nợ phải viết lại.
hoãn
Không làm rate limit (Gate G1) trước demoCần trước khi cho người ngoài pod dùng thử, nhưng nó không chặn demo — và L2 chặn rủi ro demo lớn hơn.
hoãn
Không làm LLM-judge trước khi có 30 tin thậtJudge để chấm "câu hỏi đúng trọng tâm" trên 30 tin thật; viết judge khi chưa có dữ liệu là tối ưu mù.
hoãn
Adapter Claude: 2 ngày cho adapter hay 2 ngày cho L2?Adapter viết được ngay bằng fetch giả, nhưng kiểm chứng thật thì chờ key. Đề xuất: làm L2 trước vì nó chặn rủi ro khách nhìn thấy (không mất lượt, không double reply, không im lặng), còn adapter chỉ chờ một đầu vào bên ngoài.
chờ quyết

Lịch theo ngày

từ 18/09 tới mốc demo

Thứ tự này là thứ tự phụ thuộc, không phải thứ tự sở thích: L0 trước L1 vì không có cây nguồn đóng băng thì CI chỉ báo đỏ vì việc của người khác; L2 trước L3 vì cứng kênh rẻ hơn và chặn rủi ro lớn hơn.

18/09 (tối nay) — L0Commit theo chủ đề, push, deploy, bổ sung §6, xoay khoá. Ra được: env prod chạy, tài liệu khớp code.
hôm nay
19/09 — L1 xong + L2.1–L2.2CI xanh lần đầu, hết lỗi claim 24 giờ và double reply (kèm test "3 lần giao ⇒ 1 reply").
ngày 2
20–21/09 — L2.3–L2.7Khoá thread + gộp tin, không bao giờ im lặng, handoff tối thiểu, store prod + contract test, ADR-006 hạ về proposed và được commit.
ngày 3–4
22–23/09 — L3 (phần lõi)Hợp đồng hoàn tất + sửa lỗi tiền transportType + default assumed + dạng ngày Việt + golden test Anh Minh. Ra được: done có nghĩa, không còn đường nào để bịa giá.
ngày 5–6
24–25/09 — L3 còn lạiRenderer tất định, nhóm 1+1, đo latency, rồi mới quyết window + anchor và cập nhật ADR-006/007.
ngày 7–8
Khi có key — L4Adapter Claude → LLM-judge → 30 tin thật → ADR-005b → nối Estimator UI → demo Evane.
theo key

Rủi ro & cách chặn

5 rủi ro, mỗi cái có một cơ chế cụ thể
R1 · WIP tiếp tục phìnhĐã 16 file modified + 5 file test mới. Chặn bằng L0.1 (commit theo chủ đề) + L1.1 (CI) — CI là thứ khiến việc đóng băng có giá trị lâu dài.
rủi ro
R2 · Tài liệu lệch code (đã xảy ra 3 lần)roadmap 17/09 lệch 1 chặng, tracker đếm cứng tới dòng 15, ADR-006 chưa từng được commit. Chặn bằng DoD ③④ và luật "ADR không commit = không tồn tại".
rủi ro
R3 · Zero-hallucination bị phá qua đường derived/defaultĐúng cơ chế đã gây lỗi roundtrip. Chặn bằng trạng thái assumed + luật renderer + case eval để ngưỡng "fabricated = 0" bắt được hồi quy.
rủi ro
R4 · Prod chưa có WHATSAPP_* ⇒ webhook 404Đây là blocker cứng của mọi demo qua WhatsApp. Chặn bằng L0.2.
rủi ro
R5 · Trần thời gian function vs p95 modelKhi vượt trần, khách nhận im lặng. Chặn bằng claim TTL ngắn, câu xin lỗi tĩnh, và số đo p95 thật ở L3.
rủi ro
Bản này khác bản 17/09 ở đâu: bản cũ trả lời "làm gì tiếp". Bản này trả lời cả "thế nào là xong", "cái gì cố ý không làm", và "cái gì đang chờ người khác" — ba thứ mà thiếu chúng thì roadmap nào cũng sẽ lệch lại sau một ngày.