From b3c40d4d70c95d5a53d30d1d07e3f0dcb6c2d52e Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Fri, 31 Jul 2026 14:20:44 +0700 Subject: [PATCH] wal: flush 20260731T1420 --- .claude/WAL.md | 96 +++++----------- .../2026-07-31-S164-4gd-khkk-fanout/run.md | 4 +- .../spec-4gd-khkk-tong-quat-31-07-2026.md | 12 +- .../spec-cum1-chi-tiet-31-07-2026.md | 6 +- .../spec-cum2-chi-tiet-31-07-2026.md | 2 +- .../sub-implbe-k1.md | 12 ++ .../sub-review-fable-b3.md | 103 ++++++++++++++---- 7 files changed, 138 insertions(+), 97 deletions(-) create mode 100644 .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-implbe-k1.md diff --git a/.claude/WAL.md b/.claude/WAL.md index 985f259..dbce932 100644 --- a/.claude/WAL.md +++ b/.claude/WAL.md @@ -1,74 +1,38 @@ # WAL — auto-generated, không sửa tay -updated: 2026-07-31T12:35:00+07:00 | session: S164 (L9, window 2 — /tiep; lead=Fable) | branch: main +updated: 2026-07-31T16:45:00+07:00 | session: S164 (L9, window 2 — /tiep; lead=Fable) | branch: main -goal: CHUỖI 4-GĐ SP-002 — B0 ✅ B1a ✅ B1b ✅ spec-v2 ✅ transcribe ✅ · NEXT = B2 (chờ anh liếc 6 OG, có default) +goal: CHUỖI 4-GĐ SP-002 — SPEC ĐÓNG BĂNG (B0→B3 trọn) · B4 BUILD BẮT ĐẦU (wave K1-BE đang chạy) chain: -[x] /tiep + VÁ 12/12 + nạp spec SP-002 (6 nhịp + 3 hình + 2 bổ sung) — chi tiết _context/log -[x] B0 draft-yeu-cau-owner.md (10 lời chốt + 8 nhóm + 5 mảnh + khuôn + 8 treo) -[x] B1a ×2 att: att-1 ngược-#53 (207K/0-byte/resume-chết) · att-2 kỷ-luật-ghi CỨU A-D 18.277B → - lead compile E/F + spot-check 4/4 → spec v1 (8 verdict · K1-K8 · 3 cụm) -[x] B1b wf_8eb13087-5f9 — 3 lane reviewer opus 3-lens, 3/3 SẠCH 0-empty (C2 khung-rỗng ăn): l1 FAIL 5H · - l2 6/6 chịu-lực ĐÚNG + F1 rào-1-PE-1-phiếu (:342/:1201) · l3 FAIL 6H + bác-6-nghi. Hội tụ 2-lane: - admin-hide "System-subtree" GIỮ NHẦM 2 mục cần ẩn (Workflows :1795 + PeWorkflows :1798 = CON System) -[x] Lead synthesize b1b-review-synthesis.md (41 finding → 14 vá + OG-6/OG-7) → SPEC V2 10.012B - (tập-key tường-minh · ApprovalGroup K2-chủ+backfill-1 · 8-designer đo được · K7 3-nấc · acceptance răng) -[x] F-1 resolve: file đĩa = ĐÚNG SP-002.v01 (mã ở word/header1.xml) NHƯNG 6-trang KHÔNG bảng ⇒ nguồn = - 7 ảnh anh. Lead TRANSCRIBE danh-muc-sp002-transcribe.md: 85+1 row · 8 nhóm map · 4 ô-chưa-chắc [OG-6] -[!] B2 — per cụm 3 wave (cụm-1 K1+K2+K3 · cụm-2 K4+K5+K6 · cụm-3 K7+K8): /fable-real invest sâu → - /fable-clone review. PRE: 6 OG có DEFAULT (spec v2 §④) — chạy default nếu anh không đổi; build B4 mới chặn cứng -[ ] B3 /fable-real review chốt · B4 fan-out Opus MAX · B5 dry-run E2E -[ ] closeout: seed diary vai (C2 A∖B=∅) · tally garble (+ngược-#53 ev#4) · nhãn D · K3-STATUS-row +[x] /tiep + VÁ 12/12 + spec SP-002 nạp (6 nhịp + 3 hình) — log cũ trong _context +[x] B0 draft → B1a invest (att-2 cứu) → B1b clone-review 3-lane → spec-tổng v2 +[x] B2 TRỌN 3 cụm: invest fable ×3 (c1 33KB · c2 5/5 · c3 22.9KB) + review 3-lane ×3 → 3 spec-cụm final, + 43 vá. Sự cố đã xử: ngược-#53 ev#4 · skeleton-472B ×1 · chết-ruột-188B ×1 (opus) — đan-xen từ đó 5/5 SẠCH +[x] OG CHỐT TRỌN 9: 1-gộp+UI-1-1 · 2-đội-hình-cũ · 3-NĐUQ-human-gate-VĨNH-VIỄN · 7-N-phiếu+UI-1 · 8-hiển-thị · + 9-đảo-PHÁ-VỠ-S155 · QĐ9-freeze-tái-dùng-máy-sẵn · (V)-thiết-kế-ERP-đúng+PE-test-SOLUTION-PE-{n} · + BACKLOG 3 mục giai-đoạn-sau (amendment · authz-nhóm · bung-gộp) +[x] B3 fable-review chốt: GO-WITH-SPEC-FIXES (GO 9/10 · 8 mâu-thuẫn · 0 vá-đè-vá/43 · build-order + K1→K2→K3→K4a→K4b→K5→K4c→K6→K7→K8) → 8 fix lead ÁP XONG → SPEC ĐÓNG BĂNG 4 file +[!] wf: B4 K1-BE wf_2569b79b-12f ĐANG CHẠY — implementer-backend: entity ContractCatalogEntry + config + + Mig 70 3-file + seeder 86-row từ transcribe + MenuKeys+row + CQRS/controller authz-mirror-Catalogs + + build slnx + test-không-vỡ-590. Output sub-implbe-k1.md. 🔴 KHÔNG commit/push — lead verify + OG-6 gate +[ ] B4 tiếp: K1-FE (×2 app KIND_CONFIG) + K1-test → K2 → K3 → K4a... theo build-order; mỗi wave lead verify + + reviewer-gate trước commit; PUSH K1 chờ anh soát OG-6 (bảng transcribe + 8 nhãn) +[ ] K8 dry-run: gói test SOLUTION-PE-{n} + B0-form 14 người thật (fail-closed) + đo freeze 2-nhánh +[ ] closeout: seed diary vai (C2 A∖B=∅) · tally garble (+sự-cố hôm nay) · nhãn D · STATUS row S163/S164 -next: 5/6 OG CHỐT (1 schema-GỘP+UI-1-1 · 2 đội-hình-cũ · 7 N-phiếu+UI-1 · 8 "cho hiển thị, phân quyền tính - sau" · 3 NĐUQ-tham-khảo + lên-CEO = TÁI DÙNG level-finalize [a Chương quyết, y PE]). Còn OG-6 anh soát - transcribe (chặn seed-land, KHÔNG chặn invest). wf: B2-cụm-1 wf_fe53e58b-361 ĐANG CHẠY (1 lane fable, - sub-invest-fable-b2-cum1.md, skeleton-first) → về thì: verify đĩa → merge note OG-3-finalize vào spec - chi-tiết → kết tinh → fable-clone review cụm-1. Nguyên tắc mới memory: "máy rộng, UI hẹp". - 🆕 QUYẾT ĐỊNH 9 (owner): KHÓA BUDGET tại finalize (a Chương TP.CCM) = mirror PE Mig 67 + né #81-EXT — spec §②.9. - B2c1 att-1 skeleton-472B chết · att-2 wf_0b6b511f-76d ✅ SỐNG TRỌN (33.048B 5/5 section 17 test, luật - ĐAN-XEN cứu; return CŨNG sạch). 3 QUYẾT spot-check 3/3 ĐẠT: freeze = 0-cột-mới (máy Line+??= sẵn, chỉ - thêm răng #81-EXT site :342) · catalog authz mirror CatalogsController · MÂU THUẪN OG-3 THẬT (BE chưa - port finalize — KHKK_EARLY_FINALIZE_NOTE system/ApprovalWorkflowsV2Page:151) → spec §④ OG-3 ĐÃ SỬA - (K3 3 việc a/b/c). Roster ô ⚠️ "Trưởng" 3 ứng viên — verify LIVE trước seed. - B2-r cụm-1 ✅ 3/3 lane (L1 2/9-claim-đúng GỠ-(i)-:342 [invest đọc-ngược-comment] · L2 FAIL 3H · L3 PWB - 5H) → spec-cum1-chi-tiet-31-07-2026.md FINAL (nền 33KB + 12 VÁ thắng-xung-đột; blocker: key-VÀO-All + - sweep-ép-false-AllowApproverFinalize ≥4-site + KhkkCreatePage-×2-app + submit-guard-CatalogEntryId). - OG-9 ✅ CHỐT (câu IV): anh xác nhận đảo "PHÁ VỠ" @S155 — "chỗ budget chốt chặn là a Chương" ⇒ K3 (a)-(e) - HẾT CHẶN. + OG-3 NÂNG: trần budget = HUMAN-GATE VĨNH VIỄN (a Chương quyết cần-CEO-hay-không) — XÓA mọi - ý "enforce máy wave sau" khỏi backlog. 7/7 OG nghiệp-vụ đã chốt; còn OG-6 soát-bảng (chặn seed) + OG-5. - B2 cụm-2 invest ✅ wf_15a42015-aea SẠCH (5/5 section, K4 13v·K5 6v·K6 4v, 0-mig; BÁC 2 tiền-đề lead: - 13-role=13/13-R+C+U [:2427] · fe-admin khỏi-nới-regex [ẩn subtree :186-190]; lead spot-check 2/2 ĐẠT; - drift chain 55→64→113 key · policies →452; precedent-split khai 2 khuôn ngoài-All⟂trong-All). - B2-r cụm-2 ✅ (l1 PWF 4/7-đúng-0-sai 2-MAJOR [route-ship-cùng-K4a · drift-DELTA] · l2 PWF 3H/7M [queryKey - +group · thứ-tự · nhãn-N2-mất-phá-dỡ · phase-mount-only] · 🔴 l3 CHẾT-RUỘT 188B = lane OPUS đầu tiên gãy, - phủ-bù lead-note CÓ KHAI) → spec-cum2-chi-tiet-31-07-2026.md FINAL 15 vá. - B2 cụm-3 invest ✅ wf_a21c8ff1-bc7 SẠCH (22.9KB 4/4: K7 8v/8test — BÁC tiền-đề "3 lỗ S156": ĐÃ VÁ @W6-S161 - [list :306-318 · inbox :532-543 · guard :73-92] ⇒ K7(b)→test-khóa; CẤM sửa GetEligiblePhases [:381-387 rò - xóa-mềm]; bridge +ApprovalWorkflowId input [type-3 any-ContractType]; pe.ContractId ??= giữ cây; K8 17-bước - B0-B16, B1→KHKK-N4, type NhaCungCap né hố-MB, đội hình từ K3-LIVE [Dev 0 QT-DN-V2-001]). - 🔴 HỐ-1-KHKK MỚI: phiếu KHKK DaDuyet KHÔNG XÓA nổi kể cả Admin (:1145-1148 allow-list SAU nhánh admin) + - chiếm slot (PeId,group) VĨNH VIỄN — dry-run trên PE thật = phiếu-test nằm lại, dọn = sqlcmd ⇒ CÂU (V) cho anh. - B2-r cụm-3 ✅ 3/3 (L1 7/7-ĐÚNG · L2 FAIL-5H K8-chưa-chạy-được [12/14 bước 0 người thật · QĐ9 đo-0-bit · - ZZTEST không hiện list · rollback-HĐ no-op] · L3 FAIL-4H [authz HỘI-2-khóa + Contracts.Create 0-VAI ĐƯỢC - CẤP ⇒ nút chết 403 câm — 3-lane hội tụ]) → spec-cum3-chi-tiet-31-07-2026.md FINAL 16 vá. - B2 ĐÓNG TRỌN: 3 spec final + 43 vá tổng. wf: B3 wf_567c4b38-405 ĐANG CHẠY (1 lane reviewer tier:FABLE - đối chiếu chéo 4 spec → A mâu-thuẫn-liên-spec · B vá-đè-vá · C build-order · E GO/NO-GO · F digest-owner). - Về → lead tổng → BẢNG TỔNG trình anh → B4 build K1 (anh pre-authorize "chốt kỹ rồi thì dry-run luôn"; - seed-land vẫn chờ OG-6+câu-II · K8 chờ câu-V). - (V) ✅ CHỐT TRỌN: "phiếu đã duyệt không xóa" = THIẾT KẾ ĐÚNG ERP (CẤM B4 sửa allow-list) + phương án (b) - ratified — K8 dựng gói test tên `SOLUTION-PE-1..n` đi trọn vòng, KHÔNG test trên phiếu thật (mã phiếu vẫn - auto-gen RG-001; nhận diện qua TÊN GÓI + danh-sách-ID). +BACKLOG giai-đoạn-sau: phiếu điều-chỉnh/thay-thế - (amendment, áp PE/KHKK/HĐ) + authz-per-nhóm + bung-gộp UI — spec tổng đã ghi 3 mục. - CHỜ ANH: (I) bản-15-trang · (II) B2-14-dòng+"/" · (III) ai-bấm [default Drafter+Procurement+Admin] · OG-6. - Sổ lane-chết: fable 3/8 · opus 1/12. +next: đợi wf_2569b79b-12f → VERIFY ĐĨA (sub-file + git status + dotnet build/test THẬT — disk-truth + WRITE-lane) → nếu sạch: phóng K1-FE + K1-test song song → reviewer-gate K1 → chờ OG-6 rồi commit-push. + Chết giữa chừng: relaunch-cắt-gọt theo tiep.md §4 (git status cho biết file đã tạo). verify: - grep -c 'END spec v2' .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-4gd-khkk-tong-quat-31-07-2026.md - grep -c '86 row' .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/danh-muc-sp002-transcribe.md - ls .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/ | wc -l # >=9 file + ls .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/ | wc -l # 20 file (17 + sub-implbe-k1 + 2 review c3) + git status --porcelain | head -20 # K1-BE files sau khi lane xong + grep -c 'GO-WITH-SPEC-FIXES' .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-review-fable-b3.md -notes: RÀNG BUỘC KHUÔN: GIỐNG NHAU—CHỈ KHÁC FORM—ĐỪNG CHẾ THÊM. 8 nhóm = HIỂN THỊ không phải authz (khai - thẳng spec §①). Đội hình 3 trạm QT-DN-V2-001 memory (verify LIVE trước K3). Sự cố phiên: ngược-#53 ev#4 - (B1a att-1) + StructuredOutput-fail ×2 lần B1a (đĩa cứu) — tally @closeout. mind-check 1 cờ giữ chủ-đích. - Chờ anh cũ: 54-62+42/43/44 (HANDOFF). Lead=Fable; ensemble lane pin tier:opus (GAP#6). +notes: SPEC 4 file = spec-tổng v2 (9 QĐ + backlog-3) · spec-cum{1,2,3} final (12+15+16 vá). Câu-ranh builder: + ":342" trùng số dòng 2 file — Features.cs:342-347 PHẢI đổi ⟂ WorkflowService.cs:342 CẤM đụng (B3-B4). + CHỜ ANH (không chặn K1-BE build): (I) bản-15-trang · (II) B2-14-dòng+"/"=hoặc · (III) ai-bấm-Đưa-vào-HĐ + [default Drafter+Procurement+Admin] · OG-6 soát transcribe+8-nhãn [CHẶN push K1] · OG-5 hỏi-khi-gặp. + Sổ lane-chết: fable 3/9 · opus 1/13 (đan-xen từ c1-att2: 6/6 sạch liên tiếp). Engine dùng: fable ×6 · + clone-ensemble ×9 lane · impl ×1 (đang). mind-check 1 cờ giữ chủ-đích (block refresh @cửa kế). diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/run.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/run.md index 53c96c0..d6d5a12 100644 --- a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/run.md +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/run.md @@ -17,7 +17,7 @@ | 2.c2-r | Review cụm-2 — `WF reviewer c2-{evi,cov,seq} s164` | /fable-clone (opus ×3) | ✅ l1 PWF 2-MAJOR · l2 PWF 3H/7M · 🔴 l3 CHẾT-RUỘT 188B (opus đầu tiên gãy — phủ bù lead-note có khai) → **spec-cum2-final 15 vá** | | 2.c3 | Cụm-3 K7+K8 — `WF invest-fable b2c3 s164` | /fable-real invest | ✅ SẠCH 22.9KB (K7 8v/8test BÁC tiền-đề 3-lỗ-S156-đã-vá · K8 17 bước · HỐ-1-KHKK mới) | | 2.c3-r | Review cụm-3 — `WF reviewer c3-{evi,cov,seq} s164` | /fable-clone (opus ×3) | ✅ 3/3 sạch · L1 7/7-ĐÚNG PWF 4M · L2 FAIL 5H (K8 chưa-chạy-được-như-viết) · L3 FAIL 4H (authz hội-2-khóa · Contracts.Create 0-vai) → **spec-cum3-final 16 vá** | -| 3 | Chốt spec cuối — `WF review-fable b3-chot s164` wf_567c4b38-405 | /fable-real review | ⏳ (đối chiếu chéo 4 spec: mâu-thuẫn liên-spec · vá-đè-vá · build-order · GO/NO-GO · digest owner) | +| 3 | Chốt spec cuối — `WF review-fable b3-chot s164` | /fable-real review | ✅ **GO-WITH-SPEC-FIXES**: GO 9/10 (K8 by-design) · 8 mâu-thuẫn (3 nặng A-1/A-4/A-5) · 0 vá-đè-vá/43 · build-order K1→K2→K3→K4a→K4b→K5→K4c→K6→K7→K8 · 8 fix lead ÁP XONG | | 4 | Fan-out build bám spec+checklist | Opus 5 MAX (hmw) | ☐ | | 5 | Dry-run E2E toàn trình | theo spec wave cuối | ☐ | @@ -27,6 +27,6 @@ - [x] B1a — att-1 wf_22e8949b-afa CHẾT ngược-#53 (207K tok, 0 byte) · att-2 wf_bc04352b-6a4 A-D đầy + spec-file lead kết tinh `spec-4gd-khkk-tong-quat-31-07-2026.md` (8 verdict · 8 wave K1-K8 · 3 cụm · OG-1/2/3/5) - [x] B1b — wf_8eb13087-5f9 3/3 lane sạch (l1 FAIL 5H · l2 6/6 chịu-lực ĐÚNG +l2-F1 rào-1-PE · l3 FAIL 6H + bác 6 nghi) → `b1b-review-synthesis.md` 14 vá + OG-6/OG-7 → spec v2 (hội tụ 2-lane: admin-hide tập-key tường minh; ApprovalGroup K2-chủ + backfill=1; 8 designer có phép đo; nguồn K1 = 7 ảnh [file đĩa 6-trang không bảng]) - [x] B2 — 3 cụm TRỌN: c1 (33KB + 12 vá) · c2 (5/5 + 15 vá; l3 chết-ruột phủ-bù) · c3 (22.9KB 7/7-đúng + 16 vá) = 43 vá tổng, 3 spec final -- [ ] B3 — fable-real review chốt +- [x] B3 — GO-WITH-SPEC-FIXES (sub-review-fable-b3.md 6 section; 3 anchor re-grep đĩa khớp; 8 fix áp vào 3 spec) — SPEC ĐÓNG BĂNG cho B4 - [ ] B4 — fan-out build - [ ] B5 — dry-run E2E diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-4gd-khkk-tong-quat-31-07-2026.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-4gd-khkk-tong-quat-31-07-2026.md index 9980c71..9f1ba28 100644 --- a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-4gd-khkk-tong-quat-31-07-2026.md +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-4gd-khkk-tong-quat-31-07-2026.md @@ -6,17 +6,17 @@ Chuỗi 4 GĐ per-gói-thầu theo SOL-CCM-SP-002: GĐ1 Duyệt NCC (PE = CHA, đã chạy) → GĐ2 KHKK = **duyệt HẠNG MỤC theo 8 NHÓM DUYỆT** (trình ký số trạm-by-trạm y Duyệt NCC; ký nháy = mực trên bản cứng GĐ4) → GĐ3 điều khoản → GĐ4 bản cứng 1-mốc. Scope 5 mảnh: master-data danh mục · sidebar 8 nhóm × 6 leaf · cây mirror sidebar · admin thu gọn + 8 designer · dry-run E2E. 🔴 Luật khuôn: **GIỐNG NHAU — CHỈ KHÁC FORM — ĐỪNG CHẾ THÊM**. 🔸 Khai thẳng (B1b l3-F4): đợt này **8 nhóm = đơn vị HIỂN THỊ + luồng duyệt**, KHÔNG phải đơn vị authz — mọi endpoint KHKK giữ 1 bộ policy `KeHoachKyKet.{R,C,U,D}` per-action (`ContractSigningPlansController.cs:28+`); authz-per-nhóm nếu anh muốn = wave riêng sau. -## ② Cách implement — 8 quyết định (v2) +## ② Cách implement — 9 quyết định (v2; B3-A0b sửa đếm) 1. **[OG-1]** Cardinality "đưa vào loại HĐ" default **GỘP theo cặp (NCC × dòng-danh-mục)** — N line chung `ContractId` (hợp khuôn `ContractSigningPlanLine.cs:25`, index không-unique `Configuration:26`); đảo 1-1 được cùng máy. -2. Phiếu KHKK = **per NHÓM** (1 phiếu = 1 nhóm, N hạng mục). Lines per-hạng-mục: Mig +`CatalogEntryId Guid?` +`TenHangMuc`, UNIQUE → (PlanId, SupplierId, CatalogEntryId) filtered. 🔴 **+2 vá B1b:** (a) **đổi rào 1-PE-1-phiếu** (`ContractSigningPlanFeatures.cs:342-347` + picker `:1201-1202`) → (PeId, ApprovalGroup) **[OG-7]** — FE tree đã chịu N-phiếu/PE (`usePipelineStages.ts:110-121`); (b) **bất-biến tiền**: `PeReferenceAmount` = snapshot per-NCC-toàn-phiếu (`Line.cs:6,:16-20`) — repurpose per-hạng-mục PHẢI định nghĩa lại semantics + Σ trước == Σ sau mig, acceptance rà **16 consumer** (10 BE `.Lines` + 6 file FE — danh sách l3-F18). +2. Phiếu KHKK = **per NHÓM** (1 phiếu = 1 nhóm, N hạng mục). Lines per-hạng-mục: Mig +`CatalogEntryId Guid?` +`TenHangMuc`, UNIQUE → (PlanId, SupplierId, CatalogEntryId) filtered. 🔴 **+2 vá B1b:** (a) **đổi rào 1-PE-1-phiếu** (`ContractSigningPlanFeatures.cs:342-347` + picker `:1201-1202`) → (PeId, ApprovalGroup) **[OG-7]** — FE tree đã chịu N-phiếu/PE (`usePipelineStages.ts:110-121`); (b) **bất-biến tiền**: `PeReferenceAmount` = snapshot per-NCC-toàn-phiếu (`Line.cs:6,:16-20`) — repurpose per-hạng-mục PHẢI định nghĩa lại semantics + Σ trước == Σ sau mig, acceptance rà **18 consumer** (17 grep-verified cụm-1 + `Features.cs:712-713` Σ Proposed — số chốt theo cụm-1 vá-8; B3-A-x). 3. Workflow = **1 type-10 + 8 Code `KHKK-N1..N8`**; only-ONE-active VÔ HẠI (chứng 2 mắt xích l2: create chỉ check type `:209-220`; overview không lọc IsActive `:117-134`, POST không đụng IsUserSelectable `:341-353`). 🔴 Cột `ApprovalGroup` **K2 là CHỦ DUY NHẤT** (l3-F6) — K3 chỉ đọc (map Code↔group + validator phiếu-pin-đúng-nhóm). 4. Vai catalog = 2 tầng: danh mục lưu chuỗi vai TEXT (in khối ký GĐ4) ⟂ workflow Levels lưu NGƯỜI THẬT. 🔸 Khai limitation (l1-F12): TEXT không ràng buộc máy với người-duyệt-thật — chấp nhận đợt này, khai trong doc K1. -5. NĐUQ = cột THAM KHẢO text **[OG-3]**; enforce (`CeoApprovalThreshold`) = wave opt-in sau (0 consumer CỐ Ý — `WorkflowService.cs:44`). +5. NĐUQ = cột THAM KHẢO text **[OG-3 nâng cấp]**; enforce máy = **KHÔNG BAO GIỜ** (human-gate vĩnh viễn — a Chương quyết; B3-A0a: xóa nốt vế "wave opt-in sau" sót ở đây). 6. Menu: GIỮ `Khkk_G1` + 6 leaf cũ, đổi LABEL = nhóm 1 (labelBackfill khuôn S155). Nhóm 2-8 = **42 leaf MỚI + 7 group-key mới (49 row menu mới; 48 leaf TỔNG)** — sửa số l1-F8/l2-F5. 🔴 Phiếu cũ: **backfill `ApprovalGroup = 1`** (l3-F5 — mirror bài `EvaluationType` không rỗng; acceptance đếm `COUNT(phiếu) == Σ COUNT 8 folder`). 7. Admin ẩn = fe-admin **`isAdminHidden` MỞ RỘNG TẬP KEY TƯỜNG MINH** (giữ blacklist — KHÔNG đảo whitelist, tránh đổi default menu-mới; vá hội tụ l1-F2 ⨯ l3-F1/F2): ẩn thêm {`Dashboard?`→giữ, các root nghiệp vụ: `DuyetNcc-root keys`, `KeHoachKyKet`, HR/Office/Personal, `Contracts`(đã ẩn `Ct_*`), `HardCopies`, `Forms`, `Reports`, `Catalogs/Master`, **`Workflows` (:1795)**, **`PeWorkflows` (:1798)**} — CHỪA {`System` + 4 leaf quản trị + **`ApprovalWorkflowsV2` (:1801, con System)** + subtree}. Danh sách key CHÍNH XÁC = việc B2-cụm-2 liệt từ `DbInitializer` seed; acceptance = **liệt kê đúng N mục lá còn thấy** (l3-F2). 8. Nguồn danh mục: **file đĩa `QUY_TRINH/QT TRINH KY HOP DONG TP-NCC.docx` = ĐÚNG SOL-CCM-SP-002.v01 (mã ở word/header1.xml) NHƯNG bản 6-trang KHÔNG chứa bảng** (lead đo). Nguồn bảng = **7 ảnh anh gửi @S164 (trang 5-9, trọn 5.1 A/B/C + 5.2 CEO)** → transcribe → **[OG-6] anh soát bảng seed trước land** (hoặc anh gửi file 15-trang). "/" trong ô vai = OR-of-N. -9. 🆕 **KHÓA BUDGET TẠI FINALIZE (owner @S164, verbatim: "Cái tính năng chuyển CEO và duyệt kết thúc hợp đồng -> Là khóa luôn cái budget rồi, người quyết sẽ là a Chương, Trưởng phòng CCM"):** khi phiếu KHKK được **duyệt-kết-thúc tại CCM (a Chương finalize) HOẶC CEO duyệt final** ⇒ **freeze số** (ApprovedAmount/giá chốt/NS tham chiếu) — phiếu DaDuyet đọc SNAPSHOT, không đọc live. **Mirror nguyên khuôn PE Mig 67** (`AddPeApprovedBudgetSnapshot` S133): snapshot chốt tại finalize choke-point + display-gate `frozen` + 🔴 né **#81-EXT**: grep MỌI Phase-assignment-site (kể cả admin-override + seeder) kẻo bypass hook — bài đã trả giá 1 lần bên PE. Người quyết finalize-hay-CEO = **TP.CCM Phan Văn Chương** (cấp 2 CCM đội hình `QT-DN-V2-001`). ⚠️ MERGE-PENDING: B2-cụm-1 lane phóng TRƯỚC lời này — lead merge vào spec chi tiết khi lane về (schema cột snapshot → K2, hook finalize → K3). +9. 🆕 **KHÓA BUDGET TẠI FINALIZE (owner @S164; văn SỬA theo B3-A4 — thiết kế THẬT do cụm-1/cụm-3 chốt, cha theo con):** khi phiếu KHKK **finalize tại CCM (a Chương) HOẶC CEO duyệt final** ⇒ số KHÓA. 🔴 **KHÔNG chép khuôn 11-cột Mig 67** — máy freeze per-line ĐÃ CÓ SẴN: `PeReferenceAmount` copy-at-create (`Line.cs:17-20`) + `ApprovedAmount ??=` tại choke-point (`WorkflowService.cs:301-305`, 1-site-DaDuyet verified `:129/:278/:289-292`) ⇒ việc còn lại = **phase-guard line-edit sau DaDuyet (K2) + test-khóa 1-site (K2) + phép đo 2-nhánh TRƯỢT-ĐƯỢC (K8 — sửa nguồn → reload → số KHÔNG đổi, đo cả nhánh CCM-finalize lẫn CEO)** + cột runtime `EndedByLevelFinalize` (K2 item-6 đẻ, K3 tiêu thụ — 3 spec cùng 1 cột ✓). Người quyết = **TP.CCM Phan Văn Chương**. Né #81-EXT: sweep site gán Phase — đã liệt 4 site, GỠ nghi án `WorkflowService.cs:342` (comment đọc-đủ-khối: CỐ Ý không có site gán-qua-biến). ## ③ Wave K1-K8 (v2 — PRE-gate + acceptance có răng) @@ -27,7 +27,7 @@ Chuỗi 4 GĐ per-gói-thầu theo SOL-CCM-SP-002: GĐ1 Duyệt NCC (PE = CHA, **Cụm 2 (UI):** *(l3-F8: tách phụ thuộc thật — K4a chạy song song cụm 1 được)* - **K4a Menu+grant** (0 phụ thuộc): 49 row menu + grant 3 SITE (`:1780` seed · `SeedKeHoachKyKetAccessAsync:2415` · **`KhkkKeys():2185` — site-3 l2-F6**, comment `:2204` "quên 1 bên = quyền lệch"). **K4b 4 leaf list + Thao tác** (chờ K2 param). **K4c leaf WfView/Create** (chờ K3): WfView mang `?group=` lọc theo workflow Code nhóm (hiện `WorkflowMatrixViewPage:52-71` chỉ lọc type — l2-F3). DoD: 48 leaf render đúng · leaf lọc đúng group **kể cả WfView/Create** · **2 chiều theo bảng kỳ-vọng 13 role** (seeder hiện phủ 7 vai `:2671-2675` — 6 vai còn lại khai kỳ vọng TRƯỚC, l3-F13) · key cũ 0 mồ côi. -- **K5 Cây sub-folder**: GĐ2 group-by `approvalGroup` · GĐ3/4 group-by `c.type` (đã có `:240`); thêm tầng `groups` vào `PipelineStage` (mở rộng khuôn — bẫy `content` phải truyền `count` tay `:74-75`). DoD: sub-folder khớp sidebar · **2 file đích danh SHA-identical ×2 app** (`usePipelineStages.ts` + `PipelineTreePanel.tsx` — l3-F19) · build ×2 PASS. +- **K5 Cây sub-folder**: GĐ2 group-by `approvalGroup` · GĐ3/4 group-by `c.type` (đã có `:240`); thêm tầng `groups` vào `PipelineStage` (mở rộng khuôn — bẫy `content` phải truyền `count` tay `:74-75`). DoD: sub-folder khớp sidebar · **4 file pipeline SHA-identical ×2 app** (đối chiếu cụm-2 — usePipelineStages · PipelineStageFolders · PipelineTreePanel · trang nhúng; B3 sửa đếm) · build ×2 PASS. - **K6 Admin thu gọn** (độc lập NHƯNG l3-F9: kéo sớm TRƯỚC K3 thì 8 designer chưa tồn tại — nếu kéo sớm, acceptance "đếm 8 designer" dời sang sau K3): QĐ7 tập-key tường minh. DoD: **liệt kê đúng N mục lá còn thấy (đủ tên, dư/thiếu 1 = FAIL)** · fe-user KHÔNG đổi = **`git diff --stat .. -- fe-user/src` = 0 file** (KHÔNG đo bundle-hash #69 — l3-F12). **Cụm 3 (nối + chạy):** @@ -36,7 +36,7 @@ Chuỗi 4 GĐ per-gói-thầu theo SOL-CCM-SP-002: GĐ1 Duyệt NCC (PE = CHA, **Mọi wave:** cicd PASS; **byte-verify #77 CHỈ wave có FE-ship** — wave BE-only = smoke API (l3-F17); mig = 3-file rule. -## ④ [OWNER-GATE] — 4 cũ + 2 mới (nối vào PRE từng wave ở trên) +## ④ [OWNER-GATE] — 8 hàng, cập nhật sống (B3-A0b sửa đếm) | OG | Câu hỏi | Trạng thái | Chặn wave | |---|---|---|---| diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum1-chi-tiet-31-07-2026.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum1-chi-tiet-31-07-2026.md index 59c4efe..8077804 100644 --- a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum1-chi-tiet-31-07-2026.md +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum1-chi-tiet-31-07-2026.md @@ -5,7 +5,7 @@ K1 master-data danh mục (86 row) · K2 phiếu mang hạng-mục + nhóm + fre ## ② 12 vá (build ĐỌC CẢ nền LẪN vá) -1. 🔴 **[3-lane hội tụ] Menu key PHẢI VÀO `MenuKeys.All`** — nền khai `ContractCatalog` + 8 `AwV2_KhkkN*` "ngoài All" ⇒ **0 permission row ⇒ sidebar chết** (loop grant `DbInitializer.cs:2058` nguồn = All; khuôn THẬT: 5 leaf catalog hiện hành `MenuKeys.cs:168` + 3 leaf AwV2 `:182` đều TRONG All). Fix: cả 9 key **VÀO All** + KHAI drift canonical (Menu keys 55→64 · Policies 220→256 — khai 2 row STATUS cùng lúc, đừng Goodhart giữ-số-đứng-yên). Acceptance += "login Admin THẤY leaf trong sidebar ×2 app" + 1 test seed-grant. +1. 🔴 **[3-lane hội tụ] Menu key PHẢI VÀO `MenuKeys.All`** — nền khai `ContractCatalog` + 8 `AwV2_KhkkN*` "ngoài All" ⇒ **0 permission row ⇒ sidebar chết** (loop grant `DbInitializer.cs:2058` nguồn = All; khuôn THẬT: 5 leaf catalog hiện hành `MenuKeys.cs:168` + 3 leaf AwV2 `:182` đều TRONG All). Fix: cả 9 key **VÀO All** + KHAI drift dạng **DELTA per-wave** (B3-A1 — cấm neo tuyệt-đối vì thứ tự ship: K1 = +1 key/+4 policy · K3 = +8 key/+32 policy; mỗi commit kèm lệnh đếm lại `MenuKeys.All` thực tế + cập nhật 2 row STATUS, đừng Goodhart giữ-số-đứng-yên). Acceptance += "login Admin THẤY leaf trong sidebar ×2 app" + 1 test seed-grant. 2. 🔴 **[L1-F5] GỠ phương án (i) tại site `:342`** — nền đọc NGƯỢC comment (`WorkflowService.cs:36-43` mô tả NGUỒN COPY và khẳng định KHKK CỐ Ý không có site gán-qua-BIẾN; `:342` nằm trong `ReturnOrRejectAsync` chỉ nhận TraLai/TuChoi literal — DaDuyet **unreachable** qua đó). GIỮ phương án (ii): test khóa khẳng định điều đó. Cấm "sửa" :342. 3. 🔴 **[L2-H2] K3 thêm việc (d): sweep cụm ép-false** — `grep -rn "AllowApproverFinalize|AllowApproverSkipToFinal"` toàn src + fe-*: gỡ đủ **CREATE ép-false server-side** `ApprovalWorkflowV2AdminFeatures.cs:380-381` + **PUT Conflict** `:591-594`/`:605-610` + **FE `levelFlagsPayload`** `ApprovalWorkflowsV2Page.tsx:247-258` (`earlyFinalizeLocked :638`) — không chỉ note `:151-152`. Test mới: "tạo version qua CreateCommand type-10 GIỮ được cờ". 4. 🔴 **[L2-H3] `KhkkCreatePage` ×2 app PHẢI SỬA** (mâu thuẫn nền: command +`ApprovalGroup` required nhưng page ghi "KHÔNG-ĐỔI") — body POST thêm `approvalGroup` + picker nhóm. Acceptance += "tạo phiếu nhóm 2 **TỪ UI** ×2 app" (curl-only không đủ). @@ -19,7 +19,9 @@ K1 master-data danh mục (86 row) · K2 phiếu mang hạng-mục + nhóm + fre 12. **[L1-F3/F4] Trích dẫn `:44-46` ĐỦ + khai supersede**: nguyên văn có "chủ dự án phán 'PHÁ VỠ' @S155" — spec PHẢI khai K3 = **ĐẢO phán quyết cũ theo lời owner @S164**, kèm việc (e): sửa comment `:36-43`/`:44-46` + 2 lệnh tự-kiểm `:292-293` dán PR + cập nhật `KhkkWorkflowPanel.tsx:8` ×2 app + HANDOFF:77. ✅ **[OG-9 CHỐT @S164]** anh xác nhận TƯỜNG MINH: *"đúng, chỗ budget chốt chặn là a Chương… vậy bài toán trần budget xem như đóng"* ⇒ đảo "PHÁ VỠ" @S155 hợp lệ — **K3 (a)-(e) HẾT CHẶN**. Kèm: NĐUQ = human-gate VĨNH VIỄN (không còn wave enforce-máy nào; xóa mọi ý "opt-in sau"). ## ③ Checklist final cụm-1 -- [ ] K1: 7 mục nền + **"Admin thấy leaf sidebar ×2 app"** + test seed-grant + drift 2 row STATUS khai cùng commit. +- [ ] K1: 7 mục nền + **"Admin thấy leaf sidebar ×2 app"** + test seed-grant + drift DELTA khai cùng commit. +- [ ] K2 (+B3-A6): nút **"Tạo thêm cho nhóm khác"** (OG-7 UI-hướng-1) CHỦ = K2, site picker/PE-flow `ContractSigningPlanFeatures.cs:1201-1202` + PE-detail — acceptance TỪ UI: PE có phiếu → thấy phiếu + nút phụ, bấm → form preset nhóm khác → 201. +- [ ] K3 (+B3-B3 câu-ranh): fe-admin `resolvePath` nới **CHỈ họ `AwV2_KhkkN*`** — **CẤM nới họ `Khkk_*`** (fe-admin thiếu WorkflowMatrixViewPage; phép-âm: grep route Khkk_ fe-admin = 0). - [ ] K2: 8 mục nền + **submit-guard null-CatalogEntryId (test ÂM trên phiếu có line)** + phase-guard line-edit + Σ×3 nhất quán + Mig-71 6 item + 3-file + backfill=1 + **UI tạo-phiếu-nhóm-2 ×2 app** + bảng 18 consumer (17 nền + :712-713). - [ ] K3 (SAU OG-9): 6 mục nền + sweep ép-false ≥4 site + test giữ-cờ-qua-CreateCommand + đo danh tính roster + comment/panel/HANDOFF cập nhật + verify LIVE trước seed. - [ ] Mọi wave: test ≥590+k khai k · cicd PASS · BE-only smoke API (#77 chỉ khi FE-ship). diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum2-chi-tiet-31-07-2026.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum2-chi-tiet-31-07-2026.md index b79f673..2f7eaf1 100644 --- a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum2-chi-tiet-31-07-2026.md +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum2-chi-tiet-31-07-2026.md @@ -25,7 +25,7 @@ K4 sidebar 8 nhóm × 6 leaf (49 row menu mới) · K5 cây sub-folder groups · - [ ] K4a (ship 1 khối): 49 row menu VÀO All + labelBackfill G1 + route regex resolvePath ×(fe-user; fe-admin GHI RÀNG BUỘC) + 3-site grant (+dòng site-4 đã-soi) + nhãn N2 sửa + comment :1959/:179 vá. Acceptance: Admin + 1 user thường THẤY 8 group sidebar fe-user; 42 leaf BẤM ĐƯỢC (không null-route); drift DELTA khai + đo lại All; SQL JOIN đếm designer đúng N; restart ×2 số row menu/permission KHÔNG đổi (idempotent + revoker-proof). - [ ] K4b: 4 leaf list + Thao tác preset — derive phase+group từ searchParams; `queryKey` += group; acceptance bấm leaf→leaf ĐỔI kết quả không cần F5; URL G1 6 leaf mang `group=1`. - [ ] K4c (sau K3): WfView lọc `Code==='KHKK-N'+n`. -- [ ] K5: `groups` mang leaves thật (không đường `content`) + GĐ2 by `approvalGroup` + GĐ3/4 by `c.type` + HIỆN ĐỦ 8 + fallback chưa-phân-nhóm + Σ sub-folder == tổng phiếu; SHA-identical 4 file pipeline ×2 app (lệnh đo từng file); build ×2 PASS. +- [ ] K5: `groups` mang leaves thật (không đường `content`) + GĐ2 by `approvalGroup` + GĐ3/4 by `c.type` + HIỆN ĐỦ 8 + fallback chưa-phân-nhóm + Σ sub-folder == tổng phiếu; SHA-identical 4 file pipeline ×2 app (lệnh đo từng file); build ×2 PASS. **+forward-provision (B3-A5, việc cụm-3 vá-4b đẻ cho K5):** builder GĐ3/GĐ4 nối qua **TẬP `lines[].contractId` ∪ `pe.contractId` legacy** — không thì HĐ thứ 2+ (OG-1 UI-1-1, N HĐ/PE) vô hình trên cây. - [ ] K6: blacklist 12-key tường minh + acceptance liệt kê ĐÚNG N mục lá (tên + đếm, dư/thiếu 1 = FAIL) + `git diff --stat -- fe-user/src` = 0 file + comment ràng-buộc-ngược land. - [ ] Test (lead-note bù L3): seed-menu idempotent ×2 · labelBackfill đổi-label-không-nhân-row · route-map FE có leaf nào null-path = FAIL (unit nhỏ nếu khuôn có; không thì acceptance tay + chụp). Baseline ≥590+k khai k. diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-implbe-k1.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-implbe-k1.md new file mode 100644 index 0000000..5a9d463 --- /dev/null +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-implbe-k1.md @@ -0,0 +1,12 @@ +# impl-be K1 + +## Tiến độ +- [ ] Đọc spec (4 nguồn) + +## Lệch spec (nếu có) +_(chưa có)_ + +## Kết quả build/test +_(chưa chạy)_ + +(ĐANG LÀM) diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-review-fable-b3.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-review-fable-b3.md index 7ee5a4c..1a56936 100644 --- a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-review-fable-b3.md +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-review-fable-b3.md @@ -24,39 +24,102 @@ - **Rủi ro thật:** comment `:2204` *"quên 1 bên = quyền lệch"* + cụm-2 vá-15 dạy khuôn TRONG-All có thể xúi builder "cho đủ bộ" nhét cả 9 key vào `KhkkKeys()`. **Fix 1 dòng:** thêm vào cụm-1 vá-1: *"9 key này KHÔNG vào `KhkkKeys()`/site-2/3 — chỉ All (+Admin-loop)"*. Verdict: KHÔNG mâu thuẫn, cần 1 câu chốt ranh. - Designer fe-user: KHÔNG thấy và KHÔNG NÊN — fe-user không route System subtree; đường thấy duy nhất = fe-admin (K6 CHỪA `ApprovalWorkflowsV2 :1801`). -### A-3. Chuỗi ApprovalGroup K2→K4b→K5 — (nháp sau cụm-2, chờ cụm-3 vá-5 T2) -- K2 CHỦ (cột + backfill=1 + param `group` + DTO `:34` + picker create cụm-1 vá-4) → K4b tiêu thụ (queryKey += group `spec-cum2:10` vá-3 · phase+group từ searchParams vá-5 · preset `?group=` vá-6) → K5 group-by `approvalGroup` + hiện đủ 8 + fallback NULL-group (vá-9). Chuỗi schema→API→list→tree ĐỦ 1 đường tính đến cụm-2. Chờ soi cụm-3 vá-5 "T2-sau-K2" rồi chốt. +### A-3. Chuỗi ApprovalGroup K2→K4b→K5→K7 — **VẼ ĐỦ 1 ĐƯỜNG** ✅ +- K2 CHỦ DUY NHẤT (cột + backfill=1 + DROP-unique-cũ + param `group` + DTO `:34` + picker create cụm-1 vá-4; luật l3-F6 "K3 chỉ đọc" giữ nguyên `spec-tong:13`) → K4b tiêu thụ (queryKey += group `spec-cum2:10` vá-3 · phase+group từ searchParams vá-5 · preset `?group=` vá-6) → K5 group-by `approvalGroup` + hiện đủ 8 + fallback NULL-group (vá-9) → K7 test T2 (gộp 2 line cùng NCC) khai tường minh phụ-thuộc Mig-71-DROP-unique, chạy SAU K2 (`spec-cum3:15` vá-5 — chính cụm-3 tự vá cái sót của nền mình). Verdict: chuỗi schema→API→list→tree→test KHÉP KÍN, không mắt xích nào vô chủ. -### A-4. Freeze QĐ9 — nháp sau cụm-1 (chờ cụm-3 vá-10) -- Cột runtime `EndedByLevelFinalize`: tổng `:46` OG-3-SỬA "(b) forward-provision vào Mig 71 ⇒ K3 0-mig" **KHỚP** `spec-cum1:14` vá-7 (Mig 71 item 6 + tên mig `AddKhkkApprovalGroupCatalogAndFinalizeRuntime` + khai ghost-window K2→K3). ✅ cùng 1 cột. -- ⚠️ **Snapshot budget (QĐ9 "phiếu DaDuyet đọc SNAPSHOT, mirror Mig 67 11-cột") KHÔNG THẤY trong cụm-1**: Mig 71 chỉ 6 item (1-5 nền + EndedByLevelFinalize), KHÔNG có cột snapshot; freeze cụm-1 = tổ hợp {vá-2 test-khóa :342-unreachable (`WorkflowService.cs`) + vá-6 phase-guard line-edit kéo về K2 + vá-8 "list thêm Σ Approved sau freeze"} ⇒ thiết kế freeze = **immutability-live** chứ KHÔNG snapshot-read. MERGE-PENDING `:19` của tổng **CHƯA merge** vào cụm-1 final. Chờ cụm-3 vá-10 rồi phán. -- 🪤 Bẫy **":342 hai file khác nhau"**: tổng QĐ2 dùng `:342-347` = `ContractSigningPlanFeatures.cs` (rào 1-PE-1-phiếu, K2 ĐỔI); cụm-1 vá-2 dùng `:342` = `WorkflowService.cs` (`ReturnOrRejectAsync`, CẤM sửa — DaDuyet unreachable). Builder đọc lướt sẽ sửa nhầm site. Cần 1 câu định-danh-file trong spec build. +### A-4. Freeze QĐ9 — cột runtime KHỚP 3 spec ✅ · **tổng hứa snapshot+display-gate mà KHÔNG cụm nào nhận** 🔴 +- Cột runtime `EndedByLevelFinalize`: tổng `:46` OG-3-SỬA "(b) forward-provision vào Mig 71 ⇒ K3 0-mig" **KHỚP** `spec-cum1:14` vá-7 (Mig 71 item 6 + tên mig + ghost-window K2→K3) **KHỚP** `spec-cum3:17` vá-7 (B6 đổi neo, thừa nhận "vật K3 MỚI ĐẺ, hiện 0 hit"). ✅ 3 spec cùng 1 cột trên bảng plan KHKK. +- 🔴 **Snapshot + display-gate của QĐ9 tổng (`:19` "mirror nguyên khuôn PE Mig 67: snapshot 11 cột + display-gate `frozen`") KHÔNG AI LÀM**: Mig 71 cụm-1 chỉ 6 item — 0 cột snapshot; không vá nào ở 3 cụm nhắc display-gate. Thiết kế THẬT trong cụm = **copy-at-create + immutability**: line đã mang bản chép (`PeReferenceAmount` `Line.cs:6,:16-20` + `TenHangMuc` + `ApprovedAmount` per-line) + phase-guard line-edit kéo về K2 (cụm-1 vá-6) + test-khóa 1-site-DaDuyet (cụm-1 vá-2 — verify đĩa: `ContractSigningPlanWorkflowService.cs:37-38` khai "ĐÚNG MỘT nhánh set DaDuyet", `:129/:134` ReturnOrReject chỉ TraLai/TuChoi, `:278` site duy nhất, `:289-292` helper choke-point + lệnh grep tự-kiểm) + **răng đo = cụm-3 vá-10** (`spec-cum3:22` sửa NGUỒN sau finalize → reload → số KHÔNG đổi, đo CẢ 2 nhánh CCM-finalize VÀ lên-CEO — phép đo TRƯỢT ĐƯỢC ✓ đạt sàn-sự-thật). +- **Phán:** thiết kế cụm HỢP LÝ HƠN khuôn Mig 67 (KHKK line vốn denormalized-at-create, PE thì display JOIN live nên mới cần snapshot) — nhưng tổng QĐ9 đang là VĂN STALE hứa vật không ai giao. Fix: sửa đoạn QĐ9 tổng thành "freeze KHKK = copy-at-create + phase-guard + test-khóa 1-site + phép đo 2-nhánh vá-10; KHÔNG mig snapshot mới; nếu vá-10 đo FAIL (lộ chỗ display đọc live) → lúc đó mới mở mig snapshot bổ sung". Không sửa thì builder K2 sẽ đi tìm "11 cột snapshot" không tồn tại trong cụm-1. Verdict: **MÂU THUẪN #2 — phải vá TỔNG theo cụm trước build.** +- 🪤 Bẫy **":342 hai file khác nhau"**: tổng QĐ2 dùng `:342-347` = `ContractSigningPlanFeatures.cs` (rào 1-PE-1-phiếu, K2 ĐỔI); cụm-1 vá-2 dùng `:342` = `ContractSigningPlanWorkflowService.cs` (`ReturnOrRejectAsync`, CẤM sửa — DaDuyet unreachable). Builder đọc lướt sẽ sửa nhầm site. Spec build phải ghi TÊN FILE cạnh mọi ":342". + +### A-5. Cây GĐ3: cụm-3 ĐẺ VIỆC cho K5 mà spec cụm-2 KHÔNG BIẾT 🔴 +- `spec-cum3:14` vá-4(b) gắn nhãn tường minh "**K5-liên-đới**: builder GĐ3/GĐ4 nối qua TẬP `lines[].contractId` của các phiếu KHKK thuộc gói (∪ `pe.contractId` legacy)" — nhưng `spec-cum2:28` checklist K5 chỉ có "GĐ2 by `approvalGroup` + GĐ3/4 by `c.type` (đã có `:240`)", **0 chữ về `lines[].contractId`**. Cây hiện đi `pe.contractId` ĐƠN (`usePipelineStages.ts:214-218`, khớp giới-hạn HĐ[0] đã khai S162 `CreateContractFromEvaluationFeatures.cs:145`). +- Hậu quả nếu không vá: K5 (land trước) build đúng spec cụm-2 → K7 bridge ghi `Line.ContractId` per-line → HĐ thứ 2+ **vô hình trên cây** (vá-4(a) `pe.ContractId ??=` chỉ cứu HĐ đầu); muốn sửa phải chạm lại 2 file pipeline SAU K5 → re-run SHA-identical + build ×2 ngoài kế hoạch. +- **Fix 1 dòng vào cụm-2 K5:** "GĐ3/4 nguồn HĐ = ∪ `lines[].contractId` ∪ `pe.contractId` legacy (forward-provision — trước K7 tập lines rỗng, cây không đổi hành vi)" + acceptance "phiếu 2 line 2 HĐ → cây hiện 2" (chạy được từ K7). Verdict: **MÂU THUẪN #3 — phải vá cụm-2 trước build K5.** ### A-x. Drift consumer-count tổng ⟂ cụm-1 - Tổng `:12` QĐ2: *"acceptance rà **16 consumer** (10 BE + 6 FE — l3-F18)"* ⟂ `spec-cum1:23` checklist K2: *"bảng **18 consumer** (17 nền + :712-713)"*. Cụm-1 THẮNG theo luật vá (nền 17 + vá-8 thêm 1 = 18) nhưng tổng chưa sửa số ⇒ builder đọc tổng trước sẽ rà thiếu 2. Fix 1 dòng ở tổng khi ship. ### A-6. OG-7 UI-hướng-1 — 2 cửa tạo phiếu nhóm 2 KHÔNG chỏi, nhưng NÚT PHỤ chưa có chủ (nháp sau cụm-2) - Cửa 1: KhkkCreatePage + picker nhóm (cụm-1 vá-4, thuộc K2). Cửa 2: leaf "Thao tác" preset `?group=` (cụm-2 vá-6, K4b — 0 phụ thuộc K3, chỉ cần picker vá-4). 2 cửa cùng đổ về 1 form — KHÔNG trùng/chỏi. -- ⚠️ Nhưng OG-7 tổng `:45` hứa UX cụ thể: *"PE có phiếu rồi → hiện phiếu + **nút phụ 'Tạo thêm cho nhóm khác'** (thay 409 chặn hẳn)"* — grep cả cụm-1 lẫn cụm-2: KHÔNG vá nào nhận việc "nút phụ" này (cụm-1 vá-4 = picker nhóm; K2 đổi picker PE `:1201-1202` = gỡ filter PE-đã-có-phiếu; cụm-2 vá-6 = preset group). Acceptance cụm-1 "tạo phiếu nhóm 2 TỪ UI ×2 app" đo được OUTCOME nhưng không ép UX hướng-1. → LỖ CHỦ-VIỆC nhỏ: cần 1 dòng gán "nút phụ + hiện-phiếu-thay-chặn" về K2 (cùng site picker) hoặc tuyên bố 2-cửa-là-đủ-default và hạ câu OG-7 xuống mô tả hành vi picker. Chờ cụm-3 xem có ai nhận không. +- ⚠️ Nhưng OG-7 tổng `:45` hứa UX cụ thể: *"PE có phiếu rồi → hiện phiếu + **nút phụ 'Tạo thêm cho nhóm khác'** (thay 409 chặn hẳn)"* — soi CẢ 43 vá 3 cụm: KHÔNG vá nào nhận việc "nút phụ" này (cụm-1 vá-4 = picker nhóm; K2 đổi picker PE `:1201-1202` = gỡ filter PE-đã-có-phiếu; cụm-2 vá-6 = preset group; cụm-3 = K7/K8 không đụng). Acceptance cụm-1 "tạo phiếu nhóm 2 TỪ UI ×2 app" đo OUTCOME nhưng không ép UX hướng-1 mà owner đã ratify verbatim. **Verdict: LỖ CHỦ-VIỆC (mâu thuẫn hứa⟂giao) — fix 1 dòng gán về K2** (cùng site picker `:1201-1202`: chọn PE đã-có-phiếu → hiện danh sách phiếu hiện có + nút "Tạo thêm cho nhóm khác" thay vì message chặn); không nên hạ lời OG-7 vì đó là lời chốt của owner. -## B. Vá-đè-vá (vá cụm sau có phá vá cụm trước?) -(ĐANG LÀM — cặp nghi tính đến cụm-2; chờ cụm-3 để chốt 43 vá) +## B. Vá-đè-vá (vá cụm sau có phá vá cụm trước?) — soi 43 vá (12+15+16), 7 cặp nghi -| # | Cặp | Verdict nháp | +| # | Cặp | Verdict | |---|---|---| -| B-1 | cụm-1 vá-6 (kéo phase-guard line-edit K4b→K2) ⟂ cụm-2 K4b checklist | ✅ SẠCH — cụm-2 final K4b (`spec-cum2:26`) KHÔNG còn nhắc phase-guard ⇒ move đã được cụm-2 tôn trọng, không mồ côi không trùng | -| B-2 | cụm-2 vá-6 (Thao tác preset VỀ K4b) ⟂ tổng K4b "chờ K2 param" | ✅ SẠCH — dependency K2 giữ nguyên, chỉ gỡ phụ thuộc K3 giả | -| B-3 | tổng K3 "mở resolvePath **fe-admin** `Layout.tsx:166-172` nhận code mới" ⟂ cụm-2 vá-8 "**KHÔNG nới regex fe-admin** đợt này" | ⚠️ KHÔNG phá nhau NHƯNG dễ đọc nhầm thành phá: 2 câu nói về 2 HỌ key khác nhau trên CÙNG file/hàm — K3 nới cho `AwV2_KhkkN*` (designer, System subtree, vẫn hiện sau K6) · vá-8 cấm nới cho `Khkk_*` 48-leaf (KeHoachKyKet bị ẩn admin + fe-admin THIẾU `WorkflowMatrixViewPage`). Cần 1 câu ranh trong spec build: "fe-admin resolvePath: THÊM pattern AwV2_KhkkN* — CẤM thêm pattern Khkk_*" kẻo builder K3 tiện tay nới cả hai | -| B-4 | cụm-1 vá-2 (CẤM sửa `WorkflowService.cs:342`) ⟂ tổng QĐ2 "đổi rào :342-347" | ✅ KHÔNG đụng nhau về máy — 2 file khác nhau trùng số dòng (`Features.cs:342-347` rào 1-PE-1-phiếu PHẢI đổi · `WorkflowService.cs:342` unreachable CẤM đụng); nhưng là bẫy-đọc-lướt đã ghi ở A-4, spec build phải ghi TÊN FILE cạnh mọi ":342" | +| B-1 | cụm-1 vá-6 (kéo phase-guard line-edit K4b→K2) ⟂ cụm-2 K4b checklist | ✅ SẠCH — cụm-2 final K4b (`spec-cum2:26`) KHÔNG còn nhắc phase-guard ⇒ move được cụm-2 tôn trọng, không mồ côi không trùng | +| B-2 | cụm-2 vá-6 (Thao tác preset VỀ K4b) ⟂ tổng K4b "chờ K2 param" | ✅ SẠCH — dependency K2 giữ nguyên, chỉ gỡ phụ thuộc K3 giả; đúng điều kiện "chỉ cần picker vá-4 cụm-1" | +| B-3 | tổng K3 "mở resolvePath **fe-admin** `Layout.tsx:166-172`" ⟂ cụm-2 vá-8 "**KHÔNG nới regex fe-admin** đợt này" | ⚠️ KHÔNG phá nhau NHƯNG dễ đọc nhầm thành phá: 2 HỌ key khác nhau trên CÙNG file/hàm — K3 nới cho `AwV2_KhkkN*` (designer, System subtree, vẫn hiện sau K6) · vá-8 cấm nới cho `Khkk_*` 48-leaf (KeHoachKyKet bị ẩn admin + fe-admin THIẾU `WorkflowMatrixViewPage` — L1-BÁC-2). **Cần 1 câu ranh:** "fe-admin resolvePath: THÊM pattern `AwV2_KhkkN*` — CẤM pattern `Khkk_*`" kẻo builder K3 tiện tay nới cả hai | +| B-4 | cụm-1 vá-2 (CẤM sửa `WorkflowService.cs:342`) ⟂ tổng QĐ2 "đổi rào :342-347" | ✅ KHÔNG đụng về máy — 2 file trùng số dòng (`Features.cs:342-347` rào 1-PE-1-phiếu PHẢI đổi · `WorkflowService.cs:342` unreachable CẤM đụng — verify đĩa `:129/:134/:278`); bẫy-đọc-lướt, spec build ghi TÊN FILE cạnh mọi ":342" | +| B-5 | cụm-3 vá-4(b) (K5 nối `lines[].contractId`) ⟂ cụm-2 K5 checklist | 🔴 KHÔNG phá vá cũ nhưng ĐẺ VIỆC vào wave cụm-2 mà spec cụm-2 không chứa = A-5 mâu-thuẫn #3 — vá spec cụm-2 trước build K5 | +| B-6 | cụm-3 vá-7 (B6 đổi neo `EndedByLevelFinalize` "vật K3 mới đẻ") ⟂ cụm-1 vá-7 (cột vào Mig 71/K2, K3 wire) | ✅ SẠCH — nhất quán: cột đẻ ở K2-mig (nằm im, ghost-window đã khai), K3 wire, K7-B6 neo tùy nhánh; 3 spec cùng 1 cột (A-4 ý 1) | +| B-7 | cụm-3 vá-12 (TRƯỚC K2 rào per-PE ⇒ phiếu ZZTEST khóa TOÀN BỘ PE thật) ⟂ cụm-1 K2 đổi rào | ✅ SẠCH — cụm-3 nhận thức đúng thứ tự (K8 CUỐI sau mọi wave + nghiêng phương án (b) PE-ZZTEST-riêng); không đè, chỉ ràng thêm điều kiện chạy-sau | + +**Verdict B: 0 vá cụm sau LÀM VÔ HIỆU vá cụm trước.** 7 cặp nghi xét: 5 sạch · 2 cần câu-ranh/vá-spec (B-3 câu ranh 2-họ-key · B-5 = A-5). ## C. Build-order cuối + gate -(ĐANG LÀM) -## D. Rủi ro còn hở -(ĐANG LÀM) +**Thứ tự chốt: K1 → K2 → K3 → K4a → K4b → K5 → K4c → K6 → K7 → K8** (10 đơn vị build; khớp đề xuất lead, KHÔNG đổi trình tự — chỉ siết gate). Lý do giữ K4a SAU K3 dù "0 phụ thuộc code" (l3-F8 cho song song): tránh cửa-sổ-prod 8-leaf-chưa-lọc (trước K2 API không có param `group` ⇒ 42 leaf hiện CÙNG nội dung) + nhãn 8 group cần anh gật (cụm-2 vá-7) — kéo song song chỉ khi owner chấp nhận 2 điều đó tường minh. + +| Wave | PRE-gate owner | Mig | Restart BE | Deploy | Test-k | +|---|---|---|---|---|---| +| K1 | **OG-6 ✅ (soát 86 dòng — chặn SEED, code build trước được) + OG-5 hỏi-khi-gặp** | Mig 70 (3-file) | ✅ | BE + FE ×2 (leaf catalog) → #77 | +k khai (seed-idempotent, CRUD) | +| K2 | 0 (OG-1/7 ✅ rồi) — PRE-spec-fix A-1 (lead) | Mig 71 (6 item, DROP unique cũ, backfill=1) | ✅ | BE + FE ×2 (picker+create) → #77 | +k (Σ trước==sau · 409-có-line · UI-nhóm-2 · 18-consumer) | +| K3 | OG-2 ✅ + **verify đội hình LIVE trước seed** + OG-9 ✅ | 0-mig (cột đã forward-provision K2) | ✅ (seed 8 WF + sweep ép-false) | BE + fe-admin (designer + resolvePath AwV2) → #77 | +k (8 WF · pin-sai-nhóm 409 · giữ-cờ-qua-Create · danh-tính roster · finalize 2-nhánh) | +| K4a | **8 nhãn đính file OG-6 — anh gật** | 0-mig | ✅ (seed 49 row + 3-site) | BE + fe-user (route regex) → #77 | +k (idempotent ×2 restart · SQL JOIN designer · 42 leaf bấm được) | +| K4b | 0 (sau K2) | 0 | — | FE ×2 → #77 | acceptance leaf→leaf đổi kết quả không F5 | +| K5 | 0 (sau K2) — PRE-spec-fix A-5 (lead) | 0 | — | FE ×2 → #77 | SHA-identical 4 file ×2 app + Σ sub-folder == tổng | +| K4c | 0 (sau K3) | 0 | — | fe-user → #77 | WfView lọc `Code==='KHKK-N'+n` | +| K6 | 0 (sau K3 — acceptance đếm 8 designer) | 0 | — | fe-admin → #77; `git diff --stat -- fe-user/src` = 0 | liệt kê ĐÚNG N mục lá (dư/thiếu 1 = FAIL) | +| K7 | câu III không chặn code (default dialog); acceptance "ai bấm" treo [CHỜ-ANH] | 0 | ✅ (grant `Contracts.Create`) | BE + FE ×2 → #77 | 8+2 authz 2-chiều + idempotency-double-click + cây 2-HĐ | +| K8 | **câu V (nghiêng (b) PE-ZZTEST-riêng) + câu III + B0-form 14/14 fail-closed + dặn team notification** | 0 | — | 0 code | 17 bước chụp + QĐ9 đo 2 nhánh + rollback theo ID | + +**3 spec-fix bắt buộc TRƯỚC wave tương ứng (lead tự làm, không cần owner):** ① A-1 cụm-1 vá-1 → DELTA per-wave (trước K1-commit-STATUS) · ② A-4 tổng QĐ9 → khai thiết kế copy-at-create thay snapshot-hứa (trước K2) · ③ A-5 cụm-2 K5 +1 việc `lines[].contractId` (trước K5). **5 vá 1-dòng cùng đợt:** A-0a sweep "opt-in sau" · A-0b đếm header tổng · A-x 16→18 consumer · A-6 nút-phụ gán K2 · SHA 2-file→4-file thống nhất (tổng `:30` theo cụm-2 `:28`). + +## D. Rủi ro còn hở (top-5 sau 43 vá — mỗi cái 1 guard) + +1. **QĐ9 không có snapshot dự phòng** — nếu phép đo 2-nhánh (cụm-3 vá-10) FAIL vì lộ chỗ display đọc live (kiểu PE pre-Mig-67) → phát sinh mig ngoài kế hoạch giữa chuỗi wave. *Guard:* chạy phép đo 2-nhánh trên **Dev NGAY SAU K3 land** (integration test hoặc tay), đừng để nó xuất hiện lần đầu ở K8-prod. +2. **Ghost-window K2→K3 + seed cờ sớm = config-lie #78** — `AllowApproverFinalize=true` cấp CCM-Chương seed TRƯỚC khi nhánh (a) land thì designer nói dối. *Guard:* K3 checklist đặt "seed cờ" là mục CUỐI + gate `grep AllowApproverFinalize=true` 0-hit trước mục đó (đúng thứ tự OG-3 tổng `:46` đã ghi — giữ nguyên, đừng để builder đảo). +3. **fe-admin resolvePath 2-họ-key, 2 wave chạm cùng hàm** (B-3) — builder K3 nới luôn `Khkk_*` → 48 leaf hiện trên fe-admin thiếu `WorkflowMatrixViewPage` → leaf chết. *Guard:* acceptance K3 thêm phép-âm "fe-admin sidebar đếm group `Khkk_*` = 0". +4. **Bridge authz chỉ gate FE = giả-an-toàn** — cụm-3 vá-1 nói "gate nút = HỘI 2 policy" + test 403, nhưng không câu nào bắt ENDPOINT bridge mang policy server-side; nếu builder gate FE-only, test 403 viết theo FE cũng giả-pass. *Guard:* 1 câu spec K7 "endpoint bridge mang CẢ 2 `[Authorize]` attribute (stack = AND: `KeHoachKyKet.Read` + `Contracts.Create`)" + test = **curl trần bỏ FE**. +5. **OG-6 transcribe gõ-tay-từ-ảnh, 4 ô ⚠️** — seed sai tên/vai → labelBackfill churn + khối ký GĐ4 in sai vai (TEXT không ràng máy — limitation QĐ4 đã khai). *Guard:* 4 ô ⚠️ phải được anh chốt TƯỜNG MINH trong lượt soát OG-6 (không để builder tự đoán); acceptance K1 "lệch giải trình từng dòng" giữ nguyên có răng. + +*(Ngoài top-5, đã có guard sẵn trong spec: B0-form fail-closed vá-9 · rollback theo ID vá-11/13 · phiếu-ZZTEST-khóa-PE-thật vá-12 nghiêng phương án (b).)* ## E. GO/NO-GO per wave -(ĐANG LÀM) -## F. Digest trình owner -(ĐANG LÀM) +| Wave | Verdict | Điều kiện | +|---|---|---| +| K1 | **GO (code) + GATE seed** | Seed land CHỈ SAU OG-6 ✅ (86 dòng + 4 ô ⚠️ anh chốt); code/mig/test build trước được | +| K2 | **GO** | OG-1/OG-7 ✅ rồi; PRE = spec-fix A-1 (1 dòng, lead) | +| K3 | **GO** | OG-2/OG-9 ✅; verify đội hình LIVE + sweep ép-false ≥4 site + seed-cờ mục CUỐI (D-2) | +| K4a | **GO + GATE nhãn** | 8 nhãn (kèm N2 sửa "phá dỡ") anh gật trong file OG-6 trước seed menu | +| K4b | **GO** | Sau K2 | +| K5 | **GO** | Sau K2; PRE = spec-fix A-5 (1 dòng, lead) | +| K4c | **GO** | Sau K3 | +| K6 | **GO** | Sau K3 (acceptance đếm 8 designer) | +| K7 | **GO** | Sau K2+K3; câu III chỉ treo acceptance "ai bấm" [CHỜ-ANH], không chặn code (default dialog người-có-quyền); server-side hội-2-khóa theo D-4 | +| K8 | **NO-GO tới khi đủ 4 điều kiện** | (1) mọi wave land · (2) câu V chốt — nghiêng (b) PE-ZZTEST-riêng · (3) câu III chốt · (4) B0-form 14/14 điền đủ (fail-closed) — NO-GO này là ĐÚNG THIẾT KẾ (wave cuối), không phải lỗi spec | + +**Tổng: GO = 9/10 · NO-GO = 1/10 (K8, by-design).** Toàn chuỗi GO cho B4 với điều kiện 3 spec-fix nặng (A-1/A-4/A-5) + 5 vá 1-dòng land TRƯỚC wave tương ứng — tất cả lead tự làm được, owner-gate còn lại: OG-6 (K1-seed + K4a-nhãn) · câu III/V (K7-acceptance/K8). + +## F. Digest trình owner (≤15 dòng) + +1. Em rà chéo 4 spec final (tổng v2 + cụm-1 12 vá + cụm-2 15 vá + cụm-3 16 vá = 43 vá): **GO 9/10 wave — chỉ K8 dry-run chờ anh** (câu V + câu III + form 14 người), đúng thiết kế wave cuối. +2. Thứ tự build chốt: **K1→K2→K3→K4a→K4b→K5→K4c→K6→K7→K8** (bảng gate/mig/deploy ở mục C). +3. Phát hiện **8 mâu-thuẫn liên-spec — 0 cái chạm máy-đã-chốt, toàn vá được bằng sửa chữ spec**: 3 nặng phải vá trước build + 5 nhẹ 1-dòng. +4. Nặng ①: cụm-1 còn neo số tuyệt đối (55→64) trong khi cụm-2 cấm đúng kiểu neo đó — đổi cụm-1 sang khai DELTA per-wave. +5. Nặng ②: tổng QĐ9 hứa "snapshot 11 cột + display-gate mirror PE Mig 67" nhưng KHÔNG cụm nào nhận việc này — thiết kế thật trong cụm (copy-at-create + khóa sửa + phép đo 2 nhánh trượt-được) HỢP LÝ HƠN, em đề nghị sửa văn tổng theo cụm. +6. Nặng ③: cụm-3 giao thêm việc cho cây K5 (nối HĐ qua `lines[].contractId`) mà spec cụm-2 không biết — thêm 1 dòng vào K5 kẻo HĐ thứ 2 trở đi vô hình trên cây. +7. Vá-đè-vá: soi 7 cặp nghi trên 43 vá — **0 vá cụm sau phá vá cụm trước**; 2 chỗ cần câu ranh giới (regex fe-admin 2 họ key · ":342" trùng số dòng ở 2 file khác nhau). +8. OG còn treo: **OG-6** (anh soát 86 dòng danh mục + 8 nhãn menu — chặn seed K1 + K4a) · OG-5 (hỏi khi gặp) · câu III "ai bấm bridge" · câu V "PE test riêng hay PE thật". +9. Rủi ro #1: nếu phép đo freeze 2-nhánh FAIL (lộ chỗ đọc live) → phát sinh mig ngoài kế hoạch — em đề nghị chạy phép đo này trên Dev ngay sau K3, không đợi K8. +10. Rủi ro #2: cầu KHKK→HĐ phải khóa quyền ở SERVER (2 tầng policy), không chỉ ẩn nút FE — test bằng curl trần. +11. Rủi ro #3: quyền `Contracts.Create` hiện chưa cấp cho vai nào ngoài Admin — K7 sẽ cấp cho Drafter + Procurement (default, anh đổi được ở câu III). +12. Test: baseline 590 (STATUS:472) — mỗi wave khai +k, không wave nào được giảm. + +## END + +END sub-review-fable-b3 — TOTAL: 8 mâu-thuẫn (3 nặng A-1/A-4/A-5 + 5 nhẹ-1-dòng) · 0 vá-đè-vá (7 cặp xét, 2 cần câu-ranh) · GO=9/NO-GO=1