From e5f3c5d70a89f1174952f4f8c3fb1b1835651b77 Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Mon, 13 Jul 2026 16:22:29 +0700 Subject: [PATCH] wal: flush 20260713T1622 --- .../runs/2026-07-13-pe-negative-quote/run.md | 8 +++++--- .../spec-pe-negative-quote-13-07-2026.md | 12 ++++++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.claude/workflows/runs/2026-07-13-pe-negative-quote/run.md b/.claude/workflows/runs/2026-07-13-pe-negative-quote/run.md index 27840f8..6be2644 100644 --- a/.claude/workflows/runs/2026-07-13-pe-negative-quote/run.md +++ b/.claude/workflows/runs/2026-07-13-pe-negative-quote/run.md @@ -8,8 +8,9 @@ ## Stages - [x] Stage 1 — invest (fable-clone ensemble, 4× investigator-codebase) → **DONE 4/4 clean 0-garble** (`wf_eaf52972-d18`, ~11', 516K tok). Kết luận: **FE-ONLY** (BE+DB đã nhận âm; ngân-sách bất-biến bằng kiến-trúc). Spec `spec-pe-negative-quote-13-07-2026.md` ghi xong. - [x] gate — anh Kiệt CHỐT: R1 = CHO HĐ âm (no-op) · R2 = **NỚI guard** `Sum()<=0`→`All(==0)` (anh hỏi lại: 1-NCC-âm phải gửi được, mâu thuẫn R1 → refine). Implement = FE + 1 điều-kiện BE guard + test. -- [!] Stage 2 — review (fable-clone ensemble, 3× reviewer) -- [ ] Stage 3 — review (fable-real, reviewer deep-pass) +- [x] Stage 2 — review (fable-clone 3× reviewer `wf_4824f158-b66`): Lane1 PASS_WITH_FIXES (sign-plumbing baked) · Lane2/3 PASS (mirror clean · budget invariant + #81 safe) +- [x] gate — anh Kiệt CHỐT CEO-threshold = NET (no-op, giữ hiện tại) +- [!] Stage 3 — review (fable-real, reviewer deep-pass) trên spec CUỐI - [ ] gate — owner-decisions (nếu invest/review lòi ra) - [ ] Stage 4 — implement (hmw Opus 4.8 MAX) - [ ] Stage 5 — verify (test-before "ngân sách giữ nguyên" + build 2-app) @@ -25,4 +26,5 @@ ## wf run-id - Stage 1 invest: `wf_eaf52972-d18` (task `wslm7eymc`) — 4 lane investigator-codebase, DONE 4/4 clean, HMW-ON, lead Opus 4.8 -- Stage 2 review: `wf_4824f158-b66` (task `wjhpvoyum`) — 3 lane reviewer (correctness-wire · mirror-completeness · financial-invariant-owner) +- Stage 2 review: `wf_4824f158-b66` (task `wjhpvoyum`) — 3 lane reviewer, DONE Lane1 PASS_WITH_FIXES + Lane2/3 PASS +- Stage 3 fable-real: `wf_9648d207-21b` (task `we5wjoxiq`) — single reviewer deep-pass, model:'fable' + effort max (outage→null→fallback Opus) diff --git a/.claude/workflows/runs/2026-07-13-pe-negative-quote/spec-pe-negative-quote-13-07-2026.md b/.claude/workflows/runs/2026-07-13-pe-negative-quote/spec-pe-negative-quote-13-07-2026.md index 235010e..47570cb 100644 --- a/.claude/workflows/runs/2026-07-13-pe-negative-quote/spec-pe-negative-quote-13-07-2026.md +++ b/.claude/workflows/runs/2026-07-13-pe-negative-quote/spec-pe-negative-quote-13-07-2026.md @@ -19,7 +19,8 @@ 2. **Input quote — QuoteDialog** `:2917` — cùng pattern; `neg` init từ dấu của `existing.thanhTien` (mở lại quote âm phải hiện đúng, không trắng ô). 3. **Submit gate — AddSupplierDialog** `:2226` `if (detailId && form.thanhTien > 0)` → `!== 0` (âm tạo quote; rỗng/0 vẫn skip = "chưa báo giá"). Toast `:2239` cùng sửa. 4. **KHÔNG đụng** `parseVnd`/`formatVndInput` (dùng-chung ô ngân sách cùng file `:51-52`) + **KHÔNG** truyền allowNegative cho ô ngân-sách `thanhTienNganSach:2830` (giữ ≥0). -5. **Submit-guard R2-revised (BE + FE mirror):** `PurchaseEvaluationWorkflowService.cs:206` `selectedThanhTien.Sum() <= 0` → `selectedThanhTien.All(x => x == 0)` (hoặc `!Any(x => x != 0)`) + FE mirror `PeDetailTabs.tsx:201` (`gia <= 0` → all-zero). Chặn **CHỈ khi chưa nhập giá nào**; có ≥1 giá thật (âm/dương, kể cả 1 NCC 1 hạng mục âm) → CHO gửi. Message giữ nguyên. `Count==0` (chưa chọn NCC) vẫn chặn riêng, không đổi. +5. **Submit-guard R2-revised (BE + FE mirror):** BE `PurchaseEvaluationWorkflowService.cs:206` `selectedThanhTien.Sum() <= 0` → `selectedThanhTien.All(x => x == 0)` (hoặc `!Any(x => x != 0)`). Chặn **CHỈ khi chưa nhập giá nào**; có ≥1 giá thật (âm/dương, kể cả 1 NCC 1 hạng mục âm) → CHO gửi. Message giữ. `Count==0` (chưa chọn NCC) vẫn chặn riêng. + - ⚠️ **FE mirror `:201` (Lane-3 nuance):** hiện là `gia <= 0` với `gia`=winnerQuoteTotal=**SUM** — KHÔNG được giữ sum-based (sẽ chặn net-âm mà BE cho → lệch FE/BE). Đổi sang semantics **"không có giá thật nào"** = `!selectedQuotes.some(q => q.thanhTien !== 0)`. Implementer verify FE có list quote đã-chọn tại `:201` (đang render nên có); nếu chỉ có SUM thì phải lấy thêm list. **Semantics giữ:** rỗng/0 = "chưa báo giá" (skip tạo quote); âm = quote thật (≠ rỗng). `formatVndInput(-n)→''` là lý do PHẢI tách magnitude+dấu (không chỉ nới parseVnd). @@ -33,7 +34,14 @@ - **R1 — Contract.GiaTri âm: CHO PHÉP** (khuyến nghị). Luồng PE→HĐ giữ số âm; **KHÔNG thêm clamp/floor**; validator tạo-tay `ContractFeatures.cs:46` (GiaTri≥0) GIỮ nguyên (đường khác). → **code no-op** (allow = không chặn thêm). - **R2 — submit-guard: NỚI (anh Kiệt refine S116)** — đổi chặn `Sum()<=0` → chặn CHỈ khi TẤT CẢ selected = 0 (`All(==0)`). Có ≥1 giá thật (âm/dương, **kể cả 1 NCC 1 hạng mục âm**) → CHO gửi. Lý do: rào cũ `Sum()<=0` bắt nhầm ca 1-NCC-âm → **mâu thuẫn R1** (cho HĐ âm nhưng không gửi được phiếu tạo ra nó). → **BE `:206` + FE mirror `:201` (fix nhỏ 2-tier).** - R3 (default): BgVat/ChuaVat giữ nguyên (FE chỉ expose input âm cho thanhTien). -→ **R1 no-op + R2 nới-guard ⇒ implement = 4 thay-đổi FE + 1 điều-kiện BE (submit-guard) + 4 test.** +- **R-CEO — ngưỡng CEO: DÙNG NET (anh Kiệt chốt S116)** — CeoApprovalThreshold giữ tính trên `winnerQuoteTotal` net (dòng âm giảm tổng → có thể kéo dưới ngưỡng → CCM finalize bỏ CEO; owner chấp nhận, đúng ý "duyệt theo net cam-kết"). → **code no-op** (giữ hiện tại). +→ **R1 + R-CEO no-op + R2 nới-guard ⇒ implement = 4 thay-đổi FE + 1 điều-kiện BE (submit-guard) + 4 test.** + +## 🔍 Review-reconcile Stage 2 (fable-clone 3-lane `wf_4824f158-b66` — Lane1 PASS_WITH_FIXES · Lane2/3 PASS) +**🔴 MUST bake (Lane-1 sign-plumbing):** 2 dialog commit `form.thanhTien` THẲNG ở POST (`:2232` AddSupplier · `:2875` QuoteDialog), KHÔNG có nút "Lưu số tiền" riêng như VndInlineEdit ⇒ nút ± PHẢI đảo dấu CHÍNH `form.thanhTien` NGAY (`setForm({...form, thanhTien: -form.thanhTien})`), display `formatVndInput(Math.abs(form.thanhTien))`, onChange áp dấu hiện tại. Chỉ flip cờ `neg` → bấm ± rồi Thêm không gõ thêm = **gửi sai dấu (dương) = mất-dấu thầm lặng**. +**Lane-2 nits (bake):** (a) Toast `:2239` dùng CÙNG predicate `!== 0` với gate `:2226`. (b) `neg` = `useState` RỜI, KHÔNG nhét vào form object (QuoteDialog `:2921` `setForm({thanhTien})` thay-thế object → nuốt `neg`). (c) **Re-verify mirror SAU implement:** `git diff --no-index` 2 app PeDetailTabs = exit 0 (4 chèn × 2 app = drift-risk cao nhất). +**Lane-3 test notes:** T1 (budget unchanged) hơi tautological (0 đường ghi budget từ quote) — giữ regression-lock, bề-mặt rò thật = T2. T3 cần seed ≥2 quote TRÁI DẤU/1 winner → mở rộng helper `SeedWinnerWithQuoteAsync` (`PeSubmitGuardAndBypassTests.cs:106-136`, hiện 1 quote/winner); base `:104` không đủ nửa "mixed net>0 submittable". +**✅ Owner-confirm CEO-threshold:** anh Kiệt CHỐT dùng **NET** (giữ hiện tại, no-op) — chấp nhận dòng âm có thể kéo phiếu dưới ngưỡng CEO. ## ③ Checklist (vai · deliverable · acceptance ĐO ĐƯỢC) | # | Vai | Deliverable | Acceptance đo được |