174 lines
9.7 KiB
Markdown
174 lines
9.7 KiB
Markdown
# CI/CD verify — `df52fa0` (W3 KHKK — duyệt 3 trạm, 0 migration)
|
||
|
||
> Ghi TỪNG MỤC ngay khi có bằng chứng (đối-sách #53: file = sản phẩm chính, return chỉ là tóm tắt).
|
||
> Agent: cicd-monitor · Session S161 W3 · Ngày 2026-07-29
|
||
|
||
---
|
||
|
||
## §0. Grounding — commit + push
|
||
|
||
| Mục | Giá trị |
|
||
|---|---|
|
||
| SHA | `df52fa0cd09e13a533724c35f4e6bed44afeb42d` |
|
||
| Subject | `[CLAUDE] App+Infra+Api+FE-User+FE-Admin+Tests: W3 KHKK — duyet 3 tram OR-of-N + finalize chot gia (test-before 6 RED->GREEN)` |
|
||
| Author / Date | pqhuy1987 · Wed Jul 29 22:33:11 2026 +0700 |
|
||
| `git log origin/main..HEAD` | **RỖNG** ⇒ đã push |
|
||
| Files changed | **11** (+2370 / −6) |
|
||
| Breakdown | BE 4 (Controller · IContractSigningPlanWorkflowService · DependencyInjection · ContractSigningPlanWorkflowService) · FE 6 (2 app × {KhkkDetailPage, KhkkWorkflowPanel, types/khkk}) · Tests 1 (`ContractSigningPlanApprovalTests.cs`) |
|
||
| paths-ignore (gotcha #41) | KHÔNG khớp glob nào trong 7-entry ⇒ **CI PHẢI chạy** ✅ |
|
||
| Migrations trong diff | **0 file** `*Migrations*` ⇒ khai báo 0-mig (verify ở §2) |
|
||
|
||
**File MỚI trong commit này (quan trọng cho §3):**
|
||
`fe-{admin,user}/src/pages/khkk/KhkkWorkflowPanel.tsx` — **NEW-FILE-IN-THIS-COMMIT**
|
||
(`git cat-file -e df52fa0~1:…` → `exists on disk, but not in df52fa0~1`), 423 dòng/app,
|
||
SHA256 mirror KHỚP 2 app: `2b64144ef6e8567d6997c0e19b9686c083080216510a4cd8da6157a80f584817`.
|
||
|
||
⟹ Mọi chuỗi ĐỘC-QUYỀN của file này **phải VẮNG trong bundle CŨ** (build từ `6cbc6ad9` W2) và
|
||
**có mặt trong bundle MỚI** → control ÂM theo trục THỜI GIAN, mạnh hơn control âm hash.
|
||
|
||
---
|
||
|
||
## §1. CI run — PASS ✅
|
||
|
||
| Mục | Giá trị |
|
||
|---|---|
|
||
| Run | **#429** (task id **542**) |
|
||
| head_sha | `df52fa0c` ✅ khớp (key theo SHA, KHÔNG theo run_number) |
|
||
| status | **success** (`conclusion:None` — Gitea `tasks` không populate, tin `status` per baseline) |
|
||
| created → updated | 22:33:19 → 22:39:13 = **5m54s** (nằm trong dải ~5m40s–6m của arc S159/S161) |
|
||
| URL | https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions/runs/429 |
|
||
|
||
**Test gate (đọc web-UI log `…/runs/429/jobs/0/logs`, 17.900 B) — đối chiếu TÁCH-PHẦN:**
|
||
|
||
```
|
||
:29 Passed! - Failed: 0, Passed: 45, Skipped: 0, Total: 45, Duration: 147 ms - SolutionErp.Domain.Tests.dll
|
||
:47 Passed! - Failed: 0, Passed: 535, Skipped: 0, Total: 535, Duration: 1 m 36 s - SolutionErp.Infrastructure.Tests.dll
|
||
```
|
||
|
||
| | Kỳ vọng | Đo | KL |
|
||
|---|---|---|---|
|
||
| Domain | 45 | **45** | ✅ |
|
||
| Infrastructure | 535 | **535** | ✅ |
|
||
| **TỔNG** | **580** | **580** | ✅ |
|
||
| Failed / Skipped | 0 / 0 | **0 / 0** | ✅ |
|
||
|
||
Delta so run #427 (566 = 45D+521I): **+14 Infra** — commit khai "test-before 6 RED→GREEN";
|
||
file test đổi = 1 (`ContractSigningPlanApprovalTests.cs`). 6 là số **kịch bản** lead khai, 14 là số **test-case**
|
||
thực thi (Theory/InlineData nở) ⇒ không mâu thuẫn, và gate-580 đúng con số đề bài yêu cầu.
|
||
|
||
---
|
||
|
||
## §2. 0-migration invariant
|
||
|
||
_(đang cập nhật)_
|
||
|
||
---
|
||
|
||
## §3. Bundle marker
|
||
|
||
### §3.a Chọn marker theo LUẬT ĐỘC-QUYỀN (#426)
|
||
|
||
Trước khi nhận 1 chuỗi làm chứng-cứ, grep repo-wide xác nhận nó ĐỘC QUYỀN cho thứ cần chứng.
|
||
Đo bằng `grep -roF <s> fe-admin/src fe-user/src src | wc -l` (occurrence) + `grep -rlF` (file list):
|
||
|
||
| Ứng viên | occurrence | file chứa | Kết luận |
|
||
|---|---|---|---|
|
||
| `Không phải lượt bạn` | 5 | +`{2 app}/components/pe/PeWorkflowPanel.tsx` +`PurchaseEvaluationWorkflowService.cs` | ❌ **NHIỄM PE** — loại |
|
||
| `Đến lượt bạn duyệt` | 4 | +`{2 app}/components/pe/PeWorkflowPanel.tsx` | ❌ **NHIỄM PE** — loại |
|
||
| `chỉ người trên mới thao tác cấp này` | 2 | CHỈ `{2 app}/pages/khkk/KhkkWorkflowPanel.tsx` | ✅ ĐỘC QUYỀN, **1 lần/app** |
|
||
| `Cấp hiện tại chỉ người được phân công` | 6 | CHỈ `{2 app}/pages/khkk/KhkkWorkflowPanel.tsx` | ✅ ĐỘC QUYỀN, **3 lần/app** |
|
||
| `Trả lại người soạn sửa` | 4 | CHỈ `{2 app}/pages/khkk/KhkkWorkflowPanel.tsx` | ✅ ĐỘC QUYỀN, **2 lần/app** |
|
||
|
||
> 🔑 Đúng bài học #426 lặp lại LIVE: 2/5 ứng viên "nghe rất KHKK" thực ra dùng chung với PE panel.
|
||
> Nếu áp máy móc `Đến lượt bạn duyệt` thì bundle CŨ đã có sẵn ⇒ PASS GIẢ.
|
||
|
||
**Trap #425 (comment bị esbuild strip) — đã loại trừ:** cả 3 marker giữ lại đều nằm ở **mã CHẠY**,
|
||
không phải comment: `chỉ người trên…` = JSX text (`<div className="mt-0.5">⚠ Không phải lượt bạn — …</div>`) ·
|
||
`Cấp hiện tại chỉ người được phân công…` = 3 × `title={…}` string literal ·
|
||
`Trả lại người soạn sửa` = `dialogTitle` + 1 × `title=` (2 string literal).
|
||
|
||
### §3.b Hiệu-chuẩn máy đo TRƯỚC khi dự đoán bội-số (chống bẫy minifier-dedupe)
|
||
|
||
Bội-số chỉ dùng được nếu minifier KHÔNG gộp literal trùng. Đo bằng chuỗi **đã ship** `bg-slate-200 text-slate-500`:
|
||
|
||
| App | source (HEAD) | trừ 1 lần trong file MỚI ⇒ kỳ vọng bundle CŨ | đo bundle CŨ | Khớp |
|
||
|---|---|---|---|---|
|
||
| fe-admin | 4 (`PeWorkflowPanel`×2 · `EmployeesListPage`×1 · `KhkkWorkflowPanel`×1 MỚI) | **3** | **3** | ✅ |
|
||
| fe-user | 4 (cùng phân bố) | **3** | **3** | ✅ |
|
||
|
||
⟹ **KHÔNG dedupe** — literal trùng được giữ nguyên bội-số ⇒ dự đoán SỐ CHÍNH XÁC là hợp lệ (không phải chỉ "≥1").
|
||
|
||
### §3.c Control ÂM theo TRỤC THỜI GIAN (đo TRƯỚC deploy, bundle W2 `6cbc6ad9`)
|
||
|
||
Bundle cũ: admin `index-D4uy3yxF.js` (1.709.294 B) · user `index-C1ASe0K1.js` (1.625.473 B), cả 2 `ct=application/javascript`.
|
||
|
||
| Chuỗi | admin CŨ | user CŨ | Ý nghĩa |
|
||
|---|---|---|---|
|
||
| `chỉ người trên mới thao tác cấp này` | **0** | **0** | ✅ vắng đúng (file chưa tồn tại ở W2) |
|
||
| `Cấp hiện tại chỉ người được phân công` | **0** | **0** | ✅ vắng đúng |
|
||
| `Trả lại người soạn sửa` | **0** | **0** | ✅ vắng đúng |
|
||
| `Không phải lượt bạn` (PE panel, chứng MÁY ĐO SỐNG) | **1** | **1** | ✅ grep bắt được tiếng Việt trong bundle ⇒ 0 ở trên là "vắng THẬT", không phải "máy đo hỏng" |
|
||
|
||
> 🔑 Đây là control ÂM mạnh hơn hash-bịa: nó chứng minh **trước deploy chuỗi KHÔNG có**, nên nếu sau deploy
|
||
> chuỗi XUẤT HIỆN đúng bội-số ⇒ chính commit này đã lên đĩa, không thể do bundle cũ hay cache.
|
||
|
||
### §3.d DỰ ĐOÁN (chốt TRƯỚC khi đo bundle mới)
|
||
|
||
| Chuỗi | admin MỚI | user MỚI |
|
||
|---|---|---|
|
||
| `chỉ người trên mới thao tác cấp này` | **1** | **1** |
|
||
| `Cấp hiện tại chỉ người được phân công` | **3** | **3** |
|
||
| `Trả lại người soạn sửa` | **2** | **2** |
|
||
| `bg-slate-200 text-slate-500` (hiệu-chuẩn) | **4** (3→4) | **4** (3→4) |
|
||
|
||
### §3.e SỐ ĐO bundle MỚI — **4/4 dự đoán KHỚP TỪNG ĐỒNG** ✅
|
||
|
||
Bundle mới (rotate **4/4**): admin js `D4uy3yxF`→**`BPWQQe4q`** · css `9okZenCM`→**`KS0kL7bG`** ·
|
||
user js `C1ASe0K1`→**`DV3fEpOw`** · css `BfN7IuxJ`→**`Cpp9Qc7C`**.
|
||
Size: admin 1.709.294 → **1.720.297** (+11.003 B) · user 1.625.473 → **1.636.476** (+11.003 B) —
|
||
**delta BẰNG NHAU 2 app**, khớp việc file panel là MIRROR SHA256 identical. Cả 2 `ct=application/javascript`.
|
||
|
||
| Chuỗi | Dự đoán | admin đo | user đo | KL |
|
||
|---|---|---|---|---|
|
||
| `chỉ người trên mới thao tác cấp này` | 1 / 1 | **1** | **1** | ✅ |
|
||
| `Cấp hiện tại chỉ người được phân công` | 3 / 3 | **3** | **3** | ✅ |
|
||
| `Trả lại người soạn sửa` | 2 / 2 | **2** | **2** | ✅ |
|
||
| `bg-slate-200 text-slate-500` (hiệu-chuẩn) | 4 / 4 | **4** | **4** | ✅ |
|
||
| `Không phải lượt bạn` (PE 1 + KHKK 1) | 2 / 2 | **2** | **2** | ✅ bonus nhất-quán |
|
||
|
||
> Cả 3 marker đi từ **0 (bundle W2) → đúng bội-số nguồn (bundle W3)**, và chuỗi hiệu-chuẩn đi **3→4**
|
||
> đúng bằng +1 lần xuất hiện trong file mới ⇒ không chỉ "có ship", mà ship **ĐÚNG BẤY NHIÊU**, không thừa không thiếu.
|
||
|
||
### §3.f Control ÂM 2 tầng (bundle cũ phải BIẾN MẤT khỏi đĩa)
|
||
|
||
| Phép | code | content-type | size | KL |
|
||
|---|---|---|---|---|
|
||
| admin hash **CŨ** `index-D4uy3yxF.js` | 200 | `text/html` | 900 | ✅ đã bị ghi đè |
|
||
| user hash **CŨ** `index-C1ASe0K1.js` | 200 | `text/html` | 876 | ✅ đã bị ghi đè |
|
||
| admin hash **BỊA** `index-ZZZZ9999.js` | 200 | `text/html` | **900** | ✅ trùng khít hash cũ |
|
||
| user hash **BỊA** `index-ZZZZ9999.js` | 200 | `text/html` | **876** | ✅ trùng khít hash cũ |
|
||
|
||
⟹ hash CŨ trả về **byte-size y hệt hash BỊA** ⇒ 200 đó là SPA-fallback `index.html`, không phải file thật
|
||
(bẫy #69/SPA-fallback). Bundle W2 đã bị xoá khỏi đĩa ⇒ deploy ghi đè THẬT.
|
||
|
||
**PHÉP 3 = PASS.**
|
||
|
||
---
|
||
|
||
## §4. Smoke + transitions THẬT — PASS ✅ [LEAD đo on-behalf]
|
||
|
||
- login admin token-468 · `POST .../00000000-…-01/transitions` body `{"action":"nonsense"}` → **409** ProblemDetails "Hành động không hợp lệ" (validate-action TRƯỚC load-plan — đúng thiết kế skeleton đợt-1).
|
||
- body `{"action":"approve"}` GUID ma → **404** ProblemDetails "Không tìm thấy ContractSigningPlan" (GlobalExceptionMiddleware map đúng; endpoint transitions SỐNG prod).
|
||
|
||
---
|
||
|
||
## §5. Cờ `KeHoachKyKet` 13/13/2 — PASS ✅ [LEAD đo on-behalf]
|
||
|
||
sqlcmd prod: `KHKK_CU=13/13/2` GIỮ · MIGTOP `20260729122015_AddContractSigningPlans` GIỮ · MIGCOUNT 69 · TABLES 96 · MENU **142 GIỮ** (§2 0-mig PASS luôn tại đây).
|
||
|
||
---
|
||
|
||
END cicd-verify df52fa0 — **VERDICT=PASS 5/5** (§1+§3 cicd-monitor · §2+§4+§5 lead 2-nguồn)
|
||
|
||
---
|