# S89 (2026-06-25) — PE visibility/finalize batch + xóa User test prod + Word guide

> Phiên CỰC LỚN, HMW-mode ON. anh Kiệt FDC UAT realtime. ~6 commit prod-verified + 1 prod data-op + 1 deliverable Word. em-main-led + Workflow fan-out (2: invest finalize-note + impl finalize-note) + cicd-monitor ×3. Nhiều #53 truncation (impl-frontend + cicd return rỗng) → recover-disk + self-gate.

## Bối cảnh
anh giao liên tiếp qua Zalo (anh Kiệt FDC + screenshot): (1) CCM không nhập được giá đề xuất, (2) finalize-note "không trình CEO" ra 3 surface, (3) màn hình CEO hiện nháp người khác, (4) Word hướng dẫn + danh sách user + xóa user test.

## D1 — Phiếu nháp RIÊNG TƯ người tạo (`a71753b`, Run #465 PASS, test 419→421)
**Triệu chứng:** màn hình CEO ở "chỗ thao tác" hiện bản nháp/phiếu chưa xong của NGƯỜI KHÁC.
**Root cause (2 đường lộ):** `PurchaseEvaluationFeatures.cs` IDOR filter — nháp (DangSoanThao) lộ qua **cond #2** role-eligible (`GetEligiblePhases` map Drafter/DeptManager→DangSoanThao :645) + **cond #3 V2-approver** (workflow PIN lúc TẠO phiếu `:149 ApprovalWorkflowId=request.*` → CEO là approver → thấy MỌI nháp). cond #3 = leak chính trên màn CEO.
**Fix 4 chỗ (nháp = owner-only + Admin):** GetEligiblePhases bỏ DangSoanThao · admin inbox-array bỏ DangSoanThao · list cond#3 guard `!=DangSoanThao` · detail-authz guard `isV2Approver` cho draft. +`PeDraftVisibilityTests` (2 test, test-before security — owner thấy / drafter khác KHÔNG / **CEO V2-approver KHÔNG** / admin thấy hết / phiếu đã-gửi vẫn hiện). Inbox: anh chốt "bỏ nháp khỏi inbox hẳn".
**Lesson:** `feedback_cardinality_change_grep_consumers` mở rộng — category-error (DangSoanThao=drafting phase đặt nhầm vào approval-eligible set); FK recon trước khi đụng visibility.

## D2 — CCM giá đề xuất nhập được (`f7bd97a`, cùng Run #465)
**Triệu chứng:** "PRO oki nhưng CCM giá đề xuất không nhập được" (anh Trần Xuân Lưu CCM).
**Root cause:** `SuggestedPriceRows` (PeDetailTabs:1726) gate `!readOnly && ev.canEdit*SuggestedPrice` — thêm tầng `!readOnly` mà ô **ngân sách song song KHÔNG có** (`editable={bs.canEditCcm}` role-only). Ở view readOnly=true (preview / Duyệt chưa-tới-lượt `!pendingMe`), CCM sửa ngân-sách được nhưng giá-đề-xuất rớt read-only. Vi phạm BE intent "không ràng Phase, chỉnh như tài liệu sống".
**Fix:** gỡ `!readOnly`, gate thuần role (BE setter fail-closed Forbidden = chốt chặn). Gỡ luôn prop readOnly không dùng. 2 app SHA-mirror (6 edit).
**Lesson:** 2 ô cạnh nhau cùng "nhập theo role" mà khác hành vi = gần chắc 1 ô gate sai trục (role ⟂ view-state).

## D3 — Finalize-note "không trình CEO" × 3 surface (`f0bca77`, Run cicd, test 421→422) + flow badge (`9c920ad`) + matrix flag (`fef4c33`)
**Yêu cầu:** phiếu mà quy trình có cấp bật `AllowApproverFinalize` (Mig 58) → note "kết thúc, không trình CEO" cho mọi người nắm ở dashboard + sidebar + trong phiếu.
**Invest Workflow** `wf_341f7b29-467` (4 invest investigator-codebase → design → 2 reviewer): bắt finalize-flag CHỈ lộ cho current-level → cần expose whole-flow. 2 reviewer bắt: **InboxPage SÓT** (surface sidebar) + path sai `pages/pe/` + copy phải nói "các cấp trước vẫn duyệt" (boundary cho cấp giữa) + dashboard chưa cam-kết.
**Impl Workflow** `wf_3f57edb6-514` (BE ∥ FE): BE OK (+caught CreateContractFromEvaluationFeatures.cs cùng DTO); **FE return RỖNG #53** → em-main self-gate recover-disk: fe-user 6 file + new PeFinalizeChip OK, **fe-admin chỉ types** → em-main mirror 4 file SHA-identical (cp) + verify 5 render-site + +PeFinalizeProjectionTests (EF-translate smoke 3-subquery).
**BE (no migration):** +EndsBeforeCeo/FinalizeStepName/FinalizeLevelName trên detail+list DTO + AllowApproverFinalize trên flow-level; first-reachable Step.Order→Level.Order; list/inbox/approved 3 subquery EF-safe (lv.Step!.Name); V1 null→false.
**Flow badge (`9c920ad`):** PeWorkflowPanel sơ-đồ — badge tím "⚑ Duyệt thay CEO" trên cấp finalize + làm-mờ Bước CEO "không trình tới" (anh muốn thấy NGAY trong sơ đồ).
**Matrix flag (`fef4c33`):** `WorkflowMatrixViewPage` (user, build S24 với 7 flag) **thiếu flag thứ 8** `allowApproverFinalize` (thêm Mig 58 S87 chỉ vào Designer) → "chưa hiển thị chính xác". BE đã gửi sẵn, FE matrix + AwLevelDto thiếu → thêm.
**Lesson:** (a) versioning — Designer "Lưu" = `CreateAwDefinitionCommandHandler` tạo **version MỚI** (Version++ theo Code + deactivate cũ); phiếu pin ApprovalWorkflowId lúc tạo → phiếu CŨ giữ version cũ, finalize chỉ hiện trên phiếu MỚI (đây là lý do anh "check rồi mà không thấy"). (b) doc-drift điển hình: thêm flag vào 1 surface (Designer) quên surface song song (matrix) — thêm field phải grep MỌI nơi render flag-set.

