From 27d5cd135627c0acc3f381859c860730a36dcc59 Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Sat, 8 Aug 2026 01:58:49 +0700 Subject: [PATCH] wal: flush 20260808T0158 --- .../spec-khkk-awf-mirror-ncc-08-08-2026.md | 2 +- .../sub-implementer-frontend-1.md | 93 ++++++++++++++++--- 2 files changed, 81 insertions(+), 14 deletions(-) diff --git a/.claude/workflows/runs/2026-08-08-S182-khkk-awf-mirror-ncc/spec-khkk-awf-mirror-ncc-08-08-2026.md b/.claude/workflows/runs/2026-08-08-S182-khkk-awf-mirror-ncc/spec-khkk-awf-mirror-ncc-08-08-2026.md index 47d053a..0d02429 100644 --- a/.claude/workflows/runs/2026-08-08-S182-khkk-awf-mirror-ncc/spec-khkk-awf-mirror-ncc-08-08-2026.md +++ b/.claude/workflows/runs/2026-08-08-S182-khkk-awf-mirror-ncc/spec-khkk-awf-mirror-ncc-08-08-2026.md @@ -70,7 +70,7 @@ T1 create v2 `KHKK-N1` ⇒ N2..N8 bất biến + N1 v01→false v02→true · T2 | # | Quyết | Ai | Nội dung | |---|---|---|---| -| D3 | ✅ **anh** (YC-014) | **C** — mờ ô chưa nghe, thi hành theo danh-sách-chốt W2d (6 ô disabled-state-thật + #4 forced-true-disabled + #7 giữ + #8 sống) | +| D3 | ✅ **anh** (YC-014) | **C** — mờ ô chưa nghe, thi hành theo danh-sách-chốt W2d (6 ô disabled-state-thật + #4 disabled-**state-thật** + #7 giữ + #8 sống). 🔴 **ERRATA ratified @1bis (FE FLAG-B):** chữ "forced-true" ở dòng này bản trước = **rút gọn HAO NGHĨA** của MỤC 2 *"state thật (thường TRUE)"* — hard-code `checked={true}` sẽ nói dối ca row=false, cùng class lỗi mà D3=C cấm ở 6 ô kia chỉ đảo dấu. Code theo **state thật** là ĐÚNG (default=true ở 4 lớp ⇒ thực tế vẫn hiện tick, thoả A2). MỤC 2 W2d là bản chuẩn | | D4 | ✅ lead (reviewer đồng ý) | title = menu-label + phụ đề nghiệp vụ | | D5 | 🟡 **lead chọn CÓ** (bậc-2 an toàn — reviewer-2 M-1 khuyến nghị CÓ) | rào delete-last-version nhóm ⇒ 409 (chặn seeder-tái-sinh khỏi đường UI). **Anh veto 1 câu là gỡ** | | D6 | 🟡 **lead chọn CÓ** (bậc-2 an toàn — reviewer-1 F5 khuyến nghị; tiền lệ vá-3 bridge CÙNG LỖ cho type-3) | pin-check IsActive∧IsUserSelectable + FE lọc isActive ×2 app. **Anh veto 1 câu là gỡ** | diff --git a/.claude/workflows/runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-implementer-frontend-1.md b/.claude/workflows/runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-implementer-frontend-1.md index cf6c672..d80b44f 100644 --- a/.claude/workflows/runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-implementer-frontend-1.md +++ b/.claude/workflows/runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-implementer-frontend-1.md @@ -5,17 +5,24 @@ ## §0 — Trạng thái lượt (append liên tục, chống-#53) - [x] Đọc SPEC FINAL MỤC 2 W2 (a-h) + MỤC 1 R-1..R-6 -- [ ] Đọc file đích + đo tiền-đề từ ĐĨA (line-number trong spec có thể lệch) -- [ ] W2a parse kind -- [ ] W2b synthetic slice -- [ ] W2c lockedCode -- [ ] W2d D3=C 6 ô + #4 -- [ ] W2e menuKeys ×2 app -- [ ] W2f ngưỡng CEO -- [ ] W2g auto-pin isActive ×2 app -- [ ] W2h comment + subtitle -- [ ] build fe-admin -- [ ] build fe-user +- [x] Đọc file đích + đo tiền-đề từ ĐĨA (line-number trong spec có thể lệch) +- [x] W2a parse kind +- [x] W2b synthetic slice +- [x] W2c lockedCode +- [x] W2d D3=C 6 ô + #4 +- [x] W2e menuKeys ×2 app +- [x] W2f ngưỡng CEO +- [x] W2g auto-pin isActive ×2 app +- [x] W2h comment + subtitle +- [x] build fe-admin — exit 0 +- [x] build fe-user — exit 0 + +**Lượt 2 (vá-nốt):** chẩn-đoán TS trong TASK là **ảnh cũ** — đo lại từ đĩa thì đã sạch ⇒ **0 dòng code sửa**, lượt này là ĐO + CHỨNG. Chi tiết §3.3. +- [x] tsc thật ×2 app (lệnh trong spec là phép đo CÂM — §3.1) +- [x] control-dương chứng tsc có răng (§3.2) +- [x] proof-harness 27/27 + anti-Goodhart (§3.4) +- [x] đối chiếu code-vs-spec W2a-h (§3.5) +- [x] mirror proof SHA + 4-place (§3.6) ## §1 — Đo tiền-đề từ đĩa (TRƯỚC khi gõ) @@ -96,7 +103,67 @@ Cờ chung `const isKhkk = applicableType === TYPE_INT_CONTRACT_SIGNING_PLAN` (1 - PageHeader: title = `Quy trình duyệt (Mới): {khkkGroupMenuLabel(g)}` · description = phụ đề nghiệp vụ (loại + nhóm N{n} + mã khoá + "7 nhóm còn lại không đổi"). Xem FLAG-1. ## §3 — Verify (build ×2 + proof) -(chưa chạy) + +### 3.1 🔴 Lệnh acceptance trong spec/TASK là PHÉP ĐO CÂM — phải đổi +`npx tsc --noEmit` (nguyên văn acceptance R-2 + TASK lượt 2) chạy ra **EXIT=0, 0 dòng output** ở CẢ 2 app **kể cả khi code sai**: `fe-{admin,user}/tsconfig.json` là solution-style `{"files": [], "references": [...]}` ⇒ tsc **không biên dịch file nào** rồi thoát 0. Xanh vì CÂM, không phải vì đúng. +**Lệnh THẬT** (đã dùng dưới đây): `npx tsc -p tsconfig.app.json --noEmit` — hoặc `tsc -b` (chính `npm run build`). + +| # | Lệnh | Exit | Ghi chú | +|---|---|---|---| +| V1 | `fe-admin$ npx tsc -p tsconfig.app.json --noEmit` | **0** | 114 file `src/` trong tập biên dịch (`--listFiles`), có `ApprovalWorkflowsV2Page.tsx` + `types/khkk.ts` | +| V2 | `fe-user$ npx tsc -p tsconfig.app.json --noEmit` | **0** | | +| V3 | `fe-admin$ npm run build` (`tsc -b && vite build`) | **0** | ✓ 1964 modules · `index-CmEoYZiH.js` 1.761,63 kB | +| V4 | `fe-user$ npm run build` | **0** | ✓ 1953 modules · `index-CT5Y_xQ4.js` 1.677,49 kB | + +V3/V4 chạy **SAU** khi đã hoàn tác tiêm-lỗi ⇒ đo đúng trạng thái cuối trên đĩa. +Warning PRE-EXISTING (không phải nợ mới): chunk >500 kB · `INEFFECTIVE_DYNAMIC_IMPORT realtime.ts` · CSS `@import` order. + +### 3.2 Control-DƯƠNG — chứng phép đo có RĂNG +Tiêm `const __ctrl_neg: number = khkkGroupWorkflowCode(3)` vào cuối chính file đã ship → tsc nổ **2 lỗi**: +`TS2322 Type 'string' is not assignable to type 'number'` + **`TS6133 '__ctrl_neg' is declared but its value is never read`**. +🔴 Ý nghĩa: **TS6133 (`noUnusedLocals`) CÒN SỐNG** — đúng class lỗi mà 3 chẩn-đoán "declared-never-read" (`lockedCode :417` · `isKhkk :714` · `khkkNotYetHint :717`) thuộc về. Nên "0 lỗi" ở V1 = **thật sự hết**, không phải đo hụt. +Hoàn tác: SHA trước/sau `dda4be1f9d4dabd…b69b7f71` **BẰNG NHAU** (byte-identical). + +### 3.3 🔴 Chẩn-đoán trong TASK là ẢNH CŨ — 0 dòng code phải vá +6 lỗi TS mà TASK liệt (thiếu import `khkkGroupWorkflowCode`/`khkkGroupMenuLabel` `:330/:343/:355` · `lockedCode` chưa khai ở signature `:403/:517` · 3 biến never-read) **KHÔNG còn tồn tại trên đĩa**: `import { khkkGroupMenuLabel, khkkGroupWorkflowCode } from '@/types/khkk'` ở `:36`; `lockedCode` khai đủ ở CẢ 2 signature (`TypePanel :417/:421` · `Designer :690/:699`); 3 biến đều có chỗ dùng thật (`isKhkk` 20 call-site, `khkkNotYetHint` 6, `lockedCode` 6). +⇒ Đây là **IDE-diagnostic chụp giữa lúc lane trước đang gõ** (gotcha #68). Lượt này **KHÔNG sửa 1 dòng code nào** — chỉ đo + chứng. `git diff --stat` giữ đúng **5 file**, 0 file untracked. + +### 3.4 Proof-harness — chạy CHÍNH text đã ship (extract-by-anchor, neo lệch thì script tự chết) +`node proof-w2.mjs` → **27 PASS / 0 FAIL**: +- **T1 (8/8)** dây xuyên suốt `AwV2_KhkkN{n}` → `Layout.tsx:188` → `/system/approval-workflows-v2/KhkkN{n}` → regex page parse nhóm `{n}` → `lockedCode = KHKK-N{n}`, đối chiếu đủ 3 nguồn BE+admin+user. +- **T2 (7/7) control-ÂM:** `KhkkN0` · `KhkkN9` · **`KhkkN03`** · `KhkkN10` · `khkkn1` · `"KhkkN1 "` · `KhkkN` — bị chặn ở CẢ 2 regex (regex CHUỖI, không `Number()`). +- **T3 (2/2)** control-âm cho chính T1: key bịa `AwV2_KhkkN9/N0` vắng ở cả 3 nguồn. +- **T4/T5/T6 (10/10)** D3=C — xem 3.5. + +**Anti-Goodhart** (`proof-control.mjs`, exit 0): áp ĐÚNG vị ngữ T4 và T5 lên ô **#7** (ô cố ý khoá + ép-false từ K3 S165) ⇒ **cả hai đều `false`**. Phép đo phân biệt được ô-sống ⟂ ô-khoá và bắt được ép-false; không phải luôn-luôn-PASS. + +### 3.5 Đối chiếu code-vs-spec W2a–h +| Task | Verdict | Bằng chứng | +|---|---|---| +| W2a parse kind | ✅ | `:302-306` regex chuỗi; queryKey giữ nguyên (9 panel chung 1 ô cache — khai tại `:300-301`) | +| W2b synthetic slice | ✅ **và là BẮT BUỘC** | BE `active = versions.FirstOrDefault(v => v.IsActive)` (`:210`) — với type-10 nay có **8 bản active song song** (BE lane đổi sang tắt **per-CODE** `:336-360`) ⇒ đọc `bucket.active` sẽ sai cho 7/8 panel. `history` xác nhận **KHÔNG lọc** `IsActive` (`definitions` `:118-134` chỉ lọc Type + IsUserSelectable) | +| W2c lockedCode | ✅ | signature 2 nơi · `defaultCode :733` · ô Mã `disabled :1020` · **POST `code: lockedCode ?? code` `:884`** (bất-biến theo CẤU TRÚC). Khớp khoá với vị ngữ `w.Code == request.Code` bên BE | +| W2d D3=C | ✅ **đúng danh-sách-chốt** | 6 ô `disabled={isKhkk}` + `checked={entry.…}` THẬT · #4 tooltip riêng + KHÔNG mờ · #7 giữ nguyên · **#8 `allowApproverFinalize` 0 chạm** (T4) · `levelFlagsPayload` 0 dòng đổi | +| W2e menuKeys ×2 | ✅ | 8 const khớp `MenuKeys.cs:127-134`; khối const 2 app **diff 0 dòng**, chỉ comment cố ý lệch | +| W2f ngưỡng CEO | ✅ | `disabled={isEdit \|\| isKhkk} :1052` + helper-text `:1055` + **POST `null` `:891`** | +| W2g auto-pin isActive | ✅ | `isActive` **CÓ THẬT** trong payload (`ToDto` `:176`) — không phải field bịa; 2 câu thông báo đổi sang nói ĐIỀU KIỆN (rỗng-vì-lọc ⟂ rỗng-vì-chưa-có) | +| W2h comment + tiêu đề | ✅ | subtitle gộp vào `description` (xem FLAG-1) | + +### 3.6 Mirror proof (Pattern 16-bis + SHA) +- `KhkkCreatePage.tsx` admin ⟂ user: `89dfa607061cd3d560dcbbdb8fbad157d38cae1786be3cd41a81bd8e9c1d1390` **BẰNG NHAU** (cặp `cp`, W2g). +- `types/khkk.ts` admin ⟂ user: `b26bf67492821b1003c3d523585e2ce563a26b04ef728867689911263e5a33d3` **BẰNG NHAU** — file **không sửa** ⇒ **đối chứng DƯƠNG** cho phép đo hash. +- **4-place:** ① page+types ✅ · ② `App.tsx:80` route `:typeCode` đã có (0 route mới) ✅ · ③ `menuKeys.ts` ×2 ✅ · ④ `Layout.tsx:188` staticMap **đã có sẵn từ K3 S164/S165** ⇒ chỗ-4 KHÔNG cần chạm (P8 đúng), regex Layout khớp regex page. +- **Lệch CÓ CHỦ ĐÍCH:** fe-user **không có** `ApprovalWorkflowsV2Page.tsx` + **0** nhánh `AwV2` trong `Layout.tsx` (màn cấu hình là của admin) ⇒ 8 const bên fe-user là mirror hằng-số thuần, không sinh menu. ## §4 — Nợ / FLAG cho lead -(chưa có) + +- 🔴 **FLAG-A (acceptance hỏng — cần sửa spec):** acceptance R-2 ghi *"`npm run build` ×2 app + **tsc 0-err**"*. Nếu ai chạy `npx tsc --noEmit` đúng nguyên văn thì **luôn xanh kể cả code sai** (§3.1). Đề nghị sửa acceptance thành `npx tsc -p tsconfig.app.json --noEmit`. Ảnh hưởng **mọi wave FE trước/sau**, không riêng S182. +- 🔴 **FLAG-B (spec tự mâu-thuẫn — đã chọn nhánh, xin lead ratify):** ô **#4 `allowReturnToDrafter`**. MỤC 2 dòng `d` (bảng thi-hành, có neo dòng) ghi *"hiển thị **state thật (thường TRUE)**"*; MỤC 3 bảng D3 ghi bản rút gọn *"#4 **forced-true**-disabled"*. Code đang theo **state thật** (`checked={entry.allowReturnToDrafter}`), vì: + (1) đo đĩa: mặc định `true` ở **4 lớp độc lập** — `ApprovalWorkflow.cs:129 = true` · EF `HasDefaultValue(true)` · DTO `:232/:465` · FE hydrate `?? true` (`:213`) ⇒ thực tế **vẫn hiện TICK**, thoả acceptance A2 *"ô #4 tick-disabled"*; + (2) hard-code `checked={true}` sẽ **nói dối** đúng ca hàng row có `false` — cùng class lỗi mà chính D3=C cấm ở 6 ô kia (*"CẤM ép false"*), chỉ đảo dấu. + ⇒ Đọc *"forced-true"* là **rút gọn hao nghĩa** của *"state thật (thường TRUE)"*. **Nếu lead thật sự muốn ép cứng `true`** thì nói 1 câu, sửa 1 dòng — nhưng nên biết là đánh đổi tính trung thực với DB. +- ⚠️ **FLAG-1 (P12, đã xử lý — không còn là nợ):** `@/components/PageHeader` **không có** prop `subtitle` (`title/description/actions`, cả 3 đều `ReactNode`). **Không thêm prop** — phụ đề nghiệp vụ gộp vào `description`. Lý do: PageHeader dùng chung toàn app, đẻ prop cho 1 trang là mở rộng API cho cả trăm call-site. (Bài S37, lặp lần 3 — mỗi lần lại tưởng có `subtitle`.) +- ⚠️ **Ngoài spec, đã khai:** `key={typeCode ?? 'all'}` trên `` (`:401`) — remount khi đổi nhóm; thiếu nó thì `cloneFrom/editTarget` còn trỏ bản N1 trong khi `lockedCode` đã sang N3 ⇒ POST đẻ `KHKK-N3` mang ruột N1. +- ⚠️ **Nợ nhận-thức (không chặn):** 8 panel nhóm + panel `/ContractSigningPlan` **dùng CHUNG 1 ô cache** (queryKey không có `khkkGroup` — cố ý, vì lọc client-side trên payload đã tải trọn). Invalidate sau khi lưu làm tươi cả 9. Nếu sau này BE nhận `code=` làm tham số **request** thì BẮT BUỘC thêm `code` vào queryKey, nếu không 9 màn dùng chung cache sai CÂM. +- ⚠️ **Chưa chạy (ngoài tay lane FE):** acceptance A1/A2b/A3/A4 là **UAT động** (bấm thật trên 8 leaf, sửa-tại-chỗ ⇒ 204, tạo v02 N1 kiểm 7 nhóm không mất badge). Lane này chỉ chứng được phần **tĩnh**. A3 phụ thuộc BE lane (tắt active per-CODE) — 2 nửa phải test CÙNG nhau. +- ✅ **Không nợ build/mirror:** 0 lỗi TS ×2 app · SHA-pair 2/2 · 4-place 4/4 · 27/27 proof + 3 control.