migration-todos.md: insert Phase 10 detail section (10 Plan G-* atomic per-module sprint ~3 thang T6-T8/2026 target, aggressive multi-agent parallel ROI ~70%). 4 quyet dinh anh chot S32: FULL 11 module scope + single schema dbo mo rong Mig 34-42 + reuse Workflow V2 extend ApplicableType +5 values + chunk per-module Plan rieng. Sequence Phase 9 stabilize first per anh main "tuan tu theo ke hoach tot nhat". G-P1 pure web GPS check-in (no device). G-H2 seed reference NamGroup demo data. 4 MEMORY sub-agent: append S32 startup entry (Investigator + Implementer + Reviewer + CICD Monitor) ghi nhan S31 RAG retrieval.py fix + S29 Plan CA+B deploy + Pending tasks anh main co the SendMessage reuse. Implementer 36.2KB OVER 25KB threshold FLAG curate. Refs: docs/CLAUDE.md Phase 6-9 done. docs/STATUS.md S31 wrap. gotcha #51 INFRASTRUCTURE vs DEMO seed gate (Phase 10.3 enum extend caution). gotcha #52 qdrant.search removed (RAG layer stable post-S31 fix). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
371 lines
38 KiB
Markdown
371 lines
38 KiB
Markdown
# 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:
|
||
1. Schema design decisions needed (FK strategy / nullable / discriminator)
|
||
2. UX flow decisions needed (drawer vs tab vs modal)
|
||
3. Cross-stack > 2 layers tight coupling
|
||
4. Bug fix involving reasoning chain
|
||
5. Integration testing involving multiple components
|
||
6. < 30 min trivial task
|
||
7. First time pattern (no prior precedent)
|
||
8. 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)
|
||
|
||
```bash
|
||
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":
|
||
1. **Grep discriminator field** (`ApplicableType`, `Type`, `Kind` enum)
|
||
2. **Check Service / Handler / Controller** có hardcode type cụ thể không
|
||
3. **Check FE pages** có route dynamic typeCode hay hardcode
|
||
4. **Check menu key** (BE const + FE menuKeys.ts) — thường thiếu chính ở đây
|
||
5. 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 (memory `feedback_uat_skip_verify` exception)
|
||
|
||
### Pattern 6: VND format helpers + Phone/Email validate (S20 turn 4)
|
||
|
||
Inline mỗi file FE PE:
|
||
```ts
|
||
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):** `UpdatePeDraft` cover Section 1 (Tên/Địa điểm/Mô tả/Payment + Budget) — chỉ phase Nháp / Trả lại
|
||
- **Approver scope (hẹp):** `AdjustBudget` chỉ 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:
|
||
```csharp
|
||
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`:
|
||
|
||
```csharp
|
||
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 16-bis: 4-place mirror checklist khi cookie-cutter copy page CROSS-APP (S29 Plan CA Hotfix 1 — gotcha #50)
|
||
|
||
Khi spec yêu cầu "move page X từ fe-admin → fe-user" hoặc ngược lại (Implementer Case 2 cookie-cutter mirror page), MUST mirror 4 places (NOT just 3):
|
||
|
||
1. ✅ **Page file** (`pages/<dir>/*.tsx`) — copy nguyên content, verify import path `@/...` resolves
|
||
2. ✅ **`App.tsx` Routes** — add `<Route path="..." element={...} />`
|
||
3. ✅ **`lib/menuKeys.ts` constants** — mirror BE `MenuKeys.cs` thêm key mới
|
||
4. ⚠️ **`components/Layout.tsx` `resolvePath` staticMap** — KEY mapping → route path. **DỄ MISS** vì khác file scope với pages directory.
|
||
|
||
**Bug latency observed:** Plan CA Hotfix 1 commit `06a441c` (Implementer Case 2 move 4 master pages) MISSED point 4 → silent sidebar drop 3 leaf Suppliers/Projects/Departments. Bro UAT catch screenshot post-deploy. Em main solo fix Hotfix 1 commit `e55d96b` +12 LOC. Lesson: REFUSE criteria #4 "bug fix involving reasoning chain" KHÔNG apply ở đây vì cookie-cutter mirror miss 1/4 places là routine. Phòng tránh: task prompt MUST list 4 places explicit.
|
||
|
||
**Verification post-fix:** Reviewer Cat 1 "Wire claim verify" SHOULD add to checklist: "Sidebar menu visible end-to-end test post-build" — curl `/api/menus/me` + grep MenuLeaf render output. Smart Friend prevent silent drop.
|
||
|
||
### Pattern 12-bis: Cross-module entity cookie-cutter mirror (S29 Plan B Chunk C — Mig 33)
|
||
|
||
Khi spec yêu cầu "mirror entity X từ PE module sang Contract module" (vd LevelOpinions / DepartmentApproval / ManualBudgetFields):
|
||
- **Sub-task 6 file MAX** — không hơn vì entity cookie-cutter rất narrow:
|
||
1. New entity class `Domain/<Module>/<Entity>.cs` (rename FK field + nav)
|
||
2. Modify parent entity: add `List<X> Children` nav collection
|
||
3. Modify `IApplicationDbContext`: add `DbSet<X> Xs { get; }`
|
||
4. Modify `ApplicationDbContext`: add `public DbSet<X> Xs => Set<X>();`
|
||
5. New `<Entity>Configuration.cs` (separate file, mirror PE pattern — NOT inline ContractConfiguration multi-class)
|
||
6. `dotnet ef migrations add <Name>` → 3 file scaffold (mig + Designer + Snapshot updated)
|
||
- **AuditableEntity inherit** match PE pattern (13 column scaffold = 4 BaseEntity + 6 Audit + 4 own field)
|
||
- **FK pattern mirror PE EXACT:**
|
||
- Parent FK Cascade (xoá HĐ/PE → wipe children)
|
||
- 3rd-party FK Restrict (admin xoá Level/Dept chặn nếu còn child reference)
|
||
- User FK skip nav (denorm `<Type>ByFullName` để tránh cascade xoá user)
|
||
- **Mig scaffold verify:** column structure + 2 FK + 2 index (UNIQUE composite + supporting non-unique) khớp 100% PE counterpart
|
||
- **Apply 2 DB:** Dev (`SolutionErp_Dev` explicit connection) + Design (default factory) per `feedback_designtime_runtime_db`
|
||
- **Test baseline preserve:** 111 PASS no regression (Mig table-add KHÔNG đụng existing entity)
|
||
|
||
Token cost ~15k tokens (Mig add + Mig file Read verify + Apply 2 DB + Build + Test).
|
||
Bài học S29 Plan B Chunk C commit `26c98d3`: 8 file +4265 LOC (Mig Designer.cs ~4033 LOC autogen chiếm 95%), implementer code ~232 LOC handcraft only. Em main spec deterministic 100% — 0 spec ambiguity → ACCEPT clean.
|
||
|
||
Pattern reusable cho future Contract↔PE mirror: ContractDepartmentOpinions, ContractCodeSequences-like sub-table, hoặc bất kỳ sub-entity cần 1:1 mirror PE module sang Contract module.
|
||
|
||
### 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 `AwAdminOverviewDto` từ 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=true` thay 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.
|
||
|
||
```ts
|
||
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.
|
||
|
||
```ts
|
||
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)
|
||
|
||
1. ❌ Skip MEMORY.md update — knowledge tài sản
|
||
2. ❌ Bypass pre-commit hooks `--no-verify` (forbidden absolute)
|
||
3. ❌ `git add -A` hoặc `git add .` — specific files only
|
||
4. ❌ Touch files outside spec scope — anti-fiddle rule
|
||
5. ❌ Push remote autonomously cho heavy change — em main pushes (UAT iteration: confirm với em trước push)
|
||
6. ❌ Modify `SolutionErp.slnx` autonomously — em main updates khi thêm `.cs/.csproj`
|
||
7. ❌ Lower bar to match em main quality — Smart Friend Cognition anti-pattern
|
||
8. ❌ 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`. `GlobalExceptionMiddleware` map 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 `erasableSyntaxOnly` cấm `enum` → 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 10 `TestApplicationDbContext` override `nvarchar(max) → TEXT`.
|
||
- **Build:** `dotnet build SolutionErp.slnx` clean 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 pin `20.x` (bài học NamGroup, memory `feedback_node_cicd`)
|
||
- LibreOffice `25.8.6`
|
||
- @microsoft/signalr `8.0.7`
|
||
|
||
---
|
||
|
||
## 📅 Recent activity (last 10 FIFO)
|
||
|
||
- **2026-05-26 (S32 startup — context verify + RAG live confirm + size FLAG > 25KB):** Em chủ trì spawn em verify Session 32 context. **Verify done:** (1) MEMORY size 36.2KB (Get-Item Length=36207 bytes) — **OVER 25KB threshold ~45% bigger** → FLAG cho em main schedule dedicated curate session per Pattern curate trigger rule line 364. KHÔNG self-curate vì em chủ trì preference reserve cho em main solo judgment call §6.5 KEEP vs CUT (S27 retrospective C1-C4 task lesson). (2) Patterns saved 1-12 foundation + 12-bis NEW S29 + 13-15 + 16-bis NEW S29 + 17-19 — total **17 numbered patterns** (Pattern 16 baseline implied trong recent activity S27 chưa numbered explicit). Pattern 12-bis (cross-module entity cookie-cutter mirror PE→Contract Mig 33) **SAVED line 178-200** confirmed present. Pattern 16-bis (4-place mirror cross-app S29 Plan CA Hotfix 1) **SAVED line 165-176** confirmed present. (3) MCP RAG tools **PRESENT** — `mcp__rag-unified__search_memory` + `mcp__rag-unified__cross_project_search` both visible trong tools list. Test query "Pattern 12-bis cross-module entity cookie-cutter mirror PE Contract V2" top_k=3 returned 3 results với rerank scores **0.824/0.801/0.793** — all healthy > 0.7 threshold. S31 RAG v1.3 baseline PASS confirmed live post CLI restart. **Pending tasks em main có thể gọi em lại spawn S32+:** (a) Plan B-Wrap BW1-BW7 test bundle codegen Case 2 cookie-cutter mirror PE WorkflowService test pattern (regression ApproveV2Async + UPSERT LevelOpinions test) — 7 file new test class mirror PE test bundle structure; (b) ContractWorkflowMatrixView mirror PE WorkflowMatrixView Plan AA S24 (1 page mirror cross-module — Case 2 fits Pattern 13 read-only admin Designer mirror + Pattern 14 Tailwind JIT palette + Pattern 15 HTML table rowSpan iteration helper). **Decision tree forward:** Em chủ trì gọi em với task code edit → em ACCEPT case (a)/(b) khi spec deterministic, REFUSE nếu first-time pattern. Em chủ trì confirm Layer A governance still active scope SOLUTION_ERP. Token cost spawn này ~5k (3 Read + 1 RAG query + 1 Edit + final report). KHÔNG curate — defer em main full curate session. Tag: `[verify, phase-9, infra]`.
|
||
|
||
- **2026-05-22 (S29 wrap — Plan CA Chunk B + Plan B 4 chunks Case 2 cookie-cutter + 1 stopped E3 + Pattern 12-bis NEW):** Implementer = busiest agent S29 với 5 spawn total. **Plan CA Chunk B (~10K):** 4 master pages mirror fe-admin→fe-user byte-identical SHA256, touch 6 file (4 page + App.tsx +5 route + menuKeys.ts +5 key Catalogs*), 948 LOC mirror PASS 0 TS err. Saved `pattern_master_page_mirror.md`. **Plan B 4 spawn cumulative:** (A2 Mig 32 ~25K) schema +column FK Restrict IX + Configuration + DbInitializer SeedSampleContractWorkflowV2 — **stash em main WIP ContractWorkflowService.cs** để build verify clean (em main + Implementer parallel touch BE → race condition trick); (C Mig 33 ContractLevelOpinions ~25K) entity + Mig + Config + DbSet + Contract.cs +LevelOpinions nav — **Pattern 12-bis NEW cross-module entity cookie-cutter mirror PE→Contract** scaffold 4-file pattern documented Patterns section; (D FE Workspace V2 ~12K) ContractCreatePage × 2 app +useQuery V2 + Select dropdown wire ApprovalWorkflowId, 88 LOC mirror byte-similar; (E3 stopped mid-task) FE Section 5 V2 STOPPED at "check ContractDetail type" judgment call → em main solo finish. **Lessons:** (1) **Race condition em main + Implementer parallel BE** → stash trick works but adds overhead. Forward SEQUENTIAL chunks A→B→C khi cùng touch BE, NOT parallel. (2) **Complex FE feature mirror với type extend + new component** → em main solo more reliable than Implementer khi spec ambiguity > 20% in Read-required component inspection. (3) Pattern 16-bis 4-place mirror cross-app reinforced 2× (Plan CA Chunk B + Plan B Chunk D) — verify Layout staticMap khi page move/route enhance. **Patterns proven NEW S29:** Pattern 12-bis cross-module entity scaffold + Pattern 16-bis 4-place mirror reinforced. **Anti-pattern observed:** (a) Implementer E3 stopped mid-task FE complex judgment — em main miss provide concrete component template trong prompt. (b) Race condition parallel BE → stash workaround. Tag: `[pattern, phase-9, frontend+infra]`. KHÔNG curate (33.2KB OK borderline > 25KB threshold but close — defer to next session em main full curate khi S30 wrap).
|
||
|
||
- **2026-05-22 (S29 Plan B Chunk D PASS — FE ContractCreatePage V2 Workspace dropdown × 2 app cookie-cutter mirror PE):** Spec deterministic 100% từ em main reference `fe-user/src/components/pe/PeWorkspaceCreateView.tsx` (canonical V2 dropdown lines 80-89 useQuery + lines 152-172 Select UI). 2 file mirror × 2 app `fe-admin/fe-user/src/pages/contracts/ContractCreatePage.tsx`: +44 LOC each = +88 LOC total byte-similar (git diff stat verify). Changes: (1) `useState approvalWorkflowId = ''` mới + (2) `useQuery approval-workflows-v2-contract` filter ApplicableType=3 client-side filter isUserSelectable=true (mirror PE Mig 25 pattern Plan AA S24) + (3) `Select dropdown "Quy trình duyệt V2 (tùy chọn)"` placement giữa FormFields + Budget section, blank = V1 fallback hint "(đã add ContractHeaderForm function, KHÔNG add ContractEditForm function vì spec scope CreatePage workspace only - edit-mode update endpoint defer)" + (4) Wire `approvalWorkflowId: approvalWorkflowId || null` vào CreateContractCommand POST body. BE precondition verify: `CreateContractCommand` record line 17-36 ContractFeatures.cs đã có `Guid? ApprovalWorkflowId = null` field (em main commit Chunk E1 PRIOR — comment marker "[Plan B S29 2026-05-22 Chunk E1] Drafter pick V2 workflow lúc create"). FE wire safe — no DTO mismatch. Build verify: `npm --prefix fe-admin run build` PASS 0 TS err 1926 modules 1.40MB gzip 358KB 16.07s; `npm --prefix fe-user run build` PASS 0 TS err 1916 modules 1.32MB gzip 343KB 8.84s. Pre-existing CSS @import warn + INEFFECTIVE_DYNAMIC_IMPORT realtime.ts warn unchanged (baseline noise). **Pattern 16-bis 4-place mirror check applied:** (1) Page file × 2 app DONE byte-similar; (2) App.tsx Routes N/A (enhance existing `/contracts/new` route - không route mới); (3) menuKeys.ts N/A (không menu key mới — page enhancement); (4) Layout staticMap N/A (route unchanged). Token ~12k Case 2 cookie-cutter (4 Read PE source + 2 Edit per file × 2 = 4 Edit total + 2 npm build + 1 git commit + memory update). Commit `62b50d1` clean 2 file. KHÔNG push remote — em main coordinate Chunk E final batch. **Pattern 5 mirror 2 app §3.9 applied 9th cumulative S20-S29** (proven IDENTICAL bytes hash check sau edit batch — git diff stat confirm). **Pattern 12-bis cross-module FE cookie-cutter mirror** demonstrated: PE PeWorkspaceCreateView V2 dropdown → Contract ContractCreatePage V2 dropdown clean (same useQuery shape, same Select markup, same filter logic, same POST body wire) — discriminator field ApplicableType=3 swap from `defaultType` (PE 1/2). Reusable pattern future Budget V2 / any cross-module entity với V2 workflow integration. Tag: `[pattern, phase-9, frontend]`.
|
||
|
||
- **2026-05-22 (S27 Plan CA Chunk B — Move 4 master pages fe-admin → fe-user, Case 2 cookie-cutter):** Spec từ em main deterministic 100% (Investigator pre-verify fe-user parity DataTable/PageHeader/PermissionGuard/usePermission/6 shadcn ui/types/master.ts byte-identical). Execute parallel: 4 `Write` cho master pages + 1 `Edit` menuKeys.ts (+5 key Catalogs*) + 2 `Edit` App.tsx (import + route block). LOC delta `+962` (4 file 948 LOC mirror + 14 LOC App.tsx + menuKeys.ts). Verify SHA256 byte-identical 4 file: `C1760788...` / `BDF0529E...` / `68213D62...` / `6F482614...` all match admin source. `npm run build` fe-user PASS 0 TS err 1916 modules 14.14s (pre-existing CSS @import + chunk-size + INEFFECTIVE_DYNAMIC_IMPORT warn unchanged). Commit `06a441c` 6 file changed. **Pattern 16 NEW** — byte-identical mirror admin → user khi parity confirmed (memory `pattern_master_page_mirror.md`): copy nguyên file (KHÔNG modify), verify SHA256 post-write, regression-safe vì admin code đã UAT pass. **Token cost ~10k Case 2** (4 file mirror cookie-cutter, NO logic decision). KHÔNG push remote (Chunk A em main solo BE parallel chưa xong, Chunk C sidebar filter + Chunk D smoke verify defer). Tag schema S28: `[pattern, phase-9, frontend]` cho Pattern 16. **Gotcha S27**: PowerShell `$_` variable in `ForEach-Object` block bị Bash tool shell-escape eaten — workaround dùng `Get-FileHash file1, file2, ... -Algorithm SHA256 | Format-Table` list literal thay vì pipeline iterate.
|
||
|
||
- **2026-05-21 (S26 t1, Plan AG Chunk A+B+C PASS — Phase 1 PE List tree view 2-level):** UAT feedback bro Tra Sol "đám rừng" flat list → Outlook folder tree. **3 chunk cumulative 1 commit** `0bf6c7e` 2 file +346/-116 LOC = +115 LOC each. Mirror 2 app §3.9 IDENTICAL post-edit (SHA256 verify match `21001E90...`). Chunk A useMemo group nested: `ProjectGroup{projectId, projectName, goiThauList[], totalCount}` + `GoiThauGroup{displayName, normalizedKey, items[]}`. Normalize trim + toLowerCase group key, display raw đầu tiên trong group. Fallback "(Dự án đã xoá)" empty projectName + "(Chưa phân loại)" empty TenGoiThau. Sort vi locale 2 cấp A-Z. Filter pendingMe → DaGuiDuyet áp dụng TRƯỚC group (empty state đúng). Chunk B UI `<details>/<summary>` HTML native 2-level — fe-user no shadcn Accordion → native browser disclosure widget free. Tailwind v3 named groups `group/proj` + `group/gt` cho chevron rotation `group-open/proj:rotate-90`. `[&::-webkit-details-marker]:hidden` ẩn default disclosure triangle browser. 📁 + 📄 emoji icon inline + count badge `rounded-full bg-slate-200/100`. PE card content preserve nguyên (text + badge + date format + contractId hint — line 209-248 cũ). Chunk C localStorage persist Set<string> key `pe_list_expanded_groups`. Project key: `projectId or '__no_project__'`. Gói thầu key: `${projectId}::${normalizedGoiThau}`. Default empty Set (all collapse) — Outlook-style closed default. `try/catch` defensive cho localStorage (storage quota / private browsing). Header badge `pendingMe ? totalRowCount : list.data?.total` (replace `rows.length`). Empty state check `projectGroups.length === 0` (replace `rows.length === 0`). Import `useMemo, useState` từ 'react' (file pre-existing chỉ import từ tanstack). Build: fe-user PASS 0 TS err 1291.33 KB gzip 337.00 KB 1907 modules 16.05s; fe-admin PASS 0 TS err 1402.68 KB gzip 357.51 KB 1926 modules 6.86s. Pre-existing CSS @import warn + INEFFECTIVE_DYNAMIC_IMPORT realtime.ts unchanged. KHÔNG ops git push (em main verify Reviewer rồi push). Token ~16k (close to ~14k baseline Case 2 mirror 2 app). **Pattern 19 NEW**: HTML native `<details>/<summary>` + Tailwind named groups (`group/<name>`) + localStorage Set<string> persist cho hierarchical UI when no Accordion lib available. Free open/close state native browser (Space/Enter keyboard accessible) + 0 JS state per node + serialize/deserialize Set ↔ JSON array string. Tailwind v3 named groups syntax `group/proj` parent + `group-open/proj:rotate-90` child differs from default unnamed `group` + `group-open:rotate-90` — critical when nested groups cùng level cần distinct event scope. Reusable cho future tree views: Project explorer · Dept hierarchy · Permission tree · Workflow definition step list (vs HTML5 native vs shadcn vs JS library). Anti-pattern: nested same-name `group` would inherit parent state → both rotate sync. **Pattern 5 mirror 2 app §3.9 applied 8th cumulative S20-S26** (proven reliable IDENTICAL hash check sau edit batch — recommend tooling `git diff fe-admin/X fe-user/X` after every multi-file edit batch).
|
||
|
||
- **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-22 (S28 wrap — Layer A governance distributed active, Implementer policy local apply):** S28 em main solo cả buổi (KHÔNG Implementer work code thực sự). Timeline: t1 RAG ROI verdict marginal-short/transform-long → t2 bro feedback "ghi mọi tương tác" → t3 em đề xuất 2-week monitoring 5 metric → t4 bro caught self-authorize cross-project rule mistake → t5 governance broadcast Layer A active 3-Layer distributed scope-down về SOLUTION_ERP self-discipline. **Implementer perspective về Layer A governance:** (1) Pattern proven ≥ 2× qualifies Layer B nominate. **Pattern 7 per-NV admin opt-in flag (Mig 29 AllowDrafterEdit + Mig 30 AllowApproverEditSection1 + Mig 31 AllowEarlyApprove + AllowDelegate) đã proven 4× — strong candidate Layer B promote khi unfreeze.** (2) Tag schema mandatory áp dụng forward: store Pattern chunk với format `[pattern, phase-<N>, <bc>]` — vd Pattern 19 HTML details tree view → `[pattern, phase-9, frontend]`; Pattern 18 FE userMap fallback → `[pattern, phase-9, frontend]`; Pattern 16 preventive batch fix → `[pattern, phase-9, cross-cutting]`. (3) source_path convention: `solution_erp/pattern/<topic>-<date>` — vd `solution_erp/pattern/tailwind-jit-palette-2026-05-19` cho Pattern 14, `solution_erp/pattern/per-nv-flag-2026-05-15` cho Pattern 7. (4) **KHÔNG self-authorize cross-project rule (lesson S28 t4)** — distributed governance respects boundary, Implementer agent KHÔNG override Layer A scope cho cross-project (vd "NamGroup follow SOLUTION_ERP Pattern 19" → REFUSE cross-project assertion, route lên Layer B human review). (5) Quên rule cũ "mọi tương tác mandatory store" — **ABANDONED** (was self-authorize over-reach). Forward S28+ commit: Implementer apply tag schema `[type, phase, bc-or-module]` mandatory cho mỗi Pattern entry mới + scope discipline strict SOLUTION_ERP only + KHÔNG cross-project rule assertion + 4-category default (pattern/architecture/decision/gotcha) + skip list (ephemeral, code, log) + 11 phase enum (phase-9 UAT ACTIVE) + 8 BC + 5 cross-cutting + optional prefix.
|
||
|
||
- **2026-05-22 (S27 wrap-up em main proxy - retrospective REFUSE analysis):** Em main S27 SOLO cả buổi vì registry KHÔNG load (per pitfall VIPIX #1+#2). Retrospective analysis 6 task S27 vs ACCEPT/REFUSE criteria:
|
||
|
||
| Task S27 | Implementer fit? | Verdict |
|
||
|---|---|---|
|
||
| C1 Curate cicd-monitor 72KB | ❌ REFUSE #1 (judgment §6.5 KEEP vs CUT) | Em main solo CORRECT |
|
||
| C2-C4 Curate 3 agent MEMORY | ❌ REFUSE #1 same | Em main solo CORRECT |
|
||
| C5 Audit drift §6.4 + §9.4 | ❌ REFUSE #1 same | Em main solo CORRECT |
|
||
| A3.1 Write 5 PS scripts | ✅ ACCEPT Case 2 (5 file cookie-cutter mirror pattern) | **Implementer would ACCEPT** - em main miss delegate opportunity |
|
||
| A3.2 Dashboard HTML + generator | ❌ REFUSE #7 (first time pattern, no precedent) + #2 UX design needed | Em main solo CORRECT |
|
||
| A4 rag-onboarding-guide.md 421 lines | ❌ REFUSE #2 (docs writing judgment) | Em main solo CORRECT |
|
||
| F1 Qdrant Web UI fix | ❌ REFUSE #4 (bug reasoning chain) | Em main solo CORRECT |
|
||
| F2 4 agent files fix model:inherit | ✅ ACCEPT Case 1 (4 file mechanical same edit) | **Implementer would ACCEPT** - em main miss delegate opportunity |
|
||
|
||
**Verdict: 2/8 task lẽ ra delegate được Implementer (Case 1+2) nhưng registry empty → em main forced solo.** Net loss ~30 phút time + miss cookie-cutter mirror discipline. Pattern 20 NEW saved foundation: "**5 PS scripts mirror pattern** — start/stop/status/dashboard/boot family cùng ASCII discipline + same Write-Host structure + same try-catch pattern" reusable cho future infra automation. **Pending post-restart CLI S28+:** Implementer Case 2 spawn cho any mass file mechanical refactor.
|
||
|
||
- **2026-05-22 (Curate session em main):** Archived 12 verbose Recent activity entries S21 t3 → S24 Plan AA → `archive/2026-05-q1.md`. KEEP: S26 Plan AG (Pattern 19 NEW), S25 wrap (Patterns 16-18 NEW), S25 Plan AB, setup baseline. Patterns 1-19 foundation section preserved. Memory size before: 38.8 KB → after: target ~22-24 KB.
|
||
|
||
- **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-22 em main full curate** — archived 12 verbose entries (S21 t3 → S24 Plan AA) → `archive/2026-05-q1.md`. KEEP: S26 Plan AG, S25 wrap, S25 Plan AB, setup baseline. Patterns 1-19 foundation preserved. Per `feedback_md_compact_narrative.md` §6.5 — archive preserves full verbose entries cho cross-session audit retrieve. Next curate trigger: > 25KB OR Plan B Contract V2 wire complete.
|