From d03d0978860e04387c00f37fa09faf69d594edcc Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Wed, 29 Jul 2026 23:15:44 +0700 Subject: [PATCH] wal: flush 20260729T2315 --- .claude/WAL.md | 3 +- .../sub-test-specialist-0.md | 94 +++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 .claude/workflows/runs/2026-07-29-S161-khkk-w6-duongong/sub-test-specialist-0.md diff --git a/.claude/WAL.md b/.claude/WAL.md index e9e3cdb..0071ab0 100644 --- a/.claude/WAL.md +++ b/.claude/WAL.md @@ -30,7 +30,8 @@ chain: - [x] **W3 ĐÓNG — cicd VERDICT=PASS 5/5** (§1 CI 580 + §3 marker [né PASS-GIẢ "Đến lượt bạn duyệt"] = cicd · §2 0-mig/96/142 + §4 smoke transitions THẬT 409-đúng-lời + 404-ProblemDetails + §5 CỜ 13/13/2 = lead 2-nguồn). Synthesis `runs/2026-07-29-S161-khkk-w3-duyet/w3-synthesis.md`. **GĐ2 KHKK trọn vòng đời phiếu trên prod.** Tồn: mark-read chuông cũ (chờ anh) · UAT tay cần WF-type-10 + non-Admin - [x] gate 5-anchor W6 PASS 5/5 (content-exact 0-drift) - [x] W6 đợt-1 `wf_e3b6a2bc-91d` XONG (#53, sub-md 3.7KB §0 + code trọn): 3 fix land (+142 ContractFeatures [3-site + inbox v2 + ADMIN tường minh] · +15 CWS guard **kèm chặn null==null lọt guard** `actorUserId is Guid`); build 0E + **suite 580/0 GIỮ** (lead đo); 0 test cũ bám 3 handler (lane verify trước) -- [!] wf: W6 đợt-2 `wf_131c8f87-356` test-specialist 5-PIN (+2 bonus: admin-inbox DR-4 + CreatedBy-null-guard) ĐANG CHẠY, đích ≥585 → reviewer security-wave → ship +- [x] W6 đợt-2 `wf_131c8f87-356` XONG (#53, file land): 7 test (5 PIN + 2 bonus) → **suite 587/0 lead-tươi** (580+7, vượt đích 585) +- [!] reviewer W6 security-wave ĐANG CHẠY (nới-view có mở QUÁ không · admin-inbox phase-list · guard trình 4-vế+null-trap · fidelity Resolve · test-integrity · boundary Reject/W3/KHKK 0-diff) → PASS ⇒ commit/push → cicd → W6 ĐÓNG - [ ] W5 (cầu KHKK→HĐ — cần setup WF tay TRƯỚC: type-3 + type-10 3-trạm Designer) → W7 (bản cứng 1-mốc @S161) - [ ] W6 → W5 → W7 theo đồ thị plan-cha (sau W3) - [ ] đợt-2 SAU khi wf về: test-specialist + database-agent (song song) → lead acceptance §③-B (build·test·sqlcmd 96·Down sạch·đo CỜ) → reviewer → commit/push → cicd-monitor 3-chân-kiềng diff --git a/.claude/workflows/runs/2026-07-29-S161-khkk-w6-duongong/sub-test-specialist-0.md b/.claude/workflows/runs/2026-07-29-S161-khkk-w6-duongong/sub-test-specialist-0.md new file mode 100644 index 0000000..6c553b7 --- /dev/null +++ b/.claude/workflows/runs/2026-07-29-S161-khkk-w6-duongong/sub-test-specialist-0.md @@ -0,0 +1,94 @@ +# sub-test-specialist-0 — W6 ĐỢT-2: 5 test PIN đường ống HĐ V2 (+2 bonus) + +> Run: `2026-07-29-S161-khkk-w6-duongong` · Spec: `.claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w6-duong-ong-hd-v2-29-07-2026.md` §③-B +> Luật lượt này: CHỈ `tests/**` · KHÔNG sửa production · KHÔNG commit/push · ghi TỪNG MỤC trong lúc làm (chống #53). + +--- + +## §0 — ĐO TRƯỚC KHI VIẾT (baseline tươi, KHÔNG tin số đề bài) + +Lệnh: `dotnet test SolutionErp.slnx --nologo --verbosity minimal -p:BuildInParallel=false -maxcpucount:1` + +| Project | Passed | Failed | Skipped | +|---|---|---|---| +| SolutionErp.Domain.Tests | **45** | 0 | 0 | +| SolutionErp.Infrastructure.Tests | **535** | 0 | 0 | +| **TỔNG** | **580** | **0** | 0 | + +⇒ Đề bài ghi 580 (45D+535I) — **KHỚP 3/3 con số**. Đích ≥ 585. + +--- + +## §1 — ĐỌC CODE THẬT (test theo CODE, không theo prompt) + +Diff production của đợt-1 (`git diff HEAD`, 2 file, +161/-10): + +| Điểm sửa | Vị trí đo tươi | Nội dung | +|---|---|---| +| List — vế V2 + bản-cứng | `ContractFeatures.cs:305-314` | `myWorkflowIds.Contains(x.c.ApprovalWorkflowId)` + `Phase != DangSoanThao` · `isHardCopyActor && Phase == DaPhatHanh` | +| Helper per-HĐ | `:375-395` | `HardCopyActorRoles = [Director, AuthorizedSigner, HrAdmin, CostControl]` · `ResolveUserApprovalWorkflowIdsAsync` trả `List` | +| ListDeleted — CỐ Ý KHÔNG ghép | `:426-431` | chú thích tường minh: giữ `Drafter ∪ eligible-phase` | +| Inbox — admin phase tường minh | `:487-497` | `AdminInboxPhases` = 7 legacy **+ `ChoDuyet`** | +| Inbox — v2InboxIds + early-exit | `:514-527` | `eligiblePhases.Count == 0 && v2InboxIds.Count == 0` (2 nguồn) · `where … || v2InboxIds.Contains(c.Id)` | +| Inbox — resolve con-trỏ | `:543-577` | in-memory join, `steps[idx]` theo **INDEX** (không phải `Order`), `Levels.Any(l => l.Order == cur && l.ApproverUserId == uid)` | +| Detail — vế V2 per-HĐ | `:605-621` | `isV2Approver` hỏi theo `c.ApprovalWorkflowId` · `isDraftPhase` (S89) · `isHardCopyActor && Phase == DaPhatHanh` | +| Guard trình | `ContractWorkflowService.cs:73-92` | `+Procurement` · `isCreator = actorUserId is Guid actorId && (CreatedBy == actorId ∨ DrafterUserId == actorId)` | + +**3 bẫy rút từ CODE — quyết định thiết kế test:** + +1. `CurrentWorkflowStepIndex` là **INDEX vào list sort theo `Order`**, KHÔNG phải `Order` + (`:569-571` `steps[idx]`). ⇒ mọi seed workflow đa-Bước dùng `Step.Order = 5/15` + để index 0/1 **không thể** trùng Order do may mắn. +2. `CostControl` VỪA là hard-copy actor (`:376`) VỪA có eligible-phase legacy + `{DangGopY, DangKiemTraCCM}` (`:359`) ⇒ dùng CostControl làm ca ÂM ở phase + `ChoDuyet` là ca **mạnh nhất**: nó chứng vế bản-cứng bị **chặn theo phase** + (`&& Phase == DaPhatHanh`), không phải role-blanket. +3. Trap `CreatedBy`: `actorUserId is Guid` là thứ duy nhất chặn `null == null` khi + actor null + `CreatedBy` null + decision=`Approve` (KHÔNG phải `AutoApprove`, nên + `isSystem`=false). `TestApplicationDbContext` **không wire** `AuditingInterceptor` + ⇒ HĐ seed có `CreatedBy == null` **tự nhiên** — đúng cấu hình để đo trap này. + +--- + +## §2 — 7 test đã viết + lượt chạy lọc ĐẦU TIÊN + +File MỚI (duy nhất tao ghi trong `tests/`): +`tests/SolutionErp.Infrastructure.Tests/Application/ContractV2PipelineTests.cs` + +| # | Tên | Loại | +|---|---|---| +| T1 | `Inbox_PendingLevelApprover_SeesChoDuyetContract` | PIN spec | +| T2 | `Inbox_OtherLevel_DoesNotSeeContract` | PIN spec (ÂM) | +| T3 | `View_V2Approver_NotDrafter_CanSeeChoDuyetContract` | PIN spec | +| T4 | `List_HardCopyActor_NotAdmin_SeesDaPhatHanhContract` | PIN spec (+ khối XÓA MỀM §③-B `:31`) | +| T5 | `View_UserOutsideWorkflow_WithUnrelatedRole_Gets403` | PIN spec (ÂM, role pin `CostControl`+`Procurement`) | +| T6 | `Inbox_Admin_SeesChoDuyetContract` | BONUS (DR-4 / F-B13) | +| T7 | `Submit_ProcurementAndCreator_Allowed_UnrelatedRoleAndNullActor_Forbidden` | BONUS (guard trình + bẫy actor-null) | + +Lỗi biên dịch duy nhất: thiếu `using SolutionErp.Application.Contracts.Dtos;` (DTO nằm +namespace `.Dtos`, không phải `.Contracts`) → vá 1 dòng. + +Chạy lọc `--filter FullyQualifiedName~ContractV2PipelineTests`: +**Failed: 0, Passed: 7, Total: 7** (4 s). + +--- + +## §3 — CHỨNG LƯỚI CÓ RĂNG (fault-inject: hoàn nguyên production tạm thời) + +⚠️ Test-after xanh ngay lượt đầu KHÔNG chứng được gì. Phải đo: 7 lưới này có ĐỎ dưới +mã TRƯỚC W6 không (khuôn RED-proven-via-git-stash, S86). + +🔴 **AN TOÀN / KHÔI PHỤC — đọc mục này TRƯỚC nếu tao chết giữa chừng (#53):** +bản W6 của 2 file production được sao lưu 2 LỚP trước khi hoàn nguyên: +- Lớp 1 — scratchpad: + `C:\Users\pqhuy\AppData\Local\Temp\claude\D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP\24be4c29-c54d-4ed0-ba2a-8240f62de712\scratchpad\w6-backup\` + (`ContractFeatures.cs` + `ContractWorkflowService.cs`) +- Lớp 2 — `git stash` (git tự giữ, xem `git stash list`). + +MD5 bản W6 ĐÚNG (đích của phép khôi phục): +``` +c11e3820267019995bd9ed815eac483f src/Backend/SolutionErp.Application/Contracts/ContractFeatures.cs +d564219fc9c5cb0857298ee97f6037b5 src/Backend/SolutionErp.Infrastructure/Services/ContractWorkflowService.cs +``` +Khôi phục = `git stash pop` (hoặc chép đè từ scratchpad) rồi **đối chiếu lại 2 MD5 trên** +và `git diff --stat` phải ra lại `142 +` / `15 +` = **161 insertions(+), 10 deletions(-)**.