17 KiB
investigator-codebase/2026-05-q1 — gist
distill-gen: 1 source-verbatim: .claude/agent-memory/investigator-codebase/archive/2026-05-q1.md (11 entry [10 FIFO S21→S24 + 1 setup] → 7 cụm) pointer-style: substring
TỔNG-HỢP (3-5 ý)
- Refactor cardinality Mig 29 (1-row-per-Cấp → 1-row-per-NV) làm mọi phép
FirstOrDefaulttheo khoá cũ sai âm-thầm: bug BEPurchaseEvaluationFeatures.cs:765ẩn TỪ NGÀY DEPLOY, chỉ lộ khi tick chọn-lọc per-NV; cùng bộ 7 cờAllow*hỏng 2 kiểu KHÁC nhau ở 2 lớp (F4 FE đoản-mạch readOnly ⟂ BE lấy nhầm hàng) + 1 báo-động-giả (mental-model "Trả lại"≠"nháp"). - Ranh giới kiểu dữ-liệu = điểm gãy câm: record
TransitionPeBody3 field nuốt im-lặng 3 field FE gửi đủ — phép thử rẻ = đếm field body ↔ đếm field command; 1 lượt audit FE thuần BÁC được giả-thiết, chặn em-main sửa mù xuyên tầng. - Pre-flight có bản-đồ đổi được quyết-định: Plan K neo 20+ điểm + GAP fe-user (phá luật "mirror 2 app"); Plan R 4 sqlcmd → chốt Option A; Plan F HUỶ ngay ở pre-flight vì Contract còn hoàn-toàn V1.
- Trí-nhớ/docs tự sai, phải re-ground: "3-panel" đo lại là 2-panel; Dev DB 2 user vs prod 33 user đều KHÔNG khớp spec; entry đếm-cumulative (B1-G) hết hạn nhanh — giá-trị còn lại chỉ là mốc thời-gian.
- Tailwind JIT đòi chuỗi class ĐẦY ĐỦ trong mảng (STEP_PALETTE/LEVEL_PALETTE liệt nguyên chuỗi); sidebar widen an-toàn
w-72 xl:w-80@1280px, ngưỡng rủi-row-80 xl:w-96.
Entries
[cao] B1-A — chuỗi per-NV Allow (F1-F4): 2 bug tách lớp FE/BE + 1 báo-động-giả* (gộp 3 entry: S23 t2 L2 + S23 t3 + S23 t2 M0 — giữ 3 verdict phân-biệt)
- VIỆC: 3 lượt audit UAT liên-tiếp trên cùng bộ 7 cờ
Allow*per-slot (ApprovalWorkflowLevels) sau Mig 29/30/31: (i) admin tick F3+F4 mà menu "Duyệt" vẫn read-only; (ii) admin tick 7 cờ cho riêng 1 NV mà FE không hiện checkbox; (iii) rà 4 BE + 4 FE × 2 app xem F1-F4 có tự đẩy phiếu về "nháp". - KẾT-LUẬN: (i) F3 ĐÚNG, F4 HỎNG —
PeDetailTabs.tsx:118itemsReadOnlyoverride được, nhưng:245truyềnreadOnly={readOnly}xuống BudgetAdjustSection và:973canAdjust = !readOnly && (...)đoản-mạch TRƯỚC khi F4 kịp xét ⇒ nút bút chì ẩn:1030; fix ~3-5 LOC 1 file: đảo vếisAdmin || (!readOnly && isDrafter && isDrafterPhase) || isApproverChoDuyet(land, thấy lại:977). (ii) BE lấy nhầm hàng:PurchaseEvaluationFeatures.cs:765FirstOrDefault(l => l.Order == curLevelOrder)— sau Mig 29 tách 1 Level-row PER ApproverUser thìOrdertrùng nhau trong cùng Cấp ⇒ EF trả row đầu theo PK; 2 token (admin + nv.test) gọi API ra CÙNGcurrentLevelOptions; fix 1 dòng&& l.ApproverUserId == currentUser.UserId+ fallback row-đầu cho admin. (iii) KHÔNG bug: F1.OneLevel/OneStep/Assignee + F2 + F3 + F4 đều giữ Phase=ChoDuyet; chỉ F1.Drafter:268-275đặtPhase=TraLai=98— đúng thiết-kế. - BÀI-HỌC: hai lớp cùng tính-năng hỏng theo hai kiểu khác nhau ⇒ verdict lớp này không suy ra lớp kia. Refactor cardinality làm mọi phép
FirstOrDefaulttheo khoá cũ sai âm-thầm — phải rà toàn bộ site tra-cứu cùng khoá, không vá theo từng báo-cáo lỗi. - BẤT-NGỜ: (a) bug BE CÓ TỪ NGÀY deploy Mig 29, không phải hồi-quy S23 — ẩn vì 13 user UAT cũ hầu hết ở row đầu của Cấp + admin tick toàn FALSE. (b) route
/inboxđẩy DetailPage mobile mặc-địnhreadOnly=false, còn Danh sách?pendingMe=1desktop hard-codereadOnly={true}⇒ CÙNG phiếu, 2 lối vào, 2 hành-vi. (c) lượt (iii) chốt "code đã đúng" — cái sai là mô-hình trong đầu người dùng (TraLai=98≠DangSoanThao=1). → substring:"PurchaseEvaluationFeatures.cs:765"
[cao] B1-B — Plan P: Controller record nuốt 3 field, ASP.NET im lặng
- VIỆC: em-main giả-thiết Plan P chỉ đụng BE; investigator đối-chiếu FE × 2 app xác nhận trước khi sửa.
- KẾT-LUẬN: FE
PeWorkflowPanel.tsx:113-124— nguồn ghi "SEND ĐÚNG 7 fields" nhưng LIỆT KÊ 6 (TargetPhase + Decision + Comment + ReturnMode + ReturnTargetUserId + SkipToFinal, object literal không typed-service) — lấy 6 theo danh-sách; số "7" của nguồn chưa xác-minh, tự nó là bằng-chứng sống cho bài "đếm field body so đếm field command là phép thử rẻ" (chính người viết verbatim cũng đếm nhầm — nhãn @S170 P2d, KHÔNG lặng-lẽ chọn một phía); BEPurchaseEvaluationsController.cs:267recordTransitionPeBodychỉ 3 field ⇒ model-binder BỎ IM LẶNG 3 field còn lại. Verdict: Plan P = BE Controller ONLY ~6 LOC, không cần test mới (Mig 28/31 Domain test đã phủ handler). - BÀI-HỌC: "FE gửi rồi" và "BE nhận được" là hai mệnh-đề khác nhau — điểm gãy ở ranh giới kiểu dữ-liệu (record thiếu field = mất dữ-liệu không lỗi, không log). Đếm field body ↔ đếm field command là phép thử rẻ.
- BẤT-NGỜ: một lượt audit FE thuần chặn được em-main sửa mù xuyên tầng — giá trị của spawn nằm ở chỗ nó BÁC BỎ giả-thiết, không phải xác nhận. → substring:"TransitionPeBody"
[vừa] B1-C — Pre-flight Plan K (Mig 31): bản-đồ neo + GAP fe-user + lệch Dev/prod
- VIỆC: rà trạng-thái trước khi chuyển
Users.AllowDrafterSkipToFinal→ApprovalWorkflowLevels.AllowApproverSkipToFinal(đổi cả ngữ-nghĩa Drafter-Nháp → Approver-ChoDuyet). - KẾT-LUẬN: neo đủ 20+ điểm (
User.cs:38·ApprovalWorkflow.cs:86-1056 cờ · nhánh Drafter/APPROVE service · DTO + bundle · UsersController · Designer panel 6 checkbox · UsersPage · PeDetailTabs admin/user — chi tiết file:line ở phụ-lục). Path migration thật =Persistence/Migrations/(KHÔNG phảiMigrations/). - BÀI-HỌC: GAP fe-user (không có UsersPage/Designer — quản-trị chỉ ở fe-admin) ⇒ "mirror 2 app" KHÔNG phải luật phổ-quát; xác định trước app nào có bề-mặt nào rồi mới khoanh phạm-vi UI.
- BẤT-NGỜ: Dev DB 2 user / 0 flagged, prod 33 user / 4 flagged — cả hai đều KHÔNG khớp spec (S22+2) ⇒ 4 user mất giá-trị khi DROP cột, chấp-nhận được vì ngữ-nghĩa mới làm nó vô-nghĩa. → substring:"User.cs:38"
[vừa] B1-D — Pre-flight Plan R: xoá dữ-liệu prod, 3 phương-án
- VIỆC: 4 truy-vấn sqlcmd đo trước khi xoá: 35 PE (28 active + 7 soft) · 17 V2 (15 chưa-ghim + 2 ghim) · 4 V1 (2 active + 2 inactive).
- KẾT-LUẬN:
PE.ApprovalWorkflowIdFK Restrict +ApprovalWorkflowkế-thừaBaseEntity(KHÔNG soft-delete) ⇒ buộc hard-DELETE;LevelOpinion → ApprovalWorkflowLevelRestrict chặn cascade; ước ~620 row con (446 PE-children + ~140 V2 + ~37 V1). Chốt Option A (hard-DELETE PE + bỏ V2 chưa-ghim + V1 inactive; GIỮ V2 ghim + V1 active). - BÀI-HỌC: tiền-lệ Plan F nhắc lại đúng lúc — KHÔNG drop V1 active vì còn phiếu pin vào, drop là BE crash lúc khởi-động.
- BẤT-NGỜ: hạ-tầng ra điều-kiện: SQL Express không có COMPRESSION,
RESTORE VERIFYONLYđòi sysadmin, index filtered (Mig 29) đòiSET QUOTED_IDENTIFIER ONmới chạy sqlcmd. → substring:"RESTORE VERIFYONLY"
[vừa] B1-E — Plan AA: 5Q audit → 7 commit a1a910f..ee0902a (gộp 2 entry cùng Plan: Pre-A spawn + wrap 4 polish)
- VIỆC: audit 5 câu hỏi mở đường (endpoint filter · menu seed · Designer · sidebar widen · enum) rồi em-main tự làm 4 vòng polish theo UAT.
- KẾT-LUẬN:
ApprovalWorkflowsV2Controller.cs:16-19đã[Authorize]trần từ S18 (gotcha #44 vá vĩnh-viễn) ⇒ chỉ thêm param filterIsUserSelectable; menu seedDbInitializer.cs:1429-1437+ quyền:1541-1547cho 7 role (Accounting KHÔNG có, admin cấp tay); DesignerApprovalWorkflowsV2Page.tsx975 dòng, 13 field DTO / 7 cờ; sidebarw-60 xl:w-72→w-72 xl:w-80an-toàn @1280px (w-80 xl:w-96= ngưỡng rủi-ro); enum {DuyetNcc=1, DuyetNccPhuongAn=2, Contract=3}. 7 commit:ee776d5BE+Layout ·c667802FE Page ·ac2c859docs · 4 polishda218f1/4d60598/fbbd361/ee0902a. - BÀI-HỌC: Tailwind JIT đòi chuỗi class ĐẦY ĐỦ trong mảng —
bg-${color}-100bị purge ⇒ STEP_PALETTE/LEVEL_PALETTE phải liệt nguyên chuỗi (tái dùng cho mọi cây menu phân-cấp). BỏtruncateKHÔNG đủ cho nhãn dài xuống dòng: đổi cả cấu-trúc NavLink (flex → block + inline) +text-[12px] leading-snug. - BẤT-NGỜ: trí-nhớ dự-án SAI về chính UI của mình — memory khai "PE Workspace 3-panel", đo lại là 2-panel (
[260px_1fr] xl:[320px_1fr]); chiến-lược Order=2 cho "Luồng duyệt" buộc UPDATE Order các leaf cũ, không thể chỉ INSERT-if-not-exists;Contract=3khai trong enum nhưng FE chưa nối. → substring:"STEP_PALETTE"
[vừa] B1-F — 6 phát-hiện rời S22 (hạ-tầng/identity/script)
- VIỆC: phiên em-main solo seed 20 user role-based lên prod (13→33 user); investigator ghi lại các va-chạm.
- KẾT-LUẬN: mật-khẩu Identity đòi ≥12 ký-tự (
User@12345611 ký-tự FAIL 400,TestUser@2026PASS); đổi tên user = 4 trường nguyên-tử (Email + NormalizedEmail + UserName + NormalizedUserName + FullName — gotcha #38); sqlcmd cầnSET QUOTED_IDENTIFIER ON; login trảaccessToken/refreshToken/user— KHÔNG có fieldtoken(ví-dụ Bash dùng.tokensẽ fail); script PS 5.1 phải ASCII-only (gotcha #30). - BÀI-HỌC: khuôn "admin tick opt-in TỪNG slot" củng-cố lần 2 (Mig 30 F4 lặp Mig 29 F1+F3) sau khi anh sửa lưng em-main: mặc-định là KHÔNG mở rộng quyền.
- BẤT-NGỜ: Plan F (drop V1) HUỶ ngay ở pre-flight vì sqlcmd lộ Contract còn HOÀN TOÀN V1 (chưa có cột
ApprovalWorkflowId) + 4 PE V1-only + 19 PE lai ⇒ phạm-vi drop phải tính cả thực-thể liên-đới. → substring:"TestUser@2026"
[thấp] B1-G — ảnh-chụp trạng-thái no-spawn (3 mốc)
- VIỆC: 3 mốc không spawn: 2026-05-11 khởi-tạo agent · S21 t3-t5 · S22.
- KẾT-LUẬN: baseline 2026-05-11 = 44 gotcha + 14 memory + 6 skill + 27 mig + 81 test; S21 = 84 test / 29 mig / 45 gotcha / 19 memory; S22 = 104 test (+20) / 30 mig / 46 gotcha / ~146 endpoint (+3) / 33 user prod.
- BÀI-HỌC: entry loại "đếm cumulative" hết hạn nhanh — giá-trị còn lại chỉ là mốc thời-gian, không phải con số.
- BẤT-NGỜ: khai thẳng "Investigator KHÔNG spawn" mà vẫn ghi entry — diary vai từng ghi cả phiên nó không làm gì = nguồn nhiễu khi đếm coverage. → substring:"Awaiting first SendMessage"
Phụ-lục token (coverage)
(chép TRỌN token-list section investigator-codebase/2026-05-q1 của proposal curator — lưới coverage-diff)
- gotcha#:
#45(bug fix S21 t3) ·#38(Identity rename atomic 4 field) ·#30(PS 5.1 ASCII-only script discipline) ·#44(class-level[Authorize]bare fixed permanent từ S18 2026-05-08) - surprise (nhãn nguyên-văn): "Surprise: Inbox
/inboxroute (InboxPage.tsx) navigate sang/purchase-evaluations/:id(mobile DetailPage route, default readOnly=false)" · "Surprise: 'Trả lại' trong UI memory docs đôi khi gọi 'draft' colloquial — bro confuse 2 khái niệm" · "Surprise: bug PRESENT từ deploy Mig 29 (S21 t5 2026-05-13) — không phải regression S23" · "Surprises: (1) memory responsive breakpoint stale '3-panel' (2) Order strategy shift +1 (3) Contract=3 chưa wire FE" · "Memory drift confirmed: … S24 verify ACTUAL 2-panel" · "Plan AA color palette success … Tailwind JIT yêu cầu full class strings array" · "Drift Dev DB: Total=2 user … NOT match 33-user prod seed" · "Prod actual: Total=33 / Flagged=4 (NOT 2 per S22+2 spec)" · "GAP fe-user: KHÔNG có UsersPage + ApprovalWorkflowsV2Page" - guard:
PurchaseEvaluationDraftGuard.EnsureEditableForDetailsAsync(PurchaseEvaluationDetailFeatures.cs:42, 8 callsite) · guard line 485ConflictExceptionnon-admin + flag off (F2 skipToFinal) ·ApplyReturnModeAsyncgate per-slot per-modePurchaseEvaluationWorkflowService.cs:252-265(Admin bypass :252) · entry guard:760-762(pointer null khi DaDuyet/TraLai/TuChoi) · BE budget-adjustConflictExceptionnếuAllow=false· FK RestrictPE.ApprovalWorkflowId+LevelOpinion → ApprovalWorkflowLevel·SET QUOTED_IDENTIFIER ON(filtered index Mig 29+) · class-level[Authorize]bare (gotcha #44) · Designer KHÔNG cóusePermission/PermissionGuard(route guard là đủ) - root-cause: ① "F4 = BROKEN at readOnly short-circuit" —
canAdjust = !readOnly && (…)đoản-mạch TRƯỚC khiisApproverChoDuyetđược xét (PeDetailTabs.tsx:973, nút ẩn:1030) ② "BE line 765 lookup semantic broken sau Mig 29" —Level.Ordertrùng nhau sau khi tách 1 row/ApproverUser ⇒FirstOrDefault(Order==X)lấy row đầu theo PK (PurchaseEvaluationFeatures.cs:765) ③ Plan P —TransitionPeBodyrecord 3 field ⇒ ASP.NET silent DROP 3 field còn lại (PurchaseEvaluationsController.cs:267) ④ Plan M0 — KHÔNG có root-cause code, "DISCONNECT bro mental model vs code reality post-Mig 28/29/30/31" - file:line:
User.cs:38·ApprovalWorkflow.cs:86-105·ApprovalWorkflow.cs:45-50·PurchaseEvaluationWorkflowService.cs:119-161(:125) ·~:393-525·:268-275·:285-312·:303-310·:314-333·:335-360·:364·:441-468·:483-524(:485) ·:252-265(:252) ·PurchaseEvaluationFeatures.cs:393-402·:272-329(:283-290 / :291-323) ·:735-770·:765·:281-329·PurchaseEvaluationDtos.cs:86-92·PurchaseEvaluationDetailBundleDto:214+:217·UsersController:91-98+:105·UserFeatures.cs:332·PurchaseEvaluationDetailFeatures.cs:42+:42-99(:49-51 / :54-94) ·PurchaseEvaluationsController.cs:267·ApprovalWorkflowsV2Controller.cs:16-19·DbInitializer.cs:1429-1437+:1541-1547·system/ApprovalWorkflowsV2Page.tsx:873+:853-933+:889-946+:892-948(975 dòng) ·system/UsersPage.tsx:306-318+:365-372+:181-186·PeDetailTabs.tsx:113-118+:118+:224+:245+:957-973+:973+:977+:1030+:287-297(admin) /:294-304(user) +:109-115+:967-979·PeWorkflowPanel.tsx:51+:60-68+:113-124+:331-422(:343-396, :343/:357/:371/:397) +:425-442(:425) ·fe-user/src/pages/pe/PurchaseEvaluationsListPage.tsx:256-261·fe-user Layout.tsx:325+fe-admin Layout.tsx:218·Persistence/Migrations/(path thật) · mig20260513160703_AddAllowApproverEditBudgetToLevels - định-danh khác: commit
a1a910f..ee0902a(7):ee776d5·c667802·ac2c859·da218f1·4d60598·fbbd361·ee0902a· bug UAT prod409a967· phiếuPE/2026/A/026· WFQT-DN-V2-001 v12· usernv.test@solutions.com.vn·TransitionAsyncparamskipToFinalthứ 8 (position 47:47) ·w-60 xl:w-72→w-72 xl:w-80(ngưỡng rủi-row-80 xl:w-96) · grid[260px_1fr] xl:[320px_1fr]·STEP_PALETTE/LEVEL_PALETTE5 màu · token-cost 32k (Pre-A)
Bổ-sung coverage @P3-gate S170 — ⚠️ LƯỚI GREP THUẦN, KHÔNG PHẢI DỮ KIỆN (đoạn trích sau mỗi token là phần ĐẦU DÒNG verbatim chứa token — dòng archive là mega-line nên đoạn trích thường KHÔNG liên-quan token; CHỈ dùng để coverage-diff grep trúng, đọc nội-dung thì tra verbatim theo token — reviewer P3 @S170)
ApprovalWorkflowsV2Page.tsx:889— Bro UAT loginnv.test@solutions.com.vnvào menu eoffice "Duyệt NCC → Duyệt" phiếu PE/2026/A/026 (Phase=ChoDuyet, WF=QT-DN-V2-001 v12, ở B…Mig 27— 7 commits totala1a910f..ee0902a: BE+Layout (ee776d5) + FE Page (c667802) + Docs (ac2c859) + 4 polish iter UAT (da218f1px-2 +4d60598v1 …PeDetailTabs.tsx:245— Bug UAT prod409a967: admin tick F3+F4 cho slot Approver, login actor user, vào menu "Duyệt" (?pendingMe=1cùngPurchaseEvaluationsListPage3-…PurchaseEvaluationFeatures.cs:272— Bro UAT post-Plan L deploy 2026-05-15 ~02:00: "Hiện logic cũ là khi trả lại 1 cấp hoặc chỉ định hoặc edit là trạng thái draft -…PurchaseEvaluationFeatures.cs:735— Bug UAT prod409a967: admin tick F3+F4 cho slot Approver, login actor user, vào menu "Duyệt" (?pendingMe=1cùngPurchaseEvaluationsListPage3-…PurchaseEvaluationWorkflowService.cs:285— Bro UAT post-Plan L deploy 2026-05-15 ~02:00: "Hiện logic cũ là khi trả lại 1 cấp hoặc chỉ định hoặc edit là trạng thái draft -…