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

49 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.