Files
solution-erp/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k3.md
2026-07-31 21:47:23 +07:00

72 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

REVIEWER-GATE-K3: PASS-WITH-FLAGS — 8 finding (3 MAJOR / 5 MINOR, 0 blocker build-test)
# Reviewer gate K3 — 8 workflow nhóm + port finalize + designer
Ghi-đĩa TRONG LÚC LÀM (chống #53). Đo từ ĐĨA, HEAD `2967c43`, 25 file M / +908 102; 2 untracked chỉ ở `.claude/auto-memory/`.
## §1 Build / test / npm — số NGUYÊN VĂN
| Phép | Lệnh | Kết quả nguyên văn |
|---|---|---|
| BE build | `dotnet build SolutionErp.slnx` | `Build succeeded.` · `0 Warning(s)` · `0 Error(s)` |
| BE test #1 | `dotnet test SolutionErp.slnx` | 🔴 `Failed! - Failed: 1, Passed: 568, Skipped: 0, Total: 569 - SolutionErp.Infrastructure.Tests.dll` |
| BE test #2 | `dotnet test SolutionErp.slnx` | `Passed! - Failed: 0, Passed: 45, Total: 45 - Domain.Tests` + `Passed! - Failed: 0, Passed: 569, Total: 569 - Infrastructure.Tests`**614/0** |
| BE test #3 | `--filter ~ContractSigningPlan` | `Passed! - Failed: 0, Passed: 34, Total: 34` |
| npm fe-admin | `npm run build` | `✓ 1961 modules transformed` · `✓ built in 19.63s` · 0 TS error |
| npm fe-user | `npm run build` | `✓ built in 7.81s` · 0 TS error |
⇒ 614/0 = 45D+569I **khớp claim ở lượt #2/#3**; lượt #1 FAIL → F-4.
## §2 Code-vs-spec K3 (5 điểm)
1. **Seed 8 wf khớp ROSTER §0**`DbInitializer.cs:526-688`. 3 Steps (`Phòng Cung Ứng` / `P. Kiểm soát Chi phí` / `Ban Giám đốc`), 11 email `Distinct` khớp từng dòng bảng §0 `sub-implbe-k3.md`; Cấp 1 OR-4 / OR-4 / OR-1, Cấp 2 `tra.bui` / `chuong.phan`; `AllowApproverFinalize=true` **chỉ**`(CCM, Cấp 2, chuong.phan)` đặt PER-ROW; idempotent `AnyAsync(w.Code == code)`; UNGATED demo-seed. ✅
2. **Finalize qua choke-point + 2-lệnh-grep LUẬT** — chạy CẢ HAI:
- `Phase = ContractSigningPlanPhase.DaDuyet``:280`, `:322` (+ `:336` là dòng doc)
- `ApplyApprovedValuesOnFinalize``:279`, `:321` (+ doc/def/comment)
**cùng khớp**: 2 site gán DaDuyet ↔ 2 site gọi helper, helper đứng NGAY TRƯỚC gán ở cả hai. ✅
3. **Rào (v)**`ContractSigningPlanFeatures.cs:411-420`, regex `"^KHKK-N([1-8])$"` neo 2 đầu, khớp literal seeder `$"KHKK-N{n}"` n=1..8; so với `approvalGroup` (`:395` = `request.ApprovalGroup ?? Default`); code ngoài họ → cho qua. ✅
4. **8 key VÀO All + DELTA (đếm MÁY)**`MenuKeys.All` = **64** (HEAD `2967c43` = **56**) ⇒ **+8**; policies DERIVED = **256** (HEAD **224**) ⇒ **+32**. 8 menu-row `DbInitializer.cs:1980-1989` order 3..10 dưới `ApprovalWorkflowsV2`. ✅ mã — ❌ khai (F-3).
5. **FE phép-âm `Khkk_` = 0-hit + control dương**`git diff -U0 | grep -E "^\+.*Khkk_[A-Za-z]+: *'"` = **0**; control dương cùng regex trên cả `Layout.tsx` = **6** hit ⇒ mẫu CÓ RĂNG. Nhánh mới `Layout.tsx:181` `/^KhkkN[1-8]$/` nằm TRONG `awV2Match`, đặt SAU whitelist 3 code cũ. ✅
## §3 Phán 3 quyết-định lead
- **(i) GIỮ PUT-Conflict (spec vá-3 bảo gỡ) — LEAD ĐÚNG, spec vá-3 LIỆT NHẦM.** `UpdateAwDefinitionCommandHandler` (`:515-649`) **0 lần** tham chiếu `typeEnum`/`ContractSigningPlan`; grep 2 token toàn file cho hit ở `:97/:125/:126/:331/:341/:349/:387`**tất cả** thuộc list/create, KHÔNG hit nào trong thân PUT. Guard `:598-603` (echo cờ) · `:612-617` (dòng mới) · `:627-632` (bỏ người giữ cờ) là **luật versioning CHUNG mọi ApplicableType**; gỡ = nới rào cho PE/Contract/Proposal = regression ngoài scope K3. Thêm: gỡ FE-lock (đúng) đã đủ để cờ seed `true` không đẻ 409 lúc PUT vì payload nay echo giá trị THẬT.
- **(ii) GIỮ ép-false `AllowApproverSkipToFinal` type-10 (O-1) — LEAD ĐÚNG ở BE, nhưng sweep BẤT ĐỐI XỨNG (F-2).** Tự verify: token `AllowApproverSkipToFinal` trong `ContractSigningPlanWorkflowService.cs` = **1 hit duy nhất `:47`, và là COMMENT** ⇒ service **0 lần đọc cờ**; control dương: cùng token trong `PurchaseEvaluationWorkflowService.cs` = **3 hit** (code thật) ⇒ grep có răng. Echo cờ cho type-10 = đẻ config-lie #78 mới ⇒ giữ ép-false ĐÚNG.
- **(iii) Seed cờ cùng-commit ≠ config-lie #78 — ĐÚNG, nhánh THẬT tồn tại.** `ContractSigningPlanWorkflowService.cs:276-289`: `if (actingLevel.AllowApproverFinalize && applyLevelFinalize)``EndedByLevelFinalize=true``ApplyApprovedValuesOnFinalize(plan)``Phase=DaDuyet` → xoá 2 con-trỏ → log → `return`. Cờ seed CÓ máy tiêu thụ trong cùng diff. ✅ *(nhưng đường ĐI NGƯỢC — bỏ tick để trình CEO — chết ở tầng UI: F-1)*
## §4 Ranh giới
- `ReturnOrRejectAsync` (`:354+`), `ApplyApprovedValuesOnFinalize` (`:345-349`), nhánh advance thường (`:293-329`): `git diff -U0` trên service chỉ **5 hunk** = `@@-37,10` (comment) · `@@-89,0` (thêm param) · `@@-124` (truyền param) · `@@-245` (chữ ký private) · `@@-266,0 +270,21` (khối finalize MỚI) ⇒ **0 dòng nội-dung đổi** trong 3 vùng trên. ✅
- Submit-guard K2 / file K1: không có trong `git diff --name-only`. ✅
- **0 migration mới**: `git diff --name-only | grep -i migration` = **0**; `git status --porcelain -- src tests | grep '^??'` = **rỗng**. ✅
- Route/menu-row NGOÀI 8 `AwV2_KhkkN*`: DbInitializer thêm đúng 8 row; Layout thêm đúng 1 nhánh regex họ `AwV2_`. ✅
- Rào (v) chỉ ở CREATE — `UpdateContractSigningPlanCommandHandler` không chạm `ApprovalWorkflowId`/`ApprovalGroup` (0 hit trong thân) ⇒ không có lỗ update-lách. ✅
## §5 Test lane (mở ruột 2 test)
- **T-a `ApproveV2_CapMangCoKetThuc_ChotPhieuNgay_KhongTrinhTiepBuocSau`** (`ContractSigningPlanApprovalTests.cs:944-994`): đo hành-vi THẬT qua service. Sanity 3 vế TRƯỚC (`ShouldBeAt(ChoDuyet,1,2)` · `EndedByLevelFinalize=false` · `StepCountAsync == 3` kèm lý-do *"Cấp mang cờ KHÔNG được là cấp cuối — nếu là cấp cuối thì phiếu kết thúc ở CẢ HAI thế giới và test này xanh mà không chứng minh gì"* = **anti-tautology guard**). Đo SAU 5 trục: phase + 2 con-trỏ · cờ runtime · `ApprovedAmount` 3 dòng gồm ca `??=` giữ 300 · opinion signer. Kèm **chứng-nhân song sinh** `WitnessAtFlagLevel` bất động (cả cờ lẫn giá). ✅
- **T-e `CreateAwDefinition_LoaiKhkk_GiuNguyenCoKetThucTaiCap_KhongConEpFalse`** (`:1079-1104`): 3 vế — (i) tick ⇒ `true`; (ii) không tick ⇒ `false` (chặn "bật bừa"); (iii) **đối-chứng type khác** `DuyetNcc` cũng `true` ⇒ phân biệt "gỡ ép-false" với "đổi thành ép-true". Đi qua `CreateAwDefinitionCommandHandler` THẬT. ✅
- **0 đè test cũ**: `git diff -- tests/ | grep -c '^-[^-]'` = **2**, cả 2 là cùng một sửa cơ-học `TransitionAsync(..., CancellationToken.None)``(..., ct: CancellationToken.None)` (named-arg vì thêm param) — **không** nới assert nào.
## §6 FINDING (8)
**MAJOR**
- **F-1** `fe-{user,admin}/src/pages/khkk/KhkkWorkflowPanel.tsx:136-142`**opt-out `applyLevelFinalize` KHÔNG có tầng UI ⇒ trạm CEO chết ở 8/8 workflow seed.** Body POST là **literal đúng 2 field** `{action, comment}`; `grep applyLevelFinalize fe-*/src` = **0 hit** ở KHKK. Controller `ContractSigningPlansController.cs:213` `?? true` ⇒ mọi lượt Chương bấm "Duyệt" đều finalize. Seeder cắm cờ cho `chuong.phan`**cả 8** workflow ⇒ Step 3 «Ban Giám đốc» (`truong.nguyen`) **không đường nào tới**. **Đối-chứng chứng minh đây KHÔNG phải khuôn PE**: `fe-*/src/components/pe/PeWorkflowPanel.tsx:63` = `useState(false)` + `:259` LUÔN gửi tường minh ⇒ PE mặc-định **KHÔNG** kết-thúc-sớm (opt-in tại UI); KHKK mặc-định **LUÔN** kết-thúc-sớm. Lời owner OG-3/OG-9 (*"a Chương sẽ quyết định là cái đó cần CEO ko"*) **không thực thi được từ UI**. Kèm: comment `KhkkWorkflowPanel.tsx:15-17` khẳng định *"không có gì để panel render thêm"* — tiền-đề SAI, chính wave này vừa đẻ tham số để người duyệt quyết. Acceptance: thêm ô tick opt-out ở panel (mirror `PeWorkflowPanel.tsx:778`), HOẶC khai tường minh lên HANDOFF rằng "trình CEO" hiện chỉ làm được bằng admin bỏ cờ ở Designer.
- **F-2** `ApprovalWorkflowV2AdminFeatures.cs:387``fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx:263` + `:1300-1310`**sweep ép-false bất-đối-xứng ⇒ tick bị NUỐT IM LẶNG.** FE gỡ khoá **cả 2** ô (gồm `allowApproverSkipToFinal`), BE **giữ** ép-false `SkipToFinal` cho type-10. Admin tick "Cho phép duyệt thẳng Cấp cuối" trên quy trình KHKK → CREATE lưu `false`, UI không báo gì. Đây đúng class mà comment vừa bị xoá đã cảnh báo (*"màn hình nói một đằng dữ liệu một nẻo"*), chỉ đảo chiều. **0 test phủ** (T-e chỉ đo `Finalize`). Acceptance: giữ `disabled` riêng ô SkipToFinal cho type-10, HOẶC bỏ ép-false BE + port nhánh.
- **F-3** `docs/STATUS.md:6`**DELTA đo được nhưng chưa khai.** Máy: `All` 56→**64** (+8); policies 224→**256** (+32); STATUS vẫn ghi "Policies **224** · Menu keys **56**". Spec cụm-1 vá-1 bắt "mỗi commit kèm lệnh đếm lại + cập nhật 2 row STATUS". **Tái phát y hệt** finding ④ của gate K1 cùng phiên.
**MINOR / khai-thật**
- **F-4** Suite **flake 1/3 lượt**: `dotnet test SolutionErp.slnx` lượt #1 `Failed: 1, Passed: 568``ContractSigningPlanCrudTests.DeleteContractSigningPlan_SoftDeletes_KeepsChangelog_ThenCreateAgainSucceeds` chết ở `KhkkFixture..ctor()` `:62` `EnsureCreated()``CallSiteRuntimeResolver`. Fixture có từ W2 ⇒ **không phải K3 đẻ**, nhưng câu "614/0 tươi" chỉ đúng 2/3 lượt — đừng khai trần.
- **F-5** `DbInitializer.cs:665` — seeder idempotent per-Code **thuần skip, 0 nhánh UPDATE**: roster đổi (người nghỉ / đổi phòng) ⇒ phải UPDATE tay trên prod. Cùng lớp seeder SP-002 ở K1.
- **F-6** `DbInitializer.cs:637-640``Description` khai *"Admin có thể chỉnh người/quyền tại chỗ hoặc tạo version mới"*: nửa sau đúng, nửa đầu **sai với cờ finalize**`ApprovalWorkflowV2AdminFeatures.cs:598-600` chặn đổi cờ, `:627-629` chặn bỏ người giữ cờ khi sửa tại chỗ. Chuỗi này hiển thị ra UI admin.
- **F-7** `ContractSigningPlan.cs:51` + `fe-*/src/types/khkk.ts:260``EndedByLevelFinalize` **được GHI nhưng chưa expose DTO** (chính FE type tự khai). Test T-a lý-giải *"FE/GĐ3 đọc cột này"* — hiện **chưa** ai đọc; ghost-window đã-khai, không phải bug, nhưng câu biện-minh mạnh hơn sự thật.
- **F-8** `ContractSigningPlanWorkflowService.cs:37-42` + `:335-337` — 2 lệnh grep tự-kiểm in ra **gồm cả chính dòng `///` doc** (`:336`, `:337`) ⇒ người chạy sau đếm 3 vs 5 rồi tưởng lệch. Nên nêu rõ "bỏ dòng `///` khi đếm".
## §7 Verdict
**PASS-WITH-FLAGS** — build 0W/0E · suite 614/0 (lượt tươi) · npm ×2 sạch; 5/5 điểm code-vs-spec khớp; 3/3 quyết-định lead ĐÚNG về kỹ-thuật; ranh giới sạch (0 mig, 0 đổi hành-vi vùng cấm, 0 route ngoài họ). **0 blocker kỹ-thuật**, nhưng **F-1 + F-2 là nợ HÀNH-VI**: F-1 làm mất đúng cái quyền quyết mà owner vừa chốt (OG-3/OG-9); F-2 tái tạo class "UI nói một đằng DB một nẻo" ở ô còn lại. F-3 là acceptance chưa đóng. Owner/lead quyết ship-rồi-vá hay vá-trước-ship.
END sub-reviewer-gate-k3 — TOTAL: 8 finding (3 MAJOR / 5 MINOR) · 0 blocker build-test · verdict PASS-WITH-FLAGS