# Session 23 turn 3 — 2026-05-15 — Plan M Fix F1 edge case + FE label rename **Dev:** Claude Opus 4.7 1M (4 sub-agents active + em main coordinator) **Duration:** ~2h **Base commit:** `83c9f7b` (S23 t2 Plan L5 chốt) **Final HEAD:** `4dd6f9c` (M2 tests) — local, CHƯA push remote (chờ Reviewer verdict) **Total commits Plan M:** **3** (M1 + M3 + M2) ## 🎯 Trigger session Bro UAT post-Plan L deploy (S23 t2 chốt ~02:00) phát hiện disconnect: > "Hiện logic cũ là khi trả lại 1 cấp hoặc chỉ định hoặc edit là trạng thái draft -> cái này thay đổi lại nhé, các tính năng duyệt thẳng, trả lại 1 cấp hoặc người chỉ định hoặc cho edit thì cho xử lý đc ở trạng thái đang gửi duyệt luôn." Em main pre-flight Investigator spawn audit code thực tế. **Verdict surprise:** code main path đã đúng (F1.OneLevel/Assignee + F2 + F3+F4 giữ ChoDuyet đúng spec Mig 28-31 cumulative). Chỉ **edge case F1.OneLevel/OneStep tại Bước 1** còn fallback Drafter (Phase=TraLai) — đây là "draft" bro phát hiện. Bro 3 AskUserQuestion chốt spec Plan M: - **F1.OneLevel/OneStep Bước 1**: reset (0, 1) giữ ChoDuyet (Recommended Option A — no-op effective + audit log) - **FE Phase=TraLai display label**: rename "Trả lại" → "Cần chỉnh sửa lại" - **F1.Drafter mode 4**: GIỮ NGUYÊN Phase=TraLai semantic (explicit role mode, KHÔNG phải fallback) ## 🌳 Plan M 3 chunk execution ### Chunk M1 — BE Service refactor F1 edge case (`c2042ef`) 👤 Chủ trì Solo (cross-stack reasoning F1 state machine — Implementer auto-refuse criteria #1 schema-ish + #4 bug-fix-reasoning). File: [PurchaseEvaluationWorkflowService.cs:287-333](src/Backend/SolutionErp.Infrastructure/Services/PurchaseEvaluationWorkflowService.cs:287) ```diff case WorkflowReturnMode.OneLevel: // Lùi 1 Cấp trong cùng Step. Nếu đang Cấp 1 → lùi sang Bước trước // Cấp cuối. Nếu đang Bước 1 Cấp 1 → reset về (0, 1) giữ ChoDuyet - // → fallback Drafter (no further). + // (Plan M S23 t3 — KHÔNG fallback Drafter, phiếu giữ "đang duyệt"). if (curLevel > 1) { ... } else if (curStepIdx > 0) { ... } else { - // Bước 1 Cấp 1 — no further back. Fallback Drafter. - evaluation.Phase = PurchaseEvaluationPhase.TraLai; - evaluation.CurrentWorkflowStepIndex = null; - evaluation.CurrentApprovalLevelOrder = null; - evaluation.SlaDeadline = null; - return "Trả về Người soạn thảo (fallback — đang Bước 1 Cấp 1)"; + // Bước 1 Cấp 1 → reset về (0, 1) giữ Phase=ChoDuyet (no-op effective + // — Approver A hiện tại). Audit log rõ "không lùi được". SLA reset + // dưới cuối hàm cho approver giữ nguyên. + evaluation.CurrentWorkflowStepIndex = 0; + evaluation.CurrentApprovalLevelOrder = 1; + summary = "Action 'Trả lại 1 Cấp' không lùi được — phiếu reset về Approver Bước 1 Cấp 1"; } ``` OneStep analog: line 314-333 cùng pattern reset (0, 1) thay vì fallback Drafter. **Verify:** - `dotnet build src/Backend/SolutionErp.Infrastructure` clean (0 err, 2 warn pre-existing DocxRenderer) - Diff 13+/13- LOC 1 file surgical **KHÔNG đụng:** - F1.Drafter line 268-275 (explicit role mode, giữ TraLai) - F1.Assignee line 335-360 (giữ throw nếu không match) - F2 ApproveV2Async line 483-524 (Plan L L1 fix unchanged) - F3 EnsureEditableForDetailsAsync (Mig 28 wire unchanged) - F4 AdjustBudgetCommand handler (Mig 30 wire unchanged) ### Chunk M3 — FE label Phase=TraLai rename × 2 app (`508b17a`) 🟨 Implementer Case 2 (cookie-cutter mirror 2 app, ~6K tokens spawn). Files (4 FE + 1 MEMORY): - [fe-admin/src/types/purchaseEvaluation.ts](fe-admin/src/types/purchaseEvaluation.ts): `PurchaseEvaluationPhaseLabel[98]` + `PeDisplayStatusLabel.TraLai` - [fe-user/src/types/purchaseEvaluation.ts](fe-user/src/types/purchaseEvaluation.ts) mirror - [fe-admin/src/components/pe/PeWorkflowPanel.tsx](fe-admin/src/components/pe/PeWorkflowPanel.tsx): F1 dialog tooltip + confirm message status reference - [fe-user/src/components/pe/PeWorkflowPanel.tsx](fe-user/src/components/pe/PeWorkflowPanel.tsx) mirror Diff +4/-4 LOC × 4 file = 8 LOC tổng. Mirror 2 app §3.9 strict. **Scope decisions Implementer:** - ✅ Rename 2 const map label (badge primary) - ✅ Tactical extension: rename 2 inline literal "Trả lại" trong PeWorkflowPanel.tsx F1 dialog (tooltip + confirm message — status display reference, KHÔNG phải action verb). Anti-fiddle <20% LOC threshold respected. - ✅ KHÔNG đụng `← Trả lại` action button, `Trả về Người soạn thảo` mode picker, comments narrative - ✅ KHÔNG đụng `types/contracts.ts` + `types/budget.ts` Phase 98 (Contract + Budget module ngoài scope M3) **Verify:** fe-admin npm build PASS clean (0 TS err, 9.40s) + fe-user PASS clean (0 TS err, 6.92s). ### Chunk M2 — Tests F1 edge case (`4dd6f9c`) 🟨 Implementer Case 3 (test generation cookie-cutter, ~14K tokens spawn). File: [tests/SolutionErp.Infrastructure.Tests/Services/PurchaseEvaluationWorkflowServiceReturnModeTests.cs](tests/SolutionErp.Infrastructure.Tests/Services/PurchaseEvaluationWorkflowServiceReturnModeTests.cs) 2 test mới (Pattern 11 SeedWorkflowAsync helper extend 2 param optional `allowReturnOneLevelL1` + `allowReturnOneStepL2`): - `ApplyReturnMode_OneLevel_AtStep1Level1_ResetsToBuoc1Cap1_KeepsChoDuyet` - `ApplyReturnMode_OneStep_AtStep1_ResetsToBuoc1Cap1_KeepsChoDuyet` Assertions: - Phase.Should().Be(ChoDuyet) — KHÔNG TraLai - CurrentWorkflowStepIndex.Should().Be(0) - CurrentApprovalLevelOrder.Should().Be(1) - SlaDeadline.Should().NotBeNull (reset 7d) - ContextNote contain "không lùi được" (KHÔNG `Summary` — fix spec bug em main bị Implementer correct: `LogTransitionAsync` set Summary = "Chuyển phase {from} → {to}" cố định; summary từ `ApplyReturnModeAsync` chèn vào `comment` param → ghi vào `ContextNote`) **Verify:** `dotnet test SolutionErp.slnx` **106/106 PASS** (58 Domain + 48 Infra: +2 từ 46 baseline). K7 Approver F2 NO regression (3 `ApproveV2_SkipToFinal_*` tests still green — M1 chỉ đụng F1 path). Diff +94/-2 LOC test file + 22 LOC MEMORY append. ### Pending Chunk M4 + Reviewer verdict + push - 🟥 Reviewer pre-commit running background (a7cce1b29) — verify M1+M2+M3 cumulative - 👤 Chủ trì M4 docs (STATUS + HANDOFF + session log file này + memory update) — IN PROGRESS - Push remote sau Reviewer PASS + bro confirm - 🟩 CICD Monitor post-deploy verify ## 📊 Stats Plan M chốt | Metric | Trước (S23 t2) | Sau (S23 t3) | Δ | |---|---|---|---| | DB tables | 59 | 59 | 0 | | Migrations | 31 | 31 | 0 | | Endpoints | ~145 | ~145 | 0 | | FE pages | 34 | 34 | 0 | | **Unit tests** | 104 | **106** | **+2** (F1 OneLevel/OneStep edge case) | | Gotchas | 47 | 47 | 0 | | **Memory entries** | 20 | **21** | +1 reinforcement S23 t3 (per_nv_permission_scope + uat_skip_verify update) | | Skills | 6 | 6 | 0 | | Sub-agents | 4 (1 spawn Plan L) | 4 (3 spawn Plan M: 1 Inv + 2 Imp + 1 Rev pending) | active | | **Commits Plan M** | — | **3** (M1 + M3 + M2 local) | pending push | ## 🎯 Multi-agent ROI evidence Plan M | Spawn | Agent | Cost (tokens) | Output | Catch | |---|---|---|---|---| | Pre-flight | 🟦 Investigator | ~20K | 7-feature audit matrix file:line + verdict "code main path đúng, chỉ edge case sai" | **Avoid em main spam refactor sai** — verify 6/7 feature đã đúng spec, chỉ scope hẹp Bước 1 fallback cần fix | | M1 | 👤 Chủ trì | ~self | 1 commit BE Service 13+/13- LOC | — | | M3 | 🟨 Implementer Case 2 | ~6K | 1 commit FE label rename × 4 file mirror | Tactical extension catch inline literal F1 dialog tooltip + confirm message | | M2 | 🟨 Implementer Case 3 | ~14K | 1 commit tests 2 new + 106/106 PASS | Spec field bug catch (`ContextNote` vs `Summary`) + helper extend backward-compat | | Reviewer | 🟥 Reviewer | ~22K (pending) | PASS verdict + Smart Friend guard | TBD post-spawn | | Post-deploy | 🟩 CICD Monitor | ~150K (pending) | Bundle hash + smoke F1 endpoint | TBD post-push | **Total Plan M spawn cost (excl Reviewer + CICD):** ~40K tokens — well under 200K budget per session. **Multi-agent value caught:** 1. **Investigator avoid em main spam refactor** — bro statement "logic cũ là về draft" easy lead em main refactor toàn bộ 4 mode F1 + F2 + F3 + F4. Investigator catch fact code main path đã đúng → scope giảm 80% (LOW effort vs HIGH). 2. **Implementer Case 3 catch spec bug `ContextNote` vs `Summary`** — em main spec viết `Summary.Should().Contain(...)` sai field. Implementer correct → test pass real, không pass-by-mistake. 3. **Implementer Case 2 tactical extension** — rename inline literal trong F1 dialog tooltip + confirm message (cùng status reference disconnect). Anti-fiddle threshold respected, KHÔNG scope drift. ## ⚠️ Pending S23 t4+ - 🟥 **M-Review verdict** — chờ Reviewer pre-commit Plan M cumulative - 🟩 **CICD Monitor K-Plan-M** — chờ push remote → spawn post-deploy verify - 🟡 **Plan B Contract V2 wire (Mig 32+33)** — vẫn pending S23+ (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 5 dự án** — defer chờ bro confirm - 🔧 **Gotcha #47 paths-ignore agent-memory** — PENDING bro confirm ## 📋 Pattern reinforced - **Investigator pre-flight audit avoid em main spam refactor** — khi bro statement có vẻ "code sai" mà Investigator audit verify code đã đúng → scope giảm drastically (LOW vs HIGH effort). Pattern reusable: BẮT BUỘC spawn Investigator pre-flight cho mọi bug fix scope > 50 LOC, KHÔNG em main solo audit (bias). - **Edge case "không thực hiện được" KHÔNG fallback role khác** — pattern user-level reinforced trong `feedback_per_nv_permission_scope.md` S23 t3 entry. Action per-NV flag được trigger nhưng state machine không cho phép → giữ Phase hiện tại + reset pointer hợp lệ + audit log warning. - **Service refactor semantic BẮT BUỘC test cùng commit** — Plan L L1→L4 lesson (CI #196/#197 FAIL cascade). Memory `feedback_uat_skip_verify.md` updated với rule mới. - **Implementer Case 2+3 cookie-cutter 2 spawns parallel** — M2 (test) + M3 (FE) chạy background đồng thời ~6K + ~14K tokens. Em main solo M1 (cross-stack reasoning). Total Plan M token ~40K under 200K budget. ## References - Memory user-level updated: `feedback_per_nv_permission_scope.md` (S23 t3 reinforcement) + `feedback_uat_skip_verify.md` (Plan L lesson Service refactor semantic) - Files: [Service.cs:287-333](src/Backend/SolutionErp.Infrastructure/Services/PurchaseEvaluationWorkflowService.cs:287) (M1) + [types/purchaseEvaluation.ts × 2 app](fe-admin/src/types/purchaseEvaluation.ts) + [PeWorkflowPanel.tsx × 2 app](fe-admin/src/components/pe/PeWorkflowPanel.tsx) (M3) + [PurchaseEvaluationWorkflowServiceReturnModeTests.cs](tests/SolutionErp.Infrastructure.Tests/Services/PurchaseEvaluationWorkflowServiceReturnModeTests.cs) (M2) - 4 agent MEMORY.md flushed (Investigator pending + Implementer 2 entry + Reviewer pending) at `.claude/agent-memory/{investigator,implementer,reviewer,cicd-monitor}/MEMORY.md` - Rules: §3.9 mirror 2 FE, §7 test timing, `feedback_uat_skip_verify` (updated rule Service semantic refactor), `feedback_per_nv_permission_scope` (S23 t3 reinforcement)