Files
solution-erp/docs/changelog/sessions/2026-05-15-s23-turn4-plan-n-per-nv-lookup-bug.md
pqhuy1987 fb3c22c90f
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m25s
[CLAUDE] Docs: Chunk N4 — S23 t4 Plan N HOTFIX wrap: docs + session log + 2 agent MEMORY drift
Plan N 2 commits:
- N1+N2 atomic (commit 0326458) BE fix line 765 ApproverUserId discriminator + 2 regression test
- N4 (this) docs + memory update

Docs update:
- docs/STATUS.md — Last updated S23 t4 + stats 108 test (+2 từ 106)
- docs/HANDOFF.md — TL;DR S23 t4 với Investigator pre-flight catch root cause
- docs/changelog/sessions/2026-05-15-s23-turn4-plan-n-per-nv-lookup-bug.md — Session log Plan N

Memory user-level update (1 entry CRITICAL HOTFIX section):
- feedback_per_nv_permission_scope.md — Wire checklist 9 surface points (NOT 8)
  + Point 9 mới: Handler lookup site `currentLevelOptions` MUST discriminate
  ApproverUserId. 3× cumulative gap analysis Mig 29 + 30 + 31.

Agent MEMORY drift (auto-flush):
- Investigator (.claude/agent-memory/investigator/MEMORY.md) — S23 t4 spawn N0
  audit Hypothesis B verdict + sqlcmd verify + API curl verify
- CICD Monitor (.claude/agent-memory/cicd-monitor/MEMORY.md) — S23 t3 Plan M
  Run #200 anomaly note (docs-only trigger CI mặc dù paths-ignore)

Stats final S23 t4:
- 31 mig · 59 tables · ~145 endpoints · 34 FE pages
- **108 test PASS (+2: per-NV lookup discrimination regression)**
- 47 gotcha · 20 memory (1 entry reinforced CRITICAL section)
- 6 skills · 4 sub-agents (1 Investigator spawn ~80K)
- 2 commits Plan N `0326458..HEAD` ready push

Pending: CICD Monitor post-deploy verify Plan N

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 12:42:21 +07:00

167 lines
11 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.

