From 2fed7540adc35571fd328a5daef950544da019cd Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Wed, 12 Aug 2026 22:15:40 +0700 Subject: [PATCH] wal: flush 20260812T2215 --- .claude/WAL.md | 24 +++- .../sub-wq3-test.md | 104 +++++++++++++++++- .../sub-wq3b-fe.md | 31 +++++- 3 files changed, 149 insertions(+), 10 deletions(-) diff --git a/.claude/WAL.md b/.claude/WAL.md index a3ca2f33..51263467 100644 --- a/.claude/WAL.md +++ b/.claude/WAL.md @@ -45,13 +45,25 @@ bằng 7 HD-* (data-op) + duyệt/history y KHKK (gộp Q1/Q3) + van-xả mirror [x] WQ5a data-op: seeder QT-HD-V2-001 → IsActive=false từ-lúc-sinh (env mới) + UPDATE Dev 0/0 verified (bền — idempotent-check là existence, né #75). Prod UPDATE cùng câu SQL @deploy-verify -[!] WQ3-TEST (4 Fact finalize, kỳ vọng 697) ∥ WQ3b-FE (panel 3 món ×2 + tái-vị-trí máy - duyệt về panel-3 mọi host). wf: wf_2989df28-eb6 · artifact sub-wq3-test.md + sub-wq3b-fe.md -[ ] Lead: verify-local vòng 2 (layout mới + finalize) → commit WQ* theo cụm → - DEPLOY: dọn workspace runner → push gom → CI → cicd-verify + prod UPDATE Q5a + - STATUS:476 lật → báo anh kiểm +[x] WQ3-TEST GREEN 4/4 (697, probe-vi-phân 3-thế-giới-hỏng) · WQ3b-FE #53-giữa-chừng → + lead hoàn thiện on-behalf (copy-byte content fe-admin + gắn panel 5 host + import) → + tsc/build/eslint ×2 PASS, SHA cặp khớp, content 0-render-panel +[x] COMMIT 2 cụm: 69860362 (BE Mig73+finalize+tắt-seeder+test697) · 59cb1217 (FE layout + KHKK-thuần + 3 món + máy-duyệt-panel-3 ×5 host) · 091073f9 (docs) +[x] VERIFY-LOCAL vòng-2: Mig73 áp Dev sạch · panel-3 sống (meta HD-DV v01 + sơ đồ + 2 nút, + KHÔNG nhân đôi bộ nút — content đã gỡ) · layout KHKK-thuần (1 cột trái Select-loại+ + Search+Select-trạng-thái+cây · panel-3 dashed) +[x] DEPLOY: đĩa VPS 4.7→26.6GB (xóa repo-archive 13GB cache + IIS-log cũ — an toàn, #89) → + push f8f2ef96..091073f9 → CI #600 RUNNING đúng sha (gotcha #91 guard: updated_at mới, + app KHÔNG câm) · Q5-prod: QT-HD-V2-001 → 0/0 (2 HĐ pin đều ZZTEST-K8 terminal, an toàn) + ⇒ type-3 user-selectable = 7 HD-* đúng "mỗi loại 1 quy trình" +[!] cicd-monitor #600 (agent nền): test-gate 697 · Mig73-prod · bundle rotate ×2 · smoke → + verdict PASS = anh vào kiểm được. wf agent a7b1... artifact sub-cicd-deploy-yc030.md +[ ] NEXT-em @closeout: lật STATUS:476 row Tests 693→697 (chỉ SAU cicd-verify — B1) · + bật cron.archive_cleanup Gitea (chống #89 tái phát — cần restart, để sau CI xong) · + sổ YC-029/030 vế-thi-công · session-log · un-delete a79dd579 Dev nếu cần -next: chờ wf_2989df28-eb6 → gate → commit → deploy. +next: chờ cicd-monitor #600 → báo anh verdict deploy. verify: commits: git log --oneline -8 # 2ae62f3f ed3b39ff 7b291014 09ebd20e 1cc16a2d + wal diff --git a/.claude/workflows/runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-wq3-test.md b/.claude/workflows/runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-wq3-test.md index 3b60e0a7..2ae2e940 100644 --- a/.claude/workflows/runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-wq3-test.md +++ b/.claude/workflows/runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-wq3-test.md @@ -3,14 +3,112 @@ Agent: test-specialist · Run: 2026-08-12-S190-soltuon-dieu-chinh-hd Ranh: Write CHỈ {ContractApproveFinalizeTests.cs, sub-wq3-test.md}. KHÔNG commit. KHÔNG chạm production code. +File test: `tests/SolutionErp.Infrastructure.Tests/Application/ContractApproveFinalizeTests.cs` (MỚI, 4 `[Fact]`). + ## Ca đã viết -(CHƯA VIẾT — đang đọc BƯỚC 1) +Đối tượng đo: `src/Backend/SolutionErp.Infrastructure/Services/ContractWorkflowService.cs:527-535` +(`if (matchingLevel.AllowApproverFinalize && applyLevelFinalize)` → `EndedByLevelFinalize=true` → +`FinalizeToDaPhatHanhAsync:576`). Đây là **test-bù** (mã BE land trước, chưa commit), KHÔNG phải test-before. + +**Hình chung của cả 4 ca (điều kiện SỐNG CÒN):** quy trình **2 Bước** — Bước 1 có **2 Cấp**, Bước 2 +có 1 Cấp — người bấm Duyệt luôn là **Bước 1 Cấp 1**, tức còn NGUYÊN 2 chặng phía sau. +Bài S164-K3: cắm cờ finalize ở slot CUỐI thì "phát hành + có mã" xảy ra ở CẢ HAI thế giới ⇒ F-1 +xanh mà chứng minh 0. Hình này được **chốt bằng assert** `AssertFinalizeSlotIsNotTheLastAsync` +(steps==2 ∧ levels(Bước 1)==2) gọi ngay trước mỗi lượt bấm, để lần "gọn hoá seed" sau này không âm +thầm làm rỗng cả file. + +| Ca | Tên `[Fact]` | Biến bật/tắt | Kết quả kỳ vọng | +|---|---|---|---| +| F-1 | `ApproveV2_LevelFinalizeFlag_WithDefaultApply_PublishesContractAndSetsRuntimeFlag` | cờ Cấp `AllowApproverFinalize=true` · **KHÔNG truyền** `applyLevelFinalize` | `Phase=DaPhatHanh` · `EndedByLevelFinalize=true` · `MaHopDong="PFIN1/HĐTP/SOL&FIN1/01"` · con-trỏ Bước/Cấp + SLA `null` | +| F-2 | `ApproveV2_LevelFinalizeFlag_ButApproverOptsOut_AdvancesNormally` | cờ Cấp `true` · `applyLevelFinalize:false` | `Phase=ChoDuyet` · `LevelOrder=2` · `StepIndex=0` · cờ `false` · `MaHopDong=null` | +| F-3 | `ApproveV2_NoLevelFinalizeFlag_EvenWhenApplyRequested_AdvancesNormally` | cờ Cấp `false` · `applyLevelFinalize:true` | như F-2 | +| F-4 | `ApproveV2_AfterLevelFinalize_FurtherApproveThrowsConflict_AndChangesNothing` | finalize xong rồi bấm Duyệt tiếp ×2 người | `ConflictException("*DaPhatHanh*không hỗ trợ*")` ×2 · KHÔNG đổi gì | + +### Vì sao ba ca F-1/F-2/F-3 không thay thế nhau (ma trận chứng `&&`) +- F-1 giữ **vế dương** + đo luôn ngữ nghĩa **OPT-OUT** (mặc định `true` ở `IContractWorkflowService.cs:25`) + — cố ý KHÔNG truyền tham số; truyền tay `true` là bỏ mất vế đó. +- F-2 tắt vế **ý người duyệt**; F-3 tắt vế **cấu hình Cấp**. Cài `||` thay `&&` ⇒ ĐỎ cả hai. + Bỏ đọc tham số ⇒ chỉ F-2 đỏ. Bỏ đọc cờ cấu hình ⇒ chỉ F-3 đỏ. +- F-3 còn có assert **tiền-đề** đọc lại `AllowApproverFinalize` từ DB — chốt "biến đang tắt đúng là + biến định tắt", nếu không thì seed sai cờ làm F-3 trùng hệt F-2 mà không ai biết. + +### F-4 — assert chọn theo MÃ, không theo mong muốn +Đọc `TransitionAsync` trước khi viết: sau finalize `Phase=DaPhatHanh` ⇒ lượt Duyệt kế tiếp trượt hết +mọi nhánh (reject `:55` / trình `:96` / duyệt `:159` đều đòi phase khác, `isAdmin` false) và rơi +xuống câu cuối `:268` `ConflictException("Transition {from} → {to} không hỗ trợ.")`. +⇒ assert đúng là **409 + không đổi gì**, không phải "im lặng bỏ qua". Hai người bấm, hai lý do đời thực: +(a) chính người vừa chốt bấm lại (double-click), (b) NV Cấp 2 — người bị cắt lượt, màn hình cũ còn nút Duyệt. +Vế "không đổi gì" đo cả `MaHopDong` (không cấp mã lần 2), `ContractApprovals` count==1, +`ContractLevelOpinions` count==1 — một cài đặt "ném lỗi SAU khi đã ghi" vẫn xanh nếu chỉ assert exception. + +### 2 quyết định hạ tầng +1. **`IdentityFixture`, KHÔNG dựng fixture riêng có `AuditingInterceptor`** (memory-pack gợi ý mirror + `ContractDeleteGuardTests.cs:69`). Lý do: service đòi `UserManager` THẬT, còn interceptor chỉ + phục vụ ô audit/xoá-mềm — file này không đo ô nào trong số đó. Khuôn đúng là file cùng đối tượng đo: + `Services/ContractWorkflowServiceApproveV2Tests.cs:25` (đã chạy xanh với `ContractCodeGenerator` + + transaction `Serializable` trên SQLite). +2. Mỗi ca một fixture ⇒ DB SQLite in-memory riêng ⇒ `ContractCodeSequences` không dính nhau, mã HĐ + mong đợi luôn `/01`. `NoOpNotificationService` dùng lại stub `internal` ở + `Services/PurchaseEvaluationWorkflowServiceGuardTests.cs:188` (không chép bản thứ hai). ## Kết quả chạy -(CHƯA ĐO) +### (1) Lọc — 4/4 PASS +``` +dotnet test tests/SolutionErp.Infrastructure.Tests \ + --filter FullyQualifiedName~ContractApproveFinalizeTests --nologo -p:BuildInParallel=false -maxcpucount:1 +Passed! - Failed: 0, Passed: 4, Skipped: 0, Total: 4, Duration: 3 s +``` + +### (2) CHỨNG RĂNG — probe VI-PHÂN (sửa TEST, KHÔNG chạm production) +Không được chạm mã BE ⇒ không fault-inject được. Thay bằng: thế-giới-hỏng **tương đương chính xác** +với việc gọi CHÍNH service thật bằng tham số/seed khác ⇒ đổi đúng 1 chữ TRONG TEST, chạy trên mã +production THẬT. Backup file trước, revert sau, `diff` chứng khớp byte. + +| Probe (thế giới hỏng mô phỏng) | Đổi | Kết quả | +|---|---|---| +| BE bỏ qua nhánh finalize (luôn advance) | F-1 thêm `applyLevelFinalize:false` | **ĐỎ** — `Expected contract.Phase to be DaPhatHanh {9} … but found ChoDuyet {10}` (`:240`) | +| BE bỏ đọc tham số `applyLevelFinalize` | F-2 bỏ `applyLevelFinalize:false` | **ĐỎ** — `Expected … ChoDuyet {10} … but found DaPhatHanh {9}` (`:302`) | +| BE dùng `\|\|` thay `&&` (ý người duyệt tự cấp quyền) | F-3 seed `allowFinalizeAtS1L1:true` (+ tạm bỏ assert tiền-đề để nhìn vế KẾT QUẢ đỏ) | **ĐỎ** — `Expected … ChoDuyet {10} … but found DaPhatHanh {9}` (`:359`) | + +`Failed: 3, Passed: 1` — F-4 giữ xanh đúng như thiết kế (không phụ thuộc 2 biến bị lật). +Revert: `diff backup ↔ file` **RỖNG** (khớp byte) · `grep -c PROBE` = **0**. + +🔴 F-4 KHÔNG có probe vi-phân: thế-giới-hỏng của nó ("nhánh duyệt nhận cả HĐ đã phát hành") chỉ dựng +được bằng cách sửa production ⇒ khai thẳng. Răng của F-4 là **nội tại**: `ThrowAsync` +đỏ nếu không ném, + `WithMessage("*DaPhatHanh*…")` khoá đúng lý do, + count==1 khoá vế "không ghi". + +### (3) Full suite — 697/0, khớp đúng dự đoán 693+4 +``` +dotnet test SolutionErp.slnx --nologo -p:BuildInParallel=false -maxcpucount:1 +Passed! - Failed: 0, Passed: 45, Skipped: 0, Total: 45 - SolutionErp.Domain.Tests.dll (59 ms) +Passed! - Failed: 0, Passed: 652, Skipped: 0, Total: 652 - SolutionErp.Infrastructure.Tests.dll (39 s) + tổng = 45 + 652 = 697 (baseline 693 → Δ+4, 0 hồi quy) +``` + +### (4) Audit ranh giới (isolation) +``` +git status --porcelain | grep -E "tests/|sub-wq3-test" + M .claude/workflows/runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-wq3-test.md +?? tests/SolutionErp.Infrastructure.Tests/Application/ContractApproveFinalizeTests.cs +``` +Đúng 2 file. `src/**` dirty là của lane WQ3-BE (có từ trước lượt này), tôi KHÔNG chạm. +KHÔNG commit · KHÔNG ghi `agent-memory/**` (spawn-record trả về cho em main harvest). ## Ghi chú -(đang đọc) +- **0 bug production phát hiện** — cả 4 ca xanh trên mã BE vừa land, không ca nào phải giữ ĐỎ, + không ca nào phải nới assert. +- **Spec ⟂ code:** không thấy lệch. Cột `Contract.EndedByLevelFinalize` (`Contract.cs:60`, Mig + `20260812141501_AddContractEndedByLevelFinalize`) có write-site DUY NHẤT là nhánh finalize — + F-2/F-3 khoá luôn chiều "không được gắn nhãn kết thúc sớm cho lượt duyệt thường", tức bảo vệ đúng + lý do cột này tồn tại thay vì suy từ config (bài #78). +- **Vùng KHÔNG phủ ở lane này** (khai để lead không đọc nhầm phạm vi): + - `ContractsController.cs:71` `ApplyLevelFinalize: body.ApplyLevelFinalize ?? true` — lớp + controller/DTO; test này gọi service trực tiếp nên chỉ chứng mặc định **ở tầng service** + (`IContractWorkflowService.cs:25`). Hai chỗ đang khớp nhau, nhưng đó là 2 mặc định riêng biệt. + - Ca `skipToFinal=true` **cùng lúc** `applyLevelFinalize=true` (comment `:515-521` khai skip thắng + vì `return` trước). Không viết: nằm ngoài 4 ca được giao, và đã có `ApproveV2_SkipToFinal_*` + (`ContractWorkflowServiceApproveV2Tests.cs:348`) neo nhánh skip. + - FE panel (lane WQ3b) — ngoài phạm vi. diff --git a/.claude/workflows/runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-wq3b-fe.md b/.claude/workflows/runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-wq3b-fe.md index be22275b..a279ae87 100644 --- a/.claude/workflows/runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-wq3b-fe.md +++ b/.claude/workflows/runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-wq3b-fe.md @@ -1,7 +1,36 @@ # WQ3b-FE — port 3 mon KHKK vao panel duyet HD + tai-vi-tri may duyet ve panel-3 (S190 · YC-030) +> Worker #53 chết giữa (68 tool-use, artifact 0 ruột). Trạng thái lúc chết: panel ×2 + types ×2 + +> content fe-user + MyContractsPage-comment ĐÃ sửa; THIẾU copy content fe-admin + gắn panel 5 host. +> **LEAD hoàn thiện on-behalf phần cơ học còn lại** (copy-byte + 5 khối render cùng khuôn) — khai. + ## Việc đã làm -## Ô acceptance +1. (worker) `ContractWorkflowPanel.tsx` ×2 app: port 3 món KHKK — ô tích "Cấp này KẾT THÚC quy + trình" (`allowApproverFinalize` 3 hit) + meta `{workflowCode} v{NN}` + banner + `endedByLevelFinalize` (7 hit cụm) + gửi `applyLevelFinalize` trong body Duyệt. SHA cặp + `2edbe534901d` ×2 KHỚP. +2. (worker) `types/contracts.ts` ×2 app (KHÔNG phải cặp SHA — vốn khác nhau by-design, HEAD + `1d4d649f`≠`3d2da3bd`): nở `workflowCode`/`workflowVersion`/`endedByLevelFinalize` + + body `applyLevelFinalize?`/`skipToFinal?` (fe-admin :194-220). +3. (worker) `ContractDetailContent.tsx` fe-user: GỠ khối isV2 render máy duyệt (comment lật :15, + :144 — 0 hit code-only). +4. (lead) copy-byte content → fe-admin: SHA cặp `7ab04d9d939e` ×2 KHỚP. +5. (lead) Gắn `` (vỏ `section border-brand-200`, + điều kiện `approvalWorkflowId != null` — đúng khối cũ) vào **5 host**: MyContractsPage panel-3 + (TRÊN WorkflowHistoryPanel — khuôn KhkkListPage) · ContractDetailPage ×2 app (aside) · + InboxPage fe-user · ContractsListPage fe-admin. Mỗi host +1 import. + +## Ô acceptance (lead đo @S190 sau hoàn thiện) + +- tsc ×2 EXIT=0 · build ×2 EXIT=0 (`✓ built`) · eslint fe-user **47** / fe-admin **42** = baseline KHÔNG TĂNG +- SHA cặp: panel `2edbe534901d`×2 ✅ · content `7ab04d9d939e`×2 ✅ +- Content 0 render panel (grep code-only = 0; 2 hit còn lại là comment lineage) ✅ +- 5/5 host `