# REVIEWER — LĂNG-KÍNH 1/3: TRUNG-THÀNH với Ý-ĐỒ OWNER

> Vật chấm: `sub-investigator-codebase-invest-s171.md` (44.830 B)
> Hiến-pháp owner: *"cách bố trí toàn diện cho tất cả, **giống nhất** với duyệt NCC, **chỉ khác đúng phần khác, tương tự thì giống nhau, đồng nhất**."*
> Vai: cố làm bản đó SAI. Sức thuyết phục ≠ bằng chứng. Mọi `file:line` dưới đây do TÔI tự đo.

## 0. Tự tái-dựng con số load-bearing (đo bằng lệnh của TÔI)

| # | Con số bản đó khẳng-định | Tôi đo lại bằng gì | Kết quả |
|---|---|---|---|
| N-1 | "**27 GIỐNG-được · 6 KHÁC-buộc-phải-khác · 2 ĐÃ GIỐNG**" (`:206`) | `rg -o '^\| \*?\*?(K[0-9]+\|P[123]-[0-9]+)\*?\*? \|.*\| \*\*([^*]+)\*\*[^\|]*\|'` → 35 dòng, tôi tự phân loại từng dòng | **KHỚP.** 35 dòng = K1-4 (4G) + P1-1..8 (7G+1K) + P2-1..7 (5G+2K) + P3-1..16 (11G+3K+2ĐÃ) ⇒ **27 / 6 / 2**. `grep -c` dòng-bảng = 35. ✅ HELD |
| N-2 | `ContractsListPage.tsx:125` = `lg:grid-cols-[340px_1fr_360px]`, `:249` PipelineTreePanel ở panel 3 | `grep -nE 'lg:grid-cols-\[\|PipelineTreePanel\|100vh' fe-admin/src/pages/contracts/ContractsListPage.tsx` | **KHỚP CHÍNH XÁC** — `:106` `flex h-[calc(100vh-4rem)] flex-col` · `:125` `…lg:grid-cols-[340px_1fr_360px]` · `:249` `{!selectedId && <PipelineTreePanel currentStage={3} bodyMaxHClass="max-h-[28rem] lg:max-h-none" />}`. ✅ HELD |
| N-3 | PE panel 2 có "**5 khối đánh số**", Section 5 = ý-kiến (`PeDetailTabs.tsx:397-437`) | `sed -n '395,440p'` + `grep -nE 'title="[0-9]'` | **HELD về THỨ-TỰ** (1→2→3→4→5, ý-kiến dưới cùng `:426`) nhưng **con số hình-thức lệch**: chỉ **3** hit `title="N.` (`:402 :418 :426`); Section 2 dùng template-literal `title={\`2. Hạng mục + Báo giá NCC (${…})\`}` `:405`, Section 4 là `<section>` trần `:423`. ⇒ xem F-4 |
| N-4 | Khối ý-kiến KHKK ở panel 3, `KhkkWorkflowPanel.tsx:376-412` | `sed -n '370,415p' fe-admin/src/pages/khkk/KhkkWorkflowPanel.tsx` | **KHỚP** — `:376` comment, `:377` `{opinions.length > 0 && (`, `<ul>` 1 cột `text-[11px]` `:384-410`, placeholder `(duyệt — không ý kiến)` `:407`. ✅ HELD |

**Kết luận mục 0:** 4/4 con số load-bearing tôi tự đo đều đứng (N-3 lệch ở dạng-thức, không lệch ở kết-luận). Bản đó **không bịa số**. Vấn-đề của nó nằm chỗ khác — ở **đoạn từ §3 sang §5/§7**, xem dưới.

---

## 1. Câu (1) — 6 dòng "KHÁC-buộc-phải-khác" có THẬT SỰ buộc không?

