Files
solution-erp/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-review-fable-b3.md
2026-07-31 14:20:44 +07:00

22 KiB
Raw Blame History

sub-review-fable-b3 — B3 REVIEW CHỐT CUỐI 4 spec (tổng v2 + cụm-1 + cụm-2 + cụm-3)

Engine /fable-real · reviewer adversarial · đối chiếu CHÉO liên-spec → GO/NO-GO + build-order cuối cho B4. Luật đan xen: đọc 1 spec → ghi section NGAY.

A. Mâu thuẫn LIÊN-SPEC

(ĐANG LÀM — nháp sau spec tổng, chờ đối chiếu 3 cụm)

A-0. Nội-bộ spec tổng (phát hiện khi đọc lượt 1)

  • [A-0a] QĐ5 vs OG-3-nâng-cấp TỰ MÂU THUẪN trong CÙNG file: spec-4gd-khkk-tong-quat:15 QĐ5 còn nguyên "enforce (CeoApprovalThreshold) = wave opt-in sau" trong khi :52 ra lệnh "XÓA ý 'enforce máy = wave opt-in sau' khỏi mọi spec". Spec tổng tự vi phạm lệnh của chính nó → phải sweep cụm 1-3 xem câu này còn rớt ở đâu.
  • [A-0b] Đếm sai nội bộ: header ② ghi "8 quyết định (v2)" nhưng liệt 9 items (:11-19, QĐ9 budget-freeze mới @S164); END :54 ghi "6 OG" nhưng bảng ④ có 8 hàng (OG-1/2/3/5/6/7/8/9). Con số header/footer chưa sync sau khi chèn QĐ9 + OG-8/9.
  • **[A-0c] QĐ9 mang cờ "⚠️ 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ề" (:19) → kiểm tra cụm-1/cụm-3 đã nhận merge chưa (schema snapshot → K2, hook finalize → K3).

A-1. Drift số menu/policy — MÂU THUẪN THẬT, cụm-1 CHƯA nhất quán với cụm-2 🔴

  • spec-cum1:8 vá-1 neo TUYỆT ĐỐI: "Menu keys 55→64 · Policies 220→256 — khai 2 row STATUS cùng lúc"spec-cum2:9 vá-2 CẤM đúng kiểu neo đó: "Drift khai DELTA (+49/+196), CẤM neo 2 mốc tuyệt đối (64→113 chỉ đúng nếu cụm-1 land trước — thứ tự ship đang cho song song)". Cụm-2 BIẾT về mốc 64 của cụm-1 và phòng hộ cho mình, nhưng cụm-1 không được sửa ngược → 2 spec dạy builder 2 luật ngược nhau về CÙNG 2 row STATUS.
  • Thêm: 9 key của cụm-1 trải 2 wave (ContractCatalog = K1 +1 · 8 AwV2_KhkkN* = K3 +8) ⇒ "55→64" chỉ đúng tại K3-land; khai trọn ở K1 = STATUS nói dối suốt cửa sổ K1→K3.
  • Số học nội bộ tự khớp (9×4=36: 220→256 ✓ · 49×4=196: 256→452 ✓) — lỗi KHÔNG nằm ở arithmetic mà ở kiểu neo.
  • Fix 1 dòng (trước B4): sửa cụm-1 vá-1 thành DELTA per-wave (+1 @K1 · +8 @K3) + mọi commit khai drift kèm lệnh đo lại MenuKeys.All thực tế (mượn nguyên câu cụm-2 vá-2). Verdict: MÂU THUẪN #1 — phải vá spec trước build.

A-2. 3-site grant cụm-2 ⟂ 9-key cụm-1 — NHẤT QUÁN về máy, THIẾU 1 câu ranh giới

  • Cụm-2 3-site (spec-cum2:25 — seed :1780 · SeedKeHoachKyKetAccessAsync:2415 · KhkkKeys():2185) áp cho 49 row KHKK user-facing. Cụm-1 vá-1 (spec-cum1:8) chỉ đưa 9 key VÀO All — KHÔNG nói vào KhkkKeys(). Đọc máy: đúng như vậy là CHUẨN —
    • 8 AwV2_KhkkN* = menu-con dưới ApprovalWorkflowsV2 (System subtree, admin-only theo QĐ7 tổng :17 CHỪA System + AwV2); grant qua All-loop-Admin DbInitializer.cs:2058 là đủ. Đưa vào KhkkKeys() ⇒ 13 vai thường được CanRead menu designer = quyền-lệch (fe-user không có route → #50 drop im lặng, không vỡ UI nhưng bẩn grant + họ #85 menu-rộng-hơn-API).
    • ContractCatalog = leaf nhánh Catalogs/Master, KHÔNG thuộc cây KeHoachKyKet → không có lý do vào KhkkKeys(). Acceptance cụm-1 chỉ đo "login Admin thấy leaf ×2 app" — tức đợt này user thường KHÔNG thấy danh mục (chưa grant role thường). Chấp nhận được (danh mục = master admin nhập) nhưng nên khai 1 câu để owner biết.
  • 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→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 — 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)" — 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?) — soi 43 vá (12+15+16), 7 cặp nghi

# 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ả; đú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

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 #78AllowApproverFinalize=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

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