TATrương Tuấn AnhTuna / truongtuananh.vn
Tất cả bài viết
ngày ghi
phút đọc
6
nguồn dẫn
7

Cổng kiểm pass giả: tải được 0/8 trang mà script vẫn in “không tràn ngang”

Bộ kiểm bố cục tải được 0/8 trang, quét trợ năng 0 trang, vẫn thoát mã 0. Cách tôi sửa nó về fail-closed và nguyên tắc tiêm lỗi cho checker mới.

Chủ đề: cổng kiểm, vận hành, ai có người duyệt

Ngày 18/08/2026, tôi đưa website cửa chống cháy cho Codex review toàn bộ. Kết luận số 5 là dòng tôi nhớ nhất: cổng kiểm bố cục đang cho pass giả. Bài này kể lại lỗi đó, cách sửa, và một kỷ luật tôi đã có ở dự án khác mà quên áp dụng.

Cái log nhìn rất yên tâm

Bộ kiểm bố cục mở trình duyệt thật bằng Playwright, tải từng trang ở 5 bề rộng, đo tràn ngang, ảnh méo, nút chat che nút bấm, rồi chạy axe-core quét trợ năng. Kết quả lần audit đó:

Bề rộngTrang tải được
320px0/8
390px0/8
768px0/8
1440px0/8
1560px0/8
axe-core0 trang

Sau bảng đó, script vẫn in "không tràn ngang, không ảnh méo" và thoát với mã 0. Lý do rất đơn giản. Lỗi tải trang được đẩy vào mảng canhBao, không vào mảng loi. Cuối script chỉ đếm loi. Mảng rỗng thì xanh. Thiếu Playwright thì cũng thoát 0 nốt.

Codex chấm "Accessibility confidence" 3/10, lý do là không thể coi là pass khi axe đã quét 0 trang.

Điều làm tôi khó chịu không phải con bug, mà là việc tôi đã coi dấu tích xanh là bằng chứng, trong khi Codex ghi thẳng: chưa có bằng chứng kiểm thử mới hợp lệ. Bộ kiểm chỉ trả lời câu hỏi "có lỗi nào ghi vào danh sách lỗi không". Tôi là người hỏi sai câu.

Sửa thành fail-closed

Codex đặt Phase 0 là sửa độ tin cậy của quy trình, trước khi polish giao diện, và nêu sáu yêu cầu cho cổng kiểm, từ "route không trả 2xx là lỗi chặn" tới "CI không được coi Playwright không cài là pass". Exit gate ghi một câu: test thực sự chạy, không phải chỉ exit 0.

Claude Code hiện thực. tools/kiem-tra-bo-cuc.mjs hiện chặn ở các điểm sau:

  • Origin chết thì dừng ngay. Trước khi mở trình duyệt, script fetch trang gốc với timeout 5 giây. Không tới được thì exit 1 kèm hướng dẫn start server.
  • Route không trả 2xx là lỗi chặn, không phải cảnh báo, kèm mã HTTP trong log.
  • Cổng đếm. Số lượt đo phải bằng số route nhân số bề rộng, lệch là lỗi "BỘ KIỂM KHÔNG ĐỦ DỮ LIỆU". Số trang axe quét phải bằng số route.
  • Thiếu Playwright hoặc axe-core thì exit 1. Thông báo in đúng chữ "không phải bỏ qua".
  • CI làm đủ việc trước khi kiểm. Cài Chromium, start server, curl tối đa 30 lần chờ server trả lời, rồi mới chạy cổng.
  • Chụp ảnh cho người xem. Các route canonical ở 390/768/1440 lưu vào .kiem-tra/anh/.

Số cuối phiên 18/08: bố cục 70/70 lượt đo thật, tức 14 route nhân 5 viewport, 0 lỗi. Danh sách route hiện đã là 15 trang. Axe quét 14/14 trang ở 390px, 0 vi phạm mức serious hay critical. Screenshot 4 route nhân 3 bề rộng, tôi tự mở lên nhìn trong phiên.

Tiêm lỗi cho đỏ rồi mới tin

Ở bộ khung ERP bot, tôi đã viết từ trước vào tài liệu tổng quan một kỷ luật: checker mới phải được tiêm lỗi cho đỏ rồi mới tin. Bộ đó có 153 test logic thuần cộng 6 checker cấu trúc, gom trong một lệnh, đã bắt hơn 80 lỗi thật trong quá trình xây, riêng lỗi import là 51. Kỷ luật có sẵn rồi, nhưng cổng bố cục bên site cửa chống cháy là lần tôi quên áp dụng nó. Một checker chưa từng đỏ là một checker chưa được chứng minh là có chạy.