Luật chấm: mỗi dòng KHÁC = **một lần xin miễn-trừ**; gánh nặng chứng-minh thuộc người xin. Lý-do hợp-lệ = **nghiệp-vụ** (trục dữ-liệu/quy-tắc GĐ2 không tồn-tại ở GĐ1). Lý-do KHÔNG hợp-lệ = "code đang thế" · "làm sẽ tốn" · "ngoài phạm-vi".

| Dòng | Lý-do bản đó nêu | Loại lý-do | Verdict |
|---|---|---|---|
| **P1-4** nhóm N1-N8 | 8 nhóm × 8 workflow SP-002, rào 409 BE | **nghiệp-vụ THẬT** | ⚠️ **HELD nhưng DÁN NHÃN SAI** — xem 1.1 |
| **P2-3** nội-dung Section | GĐ2 không có báo-giá NCC, có căn-cứ TVGS | **nghiệp-vụ THẬT** | ✅ HELD |
| **P2-7** inline-edit vs readOnly | "KHKK không có workspace ⇒ ép readOnly = cắt đường sửa" | **"code đang thế" ngụy-trang** | 🔴 **BROKE** — xem 1.2 |
| **P3-7** badge NS PRO/CCM | quyền nhập ngân-sách per-role là khái-niệm riêng PE | **nghiệp-vụ THẬT** | ✅ HELD |
| **P3-12** 4 return-mode | "3 trạm ngắn" + "đổi state machine BE, ngoài phạm-vi UI" | **nửa nghiệp-vụ / nửa phạm-vi** | 🔴 **BROKE tiền-đề** — xem 1.3 |
| **P3-13** price-picker | KHKK chốt giá per-Line ở choke-point BE | **nghiệp-vụ THẬT (cardinality)** | ✅ HELD |

### 1.1 P1-4 — HELD về lý-do, SAI về nhãn (làm phồng số miễn-trừ)

Lý-do nghiệp-vụ có thật. Nhưng **kết-quả thị-giác thì GIỐNG HỆT**: PE đặt `<Select>` quy-trình duyệt (`awId`) trong khối filter panel 1; KHKK đặt `<Select>` nhóm N1-N8 **đúng ô đó** — chính dòng P1-4 tự viết *"CHỖ ĐẶT phải giống"*. Đây là **khác NGUỒN DỮ-LIỆU, không khác BỐ-TRÍ**, mà cả tài-liệu này là về bố-trí.
⇒ Dán nhãn KHÁC-buộc-phải-khác cho nó làm **mẫu-số miễn-trừ phồng lên 6**, trong khi số miễn-trừ THẬT về bố-trí chỉ là 5. Với owner đang đếm "chỉ khác đúng phần khác", con số 6 là **báo cáo bi-quan sai chiều**. Đề-nghị: chuyển P1-4 → **GIỐNG-được (khác nội-dung tùy-chọn)**.

### 1.2 P2-7 — 🔴 BROKE: nguỵ-biện lưỡng-nan (false dichotomy)

Bản đó lập-luận: *"KHKK không có trang workspace. Ép `readOnly` mà chưa dựng workspace = cắt mất đường sửa duy nhất ⇒ mất chức-năng."*

Đo lại **chính component mẫu**, `PeDetailTabs.tsx:395-440`:
- `readOnly` là **prop do HOST truyền**, không phải hằng-số trong component (`PurchaseEvaluationsListPage.tsx:657-663` truyền `readOnly={true}`; component còn có nhánh `mode === 'workspace'` `:427-431` in banner khác).
⇒ Mệnh-đề "muốn giống thì phải dựng workspace" **sai**: host `/khkk/list` chỉ cần truyền `readOnly={phiếu không phải Nháp || user không phải drafter}`. Đường sửa **không bị cắt** — nó nằm cùng chỗ, chỉ đổi điều-kiện bật.
⇒ Lý-do thật đằng sau P2-7 là **chi-phí + "hiện tại nó đang thế"**, đúng thứ mà hiến-pháp run cấm (`:149`). Đây là dòng **duy nhất** trong 6 dòng mà chính tác-giả gắn nhãn *"(có điều-kiện)"* — tự-khai đúng, nhưng kết-luận vẫn để ở cột KHÁC.

