# ship-synthesis — cây 4-folder GĐ dưới từng gói thầu (S162, 2026-07-30)

VERDICT: SHIP — build ×2 EXIT 0 · TSC 0 · SHA-pair 6/6 · reviewer PASS-WITH-FLAGS (0 blocker) · 5/8 flag vá trước ship, 2 giới-hạn khai thẳng, 1 sửa-memory.

## Lệnh + 2 quyết owner
Lệnh anh 30-07 sáng (mid-turn, screenshot khoanh đỏ dải 4 GĐ → cây trái trang Duyệt NCC): "Tạo folder: Duyệt NCC / Kế hoạch Hợp đồng. / Duyệt Hợp đồng / Hợp đồng cứng." AskUser: **(1) folder DƯỚI TỪNG GÓI THẦU · (2) áp cả các trang GĐ khác.** Nhãn folder VERBATIM lời anh (GĐ2 "Kế hoạch Hợp đồng" ≠ strip "Kế hoạch ký kết HĐ" — cố ý, lời-mới-nhất-thắng, 1 lệnh đổi được).

## Cái ship
- 3 file MỚI ×2 app: `components/pipeline/PipelineStageFolders.tsx` (4 folder `<details>`, folder trang hiện tại mở sẵn, locked/failed/loading/truncated/hideEmpty) · `hooks/usePipelineStages.ts` (permission-gate → 2 index query key mới `pipeline-khkk-index`/`pipeline-contract-index` pageSize 200 → `buildStages()` nối GĐ2 qua `khkk.purchaseEvaluationId`, GĐ3 qua `pe.contractId`, GĐ4 = hasSealedCopy) · `components/pipeline/PipelineTreePanel.tsx` (panel cây trái trang GĐ2/GĐ4).
- 3 trang sửa ×2 app: PE list (folder dưới WorkItemGroup — khối `<li>` phiếu 0 dòng xoá, reviewer xác nhận từng hunk) · KhkkListPage (lưới 19rem + panel, `currentStage=2`) · HardCopiesPage (`currentStage=4` + F-7 invalidate index).
- Toàn bộ THUẦN FE: 0 API mới · 0 migration · 0 đụng menu/seeder (#84) · 0 đụng strip · 0 đụng BE.

## Chuỗi verdict
1. designer `VERDICT: SHIP-READY` — 2 lần dừng-sớm, resume-từ-diary 2/2 OK (artifact-design chống #53 ăn tiền lần nữa; "file rách" giữa chừng = diagnostics snapshot dở, tsc sau đó 0 lỗi — gotcha #68 ×3 trong 1 đợt, cả với lead-edit-batch).
2. reviewer `VERDICT: PASS-WITH-FLAGS` — 8 flag, 0 blocker; tự đo lại SHA 6/6 + diff-hunk-level.
3. lead: áp F-1 (gate = đúng key policy `KeHoachKyKet` — MenuPermissionHandler so khớp CHÍNH XÁC 1 key, không kế thừa) · F-3 (nhãn "(ngoài chỉ mục 200 — mở để xem)") · F-4 (index giữ `total` → cờ `truncated` + notice — không tụt-số im lặng) · F-6 (hideEmpty giữ folder failed/loading) · F-7 (invalidate `pipeline-contract-index` sau upload) · F-8 (sửa 2 câu memory designer sai: "0 rác 403" thêm điều kiện + "Ct_* kế thừa Contracts" là SAI vì seeder tạo row riêng).
4. Gate cuối: `npx tsc -b --force` = 0 · `npm run build` ×2 = EXIT 0 (Rolldown/Vite-8 warm ~0.5s) · SHA-pair 6/6 sau fix (4 hash mới: `403777e3…`/`88967a38…`/`5334a124…`/`e4cb0bbb…`; PE `1d8d8f75…` + Khkk `40a650bf…` giữ).

## Giới hạn CÒN LẠI (khai thẳng, không phải quên)
- **F-2:** phiếu liên-danh đẻ N HĐ chỉ nối HĐ[0] (`CreateContractFromEvaluationFeatures.cs:145` ghi 1 `ContractId`) ⇒ GĐ3/4 hụt N−1 — lớp cardinality S87/S88; đường vá THẬT = W5 (link KHKK→HĐ). Prod hiện Contracts=0 ⇒ 0 tác động tức thời.
- **F-5:** lưới `19rem` 2 trang chưa từng render thật (harness chỉ import 2 component; dev-rig authed bị chặn gotcha #3) ⇒ nghiệm thu prod bằng mắt anh — đúng cadence {đợt nhỏ → ship → anh nhìn prod}.
- Nhẹ (reviewer, không đánh số): 2 index query fire dù chưa mở folder · view "Đã xóa" vẫn hiện GĐ2-4 sống · KPI đổi dải 1024-1279px.
- Dev-data: PE=4 · KHKK=0 · Contracts=7 · PE.contractId=0/4 ⇒ Dev nhìn thấy toàn "SẮP" là ĐÚNG dữ liệu, không phải bug.

## cicd
Post-push: cicd-monitor 3 chân (Actions run + test-gate 590 + bundle-hash-delta ×2 + smoke) → `sub-cicd-monitor-2.md`. FE-only ⇒ không có chân migration.
