# S55 (2026-06-09) — Nạp master data thật từ Excel + Project +4 cột (Mig 48) — HMW-mode ON, prod-verified > **Commit `69cb393` → Gitea Run #377 PASS ~4m33s, prod-verified.** Anh: `/session-start` → giao file Excel "HẠNG MỤC CÔNG VIỆC DỰ ÁN" → "nạp master data vào đi nhé" → `/ultra-on "workflow làm xong hết đi nhé"`. HMW fan-out cross-stack, ship to prod. ## Yêu cầu Nạp master data thật của công ty từ file Excel 7-sheet (`00- DATA- HẠNG MỤC CÔNG VIỆC DỰ ÁN - trình ký online (1).xlsx`) vào hệ thống. ## Quyết định (anh chốt qua AskUserQuestion) - **Q1 schema:** Project thiếu 4 field (Năm/Chủ đầu tư/Địa điểm/Gói thầu) → **thêm cột thật + migration** (không gói Note). - **Q2 target:** **Cả 3 entity → Dev rồi deploy prod** (coexist với demo master cũ). ## Data inventory (Excel 7 sheet → 3 nguồn loadable) | Sheet | → Bảng | Số | |---|---|---| | `00- Project list` | `Project` | **62** dự án (Mã + Năm; ~6 có tên/CĐT/địa điểm/gói thầu đầy đủ) | | `01_Final - Hạng mục` / `00- DATA` | `WorkItem` | **71** (Vật tư 16 · Thầu phụ 30 · MEP 9 · Thiết bị 16) | | `00- Data list TP_NCC` | `Supplier` | **3** mẫu (TRUONGGIANG/TANPHU/TGN — template 40 cột) | **Data-quality catch (em main):** sheet Hạng mục cột MEP **gộp 2 nhóm** (9 MEP Sub + divider "THIẾT BỊ" + 16 Equipment). Pass 1 lùa hết 26 vào "MEP" + bắt nhầm divider "THIẾT BỊ" làm item → **fix split** (col J label) → đúng 71 item / 4 category. Provenance: `scripts/master-import-data.generated.md` (generated, source-of-truth cho seed). ## HMW flow (8-agent roster, fan-out + sequential verify) - **P0/P1 recon** — 🟦 investigator-codebase: map Master schema thật. KEY finding: `WorkItem` master **ĐÃ TỒN TẠI** (Code/Name/Category/IsActive) → Hạng mục resolves favorably (no new table). Seed pattern = `SeedDemoMasterDataAsync` per-code idempotent **UNGATED** (reaches prod by design). - **P2 execute (parallel, file-disjoint):** - 🟨 implementer-backend: Project entity +4 (`Year int?` · `Investor/Location/Package string?` maxlen 250/500/300) + `ProjectConfiguration` + **Mig 48 `AddProjectMasterFields`** (3-file, applied Dev+Design) + `ProjectFeatures` DTO/Create/Update/validators/handlers/projections +4 + **`SeedRealMasterDataAsync`** (62+71+3, per-code idempotent, wired UNGATED line 118 sau SeedCatalogsAsync). - 🟧 implementer-frontend: `ProjectsPage.tsx` form +4 input (Năm/Chủ đầu tư/Địa điểm/Gói thầu) + bonus cột "Chủ đầu tư" + `types/master.ts` +4 — **2 app SHA256-identical** (`b0020610…` / `93ac1b0f…`). npm build ×2 PASS. - **Runtime Dev proof (em main):** chạy API trên Dev → DbInitializer seed → sqlcmd verify: 62 proj/71 wi/3 sup landed, `CAL01.Investor` populates, 0 overflow/dup-crash. - **P4 reviewer** 🟥: ran 293s/31-tools nhưng **truncated trước verdict** (gotcha #53) → em main hoàn tất đúng việc nó định (clean `dotnet test` = 216 PASS, giải tỏa cached-binary concern) + 10-dim verify. - **P3 harvest** 👤: proxy-append 2 MEMORY truncated (implementer-backend + reviewer); FE+investigator self-appended. Containment: git-diff legit-only + Qdrant chunk 2418=2418 (0 rogue RAG-write). - **commit → cicd** 🟩: Run #377 PASS prod-verified. ## Verification - **Build 0-err · Test 216 PASS** (58 Domain + 158 Infra; +1 compile-fix dòng `MasterCatalogFilteredUniqueTests` thêm 4 null args cho CreateProjectCommand — necessary, không phải scope-creep). - **Runtime Dev:** all real data landed, Investor col works. - **Prod (Run #377 / run_number 263):** Mig 48 applied · Projects spot-6/6 (APVN01…ZOTE01) · WorkItems VT/TP/MEP/TB=71 · Suppliers 3 · CAL01.Investor="Công ty TNHH Calofic" (N-literal) · bundle admin `DmjI8Cmn`→`B-d6893W` / user `YxL_MljK`→`XdKzt9LL` · health 200/200 · /api/projects 401 wired. Prod totals: Projects=70 (62 real + 8 demo coexist), WorkItems=86. ## Key design facts - **Ungated seed = reaches prod:** `SeedDemoMasterDataAsync` (suppliers/projects) + `SeedCatalogsAsync` (workitems) đều gọi NGOÀI gate `if(!demoSeedDisabled)` (line 108/115) — by design (DbInitializer:75 comment "GIỮ … SeedDemoMasterData/Catalogs" cả khi DemoSeed:Disabled=true). `SeedRealMasterDataAsync` mirror = wired ungated line 118 → real data tự lên prod khi deploy. - **Per-code idempotent** (`existingCodes.Contains(code)→skip; else Add`) — re-run safe, coexist demo, expand-over-time. **FLOCK01 collision** (demo có sẵn) → real FLOCK01 skip (demo thắng; real code+year only, acceptable). Note cho công ty: sửa tên FLOCK01 qua UI nếu cần. - **No new table** (Mig 48 = 4 AddColumn) → tables vẫn 92. Mig 47→**48**. ## Lessons - **2 agent return truncated** (implementer-backend + reviewer, gotcha #53) → em main recover qua **disk/runtime truth** (build/test/sqlcmd/git), KHÔNG agent return-message (`feedback_agent_kill_recovery`). cicd verdict-FIRST brief → KHÔNG truncate (PASS clean) — reinforces "emit verdict early". - **Real-data import discipline:** extract Excel → clean generated spec file (chống truncation khi nhồi 136 dòng vào brief) → implementer convert to C# → runtime Dev proof TRƯỚC prod (catch overflow/dup) → cicd sqlcmd spot-check real Codes + N-literal cho unicode field. - **Data-quality:** đọc cấu trúc Excel THẬT (merged col, divider row) trước khi map — pass 1 nhầm divider "THIẾT BỊ" = item; split đúng theo label col. ## Files (17 committed `69cb393` + scratch) BE: `Project.cs` · `ProjectConfiguration.cs` · `ProjectFeatures.cs` · `DbInitializer.cs` (+210, seed) · `Mig 48` 3-file. FE: `ProjectsPage.tsx` + `types/master.ts` ×2 app. Test: `MasterCatalogFilteredUniqueTests.cs` (compile-fix). Provenance: `scripts/master-import-data.generated.md`. Memory: 4 agent MEMORY (2 self + 2 proxy).