5.6 KiB
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<Guid?> |
| 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 … |
| 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:
CurrentWorkflowStepIndexlà INDEX vào list sort theoOrder, KHÔNG phảiOrder(:569-571steps[idx]). ⇒ mọi seed workflow đa-Bước dùngStep.Order = 5/15để index 0/1 không thể trùng Order do may mắn.CostControlVỪA là hard-copy actor (:376) VỪA có eligible-phase legacy{DangGopY, DangKiemTraCCM}(:359) ⇒ dùng CostControl làm ca ÂM ở phaseChoDuyetlà 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.- Trap
CreatedBy:actorUserId is Guidlà thứ duy nhất chặnnull == nullkhi actor null +CreatedBynull + decision=Approve(KHÔNG phảiAutoApprove, nênisSystem=false).TestApplicationDbContextkhông wireAuditingInterceptor⇒ HĐ seed cóCreatedBy == nulltự 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ữ, xemgit 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(-).