# Reviewer Agent — Persistent Memory > **Persistent diary cross-session.** Auto-injected first 200 lines / 25KB at spawn. > Update BEFORE every stop. Curate when > 25KB. --- ## 🎯 Role baseline Adversarial pre-commit reviewer for SOLUTION_ERP. Read-only verification + live curl on prod UAT environment (`*.solutions.com.vn`). Tools: Read, Grep, Glob, Bash (curl + git diff + sqlcmd read). Output: PASS/FAIL verdict + concrete issues file:line. --- ## 🚨 Recurring SOLUTION_ERP bug patterns (catch with priority) ### Gotcha #44 — Silent 403 class-level Authorize quá strict (S18 lesson) - Symptom: Drafter dropdown V2 workflow empty silent (no error toast) - Root: `[Authorize(Policy = "Workflows.Read")]` class-level → non-admin 403, TanStack Query catch silent → UI empty - Verify: grep `\[Authorize\(Policy = .*\)\]` class-level vs action-level + curl với non-admin token expect 200 - Fix pattern: class-level `[Authorize]` only (any authenticated). POST/PUT/DELETE giữ `[Authorize(Policy = "X.Create")]` admin-only ### Gotcha #43 — Step.Order ≠ index 0-based - Symptom: EF query `Where(s => s.Order == i)` returns wrong row - Verify: grep `step.Order` arithmetic — array index 0-based vs Order field 1-based - Fix pattern: precompute candidates EF query → in-memory `OrderBy(s => s.Order).ToList()` → array index access ### Gotcha #42 — Dual schema workflow V1 vs V2 — Service phải branch - Symptom: PE submit failed do Service không biết V1 hay V2 schema - Verify: grep `evaluation.ApprovalWorkflowId is Guid awId` — phải branch theo pin field - Fix pattern: `if (evaluation.ApprovalWorkflowId is Guid awId) ApproveV2Async(...) else ApproveV1LegacyAsync(...)` ### Wire BE claim recurring bug pattern - Symptom: claim wire CRUD nhưng grep diff finds `// Mock` / `alert(...)` / no POST/PUT/DELETE call - Verify: grep diff mock markers + live curl POST/PUT/DELETE expect 2XX - Severity: CRITICAL — block commit ### Gotcha #17 — EF migration 3-file rule - Symptom: commit migration nhưng thiếu `.Designer.cs` hoặc `ApplicationDbContextModelSnapshot.cs` → next migration fail - Verify: `git diff --name-only | grep Migrations/` expect 3 files (target.cs + target.Designer.cs + Snapshot.cs) ### Gotcha #47 — `.claude/agent-memory/**` NOT in `paths-ignore` filter (S22 discovery, PENDING bro decide) - Symptom: MEMORY.md drift patch commit (end-of-session flush) triggers full CI deploy ~3.5min waste - Verify: check `.gitea/workflows/deploy.yml` `paths-ignore` — currently `['docs/**', '**/*.md', '.claude/skills/**']` MISSING `.claude/agent-memory/**` - Discovery: S21 CICD Monitor Run #188 verify chốt initial — confirmed via path filter audit - Fix recommended: add `.claude/agent-memory/**` vào paths-ignore (em main KHÔNG tự edit — flag bro decide; pending add to `docs/gotchas.md` 47th entry) - Severity: minor (CI waste only, no functional impact) --- ## 📋 5-category checklist (apply EVERY review) ### Category 1: Wire BE / feature claim verify - Grep mock markers in diff (`// Mock`, `alert(`, `setEditing(null) // close UI`, `TODO.*wire`) - Grep actual API call: `await api\.(post|put|delete|patch)\(` trong FE diff - Live curl POST/PUT/DELETE/PATCH if deploy claim (`https://api.solutions.com.vn/...`) - Status code matrix expected vs actual ### Category 2: Schema integrity (44 active gotchas) - Reference `docs/gotchas.md` + skill `dependency-audit-erp` - Check 3-file rule Mig - Check column types vs entity definition (Mig 27 lesson: `IsVisible bit NOT NULL DEFAULT 1` + `DisplayLabel nvarchar(200) NULL`) ### Category 3: Security - `[Authorize]` class-level on ALL new controllers - Per-action `[Authorize(Policy = "...")]` cho admin-scoped (gotcha #44 lesson) - Permission guard wrap new admin pages (FE) - Route permission map populate (`menuKeys.ts` mirror BE `MenuKeys.cs` + `All[]`) - Input validation FluentValidation Validator class - SQL parameterized (EF Core default OK) + XSS escape ### Category 4: Code quality - `dotnet build SolutionErp.slnx` clean 0 err - `npm run build` × fe-admin + fe-user clean (TS6 strict) - Tests baseline 81 PASS (Phase 9 UAT exception OK) - No `--no-verify` bypass (forbidden absolute) - Anti-fiddle audit (scope drift > 20% LOC outside spec = FAIL) - Mirror 2 FE app khi feature FE (rule §3.9) ### Category 5: Test coverage - New helper static → unit test (xUnit) - New Repository method → repo test - New endpoint API → integration test (WebApplicationFactory) - Bug recurring → regression test TDD-style (test BEFORE fix) - **Phase 9 UAT exception:** test-after default OK theo memory `feedback_uat_skip_verify` - Test count baseline 81 → tăng khi feature added theo §7 --- ## ⚠️ Anti-patterns observed (DO NOT) 1. ❌ Recommend code edits — only describe issue + acceptance criteria 2. ❌ Skip live curl verify if deploy claim — recurring risk 3. ❌ Accept "wire" claim without grep proof 4. ❌ Defer to em main authority — escalate disagreement explicitly 5. ❌ Skip MEMORY.md update với anti-patterns observed 6. ❌ Lower bar to match em main quality — Smart Friend anti-pattern Cognition --- ## 🛡️ Smart Friend anti-pattern guard Per Cognition documented research: - NEVER lower bar to match em main's apparent quality - If em main code fine → say PASS - If em main code has issues → FAIL with specifics regardless social pressure - "Quality ceiling was set by the primary, not the escalation." — Your value = raise quality through catch --- ## 🧠 SOLUTION_ERP review essentials - **Tests baseline:** 111/111 PASS (S25 unchanged from S23 t3 +7 Plan M edge case tests; pre-Plan AB Chunk A2 SQLite tie-break regression Run #215 caught by CICD test gate → em main fix EntityType + Summary discriminator filter restored 111 PASS). Must increase nếu feature added per §7; UAT iteration exception per memory `feedback_uat_skip_verify` - **Gotchas:** 47 active (`docs/gotchas.md` reference) — +#48 Multi-Changelog.Add() trong same SaveChangesAsync transaction → SQLite test frozen clock CreatedAt tie-break non-deterministic (S25 pending docs add). +#45 PE button TraLai payload mismatch + #46 Gitea API path/cache stale (S21 t3-t4). #47 paths-ignore agent-memory gap (S22 PENDING bro confirm add to docs) - **Migrations:** 31 latest `AddPeLevelOpinionsForV2` (S19 — Mig 31 Plan K1 swap F2 Drafter→Approver scope per-Level slot S23 t1). Mig 30 `AddAllowApproverEditBudgetToLevels` (S22+5 per-slot F4 flag admin opt-in Approver scope edit budget ChoDuyet branch). Mig 29 prev `RefactorAdvancedOptionsToPerLevelAndDrafterUser` (S21 t5 per-NV split) - **Per-NV Allow* scope split** (Mig 29 + Mig 30) — F1+F3 5 flag + F4 `AllowApproverEditBudget` (S22) on `ApprovalWorkflowLevels` (per Approver slot), F2 1 flag on `Users.AllowDrafterSkipToFinal` (per Drafter). DTO: `currentLevelOptions` + `drafterAllowSkipToFinal` thay vì `workflowOptions` - **Endpoints:** ~146 (+3 S22: allow-skip-final / budget-adjust / attachments/view) - **Identity password policy ≥12 chars** (S22+2 enforced by ASP.NET Identity stack — reject `User@123456` 11 chars). Existing HANDOFF mention "User@123456" pattern S4 outdated, current test creds Admin@123456 + TestUser@123456 OK - **Live deploys (Prod UAT):** https://api.solutions.com.vn · https://admin.solutions.com.vn · https://eoffice.solutions.com.vn - **Bearer token test:** - Admin: `admin@solutions.com.vn / Admin@123456` (full quyền) - UAT user: `nv.test@solutions.com.vn / TestUser@123456` (Drafter Phòng CCM — verify non-admin access patterns) - **Users active:** 33 (rename role-based pattern act.nv / act.pp / act.tp etc.) - **Conventions:** `docs/rules.md` (§3.9 mirror 2 FE, §5.2 commit format, §6.5 docs KEEP narrative, §7 test timing, §2.8 package pinning) - **6 skills:** `contract-workflow` · `permission-matrix` · `form-engine` · `ef-core-migration` · `dependency-audit-erp` · `iis-deploy-runbook` --- ## 🔑 Critical pin verify (gotcha #1-4) - MediatR `12.4.1` (14 fail DI) - Swashbuckle `6.9.0` (10 conflict OpenApi 2) - Microsoft.OpenApi `1.x` (2 breaking) - Node engines `>= 20` + CI `20.x` (Node latest fail Windows IIS) Flag commit nếu thấy ` terseness; consistent format 4 mode). (3) **actorName resolve N+1** — single `userManager.FindByIdAsync` per ApplyReturnModeAsync invocation, mirror exact LogTransitionAsync line 700-704 pattern; KHÔNG N+1 (single call per transition). (4) **FE filter substring case** — `.includes('Trả lại')` exact match BE format `$"Trả lại ({modeName}): ..."` — case-sensitive Vietnamese diacritics lowercase 'l' match. (5) **FE placeholder Vietnamese** — "Chưa có lịch sử trả lại / điều chỉnh ngân sách / gửi duyệt lại." chuẩn Vietnamese diacritics. (6) **Comment update 5 bullet rule** — clear narrative, KHÔNG noise, Plan AB S25 marker rõ. (7) **Gotcha #45 regression** — Plan AB Service-only refactor KHÔNG đụng PE button TraLai click logic (gotcha #45 đã fix S21 t3 BE guard `decision != Reject throw line 64-72` defense), no regression. (8) **Anti-fiddle scope** — 3 file đúng spec, KHÔNG out-of-scope (no agent-memory commit, no docs/changelog touch). **Minor observation (non-block, design choice):** V1 legacy phiếu (line 226-236 fallback) return early TRƯỚC khi reach new Changelog.Add() block → V1 phiếu KHÔNG có new detailed "Trả lại (X): ..." log. FE filter `phaseAtChange === TraLai(98)` line 2042 vẫn catch V1 generic LogTransitionAsync log (V1 fallback set Phase=TraLai) → V1 history vẫn hiện (1 generic row "Chuyển phase X → TraLai" thay vì detailed mode breakdown). Acceptable per Mig 22-24 spec V1 = read-only history, không cần backfill audit detail. Recommendation: PASS proceed push remote. Smart Friend guard active. - **2026-05-15 (S24 Plan AA post-wrap cumulative finalize, no re-spawn):** Post-Chunk C learning append — em main iterate **4 polish chunks back-to-back** (`da218f1` px-2 hotfix + `4d60598` redesign v1 panel-per-NV color + `fbbd361` redesign v2 table layout rowSpan + `ee0902a` wrap fix sidebar label) UAT visual feedback bro, cumulative ~1.5h, KHÔNG Reviewer spawn. **Anti-pattern observed S24 polish chunks**: UI/UX iteration thuần CSS/layout KHÔNG cần Reviewer spawn mỗi chunk — cost overhead too high (~25K spawn × 4 = ~100K cumulative). Pattern reusable: chỉ self-verify build pass + bro visual confirm post-deploy là đủ. **Smart Friend guard validation S24**: Plan AA cumulative ~620 LOC qua 7 commits (`a1a910f..ee0902a`) — Reviewer spawn 1 lần (Chunk C cumulative A+B BE+FE wire) cost ~25K = ROI tốt. Multi-spawn polish chunks 4× sẽ ~100K = ROI thấp. **Pattern saved: BUNDLE cumulative verify cho heavy chunk (wire BE / migration / cross-stack), SKIP cho < 30 min polish (CSS / layout / color)**. **Discovery #3 anomaly re-tested S24**: Plan AA Run #210 sha=ac2c859 push range mixed BE+FE+docs → CICD trigger normal 4/4 wire end-to-end + bundle hash 2 app rotate. KHÔNG reinforce docs-only anomaly hypothesis (S22 #47 gap pending separate). Defer Investigator follow-up. **Low note S24**: BE filter `IsUserSelectable=false` non-admin leak workflow chưa ghim — defer follow-up (severity Low, workflow data non-sensitive, NOTE only — Smart Friend guard didn't escalate to block commit). CICD Monitor Run #210 sha=ac2c859 PASS verify 4/4 wire end-to-end + bundle hash 2 app rotate. Cumulative state unchanged S24: 31 mig, 111 test, 47 gotcha. - **2026-05-15 (S24 Plan AA cumulative pre-commit verify, spawn):** Adversarial verify Chunk A (BE + Layout, em main solo) + Chunk B (FE WorkflowMatrixViewPage, Implementer Case 2 PASS). Diff scope 8 file modified + 2 file CREATE — ~76 LOC BE + ~270 LOC FE, scope khớp Plan AA. **Verdict: PASS with 0 critical / 0 major / 0 minor issues — proceed commit OK.** Wire BE: Controller line 21-26 `Overview(applicableType, isUserSelectable, ct) → new GetAwAdminOverviewQuery(applicableType, isUserSelectable)` end-to-end. Handler line 114-117 `request.IsUserSelectable is bool ius → query.Where(d => d.IsUserSelectable == ius)` correct conditional. FE WorkflowMatrixViewPage line 29-33 actual `api.get('/approval-workflows-v2', { params: { applicableType: typeInt, isUserSelectable: true } })` — real call no mock/alert. Route `/purchase-evaluations/workflow-matrix?type=N` wired App.tsx:38 + Layout.tsx resolvePath:81-86. Schema integrity: 0 migration mới (column `IsUserSelectable` from Mig 25), DbInitializer INSERT-OR-UPDATE-Order idempotent verified (MenuItemConfiguration HasKey(Key) → PK unique, ToDictionary safe; existing rows UPDATE Order only nếu mismatch; new rows INSERT). 7 Allow* flag count match BE DTO ↔ FE type. ApplicableType enum {1,2,3} — FE chỉ wire 2 type PE matrix view correct. Security: class-level `[Authorize]` bare line 18 PRESERVED (gotcha #44 protect). GET any authenticated → non-admin Drafter OK access. Non-admin pass `isUserSelectable=false` BE không block → workflow chưa ghim leak risk — Low severity (workflow data non-sensitive, NOTE only). Permission seed 7 role × WfView leaf via `SeedPurchaseEvaluationPermissionDefaultsAsync:1573` added — idempotent. Admin role qua `SeedAdminPermissionsAsync` chỉ cover `MenuKeys.All[]` static root keys (Pe_*_WfView dynamic NOT in All) — but admin uses fe-admin Designer, KHÔNG cần WfView access fe-user. Code quality: BE dotnet build PASS 0 err 2 warn (DocxRenderer pre-existing); FE fe-user npm build claim PASS (Implementer Case 2); FE fe-admin npm build VERIFY tự chạy PASS 1926 modules / 740ms / 0 TS err. Anti-fiddle 0% drift, scope khớp spec. Mirror 2 FE §3.9: Layout.tsx widen `w-72 xl:w-80` cả 2 ✓; remove truncate 3 site fe-user (MenuGroup+MenuLeaf+StaticLeaf) + 2 site fe-admin (MenuGroup+MenuLeaf, no StaticLeaf component) — structural asymmetry acceptable (fe-user only có "Hộp thư" StaticLeaf); WorkflowMatrixViewPage fe-user only correct (admin có Designer riêng). Test coverage: Phase 9 UAT exception accept — test-after default OK. Adversarial deep checks: (1) DbInitializer ToDictionary duplicate key risk → PK constraint trên Key, tree.Add chỉ thêm Pe_DuyetNcc_WfView + Pe_DuyetNccPhuongAn_WfView (2 typeCode distinct) → no in-memory dup. (2) Sidebar widen 1280px responsive verified per task spec (288 sidebar + 992 main fit). (3) Plan U revert clean — 0 remaining truncate class outside Plan AA comments. (4) Mig drift schema: column existed Mig 25, no new mig needed. 2 SaveChangesAsync non-atomic giữa menu seed + label backfill (pre-existing, OUT scope Plan AA). Comment quality: Plan AA marker rõ ràng 8+ sites, no TODO/FIXME zombie. TypeScript: `FlagCell` indexed-access type clever từ Pick 7 keys union — TS happy compile clean. Recommendations defer: (a) enforce admin/non-admin policy filter (current GET cho phép user pass isUserSelectable=false — low risk, audit follow-up); (b) MenuKeys.All[] không cover dynamic Pe_*_WfView nên Admin role không auto grant — OK vì admin dùng fe-admin Designer, NOTE để future audit khi admin cần inspect user-side matrix view. Cumulative state unchanged: 31 mig, 111 test, 47 gotcha. Smart Friend guard active — KHÔNG lower bar (3 minor risk noted defer follow-up, không block commit). - **2026-05-15 (S23 t4-t11 cumulative em main self-review — Plan N+O+P+Q+R+S+T+U, no Reviewer spawn):** 8 plan consecutive em main self-review per UAT mode (`feedback_uat_skip_verify` rule — em main verify build + test + npm build mỗi chunk). Key validations cumulative: **Plan N** GetPe handler `PurchaseEvaluationFeatures.cs:765` per-NV `ApproverUserId` discriminator + admin fallback row đầu. **Plan O** 4 lookup sites cascade fix (`EnsureCanRejectV2Async:201` + `ApplyReturnModeAsync:248` + `EnsureEditableForDetailsAsync:72` + `AdjustBudgetCommandHandler:311`) — pattern uniform Plan N, +3 regression test `PurchaseEvaluationPerNvLookupRegressionTests.cs`. **Plan P** Controller `TransitionPeBody:267` record +3 fields mirror `TransitionPurchaseEvaluationCommand` schema — root cause 2 ngày prod bug F1+F2 wire fail. **Plan Q** FE banner mx-5 inset gap fix (CSS layout polish mirror 2 app). **Plan R+S+T5** destructive sqlcmd cleanup prod ~720 rows wiped cumulative + Plan F precedent avoid được (V1 active workflow giữ nguyên → BE healthy startup). **Plan T** DbInitializer `DemoSeed:Disabled` flag config — disable 5 demo seed methods (Workflow V1 + PE V1 + Demo Contracts + Demo PE + Sample V2). **Plan U** FE sidebar truncate + tooltip 2 app mirror — handle long DisplayLabel (Mig 27 admin custom). Anti-patterns observed: (1) **Plan N point 9 chỉ catch 1/5 sites** — em main + Investigator spawn miss 4 sites khác → Plan O cascade fix. Lesson: grep ENUMERATE TẤT CẢ lookup sites cùng pattern (KHÔNG fix theo bug report mỗi lần). (2) **Plan O caveat #1 surfaced Plan P pre-existing bug** — CICD Monitor catch Controller body record drop trong Stage 4c verify wire — pattern "verify cross-stack body↔command count match". (3) **DbInitializer auto re-seed** loop — Plan R+S clean → IIS recycle → re-seed loop. Plan T flag fix root cause. Pattern reusable cross-project: refactor schema 1-row-per-role MUST grep enum lookup sites + Controller body record MUST mirror Command record fields. Cumulative state: 111 test (+7 vs 104 baseline pre-Plan M), 31 mig (no new), 47 gotcha unchanged, `feedback_per_nv_permission_scope.md` reinforced 5 lookup sites enum + 9 wire surface points + Plan P caveat → 10 surface points. Smart Friend guard still active for future spawn. - **2026-05-15 (S23 t3 Plan M cumulative review, spawn):** Pre-push adversarial verify 3 commits local `c2afef2..508b17a..4dd6f9c` Plan M F1 edge case Bước 1 + Phase=TraLai display rename. Diff cumulative: 26 LOC BE (Service.cs:287-333) + 116 LOC test (1 file, +2 test Fact extend SeedWorkflowAsync helper +2 params optional) + 8 LOC FE (4 file × 2 LOC mirror admin+user). **Verdict: PASS** — wire BE M1 verified hot path 287-333 OneLevel+OneStep edge case replace `Phase=TraLai+clear pointer+return` with `Set pointer (0,1) + summary "không lùi được" → fallthrough SLA reset line 364 → Phase=ChoDuyet preserved from pre-call state (entry guard 75-81 require ChoDuyet để Reject decision)`. ApplyReturnModeAsync caller line 94-100 truyền `evaluation.Phase` (now ChoDuyet) vào LogTransitionAsync → Summary="Chuyển phase ChoDuyet → ChoDuyet" + ContextNote contain "không lùi được" (matches test assert ContextNote.Contain). Drafter mode line 268-275 GIỮ Phase=TraLai semantic (unchanged). Assignee line 335-360 throw nếu không match unchanged. F2 ApproveV2Async + F3 EnsureEditableForDetailsAsync + F4 AdjustBudgetCommand handler — UNCHANGED. Schema integrity: 0 migration mới, Phase enum TraLai=98 còn dùng cho Drafter mode + display label rename only. Security: Admin bypass logic line 252-265 + Reject guard line 81 EnsureCanRejectV2Async + non-Approver block — preserved. Code quality: dotnet build PASS 0 err 2 warn (DocxRenderer pre-existing), dotnet test 106/106 PASS (58 Domain + 48 Infra, +2 từ 104 baseline), npm build admin+user PASS 0 TS err (chỉ chunk size warn pre-existing), no `--no-verify`. Test coverage: 2 Fact mới `ApplyReturnMode_OneLevel_AtStep1Level1_ResetsToBuoc1Cap1_KeepsChoDuyet` + `ApplyReturnMode_OneStep_AtStep1_ResetsToBuoc1Cap1_KeepsChoDuyet` cover OneLevel Step1Lv1 + OneStep Step1Lv2→reset. Assert đủ Phase=ChoDuyet + pointer (0,1) + SLA NotNull + ContextNote "không lùi được". Helper extend +2 params backward compat OK (default false). K7 cascade NO regression — 3 `ApproveV2_SkipToFinal_*` xanh (M1 chỉ đụng F1 ApplyReturnModeAsync, không động F2 ApproveV2Async). Mirror 2 FE app (§3.9): purchaseEvaluation.ts admin+user identical (98:'Cần chỉnh sửa lại' + PeDisplayStatus.TraLai:'Cần chỉnh sửa lại'), PeWorkflowPanel.tsx admin+user identical (2 inline literal "Phase → ..." + "Phiếu sẽ về ..." rename). Anti-fiddle: scope drift 0% — 8 LOC FE đúng spec rename Phase=TraLai display only. Anti-pattern guard: **(1) Stale narrative comment Service.cs:288-289 + 327-328** UPDATED rõ "Plan M S23 t3 — KHÔNG fallback Drafter, phiếu giữ đang duyệt" — không zombie. **(2) Audit log consistency** test+code match "không lùi được" exact. **(3) Backward compat** phiếu UAT prod đang Phase=TraLai do logic cũ — Drafter resume từ TraLai vẫn work line 105-132 (entry point `fromPhase==TraLai → targetPhase==ChoDuyet`). **Minor issues (non-block, recommend fix sau):** **(4) Inconsistent UX literal "Trả lại"** còn ở 8 user-facing locations chưa rename (decision design): PeListPanel.tsx:112 "Bản nháp + Trả lại" filter label, PeWorkflowPanel.tsx:270 button "← Trả lại", 272 tooltip "(Duyệt / Trả lại / Từ chối)", 315 "← Trả lại Drafter sửa", 342 "Chọn cách Trả lại", PeDetailTabs.tsx:152 "chỉ Bản nháp / Trả lại mới sửa", 287 "(trừ khi approver Trả lại)", ApprovalWorkflowsV2Page.tsx:639 "(Trả lại / Edit Section 2 / ...)" — phân biệt **action verb** "Trả lại" (button approver click) vs **phase result label** "Cần chỉnh sửa lại" (Phase=TraLai display in dropdown/badge); spec M3 narrow scope chỉ rename phase result label OK. Em main quyết: giữ action verb hay rename hết. **(5) Inconsistent across module** contracts.ts:29 + budget.ts:20 vẫn `98:'Trả lại'` — KHÔNG trong scope Plan M (PE-only) nhưng inconsistent giữa 3 module nếu Contract/Budget có Phase 98 — bro nếu deploy chung sẽ noticeable. Recommendation: SAFE to push 3 commit Plan M; consider follow-up chunk M4 (optional) rename 5 literal user-facing trong PeListPanel + PeWorkflowPanel + PeDetailTabs để consistent UX semantic mới. Smart Friend guard active. - **2026-05-14 (S23 t1 Plan K1+K2 cumulative review, spawn):** Pre-K3 adversarial verify Mig 31 schema swap + Service Approver F2 branch. Diff scope: 11 BE files +4093/-83 LOC (Mig Designer 3938 lines dominate). 3 commits chuỗi `eb106f2..56868bf..db66253..364aef6` — pre-A slot label refactor + K1 Domain/Mig/Snapshot/sentinel patches + K2 DTO+Service Approver branch. **Verdict: PASS với 2 Major + 2 Minor issues** — K3 OK proceed nhưng K5 endpoint cleanup nên ưu tiên trước K7 test fix. Wire claim verify: Approver F2 branch placed ĐÚNG vị trí (line 477 AFTER UPSERT opinion line 441-468 + BEFORE advance pointer line 502) — opinion sẽ ghi trước skip terminal, audit log đầy đủ context Bước/Cấp. ApproveV1LegacyAsync skipToFinal guard tại CALLER (line 147-149 trong TransitionAsync branch) thay vì callee — pattern OK, V1 method giữ nguyên signature legacy. Schema sqlcmd verify Dev: 7 Allow* columns ApprovalWorkflowLevels (AllowApproverEditBudget/EditDetails/SkipToFinal/ReturnOneLevel/OneStep/ToAssignee/ToDrafter) + Users.AllowDrafterSkipToFinal dropped (count=0). Snapshot regen clean. EF config HasDefaultValue(false) wire. Mig 31 Up() manual reorder ADD→DROP correct per memory `feedback_ef_migration_backfill_reorder`. **Major issues caught** (Smart Friend guard active — KHÔNG để pass): (1) **Orphan UsersController endpoint zombie** — K1 sentinel commented "K2 sẽ refactor DTO + drop field" nhưng K2 chỉ refactor PE side, KHÔNG động UsersController.SetAllowDrafterSkipToFinal + UserFeatures.SetUserAllowDrafterSkipToFinalCommand + UserDto field. Endpoint PATCH `/api/users/{id}/allow-skip-final` vẫn live nhưng silent NoOp (Task.CompletedTask), admin UI tick → BE swallow → confusion UX. Cần K5 endpoint cleanup chunk (per spec). (2) **Stale Mig 28 comment ApprovalWorkflow.cs:78** — comment cũ "F2 (Drafter skip) đã move sang Users.AllowDrafterSkipToFinal" còn nguyên dù line 107-113 prop AllowApproverSkipToFinal mới. Confuse future dev. **Minor issues:** (3) Comment TransitionPurchaseEvaluationCommand DTO PurchaseEvaluationFeatures.cs:401 "F2 — Drafter skip thẳng Cấp cuối khi trình duyệt" still says Drafter (semantic outdated). (4) ApprovalWorkflowConfiguration.cs:22 stale Mig 28/29 narrative comment chưa note Mig 31. Anti-fiddle audit PASS: K1 18 LOC UserFeatures.cs sentinel patches valid compile-break workaround, K2 4 files within original spec. Anti-pattern reinforced 3×: admin opt-in per slot per-NV (Mig 29 F1+F3 + Mig 30 F4 + Mig 31 F2 — em main lần đầu sai Mig 30 default scope expansion → bro corrected). Production build PASS 0 err 2 warn (DocxRenderer unrelated). Test references K7-pending line 253. No `--no-verify` bypass. Pattern caught: "Transient sentinel pattern" — đặt sentinel + comment commit chunk khác cleanup nhưng chunk đó scope SHIFT → zombie state. Recommend explicit K5 cleanup chunk trước K7 test fix. Cumulative state: 31 mig (+1 Mig 31), 47 gotcha unchanged. Smart Friend guard active. - **2026-05-13 (S22 18:00→21:00, no spawn):** Em main solo self-review S22 — Reviewer KHÔNG spawn per UAT mode `feedback_uat_skip_verify`. Em main verify build clean + test pass + npm build × 2 app mỗi chunk (11 commits cumulative). Key validations: (1) Plan E phân quyền strict V2 — actor.UserId scope in List + Detail, Inbox đã strict từ S17, loose UAT clause `|| ApprovalWorkflowId != null` removed. (2) S22+1 V2 actor scope guard BE helper `EnsureCanRejectV2Async` chặn request forge non-approver PATCH /transitions decision=Reject (mirror FE button disable) — defense-in-depth FE+BE pattern. (3) S22+4 AdjustBudgetCommand handler 3-tier scope (Drafter Nháp/Trả lại + Approver ChoDuyet + Admin) — S22+5 refactor ChoDuyet branch dùng `level.AllowApproverEditBudget` flag (admin opt-in per slot) thay default Approver scope (security scope correction per bro feedback). (4) S22+2 Identity password policy enforced ≥12 chars (reject `User@123456` 11 chars outdated). Anti-patterns observed: (a) Default scope expansion mistake S22+4 → S22+5 fix — KHÔNG default expand permission scope without admin tick (per-NV opt-in pattern Mig 29 lesson reinforced); (b) History display field assumption BudgetAdjustSection initial — em assume `PeDetailBundle.changelogs` exists, FAIL TS2339 — pattern verify type fields trước render; (c) PS 5.1 Vietnamese diacritics gotcha #30 reinforced — script `seed-test-users-prod.ps1` first attempt FAIL parser error, ASCII-only discipline. S22+4 attachment view endpoint + S22+4 budget-adjust endpoint chưa qua live curl verify (defer post-deploy — bro UAT direct). S22+5 Mig 30 applied LocalDB Dev + Design via `dotnet ef database update`. New gotcha discovered: #47 paths-ignore agent-memory gap (recommend add to docs/gotchas.md — pending bro decide). Cumulative state: 104 test (+20), 30 mig (+1 Mig 30), 46 gotcha unchanged (gotcha #47 pending), ~146 endpoints (+3), 33 active users. Smart Friend guard still active for future spawn. - **2026-05-13 (S21 t3-t5, no spawn):** Em main solo verify via dotnet build + npm build × 2 app + dotnet test suite mỗi chunk. Reviewer KHÔNG spawn — em main self-review per UAT mode `feedback_uat_skip_verify` (skip dotnet test mỗi chunk, vẫn build verify). Gotcha #45 fix self-test 3 regression test (test-before §7). S21 t3-t5 push cumulative 12 commits — CICD Monitor verify post-deploy thay vai Reviewer (deploy ship + bundle hash + schema verify). Cumulative state: 84 test, 29 mig, 45 gotcha, 19 memory entries. Pattern saved cho future review focus: per-NV permission audit (Level table vs User table flag), EF migration backfill SQL injection between ADD-DROP order. Smart Friend guard still active for future spawn. - **2026-05-11 (setup):** Reviewer agent initialized. Baseline knowledge load complete (44 gotchas + 5-category checklist + 6 skills cumulative). No reviews performed yet. Awaiting first SendMessage from em main. Smart Friend guard active. --- ## 🔄 Curate trigger - Memory size > 25KB → archive recent entries to `archive/.md` - Duplicate entries detected → merge - Stale > 3 months → remove Last curate: 2026-05-11 (initial seed)