wal: flush 20260712T2114

This commit is contained in:
pqhuy1987
2026-07-12 21:14:52 +07:00
parent e05763f46c
commit 53e8d1689d
8 changed files with 94 additions and 17 deletions

View File

@ -9,7 +9,9 @@ Cho phép chọn **≥2 NCC-TP trúng thầu vào 1 hạng mục** (PurchaseEval
## taskList snapshot (6-bước anh Kiệt)
- [x] **B1** fable-clone invest ensemble (4-lane inv-cb) → spec — `wf_dd49ddc0-f29` DONE (4/4 clean)
- [!] **B2** CHỜ anh Kiệt chốt D1-D5 → fable-clone review (reviewer ensemble) spec cuối
- [x] **B2a** anh Kiệt chốt D1-D4 all recommended (D5 default) spec LOCKED
- [x] **B2b** fable-clone review ensemble → spec cuối — `wf_1e127f4b-de5` DONE (2/3 clean, lane correctness #53-garble→em-recover; 6 adjustment A1-A6 fold)
- [!] **B3** hmw Opus 4.8 MAX implement (BE re-key 5 financial + derive-invariant + FE per-cell grid 2-app + test-before)
- [ ] **B3** hmw Opus 4.8 MAX implement (BE + FE 2-app + test)
- [ ] **B4** fable-clone reviewer verify implementation
- [ ] **B5** deploy + commit (cicd-monitor verify)

View File

@ -58,6 +58,31 @@ Hiện tại mỗi **hạng mục** (`PurchaseEvaluationDetail`) trong phiếu D
| C5 | reviewer | Verify 6 read-site re-key đủ (không sót) + total đúng + kế-thừa-HĐ N-winner | PASS: grep-suite 0 sót IsWinner-aggregation; giaTri HĐ = SUM won-lines |
| C6 | cicd-monitor | Deploy verify bundle rotate + Mig prod + smoke PE | Run PASS; byte-verify feature string |
## 🔴 REVIEW ADJUSTMENTS (Bước 2 — fable-clone review ensemble `wf_1e127f4b-de5` → FINAL spec)
> 2/3 lane PASS_WITH_ADJ (consumer-completeness + checklist-risk); lane correctness-edgecase = **#53 return-garble (null)** → em-main-solo recover (territory phủ bởi 2 lane hội-tụ). Cả 2 lane VERIFY 6 read-site inventory ĐÚNG, 0 sót. 6 adjustment fold vào implement:
### A1 (MUST) — giaTri: BỎ shortcut isSingle→detailsSum
`CreateContractFromEvaluationFeatures.cs:89-93` hiện `isSingle ? detailsSum : SUM(all w.Quotes)`. CẢ 2 nhánh SAI dưới per-hạng-mục. **Fix: giaTri per-winner w = `SUM(w.Quotes WHERE IsSelected)` cho CẢ single lẫn multi — bỏ nhánh detailsSum.**
> ⚠️ **HEADS-UP anh Kiệt:** phiếu single-winner giaTri đổi **budget (detailsSum) → bid (SUM quote)** để đúng D4. Số HĐ có thể khác số UAT cũ (comment :73-75) — đây là hệ-quả D4, đúng hơn (giá HĐ = giá chào thực, không phải ngân sách).
### A2 (MUST) — Derive IsWinner ở MỌI writer + backfill 2 chiều
Invariant BẤT BIẾN: **`supplier.IsWinner == supplier.Quotes.Any(IsSelected)`** — bảo trì bởi TẤT CẢ writer của IsSelected: (a) SelectWinner-per-detail · (b) UpsertQuote `DetailFeatures.cs:308/332` · (c) **seed DbInitializer `:1310-1316`** (hiện KHÔNG set IsWinner → seed DaDuyet vỡ). Backfill **2 chiều**: IsWinner→IsSelected (phiếu cũ) VÀ IsSelected→IsWinner (seed/dormant). Acceptance: fresh Dev DB seeded → winner-names hiện + create-contract OK.
### A3 (MUST) — Re-key SPLIT theo loại (KHÔNG blanket 6-site)
- **(i) Financial-SUM → `WHERE IsSelected`:** winnerQuoteTotal `:1189` · submit-guard `:196` · CCM-threshold `:885` · giaTri `:89` · budget-B `:907`.
- **(ii) Winner-existence/names → GIỮ IsWinner (derived):** projection List:637/Inbox:758/ListApproved:189 · CreateContract winners-list `:56`. Re-key nhóm này = vỡ display.
### A4 (SHOULD) — Endpoint + FE UX = breaking (chốt DTO)
`POST /purchase-evaluations/{id}/select-winner` payload: whole-supplier `{supplierIds}`**per-detail `{detailId, supplierIds[]}`** ("hạng mục detailId, các NCC này thắng" → set Quote.IsSelected per cell + derive IsWinner). FE **redesign UX chọn-theo-ô** trong DetailCard `:2638-2792` (checkbox per cell Detail×NCC), hạ-cấp picker phiếu-wide `:941-1020` thành summary. Mirror CẢ 2 app + patch-delta types (KHÔNG blind-copy).
### A5 (SHOULD) — Test-before + threshold-crossing + acceptance đo được
- Test-before (rules §7): test ĐỎ (over-count repro + threshold-crossing) TRƯỚC/CÙNG impl.
- Threshold-crossing regression: phiếu total-IsWinner ≥ ngưỡng CEO nhưng total-IsSelected < ngưỡng assert đúng nhánh CEO/miễn-CEO.
- Acceptance: C5 = grep `\.IsWinner`/`\.Sum(` phân-loại financial-vs-display, 0 SUM còn key IsWinner. C6 = curl phiếu joint-winner, `winnerQuoteTotal == SUM(cell IsSelected)`.
- FE consumer thêm: PeListPanel.tsx:170-178 + display helper PeDetailTabs :76-79/:344-346/:1578-1579.
### A6 (NIT) — Migration 3-file dù data-only backfill; Down = empty no-op (ghi comment). Stale comment `:920` (:1087→:1189) sửa khi động budget-B.
## Rủi ro then chốt
- **Silent total-lệch:** 6 read-site tài chính sót 1 = số sai runtime, build/test vẫn PASS (S87/S88 chính vụ).
- **R3 CCM-threshold = gate tài chính:** over/under-count chặn/cho-qua sai quyền CCM duyệt-miễn-CEO.