Phép thử rẻ nhất không cần viết thêm logic. Tắt server, chạy lại, phải đỏ. Gỡ Playwright, phải đỏ. Thêm một route không tồn tại vào danh sách, phải đỏ vì route không trả 2xx và cổng đếm lệch. Bỏ bớt route thì vô nghĩa, vì số kỳ vọng tính từ chính danh sách.

Fail-closed chống được kiểu pass giả "không đo gì". Kiểu thứ hai, "đo thật nhưng thiếu thứ quan trọng", chỉ lộ ra khi bị đau. Script này có hai vết như vậy, ghi ngay trong chú thích:

  • Dải tóm tắt dính đáy ở trang báo giá tràn từ -20 tới 410 trên viewport 390 suốt một vòng mà cổng vẫn xanh. Lúc đo nó còn hidden, bề rộng 0, nên bị bỏ qua. Giờ với trang nhiều bước, script diễn vài thao tác rồi mới đo.
  • Cổng từng xanh trong khi 6 khối nội dung thật đứng ở opacity 0, vì reveal gắn vào phần tử trong dải cuộn ngang không bao giờ được kích hoạt. Không lỗi console, không tràn ngang, ảnh không méo, còn khách thì mất hẳn nội dung. Ngày 21/08/2026 tôi thêm bất biến "nội dung vô hình": có chữ mà không nhìn thấy là lỗi.

Chiều ngược lại cũng phải giữ. Đỏ giả giết cổng kiểm nhanh không kém xanh giả. Để tránh đỏ giả, tôi bỏ nhóm rule best-practice vì nó gắn cờ cả lựa chọn thiết kế hợp lệ. Vi phạm dưới mức serious chỉ vào cảnh báo, không chặn deploy. Còn axe chỉ chạy ở 390px là chuyện thời gian: quy tắc của axe hầu như không đổi theo viewport, chạy 5 lần chỉ tốn 5 lần thời gian cho cùng một kết quả. Một cổng hay báo động giả là một cổng sắp bị tắt.

Bốn cổng và cổng thứ năm

Trước mỗi lần deploy, site chạy bốn cổng. Cái nào đỏ thì không deploy.

CổngViệcĐiều kiện
kiem-tra-sitelink hỏng, ảnh thiếu, animation vô hạnngoại tuyến
kiem-noi-dungngôn ngữ nội bộ, chuỗi ghép hỏng, khối sai loại sản phẩmngoại tuyến
kiem-tien-tođường dẫn sót tiền tố khi site nằm trong thư mục conngoại tuyến
kiem-tra-bo-cuc15 trang nhân 5 bề rộng, cộng axe WCAGcần server ở cổng 8787

Ba cổng ngoại tuyến chạy cả trong Dockerfile. Nội dung sai thì build ảnh hỏng. Đó là lưới cuối cùng.

Cổng thứ năm không nằm trong CI: kiem-hoi-quy.mjs so ảnh chụp hiện tại với thư mục baseline. Nó đỏ khi giao diện đổi, đúng việc của nó. Tôi chỉ chạy --luu để chốt baseline mới khi đã tự mắt thấy bản mới là bản muốn giữ. Lý do tách riêng: baseline sẽ vỡ ở mọi thay đổi thiết kế hợp lệ rồi bị tắt đi, còn các bất biến thì không được vỡ.

Điều tôi rút ra

  • Exit 0 không phải bằng chứng. Bằng chứng là số lượt đo khớp số kỳ vọng, và ảnh chụp có người mở ra xem.
  • Checker mới phải được tiêm lỗi cho đỏ rồi mới tin. Tắt server, gỡ thư viện, thêm một route sai: ba phép thử không cần viết thêm logic nào.
  • Đỏ giả và xanh giả cùng một kết cục: cổng bị tắt. Cái gì hay báo động thì tách khỏi CI, như cổng hồi quy ảnh.
  • Máy pass chưa phải người duyệt. Tôi tự dựng hệ thống với Claude Code và Codex, nhưng dấu tích cuối cùng vẫn là mắt tôi.

Nếu bộ kiểm của công ty bạn cũng đang xanh đều mà chưa ai thử làm nó đỏ, ta nói chuyện 15 phút.

Bài này chạm đúng việc bạn đang làm? Mười lăm phút nói chuyện không mất gì.