3.2 KiB
SUB-REVIEWER — W1 KHKK adversarial diff review (S161, 2026-07-29)
Ghi-đĩa-TRONG-lúc-làm (chống #53 — 3 vai trước chết trong wave này). File = thứ sống sót. Scope: toàn bộ M/?? trong
git status(trừ.claude/). 12 file M (+990/−19) + 20 file ?? (~8.2K dòng, trong đó Designer.cs 6.960 = sinh máy). KHÔNG phủ lại: FK/index/maxLength/parity 2 DB (database-agent 8/8) · fault-inject test (test-specialist 4 test) · suite 566/0 + build 0W/0E (lead).
TIẾN TRÌNH
- Trục 1 — seeder
SeedKeHoachKyKetAccessAsync(5 sub-check a→e) - Trục 5 — MenuKeys.All (vị trí + tác dụng phụ)
- Trục 2 — CodeGenerator twin-diff + DI
- Trục 3 — 3 site AWV2AdminFeatures + grep-cùng-lớp
- Trục 4 — FE containment 2 lớp
- Trục 6 — boundary
TRỤC 1 — Seeder (DbInitializer.cs)
(a) Call-site thứ tự — PASS. RevokeTemporarilyHiddenModulesAsync :2096 → SeedProcurementMasterAccessAsync :2102 → SeedKeHoachKyKetAccessAsync :2109. Đứng SAU revoke ⇒ thắng revoke. Cũng SAU SeedAllRolesReviewReadPermissionsAsync :2089 (nhánh read-only skip-existing) ⇒ không bị nhánh nào hạ cờ về sau. Không có seeder nào chạy sau :2109 (2 call S65/S69 đã comment-out :2119/:2128).
(e) Revoker KHÔNG phủ Khkk_/KeHoachKyKet — PASS (rủi ro 2-chiều gotcha #84 KHÔNG hiện thực). Đọc thân RevokeTemporarilyHiddenModulesAsync:2296-2310: predicate CHỈ 3 nhánh MenuKey.StartsWith("Hrm") || StartsWith("Off") || == MenuKeys.Personal. Nhánh S92 (Contracts/Master/Catalog) đã GỠ @S159. Không prefix nào ăn Khkk_* hay KeHoachKyKet ⇒ grant không bị lật ở restart kế. (Ghi chú: thứ tự :2109 sau :2096 vẫn giữ đúng phòng khi revoker sau này mở rộng prefix.)
(b) UPGRADE-if-exists — PASS. :2414-2470: existing.TryGetValue((role.Id,key), out row) → nâng từng cờ if(!row.CanX) → continue; nhánh else db.Permissions.Add(...) chỉ chạy khi row CHƯA có (fresh DB). Đúng khuôn SeedProcurementMasterAccessAsync:2375-2394, KHÔNG phải insert-only NO-OP (F-S1 đóng). Khác khuôn gốc 2 điểm CÓ CHỦ ĐÍCH: (i) key dictionary là tuple (RoleId, MenuKey) vì quét 13 role thay vì 1 → đúng, vì .Where(p => keys.Contains(p.MenuKey)) không lọc role nên ToDictionary(p => p.MenuKey) kiểu cũ sẽ ném ArgumentException trùng khoá — implementer tránh được bẫy này; (ii) thêm vế CanDelete.
(c) CanDelete chỉ Drafter+Admin, KHÔNG hạ cờ — PASS. allowDelete = role.Name == AppRoles.Admin || role.Name == AppRoles.Drafter. Mọi phép gán đều dạng if (!row.CanX) row.CanX = true ⇒ monotonic tăng, 0 câu nào set = false trên nhánh update. Nhánh insert đặt CanDelete = allowDelete (role khác = false) — đúng.
(d) 7 key khớp bộ seed menu-row — PASS (so từng chuỗi). Seeder :2419-2424 = MenuKeys.KeHoachKyKet + Khkk_WfView, Khkk_List, Khkk_Create, Khkk_Pending, Khkk_Approved, Khkk_Deleted. Menu-row :1779-1786 = Khkk_G1 + đúng 6 chuỗi trên. Khkk_G1 CỐ Ý loại (group điều hướng, CanRead-all đã có) — khai trong comment :2417-2418. 0 typo.