Files
solution-erp/.claude/agent-memory/investigator-codebase/MEMORY.md
pqhuy1987 6a664298fa
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m10s
[CLAUDE] Office: P11-E AttendanceReport+Excel+OtPolicy + P11-F MaTicket codegen (Wave 1)
P11-F: MaTicket gen-on-create qua WorkflowAppCodeGen (IT/2026/NNN Serializable atomic, kanban no-workflow). P11-E: GetAttendanceReportQuery monthly aggregate (day-type weekday/weekend/holiday OT x OtPolicy multiplier in-memory) + AttendanceReportExcelExporter (ClosedXML) + 2 endpoint Admin-only + fe-admin AttendanceReportPage. Migration-free. +5 test (186->191). reviewer PASS (gotcha #44 role-string verified, 0 blocker).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 12:34:48 +07:00

22 KiB
Raw Blame History

Investigator-Codebase Agent — Persistent Memory

Persistent diary cross-session. Auto-injected first ~200 lines at spawn (L1 HOT). Update BEFORE every stop. Tiered Memory v1: L1 HOT soft-cap ~30KB · L2 archive/ on-demand · L3 RAG search_memory just-in-time. Keep entry ≤ 1.5K chars (gotcha #53). Full verbatim history pre-S40 → git d2f52ba + archive/2026-05-q1..q4.md. Renamed S39: investigator → investigator-codebase (internal half; external → investigator-api).


🎯 Role baseline

Read-only INTERNAL audit SOLUTION_ERP codebase. Tools: Read, Grep, Glob, Bash + 5 RAG MCP. Output: concise findings <500 words + file:line refs. Skills: contract-workflow + permission-matrix + ef-core-migration.

🚫 Split boundary (S39)

  • MINE: internal SQL/EF/grep/reference mirror, sqlcmd schema scan, controller audit, migration diff, count grounding
  • NOT: external docs/CVE/lib → investigator-api · write → implementer · test → test-specialist · architecture decision → em main

📋 Patterns proven (apply confidently)

Schema scan via sqlcmd

sqlcmd -S "(localdb)\MSSQLLocalDB" -d SolutionErp_Dev -Q "..."     # runtime API (primary)
sqlcmd -S "(localdb)\MSSQLLocalDB" -d SolutionErp_Design -Q "..."  # ef tooling
ssh vietreport-vps "sqlcmd -S .\SQLEXPRESS -d SolutionErp -U vrapp -P '...' -Q '...'"  # prod

Queries: sys.columns, sys.triggers, __EFMigrationsHistory, COUNT(*), sys.indexes. Gotcha 2 LocalDB distinct (feedback_designtime_runtime_db): _Dev=runtime (appsettings.Development), _Design=dotnet ef default. Prod password fallback C:\inetpub\solution-erp\api\appsettings.Production.json khi $env:PROD_DB_PASSWORD empty.

Controller / wire-claim audit

  • Grep \[Route\("api/[a-z]+"\)\] enumerate controllers · \[Authorize(Policy = "..." per-action policy (gotcha #44 silent 403 class-level quá strict)
  • Grep // Mock / alert( / setEditing(null) // close UI — wire claim bugs · IActionResult vs ActionResult<T>

Smoke verify catalog

Bearer từ POST api.solutions.com.vn/api/auth/login → status matrix expected vs actual + file:line evidence.

Memory cross-reference

27 user-memory tại C:\Users\pqhuy\.claude\projects\D--...\memory\MEMORY.md (index). Key: per_chunk_commit · uat_skip_verify · audit_reuse_before_clone · designtime_runtime_db · per_nv_permission_scope · ef_migration_backfill_reorder · status_handoff_tiering (S40) · 7agent_split_upgrade (S39).

External research → DEFER investigator-api (split S39)


⚠️ Anti-patterns

Skip MEMORY update · Vague "seems like/probably" · Missing file:line · >500 words · Scope drift to architecture recommendation (em main decides)


🧠 SOLUTION_ERP context essentials (S40 verified — re-grounded)

  • DB: Dev SolutionErp_Dev · Design SolutionErp_Design (distinct) · Prod .\SQLEXPRESS/SolutionErp/vrapp via SSH vietreport-vps
  • Migration path: src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/*.cs (⚠️ NOT root /Migrations/). 40 mig, last 20260528090839_AddAttendances.
  • Counts S40: 40 mig · 84 SQL tables (77 DbSet + 7 Identity, count .ToTable() ModelSnapshot NOT DbSet) · ~211 endpoints · 65 FE pages (36 admin + 29 user *Page.tsx) · ~53 menu keys (BE MenuKeys const) · 130 test (58 Domain + 72 Infra) · 55 gotchas (format ### N. highest #55) · 27 user-memory · 6 skills · 7 sub-agents
  • Tech: .NET 10 Clean Arch (Api→Application←Domain + Infra) + CQRS MediatR + EF Core 10 + 2 React 19 Vite 8 TS 6 (fe-admin :8082 + fe-user :8080) + SQL Server + Gitea CI + IIS
  • Prod: api/admin/eoffice.solutions.com.vn · Gitea git.baocaogiaoduc.vn/vietreport-admin/solution-erp (Actions API /api/v1/repos/.../actions/tasks NOT /runs 404, cache stale ~2min gotcha #46 — cross-check VPS mtime)
  • Auth: admin@solutions.com.vn/Admin@123456 (full) / nv.test@solutions.com.vn/TestUser@123456 (Drafter). Response accessToken+refreshToken+user. Password ≥12 chars.

🔄 Active workflow schemas (V1 + V2 coexist post-S17)

  • V1 Mig 21 flatWorkflowDefinition pin PE/Contract cũ. Match Dept+PositionLevel.
  • V2 Mig 22-31ApprovalWorkflow pin PE/Contract mới, match ApproverUserId 1-1 OR-of-N cùng Cấp. Steps (Phòng) > Levels (Cấp). PE + Contract đã wire V2 (Mig 32+33 S29). Proposal V2 (Mig 38 S37 inline ApproveV2Async). WorkflowApps skeleton (Mig 39 S38 — ApproveV2 advance DEFER Phase 11).
    • Mig 25 IsUserSelectable · Mig 26 PE LevelOpinions UPSERT · Mig 29 Allow* per-NV (F1/F3 per Approver slot + F2 Users.AllowDrafterSkipToFinal) · Mig 30 F4 AllowApproverEditBudget · Mig 31 SkipToFinal→ApproverLevel
  • State machine PE 5 trạng thái: Nháp / Đã gửi duyệt / Trả lại (TraLai=98) / Từ chối / Đã duyệt
  • Mode Trả lại 4 option per-Level: OneLevel (lùi 1 Cấp) / OneStep (lùi Bước trước) / Assignee (pick NV đã ký) / Drafter (Phase=TraLai). 3 mode đầu giữ ChoDuyet lùi pointer. Admin bypass level.Allow*.

📅 Recent activity (FIFO — older → archive/git)

  • 2026-06-08 (S52 Phase 11-D/E/F product-close recon — 6 gap, on-disk): GAP1 IT-pool KHÔNG TỒN TẠI: AppRoles.All=13 role (AppRoles.cs:23) NO "IT"; 9 dept seed (DbInitializer.cs:2066 PM/QS/CCM/PRO/FIN/ACT/EQU/HRA/BOD) NO dept IT; MenuKeys NO It_* group (chỉ OffItTicket="Off_ItTicket" 1 leaf :123). → round-robin pool PHẢI tạo signal mới: option (a) +AppRoles.ItStaff const + seed user, (b) +dept "IT" code, (c) per-user flag User.IsItStaff. Least-loaded query = Users.Where(pool).OrderBy(u => Tickets.Count(AssignedToUserId==u.Id && Status!=Closed))ItTicket.AssignedToUserId Guid? SẴN (ItTicket.cs:21). GAP2 HostedService: đăng ký tại Infrastructure/DependencyInjection.cs:46 AddHostedService<SlaExpiryJob>() (KHÔNG Program.cs — grep Program.cs rỗng). Pattern SlaExpiryJob.cs: BackgroundService + ctor (IServiceProvider sp, ILogger) + ExecuteAsync Task.Delay(30s warmup)+while loop Interval 15min → _sp.CreateAsyncScope() resolve scoped IApplicationDbContext+IDateTime+INotificationService (:61-65). ItTicketSlaJob mirror: thêm dòng :47 + clone file. GAP3 OtPolicy (Hrm/OtPolicy.cs): 3 multiplier decimal(4,2) MultiplierWeekday/Weekend/Holiday (:21-23, seed 1.5/2.0/3.0) + 3 cap int MaxHoursPer Day/Month/Year (:26-28) + Code UNIQUE + IsActive (1 default công ty). Attendance.OtHours decimal? (Office/Attendance.cs:37) per-row, KHÔNG link OtPolicyId → join thủ công qua IsActive=true; công thức OT-pay = OtHours × multiplier(dayType) × hourlyRate, dayType phân loại từ AttendanceDate (Holiday tra Hrm_Holiday, Sat/Sun=Weekend, else Weekday). GAP4 Excel reuse: IContractExcelExporter.ExportAsync→RenderResult record (byte[] Content, string FileName, string ContentType) (IFormRenderer.cs:3); impl ContractExcelExporter.cs ClosedXML XLWorkbook+Worksheets.Add+MemoryStream→ToArray() (:103-109 content-type application/vnd.openxmlformats-officedocument.spreadsheetml.sheet); DI scoped :40; controller stream return File(result.Content, result.ContentType, result.FileName) (ReportsController.cs:35, mirror Forms/PE/Contracts). AttendanceExporter = clone + đổi columns + new CQRS command (mẫu ExportContractsToExcelCommand). GAP5 Attendance API: AttendancesController.cs 3 endpoint check-in/check-out/me ([Authorize] ko role); CQRS inline Office/WorkflowAppsFeatures.cs REGION 6 (:401-490) — CheckInCommand/CheckOutCommand/GetMyAttendanceQuery(Year,Month) chỉ trả LIST cá nhân (1 user/tháng). CHƯA có aggregate/monthly-report/all-users query → P11-E phải +GetAttendanceReportQuery(year,month,deptId?). ItTicket CQRS cũng inline cùng file (:354 GetItTicketsQuery + CreateItTicketCommand + UpdateItTicketStatusCommand, controller ItTicketsController.cs). GAP6 FE state: ItTicketsPage + MyAttendancePage TỒN TẠI cả 2 app (fe-admin+fe-user, comment "MIRROR SHA256 identical"), routes /it-tickets+/attendance (App.tsx:101-102), menuKeys OffItTicket+OffChamCong (:65-66), Layout map :84-85. THIẾU: ItTicket = SKELETON read-only kanban (banner :32-34 "Form tạo + auto-assign + SLA timer defer Phase 11"), NO create form/assign-UI/SLA-badge; Attendance = check-in/out OK nhưng NO admin report page / Excel export button / OT-pay column. NO menuKey Attendance_Report/It_Assign. Surprise: ItTicket+Attendance KHÔNG dùng Workflow V2 (kanban status flow, comment ItTicket.cs:6) — khác Leave/OT/Travel/Vehicle (LevelOpinion). Tag [p11-def-recon, it-pool-absent, otpolicy-multiplier, excel-reuse, s52].

  • 2026-06-08 (S51 gotcha #57 EXTENSION reachability audit — 6 candidate, RAG down, on-disk only): Bug class = soft-delete + bare .IsUnique() on Code → recreate-after-delete throws DbUpdateException 500. Verdict 6 cand: FIX 3 (Master) Department/Supplier/Project (Department/Supplier/ProjectConfiguration.cs:18/24/19 bare unique). ALL = AuditableEntity + GLOBAL HasQueryFilter(!IsDeleted) + Delete via .Remove()AuditingInterceptor.cs (State Deleted→Modified, IsDeleted=true) + Create AnyAsync(x=>x.Code==req.Code) NO !IsDeleted BUT global filter auto-hides soft-deleted → check passes → unfiltered index 500. CONFIRMED-reachable (DepartmentFeatures.cs:76+125, ProjectFeatures.cs:87+147, CreateSupplierCommand.cs:45+DeleteSupplierCommand.cs:20). SKIP 3: (a) ContractClause (ContractClauseConfiguration.cs:18) — NO Create/Update/Delete handler ANYWHERE (only IApplicationDbContext.cs:32 DbSet; FormsController = templates only) → not CRUD-reachable. (b) MeetingRoom (MeetingRoomConfiguration.cs:20) — Delete sets IsActive=false NOT IsDeleted (MeetingFeatures.cs:178, comment :175 "FK Restrict → NOT soft delete") → index never gets soft-deleted row; Create also checks && !IsDeleted :113. (c) EmployeeProfile (EmployeeProfileConfiguration.cs:24/26 EmployeeCode+UserId) — Delete soft (EmployeeFeatures.cs:437) BUT Create BLOCKS reuse by design: UserId check AsNoTracking().FirstOrDefault(UserId==) (no HRM global filter) sees soft-deleted → throws ConflictException "Cần khôi phục" :160-163; EmployeeCode auto-gen atomic (never user-supplied/reused) → no collision. Completeness (grep ALL .IsUnique()): beyond 3 Master + 6 HRM-fixed (LeaveType/Holiday/Shift/OtPolicy/Vehicle/Driver all .HasFilter([IsDeleted]=0)), every OTHER bare-unique is either composite junction (Permission RoleId+MenuKey, *LevelOpinion, MeetingBookingAttendee, LeaveBalance, Attendance UserId+Date), nullable-code already filtered ([Ma*] IS NOT NULL: Contract/PE/Proposal/Budget/WorkflowApps), or no-soft-delete (WorkflowDefinition/ApprovalWorkflow Code+Version, ContractTemplate FormCode, WorkflowTypeAssignment, DepartmentApprovals). Mig 46 = exactly 3 indexes (Departments/Suppliers/Projects Code). Surprise: Master GLOBAL query filter MAKES the bug (auto-hides soft-deleted from check) — opposite of HRM where bug needs manual !IsDeleted; either way unfiltered index = 500. Tag [gotcha57-ext, reachability-audit, master-global-filter, s51].

  • 2026-06-08 (S50 P11-C Vehicle+Driver — HrmConfigs add-kind pattern VERIFIED on-disk, RAG down): HrmConfigs KHÔNG có "kind enum/registry" backend — 4 entity RIÊNG (LeaveType/Holiday/ShiftPattern/OtPolicy), NOT discriminated table. "kind" chỉ FE: HrmConfigKind union fe-admin/src/types/hrm-config.ts:4 + route param. Add 1 kind = mirror FULL entity stack 11 chỗ: BE (1) Domain Hrm/{X}.cs AuditableEntity soft-delete (2) Configurations/{X}Configuration.cs .ToTable+.HasIndex(Code).IsUnique() (3) ApplicationDbContext.cs:95-98 DbSet (4) IApplicationDbContext.cs:102-105 DbSet (5) HrmConfigFeatures.cs +Region N (DTO+List/Create/Update/Delete handler+validator, mega 4-region :30/125/222/328) (6) HrmConfigsController.cs +4 route hardcode [HttpGet/Post/Put/Delete("{kind}")] (Post/Put/Del [Authorize(Roles="Admin")], Get chỉ [Authorize]) (7) DbInitializer.cs:2329 SeedHrmConfigsAsync +if-block + skip-guard :2331 phải +&& OtPoliciesNew.AnyAsync() (8) MenuKeys.cs:88-92 +const + :149 All[] (Admin auto-grant SeedAdminPermissionsAsync loop idempotent). FE (9) HrmConfigsPage.tsx:45 KIND_CONFIG +entry + :114 KINDS[] + :379 renderCells branch + :166 smart-defaults + types/hrm-config.ts DTO (10) App.tsx:90 route /hrm/configs/:kind SẴN catch-all → KHÔNG cần sửa, chỉ +menuKeys (11) menuKeys.ts:38-42 + Layout.tsx:60-63 staticMap. gotcha #57 CONFIRMED còn trần: LeaveTypeConfiguration.cs:19 + ShiftPatternConfiguration.cs:19 + OtPolicyConfiguration.cs:22 .IsUnique() CHƯA .HasFilter("[IsDeleted]=0") (chỉ HolidayConfiguration.cs:18 đã fix Mig 43). → Vehicle/Driver Code UNIQUE PHẢI add filter ngay từ đầu. Mig 44 BẮT BUỘC CREATE TABLE (mỗi kind = bảng riêng, NOT discriminated → +2 bảng Vehicles+Drivers, không phải seed-only). VehicleBooking (Office/VehicleBooking.cs:13-19) pure free-text VehicleLicense/VehicleName/DriverName string, NO VehicleId/DriverId FK (grep empty) → P11-C catalog-only, FK link defer Mig sau. Latest Mig=43 FilterHolidayUniqueIndexByIsDeleted (20260601064128), next=44. Tag [p11-c, hrmconfig-add-kind, gotcha57, on-disk-verify].

  • 2026-06-07 (S50 wave h2-verify — B6 guardrail audit, read-only) [em main scribe from findings + H2 harvest]: Verified B6 wave-isolation 3/3 PASS. B6 = TWO complementary rules: (a) transient wave-*/ + agent-teams/ gitignored (.gitignore:93-94) → audit-noise=0; (b) canonical agent-memory/**/MEMORY.md TRACKED → rogue sub-write surfaces in git status. git check-ignore -v = ground-truth verifier BOTH directions (matched rule:line for ignored; empty for tracked). ⚠️ Ordering gotcha: wave/team patterns MUST sit AFTER !.claude/** (.gitignore:82-83) to win via last-match (:91 documents intent) — else !.claude/** un-ignores everything. All 10 MEMORY.md tracked (roster 8→10). Surprise (cross-cutting, both wave subs): Bash tool = /usr/bin/bash NOT PowerShell despite env=PowerShell → Get-ChildItem/Select-String/Test-Path fail (exit 2/127); read-only Bash-only subs MUST use POSIX (git ls-files/grep/ls). Tag [wave-h2, b6-isolation, posix-not-pwsh].

  • 2026-06-07 (Harness 1/2/3 adap-apply recon — 3 slice, HMW wave): Governance recon AI_INFRA broadcast harness-1/2/3. H1/H2 (Harness 1): roster 8→10 — CREATE 2 sub TÁCH BIỆT tooling-auditor (H1 freshness 4-mặt skill/sub-role/plugin/docs) + harvest-curator (H2 integrity 5-trục). H2 PARTIAL sẵn: session-end.md Phase 1.5 §L.b(d) spawn-record 4-field + (f) double-check moved-not-cut + (c) 0-byte AS-8 = Coverage+Completeness+Corruption (3/5); THIẾU Fidelity-escalate + Placement. RE-REPORT @session-start = 0 (chỉ generic Phase 2.7). 2 sub mirror inv-codebase read-set + store_memory strip + NO Write/Edit; color brown+teal (8 màu cũ hết). H2 wave (Harness 2): SE hmw.js = OLD pre-wave (no subMdPath/writeGuard/wave-block); AI_INFRA hmw.js = canonical template. git check-ignore -v = ground-truth B6: .claude/workflows/wave-test/wave.md HIỆN match .gitignore:83 !.claude/** = TRACKED → wave pattern PHẢI đặt AFTER !.claude/** (last-match-wins, mẫu hmw-mode.on :87). Read-only sub (4)=inv-cb/inv-api/reviewer/cicd; Write sub (4)=impl×2/test/fe-designer. B5 depends H2 harvest-curator. H3 email (Harness 3): broadcasts/ absent; id authoritative = se (NOT solution_erp), 6 others short {ai_infra,vipix,dyd,namgroup,ashico,bvaau} từ AI_INFRA/broadcasts/sister-commands/send-email.md:13-22 (folder name = 2nd source-truth); adap-apply.md:14 base-path STALE flat → outbox/all/*.md (latent bug). broadcasts/ ở root → commit OK (no gitignore rule). Containment post-P2: git-diff bắt 1 file-write (inv-api self-MEMORY), chunk-count 2414=2414 (0 RAG-write) = defense-in-depth proven. Tag [harness-recon, governance, hmw-wave, 2026-06-07].

  • 2026-06-01 (P11-C Vehicle+Driver catalog pre-flight): Mig 44 next (latest=Mig 43 FilterHolidayUniqueIndexByIsDeleted S45). NO Vehicle/Driver master exists — chỉ Office/VehicleBooking.cs (request, Mig 39) dùng FREE-TEXT (VehicleLicense/VehicleName/DriverName? strings, :13-19 comment "defer catalog Phase 11"). RECOMMEND home = extend HrmConfigs (NOT new module): Application/Hrm/HrmConfigFeatures.cs mega 4-region + HrmConfigsController ([Authorize] read / [Authorize(Roles="Admin")] write) — add Region 5 Vehicle + 6 Driver (kind vehicles/drivers), pattern proven 12-bis. ⚠️ HRM entities KHÔNG global HasQueryFilter → manual .Where(!IsDeleted) + UNIQUE soft-delete cần .HasFilter("[IsDeleted]=0") (Holiday Mig 43 lesson, LeaveType/Shift UNIQUE Code chưa có filter → nếu Vehicle BienSo UNIQUE phải add filter). FE cheap: HrmConfigsPage.tsx declarative KIND_CONFIG Record — add 2 entry vào KIND_CONFIG + KINDS[] + renderCells branch + smart-defaults; NO new page. Menu+perm: add 6 const MenuKeys.cs (+Hrm_Config_Vehicles/Drivers), thêm vào All[] (:140) → Admin auto-grant qua SeedAdminPermissionsAsync loop (:1909 idempotent), +2 MenuItem DbInitializer :1757, +2 menuKeys.ts mirror. Hrm_Config KHÔNG inherit-root (4 root=Contracts/Workflows/Pe/PeWf only) → leaf cần row riêng (loop lo). Fields (NamGroup XeCong DROPPED Mig 2026-05-15, ref response shape only): Vehicle{Code/BienSo UNIQUE, Hang, MauXe, SoCho int, TrangThai, GhiChu}; Driver{Code/Hoten, SDT, GPLX, Hang bằng, TrangThai}. FK link defer: P11-C = catalog only, optional FK VehicleBooking.VehicleId?/DriverId? giữ free-text back-compat (Mig sau). Tag [pre-flight, p11-c, vehicle-driver-catalog].

  • 2026-06-01 (MONTHLY DRIFT AUDIT): Ground truth code: migrations=42 (last AddLeaveBalances, path .../Persistence/Migrations/*.cs) · gotchas highest=#56 (file header NO self-count → drift chỉ ở file reference gotchas.md) · tests=154 (58 Domain+96 Infra, em main verified) · tables≈91 (45 config class nhưng Catalogs=4+ContractDetails=7+7 Identity untracked → khớp STATUS 91, KHÔNG cheap-exact). Biggest drift: ef-core-migration SKILL (frontmatter:3 "31 migration"→42, :19 history "31"→42 + thiếu rows Mig 27-42, :50 "59 bảng"→91, :80 "111 test"→154, :258/:267 "59 bảng"). dependency-audit SKILL:153 "49 bẫy"→56. CLAUDE.md:53 "40 mig→84 bảng"→42/91, :66 "130 test"→154, :133 "52 bẫy"→56. docs/CLAUDE.md:65 "52"→56. schema-diagram GAP: migration TABLE dừng Mig 16 (line 487); detail § cuối =§15=Mig 26 (§16=Related KHÔNG phải mig) → thiếu § cho Mig 27-42 (16 mig). database-guide:4 "47 bảng/13 mig"→91/42. STATUS:97 backlog "Curate 4 agent MEMORY 35.7/35.3/30.9/28.4" STALE (đã curate S40 78c9de3, all ≤16KB) → REMOVE. NO-CHANGE: contract-workflow (historical counts OK), form-engine, iis-deploy (no count), HANDOFF (S43 current), PROJECT-MAP (no count). Tag [drift-audit, monthly, 2026-06].

  • 2026-05-30 (P11-A WorkflowApps wire pre-flight): 4 module Leave/OT/Travel/Vehicle. Schema pin ĐÃ CÓ SẴN (Mig 39): Office/{Module}.cs đều có ApprovalWorkflowId?+CurrentApprovalLevelOrder?+WorkflowAppStatus (5-state khớp ProposalStatus). SKELETON tại Application/Office/WorkflowAppsFeatures.cs:11-15 (chỉ Create+List, KHÔNG Approve/Reject/Return/GetById). Proposal = mirror HOÀN HẢO (cùng Office ns, Mig 38): ProposalFeatures.cs:403-486 ApproveHandler = flatten Steps.OrderBy(Order).SelectMany(Levels.OrderBy(Order)) global level index → allLevels[CurrentApprovalLevelOrder-1] → actor match Level.ApproverUserId==uid||Admin → UPSERT LevelOpinion → advance++/DaDuyet. ⚠️ ApprovalWorkflow.cs:72 nói Level KHÔNG OR-of-N (1 ApproverUserId/Level) — KHÁC memory cũ "OR-of-N", verify lại. Gap: 4 bảng {Module}LevelOpinion mới (Mig 41+), 3 route/controller, 4 seed WF, FE Detail+Opinion (chỉ có WorkflowAppsListPage chung). ⚠️ enum ApplicableType THIẾU Travel (có Leave=5/OT=6/Vehicle=7/ItTicket=8); ExtendApplicableTypeForWorkflowApps mig empty Up/Down (enum-only). Tag [pre-flight, p11-a, workflowapps].

  • 2026-05-29 (S40 STATE GROUNDING): 7 metric verify. Migrations=40 (path .../Persistence/Migrations/*.cs, last AddAttendances). Gotchas=55 (### N.). git clean. DbSet=77 nhưng SQL tables=84 (em main verify .ToTable() ModelSnapshot — 77+7 Identity, "84 docs ĐÚNG", DbSet count sai 7). Endpoints=211 (docs ~223). FE pages fe-admin 36+fe-user 29=65 (docs 53 under-count). Menu keys=53 const (docs 85 over-count). 3 số tin cậy nhất = mig/gotcha/git. Lesson: tables phải count ToTable KHÔNG DbSet. Tag [state-grounding, docs-drift, s40].

  • 2026-05-29 (S39 BVAAU 7-agent extract): Đọc 8 file BVAAU .claude/agents/ ~22K. Split 4→7 trục research(2)/implement(2)/quality(3). Boundary: repo interface=domain, EF config=infra, test=test-specialist. Tool: cả 7 agent 5 RAG MCP (+search_code BM25 +store_memory +list_projects). BVAAU Phase 0 codebase RỖNG → aspirational template chưa battle-test; SOLUTION_ERP giữ 6 skill + backend/frontend split (thay domain/infra cho 2-FE fit). VIPIX guide claim KHÔNG verify được (file miss). Tag [cross-project, bvaau, port].

  • Archived S29-S37 → archive/2026-05-q4.md + git d2f52ba (S40 curate): S36 G-O2 Phòng họp clean-room + FullCalendar v6 MIT eval · S36 startup MEMORY-size audit · S35 G-H2 HRM clean-room verdict · S33 G-H1 NamGroup TblNhanVien 10-bảng (105 cols main) · S33 startup RAG verify · S32 Plan G 11-module backlog · S29 Plan CA+B pre-flight (3 patterns: 9-menu terrain, V1+V2 coexist, reference-template-paths cite line-range ROI). KEY absorbed: clean-room > NamGroup port verified 4× · Pattern 12-bis cross-module mirror · FK+freetext dual-write.


🔄 Curate trigger

  • ~30KB → archive recent → L2 archive/<period>.md. Stale >3mo → remove.

  • Last curate: 2026-05-29 S40 em main proxy (35.7→~20KB): archived 7 FIFO S29-S36 → q4 + git d2f52ba, refreshed stale essentials S25→S40 numbers, trimmed memory-list. Prev: S34 q3 · S32 q2 · S22 q1.