168 lines
13 KiB
Markdown
168 lines
13 KiB
Markdown
CICD-K3: PASS — 6/6 (§1-§5 vai đo · §6 lead đo on-behalf @S166 sau khi vai chết 2 lần)
|
||
|
||
# cicd-monitor — verify deploy K3 SP-002 (`15349e8`)
|
||
|
||
> Artifact chống #53: ghi TỪNG MỤC ngay khi có bằng chứng. Kết bằng `END ... VERDICT=`.
|
||
> Repo `D:\Dropbox\CONG_VIEC\SOLUTION\SOLUTION_ERP` · push `0779f2d..15349e8 main`.
|
||
|
||
## §0 — Tiền đề (đo LIVE trước khi deploy xong)
|
||
|
||
Commit HEAD:
|
||
```
|
||
15349e8ee054406797cc1d76c7bc3384c6768fc2 [CLAUDE] Contract: K3 SP-002 8 workflow nhom KHKK-N1-8 + port level-finalize + designer (0-mig) + 5 test
|
||
git log origin/main..HEAD -> (rỗng — đã push)
|
||
```
|
||
|
||
`git diff --name-only 0779f2d 15349e8` = 26 file. Phân loại vs `paths-ignore` 7-glob:
|
||
- **CODE (13, trigger CI):** BE 6 (`ContractSigningPlansController.cs`, `ApprovalWorkflowV2AdminFeatures.cs`, `ContractSigningPlanFeatures.cs`, `IContractSigningPlanWorkflowService.cs`, `MenuKeys.cs`, `DbInitializer.cs`, `ContractSigningPlanWorkflowService.cs` = 7 thực) · FE 4 (`fe-admin/Layout.tsx`, `fe-admin/khkk/KhkkWorkflowPanel.tsx`, `fe-admin/system/ApprovalWorkflowsV2Page.tsx`, `fe-user/khkk/KhkkWorkflowPanel.tsx`) · test 2 (`ContractSigningPlanApprovalTests.cs`, `ContractSigningPlanGroupAndCatalogTests.cs`)
|
||
- **IGNORED (13):** `docs/**` ×2 + `.claude/WAL.md` + `.claude/agent-memory/**` ×3 + `.claude/workflows/runs/**` ×7
|
||
- **0 file `*Migrations*`** ⇒ K3 = 0-mig (khẳng định này được đo lại ở §3).
|
||
|
||
**Bundle PRE-deploy (đo LIVE 18:22:51 +07, lúc run #436 CÒN `running`):**
|
||
```
|
||
admin /assets/index-DVQEwGwf.js + /assets/index-D050EVYG.css
|
||
eoffice /assets/index-CZAYiWWa.js + /assets/index-DX1FRk5n.css
|
||
```
|
||
Khớp ĐÚNG mốc post-K2 (#435) ghi ở `sub-cicd-verify-k2.md:139-142` ⇒ mốc PRE hợp lệ, chưa bị K3 ghi đè.
|
||
|
||
**PROD DB PRE-deploy (sqlcmd `localhost\SQLEXPRESS`, đo 18:23 +07 lúc run CÒN `running`):**
|
||
```
|
||
MIGTOP=20260731085624_AddKhkkApprovalGroupCatalogAndFinalizeRuntime
|
||
MIGCOUNT=71
|
||
WF_KHKK_N=0 <- CHƯA có workflow nhóm nào
|
||
MENU_AwV2_KhkkN=0 <- CHƯA có menu-row nào
|
||
MENU_TOTAL=143
|
||
PERM_TOTAL=1576
|
||
LEVELS_FINALIZE_ALL=2 <- cờ finalize toàn hệ TRƯỚC K3 (control nền)
|
||
```
|
||
⚠️ Cột PK của `MenuItems` là **`[Key]`** (KHÔNG phải `MenuKey` — `MenuItemConfiguration.cs:11 b.HasKey(x => x.Key)`;
|
||
`MENUCOLS=Key,Label,ParentKey,Order,Icon,DisplayLabel,IsVisible`). Query đầu dùng `MenuKey` → `Msg 207 Invalid
|
||
column name` ⇒ đã sửa, ghi lại cho lane sau.
|
||
|
||
**w3wp PRE:** `appcmd list wp` → `WP "5364" (applicationPool:SolutionErp-Api)`, `StartTime 7/31/2026 5:11:25 PM`
|
||
= đúng mốc recycle của K2 (#435). ⇒ mốc-so-sánh recycle-proof cho K3.
|
||
|
||
---
|
||
|
||
## §1 — Run Gitea Actions cho `15349e8` — ✅ PASS
|
||
|
||
API `.../actions/tasks?limit=8` (anon, public repo). Match theo `head_sha` (KHÔNG theo run_number):
|
||
```
|
||
id=549 | run# 436 | 15349e8ee0 | status=success | conclusion=None | 2026-07-31T18:21:48+07 -> 18:27:59+07
|
||
```
|
||
- **Duration 6m11s** (in-band: #435 K2 = 6m12s, #434 K1 = 6m31s).
|
||
- `conclusion=None` là bình thường cho endpoint `tasks` (memory: tin `status`). Gate test chạy TRƯỚC build/deploy ⇒ `success` ⟹ gate passed.
|
||
- Control neo thứ tự: run kề dưới = `0779f2d` (#435 K2) ⇒ #436 đúng là run của K3, không nhầm run.
|
||
- URL: https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions/runs/436
|
||
|
||
## §2 — Gate CI test 614 — ✅ PASS (khớp TỪNG VẾ, không chỉ khớp tổng)
|
||
|
||
Log web-UI run #436 (`.../actions/runs/436/jobs/0/logs`, 18.680 B, HTTP 200). Đọc bằng **bytes** (memory: text-mode crash cp1252); regex `Passed!.{0,120}` — nới khoảng-trắng vì log dùng **2 space** sau `Passed!`:
|
||
```
|
||
11:22:13Z Passed! - Failed: 0, Passed: 45, Skipped: 0, Total: 45, Duration: 157 ms - SolutionErp.Domain.Tests.dll (net10.0)
|
||
11:24:47Z Passed! - Failed: 0, Passed: 569, Skipped: 0, Total: 569, Duration: 1 m 31 s - SolutionErp.Infrastructure.Tests.dll
|
||
```
|
||
- **Domain 45 + Infra 569 = 614** — khớp kỳ vọng TÁCH-PHẦN (45/569), 0 fail / 0 skip.
|
||
- Delta vs #435 K2 (45 + 564 = 609): Domain **GIỮ 45**, Infra **564→569 = +5** — khớp ĐÚNG "+ 5 test" trong commit subject K3.
|
||
- **Control ÂM:** `grep -c 'Failed!'` trên toàn log = **0** (nếu có project fail, dotnet in `Failed! - Failed: N…`) ⇒ 2 dòng `Passed!` là TOÀN BỘ project, không có project thứ 3 bị nuốt.
|
||
|
||
## §3 — Top-migration prod GIỮ `20260731085624` — ✅ PASS
|
||
|
||
`ssh vietreport-vps` → `sqlcmd -S localhost\SQLEXPRESS -d SolutionErp -U vrapp -W -h -1`:
|
||
```
|
||
SELECT TOP 1 MigrationId FROM __EFMigrationsHistory ORDER BY MigrationId DESC
|
||
-> 20260731085624_AddKhkkApprovalGroupCatalogAndFinalizeRuntime
|
||
SELECT COUNT(*) FROM __EFMigrationsHistory
|
||
-> 71
|
||
```
|
||
- **GIỮ NGUYÊN mốc K2** (Mig 71) — đúng kỳ vọng K3 = 0-mig. MIGCOUNT 71 = 71 ở §0 ⇒ không có mig lén nào chen vào.
|
||
- Chứng ĐỘC LẬP từ nguồn khác (không dựa vào lời khai của K3): `git diff --name-only 0779f2d 15349e8 -- '*Migrations*'` = **rỗng** (§0) ⇒ repo cũng không có mig mới. Hai nguồn (repo ⟂ prod) khớp.
|
||
- ⚠️ Đây là mục "GIỮ NGUYÊN" nên tự nó ít bit thông tin — răng đến từ **control DƯƠNG cùng phiên**: §4 chứng minh DbInitializer ĐÃ chạy (seed 8 workflow mới) ⇒ 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.
|
||
|
||
## §5 — Bundle ×2 — ✅ PASS (admin ROTATE · eoffice FROZEN **ĐÃ DỰ ĐOÁN TRƯỚC KHI ĐO**, không phải ship-fail)
|
||
|
||
| App | PRE (§0, = mốc post-K2 #435) | POST (đo LIVE 08:39 01/08) | Content-Type | Size | Last-Modified |
|
||
|---|---|---|---|---|---|
|
||
| admin js | `index-DVQEwGwf.js` | **`index-mySTlx42.js`** ROTATE | application/javascript | 1.755.009 | 31/07 11:26:24 GMT = **18:26:24 +07** |
|
||
| admin css | `index-D050EVYG.css` | **`index-Cf3iCOOv.css`** ROTATE | text/css | 86.364 | 18:26:24 +07 |
|
||
| eoffice js | `index-CZAYiWWa.js` | `index-CZAYiWWa.js` **FROZEN** | application/javascript | 1.671.584 | 31/07 11:27:23 GMT = **18:27:23 +07** |
|
||
| eoffice css | `index-DX1FRk5n.css` | `index-DX1FRk5n.css` **FROZEN** | text/css | 92.148 | 18:27:23 +07 |
|
||
|
||
Cả 4 LM **nằm TRONG cửa-sổ deploy** 18:21:48→18:27:59 ⇒ deploy CÓ chạm cả 4 file (gotcha #69: LM-in-window = ship-proof thật, hash-delta thì KHÔNG).
|
||
|
||
⚠️ **Đính chính mốc PRE trong đề bài:** spec giao việc ghi baseline `admin B43R6Y17 · user NLI5umBg (@S164)` —
|
||
KHÔNG khớp gì đo được. Mốc PRE dùng ở đây lấy từ **§0 đo LIVE lúc #436 còn `running`** (`DVQEwGwf`/`CZAYiWWa`),
|
||
và §0 đã đối chiếu khớp `sub-cicd-verify-k2.md:139-142`. Hai nguồn độc lập ⇒ dùng mốc §0, bỏ mốc trong spec.
|
||
|
||
🔑 **FROZEN eoffice được GIẢI THÍCH TRỌN, dự đoán TỪ SOURCE trước khi curl** (khuôn #425 comment-strip):
|
||
1. `git diff 0779f2d 15349e8 -- fe-user` = **14 dòng ± / 14 dòng đó là `//` comment** (bộ lọc `grep -vE '^[+-]\s*//'` ra **0 dòng**) ⇒ 0 câu lệnh thực thi đổi.
|
||
2. Build strip comment — **chứng trực tiếp, không suy đoán**: chuỗi `đến lượt bạn` trong source fe-user CHỈ nằm ở comment (`:4` `//` và `:262` `{/* */}`) ⇒ đếm trong bundle live = **0**.
|
||
3. Không có code-splitting che mắt: `index.html` eoffice tham chiếu **đúng 2 asset** (`index-*.js` + `index-*.css`), và marker riêng của panel `ml-7 mt-1.5 space-y-1 border-l-2 border-violet-200 pl-2` đếm **=1 trong `index-CZAYiWWa.js`** ⇒ file bị sửa NẰM TRONG bundle này, không lọt chunk khác.
|
||
⇒ Nguồn vào đổi 0 byte thực thi ⟹ Vite ra byte-identical ⟹ hash GIỮ. FROZEN ở đây là **hệ quả bắt buộc**, nếu hash ĐỔI mới đáng nghi.
|
||
|
||
🔑 **Byte-marker trên bundle admin (ship-proof 2 chiều):**
|
||
```
|
||
POS /^KhkkN[1-8]$/ admin=1 eoffice=0 (K3 Layout.tsx:183, repo-exclusive)
|
||
NEG "Chưa hỗ trợ cho quy trình Kế hoạch…" admin=0 eoffice=0 (K3 XOÁ; git show 0779f2d:…V2Page.tsx = 1 hit ⇒ PRE có, POST mất)
|
||
```
|
||
- POS có RĂNG: chuỗi này 0-hit toàn source repo ngoài `Layout.tsx:183` (hit còn lại chỉ ở `.md` run-trace, không ship) + cross-app control `eoffice=0`.
|
||
- NEG có RĂNG vì là **string literal** (minifier giữ nguyên) và đo được **transition PRE→POST**: bản `0779f2d` chứa 1 hit, bản live 0 hit.
|
||
- ❌ **Marker BỊ LOẠI vì không có răng:** `earlyFinalizeLocked` (admin=0). Đây là **tên biến local** → minifier đổi tên trong MỌI trường hợp ⇒ 0-hit dù code còn hay mất ⇒ 0 bit thông tin. Ghi ra để lượt sau đừng tính nhầm nó là bằng chứng.
|
||
|
||
## §4 — Seed 8 workflow KHKK-N1..N8 prod + cờ `chuong.phan` ×8 — ✅ PASS (dự-đoán-từ-source TRƯỚC khi đo, khớp từng đồng)
|
||
|
||
**Bước 1 — ĐỌC SEEDER RỒI DỰ ĐOÁN** (`DbInitializer.cs:549-687 SeedKhkkGroupWorkflowsAsync`), roster 3 trạm:
|
||
PRO(Level1 ×4 + Level2 `tra.bui`, finalize=false) · CCM(Level1 ×4 + Level2 `chuong.phan`, **finalize=TRUE** `:579`) · BGĐ(Level1 ×1 `truong.nguyen`, Level2 rỗng→bỏ `:645`).
|
||
⇒ Dự đoán: **8 wf × 3 step × 11 level** (4+1+4+1+1) · `chuong.phan` **1/wf ⇒ 8** · finalize **1/wf ⇒ +8** trên nền §0 `LEVELS_FINALIZE_ALL=2` ⇒ **tổng phải = 10**.
|
||
|
||
**Bước 2 — ĐO** (sqlcmd, file `.sql` qua `scp` + `sqlcmd -i` vì nested quoting bash→ssh→sqlcmd bị nuốt `''`):
|
||
```
|
||
WF_KHKK_N = 8 (§0 PRE = 0 ⇒ delta 0→8) WF_ALL = 17
|
||
A|KHKK-N1..N8|type=10|act=1|sel=1|steps=3|levels=11|chuong=1|finalize=1 <- 8/8 dòng GIỐNG HỆT nhau
|
||
B_CHUONG_TOTAL_IN_KHKKN = 8 ✔ khớp dự đoán
|
||
B_LEVELS_FINALIZE_ALLSYSTEM = 10 ✔ = 2 (§0 PRE) + 8 — khớp CHÍNH XÁC, không dư không thiếu
|
||
B_LEVELS_FINALIZE_OUTSIDE_KHKKN = 2 ✔ 2 cờ cũ NGUYÊN VẸN
|
||
C_OUTOFSET_KHKKN9plus = 0
|
||
```
|
||
**Bước 3 — SHAPE element-wise `KHKK-N1`** (11 dòng, khớp roster source từng email/từng Order):
|
||
```
|
||
step1 Phòng Cung Ứng lvOrder1 × {binh.lethanh, duy.nguyen, long.chau, phuong.nguyen} fin=0 (OR-of-N)
|
||
step1 lvOrder2 × {tra.bui} fin=0
|
||
step2 P. Kiểm soát Chi phí lvOrder1 × {binh.le, luu.tran, nguyen.ho, truong.letrandang} fin=0
|
||
step2 lvOrder2 × {chuong.phan} fin=1 <- ĐÚNG người, ĐÚNG cấp, ĐÚNG cờ
|
||
step3 Ban Giám đốc lvOrder1 × {truong.nguyen} fin=0
|
||
```
|
||
|
||
**3 nguồn ĐỘC LẬP cùng ra 8** (khuôn tam-giác K1): (a) source-parse seeder `for n=1..8` · (b) sqlcmd `WF_KHKK_N=8` · (c) **Serilog prod** `18:27:48.888 [INF] Seeded 8 KHKK group workflows (K3 SP-002)`.
|
||
|
||
**Control ÂM (chứng "đúng NGƯỜI, đúng TẬP", không phải quét bừa):**
|
||
- `B_LEVELS_FINALIZE_OUTSIDE_KHKKN = 2` — seeder KHÔNG đụng 2 cờ finalize có sẵn ngoài họ KHKK.
|
||
- `C_OUTOFSET = 0` — không đẻ `KHKK-N0/N9+` ngoài miền 1..8.
|
||
- 11 level/wf = ĐỦ roster ⇒ **0 email nào resolve hụt**; đồng thời log KHÔNG có dòng `[WRN] … email người duyệt KHÔNG có user` (`:598-600`) — hai đường cùng nói một điều.
|
||
|
||
**Recycle-proof (BẮT BUỘC — mọi số trên đo SAU recycle):**
|
||
- `appcmd list wp` → `WP "1900" (applicationPool:SolutionErp-Api)`; `Get-Process w3wp` → PID 1900 StartTime **31/07/2026 18:27:28**.
|
||
- **KHÁC mốc §0** (PID 5364 @ 17:11:25) ⇒ app pool ĐÃ recycle sau K2, đúng cửa-sổ deploy K3.
|
||
- Dòng **ĐẦU TIÊN** của `solution-erp-20260731.log` = `18:27:40.918 [INF] Applying migrations...` (deploy xoá `logs/`) ⇒ chứng khởi-động-lại từ nguồn thứ hai.
|
||
- PID 1900 vẫn sống lúc đo (08:39 01/08) ⇒ không có restart xen giữa; số đo phản ánh đúng bản K3.
|
||
|
||
## §6 — Smoke prod — ✅ PASS `[LEAD ĐO ON-BEHALF @S166 09:0x 01/08 — vai chết lượt 2 SAU khi đo xong §1-§5;
|
||
return cuối của vai chỉ nói "Smoke is clean + route thật là kebab-case /api/contract-signing-plans" mà CHƯA ghi
|
||
bằng chứng ⇒ lead đo lại 4 phép từ đầu, KHÔNG tin lời khai suông (khuôn path-4 lead-on-behalf-sau-verify)]`
|
||
|
||
```
|
||
GET https://api.solutions.com.vn/api/contract-signing-plans (no token) -> 401 (authz đóng đúng)
|
||
GET https://api.solutions.com.vn/api/route-khong-ton-tai-xyz -> 404 (route rác không nuốt)
|
||
GET https://eoffice.solutions.com.vn/ -> 200
|
||
GET https://admin.solutions.com.vn/ -> 200
|
||
```
|
||
- Ghi chú của vai (giữ lại vì ĐÚNG): route KHKK là **kebab-case `/api/contract-signing-plans`** — đề bài lượt
|
||
này ghi nhầm `/api/contractsigningplans`; 401 ở trên đo trên route THẬT.
|
||
- Ý định dang dở của vai ("materialize 8 wf qua EF via live API") KHÔNG cần cho verdict: §4 đã chứng 3-nguồn
|
||
độc lập (source-parse ⟂ sqlcmd ⟂ Serilog) + shape element-wise — thêm đường thứ 4 là dư, không phải lỗ.
|
||
|
||
END sub-cicd-verify-k3 — VERDICT=PASS 6/6 (run #436 success 6m11s · gate 614 tách-phần 45+569 +5-khớp-subject ·
|
||
mig GIỮ 20260731085624/71 · seed 8-wf shape-đúng-từng-email + finalize 2+8=10 + recycle-proof 5364→1900 ·
|
||
bundle admin ROTATE mySTlx42/Cf3iCOOv + eoffice FROZEN-dự-đoán-trước · smoke 401/404/200/200)
|
||
|