11 KiB
TEST-K4A: DONE — 7/7 PASS (6 gốc + T7 finding-D) · Infra 569→576 · Domain 45 · tổng 621 · 0 hồi quy · 0 prod-code touched
Lane test K4a — test-after 49 row menu KHKK 8-nhóm (S166, 2026-08-01)
Agent: test-specialist. Ghi-từng-mục TRONG LÚC LÀM (luật sống-còn bài K3 engine-exit). Mục nào chưa chạy = ghi tiêu-đề + "CHƯA ĐO", KHÔNG điền số dự-đoán.
§0 — Trạng thái khởi động
- §0.1 ĐÃ đọc khuôn. Chốt harness: seeder là
private static→ REFLECTION.SeedMenuTreeAsync(ApplicationDbContext, ILogger)— 2 tham số.SeedAllRolesReviewReadPermissionsAsync(ApplicationDbContext, RoleManager<Role>, ILogger)— 3 tham số (site-2).- Khuôn invoke đã có sẵn ở
ContractCatalogTests.cs:459(InvokePrivateSeedAsync, rm nullable) → dùng lại HÌNH, không chế fixture mới. Fixture =IdentityFixture(cần RoleManager cho site-2).
- §0.2 ĐÃ đọc BE đã land (git diff, chưa commit):
MenuKeys.cs:72-84—KhkkGroupNumbers=[2..8]·KhkkLeafActions=[WfView,List,Create,Pending,Approved,Deleted]·KhkkGroupMenuKeys= SelectMany(group → 6 leaf) · spread.. KhkkGroupMenuKeysvàoAll:244.DbInitializer.cs:2115-2157— vòng seed 49 row menu (parentKeHoachKyKet, Order nhóm = n, leaf Order 1..6) +:2235labelBackfillKhkk_G1+:2442-2446site-2KhkkKeys().Concat(KhkkGroupMenuKeys).- Đếm BY-SOURCE
All= 113 (tự cộng tay từng dòng initializer). Chưa phải số ĐO — sẽ đo runtime ở T1.
- §0.3 CHỒNG LẤN ĐÃ CÓ (không viết lại):
ContractCatalogTests.cs:445T6 K1 assertMenuKeys.All.Except(menuKeysInDb).Should().BeEmpty()sauSeedMenuTreeAsync⇒ invariant "49 key mới ĐỀU có menu-row" ĐÃ được test cũ phủ tự động (nó là phép thử của claim by-construction). Lane K4a KHÔNG nhân bản; thay vào đó đo cái test cũ KHÔNG đo: hình bộ sinh · đếm 56 row họ Khkk · idempotent ×2 · labelBackfill · grant site-2. - §0.4 Baseline Infra ĐO TƯƠI 2026-08-01 (trước khi thêm file): 569 PASS / 0 FAIL (42 s).
Đo trên cây có BE K4a đã land ⇒ test T6-K1 cũ (
All.Except(menuKeysInDb)) XANH với 49 key mới = bằng chứng độc lập rằng vòng seed 49 row khớp đúng bộ key trongAll.
§1..§4 — File test đã LAND: tests/SolutionErp.Infrastructure.Tests/Application/KhkkGroupMenuSeedTests.cs (6 test)
Harness: reflection private static + IdentityFixture (không fixture mới). Không đụng prod code.
| # | Test | Đo cái gì | Chống vacuous bằng |
|---|---|---|---|
| T1 | KhkkGroupMenuKeys_Is49Keys_GroupImmediatelyFollowedBySixLeaves |
49 key · Equal với mảng 49 chuỗi VIẾT TAY (không gọi lại factory ⇒ không tautology) · liền-kề Khkk_G{n} ngay trước Khkk_G{n}_WfView · pin 6 action |
kỳ vọng là literal, sai 1 ký tự là đỏ |
| T2 | MenuKeys_All_ContainsThe49_NoDuplicate_AndKeepsGroup1Outside |
All ⊇ 49 · OnlyHaveUniqueItems · HaveCount(113) = số ĐO runtime · KhkkGroupNumbers == [2..8] · 7 key nhóm 1 KHÔNG nằm trong All |
vế cuối = guard thật: thêm số 1 vào bộ sinh ⇒ tree.Add("Khkk_G1") lần 2 ⇒ trùng PK lúc boot |
| T3 | SeedMenuTree_RunTwice_Has56KhkkRows_NoDuplication_AndCorrectTreeShape |
seed ×2: 56 row họ Khkk (7 nhóm-1 + 49) · lần 2 danh sách key Y NGUYÊN · tổng bảng MenuItems bất động · 8 group parent=KeHoachKyKet Order=n · mỗi group đúng 6 con · 8 nhãn nhóm phân biệt |
đếm bằng Ordinal in-memory (không phụ thuộc collation LIKE); đã kiểm KHÔNG có HasData cho MenuItems ⇒ 56 row đến TỪ seeder, không phải EF seed |
| T4 | SeedMenuTree_NewGroupLeaves_MirrorGroup1_LabelIconOrder |
42 leaf mới khớp nhãn + icon + Order của leaf nhóm 1 tương ứng (đo DB↔DB, không bảng hardcode) | chốt trước "6 nhãn nhóm 1 PHÂN BIỆT" — nếu chúng trùng nhau, phép so mirror đúng ở mọi thế giới |
| T5 | SeedMenuTree_LabelBackfill_HealsGroup1Label_WithoutAddingRows_ControlKeyStaysDirty |
MA TRẬN cùng-ruột-khác-1-biến: bôi hỏng nhãn CẢ Khkk_G1 (ca thật: về chuỗi skeleton S159) LẪN Khkk_G2 trong cùng 1 lần → seed lại → G1 tự lành, G2 giữ chữ hỏng; tổng row bất động |
2 kết quả TRÁI NGƯỢC trong 1 lần chạy; khác biệt duy nhất = có/không entry labelBackfill ⇒ chứng đúng cơ chế backfill, không phải upsert "tiện tay" ghi Label (gotcha #11) |
| T6 | SeedAllRolesReviewRead_GrantsReadOnNew49KhkkKeys_ReadOnly_WithPeContrast |
site-2 phát CanRead cho cả 49 key (nêu tên Khkk_G2_List) · C/U/D=false · 7 key nhóm 1 GIỮ quyền (.Concat mở rộng chứ không thay thế) |
ĐỐI CHỨNG CÙNG LƯỢT: cùng role đó Pe_DuyetNcc_List có CanCreate=true ⇒ chuỗi "false" trên Khkk không phải vì seeder no-op. Chạy SeedMenuTreeAsync trước = smoke FK cho TOÀN grant-set |
Đường vào duy nhất của 49 key ở site-2 = KhkkKeys().Concat(MenuKeys.KhkkGroupMenuKeys) (K4a) —
All.Where(StartsWith "Pe_") không bắt Khkk_* ⇒ gỡ .Concat là T6 ĐỎ.
§5 — Chạy filtered — ĐÃ ĐO
dotnet test tests/SolutionErp.Infrastructure.Tests --filter "FullyQualifiedName~KhkkGroupMenuSeed" --nologo
→ Failed: 0, Passed: 6, Total: 6 (3 s).
Ghi chú số: MenuKeys.All runtime = 113 ĐÚNG như đếm by-source của lane BE (assert xanh) ⇒
Policies DERIVED = 113 × 4 = 452.
§6 — Full suite — ĐÃ ĐO
- Infra: Failed 0, Passed 575, Total 575 (30 s) — baseline 569 + 6 = 575 ⇒ 0 hồi quy.
- Domain: Failed 0, Passed 45 (311 ms) — đo tươi, không lấy từ trí nhớ.
- Tổng suite = 45 + 575 = 620.
Caveat trung thực: giữa lượt làm có commit 7a903cf (lane F-1, FE + ContractSigningPlanFeatures.cs)
land vào repo. Đã kiểm: git diff --stat -- src/ vẫn đúng 42/79 dòng của riêng K4a như lúc mở lượt
⇒ byte nguồn K4a KHÔNG đổi trong lúc đo; file lane F-1 đã nằm sẵn trên đĩa TRƯỚC lần chạy full
(nó là M từ đầu, commit chỉ chuyển trạng thái index) ⇒ con số 575 đo đúng trạng thái đĩa hiện tại.
§7 — Rào đã giữ
- KHÔNG chạm production code:
git statuscho thấy dướitests/chỉ có 1 file MỚIKhkkGroupMenuSeedTests.cs; 2 filesrc/đangMlà diff của lane BE K4a (có từ trước lượt này). - KHÔNG đụng
ContractSigningPlan*/KhkkWorkflowPanel/khkk.ts. - KHÔNG commit, KHÔNG push.
- KHÔNG sửa
SolutionErp.slnx(project SDK-style tự glob.cs; test đã build + chạy).
§8 — Quan sát gửi lead (KHÔNG phải bug, không tự sửa)
- Chồng lấn có lợi: test T6 lane K1 (
ContractCatalogTests.cs:445) nay là phép thử tự động cho claim "49 key ∈ All đều có menu-row" — nó XANH ở baseline 569 ⇒ claim by-construction của K4a đã có chứng nhân độc lập, lane K4a không cần lặp lại. - Nhãn G2..G8 KHÔNG tự lành (đo ở T5, đối chứng): nếu owner đổi chữ 7 nhãn nhóm sau khi prod đã
seed thì sửa trong
khkkGroupLabelslà VÔ TÁC DỤNG — phải thêm entrylabelBackfill. Comment BE:2233-2234đã khai đúng điều này; T5 nay khoá nó thành bất-biến có răng. - Số canonical cần đổi kèm K4a:
MenuKeys.AllĐO runtime = 113 ⇒docs/STATUS.mdrowMenu keys= 113 ·Policies= 452. (T2 sẽ ĐỎ nếu 2 số này drift khỏi mã.)
§D — RESUME gate K4a, finding D (MAJOR): bất-biến "revoker KHÔNG đụng Khkk_*"
Lệnh lead: +1 Fact Revoke_DoesNotTouch_KhkkGroups. Lý do: ca ĐÃ VỠ THẬT trên prod
(Run #423 — 447/494 row rơi, 11/13 role về 0; gotcha #84) mà hiện 0 test ⇒ thêm 1 chữ vào
bộ lọc revoke thì suite vẫn xanh.
- §D.1 Đọc PREDICATE THẬT từ mã (
DbInitializer.cs:2554-2568), không theo prompt:RoleId != adminRoleId && (MenuKey.StartsWith("Hrm") || MenuKey.StartsWith("Off") || MenuKey == Personal) && (bất kỳ cờ nào đang true)→ set cả 4 cờ = false. 🔴 Bẫy vacuous-pass phát hiện khi đọc mã::2546-2551— Admin role chưa seed ⇒ revoker RETURN SỚM, no-op. Test không seed Admin sẽ XANH vì revoker CHƯA TỪNG CHẠY, chứ không phải vìKhkk_*được tha. Bắt buộc seed Admin + có control dương. - §D.2 Chọn chỗ đặt:
KhkkGroupMenuSeedTests.cs(file của lane K4a) — đã có sẵn mảngExpected49+ 7 key nhóm 1 + harness seeder; đặt ởAdminOnlyModulesRevokeTests.cssẽ phải chép lại danh sách 49 key (nguồn thứ 2 = nguy cơ lệch). Vẫn MIRROR khuôn 2-vế của file đó. - §D.3 ĐÃ viết
T7 Revoke_DoesNotTouch_KhkkGroups(cuốiKhkkGroupMenuSeedTests.cs). Kịch bản 1 lượt, 3 chiều phân biệt:- seed menu THẬT + site-2 grant THẬT cho 3 role (Admin + Drafter + DeptManager);
- cấp tay 2 key trong tập ẩn (
Off_DanhBa,Personal) cho cả 3 role = CONTROL DƯƠNG; - tick thêm
CanCreatechoKhkk_G5_Create(mô phỏng admin bật cờ ghi trên ma trận); - chạy
RevokeTemporarilyHiddenModulesAsync; - Vế 1 (control dương): 2 key kia của 2 role non-Admin về false cả 4 cờ ⇒ chứng
revoker CÓ CHẠY (nếu đỏ = phép đo hỏng, không phải Khkk hỏng);
Admin giữ true ⇒ chứng vế
RoleId != adminRoleIdcòn sống; Vế 2: 56 key Khkk × 2 role = 112 row sống sót,CanReadtrue, row KHÔNG bị xoá, cờ ghi đã tick vẫn true. Đếm bằng ĐƠN VỊ của sự cố thật (row sống sót) để thông điệp lỗi cùng ngôn ngữ Run #423.
- §D.4 CHỨNG T7 CÓ RĂNG bằng PROBE VI-PHÂN (không được chạm prod ⇒ không fault-inject
vào
DbInitializer): file tạmZzProbeTeethTemp.csdựng lại ĐÚNG hình câu truy vấn revoke (:2554-2568) + thêm đúng 1 vế|| MenuKey.StartsWith("Khkk")rồi đo trên DB thật. Kết quả ĐO: trước = 112 row Khkk CanRead=true · sau bộ-lọc-bị-nới = 0 ⇒ đúng tập row mà T7 assert sẽ rơi hết ở thế giới hỏng ⇒ T7 phân biệt được 2 thế giới, KHÔNG phải assert đúng ở mọi thế giới. Probe chạy 1/1 PASS rồi XOÁ; verify 2 chiều:git status -- tests/chỉ còn 1 file??(KhkkGroupMenuSeedTests.cs) và suite = 569+7 (không phải +8) ⇒ 0 dư lượng.
§9 — SỐ CHỐT (đo tươi, lần cuối, sau khi đã xoá probe)
- Filtered
~KhkkGroupMenuSeed: 7/7 PASS. - Infra: 576 PASS / 0 FAIL (baseline 569 + 7) · Domain: 45 PASS / 0 FAIL.
- Tổng suite = 621.
END sub-test-k4a — VERDICT=7/7 PASS (+7 test, suite 621 = 45 Domain + 576 Infra, 0 hồi quy, 0 prod-code touched)