Files
solution-erp/.claude/workflows/runs/2026-08-01-S169-bookend-open/sleep-drafts/investigator-codebase--2026-05-q1.gist.draft.md
2026-08-03 10:14:49 +07:00

15 KiB
Raw Blame History

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 FirstOrDefault theo khoá cũ sai âm-thầm: bug BE PurchaseEvaluationFeatures.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 TransitionPeBody 3 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-ro w-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:118 itemsReadOnly override được, nhưng :245 truyền readOnly={readOnly} xuống BudgetAdjustSection và :973 canAdjust = !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:765 FirstOrDefault(l => l.Order == curLevelOrder) — sau Mig 29 tách 1 Level-row PER ApproverUser thì Order trùng nhau trong cùng Cấp ⇒ EF trả row đầu theo PK; 2 token (admin + nv.test) gọi API ra CÙNG currentLevelOptions; 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 đặt Phase=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 FirstOrDefault theo 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-định readOnly=false, còn Danh sách ?pendingMe=1 desktop hard-code readOnly={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=98DangSoanThao=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 gửi ĐỦ 6 field (TargetPhase + Decision + Comment + ReturnMode + ReturnTargetUserId + SkipToFinal, object literal không typed-service); BE PurchaseEvaluationsController.cs:267 record TransitionPeBody chỉ 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.AllowDrafterSkipToFinalApprovalWorkflowLevels.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-105 6 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ải Migrations/).
  • 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.ApprovalWorkflowId FK Restrict + ApprovalWorkflow kế-thừa BaseEntity (KHÔNG soft-delete) ⇒ buộc hard-DELETE; LevelOpinion → ApprovalWorkflowLevel Restrict 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) đòi SET QUOTED_IDENTIFIER ON mớ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 filter IsUserSelectable; menu seed DbInitializer.cs:1429-1437 + quyền :1541-1547 cho 7 role (Accounting KHÔNG có, admin cấp tay); Designer ApprovalWorkflowsV2Page.tsx 975 dòng, 13 field DTO / 7 cờ; sidebar w-60 xl:w-72w-72 xl:w-80 an-toàn @1280px (w-80 xl:w-96 = ngưỡng rủi-ro); enum {DuyetNcc=1, DuyetNccPhuongAn=2, Contract=3}. 7 commit: ee776d5 BE+Layout · c667802 FE Page · ac2c859 docs · 4 polish da218f1/4d60598/fbbd361/ee0902a.
  • BÀI-HỌC: Tailwind JIT đòi chuỗi class ĐẦY ĐỦ trong mảng — bg-${color}-100 bị 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ỏ truncate KHÔ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=3 khai 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@123456 11 ký-tự FAIL 400, TestUser@2026 PASS); đổi tên user = 4 trường nguyên-tử (Email + NormalizedEmail + UserName + NormalizedUserName + FullName — gotcha #38); sqlcmd cần SET QUOTED_IDENTIFIER ON; login trả accessToken/refreshToken/user — KHÔNG có field token (ví-dụ Bash dùng .token sẽ 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 /inbox route (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 485 ConflictException non-admin + flag off (F2 skipToFinal) · ApplyReturnModeAsync gate per-slot per-mode PurchaseEvaluationWorkflowService.cs:252-265 (Admin bypass :252) · entry guard :760-762 (pointer null khi DaDuyet/TraLai/TuChoi) · BE budget-adjust ConflictException nếu Allow=false · FK Restrict PE.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 khi isApproverChoDuyet được xét (PeDetailTabs.tsx:973, nút ẩn :1030) ② "BE line 765 lookup semantic broken sau Mig 29" — Level.Order trùng nhau sau khi tách 1 row/ApproverUser ⇒ FirstOrDefault(Order==X) lấy row đầu theo PK (PurchaseEvaluationFeatures.cs:765) ③ Plan P — TransitionPeBody record 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) · mig 20260513160703_AddAllowApproverEditBudgetToLevels
  • định-danh khác: commit a1a910f..ee0902a (7): ee776d5 · c667802 · ac2c859 · da218f1 · 4d60598 · fbbd361 · ee0902a · bug UAT prod 409a967 · phiếu PE/2026/A/026 · WF QT-DN-V2-001 v12 · user nv.test@solutions.com.vn · TransitionAsync param skipToFinal thứ 8 (position 47:47) · w-60 xl:w-72w-72 xl:w-80 (ngưỡng rủi-ro w-80 xl:w-96) · grid [260px_1fr] xl:[320px_1fr] · STEP_PALETTE/LEVEL_PALETTE 5 màu · token-cost 32k (Pre-A)