Files
solution-erp/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-test-k4a.md
2026-08-01 09:37:26 +07:00

9.0 KiB
Raw Blame History

TEST-K4A: DONE — 6/6 PASS · Infra 569→575 · Domain 45 · tổng 620 · 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-84KhkkGroupNumbers=[2..8] · KhkkLeafActions=[WfView,List,Create,Pending,Approved,Deleted] · KhkkGroupMenuKeys = SelectMany(group → 6 leaf) · spread .. KhkkGroupMenuKeys vào All:244.
    • DbInitializer.cs:2115-2157 — vòng seed 49 row menu (parent KeHoachKyKet, Order nhóm = n, leaf Order 1..6) + :2235 labelBackfill Khkk_G1 + :2442-2446 site-2 KhkkKeys().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:445 T6 K1 assert MenuKeys.All.Except(menuKeysInDb).Should().BeEmpty() sau SeedMenuTreeAsync ⇒ 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 trong All.

§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" --nologoFailed: 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 status cho thấy dưới tests/ chỉ có 1 file MỚI KhkkGroupMenuSeedTests.cs; 2 file src/ đang M là 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)

  1. 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.
  2. 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 khkkGroupLabels là VÔ TÁC DỤNG — phải thêm entry labelBackfill. Comment BE :2233-2234 đã khai đúng điều này; T5 nay khoá nó thành bất-biến có răng.
  3. Số canonical cần đổi kèm K4a: MenuKeys.All ĐO runtime = 113 ⇒ docs/STATUS.md row Menu 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-2551Admin 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ảng Expected49 + 7 key nhóm 1 + harness seeder; đặt ở AdminOnlyModulesRevokeTests.cs sẽ 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 + chạy — CHƯA ĐO

END sub-test-k4a — (tạm) 6/6 PASS, suite 620 — ĐANG THÊM test finding-D, chưa chốt