Files
solution-erp/.claude/agent-memory/reviewer/MEMORY.md
2026-08-07 14:42:12 +07:00

142 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Reviewer Agent — Persistent Memory
- **S180 (2026-08-07) LANE A/6 `/fable-clone reviewer` — bóc GĐ-0+GĐ-1 gói 7-giai-đoạn AI_INFRA (đĩa `runs/2026-08-07-S180-adap-upgrade-pack-phased/sub-n3-lane-a-gd01.md`, 57 KB / 355 dòng; #53 cắn ở return lượt đầu, đĩa cứu trọn):** 🔴 **Bài đắt nhất — "0 hit" ĐÚNG THEO LUẬT vẫn là LỖ THẬT.** Lead giao ca "4 thư inbox 2 ngày, `_index` 0 hit". Đo ra: **24 thư thiếu dòng / 69**, cũ nhất 25 ngày. Nhưng phân loại theo `to:` mới ra chuyện: `to=se` **23/23 CÓ dòng** (control-dương mạnh nhất — kỷ luật CÓ chạy) · `to=all-fit` **22 có / 20 thiếu**. Mà chính `_index.md:7` khai fan-out **KHÔNG** track ở đây, track ở `COMMS-LEDGER``find -iname "*COMMS*"` = **0 tệp trong SE** (control `*ledger*` = 4) ⇒ **sổ mà luật trỏ tới không tồn tại**, 21 thư không có nhà. Và S153 đã phán ca này **dương-giả** (`bookend-close-synthesis.md:25`, hồi đó 19 thư) — phán đúng cho **câu hỏi lúc đó**, sai cho câu hỏi A0-3 bây giờ. ⇒ **Luật: gặp "0 hit", hỏi (a) luật nào nói nó phải có mặt · (b) luật đó trỏ sổ nào · (c) sổ đó CÓ TỒN TẠI KHÔNG.** Bỏ (c) là đóng nhầm khoản đang hở. 🔴 **Bài 2 — đếm HỌ TÊN bằng regex ra 160/159, lệch 1 vì `S57bis`** (hậu tố chữ làm 1 tệp rơi vào 2 nhánh lọc) ⇒ mọi phép phân-họ phải **cộng lại và đối chiếu tổng**, lệch 1 cũng phải truy. Đo được: sessions/ **5 họ** (159 tệp) · runs/ **2 họ** (88, 18 lệch) · scripts/ **3 họ** + cặp sinh-đôi `session-scaffold.ps1``session_scaffold.py` (cùng khái niệm, 2 quy ước) · vai **1 họ SẠCH** (agents 26 = agent-memory 26 = `hmw.js` VALID_ROLES 26, `comm` rỗng 2 chiều — vì có máy STOP-HARD `:173`). 🔴 **Bài 3 — `CLAUDE.md` ghi quy ước nhật ký `YYYY-MM-DD-HHMM-{topic}` khớp ≤64/159 tệp thật, họ đông nhất (78) không khớp cách nào** ⇒ quy ước thành văn duy nhất trong kho **sai với đa số đĩa**, 0 máy chặn. 🔴 **Bài 4 — "single source" tự xưng ≠ chuẩn.** `vocab-alias-map.md:3` tự nhận *"nguồn duy nhất"* nhưng `:8` tự thu hẹp còn **cặp từ đồng nghĩa** ⇒ là **bảng dịch** (nhìn về sau), KHÔNG phải chuẩn (nhìn về trước). 3 phép thử tách: **tiên-đoán** (đưa vai mới chưa có tên — nó câm) · **phủ-sóng** (6 nhóm tên hub đòi: 0/6) · **hướng**. ⇒ SE **không khai `không áp dụng` GĐ-1 được**. 🔴 **Bài 5 — số-trong-chú-thích trôi, bắt bằng 1 lệnh:** `hmw.js` chú thích *"11 class: 5 view-\* + 6 gap-\*"*, đĩa `memory-budget.json` = **12** (6+6); lớp thứ 12 `view-claim-broader-than-sample` **append cuối mảng, ngoài cụm view-\*** ⇒ đếm lướt ra 5, tưởng đúng. Tập tự nhận là **ĐÓNG** mà sai số phần tử = người đọc không biết mình thiếu lớp nào. Tag `[s180, lane-a, 0hit-dung-luat-van-la-lo, so-trong-cua-luat-khong-ton-tai, phan-ho-phai-cong-lai-tong, single-source-tu-xung-la-bang-dich, so-trong-chu-thich-troi]`
- **S179 (2026-08-07) C7 re-review sau vá SỬA-1..6b — `PASS-WITH-8`, 3 MAJOR `[LEAD SEED ON-BEHALF]`:** 🔴 **Lượt ăn tiền nhất từ trước tới nay của vai này: 2/3 MAJOR là lỗi TRONG CHÍNH BẢN VÁ vừa pass 12/12 acceptance.** [1] `git status --porcelain | cut -c4-` **đẻ path RÁC** — rename in MỘT dòng `R old -> new`, path có dấu cách bị quote; lead dựng sandbox đo lại: **2/2 MISS**, thước đề-xuất **2/2 OK**. [2] đổi ba-chấm→hai-chấm **KHÔNG vô-hại mà là REGRESSION có điều-kiện** — lead ĐÚNG rằng md5 y hệt, nhưng chỉ khi `origin/main` còn ancestor; sandbox phân-kỳ: hai-chấm liệt cả `upstream_only.txt` (= ĐÃ PRODUCTION) vào "phần MỚI", ba-chấm ra đúng. ⇒ **thủ phạm thật luôn là `git diff` mù untracked**, lead gán sai tội cho ba-chấm. [3] khối MIRROR lead vừa viết mang số `:112` trong khi chính 6 dòng đó đẩy thành 118 — **mỏ-neo TỰ-VÔ-HIỆU ngay lúc viết**; lead vá thành `:118` thì 3 dòng vá đẩy tiếp thành 121 ⇒ **sửa gốc = bỏ số dòng, neo TÊN SELECTOR**. [4] census "8/9 khoá" của lead THIẾU — §D gốc 25 mục, **3 ý đóng im lặng**, 1 trong 3 (`Đợt B — NỘI DUNG từng mục`) **0 hit ở cả `_mind` lẫn `_context`**. [5] con-trỏ verbatim `ca9208f` sai (thiếu 4.636 B) ⇒ lead vá **per-block**: `d081681` cho MIND-1, `727a512` cho 3 block S179, đối chứng từng cái resolve ra bản CHƯA nén. 🔸 **Bài đắt nhất:** *chẩn-đoán sai vẫn pass acceptance* — cả 2 MAJOR lọt vì acceptance đo **HÌNH-DẠNG chuỗi**, không đo **HÀNH-VI**. 🔴 #53 garble, resume vớt trọn; mảnh garble mang "a third thước defect" ⇒ lead biết có cái thứ 3 trước khi đọc verdict. Tag `[s179, C7, bat-loi-trong-ban-va, ba-cham-dung-hai-cham-regression, cut-c4-path-rac, moc-neo-tu-vo-hieu, acceptance-do-hinh-dang-khong-do-hanh-vi]`
- **S171 (2026-08-04) — 3 lane lens ĐỐI-KHÁNG (`/fable-clone reviewer` ×3), **cả 3 CHẾT hết-giới-hạn nhưng ĐĨA CỨU 74.070 B** `[LEAD HARVEST HOI-TO @S172 — no mo tu closeout truoc; owner slot (71) chot 'gom va sleep thi auto, tu quyet'. Nguon = artifact tren dia, KHONG suy dien]; nguồn `runs/2026-08-04-S171-khkk-ui-mirror-pe/sub-reviewer-lens-{feasibility,regression,fidelity}-s171.md` 26.461 + 24.432 + 23.177 B`:** **feasibility 8 ĐẠT / 6 BROKE** — mở đầu bằng **tự bác giả-thuyết của chính lane** (*'chỉ ghi 1 nhánh' = SAI; claim D-2 HELD, ≥9 chỗ ghi → thật 10*); bắt **trích-dẫn hỏng dạng nhẹ**: `WorkflowService.cs:552` **không trỏ vào cái gì cả** (call-site thật `:485`/`:554`, định-nghĩa ở file KHÁC) nhưng **nội dung claim vẫn HELD***cite sai ≠ claim sai*, phải tách. **regression 8 ĐẠT / 4 BROKE / 10 bỏ-sót** — phát hiện nặng nhất: **A-6 kiểm SAI KHOÁ ⇒ lỗ thủng NGAY TRONG hàng rào bảo-vệ R-4** (bắt `canPe`); R-4 HELD nhưng *lý-do bản invest đưa QUÁ THÔ*. **fidelity DỞ** (§6+§8 trống, `VERDICT=?`) — lead derive ≈12/6/3; bảng N-1→N-4 đối chiếu **từng claim bằng lệnh dán kèm**: N-1 tự phân loại 35 dòng ⇒ khớp 27/6/2 · N-2 khớp chính xác `:106/:125/:249` · **N-3 HELD về THỨ TỰ nhưng lệch con số hình-thức** (chỉ 3 hit `title="N.` vì Section 2 dùng template-literal đếm động, Section 4 là `<section>` trần) — 🔴 **chính bẫy này sau đó lead tự dẫm** (grep `'<Section title='` ra 0, suýt kết FAIL). ⇒ **Bài kép: lane dự báo đúng cái bẫy mà người viết bản sửa vẫn sa vào** — có thước đúng trong tay ≠ sẽ dùng thước đúng. Tag `[s171, 3-lane-doi-khang, dia-cuu-74070, cite-sai-khac-claim-sai, a6-sai-khoa-canPe, template-literal-dem-dong]`
- **[→ archive/2026-07.md §@S166-K5-curate — verbatim] S166 gate K4b · K4a · vá F-1 (digest):** mỏ-neo XUYÊN FILE · **tham-số-trang-trí** (đo AI ĐỌC từng param) · mỏ-neo tự-vô-hiệu ngay lúc land · ô canonical sai đo được bằng 1 curl · khuôn-nguồn 2 tầng ⇒ đo GIÁ-TRỊ KHỞI-TẠO · **cây phình giữa review** ⇒ re-đo `--stat` TRƯỚC verdict · HIGH-nằm-ở-git (`git status --porcelain -- src tests | grep '^??'`) · khoá-cache định-danh REQUEST không định-danh URL.
- **[→ archive/2026-07.md §@S167-K7-curate — verbatim ĐÃ PROBE moved-not-cut] S166 gate K5 cây-GĐ2-8-folder · K4c cụm-2 (digest):** bất-biến Σ do CẤU TRÚC · **phép-đo-rẻ-nhất nằm ở file RÁC của lane khác** · chân-lý-RỖNG phải khai là rỗng · tương-đương-TỪNG-VẾ > 'cùng tập' · tiền-lệ đo ở BASE không ở cây đã sửa · 'N/N OK' chết theo phiên khi FE 0 hạ-tầng-test · **flake chỉ lộ ở LƯỢT ĐẦU và `-v q` NUỐT assert** · probe RED bằng đổi TEST-INPUT chỉ khi tham số xuất hiện ĐÚNG 1 chỗ · `Total` là vân-tay lọc-SERVER chỉ khi `CountAsync` sau `Where` trước `Skip/Take`.
- **[→ archive/2026-07.md §@S167-K7-curate-2 — verbatim ĐÃ PROBE moved-not-cut] S167 gate K7 cầu KHKK→HĐ — PASS-WITH-FLAGS 10 (digest):** **1 con số đóng 2 câu hỏi** (639 = 622 baseline + 17 `[Fact]` ⇒ chứng CẢ 'chạy thật' LẪN '0 test cũ vỡ'). **Mỏ-neo tự-vô-hiệu** — comment trỏ `:2516` nhưng cây đã là `:2523` do chính diff đẩy xuống ⇒ phải đo **2 THẾ GIỚI (HEAD ⟂ cây)**. **Prod probe sửa con số của chính comment** (13/13 role → thật 12/13). **Răng phủ NỬA**: T11 assert 4 vế nhưng `await` tuần tự ⇒ ca ĐỒNG THỜI vẫn hở. **SHA-identical KHÔNG bảo chứng route-identical** ⇒ grep route CẢ 2 app. Tag `[s167, mot-so-dong-2-cau-hoi, moneo-tu-vo-hieu, rang-phu-nua]`
- **[→ archive/2026-07.md §@S168-curate — verbatim ĐÃ PROBE moved-not-cut] S168 gate GĐ3-D cắm cây vào Panel-3 ×3 trang — PASS-WITH-FLAGS 10, 0 blocker (digest):** **khuôn dùng-lại phải ĐO LẠI theo HOST**`max-h`/`sticky` hiệu-chỉnh cho host CŨ: cây cần 100vh158 mà Panel-3 chỉ có 100vh184 (InboxPage) ⇒ 2 thanh cuộn lồng; 2 trang kia thừa 5px/13px = khít đến mong manh. **Class chết ÂM THẦM khi đổi kiểu cha** (`self-start` cha `block` · `lg:sticky` con DUY NHẤT của chính scroll-container) — tsc+build KHÔNG bắt, chỉ đọc CSS-chain mới thấy. `aside` lồng `aside``aria-label` vẫn giữ `role=complementary` ⇒ 2 landmark lồng. Prod-probe biến lo-ngại thành số: `canPe` 13/13 True ⇒ ca `!canPe` chưa xảy ra (control-âm `Permissions`/`Users` False 12/13). `{!selectedId && <X/>}` = unmount ⇒ mất state thuần (`search`) trong khi `localStorage` sống ⇒ trade-off spec khai THIẾU. Thước hỏng: python Windows đọc JSON phải khai `encoding` · `while read` bỏ dòng CUỐI khi thiếu newline · `join` text-mode đẻ CRLF vào tên file. Tag `[s168, khuon-do-lai-theo-host, class-chet-am-tham, unmount-mat-state]`
- **[→ archive/2026-07.md — verbatim @S168 K8] S168 gate K8-blocker Lines-editor KHKK — PASS-WITH-FLAGS 8, 0 blocker (digest):** 642 = 639 baseline + 3 Fact ⇒ **1 con số đóng 2 câu hỏi** · **quy-ước-của-chính-file là thước rẻ nhất** (mọi changelog sub-entity điền `EntityId`, chỗ mới là chỗ DUY NHẤT trống ⇒ MAJOR bằng 1 grep) · **`<select>` controlled NUỐT giá-trị đã lưu** khi option vắng (đang tải · query lỗi không toast · entry `IsActive=false` sau gán) ⇒ regression hiển thị do ĐỔI KIỂU Ô, tsc+build+test 0 bắt · **bình-luận tự-hẹn mắt-xích tương lai** chưa trả ⇒ nhưng ĐO khả-chạm trước khi hô (UNIQUE tầng trên khoá ⇒ hạ MINOR) · khe RỖNG khai rỗng ×2 · test phủ NỬA vế `if` (`!IsActive` chưa chạy lần nào) · thước hỏng `$?` sau `| tail` ⇒ đo lại `tsc -b --force`.
- **S170 GATE Fidelity /sleep-recovery-memory-l2 (16 gist-draft) — PASS-WITH-FIXES (digest):** **tên-cờ-bịa sống 4 hiện-vật** — grep 0-hit CẦN dụng-cụ THỨ HAI (`git log --all -S` + control-dương) mới nâng 'nghi'→'chốt: chưa từng tồn tại'; 3/4 là drift của cờ THẬT, 1/4 (`AllowDelegate`) 0 đối-ứng ⇒ **đừng gộp 2 lớp**. 🔴 **Nhãn phủ TÊN mà không phủ CON-SỐ** — claim mang tải là 'proven 4×' (kích-hoạt luật ≥2× promote), và đơn-thuốc 'giữ 4 lần, bỏ tên cờ' = **giữ khẳng-định + vứt CHỨNG-NHÂN** ⇒ bất-khả-bác (Goodhart). **Census tự-xưng đủ** ('4 LỖ') thiếu 4 lỗ nữa gồm 1 lỗ +23 — số-đóng-vai-đã-phủ-hết (meta-count blind-spot), dù draft TỰ chép đủ số để trừ ra. **Chính-sách số BẤT-ĐỐI-XỨNG trong cùng đợt**: file A bị buộc 'KHÔNG tự sửa số', file B lén sửa 7→6 field không khai ⇒ đọc-sau không biết số nào là chữ nguồn. **`pointer-style: substring` phải CHẠY THỬ**: 1/10 con-trỏ CHẾT do lệch hoa-thường (`PRIORITY` vs `priority`). **Lưới token máy-append in ĐẦU-DÒNG không in lân-cận-token** ⇒ mega-line cho trích-dẫn LẠC HẲN (gán FAIL cho Run PASS) — tái-lập ở 2 file độc-lập. Thước tốt giữ lại: control-ÂM cạnh control-dương · claim liên-file phải HAI BỜ CÙNG KHAI · tag-chain 14/14 đo bằng grep -F từng chuỗi. Tag `[s170, nhan-phu-ten-khong-phu-so, census-tu-xung-du, con-tro-chet-hoa-thuong, luoi-dau-dong]`
- **[→ archive/2026-07.md §@S167-K7-curate-2 — verbatim] S167 gate K6 admin thu-gọn — PASS-WITH-FLAGS 5 (digest):** **cây menu PROD SỐNG là thước, seed chỉ là bản vẽ** (`curl /api/menus/me` + control-âm bỏ 1 key). **`filterForAdmin` mới là bước MỘT** — còn `resolvePath→null` drop im lặng (#50) + group rỗng-hoá render như LEAF. **typo-noop**: key ẩn sai chính tả = `Set.has` false, module vẫn hiện, tsc vẫn xanh ⇒ assert TỪNG key TỒN TẠI trong cây prod. MAJOR: CẤM số-đếm trong comment.
- **[→ archive/2026-07.md §@S166-curate — verbatim] S164/S165 K3 · S164 K1 · S162 cây-4-folder · S161-W2 (digest):** tham-số-chết-vì-thiếu-tầng-UI (đo TẦNG-CUỐI ai GỬI) · sweep 2-cờ bất-đối-xứng · flake ⇒ 'N/0 tươi' phải khai SỐ LƯỢT · **ghost-policy** (grep policy, đừng suy từ 'key đã vào All') · **#82 ngược chiều** (FE OR nhiều key LỎNG HƠN policy khớp-CHÍNH-XÁC-1-key ⇒ tự chuốc 403) · hợp-đồng FE↔BE VỠ 6 điểm mà tsc+build+574-test XANH ⇒ so ROUTE+FIELD trên ĐĨA.
- **[→ archive/2026-07.md — ĐÃ RE-PROBE @S168: nội-dung CÓ trong archive; 2 nhãn `S161-W1`/`S152-D2` 0-hit nên GIỮ ở đây] S159-đợt5 · S161-W1 · S155-đợt2 · S145-4lane · S143 · S139 · S134b · S133 · S146/S147/S152-D2 (digest gộp):** chú-thích-mang-SỐ phải chạy phép đếm · cookie-cutter soi CẢ phần bản gốc đã CHẶN · `tsc`+`noUnusedLocals` > grep cho claim 'đã cắt' · comment 'bên kia lo' = ĐI ĐỌC BÊN KIA · grep bằng TOKEN-SONG-SINH · `hợp-đồng-đứt-2-bờ` · đổi-chiều-assert ≠ nới-assert · `bằng-chứng-tự-huỷ-sau-squash` · 'mọi nhánh set X' phải grep assignment-qua-BIẾN (#81) · `ExecuteDelete` ngoài transaction = mất dữ liệu · 3 THƯỚC-HỎNG (md5 CRLF · `grep -c` citation-trap · `grep -iF` MSYS 0-hit im lặng).
> **Persistent diary cross-session.** Auto-injected first ~200 lines at spawn (L1 HOT).
> 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`.
- **[→ archive/2026-07.md @S161-curate] S160 (07-29) CHỐT-CUỐI 13-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 · verify NGƯỢC premise · 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) — hard-block→soft-warning, submit-guard intact (additive-only).
- [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.
- **[→ archive @S161-curate] S160 review SPEC-BỘ KHKK:** review SPEC ≠ review CODE · seeder-grant kiểu insert = NO-OP 403 im lặng ⇒ acceptance đo CỜ không đếm ROW · acceptance 'PASS SẴN' = 0-bit · 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)) — authz-lens ≠ concurrency-lens; FE 4 render-site, plan sót 2.
- **S101 H18/H19 WF2 + LANE-C:** content-hash ≠ commit-SHA (hex strip/no-strip) · exact-token sweep miss paraphrase → widen concept-phrase. → `archive/2026-07.md`.
- [S103 H20 + crystallized-backfill](project_s103_h20_crystallized_backfill_review.md) — cảnh báo multi-axis phải nằm trong OUTPUT của script, không chỉ trong doc.
- [S111 PE sign-off design (schema/history)](project_pe_signoff_history_schema_review.md) — opinion-history append-only; REJECT version-col (phá UNIQUE + UPSERT).
- **PE per-hạng-mục ×5** ([1](project_pe_multiwinner_perhangmuc_review.md) · [2](project_s114_pe_multi_ncc_perhangmuc_financial_review.md) · [3](project_pe_multi_ncc_perhangmuc_specreview.md) · [4](project_s114_multi_ncc_perhangmuc_impl_review.md) · [5](project_pe_negative_quote_correctness_review.md)) — derived source-of-truth: re-derive MỌI write-path KỂ CẢ Delete; grep field-NGUỒN không chỉ field-đọc.
- [S113 Supplier import v2](project_s113_supplier_import_v2_review.md) — "filter added" ≠ "drafts hidden": grep-all-consumer + create write-path.
- [S118 Procurement master-access seeder](project_s118_procurement_master_access_review.md) — menu-flag grant ≠ API capability; `[Authorize]` trần = mở cho mọi user.
- [S123 governance 4-change](project_s123_governance_4change_review.md) — citation-trap gen-2: vá 1 CLASS phải grep MỌI matcher cùng-lớp TRONG diff.
- [S147 Project whitespace-dupe merge](project_project_dupe_merge_verify.md) — "FK Projects" trong COMMENT ≠ FK vật lý; INNER-join + filter = biến mất im lặng.
---
## 🎯 Role baseline
Adversarial pre-commit reviewer SOLUTION_ERP. Read-only verify + live curl prod UAT (`*.solutions.com.vn`). Tools: Read, Grep, Glob, Bash (curl + git diff + sqlcmd read) + 5 RAG MCP. Skills: `dependency-audit-erp` + `contract-workflow` + `permission-matrix`. Output: PASS/FAIL + concrete issues file:line. NEVER write code.
---
## 🚨 Recurring bug patterns (catch priority)
- **#44 Silent 403 class-level Authorize quá strict** — Drafter dropdown empty silent (TanStack catch silent → UI empty). Grep `\[Authorize\(Policy=.*\)\]` class-level + curl non-admin expect 200. Fix: class-level `[Authorize]` only (any authenticated); POST/PUT/DELETE giữ `[Authorize(Policy="X.Create")]`.
- **#43 Step.Order ≠ index 0-based** — `Where(s=>s.Order==i)` wrong row. Fix: EF query → in-memory `OrderBy(Order).ToList()` → index.
- **#42 Dual schema V1/V2 — Service phải branch** — `if (entity.ApprovalWorkflowId is Guid awId) ApproveV2Async else V1Legacy`.
- **Wire BE claim** — grep diff `// Mock`/`alert(`/no POST-PUT-DELETE call + live curl expect 2XX. Severity CRITICAL block.
- **#70 FE absolute-set stale-echo race** — N field cùng-cột share 1 mutation + echo sibling từ server-snapshot + `invalidate()` không await ⇒ lưu 2 ô liên-tiếp đè mất. Window mở SAU `isPending=false`, KHÔNG lúc in-flight. Catch: đếm field-cùng-cột share mutation + check invalidate awaited.
- **#71 enum proxy-predicate pollution** — thêm enum value vào entity dùng-chung → UI/guard phân-loại theo PROXY-predicate (`supplierId===null`) thay vì enum tường minh → value mới lẫn nhầm phân-loại + false-pass guard. Catch: grep mọi field-proxy predicate, loại value mới tường minh; build-verify TỪNG app.
- **Cross-module security mirror (S29 Smart Friend)** — mirror entity/Command cross-module (PE→Contract→Budget V2) hay focus data-shape mà MISS security guard. Luật: validate `aw.ApplicableType == ExpectedType` ON Create TRƯỚC khi instantiate (khuôn `PurchaseEvaluationFeatures.cs:62-77`) — FK Restrict chỉ check Id-tồn-tại, KHÔNG check type ⇒ Drafter forge `approvalWorkflowId` module khác = pin sai-scope. Re-verify `IsActive`+`IsUserSelectable` server-side. MAJOR.
- **#17 EF migration 3-file** — `git diff --name-only | grep Migrations/` expect 3 (target + Designer + Snapshot).
---
## 📋 6-category checklist (EVERY review)
- **Cat 1 Wire BE/feature claim:** grep mock markers diff + `await api\.(post|put|delete|patch)\(` + live curl POST/PUT/DELETE if deploy claim + status matrix.
- **Cat 2 Schema integrity:** 3-file rule Mig + column types vs entity def. Reference `docs/gotchas.md` (71 active).
- **Cat 3 Security:** `[Authorize]` class-level ALL new controllers + per-action policy admin-scoped (gotcha #44) + FE PermissionGuard + menuKeys.ts mirror BE MenuKeys.cs + FluentValidation + EF parameterized.
- **Cat 4 Code quality:** `dotnet build SolutionErp.slnx` 0 err + `npm run build` × 2 app (TS6 strict) + tests baseline **354 PASS** (Phase 9 UAT exception OK) + no `--no-verify` + anti-fiddle (scope drift >20% LOC = FAIL) + mirror 2 FE app §3.9.
- **Cat 5 Test coverage:** new helper → xUnit · new endpoint → integration · bug → regression test-before-fix. Phase 9 UAT test-after default OK (`feedback_uat_skip_verify`). Baseline 354.
- **Cat 6 Writing-quality (Harness-7, S64):** outward text (verdict gửi anh / report) = tiếng Việt câu hoàn-chỉnh đủ dấu đúng ngữ-pháp; describe issue + acceptance criteria, NOT code edits. Escalate disagreement explicit.
---
## ⚠️ Anti-patterns + 🛡️ Smart Friend guard
1. ❌ Recommend code edits (only describe issue+criteria) · 2. ❌ Skip live curl if deploy claim · 3. ❌ Accept "wire" without grep proof · 4. ❌ Defer to em main authority (escalate explicit) · 5. ❌ Skip MEMORY · 6. ❌ **Lower bar match em main** (Smart Friend Cognition anti-pattern).
**Smart Friend (Cognition):** NEVER lower bar. Em main code fine → PASS. Em main issues → FAIL with specifics regardless social pressure. "Quality ceiling set by primary, not escalation." Value = raise quality through catch.
---
## 🧠 SOLUTION_ERP review essentials (S80 verified — re-ground từ docs/STATUS.md canonical)
- **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).
---
## 📅 Recent activity (compressed — full verbatim → `archive/2026-06.md` + `archive/2026-07.md` via `archive/_INDEX.md`)
- **[→ archive @S126/@S134] S123·S124·S125·S129·S131 (digest):** follow-up phải GIỮ con-số source · re-derive từ raw (fencepost) · writer-only = NỬA-VÁ · do-token trap ⇒ re-Read full + sibling-test 2-CHIỀU · 🔴 ghi diary TRƯỚC return + vá-1-lớp phải grep MỌI matcher cùng-lớp.
- **Digest S93→S117 + June-2026 (verbatim → `archive/2026-07.md`):** code-gate re-derived denom · default-flip byte-mirror SHA ×2 · persist-claim cần reader-side + tracked + 0-drift · outward-claim 'đã sửa X' phải cat X trước gate · claim-về-code grep lại kể cả reword · verify EACH regex-alt by-hand · merge-distill đẻ false-specificity ⇒ QUALITY gate SAU presence · sha = self-declared NOT recompute · TRACKED = check-ignore ≠ ls-files · menu-hide ≠ API-lock.
- **S92 PROD-security hide 5 menu-groups admin-only — PASS (1 note):** → [project_s92_admin_only_modules_revoke.md](project_s92_admin_only_modules_revoke.md).
- **[→ archive/2026-07.md @S128/@S134] S112·S126·S127·S128 (digest):** derive guard từ ENDPOINT authz, self-flip ≠ external-accept · AGGREGATE cumulative KHÔNG vào outward artifact · direction-of-error quyết mức lỗi outward + brute-force sha-variant TRƯỚC phán tamper · hedge broadcast bằng MỞ config THẬT.
---
## 🔄 Curate trigger
- ⚠️ **@S168-K8 đo lại: 18.3KB — VƯỢT cap 17.1KB ⇒ spawn sau curate NGAY** (đã append verbatim K8 vào `archive/2026-07.md`, L1 chỉ giữ digest).
-**@S168 curate: 22.2KB → <17.1KB (ĐO, không đoán).** Trình tự S102 giữ nguyên: append archive TRƯỚC probe moved-not-cut + control-âm mới cắt. 🔴 **Bài mới:** (a) tôi ghi '~20.6KB' bằng ƯỚC LƯỢNG trong khi `wc -c` cho 22.2KB **số trong sổ phải là số ĐO**, baseline '19.0KB' thừa kế từ pass trước cũng đã stale; (b) probe moved-not-cut bằng token lấy từ DIGEST cho **0-hit GIẢ** (digest paraphrase, bản gốc dùng chữ khác) 0-hit phải **thử token thứ 2 từ thân bài** trước khi kết luận cut-not-moved suýt giữ lại 938B ích; (c) **script sinh chữ lại đẻ chữ hỏng câm** (token `join` trong chuỗi làm entry vỡ đôi dòng) đúng bài S166-K5, byte-count KHÔNG bắt, chỉ ĐỌC LẠI mới thấy.
- Hook-cap **>17.1KB** (24.4KB read-limit, S109) → archive recent → L2 `archive/<period>.md` (append additive) + `_INDEX.md` pointer. Stale >3mo → remove.
- **Prev curates:** S166-K5 (probe 3/3) · S162 (2/2) · S145 · S140 · S134 · S128 · **S102 recovery: cut-not-moved ×5 `f229b07` ⇒ mọi L1-shrink kèm '→archive' BẮT BUỘC grep moved-not-cut TRƯỚC khi trust** · S116·S113·S109·S80·S71·S70·S40.
## S152 (07-25) — R1 ranh NEVER (on-behalf lead)
- **NEVER Edit/Write code-tree · NEVER commit · NEVER push** — vai = verdict-only; sửa là việc em-main/implementer. Khai thật 2 nấc: ranh commit/push/code-tree **chưa từng vỡ**; Write/Edit runtime CÓ cấp và dùng hợp lệ cho sub-file run-folder + diary-self (AS-10). "NEVER" áp cho ĐÍCH (code/commit/push), không phải cho tool-tồn-tại; containment thật = git-diff lead. Tag `[s152, r1-retention, never-target-scoped]`
- **[→ archive/2026-07.md @S165-curate] S159 đợt-1 (07-29) diff pipeline — 7 FLAG:** rút TOÀN BỘ chuỗi hiển-thị MỚI từ diff rồi soi từng chuỗi = phép đo 100%-tiếng-Việt · 2 queryKey cùng resource = 2 ảnh-chụp khác thời-điểm · a11y nút TRÙNG tên đọc-được · bác-claim cũng phải có chứng.
## S176 (08-06) — SETUP-REVIEW đội STYLE 3 vai (engine `/fable-real`, run `wf_264fb5c2-0db`) — verdict `SỬA-6`
- **Chấm THIẾT-KẾ một đội sub-agent, không phải diff code** — trục mới của vai. Vật: `runs/2026-08-06-S176-doi-style-3-vai/sub-reviewer-0.md` (15.798 B, full-detail).
- 🔴 **Bài đắt nhất — THƯỚC DISPATCH MÙ WORKING-TREE:** đội gate pre-commit mà thước là `git diff origin/main...HEAD` (ba-chấm) ⇒ lúc review lệnh trả **RỖNG** ⇒ dispatch kết "diff không chạm ⇒ không gọi" ⇒ **0 con spawn, 0 SKIP-CO-KHAI để lộ** ⇒ đội **chết câm** đúng use-case chính. Lớp `guard-chặn-không-đường-ghi` / `dry-run bắt lời-hứa-chưa-land`. Sửa: `git diff origin/main` (2-chấm) `git status --porcelain` lọc `??`.
- **Thước TREE tự lành ca REVERT** (bằng chứng revert thật `3f339c0`): revert xong code không còn trong tree ⇒ không thành chuẩn. Lo-nghi "revert phá thước" = **lo hão** — vì thước là tree, KHÔNG phải history. Ranh này đáng nhớ: đo TREE ≠ đo HISTORY.
- **Miễn-trừ chỉ-con-trỏ = dấu-cao-su:** 3 nguồn bằng-chứng (commit-message · WAL · prompt) thì 2 do **chính lead** viết — đúng người vai sinh ra để kèm. Đòi **TRÍCH NGUYÊN VĂN ≤1 dòng** thay vì chỉ con-trỏ ⇒ khép vòng bằng **owner-visibility** (owner đọc report tự bác câu bịa), không cần đẻ thêm vai.
- **Thách-CLEAN nhánh DAT bẻ được** nếu chỉ đòi "nêu 1 khối đã khớp" mà KHÔNG bắt neo `file:line`. Khuôn `db` (kèm số đếm 3-file — con số sai được) mạnh hơn 2 con kia. Luật: **cặp neo `file:line ⇄ file:line` + 1 chi-tiết khớp cụ-thể**, thiếu neo = coi như CHƯA SOI.
- **Vắng-mặt trông giống ổn (tái phát):** 3 vai mới **thiếu dir `agent-memory/<vai>/`**`measure-agent-memory.ps1` enumerate theo DIR ⇒ 3 vai **vô hình câm** trong đo/budget. Lead tự đo lại: 3/3 THIẾU — CONFIRMED.
- **3/5 lo wiring của lead là LO HÃO** (engine đo từng đường): `spawn-model-audit.ps1` · `governance-detectors.ps1` · `mfe-eval.ps1` đều enumerate **ĐỘNG**, không hardcode ⇒ tự nhận vai mới. Bài: **đừng giả-định script hardcode — mở ra đo.**
- **Chép-luật-vào-persona vi phạm chính B1 vừa viết trong CÙNG file** (`db:32/34-35/61` vs `db:71` cấm chép; `fe:4` chép digits "React 19 + Vite 8" — class ĐÃ drift thật: root `CLAUDE.md` ghi React **18** vs `package.json` ^19.2.5). Bài: viết luật cấm-chép xong phải **grep chính file mình** xem có chép không.
- Tag `[s176, setup-review, thuoc-mu-working-tree, do-tree-khong-do-history, mien-tru-can-trich-nguyen-van, vang-mat-giong-on]`
## S180 (08-07) — N3 LANE-B /6 · adap upgrade-pack GĐ-2 "lưới ghi đĩa + sổ mục lục vật chứng" (`runs/2026-08-07-S180-adap-upgrade-pack-phased/sub-n3-lane-b-gd2.md`)
- **NGHI-THỨC ≠ MÁY, và sổ của chính SE là bằng chứng mạnh nhất** — đừng suy, hãy đọc **cột kiểu** của `error-ledger`: AS-17 ghi `procedural`, AS-19 tự khai *"🔴 hiện là nghi-thức, **chưa cơ-khí-hoá**"*. Khi bản đồ nói "SE đã có AS-17/AS-19" thì đó là **có LUẬT**, không phải **có MÁY**. Phép kiểm rẻ: grep cột kiểu, đừng grep tên mã lỗi.
- **Guard đo KÍCH THƯỚC mù với hỏng TỈ LỆ KHUNG/RUỘT** (ca S180 N1: 7.049 B, 6/9 heading là `[ĐANG ĐO]`, sau 202K token — `nhip-no-probe` báo `run-chua-gom 0`). Hai đại lượng **không tương quan**: tệp toàn heading tăng byte y hệt tệp đầy ruột. Dựng sandbox + chạy máy thật + **control-dương** (giấu `*-synthesis.md` → 1, trả lại → 0) mới phân biệt được **mù** với **hỏng thước**.
- **Vị từ bắt `skeleton-ruột-rỗng` rẻ nhất = neo NHÃN TREO VÀO HEADING**, không phải đếm thô: `grep -cE '^#{1,6} .*\[(ĐANG ĐO|CHỜ|TODO)'`. Đếm thô cho **dương-giả trên chính bản đã xong** (câu định nghĩa nhãn ở header) = đúng lớp **citation-trap self-reference** đã có trong auto-memory; discriminator vẫn là **use ⟂ mention**. Đo 3 file: 6 / 0 / 0 — 0 dương-giả.
- **"Sổ chết" có hai loại, phải tách trước khi phán:** `runs/_ledger.md` **RETIRED có khai** (lý do đo được `0/15 catch`, người kế nhiệm chỉ định, caveat parity trung thực, đường đảo ngược) = **suy-giảm hợp lệ**, KHÔNG phải "quên". Nhưng **hệ quả với người dùng vẫn y hệt**: 73/88 run-folder không có dòng nào trong sổ ⇒ *"điểm danh 2 nguồn"* mất **vế phải**, không phải mất phép so. Khen cơ chế nghỉ-hưu, vẫn FAIL khoản chức năng.
- **BỘ ĐẾM không thay được MỤC LỤC:** `run-chua-gom N` in một con số, không liệt tên, không có bộ-tệp-chuẩn, và **đọc thẳng đĩa** ⇒ nó **chính là nguồn-1**, không dùng làm nguồn-2 được. Nguồn-2 rẻ nhất đã nằm sẵn trên đĩa: **taskList snapshot trong `run.md` ghi TRƯỚC launch**.
- **Vùng chứa vật chứng đắt nhất lại nằm trong 2 vùng miễn cùng lúc:** `secrets_sweep(session_dir)` chỉ rglob `sessions/` (`session_ctx.py:173/180/787`) **và** `.claude/workflows/runs` in nguyên văn trong khối `- excluded:` của detector. C11 là cửa hậu duy nhất, chỉ soi khuôn tag FLAG + diary-delta; 21/21 dòng chạm `runs/` đều `LOW` + INFORM-only + **tách khỏi TOTAL** ⇒ mức nghiêm trọng đang **ngược chiều** yêu cầu "đắt tiền = nặng nhất".
- **Tỉ lệ không mẫu số là số vô nghĩa — ca đo được:** cùng một sự thật GĐ-2 ra **42% / 72% / 25%** tuỳ mẫu số (13 khoản lane / 8 bước thư chính / 6 ô nghiệm thu). Con số "~70%" của bản đồ **không sai**, nó là **mẫu số dễ nhất trong ba**; mẫu số hub dùng cấp nấc cho **25%**. ⇒ khi thấy tỉ lệ trần, hỏi mẫu số TRƯỚC khi hỏi ai sai.
- **Reviewer tự thành ca bệnh mình đi soi (datum, không phải lời xin lỗi):** lượt-1 của tôi hạ cánh 2.765 B / 150K token. Đối chiếu với ca N1 mới lộ ra điều không thấy nếu chỉ có 1 ca: **V-2 (nhãn treo) phân biệt đúng "khung rỗng" ⟂ "ruột thật mới bắt đầu"; V-1 (tỉ lệ) thì không.** Ca thứ hai là thứ chọn được vị từ.
- **Xác nhận ngược có giá trị:** N2 F-06 (GĐ-2(v) "khai điểm mù" vắng trọn) **ĐÚNG**, và N2 còn **nói nhẹ hơn sự thật** — SE có sẵn 2/3 vế; bỏ khoản này là **mất điểm cho việc đã làm đúng** (A13), không chỉ mất cảnh báo. Nhưng đo tiếp thì vế (v-3) **yếu hơn cả N2 lẫn tôi tưởng**: `lead-stale-auditor.md` **0 hit** `run-folder|runs/` (control-dương `FLAG`=4) ⇒ tự hạ đánh giá của chính mình, giữ câu cũ để so.
- Tag `[s180, adap-gd2, nghi-thuc-vs-may, skeleton-ruot-rong, vi-tu-heading-scoped, use-vs-mention, ledger-retired-co-khai, diem-danh-2-nguon-thieu-ve-phai, mau-so-3-cach-lech-3-lan, sandbox-control-duong]`