# Investigator Agent — Persistent Memory

> **Persistent diary cross-session.** Auto-injected first 200 lines / 25KB at spawn.
> Update BEFORE every stop. Curate when > 25KB.

---

## 🎯 Role baseline

Read-only research + audit for SOLUTION_ERP codebase. Tools: Read, Grep, Glob, Bash, WebFetch, WebSearch. Output: concise structured findings under 500 words.

---

## 📋 Patterns proven (cross-session)

### Pattern: Smoke verify catalog SOLUTION_ERP
- Bearer auth từ `https://api.solutions.com.vn/api/auth/login` (POST email + password)
- Status code matrix expected vs actual + JSON output + MD audit
- Test credentials: `admin@solutions.com.vn / Admin@123456` (full) OR `nv.test@solutions.com.vn / TestUser@123456` (Drafter UAT scope)

### Pattern: Schema scan via sqlcmd
```bash
# LocalDB Dev (runtime — primary)
sqlcmd -S "(localdb)\MSSQLLocalDB" -d SolutionErp_Dev -Q "..."

# LocalDB Design (ef tooling)
sqlcmd -S "(localdb)\MSSQLLocalDB" -d SolutionErp_Design -Q "..."

# Production (qua SSH vietreport-vps)
ssh vietreport-vps "sqlcmd -S .\SQLEXPRESS -d SolutionErp -U vrapp -P '...' -Q '...'"
```
Common queries: `sys.columns`, `sys.triggers`, `__EFMigrationsHistory`, `COUNT(*)`, `sys.indexes`.

**Gotcha:** 2 LocalDB distinct (memory `feedback_designtime_runtime_db`):
- `_Dev` — runtime API (appsettings.Development.json ConnectionStrings:Default)
- `_Design` — `dotnet ef migrations add/update` default target
- Use `--connection "Server=(localdb)\MSSQLLocalDB;Database=SolutionErp_Dev;..."` override khi cần Dev specifically.