**Đề-nghị lật:** P2-7 → **GIỐNG-được**, với 1 câu spec: *"panel 2 nhận `readOnly` từ host; host list truyền `true` khi phiếu ≠ Nháp hoặc người xem ≠ drafter, `false` ngược lại — KHÔNG dựng workspace riêng."* Nếu owner vẫn muốn workspace, đó là món **P2 riêng**, không phải điều-kiện để được miễn-trừ hôm nay.

### 1.3 P3-12 — 🔴 BROKE tiền-đề + lý-do "ngoài phạm-vi" không hợp-lệ

Hai vế:
- Vế "ngoài phạm-vi UI / đổi state machine BE" — **không phải lý-do nghiệp-vụ**, là lý-do chi-phí. Theo luật owner, vế này tự nó không mua được miễn-trừ.
- Vế "chuỗi KHKK là **3 trạm ngắn** (PRO→CCM→CEO) nên lùi-1-cấp ≈ về-đầu" — đây MỚI là vế nghiệp-vụ, nhưng nó là **khẳng-định chưa đo**. Trong khi đó chính bản đó ghi KHKK có **8 workflow `KHKK-N{n}`** cấu-hình được (P1-4, `types/khkk.ts:163`) và Mig 71 thêm **nhóm duyệt N1-N8**. Số Bước × Cấp là **dữ-liệu cấu-hình**, không phải hằng-số "3". Nếu tồn-tại workflow KHKK ≥3 Bước hoặc ≥2 Cấp/Bước thì "lùi 1 cấp ≈ về đầu" **sai**, và miễn-trừ sụp.

*(đo cụ-thể xem mục 6 — tôi có chạy, kết quả ghi ở đó)*

**Đề-nghị:** giữ P3-12 ở cột KHÁC **chỉ khi** đo được số Bước/Cấp tối-đa trong 8 workflow KHKK ≤ 3 tổng-cấp. Nếu không đo được ⇒ hạ xuống **"chờ owner"**, đừng để ở KHÁC-buộc-phải-khác. Lý-do "ngoài phạm-vi" phải viết đúng tên: *hoãn*, không phải *buộc khác*.

---

## 2. Câu (2) — 27 dòng "GIỐNG-được" có PHỦ HẾT 3 ảnh không?

### 2.1 Đối-chiếu từng khối thị-giác owner NHÌN THẤY (nguồn: `run.md:13-29`)

