Files
solution-erp/.claude/agent-memory/test-specialist/MEMORY.md
pqhuy1987 6a664298fa
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m10s
[CLAUDE] Office: P11-E AttendanceReport+Excel+OtPolicy + P11-F MaTicket codegen (Wave 1)
P11-F: MaTicket gen-on-create qua WorkflowAppCodeGen (IT/2026/NNN Serializable atomic, kanban no-workflow). P11-E: GetAttendanceReportQuery monthly aggregate (day-type weekday/weekend/holiday OT x OtPolicy multiplier in-memory) + AttendanceReportExcelExporter (ClosedXML) + 2 endpoint Admin-only + fe-admin AttendanceReportPage. Migration-free. +5 test (186->191). reviewer PASS (gotcha #44 role-string verified, 0 blocker).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 12:34:48 +07:00

10 KiB
Raw Blame History

Test-Specialist Agent — Persistent Memory

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 RAG search_memory just-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 baseline

WRITE specialist độc quyền tests/**. xUnit + FluentAssertions 7.2 + EF SQLite TestApplicationDbContext + IdentityFixture. Tools: Read, Edit, Write, Bash, Grep, Glob + 5 RAG. Skills: contract-workflow + permission-matrix.

🚫 Split boundary

  • MINE: tests/SolutionErp.{Domain,Infrastructure}.Tests/**
  • NOT: production code src/Backend/** + fe-*/** → test reveal bug → REPORT em main, KHÔNG fix
  • NOT: decide WHAT to test (test plan) → em main + reviewer chốt priority

📊 Baseline 191 tests = 191 PASS (58 Domain + 133 Infra) ← S52 +5 (3 ItTicket codegen + 2 AttendanceReport). gotcha #57 RED đã GREEN (em main Mig 45 fix landed → baseline post-fix 186, +5 S52 = 191).

Run: dotnet test SolutionErp.slnx --nologo --verbosity minimal

⚠️ Pattern: deduction hook FK → seed LeaveType cho terminal test (S43)

LeaveBalance → LeaveType Restrict FK. ApproveLeaveRequestHandler terminal branch (DaDuyet) insert LeaveBalance. Test đi tới DaDuyet PHẢI seed 1 LeaveType row + LeaveRequest.LeaveTypeId = type.Id (KHÔNG random Guid → FK fail SQLite Error 19). Non-terminal (advance/reject/return/OtRequest) KHÔNG cần (OtRequest no hook). BuildLeave thêm optional leaveTypeId default random (giữ test cũ non-terminal). Year = StartDate.Year. Negative allowed (no quota guard → Remaining<0 OK). Query lazy synth Entitled=DaysPerYear khi 0 row.

⏱️ Timing rules (docs/rules.md §7)

  • Feature mới = test-after (UAT ổn → viết, Phase 9 skip per feedback_uat_skip_verify)
  • Bug fix = test-before BẮT BUỘC (reproduce → fix)
  • Critical algo = test-before merge (codegen/guard/financial/security)
  • Skip: DTO mapping, CRUD master, FE snapshot

📋 Patterns proven (apply confidently)

Pattern 10 Reflection authz regression (~50 LOC)

Catch class-level [Authorize(Policy=...)] regression: typeof(Ctrl).GetCustomAttribute<AuthorizeAttribute>().Policy.Should().Be(...). KHÔNG WebApplicationFactory heavy. Cho gotcha #44 silent 403.

SeedWorkflowAsync (1 Step DepartmentId=null skip FK + 2 Levels) + SeedApproversAsync (N user fix.CreateUserAsync). Reusable PE/Contract/Proposal workflow test.

Pattern 12 InternalsVisibleTo

Expose internal helper via <InternalsVisibleTo Include="SolutionErp.Infrastructure.Tests" /> csproj.

Spec drift detection BEFORE write (S34 lesson)

Test theo CODE (single source truth), document mismatch header comment + report. Vd soft-delete UNIQUE: code chặn opt-out → test theo code, flag drift.

gotcha #48 SQLite tie-break

OrderByDescending(CreatedAt).First() pick wrong khi 2+ Add() cùng CreatedAt frozen-clock → discriminator filter .Where(Summary.Contains("Chuyển phase")) BEFORE OrderBy.

🎯 Coverage gap backlog (priority — Reviewer flagged S36)

  1. DONE S45 — HrmConfig Holiday composite UNIQUE (Year,Date): 7 test (HrmConfigHolidayTests.cs) + surfaced Mig 43 filtered-index fix
  2. DONE S45 — EmployeeSatellite FK invariant + soft-delete + cascade: 10 test (EmployeeSatelliteTests.cs)
  3. DONE S45 — gotcha #44 authz regression EmployeesController + HrmConfigsController: 10 test (extend AuthorizePolicyRegressionTests.cs)
  4. Phase 10.3 Proposal ApproveV2 (S37) + Workflow Apps skeleton (S38) — test-after khi UAT confirm
  5. gotcha #57 (S51 REPRODUCED — RED live): LeaveType.Code + ShiftPattern.Code bare .IsUnique() chưa filter [IsDeleted]=0 (cùng class Holiday Mig 43). Test HrmConfigFilteredUniqueTests.cs 2 RED (SQLite Error 19 UNIQUE constraint failed). Em main fix Mig 45 .HasFilter → 2 GREEN. Vehicle+Driver (Mig 44) ĐÃ filtered → 2 GREEN baseline.

📅 Recent activity (last 10 FIFO)

  • 2026-06-08 (S52 P11-E + P11-F WorkflowApps/Attendance test-after): +5 test → 191 PASS (Infra 128→133). 2 file tests/.../Application/: ItTicketCodeGenTests (3 — MaTicket regex ^IT/\d{4}/\d{3}$ + sequential 001→002 cùng prefix IT/{year} LastSeq++ + per-year-prefix 2027 reset 001) + AttendanceReportTests (2 — full aggregate day-type/weighted + DepartmentId filter). Serializable-on-SQLite GOTCHA = NON-ISSUE (confirmed): WorkflowAppCodeGen.GenerateMaDonTuAsync dùng BeginTransactionAsync(IsolationLevel.Serializable) chạy SẠCH trên SQLite — provider map isolation level gracefully (no throw), format+seq+per-year đều hold KHÔNG cần try/skip. Đã proven sẵn bởi WorkflowAppApproveV2Tests (DT/LR path). Handler CreateItTicketHandler(db, cu, clock) = 3 dep MediatR. Day-type test pattern (P11-E core): holiday check chạy TRƯỚC weekend/weekday → seed 2026-06-01 (thứ Hai) vào holidaySet → assert phân Holiday dù là weekday (override day-of-week). Holiday.Date=DateOnly → BuildHoliday dùng DateOnly.FromDateTime. OtWeighted = 2×1.5+3×2.0+1×3.0=12.0m. DepartmentId filter: seed 2 Department row + 2 user khác dept → query deptA chỉ trả 1 row (handler join Users u.DepartmentId==deptId, userMeta dùng DefaultIfEmpty nên dept row optional nhưng seed cho DepartmentName assert). No prod bug. ⚠️ MSBuild OOM chạy full parallel → dùng -maxcpucount:1 -p:BuildInParallel=false (env resource, KHÔNG test fail). Tag [s52, p11-e, p11-f, codegen, day-type, serializable-sqlite-ok, test-after].
  • 2026-06-08 (S51 P11-C HMW Wave2 filtered-unique gotcha #57): +4 test tests/.../Application/HrmConfigFilteredUniqueTests.cs185 total = 183 PASS + 2 RED (Infra 123→127). Mirror HolidayTests Case 7 (seed soft-deleted Code-slot → Create same Code → assert success + active==1 + all==2). 2 GREEN Vehicle+Driver (Mig 44 config ĐÃ filtered → 2 catalog mới đúng). 2 RED INTENTIONAL = gotcha #57 REPRODUCED (test-before): CreateLeaveType_OnSoftDeletedCodeSlot...SQLite Error 19 UNIQUE constraint failed: LeaveTypes.Code + CreateShift_OnSoftDeletedCodeSlot...ShiftPatterns.Code (bare .IsUnique() đếm cả row soft-deleted; handler app-check !IsDeleted PASS → Add+SaveChanges → DbUpdateException). NOT test lỗi — REPORTED em main fix Mig 45 .HasFilter("[IsDeleted]=0") cho 2 config → flip GREEN. ⚠️ Soft-delete trong test (giống Holiday): AuditingInterceptor (prod soft-delete Deleted→Modified+IsDeleted=true) KHÔNG wire trong SqliteDbFixture → Remove+SaveChanges = HARD delete (không test được). PHẢI seed row IsDeleted=true thủ công để mô phỏng slot bị chiếm. Handlers chỉ cần IApplicationDbContext → new CreateXxxHandler(db). Tag [s51, p11-c, gotcha-57, filtered-unique, test-before].
  • 2026-05-30 (S42 P11-A Wave4): +11 test tests/.../Application/WorkflowAppApproveV2Tests.cs141 PASS (Infra 72→83). LeaveRequest 8 case full (Submit happy/guard×2, Approve advance/terminal/UPSERT-invariant/forbidden/empty-comment-placeholder, Reject→TuChoi, Return→TraLai+RejectedFromStatus) + OtRequest smoke (submit→approve single-level→DaDuyet). No prod bug — LeaveOt ApproveV2 wire correct, all PASS first run. NEW Pattern: WorkflowApps handlers = CQRS MediatR (KHÔNG service) → instantiate handler trực tiếp new ApproveLeaveRequestHandler(db, AsUser(u), clock).Handle(cmd,ct), chỉ 3 dep (IApplicationDbContext + TestCurrentUser + FixedDateTime) — nhẹ hơn 6-dep Contract service. MaDonTu format "DT/LR/2026/001". Gap #4 (Workflow Apps) PARTIAL done — Travel/Vehicle mirror pending. ⚠️ Lesson: CWD drift (fe-user) → ghi MEMORY nhầm path, em main relocate. Verify CWD root trước Write memory.
  • 2026-05-30 (S43 P11-B Wave3 LeaveBalance): +8 test tests/.../Application/LeaveBalanceTests.cs152 PASS (Infra 86→94). Deduction hook (ApproveLeaveRequestHandler terminal) full: deduct single-level (create row from DaysPerYear), only-at-terminal multi-level (advance no-deduct + 1× terminal), accumulate UPSERT (5+2=7 no new row), negative allowed (Used20>Entitled12 → Remaining8 no throw), Reject+Return no-deduct (split 5a/5b), GetMyLeaveBalances lazy synth (2 active type filter inactive), AdjustLeaveBalance upsert. ⚠️ FOUND + FIXED 2 pre-existing RED in S42 template (Approve_LastLevel_TransitionsToDaDuyet + Approve_EmptyComment_StoresPlaceholder): Wave 1 deduction hook (uncommitted, prod) làm terminal insert LeaveBalance FK→LeaveTypes Restrict FAIL vì BuildLeave dùng LeaveTypeId=Guid.NewGuid(). NOT prod bug (prod đơn luôn pin LeaveType thật) — fix tại test: BuildLeave +optional leaveTypeId, seed LeaveType ở 2 test đó. Baseline thật trước S43 = 142-pass/2-RED (KHÔNG phải 144-green). REPORTED em main.
  • 2026-06-01 (S45 HRM coverage gaps + Holiday drift) [em main proxy]: +27 test → 181 PASS (Infra 96→123). 3 file: HrmConfigHolidayTests (7 — composite UNIQUE Create/Update, self-update giữ key đổi Name no-false-positive, soft-delete exclusion) + EmployeeSatelliteTests (10 — 5× FK-invariant parent AnyAsync(!IsDeleted) guard + soft-delete + cascade-non-behavior Case5 + EF model DeleteBehavior.Cascade config assertion) + AuthorizePolicyRegressionTests extend (10 — HrmConfigs bare-[Authorize]+writes Roles=Admin; Employees class-Policy=Hrm_HoSo.Read+per-action). FOUND drift (test theo CODE = single source): Holiday DB UNIQUE (Year,Date) unfiltered vs handler !IsDeleted → recreate-on-soft-deleted-slot DbUpdateException(500). REPORTED → em main fixed Mig 43 .HasFilter("[IsDeleted]=0") (Case 7 flipped assert SUCCESS). New pattern: EF model-metadata assertion db.Model.FindEntityType(typeof(X)).GetForeignKeys()...DeleteBehavior lock schema intent. ⚠️ gotcha #57 backlog: LeaveType.Code + ShiftPattern.Code vẫn unfiltered.

⚠️ Anti-patterns (DO NOT)

  1. Touch production code → REPORT bug · 2. Skip MEMORY · 3. Test không chạy (dotnet test must PASS) · 4. git add -A · 5. Push remote · 6. Assertion trivial

🔄 Curate trigger

Size > ~30KB → archive to L2 (tiered v1). Commit scope (em main commits): Tests.