S24 wrap deliverables:
Docs:
- docs/STATUS.md prepend Recently Done newest S24 chốt cuối row (cumulative 7 commits 3 core + 4 polish UAT iteration, multi-agent ROI ~175K ~28% solo equiv)
- docs/HANDOFF.md Last updated S24 chốt cuối (replace previous S24 t1 entry với cumulative final state)
- docs/changelog/sessions/2026-05-15-s24-turn1-plan-aa-workflow-matrix.md EXTEND
- Phase 2 Polish iteration UAT feedback section (4 commit detail):
- Polish 1 da218f1 hotfix container px-2
- Polish 2 4d60598 redesign v1 panel-per-NV color mirror Designer
- Polish 3 fbbd361 redesign v2 HTML table rowSpan tận dụng full width
- Polish 4 ee0902a wrap fix sidebar label về đầu hàng (hanging-indent reverse)
- Stats S24 chốt cuối table
- Multi-agent ROI cumulative S24 table (6 owner)
- 7 Patterns reusable cross-project saved
- Pending S25+ checklist
4 agent MEMORY drift (3 agent flushed cumulative S24 wrap + 1 CICD prior Run #210):
- .claude/agent-memory/investigator/MEMORY.md S24 Pre-A entry + memory drift note
- .claude/agent-memory/implementer/MEMORY.md +3 patterns 13/14/15 (Designer mirror + Tailwind JIT palette + rowSpan flat row builder) + S24 polish REFUSE log
- .claude/agent-memory/reviewer/MEMORY.md +4 anti-patterns (polish iteration cost vs spawn ROI + Discovery #3 negative retest + Low note IsUserSelectable leak)
- .claude/agent-memory/cicd-monitor/MEMORY.md Run #210 PASS entry (Plan AA verify 4/4 wire end-to-end)
⚠️ Implementer + CICD Monitor agent MEMORY both over 25KB curate threshold (~31.5KB + ~43KB).
Recommend archive S20-S22 old entries next session via `archive/2026-05-S20-S22.md`.
User-level memory: NO update needed per §6.2 (responsive memory đã đúng 2-panel,
hanging-indent + JIT palette patterns captured trong agent Implementer MEMORY).
Test verify post-Plan AA: 111/111 PASS unchanged (58 Domain + 53 Infra). No regression.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
32 KiB
Implementer Agent — Persistent Memory
Persistent diary cross-session. Auto-injected first 200 lines / 25KB at spawn. Update BEFORE every stop. Curate when > 25KB.
🎯 Role baseline
Code execution specialist for SOLUTION_ERP. Conditional WRITE (Case 1+2+3+5 ONLY). Tools: Read, Edit, Write, Bash, Skill, Grep, Glob. Output: commits + verification report.
🚨 STRICT scope auto-refuse criteria
REFUSE if ANY:
- Schema design decisions needed (FK strategy / nullable / discriminator)
- UX flow decisions needed (drawer vs tab vs modal)
- Cross-stack > 2 layers tight coupling
- Bug fix involving reasoning chain
- Integration testing involving multiple components
- < 30 min trivial task
- First time pattern (no prior precedent)
- Spec ambiguity > 20%
📋 Patterns proven (cross-session) — apply confidently
Pattern 1: Per-chunk discipline 5-chunk A-E (Anthropic Case 2 orchestrator-workers)
Memory feedback_per_chunk_commit chốt:
- Chunk A: Domain entities + Migration (3-file rule)
- Chunk B: Application handlers (CQRS Commands + Queries + Validators)
- Chunk C: Service layer (workflow logic, business rules)
- Chunk D: API controllers + endpoints
- Chunk E: FE update (cả 2 app mirror) + Tests + Docs + commit final
Build + test pass mỗi chunk. Commit message format:
[CLAUDE] <scope>: Chunk <X> — <one-line summary>
<body>
Verify:
- Build pass (X warning, 0 error)
- N test pass (...)
Pending Chunk <Y+1>: <next>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pattern 2: 3-file rule EF migration (BẮT BUỘC commit đủ)
Memory + gotcha #17:
Migrations/{TS}_{Name}.cs(Up + Down)Migrations/{TS}_{Name}.Designer.cs(snapshot at migration time)Migrations/ApplicationDbContextModelSnapshot.cs(current snapshot)
dotnet ef migrations add <Name> \
--project src/Backend/SolutionErp.Infrastructure \
--startup-project src/Backend/SolutionErp.Api
# Apply lên DB Dev:
dotnet ef database update --project src/Backend/SolutionErp.Infrastructure \
--startup-project src/Backend/SolutionErp.Api \
--connection "Server=(localdb)\MSSQLLocalDB;Database=SolutionErp_Dev;Trusted_Connection=True;TrustServerCertificate=true"
# Apply lên DB Design (catchup nếu thiếu):
dotnet ef database update --project src/Backend/SolutionErp.Infrastructure \
--startup-project src/Backend/SolutionErp.Api
Pattern 3: Audit reuse trước khi clone (memory feedback_audit_reuse_before_clone)
Khi user nói "clone X sang Y":
- Grep discriminator field (
ApplicableType,Type,Kindenum) - Check Service / Handler / Controller có hardcode type cụ thể không
- Check FE pages có route dynamic typeCode hay hardcode
- Check menu key (BE const + FE menuKeys.ts) — thường thiếu chính ở đây
- Default reuse 80%, chỉ thêm menu key + sample seed (3 file ~60 LOC)
Bài học S17+ Clone B: 1 commit 937eb24, deploy 1 phát chạy.
Pattern 4: Service hook vs CRUD endpoint cho derived state (memory feedback_service_hook_vs_endpoint)
State X = derived của action Y → UPSERT trong handler Y, KHÔNG endpoint /X riêng.
Bài học S19 Mig 26 PE LevelOpinions: Service ApproveV2Async UPSERT row qua match ApproverUserId == actorUserId (fallback first khi Admin override). 0 endpoint mới.
Pattern 5: FE mirror 2 app rule §3.9
Duplicate fe-admin/ + fe-user/ CÓ CHỦ ĐÍCH:
- Sửa fe-admin xong → mirror fe-user (tay)
- Khi breaking change rename prop → BẮT BUỘC
npm run build× 2 app (memoryfeedback_uat_skip_verifyexception)
Pattern 6: VND format helpers + Phone/Email validate (S20 turn 4)
Inline mỗi file FE PE:
const parseVnd = (s: string): number => Number(s.replace(/[^\d]/g, '')) || 0
const formatVndInput = (n: number): string => (n > 0 ? n.toLocaleString('vi-VN') : '')
const PHONE_RE = /^0\d{9,10}$/
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
const isValidPhone = (s: string) => !s || PHONE_RE.test(s.replace(/[\s\-.]/g, ''))
const isValidEmail = (s: string) => !s || EMAIL_RE.test(s)
Pattern 7: Per-NV admin opt-in flag (S21 t5 Mig 29 + S22 Mig 30)
ApprovalWorkflowLevel +1 column bool DEFAULT 0 (opt-in admin set explicit). EF config HasDefaultValue(false). DTO extend field. FE Designer checkbox inline mỗi Level row.
Reusable cho future flag F5/F6 (vd AllowEarlyApprove, AllowDelegate): admin per-NV opt-in qua Level table thay vì global flag. Decision tree: flag scope role-context → table mapping natural (Approver → Level table carry ApproverUserId FK, Drafter → User table direct — memory feedback_per_nv_permission_scope).
Bài học S22: AllowApproverEditSection1 (Mig 30) follow same pattern Mig 29. 0 schema redesign cần.
Pattern 8: Tách endpoint riêng cho narrow scope (S22 AdjustBudget vs UpdatePeDraft)
Khi 1 action có 2 scope khác nhau theo role:
- Drafter scope (rộng):
UpdatePeDraftcover Section 1 (Tên/Địa điểm/Mô tả/Payment + Budget) — chỉ phase Nháp / Trả lại - Approver scope (hẹp):
AdjustBudgetchỉ Budget rows — phase Đang duyệt với per-NV flag
KHÔNG default expand Drafter scope cho Approver — tránh accidental edit Section 1. Endpoint tách riêng = guard tự nhiên + audit trail rõ.
Bài học S22: AllowApproverEditSection1 flag opt-in cụ thể PATCH /budget rows, KHÔNG /full-update.
Pattern 9: Defense-in-depth FE + BE guard pair (S22+1)
UI button disabled={!canReject} + BE helper EnsureCanRejectV2Async(peId, userId) throw 403 nếu non-approver. Tránh request forge non-approver gọi PATCH direct qua DevTools.
Pattern reusable: bất kỳ action sensitive (approve/reject/adjust) → FE disable + BE guard helper riêng (NOT inline trong handler).
Bài học S22+1: 3 button (Duyệt / Trả lại / Từ chối) — UI disable + BE helper. Tránh leak action qua API direct.
Pattern 10: Reflection-based regression test cho Authorize policy (S22 Plan C task 4 #44)
5 test lightweight ~50 LOC catch class-level [Authorize(Policy = "...")] regression:
var attr = typeof(ControllerXxx).GetCustomAttribute<AuthorizeAttribute>();
attr.Policy.Should().Be("CanDoSomething");
KHÔNG cần WebApplicationFactory heavy (slow + complex setup). Reflection catch ai accidentally remove [Authorize] hoặc đổi policy name.
Pattern reusable cho future controller sensitive (Approve / Reject / Adjust / Reset).
Pattern 11: Test infra helper cookie-cutter (S22)
Trong PurchaseEvaluationWorkflowServiceReturnModeTests + PurchaseEvaluationDraftGuardTests:
private async Task<Guid> SeedWorkflowAsync(...) {
// 1 Step (DepartmentId=null skip Dept FK) + 2 Levels
}
private async Task SeedApproversAsync(Guid levelId, ...) {
// Multi user via fix.CreateUserAsync
}
Pattern reusable: test PE workflow → 1 Step + 2 Levels + N approvers per Level. DepartmentId=null skip Dept FK ràng buộc. Token cost ~80 LOC repeated cross 2 test class S22.
Pattern 12: InternalsVisibleTo csproj expose helper cho test (S22)
PurchaseEvaluationDraftGuard static helper internal — expose qua <InternalsVisibleTo Include="SolutionErp.Infrastructure.Tests" /> trong SolutionErp.Application.csproj thay vì rewrite public API.
Tránh API surface bloat. Reusable cho future guard / helper internal cần test.
Pattern 13: Read-only admin Designer mirror page (S24 Plan AA Chunk B)
Khi spec yêu cầu "user xem read-only data admin đã config" (vd workflow matrix ghim, permission summary, dept tree readonly):
- Drop edit mutations — useMutation / PATCH / POST / DELETE KHÔNG cần
- Reuse DTO types subset — copy
AwAdminOverviewDtotừ admin sang user types/ (KHÔNG re-export, KHÔNG share package — duplicate có chủ đích §3.9) - Filter via query param BE-side —
?isUserSelectable=truethay vì FE filter client (network payload nhẹ hơn + security tự nhiên) - Implementer Case 2 single file ~180-215 LOC ACCEPT đúng scope (page mới + types mới + route 3-line App.tsx)
- Verify shadcn library availability trước — fe-user thường thiếu Card/Badge (chỉ có Button/Dialog/Input/Label/Select/Textarea). Fallback inline
<div className="rounded-lg border bg-card p-4">mirror admin Designer DefinitionCard
Bài học S24 Plan AA Chunk B: 3 file ~305 LOC, useQuery readonly, no mutation, ACCEPTED ~14k tokens. Pattern reusable cho future user-side read-only page (vd permission summary, dept hierarchy view).
Pattern 14: Tailwind JIT palette array (S24 Plan AA)
Tailwind v3 JIT KHÔNG resolve dynamic class interpolation (bg-${color}-50 → purge xoá khi production build). Solution: PALETTE array với full class strings literal.
const PALETTE = [
{ bg: 'bg-blue-50/40', border: 'border-blue-200', text: 'text-blue-900', accent: 'bg-blue-100' },
{ bg: 'bg-emerald-50/40', border: 'border-emerald-200', text: 'text-emerald-900', accent: 'bg-emerald-100' },
{ bg: 'bg-amber-50/40', border: 'border-amber-200', text: 'text-amber-900', accent: 'bg-amber-100' },
// ... 6-8 colors total
] as const
// Apply cycle qua index:
const colorClasses = PALETTE[index % PALETTE.length]
<div className={`${colorClasses.bg} ${colorClasses.border}`}>...</div>
Lý do array (vs object): cycle natural qua index % length cho dynamic NV/Step/Cap count. Lý do as const: TypeScript narrow literal type tránh string.
Bài học S24 Plan AA redesign v1 (commit 4d60598): panel-per-NV color theo NV index — 6 NV cycle 6 màu blue/emerald/amber/violet/rose/cyan.
Pattern 15: HTML table rowSpan iteration helper (S24 Plan AA redesign v2)
Khi render table với nested rowSpan (vd Bước rowSpan N cấp × Cấp rowSpan M NV), nested loop + conditional cells gây nhầm key + hard maintain. Solution: flat row builder helper với metadata flags.
type FlatRow = {
stepIndex: number
capIndex: number
nvIndex: number
isFirstInStep: boolean // render Bước cell
rowSpanStep: number // cap count × nv count
isFirstInCap: boolean // render Cấp cell
rowSpanCap: number // nv count
// ... level data
}
function buildFlatRows(definition: AwDefinitionDto): FlatRow[] {
const rows: FlatRow[] = []
definition.steps.forEach((step, si) => {
const stepNvCount = step.levels.reduce((sum, lv) => sum + lv.users.length, 0)
step.levels.forEach((cap, ci) => {
cap.users.forEach((nv, ni) => {
rows.push({
stepIndex: si, capIndex: ci, nvIndex: ni,
isFirstInStep: ci === 0 && ni === 0,
rowSpanStep: stepNvCount,
isFirstInCap: ni === 0,
rowSpanCap: cap.users.length,
// ...
})
})
})
})
return rows
}
// Render flat:
{rows.map(row => (
<tr key={`${row.stepIndex}-${row.capIndex}-${row.nvIndex}`}>
{row.isFirstInStep && <td rowSpan={row.rowSpanStep}>{step.name}</td>}
{row.isFirstInCap && <td rowSpan={row.rowSpanCap}>{cap.name}</td>}
<td>{nv.fullName}</td>
{/* 7 flag cells */}
</tr>
))}
Cleaner than nested forEach + render-time if (ni === 0) <td rowSpan={...}>. Easier debug (console.log rows array thấy structure rõ).
Bài học S24 Plan AA redesign v2 (commit fbbd361): table 3 cột meta (Bước/Cấp/NV) + 7 cột flag với rowSpan natural.
⚠️ Anti-patterns observed (DO NOT)
- ❌ Skip MEMORY.md update — knowledge tài sản
- ❌ Bypass pre-commit hooks
--no-verify(forbidden absolute) - ❌
git add -Ahoặcgit add .— specific files only - ❌ Touch files outside spec scope — anti-fiddle rule
- ❌ Push remote autonomously cho heavy change — em main pushes (UAT iteration: confirm với em trước push)
- ❌ Modify
SolutionErp.slnxautonomously — em main updates khi thêm.cs/.csproj - ❌ Lower bar to match em main quality — Smart Friend Cognition anti-pattern
- ❌ Proceed when spec ambiguous > 20% — return REFUSE với reason
🧠 SOLUTION_ERP conventions (auto-load via skills)
- BE .NET 10: PascalCase tiếng Anh entities + DTO records + command names. CQRS + MediatR + FluentValidation + AutoMapper. Repository qua
IApplicationDbContext.GlobalExceptionMiddlewaremap exception → ProblemDetails (NO try-catch trong controllers). - FE React 19 + Vite 8 + TS 6: Named export only (trừ App). TanStack Query. shadcn/ui copy-paste. TS6
erasableSyntaxOnlycấmenum→ const-object pattern. UI 100% tiếng Việt. Mirror 2 app rule §3.9. - Test: baseline 104/104 PASS (58 Domain + 46 Infra: 23 baseline + 3 PE WF guard regression S21 t3 gotcha #45 + 20 mới S22 — gồm PE WF ReturnMode + Draft guard + Reflection-based Authorize policy). Phase 9 UAT skip per chunk theo memory
feedback_uat_skip_verify. Stack xUnit + FluentAssertions 7.2 + EF SQLite 10TestApplicationDbContextoverridenvarchar(max) → TEXT. - Build:
dotnet build SolutionErp.slnxclean 0 err +npm run build× 2 app pass. - Commit:
[CLAUDE] <scope>: <message>+ Co-Authored-By Claude Opus 4.7 (1M context).
Scopes (pick 1)
Contract · PurchaseEvaluation · Budget · Form · Workflow · Supplier · Auth · Admin · Api · App · Domain · Infra · FE-Admin · FE-User · Tests · Docs · CICD · Scripts · Skill
🔑 Pin versions (package pinning §2.8)
KHÔNG * / latest. Critical pins:
- MediatR
12.4.1(14 fail DI) - Swashbuckle
6.9.0(10 conflict OpenApi 2) - Node engines
>= 20+ CI pin20.x(bài học NamGroup, memoryfeedback_node_cicd) - LibreOffice
25.8.6 - @microsoft/signalr
8.0.7
📅 Recent activity (last 10 FIFO)
-
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
da218f1hotfix px-2 trivial < 30min criteria #6,4d60598redesign v1 panel-per-NV color UX flow criteria #2,fbbd361redesign v2 table rowSpan UX flow criteria #2,ee0902awrap 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 BEAwAdminOverviewDto(7 Allow* flag per Level, 5 record type AwLevelDto/AwStepDto/AwDefinitionDto/AwTypeSummaryDto/AwAdminOverviewDto); (2) CREATEfe-user/src/pages/pe/WorkflowMatrixViewPage.tsx(~215 LOC) — useQuery GET/approval-workflows-v2?applicableType=N&isUserSelectable=true(em main BE Chunk A đã thêmIsUserSelectable bool?param + Controller forward), render table 10 cột Bước (rowSpan) | Cấp | NV duyệt | 7 ✓/— flag cell, header vớititletooltip mô tả từng cột, 3 state Loading/Error/Empty rõ ràng, badgeĐang dùng(emerald isActive) +Được ghim(amber isUserSelectable Pin icon); (3) UPDATEfe-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 buildfe-user PASS clean 0 TS err, 1907 modules, 2.61s, 1282 KB. Surprise: shadcn fe-user KHÔNG cóCard/Badge(chỉ có 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=truethay vì FE filter). Cookie-cutter 0 (lần đầu pattern). Pattern 5 mirror 2 app KHÔNG apply (fe-admin có 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.
-
2026-05-15 (S24, Plan M Chunk M2 PASS): F1 edge case Bước 1 reset ChoDuyet tests (em main M1 service edit
PurchaseEvaluationWorkflowService.csline 287-333 đã DONE — fallback Drafter TraLai → reset (0, 1) giữ ChoDuyet + audit log "không lùi được"). Cookie-cutter 1 file testPurchaseEvaluationWorkflowServiceReturnModeTests.cs— 2 sub-tasks: (1) extendSeedWorkflowAsynchelper +2 params optionalallowReturnOneLevelL1+allowReturnOneStepL2(default false, không phá compat 4 test ReturnMode existing), set vàol1.AllowReturnOneLevel+l2.AllowReturnOneSteptương ứng — Pattern 3 audit-reuse EXTEND không clone helper; (2) add 2[Fact]test ngay sau test admin bypass OneLevel (line 241) —ApplyReturnMode_OneLevel_AtStep1Level1_ResetsToBuoc1Cap1_KeepsChoDuyet(PE init Step 0 Cấp 1 + actor=a1 + slot Cấp 1 tick AllowReturnOneLevel, build PE inline vì helperBuildPeAtLevel2không phù hợp cho Cấp 1) +ApplyReturnMode_OneStep_AtStep1_ResetsToBuoc1Cap1_KeepsChoDuyet(PE Step 0 Cấp 2 + actor=a2 + slot Cấp 2 tick AllowReturnOneStep, reuseBuildPeAtLevel2, OneStep service checkcurStepIdx > 0→ fallback ngay không quan tâm Cấp). Assert: Phase=ChoDuyet (KHÔNG TraLai như Drafter mode) + pointer (0, 1) + SLA NotNull + Changelog ContextNote chứa "không lùi được" (Summary field cố định"Chuyển phase {from} → {to}", summary từ ApplyReturnModeAsync chèn vào comment qua line 96-99 service → LogTransitionContextNote = comment). K7 cascade verify NO regression: 3 ApproveV2_SkipToFinal_* tests still green (M1 edit chỉ F1 OneLevel/OneStep edge case, KHÔNG đụng F2 pathApproveV2Async). Verify:dotnet test SolutionErp.slnxclean 0 err 2 warn pre-existing DocxRenderer, 106/106 PASS (58 Domain + 48 Infra: +2 từ 46 baseline post Plan L). 10 ReturnMode-class tests verified individually PASS (4 ReturnMode + 3 ApproveV2_SkipToFinal + 1 Reject_NonApprover + 2 edge case mới). Diff +94 LOC trên 1 test file (test add + helper signature 2 params). Token ~10k. Spec deterministic + 1 file independent + < 1h verified. -
2026-05-15 (S24, Plan M Chunk M3 PASS): FE rename Phase=TraLai (98) display label "Trả lại" → "Cần chỉnh sửa lại" cho UAT disconnect fix. Spec scope HẸP (display badge label + status reference) tuân thủ strict: 4 file FE × 2 app = 8 edit total. 2 file types/purchaseEvaluation.ts × 2 app:
PurchaseEvaluationPhaseLabel[98](raw phase badge) +PeDisplayStatusLabel.TraLai(display status badge — main user-facing). 2 file components/pe/PeWorkflowPanel.tsx × 2 app: rename 2 inline literal hardcode "Trả lại" trong F1 dialog tooltip (Phase → "...") + confirm message (Phiếu sẽ về "...") — đây là status display reference, KHÔNG phải action verb. Pattern 5 mirror 2 app strict applied. KHÔNG đụng: (1) action button label← Trả lại(verb), (2) F1 mode picker labelTrả về Người soạn thảo(4 mode action), (3) comments narrative line 62/71/etc giữ rationale dev (rule §6.5), (4)types/contracts.ts+types/budget.tsPhase 98 'Trả lại' — module Contract + Budget khác PE, ngoài scope M3. Verify:npm run buildfe-admin PASS clean (0 TS err, 9.40s, 1395 KB bundle unchanged trivial) +npm run buildfe-user PASS clean (0 TS err, 6.92s, 1275 KB). Diff +4/-4 LOC × 2 = 8 LOC tổng trên 4 file. Token ~9k. Decision tactical: 2 chỗ inline literal PeWorkflowPanel rename để giữ UX consistency với badge label sau rename — KHÔNG drift outside spec vì cùng "status display reference" semantics (badge + tooltip + confirm message phải mirror). Anti-fiddle threshold <20% LOC respected. -
2026-05-14 (S23 t1, K7 Chunk F PASS): Mig 31 Approver F2 service regression tests. Sub-task 1 fix broken Drafter F2 test reference K1 flagged:
PurchaseEvaluationWorkflowServiceReturnModeTests.cs:253drafter.AllowDrafterSkipToFinal = true(DELETE 3 deprecated Drafter F2 tests entire —SkipToFinal_DrafterAllowed_SetsPointerToFinalLevel+SkipToFinal_DrafterDenied_NonAdmin_Throws+SkipToFinal_AdminBypass_Succeeds, semantic deprecated no value). Sub-task 2 add 3 new Approver F2 tests:ApproveV2_SkipToFinal_AdminTickFlag_SetsPhaseDaDuyet(happy path — slot Cấp 1 Bước 1 admin tick → Phase=DaDuyet, pointer cleared, opinion + PEA + Changelog logged),ApproveV2_SkipToFinal_FlagOff_NonAdmin_ThrowsConflictException(denied — flag off non-admin slot user → throw "chưa được phép duyệt thẳng Cấp cuối"),ApproveV2_SkipToFinal_FlagOff_Admin_BypassesFlagCheck(admin bypass — flag off admin role → DaDuyet allowed). Pattern 11 SeedWorkflowAsync cookie-cutter REUSE — createdSeedApproverF2WorkflowAsynchelper (2 Steps × 2 Levels — multi-step verify skip thẳng terminal KHÔNG fallthrough advance pointer next Step), AllowApproverSkipToFinal per-slot param. PE init Phase=ChoDuyet + CurrentWorkflowStepIndex=0 + CurrentApprovalLevelOrder=1 (vs S22 happy path từ DangSoanThao). Addusing Microsoft.EntityFrameworkCorecho.ToListAsync()PEL/PEA/Changelog query. File header narrative line 17-25 REWRITE để track Mig 31 refactor semantic Approver scope ChoDuyet vs Drafter-from-Nháp cũ. Verify:dotnet buildclean 0 err 2 warn pre-existing DocxRenderer.dotnet test SolutionErp.slnx104 PASS (58 Domain + 46 Infra, 3 deleted + 3 added cancel out, baseline preserved). 3 Approver F2 tests verified individually PASS. Diff +175/-92 LOC trên 1 file. Token ~14k. -
2026-05-14 (S23 t1, K5 Chunk D PASS): Cleanup zombie F2 endpoint + UsersPage column + DTO field + stale narrative comments (Reviewer Major #1 + Major #2 + Minor #3 + Minor #4). Pattern post-refactor full cleanup atomic 1 commit. BE 7 file (UsersController.cs DELETE PATCH /allow-skip-final endpoint + SetAllowDrafterSkipToFinalBody record; UserFeatures.cs DELETE UserDto field + SetUserAllowDrafterSkipToFinalCommand + Handler + sentinel-false mappings cleanup; ApprovalWorkflow.cs REWRITE stale narrative line 78-80 Mig 31 semantic + docstring line 108; PurchaseEvaluationFeatures.cs REWRITE Command DTO comment line 401; ApprovalWorkflowConfiguration.cs APPEND Mig 31 narrative line 22-24 + clean storage move comment line 87; ApprovalWorkflowV2AdminFeatures.cs clean DTO comment line 58; IPurchaseEvaluationWorkflowService.cs + PurchaseEvaluationDtos.cs clean stale "storage Users.AllowDrafterSkipToFinal" references) + FE Admin 2 file (UsersPage.tsx DELETE "Skip cuối" column TableHeader/TableCell + FastForward import + allowSkipMut mutation hook + FastForward toggle button; types/users.ts DELETE allowDrafterSkipToFinal field). fe-user KHÔNG đụng (no UsersPage admin-only + K6 sẽ handle Workspace Drafter checkbox), FE Designer page KHÔNG đụng (K3 done — 2 stale comment line 75 + 504 leftover deferred K6). Grep
AllowDrafterSkipToFinal+allow-skip-final+allowDrafterSkipToFinal+Skip cuối+FastForwardZERO results across src/Backend (excl migrations) + fe-admin/src. Build BE production projects clean (0 err, 2 pre-existing DocxRenderer warn). Build fe-admin clean (0 TS err, 0 new warn). Diff +42/-94 LOC trên 9 file. Token ~12k. K6 Workspace Drafter checkbox cleanup next. -
2026-05-14 (S23 t1, K3 Chunk C PASS): FE Admin Designer 7th checkbox AllowApproverSkipToFinal + banner rewrite. Pattern Mig 29/30 admin opt-in per-slot mirror reinforced 3× cumulative (Mig 29 F1+F3 5 checkbox + Mig 30 F4 1 checkbox + Mig 31 F2-refactor 1 checkbox = 7 checkbox total per slot). Cookie-cutter 1 file fe-admin only (
ApprovalWorkflowsV2Page.tsx, fe-user no Designer per Investigator K0 S1). 7 sub-items atomic: (1) LevelDto type +allowApproverSkipToFinal: boolean, (2) EditLevelEntry type +same, (3)makeDefaultLevelEntrydefault false, (4)copyFromDefinitionpropagate?? false, (5) inline checkbox row position cuối list sau F4 AllowApproverEditBudget logical grouping (Edit Section 2 → Edit Budget → Skip to Final), (6) banner rewrite line ~623 từ "F2 cấu hình ở User Management" (Plan D S22 stale) → "Cấu hình quyền duyệt riêng cho từng NV trong slot Approver bên dưới (Trả lại / Edit Section 2 / Edit Budget / Duyệt thẳng Cấp cuối)", (7) POST/PATCH mutation bodylevels.map+allowApproverSkipToFinal. Verify:npm run buildfe-admin PASS clean 0 TS error, 0 new warning. Bundle 1395.74 KB (unchanged trivial vs baseline). Diff +26/-7 LOC. Token ~6k. K5 next chunk cleanup zombie endpoint + UsersPage column. -
2026-05-14 (S23 t1, K1 Chunk A PASS): Mig 31 schema swap F2 storage Users → ApprovalWorkflowLevels. Pattern Mig 29 ADD-DROP no-BACKFILL Option A (accept lose 4 prod user value
fin.pp+pm.nv+nv.test+truong.nguyen). Cookie-cutter 6 BE file (User.cs -1 prop + ApprovalWorkflow.cs +1 propAllowApproverSkipToFinalper-Approver-slot + ApprovalWorkflowConfiguration.cs +HasDefaultValue + PurchaseEvaluationWorkflowService.cs surgical -37 LOC F2 Drafter SUBMIT branch line 121-157 stub + Mig 3-file). TransitionAsyncbool skipToFinal8th param KEPT cho K2 repurpose APPROVE STEP. 4 Application compile-break sites (UserFeatures.cs LIST + GET DTO mapping + SetUserAllowDrafterSkipToFinalCommandHandler NoOp + PurchaseEvaluationFeatures.cs drafter flag = false) patched với sentinelfalse+ K2 marker comment (DTO/Command signature unchanged per spec — K2 sẽ refactor). Mig 31 Up() manual reorder ADD-DROP correct (no BACKFILL). Both DBs Dev + Design applied successful. Build production projects clean 0 err 0 warn. Test compile errorPurchaseEvaluationWorkflowServiceReturnModeTests.cs:253left for K7 chunk (spec exclude test scope). Patternfeedback_per_nv_permission_scope.mdreinforced 3× cumulative (Mig 29 F1+F3 + Mig 30 F4 + Mig 31 F2-refactor). UserConfiguration.cs file không tồn tại — User entity configured inlineApplicationDbContext.OnModelCreating~line 86, không có HasDefaultValue choAllowDrafterSkipToFinal, EF picks prop change tự động. -
2026-05-14 (S23 t1, Chunk pre-A PASS): UI polish slot label Designer Mig 31 prep. File
fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsxline 873 replacedQuyền duyệt NV #{ei + 1}→Quyền duyệt {usersList.data?.find(u => u.id === entry.approverUserId)?.fullName ?? 'Chưa chọn NV'}. Pattern: lookup user fullName từusersListquery (Option A — DTOEditLevelEntrykhông cóapproverFullNamefield, chỉLevelDtoBE response cóapproverUserNamenhưng edit state dùngEditLevelEntry).usersListđã in scope ~line 500, pattern lookup.find(x => x.id === e.approverUserId)đã dùng tại line 535 cho validation. Cookie-cutter 1 file fe-admin only (fe-user KHÔNG có Designer per Investigator K0 S1). Tailwind classes preserved (mb-1 text-[10px] font-medium uppercase text-amber-700). Verify:npm run buildfe-admin PASS clean 0 TS error, 0 new warning. Bundle 1395 KB (unchanged trivial). Token ~5k. -
2026-05-13 (S22, REFUSED 100%): Em main classified ALL S22 work as cross-stack reasoning chain (BE Mig + Service guard + DTO + FE Designer + FE Section + FE types + tests) → REFUSE per criteria #3+#4. Em main solo executed. State chốt S22: 30 migrations (+1 Mig 30 AllowApproverEditSection1 per-NV F4 flag), 104 test PASS (+20 từ 84 — gồm PE WF ReturnMode + Draft guard + Reflection-based Authorize policy regression), ~146 endpoints (+3), 46 gotchas unchanged, 33 active prod users (13 cũ + 20 mới S22+2). 7 patterns successfully applied throughout S22 (validated continued effectiveness): Pattern 7 per-NV admin opt-in flag (Mig 30 follow Mig 29), Pattern 2 EF migration 3-file rule, Pattern 8 tách endpoint narrow scope (AdjustBudget vs UpdatePeDraft), Pattern 9 defense-in-depth FE+BE guard pair (S22+1 disable 3 button), Pattern 10 Reflection-based regression test cho Authorize policy (Plan C task 4 #44, 5 test ~50 LOC), Pattern 11 test infra helper cookie-cutter (SeedWorkflowAsync + SeedApproversAsync), Pattern 12 InternalsVisibleTo csproj expose internal helper cho test. Mismatches discovered S22: (1) "Đang trong quá trình duyệt = người điều chỉnh cũng là người duyệt" — em first interpret default Approver scope always allowed → bro corrected per-NV admin opt-in flag (Mig 30). Lesson: clarify default behavior vs admin opt-in TRƯỚC khi default scope expansion. (2)
PE.changelogsfield KHÔNG có trong PeDetailBundle — em first design history display trong BudgetAdjustSection, build FAIL TS2339. Fix: removed history display (defer S23+ via separate fetch endpoint). (3) Dialogsize="xl"NOT supported — only "sm" | "md" | "lg". Use "lg" cho preview iframe. (4) API auth fieldaccessTokenkhông phảitoken. Scriptseed-test-users-prod.ps1lần đầu FAIL 401 sau auth — em fix$authResp.accessToken. -
2026-05-13 (S21 t3-t5, REFUSED 3×): Em main classified all 3 turns as cross-stack reasoning chain (BE+FE+test tightly coupled) → REFUSE per criteria #3+#4 (cross-stack > 2 layers, bug fix reasoning chain). Bug fix gotcha #45 = bug + reasoning, F1+F2+F3 = schema design decision, Refactor per-NV = drastic refactor schema + Service + FE × 2 app. All correct REFUSE — em main solo executed. Strict scope criteria validated S21 t3-t5 — REFUSE rate 100% match Anthropic warning "tightly interdependent coding". Cumulative: 84 test, 29 mig, 45 gotcha. Pattern saved future invocation: per-NV permission scope split natural theo role + EF migration BACKFILL reorder pattern.
-
2026-05-11 (setup): Implementer agent initialized. Baseline knowledge load complete (5 patterns proven cumulative S1-S20: per-chunk 5 chunk, 3-file rule Mig, audit-reuse clone, service hook derived state, FE mirror 2 app, VND format helpers). No implementations performed yet. Awaiting first SendMessage from em main. Strict scope auto-refuse criteria active.
🔄 Curate trigger
- Memory size > 25KB → archive recent entries to
archive/<period>.md - Duplicate entries detected → merge
- Stale > 3 months → remove
Last curate: 2026-05-11 (initial seed)