16 KiB
Test-Specialist Agent — Persistent Memory
-
S166-K4a (08-01) 49 row menu KHKK 8-nhóm — 7 test (6 gốc + T7 sau resume), file MỚI
Application/KhkkGroupMenuSeedTests.cs, return SẠCH[baseline đo tươi Infra 569 → sau 576, Δ+7, 0 hồi quy · Domain 45 · tổng 621]: BƯỚC ĐẮT NHẤT = TÌM CHỒNG LẤN TRƯỚC KHI VIẾT —ContractCatalogTests.cs:445(T6 lane K1) đã assertMenuKeys.All.Except(menuKeysInDb).BeEmpty()sauSeedMenuTreeAsync⇒ invariant "49 key mới đều có menu-row" TỰ ĐỘNG được phủ, và nó XANH ở baseline = chứng nhân độc lập cho claim by-construction ⇒ KHÔNG nhân bản, chỉ viết cái nó không đo. Kỹ thuật chính (tái dụng S164 ma-trận-cùng-ruột): T5 labelBackfill bôi hỏng nhãn CẢKhkk_G1LẪNKhkk_G2trong 1 lần → seed lại → G1 tự lành / G2 giữ chữ hỏng; khác biệt duy nhất = có/không entry tronglabelBackfill⇒ chứng đúng cơ-chế backfill chứ không phải upsert "tiện tay" ghi Label (gotcha #11). T6 đối-chứng-cùng-lượt: cùng role,Pe_DuyetNcc_ListCanCreate=true vs 49 key Khkk CanCreate=false ⇒ chuỗi "false" không phải do seeder no-op. T4 mirror đo DB↔DB (leaf nhóm 2..8 so với row nhóm 1) + chốt trước "6 nhãn nhóm 1 PHÂN BIỆT" — thiếu vế này thì mirror đúng ở mọi thế giới. T1 kỳ vọng = mảng 49 chuỗi VIẾT TAY, KHÔNG gọi lạiMenuKeys.KhkkGroup/KhkkLeaf(gọi lại = tautology). 2 bẫy đo đã né: (i) đếm họKhkkbằng Ordinal in-memory chứ khôngStartsWith→ LIKE SQLite case-insensitive ASCII; (ii) kiểm KHÔNG cóHasDatacho MenuItems ⇒ 56 row đến TỪ seeder, không phải EF-seed. Số ĐO:MenuKeys.Allruntime = 113 (Policies DERIVED 452) — trùng đếm by-source lane BE. 0 bug prod. Tag[s166-k4a, tim-chong-lap-truoc-khi-viet, ma-tran-2-key-1-bien, doi-chung-cung-luot, ordinal-khong-LIKE]- +T7 (resume, gate trả finding D MAJOR)
Revoke_DoesNotTouch_KhkkGroups→ 7/7, Infra 576, tổng 621: bảo vệ ca ĐÃ VỠ THẬT (Run #423 447/494 row rơi, gotcha #84). Bẫy vacuous đọc ra TỪ MÃ chứ không từ prompt::2546-2551Admin-role-chưa-seed ⇒ revoker RETURN SỚM ⇒ test không seed Admin sẽ xanh vì revoker CHƯA CHẠY → bắt buộc control dương (2 keyOff_*/Personalcủa CHÍNH 2 role đó phải về false-4-cờ) + vế Admin-giữ-true + vế 112 row Khkk sống. Chứng răng bằng PROBE VI-PHÂN (cấm chạm prod ⇒ không fault-inject được): file tạm dựng lại đúng hình query revoke + thêm ĐÚNG 1 vếStartsWith("Khkk")→ ĐO 112→0 ⇒ T7 phân biệt 2 thế giới; probe xoá + verify 2 chiều (git sạch ∧ suite = 569+7 chứ không +8). Đế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ữ với Run #423.
- +T7 (resume, gate trả finding D MAJOR)
-
S164-K3 (07-31) KHKK level-finalize + pin-đúng-nhóm — 5 test, return SẠCH
[baseline đo tươi 609/0 = 45D+564I KHỚP đề bài · sau: 614/0, Δ+5, 0 hồi quy]: +4 vàoContractSigningPlanApprovalTests.cs(T-a/b/c finalize + T-e giữ-cờ), +1 vàoContractSigningPlanGroupAndCatalogTests.cs(T-d rào (v)) — chọn file thứ 3 thay "file mới" để KHÔNG nhân bản 70 LOCSeedPeForCreateAsync+CreateAsyncđã có sẵn ở đó. Kỹ thuật chính = MA TRẬN cùng-ruột-khác-1-biến thay cho fault-inject (không được chạm prod, mà prod đang mang diff lane khác): 1SeedFinalizeScenarioAsync→ T-a (cờ+apply=true ⇒ DaDuyet+chốt giá) / T-b (cùng seed, đổi ĐÚNGapplyLevelFinalize:false⇒ (2,1) advance thường) / T-c (Cấp không cờ + default true ⇒ (0,2)). Bỏ qua cờ ⇒ T-a đỏ · bỏ qua param ⇒ T-b đỏ ·||thay&&⇒ T-c đỏ. Điều kiện SỐNG CÒN: đặt cờ ở Bước-2-Cấp-2 của quy trình 3 Bước — cờ ở cấp cuối thì "kết thúc" xảy ra ở CẢ HAI thế giới ⇒ T-a xanh mà chứng minh 0 (assertStepCountAsync==3để chốt). T-d: CÙNG workflowKHKK-N5cho 2 kết quả trái ngược (phiếu nhóm 3 = 409 · nhóm 5 = qua) + không-đốt-mã (rào (v):409-420đứng TRƯỚC codegen:428) có control-dương 001/002/003 tăng thật. Kiểm dữ-liệu chứ không chỉ đọc regex:DbInitializer.cs:609sinh đúng$"KHKK-N{n}"⇒ rào neo thật. T-e: 3 vế (tick⇒true · không-tick⇒false · đối chứng type-1 cũng true ⇒ ECHO chứ không phải đổi ép-false thành ép-true). CỐ Ý KHÔNG pinAllowApproverSkipToFinal==truedù mã đang echo: service KHKK 0 lần đọc cờ đó (:47khai "không port") ⇒ đó là ứng-viên config-lie #78 CÒN SÓT; pin nó = biến khả-năng-lỗi thành yêu cầu → REPORT lead thay vì test. 0 bug prod. Tag[s164-k3, level-finalize, ma-tran-cung-ruot-1-bien, co-o-cap-cuoi-lam-rong-phep-do, khong-pin-config-lie] -
S161-W2 (07-29) KHKK CRUD 8 test
[hmw wf_7490179a-70b · chết #53 sau khi file LAND (sub-md dừng §0.1) · lead chạy suite tươi 574/0 = 566+8, cả 8 tên đúng]:Application/ContractSigningPlanCrudTests.cs(7) + extendApi/AuthorizePolicyRegressionTests.cs(PIN reflection). 2 PIN spec + 6 acceptance: happy-path Lines=winners + SUM IsSelected đúng NCC (bẫyw.Idvsw.SupplierId) · second-create 409_AndDoesNotBurnCode(mã không đốt khi Conflict — phép đo sequence side-effect) · workflow-guard 2 nhánh Conflict/NotFound · no-winner · soft-delete-then-recreate + changelog giữ · owner/phase guard. Phát hiện đắt (sub-md §0.1): TestApplicationDbContext KHÔNG wire AuditingInterceptor ⇒Remove()= xoá CỨNG ⇒ đo "xoá-tạo-lại" trên xoá-cứng = ĐO NHẦM CƠ CHẾ (rào 1-PE-1-KH dựa global-filter che row soft-deleted, không phải row biến mất) → dựng fixture riêng CÓ interceptor cho nhóm delete-test. Baseline đo tươi trước khi viết (không tin số đề bài). Tag[s161-w2, khkk-8-test, khong-dot-ma-khi-409, fixture-interceptor-cho-soft-delete, do-nham-co-che-xoa-cung] -
S161 (07-29) W1 KHKK: 4 test schema+codegen
[hmw wf_a95c9909-14b · chết #53 LÚC ĐỢI full-suite (việc thật đã xong) → sub-md 10KB ghi-từng-mục cứu trọn; lead chạy full-suite tươi 566/0 + điền §2/§4 on-behalf]: File MỚICommon/ContractSigningPlanSchemaTests.cs— 4 test: (1) PIN-specBayBang_MoiBang_CoAuditFields_VaQueryFilter(quét EF model theo NAMESPACE →BeEquivalentTođúng bộ 7 tên [bảng #8 lọt = ĐỎ] + audit-fields + soft-delete assert 2-CHIỀU [BaseEntity phải KHÔNG có IsDeleted] + seed IsDeleted=true chứng filter là BIỂU-THỨC-THẬT); (2) PINSigningPlanCodeGenerator_Format_KhkkYearSeqD3— regex + tuyệt-đối 001→002 + row LastSeq==2 + đẩy đồng hồ 2027 → KHKK/2027/001 reset (thiếu vế này\d{4}xanh cả khi năm hardcode); (3) #57 xoá-mềm-thêm-lại KHÔNG nổ UNIQUE + vế đối chứng 2-dòng-sống PHẢI DbUpdateException (không có = xanh cả khi index chưa từng tạo); (4) pin slot 10 enum. Fault-inject 2 chiều trên bảng-kỳ-vọng rồi revert — chứngGetDeclaredQueryFilters()phân biệt 2 thế giới. Learned: (1) prompt lead ≠ đĩa — LevelOpinion là AuditableEntity nhưng CỐ Ý KHÔNG filter (lý-do ghi 2 chỗ: site orphan-purge phải thấy row soft-deleted) ⇒ test theo CODE + assert cái-cố-ý thành invariant có răng; (2) EF Core 10:GetQueryFilter()obsolete-prone →(IReadOnlyEntityType).GetDeclaredQueryFilters(); (3) Serializable trên SQLite = graceful-map, tiền lệSqliteDbFixture.cs:36-42+ PE codegen test — KHÔNG chế fixture mới; (4) KHÔNGRemove()đo xoá mềm (TestCtx không wire AuditingInterceptor → xoá CỨNG, bài S155). Tag[s161, w1-4-test, faultinject-2-chieu, test-theo-code-khong-theo-prompt, clock-2027-reset, 53-luc-doi-suite] -
S155 (07-27) PE xóa-khi-đang-duyệt +10 → 561 (1 FAIL GIỮ ĐỎ = BUG PROD cascade-detach-Added-child): 2 bài SỐNG CÒN còn dùng: (i)
TestApplicationDbContextKHÔNG wireAuditingInterceptor⇒Remove()= XÓA CỨNG — đo xóa-mềm phải dựng fixture riêng có interceptor, không thì assert đúng ở CẢ HAI thế giới; (ii) "Add con → Remove cha → 1 SaveChanges" = conAddedbị cascade thành Detached, mất row. Verbose → archive/baseline-history.md §S155. -
S153 (07-26) fault-inject máy
mind-check18/18 (KHÔNG phải test C#, baseline không đổi): 3 bài còn dùng: (i) fixture-HỎNG cho-xanh trông Y HỆT máy-ĐÚNG cho-xanh ⇒ soi RUỘT fixture (cat -A/repr), đừng chỉ đọc exit code; (ii) cặp CÙNG-RUỘT khác 1 biến = chứng đọc-config-LIVE; (iii) đo wall-clock phải đi nhánh ĐẮT (early-exit = tự đo nhánh rẻ rồi gọi là chi phí thật). Verbose → archive/baseline-history.md §S153. -
S134 (07-17) PE lũy-kế TẠM TÍNH +8 → 528: khuôn regression "bất động" mạnh nhất = C6 exact-numbers 2 hàm complementary cùng seed (gọi CẢ
ComputeAsync+ComputePendingAsync, assert số CHÍNH XÁC 2 phía ⇒ bắt double-count). +bẫy FluentAssertionsContainInOrder(params T[])overload-clash khi T=Guid → bọcnew[]{...}. Verbose → archive/baseline-history.md §S134. -
S133 (07-17) PE budget-freeze T0 REPRODUCE + T1-T9 → 519: khuôn test-before bug-fix còn dùng: đưa phiếu tới trạng-thái đích QUA service THẬT (
TransitionAsync), KHÔNG seed thẳng Phase (post-fix snapshot chỉ set qua transition ⇒ seed thẳng = đo nhầm); 2 sanity-assert chống vacuous TRƯỚC assert chính. ⚠️ 2 invocation cùng role + cùng task-index trong 1 run-folder = sub-file GHI ĐÈ nhau. Verbose → archive/baseline-history.md §S133.
Persistent diary cross-session. Auto-injected first ~200 lines at spawn (L1 HOT). Update BEFORE every stop. Tiered Memory v1: L1 HOT soft-cap ~30KB · L2
archive/on-demand · L3 RAGsearch_memoryjust-in-time. Keep entry ≤ 1.5K chars (gotcha #53). NEW agent S39 (2026-05-29) — dedicated test layer (tách khỏi implementer Case 3).
Role/split-boundary/timing-rules/Pattern-10-11-12/anti-patterns: đã có nguyên văn trong agent-definition (auto-inject mỗi spawn) ⇒ KHÔNG chép lại ở đây. Chỉ giữ thứ agent-def KHÔNG có.
📊 Baseline ĐO TƯƠI 2026-08-01 (S166): 621 = 45 Domain + 576 Infra, 0 FAIL
- ⚠️ Con số trong agent-definition ("130") là STALE — luôn đo lại
dotnet testtrước khi báo delta, đừng tin số đề bài. - Count history + verbose per-session note (S54→S155): archive/baseline-history.md (L2, on-demand).
Pattern S67: private-static seed/init → invoke qua REFLECTION (
GetMethod(name, NonPublic|Static)+Invoke(null, [db, roleManager, NullLogger.Instance])); seed MenuItem rows TRƯỚC Permission (FK MenuKey→MenuItem.Key Cascade, SQLite Error 19 nếu thiếu). Cycle-guard test: SqliteDbFixture đủ (no User); rollup-count test cần IdentityFixture. Run:dotnet test SolutionErp.slnx --nologo --verbosity minimal -p:BuildInParallel=false -maxcpucount:1(MSBuild OOM → serialize build)
⚠️ Pattern: deduction hook FK → seed LeaveType cho terminal test (S43)
LeaveBalance→LeaveType Restrict FK. ApproveLeaveRequest terminal (DaDuyet) insert LeaveBalance → test tới DaDuyet PHẢI seed 1 LeaveType + LeaveRequest.LeaveTypeId=type.Id (random Guid→FK fail SQLite 19). Non-terminal (advance/reject/return/OtRequest) KHÔNG cần. BuildLeave optional leaveTypeId default random. Year=StartDate.Year. Negative OK (no quota guard). Query lazy-synth Entitled=DaysPerYear khi 0 row.
🎯 Coverage gap backlog (priority — Reviewer flagged S36)
- ✅ DONE S45 — HrmConfig Holiday composite UNIQUE (Year,Date): 7 test (
HrmConfigHolidayTests.cs) + surfaced Mig 43 filtered-index fix - ✅ DONE S45 — EmployeeSatellite FK invariant + soft-delete + cascade: 10 test (
EmployeeSatelliteTests.cs) - ✅ DONE S45 — gotcha #44 authz regression EmployeesController + HrmConfigsController: 10 test (extend
AuthorizePolicyRegressionTests.cs) - Phase 10.3 Proposal ApproveV2 (S37) + Workflow Apps skeleton (S38) — test-after khi UAT confirm
- gotcha #57 (S51+S52 REPRODUCED): HRM
HrmConfigFilteredUniqueTests2 RED (LeaveType+Shift+OtPolicy) → em main Mig 45.HasFilterGREEN. S52 EXT MasterMasterCatalogFilteredUniqueTests3 RED (Department cfg:18 / Project:19 / Supplier:24 bare.IsUnique()) → pending em main fix migration. Vehicle+Driver (Mig 44) ĐÃ filtered. Pattern: seedIsDeleted=trueslot + Create cùng Code → assert active==1 +IgnoreQueryFiltersall==2.
📅 Recent activity (one-line FIFO — verbose in archive/baseline-history.md)
Danh sách FIFO S54→S118b (22 mục) ĐÃ nằm trọn trong
archive/baseline-history.md+archive/_INDEX.md— gỡ khỏi index @S166 vì trùng lặp. Dưới đây CHỈ giữ mẹo còn tái dụng:
- Bẫy đo lặp nhiều lần: (i)
MethodInfo.InvokeKHÔNG auto-bind optional param → phải pass đủ arg (S117); (ii) SQLite collation BINARY không bắt dup khác-hoa-thường, prod SQL Server thì CÓ → dedup phải nằm ở SERVICE, đừng dựa DB (S113/D3); (iii) test invoke method CÔ-LẬP qua reflection VẪN PASS dù prod đã tắt call trong chainSeedAsync— reflection-test không chứng chain còn sống (S92). - Khuôn assert mạnh: CONTRAST/by-contrast trong CÙNG một lần chạy (S54/S118) · GUARD-FIRST (S60) · RED-proven-via-
git stashcho bug-fix test (S86) · boundary strict-<(S69b) · ranh giớinet==0mà từng-dòng≠0 (S116).
🔄 Curate trigger
Index > ~17KB → archive sang L2 (archive/baseline-history.md + con-trỏ trong archive/_INDEX.md). Commit scope (em main commits): Tests.
S161-W7d2 (2026-07-30) — 3 PIN ban-cung Hdc_ (lead VERIFY-APPEND tu memoryDelta return; suite 587→590/0 CI-doc-lap xac nhan)
- Total cua PagedResult = dau van tay loc SERVER-SIDE: CountAsync sau moi Where ⇒ ban "lay pageSize:100 roi loc client" cho Items Y HET nhung Total = ca the gioi. Items-only KHONG phan biet duoc; +1 dong assert Total thi phan biet.
- Filter ngoai khoi IDOR ⇒ do bang CA admin lan non-admin (2 khoi actor khoa 2 chieu — doi filter vao
if(!admin)thi ban chi-do-1-vai van xanh). - Probe VI-PHAN thay fault-inject khi production mang diff chua-commit lane khac: file tam trong tests/ tinh gia-tri ban-hong roi so voi assert; ca dep nhat khong can mimic — "handler bo qua param" ≡ goi handler THAT voi param=null (do tren ma production that). Zero-risk. Xoa xong verify 2 chieu (git sach + so test tut ve dung).
- Chon hang-xom phase seed theo NGHIA-TU: DangDongDau=8 ten dung la khau ban-cung = moi ngon nhat cho cai-dat sai; TraLai=98/TuChoi=99 >9 ⇒ moi
>=sai deu lo. - 🔴 Surprise tu-thu: ban dau viet tron §5-§8 kem so chua-do (587→590 + 3 dong fault-inject BIA) — "ghi-tung-muc" bi hieu thanh "ghi dan bai roi dien". Cat ve 98 dong, de vet. So cuoi TRUNG du-doan ⇒ neu khong cat thi khong ai phat hien. Bai: dan-bai co san con-so ky-vong = bay claim-truoc-do tinh-vi nhat (trong y het "ghi dia chong #53"); muc chua chay CHI duoc tieu-de + "CHUA DO".