Files
solution-erp/docs/changelog/sessions/2026-06-01-S45-hrm-test-gaps-holiday-fix.md
pqhuy1987 7fbe05a19c [CLAUDE] Docs: S45 session-end — test-gap + Mig 43 sync
STATUS/HANDOFF S45 (154->181 test, Mig 43) + gotcha #57 (soft-delete UNIQUE must filter [IsDeleted]=0) + session log + root CLAUDE counts + ef-core skill Mig 43 row + flush 3 agent MEMORY (test-specialist proxy after #53 truncation + cicd Run #368 + investigator P11-C recon).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 14:49:28 +07:00

4.9 KiB
Raw Blame History

Session 45 — HRM test-gap stabilization + Holiday drift fix (Mig 43)

Date: 2026-06-01 Scope: Tests + Infra (schema) Commits: 051b62b (Tests) → 0c5a014 (Mig 43) → docs (this session-end) CI: Gitea Run #368 (run_number 254) PASS ~4m20s — verified prod Test: 154 → 181 PASS (58 Domain + 123 Infra, 0 fail / 0 skip)


Bối cảnh + quyết định

Anh giao quyền chọn thứ tự việc. Em main chọn "stabilize before extend": đóng 3 test-gap deferred từ S35-S38 TRƯỚC khi chồng schema Phase 11 mới (P11-C). Lý do: 1 gap CRITICAL-flagged, nhỏ + low-risk, deferred nhiều session; làm xong baseline vững rồi mới thêm Mig.

Việc done

1. Đóng 3 test-gap (commit 051b62b, +27 test)

🟪 test-specialist viết (em main chốt test plan sau recon 8 file):

  • Gap1 (CRITICAL) — HrmConfigHolidayTests.cs (7 test): Holiday composite UNIQUE (Year, Date). Create duplicate → Conflict; same-date-diff-year → OK; Update→occupied-slot → Conflict; self-update giữ (Year,Date) đổi Name → KHÔNG false-positive (guard short-circuit entity.Year!=req.Year || entity.Date!=req.Date); Update→empty-slot OK; Update non-existent → NotFound; soft-delete exclusion.
  • Gap2 (MAJOR) — EmployeeSatelliteTests.cs (10 test): 5× FK-invariant (mọi Create satellite guard parent AnyAsync(Id && !IsDeleted) → NotFound); soft-deleted parent → NotFound; happy path FK đúng; Delete soft + DeletedBy + re-operate NotFound; DeleteEmployeeProfile soft KHÔNG cascade satellite (behavior hiện tại — handler chỉ soft-delete parent); EF model DeleteBehavior.Cascade config assertion (lock schema intent).
  • Gap3 (MAJOR) — extend AuthorizePolicyRegressionTests.cs (10 test): 2 controller shape KHÁC nhau lock đúng intent — HrmConfigsController (class [Authorize] trần Policy/Roles null + writes Roles="Admin") vs EmployeesController (class Policy="Hrm_HoSo.Read" + per-action Create/Update/Delete + 1 satellite representative).

⚠️ gotcha #53 recurrence: test-specialist return truncated mid-MEMORY-update ("let me read it first"). → em main verify-on-disk (glob + git status + đọc 3 file line-by-line + dotnet test) thay vì tin output cụt. MEMORY proxy-updated bởi em main.

2. Holiday drift fix (commit 0c5a014, Mig 43)

👤 em main solo (bug-fix reasoning chain + schema decision tightly coupled → tránh spawn-truncation cho change nhỏ).

  • Bug Gap1 lòi ra: HolidayConfiguration DB UNIQUE (Year,Date) plain .IsUnique() KHÔNG filter, trong khi handler check !IsDeleted → admin xoá (soft) 1 ngày lễ rồi tạo lại cùng (Year,Date) → app-check PASS nhưng DB UNIQUE reject → DbUpdateException 500 reachable.
  • Fix: .HasFilter("[IsDeleted] = 0") — khớp pattern 13× sẵn có (Catalogs ×4, Contract/PE/Proposal/Budget/WorkflowApps code-unique). Mig 43 FilterHolidayUniqueIndexByIsDeleted (DropIndex + CreateIndex filter; Down reverse sạch). Applied Dev + Design LocalDB.
  • Test flip: Case 7 từ assert DbUpdateException → assert SUCCESS (reuse slot, 1 active + 1 soft-deleted). Spec-change → update test cùng commit.
  • Table count vẫn 91 (index-only mig, no CREATE TABLE).

3. cicd verify (🟩 Run #368 PASS)

test gate 181 · Mig 43 applied prod (__EFMigrationsHistory top) · IX_Holidays_Year_Date filter_definition = ([IsDeleted]=(0)) live (was NULL) · FE bundle UNCHANGED Krjvg_3j/6sNStgxa (đúng — BE-only push, KHÔNG flag ship-fail) · health 200 · 0 regression.

4. P11-C pre-flight (🟦 investigator-codebase)

Vehicle+Driver catalog: chưa có master entity (chỉ VehicleBooking free-text Mig 39). Recommend: extend HrmConfigs +2 kind (vehicles+drivers) declarative KIND_CONFIG, Mig 44, giữ VehicleBooking free-text (FK link defer). Caught gotcha #57 backlog (LeaveType/Shift unfiltered).

Learnings

  • gotcha #57 NEW: soft-delete + UNIQUE → MUST .HasFilter("[IsDeleted]=0"). Backlog: LeaveType.Code + ShiftPattern.Code vẫn unfiltered.
  • feedback_background_spawn_visibility: spawn agent foreground = im lặng vài phút = "looks frozen" (anh phản hồi). → đẩy long work background + report "đã launch X" ngay. Cũng có 1 dead turn ("No response requested") = hiccup thật, em main nhận.
  • Test theo CODE = single source of truth → test lòi drift thật (Holiday) → REPORT → fix proper. Closed loop: gap test → bug surfaced → fixed + verified prod cùng session.
  • EF model-metadata assertion (db.Model.FindEntityType(...).GetForeignKeys()...DeleteBehavior) = cách lock schema intent (cascade) không cần DB round-trip — Pattern-10-style cho EF model.

Next (S46, anh pick)

P11-C Vehicle+Driver (Mig 44, recon ready) · gotcha #57 fix LeaveType/Shift filtered-unique (gộp P11-C) · P11-D ItTicket SLA / P11-E AttendanceReport / P11-F MaTicket · Phase 9 Ops.