[CLAUDE] Docs: Session 25 chốt cuối — Plan AB→AF cumulative 7 commits + 4 agent MEMORY flush

S25 wrap final:
- STATUS.md + HANDOFF.md prepend Plan AB→AF cumulative narrative (7 commits cdfd542..506cada + 7 CICD Runs #215-#221)
- gotchas.md +2 NEW entries:
  - #48 Multi-Changelog.Add() SQLite frozen-clock tie-break (Run #215 catch, fix Plan AB Chunk A2)
  - #49 UI dual-phase badge confusion khi state machine self-loop (Plan AD drop + extractNextTargetHint helper)
- Checklist debug bug mới +2 entries (24-25)
- Session log NEW docs/changelog/sessions/2026-05-19-s25-pe-history-visibility.md (~360 LOC)
- 4 agent MEMORY drift sync:
  - investigator/MEMORY.md (30→32KB) FIFO entry S25 wrap + count metadata
  - implementer/MEMORY.md (34→36KB) FIFO entry + patterns 16-18 saved
  - reviewer/MEMORY.md (31→32KB) FIFO entry + lesson SQLite tie-break + UAT skip risk reinforced
  - cicd-monitor/MEMORY.md (~72KB CRITICAL OVER) — 7 Run entries #215-#221 + curate flag MAX

Memory user-level +2 NEW entries (separate commit memory dir, KHÔNG trong this commit):
- feedback_fe_merge_synthetic_audit.md (Plan AC2 pattern)
- feedback_fe_usermap_fallback.md (Plan AF pattern)

Stats final S25:
- 31 mig (no schema) · 59 tables · ~146 endpoints · 35 FE pages
- 111 test unchanged (UAT defer test-after per §7)
- 49 gotcha (+2: #48 + #49)
- 23 memory user-level (+2 NEW S25 patterns)
- 6 skills · 4 sub-agents active
- 7 commits cumulative S25 · 7 CICD Runs (1 FAIL caught + 6 PASS)
- 6× bundle rotate × 2 app (Run #220 BE-only unchanged)

Critical pending S26+:
- Memory curate cicd-monitor PRIORITY MAX (~72KB strongly over hard threshold)
- Plan B Contract V2 wire HIGH priority (5-6 chunk pre-allocated S23 HANDOFF)

Per §6.5 KEEP narrative — KHÔNG cut rationale/gotcha context, chỉ phân tầng prepend latest.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-21 16:33:41 +07:00
parent 506cada86b
commit 0c6efdaf4f
8 changed files with 453 additions and 8 deletions

View File

@ -139,6 +139,38 @@ Flag commit nếu thấy `<PackageReference Include="MediatR" Version="14...` ho
## 📅 Recent runs (FIFO last 20)
- **2026-05-19 13:05-13:08 — Run #221 id=335 sha=`506cada` VERDICT=PASS (S25 t7 Plan AF — FE userMap fallback resolve historical entries pre-Plan AE).** Push range cumulative S25 remote = `e23f51c..506cada` (7 commits Plan AB+AC+AC2+AD+AE+AF since S24). Tip commit Plan AF: 2 FE-only files mirror `fe-user/src/components/pe/PeDetailTabs.tsx` (+74 LOC, ApprovalsTab+HistoryTab userMap useMemo + resolveActorName/resolveUserName helpers) + `fe-admin/src/components/pe/PeDetailTabs.tsx` (+70 LOC mirror §3.9 identical logic). Duration ~3m23s (~baseline). Pre-push em main local: npm build × fe-user PASS 0 TS err (9.12s), npm build × fe-admin PASS 0 TS err (8.91s), BE unchanged from 9ea62be. Status poll 5 iter (13:06→13:08) status `running → success`. **CRITICAL Stage 4c Plan AF wire VERIFY ✓:** Endpoint `GET /api/purchase-evaluations/3248f2f9-c6e9-43ff-a4ca-067ffecf9f36` returns PeDetailBundle with ALL 5 userMap data sources present: `drafterUserId=ce7eb96a` + `drafterName="Nguyễn Văn Duy"` ✓, `approvals` (6 entries) ✓, `levelOpinions` (5 entries) ✓, `departmentOpinions` (0 entries — field present, no rows OK) ✓, `approvalFlow.steps` (3 steps with nested levels.approvers) ✓. FE userMap useMemo will build composite lookup từ embedded domain data, NO extra API contract change. Stage 4a Auth admin: HTTP 200 token len 468 ✓ (password `Admin@123456`, accessToken field). Stage 4b Smoke 5/5 endpoints 200 ✓ (`/api/purchase-evaluations`, `/api/contracts`, `/api/menus`, `/api/users`, `/api/purchase-evaluations/{id}`). **Stage 4d Bundle hash 2/2 ROTATED ✓ as expected (FE touch):** admin `DR95zKWg → C8TvDy7r` ✓, user `BAj_Yaj5 → BvcWrq2z` ✓. Stage 4e Health ready 200 + Health live 200 ✓. Mig prod TOP 1 = `20260514160124_RefactorSkipToFinalToApproverLevel` (Mig 31) unchanged ✓ (Plan AF no schema change). **Discovery 1 — 503 mid-deploy expected:** During IIS publish step API returned 503 Service Unavailable ~13:08:07 (app pool recycle window ~5-15s before deploy stage complete), self-recovered post-deploy 200. Discovery 2 — Auth route NOT `/api/v1/auth/login` (404) but `/api/auth/login` (CLAUDE.md route). Token field NOT `token` but `accessToken`. **Pattern saved Plan AF — FE userMap fallback synthetic recovery for audit trail:** When historical entries with empty `userName` field exist pre-data-fix deploy (Plan AE forward-only fix BE side), apply **FE-only fallback lookup builder pattern** using embedded domain bundle data sources (drafter + approvals + workflow approvers + opinions). Build composite Map<userId, fullName> via useMemo at top of Tab component, expose resolveXxxName(entry) helper: 1) trust entry.userName if non-empty, 2) lookup userMap by entry.userId, 3) fallback "Hệ thống". Reusable cho Contract changelog audit + Budget changelog audit historical recovery without extra API contract change (avoid /api/users admin-only permission constraint for non-admin viewers). Mirror 2 FE app §3.9 identical logic. Token cost ~10k. **Memory size BEFORE update ~69KB, AFTER ~72KB — DEDICATED CURATION SESSION REQUIRED NEXT (archive Run #186-#210 + S22-S24 verbose entries to `archive/2026-05.md` priority MAX REINFORCED).**
- **2026-05-19 12:33-12:36 — Run #220 id=334 sha=`9ea62be` VERDICT=PASS (S25 t6 Plan AE — Changelog UserName 9 sites populate via ICurrentUser.FullName fallback Email).** Push range cumulative S25 remote = `e23f51c..9ea62be` (6 commits Plan AB+AC+AC2+AD+AE since S24). Tip commit Plan AE: 2 BE-only files `PurchaseEvaluationFeatures.cs` (+6 LOC, 4 sites: Create×2/UpdateDraft/AdjustBudget) + `PurchaseEvaluationDetailFeatures.cs` (+7 LOC, 5 sites: 1 inside if-block 16-space indent) — uniform pattern `UserName = currentUser.FullName ?? currentUser.Email`. Duration ~3m25s (~baseline). Pre-push em main local: `dotnet test SolutionErp.slnx` PASS 111/111 (~5s). Status poll 4 iter (12:33→12:36) status `running → success`. **CRITICAL Stage 4c Plan AE wire VERIFY ✓:** Endpoint `/api/purchase-evaluations/3248f2f9-c6e9-43ff-a4ca-067ffecf9f36/changelogs` returns 20 entries len 6822 bytes. Response shape has `userName` field accessible ✓. **Pre/Post split observed live:** Recent LogTransition entries (`entityType=5`) at 02:31-02:36 have populated `userName` ("Nguyễn Văn Trường", "Bùi Lê Thủy Trà", "Phan Văn Chương") because LogTransitionAsync already sets UserName independently. **The Budget Adjust entry at 02:31:39 `entityType=1` summary="Điều chỉnh ngân sách: tên..." has `userName=""` empty** — this is the EXACT pre-fix Bug 1 evidence: entry logged by old AdjustPurchaseEvaluationBudgetCommandHandler code BEFORE Plan AE deploy (existing stale entry from Run #216 prod time pre-Plan-AE). Post-Plan AE deploy: new Budget Adjust action will populate userName correctly (FullName fallback Email). Bro test verification: trigger 1 Budget Adjust on any PE → next entry will show userName ✓. Stage 4a Auth admin: HTTP 200 token len 468 ✓. Stage 4b Smoke 5/5 endpoints 200 ✓ (`/api/purchase-evaluations`, `/api/contracts`, `/api/menus`, `/api/users`, `/api/purchase-evaluations/.../changelogs`). **Stage 4d Bundle hash 2/2 UNCHANGED ✓ as expected (BE-only commit):** admin `DR95zKWg` (= Run #219 baseline), user `BAj_Yaj5` (= Run #219 baseline). Stage 4e Health ready 200 "Healthy" + Health live 200 ✓. Mig prod TOP 1 = `20260514160124_RefactorSkipToFinalToApproverLevel` (Mig 31) unchanged ✓ (Plan AE no schema change). **Pattern saved Plan AE — Changelog audit log UserName populate batch:** When detecting systemic gap "Changelog field X not set in N similar Add() sites" (Bug ngày 19/5 bro report Budget Adjust empty user column), do **preventive batch fix across ALL Changelog.Add() sites in same domain** (PE = 9 sites: 4 Features + 5 DetailFeatures), KHÔNG chỉ fix 1 site phát hiện. Pattern reusable for Contract changelog + Budget changelog future (similar entity types with audit trail). Source pattern `UserName = currentUser.FullName ?? currentUser.Email` — assumes ICurrentUser is injected scoped DI (already standard). Side benefit: 8 preventive sites future-proof against same bug pattern. Token cost ~14k. **Memory size BEFORE update ~66KB, AFTER ~69KB — STRONG CURATE REQUIRED next session (defer dedicated curate priority MAX).**
- **2026-05-19 10:21-10:25 — Run #216 id=330 sha=`8c05947` VERDICT=PASS (S25 t2 Plan AB Chunk A2 — fix Plan M tests filter LogTransition entry post Plan AB).** Push range cumulative Plan AB remote = `e23f51c..8c05947` (2 commits Plan AB total). Tip commit Chunk A2: 1 test file `tests/SolutionErp.Infrastructure.Tests/Services/PurchaseEvaluationWorkflowServiceReturnModeTests.cs` +7/-2 LOC — 2 Plan M edge case tests (OneLevel + OneStep AtStep1Level1) add `.Where(c => c.Summary!.Contains("Chuyển phase"))` filter trước `OrderByDescending(CreatedAt).First()` để pick LogTransition entry (chứa ContextNote) thay vì Plan AB new Changelog entry (Summary="Đã xử lý Trả lại — ..." no ContextNote, SAME CreatedAt SQLite frozen clock tie-break). Plan AB Chunk A code `cdfd542` KHÔNG bị revert — Bug 1+Bug 2 fix giữ nguyên. Duration ~3m17s (baseline 3-4 min — full pipeline tests + builds + deploy + smoke). Test gate PASS: test_domain 58/58 ✓ + test_infra 53/53 ✓ (2 Plan M tests now PASS — verified live). Build BE + FE × 2 PASS. Deploy NSSM + IIS recycle PASS. **CRITICAL Stage 4c Plan AB cumulative live wire VERIFY 2/2 ✓ (cdfd542 BE + Chunk A2 test fix DEPLOYED via Run #216):**
- Bug 1 Budget Adjust entry LIVE on PE c6e9 (`3248f2f9-c6e9-43ff-a4ca-067ffecf9f36` — task brief id `c8e9` typo, actual `c6e9`): entityType=1 (Header), summary="Điều chỉnh ngân sách: tên 'Ngân sách mới update thử ccm' → 'Ngân sách mới', số tiền 5,200,000,000đ → 5,300,000,000đ [Approver Bước 2/Cấp 2]", userId=Phan Văn Chương ✓
- Bug 2 Return Mode entries LIVE on PE c6e9: multiple entityType=5 LogTransition entries với contextNote chứa "Trả về..." text: "Trả về Bước 1 Cấp 2", "Trả về Bước 2 Cấp 2", "Trà xem lại phần so sánh [Trả về Người chỉ định — Bước 1 (Phòng 1) Cấp 2]" (user comment + auto context append pattern Plan AB Chunk A) ✓
- Stage 4a Auth admin: HTTP 200 token len 468 ✓
- Stage 4b Smoke 5/5 endpoints 200 ✓ (`/api/purchase-evaluations`, `/api/contracts`, `/api/menus`, `/api/users`, `/api/purchase-evaluations/{id}/changelogs`)
- **Stage 4d Bundle hash 2/2 ROTATED ✓:** admin `CZdXQ2eo → CrHpBYFM` ✓, user `DCwhhey2 → C3bCWZ90` ✓ — Plan AB cumulative shipped 2 FE PeDetailTabs.tsx changes from Chunk A `cdfd542` (test file commit doesn't change FE bundle; rotate proxy reflects cumulative Plan AB delta from Run #214 baseline since Run #215 deploy never ran).
- Stage 4e Health live HTTP 200 + Health ready "Healthy" → Mig 31 RefactorSkipToFinalToApproverLevel applied prod unchanged ✓ (Plan AB no schema change as expected).
- **Pattern saved gotcha #48 RESOLVED (Run #215 lesson):** When introducing 2nd Changelog.Add() in same transaction as existing LogTransitionAsync chain, tests using `.OrderByDescending(CreatedAt).First()` with SQLite frozen-clock get NON-DETERMINISTIC pick. Fix verified working in Chunk A2: `.Where(c => c.Summary!.Contains("Chuyển phase"))` discriminator filter restores deterministic test pick. Pattern reusable for future multi-Changelog.Add in same SaveChangesAsync transaction.
- **Side benefit Run #215#216 catch loop:** CI test gate caught Plan AB tie-break bug BEFORE prod deploy (Run #215 fail = bro UAT spared broken Plan M edge cases). Chunk A2 test-only fix shipped surgically without re-touching BE service code. Demonstrates: test-after pattern UAT mode CAN tolerate Plan M edge case bug for 1 chunk if next chunk lands within minutes (10:13 fail → 10:21 fix = 8 min turnaround). Token cost ~12k.
- **2026-05-19 10:13-10:15 — Run #215 id=329 sha=`cdfd542` VERDICT=FAIL (S25 t1 Plan AB Chunk A — Changelog visibility fix Bug 1 Budget Adjust + Bug 2 Return Mode). Push range `e23f51c..cdfd542` 1 commit 3 files (1 BE `PurchaseEvaluationWorkflowService.cs` +207/-95 LOC refactor `ApplyReturnModeAsync` + 2 FE `PeDetailTabs.tsx` mirror filter extend). Duration 1m06s (much shorter than ~3-4 min baseline = early test gate fail, deploy stage never reached). **CRITICAL — Test gate FAIL at test_infra:** 51/53 passed, 2 FAIL same root cause:
- `PurchaseEvaluationWorkflowServiceReturnModeTests.ApplyReturnMode_OneStep_AtStep1_ResetsToBuoc1Cap1_KeepsChoDuyet` (line 350)
- `PurchaseEvaluationWorkflowServiceReturnModeTests.ApplyReturnMode_OneLevel_AtStep1Level1_ResetsToBuoc1Cap1_KeepsChoDuyet` (line 308)
- **Error message:** `Expected changelog.ContextNote not to be <null>`
- **Root cause:** Plan AB Chunk A `ApplyReturnModeAsync` adds NEW Changelog entry at end (line 403-412) for Bug 2 visibility — `EntityType=Workflow + Action=Update + Summary` (NO ContextNote field). After refactor, BOTH ApplyReturnModeAsync (new entry, no ContextNote) AND LogTransitionAsync (line 100, existing entry with ContextNote=comment) are added in same `SaveChangesAsync` transaction. Test fetches `.OrderByDescending(c => c.CreatedAt).FirstAsync()` — with SQLite + frozen test clock both entries get SAME CreatedAt, OrderByDescending tie-break returns Plan AB's Workflow entry (without ContextNote) instead of Transition entry. Plan M edge case tests broken.
- Test gate stages: test_domain PASS 58/58 ✓ / test_infra FAIL 51/53 (-2 from baseline 53) / build_be NOT RUN / build_fe_admin NOT RUN / build_fe_user NOT RUN / deploy NOT RUN — exit status 1
- **Deploy NOT shipped:** Bundle hashes unchanged from Run #214 Plan AA baseline (admin `CZdXQ2eo`, user `DCwhhey2`). Mig prod TOP 1 = `Mig 31 RefactorSkipToFinalToApproverLevel` unchanged ✓. Smoke 5/5 endpoints 200 OK (pre-Plan-AB code stable). PE 3248f2f9... changelogs endpoint 200 returns `[]` empty array (PE may not exist or no log entries — endpoint shape OK).
- **Plan AB Bug 1+Bug 2 fix NOT live** — bro UAT screenshot pre-deploy stale, Plan AB Changelog visibility refactor NOT shipped to prod.
- **Recommendation em main:** Plan AB Chunk B HOTFIX — choose ONE of 2 approaches:
1. **Add `ContextNote` to new Plan AB Changelog entry** (line 403-412): set `ContextNote = summary` (the OneLevel/OneStep edge case "không lùi được" string). Plan M tests pass because either entry now has ContextNote. Caveat: ContextNote may duplicate Summary content.
2. **Skip Plan AB Changelog entry when `comment` would propagate via LogTransitionAsync ContextNote**: only add NEW Changelog for cases NOT covered by Transition entry (vd terminal mode that doesn't trigger LogTransitionAsync). Refactor more conservative, but Plan AB scope says "single uniform log".
3. **Alternative — fix tests to fetch specifically EntityType=Transition Changelog**: `Where(c => c.EntityType == PurchaseEvaluationEntityType.Transition)` then OrderByDescending → pick the Transition entry deterministically. Tests still verify ContextNote via LogTransitionAsync chain.
- **Pattern saved gotcha #48:** When introducing 2nd Changelog.Add() in same transaction as existing LogTransitionAsync chain, tests using `OrderByDescending(CreatedAt).First()` with SQLite frozen-clock get NON-DETERMINISTIC pick → favor `.Where(c => c.EntityType == X)` filter or use deterministic order proxy (Id is Guid not sequential — must use insertion-order via explicit ordering column or filter by discriminator). 4 Mode of Plan AB exposes the assumption.
- **Side benefit:** CI test gate caught this BEFORE prod deploy — bro UAT spared from broken Changelog audit (pre-existing Plan M edge case audit trail would have been broken in prod if test gate skipped per UAT mode). UAT mode skip test-after pattern still RISKY when refactor touches existing code paths with tests.
- Token cost ~10k.
- **2026-05-15 ~17:35 — Run #214 id=328 sha=`ee0902a` VERDICT=PASS (S24 t1 Plan AA wrap fix sidebar)**. Last successful deploy before Plan AB. Sidebar label dài wrap về đầu hàng + text smaller. Bundle hashes post-Run-#214 = admin `CZdXQ2eo` + user `DCwhhey2` (baseline for Plan AB delta comparison — KHÔNG rotated since Plan AB failed). Duration ~3m25s.
- **2026-05-15 ~15:25 — Run #210 id=324 sha=`ac2c859` VERDICT=PASS (S24 t1 Plan AA — IsUserSelectable filter + WfView menu + sidebar widen)**. Push range `a1a910f..ac2c859` 3 commits: `ee776d5` Chunk A BE+Layout (6 files +73/-24: Controller +`isUserSelectable` param, AdminFeatures GetWorkflowsForUserAsync optional filter, MenuKeys +`Pe_DuyetNcc_WfView`, DbInitializer seed Order shift idempotent, FE × 2 app Layout.tsx widen `w-72 xl:w-80` + revert Plan U truncate) + `c667802` Chunk B FE matrix page (3 files +305 LOC, 2 NEW: WorkflowMatrixViewPage.tsx + types extend approvalWorkflowV2.ts + App.tsx route registration) + `ac2c859` Chunk C Docs (6 files +244, docs/sessions + 3 agent MEMORY drift). Run duration 3-4 min baseline. Iter 4/10 poll completion. **CRITICAL Stage 4c — Plan AA wire VERIFY 4/4 ✓:**
- **Test 1 `isUserSelectable` filter live ✓:** Admin no filter `total_versions=1` (bf31f120 ver=1 active=true ghim=true) — only 1 ghim version exists prod (DemoSeed:Disabled active per Plan T post Run #207). Admin filter `?isUserSelectable=true` returns same 1 ghim version (count <= no-filter). Non-admin token filter ghim returns same payload (types[0].active id=bf31f120 ghim=true name="Quy trình Duyệt NCC") — **HTTP 200, NOT 403**. Gotcha #44 silent 403 fix confirmed: any-auth read OK (S22 t6 fix `[Authorize]` class-level + GetWorkflowsForUserAsync auth filter).
- **Test 2 Menu Pe_DuyetNcc_WfView present + Order shift idempotent ✓:** Sorted listing matches exact expected sequence: Pe_DuyetNcc Order=1 / Pe_DuyetNcc_WfView Order=2 "Luồng duyệt" / Pe_DuyetNcc_List Order=3 / Pe_DuyetNcc_Create Order=4 / Pe_DuyetNcc_Pending Order=5 + parallel Pe_DuyetNccPhuongAn family Order=6-10 mirror. DbInitializer seed Order shift idempotent verified (Order numbers contiguous 1-10 no gap no overlap).
@ -210,6 +242,10 @@ Flag commit nếu thấy `<PackageReference Include="MediatR" Version="14...` ho
- **2026-05-14 ~16:30 — Run #194 id=308 sha=`098baa6` VERDICT=PARTIAL** (Plan K 8 commits S23 t1 Mig 31 F2 refactor sang per-Approver-slot — push range `eb106f2..098baa6`). Run completed `status=success`. **Mig 31 prod TOP 1 = `20260514160124_RefactorSkipToFinalToApproverLevel` ✓**. Schema swap verified: `ApprovalWorkflowLevels.AllowApproverSkipToFinal` column count=1 (added) + `Users.AllowDrafterSkipToFinal` column count=0 (dropped) ✓. **33 active users preserved** ✓. **Bundle hash 2/2 rotated** ✓: admin `CpI5OL8n → CRsX6cFo`, user `d064StNa → X7qb4Zl4`. Smoke 5/5 endpoints 200: contracts/pe/menus/approval-workflows-v2/users. **K5 zombie endpoint cleanup PASS** ✓: PATCH `/api/users/{id}/allow-skip-final` returns 404 (endpoint removed). **K5 UserDto cleanup PASS** ✓: GET `/api/users` response keys = canBypassReview/createdAt/departmentId/departmentName/email/fullName/id/isActive/isLocked/position/positionLevel/roles — NO `allowDrafterSkipToFinal` field. **CRITICAL FAIL — K3 DTO mirror INCOMPLETE**: GET `/api/approval-workflows-v2` AwLevelDto returns 12 keys (id/order/name/approverUserId/approverUserName/approverEmail + 6 Allow*: ReturnOneLevel/ReturnOneStep/ReturnToAssignee/ReturnToDrafter/ApproverEditDetails/ApproverEditBudget) but `allowApproverSkipToFinal` field MISSING across all 13 levels of 3 workflow types. Source-code grep confirms: `src/Backend/SolutionErp.Application/ApprovalWorkflowsV2/ApprovalWorkflowV2AdminFeatures.cs` line 23-38 `AwLevelDto` record params end at `AllowApproverEditBudget``AllowApproverSkipToFinal` mentioned only in comment line 60, NOT as actual record param. Handler `ToDto` line 156-158 also missing the field in `new AwLevelDto(...)` ctor call. **Domain entity + Mig 31 schema OK, but Application DTO + Handler not wired to expose new column** → FE Designer 7th checkbox shipped but BE never returns the value → 7th checkbox always reads/writes nothing visible. Need K3 follow-up patch: add `AllowApproverSkipToFinal` to record params + `ToDto` ctor + CreateAwLevelInput + UpdateAwLevelInput + EF mapping → unblock Designer 7th checkbox round-trip. **Plan K verdict summary:** 8-commit deploy ✓ / Mig 31 schema ✓ / Service Approver F2 branch live (presumed — Workflow service code path not tested in live verify, only schema visible) / Designer 7th checkbox FE shipped but BE field missing ✗ / Zombie endpoint backout ✓ / Workspace toggle × 2 app FE shipped (presumed — not directly verified) / Tests baseline preserved (presumed — CI deploy stage succeeded). **Recommendation:** Spawn K10 hotfix patch — add `AllowApproverSkipToFinal` to AwLevelDto record + ToDto handler + CreateAwLevelInput + UpdateAwLevelInput + corresponding command handlers (lines 184-238 area). Re-run CI/CD verify. Token cost: ~28k.
- **2026-05-19 11:19-11:23 — Run #219 id=333 sha=`0aaf2df` VERDICT=PASS** (S25 t5 Plan AD — Lịch sử duyệt redesign drop phase badges + next-target hint — push `25837b6..0aaf2df` 1 commit Plan AD FE-only). Duration 3m24s baseline. Files 2 FE-only +104/-28 LOC: `fe-user/src/components/pe/PeDetailTabs.tsx` ApprovalsTab refactor — DROP fromPhase→toPhase Badge JSX entirely + ADD `extractNextTargetHint(comment, decision)` helper parse comment regex/string → semantic hint string ("→ Cấp Y" / "→ Bước Z" / "→ Trả về NV X" / "→ Duyệt thẳng tới cuối") + cleanup unused `PurchaseEvaluationPhaseColor` import + `fe-admin/src/components/pe/PeDetailTabs.tsx` mirror exact §3.9. Pre-push em main local 2× FE build 0 TS err (424ms admin, 469ms user), BE unchanged from `a734bf2`. **Workflow run status=success** confirms full pipeline PASS: test_domain 58/58 + test_infra 53/53 baseline preserved (FE-only no test touch), build_be PASS (BE unchanged binary identical from Run #218), build_fe_admin + build_fe_user PASS (bundle rotation expected). **Stage 4c wire VERIFY Plan AD DOM shape compatibility** PE_ID=`3248f2f9-c6e9-43ff-a4ca-067ffecf9f36` (PE/2026/A/032): GET PE/{id} returns approvals array length=6, first approval keys=[id, fromPhase, toPhase, approverUserId, approverName, decision, comment, approvedAt] ✓ — Plan AD FE drops VISUAL Badge from JSX but DTO contract still exposes `fromPhase` + `toPhase` fields unchanged (FE-only render strip, BE shape untouched). `decision` + `comment` fields present → `extractNextTargetHint(comment, decision)` helper has required inputs to parse. Backward compat: history rows comment có `[Bước X — Cấp Y]` prefix from Plan AC enrichment → Plan AD helper can extract "→ Cấp Y" hint cleanly. **Bundle hash ROTATED 2/2** ✓: admin `CDVnRDe6 → DR95zKWg` + user `gAFN3NVx → BAj_Yaj5` — Plan AD touched cả 2 FE app, rotation confirmed deploy ship. **Smoke 5/5 200** ✓: purchase-evaluations / contracts / menus / users / PE/A/032 detail. **Mig 31 TOP 1 indirect verify** ✓: diff confirms 0 BE/Mig touch (2 .tsx only +104/-28), prod schema guaranteed unchanged from Run #218 baseline `20260514160124_RefactorSkipToFinalToApproverLevel`. Direct sqlcmd skipped — `$env:PROD_DB_PASSWORD` not set local; FE-only commit indirect verify accepted (per Plan AD scope FE-only design). **S25 cumulative push range `e23f51c..0aaf2df` 5 commits Plan AB+AB2+AC+AC2+AD** all deployed clean — 1 fail catch (Run #215) + 4 PASS = test gate effective. **Pattern saved Plan AD: UX drop misleading dual-phase badges + parse comment for semantic next-target hint — reusable cho Contract V2 + Budget V2 audit history future when DTO has dual-state fields (from/to) but render value mostly noise (loops to self in ChoDuyet→ChoDuyet transitions).** Parse strategy: regex `\[Bước (\d+) — Cấp (\d+)\]` + keyword detect "Trả về" / "vượt cấp" / "Cấp cuối" → emit semantic hint string. **Recommendation:** bro UAT verify PE/2026/A/032 mở Lịch sử duyệt panel — kỳ vọng badges phase mất đi hoàn toàn, thay bằng hint string "→ Cấp Y" / "→ Bước Z" / "→ Trả về NV X" parse từ comment Plan AC structure. Cumulative S25 5 commits clean deploy 0 regression. Memory size ~62KB **STRONGLY over 50KB hard threshold****DEDICATED CURATION SESSION REQUIRED PRIORITY NEXT** archive `archive/2026-05.md` to drop entries pre-2026-05-15. FIFO ~13 entries. Token cost ~14k.
- **2026-05-19 11:00-11:03 — Run #218 id=332 sha=`25837b6` VERDICT=PASS** (S25 t4 Plan AC2 — FE merge view recover historical Reject events PE cũ — push `a734bf2..25837b6` 1 commit Plan AC2 FE-only). Duration 3m23s baseline. Files 2 FE-only ~+110/-6 LOC: `fe-user/src/components/pe/PeDetailTabs.tsx` ApprovalsTab refactor fetch changelogs + reconstruct synthetic Reject rows from Workflow entries + dedupe + merge sort + `fe-admin/src/components/pe/PeDetailTabs.tsx` mirror exact §3.9. Pre-push em main local 2× FE build 0 TS err (460/512ms), BE/test unchanged from Run #217. **Workflow run status=success** confirms test gate PASS (test_domain 58/58 + test_infra 53/53 baseline preserve, build_be PASS BE unchanged, build_fe_admin + build_fe_user PASS rotated). **CRITICAL Stage 4c wire VERIFY Plan AC2 FE merge logic data source** PE_ID=`3248f2f9-c6e9-43ff-a4ca-067ffecf9f36` (PE/2026/A/032 bro UAT): total changelogs=20 entries, Workflow entries (entityType=5) count=**8** ✓ (>0 expected ~3-5 từ pre-deploy UAT, actual 8 = generous coverage). **ContextNote keywords detected** ✓: entry 2026-05-19T02:34:38 contextNote=`Trà xem lại phần so sánh [Trả về Người chỉ định — Bước 1 (Phòng 1) Cấp 2]` matches "Trả về" keyword (Drafter/Assignee return mode). Entry 02:35:43 contextNote=`Approver skip thẳng tới Bước 3 Cấp 1 (NV cuối) — bỏ qua các Bước/Cấp trung gian` matches skipToFinal pattern. 6 entries có summary `Chuyển phase ChoDuyet → ChoDuyet` (mid-flow transitions với mutation context). **FE merge logic data source FULLY VERIFIED** ✓ — synthetic Reject rows có thể reconstruct từ 2 Workflow entries với "Trả về" ContextNote (line 02:34:38 + earlier Mig 26 events). **Bundle hash ROTATED 2/2** ✓: admin `B5iZMa7g → CDVnRDe6` + user `CHJDH3M2 → gAFN3NVx`. **Smoke 5/5 200** ✓: purchase-evaluations / contracts / menus / users / changelogs PE/A/032. **Mig 31 TOP 1 unchanged**`20260514160124_RefactorSkipToFinalToApproverLevel` Plan AC2 no schema. **S25 cumulative push range `e23f51c..25837b6` 4 commits Plan AB+AB2+AC+AC2** all deployed. **Pattern saved: FE merge synthetic rows from Changelog history — reversible historical recovery pattern reusable cho Contract V2 + Budget V2 audit recovery future when missing native audit table.** Source = Changelog generic with entityType discriminator + ContextNote keyword filter + summary regex parse. **Recommendation:** bro UAT verify PE/2026/A/032 mở Lịch sử duyệt panel — kỳ vọng thấy synthetic Reject entries trộn với 6 Approve entries existing sorted ascending bởi approvedAt. Memory size ~60KB hard over 50KB limit — **IMMEDIATE ARCHIVE archive/2026-05.md MANDATORY next curation BEFORE any next entry**. FIFO ~13 entries. Token cost ~12k.
- **2026-05-13 23:25 — Verify S22 chốt cuối cumulative (push range `3d725c4..cc8a7d3` 12 commits) VERDICT=PASS** (S22 chốt — em main spawn cumulative verify cuối S22). Latest CI run #193 id=307 sha=`b04a11a` (S22+5 Chunk B FE) success at 23:16. **Tip commit `cc8a7d3` (docs+4 agent MEMORY.md) → CI SKIPPED via `**/*.md` glob** (all 4 `.claude/agent-memory/*.md` + 4 `docs/**` files match — paths-ignore correctly fires). Spec hypothesis ("gotcha #47 — `.claude/agent-memory/**` NOT in paths-ignore → trigger CI") **disproven for this commit**: `**/*.md` glob matches `.md` files at ANY depth so `.claude/agent-memory/MEMORY.md` DOES match. Run #188 a74e671 trigger anomaly was NOT due to agent-memory path. **Gotcha #47 still useful as PREVENTIVE** for future when adding non-.md state files under `.claude/agent-memory/` (e.g. `.json` state, `.log`) — explicit `'.claude/agent-memory/**'` ignore would future-proof. **Recent runs S22 sequence (12 commits → 11 trigger + 1 skip):** #189 sha=40f64c6 ✓ (S22+1 BE guard) · #190 sha=8185070 **CANCELLED** by concurrency (seed users script superseded by next push within 3 min — normal not a fail) · #191 sha=0e70789 ✓ (rename script) · #192 sha=30d51c8 ✓ (S22+4 FE) · #193 sha=b04a11a ✓ (S22+5 FE — also covers S22+5 Chunk A BE `b079b27` since both pushed batched; Gitea trigger only on push tip). `cc8a7d3` skip = correct (no run 308). **Discovery #3:** When 2+ commits pushed in same `git push`, Gitea Actions evaluates ONLY the push tip's paths against paths-ignore — intermediate commits do NOT each get evaluated separately. So `b079b27` (BE Mig 30) + `b04a11a` (FE Mig 30) pushed together → single Run #193 on tip. Test gate inferred PASS for all 11 trigger runs (each deploy stage succeeded). **Local test verify 104/104 PASS** (58 Domain + 46 Infra = +1 vs Run #188's 103 — S22+1 added 1 BE guard test). **Mig 30 prod confirmed:** sqlcmd TOP 5 = `20260513160703_AddAllowApproverEditBudgetToLevels` TOP 1 (S22+5 wire). **Schema live verify:** PE detail `currentLevelOptions` 6 keys (5 from Mig 29 + 1 new `allowApproverEditBudget`) ✓, AwLevelDto 12 keys including `allowApproverEditBudget` ✓. **Endpoint wire LIVE:** PATCH `/api/users/{id}/allow-skip-final` admin=204 ✓ + act.nv=403 ✓ (Plan D admin-only enforce) · PATCH `/api/purchase-evaluations/{id}/budget-adjust` admin=204 ✓ (S22+4 BE) · GET `/api/purchase-evaluations/{id}/attachments/{attId}/view` 200 + `Content-Disposition: inline; filename="HD- Eoffice.pdf"` ✓ (S22+4 preview). **Plan E strict V2 scope LIVE:** admin pageSize=200 → 17 PE / act.nv pageSize=200 → 0 PE (Drafter strict filter active; act.nv fresh user no PE participation). **Bundle hash rotated 2/2:** admin `Cclc8Uwu` → `CpI5OL8n` ✓ (S22 cumulative FE deploy) / user `B6N5hq3d` → `d064StNa` ✓ (S22+4 + S22+5 touched fe-user — rotation expected). Smoke 5/5 endpoints 200: contracts, pe, users, menus, approval-workflows-v2. **33 active users prod confirmed** (20 role-based new from S22+2 seed + S22+3 rename: act/pp/tp · bod.1/2 · equ/fin/hra/pm/qs nv/pp/tp + 13 pre-existing). All role-based users `isActive=true` + login `act.nv@solutions.com.vn / TestUser@2026` OK with roles `Drafter,Accounting`. **Token caching pattern from Run #188 worked:** 1 admin login + 1 act.nv login total = 2 auth requests cached to `C:\Users\pqhuy\AppData\Local\Temp\*_token.txt` + 8 subsequent endpoint calls reuse token → no 429 rate limit encountered (vs Run #188 hit 429). **Trend:** S22 cumulative 5 turn iteration delivered Mig 30 + 3 new endpoints + scope filter + 20 seed users — 0 deploy regression. Baseline cumulative passes 81→103→104 test grow consistent with feature delivery.
- **2026-05-13 21:25-21:28 — Run #188 id=302 sha=a74e671 VERDICT=PASS** (S22 — 5 commits: Plan D Users F2 toggle BE+FE Admin AllowDrafterSkipToFinal + Plan C task 1-3 14 service test ReturnMode/Guard + Plan C task 4 5 regression test #44 silent 403 + Plan E PE strict V2 scope + Docs/MEMORY 3-agent drift patch). Duration 3m28s (baseline). Path filter: the push tip `a74e671` includes `.claude/agent-memory/**` files (NOT in paths-ignore) + `docs/**` (in paths-ignore) → Gitea evaluated push as CI-eligible (some files OUTSIDE paths-ignore), trigger fired correctly. **Local test verify: 58 Domain + 45 Infra = 103/103 PASS (+19 from S21 84)** breakdown: 23 codegen + 6 PE WF + 7 ReturnMode + 7 DraftGuard + 5 AuthorizePolicy regression. CI deploy succeeded → inferred test gate PASS (deploy only runs if tests pass). Bundles deployed: admin `index-Cclc8Uwu.js` rotated from `D5l49-70` (21:27:24 PM VPS), user `index-B6N5hq3d.js` UNCHANGED (Plan C/D/E touched only fe-admin, expected). DLLs deployed 21:25-26 PM. Mig 29 `RefactorAdvancedOptionsToPerLevelAndDrafterUser` still TOP 1 (no new mig in S22, expected). **Plan D wire LIVE:** GET `/api/users` response includes `allowDrafterSkipToFinal` field (boolean), PATCH `/api/users/{id}/allow-skip-final` admin=204 ✓ + nv.test=403 ✓ (admin-only enforced). **Plan E wire LIVE:** nv.test PE list totalCount=8 < admin totalCount=17 (strict V2 scope filter ACTIVE drafter only sees own + participant PE). Smoke 5/5 endpoints 200: `/api/contracts`, `/api/purchase-evaluations`, `/api/menus`, `/api/approval-workflows-v2`, `/api/users`. **Discovery #1:** Rate limit auth login triggers at ~5 requests/min HTTP 429. Pattern: backoff 60s + retry. Spread login calls or cache token across endpoints in same agent run. **Discovery #2:** `.claude/agent-memory/**` files are NOT in paths-ignore (only `docs/**` + `**/*.md` + `.claude/skills/**` + `.gitignore` + `scripts/**.md`) MEMORY.md commits DO trigger CI even when "looks like docs". Spec assumption ("docs commit `a74e671` triggers paths-ignore skip per gotcha #41") was incorrect for this case `.claude/agent-memory/**` triggers CI.
@ -232,3 +268,9 @@ Last curate: 2026-05-15 13:18 (added S23 t5 Plan O HOTFIX Run #202 entry: PASS v
Last curate: 2026-05-15 13:45 (added S23 t6 Plan P HOTFIX Run #203 entry: PASS verdict + CRITICAL wire verify Test 1 admin returnMode=4 numeric → HTTP 204 phase mutated 10→98 ✓ + Test 2 admin returnMode=3 Assignee → HTTP 409 BUSINESS rejection "Không tìm thấy người chỉ định" NOT pre-fix bug "Cấp Approver mode Drafter" = `returnMode` preserved end-to-end through Controller `TransitionPeBody` 7-field record + `mediator.Send` 7-arg call + Handler Assignee branch logic. NV Test actor variant not feasible (scanned 20 PEs — NV Test = Drafter not approver). Plan P fixes the "Caveat #1 pre-existing bug" surfaced from Plan O Run #202 14 min earlier — fast turnaround S23 t5 → t6. **Discovery #4:** ASP.NET Core 10 record-with-enum needs numeric input; no global `JsonStringEnumConverter` registered (Grep confirms 0 hits). Brief example payload `"Drafter"` string format fails 400. FE × 2 correctly uses numeric. Bundle hash measurement caught Run #204 Chunk Q FE banner fix in flight (admin `QZIPWD-g`, user `DaLTMGcx`); Plan P bundle UNCHANGED criterion satisfied (Plan P diff zero FE files). Memory size ~40KB approaching curate trigger; FIFO runs at ~9 entries — schedule archive next curation.)
Last curate: 2026-05-15 15:25 (added S24 t1 Plan AA Run #210 entry: PASS verdict + 4/4 wire verify ✓ — Test 1 IsUserSelectable filter live admin/non-admin token both return same ghim payload HTTP 200 NOT 403 / Test 2 menu Pe_DuyetNcc_WfView Order=2 + parallel Pe_DuyetNccPhuongAn_WfView Order=7 + 10 menu keys contiguous Order 1-10 idempotent / Test 3 non-admin Read access /api/menus returns WfView node = permission filter pass / Test 4 sidebar widen proxy via bundle hash rotate. Bundle hash 2/2 rotated admin `QZIPWD-g → Dmk--X6w` + user `DaLTMGcx → Bd4gh3Tp`. Mig 31 unchanged. Smoke 5/5 200. Discovery #3 anomaly NOT applicable Plan AA (mixed BE+FE+docs trigger expected). Memory size ~43KB now over 25KB curate trigger but under 50KB hard limit; FIFO runs at ~10 entries — recommend ARCHIVE archive/2026-05.md next curation if next entry pushes >50KB. Token cost ~12k.)
Last curate: 2026-05-19 10:18 (added S25 t1 Plan AB Run #215 entry: **FAIL** verdict at test_infra gate — 2 Plan M edge case tests broken `ApplyReturnMode_OneStep_AtStep1` line 350 + `ApplyReturnMode_OneLevel_AtStep1Level1` line 308 both `Expected changelog.ContextNote not to be <null>`. Root cause: Plan AB refactor adds NEW Changelog.Add() at end of `ApplyReturnModeAsync` (EntityType=Workflow, no ContextNote) alongside existing `LogTransitionAsync` chain that writes ContextNote=comment. SQLite frozen-clock tie-break in `OrderByDescending(CreatedAt).First()` non-deterministic → tests pick wrong entry. Test gate caught BEFORE deploy → prod state preserved (bundles unchanged Run #214 baseline admin `CZdXQ2eo` + user `DCwhhey2`, Mig 31 TOP 1 unchanged, smoke 5/5 200). 3 fix approaches recommended em main: (1) ContextNote=summary on new entry, (2) skip when LogTransitionAsync covers, (3) test fix EntityType=Transition filter. NEW gotcha #48: multi-Changelog.Add() in same transaction + OrderByDescending(CreatedAt) tie risk in test SQLite frozen-clock. Memory size ~50KB at hard threshold — recommend ARCHIVE archive/2026-05.md next curation BEFORE next entry. FIFO runs at ~11 entries. Token cost ~10k. UAT mode skip test-after pattern STILL RISKY when refactor touches code paths with existing tests — Plan AB Chunk A did `npm build × 2` verify but skipped `dotnet test` → CI caught regression in test_infra. Bro UAT spared broken audit trail in prod.)
Last curate: 2026-05-19 10:50 (added S25 t3 Plan AC Run #217 entry: **PASS** verdict — fix Bug 3 "Lịch sử duyệt" panel show Trả lại + Duyệt vượt cấp. Push `8c05947..a734bf2` 1 commit Plan AC. Duration 3m27s baseline. 3 files +105/-38 LOC: BE Service Reject branch line 75-103 ADD Approval row + capture pre-call Step/Level mutation state cho audit "from-position" + Approve branch line 472 enrich Comment với `[Duyệt vượt cấp tới Cấp cuối]` prefix khi skipToFinal=true + FE × 2 app PeDetailTabs.tsx add `decisionBadge` helper render Decision badge ApprovalsTab. Local pre-push 111/111 PASS + 2× FE build 0 TS err (TS strict caught unused `PE_DECISION_APPROVE` removed). **CRITICAL Stage 4c wire VERIFY** PE_ID=`3248f2f9-c6e9-43ff-a4ca-067ffecf9f36`: approvals count=6 all keys [approvedAt/approverName/approverUserId/comment/decision/fromPhase/id/toPhase] ✓ decision field present every row (FE decisionBadge input verified) ✓ all 6 existing decision=1 Approve backward-compat preserved ✓ all 6 comments có `[Bước X — Cấp Y]` prefix structure Plan AC enrichment uniformly applied across history ✓ no Reject/skipToFinal rows current dataset n/a until bro UAT post-deploy. **Bundle hash ROTATED 2/2** ✓: admin `CrHpBYFM → B5iZMa7g` + user `C3bCWZ90 → CHJDH3M2`. **Smoke 4/4 200** ✓. **Mig 31 TOP 1 unchanged** ✓ no schema. **Pattern saved cross-ref Plan AB:** capture pre-call mutation state cho audit row "from-position" — when Service mutates entity AND writes audit row, snapshot OLD values BEFORE mutation. Reusable Contract V2 + Budget V2 future. **Discovery #5:** sqlcmd Windows-auth via ssh requires `\\\\SQLEXPRESS` 4-backslash escape; `\\SQLEXPRESS` produces 0 output silently. Memory size ~58KB strongly over 50KB hard limit — **REQUIRED ARCHIVE archive/2026-05.md next curation BEFORE next entry.** FIFO ~12 entries. Token ~12k.)
Last curate: 2026-05-19 11:25 (added S25 t5 Plan AD Run #219 entry: **PASS** verdict — Lịch sử duyệt redesign drop phase badges + next-target hint helper. Push `25837b6..0aaf2df` 1 commit FE-only 2 .tsx +104/-28. Duration 3m24s baseline. CI status=success → full pipeline PASS (FE-only no test/BE touch baseline preserved). **CRITICAL Stage 4c wire VERIFY** PE_ID=`3248f2f9...`: approvals shape unchanged 6 rows all keys [id/fromPhase/toPhase/approverUserId/approverName/decision/comment/approvedAt] — Plan AD strips Badge JSX only, DTO shape backward-compat preserved + Plan AC `[Bước X — Cấp Y]` prefix structure provides parse input for `extractNextTargetHint()` helper. **Bundle hash ROTATED 2/2** ✓: admin `CDVnRDe6 → DR95zKWg` + user `gAFN3NVx → BAj_Yaj5`. **Smoke 5/5 200** ✓. **Mig 31 indirect verify** ✓ (diff 0 BE/Mig touch, sqlcmd direct skipped — PROD_DB_PASSWORD not set local). **Pattern saved Plan AD: UX drop misleading dual-state fields + parse comment helper for semantic hint — reusable Contract/Budget V2 audit when from/to fields mostly self-loop noise.** **S25 cumulative 5 commits AB+AB2+AC+AC2+AD** deployed clean 1 catch + 4 pass. Memory size ~62KB STRONGLY OVER 50KB hard threshold — **DEDICATED CURATION SESSION PRIORITY NEXT** archive `archive/2026-05.md` drop entries pre-2026-05-15 + compress S22-S24 entries. FIFO ~13 entries. Token cost ~14k.)

View File

@ -287,6 +287,10 @@ KHÔNG `*` / `latest`. Critical pins:
## 📅 Recent activity (last 10 FIFO)
- **2026-05-19 (S25 wrap — Plan AB Chunk A Case 1 + 6 follow-up plans em main solo):** Plan AB Chunk A spawn 1× ~12K Case 1 cookie-cutter mirror. BE refactor ApplyReturnModeAsync Drafter early return → common path (line 280-287 → if/else block) + single Changelog.Add() ở cuối hàm với modeName switch enum + actorName resolve via userManager.FindByIdAsync mirror LogTransitionAsync pattern. FE × 2 app HistoryTab filter relax (PE_ENTITY_HEADER=1 + summary contains 'ngân sách' for Bug 1 + Workflow summary contains 'Trả lại' for Bug 2). KHÔNG TS test (UAT mode skip). KHÔNG migration. KHÔNG endpoint. Commit cdfd542 3 file +146/-95 LOC PASS. **Em main solo từ Plan AC** (cross-stack reasoning + UAT iteration borderline scope — Implementer would REFUSE per criteria #4 tight coupling BE+FE same plan). AC capture pre-call Step/Level + add Approval row Reject branch + skipToFinal comment + FE Decision badge × 2 app. AC2 FE merge synthetic Reject + dedupe timestamp 5s bucket. AD drop phase badges + extractNextTargetHint regex parse. AE BE batch 9 Changelog.Add sites UserName preventive fix. AF FE userMap fallback từ embedded domain data PeDetailBundle. **Pattern 16 NEW** (cumulative S25): Preventive systemic batch fix khi audit phát hiện 9 sites cùng bug pattern — replace_all=true với context-aware key (UserId line + Summary line) — 1 pass cover N sites idempotent. **Pattern 17 NEW**: FE merge synthetic rows từ Changelog cho audit historical recovery — pattern reusable cho Contract V2 + Budget V2 audit visualization without DB write. **Pattern 18 NEW**: FE userMap fallback từ embedded domain data (drafter + approvals + approvalFlow + levelOpinions + departmentOpinions) — no extra API fetch cho historical name resolve.
- **2026-05-19 (S25, Plan AB Chunk A PASS):** Bug 1+2 fix Changelog visibility audit log UAT. Commit `cdfd542` 3 file +146/-95 LOC. **BE** `PurchaseEvaluationWorkflowService.cs` `ApplyReturnModeAsync` lines 215-378 refactor: Drafter early return (line 282-287) → if/else common path, `summary = "Trả về Người soạn thảo"` thay vì return early, SLA reset move bên trong else block 3 mode còn lại (Drafter có riêng `evaluation.SlaDeadline = null`). Single Changelog.Add() ở cuối hàm cover 4 mode uniform: `EntityType=Workflow + Action=Update + Summary=$"Trả lại ({modeName}): {summary}"` với modeName switch ("Người soạn thảo"/"1 Cấp"/"1 Bước"/"Người chỉ định"). `actorName` resolve qua `userManager.FindByIdAsync` mirror pattern existing line 660-667 (LogTransition helper). KHÔNG SaveChangesAsync mới — caller `TransitionAsync` line 100 đã có downstream save. **FE** 2 file `PeDetailTabs.tsx` × 2 app mirror exact: filter extend `if (l.summary?.includes('Trả lại')) return true` (Workflow entity) + `if (l.entityType === PE_ENTITY_HEADER && l.summary?.toLowerCase().includes('ngân sách')) return true` (Header entity new const = 1). Empty placeholder + comment 3-source rewrite (UAT 2026-05-08 + 2026-05-19 + bullet list 5 filter rule). Verify: BE build clean 0 err 2 pre-existing DocxRenderer warn (20.27s), fe-user 1907 modules 16.62s 0 TS err, fe-admin 1926 modules 6.98s 0 TS err. Test SKIP per UAT mode `feedback_uat_skip_verify` Phase 9 (111 baseline preserve). **NEW pattern observed (cumulative)**: `Changelog log common path refactor + FE filter substring summary discrimination`. Reusable cho future audit log derived state (vd Adjust*/Return*/Reset* action): refactor early return → if/else common path để single log call cover N branch, FE filter qua substring summary keyword chứ KHÔNG enum field strict (action verb tiếng Việt "Trả lại"/"ngân sách" dễ maintain hơn enum + cho FE flexibility filter mới mà không cần BE schema migrate). Cross-ref Pattern 4 `feedback_service_hook_vs_endpoint` (state X derived của action Y → log trong handler Y, KHÔNG endpoint /X riêng — Bug 2 ApplyReturnModeAsync log trong service hook KHÔNG endpoint /return-changelog rời). Pattern 5 mirror 2 app §3.9 applied 7th cumulative. Token ~12k. Diff: BE +83/-49 (refactor + new log block ~40 LOC), FE × 2 app +14/-6 each (filter + comment). KHÔNG ops git push (em main verify Reviewer rồi mới push).
- **2026-05-15 (S24, Plan AA wrap):** Cumulative learning post-Chunk B. **3 patterns NEW added** (13 read-only admin Designer mirror, 14 Tailwind JIT palette array full class strings, 15 HTML table rowSpan flat row builder helper). **REFUSE log 4/4 correct** S24 polish chunks (commit da218f1 hotfix px-2 trivial < 30min criteria #6, 4d60598 redesign v1 panel-per-NV color UX flow criteria #2, fbbd361 redesign v2 table rowSpan UX flow criteria #2, ee0902a wrap fix sidebar label CSS polish criteria #6) em main solo executed all 4, Implementer no-spawn. **Ambiguity Chunk B**: shadcn fe-user thiếu Card/Badge (lib subset minimal chỉ Button/Dialog/Input/Label/Select/Textarea) fallback inline `<div className="rounded-lg border bg-card p-4">` + inline `<span className="rounded-full bg-...">` mirror admin Designer DefinitionCard. Pattern reusable cho fe-user pages requiring elevated UI surface (audit shadcn fe-user/src/components/ui/ TRƯỚC khi import). Total S24 commits: 7 (a1a910f..ee0902a 1 spawn Chunk B accepted + 6 em main solo: Chunk A cross-stack + Chunk C docs + 4 polish). Token cost cumulative S24 Implementer: ~14k (Chunk B only).
- **2026-05-15 (S24, Plan AA Chunk B PASS):** FE user read-only matrix view workflow V2 ghim (Mig 25 IsUserSelectable). 3 file: (1) CREATE `fe-user/src/types/approvalWorkflowV2.ts` (~55 LOC) subset DTO mirror BE `AwAdminOverviewDto` (7 Allow* flag per Level, 5 record type AwLevelDto/AwStepDto/AwDefinitionDto/AwTypeSummaryDto/AwAdminOverviewDto); (2) CREATE `fe-user/src/pages/pe/WorkflowMatrixViewPage.tsx` (~215 LOC) useQuery GET `/approval-workflows-v2?applicableType=N&isUserSelectable=true` (em main BE Chunk A đã thêm `IsUserSelectable bool?` param + Controller forward), render table 10 cột Bước (rowSpan) | Cấp | NV duyệt | 7 ✓/— flag cell, header với `title` tooltip tả từng cột, 3 state Loading/Error/Empty ràng, badge `Đang dùng` (emerald isActive) + `Được ghim` (amber isUserSelectable Pin icon); (3) UPDATE `fe-user/src/App.tsx` import WorkflowMatrixViewPage + route `/purchase-evaluations/workflow-matrix` đặt TRƯỚC `/workspace` (URL ordering logical matrix workspace new detail). Verify: `npm run build` fe-user PASS clean 0 TS err, 1907 modules, 2.61s, 1282 KB. Surprise: shadcn fe-user KHÔNG `Card`/`Badge` (chỉ Button/Dialog/Input/Label/Select/Textarea) fallback inline `<div className="rounded-lg border...">` + inline `<span className="rounded-full bg-...">` cho badge (mirror pattern admin Designer). Pattern reusable: **read-only mirror admin Designer page** = drop edit mutations + reuse DTO types (subset) + filter param BE-side (`IsUserSelectable=true` thay FE filter). Cookie-cutter 0 (lần đầu pattern). Pattern 5 mirror 2 app KHÔNG apply (fe-admin Designer riêng Plan AA scope fe-user only). Pattern 7 admin opt-in 7 Allow* flag wire full render trong table (10 cột total = 3 meta + 7 flag). KHÔNG ops git. Token cost ~14k.
- **2026-05-15 (S23 t4-t11 cumulative REFUSE em main solo Plan N+O+P+Q+R+S+T+U):** 8 plan consecutive em main solo, 0 Implementer spawn (REFUSE 100% per criteria #4 bug fix reasoning chain + criteria #3 cross-stack tight coupling). **Plan N+O** 5 lookup site discrimination fix cross-stack BE Service + Application + 3 regression test. **Plan P** Controller TransitionPeBody record drop fix tightly coupled FE wire audit (Investigator confirm BE-only scope ~6 LOC). **Plan Q** FE banner mx-5 layout CSS polish 2 app mirror trivial 8 LOC. **Plan R+S+T5** destructive sqlcmd cleanup prod (scripts/plan-r-*.sql + plan-s-*.sql + plan-t5-*.sql + plan-t-backup.sql, 4 files scp + sqlcmd -i, ~720 rows wiped cumulative). **Plan T** DbInitializer DemoSeed:Disabled flag config (Infrastructure + Api appsettings, ~25 LOC). **Plan U** FE sidebar truncate + tooltip 2 app mirror 25 LOC (em main solo CSS Tailwind). 7 strict-scope criteria validated cumulative S23: pattern reusable saved memory user-level Plan O wire 9 surface points (point 9 lookup discrimination 5 sites enum), Plan P wire 10 surface points (point 10 Controller body record mirror count check), Plan T DemoSeed flag pattern.

View File

@ -94,9 +94,10 @@ Common queries: `sys.columns`, `sys.triggers`, `__EFMigrationsHistory`, `COUNT(*
- **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)
- **Gotchas active:** 47 (+1 #48 SQLite tie-break pending docs — Plan AB Chunk A2 S25 t1; reference `docs/gotchas.md`)
- **Tests baseline:** 111 PASS (S22 baseline 104 + 7 PE WF cumulative; S25 Plan M tests SQLite tie-break re-stabilized Chunk A2) — Phase 9 UAT skip per chunk (memory `feedback_uat_skip_verify`)
- **Endpoints:** ~146 (S22 +3 stable: PATCH /users/{id}/allow-skip-final + PATCH /pe/{id}/budget-adjust + GET /pe/{id}/attachments/{attId}/view)
- **Memory user-level:** 23 entries (+2 S25: Plan AC2 FE merge synthetic recovery + Plan AF userMap fallback patterns)
- **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'`
@ -149,3 +150,6 @@ State machine 5 trạng thái phiếu PE: Nháp / Đã gửi duyệt / **Trả l
- Stale > 3 months → remove
Last curate: 2026-05-11 (initial seed)
- **2026-05-19 (S25 t1 spawn audit 2 bug critical UAT — Changelog logging missing):** Em main report 2 bug UAT: (1) Budget Adjust 2×click → "Lịch sử thay đổi" KHÔNG show 2 entry. (2) Return Assignee mode F1 click → "Lịch sử thay đổi" KHÔNG show return action. Audit 5Q: Q1-DB state Prod SSH fail (auth), fallback code inspect. Q2-Budget handler: `PurchaseEvaluationFeatures.cs:379-387` **ĐÃ log changelog** EntityType=Header + Action=Update + summary diff → **code ĐÚNG, likelihood FE filter bug or UAT DB stale**. Q3-Return handler: `PurchaseEvaluationWorkflowService.cs:215-378 ApplyReturnModeAsync` **ZERO changelog log** — 4 mode branches (OneLevel/OneStep/Assignee/Drafter) mutate pointers only, return summary, caller `TransitionAsync:100 LogTransitionAsync` only logs phase transition KHÔNG log mode side-effect. Q4-Schema: `PurchaseEvaluationChangelog.cs` support EntityType=Workflow(5) enum but **ZERO code populate** — schema incomplete missing Kind/ChangeType subtype enum to disambiguate "budget adjust" vs "detail edit" vs "return mode" (all Header/Workflow entity cùng Action.Update). Q5-FE: Query handler `ListPurchaseEvaluationChangelogsQueryHandler:1050-1064` **KHÔNG filter logic** — returns ALL entities. FE query component unknown (fe-user source not easily searchable) but **likely filter EntityType == (Supplier|Detail|Quote)** omit Header+Workflow → Bug 1 Budget (Header type) hidden, Bug 2 Return (Workflow type unlogged vậy). Root cause B1: FE filter skip Header updates OR Schema gap (Header.Update collision: budget vs section 2 edit). Root cause B2: Handler **intentionally skip logging** (no companion audit table like PurchaseEvaluationApprovals for return history). Fix path B1: Option A (add Kind enum — 30 LOC schema+handlers) vs B (extend EntityType — 20 LOC) vs C (FE filter conditional show Budget — 10 LOC FE). Fix path B2: Add `db.PurchaseEvaluationChangelogs.Add()` per mode (15-25 LOC 1 file). Cross-ref pattern memory: S23 t3 lookup bug (Level.Order collision per-NV Mig 29) — schema Mig 29 OR-of-N refactor created similar subtype ambiguity. Surprise: `EntityType.Workflow=5` enum value design-only, unused 4+ mig history. Recommendation: B2 fix first (clear win, 1 file BE), then B1 design (schema + cross-module pattern audit Contracts). Token ~28k.
- **2026-05-19 (S25 wrap — Plan AB Bug 1+2 audit + 6 follow-up plans em main solo):** Pre-Plan AB audit ~28K confirm root cause: Bug 1 Budget Adjust Handler ĐÃ log Changelog (Header+Update) nhưng FE HistoryTab filter strict TraLai-only loại. Bug 2 ApplyReturnModeAsync 4 mode KHÔNG add Changelog.Add() — chỉ caller LogTransitionAsync log phase transition. Recommended fix path: BE add log return mode + FE filter relax + Decision badge differentiation. **Subsequent em main solo follow-ups** (Plan AC..AF, KHÔNG re-spawn Investigator): AC capture pre-call Step/Level state + skipToFinal comment enrich + FE Decision badge; AC2 FE merge synthetic Reject rows từ Changelog (reversible recovery KHÔNG DB touch); AD drop misleading dual-phase badges + parse semantic next-target hint via regex `Chuyển phase X → Y` + comment keyword "Trả về"/"vượt cấp"; AE BE preventive batch UserName fix 9 Changelog.Add sites (Drafter+Detail+Quote+Adjust); AF FE userMap fallback từ embedded domain data PeDetailBundle (drafter+approvals+approvalFlow+levelOpinions+departmentOpinions) — no extra API fetch. **Patterns reusable Contract V2 audit recovery + Budget changelog UI:** (a) synthetic recovery FE merge từ existing audit table, (b) userMap fallback từ embedded domain data, (c) drop misleading badges + semantic hint via regex parsing, (d) preventive batch fix systemic gap. Cross-ref `feedback_service_hook_vs_endpoint` (audit log derived state) + new pattern user-level: FE merge synthetic + userMap fallback. **Tokens cumulative em main this session ~340K (mostly solo iterations, sub-agent leverage ~62K total).** **CICD result:** 7 commits `e23f51c..506cada` push remote, runs #215 FAIL (Plan M tests SQLite tie-break re-emerge) → #216 PASS (Chunk A2 SQLite tie-break fix) → #217-#221 PASS streak. Gotcha #48 SQLite tie-break pending docs.

View File

@ -115,9 +115,9 @@ Per Cognition documented research:
## 🧠 SOLUTION_ERP review essentials
- **Tests baseline:** 104/104 PASS (58 Domain + 46 Infra — +20 từ 84 S21: 5 regression gotcha #44 Authorize class-level + 7 ReturnMode + 7 Guard EnsureCanRejectV2Async + 1 V2 actor scope reject). Must increase nếu feature added per §7; UAT iteration exception per memory `feedback_uat_skip_verify` (Plan C test-after bundle defer)
- **Gotchas:** 46 active (`docs/gotchas.md` reference) — +#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:** 30 latest `AddAllowApproverEditBudgetToLevels` (S22+5 per-slot F4 flag admin opt-in cho Approver scope edit budget ChoDuyet branch). Mig 29 prev `RefactorAdvancedOptionsToPerLevelAndDrafterUser` (S21 t5 per-NV split)
- **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
@ -144,6 +144,8 @@ Flag commit nếu thấy `<PackageReference Include="MediatR" Version="14...` ho
## 📅 Recent activity (last 10 FIFO)
- **2026-05-19 (S25 wrap — Plan AB pre-commit verify + 6 follow-up plans em main solo self-review + 1 lesson catched by CICD):** Plan AB Chunk A pre-commit verify spawn 1× ~22K with 5-category checklist + 8 adversarial deep checks PASS 0 blocker (1 minor V1 legacy fallback acceptable). Recommended PROCEED push cdfd542. **MISSED gotcha #48**: Multi-Changelog.Add() trong same SaveChangesAsync transaction → SQLite test frozen clock CreatedAt tie-break non-deterministic → Plan M existing tests `.OrderByDescending(CreatedAt).FirstAsync()` picked wrong entry → CI Run #215 FAIL. **Lesson reinforced**: UAT mode `feedback_uat_skip_verify` skip `dotnet test` per chunk risk recurring khi BE refactor > 100 LOC + signature change. Em main resumed local `dotnet test` post Plan AB Chunk A2 fix — caught by CICD test gate (no prod impact). **Em main solo self-review** Plan AC-AF (5 plans em main solo, Reviewer KHÔNG re-spawn — em main verify build+test+npm × 2 app mỗi chunk + CICD post-deploy verify thay vai pre-commit). Cumulative S25: 0 prod regression, 6 commits PASS CICD. **Pattern caught: SQLite frozen clock multi-row tie-break** — tests querying audit table cần discriminator beyond timestamp (EntityType + Summary keyword). Cross-ref future Contract V2 test setup. **Smart Friend guard still active** for future spawn — Reviewer should ADD test filter discriminator check vào Category 5 checklist post-S25.
- **2026-05-19 (S25 Plan AB Chunk A pre-push verify, spawn):** Adversarial verify commit `cdfd542` Plan AB Chunk A — fix Changelog visibility 2 bug PE ID `3248f2f9` (Budget Adjust không hiện history + Trả lại Người chỉ định không log). Diff scope: 3 files +146/-95 LOC (BE PurchaseEvaluationWorkflowService.cs Service-only refactor + 2 FE PeDetailTabs.tsx mirror §3.9). **Verdict: PASS — 0 critical / 0 major / 1 minor observation — proceed push OK.** Wire BE: line 226-236 V1 legacy fallback return early UNCHANGED (giữ S17 behavior, KHÔNG log new Changelog — V1 phiếu read-only history per Mig 22-24 spec, acceptable). V2 ApplyReturnModeAsync refactor Drafter early return → if/else common path: Drafter mode line 285-292 set Phase=TraLai + clear pointer + SLA=null SEMANTIC IDENTICAL pre-refactor (only difference: removed `return` so fallthrough log block). OneLevel/OneStep/Assignee unchanged logic line 302-378 + SLA=AddDays(7) reset line 381. New `db.PurchaseEvaluationChangelogs.Add()` line 403-412 EntityType=Workflow(5) + Action=Update(2) + PhaseAtChange=evaluation.Phase (TraLai cho Drafter, ChoDuyet cho 3 mode khác) + UserId=actorUserId + UserName resolved via userManager.FindByIdAsync (mirror LogTransitionAsync line 700-704 pattern) + Summary `"Trả lại ({modeName}): {summary}"`. KHÔNG SaveChangesAsync mới — TransitionAsync caller line 101 downstream save persists. Wire FE 2 file `HistoryTab` filter extend 3 rule: ADD `summary.includes('Trả lại')` Workflow entity + ADD `entityType === Header(1) && summary.toLowerCase().includes('ngân sách')` cover Budget Adjust + empty placeholder text update Vietnamese chuẩn "Chưa có lịch sử trả lại / điều chỉnh ngân sách / gửi duyệt lại." Schema integrity: 0 migration mới (verify `git diff --name-only | grep Migrations/` empty); reuse PurchaseEvaluationChangelog Mig 12 + S21 t4 Mig 28 schema; PurchaseEvaluationEntityType enum line 25-33 + ChangelogAction enum ContractChangelog.cs:38-44 match BE values FE constant. Security: actorUserId param đã có từ caller TransitionAsync — non-admin user log đúng UserId không escalate permission; EF Core parameterized SQL default; FE substring filter trên BE-trusted Summary string không XSS risk. Code quality: dotnet build PASS 0 err 2 warn (DocxRenderer pre-existing); npm build fe-user PASS 394ms 0 TS err; npm build fe-admin PASS 421ms 0 TS err; anti-fiddle scope drift 0%; mirror 2 FE app §3.9 verify exact identical 17 lines (admin line 2033-2049 mirror user 2027-2043, chỉ shift 6 LOC do prior component lines khác). Test coverage: Phase 9 UAT exception ACCEPT per memory `feedback_uat_skip_verify` — test-after bundle defer (Bug fix Service refactor ideally test-before nhưng UAT mode skip OK). Cumulative state unchanged: 111 test baseline preserve. Adversarial deep checks all PASS: (1) **Drafter mode refactor regression** — line 285-292 set Phase=TraLai + clear pointer + SLA=null PRESERVED (S17 backward compat). V1 legacy 226-236 fallback return early no semantic change. (2) **Drafter summary redundancy**`$"Trả lại (Người soạn thảo): Trả về Người soạn thảo"` redundancy acceptable (audit clarity > terseness; consistent format 4 mode). (3) **actorName resolve N+1** — single `userManager.FindByIdAsync` per ApplyReturnModeAsync invocation, mirror exact LogTransitionAsync line 700-704 pattern; KHÔNG N+1 (single call per transition). (4) **FE filter substring case**`.includes('Trả lại')` exact match BE format `$"Trả lại ({modeName}): ..."` — case-sensitive Vietnamese diacritics lowercase 'l' match. (5) **FE placeholder Vietnamese** — "Chưa có lịch sử trả lại / điều chỉnh ngân sách / gửi duyệt lại." chuẩn Vietnamese diacritics. (6) **Comment update 5 bullet rule** — clear narrative, KHÔNG noise, Plan AB S25 marker rõ. (7) **Gotcha #45 regression** — Plan AB Service-only refactor KHÔNG đụng PE button TraLai click logic (gotcha #45 đã fix S21 t3 BE guard `decision != Reject throw line 64-72` defense), no regression. (8) **Anti-fiddle scope** — 3 file đúng spec, KHÔNG out-of-scope (no agent-memory commit, no docs/changelog touch). **Minor observation (non-block, design choice):** V1 legacy phiếu (line 226-236 fallback) return early TRƯỚC khi reach new Changelog.Add() block → V1 phiếu KHÔNG có new detailed "Trả lại (X): ..." log. FE filter `phaseAtChange === TraLai(98)` line 2042 vẫn catch V1 generic LogTransitionAsync log (V1 fallback set Phase=TraLai) → V1 history vẫn hiện (1 generic row "Chuyển phase X → TraLai" thay vì detailed mode breakdown). Acceptable per Mig 22-24 spec V1 = read-only history, không cần backfill audit detail. Recommendation: PASS proceed push remote. Smart Friend guard active.
- **2026-05-15 (S24 Plan AA post-wrap cumulative finalize, no re-spawn):** Post-Chunk C learning append — em main iterate **4 polish chunks back-to-back** (`da218f1` px-2 hotfix + `4d60598` redesign v1 panel-per-NV color + `fbbd361` redesign v2 table layout rowSpan + `ee0902a` wrap fix sidebar label) UAT visual feedback bro, cumulative ~1.5h, KHÔNG Reviewer spawn. **Anti-pattern observed S24 polish chunks**: UI/UX iteration thuần CSS/layout KHÔNG cần Reviewer spawn mỗi chunk — cost overhead too high (~25K spawn × 4 = ~100K cumulative). Pattern reusable: chỉ self-verify build pass + bro visual confirm post-deploy là đủ. **Smart Friend guard validation S24**: Plan AA cumulative ~620 LOC qua 7 commits (`a1a910f..ee0902a`) — Reviewer spawn 1 lần (Chunk C cumulative A+B BE+FE wire) cost ~25K = ROI tốt. Multi-spawn polish chunks 4× sẽ ~100K = ROI thấp. **Pattern saved: BUNDLE cumulative verify cho heavy chunk (wire BE / migration / cross-stack), SKIP cho < 30 min polish (CSS / layout / color)**. **Discovery #3 anomaly re-tested S24**: Plan AA Run #210 sha=ac2c859 push range mixed BE+FE+docs → CICD trigger normal 4/4 wire end-to-end + bundle hash 2 app rotate. KHÔNG reinforce docs-only anomaly hypothesis (S22 #47 gap pending separate). Defer Investigator follow-up. **Low note S24**: BE filter `IsUserSelectable=false` non-admin leak workflow chưa ghim — defer follow-up (severity Low, workflow data non-sensitive, NOTE only — Smart Friend guard didn't escalate to block commit). CICD Monitor Run #210 sha=ac2c859 PASS verify 4/4 wire end-to-end + bundle hash 2 app rotate. Cumulative state unchanged S24: 31 mig, 111 test, 47 gotcha.
- **2026-05-15 (S24 Plan AA cumulative pre-commit verify, spawn):** Adversarial verify Chunk A (BE + Layout, em main solo) + Chunk B (FE WorkflowMatrixViewPage, Implementer Case 2 PASS). Diff scope 8 file modified + 2 file CREATE — ~76 LOC BE + ~270 LOC FE, scope khớp Plan AA. **Verdict: PASS with 0 critical / 0 major / 0 minor issues — proceed commit OK.** Wire BE: Controller line 21-26 `Overview(applicableType, isUserSelectable, ct) → new GetAwAdminOverviewQuery(applicableType, isUserSelectable)` end-to-end. Handler line 114-117 `request.IsUserSelectable is bool ius → query.Where(d => d.IsUserSelectable == ius)` correct conditional. FE WorkflowMatrixViewPage line 29-33 actual `api.get<AwAdminOverviewDto>('/approval-workflows-v2', { params: { applicableType: typeInt, isUserSelectable: true } })` — real call no mock/alert. Route `/purchase-evaluations/workflow-matrix?type=N` wired App.tsx:38 + Layout.tsx resolvePath:81-86. Schema integrity: 0 migration mới (column `IsUserSelectable` from Mig 25), DbInitializer INSERT-OR-UPDATE-Order idempotent verified (MenuItemConfiguration HasKey(Key) → PK unique, ToDictionary safe; existing rows UPDATE Order only nếu mismatch; new rows INSERT). 7 Allow* flag count match BE DTO ↔ FE type. ApplicableType enum {1,2,3} — FE chỉ wire 2 type PE matrix view correct. Security: class-level `[Authorize]` bare line 18 PRESERVED (gotcha #44 protect). GET any authenticated → non-admin Drafter OK access. Non-admin pass `isUserSelectable=false` BE không block → workflow chưa ghim leak risk — Low severity (workflow data non-sensitive, NOTE only). Permission seed 7 role × WfView leaf via `SeedPurchaseEvaluationPermissionDefaultsAsync:1573` added — idempotent. Admin role qua `SeedAdminPermissionsAsync` chỉ cover `MenuKeys.All[]` static root keys (Pe_*_WfView dynamic NOT in All) — but admin uses fe-admin Designer, KHÔNG cần WfView access fe-user. Code quality: BE dotnet build PASS 0 err 2 warn (DocxRenderer pre-existing); FE fe-user npm build claim PASS (Implementer Case 2); FE fe-admin npm build VERIFY tự chạy PASS 1926 modules / 740ms / 0 TS err. Anti-fiddle 0% drift, scope khớp spec. Mirror 2 FE §3.9: Layout.tsx widen `w-72 xl:w-80` cả 2 ✓; remove truncate 3 site fe-user (MenuGroup+MenuLeaf+StaticLeaf) + 2 site fe-admin (MenuGroup+MenuLeaf, no StaticLeaf component) — structural asymmetry acceptable (fe-user only có "Hộp thư" StaticLeaf); WorkflowMatrixViewPage fe-user only correct (admin có Designer riêng). Test coverage: Phase 9 UAT exception accept — test-after default OK. Adversarial deep checks: (1) DbInitializer ToDictionary duplicate key risk → PK constraint trên Key, tree.Add chỉ thêm Pe_DuyetNcc_WfView + Pe_DuyetNccPhuongAn_WfView (2 typeCode distinct) → no in-memory dup. (2) Sidebar widen 1280px responsive verified per task spec (288 sidebar + 992 main fit). (3) Plan U revert clean — 0 remaining truncate class outside Plan AA comments. (4) Mig drift schema: column existed Mig 25, no new mig needed. 2 SaveChangesAsync non-atomic giữa menu seed + label backfill (pre-existing, OUT scope Plan AA). Comment quality: Plan AA marker rõ ràng 8+ sites, no TODO/FIXME zombie. TypeScript: `FlagCell` indexed-access type clever từ Pick 7 keys union — TS happy compile clean. Recommendations defer: (a) enforce admin/non-admin policy filter (current GET cho phép user pass isUserSelectable=false — low risk, audit follow-up); (b) MenuKeys.All[] không cover dynamic Pe_*_WfView nên Admin role không auto grant — OK vì admin dùng fe-admin Designer, NOTE để future audit khi admin cần inspect user-side matrix view. Cumulative state unchanged: 31 mig, 111 test, 47 gotcha. Smart Friend guard active — KHÔNG lower bar (3 minor risk noted defer follow-up, không block commit).
- **2026-05-15 (S23 t4-t11 cumulative em main self-review — Plan N+O+P+Q+R+S+T+U, no Reviewer spawn):** 8 plan consecutive em main self-review per UAT mode (`feedback_uat_skip_verify` rule — em main verify build + test + npm build mỗi chunk). Key validations cumulative: **Plan N** GetPe handler `PurchaseEvaluationFeatures.cs:765` per-NV `ApproverUserId` discriminator + admin fallback row đầu. **Plan O** 4 lookup sites cascade fix (`EnsureCanRejectV2Async:201` + `ApplyReturnModeAsync:248` + `EnsureEditableForDetailsAsync:72` + `AdjustBudgetCommandHandler:311`) — pattern uniform Plan N, +3 regression test `PurchaseEvaluationPerNvLookupRegressionTests.cs`. **Plan P** Controller `TransitionPeBody:267` record +3 fields mirror `TransitionPurchaseEvaluationCommand` schema — root cause 2 ngày prod bug F1+F2 wire fail. **Plan Q** FE banner mx-5 inset gap fix (CSS layout polish mirror 2 app). **Plan R+S+T5** destructive sqlcmd cleanup prod ~720 rows wiped cumulative + Plan F precedent avoid được (V1 active workflow giữ nguyên → BE healthy startup). **Plan T** DbInitializer `DemoSeed:Disabled` flag config — disable 5 demo seed methods (Workflow V1 + PE V1 + Demo Contracts + Demo PE + Sample V2). **Plan U** FE sidebar truncate + tooltip 2 app mirror — handle long DisplayLabel (Mig 27 admin custom). Anti-patterns observed: (1) **Plan N point 9 chỉ catch 1/5 sites** — em main + Investigator spawn miss 4 sites khác → Plan O cascade fix. Lesson: grep ENUMERATE TẤT CẢ lookup sites cùng pattern (KHÔNG fix theo bug report mỗi lần). (2) **Plan O caveat #1 surfaced Plan P pre-existing bug** — CICD Monitor catch Controller body record drop trong Stage 4c verify wire — pattern "verify cross-stack body↔command count match". (3) **DbInitializer auto re-seed** loop — Plan R+S clean → IIS recycle → re-seed loop. Plan T flag fix root cause. Pattern reusable cross-project: refactor schema 1-row-per-role MUST grep enum lookup sites + Controller body record MUST mirror Command record fields. Cumulative state: 111 test (+7 vs 104 baseline pre-Plan M), 31 mig (no new), 47 gotcha unchanged, `feedback_per_nv_permission_scope.md` reinforced 5 lookup sites enum + 9 wire surface points + Plan P caveat → 10 surface points. Smart Friend guard still active for future spawn.