[CLAUDE] Docs: S58 closeout — lock fix prod-verified Run #382 + S57bis flush + gotcha #59/#60 + harvest on-behalf

- STATUS/HANDOFF: thêm S57bis + S58 (2-session gap S57bis đóng vội), counts
  re-ground (Mig 49 · test 240 · gotcha 60 · menu 57 · bundle CP4CB1ym/BmZ3VHnm
  curl-verified · RAG 2420). Ops S56 "gán user IT" RESOLVED (nv.cao/nv.truong
  sống lại nhờ password fix).
- gotchas: #59 (PS5.1 git commit -F, residual S57bis) + #60 NEW (Identity seed
  CreateAsync silent-fail vs prod RequiredLength=12 — population Dev ≠ prod,
  dump data thật trước lock/seed-by-email) + checklist 31/32.
- agent-memory: cicd Run #381 (residual) + #382 · 4 spawn-record on-behalf
  (database-agent/impl-backend/impl-frontend/reviewer — H2 Coverage 4-MISS đóng)
  · investigator-codebase recon · 2 monitor RE-REPORT entries.
- skills: ef-core +row Mig 49 (49 mig ×5 chỗ) · README + dep-audit count sync.
- CLAUDE.md root: Mig 49 + test 240 + gotcha 60 + schema-ref 32-49.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-11 13:09:29 +07:00
parent 5998163642
commit 2aefb3134d
15 changed files with 102 additions and 23 deletions

View File

@ -74,6 +74,8 @@ UI `disabled={!canX}` + BE helper `EnsureCanXAsync(id, userId)` throw 403 (NOT i
## 📅 Recent activity (FIFO — older → archive/git)
- **2026-06-11 (S57bis PE WorkItemId BE slice — PARTIAL, on-behalf em main ghi hộ, H2-proposed):** Return-truncated #53 TRƯỚC Mig 49 + projection-3 → em main solo hoàn tất (fix CS7036 + CS8019, Mig 49 `AddWorkItemToPurchaseEvaluation` 3-file, projection ListItemDto ×3 LEFT-join WorkItems, UpdateDraft null-safe `if (request.WorkItemId is not null)` chống null-hóa bug-class S42). LEARNED: FK-guard loose-Guid `AnyAsync(w.Id==x && w.IsActive)`→Conflict (mirror S43); validator `NotEmpty` create-only, DB nullable backward-compat 4 phiếu cũ; `NotEmpty()` trên `Guid?` KHÔNG chặn `Guid.Empty` → handler guard bắt (defense-in-depth). SURPRISE: truncate 2 session liên tiếp (S55, S57bis) ở slice lớn cross-layer → cắt stage nhỏ hơn (entity+config / mig / projection tách spawn). Tag `[s57bis, truncated-53, on-behalf]`.
- **2026-06-10 (S57-resume spawn-test H4.8 — Harness-4 two-tier):** Mình bị DEMOTE pin `model: claude-opus-4-8` (deterministic-scaffold class, double-gate reviewer+test+cicd sau lưng). Spawn-test echo model NGAY sau edit → self-report `claude-fable-5[1m]` = SE env (CCD harness) KHÔNG fresh-read frontmatter → pin ăn SAU restart CLI. Post-restart mình chạy Opus 4.8 (effort Max giữ env-wide); task hệ-trọng giao mình qua hmw có thể override `tier:'fable'`. Tag [h4-demote, spawn-test, pending-restart].
- **S56 GOLIVE-HARDEN 3 BE fix (NO mig, 3 file edit, em-main spec deterministic 100% → ACCEPT Case 1):** **#3 LeaveBalance lost-update** `LeaveOtApprovalFeatures.cs` terminal DaDuyet branch → atomic-executeupdate-tx (spec chosen, KHÔNG RowVersion/Mig). Replaced in-mem `bal.UsedDays += NumDays` với: set p.Status/Updated* → `(DbContext)db` cast + `BeginTransactionAsync(ct)` (plain, NO IsolationLevel — READ COMMITTED đủ vì increment atomic) → STEP1 ensure-row (FirstOrDefault, auto-create UsedDays=0 via tracker) + SaveChanges (opinion+status+insert trong tx) → STEP2 `db.LeaveBalances.Where(...).ExecuteUpdateAsync(s=>s.SetProperty(b=>b.UsedDays, b=>b.UsedDays+p.NumDays), ct)` server-side row-lock race-free → `tx.CommitAsync` + **`return;`** (skip trailing shared SaveChanges). **STALE-TRACKED caveat (load-bearing):** ExecuteUpdate bypass tracker → tracked `bal` giữ pre-increment value; SAFE vì không đọc lại + handler return ngay; KHÔNG thêm `bal.UsedDays +=` (double-count). `using System.Data` + EF Core đã import. **#5 AssignItTicketHandler existence-oracle** `WorkflowAppsFeatures.cs:493` → moved Admin-OR-dept-IT Forbidden guard (itDeptId+isAdmin+myDeptId resolve) TRƯỚC ticket NotFound lookup → fail-closed (non-IT nhận Forbidden cho MỌI ticketId). assignee-must-be-IT Conflict + reassign giữ nguyên. **#6 DocxRenderer.cs:30,40 CS8602** → hoist `mainPart = doc.MainDocumentPart ?? throw InvalidOperationException` + `document = mainPart.Document ?? throw` (Document cũng nullable — KEY: 1st hoist chỉ fix part, vẫn còn 1 warn ở `.Document.Body`); deref qua local non-null. Build SolutionErp.slnx **0 err 0 warn** (DocxRenderer warn CLEARED — thực tế 1 warn không phải 2 như MEMORY ghi). Test 58 Domain PASS + 154/158 Infra: **4 FAIL `LeaveBalanceTests` (Approve_LastLevel_DeductsLeave.../AccumulatesExisting.../OverEntitled.../MultiLevel_NoDeductAtIntermediate)** = EXPECTED #3 stale-tracked (re-query trả tracked instance pre-increment, DB row đúng) → tests_to_update cho test-specialist (add AsNoTracking/ChangeTracker.Clear). ItTicket authz tests #5 PASS (Case5 đã expect Forbidden, NotFound case dùng Admin caller). KHÔNG touch tests/FE/commit. #4 (Travel/Vehicle smoke test) = test-specialist next stage. Tag `[s56, golive-harden, executeupdate-atomic, fail-closed-authz, cs8602, no-mig]`.