# S116 — PE cho nhập giá ÂM ô "Số tiền báo giá cho hạng mục" (2026-07-13)

**Commit:** `88368fd` · **CI:** Run 386 PASS 5m28s · **State:** Mig 65 · 89 bảng · **495 test** (486→495) · gotcha 81 · bundle admin `Dd55jBpj` / user `DVDr1UQ4`
**Lead:** Opus 4.8 (owner-choice; Fable UP — xác nhận qua fable-real `claude-fable-5`) · HMW-ON · em-main-led

## Đề bài (anh Kiệt FDC ⇄ Duy Nguyen, Zalo)
Ô **"Số tiền báo giá cho hạng mục"** (`form.thanhTien` → `Quote.ThanhTien`) trong dialog "Thêm NCC vào phiếu" PE **không nhập được số âm**. Yêu cầu cho nhập âm — số âm = **phát-sinh-giảm / hoàn-tiền** của NCC = giá **THẬT** (không phải lỗi). Rule: **ngân sách GIỮ NGUYÊN**; "có giá là được" (≥1 giá thật âm/dương → gửi được; chỉ chưa-nhập-gì mới chặn).

## Pipeline (anh chỉ định: /fable-clone invest-review → /fable-real → hmw Opus MAX → commit+deploy)
| Stage | Workflow | Kết quả |
|---|---|---|
| invest | `wf_eaf52972-d18` 4× investigator-codebase | **FE-ONLY** — BE/DB nhận âm sẵn (0 validator `UpsertQuoteCommand`, `decimal(18,2)` no CHECK); ngân sách safe by architecture (`PeWorkItemBudgets` role-gated, quote-path không đụng) |
| gate | AskUser ×2 (4 decision) | R1 · R2 · R2-revised · R-CEO (dưới) |
| review | `wf_4824f158-b66` 3× reviewer | Lane1 PASS_WITH_FIXES (sign-plumbing) · Lane2/3 PASS |
| deep-pass | `wf_9648d207-21b` 1× reviewer (Fable) | **#53 garble → em-main-solo gate GO-WITH-FIXES** |
| implement | `wf_48834aca-c41` FE‖(BE→test) Opus MAX | 0-garble, 486→495 |
| verify | em-main độc-lập | dotnet test 495 · mirror SHA · BE build |
| deploy | cicd-monitor | Run 386 PASS, byte-level ship-proof |

## Owner-decisions (anh Kiệt chốt)
- **R1** — Contract.GiaTri âm: **CHO PHÉP** (no clamp; `CreateContractFromEvaluationFeatures.cs:88-100` giữ âm; validator tạo-tay `ContractFeatures.cs:46` GiaTri≥0 = đường khác, giữ).
- **R2 (revised)** — submit-guard `Sum()<=0` → **`All(x=>x==0)`**. Anh **hỏi lại mid-pipeline**: "1 NCC / 1 hạng mục âm thì có chặn không?" → phát hiện guard cũ **mâu-thuẫn R1** (cho HĐ âm nhưng chặn phiếu tạo ra nó). Guard là **proxy sai** cho ý-định "chưa báo giá" → sửa về đúng ý-định.
- **R-CEO** — ngưỡng CEO: **giữ NET** (`winnerQuoteTotal` net, dòng âm có thể kéo phiếu dưới ngưỡng → CCM finalize bỏ CEO; owner chấp nhận "duyệt theo net cam-kết").
- **R3** — BgVat/ChuaVat giữ nguyên.

## Thay đổi code (FE + 1 BE, KHÔNG migration)
**FE** `PeDetailTabs.tsx` (fe-user + fe-admin byte-identical SHA `3e16dba5`, 112 dòng/app):
- Nút **± toggle** 2 input quote (AddSupplierDialog `:2365` + QuoteDialog `:2917`), ghi giá-**CÓ-DẤU** thẳng vào `form.thanhTien` (2 dialog POST commit trực tiếp, không nút Lưu riêng → nếu chỉ flip cờ `neg` = mất-dấu thầm lặng — review Lane-1 bắt).
- Submit gate `:2226` + toast `>0` → `!==0`. Ô ngân sách `:2830` giữ ≥0 (không toggle).
- Helper mới `hasRealSelectedQuote` thay 2 FE submit-mirror (`:201` missingForApproval + `:235` submitChecklist) — SUM `computeGiaChaoThau` không phân-biệt all-zero vs net-zero → iterate `ev.details[].quotes` (KHÔNG `suppliers[].quotes` — FE-agent tự sửa spec-shape-error).

**BE** `PurchaseEvaluationWorkflowService.cs:206`: `selectedThanhTien.Sum() <= 0` → `.All(x => x == 0)` (1 điều-kiện) + stale-comment fix. `Count==0` guard giữ riêng.

**Tests** +9 (486→495): T1 ngân-sách-bất-biến (`PeWorkItemBudgetTests`) · T2 winnerQuoteTotal signed-sum (`PeMultiWinnerTests`) · T3 submit-guard all-zero/pure-neg/net-zero (`PeSubmitGuardAndBypassTests` + helper ext) · T4 CCM-net-threshold (`PeCcmThresholdFinalizeTests`).

## Lessons
- **Owner bắt mâu-thuẫn giữa 2 decision** (R1⇄R2) mà invest+review đều chưa nối — cho dữ-liệu-âm ở đầu-ra nhưng chặn con-đường tạo ra nó. → engine phải nối các quyết-định, không xét độc-lập.
- **Guard là proxy sai:** `Sum()<=0` ≠ ý-định "chưa báo giá" (= `All(==0)`). Sửa về đúng ý-định giải mâu-thuẫn + đúng ngữ-nghĩa.
- **#53-garble ×19 (fable-real, reasoning-lane):** garble ≠ mất-việc. Recover **transcript-forensics** (thấy nó verify CEO-threshold, chưa kịp verdict) → **em-main-solo gate** vẫn có RĂNG (bắt thêm FE mirror `:235`). `parallel()` + schema-nhỏ → 4/5 workflow 0-garble.
- **verify-deployed-byte-level (#77):** cicd curl bundle prod grep feature-string PRESENT (bundle cũ=0) = ship-proof thật, không cache. + bắt bẫy snapshot-while-CI-running → poll-success trước re-snapshot.
- **FE agent verify-on-disk** sửa spec-shape-error (quotes ở `details[]` không `suppliers[]`) — lý do worker phải verify, không tin spec mù.

## Carry NEXT
- Anh UAT incognito (7 điểm → HANDOFF).
- run-trace + agent-memory `.claude/`-gitignored → force-add @closeout.
- PE "lỗi phân quyền vào phiếu" (chờ số-phiếu+user) · BVAAU (`AUTH_ENFORCE_CRM_GATE`+User_ID) · monthly re-tier 2026-08-01.
