Files
solution-erp/.claude/agent-memory/reviewer/MEMORY.md
2026-08-01 10:11:59 +07:00

104 lines
20 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
- **S166 (08-01) gate K4b nối `?group=` end-to-end — PWF 4 MAJOR/5 MINOR, 0 blocker:** lõi ĐÚNG (derive-thuần + reset-trong-render `navKey`, 6/6 ca chuyển leaf hết cần F5; BE `/deleted` mirror list-sống ĐÚNG TỪNG NÉT, vế lọc SAU IDOR; sha mirror ×3 khớp; build 0E + `tsc -b` ×2 EXIT=0 **tôi tự chạy**). **Bài thu:** ① 🔴 **mỏ-neo XUYÊN FILE** — wave-B sửa file A làm sai chú-thích-neo-số-dòng trong file B (`Layout.tsx:204` trỏ `KhkkListPage :61/:62`, đĩa = `:74/:76`), 2 wave vào **1 commit** ⇒ sai từ **byte-0** chứ không trôi dần; đo 2 đầu rẻ: `git show <base>:<file> | grep -n` vs đĩa. Tái phát bài K4a ② sau ĐÚNG 1 wave, lần này khác file ⇒ quét mỏ-neo phải quét **file BỊ dời**, không chỉ file đang sửa. ② **phán NGƯỢC 1 FLAG của lane** (queryKey mang giá-trị-ĐÃ-GIẢI-MÃ): ĐÚNG, vì khoá cache định danh **REQUEST** không định danh URL — kèm **điều-kiện-phản-chứng** ("sai nếu raw `filter` chảy vào JSX", đã grep hết đường đi) thay vì gật "OK". ③ **HIGH-nằm-ở-git tái xuất** — sắp commit gộp mà `git status --porcelain -- src tests | grep '^??'` vẫn ra test K4a **chưa track** ⇒ mã seed lên repo, test chứng minh nó thì không. ④ **cây phình giữa review** lại xảy ra (HEAD +2 commit, +123 dòng) nhưng phân lập được bằng `git diff --stat -- <đường-code>` + sha lại file mirror ⇒ **.claude-only, verdict giữ**; đây là cách rẻ để không phải soi lại từ đầu. ⑤ tham-số-trang-trí **không tự khỏi**: K4b đẻ instance thứ 8 (`Khkk_WfView?group=1`) khi consumer vẫn 0 hit. ⑥ positional-record + object-initializer: điều-kiện ẨN = base phải là **record** (record không kế thừa class) — kiểm base rồi hãy phán "compile được". Tag `[s166, moneo-xuyen-file, khoa-cache-dinh-danh-request, high-o-git, cay-phinh]` **Evidence:** `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k4b.md`
- **S166 (08-01) gate K4a 49-row menu KHKK 8-nhóm — PWF 4/0 blocker:** lõi ĐÚNG hiếm thấy (bộ-sinh 1 nguồn feed 3 phía `All`/seed-row/grant ⇒ khớp by-construction; 8/8 nhãn khớp TỪNG KÝ TỰ; suite **620/620 tôi tự chạy**). **Bài thu:** ① 🔴 **tham-số-trang-trí** — URL leaf mang `?group=n``grep "get('group')"` ×2 app = **0 hit** ⇒ 7 nhóm × 6 leaf mở ra CÙNG nội dung, `WfView` hiện toàn bộ workflow type-10; *đo "route có tồn tại" là chưa đủ, phải đo **AI ĐỌC** từng param* (đối xứng ca S164 "tham-số-chết-vì-thiếu-tầng-UI", lần này chết ở tầng ĐỌC). ② **mỏ-neo tự-vô-hiệu ngay lúc land** — 2 comment mới trỏ dòng trong CHÍNH file đang sửa, sai đúng **+34 = kích thước khối vừa chèn** (tác giả tính trên bản trước khi chèn); cùng diff đó vừa DỌN lỗi y hệt ở BE (`1893`) ⇒ **mỏ neo trỏ vào file mình đang sửa phải đo SAU khi chèn**, hoặc bỏ số dùng grep-anchor. ③ **ô canonical sai đo-được bằng 1 curl** — STATUS ghi bundle `mySTlx42`/`CZAYiWWa`, live = `1yiNV4VH`/`DoULfmdT` (2 css KHỚP ⇒ chứng đo đúng site, không phải đo nhầm). ④ **bất-biến từng-vỡ-thật lại là bất-biến 0 test** (revoker không đụng `Khkk_*`; thêm 1 chữ vào filter thì 620/620 vẫn xanh, đúng kịch bản Run #423 mà chính comment dẫn lại) — khuôn có sẵn `Revoke_DoesNotTouch_PeModule`. ⑤ test gọi seeder LẺ qua reflection ⇒ chuỗi `SeedAsync` (grant→revoke→site-3) ngoài vùng test ⇒ **restart-thật KHÔNG được coi là đã phủ**. Tag `[s166, tham-so-trang-tri, moneo-tu-vo-hieu, o-canonical-sai-1-curl]` **Evidence:** `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k4a.md`
- **S166 (08-01) vá F-1 ô-tích opt-out `applyLevelFinalize` KHKK — PWF 7 finding (3 MAJOR):** vá ĐÚNG kỹ thuật (mirror 2 app chứng bằng **blob-SHA in ngay trong `git diff` index-line** — rẻ hơn sha256 tay; body không rò field; cấp thường bất-biến từng bit). **Bài thu:** ① 🔴 **khuôn-nguồn có 2 tầng, chú-thích nói dối tầng dưới** — implementer trích ĐÚNG dòng JSX PE `:772-791` + nhãn "khuôn PE S96 default tick", nhưng `useState` PE `:61` = `false` (S97 owner **ĐẢO** sang opt-IN) và chính chú-thích PE `:769-771` cũng stale ⇒ **đo khuôn phải đo GIÁ-TRỊ KHỞI-TẠO, không đọc chú-thích**; tái phát S165 F-1 (đo sai tầng). ② **cây làm việc PHÌNH GIỮA LƯỢT REVIEW** — đo `git status` 2 lần cách ~40 tool-call: 5 file→7 file (+121 dòng K4a, `All` 64→113) ⇒ **verdict phải neo mốc đo + re-đo `--stat` TRƯỚC khi phát verdict**, nếu không lead commit ké code chưa qua cổng. ③ vắng-mặt-đọc-thành-sạch: `isApproved ⇒ mọi Bước 'Done'` ⇒ CEO chưa đụng vẫn "đã duyệt", dấu-vết duy nhất = THIẾU dòng "✓ ký". ④ **sợi-dây-1-argument** (projection `l.AllowApproverFinalize`) 0 test ⇒ xoá là control biến mất mà 614 test + tsc vẫn xanh. Tag `[s166, khuon-2-tang-chu-thich-noi-doi, cay-phinh-giua-review, sợi-day-1-argument]` **Evidence:** `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-f1-checkbox.md`
- **[→ archive/2026-07.md — verbatim ĐÃ VERIFY moved-not-cut 4/4 @S166-curate] S164/S165 gate K3 · S164 gate K1 · S162 cây-4-folder · S161-W2 KHKK-CRUD (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 · giá-trị lớn nhất ở GATE QUY-TRÌNH không ở mã · **ghost-policy** (grep policy, đừng suy từ "key đã vào All") · default-lấn-ngữ-nghĩa · im-lặng-về-độ-chính-xác-của-con-số ×3/diff · **#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 (2 lỗi CHE NHAU) ⇒ so ROUTE+FIELD trên ĐĨA.
- **[→ archive/2026-07.md — verbatim, verify moved 5/5 @S166-curate] 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' · **HIGH nằm ở `git`** (gate `git status --porcelain -- src tests | grep '^??'` RỖNG trước commit) · comment 'bên kia lo' = ĐI ĐỌC BÊN KIA · grep bằng TOKEN-SONG-SINH · `hợp-đồng-đứt-2-bờ` · re-đo đĩa TRƯỚC verdict · đổi-chiều-assert ≠ nới-assert · bất-biến chia-đôi 2-axis chỉ cross-cut sweep bắt · `bằng-chứng-tự-huỷ-sau-squash` · re-measure acceptance từ git HEAD + no-self-exempt · 'mọi nhánh set X' phải grep assignment-qua-BIẾN (#81) · `ExecuteDelete` ngoài transaction = mất dữ liệu · test đang KHOÁ chiều ngược CẤM nới assert · xanh-giả bắt bằng phép 2-thế-giới · 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) — PASS: hard-block→soft-warning; submit-guard intact + validator giữ `BudgetPeriodAmount>0`, row8 negative-safe (additive-only). Validator class `PurchaseEvaluationFeatures.cs:317`.
- [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/2026-07.md @S161-curate] S160 (07-29) review SPEC-BỘ dry-run KHKK:** review SPEC ≠ review CODE (lỗ ở acceptance + default-lấn-quyền) · seeder-grant kiểu insert = NO-OP 403 im lặng ⇒ acceptance phải đ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)) — adjustMut share race + authz-lens ≠ concurrency-lens · FE 4 render-sites plan-missed-2 · ground-truth-accurate-nhưng-gaps.
- **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 review](project_s103_h20_crystallized_backfill_review.md) — WF2 PASS; 6/6 hash recompute MATCH + 4 already-met verified. Lesson: multi-axis warning phải nằm trong OUTPUT của script (reader chạy inline), không chỉ doc.
- [S111 PE sign-off 6-decision design review (schema/history lens)](project_pe_signoff_history_schema_review.md) — GO-WITH-ADJ; D5 opinion-history: append-only table, REJECT version-col (drops UNIQUE + breaks UPSERT).
- **PE per-hạng-mục series ×5** ([cardinality#3](project_pe_multiwinner_perhangmuc_review.md) · [BE-financial](project_s114_pe_multi_ncc_perhangmuc_financial_review.md) · [spec-l3](project_pe_multi_ncc_perhangmuc_specreview.md) · [IMPL](project_s114_multi_ncc_perhangmuc_impl_review.md) · [neg-quote](project_pe_negative_quote_correctness_review.md)) — derived src-of-truth: re-derive MỌI write-path KỂ CẢ Delete · grep field-NGUỒN không chỉ field-đọc · sign-loss: defer-parse tới field-chung mọi mutation.
- [S113 Supplier import v2 close-review (owner anh Kiệt)](project_s113_supplier_import_v2_review.md) — GO-WITH-ADJ 2 must-fix (consumers không pass published=true → drafts leak). Lesson: "filter added" ≠ "drafts hidden" — grep-all-consumer + create write-path.
- [S118 Procurement master-access seeder review](project_s118_procurement_master_access_review.md) — PASS(cond); MAJOR Reports.Read leaks financials + Suppliers.Update grant ≠ edit. Lesson: menu-flag grant ≠ API capability; bare `[Authorize]` GET = open-to-all.
- [S123 governance 4-change review (backtick-guard + H24-3 + retire dạng-3 + mark)](project_s123_governance_4change_review.md) — PASS_WITH_FIXES; CAUGHT H24-3 thiếu enclosure-guard mà cùng diff vừa chứng cần (gen-2 citation-trap) + greedy `.*` lấy `(S<N>` CUỐI≠MAX + lý-do-retire áp cho dạng-2 thì giết C8. Q5 "HOÀN-THÀNH mark" = nguỵ-biện. Q8 ENDORSE không-bump.
- [S147 Project whitespace-dupe merge verify](project_project_dupe_merge_verify.md) — 7/7 PASS(2 FK-terminology corrections); "FK Projects" COMMENT ≠ physical FK (sys.foreign_keys=0 to Projects, all loose-Guid); seed-durability FORCES survivor=no-space blanket; INNER-join+filter=silent-vanish→repoint-before-soft-delete; prod ref-dist unverifiable (Server=localhost+secret).
---
## 🎯 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 · HELD stale run-id · persist-claim cần reader-side + tracked + 0-drift · outward-claim 'đã sửa X' phải cat X trước gate · gist meta-count ≠ đĩa · claim-về-code grep lại kể cả reword · nâng-nấc-quên-sync cùng-diff · 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
- ⚠️ **NỢ CURATE @S166-K4b:** file đang ~20KB (quá ngưỡng 17.1KB, VẪN dưới read-limit 24.4KB nên chưa mất dòng nào). CỐ Ý không curate vội giữa lượt gate — curate gấp là đúng kịch bản `cut-not-moved` S102. Phiên sau: move VERBATIM 2-3 entry S166 (K4a/F-1/K4b) → `archive/2026-07.md`, probe moved-not-cut TRƯỚC khi xoá khỏi L1; detail đầy đủ đã nằm sẵn ở `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-*.md` (git-tracked).
- Hook-cap **>17.1KB** (24.4KB read-limit — đổi từ ~30KB cũ, S109) → archive recent → L2 `archive/<period>.md` (append additive) + `_INDEX.md` substring pointer. Stale >3mo → remove.
- **S162-curate (self, 2026-07-30, 23.9KB→<17.1KB):** move VERBATIM 2 entry S161-W2 + S161-W1 `archive/2026-07.md` @S162-curate (probe moved-not-cut 2/2 TRƯỚC khi xoá khỏi L1, bài S102) + nén 10 dòng digest đã-archive-sẵn. KHÔNG cut-without-move.
- **Prev curates:** S162 (moved-not-cut probe 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 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ấp 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 chứng.