[CLAUDE] Docs: S88 closeout — PE stability audit + D1/D2 prod-verified
STATUS/HANDOFF S88 prepend (State THAT: Mig 59 · 88 bang · 419 test (45D+374I) · gotcha 73 · bundle admin BQq2eTP6/user dHa64I59) + session log + agent-memory harvest (6 sub: cicd/impl-backend/impl-frontend/inv-codebase/reviewer/test-spec). D1/D2 production already shipped:73cce1f(Run #347 PASS, +11 test, the 6 fixes) +1aa3bdb(Run success, +6 test, create-contract 1->N + list winner names). Both prod-verified (bundle rotation + Gitea run=success; cicd-monitor verdict truncated #53 -> curl-self-verify). Curate-debt: test-specialist L1 34.8KB OVER-SOFT (root-caused #53 x3 this session) DEFERRED next session as #1 NEXT-em (proper byte-exact L1->L2 + _INDEX, not rushed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -6,6 +6,21 @@
|
||||
|
||||
---
|
||||
|
||||
## 🆕 S88 D2 (2026-06-25) — PE multi-winner OUTWARD FE ×2 app (BE đã đổi: create→LIST, list DTO winner names)
|
||||
3 edit OUTWARD, em-main chốt FE behavior, coord BE (impl-backend đã viết). 2 SHA-pair + 1 type-DIVERGE.
|
||||
- **E1 CreateContractDialog (PeDetailTabs ~:2144):** mut type `{contractId:string}`→**`{contractIds:string[]}`** (BE tạo 1 HĐ/mỗi IsWinner). onSuccess: toast `` `Đã tạo ${res.data.contractIds.length} hợp đồng từ phiếu.` `` + `navigate(/contracts/${res.data.contractIds[0]})` (giữ destination `/contracts/${...}` của bản single). Dialog GIỮ joined winner-names (:2174) + 1 ContractType-cho-mọi-winner. Bản gốc KHÔNG invalidate → nothing to preserve.
|
||||
- **E2 PeListPanel label (~:168):** `{p.selectedSupplierName && …✓…}` → prefer `winnerSupplierNames.join(', ')` khi `winnerSupplierNames?.length>0`, else `selectedSupplierName`. Giữ ✓ + `text-emerald-600`. Ternary lặp 2 lần (guard + render) — optional-chain `?.length` an-toàn undefined.
|
||||
- **E3 type (DIVERGE 2 file):** `PeListItem` +`winnerSupplierNames:string[]` sau urgent-flags (anchor `isUrgentByPro/Ccm`+`}` byte-identical 2 app → Edit same string ×2, grep-confirm KHÔNG vào inter-app diff, stat giữ 30ins/26del). Create-contract response = **inline generic** trong PeDetailTabs (KHÔNG named type ở types file) → E3b no-op; `contractId:string|null` :121/:443 = link-HĐ-đã-gắn field KHÁC, GIỮ.
|
||||
- **SHA256 ×2 pair:** PeDetailTabs `9d8120b6…`, PeListPanel `c97e133d…` (cp admin→user, git-diff --no-index IDENTICAL). Build PASS ×2 (admin `index-C3j9HaFh.js` 2.18s / user `index-Ct2cpC7h.js` 2.23s, 0 TS err). Pre-existing warn: >500KB + realtime.ts dynamic. NO BE/test touch. **LESSON: OUTWARD multi-winner = winnerSupplierNames[] (BE null selectedSupplierName khi ≥2) → FE prefer-list-fallback-single; type DIVERGED ≠ cp → edit-same + verify-not-in-diff (S87+ confirm).** Tag `[s88, pe-multi-winner-outward, contractIds-list, winner-names-fallback, sha256-2pair, type-diverge-edit-same]`.
|
||||
|
||||
## 🆕 S87+ (2026-06-25) — FROZEN PE behavior-preserving cleanup ×2 app (em-main chốt, coord BE null-safe)
|
||||
4 edit `PeDetailTabs.tsx` (SHA-pair) + 2 wording `types/purchaseEvaluation.ts` (DIVERGED — KHÔNG SHA-pair, edit identical 2 file).
|
||||
- **E1 HoSoLink clear:** `HoSoLinkRow.save` (~:2020) `hoSoLink: hoSoLink || null` → **`hoSoLink.trim()`** (state đã string nên `??""`=no-op; trim ra `""` khi xóa). Coord BE `UpdatePeDraftHandler` null-safe: `""`=CLEAR, null/omit=PRESERVE, val=set (fix data-loss xóa link khi edit header). **GUARD: InfoTab.save (:817) + `PeHeaderForm` PUT body GIỮ OMIT hoSoLink** (omit=preserve = đúng fix) — verify KHÔNG thêm.
|
||||
- **E2 #70 stale-echo guard:** 2 ô PRO `adjustMut` (row3 NS-kỳ-này :1548 + row8 GT-còn-lại :1649) chỉ `saving={adjustMut.isPending}` → `|| peFetching` (`replace_all` đúng 2 occ; `peFetching` computed :1268). Sibling ccmPeriod/proPrice/ccmPrice/proMut/ccmMut đã có. Chống fast-double-save clobber stale `ev.*` (2 ô share 1 absolute-set mut cross-echo).
|
||||
- **E3 stale comment :2507:** "AddItemDialog giữ (dead)…" → đã xóa (grep chỉ comment match; live = `DetailDialog`). Sửa thành "nút đã bỏ (dialog = DetailDialog)".
|
||||
- **E4 type wording (2 file):** `previousSelectedTotal`/`currentProposalTotal` inline cmt "của SelectedSupplier" → "NCC trúng (IsWinner)" (BE giờ multi-winner). Block 7-dòng byte-identical 2 app → edit same → KHÔNG new divergence (grep-confirm my-line ∉ diff).
|
||||
- **SHA256 PeDetailTabs ×2 = `36292924…`** (cp admin→user, git-diff empty). PeHeaderForm untouched `987291c1…` identical. Build PASS ×2 (admin 1946mod `index-CqiQWR8e.js` / user 1935mod `index-Cp0DuKFQ.js`, 0 TS err). Pre-existing warn: @import CSS + >500KB + realtime.ts. NO BE/test touch. **LESSON: type files DIVERGED (S76/S79 color+prose) ≠ SHA-pair → mirror = edit-identical-block + verify-not-in-diff, KHÔNG cp.** Tag `[s87plus, pe-frozen-cleanup, hosolink-clear-empty, gotcha70-guard, type-diverge-edit-identical]`.
|
||||
|
||||
## 🆕 S79 (2026-06-19) — PE detail: live thousand-sep + ghi chú giá PRO/CCM + typo (×2 app)
|
||||
3 task presentation+wiring `PeDetailTabs.tsx` (+`PeWorkspaceCreateView.tsx` typo). BE thêm `note` body song song; FE chốt UX rồi.
|
||||
- **A live phân cách:** chỉ **2 comp** thiếu sep — `VndInlineEdit` (~990) + `BudgetCell` (~1100): đổi `onChange` `value.replace(/[^\d.]/g,'')` → **`formatVndInput(parseVnd(e.target.value))`** (format-on-keystroke, reuse helper module-level :51/52). Dialog money inputs (2111/2555/2645) ĐÃ dùng `formatVndInput`/`parseVnd` sẵn → no-op. KHÔNG đụng phone(tel)/%/qty.
|
||||
|
||||
Reference in New Issue
Block a user