[CLAUDE] Docs: Harness-4 two-tier runtime-VERIFIED (spawn-test 2 chiều post-restart) + email-back AI_INFRA
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
- Spawn-test 2 chiều S57bis: H1 tooling-auditor (demote pin) self-report claude-opus-4-8[1m] + H2 harvest-curator (promote inherit) self-report claude-fable-5[1m] → nấc executed-file/PENDING-RESTART → RUNTIME-VERIFIED (adap-report §2/§5 + STATUS row). [1m] 1M-resolve SE tự verify. - Email update 2026-06-11-se-to-ai_infra-harness-4-runtime-verified (nac sent, sha ecf1d587, honest n=1/chiều, hmw.js executed-file giữ) + _index OUTBOUND. - Lesson env: CCD harness cache agent frontmatter — restart CLI mới ăn (2 data-point 06-10/06-11). - Bundle 06-10 carry: 7 agent pin opus-4-8 + 4 inherit + hmw.js tier-map H4.5 + agents/README two-tier + 2 adap-report + email 06-10 + agent-memory delta (KEEP-ALL-5 H2-verified) + investigator L1→L2 archive curate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@ -15,7 +15,7 @@ WRITE specialist độc quyền `tests/**`. xUnit + FluentAssertions 7.2 + EF SQ
|
||||
- ❌ 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 228 tests = 228 PASS (58 Domain + 170 Infra) ← S56 +12 (2 LeaveBalance deduct-correctness + 4 Travel/Vehicle ApproveV2 smoke + 2 ItTicket existence-oracle + 4 DocxRenderer). Pre-S56 = 216.
|
||||
## 📊 Baseline 240 tests = 240 PASS (58 Domain + 182 Infra) ← S57bis +12 (PeWorkItemGuardTests: 3 validator + 4 create-FK-guard + 5 update-null-safe). Pre = 228 (S56).
|
||||
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)
|
||||
@ -53,6 +53,7 @@ Test theo CODE (single source truth), document mismatch header comment + report.
|
||||
|
||||
## 📅 Recent activity (last 10 FIFO)
|
||||
|
||||
- **2026-06-11 (S57bis P2 PE WorkItemId guard Mig 49 — test-after, code đã đúng sẵn):** +12 test `tests/.../Application/PeWorkItemGuardTests.cs` → **228→240 PASS** (58 Domain + Infra 170→182, 0 fail). PE `Guid? WorkItemId` loose-Guid (KHÔNG FK vật lý, convention giống ProjectId). **Cover-map 3 trục:** (1) **Validator ×3** — `CreatePurchaseEvaluationCommandValidator.Validate(cmd)` plain API (KHÔNG có FluentValidation.TestHelper package): null→invalid+error trên WorkItemId / present→valid. (2) **Create-FK-guard ×4** — handler 4-dep instantiate THẬT trên SQLite (`new PurchaseEvaluationWorkflowService(db,dt,notify,um)` + `new PurchaseEvaluationCodeGenerator(db,dt)` — Serializable-tx non-issue SQLite proven S52; reuse `NoOpNotificationService` internal từ ...Services ns + IdentityFixture): bogus-Guid→Conflict / inactive→Conflict / active→OK+`saved.WorkItemId==active.Id`. (3) **Update-null-safe ×5 (bug-class S42 picker)** — `UpdatePurchaseEvaluationDraftCommandHandler(db,cu)` 2-dep nhẹ: request.WorkItemId=null→GIỮ w1 KHÔNG null-hoá (⭐ core) / W2-active→đổi / bogus→Conflict+giữ w1 (AsNoTracking re-read DB-truth) / inactive→Conflict / same-as-existing→skip-lookup-success. **⚠️ SPEC-DRIFT FOUND (test theo CODE, S34 rule):** `NotEmpty()` trên `Guid?` (nullable) chỉ bắt `null`, KHÔNG bắt `Guid.Empty` (FV 7.2 so default(Guid?)==null) → Guid.Empty PASS validator. KHÔNG phải lỗ hổng — create handler FK-guard (`is Guid wiId` true cho Empty + AnyAsync false) chặn → Conflict. Test LOCK behavior (1 validator-test assert Empty pass + 1 handler-test chứng minh defense-in-depth catch). REPORT em main: validator một mình không reject Guid.Empty, dựa handler. No prod bug — code đúng spec, defense-in-depth layered. Tag [s57bis, p2, pe-workitemid, mig49, validator-plain-api, null-safe-partial-update, guid-empty-nullable-notempty-drift, defense-in-depth].
|
||||
- **2026-06-09 (S56 GOLIVE-HARDEN TEST stage — 4 pre-golive fixes, test-after build):** +12 test → **216→228 PASS** (58 Domain + Infra 158→170, 0 fail). Build stage đã land prod fixes (CONTRACT từ build, signatures UNCHANGED). **#3 LeaveBalance lost-update fix:** handler terminal nay increment `db.LeaveBalances.Where(...).ExecuteUpdateAsync(s=>s.SetProperty(b=>b.UsedDays, b=>b.UsedDays+p.NumDays))` server-side + 1 explicit tx (READ COMMITTED, NO IsolationLevel). **⭐ GOTCHA: ExecuteUpdateAsync BYPASS change tracker** → instance bal tracked (Add STEP1 hoặc pre-seed cùng context) GIỮ UsedDays PRE-increment. **4 test cũ LeaveBalanceTests (case 1/2/3/4 line 163/201/240/269) FAIL ở baseline = stale-tracked-read, KHÔNG regression** (spec TEST GUIDANCE đã tiên đoán). Fix = `.AsNoTracking()` re-read (hoặc `ChangeTracker.Clear()`). +2 new: `TwoSeparateRequests_BothTerminal_UsedDaysAccumulates_NotOverwrites` (3+5=8 chứng minh increment accumulate KHÔNG overwrite = race-free invariant) + `Approve_AlreadyDaDuyet_ReApprove_ThrowsConflict_NoDoubleDeduct` (early guard Status!=DaGuiDuyet:296 → exactly-once, balance vẫn 3 not 6). **#4 Travel/Vehicle ApproveV2 smoke (WorkflowAppApproveV2Tests.cs +4):** mỗi module Submit→Approve→DaDuyet happy + outsider→Forbidden. ApplicableType Travel=9 prefix `DT/CT`, Vehicle=7 prefix `DX/XE`. Travel/Vehicle KHÔNG trừ balance → không seed LeaveType. Helper mới `SeedWorkflowForTypeAsync(type,code,...approverIds)`. **#5 ItTicket existence-oracle (ItTicketReassignAuthzTests.cs +2):** authz reorder (Forbidden TRƯỚC NotFound) — non-IT non-admin nhận Forbidden cho ticketId tồn tại VÀ không tồn tại (cặp 5b/5c phản hồi giống nhau = no oracle leak). Reorder KHÔNG vỡ test cũ (Case5 đã expect Forbidden; TicketNotFound dùng Admin caller pass authz hợp lệ). **#6 DocxRenderer (Forms/DocxRendererTests.cs NEW +4):** 0 test trước đó. MainDocumentPart null→`InvalidOperationException("*MainDocumentPart*")` (OpenXml 3.5.1 `WordprocessingDocument.Create(path,type)` tạo package RỖNG no main part) + placeholder replace happy + unknown-key giữ literal + null-value→empty. **⚠️ test helper ExtractBodyText: tránh `MainPart!.Document.Body!` (CS8602 warning) → dùng `?.Document?.Body` + `.Should().NotBeNull()`.** No prod bug found — tất cả fixes là build-stage, tôi WRITE test theo CONTRACT. Tag [s56, golive-harden, executeupdate-tracker-bypass, asnotracking-reread, travel-vehicle-smoke, existence-oracle, docxrenderer].
|
||||
↳ **[em main post-review S56]** Shipped tx = `IsolationLevel.Serializable` (code `LeaveOtApprovalFeatures.cs:369`), KHÔNG READ COMMITTED — entry's '(READ COMMITTED, NO IsolationLevel)' = build-stage snapshot, **superseded** post-review (SQLite test path unaffected — codegen Serializable already green).
|
||||
- **2026-06-08 (S54 ItTicket reassign authz — test-before-merge SECURITY) [harvested by em main — agent MEMORY write mis-landed, B2/B3]:** +13 test `tests/.../Application/ItTicketReassignAuthzTests.cs` → **203→216 PASS** (58 Domain + Infra 145→158, 0 fail). **GetAssignableItStaff (6):** Admin→CanReassign=true + 2 IT-active ordered FullName (Cao<Truong) no KT/inactive leak · IT-staff→true · non-IT non-admin (KT)→false + **empty staff (0-leak assert)** · dept-null→false+empty · inactive-IT-excluded · UserId null→Unauthorized. **AssignItTicket (7):** non-IT non-admin→**ForbiddenException** + side-effect `AssignedToUserId.Should().BeNull()` (no-mutation) · Admin+assignee∈IT→success · IT-staff+assignee∈IT→success · assignee∉IT(KT)→**ConflictException** "Người được giao phải thuộc tổ IT." · assignee inactive→NotFound · ticket not found→NotFound · null→Unauthorized. **Pattern mới: authz-capability test = seed 2-dept (IT+KT) + fake `ICurrentUser` role/dept matrix; assert canReassign flag + Forbidden/Conflict guard; empty-staff = 0-leak.** Forbidden red-able **by-contrast** (case5 non-IT vs case7 IT-staff identical-setup → chỉ khác caller-identity; rule cấm sửa prod để chứng minh RED). **No prod bug** — handler-level data-dependent authz (caller-dept vs IT-dept) = CORRECT pattern, KHÔNG phải gotcha #44 silent-403 gap (Pattern 10 reflection-regression chỉ cho static `[Authorize(Policy)]`; data-driven authz PHẢI ở handler = enforcement point, test cover tại đó). Tag [s54, it-ticket-reassign, authz-capability, forbidden-conflict-guard, test-before-merge, 0-leak].
|
||||
@ -62,7 +63,6 @@ Test theo CODE (single source truth), document mismatch header comment + report.
|
||||
- **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.cs` → **185 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 (S43 P11-B Wave3 LeaveBalance):** +8 test `tests/.../Application/LeaveBalanceTests.cs` → **152 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 → Remaining−8 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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user