Files
solution-erp/.claude/agent-memory/implementer/MEMORY.md
pqhuy1987 6eec8d78fb [CLAUDE] Docs+Memory: Plan CA wrap — gotcha #50 + Implementer Pattern 16-bis + STATUS
docs/gotchas.md:
- Add gotcha #50 "Page move cross-app Layout.tsx resolvePath staticMap missed mirror → silent sidebar drop"
- Reference Hotfix 1 commit e55d96b + Implementer Chunk B 06a441c missed point 4
- Add checklist item 25 vào "Checklist debug bug mới" section

.claude/agent-memory/implementer/MEMORY.md:
- Add Pattern 16-bis "4-place mirror checklist khi cookie-cutter copy page CROSS-APP"
- 4 places: page + Routes + menuKeys.ts + Layout.tsx staticMap
- Bug latency observed lesson + REFUSE criteria note + Reviewer Cat 1 wire claim verify suggestion

docs/STATUS.md:
- New Last updated S29 header với Plan CA cumulative summary
- 7 commits chain + 2 CI runs PASS + bundle hash rotate + multi-agent ROI breakdown
- Stats updated: 50 gotcha (+1), 13 AppRoles (+1 CatalogManager), 34 active users (+catalog.manager), 36 FE pages (+4)

Docs-only commit → CI skip per paths-ignore (gotcha #41 + #47 confirmed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 11:45:41 +07:00

29 KiB
Raw Blame History

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)
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:

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:

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).

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.

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 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.

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)

  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-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 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 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.