# GATE-K4C — IN-PROGRESS > Reviewer adversarial gate, wave K4c (chốt cụm-2), S166. Ghi TỪNG MỤC ngay khi đo xong (chống #53: file luôn hợp-lệ giữa chừng). > Verdict CHỈ hợp-lệ khi có dòng `END` cuối file. Chưa có END = lượt chạy chưa xong, ĐỪNG đọc verdict. ## 0. Bối cảnh nhận từ lead - Diff CHƯA commit, lead khai HEAD `ce35f90`, 2 file: - `fe-user/src/pages/pe/WorkflowMatrixViewPage.tsx` (+68/−5) — WfView lọc nhóm client-side - `tests/SolutionErp.Infrastructure.Tests/Application/ContractSigningPlanCrudTests.cs` (+1 Fact) — MAJOR-A `/deleted` lọc server-side - Lane artifacts: `sub-implfe-k4c.md` (DONE, 21/21 + 2 control-âm, 2 FLAG minor) · `sub-test-k4a.md` §MAJOR-A (8/8, RED→GREEN 2 chiều) ## 1. Đo — điền dần ### 1.0 Phạm vi diff (đo, không tin khai) - HEAD thật lúc review = `2023f41` (`wal: flush 20260801T1045`), **KHÔNG** phải `ce35f90` như lead khai — `ce35f90` là commit code cuối (K5), sau đó có 1 commit `wal:` chèn vào. Không ảnh hưởng nội dung diff (2 wal-commit không đụng `src|tests|fe-*`), nhưng nhãn base trong spec lead SAI 1 nấc. - `git diff --numstat` (working tree vs HEAD), lọc cây code: - `fe-user/src/pages/pe/WorkflowMatrixViewPage.tsx` **+68 / −5** ✅ khớp khai. - `tests/.../ContractSigningPlanCrudTests.cs` **+106 / −2** (lead khai "+1 Fact" — đúng về SỐ FACT, nhưng LOC lớn hơn vì còn sửa helper `CreateAsync` + thêm helper `ListDeletedAsync`; không phải chỉ-thêm-1-Fact thuần). - `git status --porcelain -- src tests fe-user fe-admin` = đúng 2 dòng ` M` trên, **0 dòng `??`** ⇒ cây code KHÔNG phình. - `??` toàn repo = **1** file duy nhất: chính artifact này (`sub-reviewer-gate-k4c.md`). 8 file `M` còn lại đều là agent-memory / run-artifact / `.session-counter.json` — ngoài cây code, không tính scope drift. - fe-admin: **0 diff** ✅ (không có dòng nào của `fe-admin` trong git status). ### 1.1 SOI-1 — lọc client-side WfView - Vị ngữ: `allWorkflows.filter(wf => wf.code === khkkGroupWorkflowCode(khkkGroup))`, `khkkGroupWorkflowCode = n => \`KHKK-N${n}\`` (`fe-user/src/types/khkk.ts:163`). Khớp **BE**: seeder `DbInitializer.cs:609` `var code = $"KHKK-N{n}"` ✅ và rào (v) `ContractSigningPlanFeatures.cs:420` regex `^KHKK-N([1-8])$` ✅. **Cả 2 số dòng trích trong comment đều ĐÚNG** (đã grep, không trượt). - `AwDefinitionDto.code` tồn tại (`fe-user/src/types/approvalWorkflowV2.ts:41`) ✅. Lọc theo `code` (không theo `id`/`name`) ⇒ giữ đủ mọi **version** cùng nhóm — đúng như comment khai, và đúng với `history: AwDefinitionDto[]`. - Guard `/^[1-8]$/` — ca `"03"`: regex TRƯỢT (đòi đúng 1 ký tự) ⇒ `khkkGroup = null` ⇒ **bỏ lọc, hiện tất cả**, KHÔNG bị `Number("03")=3` nuốt thành nhóm 3. **Lane khai đã xử = ĐÚNG, verify độc lập xong.** - Đồng nhất 3 chỗ: `KhkkListPage.tsx:80` và `KhkkCreatePage.tsx:67` dùng **y hệt** `/^[1-8]$/` ⇒ không đẻ luật thứ 2 cho cùng một tham số. - Đường sinh link không bao giờ đẻ `"03"`: `Layout.tsx:216` lấy `group` từ capture của regex `^Khkk_G([1-8])_(...)$` ⇒ luôn 1 chữ số. - Regression type ≠ 10: `typeInt === 10 &&` là **liên từ ĐẦU TIÊN** ⇒ type 1/2/3 (PE + Contract) luôn cho `khkkGroup = null` ⇒ `workflows === allWorkflows`, `actions = undefined` (PageHeader có `{actions && ...}` nên render **y hệt** trước). Mọi consumer downstream (`workflows.length === 0`, `workflows.map`) không đổi ⇒ **0 đổi hành vi cho matrix PE/HĐ**. ✅ - Rỗng-vì-lọc ⟂ rỗng-thật: tách 2 nhánh THẬT (`:157-165`), nhánh lọc còn nói thêm "loại phiếu này có N quy trình ở nhóm khác" — bảo vệ đúng ca người nhóm N5 tưởng cả module chưa cấu hình. Điều kiện `allWorkflows.length > 0 &&` là **phép so sánh** (không phải `{0 && ...}`) ⇒ không rò số `0` ra UI. ✅ ### 1.2 SOI-2 — queryKey KHÔNG đổi: đúng hay rò cache? **Phán: ĐÚNG, không rò.** 3 vế: 1. Payload không phụ thuộc `group`: query gọi `/approval-workflows-v2?applicableType=10&isUserSelectable=true` (`:63-71`) — BE `ApprovalWorkflowsV2Controller.cs:24-26` chỉ nhận `applicableType` + `isUserSelectable`, **không có** trục `group` ⇒ 8 nhóm dùng chung ĐÚNG một payload. Thêm `group` vào `queryKey` = 8 lần gọi mạng cho cùng một body + 8 ô cache trùng nội dung. Bỏ ra là đúng. 2. Không stale khi đổi leaf: `khkkGroup`/`workflows` là **giá trị dẫn xuất trong render** từ `useSearchParams()`, KHÔNG phải `useState` khởi tạo-một-lần ⇒ điều hướng leaf→leaf (cùng route, React Router không remount) vẫn tính lại ngay. Đây đúng là cái bẫy "vá-5" đã cắn `KhkkListPage` ở K4b, lần này **tránh được by-construction**, không cần `useEffect`. 3. Cache dùng chung là ĐIỀU MONG MUỐN: nhảy N1→N2 không refetch, lọc lại tại chỗ. Cái giá (đã cân, chấp nhận): tải trọn bộ type-10 rồi mới cắt — với 8 workflow seed thì không đáng kể. ### 1.3 SOI-4 + SOI-5 — build + cây | Phép đo | Lệnh | Kết quả | |---|---|---| | tsc fe-user | `npx tsc -b` (reviewer tự chạy, KHÔNG đọc panel IDE) | **exit 0**, 0 dòng lỗi ✅ | | tsc fe-admin | `npx tsc -b --force` | **exit 0** ✅ | | fe-admin diff | `git status --porcelain -- fe-admin` | **rỗng** ✅ | | Cây phình | `git status --porcelain -- src tests fe-user fe-admin \| grep '^??'` | **0 hit** ✅ (control dương: cùng lệnh bỏ path-filter ra 1 hit = artifact này ⇒ phép đo KHÔNG rỗng) |