12 KiB
implementer-backend/2026-05-q2 — gist
distill-gen: 1 source-verbatim: .claude/agent-memory/implementer-backend/archive/2026-05-q2.md (5 entry → 5 cụm) pointer-style: substring
TỔNG-HỢP (3-5 ý)
- Mirror phải chứng bằng máy, không bằng mắt: SHA256 sau khi ghi (AG
21001E90…; Plan CA 4 hash) hoặcgit diff --statbyte-similar; Pattern 5 (mirror 2 app §3.9) tự đếm tích-luỹ 7th → 8th → 9th — kinh-nghiệm biến thành con-số kiểm được. - Gộp N nhánh log về MỘT đường chung (Plan AB
cdfd542: gỡreturnsớm nhánh Drafter → 1Changelog.Add()duy nhất cuối phủ cả 4 mode); FE lọc bằng substring của summary (động-từ tiếng Việt) thay enum cứng ⇒ thêm luật lọc mới không cần migrate BE. - Pattern 19 — thiếu thư-viện thì dùng thẻ HTML gốc:
<details>/<summary>+ Tailwind named-group +localStorage(fe-user không có Accordion); anti-pattern nestedgroupkhông đặt tên ⇒ con kế-thừa trạng-thái cha, cả hai chevron xoay cùng lúc. - VA-CHẠM số-hiệu Pattern 16 (2 nghĩa khác nhau trong cùng file — CẤM gộp khi nén) + bẫy công-cụ: PowerShell
$_trongForEach-Objectbị Bash tool nuốt khi escape ⇒ đổi sangGet-FileHashdạng liệt-kê — chính cách gọi shell làm hỏng phép kiểm, không phải lệnh sai.
Entries
⚠️ VA-CHẠM Pattern 16 (fidelity — giữ nguyên từ curator, lead định-đoạt): trong verbatim, nhãn "Pattern 16 NEW" được gán cho HAI thứ khác nhau: (S25 wrap) "Preventive systemic batch fix khi audit phát hiện 9 sites cùng bug pattern" ⟂ (S27 Plan CA) "byte-identical mirror admin → user khi parity confirmed". Verbatim q4 tự khai chỗ mờ: "Pattern 16 baseline implied trong recent activity S27 chưa numbered explicit". ⇒ CẤM gộp 2 mục này thành một chỉ vì trùng số.
[cao] G1 — Plan AB Chunk A: gộp 4 nhánh về một chỗ ghi log
- VIỆC: sửa 2 lỗi UAT về nhật-ký duyệt (
cdfd542, 3 file, +146/-95). - KẾT-LUẬN: BE viết lại
ApplyReturnModeAsync(:215-378): bỏreturnsớm của nhánh Drafter (~:282-287) → chuyển thànhif/elsemột đường chung, để mộtChangelog.Add()duy nhất ở cuối phủ cả 4 mode (Summary=$"Trả lại ({modeName}): {summary}",modeNameswitch 4 giá-trị tiếng Việt);actorNamelấy quauserManager.FindByIdAsynctheo đúng khuônLogTransition~:660-667; không gọiSaveChangesAsyncmới vì callerTransitionAsync:100đã lưu. FE 2 app nới bộ lọc: theosummarychứa "Trả lại" (Workflow) vàentityType === PE_ENTITY_HEADER(=1)+ chứa "ngân sách". Test bỏ qua theo chế-độ UAT (giữ mốc 111). - BÀI-HỌC: khi N nhánh cùng phải ghi một loại log, gỡ return sớm để có đường chung rồi ghi một lần — thay vì rải N lời gọi. Và lọc ở FE bằng chuỗi con của summary (động-từ tiếng Việt) thay vì enum cứng: FE thêm luật lọc mới không cần migrate BE.
- BẤT-NGỜ: cùng một đoạn được tả 2 lần trong cùng file với số dòng lệch nhau (
282-287ở entry dày vs280-287ở entry wrap) ⇒ khi hợp-nhất phải chọn bản dày, đừng trộn số. → substring:"cdfd542"
[cao] G2 — Plan AG: cây 2 tầng bằng HTML thuần (Pattern 19)
- VIỆC: bro phản-hồi danh-sách PE phẳng là "đám rừng" → dựng cây Dự-án ▸ Gói-thầu kiểu thư-mục Outlook (
0bf6c7e, 2 file, +346/-116). - KẾT-LUẬN: gom bằng
useMemo2 tầng (ProjectGroup/GoiThauGroup, khoá chuẩn-hoátrim+toLowerCase, hiển-thị bản gốc đầu tiên), có nhánh dự-phòng "(Dự án đã xoá)" / "(Chưa phân loại)", sắp theo localevi, lọc trước khi gom để trạng-thái rỗng đúng. UI dùng<details>/<summary>thuần trình-duyệt (fe-user không có Accordion của shadcn) + Tailwind named groupgroup/proj·group/gt+[&::-webkit-details-marker]:hidden. Ghi nhớ trạng-thái mở bằnglocalStorage(pe_list_expanded_groups, khoá${projectId}::${normalizedGoiThau}, mặc-định đóng hết) cótry/catchphòng chế-độ ẩn-danh. 2 app giống nhau tới SHA256 (21001E90…). - BÀI-HỌC: thiếu thư-viện thì dùng thẻ HTML gốc:
<details>cho sẵn trạng-thái đóng/mở, bàn-phím Space/Enter, 0 dòng JS quản trạng-thái từng nút. Đổi thước đếm cũng phải đổi đồng-bộ (rows.length→projectGroups.length), nếu không trạng-thái rỗng sẽ nói dối. - BẤT-NGỜ: anti-pattern được ghi rõ: nếu hai group lồng nhau trùng tên
group(không đặt tên) thì con kế thừa trạng-thái cha ⇒ cả hai xoay chevron cùng lúc — một lỗi UI chỉ lộ khi lồng, và named-group là cách chữa. → substring:"pe_list_expanded_groups"
[cao] G3 — Plan CA Chunk B: mirror nguyên-si + bẫy PowerShell
- VIỆC: dời 4 trang danh-mục từ fe-admin sang fe-user (
06a441c, 6 file, +962 LOC). - KẾT-LUẬN: vì Investigator đã xác-nhận 2 app ngang bằng (DataTable/PageHeader/PermissionGuard/usePermission/6 shadcn/types), nên chép nguyên file không sửa, rồi verify SHA256 cả 4 (
C1760788…/BDF0529E…/68213D62…/6F482614…) ⇒ an-toàn vì mã bên admin đã qua UAT. Đúcpattern_master_page_mirror.md. - BÀI-HỌC: "chép y nguyên" chỉ hợp-lệ khi đã chứng ngang-bằng trước; và bằng-chứng phải là hash sau khi ghi, không phải cảm-giác đã-copy-đúng.
- BẤT-NGỜ: bẫy công-cụ: biến
$_của PowerShell trong khốiForEach-Objectbị Bash tool nuốt khi escape ⇒ phải đổi sang dạng liệt-kêGet-FileHash file1, file2, … | Format-Tablethay vì lặp qua pipeline. Tức chính cách gọi shell làm hỏng phép kiểm, không phải lệnh sai. → substring:"06a441c"
[vừa] G4 — Plan B Chunk D: dropdown V2 cho ContractCreatePage
- VIỆC: mirror ô chọn quy-trình V2 từ PE sang HĐ (
62b50d1, 2 file, +44 LOC mỗi app). - KẾT-LUẬN: dựa nguyên bản
PeWorkspaceCreateView.tsx(:80-89useQuery +:152-172UI Select), đổi duy nhất trường phân-biệtApplicableType=3; kiểm tiền-đề BE trước khi wire:CreateContractCommand(ContractFeatures.cs:17-36) đã cóGuid? ApprovalWorkflowId = nullkèm marker của em-main ⇒ không lệch DTO. Áp Pattern 16-bis 4 chỗ: trang ×2 DONE, còn Routes / menuKeys / Layout staticMap đều N/A có lý-do. - BÀI-HỌC: mirror xuyên module thì liệt-kê đủ 4 chỗ rồi ghi N/A kèm lý-do, đừng im lặng bỏ qua — "N/A" có lý-do mới chứng-minh là đã xét.
- BẤT-NGỜ: vai kiểm tiền-đề phía BE trước khi sửa FE (đọc record của commit em-main làm trước) — nhờ vậy không đẻ ra lỗi lệch hợp-đồng dữ-liệu; và tự khai phần cố-ý không làm (chỉ
ContractHeaderForm, không đụngContractEditForm). → substring:"62b50d1"
[cao] G5 — META: mirror phải chứng bằng hash
- VIỆC: trục lặp ở 3/5 entry.
- KẾT-LUẬN: Pattern 5 (mirror 2 app §3.9) được đếm tích-luỹ lần 7 → 8 → 9; mỗi lần đều kèm bằng-chứng máy: SHA256 khớp (AG, CA) hoặc
git diff --statbyte-similar (Chunk D). Verbatim còn đề-xuất biến thành công-cụ: "recommend toolinggit diff fe-admin/X fe-user/Xafter every multi-file edit batch". - BÀI-HỌC: với công-việc nhân-bản, đối-chứng máy rẻ hơn review mắt và phát-hiện được thứ mắt không thấy (khác 1 ký-tự).
- BẤT-NGỜ: vai tự đếm số lần áp-dụng một pattern (7/8/9) — biến "kinh-nghiệm" thành con-số kiểm được, thay vì nói "đã dùng nhiều lần". → substring:"git diff fe-admin"
Phụ-lục token (coverage)
- Pattern#:
4feedback_service_hook_vs_endpoint(log trong service hook, KHÔNG endpoint/return-changelogrời) ·5mirror 2 app §3.9 (7th/8th/9th cumulative) ·16(VA-CHẠM — 2 nghĩa, xem cảnh-báo trên) ·16-biskiểm 4 chỗ cross-app ·17FE merge synthetic row ·18FE userMap fallback từ dữ-liệu nhúng ·19<details>+named group+localStorage ·12-biscookie-cutter xuyên module · Pattern 7 (per-NV opt-in, nhắc lại) - criteria#:
#4(tight coupling BE+FE ⇒ vai sẽ REFUSE Plan AC trở đi) - surprise: "Gotcha S27: PowerShell
$_variable inForEach-Objectblock bị Bash tool shell-escape eaten" · "fe-user no shadcn Accordion → native browser disclosure widget free" · "Anti-pattern: nested same-namegroupwould inherit parent state → both rotate sync" · "Mirror 2 app §3.9 IDENTICAL post-edit (SHA256 verify match21001E90...)" · "stash em main WIP ... race condition trick" (nhắc chéo) · "KHÔNG ops git push (em main verify Reviewer rồi mới push)" (lặp 3 entry) · "FE filter qua substring summary keyword chứ KHÔNG enum field strict" · "recommend toolinggit diff fe-admin/X fe-user/Xafter every multi-file edit batch" · số dòng lệch282-287vs280-287cho cùng đoạn - guard:
try/catchquanhlocalStorage(quota / ẩn-danh) · lọcpendingMeTRƯỚC khi gom nhóm ·projectGroups.length === 0thayrows.length === 0· SHA256 sau khi ghi (4 file) ·git diff --statbyte-similar · kiểm tiền-đề BE (Guid? ApprovalWorkflowId = null) trước khi wire FE ·[&::-webkit-details-marker]:hidden· named groupgroup/proj⟂groupmặc-định · không gọiSaveChangesAsyncmới (caller đã lưu) - root-cause:
returnsớm ở nhánh Drafter ⇒ không có đường chung ⇒ phải rải nhiều lời-gọi log ⇒ gom vềif/else+ 1Changelog.Add()· fe-user thiếu Accordion ⇒ chuyển sang<details>gốc ·groupkhông đặt tên khi lồng ⇒ con kế-thừa trạng-thái cha · Bash tool escape nuốt$_⇒ForEach-Objectgãy - file:line / định-danh:
PurchaseEvaluationWorkflowService.csApplyReturnModeAsync:215-378, Drafter early-return :282-287 (wrap ghi:280-287),userManager.FindByIdAsyncmirror :660-667, callerTransitionAsync:100 ·PeDetailTabs.tsx×2 (filter + comment 3-nguồn) ·PE_ENTITY_HEADER= 1 ·Summary=$"Trả lại ({modeName}): {summary}"("Người soạn thảo"/"1 Cấp"/"1 Bước"/"Người chỉ định") ·ProjectGroup{projectId, projectName, goiThauList[], totalCount}·GoiThauGroup{displayName, normalizedKey, items[]}·pe_list_expanded_groups·__no_project__·${projectId}::${normalizedGoiThau}·group/proj·group/gt·group-open/proj:rotate-90·PeWorkspaceCreateView.tsx:80-89 + :152-172 ·ContractCreatePage.tsx×2 ·CreateContractCommand@ContractFeatures.cs:17-36 (Guid? ApprovalWorkflowId = null, marker[Plan B S29 2026-05-22 Chunk E1]) ·ApplicableType=3· Mig 25IsUserSelectable·pattern_master_page_mirror.md·feedback_uat_skip_verify - sha / số-đo:
cdfd542(3 file +146/-95; BE +83/-49; FE +14/-6 mỗi app) ·0bf6c7e(2 file +346/-116 = +115 mỗi app) ·06a441c(6 file, +962) ·62b50d1(2 file, +44 ×2 = +88) · SHA25621001E90…·C1760788…/BDF0529E…/68213D62…/6F482614…· build: BE 20.27s · fe-user 1907 module 16.62s / 16.05s / 14.14s / 8.84s · fe-admin 1926 module 6.98s / 6.86s / 16.07s · bundle fe-user 1291.33 KB (gzip 337.00) / 1.32MB (gzip 343KB) · fe-admin 1402.68 KB (gzip 357.51) / 1.40MB (gzip 358KB) · test mốc 111 (bỏ qua theo UAT) · token ~10k-16k · warn nền: CSS@import+INEFFECTIVE_DYNAMIC_IMPORT realtime.ts(lặp 3 entry) · tag[pattern, phase-9, frontend]