wal: flush 20260808T0132
This commit is contained in:
@ -9,14 +9,15 @@ chain:
|
|||||||
[x] B1 3× fable-real invest XONG-TRỌN-ĐĨA: BE 21KB (generic ~85%, 4 site sửa) · DB 18KB (VERDICT 0-MIG, 3 mìn M1/M2/M3) · FE 14KB (1 file chính ~60-90 dòng, SHA-mirror KHÔNG áp dụng)
|
[x] B1 3× fable-real invest XONG-TRỌN-ĐĨA: BE 21KB (generic ~85%, 4 site sửa) · DB 18KB (VERDICT 0-MIG, 3 mìn M1/M2/M3) · FE 14KB (1 file chính ~60-90 dòng, SHA-mirror KHÔNG áp dụng)
|
||||||
[x] B2 spec DRAFT ghi (spec-khkk-awf-mirror-ncc-DRAFT.md — W0..W5)
|
[x] B2 spec DRAFT ghi (spec-khkk-awf-mirror-ncc-DRAFT.md — W0..W5)
|
||||||
[x] D3 anh chốt = C "Mờ ô chưa nghe" (YC-014, sổ + owner-decisions-08-08-2026.md) ⇒ W3 HỦY
|
[x] D3 anh chốt = C "Mờ ô chưa nghe" (YC-014, sổ + owner-decisions-08-08-2026.md) ⇒ W3 HỦY
|
||||||
[!] wf: B3 2× fable-real reviewer — spawn @01:05, artifact-first, skeleton đã trên đĩa
|
[x] B3 2× fable-real reviewer — R1 PASS_WITH_FIXES 2C/5M (F1-F12) · R2 PASS_WITH_FIXES 1C/5M+7m (§8 FINAL)
|
||||||
[ ] B4 lead merge → spec FINAL (spec-khkk-awf-mirror-ncc-08-08-2026.md)
|
[x] B4 spec FINAL land (spec-khkk-awf-mirror-ncc-08-08-2026.md — merge 2 review, R-1..R-6 + D5/D6 bậc-2 lead-chọn-CÓ)
|
||||||
[ ] B5 hmw fan-out Opus 5 MAX execute (W0 prep-local → W1 BE-1 4-fix → W2 FE → W4 test → W5 review+cicd)
|
[!] wf: B5 ĐỢT-1 fan-out Opus 5 MAX — 4 lane: BE(W0+W1 5-fix) ‖ FE(W2 a-h gồm e) ‖ TEST(14 ca) ‖ PRECHECK(W0.4 prod đọc-only)
|
||||||
|
[ ] B5 ĐỢT-2 (sau đợt-1): full-suite verify → reviewer pre-commit → lead COMMIT MỘT PHÁT (R-1) → push → cicd 4-chân → acceptance prod đọc-only
|
||||||
|
|
||||||
wf: run-id=2026-08-08-S182-khkk-awf-mirror-ncc | script=Agent-tool model:fable ×2 parallel (reviewer) | trạng-thái=B3-đang-chạy | artifact=sub-review-{1,2}-fable.md | relaunch=re-spawn reviewer còn thiếu ruột artifact; KHÔNG re-chạy invest (3 sub-invest đã đầy)
|
wf: run-id=wf_a07b53c8-47e | script=hmw.js scriptPath | trạng-thái=ĐỢT-1-4-lane-đang-chạy | artifact=runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-{implementer-backend,implementer-frontend,test-specialist,cicd-monitor}-0.md | relaunch=Workflow resumeFromRunId wf_a07b53c8-47e (lane xong = cached; đọc journal.jsonl trước khi tin cached-rỗng)
|
||||||
|
|
||||||
next: khi 2 reviewer trả → đọc 2 sub-review → merge finding + WAVE-PLAN FINAL của review-2 → ghi spec final → B5 fan-out (Workflow scriptPath hmw.js, worker-pin opus+max sẵn)
|
next: khi wf_a07b53c8-47e xong → đọc 4 sub-file + return → xử BLOCKED/LỆCH nếu có → đợt-2 (full-suite + reviewer pre-commit + commit 1 phát [CLAUDE] Workflow: ... + push + cicd-monitor 4-chân)
|
||||||
|
|
||||||
verify: grep -c 'REVIEW-[12]:' runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-review-*.md (2 verdict) ; wc -c sub-review-* (≥5KB mỗi cái)
|
verify: wc -c runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-implementer-*.md sub-test-*.md sub-cicd-monitor-0.md (4 file ≥2KB) ; dotnet build exit-0 ; git status (code đổi CHƯA commit — đúng, chờ đợt-2)
|
||||||
|
|
||||||
treo-chờ-anh (từ bookend @open, KHÔNG chặn YC-013): slot(67) upload-khi-duyệt · VK-5 nhánh A/B · (72) mfe-eval · ring5-audit slot(41)
|
treo-chờ-anh (từ bookend @open, KHÔNG chặn YC-013): slot(67) upload-khi-duyệt · VK-5 nhánh A/B · (72) mfe-eval · ring5-audit slot(41)
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
# Reviewer Agent — Persistent Memory
|
# Reviewer Agent — Persistent Memory
|
||||||
|
|
||||||
|
- **S182 (08-08) REVIEW-1 Fable spec KHKK-AWF-mirror — `PASS_WITH_FIXES 2C/5M` (đĩa `runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-review-1-fable.md`):** review SPEC = đo lại claim trên code, đa số HELD nhưng: 🔴 **spec-unbuildable vì assembly-ranh** — "extract helper + gọi 3 site" chết vì site-3 (Submit) ở Infrastructure còn helper `internal` Application, `InternalsVisibleTo` chỉ mở Tests ⇒ kiểm ACCESSIBILITY mọi extract-helper đa-assembly trước khi phán vá-rẻ · 🔴 **usage-count trên bảng có `HasQueryFilter` thiếu `IgnoreQueryFilters()`** = đếm sót phiếu xoá-mềm mà FK vẫn chặn ⇒ test-hẹp xanh, ca phổ biến vẫn 500 (claim "hết 500" mạnh hơn fix) · 🔴 **"FK chặn nên data không mất" phải grep FK THẬT**: 8 cột pin ⟂ 4 `HasForeignKey` hit ⇒ 5 pin loose-Guid hard-delete êm + dangling — invest suy từ 3 module đã biết · **2 invest cùng chữ "per-Code" ≠ cùng công-thức** (typeEnum==10 ⟂ regex-họ-mã, KHÁC hành vi ở code ngoài-họ) — spec khai "hội tụ" che lệch ⇒ khoá công thức + test ca phân-kỳ · **cờ ignored-nhưng-hành-vi-luôn-bật** gray-out kiểu "chưa áp dụng" = nói dối chiều ngược ⇒ forced-true-disabled · baseline "645" spec ⟂ STATUS 644 — đo tươi đừng chép. ⚠️ sổ này `wc -c` 21.058B — nghi chạm cap ký-tự, lượt sau đo + curate đúng trình tự.
|
||||||
|
|
||||||
- **[→ `archive/2026-08.md` §@S180 — verbatim, probe 10/10 + control-âm 0] S180 (08-07) LANE A/6 GĐ-0+GĐ-1 (đĩa `runs/…-S180-adap-upgrade-pack-phased/sub-n3-lane-a-gd01.md` 57 KB):** 🔴 **"0 hit" ĐÚNG THEO LUẬT vẫn là LỖ THẬT** — `_index` thiếu **24/69** thư (lead giao "4"); `to=se` **23/23 sạch** ⟂ `to=all-fit` 22 có/20 thiếu; luật `:7` trỏ `COMMS-LEDGER` mà `find "*COMMS*"`=**0 trong SE** (control `*ledger*`=4) ⇒ **sổ mà luật trỏ tới KHÔNG TỒN TẠI**; S153 phán dương-giả = đúng cho câu-hỏi CŨ. ⇒ gặp 0-hit phải hỏi thêm **"sổ đó có tồn tại không"** · **phân-họ regex 160/159, lệch 1 vì `S57bis`** ⇒ luôn cộng lại đối-chiếu tổng · **`CLAUDE.md` quy-ước nhật-ký khớp ≤64/159 đĩa** · **"single source" tự-xưng ≠ chuẩn** (bảng-dịch; 3 phép thử tiên-đoán/phủ-sóng/hướng) · **số-trong-chú-thích trôi** (`hmw.js` "11 class" ⟂ đĩa **12**).
|
- **[→ `archive/2026-08.md` §@S180 — verbatim, probe 10/10 + control-âm 0] S180 (08-07) LANE A/6 GĐ-0+GĐ-1 (đĩa `runs/…-S180-adap-upgrade-pack-phased/sub-n3-lane-a-gd01.md` 57 KB):** 🔴 **"0 hit" ĐÚNG THEO LUẬT vẫn là LỖ THẬT** — `_index` thiếu **24/69** thư (lead giao "4"); `to=se` **23/23 sạch** ⟂ `to=all-fit` 22 có/20 thiếu; luật `:7` trỏ `COMMS-LEDGER` mà `find "*COMMS*"`=**0 trong SE** (control `*ledger*`=4) ⇒ **sổ mà luật trỏ tới KHÔNG TỒN TẠI**; S153 phán dương-giả = đúng cho câu-hỏi CŨ. ⇒ gặp 0-hit phải hỏi thêm **"sổ đó có tồn tại không"** · **phân-họ regex 160/159, lệch 1 vì `S57bis`** ⇒ luôn cộng lại đối-chiếu tổng · **`CLAUDE.md` quy-ước nhật-ký khớp ≤64/159 đĩa** · **"single source" tự-xưng ≠ chuẩn** (bảng-dịch; 3 phép thử tiên-đoán/phủ-sóng/hướng) · **số-trong-chú-thích trôi** (`hmw.js` "11 class" ⟂ đĩa **12**).
|
||||||
|
|
||||||
- **[→ `archive/2026-08.md` §@S179 — verbatim] S179 (08-07) C7 re-review sau vá — `PASS-WITH-8`, 3 MAJOR:** **2/3 MAJOR là lỗi TRONG CHÍNH BẢN VÁ vừa pass 12/12 acceptance** — vì acceptance đo **HÌNH-DẠNG chuỗi, không đo HÀNH-VI**. `cut -c4-` đẻ path RÁC (rename 1 dòng `R old -> new`) · ba-chấm→hai-chấm = **regression có điều-kiện** (thủ phạm thật = `git diff` mù untracked, lead gán sai tội) · mỏ-neo `:112` **tự-vô-hiệu ngay lúc viết** ⇒ neo TÊN SELECTOR không neo số dòng · census "8/9" thiếu 3 ý đóng im lặng.
|
- **[→ `archive/2026-08.md` §@S179 — verbatim] S179 (08-07) C7 re-review sau vá — `PASS-WITH-8`, 3 MAJOR:** **2/3 MAJOR là lỗi TRONG CHÍNH BẢN VÁ vừa pass 12/12 acceptance** — vì acceptance đo **HÌNH-DẠNG chuỗi, không đo HÀNH-VI**. `cut -c4-` đẻ path RÁC (rename 1 dòng `R old -> new`) · ba-chấm→hai-chấm = **regression có điều-kiện** (thủ phạm thật = `git diff` mù untracked, lead gán sai tội) · mỏ-neo `:112` **tự-vô-hiệu ngay lúc viết** ⇒ neo TÊN SELECTOR không neo số dòng · census "8/9" thiếu 3 ý đóng im lặng.
|
||||||
|
|||||||
@ -0,0 +1,80 @@
|
|||||||
|
# SPEC FINAL — YC-013: 8 panel "Duyệt KHKK — Nhóm 1..8" mirror trang Duyệt NCC (S182/L13, 2026-08-08)
|
||||||
|
|
||||||
|
> **Nguồn:** spec DRAFT + merge 2 review Fable — `sub-review-1-fable.md` (`PASS_WITH_FIXES 2C/5M`, F1-F12) + `sub-review-2-fable.md` (`PASS_WITH_FIXES 1C/5M+7m`, §8). Mọi file:line đã được ÍT NHẤT 1 reviewer re-verify trên cây (HEAD nền `936d1aed`).
|
||||||
|
> **Owner-decisions:** D3 = **C** (YC-014, anh chốt qua AskUser) · D4 = title menu-label + phụ đề nghiệp vụ · **D5/D6 = lead chọn nhánh an toàn theo bậc-2 luật tự-trị, anh veto 1 câu là gỡ** (khai ở MỤC 3).
|
||||||
|
> **Executor:** hmw fan-out, worker **Opus 5 MAX** (worker-tier-pin sẵn). Cầm ĐÚNG file này chạy.
|
||||||
|
|
||||||
|
## MỤC 1 — Ràng buộc toàn cục (R-1..R-6, đọc trước mọi wave)
|
||||||
|
|
||||||
|
- **R-1 (C-1):** W1+W2 = **MỘT commit code duy nhất**. Nếu buộc tách: BẮT BUỘC W1 → CI xanh → W2. **CẤM mọi commit chứa W2 mà thiếu W1a** — nút "Tạo phiên bản mới" trên panel nhóm khi BE còn deactivate-per-type = tắt IsActive cả 8 nhóm prod. (Bom đã armed sẵn hôm nay qua panel `/ContractSigningPlan`.)
|
||||||
|
- **R-2 (M-4/F10):** trên PROD chỉ đo ĐỌC. Mọi acceptance có GHI chạy **LOCAL**. Không có endpoint re-activate — POST version mới là ratchet một chiều.
|
||||||
|
- **R-3 (M-3/F9):** baseline test = **số đo tươi tại W0** ghi vào `run.md`. KHÔNG chép 644/645 từ doc nào. *(Tham chiếu: lead đo tươi @bootstrap S182 = 645 PASS (45D+600I) — vẫn phải đo lại tại W0.)*
|
||||||
|
- **R-4:** 0 migration. Wave nào phát hiện cần mig ⇒ DỪNG, báo lead (premise 3-lens vỡ).
|
||||||
|
- **R-5:** commit `[CLAUDE] Workflow: KHKK 8 panel nhóm mirror DuyetNcc + BE guards (0-mig)`. Artifact run-folder không trigger CI (paths-ignore verified).
|
||||||
|
- **R-6 (F4):** 🔴 **CÔNG THỨC W1a KHOÁ** = `typeEnum == ContractSigningPlan ⇒ Where(w => w.Code == request.Code && w.ApplicableType == typeEnum && w.IsActive)`. **CẤM biến-thể regex `^KHKK-N[1-8]$`** (công thức FE-invest D1 — code lạ type-10 như `QT-KHKK-V2-001` sẽ rơi nhánh per-type → NUKE cả 8 nhóm).
|
||||||
|
|
||||||
|
## MỤC 2 — WAVE
|
||||||
|
|
||||||
|
### W0 — prep + đo nền (blocking)
|
||||||
|
| # | Task | Đạt khi |
|
||||||
|
|---|---|---|
|
||||||
|
| 0.1 | `dotnet ef database update` ×2 DB (Dev + Design — kẹt Mig 71, đĩa Mig 72; đo lại drift tại chỗ) | `sqlcmd` top MigrationId = `20260806070242` cả 2 |
|
||||||
|
| 0.2 | Boot API 1 lần → seeder đẻ 8 row local | SQL: 8 row `KHKK-N1..8` type-10 IsActive=1. Roster local **rỗng/đủ người đều KHÔNG phải bug** (seeder resolve email; local có 14 user Solutions thật) |
|
||||||
|
| 0.3 | Đo baseline test TƯƠI → ghi `run.md` | R-3 |
|
||||||
|
| 0.4 | Prod-state check ĐỌC-only: `ssh vietreport-vps` + `sqlcmd -E` (integrated — KHÔNG cần password) chạy 3 query DB-invest §4 + query audit pin-lệch (F11): `SELECT p.MaKeHoach, p.ApprovalGroup, w.Code FROM ContractSigningPlans p JOIN ApprovalWorkflows w ON w.Id=p.ApprovalWorkflowId WHERE w.Code LIKE 'KHKK-N%' AND w.Code <> CONCAT('KHKK-N', p.ApprovalGroup)` | Kỳ vọng: 8 row IsActive=1 · phiếu KHKK đều Phase=3 (DaDuyet=TERMINAL, đã verify enum) · audit = 0 row. **LỆCH ⇒ báo lead TRƯỚC W1** (nhóm Archived-oan → recovery = tạo version mới từ panel sau W2; phiếu treo pin lệch → sẽ kẹt submit sau W1b by-design, phải biết số trước) |
|
||||||
|
|
||||||
|
### W1 — BE: 5 fix + 14 test, 2 file + 1 file MỚI, 0-mig
|
||||||
|
Files: `src/Backend/SolutionErp.Application/ApprovalWorkflowsV2/ApprovalWorkflowV2AdminFeatures.cs` · `src/Backend/SolutionErp.Application/ContractSigningPlans/ContractSigningPlanFeatures.cs` · **MỚI** `src/Backend/SolutionErp.Application/ContractSigningPlans/ContractSigningPlanWorkflowGuards.cs` · `src/Backend/SolutionErp.Infrastructure/Services/ContractSigningPlanWorkflowService.cs` (1 call-site).
|
||||||
|
|
||||||
|
| # | Fix | Site | Cách |
|
||||||
|
|---|---|---|---|
|
||||||
|
| a | 🔴 Deactivate-per-Code type-10 | `AdminFeatures.cs:339-343` | Công thức R-6. Type khác GIỮ per-type. **Sửa comment `:339` "only ONE active per type" CÙNG COMMIT** (F12d). Ghi chú nhất quán: `nextVersion :334-337` đã per-Code sẵn |
|
||||||
|
| b | Group-match guard 3-site (F1) | Create `:479-486` · UpdateDraft `:603-607` · `SubmitAsync` (Service, cạnh rào hạng-mục `:169-187` trước `LoadStepsAsync :189` — executor verify điểm chèn tại chỗ) | 🔴 **File MỚI `ContractSigningPlanWorkflowGuards.cs` — `public static class`** (KHÔNG nhét vào `Scope` internal — Submit ở Infrastructure không gọi được; KHÔNG `InternalsVisibleTo(Infrastructure)`; KHÔNG inline-duplicate). Method `EnsureWorkflowGroupMatchAsync(IApplicationDbContext, Guid awId, int approvalGroup, CancellationToken)` — move NGUYÊN logic rào (v), **GIỮ semantics cho-qua-code-ngoài-họ** (`:477-478` chủ-đích). 3 site cùng gọi. Message 409: *"Phiếu nhóm N{g} đang gắn quy trình N{k} — vào phiếu (Nháp/Trả lại) đổi lại quy trình đúng nhóm trước khi trình."* |
|
||||||
|
| b2 | Pin-check IsActive ∧ IsUserSelectable (F5 — **D6**) | Create (sau rào iv) + UpdateDraft (CHỈ trong nhánh `awId != plan.ApprovalWorkflowId` `:603`) | Mirror vá-3 `CreateContractFromSigningPlanFeatures.cs:141-147` — 2 message tách "đã ngừng hoạt động"/"chưa ghim". Giữ-nguyên-pin KHÔNG check (phiếu cũ pin bản archived vẫn sửa GhiChu) |
|
||||||
|
| c | Changelog PUT type-10 | `AdminFeatures.cs:863-893` | Nhánh `else if type-10`: query `ContractSigningPlans` (`ApprovalWorkflowId==def.Id && Phase != DaDuyet && Phase != TuChoi`; query-filter tự loại phiếu xoá-mềm — ĐÚNG cho changelog) → add `ContractSigningPlanChangelog { EntityType=Workflow /*=4 enum SẴN*/, Action=Update, EntityId=def.Id, PhaseAtChange, UserId/UserName, Summary="Sửa quy trình duyệt tại chỗ: {Code} v{NN} (giữ nguyên phiên bản)", ContextNote (kèm Reason) }` mirror block PE. *(Dialog PUT đang HỨA nguyên văn "ghi vào lịch sử phiếu đang chạy" `Page.tsx:963-977` — fix này làm lời hứa thành thật)* |
|
||||||
|
| d | DELETE usage-check → 409/404 (F2+F3+M-1) | `AdminFeatures.cs:1193-1205` | (i) đếm pin **8 module** có cột `ApprovalWorkflowId` (grep Domain để liệt, đừng chép): PE/Contract/KHKK **BẮT BUỘC `IgnoreQueryFilters()`** (soft-deleted vẫn chặn FK) · Proposal/Leave/Ot/Vehicle/Travel đếm thẳng — 🔴 5 module này pin **LOOSE 0-FK** ⇒ guard này là **RÀO DUY NHẤT chống dangling** (rationale 2 vế: FK-modules = UX 547→409; office = DATA-INTEGRITY) · (ii) đếm opinions **8 bảng `*LevelOpinion`** theo level-ids của workflow, `IgnoreQueryFilters()` → 409 "N phiếu đang gắn + M chữ ký" · (iii) `KeyNotFoundException` → `NotFoundException` (id lạ = 404, hết 500 thô — middleware không map BCL) · (iv) **D5:** code họ `KHKK-N[1-8]` && version CUỐI của Code ⇒ 409 *"Nhóm N{n} phải còn ≥1 version"* (chặn ca seeder-tái-sinh M-1 khỏi đường UI) |
|
||||||
|
|
||||||
|
**Test W1 — 14 ca (test-before a/b/b2 · test-after c/d).** Homes verified: `tests/SolutionErp.Infrastructure.Tests/Application/UpdateAwDefinitionTests.cs` + `ContractSigningPlanApprovalTests.cs`:
|
||||||
|
T1 create v2 `KHKK-N1` ⇒ N2..N8 bất biến + N1 v01→false v02→true · T2 regression type-1 Code-mới-cùng-type vẫn tắt Code cũ · T3 POST type-10 **code lạ** `QT-KHKK-V2-001` ⇒ 8 nhóm bất biến (F4) · T4 UpdateDraft re-pin lệch nhóm ⇒ 409 · T5 phiếu pin-lệch PRE-EXISTING (seed thẳng DbContext) Submit ⇒ 409 · T6 code ngoài họ: Create/UpdateDraft/Submit PASS như cũ (negative M-5c.ii) · T7 re-pin bản archived ⇒ 409 (D6) · T8 PUT workflow nhóm có phiếu ChoDuyet ⇒ 1 row changelog đúng shape · T9 phiếu DaDuyet/TuChoi ⇒ 0 row (negative) · T10 DELETE có pin KHKK ⇒ 409 · T11 **phiếu KHKK ĐÃ XOÁ MỀM pin ⇒ vẫn 409** (F2) · T12 **phiếu Leave (office, 0-FK) pin ⇒ 409** (F3 — hôm nay là 200-xoá-êm) · T13 id không tồn tại ⇒ 404 · T14 xoá version CUỐI nhóm ⇒ 409 (D5); version 0-usage không-phải-cuối ⇒ xoá OK.
|
||||||
|
**Đạt khi:** build 0-err + FULL suite = baseline-W0 + 14, 0 fail.
|
||||||
|
|
||||||
|
### W2 — FE: fe-admin `src/pages/system/ApprovalWorkflowsV2Page.tsx` (~70-100 dòng) + `KhkkCreatePage` ×2 app
|
||||||
|
| # | Task | Site | Cách |
|
||||||
|
|---|---|---|---|
|
||||||
|
| a | Parse kind | `:164-172` | `typeCode?.match(/^KhkkN([1-8])$/)` → `khkkGroup`; `selectedTypeInt = khkkGroup ? TYPE_INT_CONTRACT_SIGNING_PLAN : TYPE_CODE_TO_INT[typeCode]`; query overview giữ `applicableType=10` (queryKey dùng chung — invalidate prefix tự tươi cả panel nhóm lẫn panel type-10, đã verify `:292/:348`) |
|
||||||
|
| b | Synthetic slice per-Code | `:299-301` | `versions = type10.history.filter(d => d.code === khkkGroupWorkflowCode(g))` (🔴 `History` = FULL list kể cả active — verified BE `:206-211`; panel tự filter `!isActive` khi render) · `active = versions.find(v=>v.isActive) ?? null` (KHÔNG đọc ô `Active` per-type — 1-trong-8) · giữ shape `TypeSummaryDto` |
|
||||||
|
| c | `lockedCode` xuyên suốt | `TypePanel:357` → `Designer:620/:650-651/:798/:920-933` | prop `lockedCode = khkkGroupWorkflowCode(g)`; ô Mã `disabled={isEdit \|\| !!lockedCode}` + hint "Mã khoá theo nhóm — version tự tăng" (F12a); POST gửi `lockedCode ?? code` |
|
||||||
|
| d | **D3=C thi hành — danh-sách CHỐT (F6+M-2 merge)** | `:1235-1328` | Gate `applicableType === TYPE_INT_CONTRACT_SIGNING_PLAN` (áp cả panel ContractSigningPlan cũ — nhất quán). **6 ô** (#1 `allowReturnOneLevel` · #2 `allowReturnOneStep` · #3 `allowReturnToAssignee` · #5 EditDetails `:1268-1276` · #6 EditBudget `:1277-1285` · #9 Delete `:1320-1328`): thêm `disabled` + `title` tooltip "Chưa áp dụng cho KHKK" — 🔴 **GIỮ `checked={entry.<flag>}` state THẬT, CẤM ép false** (trung thực với DB; payload `levelFlagsPayload :255-267` echo state, không đổi). **Ô #4 `allowReturnToDrafter`**: disabled + hiển thị **state thật (thường TRUE)** + tooltip RIÊNG *"KHKK hiện luôn trả về người soạn khi Trả lại — cờ chưa phân nhánh"* (KHÔNG mờ-kiểu-chưa-có — hành-vi thật là LUÔN-CHO). **#7 SkipToFinal GIỮ NGUYÊN** như đang có (`:1292-1302`) · **#8 Finalize SỐNG** |
|
||||||
|
| e | (optional — kéo eoffice rotate) mirror menuKeys | `fe-{admin,user}/src/lib/menuKeys.ts:31-32` | +8 const `AwV2_KhkkN1..8` — 0 hệ quả runtime |
|
||||||
|
| f | **Ô Ngưỡng CEO — NGOÀI D3, disable type-10 VÔ ĐIỀU KIỆN** (F7) | `:944-961` | `disabled={isEdit \|\| applicableType === TYPE_INT_CONTRACT_SIGNING_PLAN}` + helper-text "KHKK không dùng ngưỡng máy — NĐUQ quyết" + POST type-10 gửi `null`. Tiền lệ `:1292`. (`CeoApprovalThreshold` KHÔNG port VĨNH VIỄN — OG-3) |
|
||||||
|
| g | Auto-pin lọc isActive ×2 app (F5/D6) | fe-user `KhkkCreatePage.tsx:114` + fe-admin `:113-116` | `find(w => w.isActive && code-match)` — giữ filter `isUserSelectable :104`. Mirror LOGIC 2 app (2 file vốn khác nhau — không cần byte-equal) |
|
||||||
|
| h | Comment lệch + D4 phụ đề | `:641-644` + PageHeader `:305-318` | sửa comment "2 ô duyệt sớm sống cho MỌI loại" cho khớp thực tế (m-2) · thêm ~1 prop `subtitle = khkkGroupMenuLabel(g)` (`types/khkk.ts:159-168` — 2-app identical sẵn) |
|
||||||
|
|
||||||
|
**Acceptance LOCAL (R-2):** A1 8 leaf → 8 slice khác nhau, hết landing · A2 dialog đúng khuôn ảnh theo D3=C (title `KHKK-N{n} v01 (giữ nguyên phiên bản)`, ô #4 tick-disabled, 6 ô disabled-state-thật, rule-box) · A2b sửa-tại-chỗ THẬT 1 nhóm ⇒ 204 + panel giữ v01 (M-5/m-5) · A3 tạo v02 N1 ⇒ nằm ĐÚNG panel N1 + badge 7 nhóm KHÔNG mất · A4 regression 4 route cũ + fe-user auto-pin. **Đạt khi:** `npm run build` ×2 app + tsc 0-err.
|
||||||
|
🔸 **Răng nút Ghim (sửa theo F5):** sau D6, bỏ-ghim **bản active** = chặn tạo phiếu nhóm; bỏ ghim cả 8 = đóng cửa tạo phiếu KHKK toàn cục (không có rào chặn bỏ-ghim-cái-cuối — khai, không rào đợt này).
|
||||||
|
|
||||||
|
### W3 — **N/A** (D3=C đã chốt; port sau theo lệnh owner = gỡ mờ per-cờ CÙNG wave, khuôn K3-F5)
|
||||||
|
|
||||||
|
### W4 — test-specialist đóng suite: FULL `dotnet test SolutionErp.slnx` = baseline-W0 + 14, 0 fail. Số canonical đổi ⇒ update DUY NHẤT `docs/STATUS.md` row Tests (B1).
|
||||||
|
|
||||||
|
### W5 — ship + verify
|
||||||
|
1. **Commit MỘT phát** BE+FE+tests (R-1, R-5) → push.
|
||||||
|
2. **cicd-monitor 4-chân (m-3):** (i) CI Run success + test-gate = số W4 · (ii) bundle **admin** rotate + grep js mới marker `KhkkN1` (control-âm bundle cũ 0-hit); **eoffice: đổi nếu làm W2e/W2g-fe-user, GIỮ nếu không — ĐO đừng suy** · (iii) BE DLL: ssh grep `SolutionErp.Application.dll` token `EnsureWorkflowGroupMatch` 2-encoding UTF-8/UTF-16 (khuôn S177) + control-dương token cũ · (iv) query-1 lại: 8 row IsActive=1 bất biến qua deploy.
|
||||||
|
3. **Acceptance PROD đọc-only:** login `admin@solutions.com.vn` → ≥3/8 panel render đúng slice + mở dialog rồi Hủy · 3 query SQL + audit pin-lệch (F11) · **KHÔNG bấm "Tạo phiên bản mới" trên prod** · note: role thường chưa grant menu-row ⇒ không thấy leaf = đúng thiết kế 2-tầng (#82).
|
||||||
|
4. Đóng sổ: STATUS/HANDOFF/WAL + tick `YC-013` + khai **accepted-risk**: race 2-admin cùng Code → 500 thô (UNIQUE đỡ data — không mở scope middleware).
|
||||||
|
|
||||||
|
### Rollback
|
||||||
|
0-mig ⇒ revert commit sạch phần MÁY. Data ở lại hợp lệ (changelog rows = audit-history; v02+ = ratchet vô hại, pin by-Id). 🔴 **Revert W1a = bom per-type TÁI VŨ TRANG** — sau revert, CẤM "Tạo phiên bản mới" mọi panel type-10 tới khi re-apply.
|
||||||
|
|
||||||
|
## MỤC 3 — Quyết định + khai
|
||||||
|
|
||||||
|
| # | Quyết | Ai | Nội dung |
|
||||||
|
|---|---|---|---|
|
||||||
|
| D3 | ✅ **anh** (YC-014) | **C** — mờ ô chưa nghe, thi hành theo danh-sách-chốt W2d (6 ô disabled-state-thật + #4 forced-true-disabled + #7 giữ + #8 sống) |
|
||||||
|
| D4 | ✅ lead (reviewer đồng ý) | title = menu-label + phụ đề nghiệp vụ |
|
||||||
|
| D5 | 🟡 **lead chọn CÓ** (bậc-2 an toàn — reviewer-2 M-1 khuyến nghị CÓ) | rào delete-last-version nhóm ⇒ 409 (chặn seeder-tái-sinh khỏi đường UI). **Anh veto 1 câu là gỡ** |
|
||||||
|
| D6 | 🟡 **lead chọn CÓ** (bậc-2 an toàn — reviewer-1 F5 khuyến nghị; tiền lệ vá-3 bridge CÙNG LỖ cho type-3) | pin-check IsActive∧IsUserSelectable + FE lọc isActive ×2 app. **Anh veto 1 câu là gỡ** |
|
||||||
|
|
||||||
|
**Khai mâu-thuẫn lens (F8):** (a) công thức W1a: BE-invest thắng, FE-invest regex BỊ CẤM (R-6) · (b) D3: FE-invest nghiêng A, BE-invest nghiêng C — anh đã chốt C · (c) DB-invest W-DB-2 (param `code=` phía BE) = **KHÔNG LÀM** — chọn client-side slice (payload nhỏ, 0-đổi-BE); disposition khai tại đây.
|
||||||
|
|
||||||
|
**Nợ NGOÀI scope (khai, không lặng):** GET Overview 0-policy lộ roster+flags cho mọi user authenticated (owner ngó sau) · roster 8 nhóm = snapshot email lúc seed, không tự sync theo QT-DN-V2-001 · `Khkk_WfView` panel aggregate giấu 7/8 nhóm (re-point = việc riêng) · sửa-workflow không notify approver phiếu treo (parity PE) · `DEFAULT_CODE_BY_TYPE[10]` panel cũ vẫn gợi mã ngoài-họ (sau W1a vô hại — per-Code) · comment "7 bảng" `:1120` · race 2-admin 2601→500 (accepted).
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
# sub-implementer-backend-0 — ĐỢT-1 lane BE (W0 + W1) — S182 YC-013
|
||||||
|
|
||||||
|
> Artifact ghi LIÊN TỤC trong lúc làm (chống-#53). Spec nguồn: `spec-khkk-awf-mirror-ncc-08-08-2026.md` MỤC 2.
|
||||||
|
> Trạng thái: **IN-PROGRESS** (khởi tạo lúc bắt đầu lane).
|
||||||
|
|
||||||
|
## 0. Kế hoạch lane
|
||||||
|
- W0.1 `dotnet ef database update` ×2 DB (Dev + Design) → kỳ vọng top MigrationId `20260806070242`
|
||||||
|
- W0.2 boot API 1 lần → verify 8 row `KHKK-N1..8` type-10 IsActive=1
|
||||||
|
- W0.3 `dotnet test SolutionErp.slnx` baseline TƯƠI → ghi `run.md`
|
||||||
|
- W1a deactivate-per-Code type-10 (`ApprovalWorkflowV2AdminFeatures.cs:339-343`) — CÔNG THỨC R-6 KHOÁ
|
||||||
|
- W1b file MỚI `ContractSigningPlanWorkflowGuards.cs` + gọi 3 site
|
||||||
|
- W1b2 pin-check IsActive ∧ IsUserSelectable (D6)
|
||||||
|
- W1c changelog type-10 (`:863-893`)
|
||||||
|
- W1d DELETE guard (`:1193-1205`)
|
||||||
|
|
||||||
|
## 1. W0 — prep + đo nền
|
||||||
|
_(đang chạy)_
|
||||||
|
|
||||||
|
## 2. W1 — 5 fix
|
||||||
|
_(chưa bắt đầu)_
|
||||||
|
|
||||||
|
## 3. Verify
|
||||||
|
_(chưa)_
|
||||||
|
|
||||||
|
## 4. Ambiguity / lệch spec khai
|
||||||
|
_(chưa)_
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
# sub-implementer-frontend-1 — S182 W2 (a-h) lane FE
|
||||||
|
|
||||||
|
> ⚠️ TÊN FILE: TASK text ghi `sub-implementer-frontend-0.md`, RUN-TRACE block + structured-output ghi `sub-implementer-frontend-1.md`.
|
||||||
|
> Chọn `-1` (bản RUN-TRACE = bản em main đọc qua `subMdPath`). Khai ở đây để lead biết.
|
||||||
|
|
||||||
|
## §0 — Trạng thái lượt (append liên tục, chống-#53)
|
||||||
|
- [x] Đọc SPEC FINAL MỤC 2 W2 (a-h) + MỤC 1 R-1..R-6
|
||||||
|
- [ ] Đọc file đích + đo tiền-đề từ ĐĨA (line-number trong spec có thể lệch)
|
||||||
|
- [ ] W2a parse kind
|
||||||
|
- [ ] W2b synthetic slice
|
||||||
|
- [ ] W2c lockedCode
|
||||||
|
- [ ] W2d D3=C 6 ô + #4
|
||||||
|
- [ ] W2e menuKeys ×2 app
|
||||||
|
- [ ] W2f ngưỡng CEO
|
||||||
|
- [ ] W2g auto-pin isActive ×2 app
|
||||||
|
- [ ] W2h comment + subtitle
|
||||||
|
- [ ] build fe-admin
|
||||||
|
- [ ] build fe-user
|
||||||
|
|
||||||
|
## §1 — Đo tiền-đề từ đĩa (TRƯỚC khi gõ)
|
||||||
|
(đang đo)
|
||||||
|
|
||||||
|
## §2 — Thay đổi từng task
|
||||||
|
(đang làm)
|
||||||
|
|
||||||
|
## §3 — Verify (build ×2 + proof)
|
||||||
|
(chưa chạy)
|
||||||
|
|
||||||
|
## §4 — Nợ / FLAG cho lead
|
||||||
|
(chưa có)
|
||||||
@ -1,20 +1,24 @@
|
|||||||
# REVIEW-1 (Fable, adversarial ĐÚNG-SAI) — S182 khkk-awf-mirror-ncc
|
# REVIEW-1 (Fable, adversarial ĐÚNG-SAI) — S182 khkk-awf-mirror-ncc
|
||||||
|
|
||||||
> Vai: `/fable-real reviewer` #1/2 — lens SAI/SÓT/MÂU-THUẪN trên spec DRAFT + 3 invest.
|
> Vai: `/fable-real reviewer` #1/2 — lens SAI/SÓT/MÂU-THUẪN trên spec DRAFT + 3 invest.
|
||||||
> Trạng thái: ĐANG ĐỔ RUỘT (skeleton @spawn, Edit liên tục).
|
> Trạng thái: HOÀN TẤT (3 đợt đo trực tiếp trên code + findings + wave-final).
|
||||||
|
|
||||||
## VERDICT (điền cuối)
|
## VERDICT
|
||||||
- (pending)
|
**REVIEW-1: PASS_WITH_FIXES — 2C/5M** (+5m)
|
||||||
|
- Kiến trúc spec ĐÚNG HƯỚNG, đa số claim load-bearing HELD khi đo lại trên code (History-full-list, deactivate-site, PUT-guards, rào-v, delete-0-guard, middleware, seeder, 0-consumer AwV2_). Verdict không phải FAIL vì không có finding nào lật kiến trúc — nhưng 2C (F1 unbuildable W1b, F2 IgnoreQueryFilters) PHẢI vào spec final trước khi execute, 5M nên vào cùng đợt.
|
||||||
|
- C: **F1** (W1b helper internal ⟂ Submit Infrastructure — không biên dịch được như viết) · **F2** (W1d thiếu `IgnoreQueryFilters` ⇒ claim "hết 500" sai ở ca phổ biến nhất).
|
||||||
|
- M: **F3** (5 office-pin LOOSE 0-FK — DB-invest M3 sai, W1d là rào duy nhất) · **F4** (khoá công thức W1a + belt + test code-lạ) · **F5** (KHKK-create không check IsActive — răng nút Ghim mô tả sai sau wave) · **F6** (D3=C: ô #4 phải forced-true, không mờ-chưa-có) · **F7** (ô Ngưỡng CEO tách khỏi D3, disable vô điều kiện).
|
||||||
|
- m: F8 (khai mâu-thuẫn 3 lens) · F9 (baseline 645⟂644 — đo tươi) · F10 (môi trường acceptance #3) · F11 (audit pin-lệch tồn đọng) · F12 (hint lockedCode · notify-parity · comment `:339` · invalidate-keys OK).
|
||||||
|
|
||||||
## Checklist việc (8 mục từ lệnh)
|
## Checklist việc (8 mục từ lệnh)
|
||||||
- [ ] 1. W1a deactivate-per-Code — đọc `ApprovalWorkflowV2AdminFeatures.cs:339-343` + grep consumer `IsActive`
|
- [x] 1. W1a deactivate-per-Code — đọc `:326-398` + grep IsActive consumer toàn BE/Office → F4, kết luận P1 đủ (P2 không cần — 0 consumer server-side dựa active-per-type-10)
|
||||||
- [ ] 2. W2b synthetic slice — `ApprovalWorkflowsV2Page.tsx:286-353` + DTO `AwTypeSummaryDto` `:199-213`
|
- [x] 2. W2b synthetic slice — BE `:199-216` + FE `:286-353` → HELD (History = full list; slice đúng shape; queryKey/invalidate OK)
|
||||||
- [ ] 3. W2c lockedCode — PUT đổi Code 409 `:539-550` + đường rơi khỏi slice
|
- [x] 3. W2c lockedCode — PUT Code-echo 409 `:539-541` HELD; đường rơi-khỏi-slice còn lại = POST panel khác (chấp nhận, per-Code fix F4 khiến vô hại) → F12a hint
|
||||||
- [ ] 4. W1b group-match Submit — phiếu cũ pin lệch
|
- [x] 4. W1b group-match Submit — Submit `:163-213` không re-check; extract-helper UNBUILDABLE → F1; phiếu pin lệch tồn đọng → F11
|
||||||
- [ ] 5. W1d DELETE 409 — đếm module pin từ ModelSnapshot
|
- [x] 5. W1d DELETE — đếm từ Domain+snapshot: 8 cột pin, chỉ 3 FK, 5 LOOSE; ItTicket không pin → F2, F3
|
||||||
- [ ] 6. D3 chấm A/B/C — bảng 9-flag, #4 Trả-về-Drafter
|
- [x] 6. D3 chấm A/B/C — A: giữ #78 6-ô + đẻ "sleeping-config" khi port sau; B: nặng, thuộc owner (service comment `:48-50` tự khai); C: khả thi có tiền lệ NHƯNG phải theo danh-sách F6 (#4 forced-true) + F7 tách CEO-box. Không chấm thay anh — cả 3 sống, C rẻ+trung thực nhất, A đúng "ko lệch" nhất (khai trade-off)
|
||||||
- [ ] 7. Mâu thuẫn 3 lens
|
- [x] 7. Mâu thuẫn 3 lens → F8 (a/b/c)
|
||||||
- [ ] 8. Sót chung (notification / invalidate keys / optimistic)
|
- [x] 8. Sót chung → F12 (notify parity-PE không làm · invalidate keys ĐO OK · optimistic không dùng — trang này invalidate-only)
|
||||||
|
|
||||||
## GHI NHẬN SAU KHI ĐỌC 4 PIN (trước khi mở code)
|
## GHI NHẬN SAU KHI ĐỌC 4 PIN (trước khi mở code)
|
||||||
- Spec DRAFT 68 dòng, 3 invest đọc đủ. Nghi vấn dựng sẵn để đo:
|
- Spec DRAFT 68 dòng, 3 invest đọc đủ. Nghi vấn dựng sẵn để đo:
|
||||||
@ -99,4 +103,51 @@ Bảng BE §3 dòng #4: KHKK **BỎ QUA cờ nhưng hành-vi = LUÔN-CHO** (retu
|
|||||||
**F12 [m] — Sót nhỏ (mục 8):** (a) hint ô Mã `:929-932` khi `lockedCode` nên đổi chữ ("Mã khoá theo nhóm — version auto-tăng"); (b) sửa-workflow-tại-chỗ KHÔNG notify approver phiếu treo — parity PE (PE cũng không notify), KHÔNG làm wave này, khai vào Nợ; (c) invalidate keys ĐÃ ĐO ĐỦ: key `['approval-workflow-v2-overview', selectedTypeInt]` + mutations invalidate prefix ⇒ 8 panel nhóm và panel type-10 dùng chung cache tự tươi, 0 việc; fe-user cache là app khác — không cross-invalidate được, chấp nhận (hành vi sẵn có); (d) comment BE `:339` "only ONE active per type" phải sửa CÙNG COMMIT với W1a kẻo comment nói dối.
|
**F12 [m] — Sót nhỏ (mục 8):** (a) hint ô Mã `:929-932` khi `lockedCode` nên đổi chữ ("Mã khoá theo nhóm — version auto-tăng"); (b) sửa-workflow-tại-chỗ KHÔNG notify approver phiếu treo — parity PE (PE cũng không notify), KHÔNG làm wave này, khai vào Nợ; (c) invalidate keys ĐÃ ĐO ĐỦ: key `['approval-workflow-v2-overview', selectedTypeInt]` + mutations invalidate prefix ⇒ 8 panel nhóm và panel type-10 dùng chung cache tự tươi, 0 việc; fe-user cache là app khác — không cross-invalidate được, chấp nhận (hành vi sẵn có); (d) comment BE `:339` "only ONE active per type" phải sửa CÙNG COMMIT với W1a kẻo comment nói dối.
|
||||||
|
|
||||||
## TỔNG HỢP WAVE FINAL ĐỀ XUẤT
|
## TỔNG HỢP WAVE FINAL ĐỀ XUẤT
|
||||||
- (điền cuối)
|
> Bản wave-plan ĐÃ SỬA theo F1-F12 — đủ chi tiết cho executor Opus MAX. Chỗ nào giữ nguyên spec DRAFT thì ghi "như spec".
|
||||||
|
|
||||||
|
### W0 — prep local (như spec) + 2 bổ sung
|
||||||
|
1. `dotnet ef database update` ×2 DB (Dev + Design — đo lại drift tại chỗ, đừng tin số cũ) → boot API 1 lần → 8 row `KHKK-N*` local (RỖNG NGƯỜI là ĐÚNG).
|
||||||
|
2. **[F9]** `dotnet test SolutionErp.slnx` đo baseline TƯƠI, ghi số vào `run.md` (spec 645 ⟂ STATUS 644 — không chép, đo).
|
||||||
|
3. **[F10]** Chốt môi trường acceptance: #1/#2 local + prod; #3 = integration test (chứng chính) + UI local; prod-#3 CHỈ khi anh gật "v02 clone thành bản sống".
|
||||||
|
|
||||||
|
### W1 — BE: 5 fix, 2 file + 1 file MỚI, 0-mig
|
||||||
|
| # | Fix | Site | Cách (đã sửa theo finding) |
|
||||||
|
|---|---|---|---|
|
||||||
|
| a | Deactivate-per-Code type-10 **[F4]** | `ApprovalWorkflowV2AdminFeatures.cs:339-343` | CÔNG THỨC KHOÁ: `typeEnum == ContractSigningPlan` ⇒ `Where(w => w.Code == request.Code && w.ApplicableType == typeEnum && w.IsActive)`; type khác giữ per-type. CẤM biến-thể regex `^KHKK-N[1-8]$` của FE-invest D1 (code lạ type-10 sẽ rơi per-type → nuke 8 nhóm). Sửa comment `:339` cùng commit **[F12d]** |
|
||||||
|
| b | Group-match guard 3-site **[F1]** | Create `:479-486` · UpdateDraft `:603-607` · `SubmitAsync` (`ContractSigningPlanWorkflowService.cs`, sau guard pin `:163-165`) | File MỚI `Application/ContractSigningPlans/ContractSigningPlanWorkflowGuards.cs` — `public static class`, method `EnsureWorkflowGroupMatchAsync(IApplicationDbContext, Guid awId, int approvalGroup, CancellationToken)` (move nguyên logic rào (v), GIỮ semantics cho-qua-ngoài-họ + khai trong spec). 3 site cùng gọi. Message 409: "Phiếu nhóm N{g} đang gắn quy trình N{k} — vào phiếu (Nháp/Trả lại) đổi lại quy trình đúng nhóm trước khi trình." |
|
||||||
|
| b2 | **MỚI [F5]** IsActive∧IsUserSelectable cho pin KHKK | Create (sau rào iv) + UpdateDraft (trong nhánh `awId != plan.ApprovalWorkflowId` `:603`) | Mirror vá-3 `CreateContractFromSigningPlanFeatures.cs:141-147` — 2 message tách "đã ngừng hoạt động"/"chưa ghim". Giữ-nguyên-pin KHÔNG check (phiếu cũ pin bản archived vẫn sửa GhiChu được) |
|
||||||
|
| c | Changelog type-10 khi PUT **(như spec, chi tiết chốt)** | `:863-893` | Nhánh `else if (def.ApplicableType is ContractSigningPlan)`: query `db.ContractSigningPlans.Where(p => p.ApprovalWorkflowId == def.Id && p.Phase != DaDuyet && p.Phase != TuChoi)` (query-filter tự loại phiếu xoá-mềm — ĐÚNG cho changelog) → add `ContractSigningPlanChangelogs { EntityType = Workflow /*=4, enum sẵn*/, Action = Update, EntityId = def.Id, PhaseAtChange, UserId/UserName, Summary + ContextNote }` mirror block PE |
|
||||||
|
| d | DELETE usage-check → 409 **[F2][F3]** | `:1193-1205` | Đếm pin **8 module** (PE/Contract/KHKK **BẮT BUỘC `IgnoreQueryFilters()`**; Proposal/Leave/Ot/Vehicle/Travel đếm thẳng — 5 module này pin LOOSE 0-FK, guard này là RÀO DUY NHẤT chống dangling) + đếm opinions 8 bảng theo level-ids của workflow (IgnoreQueryFilters — FK không quan tâm IsDeleted) → 409 kể tên "N phiếu đang gắn + M chữ ký". Rationale 2 vế: FK-modules = UX 547→409; office = data-integrity |
|
||||||
|
|
||||||
|
**Test W1 (test-before a/b/b2, test-after c/d):**
|
||||||
|
1. Tạo v2 `KHKK-N1` ⇒ N2..N8 IsActive bất biến. 2. DuyetNcc tạo Code-mới-cùng-type vẫn tắt Code cũ (regression per-type). 3. **[F4]** POST type-10 code-lạ `QT-KHKK-V2-001` ⇒ 8 nhóm bất biến. 4. UpdateDraft re-pin lệch nhóm ⇒ 409; re-pin bản archived ⇒ 409 **[F5]**; Submit phiếu pin lệch ⇒ 409. 5. PUT workflow nhóm có phiếu treo ⇒ 1 row `ContractSigningPlanChangelogs`. 6. DELETE version có pin KHKK ⇒ 409; **phiếu KHKK ĐÃ XOÁ MỀM pin ⇒ vẫn 409 [F2]**; **phiếu Leave (office, 0-FK) pin ⇒ 409 [F3]**; version 0-usage ⇒ xoá OK.
|
||||||
|
|
||||||
|
### W2 — FE `ApprovalWorkflowsV2Page.tsx` (~70-100 dòng) + KhkkCreatePage ×2
|
||||||
|
| # | Chạm | Site | Cách |
|
||||||
|
|---|---|---|---|
|
||||||
|
| a | Parse kind (như spec) | `:164-172` | `match(/^KhkkN([1-8])$/)` → `khkkGroup`; `selectedTypeInt = khkkGroup ? 10 : TYPE_CODE_TO_INT[typeCode]` |
|
||||||
|
| b | Synthetic slice (như spec — ĐÃ VERIFY `History` = full list kể cả active, BE `:206-211`) | `:299-301` | `versions = type10.history.filter(d => d.code === khkkGroupWorkflowCode(g))` · `active = versions.find(v => v.isActive) ?? null` · label = "Duyệt KHKK — Nhóm {g}" + phụ đề `khkkGroupMenuLabel(g)` (D4) |
|
||||||
|
| c | `lockedCode` (như spec) + hint **[F12a]** | `TypePanel:357` → `Designer:620/:650-651/:798/:920-933` | prop `lockedCode?: string`; ô Mã `disabled={isEdit \|\| !!lockedCode}` + hint "Mã khoá theo nhóm"; POST gửi `lockedCode ?? code` |
|
||||||
|
| d | D3 — thi hành theo anh chốt; **nếu C thì theo danh-sách-chốt [F6]** | `:1235-1328` | 6 ô mờ-FALSE (#1#2#3 return-modes · #5 `:1268-1276` · #6 `:1277-1285` · #9 `:1320-1328`) + **#4 FORCED-TRUE-disabled** tooltip "KHKK luôn trả về người soạn — cờ không tắt được" + #7 giữ disabled sẵn + #8 sống. Gate `applicableType === TYPE_INT_CONTRACT_SIGNING_PLAN` (áp cả panel ContractSigningPlan). Payload ô mờ = echo giá-trị-đang-lưu |
|
||||||
|
| e | (optional, như spec) mirror menuKeys +8 const | `fe-{admin,user}/src/lib/menuKeys.ts:31-32` | 0 hệ quả runtime |
|
||||||
|
| f | **MỚI [F7]** — Ô Ngưỡng CEO: disable type-10 VÔ ĐIỀU KIỆN (mọi phương án D3) | `:944-961` | `disabled={isEdit \|\| applicableType === TYPE_INT_CONTRACT_SIGNING_PLAN}` + tooltip "KHKK không dùng ngưỡng máy — NĐUQ quyết" + POST type-10 gửi `null`. Tiền lệ `:1292` |
|
||||||
|
| g | **MỚI [F5]** auto-pin lọc isActive ×2 app | fe-user `KhkkCreatePage.tsx:114` + fe-admin `:113-116` | `find(w => w.isActive && codeMatch)` — giữ filter `isUserSelectable` `:104`. Răng nút Ghim đúng lại: bỏ ghim BẢN ACTIVE = chặn tạo phiếu nhóm |
|
||||||
|
|
||||||
|
**Regression (như spec) + sửa câu răng-Ghim theo F5.** SHA-mirror: KHÔNG áp cho Designer (fe-admin-only, đã chứng); RIÊNG W2g là cặp file 2-app — diff phải mirror logic (không cần byte-equal vì 2 file vốn khác nhau).
|
||||||
|
|
||||||
|
### W3 — CHỈ KHI D3=B (như spec; anchors `PeSoftDeleteFeatures.cs:110-114` / `PurchaseEvaluationWorkflowService.cs:421-424/:810` CHƯA re-đo trong review này — executor verify trước khi port; mỗi cờ 1 test RED→GREEN; `CeoApprovalThreshold` vĩnh viễn KHÔNG port — F7 vẫn áp)
|
||||||
|
|
||||||
|
### W4 — test-specialist đóng suite: baseline = SỐ ĐO Ở W0 (không phải 645) + N test mới W1/W3
|
||||||
|
|
||||||
|
### W5 — reviewer pre-commit → commit → cicd 3-chân (BE api + bundle admin rotate; +eoffice nếu W2e/W2g fe-user) → acceptance + SQL verify
|
||||||
|
- 3 query DB §4 (như spec) + **[F11]** query audit pin-lệch: `... WHERE w.Code LIKE 'KHKK-N%' AND w.Code <> CONCAT('KHKK-N', p.ApprovalGroup)` — >0 báo anh xử tay.
|
||||||
|
- Query 8-nhóm: nhóm nào 0-active (bom nổ trước vá) → recovery = "Tạo phiên bản mới" từ panel nhóm đó (lockedCode tự điền mã, sinh vNext active).
|
||||||
|
- Acceptance 1-4 như spec, #3 theo môi trường đã chốt ở W0.3 **[F10]**.
|
||||||
|
|
||||||
|
### Điểm quyết cho anh (cập nhật theo review)
|
||||||
|
- **D3** giữ 3 phương án NHƯNG: (i) khai 2 lens khuyến nghị ngược nhau (FE nghiêng A, BE nghiêng C) **[F8b]**; (ii) nếu C → dùng danh-sách-chốt F6 (ô #4 forced-true, KHÔNG mờ-kiểu-chưa-có); (iii) ô Ngưỡng CEO KHÔNG thuộc D3 — disable vô điều kiện **[F7]**.
|
||||||
|
- **D4** (title panel) giữ như spec.
|
||||||
|
- **MỚI D5 [F5]:** chốt hành vi pin: (khuyến nghị) thêm check IsActive∧IsUserSelectable + FE lọc isActive — hay giữ nguyên semantics cũ và sửa lại câu răng-nút-Ghim trong spec.
|
||||||
|
|
||||||
|
### Nợ NGOÀI scope (giữ như spec, +2)
|
||||||
|
GET Overview 0-policy (information-disclosure mềm) · roster snapshot-email · `Khkk_WfView` panel aggregate giấu 7/8 · comment "7 bảng" `:1120` · **+ sửa-workflow-tại-chỗ không notify approver phiếu treo (parity PE) [F12b]** · **+ W-DB-2 (param `code=` phía BE) = KHÔNG LÀM, chọn client-side slice — disposition khai [F8c]**.
|
||||||
|
|||||||
@ -0,0 +1,44 @@
|
|||||||
|
# sub-test-specialist-2 — ĐỢT-1 lane TEST W1 (14 test T1-T14)
|
||||||
|
|
||||||
|
> ⚠️ TASK header ghi artifact = `sub-test-specialist-0.md`, nhưng khối RUN-TRACE (ISOLATION B6) ra lệnh
|
||||||
|
> **CHỈ ĐƯỢC GHI** `sub-test-specialist-2.md`. Ưu tiên luật isolation ⇒ ghi file NÀY, KHÔNG tạo `-0`.
|
||||||
|
|
||||||
|
- ts-mở: 2026-08-08 · lane: test-specialist (WRITE `tests/**` ONLY, 0 chạm `src/**`)
|
||||||
|
- SPEC: `spec-khkk-awf-mirror-ncc-08-08-2026.md` MỤC 2 W1 khối Test (:37-39)
|
||||||
|
- Homes: `tests/SolutionErp.Infrastructure.Tests/Application/UpdateAwDefinitionTests.cs` (T1-T3, T8-T14)
|
||||||
|
· `tests/SolutionErp.Infrastructure.Tests/Application/ContractSigningPlanApprovalTests.cs` (T4-T7)
|
||||||
|
- 🔴 implementer-backend land 5 fix SONG SONG ⇒ test viết theo **HÀNH VI ĐÍCH**; ca đỏ-vì-BE-chưa-land = RED hợp lệ.
|
||||||
|
|
||||||
|
## §0 — Ghi liên tục (chống-#53). Mục CHƯA CHẠY chỉ có tiêu-đề + "CHƯA ĐO".
|
||||||
|
|
||||||
|
## §1 — Đọc nền (prod code sites)
|
||||||
|
|
||||||
|
CHƯA ĐO
|
||||||
|
|
||||||
|
## §2 — Baseline đo tươi
|
||||||
|
|
||||||
|
CHƯA ĐO
|
||||||
|
|
||||||
|
## §3 — T1-T3 (deactivate-per-Code, home UpdateAwDefinitionTests)
|
||||||
|
|
||||||
|
CHƯA ĐO
|
||||||
|
|
||||||
|
## §4 — T4-T7 (group-match guard + pin-check, home ContractSigningPlanApprovalTests)
|
||||||
|
|
||||||
|
CHƯA ĐO
|
||||||
|
|
||||||
|
## §5 — T8-T9 (changelog PUT type-10)
|
||||||
|
|
||||||
|
CHƯA ĐO
|
||||||
|
|
||||||
|
## §6 — T10-T14 (DELETE usage-check 409/404 + D5 last-version)
|
||||||
|
|
||||||
|
CHƯA ĐO
|
||||||
|
|
||||||
|
## §7 — Bảng kết {test → RED | GREEN | đợi-BE}
|
||||||
|
|
||||||
|
CHƯA ĐO
|
||||||
|
|
||||||
|
## §8 — Bug prod phát hiện / spec drift
|
||||||
|
|
||||||
|
CHƯA ĐO
|
||||||
Reference in New Issue
Block a user