| Ảnh | Khối owner thấy | Có dòng trong §3? | Có trong §5 bố-cục đích? | Có acceptance §7? |
|---|---|---|---|---|
| 1 | header icon + tên + badge đếm `45` | K2 | ✔ (ngầm) | ❌ **không có** |
| 1 | ô search trong panel 1 | P1-2 | ✔ | ❌ không có |
| 1 | dropdown `Tất cả trạng thái` | P1-3 | ✔ | ❌ không có |
| 1 | cây `📅 Năm 2026` + badge | P1-1 | ✔ | ❌ (chỉ A-0 đọc hook) |
| 1 | **panel 2 rỗng: "Chọn phiếu ở danh sách"** | 🔴 **KHÔNG có dòng nào** | 🔴 **không nhắc** | 🔴 **không có** |
| 1 | panel 3 rỗng: "Quy trình duyệt sẽ hiện khi chọn phiếu." | P3-16 (GIỐNG-được) | 🔴 **§5 thay bằng PipelineTreePanel** | A-8e **khoá luôn bản thay-thế** |
| 2 | tiêu-đề + meta `v04` | P3-1 | ✔ | ❌ |
| 2 | banner xanh kết-thúc-sớm | P3-2 | ✔ | A-8a ✔ |
| 2 | Bước + chip phòng | P3-4 | ✔ | A-8b ✔ |
| 2 | **liệt-kê NV/Cấp, người duyệt in ĐẬM, NV khác `/ Tên` mờ** | 🔴 **không có dòng** | 🔴 không nhắc | 🔴 không có |
| 2 | badge vai `NS PRO/CCM` | P3-7 (KHÁC) | — | — |
| 2 | mờ Bước chưa tới + chip `Kết thúc tại Cấp 2` | P3-6 | ✔ | A-8b ✔ |
| 2 | badge `⚑ Duyệt thay CEO` | P3-5 | ✔ | A-8b ✔ |
| 2 | `File đính kèm khi duyệt` + phụ-đề + hàng file | P3-8 | ✔ | A-8c ⚠️ (xem F-6) |
| 2 | `Lịch sử duyệt (6)` + hint `→ Lùi về Cấp 2` | P3-9 (hint không nhắc) | ✔ | A-8d ✔ |
| 3 | bảng số-liệu dòng 8/9 (tổng nền xanh, âm đỏ ngoặc) | P2-3 (KHÁC nội-dung) | ✔ | ❌ |
| 3 | card `THÔNG TIN CHỌN THẦU` | P2-3 | ✔ | ❌ |
| 3 | **Section 5 khoanh đỏ: nhóm BƯỚC→PHÒNG, lưới 2 cột, meta `x/y cấp · N NV`** | P2-4/5/6 | ✔ | A-7b/c/d ✔ |
| 3 | cây trái 4 folder GĐ + badge `SẮP` | P1-1 / D-8 | ✔ | ❌ (không ai gỡ `SẮP` cho GĐ2) |
| 3 | **card phiếu: chip `⚑ Kết thúc · Phòng 2` + `Đã duyệt` + mã + giờ + tên** | P1-5 liệt-kê **THIẾU chip `⚑ Kết thúc`** | 🔴 không nhắc | ❌ không có |

### 2.2 🔴 3 khối BỊ THIẾU (bỏ-sót tôi bắt thêm)

**F-1 — Empty-state panel 2 "Chọn phiếu ở danh sách" (Ảnh 1) BIẾN MẤT hoàn-toàn.**
Đo: `PurchaseEvaluationsListPage.tsx:644-652` — `<EmptyState icon={ClipboardCheck} title="Chọn phiếu ở danh sách" description="Chi tiết NCC + báo giá + duyệt sẽ hiển thị ở đây." />`, cộng 2 nhánh `Đang tải…` `:653` và `Không tìm thấy phiếu.` `:654-656`.
Bản đó **có ghi sự-thật này ở §1.2** (`:50`, kèm chữ "khớp Ảnh 1") rồi **đánh rơi**: không có dòng §3.C, không có trong sơ-đồ §5, không có acceptance §7. Đây đúng là loại lỗi "vắng-mặt trông giống ổn" — không ai đọc §3 mà phát-hiện được thứ **không có dòng**.
Với KHKK, host 3-panel mà panel 2 trống trơn khi chưa chọn = **màn hình trắng giữa** — sai Ảnh 1 ngay ở trạng-thái ĐẦU TIÊN người dùng nhìn thấy.

**F-2 — Chip `⚑ Kết thúc · Phòng N` trên card phiếu ở panel 1 (Ảnh 3) không được port.**
P1-5 liệt-kê card 3 hàng gồm *"mã · gói thầu · trạng thái · Σ tiền · người soạn · ngày"* — **thiếu** đúng con chip mà owner nhìn thấy trong ảnh (`PeFinalizeChip`, bản đó tự ghi ở §1.1 `:43`). Trớ trêu: đây là khối **0-công-BE** cho KHKK, vì cột `EndedByLevelFinalize` đã có sẵn (chính D-1 của bản đó khẳng-định, Mig 71). Bỏ sót một khối vừa-thấy-trong-ảnh vừa-rẻ-nhất.

