Files
solution-erp/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-clone-l2-b1b.md
2026-07-31 11:55:53 +07:00

8.4 KiB
Raw Blame History

lens2-evi — 8 verdict vs code

Findings

V-a (claim: Line per-NCC + UNIQUE(PlanId,SupplierId) filtered + ContractId per-line KHÔNG unique) = ĐÚNG

  • Domain/ContractSigningPlans/ContractSigningPlanLine.cs:14-25ContractSigningPlanId + SupplierId + ContractId? (:25).
  • Infrastructure/Persistence/Configurations/ContractSigningPlanLineConfiguration.cs:22-24HasIndex(PlanId, SupplierId).IsUnique().HasFilter("[IsDeleted] = 0").
  • :26 HasIndex(x => x.ContractId) KHÔNG .IsUnique() ⇒ N-line→1-HĐ (OG-1 gộp) hợp khuôn schema hiện tại. ĐÚNG 3/3 vế.

V-b (claim: create validator CHỈ check ApplicableType==10, không check IsActive) = ĐÚNG

  • Application/ContractSigningPlans/ContractSigningPlanFeatures.cs:209-220EnsureWorkflowTypeAsync chỉ Select(w => (int?)w.ApplicableType) (:214) + nhánh NotFound (:216-217) + so type (:218-219). 0 đọc IsActive/IsUserSelectable.
  • Call-site: :350 (Create) + :460 (Update pin) — cả 2 nhánh cùng guard.

V-c (claim: picker FE lọc isUserSelectable) = ĐÚNG

  • fe-user/src/pages/khkk/KhkkCreatePage.tsx:56-66 — GET /approval-workflows-v2?applicableType=10types.find(...).history.filter(w => w.isUserSelectable).
  • Chuỗi bổ trợ (lens2 tự đo, sub-invest KHÔNG nêu): ApprovalWorkflowV2AdminFeatures.cs:117-134 overview KHÔNG lọc IsActive ⇒ history trả CẢ bản inactive; POST tạo mới :341-343 chỉ set IsActive=false cho bản cũ, KHÔNG đụng IsUserSelectable (:352-353 bản mới = true) ⇒ 8 workflow cùng type-10 vẫn hiện đủ ở picker. Verdict "only-ONE-active VÔ HẠI" ĐỨNG VỮNG cho đường picker.

