wal: flush 20260729T2006
This commit is contained in:
@ -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