wal: flush 20260729T1843

This commit is contained in:
pqhuy1987
2026-07-29 18:43:24 +07:00
parent 8f37910552
commit f27fc3338f
8 changed files with 31 additions and 26 deletions

View File

@ -1,24 +1,25 @@
# WAL — auto-generated, không sửa tay # WAL — auto-generated, không sửa tay
updated: 2026-07-29T17:05+07:00 | session: S160 (phiên-LOGIC L8, window 2 — /pause PAUSE-2) | branch: main updated: 2026-07-29T18:45+07:00 | session: S161 (phiên-LOGIC L8, window 3 — /tiep nối PAUSE-2) | branch: main
goal: DRY-RUN TOÀN TRÌNH ĐẾN HỢP ĐỒNG CỨNG (lệnh anh @S160). Pipeline 5 bước đã qua 4/5 (2 invest → plan+7spec → clone-review → owner-decision+13fix → chốt-cuối). Còn: vá 3 dư-lượng nhỏ → hmw thi công từng wave. goal: DRY-RUN TOÀN TRÌNH ĐẾN HỢP ĐỒNG CỨNG. Pipeline 5 bước XONG + 4 dư-lượng ĐÃ VÁ @S161. Còn: 3 quyết owner trước W1 → hmw thi công từng wave.
chain: chain:
- [x] closeout arc-2 + đóng đầu việc (commit `1d3d167`; push chờ session-end squash) - [x] (S160 window-2: pipeline 4/5 + chốt-cuối GO-WITH-FIXES — xem `_context` PAUSE-2 + `sub-reviewer-chot-cuoi-s160.md`)
- [x] 2 lane /fable-real invest verified (lane-2 #53×1 resume sạch); +đo prod Contracts=0 (sổ S156 "7 HĐ V1" STALE) - [x] vá 4 dư-lượng @S161: DR-1 (W7 bảng §① b.19 → derive `InitialSigned`/`SealedCopy`, `has(ScannedSigned)`=0) · DR-2 (W3 anchor#5`ContractFeatures.cs:356-360`, verify đĩa đúng khuôn) · DR-3 (W1 + `:1256-1257` SkipToFinal, verify đĩa 2 dải đúng) · DR-4 CHỐT (spec-hoá nhánh ADMIN mirror PE `:731-748` vào W6 §②-4 + 1 vế acceptance admin-inbox — F-B13 verify đĩa: dict `:421-430` 0 ChoDuyet THẬT) + 1 site CÙNG-LỚP `plan-cha:75` (gỡ ScannedSigned khỏi derive option-A)
- [x] Plan cha + 7 spec-wave (W1-3,5-8; W4/W9 defer; 1 mig 69/W1) → `plan-cha-dry-run-toan-trinh-29-07-2026.md` - [x] ctx-verifier @tiep-2 CO-CO 10 cờ (biên-nhận `_tiep-2.md`) → vá ngay run.md ledger (hàng 2/3/4/6b flip [x] + xoá 2 dòng duplicate stale); còn lại → housekeeping
- [x] /fable-clone reviewer 6 lane (`wf_0eb994aa-a63`) → 5/5 SUA-TRUOC-THI-CONG; lead-verify 5 claim 5/5 CONFIRMED đĩa → `review-synthesis-clone-s160.md` - [!] CHỜ ANH 3 quyết trước W1 (report S161 đánh số): (1) mã phiếu KHKK `KHKK/{YYYY}/{Seq:D3}` · (2) viết tắt "MB" codegen · (3) GĐ4 option A (0-mig, default) / B (1-mig)
- [x] Owner-decision (AskUser): **W8=O-A để mở** + **đổi tên test khớp repo**; 13 fix NHÓM-2 áp trọn
- [x] /fable-real reviewer chốt cuối → **GO-WITH-FIXES** (reviewer #53 chết sau Trục-1+2, lead finalize on-behalf từ đĩa: 12/13 landed + 30 anchor CONFIRMED + 0 HIGH sót) → `sub-reviewer-chot-cuoi-s160.md`
- [!] vá 3 dư-lượng: DR-1 (W7 bảng §① badge còn ScannedSigned, §② đã sửa=half-fix) · DR-2 (W3 anchor#5 `PEWS:1008``ContractFeatures.cs:356-360`) · DR-3 (W1 anchor +`:1256-1257`) + check DR-4 (W6 admin-inbox ChoDuyet)
- [ ] hmw Opus-5-MAX thi công từng wave theo Plan cha (W1 đầu, mig 69) + gate 5-anchor mỗi wave + cicd 3-chân-kiềng - [ ] hmw Opus-5-MAX thi công từng wave theo Plan cha (W1 đầu, mig 69) + gate 5-anchor mỗi wave + cicd 3-chân-kiềng
- [ ] setup thủ công TRƯỚC W5 (SAU W1 vì type=10 cần mig 69): dựng workflow type=3 + type=10 3-trạm qua Designer (seed chỉ 1 trạm)
- [ ] housekeeping @pause/closeout kế: nén MIND-1 5.447B (trần `_mind` 83,2% — MIND-5 chắc vượt) · re-carry 2 ý D rơi (vá-GỐC-Phase-3.5-refresh {mới-nêu} CÒN SỐNG + khuôn-5-đợt→sổ bền {gần-chốt}) · STATUS:6 bổ arc dry-run S160 (mù có lý do — land 15:27 trước pipeline) · hạ nhãn DR/WF-3-trạm đã-định-đoạt · E đếm 7 sub-file (không 6) · mở lại slot-45 trần `_mind` (tiền-đề lật: file SỐNG 83,2%) · quyết bookkeeping OVERDUE:light (cặp H24 chạy @S159 bookend mà `last_audit` đứng 27)
next: /tiep → vá 3 dư-lượng DR-1/2/3 (con-trỏ `sub-reviewer-chot-cuoi-s160.md` §LỖI-MỚI) + check DR-4 → rồi hmw wave W1. Setup thủ công trước W5: dựng workflow type=3 + type=10 3-trạm qua Designer (seed chỉ 1 trạm). next: chờ anh trả lời (1)(2)(3) → hmw wave W1 (mig 69). Anh gật default hết ⇒ W1 chạy được ngay.
verify: verify:
- [!] `grep -n "ScannedSigned" .claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w7-ban-cung-hdc-29-07-2026.md` — bảng §① còn 1 hit cần đổi InitialSigned/SealedCopy (DR-1) - `grep -c "has(ScannedSigned)" .claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w7-ban-cung-hdc-29-07-2026.md` = 0 (DR-1)
- [!] `grep -n "1008" spec-wave-w3-duyet-3-tram-29-07-2026.md` — anchor#5 §③-A còn trỏ PEWS:1008 cần đổi (DR-2) - `grep -n "356-360" .claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w3-duyet-3-tram-29-07-2026.md` → :14 thân + :26 anchor#5 (DR-2)
- [!] `grep -n "1267-1268" spec-wave-w1-schema-designer-29-07-2026.md` — anchor cần thêm :1256-1257 (DR-3) - `grep -n "1256-1257" .claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w1-schema-designer-29-07-2026.md` :25 (DR-3)
- 🔴 O-3 "hợp đồng cứ từ từ" + O-A anh chốt @S160 = W8 KHÔNG siết, Contract để mở; rủi ro disclose plan §4.7 - `grep -cn "F-B13" .claude/workflows/runs/2026-07-29-S160-khkk-dryrun-plan/spec-wave-w6-duong-ong-hd-v2-29-07-2026.md` ≥ 2 (§②-4 + acceptance, DR-4)
- 🔴 O-3 "hợp đồng cứ từ từ" + O-A @S160 = W8 KHÔNG siết, Contract để mở; rủi ro disclose plan §4.7
- 🔴 GATE 5-anchor per-wave (spec §③-A) + seeder UPGRADE-if-exists KHÔNG insert (F-S1) + CẤM SQL tay menu (#84) - 🔴 GATE 5-anchor per-wave (spec §③-A) + seeder UPGRADE-if-exists KHÔNG insert (F-S1) + CẤM SQL tay menu (#84)
- prod state: Contracts 0 · menu 142 · test 562 · Mig 68/89 bảng · bundle admin D0sXA0fe/user Y6dW_5CM - prod state: Contracts 0 · menu 142 · test 562 · Mig 68/89 bảng · bundle admin D0sXA0fe/user Y6dW_5CM
- tick S161 CLEAN counter 35 · probe OVERDUE:light 8/6 (surface, chưa fire — xem housekeeping) · thư-mới se=0 all=0 · mind-check 11đ/0t

View File

@ -0,0 +1,6 @@
ts: 2026-07-29T18:33:30+07:00
head-sha: 8f37910552a4af0e995eaa304d5298f586068d0c
window-ordinal: 3
jsonl-hint: D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP/24be4c29-c54d-4ed0-ba2a-8240f62de712
account-label: none
ctx-verifier: CO-CO — 10 cờ (K1 hướng-tiếp thiếu setup-W5 · K3a 2 ý D rơi im-lặng [Phase-3.5-refresh CÒN SỐNG + khuôn-5-đợt 0-hit sổ bền] · K3b DR-1..3+WF-3-trạm đã-định-đoạt cần hạ nhãn @block-kế · K2 run.md ledger mâu-thuẫn ×2 [đã vá @S161] + STATUS:6 mù arc dry-run S160 · K4 E ghi 6 sub-file thật 7 · TRẦN _mind 83,2% ⇒ nén MIND-1 trước MIND-4 + đề mở lại slot-45)

View File

@ -72,7 +72,7 @@ W8: GỠ (O-A — anh chốt để mở @S160)
| 5 | O-Q2 checkbox per-phòng | comment tự do LevelOpinions (W4 DEFERRED, 0 dev) | số hoá checkbox (wave riêng) | lane-1 F-18 | | 5 | O-Q2 checkbox per-phòng | comment tự do LevelOpinions (W4 DEFERRED, 0 dev) | số hoá checkbox (wave riêng) | lane-1 F-18 |
| 6 | Mã phiếu KHKK | `KHKK/{YYYY}/{Seq:D3}` qua `WorkflowAppCodeSequence` (RG-001 v02 CÂM về phiếu) | đổi format 1 chỗ CodeGen | lane-1 F-07 + spec cũ `:128` | | 6 | Mã phiếu KHKK | `KHKK/{YYYY}/{Seq:D3}` qua `WorkflowAppCodeSequence` (RG-001 v02 CÂM về phiếu) | đổi format 1 chỗ CodeGen | lane-1 F-07 + spec cũ `:128` |
| 7 | Viết tắt "MB" (Mua bán) — codegen tự chế, KHÔNG có trong RG-001 v02 | **GIỮ hiện trạng** + flag (đổi codegen giữa dry-run = rủi ro) | map MuaBan→NCC hoặc loại type khỏi dry-run | lane-1 F-06/F-21, verify `ContractCodeGenerator.cs:25` | | 7 | Viết tắt "MB" (Mua bán) — codegen tự chế, KHÔNG có trong RG-001 v02 | **GIỮ hiện trạng** + flag (đổi codegen giữa dry-run = rủi ro) | map MuaBan→NCC hoặc loại type khỏi dry-run | lane-1 F-06/F-21, verify `ContractCodeGenerator.cs:25` |
| 8 | GĐ4 vật mang | **Option A: 0-mig DERIVE** từ `phase=9` + attachment (SealedCopy/ScannedSigned/+InitialSigned enum-extend) | Option B: +`HardCopyStatus/Note` 1 mig AddColumn | lane-2 §3 | | 8 | GĐ4 vật mang | **Option A: 0-mig DERIVE** từ `phase=9` + attachment (SealedCopy/+InitialSigned enum-extend — KHÔNG `ScannedSigned`, F-C6/gotcha #71: =2 là chữ ký NCC ở DangInKy) | Option B: +`HardCopyStatus/Note` 1 mig AddColumn | lane-2 §3 |
| 9 | Số bộ gốc / nơi lưu / ngày giao | ghi vào **note khi upload SealedCopy** (option A không có field) | option B field tường minh | lane-1 F-13/F-14 (nguồn câm) | | 9 | Số bộ gốc / nơi lưu / ngày giao | ghi vào **note khi upload SealedCopy** (option A không có field) | option B field tường minh | lane-1 F-13/F-14 (nguồn câm) |
| 10 | Thời điểm gán mã HĐ (QT đòi b.17, máy gen ở create + terminal) | **GIỮ máy hiện trạng** (create-time `ContractFeatures.cs:113-118` — có mã TRƯỚC khi in, sớm hơn cả QT đòi) + khai lệch trình tự so QT | dời site gen | lane-1 F-16 + lane-2 §1-b.13 | | 10 | Thời điểm gán mã HĐ (QT đòi b.17, máy gen ở create + terminal) | **GIỮ máy hiện trạng** (create-time `ContractFeatures.cs:113-118` — có mã TRƯỚC khi in, sớm hơn cả QT đòi) + khai lệch trình tự so QT | dời site gen | lane-1 F-16 + lane-2 §1-b.13 |
| 11 | Authz Contract | ✅ **RESOLVED — anh chốt O-A @S160: ĐỂ MỞ, không siết. W8 GỠ.** Rủi ro disclose §4.7 | (anh đổi ý lúc nào cũng kịp — bật lại W8 = 1-2 file) | owner @S160 | | 11 | Authz Contract | ✅ **RESOLVED — anh chốt O-A @S160: ĐỂ MỞ, không siết. W8 GỠ.** Rủi ro disclose §4.7 | (anh đổi ý lúc nào cũng kịp — bật lại W8 = 1-2 file) | owner @S160 |

View File

@ -32,18 +32,16 @@
| # | Stage | Vai / cách | Trạng thái | | # | Stage | Vai / cách | Trạng thái |
|---|---|---|---| |---|---|---|---|
| 1 | Scaffold + extract RG-001 v02 | lead | [x] | | 1 | Scaffold + extract RG-001 v02 | lead | [x] |
| 2 | invest lane-1: NGUỒN/QUY-TRÌNH GĐ3-GĐ4 (b.13→21 chi tiết + RG-001 v02 diff + FO-002.01 checklist-map + "hợp đồng cứng" = gì cụ thể) | `/fable-real investigator-codebase` #1 | [ ] | | 2 | invest lane-1: NGUỒN/QUY-TRÌNH GĐ3-GĐ4 (b.13→21 chi tiết + RG-001 v02 diff + FO-002.01 checklist-map + "hợp đồng cứng" = gì cụ thể) | `/fable-real investigator-codebase` #1 | [x] |
| 3 | invest lane-2: CODEBASE dry-run map (PE→KHKK→Contract→Hdc gap-map + reuse Contract V2 + authz khoanh vùng + dry-run mode + wave structure đề xuất) | `/fable-real investigator-codebase` #2 | [ ] | | 3 | invest lane-2: CODEBASE dry-run map (PE→KHKK→Contract→Hdc gap-map + reuse Contract V2 + authz khoanh vùng + dry-run mode + wave structure đề xuất) | `/fable-real investigator-codebase` #2 | [x] |
| 4 | Plan cha + spec-chi-tiết + checklist per-wave | lead (từ 2 invest + spec cũ) | [ ] | | 4 | Plan cha + spec-chi-tiết + checklist per-wave | lead (từ 2 invest + spec cũ) | [x] |
| 5 | Review ensemble — 6 lane reviewer `tier:'opus'` (run `wf_0eb994aa-a63`) | `/fable-clone reviewer` | [x] | | 5 | Review ensemble — 6 lane reviewer `tier:'opus'` (run `wf_0eb994aa-a63`) | `/fable-clone reviewer` | [x] |
| 5b | Synthesis + lead-verify 5 claim (5/5 CONFIRMED đĩa) → `review-synthesis-clone-s160.md`; disposition: 2 owner-gate + ~18 fix | lead | [x] | | 5b | Synthesis + lead-verify 5 claim (5/5 CONFIRMED đĩa) → `review-synthesis-clone-s160.md`; disposition: 2 owner-gate + ~18 fix | lead | [x] |
| 5c | Owner-decision (AskUser): **W8=O-A để mở** + **đổi tên test khớp repo** | anh @S160 | [x] | | 5c | Owner-decision (AskUser): **W8=O-A để mở** + **đổi tên test khớp repo** | anh @S160 | [x] |
| 5d | Fix NHÓM-2 (13 spec-edit: W8→O-A biên bản · seeder UPGRADE · W3 2-write-path+changelog-KHKK+bỏ-port · W6 view-per-HĐ-3-site · W7 param-type · tên test khuôn repo · dựng WF 3-trạm · disclose §4.7) | lead | [x] | | 5d | Fix NHÓM-2 (13 spec-edit: W8→O-A biên bản · seeder UPGRADE · W3 2-write-path+changelog-KHKK+bỏ-port · W6 view-per-HĐ-3-site · W7 param-type · tên test khuôn repo · dựng WF 3-trạm · disclose §4.7) | lead | [x] |
| 6 | `/fable-real reviewer` chốt cuối — **VERDICT GO-WITH-FIXES** (reviewer #53 chết sau Trục-1+Trục-2; lead finalize on-behalf từ đĩa: 12/13 fix landed-đúng + 30 anchor CONFIRMED + 0 HIGH leftover; 3 dư-lượng nhỏ DR-1..3 + 1 check DR-4) | `/fable-real` | [x] | | 6 | `/fable-real reviewer` chốt cuối — **VERDICT GO-WITH-FIXES** (reviewer #53 chết sau Trục-1+Trục-2; lead finalize on-behalf từ đĩa: 12/13 fix landed-đúng + 30 anchor CONFIRMED + 0 HIGH leftover; 3 dư-lượng nhỏ DR-1..3 + 1 check DR-4) | `/fable-real` | [x] |
| 6b | Vá 3 dư-lượng DR-1 (W7 badge bảng §①) · DR-2 (W3 anchor#5 →:356-360) · DR-3 (W1 anchor +:1256-1257) + check DR-4 (W6 admin-inbox) | lead | [ ] | | 6b | Vá 3 dư-lượng DR-1 (W7 badge bảng §①) · DR-2 (W3 anchor#5 →:356-360) · DR-3 (W1 anchor +:1256-1257) + check DR-4 (W6 admin-inbox) | lead | [x] @S161 — 4/4 xong + 1 site CÙNG-LỚP lòi thêm `plan-cha:75` (gỡ `ScannedSigned` khỏi bộ derive option-A, F-C6); DR-4 chốt = spec-hoá nhánh ADMIN (mirror PE `:731-748`) vào W6 §②-4 + 1 vế acceptance admin-inbox |
| 7 | hmw Opus-5-MAX thi công từng wave + kiểm (SAU vá DR) | hmw | [ ] | | 7 | hmw Opus-5-MAX thi công từng wave + kiểm (SAU vá DR) | hmw | [ ] |
| 6 | Review chốt cuối | `/fable-real reviewer` | [ ] |
| 7 | hmw Opus-5-MAX chạy dry-run từng wave theo Plan cha + kiểm | hmw (worker-tier-pin) | [ ] |
## Ràng buộc mang theo (từ sổ bền) ## Ràng buộc mang theo (từ sổ bền)

View File

@ -22,7 +22,7 @@
8. 🔴 **DbInitializer grant — UPGRADE-IF-EXISTS, KHÔNG INSERT (review F-S1/F-O3/F-O4 — 4 lane hội tụ, lead verify đĩa CONFIRMED):** row Permission key `KeHoachKyKet` + `Khkk_*` **ĐÃ tồn tại CanRead-only cho mọi role** (`DbInitializer.cs:2204-2213` nhánh read-only), và nhánh grant key-non-Pe là **skip-existing `continue`** (`:2242-2245`) ⇒ thêm grant kiểu **insert = NO-OP im lặng** ⇒ CanCreate/Update giữ `false`**W2/W3 lên prod 403 cho 13/13 role, chỉ Admin qua = GIẾT dry-run** (gotcha #44). **Fix:** viết method mới khuôn **`SeedProcurementMasterAccessAsync:2367-2374`** (`if (existing.TryGetValue(key,out row)) { if(!row.CanCreate){row.CanCreate=true;…} }`), chạy **SAU** `RevokeTemporarilyHidden…` (mirror `:2098-2101`) để thắng. Cấp CanCreate/CanUpdate cho **13/13 role** (đúng O-A "hiển thị hết để góp ý") + CanDelete cho Drafter/Admin, trên `KeHoachKyKet` + 6 leaf `Khkk_*`. 🔴 **CẤM SQL tay** (gotcha #84 — vết `DbInitializer.cs:2287-2296` Run #423 grant tay bị revoker lật 447/494). (b) KHÔNG đụng menu-row `Khkk_*` (đã seed). (c) label chỉnh = labelBackfill (gotcha #11). 8. 🔴 **DbInitializer grant — UPGRADE-IF-EXISTS, KHÔNG INSERT (review F-S1/F-O3/F-O4 — 4 lane hội tụ, lead verify đĩa CONFIRMED):** row Permission key `KeHoachKyKet` + `Khkk_*` **ĐÃ tồn tại CanRead-only cho mọi role** (`DbInitializer.cs:2204-2213` nhánh read-only), và nhánh grant key-non-Pe là **skip-existing `continue`** (`:2242-2245`) ⇒ thêm grant kiểu **insert = NO-OP im lặng** ⇒ CanCreate/Update giữ `false`**W2/W3 lên prod 403 cho 13/13 role, chỉ Admin qua = GIẾT dry-run** (gotcha #44). **Fix:** viết method mới khuôn **`SeedProcurementMasterAccessAsync:2367-2374`** (`if (existing.TryGetValue(key,out row)) { if(!row.CanCreate){row.CanCreate=true;…} }`), chạy **SAU** `RevokeTemporarilyHidden…` (mirror `:2098-2101`) để thắng. Cấp CanCreate/CanUpdate cho **13/13 role** (đúng O-A "hiển thị hết để góp ý") + CanDelete cho Drafter/Admin, trên `KeHoachKyKet` + 6 leaf `Khkk_*`. 🔴 **CẤM SQL tay** (gotcha #84 — vết `DbInitializer.cs:2287-2296` Run #423 grant tay bị revoker lật 447/494). (b) KHÔNG đụng menu-row `Khkk_*` (đã seed). (c) label chỉnh = labelBackfill (gotcha #11).
9. **Mã phiếu**: CodeGen service prefix `"KHKK/{YYYY}"` qua `WorkflowAppCodeSequence` (spec cũ #8-CẮT: bảng dùng chung 4 module Office, atomic = transaction SERIALIZABLE trong service, `ContractCodeSequence.cs:5`). 9. **Mã phiếu**: CodeGen service prefix `"KHKK/{YYYY}"` qua `WorkflowAppCodeSequence` (spec cũ #8-CẮT: bảng dùng chung 4 module Office, atomic = transaction SERIALIZABLE trong service, `ContractCodeSequence.cs:5`).
10. **fe-admin Designer type-10**: `ApprovalWorkflowsV2Page.tsx` map `TYPE_CODE_TO_INT` (site thực `:144-148`, KHÔNG phải comment `:143` — review chéo) + 3 site `ApprovalWorkflowV2AdminFeatures.cs` liệt-kê-thủ-công (`:911/:929` merge chữ-ký-sống · `:971/:992` RetainedOpinionRef · `:1044/:1056` chữ ký mồ côi) — thiếu ⇒ admin xoá Level có chữ ký nổ FK 500. 10. **fe-admin Designer type-10**: `ApprovalWorkflowsV2Page.tsx` map `TYPE_CODE_TO_INT` (site thực `:144-148`, KHÔNG phải comment `:143` — review chéo) + 3 site `ApprovalWorkflowV2AdminFeatures.cs` liệt-kê-thủ-công (`:911/:929` merge chữ-ký-sống · `:971/:992` RetainedOpinionRef · `:1044/:1056` chữ ký mồ côi) — thiếu ⇒ admin xoá Level có chữ ký nổ FK 500.
🔴 **Ẩn 2 checkbox early-finalize cho type=10 (review F-B3 — containment THẬT):** Designer V2 render checkbox `AllowApproverFinalize`/`AllowApproverSkipToFinal` (`ApprovalWorkflowsV2Page.tsx:1267-1268`) = per-Level admin opt-in. Anh phán 2 đường này **"PHÁ VỠ"** (S155). W3 KHÔNG port code path ⇒ để checkbox sống mà backend không xử = cờ chết đánh lừa admin. **Fix:** ẩn/disable 2 checkbox khi `typeCode==10` (hoặc render read-only + tooltip "chưa hỗ trợ cho quy trình KHKK"). Đây là cách làm default #1 ("đường THƯỜNG") thành **containment thật** thay vì "port-nhưng-không-kích-hoạt" (giả). 🔴 **Ẩn 2 checkbox early-finalize cho type=10 (review F-B3 — containment THẬT):** Designer V2 render checkbox `AllowApproverFinalize`/`AllowApproverSkipToFinal` (`ApprovalWorkflowsV2Page.tsx:1256-1257` SkipToFinal + `:1267-1268` Finalize) = per-Level admin opt-in. Anh phán 2 đường này **"PHÁ VỠ"** (S155). W3 KHÔNG port code path ⇒ để checkbox sống mà backend không xử = cờ chết đánh lừa admin. **Fix:** ẩn/disable 2 checkbox khi `typeCode==10` (hoặc render read-only + tooltip "chưa hỗ trợ cho quy trình KHKK"). Đây là cách làm default #1 ("đường THƯỜNG") thành **containment thật** thay vì "port-nhưng-không-kích-hoạt" (giả).
11. Build + test + commit `[CLAUDE] Domain+Infra+Admin: W1 KHKK schema Mig 69 + policy KeHoachKyKet + Designer type-10`. 11. Build + test + commit `[CLAUDE] Domain+Infra+Admin: W1 KHKK schema Mig 69 + policy KeHoachKyKet + Designer type-10`.
## ③ CHECKLIST ## ③ CHECKLIST

View File

@ -23,7 +23,7 @@ Phiếu KHKK chạy trọn `DangSoanThao → ChoDuyet → (PMH → CCM → CEO)
## ③ CHECKLIST ## ③ CHECKLIST
**A. Gate 5-anchor:** `ContractWorkflowService.cs:217-394` (nguồn copy) · `:259-260` (OR-of-N) · `:292-316` (UPSERT) · `ApprovalWorkflow.cs:95+:116-125` (return-mode cờ, class trong file này) · `PurchaseEvaluationWorkflowService.cs:1008` (RULE choke-point). **A. Gate 5-anchor:** `ContractWorkflowService.cs:217-394` (nguồn copy) · `:259-260` (OR-of-N) · `:292-316` (UPSERT) · `ApprovalWorkflow.cs:95+:116-125` (return-mode cờ, class trong file này) · `ContractFeatures.cs:356-360` (khuôn RULE choke-point — LUẬT + `grep -rn` + "không đếm số"; thay `PEWS:1008` per F-B4, khớp §②-3(a)).
**B. Acceptance (spec cũ W3 `:348-384` — SÀN 6 test, thiếu 1 tên = TRƯỢT):** **B. Acceptance (spec cũ W3 `:348-384` — SÀN 6 test, thiếu 1 tên = TRƯỢT):**
- [ ] 🔴 OR-of-N 4 vế: (a) 2 phiếu song sinh — phiếu-1 A duyệt → tiến; phiếu-2 B duyệt → CŨNG tiến; (b) ca ÂM: người ngoài cấp → 403; (c) `LevelOpinions WHERE PlanId=@id` = 1 row; (d) KHÔNG đòi cả A và B. - [ ] 🔴 OR-of-N 4 vế: (a) 2 phiếu song sinh — phiếu-1 A duyệt → tiến; phiếu-2 B duyệt → CŨNG tiến; (b) ca ÂM: người ngoài cấp → 403; (c) `LevelOpinions WHERE PlanId=@id` = 1 row; (d) KHÔNG đòi cả A và B.
- [ ] Con-trỏ đôi: workflow 3 Bước → StepIndex 1→2→3, LevelOrder reset về 1 mỗi Bước mới. - [ ] Con-trỏ đôi: workflow 3 Bước → StepIndex 1→2→3, LevelOrder reset về 1 mỗi Bước mới.

View File

@ -15,7 +15,7 @@ Wave này = 0 UI mới, 0 mig; sau deploy: approver thấy + mở + duyệt đư
1. **Gate 5-anchor** (§③-A). 1. **Gate 5-anchor** (§③-A).
2. **Test-before** 3 test (§③-B) RED. 2. **Test-before** 3 test (§③-B) RED.
3. 🔴 **View — ĐÚNG CÁCH per-HĐ, KHÔNG role-blanket (review F-S3/F-C2/F-01):** `GetEligiblePhases(userRoles)` (`ContractFeatures.cs:334-350`) chữ ký **chỉ nhận role** ⇒ nếu chỉ nhét `ChoDuyet`/`DaPhatHanh` vào tập role thì mở toang cho MỌI user mang role đó (kể cả HĐ xóa mềm ở `:381`). **Fix:** thêm nhánh V2 **membership-theo-HĐ** ở CẢ 3 call-site của `GetEligiblePhases` (`:301` List · `:381` ListDeleted · `:486` Detail — review F-S3 chỉ ra gate cũ thiếu 2 site) — user thấy HĐ `ChoDuyet` **nếu là `ApproverUserId` của Level trong workflow pin CỦA CHÍNH HĐ đó**, và HĐ `DaPhatHanh` **nếu thuộc workflow HĐ đó HOẶC mang vai bản-cứng** (Director/AuthorizedSigner/HrAdmin/CostControl — actor b.19/20/21, cho GĐ4/W7). Admin giữ thấy-hết. KHÔNG mở toang: user ngoài cả hai điều kiện → 403 y cũ. *(Đây là điều kiện W7 phụ thuộc — F-C2.)* 3. 🔴 **View — ĐÚNG CÁCH per-HĐ, KHÔNG role-blanket (review F-S3/F-C2/F-01):** `GetEligiblePhases(userRoles)` (`ContractFeatures.cs:334-350`) chữ ký **chỉ nhận role** ⇒ nếu chỉ nhét `ChoDuyet`/`DaPhatHanh` vào tập role thì mở toang cho MỌI user mang role đó (kể cả HĐ xóa mềm ở `:381`). **Fix:** thêm nhánh V2 **membership-theo-HĐ** ở CẢ 3 call-site của `GetEligiblePhases` (`:301` List · `:381` ListDeleted · `:486` Detail — review F-S3 chỉ ra gate cũ thiếu 2 site) — user thấy HĐ `ChoDuyet` **nếu là `ApproverUserId` của Level trong workflow pin CỦA CHÍNH HĐ đó**, và HĐ `DaPhatHanh` **nếu thuộc workflow HĐ đó HOẶC mang vai bản-cứng** (Director/AuthorizedSigner/HrAdmin/CostControl — actor b.19/20/21, cho GĐ4/W7). Admin giữ thấy-hết. KHÔNG mở toang: user ngoài cả hai điều kiện → 403 y cũ. *(Đây là điều kiện W7 phụ thuộc — F-C2.)*
4. **Inbox**: mirror khuôn PE `ResolveV2InboxIdsAsync` (precompute id-set các HĐ mà con-trỏ Step/Level hiện tại chứa `ApproverUserId==actor`) — GHÉP vào inbox query hiện có thay vì chỉ `PhaseActorRoles` legacy. Giữ nhánh legacy cho HĐ V1 (nếu prod xuất hiện lại data V1). 4. **Inbox**: mirror khuôn PE `ResolveV2InboxIdsAsync` (precompute id-set các HĐ mà con-trỏ Step/Level hiện tại chứa `ApproverUserId==actor`) — GHÉP vào inbox query hiện có thay vì chỉ `PhaseActorRoles` legacy. Giữ nhánh legacy cho HĐ V1 (nếu prod xuất hiện lại data V1). 🔴 **Nhánh ADMIN (F-B13, DR-4 chốt @S161):** admin hiện lấy `eligiblePhases = PhaseActorRoles.Keys` (`ContractFeatures.cs:440-441`) mà dict `:421-430` KHÔNG có `ChoDuyet` ⇒ ghép v2InboxIds xong admin VẪN mù HĐ ChoDuyet. Mirror TRỌN khuôn PE `PurchaseEvaluationFeatures.cs:731-748`: admin dùng danh-sách phase liệt TƯỜNG MINH **+ `ChoDuyet`** (admin thấy mọi HĐ chờ duyệt qua nhánh PHASE; `v2InboxIds` để rỗng cho admin đúng như PE `:746-748`).
5. **Guard trình** (`ContractWorkflowService.cs:73-78`): nới thành `Drafter DeptManager CreatedBy==actor Procurement` (dòng tối thiểu đóng lớp 403-PMH; giữ 403 cho role ngoài). 5. **Guard trình** (`ContractWorkflowService.cs:73-78`): nới thành `Drafter DeptManager CreatedBy==actor Procurement` (dòng tối thiểu đóng lớp 403-PMH; giữ 403 cho role ngoài).
6. (Nếu DTO cần) thêm `currentApproval` info vào detail DTO cho FE panel — chỉ khi FE thiếu dữ liệu hiển thị. 6. (Nếu DTO cần) thêm `currentApproval` info vào detail DTO cho FE panel — chỉ khi FE thiếu dữ liệu hiển thị.
7. Build + test GREEN + commit `[CLAUDE] Contract: W6 duong ong V2 view+inbox+trinh`. cicd verify. 7. Build + test GREEN + commit `[CLAUDE] Contract: W6 duong ong V2 view+inbox+trinh`. cicd verify.
@ -26,7 +26,7 @@ Wave này = 0 UI mới, 0 mig; sau deploy: approver thấy + mở + duyệt đư
**B. Acceptance (lane-2 §7-W6):** **B. Acceptance (lane-2 §7-W6):**
- [ ] 5 test ĐÚNG TÊN (khuôn repo) trong `ContractV2PipelineTests`: `Inbox_PendingLevelApprover_SeesChoDuyetContract` · `Inbox_OtherLevel_DoesNotSeeContract` (ca ÂM) · `View_V2Approver_NotDrafter_CanSeeChoDuyetContract` · `List_HardCopyActor_NotAdmin_SeesDaPhatHanhContract` (🔴 review F-01: LIST test cho actor bản-cứng — không wave nào đo LIST trước) · `View_UserOutsideWorkflow_WithUnrelatedRole_Gets403` (🔴 review F-S4: ca ÂM **pin ROLE cụ thể** như CostControl/Procurement, KHÔNG chọn HrAdmin cho pass dễ). - [ ] 5 test ĐÚNG TÊN (khuôn repo) trong `ContractV2PipelineTests`: `Inbox_PendingLevelApprover_SeesChoDuyetContract` · `Inbox_OtherLevel_DoesNotSeeContract` (ca ÂM) · `View_V2Approver_NotDrafter_CanSeeChoDuyetContract` · `List_HardCopyActor_NotAdmin_SeesDaPhatHanhContract` (🔴 review F-01: LIST test cho actor bản-cứng — không wave nào đo LIST trước) · `View_UserOutsideWorkflow_WithUnrelatedRole_Gets403` (🔴 review F-S4: ca ÂM **pin ROLE cụ thể** như CostControl/Procurement, KHÔNG chọn HrAdmin cho pass dễ).
- [ ] `dotnet test` PASS 0 fail, số-sau ≥ baseline + 5. - [ ] `dotnet test` PASS 0 fail, số-sau ≥ baseline + 5.
- [ ] Prod ③: login approver-V2 KHÔNG-admin → `GET /api/contracts/inbox` ≥1 HĐ ChoDuyet mà mình là Level hiện tại + `GET /{id}` 200; login actor bản-cứng non-admin (vd Director) → `GET /api/contracts?type=1&phase=9` ≥1 dòng (trước W6: 0 dòng + 403). - [ ] Prod ③: login approver-V2 KHÔNG-admin → `GET /api/contracts/inbox` ≥1 HĐ ChoDuyet mà mình là Level hiện tại + `GET /{id}` 200; login **admin**`/api/contracts/inbox` ≥1 HĐ ChoDuyet (🔴 F-B13 — trước W6: admin 0 dòng vì `PhaseActorRoles.Keys` không có ChoDuyet); login actor bản-cứng non-admin (vd Director) → `GET /api/contracts?type=1&phase=9` ≥1 dòng (trước W6: 0 dòng + 403).
- [ ] Ca ÂM giữ (pin role): user role KHÔNG liên quan + không thuộc workflow HĐ nào → `GET /{id}` vẫn 403 (chứng KHÔNG mở toang qua role-blanket). - [ ] Ca ÂM giữ (pin role): user role KHÔNG liên quan + không thuộc workflow HĐ nào → `GET /{id}` vẫn 403 (chứng KHÔNG mở toang qua role-blanket).
- [ ] 🔴 Kiểm hở xóa-mềm: HĐ `ChoDuyet` đã soft-delete → user V2 KHÔNG thấy ở `:381` ListDeleted (fix membership không được rò sang màn Đã-xóa). - [ ] 🔴 Kiểm hở xóa-mềm: HĐ `ChoDuyet` đã soft-delete → user V2 KHÔNG thấy ở `:381` ListDeleted (fix membership không được rò sang màn Đã-xóa).
- [ ] CI run PASS; 0 mig (diff `*Migrations*` = 0 — khuôn M2 đợt-5). - [ ] CI run PASS; 0 mig (diff `*Migrations*` = 0 — khuôn M2 đợt-5).

View File

@ -9,7 +9,7 @@
Mapping trạm → bằng chứng upload (đảo được sang option B nếu anh muốn field tường minh): Mapping trạm → bằng chứng upload (đảo được sang option B nếu anh muốn field tường minh):
| Trạm (QT) | Ai | Bằng chứng hệ thống | Derive badge | | Trạm (QT) | Ai | Bằng chứng hệ thống | Derive badge |
|---|---|---|---| |---|---|---|---|
| b.19 Ký GĐ/NĐUQ | BOD | upload `ScannedSigned` (scan bản có chữ ký GĐ) | "Đã ký GĐ" = has(ScannedSigned) | | b.19 Ký GĐ/NĐUQ | BOD | upload scan bản có chữ ký GĐ (purpose: KHÔNG `ScannedSigned` — F-C6/gotcha #71, =2 nghĩa "scan chữ ký NCC ở DangInKy") | "Đã ký GĐ" = derive từ `InitialSigned`/`SealedCopy` (2 cờ DTO, khớp §②-2(c)) |
| b.20 Đóng dấu | HRA/ISO | (gộp vào b.21 — option A không tách được 2 mốc; khai lệch so 4-mốc lane-1 F-14) | — | | b.20 Đóng dấu | HRA/ISO | (gộp vào b.21 — option A không tách được 2 mốc; khai lệch so 4-mốc lane-1 F-14) | — |
| b.21 Phát hành + Lưu | PB/BCH + CCM | upload `SealedCopy` (scan bộ đóng dấu) + **note bắt buộc: số bộ gốc · đã giao CCM/NTP · nơi lưu/Filing path** (plan cha default #9) + upload scan cover FO-002.01 (luật (c) lane-1) | "Đã lưu bản cứng" = has(SealedCopy) | | b.21 Phát hành + Lưu | PB/BCH + CCM | upload `SealedCopy` (scan bộ đóng dấu) + **note bắt buộc: số bộ gốc · đã giao CCM/NTP · nơi lưu/Filing path** (plan cha default #9) + upload scan cover FO-002.01 (luật (c) lane-1) | "Đã lưu bản cứng" = has(SealedCopy) |
Readonly từ GĐ3 (F-11): khối "Ký nháy & cover b.17-18" hiển thị từ attachments (`InitialSigned` mới) + LevelOpinions HĐ. Readonly từ GĐ3 (F-11): khối "Ký nháy & cover b.17-18" hiển thị từ attachments (`InitialSigned` mới) + LevelOpinions HĐ.