V-e (claim: KHKK service KHÔNG port CeoApprovalThreshold ⇒ set = config-lie #78) = ĐÚNG

  • Grep CeoApprovalThreshold|AllowApproverFinalize trên toàn *ContractSigningPlan* (src/Backend): hit DUY NHẤT = comment ContractSigningPlanWorkflowService.cs:44 + Designer migration (schema ApprovalWorkflow). 0 hit đọc-giá-trị trong code KHKK ⇒ 0 consumer THẬT (không phải chỉ comment khai).

V-f (claim: leaf key KHÔNG infix G1) = ĐÚNG

  • DbInitializer.cs:1780-1787Khkk_G1 (group) + 6 leaf Khkk_WfView/List/Create/Pending/Approved/Deleted parent = "Khkk_G1", key leaf KHÔNG mang G1.

V-d (claim: GĐ3/4 đã có c.type; PipelineStage leaves PHẲNG, muốn nhóm thì groups? hoặc content) = ĐÚNG

  • fe-user/src/components/pipeline/PipelineStageFolders.tsx:58-72PipelineStage = {n, leaves[], locked?, failed?, loading?, content?, count?, truncated?} — KHÔNG có groups.
  • :74-75 stageCount = content !== undefined ? (count ?? 0) : leaves.length ⇒ đi đường content thì count PHẢI truyền tay (bẫy đếm S162).
  • usePipelineStages.ts:240 navigate('/hard-copies?type=' + c.type)c.type có trên leaf GĐ4; GĐ3 :220-229 dùng cùng object c ⇒ group-by type = thuần FE. ĐÚNG.
  • BONUS ĐO ĐƯỢC (mirror claim K5): sha256 usePipelineStages.ts fe-user == fe-admin = 7144eeb7…ab148; PipelineStageFolders.tsx = d449cc8d…cdc2d — 2/2 cặp IDENTICAL, tiền-đề "mirror SHA ×2 app" ĐÚNG tại HEAD.

F-L2-1 [HIGH] "Phiếu per NHÓM" (quyết-định ②.2) VA vào rào 1-PE-1-phiếu đang sống — K2 không liệt site này

  • ContractSigningPlanFeatures.cs:342-347 — Create chặn: AnyAsync(p => p.PurchaseEvaluationId == pe.Id && p.Phase != TuChoi) ⇒ 409 "Phiếu Duyệt NCC này đã có kế hoạch ký kết."
  • Cặp sinh đôi ở picker: :1201-1202 !db.ContractSigningPlans.Any(pl => pl.PurchaseEvaluationId == e.Id && pl.Phase != TuChoi) ⇒ PE biến mất khỏi dropdown ngay sau phiếu ĐẦU.
  • Hệ quả: 1 gói thầu có hạng mục thuộc >1 nhóm duyệt ⇒ phiếu nhóm thứ 2 KHÔNG tạo được. Spec K2 (§③) chỉ liệt Mig 71 + validator + FE lines editor — 2 vị-ngữ trên KHÔNG có trong phạm vi.
  • DoD K2 hiện tại ("tạo phiếu nhóm X + N hạng mục; line khác nhóm → 409") PASS mà lỗ vẫn còn ⇒ acceptance mù đúng chỗ nguy hiểm.
  • Falsifier: nếu owner chốt "1 PE chỉ thuộc ĐÚNG 1 nhóm" thì finding rớt xuống LOW — nhưng khi đó "phiếu per NHÓM" == "phiếu per PE", cần khai rõ.
  • Đề nghị: thêm dòng K2 "đổi 2 vị-ngữ uniqueness sang (PeId, ApprovalGroup)" + DoD "tạo phiếu nhóm 2 CÙNG PE → 201".

F-L2-2 [MED] "8 designer entry" (K6 DoD) không khả thi với hình-dạng route hiện tại

  • Deep-link designer là PER-TYPE: fe-admin staticMap literal Khkk_WfView: '/system/approval-workflows-v2/ContractSigningPlan' (fe-admin/src/components/Layout.tsx:35), route :code = TYPE-code.
  • resolvePath nhánh AwV2_ chỉ nhận 3 code DuyetNcc|DuyetNccPhuongAn|Contract (fe-admin/Layout.tsx:166-172) ⇒ leaf AwV2_* code mới trả null = leaf RỚT IM LẶNG (gotcha #50, chính comment :40 cảnh báo).
  • ⇒ muốn 8 entry designer phải (a) mở regex/whitelist + (b) route nhận per-workflow (Code/Id), không có trong K3/K6 scope.

F-L2-3 [MED] Leaf WfView (và Create) không có đường mang group — K4 DoD chỉ đo leaf list

  • WorkflowMatrixViewPage.tsx:52-71 lọc DUY NHẤT theo ?type= (typeInt whitelist 1|2|3|10) rồi render summary.history (mọi workflow isUserSelectable của type) ⇒ 8 leaf Khkk_G{n}_WfView sẽ trỏ CÙNG /khkk/workflow-matrix?type=10 và hiện CẢ 8 nhóm.
  • K4 DoD (§③) chỉ đòi "bấm từng leaf list lọc đúng ApprovalGroup" ⇒ 8/48 leaf WfView + 8/48 leaf Create nằm NGOÀI phép đo.

F-L2-4 [LOW-MED] Citation §D K5 gọi tên BE-artifact KHÔNG tồn tại

  • Sub-invest §D K5: "BE: KhkkListItemDto +approvalGroup". Grep src/Backend: 0 hit KhkkListItemDto; record thật = ContractSigningPlanListItemDto (ContractSigningPlanFeatures.cs:34). KhkkListItemDto là type FE (fe-user/src/types/khkk.ts:106).

F-L2-5 [LOW] Số leaf trong ②.6 mâu thuẫn với §C-6

  • Spec ②.6: "nhóm 2-8 = key mới Khkk_G{n}_* (48 leaf…)" — đọc như 48 leaf MỚI; §C-6 sub-invest ghi "48 leaf TỔNG". Đúng số: 7 nhóm mới × 6 = 42 leaf mới + 7 group-key mới = 49 row menu mới; tổng leaf = 48.
  • Ảnh hưởng thật: 2 danh sách key TRONG DbInitializer phải khớp từng dòng — KhkkKeys() (DbInitializer.cs:2185-2188, 7 key) và bộ grant (:2418-2424) — sai số ở spec = sai 2 chỗ enumerate.

F-L2-6 [MED] K4 liệt 2 site BE nhưng có 3 — KhkkKeys() bị bỏ sót (đúng lớp S155 mà spec tự trích)

  • Site 1 menu seed: DbInitializer.cs:1780-1787 (SeedMenuTreeAsync :1737).
  • Site 2 grant KHKK: SeedKeHoachKyKetAccessAsync (:2415, key-list :2418-2424).
  • Site 3 KHÔNG được spec nêu: KhkkKeys() :2185-2189 (7 key hardcode) → :2216 .Concat(KhkkKeys()) bên trong SeedAllRolesReviewReadPermissionsAsync (:2144). Chính comment :2204-2205 cảnh báo lớp này: "phải có mặt ở CẢ HAI danh sách permission … quên 1 bên = quyền lệch".
  • Quên site 3 ⇒ 42 leaf mới không có CanRead trên đường review-scope (fresh-DB / env khác) — lỗi IM LẶNG kiểu menu-vắng.

Ghi chú kiểm-chứng phụ (không tính là finding)

  • "0 workflow type-10 seed" (§B.7) ĐÚNG 2 nguồn độc lập: grep ContractSigningPlan trong DbInitializer.cs = 0 hit ngoài Khkk_* menu; danh sách hàm seeder (:171,:223,:273,:325,:373,:421,:469) có Contract/Proposal/Leave/Ot/Travel/Vehicle — KHÔNG có ContractSigningPlan.
  • Khuôn được trích tồn tại thật: SeedRealMasterDataAsync :2901 (K1) · SeedSampleApprovalWorkflowsV2Async :171 (K3) · isAdminHidden chỉ Ct_ fe-admin/Layout.tsx:182-184 (K6).
  • FE tree ĐÃ chịu được N-phiếu/1-PE: usePipelineStages.ts:110-121 Map<string, KhkkListItemDto[]> (bucket mảng + sort desc) ⇒ F-L2-1 là rào BE thuần, FE không phải sửa.

Verdict

LENS2: 8/11 claim ĐÚNG · 1 SAI · 2 LỆCH-NHẸ. 6 claim chịu-lực (a)-(f) = 6/6 ĐÚNG ⇒ nền kỹ-thuật của 8 verdict §C VỮNG. Rủi ro không nằm ở evidence sai mà ở phần spec KHÔNG nói: F-L2-1 (HIGH, rào 1-PE-1-phiếu chặn thẳng quyết-định "phiếu per NHÓM") + F-L2-6 (MED, thiếu 1 site permission) + F-L2-2/3 (MED, designer-entry & leaf WfView/Create ngoài phép đo K4/K6).

(XONG — 6 verdict verify + 6 finding, không còn mục treo)