# review-synthesis — S157 · spec "KẾ HOẠCH KÝ KẾT HỢP ĐỒNG" (S6 + S7)

> 🔴 **SUPERSEDED @S159 08:41 — ĐỌC DÒNG NÀY TRƯỚC §4 VÀ §6.** Hai gap mà file này ghi là "còn hở" **ĐÃ ĐƯỢC VÁ TRONG CHÍNH PHIÊN VIẾT RA NÓ**: **H5** (`spec` W3 #8 nay pin `N ≥ 6` + 6 tên test; site cùng-lớp W1 #4 pin `N ≥ 2` + 2 tên) · **H6** (vá **4 site**: cơ-chế · nhãn bảng wave · `DbInitializer` W2 · dòng changelog).
> ⇒ **§4 và §6 giữ làm SỬ-KÝ trạng-thái lúc 08:26, KHÔNG còn là gap-list.** Đừng đi vá lại chỗ đã vá.
> *(H2 `harvest-curator` F-05 HIGH bắt được vì nó **đo LẠI giữa chừng** — đo lần 1 lúc ~08:40 thấy spec 45.158 B mtime 07-28T11:29, đo lần 2 lúc 08:43 thấy 48.621 B mtime 07-29T08:41:44. Stage ARC chạy **song song** với vòng V1 nên file bị vá giữa 2 phép đo. Bài: **một phép đo là ảnh chụp, không phải sự thật vĩnh viễn**.)*
> 🔸 Khai lệch nhỏ: H2 chốt H6 = **3/3 site** vì nó đo lúc 08:43; lead tìm ra **site thứ 4** (`DbInitializer` W2) sau đó. Con số đúng là **4**.

> **run-id:** `2026-07-28-S157-ke-hoach-ky-ket-hd` · phiên-LOGIC L7, window 4
> **Viết:** 2026-07-29 (retro-harvest @S159) — 🔴 **file này ĐÓNG stage S7** (*lead refute + synthesize → trình anh*), không chỉ là bản tóm tắt.
> **Đích chấm:** `spec-ke-hoach-ky-ket-hd-28-07-2026.md` (45.158 B) · commit `d7eaece`.
> Mọi trạng-thái "còn hở / đã vá" dưới đây **đo tươi trên đĩa 2026-07-29**, không chép từ HANDOFF.

---

## 0. Vì sao S7 treo, và nó treo ở đâu

Ledger `run.md` để `[ ]` cho **S6** (dòng *"S6 — `/fable-clone reviewer` ensemble chấm spec"*) và **S7** (dòng *"S7 — lead refute + synthesize → trình anh"*). Đối chứng đĩa:

> 🔧 **Cite đổi sang NEO VĂN BẢN @S159** (H2 F-06 + m#24): bản đầu dẫn `run.md:206-207`; số đó chết ngay sau khi lead tick ledger lúc 08:27 (S6 nở 2 dòng ⇒ S7 dời +1). **File được dẫn nằm trong CÙNG đợt sửa ⇒ đừng cite bằng `:NNN`.**

> 🔴 **F-04 (H2 bắt) — GIẢI QUYẾT XONG @S159, số đúng là 10:** bản đầu bảng dưới ghi *"+9 củng cố"*, chép theo thân bài `sub-review-wave-1.md:12`. Nhưng **nguồn tự mâu thuẫn với chính nó** — END-line `:288` ghi `10 cung-co`. Lead đếm ĐĨA: section `## Điểm CỦNG CỐ` (`:262`) có **đúng 10 mục, đánh số 1→10 liên tục** ⇒ **END-line ĐÚNG, thân bài SAI**. Đã sửa thành 10.
> 🔸 **Bẫy đo lộ ra khi đếm:** `grep -i 'củng cố'` trả **0 hit** trên heading `CỦNG CỐ` — `-i` KHÔNG case-fold đáng tin cho dấu tiếng Việt (`ủ`↔`Ủ`). Âm-giả này trông y hệt *"section không tồn tại"*, suýt khiến lead báo rằng H2 trỏ sai chỗ. Cùng họ `E-010`. **Đếm bằng `sed -n '<start>,$p' | grep -cE '^[0-9]+\. '`, đừng dựa `-i`.**

- **S6 ĐÃ CHẠY** — 4 file lăng kính tồn tại thật (26.561 + 23.202 + 16.496 + 17.366 B), commit `d7eaece` ghi rõ *"review 4 lăng kính"*. Ledger sai.
- **S7 CHẠY MỘT NỬA** — phần *refute* có thật (lead rà 6 HIGH của lăng kính 1, kết luận 4 phủ trọn / 2 còn hở) và phần *trình anh* đã đi qua `HANDOFF.md:8,10`. Cái thiếu là **bản hợp nhất 4 lăng kính ở một chỗ** — chính file này.

⇒ Nợ ở đây **không phải việc chưa làm**, mà là **kết quả nằm rải 5 file + 1 dòng HANDOFF, không ai gom**. Sàn-3 ① bắt đúng.

---

## 1. Bốn lăng kính — verdict nguyên văn

| # | Lăng kính | Verdict | Định lượng |
|---|---|---|---|
| 1 | **WAVE-PLAN + ACCEPTANCE** | 🔴 **`SUA-TRUOC-W1`** | **19 điểm: 6 HIGH · 8 MED · 5 LOW** (+**10** củng cố) |
| 2 | **TRUNG THỰC VỚI NGUỒN GỐC** | 🟡 `GO-WITH-FIXES` | chân chống **không sập**; hạ phạm vi 1 câu + vá bảng §1.7 (B1·B2·N1) |
| 3 | **SCHEMA 7 BẢNG** | 🟡 `GO-WITH-FIXES` | **5 HIGH phải đóng TRƯỚC W1** |
| 4 | **VERIFY CLAIM `file:line`** | 🟢 `SPEC §② VỮNG` | **39 ĐÚNG / 4 SAI / 5 không kiểm được** |

**Đọc chéo 4 verdict:** không lăng kính nào bác **lõi** spec. Cả 4 hội tụ vào cùng một hình dạng lỗi — **spec đúng hướng nhưng chưa đủ RĂNG**: acceptance không làm cho trượt được, bảng schema thiếu mắt xích im lặng, và một số câu khẳng định rộng hơn bằng chứng đỡ nó.

---

## 2. Từng lăng kính — cái đáng giữ

### 2.1 Lăng kính 1 — wave-plan (nặng nhất, và là lăng kính chặn)

Hai cáo buộc load-bearing:
1. **W1 và W2 chưa deploy độc lập được** như bảng khai.
2. **4 phép đo trụ cột** (policy · OR-of-N · test-count · dark-launch) **không thể làm cho trượt** kể cả khi implement sai.

🔴 Điểm (2) là loại lỗi nguy nhất trong cả run: acceptance **trông như đo** nhưng **thiếu răng** ⇒ wave sai vẫn PASS. Cùng họ với bài học S155 *"cơ-chế đúng, thứ đi qua nó không có"*.

### 2.2 Lăng kính 2 — trung thực với nguồn (ISO)

- ✅ **XÁC NHẬN "9 bước ISO ↔ 9 `ContractPhase` khớp 1:1"** — đếm tay Bảng 2, 9/9 khớp cả tên trạm lẫn thứ tự: `DangChon` · `DangSoanThao` · `DangGopY` · `DangDamPhan` · `DangInKy` · `DangKiemTraCCM` · `DangTrinhKy` · `DangDongDau` · `DaPhatHanh` (`src-QT-TRINH-KY-HD.txt:60-68`).
- ⚠️ **"ISO đi thẳng 1→2" — ĐÚNG nghĩa hẹp, BÁC nghĩa rộng.** Trong Bảng 2 thì đúng. Nhưng spec `:18` kết luận rộng hơn — *"Không có trong quy trình ISO đang ban hành"* — trong khi **chính bước 1 trỏ sang một quy trình khác chưa ai đọc**: `SOL-PRO-SP-001 Quy trình Cung ứng` (`:47`, `:60`).

🔴 **Hệ quả đúng mức:** kết luận *"khoảng trống nằm giữa ISO-1 và ISO-2"* **vẫn đứng** đối với văn bản trình ký. Cái phải sửa là **phạm vi của câu khẳng định vắng mặt**. Điểm CAO ở đây **không chặn W1-W2 về kỹ thuật** — nó chặn **tư cách văn bản** khi gửi owner với danh nghĩa *"đề xuất sửa ISO"*.

### 2.3 Lăng kính 3 — schema 7 bảng

Hình dạng ĐÚNG HƯỚNG (loose-Guid · `decimal(18,2)` · query-filter · FK Cascade/Restrict đều khớp twin thật). **5 HIGH làm migration/CQRS/FE sai IM LẶNG (build vẫn xanh):**
1. thiếu **bảng lịch-sử-transition** mà chính service được lệnh copy **có ghi vào**
2. thiếu đăng ký ở **3 site cross-module** `ApprovalWorkflowV2AdminFeatures`
3. thiếu **4 cột Changelog**
4. không khai **base-class** cho bảng #2–#7
5. **bộ số enum phase đụng khuôn FE** đang được copy

### 2.4 Lăng kính 4 — verify claim `file:line`

**39 ĐÚNG / 4 SAI / 5 không kiểm được.** 🔴 **Cả 4 cái SAI đều là lệch ANCHOR, 0 sai NỘI DUNG** — tức spec **nói đúng sự thật nhưng trỏ sai dòng**; 1 trong 4 trỏ **đường dẫn file KHÔNG TỒN TẠI** (implementer mở sẽ trượt).

Hai claim quyết-định-kiến-trúc **ĐÚNG, khớp từng dòng** — đây là 2 cái đỡ toàn bộ quyết định *"copy Contract, KHÔNG copy Proposal"*:
- **B.1** `ProposalFeatures.cs` phá OR-of-N
- `Pe_*` nằm **ngoài** `MenuKeys.All`

---

## 3. Lead refute độc lập — 4 claim load-bearing, verify trên ĐĨA (không tin return)

| Claim | Verdict | Bằng chứng |
|---|---|---|
| **B.1 Proposal-lite phá OR-of-N** | ✅ **THẬT** | `ProposalFeatures.cs` `SelectMany` flatten `:427-429` + `ElementAtOrDefault` **1 row** `:433` + so đúng **1** `ApproverUserId` `:439`; comment code **TỰ THÚ**: *"Lite version: assume 1 step per workflow"* |
| **slot enum 10 trống** | ✅ **THẬT** | `ApprovalWorkflow.cs:53-67` dừng ở `TravelRequest = 9` |
| **`Off_DeXuat` 4 key đều trong `All`; `Pe_*` sinh bằng factory NẰM NGOÀI `All`** | ✅ **THẬT** | `MenuKeys.cs:171` · factory `:150`/`:154` ⇒ **policy per-action không tồn tại** — bẫy claim đúng |
| **Mig cuối = 68** | ✅ khớp | `docs/STATUS.md` CURRENT STATE |

---

## 4. 🔴 DISPOSITION — 6 HIGH của lăng kính 1: 4 phủ trọn, **2 CÒN HỞ** (đo tươi 2026-07-29)

**Chứng chưa vá:** `spec-*.md` mtime **2026-07-28 11:29** · `HANDOFF.md` mtime **2026-07-28 20:44** ⇒ spec **không bị chạm ở S158**.

### ❌ H5 — acceptance test-count vẫn không có răng

`spec:353` (W3 acceptance #8) vẫn là: `dotnet test` → **562 + N mới**, 0 fail — **`N` thả tự do ⇒ `N=0` vẫn PASS**. Reviewer đòi **pin `N ≥ 6` + liệt tên test**.

🔴 **Phát hiện MỚI khi đo (chưa ai ghi):** đây là ca **vá một chỗ, sót chỗ cùng lớp**. Dòng `spec:284` (acceptance #4) **ĐÃ được vá** từ *"562 giữ nguyên"* → *"562 + số test mới"*, kèm chú thích tự phê *"= **0 bit**"*. Cùng một lỗ, **cùng một file**, vá một nửa. `grep -n '562'` tốn **1 lệnh** và lộ ngay — đúng bài `feedback_root_cause_over_symptom` (S122: *được-chỉ-1-chỗ ⇒ PHẢI grep cùng-lớp*).

### ❌ H6 — spec tự mâu thuẫn về dark-launch

`spec:224` vẫn giữ: *"**Dark-launch được bằng `IsVisible=0`** rồi bật sau"*.
`spec:289-290` **cùng file** đã đo-đĩa và **bác** cơ chế đó: filter **CHỈ theo `CanRead`**, `IsVisible` chỉ **pass-through** `:88`; `MenuDtos.cs:13` ghi thẳng *"fe-admin vẫn thấy"* ⇒ `IsVisible=0` **KHÔNG phải cơ chế dark-launch toàn cục**, chỉ tối với fe-user.

🔴 **Đo thêm — lỗ rộng hơn 2 dòng:** `spec:252` bảng wave vẫn xếp **W1 = "Schema + permission (dark-launch)"**, và `spec:443` liệt *"bỏ tiêu chí dark-launch sai cơ chế"* như việc **chưa làm**. ⇒ vá H6 phải chạm **≥3 site** (`:224` · `:252` · `:443`), không phải 1.

### ✅ Gate 5-ANCHOR — đã nhận, đã di-trú

Reviewer đề (`sub-review-claims-4.md:119`), lead nhận, ghi `spec:458`. Vì `grep -rn "5 anchor"` từng ra **0 hit** ở mọi bề mặt bền, gate đã được **di-trú lên `HANDOFF.md:8`** (lead-gap-auditor FLAG-4 @S158). Luật: *trước khi thi công **mỗi wave**, mở **5 anchor bất kỳ** của wave đó; **≥1 anchor trượt ⇒ chấm lại TOÀN BỘ anchor** của wave.*

---

## 5. Sự cố kỹ thuật trong run — 2 ca `#53`, khai đủ

Stage S3 (`/fable-real investigator-codebase`) chạy **3 lượt, 2 sự cố**, kết quả **PARTIAL-HONEST**:

| Lượt | Sự cố | Thiệt hại thật |
|---|---|---|
| 1 | **`skeleton-ruột-rỗng`** — 202K tok / 35 tool-use, đĩa chỉ **1.661 B** khung rỗng 4 mục `[PENDING]`; return garble `#53` | 🔴 **byte > 0 mà ruột trống** ⇒ guard *"verify byte tăng"* **KHÔNG bắt được** |
| 2 | (resume, cắt còn 2 mục) | ✅ §A + §B **CLEAN**, đĩa 1.661 → **23.085 B**, return khớp đĩa |
| 3 | **`engine-process-exit`** — tiến trình CLI thoát giữa chừng | đĩa **KHÔNG đổi** (23.085 B, mtime 10:55) ⇒ §C/§D **chưa từng được ghi**; **0 mất dữ liệu đã có** |

**Quyết định lead:** KHÔNG resume lần 3 — H21 ① cho phép, vì engine là **propose-only** còn **spec do LEAD ghi**; §A/§B chính là phần propose. §C (wave-plan) + §D do lead tự viết.

⇒ Củng cố `feedback_agent_return_garble_recover`: **ghi-đĩa-trong-lúc-làm = CẦN, KHÔNG ĐỦ** — phải verify **RUỘT có chữ**, không chỉ byte > 0.

---

## 6. Kết luận trình anh (đây là phần S7 nợ)

**Spec KHKK đủ tư cách làm nền thi công, với 2 điều kiện chưa thoả:**

1. ❌ **H5** — pin `N ≥ 6` + liệt tên test ở `spec:353` *(và grep `562` để không sót site thứ 3)*
2. ❌ **H6** — chọn **một phía** cho dark-launch, sửa đồng bộ `:224` · `:252` · `:443`

Cộng 5 HIGH schema (lăng kính 3) + 4 anchor lệch (lăng kính 4) + hạ phạm vi 1 câu ISO (lăng kính 2) — **tất cả đều là sửa văn bản, không sửa kiến trúc**. Lõi spec **không lăng kính nào bác**.

🔸 **Không chặn W1-W2 nhưng phải biết:** 5 câu thiết kế (Q3 · Q6 · Q11 + O-Q1 · O-Q2) chờ anh · nguồn thứ 4 `SOL-PRO-SP-001` **chưa ai đọc** · 2 đường kết thúc sớm W3 (`AllowApproverFinalize` · `CeoApprovalThreshold` — anh từng phán **PHÁ VỠ** @S155).
🔴 **Wave 5 chạm Hợp đồng ⇒ PHẢI hỏi lại anh trước khi chạy** — lỗ hổng an ninh HĐ đang **treo có chủ đích** (*"chỗ hợp đồng cứ từ từ"*).

---

<!-- END review-synthesis · S157 · TOTAL=4 lăng kính + 2 gap MỞ (H5·H6) · retro-harvest @S159 2026-07-29 -->