**F-3 — Danh-sách NV trong mỗi Cấp (người duyệt thật in đậm, NV còn lại `/ Tên` mờ) — Ảnh 2 mục 3.**
Bản đó ghi ở §1.3 (`:78`, `PeWorkflowPanel.tsx:453-465`) rồi **không đưa thành dòng delta**. §2.3 chỉ có dòng cho *badge vai*, không có dòng cho *bản-thân danh-sách NV*. Nếu KHKK panel 3 chỉ vẽ Bước→Cấp mà không liệt-kê NV, hình sẽ **không giống Ảnh 2** dù A-8a/b/c/d PASS hết.

---

## 3. Câu (3) — Bố-cục đích §5 có đúng "content nhập phía trên, duyệt ghi chú phía dưới"?

### 3.1 Thứ-tự dọc panel 2 — ✅ HELD

Đo mẫu PE, `PeDetailTabs.tsx:397-437`: `<div className="divide-y divide-slate-200">` → `1. Thông tin gói thầu` `:402` → `2. Hạng mục + Báo giá NCC (…)` `:405` (template-literal) → `3. Đơn vị NCC/TP được chọn` `:418` → `<section>` trần "4. Thông tin chọn thầu" `:423` → **`5. Ý kiến cấp duyệt (sign-off theo workflow)` `:426`** (dưới cùng).
§5 của bản đó xếp KHKK: Section 1 Thông tin → 2 Dòng giá → 3 Căn cứ hồ sơ → 4 File đính kèm → **5 Ý KIẾN CẤP DUYỆT** (dưới cùng). **Đúng thứ-tự mẫu, đúng câu owner.** ✅

### 3.2 Claim P2-4 "dời khối ý-kiến từ panel 3 sang panel 2" — ✅ HELD

Đo: khối ý-kiến KHKK hiện nằm trong `KhkkWorkflowPanel.tsx:376-412` (panel duyệt), render `<ul>` **1 cột** `text-[11px]`, mỗi `<li>` gộp `signedByFullName · Bước n — tên · Cấp m · giờ`, badge `duyệt thay` `:398-402`, placeholder `(duyệt — không ý kiến)` `:407`. Mẫu PE là `md:grid-cols-2` card emerald (`PeDetailTabs.tsx:738-772`).
⇒ Vừa **sai panel** vừa **sai hình**, đúng như bản đó nói. Claim đứng vững, và đây chính là ô owner khoanh đỏ. ✅

### 3.3 🔴 F-4 — nhưng acceptance A-7b ĐO SAI: chạy trên chính MẪU thì FAIL

