wal: flush 20260729T2006
This commit is contained in:
@ -12,7 +12,9 @@ chain:
|
||||
- [x] wf đợt-1 `wf_7d6fb81b-640`: FE lane CLEAN (Designer type-10, containment 2-lớp, build tươi lead-verify PASS, đã harvest) · BE lane chết #53 sau Domain-layer (8 entity + type-10 + 4/7 config trên đĩa, 0 sub-md)
|
||||
- [x] wf BE `wf_f8c806d2-5a3` chết #53 lần 2 NHƯNG sub-md ghi-từng-mục cứu trọn (Mig 69 apply 2 DB, 96 bảng) → lead solo đuôi {seeder SeedKeHoachKyKetAccessAsync + CodeGen KHKK + DI + 3 site AWV2Admin} → **build 0W/0E 47s**; harvest 2 diary on-behalf xong
|
||||
- [x] wf ĐỢT-2 `wf_a95c9909-14b`: database-agent **PASS 8/8+DB11 0-blocker** (parity 2 DB, Down script-proof) · test-specialist **4 test + fault-inject 2-chiều** (chết #53 lúc đợi suite — sub-md cứu, lead chạy tươi **566/0**); harvest 2 diary xong. Tally #53 wave này: 3/5 lượt spawn
|
||||
- [!] reviewer adversarial ĐANG CHẠY nền (trước commit — schema mig; focus revoker-2-chiều seeder + 3-site + FE containment + boundary) → PASS thì: commit file-cụ-thể + push → cicd-monitor 3-chân-kiềng → stage-7 prod-verify {đo CỜ policy + Designer type-10 3-Bước}
|
||||
- [x] reviewer PWF 10-issue 0-chặn (lượt-1 garble #53 → resume sạch): 8 fix cùng commit + 2 giữ; build+suite giữ 0W/0E · 566/0; residual-write MEMORY reviewer ACCEPT verified-KEPT (AS-10)
|
||||
- [x] commit `a8027c0` (30 file +8.987/−22, F-0 gate ĐẠT) + PUSH origin/main
|
||||
- [!] wf: cicd-monitor verify `a8027c0` ĐANG CHẠY nền — 6 phép (CI 566 · mig 69 prod · menu 142 · marker `QT-KHKK-V2-001` · đo-CỜ F-04 2 chiều · smoke+label); về PASS ⇒ W1 ĐÓNG, còn nghiệm thu tay Designer type-10 3-Bước (deep-link `/system/approval-workflows-v2/ContractSigningPlan`) + dựng WF trước W5
|
||||
- [ ] đợt-2 SAU khi wf về: test-specialist + database-agent (song song) → lead acceptance §③-B (build·test·sqlcmd 96·Down sạch·đo CỜ) → reviewer → commit/push → cicd-monitor 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)
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
# Reviewer Agent — Persistent Memory
|
||||
|
||||
- **S159 (07-29) đợt-5 menu 6-leaf HĐ + endpoint `/contracts/deleted` (PWF 10 FLAG 0H/4M/6L):** 🔴 **con-số TRONG CHÚ THÍCH cũng là khẳng-định đo-được** — diff SỬA comment D3 thành "NAY CÓ 2 chỗ `IgnoreQueryFilters`", `grep -rn` ra **3 file/17 site** (ApprovalWorkflowV2AdminFeatures 15 site); tôi suýt duyệt bằng mắt ⇒ **luật: comment mang số ⇒ chạy phép đếm, và số viết dưới dạng LUẬT ("chỗ duy nhất ⇒ CẤM…") sai thì lan sang người sửa sau**. · class **`mirror-nửa-vời khai thừa phạm-vi`**: comment nói "Hộp thư + Tổng quan viết HOA" nhưng "Hộp thư" render bằng `StaticLeaf` KHÁC component ⇒ đọc comment ≠ đọc call-site. · **cookie-cutter phải soi CẢ phần PE đã CHẶN**: bản HĐ copy list-deleted nhưng bỏ `disabled={deletedView}` ⇒ click row → detail 404 → panel **trắng** (page thiếu nhánh `isError`) + mobile navigate ra trang 404. · mirror 2-app: fe-admin ẩn `Ct_*` (⇒ 21 leaf mới KHÔNG cần route) nhưng `Khkk_*` KHÔNG ẩn ⇒ thiếu 2 staticMap = drop silent #50 — **kiểm hide-filter TRƯỚC khi kêu thiếu mirror**. · `tsc -p tsconfig.app.json` EXIT=0 + `noUnusedLocals` = chứng cắt-hero-không-mồ-côi MẠNH HƠN grep (nhắc lại: fe-user KHÔNG bật `strict`). · `Contracts` ∈ `MenuKeys.All` ⇒ policy `Contracts.Read` có thật; `MenuPermissionHandler` khớp ĐÚNG-KHOÁ, KHÔNG kế thừa root (#82). [→ `runs/2026-07-29-S159-tong-quan-pipeline-menu/sub-reviewer-diff-dot5.md`]
|
||||
- **[→ archive/2026-07.md @S161-curate] S159 đợt-5 (07-29) menu 6-leaf HĐ + `/contracts/deleted` (PWF 0H/4M/6L):** chú-thích-mang-SỐ phải chạy phép đếm (comment "2 chỗ IgnoreQueryFilters" — thật 3 file/17 site) · cookie-cutter phải soi CẢ phần bản gốc đã CHẶN (thiếu `disabled={deletedView}` ⇒ panel trắng) · kiểm hide-filter TRƯỚC khi kêu thiếu mirror 2-app · `tsc` + `noUnusedLocals` mạnh hơn grep cho claim "đã cắt".
|
||||
|
||||
- **S159 (07-29) dashboard "toàn trình" đợt-4 FE-only (fe-user 984+/337−, PWF 7 FLAG 0H/2M/5L):** 🔴 **`tsc` XANH đo ÍT hơn vẻ ngoài** — `fe-user/tsconfig*.json` KHÔNG có `strict`/`strictNullChecks` (chỉ `noUnusedLocals`) ⇒ **tra cờ tsconfig TRƯỚC khi trích tsc làm bằng chứng**; ngược lại `noUnusedLocals`+pass = bằng chứng MẠNH HƠN grep cho claim "đã gỡ khối X" (compiler chặn nếu sót import). · class **`nhãn khẳng định chiều-ngược`**: dot-map `none='chưa tới'` — không-suy-diễn "đã xong" là đúng, nhưng "chưa tới" CŨNG là khẳng định ⇒ sai cho GĐ ĐỨNG TRƯỚC + sai khi `contractId != null` **có sẵn trong payload**. · pager tính `data.page±1` (keepPreviousData ⇒ stale) thay vì state ⇒ double-click = no-op. · **verify đích điều hướng phải đọc CẢ breakpoint trang đích** (panel `hidden lg:block` ⇒ ngõ cụt mobile; trang đích tự có nhánh `matchMedia` mà caller mới không copy). · regression đo HEAD⟂work bằng `grep -c` từng token: count 5→2 mà KHÔNG mất nhãn (inline-prop → `STAGES[i].title`) ⇒ **đếm lệch phải truy CẤU TRÚC trước khi kêu hồi quy**. · tự tính lại 4 tỉ-số contrast + tra `@theme` mọi `var(--color-*)` (0 dòng `--color-*: initial` ⇒ nấc mặc định còn) — 3/3 số designer ĐÚNG. · lời khai sub-file "766→1.130 dòng" SAI (đĩa 1.413 = 766−337+984). [→ `runs/2026-07-29-S159-tong-quan-pipeline-menu/sub-reviewer-diff-dot4.md` 28,5KB]
|
||||
- **S161 (07-29) W1 KHKK tiền-commit (Mig 69 + seeder + Designer type-10) — PWF 10 FLAG 1H/3M/4m/2L:** 🔴 **HIGH lại nằm ở `git` chứ không ở mã (S155 tái diễn):** 2/3 file Mig 69 UNTRACKED `??` mà snapshot đã tracked-M ⇒ `commit -a` nạp model 7 bảng nhưng BỎ migration; build+566 test vẫn xanh ⇒ **gate = `git status --porcelain -- src tests | grep '^??'` phải RỖNG ngay trước commit**. · **MAJOR bắt được nhờ đi NGƯỢC lời-khai FE:** comment FE tự khai "nhãn lấy từ BE `applicableTypeLabel`" ⇒ đi kiểm bờ BE: `AwLabels.Type` chỉ 3 entry, `GetValueOrDefault(type, type.ToString())` ⇒ UI hiện **"ContractSigningPlan"** tiếng Anh và `useState(\`Quy trình ${label}\`)` **GHI chuỗi Anh vào cột Name DB** — lớp *hợp-đồng-đứt-2-bờ*, tsc+build+test đều xanh. **Luật rút: câu comment dạng "bên kia lo" = ĐI ĐỌC BÊN KIA.** · seeder 5/5 PASS (call sau revoke `:2109`>`:2096`; revoker chỉ `Hrm|Off|Personal` ⇒ không lật 2-chiều; `TryGetValue` tuple `(RoleId,MenuKey)` — khuôn 1-role sẽ ném dup-key, unique-index `PermissionConfiguration:26` cứu) nhưng **acceptance "đo CỜ" chưa đo được ở đâu**: Dev DB **0 row** `Khkk*` cả MenuItems lẫn Permissions (menus 100 vs prod 142) ⇒ chưa nhánh nào từng chạy. · **`grep`-cùng-lớp bằng TOKEN-SONG-SINH** (`VehicleBookingLevelOpinions` repo-wide) mạnh hơn grep tên-mới: chứng 3/3 site đủ + 0 site thứ 4. · 2 chú thích cùng file nay SAI SỐ ("7 bảng"/"7 khối" → 8) + comment nguồn `MenuKeys.cs:37` "CỐ Ý NGOÀI All" nay sai + anchor `(:614)` trỏ dòng TRƯỚC-commit (đúng = :645) ⇒ **diff sửa mã phải sửa MỌI số/neo trong chú thích cùng file**. · STATUS.md `Menu keys 54`/`Policies 216` không đổi dù |All|=55 ⇒ derived-drift. Tag `[s161, high-o-git-khong-o-ma, hop-dong-dut-2-bo-nhan-BE, token-song-sinh-sweep, seeder-upgrade-if-exists, comment-mang-so-va-neo]`
|
||||
- **[→ archive/2026-07.md @S159-curate] S155-đợt2 (07-27) PE delete-approver DIFF-review #2 (12 FLAG 2H/4M/6L · ĐỪNG-DEPLOY):** class **`hợp-đồng-đứt-giữa-2-bờ`** (FE type khai cờ, BE DTO không có ⇒ nút chết mà tsc+build+561-test đều xanh) · policy-gate đo DB 11/13 vai `CanDelete=0` · mã ĐỔI giữa lượt soi ⇒ re-đo đĩa TRƯỚC verdict · đổi-chiều-assert ≠ nới-assert.
|
||||
- **[→ archive/2026-07.md @S155-curate] S155 ×2 (07-27) PE delete-approver — DIFF-review đợt 1 tiền-deploy (14 FLAG 4H/6M/3L/1I, DEPLOY-CÓ-RỦI-RO) + SPEC-review (PWF 4H/8M/5L):** 🔴 class MỚI **`HIGH nằm ở git chứ không ở mã`** — 2/3 file migration UNTRACKED mà snapshot ĐÃ tracked ⇒ `commit -a` nạp model-có-cột nhưng bỏ migration ⇒ `Invalid column name` cả 7 module, build+test vẫn xanh ⇒ **gate deploy phải chấm `git status ^??` cho `Migrations/`** · `ExecuteDelete` ngoài transaction TRƯỚC `SaveChanges` = mất dữ liệu không hoàn tác · purge xoá CỨNG chữ ký phiếu XOÁ MỀM ⇒ **test đang KHOÁ chiều ngược, vá xong test đỏ ≠ hồi quy, CẤM nới assert** · ~600 dòng BE = mã chết (`grep api.put`=0) · **xanh-giả bắt bằng phép 2-thế-giới** (còn-gate ⟂ bỏ-gate cùng cho 0 ⇒ 0 thông tin) · CLEAN chứng bằng **liệt kê vét cạn** write-site + sweep gián-tiếp (#81-EXT) · 2 lỗi TỰ BẮT: trích line-number **từ diff** (diff không mang số dòng file) · `grep -v Snapshot` ăn nhầm tên migration · **file bị sửa TRONG LÚC soi ⇒ neo bằng NỘI DUNG DÒNG + ghi bản-đồ-trôi**.
|
||||
- **[→ archive/2026-07.md @S155-curate] S146·S147·S152-D2 (digest):** S146 lead sửa 1 phép quét 4 lần/phiên vì mã-hoá ý-định NGỮ-NGHĨA vào regex ⇒ nấc đúng = lưới-soát-cho-người + allowlist CÓ TÊN + use⟂mention · S147 **decouple 1 gate ⇒ truy xem prop dùng chung đã mang carve-out chưa** (`itemsReadOnly` ≠ raw `readOnly`); "same fix" cho surface anh-em có thể trúng gate KHÁC · S152-D2 census thay spot 307/307; **3 THƯỚC-HỎNG** (md5 disk vs `git show` = FAIL giả do CRLF⟂LF · `grep -c` dính citation-trap · `grep -iF` MSYS trả 0-hit IM LẶNG trên UTF-8) + máy-trích mù đuôi `{.yml,.json,.sql}`.
|
||||
@ -14,12 +14,12 @@
|
||||
> Update BEFORE every stop. Tiered Memory v1: L1 HOT cap ~17KB (hook 24.4KB read-limit) · L2 `archive/` on-demand · L3 RAG `search_memory` just-in-time. Keep entry ≤ 1.5K chars (gotcha #53).
|
||||
> Full verbatim history pre-S40 → git `d2f52ba` + `archive/2026-05-q1..q2.md`; S51→S76 detail → `archive/2026-06.md` (S69/S70/S71/**S80** curate). Archive map: `archive/_INDEX.md` + per-period `.gist.md`.
|
||||
|
||||
- **S160 (07-29) reviewer CHỐT-CUỐI /fable-real (verify 13-fix landed) — #53 chết sau Trục-1+Trục-2, đĩa cứu:** khuôn review-của-review: chấm "fix ĐÃ LAND + ĐÚNG codebase, không đẻ lỗi mới" — **12/13 landed-đúng + ~30 anchor re-verify THẬT @HEAD, 1 half-fix**. Bài: (1) **fix áp NỬA spec = dư-lượng thật** — W7 §② sửa badge-nguồn nhưng bảng §① cùng file sót ⇒ soi CẢ FILE khi nhận "đã fix", không chỉ chỗ được trỏ (lớp vá-1-nửa-cùng-lớp S122); (2) **anchor-label ⟂ thân** — gate-5-anchor W3 vẫn liệt `PEWS:1008` sau khi thân phán khuôn đó SAI ⇒ anchor-list là artifact riêng phải sync khi thân đổi; (3) **anchor off-by-N** — "2 checkbox :1267-1268" trúng 1 (SkipToFinal ở :1256) ⇒ dải anchor phải grep CẢ 2 symbol; (4) **verify NGƯỢC premise clone**: re-đo `ContractWorkflowService.cs:191-198` admin-override-gán-qua-biến + `ContractChangelogConfiguration:22-25` FK-Cascade + `ContractAttachmentFeatures:56-152` 0-IDOR — 3/3 premise HIGH clone ĐỨNG ⇒ clone-review có răng thật; (5) **O-A moot-check**: owner để-mở ⇒ F-C3/F-C5/F-S2-grant MOOT-đúng (không siết thì không grant), KHÔNG phải lead né. #53 lần 2/phiên trên reviewer — return "Trục-2: xác vị file…" (mẩu giữa việc) nhưng sub-file 8KB có Trục-1+Trục-2 đủ ⇒ **lead finalize VERDICT+LỖI-MỚI+LEFTOVER on-behalf từ đĩa** (0 mất kết-luận vì ghi-đĩa-trong-lúc-làm). Tag `[s160, chot-cuoi-verify-fix-landed, half-fix-soi-ca-file, anchor-label-vs-than, verify-nguoc-premise-clone, o-a-moot-check, 53-doc-cuu]`
|
||||
- **[→ archive/2026-07.md @S161-curate] S160 (07-29) CHỐT-CUỐI verify 13-fix landed (12 landed + 1 half-fix):** fix áp NỬA spec = dư-lượng (soi CẢ FILE khi nhận "đã fix") · anchor-list là artifact RIÊNG phải sync khi thân đổi · dải anchor phải grep CẢ 2 symbol · verify NGƯỢC premise clone 3/3 đứng · owner để-mở ⇒ finding MOOT-đúng.
|
||||
|
||||
## 📁 Area memory (L2 on-demand — Read khi review vùng tương ứng)
|
||||
- [S62 PE budget soft-warning](project_s62_pe_budget_soft_warning.md) — PASS: hard-block→soft-warning; submit-guard intact + validator giữ `BudgetPeriodAmount>0`, row8 negative-safe (additive-only). Validator class `PurchaseEvaluationFeatures.cs:317`.
|
||||
- [Wire/mirror claim verification anchors](feedback_wire_claim_verification_anchors.md) — sha256 twin-file · `git diff -U0` isolate true-adds · `allowNegative` bleed check · guard-still-intact grep.
|
||||
- **S160 (07-29) review SPEC-BỘ dry-run KHKK→HĐ-cứng [engine `/fable-clone` 6 lane opus + `/fable-real` chốt fable; `runs/2026-07-29-S160-khkk-dryrun-plan/review-synthesis-clone-s160.md`]:** 6 lane (anchor-A rỗng #StructuredOutput-fail nhưng ghi-đĩa-lượt-1-2 cứu · B/C/wave-logic/owner-consist/security). **5/5 verdict SUA-TRUOC-THI-CONG, hội tụ cao** ⇒ lead-verify 5 claim load-bearing 5/5 CONFIRMED đĩa. Bài đắt: (1) **review SPEC ≠ review CODE — bắt lỗ ở acceptance + default-lấn-quyền + hố-chưa-khai, KHÔNG chỉ anchor** (anchor 24-28/28 đúng dòng nhưng spec vẫn hỏng cấu-trúc); (2) **seeder-grant no-op = 403 giết-feature IM LẶNG** — row Permission đã tồn tại CanRead-only ⇒ grant kiểu insert rơi skip-existing `continue` (`DbInitializer.cs:2242-2245`), phải UPGRADE-if-exists (`SeedProcurementMasterAccessAsync:2367-2374`); **acceptance đếm ROW = 0-bit, phải đo CỜ CanCreate/CanUpdate**; (3) **owner-authority finding** — lane owner-consistency bắt lead đặt default lấn đúng chỗ owner phán "để yên" (O-3 "hợp đồng cứ từ từ" + STATUS:13 tái-khẳng-định) ⇒ surface AskUser thay vì tự quyết → anh chọn O-A gỡ hẳn wave; (4) **"204 KHÔNG 409" PASS SẴN** = acceptance 0-bit nửa-vế vì nhánh trình không đọc workflow (`ContractWorkflowService.cs:70-89`) — vế răng = `currentApprovalLevelOrder=1` phải chạy tới lượt DUYỆT; (5) **FK-547 compiler-không-chặn**: gọi `LogWorkflowTransitionAsync(Guid contractId)` với plan.Id = enum/Guid cast được nên build xanh, nổ runtime — dùng bảng changelog RIÊNG của module mới; (6) **choke-point "DUY NHẤT" sai** — admin-override gán Phase QUA BIẾN (`:190-193`) nên literal-grep miss (lớp #81), phải kê 2 write-path. **anchor-B census tên-test: repo 0/460 tên thuần-Việt ⇒ khuôn = English-predicate** (owner chốt đổi). Ensemble ĐÓNG GÓI C2 ăn: 6 lane ≤3-file + khung-rỗng-lượt-1-2 ⇒ 0 lane chết dù 1M+ token. Tag `[s160, review-spec-bo, seeder-grant-no-op-403, acceptance-dem-row-0bit, owner-authority-surface, 204-khong-409-pass-san, fk-547-compiler-mien, choke-point-2-write-path, test-name-census-repo]`
|
||||
- **[→ archive/2026-07.md @S161-curate] S160 (07-29) review SPEC-BỘ dry-run KHKK (6 lane, 5/5 SUA-TRUOC-THI-CONG):** review SPEC ≠ review CODE — lỗ ở acceptance + default-lấn-quyền, không chỉ anchor · seeder-grant kiểu insert = NO-OP 403 im lặng ⇒ acceptance phải đo CỜ không đếm ROW · owner-authority surface AskUser thay tự quyết · acceptance "PASS SẴN" = 0-bit · FK-547 compiler-không-chặn · choke-point "DUY NHẤT" sai vì gán QUA BIẾN (#81).
|
||||
- **S89 trio** ([sectionB](project_s89_pe_sectionb_review.md) · [endsBeforeCeo](project_s89_pe_endsbeforeceo_plan_review.md) · [finalize-note](project_s89_finalize_note_plan_review.md)) — adjustMut share race + authz-lens ≠ concurrency-lens · FE 4 render-sites plan-missed-2 · ground-truth-accurate-nhưng-gaps.
|
||||
- **S101 H18/H19 WF2 + LANE-C — PWC/PASS:** content-hash ≠ commit-SHA (hex strip/no-strip) · exact-token sweep misses paraphrase → widen concept-phrase. → `archive/2026-07.md`.
|
||||
- [S103 H20+crystallized-backfill review](project_s103_h20_crystallized_backfill_review.md) — WF2 PASS; 6/6 hash recompute MATCH + 4 already-met verified. Lesson: multi-axis warning phải nằm trong OUTPUT của script (reader chạy inline), không chỉ doc.
|
||||
@ -72,10 +72,7 @@ Adversarial pre-commit reviewer SOLUTION_ERP. Read-only verify + live curl prod
|
||||
|
||||
## 🧠 SOLUTION_ERP review essentials (S80 verified — re-ground từ docs/STATUS.md canonical)
|
||||
|
||||
- **Tests baseline:** **354 PASS** (45 Domain + 309 Infra · 0 fail/skip). Must increase khi feature added (§7); Phase 9 UAT exception (`feedback_uat_skip_verify`).
|
||||
- **Gotchas:** **71 active** (`docs/gotchas.md`, format `### N.`). Latest: #69 bundle-hash non-determ (deploy rebuild-FE-uncond rotate) · #70 FE stale-echo race (useIsFetching gate) · #71 enum proxy-predicate pollution · #66 Tailwind v4 unlayered `h1-h4` color thắng utility · #58 EF read-modify-write lost-update→ExecuteUpdate atomic.
|
||||
- **Migrations:** **57 latest `AddPeSuggestedPriceNotes`** (path `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/`). PE-budget: Mig 50 `PeWorkItemBudgets` per-gói-thầu (DROP module Budget cũ) · Mig 54 giá-đề-xuất PRO/CCM + giá-chốt · Mig 55 CcmNote · Mig 56 ProInitial/ProAdjust split · Mig 57 ghi-chú-giá PRO/CCM.
|
||||
- **Endpoints:** ~253 · **88 SQL tables**.
|
||||
- **Tests · gotchas · migration · endpoint · bảng = SỐ CANONICAL ở `docs/STATUS.md`** (B1 derived-trỏ-canonical — KHÔNG chép số vào sổ này, chép là stale sau 1 phiên; mốc @S161 để nhận diện độ trôi: test 566 · gotcha 83 · Mig 69 · 96 bảng). Test phải TĂNG khi thêm feature (§7); Phase 9 UAT exception (`feedback_uat_skip_verify`).
|
||||
- **Identity password ≥12 chars** (reject 11-char). Test creds: admin `admin@solutions.com.vn/Admin@123456` (full) · UAT `nv.test@solutions.com.vn/TestUser@123456` (Drafter CCM).
|
||||
- **Prod:** api/admin/eoffice.solutions.com.vn. Bundle live admin `CsJetgZH` / user `BVS0ApIm` (Run #330). **Pin:** MediatR `12.4.1` (flag `Version="14`) · Swashbuckle `6.9.0` · Node CI `20.x`.
|
||||
- **Conventions:** `docs/rules.md` (§1.1 outward writing, §3.9 mirror 2 FE, §5.2 commit, §6.5 docs narrative, §7 test timing, §2.8 pin).
|
||||
|
||||
@ -168,3 +168,14 @@
|
||||
## S149 (2026-07-24) — gate hội-tụ-bookend [LEAD GHI ON-BEHALF @S150 — M9/B3 theo H2-F4 (1 invocation thật → 0 entry); nguồn: `runs/2026-07-24-S149-hoi-tu-bookend/sub-reviewer-hoi-tu.md` 15.733B]
|
||||
|
||||
- `/fable-real reviewer` gate spec hội-tụ-bookend: **GO-WITH-FIXES 1C/6M/4m** (CLEAN 218K, 0 garble) — spec v1→v2 trước wave implement 5-lane Opus (5/5 done 946K 0-garble). Lưu ý sổ: lượt gate adap-backlog `wf_f4e4c006` KHÔNG tính invocation vai này (reviewer-lane **skeleton-ruột-rỗng** — khung 274B, 0 append, return+resume đều fail → em-main-solo re-do; xem sổ garble sub-class @S150).
|
||||
|
||||
|
||||
## @S161-curate (2026-07-29) — moved from L1 HOT (hook-cap 24.5KB > 17.1KB)
|
||||
|
||||
- **S159 (07-29) dashboard "toàn trình" đợt-4 FE-only (fe-user 984+/337−, PWF 7 FLAG 0H/2M/5L):** 🔴 **`tsc` XANH đo ÍT hơn vẻ ngoài** — `fe-user/tsconfig*.json` KHÔNG có `strict`/`strictNullChecks` (chỉ `noUnusedLocals`) ⇒ **tra cờ tsconfig TRƯỚC khi trích tsc làm bằng chứng**; ngược lại `noUnusedLocals`+pass = bằng chứng MẠNH HƠN grep cho claim "đã gỡ khối X" (compiler chặn nếu sót import). · class **`nhãn khẳng định chiều-ngược`**: dot-map `none='chưa tới'` — không-suy-diễn "đã xong" là đúng, nhưng "chưa tới" CŨNG là khẳng định ⇒ sai cho GĐ ĐỨNG TRƯỚC + sai khi `contractId != null` **có sẵn trong payload**. · pager tính `data.page±1` (keepPreviousData ⇒ stale) thay vì state ⇒ double-click = no-op. · **verify đích điều hướng phải đọc CẢ breakpoint trang đích** (panel `hidden lg:block` ⇒ ngõ cụt mobile; trang đích tự có nhánh `matchMedia` mà caller mới không copy). · regression đo HEAD⟂work bằng `grep -c` từng token: count 5→2 mà KHÔNG mất nhãn (inline-prop → `STAGES[i].title`) ⇒ **đếm lệch phải truy CẤU TRÚC trước khi kêu hồi quy**. · tự tính lại 4 tỉ-số contrast + tra `@theme` mọi `var(--color-*)` (0 dòng `--color-*: initial` ⇒ nấc mặc định còn) — 3/3 số designer ĐÚNG. · lời khai sub-file "766→1.130 dòng" SAI (đĩa 1.413 = 766−337+984). [→ `runs/2026-07-29-S159-tong-quan-pipeline-menu/sub-reviewer-diff-dot4.md` 28,5KB]
|
||||
|
||||
- **S159 (07-29) đợt-5 menu 6-leaf HĐ + endpoint `/contracts/deleted` (PWF 10 FLAG 0H/4M/6L):** 🔴 **con-số TRONG CHÚ THÍCH cũng là khẳng-định đo-được** — diff SỬA comment D3 thành "NAY CÓ 2 chỗ `IgnoreQueryFilters`", `grep -rn` ra **3 file/17 site** (ApprovalWorkflowV2AdminFeatures 15 site); tôi suýt duyệt bằng mắt ⇒ **luật: comment mang số ⇒ chạy phép đếm, và số viết dưới dạng LUẬT ("chỗ duy nhất ⇒ CẤM…") sai thì lan sang người sửa sau**. · class **`mirror-nửa-vời khai thừa phạm-vi`**: comment nói "Hộp thư + Tổng quan viết HOA" nhưng "Hộp thư" render bằng `StaticLeaf` KHÁC component ⇒ đọc comment ≠ đọc call-site. · **cookie-cutter phải soi CẢ phần PE đã CHẶN**: bản HĐ copy list-deleted nhưng bỏ `disabled={deletedView}` ⇒ click row → detail 404 → panel **trắng** (page thiếu nhánh `isError`) + mobile navigate ra trang 404. · mirror 2-app: fe-admin ẩn `Ct_*` (⇒ 21 leaf mới KHÔNG cần route) nhưng `Khkk_*` KHÔNG ẩn ⇒ thiếu 2 staticMap = drop silent #50 — **kiểm hide-filter TRƯỚC khi kêu thiếu mirror**. · `tsc -p tsconfig.app.json` EXIT=0 + `noUnusedLocals` = chứng cắt-hero-không-mồ-côi MẠNH HƠN grep (nhắc lại: fe-user KHÔNG bật `strict`). · `Contracts` ∈ `MenuKeys.All` ⇒ policy `Contracts.Read` có thật; `MenuPermissionHandler` khớp ĐÚNG-KHOÁ, KHÔNG kế thừa root (#82). [→ `runs/2026-07-29-S159-tong-quan-pipeline-menu/sub-reviewer-diff-dot5.md`]
|
||||
|
||||
- **S160 (07-29) reviewer CHỐT-CUỐI /fable-real (verify 13-fix landed) — #53 chết sau Trục-1+Trục-2, đĩa cứu:** khuôn review-của-review: chấm "fix ĐÃ LAND + ĐÚNG codebase, không đẻ lỗi mới" — **12/13 landed-đúng + ~30 anchor re-verify THẬT @HEAD, 1 half-fix**. Bài: (1) **fix áp NỬA spec = dư-lượng thật** — W7 §② sửa badge-nguồn nhưng bảng §① cùng file sót ⇒ soi CẢ FILE khi nhận "đã fix", không chỉ chỗ được trỏ (lớp vá-1-nửa-cùng-lớp S122); (2) **anchor-label ⟂ thân** — gate-5-anchor W3 vẫn liệt `PEWS:1008` sau khi thân phán khuôn đó SAI ⇒ anchor-list là artifact riêng phải sync khi thân đổi; (3) **anchor off-by-N** — "2 checkbox :1267-1268" trúng 1 (SkipToFinal ở :1256) ⇒ dải anchor phải grep CẢ 2 symbol; (4) **verify NGƯỢC premise clone**: re-đo `ContractWorkflowService.cs:191-198` admin-override-gán-qua-biến + `ContractChangelogConfiguration:22-25` FK-Cascade + `ContractAttachmentFeatures:56-152` 0-IDOR — 3/3 premise HIGH clone ĐỨNG ⇒ clone-review có răng thật; (5) **O-A moot-check**: owner để-mở ⇒ F-C3/F-C5/F-S2-grant MOOT-đúng (không siết thì không grant), KHÔNG phải lead né. #53 lần 2/phiên trên reviewer — return "Trục-2: xác vị file…" (mẩu giữa việc) nhưng sub-file 8KB có Trục-1+Trục-2 đủ ⇒ **lead finalize VERDICT+LỖI-MỚI+LEFTOVER on-behalf từ đĩa** (0 mất kết-luận vì ghi-đĩa-trong-lúc-làm). Tag `[s160, chot-cuoi-verify-fix-landed, half-fix-soi-ca-file, anchor-label-vs-than, verify-nguoc-premise-clone, o-a-moot-check, 53-doc-cuu]`
|
||||
|
||||
- **S160 (07-29) review SPEC-BỘ dry-run KHKK→HĐ-cứng [engine `/fable-clone` 6 lane opus + `/fable-real` chốt fable; `runs/2026-07-29-S160-khkk-dryrun-plan/review-synthesis-clone-s160.md`]:** 6 lane (anchor-A rỗng #StructuredOutput-fail nhưng ghi-đĩa-lượt-1-2 cứu · B/C/wave-logic/owner-consist/security). **5/5 verdict SUA-TRUOC-THI-CONG, hội tụ cao** ⇒ lead-verify 5 claim load-bearing 5/5 CONFIRMED đĩa. Bài đắt: (1) **review SPEC ≠ review CODE — bắt lỗ ở acceptance + default-lấn-quyền + hố-chưa-khai, KHÔNG chỉ anchor** (anchor 24-28/28 đúng dòng nhưng spec vẫn hỏng cấu-trúc); (2) **seeder-grant no-op = 403 giết-feature IM LẶNG** — row Permission đã tồn tại CanRead-only ⇒ grant kiểu insert rơi skip-existing `continue` (`DbInitializer.cs:2242-2245`), phải UPGRADE-if-exists (`SeedProcurementMasterAccessAsync:2367-2374`); **acceptance đếm ROW = 0-bit, phải đo CỜ CanCreate/CanUpdate**; (3) **owner-authority finding** — lane owner-consistency bắt lead đặt default lấn đúng chỗ owner phán "để yên" (O-3 "hợp đồng cứ từ từ" + STATUS:13 tái-khẳng-định) ⇒ surface AskUser thay vì tự quyết → anh chọn O-A gỡ hẳn wave; (4) **"204 KHÔNG 409" PASS SẴN** = acceptance 0-bit nửa-vế vì nhánh trình không đọc workflow (`ContractWorkflowService.cs:70-89`) — vế răng = `currentApprovalLevelOrder=1` phải chạy tới lượt DUYỆT; (5) **FK-547 compiler-không-chặn**: gọi `LogWorkflowTransitionAsync(Guid contractId)` với plan.Id = enum/Guid cast được nên build xanh, nổ runtime — dùng bảng changelog RIÊNG của module mới; (6) **choke-point "DUY NHẤT" sai** — admin-override gán Phase QUA BIẾN (`:190-193`) nên literal-grep miss (lớp #81), phải kê 2 write-path. **anchor-B census tên-test: repo 0/460 tên thuần-Việt ⇒ khuôn = English-predicate** (owner chốt đổi). Ensemble ĐÓNG GÓI C2 ăn: 6 lane ≤3-file + khung-rỗng-lượt-1-2 ⇒ 0 lane chết dù 1M+ token. Tag `[s160, review-spec-bo, seeder-grant-no-op-403, acceptance-dem-row-0bit, owner-authority-surface, 204-khong-409-pass-san, fk-547-compiler-mien, choke-point-2-write-path, test-name-census-repo]`
|
||||
|
||||
@ -14,8 +14,8 @@
|
||||
| 3 | Đợt-2a: schema test + codegen format test (`ContractSigningPlanSchemaTests` + `SigningPlanCodeGenerator_Format_KhkkYearSeqD3`, N ≥ 2) | hmw `test-specialist` | [x] `wf_a95c9909-14b` — **4 test** (vượt sàn 2) + fault-inject 2 chiều chứng răng + bắt LỆCH prompt-vs-đĩa (LevelOpinion CỐ Ý không filter → assert thành invariant); vai chết #53 lúc đợi full-suite → lead chạy tươi + điền §2/§4 on-behalf |
|
||||
| 4 | Đợt-2b: design-review Mig 69 TRƯỚC deploy (reversible Down · snapshot drift · FK/index) | hmw `database-agent` | [x] cùng wf — **PASS 8/8 + DB11, 0 blocker** (đo sys.foreign_keys/filter_definition; parity 2 DB tuyệt đối; Down script atomic sạch; IX superset khuôn PE; 4 advisory wave-sau) — `sub-database-agent-1.md` 21KB |
|
||||
| 5 | Lead: build ×2 + `dotnet test` + sqlcmd 89→96 + Down-script sạch + acceptance §③-B sweep | lead | [x] build BE 0W/0E 47s + FE build tươi PASS · test **566/0** (562+4 ≥ sàn 564) · sys.tables 96 ×2 DB · Down script-proof · CÒN 2 vế prod-side @stage-7: đo-CỜ policy sau seed prod + Designer tạo type-10 3-Bước |
|
||||
| 6 | Reviewer adversarial diff (schema mig >50 LOC — bắt buộc trước commit) | `reviewer` | [!] ĐANG CHẠY nền — focus: revoker-2-chiều seeder · 3-site mirror · FE containment · boundary 0-diff ContractCodeGenerator/CWS |
|
||||
| 7 | Commit + push + cicd-monitor 3-chân-kiềng (CI PASS · mig 69 prod · menu 142 giữ) | lead + `cicd-monitor` | [ ] |
|
||||
| 6 | Reviewer adversarial diff (schema mig >50 LOC — bắt buộc trước commit) | `reviewer` | [x] **PASS_WITH_FLAGS 10 issue (1H/3M/4m/2L), 0 chặn logic** — lượt-1 garble #53 giữa Trục-1 → SendMessage-resume về SẠCH đủ 6 trục. Disposition TỪNG DÒNG: 8 FIX cùng commit (F-0 git-add-tường-minh gate · F-7 label VN type-10 vào AwLabels · F-8 ép-false 2 cờ tầng BE · F-2 STATUS 55/220 · F-5 comment 7→8 · F-3 comment 2 chỗ · F-9 neo-tên-thay-số-dòng · F-6b khai giới hạn changelog) + 2 GIỮ (F-1 đo-CỜ chờ prod @stage-7 · F-4 kế thừa y PE prod). Sau fix: build 0W/0E + suite 566/0 GIỮ. Residual-write MEMORY tự-curate → verify ĐẠT, ACCEPT verified-KEPT (AS-10) — `sub-reviewer-2.md` |
|
||||
| 7 | Commit + push + cicd-monitor 3-chân-kiềng (CI PASS · mig 69 prod · menu 142 giữ) | lead + `cicd-monitor` | [!] commit **`a8027c0`** (30 file, +8.987/−22, mig 3-file đủ, F-0 gate porcelain-??-rỗng ĐẠT) đã PUSH → CI đang chạy; `cicd-monitor` spawn nền — 6 phép {CI+test-gate 566 · mig 69 prod · menu 142 GIỮ · byte-marker `QT-KHKK-V2-001` độc-quyền · **đo CỜ F-04** (Create/Update 13/13 + Delete chỉ Drafter/Admin cả chiều âm) · smoke 3 domain + label type-10} |
|
||||
|
||||
## Ràng buộc mang theo
|
||||
- 🔴 Seeder = **UPGRADE-if-exists khuôn `SeedProcurementMasterAccessAsync:2367-2374` + mở rộng vế CanDelete**, chạy SAU revoke (mirror `:2098-2101`) — KHÔNG insert (F-S1, 403 giết dry-run) · CẤM SQL tay (#84).
|
||||
|
||||
@ -24,4 +24,92 @@
|
||||
|
||||
**(c) CanDelete chỉ Drafter+Admin, KHÔNG hạ cờ — PASS.** `allowDelete = role.Name == AppRoles.Admin || role.Name == AppRoles.Drafter`. Mọi phép gán đều dạng `if (!row.CanX) row.CanX = true` ⇒ monotonic tăng, 0 câu nào set `= false` trên nhánh update. Nhánh insert đặt `CanDelete = allowDelete` (role khác = false) — đúng.
|
||||
|
||||
**(d) 7 key khớp bộ seed menu-row — PASS (so từng chuỗi).** Seeder `:2419-2424` = `MenuKeys.KeHoachKyKet` + `Khkk_WfView, Khkk_List, Khkk_Create, Khkk_Pending, Khkk_Approved, Khkk_Deleted`. Menu-row `:1779-1786` = `Khkk_G1` + đúng 6 chuỗi trên. `Khkk_G1` CỐ Ý loại (group điều hướng, CanRead-all đã có) — khai trong comment `:2417-2418`. 0 typo.
|
||||
**(d) 7 key khớp bộ seed menu-row — PASS (so từng chuỗi).** Seeder `:2419-2424` = `MenuKeys.KeHoachKyKet` + `Khkk_WfView, Khkk_List, Khkk_Create, Khkk_Pending, Khkk_Approved, Khkk_Deleted`. Menu-row `:1779-1786` = `Khkk_G1` + đúng 6 chuỗi trên. `Khkk_G1` CỐ Ý loại (group điều hướng, CanRead-all đã có) — khai trong comment `:2417-2418`. 0 typo. Phép đếm máy: tập literal `Khkk_*` trong TOÀN file = đúng 7 chuỗi `{G1, WfView, List, Create, Pending, Approved, Deleted}` — không có key thứ 8 lạc đâu đó.
|
||||
|
||||
**2 rủi ro phụ đã truy và ĐÓNG (không thành flag):**
|
||||
- `existing.ToDictionary((RoleId,MenuKey))` có thể ném `ArgumentException` nếu DB có row trùng ⇒ đã kiểm `PermissionConfiguration.cs:26` có `HasIndex(RoleId, MenuKey).IsUnique()` ⇒ không thể trùng.
|
||||
- Nhánh INSERT (fresh DB) cần MenuItems tồn tại trước vì FK `Permission.MenuKey → MenuItems.Key` (`PermissionConfiguration.cs:21-24`) ⇒ `SeedMenuTreeAsync` `:109` chạy TRƯỚC `SeedAdminPermissionsAsync` `:110` (ungated) ⇒ FK an toàn.
|
||||
|
||||
**F-1 (MAJOR, evidence-gap KHÔNG phải lỗi mã) — acceptance §③-B "đo CỜ" hiện KHÔNG đo được ở đâu.** Đo đĩa+DB @review: `SolutionErp_Dev` có `sys.tables=96`, mig cuối `20260729122015_AddContractSigningPlans` (Mig 69 đã apply), **nhưng `SELECT COUNT(*) FROM Permissions WHERE MenuKey LIKE 'Khkk%' OR MenuKey='KeHoachKyKet'` = 0** và `MenuItems` cũng **0 row Khkk** (menus=100 vs prod 142) ⇒ DB Dev CHƯA từng chạy app sau S159 ⇒ **cả 2 nhánh (upgrade trên prod · insert trên fresh) chưa nhánh nào chạy thật lần nào**. Không chặn commit (code đúng khuôn, test-specialist có test seeder-reflection), nhưng **acceptance F-04 chỉ đóng được sau restart prod** — đừng tick trước.
|
||||
|
||||
---
|
||||
|
||||
## TRỤC 5 — MenuKeys.All
|
||||
|
||||
**Vị trí + đúng array — PASS (đo máy, không đọc mắt).** Parse `public static readonly string[] All = [...]` → **55 entry**, có `KeHoachKyKet`, **KHÔNG có** `HopDongCung` (GĐ4 vẫn ngoài All — đúng chủ đích W1). Dòng thêm = `MenuKeys.cs:179`, nằm TRONG array (giữa `Personal` :178 và `System` :180), không phải trong comment. **Đúng 1 key vào All trong cả diff** — 0 key ngoài chủ đích.
|
||||
|
||||
**Tác dụng phụ — quét 7 call-site `MenuKeys.All` toàn repo:** `Program.cs:82` (sinh 4 policy — chủ đích) · `DbInitializer.cs:2057` (Admin full-CRUD; prod row đã có ⇒ skip-existing, nhưng seeder mới `:2109` nâng đủ cờ cho CẢ Admin ⇒ không hở) · `DbInitializer.cs:2209` (`.Where(InReviewScope)` = `StartsWith("Pe_")` ⇒ KeHoachKyKet không lọt) · `AuthorizePolicyRegressionTests.cs:138` (lưới policy-∈-All — nay hợp lệ) · 3 chỗ còn lại là comment. ⇒ 0 tác dụng phụ ngoài ý muốn.
|
||||
|
||||
**Gotcha #35 (root có con phải extend 3 chỗ `GetMyMenuTreeQuery`) — KHÔNG áp.** Đọc `GetMyMenuTreeQuery.cs:56-84`: 4 inherit-root hardcode (Contracts/Workflows/PurchaseEvaluations/PeWorkflows). `KeHoachKyKet` KHÔNG cần vào đó vì 7 row `Khkk_*` có Permission TƯỜNG MINH (không sống nhờ kế thừa). Đúng thiết kế — nhưng nghĩa là **quên grant 1 leaf = leaf đó biến mất im lặng**, không có lưới kế thừa đỡ.
|
||||
|
||||
**F-2 (MAJOR) — canonical drift `docs/STATUS.md` chưa cập nhật, mà chính row đó tự ràng buộc.** `docs/STATUS.md:464` `| Menu keys | **54** |` và `:463` `| Policies | **216** |`, trong đó `:463` viết nguyên văn *"row này BUỘC đổi CÙNG row `Menu keys`: thêm 1 menu key ⇒ 55 × 4 = 220"*. Đo mã: `|All| = 55` ⇒ **Policies thật = 220**. Diff KHÔNG đụng `docs/` ⇒ commit này làm lệch cả 2 số canonical + `governance-detectors.ps1` `Get-StatusValue` resolve số cũ. Fix 1 dòng: sửa `Menu keys → 55` + `Policies → 220` cùng commit (đếm consts hiện = 56 `public const string`, ≠ |All| vì `HopDongCung` cố ý ngoài All — nếu row `Menu keys` neo theo const thì ghi rõ thước).
|
||||
|
||||
**F-3 (MINOR) — comment nguồn của chính const nay SAI.** `MenuKeys.cs:37-40` vẫn viết *"2 root PLACEHOLDER … **CỐ Ý NGOÀI `All`** — chưa có module ⇒ không sinh policy per-action"*, áp cho CẢ `KeHoachKyKet` lẫn `HopDongCung`. Sau diff mệnh đề này chỉ còn đúng cho `HopDongCung`. Cùng lớp: `DbInitializer.cs:1772` *"Ngoài MenuKeys.All"*. Fix: tách câu — `KeHoachKyKet` ĐÃ vào All @S161, `HopDongCung` còn ngoài.
|
||||
|
||||
---
|
||||
|
||||
## TRỤC 2 — `ContractSigningPlanCodeGenerator` + DI
|
||||
|
||||
**Twin-diff vs `PurchaseEvaluationCodeGenerator` — PASS, lệch đúng 3 điểm CHỦ ĐÍCH.** So từng câu (`ContractSigningPlanCodeGenerator.cs:16-51` ⟂ `PurchaseEvaluationCodeGenerator.cs:14-54`): cùng `IsolationLevel.Serializable` + `FirstOrDefaultAsync(s => s.Prefix == prefix)` + nhánh null `LastSeq = 1` / nhánh có `LastSeq += 1` + `UpdatedAt` + `SaveChanges` → `Commit` → `return $"{prefix}/{seq.LastSeq:D3}"` + `catch { Rollback; throw; }`. Lệch: (1) prefix `KHKK/{year}` thay `PE/{year}/{typeLetter}` — bỏ tham số entity nên `GenerateAsync(CancellationToken)` không nhận entity (hợp lý: mã không phụ thuộc phiếu); (2) bảng dùng chung `WorkflowAppCodeSequences` thay bảng riêng; (3) không có `typeLetter` switch. **D3 giữ nguyên** ⇒ khớp `^KHKK/\d{4}/\d{3}$`.
|
||||
|
||||
**DI — PASS.** `DependencyInjection.cs:42` `services.AddScoped<IContractSigningPlanCodeGenerator, ContractSigningPlanCodeGenerator>();` đặt ngay cạnh `IPurchaseEvaluationCodeGenerator` `:40`, cùng scope `Scoped` (đúng — service chạm DbContext scoped). Namespace `using SolutionErp.Application.ContractSigningPlans.Services;` `:7` đã thêm.
|
||||
|
||||
**Bảng dùng chung — kiểm tương thích:** `WorkflowAppCodeSequenceConfiguration.cs:17` `Prefix` PK `HasMaxLength(20)`; `"KHKK/2026"` = 9 ký tự ⇒ OK, và không đụng prefix 4 module Office (`DT/LR|DT/OT|DT/CT|DX/XE`). Semantics khớp helper cũ `TravelVehicleCodeGen.GenerateMaDonTuAsync` (`TravelVehicleApprovalFeatures.cs:818-834`): helper tạo row `LastSeq=0` rồi `++`, bản mới tạo thẳng `=1` — **cùng kết quả 001**, không lệch. Không tái dùng helper được vì nó `internal static` trong assembly Application (Infrastructure không thấy) ⇒ trùng lặp là BẮT BUỘC, không phải cẩu thả.
|
||||
|
||||
**F-4 (LOW, kế thừa từ twin — KHÔNG phải hồi quy mới):** `dateTime.UtcNow.Year` ⇒ đêm 31/12 giờ VN (UTC+7) sinh mã mang năm CŨ; và `:D3` tràn thành 4 chữ số từ phiếu thứ 1000 (test regex `\d{3}` sẽ đỏ). Cả 2 y hệt PE codegen đang chạy prod ⇒ ghi nhận, không chặn W1.
|
||||
|
||||
**Ghi nhận (không tính flag):** generator hiện CHƯA có call-site sản xuất nào (`grep` chỉ ra DI + test) — đúng phạm vi W1 (schema-first), W2 mới gọi. Cũng lưu ý cho W2: `BeginTransactionAsync` sẽ ném nếu handler đã mở transaction ngoài.
|
||||
|
||||
---
|
||||
|
||||
## TRỤC 3 — 3 site `ApprovalWorkflowV2AdminFeatures.cs`
|
||||
|
||||
**Mirror khuôn VehicleBooking từng mệnh đề — PASS 3/3** (so sát dòng-kề-dòng):
|
||||
- Site 1 `CountLiveOpinionsAsync:945-949` ⟂ twin `:935-939`: đủ `.AsNoTracking()` · `!o.IsDeleted` · `db.ContractSigningPlans.Any(p => p.Id == o.ContractSigningPlanId && !p.IsDeleted)` viết TƯỜNG MINH (đúng ý comment `:889` — không dựa query-filter) · `GroupBy` + `LevelOpinionCount`. KHÔNG dùng `IgnoreQueryFilters` — ĐÚNG (site này chỉ đếm phiếu SỐNG).
|
||||
- Site 2 `ListRetainedOpinionsAsync:1017-1022` ⟂ twin `:1009-1015`: đủ `.AsNoTracking().IgnoreQueryFilters()` (bắt buộc — header KHKK CÓ `HasQueryFilter(!IsDeleted)`, nếu thiếu thì phiếu xoá mềm rơi khỏi JOIN ⇒ bị kết luận "mồ côi" ⇒ xoá cứng nhầm) · `.Join(db.ContractSigningPlans, …)` · `.Where(x => x.o.IsDeleted || x.p.IsDeleted)` · nhãn module `"Kế hoạch ký kết HĐ"` + mã `x.p.MaKeHoach` + `x.p.IsDeleted`.
|
||||
- Site 3 `PurgeOrphanOpinionsAsync:1083-1086` ⟂ twin `:1078-1081`: đủ `!db.ContractSigningPlans.IgnoreQueryFilters().Any(...)` (KHÔNG có vế `o.IsDeleted` — đúng bản thu hẹp F2, giữ chữ ký thu-hồi trên phiếu còn sống) · `ExecuteDeleteAsync` · cộng vào `n`.
|
||||
|
||||
**Site thứ 4 cùng lớp — quét 2 hướng, KẾT LUẬN: không có site enumeration nào bị bỏ sót.**
|
||||
1. `grep -n "LevelOpinions"` trong file = 24 dòng mã = 8 module × 3 site (PE·Contract·Proposal·Leave·Ot·Travel·Vehicle·**ContractSigningPlan**) — không lệch.
|
||||
2. Quét **token-song-sinh** `VehicleBookingLevelOpinions` toàn repo (trừ `Migrations/`) ra 6 file: AdminFeatures (3 site ✓) · `IApplicationDbContext.cs` (DbSet — đã thêm `:152` ✓) · `ApplicationDbContext.cs` (impl ✓) · `VehicleBookingLevelOpinionConfiguration.cs` (module-riêng) · `TravelVehicleApprovalFeatures.cs` (đường Approve của MODULE đó — bản KHKK là việc W2) · `WorkflowAppApproveV2Tests.cs` (test module đó). ⇒ 0 site liệt-kê-thủ-công còn thiếu.
|
||||
|
||||
**F-5 (MINOR) — 2 con SỐ trong chú thích cùng file nay SAI, do chính diff này.** `:886-887` *"quét CẢ **7 bảng** LevelOpinion đang FK vào ApprovalWorkflowLevels (PE + HĐ + 5 module Văn phòng số)"* và `:961` *"giữ **7 khối** cùng một hình dạng"* — sau diff là **8**. Đây đúng lớp "chú thích mang số = khẳng định đo được" (bài S159): người sửa sau đếm 7 rồi dừng ⇒ bỏ sót đúng module mới. Fix: sửa 7→8 + thêm "+ KHKK" vào ngoặc liệt kê.
|
||||
|
||||
**F-6b (LOW, kế thừa) — site GHI VẾT changelog `:847-877` KHÔNG phủ type=10.** Điều kiện `def.ApplicableType is DuyetNcc or DuyetNccPhuongAn` ⇒ admin sửa quy trình KHKK tại chỗ sẽ KHÔNG ghi changelog vào phiếu KHKK đang treo, dù module MỚI CÓ bảng `ContractSigningPlanChangelogs` (entity #6). Hiện Contract cũng đang bị bỏ y vậy nên đây là **hố có sẵn**, không phải hồi quy — nhưng chú thích `:843-846` chỉ khai giới hạn cho "5 module Văn phòng số", nay hụt thêm KHKK ⇒ nên khai đủ hoặc wire ở W2/W3.
|
||||
|
||||
---
|
||||
|
||||
## TRỤC 4 — FE `ApprovalWorkflowsV2Page.tsx` (fe-admin)
|
||||
|
||||
**(a) `copyFromDefinition` — containment ĐỦ, và đúng chỗ.** `copyFromDefinition:204-205` vẫn bê `allowApproverSkipToFinal/Finalize` từ nguồn (clone/edit) vào state — nhưng cả 2 đường RA đều đã bịt: `levelFlagsPayload(e, lockEarlyFinalize)` ép `false` (`:255-256`) và cả **2** call-site truyền cờ (`:783` POST-create, `:815` PUT-sửa-tại-chỗ). `grep levelFlagsPayload` = 1 định nghĩa + đúng 2 call-site ⇒ **không có đường thứ 3** bỏ sót. Kịch bản độc: clone 1 quy trình type-3 có `finalize=true` sang type-10 ⇒ state true nhưng payload false ⇒ DB false, và render cũng hiện untick (`checked={earlyFinalizeLocked ? false : …}`) ⇒ màn hình khớp dữ liệu. `applicableType` là **prop của definition đang mở** (`:441` truyền `type.applicableType`), không phải state trôi ⇒ khoá đúng đối tượng.
|
||||
|
||||
**(b) `DEFAULT_CODE_BY_TYPE[10] = 'QT-KHKK-V2-001'` — suy diễn HỢP LỆ.** Khớp khuôn 3 dòng có sẵn (`QT-DN-V2-001` / `QT-DN-PA-V2-001` / `QT-HD-V2-001` = `QT-{viết tắt}-V2-001`), chỉ là giá trị điền sẵn ô Mã (`:645 defaultCode = … ?? 'QT-V2-001'`), admin sửa được. Không khai thì rơi fallback chung — nghĩa là **không khai cũng không vỡ**, khai chỉ để đẹp. Không có rủi ro.
|
||||
|
||||
**(c) Regression type≠10 — 0 pixel, xác minh từng nhánh.** Khi `earlyFinalizeLocked=false`: className 2 label trả về **đúng chuỗi cũ** (`…text-slate-700` và `…text-emerald-700`), `title={undefined}` (React bỏ attribute), `checked={false ? false : entry.x}` ≡ `entry.x`, `disabled={false}` (bỏ attribute), khối ghi chú bọc `{earlyFinalizeLocked && …}` không render. ⇒ Designer type 1/2/3 không đổi gì.
|
||||
|
||||
**F-7 (MAJOR) — nhãn tiếng Việt của type 10 KHÔNG TỒN TẠI ở BE ⇒ UI hiện tên enum tiếng Anh, và tên đó bị LƯU vào DB.** FE cố ý bỏ bảng nhãn và khai rõ (`ApprovalWorkflowsV2Page.tsx:159-161`: *"nhãn hiển thị lấy từ BE qua `applicableTypeLabel`"*), nhưng BE `AwLabels.Type` (`ApprovalWorkflowV2AdminFeatures.cs:90-95`) chỉ có **3** entry (DuyetNcc/DuyetNccPhuongAn/Contract); `:206` fallback `type.ToString()`. Hệ quả tại chính màn W1 phải nghiệm thu: tiêu đề trang `:302` → *"Quy trình duyệt (Mới): **ContractSigningPlan**"* · card `:320` → **"ContractSigningPlan"** · và nặng nhất `:647` `useState(\`Quy trình ${applicableTypeLabel}\`)` ⇒ admin bấm Lưu là **ghi vào cột Name của DB chuỗi "Quy trình ContractSigningPlan"**. Vi phạm quy ước "UI 100% tiếng Việt". Đây là lớp *hợp-đồng-đứt-giữa-2-bờ*: FE khai bên kia lo, bên kia không có, mà `tsc` + build + 566 test đều xanh. Fix 1 dòng: thêm `[ApprovalWorkflowApplicableType.ContractSigningPlan] = "Kế hoạch ký kết HĐ"` vào `:94`. (Chuỗi tiếng Việt đã có sẵn trong CÙNG file ở `:1021` cho `RetainedOpinionRef` ⇒ càng lộ chỗ thiếu.)
|
||||
|
||||
**F-8 (MINOR) — "containment 2 lớp" thực chất là 2 lớp CỦA CÙNG 1 client; BE không có rào.** `CreateAwDefinitionCommand` gán thẳng `AllowApproverSkipToFinal/Finalize` từ request (`:373-374`) và validator không ràng theo `ApplicableType` (grep 2 cờ trong file: chỉ có rào ở đường PUT `:584-616` và ép false cho dòng MỚI `:802-803`). ⇒ 1 lệnh `curl POST /api/approval-workflows-v2` với `applicableType=10, allowApproverFinalize=true` vẫn tạo được **đúng cái "cờ chết"** mà F-B3 muốn diệt. Spec §②-10 chỉ yêu cầu FE nên KHÔNG tính lệch-spec, nhưng nếu muốn containment thật thì thêm rule validator: type 10 ⇒ 2 cờ phải false.
|
||||
|
||||
**F-9 (LOW) — neo dòng trong chú thích mới trỏ dòng TRƯỚC commit.** `:157-158` viết *"rơi về fallback chung 'QT-V2-001' (:614)"*; sau chính diff này fallback nằm ở **`:645`** (`:614` giờ là dòng destructuring prop `applicableType`). Người đọc sau nhảy tới :614 sẽ thấy thứ khác. Fix: đổi `(:614)` → `(:645)` hoặc bỏ số dòng, trỏ tên biến `defaultCode`.
|
||||
|
||||
**Ghi nhận i-1 (không phải lỗi diff) — đường tới Designer type 10 CHỈ có URL gõ tay.** Xác minh độc lập: `Layout.tsx:163-167` allowlist `AwV2_*` chỉ nhận `DuyetNcc|DuyetNccPhuongAn|Contract`; landing card `:317-333` **không phải link** (mô tả `:309` bảo "chọn loại quy trình từ menu bên trái"). Route `App.tsx:76 /system/approval-workflows-v2/:typeCode` có ⇒ deep-link `/system/approval-workflows-v2/ContractSigningPlan` chạy được nhờ `TYPE_CODE_TO_INT`. Đúng spec "menu KHÔNG đổi" — nhưng acceptance §③-B *"Admin tạo được quy trình type=10 3 Bước"* **phải nghiệm thu bằng deep-link đó**, đừng chờ thấy nó trên sidebar.
|
||||
|
||||
**Mirror 2-app (§3.9) — N-A.** `fe-user/src/pages/system/` không tồn tại; `grep ApprovalWorkflow fe-user/src` chỉ ra màn xem read-only của module khác. Designer là admin-only ⇒ không cần mirror.
|
||||
|
||||
---
|
||||
|
||||
## TRỤC 6 — Boundary
|
||||
|
||||
**3 file phải 0-diff — PASS.** `git status --porcelain` không liệt `ContractCodeGenerator.cs` (quyết "bỏ MB" KHÔNG đụng codegen ✓), `ContractWorkflowService.cs`, `ContractFeatures.cs` (O-A để mở ✓). Toàn bộ 12 file `M` + 20 file `??` đều nằm trong phạm vi W1 (Domain/Config/Mig/DbSet/MenuKeys/DI/Seeder/AWV2-3-site/FE-Designer/test). 0 file lạc.
|
||||
|
||||
**Mig 3-file (#17) — ĐỦ nhưng xem F-0.** `20260729122015_AddContractSigningPlans.cs` (372 dòng) + `.Designer.cs` (6.960) + `ApplicationDbContextModelSnapshot.cs` (+550, tracked-M) = 3/3.
|
||||
|
||||
**F-0 (HIGH — GATE THỦ TỤC, phải xử lý TRƯỚC commit).** 2/3 file migration đang **UNTRACKED** (`??`) trong khi snapshot đã **tracked-M**. Đây đúng vết S155: `git commit -a` (hoặc `-am`) chỉ nạp file đã theo dõi ⇒ commit sẽ mang **snapshot + 7 DbSet + 7 EF Config + Domain** nhưng **THIẾU migration** ⇒ CI/prod dựng model có 7 bảng mà DB không có bảng ⇒ `Invalid object name 'ContractSigningPlans'`; build + 566 test local VẪN XANH nên không lộ. Tổng cộng **20 đường dẫn `??`** (2 thư mục Domain/Application + 7 Configuration + 2 Migration + 1 Service + 1 test) phải `git add` tường minh. Nghiệm thu 1 lệnh: `git status --porcelain -- src tests | grep '^??'` phải **rỗng** ngay trước `git commit`.
|
||||
|
||||
---
|
||||
|
||||
## TIẾN TRÌNH (cập nhật cuối)
|
||||
- [x] Trục 1 · [x] Trục 5 · [x] Trục 2 · [x] Trục 3 · [x] Trục 4 · [x] Trục 6
|
||||
|
||||
VERDICT: PASS_WITH_FLAGS — 10 issue (1 HIGH-gate · 3 MAJOR · 4 MINOR · 2 LOW-kế-thừa). Không có lỗi logic nào chặn commit; F-0 là điều kiện thủ tục BẮT BUỘC, F-7 nên fix cùng commit (1 dòng).
|
||||
|
||||
Reference in New Issue
Block a user