### Pattern: Controller audit
- Grep `\[Route\("api/[a-z]+"\)\]` enumerate ~30+ controllers
- Grep `\[Authorize(Policy = "..."` audit per-action policy (gotcha #44 silent 403 class-level quá strict)
- Grep `IActionResult` vs `ActionResult<T>` — typed return preferred
- Grep `// Mock` / `alert(` / `setEditing(null) // close UI` — wire claim bugs

### Pattern: Memory cross-reference
19 memory entries tại `C:\Users\pqhuy\.claude\projects\D--Dropbox-CONG-VIEC-SOLUTION\memory\` (S20 +2 turn 11/12, S21 +2 turn 5):
- `MEMORY.md` — index
- `project_solution_erp.md` — cumulative narrative S1-S17
- `feedback_per_chunk_commit.md` — 5-chunk A-E discipline
- `feedback_uat_skip_verify.md` — Phase 9 skip test rule
- `feedback_drastic_refactor_scope.md` — defer dedicated session
- `feedback_audit_reuse_before_clone.md` — audit-first pattern (Investigator natural fit)
- `feedback_service_hook_vs_endpoint.md` — derived state hook pattern
- `feedback_n_stage_workflow_pattern.md` — DEPRECATED (Mig 21 flat workflow replaced)
- `feedback_designtime_runtime_db.md` — 2 LocalDB distinct
- `feedback_md_compact_narrative.md` — §6.5 KEEP narrative rule
- `feedback_unittest_timing.md` — §7 test timing
- `feedback_cron_monthly_limitation.md` — Cron SDK 7-day expire
- `feedback_user_manual_style.md` — non-tech docs style
- `feedback_node_cicd.md` — Node 20.x pin
- `feedback_responsive_laptop_breakpoint.md` — 4-tầng responsive pattern (S20 t11)
- `feedback_multi_agent_setup.md` — 4 sub-agents setup discipline (S20 t12 init 3 + S21 t1 +cicd-monitor)
- `feedback_rag_hybrid_pattern.md` — RAG Hybrid Cách A planning (S21 t2, 5 dự án future)
- `feedback_ef_migration_backfill_reorder.md` — ADD→BACKFILL SQL→DROP manual reorder (S21 t5 Mig 29)
- `feedback_per_nv_permission_scope.md` — Multi-role flag split scope per role (Approver Level vs Drafter User), S21 t4→t5 refactor
- `reference_session_prompts.md` — canonical session start template

### Pattern: External research priority sources
- `anthropic.com/engineering/` (official patterns)
- `cognition.ai/blog/` (Devin lessons)
- `philschmid.de` + `eugeneyan.com` + `hamel.dev` (senior engineers)
- `learn.microsoft.com/en-us/aspnet/core/` (.NET 10 official)
- `tanstack.com/query/latest` (TanStack Query)

---

## ⚠️ Anti-patterns observed

- ❌ Skip MEMORY.md update before stop — lose knowledge tài sản
- ❌ Vague conclusion "seems like" / "probably" — em main rejects
- ❌ Missing file:line refs — non-verifiable evidence
- ❌ Exceed 500 words — em main reads too slow
- ❌ Scope drift to architectural recommendations — em main decides, not me

---

## 🧠 SOLUTION_ERP context essentials (auto-load)

- **DB Dev:** `SolutionErp_Dev` LocalDB (59 tables / 30 migrations / Mig 30 latest `AddAllowApproverEditBudgetToLevels`)
- **DB Design:** `SolutionErp_Design` (ef tooling distinct)
- **DB Prod:** `.\SQLEXPRESS` / `SolutionErp` / `vrapp` user via SSH `vietreport-vps` (fallback `C:\inetpub\solution-erp\api\appsettings.Production.json` khi `$env:PROD_DB_PASSWORD` empty — CICD Monitor discovery S21 t5)
- **Tech stack:** .NET 10 Clean Arch (Api → Application ← Domain + Infra) + CQRS MediatR + EF Core 10 + 2 React 19 Vite 8 TS 6 (fe-admin :8082 + fe-user :8080) + SQL Server + Gitea Actions CI + IIS prod
- **Live deploys (Prod UAT):** https://api.solutions.com.vn · https://admin.solutions.com.vn · https://eoffice.solutions.com.vn
- **Gitea remote:** https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp
- **Gitea Actions API:** path `/api/v1/repos/.../actions/tasks` (NOT `/actions/runs` — 404). Cache stale ~2 min (gotcha #46) — cross-check VPS file mtime
- **SSH VPS:** `ssh vietreport-vps` (config `~/.ssh/config` user=Administrator key=id_ed25519)
- **Gotchas active:** 46 (reference `docs/gotchas.md`)
- **Tests baseline:** 104 PASS (+20 S22: 5 reg #44 Authorize policy + 7 ReturnMode + 7 Guard + 1 V2 actor scope reject) — Phase 9 UAT skip per chunk (memory `feedback_uat_skip_verify`)
- **Endpoints:** ~146 (+3 S22: PATCH /users/{id}/allow-skip-final + PATCH /pe/{id}/budget-adjust + GET /pe/{id}/attachments/{attId}/view)
- **Users:** 30 demo + 33 active prod (13 cũ + 20 mới S22+2 role-based: act/bod/equ/fin/hra/pm/qs prefix `.nv/.pp/.tp` + bod.1/2). Password policy ≥12 chars (S22+2 discovery, `TestUser@2026`)
- **API auth response:** `accessToken` + `refreshToken` + `user` (S22+2, NOT `token`)
- **Master HEAD reference:** check via `git log -1 --format='%H'`
- **6 skills:** `contract-workflow` · `permission-matrix` · `form-engine` · `ef-core-migration` · `dependency-audit-erp` · `iis-deploy-runbook`

---

## 🔄 Active workflow schemas (V1 + V2 coexist post-Session 17)

- **V1 Mig 21 flat workflow** — `WorkflowDefinition` pin với PE/Contract cũ. Match Dept+PositionLevel.
- **V2 Mig 22-30** — `ApprovalWorkflow` pin với PE mới + match `ApproverUserId` 1-1 OR-of-N cùng Cấp. Steps (Phòng) > Levels (Cấp). PE đã wire V2. Contract V2 PENDING (Plan F drop V1 ABORTED S22+4 — Contract entity HOÀN TOÀN V1 chưa wire V2 + 4 PE V1-only + 19 PE V1+V2 mix).
  - **Mig 25** IsUserSelectable (admin pin/unpin per workflow cho user pick)
  - **Mig 26** PE Level Opinions UPSERT (service hook khi Duyệt)
  - **Mig 28** (S21 t4) 6 Allow* workflow-level — **REPLACED by Mig 29**
  - **Mig 29** (S21 t5) Allow* refactor per-NV: 5 flag on `ApprovalWorkflowLevels` (F1+F3 per Approver slot) + 1 flag on `Users.AllowDrafterSkipToFinal` (F2 per Drafter)
  - **Mig 30** (S22+5) F4 `AllowApproverEditBudget` per-Level slot on `ApprovalWorkflowLevels` — admin Designer tick per slot cho Approver được edit Budget khi review. Pattern reinforced 2× với Mig 29 F1+F3: default = admin opt-in per slot, KHÔNG = mở rộng default. Cross-ref memory `feedback_per_nv_permission_scope.md` proven cumulative Mig 29 + Mig 30.

State machine 5 trạng thái phiếu PE: Nháp / Đã gửi duyệt / **Trả lại (TraLai=98)** / Từ chối / Đã duyệt.

**Mode Trả lại 4 option per-Level** (S21 t4-t5 Mig 28→29):
- OneLevel = lùi 1 Cấp cùng Step (peer review)
- OneStep = lùi sang Bước trước Cấp cuối
- Assignee = pick NV đã ký runtime (PeLevelOpinions)
- Drafter = Phase=TraLai clear pointer (S17 backward compat default TRUE)

3 mode đầu giữ Phase=ChoDuyet lùi pointer. Mode Drafter giữ Phase=TraLai. Admin bypass `level.Allow*` flag.

---

## 📅 Recent activity (last 10 FIFO)

- **2026-05-14 (S23 t1 spawn K0 — Plan K F2 refactor pre-flight):** Audit F2 state cho Plan K Mig 31 (move `Users.AllowDrafterSkipToFinal` → `ApprovalWorkflowLevels.AllowApproverSkipToFinal` + change semantic Drafter Nháp → Approver ChoDuyet skip thẳng Cấp cuối). **Confirmed state Mig 30:** Migrations path = `Persistence/Migrations/` (not direct `Migrations`); 30 mig latest = `20260513160703_AddAllowApproverEditBudgetToLevels`; `User.cs:38` AllowDrafterSkipToFinal prop; `ApprovalWorkflow.cs:86-105` 6 Allow* props (4 ReturnMode + EditDetails + EditBudget) per Level slot; F2 Drafter branch ở `PurchaseEvaluationWorkflowService.cs:119-161` trong SUBMIT branch (line 125 `if (skipToFinal && evaluation.ApprovalWorkflowId is Guid skipAwId)` check user.AllowDrafterSkipToFinal); APPROVE STEP branch ở `~line 393-525` (advance pointer). TransitionAsync signature: `skipToFinal` là param thứ 8 (position 47:47), default=false. `TransitionPurchaseEvaluationCommand` ở `PurchaseEvaluationFeatures.cs:393-402` với param `SkipToFinal=false` default. `ApprovalWorkflowOptionsDto` ở `PurchaseEvaluationDtos.cs:86-92` (6 field). `PurchaseEvaluationDetailBundleDto.DrafterAllowSkipToFinal` ở line 217 + `CurrentLevelOptions` ở line 214. UsersController `PATCH /users/{id}/allow-skip-final` ở line 91-98 + `SetAllowDrafterSkipToFinalBody` ở line 105. `SetUserAllowDrafterSkipToFinalCommand` ở `UserFeatures.cs:332`. **FE state:** fe-admin Designer `system/ApprovalWorkflowsV2Page.tsx` slot label "NV #{ei + 1}" ở line 873 (KHÔNG phải "#NV {order}" theo prompt) — inline checkbox panel 5+1=6 checkbox ở line 853-933 (4 ReturnMode + EditDetails + EditBudget). fe-admin `system/UsersPage.tsx` "Skip cuối" column line 306-318 + FastForward button toggle line 365-372 + allowSkipMut hook line 181-186. fe-admin/fe-user PeDetailTabs Drafter Workspace checkbox "Gửi thẳng Cấp cuối (skip trung gian)" ở line 287-297 (admin) / 294-304 (user). **GAP fe-user**: KHÔNG có UsersPage + ApprovalWorkflowsV2Page (admin-only mgmt) → Plan K UI changes localized fe-admin chỉ; fe-user side chỉ touch PeDetailTabs (remove old Drafter checkbox + thêm Approver toggle near Duyệt button). **Drift Dev DB**: Total=2 user (admin + test.drafter), Flagged=0 — NOT match 33-user prod seed. **Prod actual**: Total=33 / Flagged=4 (NOT 2 per S22+2 spec). 4 user flagged sẽ lose value when DROP column — acceptable per new semantic (Drafter pre-submit moot).
- **2026-05-13 (S22, no spawn — em main solo throughout):** S22 18:00→~21:00 em main solo. Cumulative state: 30 mig (+1 Mig 30 `AddAllowApproverEditBudgetToLevels` F4 per-Level slot), 104 test PASS (+20: 5 reg #44 Authorize policy + 7 ReturnMode + 7 Guard + 1 V2 actor scope reject), ~146 endpoints (+3: PATCH /users/{id}/allow-skip-final + PATCH /pe/{id}/budget-adjust + GET /pe/{id}/attachments/{attId}/view), 46 gotcha unchanged, 19 memory unchanged (recommend +1 entry — see below). Prod active users 13→33 (+20 role-based: act.nv/pp/tp, bod.1/2, equ/fin/hra/pm/qs.nv/pp/tp). **Discoveries S22:** (1) **Per-NV admin opt-in flag pattern reinforced 2×** — Mig 30 F4 cùng pattern Mig 29 F1+F3 (S21 t5). Bro corrected em main lần đầu: "phải tick checkbox như Section 2", default = admin opt-in per slot, KHÔNG = mở rộng default. Cross-ref memory `feedback_per_nv_permission_scope.md` proven 2×. (2) **Plan F drop V1 ABORTED** — pre-flight sqlcmd reveal Contract entity HOÀN TOÀN V1 chưa wire V2 (chưa có ApprovalWorkflowId column) + 4 PE V1-only + 19 PE V1+V2 mix. Lesson: drop migration cần verify entity scope toàn bộ (Contract liên đới — không chỉ PE). (3) **Identity password policy ≥12 chars** — seed 20 user FAIL 400 với "User@123456" (11 chars), `TestUser@2026` (13 chars) pass. (4) **Identity rename atomic 4 fields** confirm gotcha #38: Email + NormalizedEmail + UserName + NormalizedUserName + FullName; sqlcmd cần `SET QUOTED_IDENTIFIER ON` cho filtered unique index. (5) **API login response field name `accessToken` + `refreshToken` + `user`** — KHÔNG có field `token` (correct prior Bash example trong spec dùng `.token` sẽ fail). (6) **PS 5.1 ASCII-only script discipline** reinforced gotcha #30: `seed-test-users-prod.ps1` viết Vietnamese names without diacritics tránh parser error. Recommend bro add 1 memory entry "Admin opt-in flag pattern proven 2×" cumulative Mig 29 + Mig 30.
- **2026-05-13 (S21 t3-t5, no spawn):** Em main solo 3 turns (bug fix gotcha #45 + F1+F2+F3 workflow-level Mig 28 + refactor per-NV Mig 29). Implementer REFUSE per cross-stack reasoning chain rule. Investigator KHÔNG spawn — em main đã có context cumulative S20 t12 setup + active dev throughout. No findings to flush. Cumulative state update: 84 test, 29 mig, 45 gotcha, 19 memory entries (+2 S21 t5 pending), 6 skills unchanged. Pattern reusable saved cho future spawn: per-NV permission scope split + EF migration ADD→BACKFILL→DROP reorder.
- **2026-05-11 (setup):** Investigator agent initialized. Baseline knowledge load complete (44 gotchas + 14 memory entries + 6 skills + 27 mig + 81 test pass cumulative). No investigations performed yet. Awaiting first SendMessage from em main.

---

## 🔄 Curate trigger

- Memory size > 25KB → archive recent entries to `archive/<period>.md`
- Duplicate entries detected → merge
- Stale > 3 months → remove

Last curate: 2026-05-11 (initial seed)
