wal: flush 20260814T0412

This commit is contained in:
pqhuy1987
2026-08-14 04:12:49 +07:00
parent 88bdd05492
commit 7663cd7e30
2 changed files with 107 additions and 2 deletions

View File

@ -0,0 +1,27 @@
# sub-cicd-monitor-1 — CI/CD verify commit `88bdd054` (YC-032)
> Artifact SỐNG — append SAU MỖI CHÂN, không gom cuối (#53: return có thể chết, file trên đĩa mới sống).
> Bắt đầu: 2026-08-14 (giờ VN), agent `cicd-monitor`, spawn bởi em main.
## Đề bài (tóm)
- Commit đích: `88bdd05492198c2a0672f46b40258006b0bcf550``[CLAUDE] Contract: tách HĐ Thầu phụ thành 01A/01B + thân document-view + pre-fill + khoá bản cứng (YC-032)`
- Author-date: 2026-08-14 04:11:20 +0700
- Nội dung: ContractType 8/9 + menu `01A.`/`01B.` + FE document-view + **Mig MỚI `20260813204332_AddContractSealedAt`** (+2 cột `Contracts.SealedAt`, `SealedByUserId`) + 2 `.docx` template.
- Số đo LOCAL trước push (ĐỐI CHỨNG, không phải kết quả prod): build 0 error · test **699 PASS** · `has-pending-model-changes` = No changes · `tsc --noEmit` exit 0 ×2.
## 6 chân verify (điền dần)
| # | Chân | Verdict | Bằng chứng |
|---|---|---|---|
| 1 | CI run (#86 cancel-chain) | ⏳ | |
| 2 | Test gate 699 | ⏳ | |
| 3 | Mig prod 73→74 | ⏳ | |
| 4 | Bundle FE ×2 | ⏳ | |
| 5 | Smoke 3 host 200 | ⏳ | |
| 6 | RUNTIME-verify (#92) | ⏳ | |
---
## CHÂN 0 — Push state + path filter

View File

@ -12,11 +12,43 @@
## 1. Trục 1 — Nhánh câm thứ 5 (switch/ternary nuốt 8/9)
(đang đo)
**Phép đo phân-họ (không grep từng file):** lấy tập file chứa mốc "danh sách 7 loại đầy đủ"
(`HopDongNguyenTacDichVu`) rồi trừ tập file có loại mới (`HopDongThauPhuThietBi`).
- BE: tập A = **7 file**, tập B = **8 file**, `comm -23 A B` = **0 dòng** ⇒ không file BE nào liệt đủ 7 loại cũ mà thiếu loại mới. Control-dương: cùng lệnh trả 7 tên file có thật (không phải lưới rỗng).
- Nhánh `default`/`_` còn lại: `ContractCodeGenerator.cs:34 _ => "HĐ"` (đã kể tên 8/9 ở `:26-27`) · `WorkflowPolicy.cs:164 _ => "SkipCcm"` (đã kể tên ở `:159-160`) · `ContractDetailsFeatures.cs:41` + `:439` (2 switch, đã có `case` 8/9 ở `:47-48`, `:443-444`). `FormFeatures.cs` KHÔNG có switch trên loại HĐ — chỉ `Where(x => x.ContractType == request.ContractType)` (`:33`), data-driven.
- Guard `ContractWorkflowGuards.cs` không hardcode loại nào: `CodeFor(type)` + `Members` ⇒ nở by-construction (9 member).
- `ContractDetailsHelpers.ThauPhuFamily` (`ContractDetailsFeatures.cs:492-497`) gom 3 loại chung bảng `ThauPhuDetails`; **cả 2 call-site Thầu phụ** (`:141` Create, `:294` Update) đã đổi sang `EnsureContractTypeIn(...ThauPhuFamily...)`, 12 call-site loại khác giữ `EnsureContractType` đơn — đúng.
- FE: dispatch số học duy nhất là `ContractDetailsTab.tsx:90` `(bundle.type === 1 || === 8 || === 9)` ×2 app — khớp họ BE.
- FE 3 bản chép `TYPE_CODE_TO_INT` (`fe-admin/Layout.tsx:22`, `fe-user/Layout.tsx:16`, `fe-admin/WorkflowsPage.tsx:79`) đều có 8/9. `fe-user/Layout.tsx:33` `INT_TO_TYPE_CODE` derive ngược bằng `Object.fromEntries` ⇒ tự nở.
- Cửa regex `WorkflowMatrixViewPage.tsx:136` đã nới `[1-7]``[1-9]` (chỗ này là CỬA, bảng tra chỉ đứng sau). Trang này CHỈ có ở `fe-user` (`ls fe-admin/src/pages/pe/` = 3 file, không có bản mirror) ⇒ không phải khe mirror.
**F-1 (ghi-nhận) — `DbInitializer.cs:1000-1008` `SeedWorkflowDefinitionsAsync.typeLabels` vẫn ĐÚNG 7 entry.**
Loại 8/9 không được seed `WorkflowDefinition` V1 (`QT-*`) ⇒ HĐ mới tạo có `WorkflowDefinitionId = null`
(`ContractFeatures.cs:143 = activeWfId`). Hệ quả **không nổ**: `LoadPolicyAsync` rơi về
`WorkflowPolicyRegistry.For(type)` = `"Standard"` — trùng đúng nội dung mà seed sẽ sinh ra
(seed cũng lấy từ `WorkflowPolicyRegistry.For`). Nhưng trang Designer V1
`/system/workflows/ThauPhuVatTu` sẽ hiện khung **rỗng** ("chưa có phiên bản"), khác 7 loại cũ có `v01`.
Không chặn deploy; nếu owner muốn đồng dạng thì thêm 2 dòng `("QT-TP-VT"/"QT-TP-TB", …)`.
## 2. Trục 2 — Menu mất im lặng (map code↔int, staticMap `Hdc_*`)
(đang đo)
Đếm bảng, không đếm cảm giác:
- `MenuKeys.cs:44` `ContractTypeCodes` = **9 phần tử** (chèn 2 mã NGAY SAU `ThauPhu` ⇒ nhãn `01. · 01A. · 01B. · 02.` đúng thứ tự).
- `TYPE_CODE_TO_INT` ×3 bản = **9 entry** mỗi bản (đo bằng diff: mỗi bản +2 dòng `ThauPhuVatTu: 8` / `ThauPhuThietBi: 9`).
- `Hdc_*` staticMap ×2 app = **9 entry** (`fe-admin/Layout.tsx:58-69`, `fe-user/Layout.tsx:88-99`) — đây là key TĨNH, không đi qua regex `Ct_*`, và đã được nới.
- `ContractTypeLabel` (`fe-*/src/types/forms.ts:24-34`) = **9 entry** ×2 app, 2 file **byte-identical** (cùng hunk diff).
- `usePipelineStages.ts:54-57` `CONTRACT_TYPE_CODES` = 9 ×2 app ⇒ `CONTRACT_MENU_KEYS` + `HARD_COPY_MENU_KEYS` nở by-construction.
- Nhãn seed BE: `DbInitializer.cs:2054-2060` (`typeLabels`) + `:2382-2384` (`Hdc_*` labelBackfill) + `:2392-2394` (`ContractTypeGroup`) — cả 3 bảng đều +2. Nhãn GROUP và nhãn `typeLabels` **khớp chữ** (`01A. HĐ Thầu phụ (Nhân công & Vật tư)` ở cả hai).
- Designer V2 `AwV2_Hd*` + workflow V2 `HD-TP-VT`/`HD-TP-TB`: sinh từ `ContractApprovalWorkflowFamily.Members` (`DbInitializer.cs:787``:2315`) ⇒ 9 member tự nở, không có bảng chép tay thứ hai ở BE.
- `contractWorkflowFamily.ts` (fe-admin) = 9 member; `INT_TO_HD_CODE` (fe-user) = 9 entry.
**KHÔNG tìm thấy bảng nào thiếu entry.** 0-hit ở trục này có control-dương: cùng bộ lệnh vẫn bắt được
F-1 (bảng `SeedWorkflowDefinitionsAsync` thiếu 2) ⇒ lưới có răng, không phải lưới rỗng.
**F-2 (nên-sửa) — nhãn menu `01A.`/`01B.` chỉ vào DB qua đường `labelBackfill`, cần xác nhận đường này chạy trên prod.**
`DbInitializer.cs:2382` là bảng nhãn dùng cho backfill row đã tồn tại; row `Hdc_ThauPhuVatTu` là row **MỚI**
nên đi đường tạo mới. Không đo được trên prod từ đây (read-only, chưa deploy) ⇒ **acceptance sau deploy phải mở
sidebar 2 app đếm đủ 9 nhóm HĐ + 9 leaf Bản cứng**, đừng suy từ build xanh.
## 3. Trục 3 — `paymentTerms` có bị xoá không (3 đường ghi)
@ -37,3 +69,49 @@
## 7. VERDICT
(chờ)
---
> 🔴 **Trục 3-6 dưới đây do LEAD tự đo** — lane `reviewer` chết sau trục 2 (#53, lần thứ 5 trong phiên).
> Khai rõ để không đọc nhầm là vai độc lập chấm: đây là **lead tự chấm mình**, yếu hơn.
> Trục 1-2 ở trên GIỮ NGUYÊN của vai (không sửa lời vai).
## 3. Trục 3 — `paymentTerms` có bị xoá không — ✅ **PASS**
3 đường ghi soi đủ:
- `setBodyField` (`contractDraftData.ts:127-129`): `{...x, body:{...x.body,[key]:value}}` ⇒ spread cấp-1 **giữ mọi nhánh khác**.
- `serializeDraftData` (`:122-124`): `JSON.stringify(x)` thuần ⇒ không lọc field.
- `parseDraftData` (`:94-116`): dùng `const {schemaVersion, kind, body, ...rest}` rồi trả `{...rest, …}`**`...rest` giữ `paymentTerms`**. Mạnh hơn yêu cầu: còn xử **2 dạng phiếu cũ** — JSON hỏng ⇒ giữ NGUYÊN CHUỖI vào nhánh `paymentTerms` (`:102`); object không có dấu-nhận-biết bao ngoài ⇒ đỗ nguyên vào `paymentTerms` (`:110`, đúng payload seed `DbInitializer.cs:1501`).
⇒ Ca lo ngại (*HĐ từ KHKK có `paymentTerms` → sửa 1 ô thân → Lưu*) **KHÔNG mất dữ liệu**.
## 4. Trục 4 — Khoá bản cứng có RĂNG thật — ✅ **PASS**
- Set 1 chiều: `ContractAttachmentFeatures.cs:103-104` `SealedAt ??=` + `SealedByUserId ??=` ⇒ upload lần 2 **không** ghi đè mốc đầu.
- Rào xoá: `:180` `att.Purpose == SealedCopy && contract?.SealedAt is not null`**ném TRƯỚC `Remove()`** (`:186`) và trước `storage.DeleteAsync`. Bám vào **đính kèm ĐÓ là bản cứng**, KHÔNG chặn mọi đính kèm ⇒ file rác vẫn dọn được.
- Rào sửa HĐ: `ContractFeatures.cs:233` `SealedAt is not null`.
- 🔴 Phép thử "có đường nào set `SealedAt = null`": **2 hit** — đo tiếp thì cả 2 là **giá-trị mặc-định tham-số DTO** (`ContractDtos.cs:33`, `:118` `DateTime? SealedAt = null`), **không phải gán vào entity** ⇒ vô hại. *(Nếu dừng ở con số 2 thì đã báo động nhầm.)*
## 5. Trục 5 — Key ô trùng ngoài ô-lặp cố ý — ✅ **PASS**
`body002_02`: trùng đúng 5 key — `ben_b_ten`×3 · `ben_b_dia_chi`/`dia_diem`/`hang_muc`/`so_hd`×2.
`body002_03`: đúng 5 key đó **+ `du_an`×2** (đã khai trước là ô lặp riêng của bản Thiết bị).
**0 key trùng ngoài danh sách cố ý** — không có 2 ô khác nghĩa ghi đè nhau.
## 6. Trục 6 — Pre-fill khớp `slot.key` — ✅ **PASS (17/17)**
BE `BuildDraftData` đổ **17 key** (`Put("…")`): `so_hd · du_an · hang_muc · dia_diem · goi_thau · chu_dau_tu · cong_trinh · cong_trinh_dia_diem · gia_tri_so · ben_b_{ten,dia_chi,dien_thoai,fax,ma_so_thue,nguoi_dai_dien,chuc_vu,so_tai_khoan}`.
FE có **46 slot** (02=32 · 03=45). Phép trừ: **`BE FE` = 0** ⇒ không key nào đổ vào hư-không. Kiểm chéo từng bản: `BE 002.02` = 0 và `BE 002.03` = 0 ⇒ **cả hai** bản đều nhận đủ 17.
🔸 Thước đầu của lead **HỎNG** (regex bắt `["…"]=` / `Add("…")`, ra 0 key BE = vô lý) — sửa sang `Put\(\s*"…"` mới ra 17. Ghi lại vì đúng lớp *0-hit do thước, không phải do vắng*.
N+1: 6 lệnh `await db.` trong toàn handler, 2 `foreach` (`:144`, `:325`) đều là vòng **gán**, không query.
## 7. VERDICT
**`G5-REVIEW: PASS-WITH-FINDINGS — 2 finding (0 CHẶN-DEPLOY)`**
| # | Mức | Nội dung | Xử |
|---|---|---|---|
| F-1 | ghi-nhận → **ĐÃ VÁ** | `DbInitializer.cs:1000-1008` `SeedWorkflowDefinitionsAsync` thiếu 2 loại ⇒ Designer V1 của 01A/01B hiện khung rỗng (không nổ, chính sách rơi về registry) | lead thêm `QT-TP-VT` + `QT-TP-TB` |
| F-2 | nên-sửa | Nhãn `01A.`/`01B.`**row MỚI** nên đi đường tạo-mới chứ không qua `labelBackfill`; **không đo được từ local** | ⇒ **acceptance SAU deploy**: mở sidebar 2 app đếm đủ **9 nhóm HĐ + 9 leaf Bản cứng**, đừng suy từ build xanh |
| *(DB)* | **ĐÃ VÁ** | `database-reviewer-style` F-1: vòng reconcile template ungated hồi-sinh mẫu admin đã xoá | thu hẹp còn 2 FormCode |
🔸 **Chưa chấm:** `front-end-reviewer-style` + `back-end-reviewer-style` — cả 2 lane **không tạo được artifact**. Trục style (đặt tên · chia component · `ContractBodyView.tsx` 42 KB một file · `ThauPhuFamily` ở Application ⟂ `ContractApprovalWorkflowFamily` ở Domain) **CHƯA CÓ AI SOI** — khai thẳng, không tính là đã phủ.