## Xóa User TEST khỏi prod (`681b1ed`, prod data-op)
anh: "Xóa hết User test, giữ User Solution thật". Quy trình S59/S85 chuẩn: **recon → AskUserQuestion chốt → backup → script → run → verify**.
**Recon (ssh sqlcmd prod):** 55 user. FK: `ApproverUserId` NO_ACTION (chặn) nhưng **KHÔNG user test nào là approver** (10 approver đều thật) → an toàn; 5 bảng con CASCADE; `nv.test` 1 PE (DrafterUserId loose, không FK). Edge: `chuong.phan@solution.com.vn` typo-domain (anh chốt xóa).
**Script `scripts/s89-delete-test-users.sql`:** whitelist-keep 17 + BACKUP (`SolutionErp_S89_preuserdelete.bak`) + XACT_ABORT + count-guard[30,45]. Chạy: count=38, PE=1, **còn đúng 17 user thật**.
**Seed (`DbInitializer.cs`):** gỡ 16 user mẫu khỏi `SeedDemoUsersAsync` + gỡ `LockDemoSampleUsersAsync` (call+method). SeedItDepartmentStaff + sample-workflow seeds null-guard → deploy KHÔNG resurrect/crash. **PHẢI deploy** (binary cũ chứa seed-test sẽ tái-tạo khi prod restart).
**Lesson:** whitelist-keep > blacklist (an toàn — chỉ giữ tập đã verify); count-guard + backup + XACT_ABORT = 3 lớp chống xóa-nhầm; `chuong.phan@solution`(typo) KHÔNG phải approver → xóa an toàn, anh Chương dùng bản `@solutions` (pass seed `User@1234567`).

## Word guide — `docs/Huong-dan-Duyet-NCC.docx`
anh: "làm file Word hướng dẫn Duyệt NCC theo mẫu, logo Solution, kiểu 1→2→3 khoanh đỏ". Dùng skill `docx` (docx-js Node). Logo `fe-user/public/logo.png` (407×145) nhúng. 8 phần step-by-step + 12 ô chừa ảnh nét-đứt kiểu "khoanh đỏ theo số (1→2→3)" + Quy ước ảnh + TOC + cover + footer. Valid (ZIP+XML UTF-8 OK; validator charmap-error = bug encoding script trên Windows, không phải lỗi file). Copy sang Downloads.
**Pending:** ẢNH THẬT chưa chèn — em KHÔNG chụp được app từ máy (không trình-duyệt nối prod + pass role; lái máy anh cần quyền + tạo rác prod vừa-dọn). Cần anh chụp 12 màn gửi → em annotate khoanh-đỏ + chèn. (Mẫu PDF anh không render được pdftoppm/pypdf/fitz đều thiếu → dựng layout-chuẩn-Solution.)

## State THẬT (cuối S89)
**Mig 59 · 88 bảng · 422 test (45D+377I) · gotcha 73 · menu 54 · bundle admin `DalcOhvb`/user `CdS4tX_2`** (sau `9c920ad`; `fef4c33` matrix rotate user→`CdS4tX_2` — verify "không trình tiếp CEO" in-bundle). Prod **17 user thật**.

## 🔴 NEXT
- **Anh:** ⚠️ restart CLI (carry budget/cmd). **Chèn ảnh guide:** chụp 12 màn (theo nhãn ô) gửi em → em khoanh-đỏ 1→2→3 + chèn → xuất bản. Hoặc bật Chrome+extension Claude-in-Chrome + pass admin → em tự chụp.
- **Em (carry):** 🔴 curate `test-specialist` L1 **34.8KB OVER-SOFT** + cicd 28KB + reviewer 27.7KB (archive-gate). **Monthly 2026-07-01:** ef-core skill Mig→59 · STATUS/HANDOFF re-tier mega-line · 3 vocab-fork alias-map · docs/CLAUDE Budget-removed · matrix-flag-count comment.
- **Pending product:** Section B cột Dự-án wire · Ngưỡng giá CEO Mig 54 Designer UAT · "C" chuyển phiếu→dự án spec.
- **Ops:** email typo anh Chương (đã xóa bản typo S89) · 5 real-staff pw · gán CNTT.

**Residual:** 5 file agent-memory (cicd/inv/reviewer MEMORY + 2 plan-review reviewer) = harvest hợp-lệ sub-workflow, commit kèm closeout.
