Files
solution-erp/docs/changelog/sessions/2026-07-13-S116-pe-negative-quote.md
pqhuy1987 73f2939d8b [CLAUDE] Docs: S116 closeout — PE negative-quote (STATUS/HANDOFF/session-log + harvest)
- STATUS/HANDOFF prepend S116 (test 486->495 · bundle Dd55jBpj/DVDr1UQ4) + fix
  D1 Tests-row (486->495, 441->450 Infra) + D2 bundle-live-pointer (tooling-auditor
  caught 2 derived-summary lags below the mega-line).
- Session log 2026-07-13-S116-pe-negative-quote.md.
- Harvest: investigator-codebase on-behalf S116 (invest lanes RETURN-only) +
  reviewer/impl-fe/impl-be/test/cicd self-written · monitor diaries (harvest-curator
  self-compact moved-not-cut + tooling-auditor archive-move).
- §5.0 squash 2 wal-trailing (dfa1c8c/0edbc58, post-feature Stop-hook flush) folded here.
- Feature already shipped 88368fd (Run 386 PASS 5m28s); this commit = docs/memory/run-trace
  only -> CI skip (paths-ignore #41).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 17:40:27 +07:00

5.2 KiB
Raw Blame History

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.thanhTienQuote.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()<=0All(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.