# Session 23 turn 4 — 2026-05-15 — Plan N HOTFIX per-NV lookup site discrimination
**Dev:** Claude Opus 4.7 1M (4 sub-agents active + em main coordinator)
**Duration:** ~1h
**Base commit:** `f4055a1` (S23 t3 Plan M wrap)
**Final HEAD:** `<pending>` (Plan N batch + docs)
**Total commits Plan N:** **2** (atomic N1+N2 BE+test + N4 docs)
## 🎯 Trigger session
Bro UAT screenshot post-Plan M deploy phát hiện disconnect cực nghiêm trọng:
> "Hiện User UAT test v2 vẫn chưa thấy cho chuyển tiếp đến người cuối hoặc các option trả lại trong menu Duyệt NCC → Duyệt → Chưa thấy xuất hiện option duyệt thẳng, trả lại theo option và cho Edit"
4 screenshots evidence:
- **Workflow Designer:** Admin tick TRUE 7 flag cho NV Test (UAT V2) slot Bước 2 Cấp 1, 3 NV khác CHỈ Drafter flag
- **Dialog ✓ Duyệt:** Chỉ có "Ghi chú (tùy chọn)" + Xác nhận — KHÔNG có checkbox F2 skipToFinal
- **Dialog ← Trả lại:** Chỉ có 1 radio "Trả về Người soạn thảo (mặc định)" — KHÔNG có 3 mode F1 khác (OneLevel/OneStep/Assignee)
- **PE detail UI:** KHÔNG có F3 Edit Section 2 + F4 Edit ngân sách
## 🔍 Investigator pre-flight audit (~80K spawn, Hypothesis B verify)
🟦 Investigator spawn audit DB + API + FE wire cross-stack:
**API curl verify (admin token):**
- GET `/api/purchase-evaluations/<id>``currentLevelOptions = {allowReturnToDrafter: true, 6 flag khác: false}` — KHÔNG match flag admin tick cho NV Test
- GET `/api/approval-workflows-v2/<wfId>` → 4 Level cùng Order=1, NV Test slot có 7 flag TRUE, 3 NV khác CHỈ AllowReturnToDrafter=true
**sqlcmd prod verify:**
- Schema `ApprovalWorkflowLevels` 4 rows cùng (ApprovalWorkflowStepId, Order=1) trong Step 2 — đúng OR-of-N Mig 29 pattern
- NV Test (UAT V2) row có 7 flag TRUE: AllowReturnOneLevel + OneStep + ToAssignee + ToDrafter + EditDetails + EditBudget + SkipToFinal
- 3 NV khác chỉ AllowReturnToDrafter=true
**FE wire grep verify:**
- `fe-user/src/components/pe/PeWorkflowPanel.tsx:51,335-425` đọc `evaluation.currentLevelOptions.allow*` đúng tên field, conditional render đủ
- `fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx:889-946` Designer wire 7 checkbox per slot đúng
**Verdict: HYPOTHESIS B confirm — BE handler bug line 765:**
```csharp
// BUG ([PurchaseEvaluationFeatures.cs:765])
var curLevel = curStep?.Levels.FirstOrDefault(l => l.Order == curLevelOrder);
```
Schema Mig 29 (S21 t5 2026-05-13) refactor: 1 `ApprovalWorkflowLevel` row per `ApproverUserId` (OR-of-N cùng Order). 4 NV cùng Cấp = 4 row có `Order=1`. `FirstOrDefault(Order==X)` không có discriminator → **luôn lấy row đầu DB** (Trần Xuân Lưu / Lê Văn Bính / etc. tuỳ ordering EF nội bộ, đều chỉ Drafter flag) → bỏ qua admin tick per-NV của NV Test.
**Bug present từ Mig 29 deploy 2026-05-13** (2 ngày prod) nhưng chỉ bộc lộ khi lần đầu admin tick selectively per-NV. Trước đây tất cả slot FALSE → behavior giống nhau (mọi actor đều thấy "không có options"), không lộ.
## 🌳 Plan N 2 chunk execution
### Chunk N1 + N2 — BE fix + regression test (atomic commit)
👤 Chủ trì Solo (bug fix reasoning chain cross-stack — Implementer auto-refuse criteria #4).
**N1 BE fix ([PurchaseEvaluationFeatures.cs:765-781](src/Backend/SolutionErp.Application/PurchaseEvaluations/PurchaseEvaluationFeatures.cs:765)):**
```diff
- var curLevel = curStep?.Levels.FirstOrDefault(l => l.Order == curLevelOrder);
+ // Match actor.UserId trong slot (per-NV admin opt-in flag).
+ // Admin / non-approver fallback row đầu (giữ behavior view detail).
+ var curLevel = curStep?.Levels.FirstOrDefault(l =>
+ l.Order == curLevelOrder && l.ApproverUserId == currentUser.UserId)
+ ?? curStep?.Levels.FirstOrDefault(l => l.Order == curLevelOrder);
```
5 LOC delta. `ICurrentUser currentUser` đã có DI sẵn line 652.
**N2 Regression test (`tests/SolutionErp.Infrastructure.Tests/Application/GetPurchaseEvaluationCurrentLevelOptionsTests.cs`):**
2 test method (~210 LOC test new file):
- `GetPe_PerNvLookup_ActorMatchesSlot_ReturnsActorSpecificFlags`:
- Seed 1 Workflow + 1 Step + 4 Level cùng Order=1, mỗi Level distinct flag profile (A=Drafter / B=OneLevel / C=SkipToFinal / D=EditBudget)
- 4 actor scenarios → assert mỗi actor nhận flag-set RIÊNG (KHÔNG profile khác)
- Critical assertion: Actor C → `AllowApproverSkipToFinal=true` (regression bug bro UAT)
- `GetPe_PerNvLookup_AdminNonApprover_FallsBackToFirstRow`:
- Admin actor (KHÔNG match) → fallback FirstOrDefault EF SQLite non-deterministic ordering
- Weak assertion: NOT null + match 1 trong 4 distinct profile (mỗi Level distinct flag → fallback pick exactly 1)
**Verify:**
- `dotnet build src/Backend/SolutionErp.Application` clean (0 warning, 0 error)
- `dotnet test SolutionErp.slnx` **108/108 PASS** (+2 từ 106: 58 Domain + 50 Infra)
- 2 test scenario N2 PASS individually + full suite no regression
### Chunk N4 — Docs + memory update + commit (this commit)
- `docs/STATUS.md` Last updated S23 t4 entry
- `docs/HANDOFF.md` TL;DR S23 t4 đầy đủ
- Session log file này
- Memory user-level `feedback_per_nv_permission_scope.md` reinforcement S23 t4 wire checklist 9 surface points (NOT 8)
## 📊 Stats Plan N chốt
| Metric | Trước (S23 t3) | Sau (S23 t4) | Δ |
|---|---|---|---|
| DB tables | 59 | 59 | 0 |
| Migrations | 31 | 31 | 0 |
| Endpoints | ~145 | ~145 | 0 |
| FE pages | 34 | 34 | 0 |
| **Unit tests** | 106 | **108** | **+2** (per-NV lookup discrimination regression) |
| Gotchas | 47 | 47 | 0 |
| Memory entries | 20 | 20 | 0 (1 entry `feedback_per_nv_permission_scope.md` reinforced — wire 9 points checklist) |
| Skills | 6 | 6 | 0 |
| Sub-agents | 4 | 4 (1 Investigator spawn ~80K) | active |
| Commits Plan N | — | **2** (atomic N1+N2 + N4 docs) | pending push |
## 🎯 Multi-agent ROI evidence Plan N
| Spawn | Agent | Cost (tokens) | Output | Catch |
|---|---|---|---|---|
| Pre-flight | 🟦 Investigator | ~80K | Hypothesis B verdict + file:line + DB sqlcmd verify + API curl verify + FE wire grep verify | **Critical root cause** — em main lần đầu hypothesize 3 candidates (A: admin chưa tick + B: BE handler bug + C: FE wire bug), Investigator confirm B với evidence-based file:line, avoid em main spam fix WRONG |
| N1 fix | 👤 Chủ trì | ~self | 5 LOC BE Service handler line 765 | — |
| N2 test | 👤 Chủ trì | ~self | 210 LOC test new file 2 scenario | First iteration EF SQLite ordering non-deterministic → fix weak assert fallback test |
| Reviewer | (skip) | 0 | — | LOW effort 5 LOC BE + isolated test, em main solo per criteria small scope < 30 min |
| Post-deploy | 🟩 CICD Monitor | TBD (pending) | Bundle hash + smoke + sqlcmd | Spawn sau push |
**Total Plan N spawn cost (excl CICD):** ~80K tokens Investigator chính, em main solo execute.
**Multi-agent value caught:**
1. **Investigator catch root cause precisely** file:line + sqlcmd + API + FE evidence-based. Em main solo thể đã spawn fix sai (vd suspect admin chưa tick ask bro re-tick ích admin đã tick đúng).
2. **3-spawn cumulative pattern caught** Mig 29 + 30 + 31 + Plan N reveal: 3× refactor wire 8 surface points đúng nhưng MISS point 9 lookup discrimination. Pattern reinforced cho future flag F5+.
## ⚠️ Pattern reinforced — Per-NV admin opt-in wire 9 surface points (KHÔNG 8)
**Old (S23 t1 K9 catch — 8 points):** Mig 29 + 30 + 31 wire checklist 8 points (Domain + EF config + Mig 3-file + Service guard + PE bundle DTO + Admin AwLevelDto + CreateAwLevelInput + FE Designer).
**NEW S23 t4 Plan N catch:** Thêm point 9:
> **9. Handler lookup site `currentLevelOptions` MUST discriminate `ApproverUserId == currentUser.UserId`** (fallback row đầu cho admin/non-approver). Áp dụng cho TẤT CẢ handler đọc Allow* flag từ Level slot khi schema OR-of-N approvers cùng Cấp.
**Audit checklist trước commit cho future flag F5+:**
- [ ] Grep `FirstOrDefault.*Order ==` trong codebase enumerate all lookup sites
- [ ] Verify mỗi site discriminator role-context (ApproverUserId hoặc role-specific column)
- [ ] Test regression: seed N rows cùng Order × N actor distinct assert actor-specific flag returned
**3× cumulative gap analysis (Mig 29 + 30 + 31):**
| Migration | Wire 9 points | Bug surface | Caught when |
|---|---|---|---|
| Mig 29 F1+F3 | 1-8 OK, **9 GAP** | Lookup row đầu DB | Plan N S23 t4 (2 ngày prod) |
| Mig 30 F4 | 1-8 OK, **9 GAP** | Same | Same (cumulative) |
| Mig 31 F2 | 1-8 OK, **9 GAP** | Same | Same |
3× cumulative refactor wire SAME bug point 9 lookup discrimination chưa precedent em main + Reviewer + Implementer all MISS xuyên 3 plan.
## ⏭ Pending S23 t5+
- 🟩 **CICD Monitor post-deploy verify** spawn sau push remote
- 🟦 **Investigator follow-up gotcha #41/#48 candidate** controlled test paths-ignore (carry from Plan M)
- 🟡 **Plan B Contract V2 wire (Mig 32+33)** HIGH priority next
- **Plan F drop V1** defer sau Plan B + UAT 2-3 tuần
- 🟢 **Plan H PE PDF Export** LOW priority carry
- 🟡 **Plan I RAG Hybrid setup** defer chờ bro confirm
- 🔧 **Gotcha #47 paths-ignore agent-memory** PENDING bro confirm
## 📋 Pattern reinforced Plan N
1. **Per-NV admin opt-in flag wire 9 surface points (NOT 8)** point 9 handler lookup discrimination added. Memory user-level `feedback_per_nv_permission_scope.md` updated CRITICAL HOTFIX S23 t4 section.
2. **Investigator pre-flight audit BẮT BUỘC cho bug fix cross-stack** em main solo thể spam fix WRONG hypothesis. Investigator file:line + sqlcmd + API + FE grep evidence base.
3. **Atomic commit BE fix + regression test cùng commit** (per `feedback_uat_skip_verify` updated rule Plan L lesson) Service semantic refactor BẮT BUỘC test cùng commit.
4. **EF SQLite non-deterministic ordering** test gotcha weak assertion cho fallback path (NOT null + match 1 distinct profile), KHÔNG assume "row đầu" deterministic.
## References
- Memory user-level updated: `feedback_per_nv_permission_scope.md` CRITICAL HOTFIX S23 t4 section
- Files: [PurchaseEvaluationFeatures.cs:765-781](src/Backend/SolutionErp.Application/PurchaseEvaluations/PurchaseEvaluationFeatures.cs:765) (N1) + [GetPurchaseEvaluationCurrentLevelOptionsTests.cs](tests/SolutionErp.Infrastructure.Tests/Application/GetPurchaseEvaluationCurrentLevelOptionsTests.cs) (N2)
- Rules: §3.9 mirror 2 FE, §7 test timing test-before (regression bug), `feedback_per_nv_permission_scope` (S23 t4 wire 9 points), `feedback_uat_skip_verify` (Plan L Service refactor + test atomic)