15 KiB
CICD-K4AB: IN-PROGRESS — 0/7
cicd-monitor — verify deploy K4a+K4b SP-002 (88e7ecf) + phủ luôn F-1 (7a903cf)
Artifact chống #53: ghi TỪNG MỤC ngay khi có bằng chứng. Kết bằng
END ... VERDICT=. RepoD:\Dropbox\CONG_VIEC\SOLUTION\SOLUTION_ERP· push7a903cf..88e7ecf main· phiên S166 01/08. Khuôn kế thừa k1/k2/k3 cùng folder: tam-giác 3-nguồn ⟂ control ÂM ⟂ recycle-proof ⟂ dự-đoán-TRƯỚC-khi-đo.
§0 — Tiền đề (git, đo LIVE)
HEAD = 88e7ecf263f019f4b31d4defb9520704568042a9 2026-08-01 10:10:11 +0700
[CLAUDE] Contract: K4a+K4b SP-002 sidebar 8 nhom x 6 leaf + noi ?group= end-to-end (0-mig)
git log origin/main..HEAD -> (rỗng — đã push)
git diff --name-only 7a903cf..88e7ecf = 33 file. Phân loại vs paths-ignore 7-glob:
- CODE (13, trigger CI):
- BE 4:
ContractSigningPlansController.cs·ContractSigningPlanFeatures.cs·MenuKeys.cs·DbInitializer.cs - FE-admin 4:
components/Layout.tsx·pages/khkk/KhkkCreatePage.tsx·pages/khkk/KhkkListPage.tsx·types/khkk.ts - FE-user 4: y hệt 4 file trên (cặp song sinh)
- test 1:
tests/…/Application/KhkkGroupMenuSeedTests.cs
- BE 4:
- IGNORED (20):
docs/STATUS.md(**/*.md) +.claude/WAL.md+.claude/agent-memory/**×10 +.claude/workflows/runs/**×8 - 0 file
*Migrations*⇒ K4a+K4b = 0-mig (khẳng định này đo lại độc lập ở §3).
F-1 7a903cf (run #437, chưa verify riêng — lượt này phủ luôn):
git diff --name-only 15349e8..7a903cf = 41 file; CODE 5 (fe-admin/khkk/KhkkWorkflowPanel.tsx + fe-admin/types/khkk.ts + fe-user/khkk/KhkkWorkflowPanel.tsx + fe-user/types/khkk.ts + ContractSigningPlanFeatures.cs) — khớp mô tả "FE+DTO nhỏ"; phần còn lại ignored-path (CLAUDE.md, docs/**, .claude/**).
§0.1 — Snapshot PRE đo LIVE lúc run #438 CÒN running (10:12-10:14 +07)
Đây là mốc PRE MẠNH NHẤT có thể có: đo trong lúc CI đang chạy ⇒ chắc chắn chưa bị K4a/K4b ghi đè.
Bundle PRE (curl index.html, 10:12:09):
admin /assets/index-1yiNV4VH.js + /assets/index-Cf3iCOOv.css
eoffice /assets/index-DoULfmdT.js + /assets/index-DX1FRk5n.css
✔ Khớp ĐÚNG mốc đề bài lead giao (1yiNV4VH / DoULfmdT) và khớp nguồn gốc của mốc đó
(sub-reviewer-gate-k4a.md:131,133 — gate-K4a đo post-#437). 2 nguồn độc lập ⇒ mốc PRE hợp lệ.
Prod DB PRE (sqlcmd localhost\SQLEXPRESS):
MENU_TOTAL = 151
MENU_KHKK_PCT = 7 (đúng 7 key nhóm-1 không-infix: Khkk_G1/WfView/List/Create/Pending/Approved/Deleted)
MENU_KHKK_G1_LABEL = "1. Kế hoạch ký kết HĐ (NCC-TP)" <- nhãn SKELETON S159, chưa backfill
PERM_TOTAL = 1584
PERM_KHKK_PCT = 91 (= 7 × 13, và CanRead=1 cả 91 ⇒ họ Khkk đang mở đủ)
ROLE_TOTAL = 13 (Accounting/Admin/AuthorizedSigner/CatalogManager/CostControl/DeptManager/
Director/Drafter/Equipment/Finance/HrAdmin/Procurement/ProjectManager)
MIGTOP = 20260731085624_AddKhkkApprovalGroupCatalogAndFinalizeRuntime · MIGCOUNT = 71
CONTROL ÂM nền #84 : Hrm*/Off* rows=377 nhưng CanRead=1 chỉ **29** (revoker đang SỐNG, giữ 348 row tắt)
⚠️ Cột PK MenuItems = [Key]; bảng quyền Permissions(Id,RoleId,**MenuKey**,CanRead,CanCreate,CanUpdate,CanDelete)
— 1 ROW / cặp (role,key) với 4 cột cờ, KHÔNG phải 4 row. Bảng role = Roles (non-prefix).
🔴 ĐÍNH CHÍNH MỐC PRE TRONG ĐỀ BÀI (đo, không đoán): lead giao MENU_TOTAL PRE=143 ⇒ kỳ vọng 192.
Đo LIVE ra 151. Truy PHẠM-VI-QUERY trước khi hô drift (bài #422) → giải thích TRỌN, element-wise:
K3 (#436) đẻ thêm 8 menu-row AwV2_KhkkN1..N8 (đo: MENU_AwV2_ALL=10 = 2 cũ AwV2_DuyetNcc/
AwV2_DuyetNccPhuongAn + 8 mới, liệt kê đủ tên). 143 + 8 = 151 khít ⇒ 143 là mốc PRE-K3 đã lão hoá,
không phải drift. Kỳ vọng đúng cho lượt này = 200, KHÔNG phải 192.
w3wp PRE: appcmd list wp → WP "4876" (applicationPool:SolutionErp-Api), StartTime 01/08 09:11:51
= đúng cửa-sổ recycle của #437 (09:05:59→09:12:21). ⇒ mốc-so-sánh recycle-proof cho #438.
(VPS có 6 w3wp chung VIETREPORT ⇒ map PID→pool bằng appcmd, CẤM đoán PID.)
§0.2 — DỰ ĐOÁN TỪ SOURCE, ghi ĐĨA TRƯỚC KHI ĐO POST
Đọc MenuKeys.cs:72-84 + DbInitializer.cs (vòng seed menu K4a + labelBackfill + grant site-2):
KhkkGroupNumbers=[2..8](7) × (KhkkGroup(n)1 +KhkkLeafActions6 =WfView,List,Create,Pending,Approved,Deleted) ⇒KhkkGroupMenuKeys= 7 × 7 = 49 key MỚI (7 group + 42 leaf).- Vòng seed menu-row dùng CHÍNH bộ sinh đó ⇒ MENU_TOTAL 151 → 200 · MENU_KHKK_PCT 7 → 56.
labelBackfill["Khkk_G1"]⇒ Label đổi → "1. Thiết bị, máy móc, vật tư phụ (A1)" (key GIỮ, 0 row mới).- Grant: site-1 loop
MenuKeys.Allcấp Admin; site-2KhkkKeys().Concat(KhkkGroupMenuKeys)cấp CanRead mọi role, skip-existing ⇒ hợp lại = 49 key × 13 role = +637 ROW. ⇒ PERM_TOTAL 1584 → 2221 · PERM_KHKK_PCT 91 → 728 (chéo: 728 = 56 × 13, và 728−91 = 637 — hai lối tính khớp). - ⚠️ Số 196 trong đề bài (
49×4) là POLICY (|All|×4 action, tầng authz —MenuKeys.cs:57-62khai đúng vậy), KHÔNG phải row DB. Hai đại lượng khác nhau, đừng cộng nhầm vào PERM_TOTAL. - Mig: 0 file
*Migrations*trong diff ⇒ GIỮ 71 / top20260731085624.
§1 — Run Gitea Actions — ✅ PASS (2 run: #438 K4a+K4b · #437 F-1)
API .../actions/tasks?limit=8 (anon, public repo). Match theo head_sha, KHÔNG theo run_number:
id=551 | run# 438 | 88e7ecf263 | status=success | concl=None | 10:10:19 -> 10:16:42 +07 <- K4a+K4b
id=550 | run# 437 | 7a903cf108 | status=success | concl=None | 09:05:59 -> 09:12:21 +07 <- F-1 (phủ lượt này)
id=549 | run# 436 | 15349e8ee0 | status=success | concl=None | 31/07 18:21:48 -> 18:27:59 <- K3 (neo thứ tự)
- #438 duration 6m23s · #437 duration 6m22s — in-band (#436 6m11s · #435 6m12s · #434 6m31s).
- Control neo thứ tự 2 tầng: run kề dưới #438 =
7a903cf(F-1), kề dưới nữa =15349e8(K3, đã verify ởsub-cicd-verify-k3.md) ⇒ chuỗi #436→#437→#438 liền mạch, không có run lạ chen giữa, không nhầm run. - Tao đo LIVE lúc #438 còn
running(poll 10:12→10:16:51, 3 nhịprunningrồisuccess) ⇒ không dính bẫy false-positive "verify khi còn running" (Run #242). concl=Nonelà bình thường với endpointtasks⇒ tinstatus(gate test chạy TRƯỚC build/deploy).- URL:
https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions/runs/438(và/437).
§2 — Gate CI 621 = 45 + 576 — ✅ PASS (khớp TỪNG VẾ + đo luôn F-1)
Log web-UI .../actions/runs/{438,437}/jobs/0/logs (HTTP 200; 18.665 B và 18.689 B). Đọc bằng bytes
(text-mode crash cp1252); regex nới khoảng-trắng vì log dùng 2 space sau Passed!:
#438 Passed! - Failed: 0, Passed: 45, Skipped: 0, Total: 45 — SolutionErp.Domain.Tests.dll
#438 Passed! - Failed: 0, Passed: 576, Skipped: 0, Total: 576 — SolutionErp.Infrastructure.Tests.dll
#437 Passed! - Failed: 0, Passed: 45, Skipped: 0, Total: 45 — SolutionErp.Domain.Tests.dll
#437 Passed! - Failed: 0, Passed: 569, Skipped: 0, Total: 569 — SolutionErp.Infrastructure.Tests.dll
- #438 = 45 + 576 = 621 ✔ khớp kỳ vọng TÁCH-PHẦN (45D/576I), 0 fail / 0 skip.
- Chuỗi delta khép kín 3 mốc (đây là chỗ việc phủ-2-run trả giá trị): #436 K3 = 45+569 = 614 →
#437 F-1 = 45+569 = 614 (Infra GIỮ 569, +0) → #438 = 45+576 = +7.
⇒ F-1 đúng là "FE+DTO nhỏ, 0 test mới"; toàn bộ +7 thuộc về K4a+K4b, khớp
KhkkGroupMenuSeedTests.cs(file test DUY NHẤT trong diff #438). Domain GIỮ 45 suốt 3 run. - Control ÂM:
grep -c 'Failed!'= 0 trên CẢ HAI log ⇒ 2 dòngPassed!là TOÀN BỘ project, không có project thứ 3 bị nuốt (nếu fail, dotnet inFailed! - Failed: N…).
§3 — Mig GIỮ 71 — ✅ PASS (2 nguồn ĐỘC LẬP repo ⟂ prod)
prod: SELECT MAX(MigrationId) -> 20260731085624_AddKhkkApprovalGroupCatalogAndFinalizeRuntime ; COUNT(*) = 71
repo: git diff --name-only 7a903cf..88e7ecf -- '*Migrations*' -> (rỗng)
- MIGCOUNT 71 (§0.1 PRE) == 71 (POST) ⇒ không có mig lén chen vào; top y nguyên mốc K2.
- ⚠️ Mục "GIỮ NGUYÊN" tự nó ít bit ⇒ răng lấy từ control DƯƠNG cùng phiên: §4 chứng minh DbInitializer ĐÃ chạy (seed 49 row + backfill 1 label) ⇒ startup-hook SỐNG. "Mig không nhích" là vì không có mig, chứ không phải vì app không khởi động lại.
§4 — Seed 49 menu-row + 637 permission-row + backfill label — ✅ PASS (TAM-GIÁC 3 NGUỒN, khớp TỪNG ĐỒNG)
Mọi số dưới đo SAU recycle (recycle-proof ở §4.1). Đối chiếu với dự đoán §0.2 đã ghi đĩa TRƯỚC khi đo:
| Chỉ số | PRE (§0.1) | DỰ ĐOÁN §0.2 | ĐO POST | |
|---|---|---|---|---|
MENU_TOTAL |
151 | 200 | 200 | ✔ |
MenuItems LIKE Khkk% |
7 | 56 | 56 | ✔ |
Khkk_G1.Label |
"1. Kế hoạch ký kết HĐ (NCC-TP)" | "1. Thiết bị, máy móc, vật tư phụ (A1)" | đúng chuỗi đó | ✔ |
PERM_TOTAL |
1584 | 2221 | 2221 | ✔ |
Permissions LIKE Khkk% |
91 | 728 (=56×13) | 728 | ✔ |
… trong đó CanRead=1 |
91 | 728 | 728 (100%) | ✔ |
MIGCOUNT |
71 | 71 | 71 | ✔ |
3 NGUỒN ĐỘC LẬP cùng ra 49 / 637 (khuôn tam-giác K1):
- (a) source-parse:
KhkkGroupNumbers[2..8] × (1 group +KhkkLeafActions6) = 7×7 = 49; grant 49 × 13 role = 637. - (b) sqlcmd prod: menu 151→200 (+49) · perm 1584→2221 (+637).
- (c) Serilog prod (nguồn thứ 3, độc lập hoàn toàn với 2 nguồn trên):
10:16:30.458 [INF] Seeded 49 menu items
10:16:30.531 [INF] Backfilled 1 menu labels
10:16:30.711 [INF] Seeded 49 admin permissions
10:16:31.298 [INF] Seeded all-roles review perms: 588 added + 0 upgraded (139 keys × 13 roles)
🔑 Phân rã 637 khớp CHÍNH XÁC cơ chế 2-site: site-1 (loop MenuKeys.All, chỉ Admin) = 49;
site-2 (KhkkKeys().Concat(KhkkGroupMenuKeys), mọi role, skip-existing nên Admin không đếm lại) =
588 = 49 × 12 role còn lại. 49 + 588 = 637 ✔. Con số 588 này KHÔNG suy ra được từ tổng —
nó chỉ khớp nếu đúng cơ chế skip-existing ⇒ đây là bit thông tin thật, không phải trùng khớp số học rỗng.
0 upgraded cũng đúng: 49 key MỚI toàn đi nhánh INSERT.
SHAPE element-wise 8 nhóm (không chỉ đếm — soi từng dòng, khớp bảng nhãn owner danh-muc-sp002-transcribe.md):
Khkk_G1|ord=1|kids=6| 1. Thiết bị, máy móc, vật tư phụ (A1) <- nhãn ĐÃ backfill
Khkk_G2|ord=2|kids=6| 2. Kết cấu, hạ tầng, phá dỡ & DV hỗ trợ thi công (A2-A3)
Khkk_G3|ord=3|kids=6| 3. Hoạt động văn phòng (A4)
Khkk_G4|ord=4|kids=6| 4. Vật tư (B1)
Khkk_G5|ord=5|kids=6| 5. Thầu phụ xây dựng (B2)
Khkk_G6|ord=6|kids=6| 6. Thầu phụ MEP (B3)
Khkk_G7|ord=7|kids=6| 7. BCH công trường (C1-C3)
Khkk_G8|ord=8|kids=6| 8. HĐ chưa ủy quyền — CEO (5.2)
8 nhóm × đúng 6 kids mỗi nhóm · Order 1..8 liền không trùng · 8/8 nhãn khớp bảng owner từng ký tự.
Control ÂM (chứng "đúng NGƯỜI, đúng TẬP", không quét bừa):
CTRL_OUTOFSET_G0_G9plus = 0— không đẻKhkk_G0/Khkk_G9+ngoài miền 1..8.- Revoker #84 còn SỐNG mà KHÔNG đụng Khkk:
Hrm*/Off*có 377 row nhưngCanRead=1chỉ 29 — y hệt PRE (29). Nếu revoker chết thì số này bung lên 377; nếu revoker quét lố sangKhkk_*thì 728 đã tụt. Cả hai đều không xảy ra ⇒ checker còn răng VÀ phạm vi đúng (chân-kiềng iii).
§4.1 — Recycle-proof (2 nguồn) — mọi số §4 đo SAU khởi động lại
appcmd list wp→WP "7020" (applicationPool:SolutionErp-Api);Get-Process w3wp→ PID 7020 StartTime 01/08 10:16:22. KHÁC PRE (PID 4876 @ 09:11:51) ⇒ pool ĐÃ recycle, đúng cửa-sổ deploy #438. (VPS có 6 w3wp chung VIETREPORT ⇒ map PID→pool bằngappcmd, CẤM đoán PID.)- Nguồn 2: dòng ĐẦU TIÊN của
solution-erp-20260801.log=10:16:23.961 [INF] Applying migrations...(deploy xoálogs/⇒ dòng đầu = boot). Seed log 10:16:30 nằm sau đó ⇒ đúng lần boot này.
§6 — Bundle ×2 — DỰ ĐOÁN TỪ SOURCE trước khi curl (ghi đĩa trước, đo sau)
🔴 LOẠI marker lead gợi ý — nó KHÔNG CÓ RĂNG. Đề bài đề xuất Kết cấu, hạ tầng, phá dỡ (từ
KHKK_APPROVAL_GROUP_LABELS) với kỳ vọng "0-hit PRE / 1-hit POST". Đo nguồn:
git show 7a903cf:fe-user/src/types/khkk.ts | grep -c = 1 (và fe-admin cũng 1) ⇒ chuỗi này ĐÃ CÓ
từ trước K4 (nó vào repo ở wave trước, K4 chỉ thêm comment quanh nó) ⇒ đã nằm sẵn trong bundle PRE
⇒ 0 bit. Cùng lớp sai lầm với earlyFinalizeLocked (§5 k3). Thay bằng 3 marker sau, đều là string
literal (minifier giữ nguyên) và đều có transition PRE→POST đo được:
| Marker | Loại | Nguồn PRE 7a903cf |
Nguồn POST 88e7ecf |
Kỳ vọng bundle LIVE |
|---|---|---|---|---|
/khkk/list?group=1 |
POS | admin 0 · user 0 | admin 4 · user 4 | >0 CẢ HAI |
/khkk/list?view=deleted |
NEG | admin 1 · user 1 | admin 0 · user 0 | 0 CẢ HAI |
workflow-matrix?type=10&group= |
DIFFERENTIAL | admin 0 · user 0 | admin 1 (trong // comment) · user 2 (code) |
admin 0 · user 2 |
- NEG ĐỘC QUYỀN (bài "control ÂM phải độc quyền"):
grep -rntoànfe-admin/src+fe-user/srcbản POST = 0 hit ⇒ vắng mặt trong bundle là vắng mặt THẬT, không phải chuỗi còn sống ở chỗ khác. - DIFFERENTIAL là marker mạnh nhất lượt này, 2 mũi cùng lúc: (1) chứng bất-đối-xứng CỐ Ý đã ship
(fe-admin cố ý KHÔNG nới regex
Khkk_G*— lead chốt 27/07), (2) tự chứng comment bị strip — admin có đúng 1 lần xuất hiện và nó nằm trong//(dòng 39) nên phải ra 0; nếu admin ra 1 thì hoặc comment lọt vào bundle hoặc tao grep nhầm file.