wal: flush 20260801T1038

This commit is contained in:
pqhuy1987
2026-08-01 10:38:46 +07:00
parent 284233f2dc
commit 80b8cf5113
2 changed files with 35 additions and 12 deletions

View File

@ -24,4 +24,27 @@ Vai: reviewer (READ-only, verdict-only). Ghi TỪNG MỤC, Edit sau mỗi mục
| `npx tsc -b` | `fe-admin` | **0** |
Lời khai lane (`tsc -b` ×2 exit 0 + `npm run build` ×2) khớp phần tôi đo lại. Bundle hash lane khai (`index-CZUcTUUg.js` / `index-BZWvx0Y8.js`) tôi **KHÔNG** kiểm lại — chưa deploy nên không có ô canonical để đối chứng; ghi rõ là **lời khai chưa đo**, đừng đọc thành đã-verify (bài K4a ③).
(đang tiếp tục §3)
## §3 SOI-1 — Node nhóm đúng nguồn + route khớp K4b ✅
- **1 nguồn, 0 map thứ hai.** `grep KHKK_APPROVAL_GROUPS|khkkGroupMenuLabel` toàn `fe-user/src`+`fe-admin/src`: consumer = hook K5 (`:217/:228/:230`) + `KhkkCreatePage` + `KhkkListPage`, **tất cả import từ `@/types/khkk`**. Không có mảng 8 phần tử nào khác, không có bảng nhãn thứ hai.
- 8 node dựng bằng `KHKK_APPROVAL_GROUPS.map(...)` (hằng `[1..8] as const`), nhãn `khkkGroupMenuLabel(n)` = `"{n}. " + KHKK_APPROVAL_GROUP_LABELS[n]`**derive, không chép**.
- 🟢 **ĐỐI CHIẾU LIVE (tôi tự đo, không nhận lời khai):** so nhãn cây suy ra ⟂ nhãn thật trong payload `/api/menus/me` (`menus.json` prod) → **8/8 KHỚP TỪNG KÝ TỰ**, cả 8 node `Khkk_G1..G8` đều `displayLabel = null`. Tức hôm nay cây và sidebar gọi cùng một nhóm bằng cùng một tên.
- **Route:** `onOpenAll → /khkk/list?group=${n}`. Đối chiếu K4b: `Layout.tsx:217` `khkkLeafPath(group,'List')` = `/khkk/list?group=${group}`, và leaf tĩnh `Khkk_List: '/khkk/list?group=1'` (`:63`) ⇒ **chuỗi TRÙNG KHÍT**.
- **Nối end-to-end (3 chặng, đo cả 3):** `KhkkListPage.tsx:79-80` đọc `searchParams.get('group')` + rào `^[1-8]$``:124` gửi `group` lên server → BE `ContractSigningPlanFeatures.cs:757-758` `q.Where(p => p.ApprovalGroup == request.ApprovalGroup)`. Không phải tham-số-trang-trí (khác hẳn bài K4a ①).
- **Sáng đúng mục sidebar:** `Layout.tsx:388-390` `isActive = pathname khớp && queryMatches(...)` (so khớp TẬP query) ⇒ `?group=n` từ cây ăn khớp leaf nhóm n. Lời khai lane "trang tự sáng đúng mục" **đúng, đã kiểm**.
## §4 SOI-2 — Phân phiếu, fallback, bất-biến Σ ✅ (1 MINOR)
- **KHÔNG có ca phiếu rơi khỏi cả 9 ngăn.** Vòng `:215-224` là if/else **toàn phần**: khớp `typeof g === 'number' && GROUPS.includes(g)` → ngăn n; **mọi thứ còn lại** (null · undefined · thiếu field · 0 · 9 · NaN · chuỗi) → `khkkUngrouped`. Không nhánh nào `continue`/bỏ qua.
- **Σ enforce ở đâu — trả lời thẳng: ở CẤU TRÚC, không phải ở kỷ luật.** `khkkLeaves` và các ngăn cùng sinh từ **một mảng `khkkItems`** bằng một phép phân hoạch; `stage.leaves` giữ vai danh sách phẳng canonical và `stageCount()` (`PipelineStageFolders.tsx:96`) vẫn đếm trên nó ⇒ chip số của folder cha **không thể** lệch tổng các ngăn. `console.warn` `:252` chỉ là chuông, và là **DEV-only**.
- Thứ tự đúng: ngăn "(chưa phân nhóm)" `push``:238-245` **TRƯỚC** khi `reduce` tính Σ ở `:251` ⇒ chuông không tự báo động giả.
- **Ngăn lạc gần như không thể xảy ra** (đo BE): `ApprovalGroup``int` non-null, validator `InclusiveBetween(1,8)` (`:353-356`), default 1 (`:399`), backfill Mig 71 = 1, và **0 đường update** nào ghi lại field này. ⇒ nhánh fallback là phòng thủ, không phải đường sống.
- 🟡 **MINOR-1 — nhãn ngăn lạc hứa một đằng, đi một nẻo:** `onOpenAll: () => navigate('/khkk/list')` (`:243`). Không kèm `?group=` ⇒ BE **không lọc gì cả**, trang mở ra là **toàn bộ phiếu của cả 8 nhóm**, trong khi nhãn và tooltip nói "Mở danh sách: (chưa phân nhóm)". Sidebar cũng không sáng mục nào (query rỗng không khớp leaf nào). BE hiện **không có** bộ lọc "không thuộc nhóm nào" để trỏ tới, nên đây là hạn chế thật chứ không phải quên gõ. Đề nghị: bỏ `onOpenAll` cho riêng ngăn này (component đã có nhánh `<span>` khi thiếu `onOpenAll`, `:151-155`) — mất một cú bấm gây hiểu nhầm, không mất gì khác.
## §5 SOI-3 — Ngăn rỗng render THẬT ✅
Đo đường đi, không đọc lời khai — **3 chốt, không chốt nào lọc theo `length`**:
1. Dựng: `KHKK_APPROVAL_GROUPS.map(...)``.map` trên hằng 8 phần tử, **0 `.filter`** trong cả khối.
2. Vẽ: `PipelineStageFolders.tsx:287-295` `stage.groups !== undefined ? stage.groups.map(g => <GroupFolder…>)` — vẽ **thẳng mảng nhận được**, không điều kiện phụ.
3. Trong ngăn: `GroupFolder` `count === 0` → vẫn render `<details>` đủ (chevron + tên bấm được + `SoonChip`), thân in *"Chưa có phiếu ở nhóm này."*
- Nhánh *"Chưa có dữ liệu ở giai đoạn này."* (`:296`) nay **bị nhánh `groups` chặn trước** ⇒ GĐ2 rỗng hiện 8 ngăn thay vì 1 dòng. Đúng spec "HIỆN ĐỦ 8 kể cả rỗng".
- Không đụng `hideEmpty`: vẫn lọc ở tầng **stage** bằng `stageCount()` = `leaves.length` ⇒ đang tìm-kiếm mà gói không có KHKK thì cả folder GĐ2 ẩn, **không** đổ ra 8 ngăn rỗng.
(đang tiếp tục §6)