# Session S42-S43 — 2026-05-30 — Phase 11 P11-A + P11-B (WorkflowApps ApproveV2 + LeaveBalance)

> 7-agent end-to-end. S42 P11-A wire + Max re-review fix. S43 P11-B LeaveBalance. Agents upgrade High→Max giữa S42-S43 → chất lượng cải thiện rõ rệt.

## Commit chain (8)
| SHA | Scope | Gitea |
|---|---|---|
| `e7b66cd` | P11-A wire ApproveV2 + LevelOpinions 4 module + Mig 41 | #364 PASS |
| `75df04e` | P11-A fix 2 bug picker (Max re-review) + SetWorkflow endpoint | #365 PASS |
| `e47ef1d` | ProposalCreatePage workflow dropdown shape (latent S37 bug, chip task) | (range) |
| `ffb2062`+`0db5e1f` | Docs STATUS reconcile P11-A | CI-skip |
| `82d7fcf` | P11-B LeaveBalance + Mig 42 | #367 PASS |
| `efc5f5f` | Docs STATUS P11-B | CI-skip |

## S42 — P11-A: wire ApproveV2 + LevelOpinions 4 WorkflowApps module

**Reference:** Proposal (Mig 38) = mirror 1:1 (cùng namespace Office, cùng WorkflowAppStatus 5-state) — tốt hơn PE/Contract.

**Schema (Mig 41 `WireWorkflowAppsApprovalV2`):** +4 `{Leave,Ot,Travel,Vehicle}LevelOpinions` (UNIQUE composite + Cascade parent + Restrict Level) + `WorkflowAppCodeSequences` (shared atomic MaDonTu — gộp P11-F cho 4 module) + 4 cột `RejectedFromStatus` + enum `TravelRequest=9`. 84→89 tables.

**BE:** 30 handler (GetById/Update/Submit/Approve-UPSERT-advance/Reject/Return) × 4 module + 8 controller route + seed 4 WF mẫu (QT-NP/OT/CT/XE-V2-001, AppType 5/6/7/9). ItTicket KHÔNG đụng (kanban).

**FE:** `WorkflowAppDetailPage.tsx` declarative 4-kind (admin+user SHA256 identical) — status + opinion timeline + Submit/Approve/Reject/Return.

**⚠️ Max re-review phát hiện 2 BUG FE picker (agents chạy High để lọt):**
1. `pinWorkflow` PUT `/{id}` chỉ gửi `{approvalWorkflowId}` → UpdateDraft validator (Reason/NumDays) fail → 400.
2. fetch workflow expect flat array nhưng endpoint trả `AwAdminOverviewDto {types:[...]}` → picker rỗng/crash. Agent copy nhầm pattern hỏng `ProposalCreatePage` thay vì proven PE/Contract.
**Fix:** dedicated endpoint `PUT /{id}/workflow` (set workflow only, verify ApplicableType) + fetch mirror `data.types.find(t=>applicableType===X)?.history.filter(isUserSelectable)`. **Bonus:** ProposalCreatePage có bug #2 có sẵn từ S37 (latent) → chip task `e47ef1d`.

**Test:** +11 ApproveV2 + +3 SetWorkflow. Auth-verified prod dropdown shape thật.

## S43 — P11-B: LeaveBalance business logic

**Decision (anh main chốt):** (1) số dư không đủ → **cho phép + cảnh báo** (âm OK) · (2) FE **tích hợp trang đơn nghỉ** (không trang riêng).

**Schema (Mig 42 `AddLeaveBalances`):** `LeaveBalances` (User×LeaveType×Year + Entitled/Used/Adjustment, UNIQUE composite + FK LeaveTypes Restrict, decimal 5,2). Remaining = Entitled+Adjustment−Used (computed). 90→91 tables.

**Trừ phép:** hook `ApproveLeaveRequestHandler` nhánh terminal DaDuyet — **exactly-once** (guard Status!=DaGuiDuyet chặn re-approve), upsert auto-create từ DaysPerYear, UsedDays+=NumDays, Year=StartDate.Year.

**FK invariant guard (em Max-review thêm sau test reveal):** Create + UpdateDraft validate LeaveTypeId tồn tại → ConflictException. Đóng cửa hẳn (grep xác nhận 2 write site duy nhất) → bogus type không thể tới deduction FK insert (tránh 500 kẹt đơn).

**CQRS:** GetMy (self lazy-merge active LeaveType) + GetUser (admin) + Adjust (admin upsert). Embed balance NGƯỜI TẠO vào leave detail DTO (approver xem đúng — KHÔNG dùng /my = viewer).

**FE:** block "Số dư phép" + cảnh báo vượt (kind=leave, SHA256 identical).

**Test:** +11 (deduction single/multi-level/accumulate/negative/reject-return-no-deduct + lazy-merge + adjust + Create guard) + repair 2 template terminal FK-fail. 130→**154 PASS**.

## Lessons (→ gotcha/memory)
- **High→Max upgrade tác động lớn:** P11-A High → truncate 3× + lọt 2 FE bug + 1 sai run-id. P11-B Max → 0 truncate, test-specialist tự tìm FK risk, reviewer thorough no-truncate, 0 bug lọt. → memory `feedback_high_to_max_multiagent_quality`.
- **WIRE FE phải đọc reference proven (không đoán):** 2 bug P11-A do agent đoán endpoint/shape. Brief FE agent BẮT BUỘC chỉ file reference proven cụ thể.
- **FK-invariant-at-write-doors pattern:** thêm deduction/insert có FK → enforce FK validity tại MỌI write door (Create+Update), không assume. Test reveal gap.
- **Gotcha #56 CWD-drift stray memory:** `cd` trước spawn → agent ghi MEMORY nhầm `fe-user/.claude`. 3× recover.

## State cuối
42 mig · 91 tables · ~241 endpoint · 67 FE page · **154 test** · 56 gotcha · bundle `Krjvg_3j`/`6sNStgxa`. Phase 11: P11-A + P11-B DONE. Next: P11-C..F.

## Carry-over (chưa đụng)
- `M docs/governance/BROADCAST-OUT-...-2026-05-29.md` + `?? .mcp.json` (untracked) — anh main quyết (từ S40).
- RAG `solution_erp` last_indexed S41 (2407 chunks) — S42-S43 content chưa index, stopgap store_memory. Flag AI_INFRA re-index.
- cicd flag: skill `iis-deploy-runbook` IIS path stale · `.claude/agent-memory/**/*.md` không trong paths-ignore (memory commit trigger CI).
