13 KiB
CICD-K6: PASS — 5/5
cicd-monitor — verify deploy K6 (S167, 2026-08-01)
Push range e202393..1c6d77a (2 commit: d82c5a8 wal-flush + 1c6d77a K6). ĐÚNG 1 file code fe-admin/src/components/Layout.tsx. 0-mig · fe-user 0-diff · BE 0-diff (đo: git diff --name-only e202393..1c6d77a -- fe-user/ src/Backend/ tests/ = 0 file).
Run #440 (task id 553) — success, 11:54:38 → 12:01:07 (6m29s, trong dải quen 5m3x–6m3x).
Artifact ghi TỪNG MỤC ngay khi có bằng chứng (luật #53: ghi-đĩa-TRONG-lúc-làm; return chỉ là tóm tắt).
M0 — Mốc PRE (tự đo LIVE lúc run CÒN running, KHÔNG tin số chép)
Cửa sổ vàng: bắt được #440 ở running lúc 11:55:43 ⇒ bundle LIVE lúc đó = PRE thật.
| App | index-*.js | index-*.css | size js (B) | Last-Modified js | Content-Type |
|---|---|---|---|---|---|
| admin | index-C2FhHCNT.js |
index-DqXm5Hpn.css (86.495) |
1.758.685 | 01 Aug 04:13:05 GMT = 11:13:05 +07 | application/javascript |
| eoffice | index-DFOCQ2ks.js |
index-DlN3yZ5L.css (92.233) |
1.676.752 | 01 Aug 04:14:05 GMT = 11:14:05 +07 | application/javascript |
🔑 PRE tự chứng là bundle #439 bằng LM, không chỉ bằng hash: LM 11:13:05 / 11:14:05 nằm TRỌN trong cửa-sổ deploy #439 (11:08:17 → 11:14:33). Trùng baseline đề bài — nhưng trùng đó là KẾT QUẢ ĐO, không phải giả-định đầu vào (bài "mốc PRE lão hoá sau MỖI deploy").
Content-Type application/javascript + ~1,7MB ⇒ không dính bẫy SPA-fallback (text/html ~900B). File tải về khớp byte-for-byte Content-Length.
M0-bis — Chọn byte-marker CÓ RĂNG (verify 0-hit PRE TRƯỚC khi phong)
Đề bài cảnh báo đúng: K6 = 12 key literal đã có từ K4a + comment sẽ bị Vite strip ⇒ marker ngây thơ = 0 bit. Đo PRE xác nhận từng cái:
❌ LOẠI "key đơn lẻ" — PRE admin đã có sẵn: PurchaseEvaluations 4 · KeHoachKyKet 1 · HopDongCung 1 · PeWorkflows 3 ⇒ POST có hit cũng 0 bit.
❌ LOẠI tên biến ADMIN_HIDDEN_KEYS — minifier đổi tên; đo POST: source-name 0 hit, thực tế thành var IW=new Set([...]). (Bài K3 earlyFinalizeLocked tái xác nhận.)
❌ LOẠI comment lineage — NƠI-CONFIG / thắng mốc trước: PRE 0 POST 0 ⇒ Vite strip đúng như dự đoán.
✅ CHỌN marker HỢP-CHẤT: TRẬT TỰ KỀ NHAU của 12 literal trong new Set([...]). Từng literal thì cũ, nhưng thứ tự kề nhau chỉ sinh ra khi Set mới được minify. Lineage source: git grep ADMIN_HIDDEN_KEYS @e202393 = 0 hit (exit 1) · @1c6d77a = 2 hit ⇒ marker chưa tồn tại ở mốc PRE.
✅ Marker ÂM (K6 là DISPLAY-ONLY, không gỡ route): /purchase-evaluations, /khkk/list, /suppliers PHẢI CÒN trong bundle admin POST.
✅ Differential: eoffice kỳ vọng FROZEN (fe-user 0-diff) ⇒ marker phải 0 ở eoffice cả PRE lẫn POST.
Mục 1 — Run Gitea cho 1c6d77a ✅ PASS
| head_sha | 1c6d77a6ccd95b2e287a3602f23780558c9d1ecc (khớp HEAD; git log origin/main..HEAD rỗng) |
| run | #440 / task id 553 / status=success |
| thời gian | created 11:54:38 → updated 12:01:07 = 6m29s |
| tail log | Deploy done. App pool started. → API /health/live -> 200 → 🏁 Job succeeded |
paths-ignore (7-glob): 8/10 file trong range là .claude/** (bị bỏ qua), nhưng fe-admin/** KHÔNG ⇒ CI đúng ra phải chạy, và nó đã chạy.
Mục 2 — Gate CI 622 = 45 D + 577 I ✅ PASS (tách-phần, khớp từng vế)
Đo ở web-UI log …/actions/runs/440/jobs/0/logs (18.697 B):
| Project | dòng log | Failed | Passed | Skipped |
|---|---|---|---|---|
SolutionErp.Domain.Tests.dll |
L29 | 0 | 45 | 0 |
SolutionErp.Infrastructure.Tests.dll |
L47 | 0 | 577 | 0 |
| Tổng | 0 | 622 | 0 |
- Khớp dự đoán TRƯỚC khi đo: giữ nguyên 622, delta 0 — đúng: K6 chỉ thêm
Set+ comment, 0 file test trong range. - control ÂM:
grep -c 'Failed!'= 0; pattern lỗi = 1 hit duy nhất là dòng runner vô hạiFailed to setup Pty Unsupported(L12, có ở mọi run). - Flaky đã khai
DeleteContractSigningPlan_SoftDeletes: run này KHÔNG đỏ (Failed 0). Mốc #439 xanh, #440 xanh ⇒ 2 run liên tiếp sạch, chưa cần re-run.
Mục 3 — Mig GIỮ 71 + sys.tables 97 ✅ PASS (2 nguồn)
- Nguồn 1 — git:
git diff e202393..1c6d77a -- '*Migrations*'= rỗng ⇒ 0-mig phía code. Đếm file repo (filter neo-đuôiDesigner\.cs$|ModelSnapshot\.cs$— bản vá từ K5) = 71. - Nguồn 2 — sqlcmd prod (đo SAU
status=success, tức sau recycle):MIGTOP=20260731085624_AddKhkkApprovalGroupCatalogAndFinalizeRuntime(= Mig 71, GIỮ) ·MIGCOUNT=71·SYSTABLES=97(is_ms_shipped=0). - Anchor DB không nhích (đúng cho FE-only):
MENUITEMS=200·PERMS=2221— y hệt mốc #438.
Mục 4 — Bundle: admin ROTATE / eoffice FROZEN-hợp-lệ ✅ PASS
| App | asset | PRE | POST | size | LM POST (+07) | trong cửa-sổ deploy? |
|---|---|---|---|---|---|---|
| admin | js | C2FhHCNT |
Ig1R5tAh ROTATE |
1.758.685 → 1.758.853 (+168) | 11:59:40 | ✅ (11:54:38–12:01:07) |
| admin | css | DqXm5Hpn |
DqXm5Hpn FROZEN |
86.495 (giữ) | 11:59:40 | ✅ |
| eoffice | js | DFOCQ2ks |
DFOCQ2ks FROZEN |
1.676.752 (giữ) | 12:00:41 (PRE là 11:14:05) | ✅ |
| eoffice | css | DlN3yZ5L |
DlN3yZ5L FROZEN |
92.233 (giữ) | 12:00:41 | ✅ |
Admin rotate = ĐẠT điều kiện FAIL-nếu-không của đề bài. Δ +168 B — dương, nhỏ, đúng cỡ 1 new Set 12 key backtick (~170 ký tự); comment bị strip nên không cộng thêm.
🔑 eoffice FROZEN là LÀNH TÍNH — chứng bằng 3 nhân chứng độc lập, KHÔNG phải "đoán vì fe-user 0-diff":
- LM ĐÃ ĐỔI 11:14:05 → 12:00:41, nằm trong cửa-sổ #440 ⇒ file có bị ghi lại (deploy.yml copy
dist\*vô điều kiện = #69 mode-A), không phải bundle cũ kẹt lại. Đây là discriminator quyết định: bundle-cũ-kẹt sẽ giữ LM 11:14:05. - Log CI in thẳng asset phát ra — L128
dist/assets/index-DFOCQ2ks.js 1,676.75 kBlúc05:00:41.56GMT ⇒ runner ĐÃ BUILD LẠI fe-user trong CHÍNH run này và Vite phát ra cùng hash. LM trên prod = mốc build này khớp tới từng giây. Frozen = build-determinism, không phải skip. cmpPRE vs POST eoffice = byte-identical ⇒ nhất quán với source 0-diff. (Đối chiếu admin: L93dist/assets/index-Ig1R5tAh.js 1,758.85 kB@04:59:40.39— khớp cả hash lẫn size lẫn LM prod. Log-CI là nhân chứng thứ 4, độc lập với curl prod.)
🔑 Control-ÂM tầng-2 (chứng ghi-đè thật): GET hash CŨ admin index-C2FhHCNT.js → 200 text/html 900B ⇒ rơi về SPA-fallback ⇒ bundle cũ đã biến mất khỏi đĩa. (200 ở đây KHÔNG phải "còn sống" — discriminator là Content-Type.)
4-bis — Byte-marker: 🔴 SUÝT FAIL-OAN 2 LẦN vì CƠ-CHẾ REGEX, không phải vì code
Marker hợp-chất đo lần đầu ra PRE 0 / POST 0 — đọc vội thì thành "K6 không ship" ⇒ FAIL. Không phong vội, đi soi byte thật (grep -oE '.{90}HopDongCung.{90}') thì thấy dạng minify THẬT:
var IW=new Set([`PurchaseEvaluations`,`KeHoachKyKet`,`Contracts`,`HopDongCung`,`Forms`,
`Reports`,`Master`,`Hrm`,`Off`,`Personal`,`Workflows`,`PeWorkflows`]);
- Sai lần 1: regex của tao chỉ chấp
["']— rolldown/Vite 8 phát backtick (template literal). 0-hit là do regex không thể khớp, KHÔNG phải do vắng mặt. - Sai lần 2: vá xong, truyền pattern qua biến trong
"..."→ backtick bị shell nuốt,grep -cEgãy (grep: Unmatched () và trả 0 gần như im lặng trong vòng lặp. Lại một 0-hit giả. - Chốt bằng
grep -Ffixed-string (không còn regex để sai):
| Marker | PRE admin | POST admin | POST eoffice | kỳ vọng | |
|---|---|---|---|---|---|
Trọn chuỗi 12-key new Set([...]) |
0 | 1 | 0 | 0→1, eoffice 0 | ✅ |
Adjacency 3-key `PurchaseEvaluations`,`KeHoachKyKet`,`Contracts` |
0 | 1 | 0 | 0→1 | ✅ |
control-ÂM đảo trật tự `KeHoachKyKet`,`PurchaseEvaluations` |
0 | 0 | 0 | 0 | ✅ |
control-ÂM chuỗi bịa ZZZ_NOT_EXIST_MARKER |
0 | 0 | 0 | 0 | ✅ |
🔑 COUNT-DELTA — nhân chứng thứ 2, độc lập với adjacency. Vì literal đã tồn tại từ K4a nên sự có mặt = 0 bit, nhưng số lần xuất hiện tăng thì đo được. PRE→POST admin, cả 12/12 key đều +1:
PurchaseEvaluations 4→5 · KeHoachKyKet 1→2 · Contracts 7→8 · HopDongCung 1→2 · Forms 3→4 · Reports 3→4 · Master 4→5 · Hrm 28→29 · Off 400→401 · Personal 2→3 · PeWorkflows 3→4 · Workflows 9→11 (+2).
Con +2 duy nhất KHÔNG phải bất thường mà là kiểm-tra-nhất-quán tự thân: Workflows là substring của PeWorkflows, nên Set thêm 1 Workflows + 1 PeWorkflows ⇒ đếm substring ra +2. Nếu K6 chỉ ship một phần thì hình dạng 12×(+1) với đúng 1 ngoại lệ giải-thích-được này sẽ không dựng lại được.
🔑 Marker ÂM (display-only, KHÔNG phải gỡ route) — ĐẠT: /purchase-evaluations 68→68 · /khkk/list 13→13 · /suppliers 16→16. Route còn nguyên trong bundle admin ⇒ K6 cắt đúng lớp hiển thị, không lỡ tay cắt lớp routing.
Mục 5 — Smoke + phép K6-đặc-thù ✅ PASS
Bearer admin: POST /api/auth/login → accessToken len 468 ✅
| Endpoint | code |
|---|---|
GET /api/contracts |
200 |
GET /api/purchase-evaluations |
200 |
GET /api/menus |
200 |
GET /api/contract-signing-plans |
200 |
control-ÂM GET /api/khong-ton-tai-zzz (có bearer) |
404 ✅ |
control-ÂM GET /api/contracts KHÔNG token |
401 ✅ |
🔑 Phép K6-đặc-thù — 2 tầng độc lập (gotcha #82) đo được bằng số: GET /api/menus bearer admin trả 200 item (khớp MENUITEMS=200 sqlcmd ⇒ không mất row nào). Trong đó 10/10 root bị K6 ẩn VẪN được BE trả về: Contracts, Forms, HopDongCung, Hrm, KeHoachKyKet, Master, Off, Personal, PurchaseEvaluations, Reports — cộng cả 2 con của System là Workflows + PeWorkflows ⇒ 12/12.
⇒ Đúng như comment K6 tự khai: ẩn ở client, KHÔNG thu quyền. Deep-link + API vẫn 200. Muốn CHẶN thật phải làm ở BE authz.
Verdict
PASS 5/5. Run #440 1c6d77a success 6m29s · gate 622 = 45 D + 577 I (Failed 0, delta 0 đúng dự đoán) · Mig GIỮ 71 + sys.tables 97, MenuItems/Perms đứng im 200/2221 · admin ROTATE Ig1R5tAh (+168 B) & eoffice FROZEN-lành-tính (LM đổi + log CI in cùng hash + byte-identical) · marker 12-key Set PRE 0→POST 1 + count-delta 12/12 + marker-ÂM route 68/13/16 nguyên vẹn · smoke 4/4 + 2 control-âm + menu-tree 12/12 key vẫn được BE phục vụ.
Treo / khuyến nghị (không chặn):
- 🔴 Bài học to nhất run này: 0-hit marker bị SAI 2 lần liên tiếp do cơ-chế regex, cả 2 lần đều trông y hệt "code không ship". (a) rolldown/Vite 8 minify string → backtick, regex neo
["']không bao giờ khớp; (b) truyền pattern chứa backtick qua biến trong"..."làm grep gãy và trả 0 gần như im lặng. ⇒ Từ nay: marker chuỗi trên bundle dùnggrep -Ffixed-string, và luôn trích byte thật quanh literal (.{90}X.{90}) trước khi kết luận vắng mặt. - Kỹ thuật mới dùng được lại — COUNT-DELTA: khi literal đã tồn tại từ đợt trước (marker "có/không" = 0 bit), đo số lần xuất hiện PRE→POST. Ngoại lệ substring (
Workflows⊂PeWorkflows⇒ +2) lại thành kiểm-tra-nhất-quán miễn phí. - Log CI in thẳng
dist/assets/index-<hash>.js <size>— nhân chứng thứ 4 cho ship-proof, độc lập hoàn toàn với curl prod, và là cách rẻ nhất phân biệt FROZEN-lành-tính với bundle-kẹt (so LM prod với mốc build in trong log).
Bundle baseline MỚI (post-#440): admin Ig1R5tAh/DqXm5Hpn · eoffice DFOCQ2ks/DlN3yZ5L. (Snapshot-per-run — lão hoá ngay ở deploy kế.)
END cicd-k6 — VERDICT=PASS 5/5