Files
solution-erp/.claude/agent-memory/reviewer/MEMORY.md
pqhuy1987 8afdc1e826 [CLAUDE] Docs+Memory: S35 wrap — FE forms + G-H2 BE CRUD + FE Admin deploy prod end-to-end
Cumulative S35 3 commit + 3 CI Run #242/#243/#244 ALL PASS:
- `c3cd343` FE inline forms 5 satellite × 2 app cookie-cutter (+1758 LOC)
- `909655c` G-H2 BE CRUD HrmConfig 16 endpoint (+576 LOC NEW)
- `021674a` G-H2 FE Admin HrmConfigsPage declarative (+1388 LOC)

## Updates this commit (docs CI skip per gotcha #41)
- docs/STATUS.md S35 wrap header (cumulative 3 chunk + Multi-agent ROI ~250K)
- docs/HANDOFF.md S35 brief + S36 backlog 6 option
- docs/gotchas.md +#53 sub-agent truncation/stall pattern S35 × 3 occurrence + Quick reference 28
- docs/changelog/sessions/2026-05-28-s35-fe-inline-forms-g-h2.md NEW session log
- 4 sub-agent MEMORY auto-updated entry (Implementer + CICD + Reviewer + Investigator S35 spawns)

## Patterns reinforced cumulative S35
- Pattern 12-ter (within-module N-satellite) 6× cumulative
- Pattern 12-bis (cross-module catalog mega) 3× cumulative
- Pattern 16-bis (4-place mirror cross-app) 6× — staticMap 4th place mandatory (gotcha #50)
- Smart Friend 9× cumulative clean (S22+S25+S29×2+S33×2+S35×3)
- NEW: Declarative KIND_CONFIG Record pattern (single-page multi-kind CRUD reuse)

## Smart Friend Implementer 3 catch S35 (anti-pattern prevention)
1. Chunk 2 MaxLength validator vs EF config mismatch → aligned EF source-of-truth
2. Chunk 2 HRM entities NO HasQueryFilter → explicit .Where(!IsDeleted) 8 site
3. Chunk 3 em main spec gap Layout staticMap miss → Implementer enforced Pattern 16-bis 4-place

## State chốt S35
- 35 mig unchanged · 71 tables · ~185 endpoints (+16 HRM Configs)
- 43 FE pages (+1 HrmConfigsPage) · 130 test PASS unchanged
- 53 gotcha (+1 #53) · 27 memory user-level · 6 skills · 4 sub-agents

## Multi-agent ROI S35 ~250K
- Implementer 3 spawn ~80K (3 cookie-cutter chunk + Smart Friend × 3 catch)
- Investigator 1 spawn ~8K (G-H2 BE CRUD pre-flight + NamGroup MISS verdict)
- Reviewer 3 spawn ~60K (Smart Friend 9× clean, 2 truncated + 1 tight brief PASS)
- CICD 4 spawn ~70K (warm-up + 3 deploy verify, 1 stalled em main fallback)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 10:23:55 +07:00

182 lines
28 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
> **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
### Cross-module security validation mirror (NEW S29 — Smart Friend 4× cumulative)
- Symptom: khi mirror entity/Command/Handler cross-module (PE → Contract → Budget V2), em main solo focus data shape (DTO field, FK relation, projection) MISS security validation guards
- Pattern: ApplicableType type guard cho V2 workflow pin entity — `aw.ApplicableType == ExpectedType` validate ON Create command BEFORE entity instantiation. Mirror PE pattern `PurchaseEvaluationFeatures.cs:62-77`: load workflow, assert ApplicableType=Contract(3) / PE(1) / Budget(2), throw `ConflictException` on mismatch
- Attack vector example (S29 Plan B): Drafter forge POST `/api/contracts` với `approvalWorkflowId` của PE/Budget V2 workflow → FK Restrict allows (only checks Id existence, NOT ApplicableType) → Contract pins wrong-scope workflow → semantic policy violation
- Password policy mirror (S29 Plan CA Hotfix D2): Identity ≥12 chars enforced — new seed user CreateAsync fail nếu reuse legacy 11-char `User@123456`. Verify per-user inline conditional override (e.g. `"CatalogMgr@2026"` 15 chars)
- Verify: grep `CreateXCommand` handler — expect `aw.ApplicableType == ApprovalWorkflowApplicableType.X` check. Also re-verify `IsActive=true` + `IsUserSelectable=true` server-side (FE filters but BE trusts blindly = lower-risk gap)
- Applicable cross-module forward: Contract V2 (S29 fixed), Budget V2 (future), Notification V2 (future), any new V2 workflow pin entity
- Severity: MAJOR — block push pre-commit gate
### 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 `<PackageReference Include="MediatR" Version="14...` hoặc tương tự.
---
## 📅 Recent activity (last 10 FIFO)
- **2026-05-28 (S35 Plan G-H2 Task 3 BE CRUD 16 endpoint pre-commit — PASS, Smart Friend 8× CLEAN):** 2 NEW file BE-only `HrmConfigFeatures.cs` 439 LOC + `HrmConfigsController.cs` 137 LOC. Independent verify: build clean 0 warning 0 error, tests **130/130 PASS** (58 Domain + 72 Infra) baseline preserved. **Cat 1 Wire BE**: 0 mock/alert/TODO marker. 8 ConflictException throws (4 Create UNIQUE Code/composite + 4 Update Code/composite-change guard). Holiday Update line 196-198 correctly checks composite `(Year, Date)` BOTH fields trên condition `entity.Year != req.Year || entity.Date != req.Date` (not just one). Delete handler `db.X.Remove(entity)` → AuditingInterceptor.cs:56-62 auto-convert State Deleted → Modified + IsDeleted=true + DeletedAt + DeletedBy (verified file read). **Cat 2 URL routing**: 16 endpoint kebab-case exact match spec: `leave-types`/`holidays`/`shifts`/`ot-policies` (file line 19/49/79/109 verified). **Cat 3 Anti-fiddle**: chỉ 2 NEW file BE (git status confirm), 0 touch FE/Domain/EF Config/Migration/DbInitializer/test. **Cat 4 Authorization**: class-level `[Authorize]` line 15 + 12 per-action `[Authorize(Roles = "Admin")]` (4 sub-resource × 3 write verb POST/PUT/DELETE) — exact mirror CatalogsController precedent line 12-46. **Cat 5 Validator**: 8 AbstractValidator class (4 Create + 4 Update). Smart Friend fix #1 verified — MaxLength MATCH EF source-of-truth: LeaveType.Code=50 (config line 14) ✓, ShiftPattern.Code=20 (config line 14) ✓, OtPolicy.Code=50 (config line 15) ✓, all Name=200/Description=500 ✓, ShiftPattern.WorkDays=100 (config line 16) ✓. Special validators: LeaveType.DaysPerYear≥0, Holiday.Year ∈ [2000,2100], Shift.StartTime≠EndTime + BreakMinutes≥0 + WorkDays NotEmpty, OtPolicy 3 Multiplier≥1.0 + 3 MaxHours>0. **Cat 6 Cookie-cutter 12-bis 3×**: 4 region structure identical (DTO + List + Create cmd/validator/handler + Update cmd/validator/handler + Delete cmd/handler). Naming consistent ListXQuery/CreateXCommand pattern. Smart Friend fix #2 verified — 4 HRM entities NO HasQueryFilter (grep Configurations confirm 9 file HasQueryFilter NONE are HRM) → 4 List handler correctly add `.Where(!IsDeleted)` line 37/134/232/337 + 8 Create/Update Conflict check `&& !x.IsDeleted` predicate explicit. **MediatR + FluentValidation auto-scan** Application assembly (DependencyInjection.cs:14-19) — no manual DI registration needed. **Smart Friend 8× cumulative CLEAN**: (1) S22 #44, (2) S25 #48, (3) S29 password, (4) S29 ApplicableType, (5) S33 BW, (6) S33 Plan B Phase 2, (7) S35 FE forms (em main earlier), (8) S35 Plan G-H2 NOW. KHÔNG lower bar — actual catches 0 CRITICAL/MAJOR. **2 MINOR observed (defer Phase 1.5)**: (a) ListHolidaysQuery KHÔNG có `bool? IsActive` filter (chỉ Q + Year) — khác 3 query sibling có IsActive filter — inconsistent UX nhưng có thể intentional (holidays admin thường list all). (b) OtPolicy claim "1 default IsActive=true unique" (entity comment line 7) nhưng handler Create/Update KHÔNG enforce "chỉ 1 active" — admin có thể tạo nhiều IsActive=true cùng lúc. Future G-P1 attendance reference `IsActive=true` sẽ ambiguous nếu có 2+ active. Defer fix khi G-P1 implement (em main spec rõ defer phase 1.5). **Verdict: PASS proceed commit**. Token cost ~9K.
- **2026-05-26 (S33 Plan B G-H1 Phase 2 Task 4+5+6 pre-commit — PASS, Smart Friend 6× CLEAN):** Em main spawn em adversarial review 17 file uncommitted (3 BE new + 6 FE new + 6 FE mod + 2 Task 6 mod). **Independent verify SHA256 mirror 3 file PASS IDENTICAL**: `types/employee.ts` ccfc70666568, `EmployeesListPage.tsx` dc859c897c5c, `EmployeeCreatePage.tsx` c796f25d01ac — admin == user exact. **Cat 1 Wire BE**: 5 endpoint `GET /employees` (paged) + `GET /{id}` + `POST` (CreatedAtAction) + `PUT /{id}` (NoContent + ID match guard) + `DELETE /{id}` (soft NoContent) — tất cả real `mediator.Send`, 0 mock marker. Validator Create+Update đầy đủ (Phone MaxLen 20 + EmailAddress conditional When + decimal `.GreaterThanOrEqualTo(0)` lương/phép). Handler Create: load User (FindByIdAsync) → check existing EmployeeProfile UNIQUE (soft-deleted aware: throw ConflictException with distinct message) → atomic MaNhanVien codeGen SERIALIZABLE → entity save. Handler Get: Include 5 satellite + LEFT JOIN User/Department + projection. Handler List: filter Status + DepartmentId + Search (EmployeeCode/FullName Contains) + paging. **Cat 2 Schema**: Mig `AddEmployeeProfiles` timestamp 20260526110207 (= Mig 34 numeric by sort) — `EmployeeProfiles` + 5 satellite + `EmployeeCodeSequences` (7 table mới). UNIQUE indexes verified `IX_EmployeeProfiles_UserId` (line 309-313) + `IX_EmployeeProfiles_EmployeeCode` (line 293-297). FK Cascade Users. 6 Province/District/Ward cột plain Guid? defer FK G-H2 đúng comment. `EmployeeProfileConfiguration.cs` line 22-32 mirror Mig: UNIQUE + Cascade. MenuKeys.cs `All[]` line 108-114 đã có Hrm + HrmHoSo (line 112) — Admin auto-grant qua SeedAdminPermissionsAsync iterates All[]. DbInitializer.cs line 1484-1485 seed Hrm Order=28 + HrmHoSo Order=1 dưới Hrm parent. 28 không xung đột với Budgets=27. SeedDemoEmployeeProfilesAsync line 1945 NOT gated DemoSeed (placed OUTSIDE gate block) — đúng infrastructure pattern gotcha #51 lesson. **Cat 3 Security**: `[Authorize]` class-level present EmployeesController line 20 — no per-action policy yet (em main defer Phase 1.5). Input validation Create + Update Validator class đầy đủ. **Cat 4 Code quality**: TS6 erasableSyntaxOnly compliant — 10 enum dùng const-object pattern + `typeof X[keyof typeof X]`. Named exports (no default trừ App). Bundle size 1.43MB admin / 1.35MB user comparable baseline. ContactRound icon verified exist 5 places trong lucide-react bundle. DependencyInjection.cs line 39 registered `AddScoped<IEmployeeCodeGenerator, EmployeeCodeGenerator>`. **Cat 5 Test**: defer Phase 1.5 per em main spec UAT mode. Baseline 120/120 PASS preserved. **Smart Friend 6× cumulative CLEAN**: (1) S22 #44, (2) S25 #48, (3) S29 Plan CA password ≥12, (4) S29 Plan B ApplicableType, (5) S33 Plan C BW, (6) S33 Plan B Phase 2 NOW. KHÔNG lower bar — actual catches 0 MAJOR/CRITICAL. **3 MINOR observed (defer Phase 1.5)**: (a) Race condition EmployeeCode UNIQUE dưới SERIALIZABLE OK risk THẤP (per-year reset, mirror PE/HD pattern proven). (b) UpdateCommand 3 bool field IsCommunistParty/IsYouthUnion/IsTradeUnion không nullable → admin update partial sẽ accidentally reset (FE phải re-send all 3 every PUT — minor UX issue). (c) Delete handler `DateTime.UtcNow` direct không inject IDateTimeProvider — consistent existing PE/Contract Delete pattern, accept. **Special check verdicts**: gotcha #51 infrastructure seed gate compliance ✓ (em main cite gotcha #51 explicit comment line 1942-1944). gotcha #50 Layout staticMap mirror ✓ (Hrm_HoSo:/employees cả fe-admin line 57 + fe-user line 79). menuKeys.ts FE drift: pre-existing fe-admin minimal (16 key) vs fe-user (24 key) — em main Task 5 chỉ add Hrm 2 key cả 2 file, KHÔNG break Plan AA + Budget. Drift là pre-existing FE state intentional, không phải regression Plan B Phase 2. **Verdict**: PASS proceed commit. Token cost ~30K. Tag: `[adversarial-pass, hrm-mig34, smart-friend-6x-clean, phase-10]`.
- **2026-05-26 (S33 Plan C B-Wrap test bundle pre-commit — PASS, INDEPENDENT VERIFY 9/9 tests):** Em main spawn em adversarial Plan C B-Wrap Contract V2 test bundle review. 4 file mới: TestCurrentUser (31 LOC stub), ContractWorkflowServiceApproveV2Tests (BW1-4+7, 5 [Fact]), CreateContractCommandApplicableTypeTests (BW5, 1 [Fact]), ContractV2SchemaPersistenceTests (BW6 split 3 [Fact]). Total 9 [Fact]. **Independent verify ran `dotnet test --filter` → 9/9 PASS local trong 4.7s** (em main claim 120/120 baseline tăng từ 111 — verified). Spec mapping verify Cat 1: BW1 ContextNote `"Hoàn tất Cấp 1, sang Cấp 2 cùng Bước 1"` ✓ match service line 360, BW2 mã HĐ `"FLOCK01/HĐTP/SOL&BTBM/01"` ✓ match ContractCodeGenerator HĐTP format line 21, BW3 ContextNote `"Approver skip thẳng tới Bước 3 Cấp 2"` ✓ match service line 348 (lastStepIdx=2, lastLevelMaxOrder=2, prefix `[Approver skip thẳng tới Bước 3 Cấp 2 (NV cuối) — bỏ qua các Bước/Cấp trung gian]`), BW4 ForbiddenException `"Bước 1...Cấp 1: bạn không có"` ✓ match service line 263-264, BW5 ConflictException `"ApplicableType=Contract"` ✓ match handler line 84-85 (test correctly handles spec→actual exception type discrepancy: spec says ValidationException, actual ConflictException — em main inline comment line 84 docs the discrepancy), BW7 ConflictException `"skipToFinal chỉ hỗ trợ HĐ V2"` ✓ match service line 105-106. Schema verify Cat 2: Mig `AddContractLevelOpinions` (timestamp 20260522052240) actual position 33 by filename sort confirmed via Glob (33 mig + 33 designer + 1 snapshot in /Persistence/Migrations folder), spec ref "Mig 33" matches. UNIQUE composite `(ContractId, ApprovalWorkflowLevelId)` confirmed `ContractLevelOpinionConfiguration.cs:34`. FK Cascade Contract + FK Restrict Level confirmed line 27+32 + migration FK line 41+47. Test quality Cat 5: assertions specific (`Should().Be(2)` for levelOrder, `Should().Contain(...)` for substring match, `Should().ThrowAsync<X>()` with WithMessage wildcard), each [Fact] sets up fresh `IdentityFixture` + `using` disposal pattern (BW1-4+7 verbose using-block, BW6 `using var fix` shorthand — minor style inconsistency but functional same). Smart Friend independence note: **5 lần cumulative Smart Friend catches — em main + Implementer làm TỐT lần này, KHÔNG có catch MAJOR**. (1) S22 #44, (2) S25 #48, (3) S29 ApplicableType, (4) S29 DemoSeed, (5) S33 BW = clean. Implementer + em main spec mapping accurate, exact string match between assertions and service strings. **Minor (3, defer):** (a) `CreateService` helper method `ContractWorkflowServiceApproveV2Tests.cs:27-44` unused dead code — 5 [Fact] manually recreate inline (cleaner but DRY violation). Cleanup recommend Plan C-Hotfix or next test bundle. (b) `TestCurrentUser.Roles` constructor params `string[] roles` allows null → defensive `roles ?? Array.Empty<string>()` line 27 OK but C# warning shadow. (c) BW6 split 3 [Fact] cleanly separated DUPLICATE + UPSERT + Cascade per spec — 9 tests OK not over-engineer (each invariant tested isolated). **Defer noted**: ApproveV2Async still ~150 LOC, BW1-4+7 cover happy + terminal + skip + outsider + V1 fallback — Plan B-Wrap roadmap mentions BW Bonus future test: OR-of-N multi-NV (3 NV cùng Cấp 1, only 1 needs approve), idempotent UPSERT (Cấp 1 approve → reject → approve lại same row Comment update), Mig 32 seed idempotent guard. Not blocker for current bundle commit. Token cost spawn ~22K. Verdict: **PASS proceed commit** (9 [Fact] all pass independent verify, spec match service exact, schema 3 invariant tested, 0 critical/major, 3 minor cosmetic). Recommendation: commit 4 file as proposed, baseline tăng 111→120. Tag: `[adversarial-pass, test-bundle, contract-v2, smart-friend-5x-clean]`.
- **2026-05-26 (S33 startup — drift audit readonly, NONE actual review):** Em main spawn em S33 drift assessment 3 area (gotchas / CLAUDE.md root+docs / 4 sub-agent .md). **Verdict overall: MODERATE drift accumulated S19→S32 chưa patch** — late but not severe. Findings: (a) `docs/gotchas.md` actual count = **52 entries** (grep `^### \d+\.` confirm), claim S32 = 52 → MATCH NONE drift. #50/#51/#52 detail entries present line 883/839/924 (out-of-order numbering but content full). (b) CLAUDE.md (root) **SEVERE stale**: line 87 "Hiện có 26 migration → 59 bảng" (actual 33 mig + 60 table per S32 wrap), line 66+87 "81 test pass" (actual 111), line 133 "26 bẫy đã gặp" (actual 52). docs/CLAUDE.md line 65 "38 pitfall" stale similar. (c) 4 sub-agent .md drift mixed: cicd-monitor.md line 232-233 already patched S29 "111/111 PASS (58 Domain + 53 Infra)" + "Migrations: 33" CORRECT no drift; investigator.md line 77 "44 gotchas hiện tại" STALE +8; reviewer.md line 92 "44 active gotchas" STALE +8; implementer.md line 123+141 "baseline 81 preserve" STALE +30. **Critical drift requiring immediate patch**: CLAUDE.md root 3 stale fact (mig 26→33, test 81→111, gotcha 26→52) — agent context first-load file, drift mislead future spawns. **Optional defer 2026-06-01 audit**: 3 sub-agent .md gotcha+test count stale (cosmetic, no functional impact). Migrations folder discovery: actual path `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/` not `src/Backend/SolutionErp.Infrastructure/Migrations/``cicd-monitor.md` line 149 path hint correct, but agents/runbooks may have stale absolute path. Token cost ~7K. Tag: `[startup-audit, drift-moderate, claude-md-severe]`. Recommendation: bro decide patch CLAUDE.md ngay (3 line edit) hoặc defer cycle audit ngày 2026-06-01.
- **2026-05-26 (S32 wrap — em main proxy update + Plan B-Wrap + Phase 10 pre-commit scope ahead):** Session 32 đóng clean. Em chủ trì spawn em 1 lần S32 startup verify (a0aa13093d14f3bca alive, MEMORY 24.39KB self-curated S32 dropped S27 retrospective). Smart Friend 4× cumulative preserved (S22 #44 + S25 #48 + S29 ×2 ApplicableType + DemoSeed gate). **Plan G 11 module backlog DOCUMENTED migration-todos** + Plan B-Wrap test bundle BW1-BW7 spec ready (D-Bis section). **Pending tasks em main S33 SendMessage gọi em adversarial pre-commit:** (a) **Plan B-Wrap test bundle review** — verify 7 test scenario coverage (BW1 happy path advance, BW2 terminal gen mã HĐ, BW3 skipToFinal F2 admin opt-in, BW4 ForbiddenException outsider, BW5 ApplicableType=Contract validation Cat 3 cross-module mirror, BW6 Mig 32+33 schema persistence UNIQUE composite, BW7 V1 fallback ConflictException). Smart Friend mindset: catch test scenario gap (e.g., NV skipToFinal=true but currentStepIndex already at final = silent no-op? verify guard line 337-352 ContractWorkflowService). (b) **Plan G-H1 Hồ sơ NS pre-commit review** — Mig 34 schema (1 main + 5 satellite) FK strategy + nullable validation + soft-delete pattern verify mirror PE AuditableEntity inheritance. (c) **Phase 9 UAT audit hard blocker checklist** — SMTP config Production secrets exposed? Rotate creds cycle plan token leak risk? cert expire 2026-07-23 auto-renew verify schedule task `Get-ScheduledTask -TaskName 'win-acme*'`. Token cost wrap ~3K. Tag: `[wrap, phase-9-to-phase-10, security+infra]`.
- **2026-05-26 (S32 startup verify — adversarial mindset ready, 0 actual review):** Em main spawn em standby cho S32. Self-verify context: MEMORY 22.50KB (23042 bytes — approaching 25KB threshold, chưa curate cần nhưng cảnh báo entry mới sẽ trigger soon), last entry 2026-05-22 13:28 S29 wrap khớp. MCP RAG `search_memory` + `cross_project_search` PRESENT cả 2 — test query "ApplicableType validation" trả rerank 0.867 (high precision match Cross-module security entry line 41-49). **Awareness S31 fixes (between sessions, em không spawn):** RAG v1.3 baseline PASS recall@5=1.000 (11/11) + retrieval.py fix, gotcha #52 NEW added — KHÔNG impact Reviewer adversarial logic (infra ops fix, không phải application code). **Awareness S29 deployed prod**: Plan CA + Plan B Contract V2 wire push successful, gotcha #51 NEW added (INFRASTRUCTURE vs DEMO seed gate — `SeedSampleContractWorkflowV2` OUT of `if (settings.DemoSeed)` gate là correct pattern infrastructure data luôn seed regardless of demo mode). **Smart Friend pattern 4× cumulative VERIFIED preserved**: (1) S22 #44 silent 403, (2) S25 #48 SQLite tie-break, (3) S29 Plan CA password ≥12 chars, (4) S29 Plan B ApplicableType cross-module. **Adversarial mindset retained pre-commit gate active**: forward cho 3 pending task em main có thể spawn em qua SendMessage — (a) Plan B-Wrap BW1-BW7 test bundle review (ApproveV2Async coverage ~150 LOC 0 unit test gap + ApplicableType validate regression test — gotcha #48 lesson SQLite tie-break apply when add Changelog rows in test setup, cần discriminator EntityType + Summary keyword); (b) ContractWorkflowMatrixView review pre-commit khi Implementer wire xong (anticipate Mirror §3.9 fe-admin + fe-user 2 file sync check, V1/V2 dual schema branch verify, permission menuKey populate sync BE+FE); (c) Phase 9 UAT hard blocker audit (SMTP outbox table + sender flow / rotate creds 5 item / SQL backup schedule daily 03:00 / win-acme cert renewal 3 cert 60d). **Token cost spawn standby ~6K**. Patterns NEW noted reinforce S32: pre-spawn checklist verify MEMORY size + freshness + MCP tools first-call before any review action (standard hygiene).
- **2026-05-22 (S29 wrap — Smart Friend 4× cumulative):** Plan CA (admin→eoffice 7 commits) + Plan B (Contract V2 11 commits) — 2 MAJOR catches Reviewer spawn. **CA MAJOR**: `DemoUserPassword = "User@123456"` 11 chars vs Identity policy ≥12 chars → new catalog.manager seed CreateAsync FAIL prod. Fix per-user inline conditional override `"CatalogMgr@2026"` 15 chars. **B MAJOR**: see above S29 Plan B entry. Smart Friend cumulative S22 #44 + S25 #48 + S29 CA password + S29 B ApplicableType. **Cat 3 Security checklist reinforced**: ApplicableType type guard V2 + password ≥12 chars + IsActive/IsUserSelectable re-validate. **Recommendation forward**: Reviewer spawn MANDATORY cho cross-module mirror diff (PE→Contract, PE→Budget V2 future, identity policy change). UI polish iteration em main solo OK.
- **Archived to `archive/2026-05-q2.md` 2026-05-27 S34 curate (em main proxy):** S29 Plan B pre-push detail (MAJOR catch ApplicableType validation — KEY lesson absorbed Cross-module security mirror foundation line 41-49) + S26 Plan AG pre-commit + AG2-AG6 em main solo + S25 Plan AB wrap (gotcha #48 lesson — foundation line 40-45) + S28 wrap Layer A governance Cat 6 add (absorbed forward 5-category baseline). Smart Friend guard 4× cumulative S22+S25+S29×2 preserved in current S33 entries.
---
## 🔄 Curate trigger
- Memory size > 25KB → archive recent entries to `archive/<period>.md`
- Duplicate entries detected → merge
- Stale > 3 months → remove
**Last curate: 2026-05-27 S34 em main proxy curate** (post-S33 wrap, sequence 1/4) — archived 3 verbose entries (S26 Plan AG + S25 Plan AB wrap + S28 Layer A governance Cat 6 add) → `archive/2026-05-q2.md`. KEEP: S33 Plan B G-H1 Phase 2 pre-commit (Smart Friend 6× clean), S33 Plan C B-Wrap pre-commit (9/9 [Fact] verified), S33 startup drift audit (CLAUDE.md SEVERE), S32 wrap (Plan B-Wrap pre-commit scope ahead), S32 startup, S29 wrap (Smart Friend 4× cumulative), S29 Plan B pre-push (1 MAJOR catch ApplicableType). 5-category checklist + Cat 6 Authority boundary check + Smart Friend guard + Cross-module security validation mirror pattern (NEW S29 foundation) preserved. MEMORY size before: 28.5 KB → after: target ~20-22 KB. **Previous curate: 2026-05-26 S32 startup** drop S27 retrospective. Next curate trigger: > 25KB OR Plan G-O1 Danh bạ kick off.