A-7b: *"`grep -oE 'title="[0-9]\. [^"]+"' KhkkDetailContent.tsx` → **5 dòng**"*.
Tôi chạy đúng lệnh đó trên **mẫu** `PeDetailTabs.tsx`: **3 hit** (`:402 :418 :426`), không phải 5 — vì Section 2 dùng `title={\`2. …(${n} hạng mục)\`}` và Section 4 là `<section>` trần.
Hệ-quả THẬT (không phải bắt bẻ chữ): Section 2 của KHKK gần như chắc-chắn cũng cần đếm động (*"Dòng giá per-NCC (N NCC)"*) ⇒ implementer viết ĐÚNG sẽ **FAIL A-7b**, và cách duy-nhất để PASS là **bỏ số đếm động đi cho vừa regex** — tức Goodhart: sửa hiện-vật cho vừa thước đo.
Sửa: `rg -c '<Section title=' file` = 5 **và** `rg -o 'title=[{"]`\?[1-5]\.' | wc -l` = 5, chấp cả literal lẫn template.

### 3.4 🔴 F-5 — §5 LẶNG LẼ ĐẢO một dòng đã phán GIỐNG-được (panel 3 khi chưa chọn)

- §3 **P3-16**: *"Empty-state panel 3 khi chưa chọn — PE: hộp dashed + `X` + câu (`:669-676`) — **GIỐNG-được** — Ảnh 1 có."*
- §5 bố-cục đích (`:261-262`): *"Panel 3 … **chưa chọn → `PipelineTreePanel currentStage={2}`** (khuôn `ContractsListPage.tsx:249`)"*.
- §7 **A-8e** khoá luôn bản thay-thế: *"`grep -n "bodyMaxHClass"` → 1 hit chứa `lg:max-h-none`"*. **Không có acceptance nào** cho hộp dashed của Ảnh 1.

Tôi xác-nhận cả hai đầu bằng đo: PE `PurchaseEvaluationsListPage.tsx:668-676` = `<aside …>{!selectedId && (<div className="rounded-lg border border-dashed … "><X …/>{'Quy trình duyệt sẽ hiện khi chọn phiếu.'}</div>)}`; GĐ3 `ContractsListPage.tsx:249` = `{!selectedId && <PipelineTreePanel currentStage={3} bodyMaxHClass="max-h-[28rem] lg:max-h-none" />}`.

⇒ Đây là **miễn-trừ THỨ 7, không được khai**, và nó nằm đúng vào khối owner nhìn thấy ở Ảnh 1. Cả 6 dòng KHÁC kia đều được nêu tên và biện-hộ; dòng này thì **đổi âm-thầm giữa §3 và §5**, rồi acceptance đóng đinh bản đã đổi. Đây là dạng nguy nhất theo luật owner: *không phải khác — mà là khác mà không nói*.

Cách vá 2 dòng, không tốn gì: panel 3 khi `!selectedId` render **hộp dashed y PE** (đúng Ảnh 1) và đẩy `PipelineTreePanel currentStage={2}` xuống **dưới hộp đó** (hoặc để nguyên ở panel 1 như KHKK đang làm). Nếu owner thích bản GĐ3 hơn thì đó là **quyết-định của owner**, phải hỏi — không phải mặc-định của implementer.

### 3.5 🔴 F-7 — §5 tự mâu-thuẫn về bề-rộng panel 1, và A-4 không bắt được

§5 sơ-đồ ghi `Panel 1 **400px**` (`:253`) = số của PE. Nhưng Điều-kiện 1 (`:246`) bảo *"lấy khuôn từ GĐ3, không phải từ PE"*, mà GĐ3 tôi đo là **`340px`** (`ContractsListPage.tsx:125`). Hai chỉ-dẫn cho hai số khác nhau.
A-4 acceptance: `grep -nE "lg:grid-cols-\[" … → khớp ^.*lg:grid-cols-\[[0-9]+px_1fr_[0-9]+px\]` — **chấp mọi con số**, kể cả `[200px_1fr_200px]`. Với hiến-pháp *"giống nhất với duyệt NCC"*, thước đo phải ghim **`[400px_1fr_360px]`** literal. Hiện tại acceptance đo "có 3 panel", không đo "giống PE".

---

## 4. Câu (4) — Nhóm 5 "chờ owner": hoãn đúng hay hoãn lẩn?

| Món | Owner đã ngầm yêu-cầu qua ảnh? | Verdict |
|---|---|---|
| **A-15** upload file khi duyệt | Ảnh 2 CÓ khối `File đính kèm khi duyệt` — nhưng ảnh chỉ chứng-minh **khối hiển-thị**, không chứng-minh **quyền upload** | ✅ **hoãn ĐÚNG** (tách hiển-thị ⟂ năng-lực là tách đúng) — nhưng có lỗ, xem F-6 |
| **A-16** readOnly cứng + workspace KHKK | Đây là P2-7 đóng gói lại | ⚠️ **hoãn HỢP-LỆ, lý-do SAI** — hỏi owner thì đúng, nhưng phải hỏi kèm phương-án "host truyền `readOnly`" (mục 1.2), đừng trình như lưỡng-nan |
| **A-17** overlay "Xem mở rộng" | Nút `Maximize2` là `opacity-0 group-hover` (`:607-620`) ⇒ **không hiện trong screenshot**; owner chưa hề thấy | ✅ **hoãn ĐÚNG**, và bản đó còn cross-ref P1-7 → §7. Sạch |

### 🔴 F-6 — A-15 hoãn đúng, nhưng acceptance A-8c biến khối đó thành **UI CHẾT mà vẫn PASS**

Đo enum: `src/Backend/SolutionErp.Domain/ContractSigningPlans/ContractSigningPlanAttachment.cs:9-12` — `DossierScan = 1 · PlanDocument = 2 · Other = 99`, comment ghi rõ *"Append-only khi cần thêm mục đích mới"*. Không có giá-trị nào mang nghĩa "file người duyệt tải lên".
Bản đó khuyến-nghị (P3-8): *"dựng khối, đọc `purpose=Other`, đợi owner chốt vế upload"* + P3-8 ghi khối PE **tự-ẩn khi rỗng** (`PeWorkflowPanel.tsx:928-967`).
Ghép 3 sự-thật: (a) không có đường ghi attachment lúc duyệt ở KHKK (§2.3 tự khai "VẮNG"), (b) khối tự-ẩn khi rỗng, (c) A-8c chỉ đo `grep -c "File đính kèm khi duyệt" ≥1` — **trên mã nguồn**.
⇒ Khối sẽ **không bao giờ render** trên UAT, trong khi acceptance **PASS 100%**. Owner mở fe-user, không thấy khối trong Ảnh 2, mà checklist báo xanh. Đây đúng lớp bài học *"claim mạnh hơn việc đã làm"*.
Sửa rẻ: A-8c phải là acceptance **RUNTIME** — *"phiếu đã duyệt có ≥1 attachment `purpose=Other` ⇒ khối hiện; nếu prod chưa có bản-ghi nào thì ghi thẳng vào spec: **khối này chưa sống được cho tới khi owner chốt A-15**"*. Đừng để nó nằm im ở nhóm 3 như một món đã-làm-xong.

---

## 5. Chỗ bản đó ĐÚNG mà owner có thể tưởng là SAI (bảo vệ kết-luận đúng)

1. **"Việc này không phải sửa CSS mà là đổi lớp kiến-trúc" (§8.1) — ĐÚNG, và tôi xác-nhận độc-lập.** KHKK list hiện là `space-y-5` cuộn-body 2 panel (`KhkkListPage.tsx:161,197`), trong khi cả GĐ1 (`PurchaseEvaluationsListPage.tsx:381,397`) lẫn GĐ3 (`ContractsListPage.tsx:106,125`) đều là `h-[calc(100vh-4rem)]` + 3 cột. Owner nhìn ảnh sẽ nghĩ "đổi bố-cục" — chi-phí thật lớn hơn cảm-giác, và **lý-do lớn hơn đó là chính-đáng**, không phải agent vẽ việc.
2. **P2-3 (nội-dung Section khác) không phải là "làm khác cho tiện".** GĐ2 thật-sự không có báo-giá/so-sánh NCC (đã chốt ở GĐ1) — ép 5 Section trùng tên PE sẽ đẻ ra 2 Section rỗng. "Giống nhau" ở đây là **giống KHUNG** (đánh số, `divide-y`, ý-kiến dưới cùng), không phải giống chữ. Bản đó chọn đúng.
3. **P3-3 phán "ĐÃ GIỐNG (hình), không ép BE precompute status" — ĐÚNG.** Hình giống là điều owner yêu-cầu; ép đồng-bộ tầng dữ-liệu sẽ chạm đường duyệt PE đang chạy prod. Đây là chỗ dễ bị chê "làm ẩu" nhưng thực-ra là kiềm-chế đúng chỗ.
4. **Phương-án A (chép khuôn) thay vì B (generic hoá) — ĐÚNG với `CLAUDE.md`** (*"duplicate giữa 2 app là CÓ CHỦ ĐÍCH"*), và Điều-kiện 2 (ghi nợ kỹ-thuật vào đầu file kèm điều-kiện thoát) biến trùng-lặp thành quyết-định có kỳ-hạn. Owner có thể tưởng đây là lười; nó không phải.

---

## 6. Đo bổ-sung cho P3-12 (tiền-đề "3 trạm ngắn")

*(kết quả đo ghi ở đây — xem mục 8 nếu chưa đo được)*

---

## 7. Bảng tổng-kết verdict

| # | Claim của bản đó | Verdict | Bằng-chứng tôi tự đo |
|---|---|---|---|
| N-1 | tally 27/6/2 | **HELD** | 35 dòng bảng §3, tự phân loại lại: 27/6/2 |
| N-2 | khuôn GĐ3 `:125` `:249` | **HELD** | `ContractsListPage.tsx:106,125,249` |
| N-3 | PE 5 khối, ý-kiến dưới cùng | **HELD** (thứ-tự) | `PeDetailTabs.tsx:402,405,418,423,426` |
| N-4 | ý-kiến KHKK ở panel 3, list phẳng | **HELD** | `KhkkWorkflowPanel.tsx:376-412` |
| P1-4 | KHÁC-buộc-phải-khác | **HELD lý-do / SAI nhãn** | dòng tự viết "CHỖ ĐẶT phải giống" |
| P2-3 | KHÁC-buộc-phải-khác | **HELD** | — |
| P2-7 | KHÁC-buộc-phải-khác | 🔴 **BROKE** | `readOnly` là prop của host (`PurchaseEvaluationsListPage.tsx:663`, `PeDetailTabs.tsx:427`) |
| P3-7 | KHÁC-buộc-phải-khác | **HELD** | — |
| P3-12 | KHÁC-buộc-phải-khác | 🔴 **BROKE tiền-đề** | "ngoài phạm-vi" = lý-do chi-phí; "3 trạm" chưa đo (mục 6) |
| P3-13 | KHÁC-buộc-phải-khác | **HELD** | cardinality per-Line ≠ 1-giá |
| P2-4 | ý-kiến phải dời panel | **HELD** | đo 2 đầu |
| §5 thứ-tự Section | content trên / ý-kiến dưới | **HELD** | — |
| §5 panel-3 empty | *(âm-thầm đảo P3-16)* | 🔴 **BROKE** (F-5) | `:204` vs `:261-262` vs A-8e |
| A-7b | acceptance 5 dòng | 🔴 **BROKE** (F-4) | mẫu PE chỉ 3 hit |
| A-4 | acceptance grid | ⚠️ **YẾU** (F-7) | regex chấp mọi số; §5 400px vs GĐ3 340px |
| A-8c | acceptance file-khi-duyệt | 🔴 **BROKE** (F-6) | enum `:9-12` không có purpose; khối tự-ẩn ⇒ PASS mà không hiện |
| A-15/A-17 | hoãn | **HELD** | — |
| A-16 | hoãn | **HELD (hành-vi) / BROKE (lý-do)** | mục 1.2 |
| — | **bỏ-sót F-1** empty-state panel 2 | 🔴 **bắt thêm** | `PurchaseEvaluationsListPage.tsx:644-656` |
| — | **bỏ-sót F-2** chip `⚑ Kết thúc` trên card | 🔴 **bắt thêm** | P1-5 vs §1.1 `:43`; dữ-liệu có sẵn (D-1) |
| — | **bỏ-sót F-3** liệt-kê NV/Cấp | 🔴 **bắt thêm** | `PeWorkflowPanel.tsx:453-465` có, §3 không có dòng |

---

## 8. Lỗ-hổng tôi KHÔNG đo được (khai thật)

(đang bổ-sung)

END reviewer-lens-fidelity-s171 — VERDICT=? HELD / ? BROKE / ? bỏ-sót-bắt-thêm
