Compare commits
3 Commits
fe28ca3993
...
53f1d29e44
| Author | SHA1 | Date | |
|---|---|---|---|
| 53f1d29e44 | |||
| 4e09413fdb | |||
| c34bb51f71 |
@ -48,9 +48,9 @@ Read-only CI/CD + post-deploy verifier SOLUTION_ERP. Polls Gitea Actions API, ve
|
||||
- **Prod:** api/admin/eoffice `.solutions.com.vn` · SSH `ssh vietreport-vps` (Administrator, id_ed25519) · IIS site phys paths (S42 verified): API `C:\inetpub\solution-erp\api` · admin `\fe-admin` · user `\fe-user` (3 sites Started). DB `.\SQLEXPRESS`/`SolutionErp`/`vrapp` SQL-auth. **Conn string key = `ConnectionStrings.Default` (NOT `DefaultConnection`!)** — read pw from prod appsettings.Production.json when `$env:PROD_DB_PASSWORD` empty.
|
||||
- **SSH→PS quoting (S42 lesson):** nested bash→ssh→powershell mangles `$var`/`\"`. Use `iconv UTF-16LE | base64` → `powershell -EncodedCommand $B64`. Single-quote literal paths.
|
||||
- **Tests baseline:** **263 PASS** (S62 Run #286 sha 7926c21 spec; 45 Domain + 218 Infra — em-main supplied; supersedes prev 228/240/256). CI gate runs both test projects BEFORE build/deploy → status=success ⟹ test gate passed (`tasks` endpoint reports terminal as `status:success`, `conclusion` field NOT populated). Local grep undercounts (Theory/InlineData) — trust CI conclusion. Phase 9 UAT mode skip per chunk OK.
|
||||
- **Mig latest repo:** **Mig 50 `20260612173224_ReplaceBudgetModuleWithPeWorkItemBudgets`** (S61; DROPS old Budget module tables + adds PeWorkItemBudgets — schema net-reduce). Prev Mig 49 `AddWorkItemToPurchaseEvaluation` + 48 AddProjectMasterFields. Path `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/` (50 mig .cs non-designer total). Prod check `sqlcmd __EFMigrationsHistory ORDER BY MigrationId DESC TOP 5`. ⚠️ Table-count: `sys.tables` (is_ms_shipped=0, excl mighist) = **88** (S62 Run #286 verified — S61 Budget-replace DROPPED tables 93→88). Narrative-93 is STALE pre-S61 — when commit touches no schema, 88 is correct, don't FAIL on 88↔93. Always cross-ref COMMIT scope vs ambient count.
|
||||
- **Mig latest repo:** **Mig 52 `20260616035929_AddHoSoLinkToPurchaseEvaluation`** (S65; PE +HoSoLink hyperlink-NAS, AddColumn-only no new table). Prev Mig 51 `AddDepartmentParentId` (S65 Department.ParentId loose-Guid org-tree, AddColumn-only) + Mig 50 `ReplaceBudgetModuleWithPeWorkItemBudgets` (S61 Budget→PeWorkItemBudgets net-reduce). Path `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/` (52 mig .cs non-designer total). Prod check `sqlcmd __EFMigrationsHistory ORDER BY MigrationId DESC TOP 5`. ⚠️ Table-count: `sys.tables` (is_ms_shipped=0, excl mighist) = **88** (S62 Run #286 verified — S61 Budget-replace DROPPED tables 93→88). Narrative-93 is STALE pre-S61 — when commit touches no schema, 88 is correct, don't FAIL on 88↔93. Always cross-ref COMMIT scope vs ambient count.
|
||||
- **Bearer:** admin `admin@solutions.com.vn/Admin@123456` (full) · UAT `nv.test@solutions.com.vn/TestUser@123456` (Drafter CCM, gotcha #44 check)
|
||||
- **Bundle hash live S69:** admin `BDwV5d0X` (FROZEN since S68 Run #293 — fe-admin untouched S69) · user `CZfo_PFZ` (Run #294 sha ec517f7 — ROTATED from `DXkyUjtQ`, FE-user-only EmployeesListPage org-tree root "SOLUTION COMPANY" 1 file). ⚠️ ASYMMETRIC-deploy lesson (S66): FE-one-app commit → that app's bundle MUST rotate + OTHER app MUST stay frozen; admin-rotate-when-only-fe-user-changed = anomaly → flag. S50 mid-deploy transient lesson: pre-success snapshot can show intermediate FE copy in-flight — re-confirm hash AFTER status=success ALWAYS (anti-pattern #3). FROZEN-expectation runs (BE-only or other-app): hash MUST stay = live pre-deploy value; rotate w/o relevant FE change = anomaly.
|
||||
- **Bundle hash live S70:** admin `BDwV5d0X` (FROZEN since S68 Run #293 — fe-admin untouched S69-S70) · user `DbVv6rsf` (Run #295 sha 456c7a7 — ROTATED from `CZfo_PFZ`, FE-user-only EmployeesListPage layout-2col + tô-màu 1 file). ⚠️ ASYMMETRIC-deploy lesson (S66): FE-one-app commit → that app's bundle MUST rotate + OTHER app MUST stay frozen; admin-rotate-when-only-fe-user-changed = anomaly → flag. S50 mid-deploy transient lesson: pre-success snapshot can show intermediate FE copy in-flight — re-confirm hash AFTER status=success ALWAYS (anti-pattern #3). FROZEN-expectation runs (BE-only or other-app): hash MUST stay = live pre-deploy value; rotate w/o relevant FE change = anomaly.
|
||||
- **DB pw (S42, when `$PROD_DB_PASSWORD` empty):** `vrapp/buKL3TGBkD0wDDbYVw65QeX9` read from `C:\inetpub\solution-erp\api\appsettings.Production.json`→`ConnectionStrings.Default`. ⚠️ Skill-doc path `C:\inetpub\apps\SolutionErp\Api` is STALE → real path `C:\inetpub\solution-erp\api`. sqlcmd over SSH works direct (no UTF-16 encode needed). ⚠️ sys-catalog string-concat queries hit collation conflict (`Latin1_General_CI_AS_KS_WS` vs `SQL_Latin1_General_CP1_CI_AS`) → add `COLLATE DATABASE_DEFAULT` per concatenated column.
|
||||
|
||||
## 🔑 Critical config (flag commit nếu tái xuất)
|
||||
@ -75,39 +75,11 @@ BE (test+build) ~90s · FE × 2 ~60s/app · deploy ~30s · **total ~3min code /
|
||||
- **2026-06-16 S66 Run #290 (run_number 290, id404) sha=`c98030f` PASS ~4m24s (redesign foundation màu fe-user "nâng màu giữ brand" — FE-USER-ONLY 14 files, NO BE, NO migration):** Push `4004481..c98030f` 14 files all `fe-user/src/**` (index.css + 6 ui primitives Button/Dialog/Input/Label/Select/Textarea + 4 shell DataTable/Layout/PageHeader/TopBar + UserDashboardPage + 2 color-map types contracts/purchaseEvaluation). `.tsx`+`.css` → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + (DB pw read deferred, FE-only no DB touch). Run IN-PROGRESS first poll (running 10:15) — correctly did NOT verify-bundle-mid-flight (anti#3), polled iter3 status=success (10:13:04→10:17:28 ≈4m24s). CI gate (both test proj pre-deploy ⟹ status=success ⟹ test gate **263** baseline (45 Domain + 218 Infra) passed; `conclusion` empty — trust success). **★ BUNDLE ASYMMETRIC (the change-point — one-app-FE verify) ALL PASS, verified AFTER status=success +re-confirm STABLE no transient: user ROTATE `Cpion_xQ→DxK3fCfh`** ✓ (fe-user 14 files shipped) **+ admin FROZEN `DRob3iVl`==baseline** ✓ (fe-admin 0 files touched → MUST NOT rotate = correct). Health api live+ready **200/200** + admin/eoffice root 200. **★ CSS-REDESIGN-SHIPPED PROOF (live-vs-source diff, defeats stale-bundle false-pass):** fetch live eoffice CSS `index-DZ-56qoN.css` (71740 B) → grep brand `#1F7DC1` PRESENT + NEW accent tokens `--color-teal-{50..800}` + `app-gradient-brand` + `card-accent` (×5) + `--color-accent-{500,600}` ALL PRESENT ✓. Cross-check: these tokens = **0 occurrences in HEAD~1 index.css**, **added in c98030f** (git show source: teal×6, app-gradient-brand×1, card-accent×5, 1F7DC1×1) → live CSS IS new redesign NOT stale. **NO migration** — repo HEAD top = Mig 50 `ReplaceBudgetModuleWithPeWorkItemBudgets` GIỮ ✓ (commit 0 mig files; FE-only cannot alter schema → prod `__EFMigrationsHistory` top stays Mig 50 by construction, fe-user site static no .NET runtime — DB check skipped per FE-only scope). 0 regression. **LESSON: ASYMMETRIC FE-one-app verify = (a) status=success ⟹ deploy ran; (b) target-app bundle ROTATE + sibling-app FROZEN (rotate-sibling-when-untouched = anomaly→flag); (c) for visual/CSS redesign — fetch live CSS asset + grep claimed tokens, AND diff-prove tokens were 0-in-HEAD~1 / added-in-commit (live-token-present alone could be coincidental stale; the 0→N delta defeats stale-bundle false-pass). Visual "đẹp" NOT verified (anh xem mắt) — only ship+rotate+CSS-token-present. Tokens empty: anon Gitea works; FE-only ⟹ no DB pw needed.** Tag `[s66, run290, pass, fe-user-redesign-foundation, fe-only-14files, bundle-asymmetric-user-rotate-admin-frozen, css-tokens-shipped-0to-N-delta, teal-accent-gradient-brand, no-mig, test263]`.
|
||||
|
||||
- **2026-06-16 S65 Run #289 (run_number 289, id403) sha=`4004481` PASS ~4m41s (mở quyền XEM "Hồ sơ Nhân sự" read-only cho MỌI role eoffice — BE-ONLY 1 file DbInitializer SEED, NO migration, NO FE):** Push `cfed3d0..4004481` 1 file `DbInitializer.cs` (+66, new `SeedAllRolesHrmProfileReadPermissionsAsync` grant CanRead `Hrm`+`Hrm_HoSo` 13 role, upgrade-only mirror PE :2107, chạy SAU `RevokeTemporarilyHiddenModulesAsync` S58 để THẮNG revoke; Create/Update/Delete giữ false). `.cs` → full pipeline RAN. **GITEA_TOKEN+PROD_DB_PW empty** → anon Gitea API + DB pw từ prod `appsettings.Production.json`→`ConnectionStrings.Default` (`buKL3...`). Run IN-PROGRESS first poll (running 09:53) — correctly did NOT FAIL/verify-bundle-mid-flight (anti#3), polled iter5 status=success (09:52:03→09:56:44 ≈4m41s). CI gate (both proj pre-deploy ⟹ status=success ⟹ test gate **263** baseline (45 Domain + 218 Infra) passed; `conclusion` empty — trust success). **Bundle FROZEN (BE-only, NO FE change → MUST NOT rotate = correct): admin `DRob3iVl` + user `Cpion_xQ`** ✓ both unchanged pre==post (live advanced from S62 `0xKYGhhf`/`C81ZdG9G` via intervening S63/S64 FE deploys — narrative-Run#286 hash now 3 deploys stale; current live = baseline). Health live+ready **200/200** + admin/eoffice root 200. **NO migration** — prod `__EFMigrationsHistory` top = `20260612173224_ReplaceBudgetModuleWithPeWorkItemBudgets` (Mig 50) == repo HEAD GIỮ ✓ (commit 0 mig files). **★ SEED-EFFECT 7-CHECK reviewer ALL PASS (the change-point — asymmetric read-open/write-locked, non-admin `nv.test`=Drafter + admin):** (1) menus/me non-admin tree = exactly `['Hrm','Hrm_HoSo']` present ✓ + (4) `Hrm_Dashboard`+`Hrm_Config*` ABSENT ✓ (revoke still che); (2) non-admin GET /api/employees?page=1&pageSize=20 = **200** ✓ (was 403 — MẤU CHỐT, seed áp đúng + `Hrm_HoSo.Read` resolve qua permission matrix); (3) non-admin GET /api/employees/{id} = **200** ✓; (5) non-admin POST = **403** ✓; (6) non-admin PUT+DELETE = **403/403** ✓ (read-only giữ); (7) admin GET = **200** ✓ no regression. **DB-level ground-truth (sqlcmd via SSH):** `Permissions WHERE MenuKey IN ('Hrm','Hrm_HoSo')` = 13 rows EACH, all CanRead=1, AnyWrite=1 (=Admin only, full CRUD legit — upgrade-only KHÔNG hạ write existing) ✓. EmployeeProfiles=33 INTACT + ZZCICD-PROBE=0 (403 POST tạo 0 rows, no leak) ✓. ⚠️ **CRED NOTE: reviewer spec ghi non-admin pw `User@1234567` SAI** → 401 "Email/mật khẩu không đúng"; pw THẬT = memory-baseline `TestUser@123456` ✓. 0 regression. **LESSON: SEED-change verify (DbInitializer, no-mig) = (a) status=success ⟹ app restarted ⟹ seed ran; (b) prove EFFECT not schema — curl asymmetric probe (read 200 / write 403 / admin 200) + sqlcmd Permission-row count==role-count w/ CanRead=1 & write-row=Admin-only; (c) "seed NO-OP" failure-class (S58) caught iff check#2 still 403 post-restart — here 200 ⟹ revoke-then-grant ordering correct. BE-only ⟹ bundle FROZEN = pass-signal (rotate w/o FE = anomaly). Tokens empty: anon Gitea + prod-appsettings DB pw works. Spec creds may be illustrative — fall back to memory-baseline on 401.** Tag `[s65, run289, pass, hrm-hoso-public-readonly, seed-only-no-mig, bundle-frozen, asymmetric-read200-write403, permrows-13-canread, no-leak, spec-cred-wrong-fallback-baseline]`.
|
||||
- **2026-06-13 S62 Run #286 (run_number 286, id400) sha=`7926c21` PASS ~4m41s (PE "vượt ngân sách" → SOFT-WARNING: gỡ chặn số âm — CROSS-STACK 1 BE validator-rule-removal + 2 FE PeDetailTabs ×2 + 1 test flip, NO migration):** Push `79ef8da..7926c21` 4 files: BE `PurchaseEvaluationFeatures.cs` (gỡ 1 FluentValidation rule `ExpectedRemainingAmount >= 0` trong `AdjustPurchaseEvaluationBudgetCommandValidator`) + `PeDetailTabs.tsx` ×2 app (allowNegative row8 + banner "Vượt ngân sách") + `PeWorkItemBudgetTests.cs` (flip 1 test). `.cs`+`.tsx` → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prod `appsettings.Production.json`→`ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 11:15) — correctly did NOT FAIL/verify-bundle-mid-flight (anti-pattern #3), polled iter5 status=success (started 11:14:00 → success 11:18:41 ≈4m41s). CI gate (both test proj pre-deploy ⟹ status=success ⟹ test gate **263** baseline (45 Domain + 218 Infra) passed; `tasks` endpoint reports terminal as `status:success`, `conclusion` empty — trust success). **Bundle ROTATE BOTH (load-bearing FE×2, verified AFTER status=success +re-confirm STABLE no transient — anti-pattern#3): admin `DsGZlNzT→0xKYGhhf` + user `DTL_bjzQ→C81ZdG9G`** ✓ both touched (FE changed both apps). Title "Solutions ERP · Admin" preserved. Health live+ready **200/200** + admin/eoffice root 200. Smoke: PE unauth **401** (auth gate real) + control `/api/zzz-not-a-route` **404** (routing live, 401 not catch-all). **NO migration** — prod `__EFMigrationsHistory` top = `20260612173224_ReplaceBudgetModuleWithPeWorkItemBudgets` (= S61 "Mig 50", Budget→PeWorkItemBudgets replace) == repo HEAD, GIỮ NGUYÊN ✓ (commit 0 migration files; repo 50 mig .cs total). sys.tables(excl mighist)=**88** (S61 replace-mig DROPPED Budget tables 93→88; convention/count shift from S61 NOT this commit — FE+validator-only cannot alter schema). 0 regression. **LESSON: validator-rule-removal (negative-allow soft-warning) = internal handler-pipeline behavior — cannot curl-assert "now accepts negative ExpectedRemainingAmount" without authed multi-step adjust flow → rely on +flip PeWorkItemBudgetTests in CI gate 263 passing + bundle-rotate-both (FE banner shipped). Table count 88 (not 93) is S61 Budget-replace aftermath, not regression — always cross-ref what the COMMIT touched vs ambient schema state.** Tag `[s62, run286, pass, pe-budget-soft-warning, allow-negative, cross-stack, bundle-rotate-both, no-mig, test263, tables88-s61-aftermath]`.
|
||||
- **2026-06-12 S60 Run #283 (run_number 283) sha=`37122f0` PASS ~5m (PE guard 4-thông-tin mục 3 khi gửi duyệt + bypass người-soạn-trong-chuỗi-duyệt + rename heading "Đơn vị NCC/TP được chọn" — CROSS-STACK 1 BE service + 2 FE PeDetailTabs ×2 + 1 NEW test file):** Push `792c030..37122f0` 7 files: `PurchaseEvaluationWorkflowService.cs` (BE submit-guard + drafter-bypass) + `PeDetailTabs.tsx` ×2 app + `PeSubmitGuardAndBypassTests.cs` (NEW, +14 → 240→**254** expected) + 3 agent-memory `.md` (harvest-curator/investigator-codebase/test-specialist — `.claude/agent-memory/**` matches `**/*.md` glob → ignored, but `.cs`+`.tsx` present ⟹ whole-range builds, Discovery #3). GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prod `appsettings.Production.json`→`ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 11:55) — correctly did NOT FAIL, polled iter5 status=success (started ~11:54 → success 11:59:26 ≈5m). CI gate (both test proj pre-deploy ⟹ status=success ⟹ test gate 254 passed; `tasks` endpoint reports terminal as `status:success`, `conclusion` empty — trust success). **Bundle ROTATE BOTH (load-bearing, verified AFTER status=success — anti-pattern#3): admin `B1DtNT9C→akytoBnc` + user `D6uF3Mln→BzSdQmN0`** ✓ both touched (FE changed both apps). Brand `1F7DC1` preserved both HTML. Health live+ready **200/200** + admin/eoffice root 200. Smoke: PE unauth **401** + contracts unauth **401** + control `/api/zzz-not-a-route` **404** (auth gates real, routing live). **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓ (PE.MaPhieu col, not Code). sys.tables(excl mighist)=**92** (convention diff vs narrative-93, no new table — col/logic-only). **DATA INTACT (no-touch verify, sqlcmd): PE_count=3 · PE/2026/A/001 EXISTS (=1, phiếu UAT thật giữ nguyên ✓) · Suppliers=23 · WorkItems=71** — counts vs S59 (PE was 1 #275, Suppliers 22 #278) GREW from legit ongoing-UAT (this commit = FE+BE-service, NO DbInitializer/seed change → cannot resurrect/wipe; growth is user activity not deploy-induced). 0 regression. **LESSON (cross-stack submit-guard + drafter-bypass = ship-proof via run-success + test 254 + bundle-rotate-both + PE-data-preserved; the guard/bypass logic is internal handler behavior — cannot curl-assert "block submit when mục-3 incomplete" or "skip drafter in chain" without authed multi-step flow → rely on +14 PeSubmitGuardAndBypassTests in CI gate passing). SSH→sqlcmd via `iconv UTF-16LE|base64`→`powershell -EncodedCommand` (nested bash→ssh→PS strips `$vars`/mangles quotes); PE code column = `MaPhieu` NOT `Code`.** Tag `[s60, run283, pass, pe-submit-guard, drafter-bypass-in-chain, cross-stack, bundle-rotate-both, no-mig, test254, pe-a001-preserved]`. **↳đợt2 (14:14): Run #284 (run_number 284, id398) sha=`6db195d` PASS ~4m31s — GỠ hành động "Từ chối" khỏi quy trình PE (chỉ còn Duyệt/Trả lại; CROSS-STACK Domain `PurchaseEvaluationPolicy.cs` + Infra `PurchaseEvaluationWorkflowService.cs` guard + FE `PeWorkflowPanel.tsx` ×2 app + 2 NEW test `PurchaseEvaluationPolicyTests`/`PurchaseEvaluationWorkflowServiceGuardTests`, +2 → 254→256 expected: 59 Domain + 197 Infra). Push `37122f0..6db195d` 6 files (.cs+.tsx → full pipeline). Tokens empty → anon Gitea API + prod appsettings DB pw `ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 14:31) — correctly did NOT FAIL, polled iter5 status=success (14:30:51→14:35:22 ≈4m31s; CI both-proj-pre-deploy ⟹ success ⟹ 256-gate passed, `conclusion` empty trust success). Bundle ROTATE BOTH (verified AFTER status=success — anti#3): admin `akytoBnc→DSvM8h3A` + user `BzSdQmN0→Cs2Tt5n6` ✓ both touched. Health live+ready 200/200 + admin/eoffice root 200 + PE unauth 401 + control /api/zzz-not-a-route 404. NO migration — prod top=Mig 49 `AddWorkItemToPurchaseEvaluation`==repo GIỮ ✓. sys.tables(excl mighist)=92. DATA INTACT: PE_count=4 (grew from 3 @#283 — legit ongoing-UAT; BE-policy+FE-only NO seed change → cannot resurrect/wipe) · PE/2026/A/001 EXISTS (=1 phiếu UAT thật giữ ✓). 0 regression. LESSON: "Từ chối"-removal = internal policy/handler behavior, cannot curl-assert "reject action gone" without authed multi-step flow → rely on +2 PolicyTests/GuardTests in CI gate passing. Tag `[s60-dot2, run284, pass, pe-remove-reject-action, cross-stack, bundle-rotate-both, no-mig, test256, pe-a001-preserved]`.**
|
||||
- **2026-06-11 S59-CLOSE Run #280 (run_number 280) sha=`69997da` PASS ~4m24s (FINAL đóng sổ session — FE-only ×2 PeDetailTabs+PeHeaderForm bỏ ô "Tên ngân sách" manual budget UAT vòng4):** Push `f21c55d..69997da` 4 `.tsx` (PeDetailTabs+PeHeaderForm ×2 app). **Run #279 (id393) sha=`f21c55d` (NCC table-fixed UAT vòng3) = `cancelled` @18:22:33 — supersede-BENIGN:** #280 push @18:22:34 (1s gap → Gitea concurrency-cancel in-flight) + `git merge-base --is-ancestor f21c55d 69997da`=TRUE ✓ (f21c55d preserved trong HEAD, ships via #280 — verified diff f21c55d→69997da chỉ +4 PeDetail/Header file, không re-touch 12 file vòng3). Tokens empty → anon Gitea API + prod appsettings DB. Poll iter4 status=success (18:22:34→18:26:58). **Bundle ROTATE BOTH FINAL (verified AFTER success +re-confirm STABLE no transient — anti#3): admin `BSh2fG2X→BKy_8OO9` + user `D22KfpPc→XcZ6PRyA`** ✓ session-close hash, brand `1F7DC1`+"Solutions ERP" preserved ×2. Health live+ready **200/200** + admin/eoffice root 200 + PE unauth 401 + control 404. **NO migration** (FE-only, Mig 49 held). LESSON (mirror Run #385 supersede-chain): same-SHA `cancelled` mid-flight = concurrency-supersede bởi newer push (1s HEAD-move), KHÔNG build/deploy-fault → ancestor-check TRUE = benign, verify prod qua SUCCESSFUL run #280 (NOT cancelled #279), KHÔNG escalate. Tag `[s59-close, run280-pass, run279-cancelled-benign, supersede-chain, fe-budget-name-remove-x2, bundle-rotate-both-FINAL, no-mig]`. **↳FINAL-v2 (tối): `80b64dd` (Run #281 cancelled-BENIGN) gỡ "Điều khoản thanh toán" 3-form ×2 → superseded bởi `792c030` Run #282 PASS ~4m (UAT vòng6 bỏ nút "+Thêm hạng mục" PeDetailTabs ×2). Ancestor 80b64dd⊂792c030=TRUE ✓ (792c030 chỉ re-touch PeDetailTabs, KHÔNG đụng PeHeaderForm/PeWorkspaceCreateView → paymentTerms-removal survives). Verify qua #282-success. Bundle ROTATE BOTH ĐÓNG-SỔ-THẬT (AFTER success +re-confirm STABLE no transient): admin `BKy_8OO9→B1DtNT9C` + user `XcZ6PRyA→D6uF3Mln` ✓, brand `1F7DC1` ok. Health live+ready 200/200 + 2 FE root 200. NO mig (FE-only). Lần thứ 3 liên tiếp supersede-chain (#279/#281 cancelled-benign) — pattern stable.**
|
||||
- **2026-06-11 Run #278 (run_number 278) sha=`9c330d2` PASS ~3m45s (S59-đợt6 CROSS-STACK — BE SuppliersController POST hạ `[Authorize(Roles="Admin,CatalogManager")]` → class-level `[Authorize]` any-auth (anh chốt quick-add NCC đi-thầu phát sinh liên tục), PUT/DELETE GIỮ khóa Admin+CatalogManager; FE×2 PeDetailTabs AddSupplierDialog SearchableSelect+quick-create+upload-multi + PeWorkflowPanel ẩn Trả-lại/Từ-chối khi drafterUserId==currentUser):** Push `faed59f..9c330d2` 5 files: 4 FE `.tsx` (PeDetailTabs+PeWorkflowPanel ×2 app) + `SuppliersController.cs`. `.cs`+`.tsx` → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prod appsettings.Production.json→`ConnectionStrings.Default` (`vrapp/buKL3...`). Run IN-PROGRESS first poll (running) — polled iter6 status=success. **Bundle ROTATE BOTH (load-bearing FE×2, verified AFTER status=success +re-confirm stable ×2 NO transient — anti-pattern#3): admin `ex7Tc92G→BSh2fG2X` + user `DzUeSk96→D22KfpPc`** ✓ both touched. Brand `1F7DC1`+"Solutions ERP" preserved. Health live+ready **200/200** + admin/eoffice root 200. **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo ✓. **★ AUTHZ PROBE 4-điểm (the change-point — asymmetric POST-open/DELETE-locked verify) ALL PASS:** (a) unauth POST /api/suppliers (no token) = **401** ✓ (vẫn phải login, KHÔNG anonymous — class `[Authorize]` giữ); (b1) nv.test (Drafter non-admin) POST `{code:ZZCICD-TEST,type:1}` = **201** ✓ id `bc64c0c0-...` (quick-add mở OK); (b2) nv.test DELETE same-id CÙNG token = **403** ✓ (Sửa/Xóa vẫn khóa Admin+CatalogManager — method-level attr giữ); cleanup admin DELETE = **204** + GET = **404** ✓ (probe gỡ sạch). Spot sqlcmd ground-truth: **WorkItems active=71 HELD** ✓ (no resurrect) + **Suppliers active=22** ✓ (==pre-probe; DELETE là SOFT `IsDeleted=1` → active count về 22, total=23 với 1 tombstone ZZCICD `IsDeleted=1` — by-design audit, KHÔNG leak: list/GET ẩn nó). ⚠️ API `/api/suppliers` list trả 20 (paginated/filtered default page — KHÔNG authoritative, dùng sqlcmd cho count thật). Test gate (CI both proj pre-deploy ⟹ success=passed). 0 regression. **LESSON: cross-stack authz-relax verify = probe CẢ asymmetry — (i) unauth vẫn 401 (relax ≠ anonymous), (ii) target-role action mở (201), (iii) SIBLING action vẫn locked (403 same token), (iv) cleanup soft-delete → active-count về baseline + tombstone total+1 (soft-delete ≠ rác nếu list/GET ẩn). API list-count KHÔNG tin (pagination) → sqlcmd `WHERE IsDeleted=0` cho count thật.** Tag `[s59-dot6, run278, pass, supplier-post-authz-relax, asymmetric-probe-401-201-403, soft-delete-cleanup, bundle-rotate-both, no-mig, wi71-held]`.
|
||||
- **2026-06-11 Run #277 (run_number 277) sha=`faed59f` PASS ~4m09s (S59-đợt5 FE-only ×2 — NEW ui/SearchableSelect combobox gõ-lọc-bỏ-dấu + PeWorkspaceCreateView/PeHeaderForm Hạng mục+Dự án combobox + auto-fill Địa điểm từ Project.Location + PeDetailTabs paymentTerms Textarea; UAT 4-điểm screenshot 16:40):** Push `c869d26..faed59f` 8 files all `.tsx` (4 fe-admin + 4 fe-user, NEW SearchableSelect mirror ×2) → pipeline RAN. Tokens empty → anon API + prod appsettings pw. Run IN-PROGRESS first poll (running 17:40) — polled iter5 status=success (17:40:18→17:44:27). **Bundle ROTATE BOTH (verified AFTER success +re-confirm stable NO transient — anti-pattern#3): admin `BBA0KSWu→ex7Tc92G` + user `DzdTI18G→DzUeSk96`** ✓ both apps touched. Brand `1F7DC1` preserved both HTML. Health live+ready **200/200** + admin/eoffice root 200. **NO migration** (FE-only). Spot DB: **WorkItems active=71 HELD** (==#276 ✓ no resurrect — FE-only no restart risk) + PE=1 (info-only UAT leftover unchanged, NOT regression). Test gate (CI both proj pre-deploy ⟹ success=passed). 0 regression. LESSON: FE-only follow-up of a data-session needs only light WorkItems=71+PE re-confirm (no infra re-audit). SSH→sqlcmd pw-read: nested bash→ssh→PS strips `$vars` → use `iconv UTF-16LE|base64` → `powershell -EncodedCommand`. Tag `[s59-dot5, run277, pass, fe-searchableselect-x2, bundle-rotate-both, no-mig, wi71-held]`.
|
||||
- **2026-06-11 Run #276 (run_number 276) sha=`c869d26` PASS ~4m33s (S59-đợt4 FINAL — rename 71 WorkItems theo format PMH anh Kiệt FDC: BE DbInitializer seed-tuple mới MAT-n/SUB-n/MEP-SUB-n/MEP-EQU-n + FE×2 sort numeric, SQL rename ran TAY prod TRƯỚC push giữ Id):** Push `bbd1554..c869d26` 9 files: 6 FE (`PeHeaderForm`+`PeWorkspaceCreateView`+`PurchaseEvaluationsListPage` ×2 app) + `DbInitializer.cs` + `s59-rename-workitems-pmh.sql` + generated.md. `.cs`+`.tsx` → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon API + prod appsettings pw `ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 17:14) — polled iter5 status=success (17:14:14→17:18:47). **Bundle ROTATE BOTH (3 FE file both apps, verified AFTER success +re-confirm stable NO transient — anti-pattern#3): admin `DuU7OTym→BBA0KSWu` + user `DWyeTzf3→DzdTI18G`** ✓ both reachable 200, brand `1F7DC1`+title "Solutions ERP" preserved. Health live+ready **200/200** + admin/eoffice root 200 + PE unauth 401 + control 404. **NO migration** — prod top=Mig 49 `AddWorkItemToPurchaseEvaluation`==repo ✓. **★ RISK-POINT CLEARED (app restart ran SeedRealMasterDataAsync w/ NEW tuples — rename SQL ALREADY took → seed found all 71 new codes exist → added 0, NOT 142): WorkItems=ĐÚNG 71** (142=FAIL averted) + **old VT-/TP-/TB-=0** ✓ + **new MAT-/SUB-/MEP-=71** ✓ + spot `MEP-SUB-1`="1 MEP Sub MEP (Full)" EXACT ✓ + sample MAT-1/SUB-1/MEP-SUB-9/MEP-EQU-16 all present. PE=1 (info-only, UAT leftover A/001 — not resurrect). Test gate 240 (CI both proj pre-deploy ⟹ success=passed). 0 regression. **LESSON: rename-via-prod-SQL + seed-tuple-change verify = (a) target count EXACT (double = idempotent-seed re-added because SQL rename didn't take), (b) old-prefix=0 + new-prefix=full-count, (c) spot Code→Name exact match. Idempotent UNGATED seed re-runs on every restart → if hand-SQL rename succeeded BEFORE deploy, seed finds new codes present → adds 0 (safe); if rename failed → seed ADDS duplicates = 2× count = critical FAIL.** Tag `[s59-dot4, run276, pass, workitems-rename-pmh, bundle-rotate-both, no-mig, count-71-no-dup]`.
|
||||
- **2026-06-11 Run #275 (run_number 275) sha=`bbd1554` PASS ~3m44s (S59-đợt3 BE-only DbInitializer GỠ seed 15 WorkItems demo — chị Trà Sol chốt giữ đúng 71 mã PMH + `scripts/s59-wipe-demo-workitems.sql` ran TAY prod TRƯỚC push 86→71):** Push `0eafcd3..bbd1554` 2 files `DbInitializer.cs` + wipe-sql ONLY, NO FE/Mig. `.cs` → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon API + prod appsettings pw `ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 16:57) — polled iter6 status=success (16:57:41→17:01:25). **Bundle FROZEN admin `DuU7OTym` + user `DWyeTzf3`** (== #274 UNCHANGED ✓ CORRECT BE-only — verified AFTER status=success, no FE leak). **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo ✓. Health live+ready **200/200** + admin/eoffice root 200. **★ RESURRECT-VERIFY (risk point — app recycle post-deploy did NOT re-seed demo WorkItems, seed-block removal HELD): WorkItems=71 (ACTIVE=71 INACTIVE=0 DELETED=0 — hard-wipe not soft) + 4 categories EXACT: MEP 9 / Thầu phụ-Xây dựng 30 / Thiết bị 16 / Vật tư-Xây dựng 16** ✓ + **demo-codes DAO-MONG/SON-NUOC/VC-PHE-THAI = 0** ✓ (SeedRealMasterDataAsync idempotent re-ran, added 0 — 71 codes all exist). ⚠️ **PARTIAL item 5 — PE=1 không phải 0:** 1 row `PE/2026/A/001` Phase=10 created 09:46:42 **UTC = 16:46 chiều local** (CreatedAt lưu UTC — em main annotate S59-end kẻo đọc nhầm timeline; sau wipe Run #273 ~15:36 local, là phiếu UAT thật user tạo buổi test chiều, KHÔNG do deploy resurrect — BE-only bundle-frozen, DbInitializer KHÔNG seed transactional PE). INFO-flag, NOT deploy-fail. Test gate 240 (CI both proj pre-deploy ⟹ success=passed). 0 regression. **LESSON: seed-removal verify (mirror wipe-verify #273) = (a) target table count exact + category breakdown + demo-code spot-check 0 AFTER recycle (idempotent real-seed re-runs but adds 0), (b) ACTIVE/DELETED split proves hard-wipe vs soft-delete. PE=1 leftover-UAT ≠ regression: check CreatedAt timestamp vs wipe-time — pre-wipe-then-new-create is legit UAT activity, only assert PE=0 if no UAT happened between wipe and deploy.** Tag `[s59-dot3, run275, pass-partial, be-seed-removal, workitems-71-no-resurrect, bundle-frozen, no-mig, pe1-uat-leftover]`.
|
||||
- **2026-06-11 Run #273 (run_number 273) sha=`56882ac` PASS ~3m34s (S59 FE×2 PE-list tree regroup "Dự án(Năm)→Hạng mục→Phiếu" bỏ tầng NCC + prod data WIPE):** Push `1577927..56882ac` 3 files: `PurchaseEvaluationsListPage.tsx` ×2 app (SHA256 mirror identical, Panel-1 tree drop NCC tier) + `scripts/s59-wipe-testing-data.sql` (ran TAY prod TRƯỚC push, NOT in pipeline). `.tsx` present → pipeline RAN. ⚠️ GITEA_TOKEN+PROD_DB_PASSWORD empty → anon Gitea API (works, public) + read DB pw from prod `appsettings.Production.json`→`ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 15:36) — polled iter5 status=success (15:36:26→15:40:00). **Bundle ROTATE BOTH (load-bearing, verified AFTER success +6s stable NO transient — anti-pattern#3): admin `DMm9rtNA→R9uGRxvw` + user `BUkOMn_Y→DikfX1RD`** ✓ both apps touched. Brand `1F7DC1` preserved both HTML. Health live+ready **200/200** + admin/eoffice root 200. **NO migration** — prod top=Mig 49 `AddWorkItemToPurchaseEvaluation`==repo ✓. sys.tables(excl mighist)=**92**. **★ WIPE-VERIFY (the risk point — app restart post-deploy did NOT resurrect demo data, DemoSeed:Disabled gate HELD): PE=0 · Contracts=0 · Notifications=0 · PESeq=0** (all wiped clean, stayed clean post-recycle) + **infra preserved: ApprovalWorkflows=7 all IsActive=1 · Projects=70 · WorkItems=86 · Users=55** — ALL counts EXACT match expected. Test gate **240** (CI both proj pre-deploy ⟹ success=passed). 0 regression. **LESSON: post-wipe deploy verify = confirm both halves — (a) demo/transactional tables stay 0 after app-pool recycle (gate held, no re-seed) AND (b) infra/master tables (AW/Projects/WorkItems/Users) untouched (wipe was surgical, not nuke). Count-exact on both sides = PASS.** Tag `[s59, run273, pass, fe-list-regroup-x2, bundle-rotate-both, prod-wipe-verify, no-mig]`.
|
||||
- **2026-06-11 Run #274 (run_number 274) sha=`0eafcd3` PASS ~4m51s (S59-đợt2 FE×2 PE-list tree 4-tầng "Năm>Dự án>Hạng mục>Phiếu" — follow-up Run #273 đổi từ 2-tầng-gộp-label sang 4-tầng explicit):** Push `56882ac..0eafcd3` 2 files `PurchaseEvaluationsListPage.tsx` ×2 app ONLY (SHA256 mirror identical `95d524ee`). `.tsx` → pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon API + prod appsettings pw. Run IN-PROGRESS first poll (running 16:37) — polled iter6 status=success (16:37:06→16:41:57). **Bundle ROTATE BOTH (verified AFTER success +re-confirm stable NO transient — anti-pattern#3): admin `R9uGRxvw→DuU7OTym` + user `DikfX1RD→DWyeTzf3`** ✓ both touched. Health live+ready **200/200** + admin/eoffice root 200. **NO migration** (FE-only). Spot-check **PE=0** held post-deploy (FE-only no restart-resurrection risk; wipe gate still HELD from #273). Test gate 240 (CI both proj pre-deploy ⟹ success=passed). 0 regression. LESSON: FE-only follow-up of a wipe-session needs only light PE=0 re-confirm (no full infra re-audit) — restart risk already cleared #273. Tag `[s59-dot2, run274, pass, fe-list-4tier-x2, bundle-rotate-both, no-mig, pe-zero-held]`.
|
||||
- **2026-06-11 Run #385→#386 SUPERSEDE-CHAIN sha=`ea793a4` CANCELLED(benign)→shipped-via `3ebaf84` #386 PASS ~4m25s (S58 brand-accent polish x2 app then PE-workitem-merge):** Target push `6e53e33..ea793a4` 8 files FE polish CẢ 2 app (Layout/TopBar/PageHeader/DataTable each — stripe đỉnh + logo-zone tint + PageHeader accent bar + thead brand-50/60), NO BE/Mig. **Run #385 (run_number 271) status=`cancelled` @14:14:22 — NOT a fail: superseded by newer push `3ebaf84` (#386 run_number 272) landed @14:14:31 (Gitea concurrency-guard cancels in-flight same-branch run).** HEAD moved ea793a4→`3ebaf84`. **Verified ea793a4 IS ancestor of 3ebaf84 + the 8 polish files NOT re-touched by 3ebaf84 → polish PRESERVED in tree, ships via #386.** #386 adds 4 PE files (PeHeaderForm/PeWorkspaceCreateView ×2 app, anh Kiệt FDC 14:06 — gộp Tên gói thầu=chọn Hạng mục) → both apps rebuilt anyway. Polled #386 to status=`success` (started 14:14:31→14:18:56). **Bundle ROTATE BOTH (load-bearing, verified AFTER #386 success — anti-pattern #3): admin `CP4CB1ym→DMm9rtNA` (css `vMtY6u47→DDlKud5i`) + user `CKjwqnGL→BUkOMn_Y` (css `CV0H5hnq→BgAUPcnL`)** ✓ both touched → both rotate. **Brand preserved both apps: `1F7DC1` in HTML + `Be Vietnam Pro`+`1f7dc1` in CSS bundle; BONUS polish landed: `brand-50`/`brand-60` Tailwind classes present in BOTH CSS bundles** (thead/tint/accent shipped). Health live+ready **200/200** + admin/eoffice root 200. **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓ (neither ea793a4 nor 3ebaf84 has Mig). Smoke PE+contracts unauth=**401** + control `/api/zzz-not-a-route`=**404** (auth gates real). Test gate (CI both proj pre-deploy ⟹ #386 success=passed). Prior today #382/#383/#384 all PASS. **LESSON (cancelled ≠ fail — supersede-chain verify): a same-SHA run flipping to `cancelled` mid-flight is almost always Gitea concurrency-supersede by a newer push, NOT a build/deploy fault → MUST (1) check tasks list for newer run + HEAD movement, (2) `git merge-base --is-ancestor` confirm target commit preserved in new HEAD, (3) `git diff target..newHEAD -- <target-files>` empty ⟹ target changes survive, (4) verify prod via the SUCCESSFUL superseding run not the cancelled one. Do NOT report FAIL/escalate on a benign supersede-cancel.** Tag `[s58, run385-cancelled-benign, run386-pass, supersede-chain, brand-polish-x2, bundle-rotate-both, no-mig]`.
|
||||
- **2026-06-11 Run #384 (run_number 270) sha=`e959f72` PASS ~4m30s (S58 FE-USER visual redesign density-first per AI_INFRA UI/UX guide — keep brand #1F7DC1/Be Vietnam Pro/slate; FE-USER-ONLY, ZERO BE/Mig/fe-admin):** Push `6c5fd26..e959f72` 1 commit 16 files: 14 fe-user (`index.css` tokens + 6 ui primitives Button/Dialog/Input/Label/Select/Textarea + 6 shell DataTable/EmptyState/Layout/PageHeader/PhaseBadge/TopBar + LoginPage) + 2 broadcasts `.md`. NO fe-admin, NO `.cs`, NO Mig. `.tsx`/`.css` present → NOT docs-skip, pipeline RAN. ⚠️ GITEA_TOKEN empty both shells → unauth public API (200, no token needed). Run IN-PROGRESS at first poll (status=running 13:51) — correctly did NOT FAIL, polled iter6 status=success (started 13:51:18 → 13:55:48). **ASYMMETRIC bundle (load-bearing) PASS: user ROTATE `BmZ3VHnm→CKjwqnGL`** (redesign shipped, verified AFTER status=success, stable on +recheck no transient) **+ admin FROZEN `CP4CB1ym`** (=#382 UNCHANGED ✓ scope-correct, NO fe-admin leak — mirror Run #378 asymmetric fe-admin-only logic, inverted). user `.js` HEAD 200 app/js 1.47MB + CSS rotate `index-CV0H5hnq.css` 200 63KB. **Brand preserved: `1F7DC1` in HTML + `Be Vietnam Pro`+`1f7dc1` in CSS bundle** ✓; title "Solutions ERP". Health live+ready **200/200** + admin/eoffice root 200. **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓. sys.tables(excl mighist)=**92** (FE-only no new table). Smoke PE unauth=**401** + control `/api/zzz`=**404** (auth gates real). Test gate **240** (CI both proj pre-deploy ⟹ success=passed). 0 regression. Prior today #382(`5998163` lock-fix)+#383(`6c5fd26` hide-modules) both PASS as noted. **LESSON (single-app FE-USER redesign — asymmetric verify, inverse of #378):** PASS criteria asymmetric — user hash MUST rotate (ship-proof) AND admin hash MUST stay frozen (scope-proof, no accidental fe-admin redeploy). admin-unchanged is POSITIVE here. Visual-only CSS-token+className redesign rotates bundle exactly like logic change (Vite content-hash byte-sensitive). SSH→sqlcmd `<>`/`NOT LIKE '__%'` quoting traps: `<` mangled by PS redirect (use `!=`/CONCAT-CHAR), `_` is LIKE-wildcard (escape `'[_][_]%'`). Tag `[s58, run384, pass, fe-user-only-redesign, asymmetric-bundle-verify, no-mig, brand-preserved]`.
|
||||
- **2026-06-16 S? Run #291 (run_number 291, id405) sha=`8c8179c` ❌ FAIL ~64s (TEST-GATE COMPILE BREAK — Department.ParentId phân cấp cây tổ chức, BE Mig + FE-admin picker; DEPLOY DID NOT RUN, prod UNCHANGED @baseline):** Push `c98030f..8c8179c` 2 commits: `0f44d97` BE (Mig `20260616032402_AddDepartmentParentId` = AddColumn `ParentId Guid? nullable` + CreateIndex `IX_Departments_ParentId`, NO new table; `GET /api/departments/tree`; Create/Update nhận parentId — `CreateDepartmentCommand` record signature CHANGED to `(string,string,Guid?,string?,Guid?)` +5th positional ParentId, `UpdateDepartmentCommand` +6th) + `8c8179c` FE-admin DepartmentsPage picker "Phòng cha". Tokens empty → anon Gitea + prod-appsettings DB pw. Task #291 status=**failure** created 10:41:14 → updated 10:42:18 = **~64s** (far < ~3min normal → early-stage fail, NOT deploy stage). Anon API can't reach `/tasks/{id}` + `/logs` (404 — need auth) + WebFetch Actions UI JS-rendered (empty) → **reproduced FAIL locally** (anti-pattern #2 no-speculate): `dotnet build SolutionErp.slnx -c Release` → **error CS7036** `tests/SolutionErp.Infrastructure.Tests/Application/MasterCatalogFilteredUniqueTests.cs(63,25)`: "no argument given that corresponds to the required parameter 'ParentId' of CreateDepartmentCommand". **Root cause: spec-change miss** — commit added `ParentId` as REQUIRED positional param but the gotcha#57 filtered-unique test line 63 still calls old 4-arg `new CreateDepartmentCommand("DUP1","Phòng ban mới", null, null)` (needs 5). grep `new CreateDepartmentCommand\(` repo-wide = ONLY this 1 broken call site; UpdateDepartmentCommand has 0 test call site (compiles). Test gate runs BEFORE build/deploy → compile-fail in test proj ⟹ whole `dotnet build slnx` (incl tests) fails ⟹ **deploy never ran**. **Prod CONFIRMED untouched @ baseline c98030f (Run #290):** admin bundle `DRob3iVl` (FROZEN=baseline ✓ NOT rotated — picker NOT shipped) · user `DxK3fCfh` (FROZEN=baseline ✓ correct, fe-user untouched) · health api live+ready **200/200** + admin/eoffice root 200 · prod `__EFMigrationsHistory` top = `20260612173224_ReplaceBudgetModuleWithPeWorkItemBudgets` (Mig 50) — **`AddDepartmentParentId` NOT applied** ✓ (deploy didn't run, DbInitializer never fired). All 4 post-deploy KEY checks correctly N/A (no ship). **ESCALATE em-main: fix = update `MasterCatalogFilteredUniqueTests.cs:63` to pass 5th arg (e.g. `..., null, null, null)`) — CLAUDE.md §7 "spec change = update test cũ + code chung commit" violated; re-push → re-verify deploy.** READ-only, did NOT fix. **LESSON: short-duration (~60s) `failure` on a BE/FE commit = test-gate or BE-build compile break, NOT deploy/transient — when anon API blocks logs, `dotnet build SolutionErp.slnx` locally reproduces exact CS error + line; a record-constructor positional-param ADD silently breaks every un-updated call site (grep `new <Command>\(` to enumerate). FAIL ⟹ deploy gated ⟹ verify prod = STILL baseline (bundles frozen + mig NOT applied) rather than skipping post-deploy entirely.** Tag `[s?, run291, FAIL, test-gate-compile-break, CS7036-CreateDepartmentCommand-5th-param, dept-parentid-tree, deploy-did-not-run, prod-unchanged-baseline, bundle-frozen-both, mig-not-applied, escalate-fix-test-line63]`.
|
||||
- **2026-06-11 Run #382 (run_number 268) sha=`5998163` PASS ~3m31s (S58 FIX the Run #381 lock NO-OP — DbInitializer.cs ONLY, BE-only, NO Mig/FE):** Push `dd117b7..5998163` 1 commit 1 file `DbInitializer.cs` (+28/-5). Fix: (1) `LockDemoSampleUsersAsync` union +20 UAT-matrix prod email (`{act,equ,fin,hra,pm,qs}.{nv,pp,tp}@`+`bod.{1,2}@`) into prior 14 named-person = 34-email list; (2) `DemoUserPassword` 11→12 chars (`User@123456`→`User@1234567`) fixing silent CreateAsync-fail vs prod `RequiredLength=12` (S56 helpdesk-inert root cause). `.cs` present → full pipeline RAN. Poll iter5 status=success (started 12:58:06 → 13:01:37). **Bundle FROZEN admin `CP4CB1ym` + user `BmZ3VHnm`** (= #381 UNCHANGED ✓ CORRECT for BE-only, verified AFTER status=success — NOT ship-fail). **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓. sys.tables=**93** unchanged. Health live/ready 200 + admin/eoffice root 200. **THE FIX VERIFIED prod (Users table — note: custom Identity table name `Users` NOT `AspNetUsers`):** total **55** users · **21 active** · **34 inactive==34 locked-future** (== lock-list size exactly). 12-sample UAT-matrix all `active=0 locked=1` (#381 NO-OP now RESOLVED — these exist in prod + got locked ✓). Named-person 14/14 found+locked (CREATED this startup via 12-char pw fix + locked same run). **Must-stay-active 6/6** admin·catalog.manager·nv.test·chuong.phan@solution.com.vn(typo-domain)·**nv.cao+nv.truong** ALL `active=1` (IT helpdesk pool ALIVE — S56 ops-pending RESOLVED by pw fix, created this startup not in lock-list). **5 new real staff** (thanh.lethanh/anh.nguyen/tring.le/truong.le/long.nguyen) all CREATED+`active=1` ✓ (12-char pw passes RequiredLength=12). Smoke nv.test login OK (token 477) + GET /api/menus 200 + /purchase-evaluations 200. 0 regression. **LESSON: lock-by-email NO-OP (#381) was a DATA-mismatch not code-bug → S58 reconciled email-list to actual prod population (UAT-matrix created via admin UI, never in seed) + the 11-vs-12 pw bug was a SECOND latent cause silently blocking ALL non-existing-user CREATE on prod (RequiredLength=12) — same fix resurrected 16 named + 5 staff + helpdesk pool. Verify lock-fix = dump Users cohorts (active/inactive split + named exact-IN), NOT just total count.** Tag `[s58, run382, pass, fix-lock-noop, pw-11to12, be-only-bundle-frozen]`.
|
||||
- **2026-06-11 Run #381 (run_number 267) sha=`dd117b7` PASS+1PARTIAL ~4m25s (S57bis PE gắn WorkItem Mig 49 + all-role Pe perm + menu Cá nhân regroup + lock-14-demo-user — cross-stack BE+FE×2+Mig+test, +12 PeWorkItemGuardTests→240):** 2-commit push: prev `17b23a4` (governance+hmw.js → Run #380 **cancelled**, superseded — correct, no FE/BE contract change) then `dd117b7` (PRODUCT, Run 381 = the deciding run). 26 files: Mig 49 `20260611044424_AddWorkItemToPurchaseEvaluation` (3-file, PE.WorkItemId Guid? loose-Guid NO physical FK + `IX_PurchaseEvaluations_WorkItemId`) + Domain `PurchaseEvaluation.cs` + Config + Features + DbInitializer (perm + `LockDemoSampleUsersAsync` + menu regroup) + MenuKeys + 3 master controllers (write-lock Admin/CatMgr) + FE×2 (PeDetailTabs/PeHeaderForm/PeWorkspaceCreateView/menuKeys/types). **Run IN-PROGRESS at first check (status=running 12:14) — polled to terminal** (12:14:16→12:18:41 ≈4m25s success). ⚠️ poll-grep gotcha: `"status"` field sits AFTER `"display_title"` in tasks JSON → `[^}]*"display_title"` regex cut before status (showed blank all 10 iters); final FULL-object parse `\{"id":381,...deploy.yml[^}]*\}` confirmed status=success. **Bundle ROTATE BOTH** admin `4SUwDLD8→CP4CB1ym` + user `XdKzt9LL→BmZ3VHnm` (PE in both apps ✓ shipped, verified AFTER status=success). **Mig 49 applied prod** (`__EFMigrationsHistory` top = AddWorkItem... ✓ + WorkItemId col=1 + IX=1). sys.tables=**93** (col-only, no delta). Health live/ready 200 + admin/eoffice 200. **Perm seed STRONG: Pe_* CanCreate=1 = 130 rows across 13 roles** (was 3-role → all-role open landed); PeWf%=0 + AwV2%=2 (designer stays admin-only ✓ no leak). Menu regroup ✓: Personal root@30 · Off_ChamCong→Personal@1 · **Hrm_Config**→Master@25 (spec said key `HrmConfig`, real key has underscore `Hrm_Config` — verify by ParentKey/Order NOT literal Key) · Contracts@31 · Hrm_Dashboard→Hrm@1. Smoke PE unauth 401 (/purchase-evaluations + /catalogs/work-items) vs control 404 (auth real). WorkItems VT/TP/MEP/TB=71. **⚠️ PARTIAL item 7 — lock-14-users is a prod NO-OP:** `LockDemoSampleUsersAsync` SHIPPED+RAN but its 14 hardcoded emails (`bod.huynh@`,`pm.nguyen@`,`fin.do@`,`qs.hoang@`...) **DON'T EXIST in prod** — real demo set uses dept.position scheme `bod.1@`/`bod.2@`/`pm.{nv,pp,tp}@`/`fin.{nv,pp,tp}@`/`qs.{nv,pp,tp}@` (34 users ALL active, INACTIVE_TOTAL=0). Each FindByEmail→null→locked=0. Guard `nv.cao`/`nv.truong` also absent (-1, vacuously safe); catalog.manager+admin confirmed active. NOT a deploy fail (code correct) — email list stale vs this DB seed. Escalated em main: reconcile lock-list to actual `*.{nv,pp,tp}@` scheme OR confirm named-person legacy users were ever seeded. **LESSON: lock/deactivate-by-email assertion returning 0/`-1` ⟹ ALWAYS dump actual `Users` set before scoring FAIL — code may have run as no-op against mismatched data, NOT broken.** Tag `[s57bis, run381, pass-partial, mig49-pe-workitem, allrole-perm-130, lock-noop-email-mismatch]`.
|
||||
- **2026-06-09 Run #379 (run_number 265) sha=`a20cde8` PASS ~4m20s (S56 GOLIVE-HARDEN BE fixes — LeaveBalance concurrency + ItTicket authz-order + DocxRenderer null-guard + tests, ZERO FE/Mig):** Push `bef5825..a20cde8` 1 commit 13 files: 3 BE `LeaveOtApprovalFeatures.cs` (atomic ExecuteUpdate + Serializable tx vs lost-update) + `WorkflowAppsFeatures.cs` (authz reorder Forbidden-before-NotFound) + `DocxRenderer.cs` (null-guard) + 4 test files (+12 → 216→**228**) + 6 agent-memory `.md`. `.cs`+test present → NOT docs-skip, full pipeline RAN. **Run IN-PROGRESS at first check (status=running 17:51) — correctly did NOT FAIL, polled to terminal** (started 17:51:45 → updated 17:56:05 ≈4m20s status=success iter5). **Bundle FROZEN admin `4SUwDLD8` + user `XdKzt9LL`** (= #378, UNCHANGED ✓ CORRECT for BE-only — NOT ship-fail, mirror Run #243/#368; verified pre-deploy + post-success + +5s re-confirm, NO transient, NO unexpected rotation). **NO migration** — prod `__EFMigrationsHistory` top = `20260609020759_AddProjectMasterFields` (Mig 48) == repo latest, GIỮ NGUYÊN ✓ (BE-logic-only, schema untouched). sys.tables=**93** unchanged. Health live+ready **200/200** + admin/eoffice root 200. **Smoke changed-area endpoints (all gated, none crash):** `GET /it-tickets/assignable-staff` unauth=**401** · `PUT /it-tickets/{guid}/assign` unauth+body=**401** (authz-reorder fix live, route wired) · `GET /leave-balances/my` unauth=**401** (concurrency fix dll deployed) · control fake `/it-tickets/zzz-not-a-route`=**404** (proves 401s are real auth gates not catch-all). 0 regression. **Ship-proof for BE-only no-contract-change = run success + test 228 + Mig 48 unchanged + bundle frozen + health 200** (no observable API delta — fixes are internal handler logic: atomic tx / exception order / null-guard; cannot curl-assert lost-update fix, rely on +12 tests passing in CI gate). Tag `[s56, run379, pass, golive-harden, be-only-bundle-frozen, no-mig]`.
|
||||
- **2026-06-09 (S56 pre-golive verify — NO deploy, read-only audit):** Re-verified prod truth at golive gate (HEAD `bef5825` docs-only → prod correctly = Run #378). build SolutionErp.slnx 0-err + fe-admin/fe-user npm build 0-TS each + test **216** (58D+158I) exact. Prod health live+ready 200; admin root serves `4SUwDLD8` / eoffice `XdKzt9LL` (== baseline, NO drift). `__EFMigrationsHistory` top = Mig 48 == repo; 92 tables. Master-data prod spot: Projects=70 (62 real+8 demo), CAL01.Investor=N'Công ty TNHH Calofic' exact, WorkItems real=71 (VT16/TP30/MEP9/TB16) of 86, Suppliers 3/3. **LESSON — local-vs-prod FE hash divergence is EXPECTED, not ship-fail:** fresh local `npm build` produces a DIFFERENT content-hash than CI-built prod artifact (node_modules/timestamp inputs not byte-reproducible) → load-bearing check is `prod-hash == documented-baseline`, NOT `== my-local-rebuild`. Don't false-alarm on local≠prod when HEAD unchanged. Tag [s56, pre-golive-verify, prod-truth-pass, local-vs-prod-hash-lesson].
|
||||
|
||||
- **2026-06-09 Run #378 (run_number 264) sha=`7feb53e` PASS ~4m24s (S55 Phase-1 FE-Admin VISUAL redesign density-first design-system NAMGROUP-ref keep brand #1F7DC1 — FE-ADMIN-ONLY, ZERO BE/Mig/fe-user):** Push `84fa638..7feb53e` 1 commit 15 files: 13 fe-admin (`index.css` design tokens + 6 ui primitives Button/Dialog/Input/Label/Select/Textarea + 6 shell DataTable/EmptyState/Layout/PageHeader/PhaseBadge/TopBar + DashboardPage) + 2 agent-memory `.md` (frontend-designer/reviewer). NO fe-user, NO `.cs`, NO Mig. `.tsx`/`.css` present → NOT docs-skip, pipeline RAN. **Run IN-PROGRESS at first check (status=running 11:51) — correctly did NOT FAIL, polled to terminal** (started 11:51:06 → updated 11:55:30 ≈4m24s status=success; updated_at froze 11:55:30 across 3 poll iters = terminal signal before status field parsed). **THE KEY PROOF — admin bundle ROTATE `B-d6893W→4SUwDLD8`** (✓ redesign shipped, verified AFTER status=success; pre-success snapshot 11:51 still showed OLD `B-d6893W` = anti-pattern #3 timing confirmed AGAIN; re-confirm +3s post-success = stable `4SUwDLD8`, NO transient this run). **fe-user bundle UNCHANGED `XdKzt9LL`** (= #377; untouched ✓ NOT ship-fail — correct, no fe-user file in commit). Admin root **200 text/html** + serves `<title>Solutions ERP · Admin</title>` + `<div id="root">` (app loads ✓). **NO migration** — prod `__EFMigrationsHistory` top = `20260609020759_AddProjectMasterFields` (Mig 48) == repo latest, GIỮ NGUYÊN ✓ (FE-only, BE/Domain untouched). Health live+ready **200/200** (both pre- and post-deploy). Test gate **216** (CI both proj pre-deploy ⟹ success=passed; `tasks` endpoint reports terminal as `status:success`, `conclusion` NOT populated — trust CI conclusion). 0 regression. **LESSON (single-app FE redesign — asymmetric bundle verify):** when ONLY fe-admin changes, the PASS criteria is asymmetric — admin hash MUST rotate (proof shipped) AND user hash MUST stay frozen (proof scope-correct, no accidental fe-user redeploy). User-unchanged is a POSITIVE signal here (mirror of BE-only Run #243/#368 where admin+user both stay frozen). Visual-only redesign (CSS tokens + className) rotates bundle exactly like logic change — Vite content-hash byte-sensitive. Status-grep gotcha: greedy `.*?` regex failed to isolate `"status"` field mid-poll → use `grep -oE '\\{"id":378,[^}]*\\}'` to capture full object then sub-grep status. Tag `[s55, run378, pass, fe-admin-only-redesign, asymmetric-bundle-verify, no-mig]`.
|
||||
- **2026-06-09 Run #377 (run_number 263) sha=`69cb393` PASS ~4m33s (S55 HMW-P4 real master-data seed from Excel + Project +4 cols Mig 48 — cross-stack BE+FE×2+Mig+seed):** Push `f8640d6..69cb393` 1 commit 18 files: Mig 48 `20260609020759_AddProjectMasterFields` (3-file) + Domain `Project.cs` (+Year/Investor/Location/Package nullable) + `ProjectConfiguration.cs` + App `ProjectFeatures.cs` + **`DbInitializer.cs` NEW `SeedRealMasterDataAsync` (UNGATED, per-code idempotent)** + FE×2 `master/ProjectsPage.tsx` + `types/master.ts` + 1 test `MasterCatalogFilteredUniqueTests.cs` + 4 agent-memory .md. `.cs`+`.tsx`+Mig present → full pipeline RAN. **Run was IN-PROGRESS at first check (status=running 09:28) — correctly did NOT FAIL, polled to terminal** (started 09:27:19 → updated 09:31:52 ≈4m33s status=success). ⚠️ `jq` NOT in Bash-tool bash (env is bash not PS despite shell=PowerShell env-line) — parse JSON via `grep -oE '\"id\":377[^}]*'` fallback; the working first call only used `head -c` not jq. **Bundle ROTATE admin `DmjI8Cmn→B-d6893W` + user `YxL_MljK→XdKzt9LL`** (BOTH changed ✓ FE shipped both apps, verified AFTER status=success; pre-success snapshot 09:28 still showed OLD DmjI8Cmn/YxL_MljK = anti-pattern #3 timing confirmed again; re-confirm +3s post-success = stable, no transient). **Mig 48 applied prod** (`__EFMigrationsHistory` top = `...AddProjectMasterFields` ✓ + `COL_LENGTH('Projects','Investor')` EXISTS). **THE KEY CHECK — real master-data landed (4/4 spot PASS):** Projects spot6 (APVN01/ZOTE01/CAL01/MIDEA01/SAM01/TLB01)=**6** · WorkItems VT-/TP-/MEP-/TB-=**71** · Suppliers (TRUONGGIANG/TANPHU/TGN)=**3** · `CAL01.Investor` =EXACT match N'Công ty TNHH Calofic' (console showed `C<>ng` = sqlcmd codepage mangle of `ô`, NOT data corruption — confirmed via `WHERE Investor=N'...'` EXACT). Totals: Projects=**70** (62 real + 8 demo coexist ✓ ungated seed idempotent), WorkItems=**86**, 5 Projects carry Investor / 23 carry Year (Excel sparse-fill, only some rows enriched — expected). Health live+ready **200/200**. `GET /api/projects` unauth=**401** (route wired, auth gates ✓). 0 regression. **LESSON (ungated prod seed verify = count spot-checks NOT schema):** `SeedRealMasterDataAsync` runs unconditionally on every prod startup (NOT inside `if(!demoSeedDisabled)` — correct per gotcha #51 INFRASTRUCTURE-seed rule); verify = sqlcmd COUNT spot-checks of real Codes + N-literal EXACT match for unicode fields (console codepage will mangle Vietnamese diacritics → always re-assert via `=N'...'`, never trust raw sqlcmd console render). Tag `[s55, run377, pass, mig48-master-fields, real-seed-ungated, sqlcmd-codepage-lesson]`.
|
||||
- **2026-06-08 Run #376 (run_number 262) sha=`ca4b602` PASS ~4m18s (S54 IT-staff self-reassign ticket — authz Admin-OR-IT + scoped capability endpoint, cross-stack, NO migration):** Push `18d397f..ca4b602` 1 commit 13 files: BE `WorkflowAppsFeatures.cs` (NEW `GetAssignableItStaffQuery` capability + `AssignItTicketHandler` authz Admin-OR-IT) + `ItTicketsController.cs` (NEW `GET /it-tickets/assignable-staff` + `/assign` LOWERED Authorize-Roles) + FE×2 `ItTicketsPage.tsx` (SHA256-identical) + `workflowApps.ts`×2 (+2 type) + `ItTicketReassignAuthzTests.cs` (+13 → 203→**216**) + 6 agent-memory `.md`. `.cs`+`.tsx` present → NOT docs-skip, full pipeline RAN. Poll iter5 status=success (started 16:12:23 → updated 16:16:41 ≈4m18s). **Bundle ROTATE admin `DfCfHUE9→DmjI8Cmn` + user `_3S0BPJ2→YxL_MljK`** (BOTH changed ✓ FE shipped, verified AFTER status=success; pre-deploy iter0 still showed OLD DfCfHUE9/_3S0BPJ2 — correct timing anti-pattern #3). **NO migration** — prod `__EFMigrationsHistory` top = `...FilterMasterCatalogUniqueIndexesByIsDeleted` (Mig 47) == repo latest, GIỮ NGUYÊN ✓ (DepartmentId reuse). sys.tables=**93** stable (no new table). Test gate **216** (CI both proj pre-deploy ⟹ success=passed; grep undercounts InlineData — trust CI). Health live+ready 200 + admin/eoffice root 200. **Smoke NEW endpoint:** `GET /api/it-tickets/assignable-staff` unauth=**401** (route wired, [Authorize] gates) · `PUT /api/it-tickets/{guid}/assign` unauth bare=**411** then **WITH body `-d '{}'`=401** (IIS demands Content-Length before auth eval; 411 is pre-auth Length-check NOT routing-miss) · control fake route `/it-tickets/zzz`=**404** (proves 401s are real auth gates not catch-all). 0 regression. **LESSON (411 vs 401 on bodyless PUT/POST):** unauth bodyless PUT/POST to a JSON-body endpoint returns **411 Length Required** from IIS BEFORE the [Authorize] filter runs — NOT a 404/route-miss. Re-send with `-d '{}'` to force auth eval → real 401. Consistent w/ Run #367 `PUT /adjust=411` + #364 `POST /approve=411` (same pattern, now explained). Tag `[s54, run376, pass, it-reassign-authz, no-mig, 411-precheck-lesson]`.
|
||||
- **2026-06-08 Run #371 (run_number 257) sha=`30a99aa` PASS ~4m18s (S50 HMW-Wave2 P11-C Vehicle+Driver catalogs Mig 44 + gotcha #57 filtered-unique 3 HRM catalog Mig 45 — BE+FE×2+2Mig+tests):** Push `f8179c5..30a99aa` 1 commit 28 files: BE Domain `Vehicle.cs`/`Driver.cs` + App `HrmConfigFeatures.cs`+IApplicationDbContext + `HrmConfigsController` + 5 Config (Driver/Vehicle/LeaveType/OtPolicy/ShiftPattern) + DbContext + DbInitializer + MenuKeys + Mig44/45 (6 files) + FE×2 (HrmConfigsPage/Layout/menuKeys/hrm-config.ts) + `HrmConfigFilteredUniqueTests.cs` (+5 test → 181→**186**). All BE/FE/Mig, none in paths-ignore → CI ran. Poll iter3 status=success (started 10:32:58 → 10:37:16). **Bundle ROTATE admin `DPPTx2Kw→Cg9mvltU` + user `CjoUEsoV→YgqDvsqr`** (BOTH changed ✓ FE shipped, verified AFTER status=success). **NEW LESSON (timing trap):** pre-success snapshot showed transient `CVbyotwa`/`BBlyMlJH` (intermediate FE copy mid-deploy, NOT final) → re-verify post-success gave real `Cg9mvltU`/`YgqDvsqr`. Confirms anti-pattern #3 + Run #242 lesson: NEVER trust bundle hash until status=success; mid-deploy can show a 3rd transient hash. **Mig 44+45 auto-applied prod** (`__EFMigrationsHistory` top2 = FilterHrmCatalog... + AddVehicleAndDriver...). **Vehicles+Drivers tables EXIST**; sys.tables=**92** (was 90 +2, narrative-93 = convention diff, NOT missing). **gotcha #57 LIVE — all 5 idx filtered:** IX_{Vehicles,Drivers,LeaveTypes,ShiftPatterns,OtPolicies}_Code ALL `is_unique=1 filter=([IsDeleted]=(0))` (3 HRM ones LeaveType/Shift/OtPolicy were NULL pre-Mig45 → now filtered = proof applied). Health live+ready 200 + admin/eoffice index 200. New endpoint `GET /api/hrm-configs/{vehicles,drivers}` unauth=**401** (route wired, no crash) + admin auth=**200** seed 2/catalog (vehicles XE-01/XE-02, drivers TX-01/TX-02 ✓ DbInitializer infra seed ran). 0 regression. Tag `[s50, run371, pass, p11c-vehicle-driver, mig44-45, gotcha57-filtered-5idx]`.
|
||||
- **2026-06-03 Run #369 (run_number 255) sha=`350b2bf` PASS ~4m13s (S48 FE-only login subtitle a11y `text-slate-500→600`, ZERO BE/Mig):** Push range `7bbfa5a..350b2bf` 2 commits: `009dd94` DOCS/GOVERNANCE-only (9 files: STATUS/HANDOFF + 3 adap-reports + error-ledger + session-log + frontend-designer MEMORY + session-end.md cmd — ALL `.md`/`.claude/**`) + `350b2bf` CODE 2 files `fe-{admin,user}/src/pages/LoginPage.tsx` (1-line each, slate-500→600 subtitle contrast). Mixed push: `.tsx` present → **NOT path-filter skipped, full pipeline RAN** (gotcha #41 Discovery #3 — ≥1 non-ignored file in range ⟹ whole range builds; docs commit alone would skip but `.tsx` overrides). Poll iter5 status=success (started 00:06:33 → 00:10:46). **Bundle ROTATE admin `Krjvg_3j→DPPTx2Kw` + user `6sNStgxa→CjoUEsoV`** (BOTH changed ✓ FE shipped — verified AFTER status=success; pre-deploy snapshot iter0 still showed OLD `Krjvg_3j`/`6sNStgxa`, correct timing per anti-pattern #3). **NO migration** — repo 43 == prod `__EFMigrationsHistory` 43, latest both `...FilterHolidayUniqueIndexByIsDeleted` (Mig 43 unchanged, BE/Domain untouched ✓). Health live+ready 200 + admin/eoffice index 200. Test gate 181 (CI both proj pre-deploy ⟹ success=passed). 0 regression. NEW LESSON: smallest possible FE change (1-line className) still rotates bundle hash — Vite content-hash sensitive to any source byte; mixed docs+tsx push is the canonical case where docs-only-skip does NOT apply. Tag `[s48, run369, pass, fe-only-a11y, mixed-push-not-skipped]`.
|
||||
- **2026-06-01 Run #368 (run_number 254) sha=`0c5a014` PASS ~4m20s (S45 Mig 43 filter Holiday UNIQUE by IsDeleted + 3 HRM test gaps — BE+tests ONLY, ZERO FE):** Push range `dbbed15..0c5a014` 2 commits: `051b62b` Tests +27 (HrmConfigHolidayTests + EmployeeSatelliteTests + AuthorizePolicyRegressionTests-ext → baseline 154→**181**) + `0c5a014` Mig 43 `20260601064128_FilterHolidayUniqueIndexByIsDeleted` (drops+recreates `IX_Holidays_Year_Date` as filtered UNIQUE `WHERE [IsDeleted]=0`, was unfiltered) + HolidayConfiguration.cs edit + Case-7 test flip. 7 files, all BE+tests, none in paths-ignore → CI ran. Poll iter4 status=success (started 13:43:47 → 13:48:07). **Bundle hashes UNCHANGED admin `Krjvg_3j` + user `6sNStgxa`** (= #367) — CORRECT for BE-only push, NOT ship-fail (Run #243 precedent; ship-proof = Mig 43 applied, not bundle rotate). **Mig 43 auto-applied prod** (history top = `...FilterHolidayUniqueIndexByIsDeleted` ✓). **THE FIX VERIFIED prod:** `IX_Holidays_Year_Date | unique=1 | filter=([IsDeleted]=(0))` — filter_definition non-NULL = filtered UNIQUE live (soft-deleted holidays no longer collide on UNIQUE). Health live+ready 200 Healthy. `Holidays` table exists, 10 rows, 2 named idx (PK + filtered UNIQUE). Prod tables=90-by-sys.tables (index-only change, NO new table — consistent #364 delta). NEW LESSON: filtered-index migration verify = check `sys.indexes.filter_definition` non-NULL (NOT just mig-history row); index-only mig = bundle unchanged + table-count unchanged both EXPECTED. Tag `[s45, run368, pass, mig43-filtered-index, be-only-bundle-unchanged]`.
|
||||
- **2026-05-30 Run #367 (run_number 253) sha=`82d7fcf` PASS ~4m08s (S42 P11-B LeaveBalance business logic, Mig 42):** Code commit 22 files (4 BE: Domain `LeaveBalance.cs` + App `LeaveBalanceFeatures.cs`/`LeaveOtApprovalFeatures` deduction hook + `LeaveBalancesController` + IApplicationDbContext + DbContext + Config + Mig42 3-file + 2 FE `WorkflowAppDetailPage`×2 +`workflowApps.ts`×2 + 2 tests + 4 agent-memory .md). Started 11:11:40 → success iter4 11:15:48. **Bundle rotate admin `BU8FTBRi→Krjvg_3j` + user `tepE4jvR→6sNStgxa`** (both changed ✓ FE shipped, verified AFTER status=success — pre-deploy snapshot still showed old hash, correct timing). **Mig 42 `20260530034336_AddLeaveBalances` auto-applied prod** (tables 90→**91**, `LeaveBalances` EXISTS). Schema ✓: UserId/LeaveTypeId/Year/EntitledDays/UsedDays/AdjustmentDays decimal + AuditableEntity soft-delete. **UNIQUE `IX_LeaveBalances_UserId_LeaveTypeId_Year`** + **FK→LeaveTypes del=NO_ACTION** (=Restrict) ✓. New endpoint smoke: `GET /api/leave-balances/my` unauth=**401** (route live not 404) + admin auth=**200** lazy-default 5 LeaveTypes (ANNUAL12/COMPASSIONATE3/MATERNITY180/SICK30/UNPAID0, all Used=0, `remainingDays`=entitled ✓ DTO shape has remainingDays/entitledDays) + `?year=2026` admin route 401 unauth + `PUT /adjust`=411 (route reg). health live/ready 200 Healthy. **NO seed gate concern** (plain table, lazy DTO — Stage 4.6 N/A). 0 regression. Note: prev run #366 (ffb2062 docs STATUS update) was a CODE-path push w/ status=success — NOT docs-only-skipped (commit touched only .md but Gitea still ran since prior range?); actually #366 display_title is Docs but ran full → confirms agent-memory .md NOT in paths-ignore (`.claude/skills/**` ignored, `.claude/agent-memory/**` NOT). Tag `[s42, run367, pass, p11b-leavebalance, mig42]`.
|
||||
- **2026-05-30 Run #365 sha=`75df04e` PASS ~4m05s (S42 P11-A fix workflow picker 2-bug + SetWorkflow endpoint, NO mig):** 11 files BE+FE×2+test. Bundle rotate admin `BLA09-qv→6D4k-aRi` + user `CXvejOE-→DkME-974`. +4 `PUT /api/{leave,ot,travel,vehicle-bookings}/{id}/workflow` unauth=401. Test 144. NAMING RECONCILE: use real Gitea task id (#364=e7b66cd mem-labeled "#250"). Tag `[s42, run365, pass, p11a-setworkflow]`.
|
||||
- **2026-05-30 Run #364 (mem #250) sha=`e7b66cd` PASS ~4m07s (S42 P11-A wire ApproveV2+LevelOpinions 4 WorkflowApps):** 1 commit BE+FE×2+Mig41+Tests. Status=success iter3. Bundle rotate admin `cWAXid0q→BLA09-qv` + user `CX79e2kZ→CXvejOE-`. **Mig 41 auto-applied prod** (latest=`20260530021936_WireWorkflowAppsApprovalV2`). Tables 84→**90** (+5: Leave/Ot/Travel/VehicleRequest LevelOpinions + WorkflowAppCodeSequences — ALL EXIST). 4 new endpoint smoke 200 auth (leave/ot/travel/vehicle-requests) + unauth 401 (route exists) + POST .../approve=411 (route reg). health live/ready 200. **Stage 4.6 seed gate PASS** (gotcha #51): 4 WF seeded prod despite DemoSeed:Disabled — QT-NP/OT/CT/XE-V2-001 AppType=5/6/7/9, verified call-site L142-145 OUTSIDE `if(!demoSeedDisabled)` gate. Test gate 141 (CI runs both proj pre-deploy). Note: table count 90 vs spec-expected 89 = baseline-count diff, NOT missing table (all 5 present). Stale doc drift deploy.yml comments "54/17 test" (cosmetic, flag em main). Tag `[s42, run250, pass, p11a-approvev2-workflowapps]`.
|
||||
- **2026-05-28 Run #247 sha=`e54a22d` PASS 3m25s (S38 SKELETON 5-plan combo Mig 39+40 dual):** Push 1 commit mega `Domain+App+Infra+Api+FE×2`. ALL PASS. Bundle rotate admin `CGueDk22→cWAXid0q` + user `CEt0QRgX→CX79e2kZ`. Mig 39+40 dual auto-applied startup (90830→90839). 6 endpoint smoke 200 (leave/ot/travel/vehicle/it-tickets/hr-dashboard `totalEmployees=33 male=17 female=16`). 6 new tables + 8 menu seeded. 0 regression. Fastest S38 deploy. Tag `[s38, run247, pass, skeleton-combo]`.
|
||||
- **Archived Run #246 (S37 Proposal Mig 37+38 — `/api/proposals` 200 + QT-DX-V2-001 AppType=4 seed + Stage 4.6 INFRASTRUCTURE-gated correct gotcha #51) + #359/#243/#242/#241/#240 + S35/S36 startup → `archive/2026-05-q4.md` + git d2f52ba (S40 curate):** Run #359 G-O2 Meeting Mig 36 · #243 HrmConfig BE 16 endpoint (BE-only bundle unchanged anti-pattern verify) · #242 FE inline forms 5 satellite · #241 Mig 35 HRM foundation · #240 satellite CRUD. Discovery #7 path-filter eval/** + #8 collection `proj_*`. KEY absorbed in essentials/Stage sections above.
|
||||
- **[⚠️ VỊ TRÍ LẠC — entry MỚI 2026-06-11, thuộc FIFO slot giữa #384/#382 phía trên nhưng ghi lạc vào khu archive-zone này; curate-L2 ĐỪNG archive nhầm (H2 S58 P2 flagged); relocate khi curate] 2026-06-11 Run #383 (run_number 269) sha=`6c5fd26` PASS ~4m25s (S58b TẠM ẨN HRM/Văn phòng số/Cá nhân khỏi non-Admin + Danh mục xuống cuối — BE-only seed, NO Mig/FE):** Push `2aefb31..6c5fd26` 1 file `DbInitializer.cs` (+61/-5): NEW `RevokeTemporarilyHiddenModulesAsync` (set 4 CRUD=false MỌI role TRỪ Admin trên `Hrm%`+`Off%`+`Personal`, idempotent, KHÔNG xóa row) + `SeedAllRolesReviewReadPermissionsAsync` scope THU HẸP còn Master/Catalogs/Pe_* + menu `Master` Order 20→80. `.cs` present → full pipeline RAN. Run IN-PROGRESS at first check (status=running 13:36) — correctly did NOT FAIL, polled to terminal (started 13:36:15 → success 13:40:40 iter5). **Bundle FROZEN admin `CP4CB1ym` + user `BmZ3VHnm`** (= Run #382 UNCHANGED ✓ CORRECT BE-only — verified AFTER status=success, NOT ship-fail). **NO Mig** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓. Health live/ready 200 + admin/eoffice root 200. **6 prod sqlcmd ALL PASS exact (DB SolutionErp, custom tables `MenuItems`/`Permissions`/`Roles`):** MasterOrder=**80** ✓ · HiddenReadNonAdmin=**0** ✓ (revoke landed, `Hrm%`+`Off%`+`Personal` all CRUD=false non-Admin) · HiddenReadAdmin=**29** (>0, Dev est 28, Admin GIỮ ✓) · PeCreateNonAdmin=**120** (Pe_* untouched ✓) · MasterReadNonAdmin=**48** (Master still visible ✓). **Menu-tree smoke (gotcha #44 dual-role):** nv.test `/api/menus/me` 200 → keys = Master/Suppliers/Projects/Departments + Catalogs/Catalog* + all Pe_DuyetNcc*/Pe_DuyetNccPhuongAn* — **ZERO Hrm/Hrm_*/Off/Off_*/Personal** ✓; admin counter-check VẪN CÒN Hrm/Hrm_Config*/Off/Off_*/Personal + Contracts/Budgets/System ✓ (revoke scoped non-Admin only). 0 regression. **LESSON (seed-only permission-revoke verify = sqlcmd matrix + dual-role menu-tree, NOT bundle/endpoint):** RevokeTemporarilyHiddenModulesAsync runs UNCONDITIONALLY on startup (NOT gated — correct, it's a permission-correction not demo-seed); verify = COUNT(CanRead non-Admin)=0 for revoked-prefix + COUNT Admin>0 (kept) + COUNT untouched-scope (Pe/Master) unchanged + `/api/menus/me` key-set diff between regular-user (modules gone) and admin (modules present). FE has NO PermissionGuard per-route (commit note) → direct-URL still renders trang, mức "tạm ẩn" = menu hide + permission matrix only; acceptable pre-golive. Tag `[s58b, run383, pass, revoke-hidden-modules, master-order-80, be-only-bundle-frozen, no-mig, dual-role-menutree]`.
|
||||
- **Archived Run #232 (S29 gotcha #51 catch — SeedSampleContractWorkflowV2 nested in demoSeedDisabled → empty V2 dropdown, hoist fix) → `archive/2026-05-q4.md` + git. Smart Friend ROI 4× cumulative (S22 #44 + S25 #48 + S29 ApplicableType + S29 DemoSeed).**
|
||||
- **Older runs (S62 #286 06-13 <- ... -> S29 #232) full verbatim archived S66 -> `archive/2026-06.md`** (incl #291 06-16 FAIL forensic [lesson=gotcha #65 + #292-inline] + #383 ex-VITRILAC); pre-S38 -> `archive/2026-05-{runs,q2,q3,q4}.md` + git `d2f52ba`.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Curate trigger
|
||||
- >~30KB → archive recent runs → L2 `archive/<period>.md`. Dup failure patterns → merge. Stale >3mo → remove.
|
||||
- **Last curate: 2026-05-29 S40 em main proxy** (35.3→~21KB): archived Run #359/#243/#242/#241/#240 + S35/S36 startup → q4 + git d2f52ba; refreshed stale 120→130 test + Mig 34→40 + Stage 3 111→130. Foundation (gotcha patterns + Stage 0-5 + Stage 4.6 + 10-point + Discovery #4-8) preserved. Prev: S34 q3 · S32 q2 · S22 runs.
|
||||
- **Last curate: 2026-06-16 S66 em main** (86.8→29.2KB — 2.9× over-cap fix): byte-exact `sed` move Run #286→#232 (S62→S29, incl #291 forensic [lesson=gotcha #65 + #292-inline] + #383 ex-VỊ-TRÍ-LẠC) → `archive/2026-06.md`; refreshed essentials Mig 50→52 + bundle-live S69→S70 #295. Kept baseline (gotcha patterns + Stage 0-5 + Stage 4.6 + 10-point + Discovery #4-8) + 6 current 06-16 runs #289-#295.
|
||||
- **Prev curate: 2026-05-29 S40 em main proxy** (35.3→~21KB): archived Run #359/#243/#242/#241/#240 + S35/S36 startup → q4 + git d2f52ba; refreshed stale 120→130 test + Mig 34→40. Prev: S34 q3 · S32 q2 · S22 runs.
|
||||
|
||||
37
.claude/agent-memory/cicd-monitor/archive/2026-06.md
Normal file
37
.claude/agent-memory/cicd-monitor/archive/2026-06.md
Normal file
@ -0,0 +1,37 @@
|
||||
# CI/CD Monitor — Archive 2026-06 (L2 COLD, read-on-demand)
|
||||
|
||||
> Curated S66 (2026-06-16) from L1 MEMORY.md to keep L1 < ~35KB. Older run-records (S62 #286 06-13 -> S29 #232) moved here VERBATIM. L1 retains the 6 current-session 06-16 deploys (#289-#295).
|
||||
> Note: #291 (06-16 FAIL, CS7036) full forensic detail lives here; its lesson = canonical gotcha #65 + summarized inline in the L1 #292 entry, so not orphaned. #383 entry (was tagged VI-TRI-LAC in L1 FIFO) now correctly archived.
|
||||
|
||||
---
|
||||
|
||||
- **2026-06-13 S62 Run #286 (run_number 286, id400) sha=`7926c21` PASS ~4m41s (PE "vượt ngân sách" → SOFT-WARNING: gỡ chặn số âm — CROSS-STACK 1 BE validator-rule-removal + 2 FE PeDetailTabs ×2 + 1 test flip, NO migration):** Push `79ef8da..7926c21` 4 files: BE `PurchaseEvaluationFeatures.cs` (gỡ 1 FluentValidation rule `ExpectedRemainingAmount >= 0` trong `AdjustPurchaseEvaluationBudgetCommandValidator`) + `PeDetailTabs.tsx` ×2 app (allowNegative row8 + banner "Vượt ngân sách") + `PeWorkItemBudgetTests.cs` (flip 1 test). `.cs`+`.tsx` → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prod `appsettings.Production.json`→`ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 11:15) — correctly did NOT FAIL/verify-bundle-mid-flight (anti-pattern #3), polled iter5 status=success (started 11:14:00 → success 11:18:41 ≈4m41s). CI gate (both test proj pre-deploy ⟹ status=success ⟹ test gate **263** baseline (45 Domain + 218 Infra) passed; `tasks` endpoint reports terminal as `status:success`, `conclusion` empty — trust success). **Bundle ROTATE BOTH (load-bearing FE×2, verified AFTER status=success +re-confirm STABLE no transient — anti-pattern#3): admin `DsGZlNzT→0xKYGhhf` + user `DTL_bjzQ→C81ZdG9G`** ✓ both touched (FE changed both apps). Title "Solutions ERP · Admin" preserved. Health live+ready **200/200** + admin/eoffice root 200. Smoke: PE unauth **401** (auth gate real) + control `/api/zzz-not-a-route` **404** (routing live, 401 not catch-all). **NO migration** — prod `__EFMigrationsHistory` top = `20260612173224_ReplaceBudgetModuleWithPeWorkItemBudgets` (= S61 "Mig 50", Budget→PeWorkItemBudgets replace) == repo HEAD, GIỮ NGUYÊN ✓ (commit 0 migration files; repo 50 mig .cs total). sys.tables(excl mighist)=**88** (S61 replace-mig DROPPED Budget tables 93→88; convention/count shift from S61 NOT this commit — FE+validator-only cannot alter schema). 0 regression. **LESSON: validator-rule-removal (negative-allow soft-warning) = internal handler-pipeline behavior — cannot curl-assert "now accepts negative ExpectedRemainingAmount" without authed multi-step adjust flow → rely on +flip PeWorkItemBudgetTests in CI gate 263 passing + bundle-rotate-both (FE banner shipped). Table count 88 (not 93) is S61 Budget-replace aftermath, not regression — always cross-ref what the COMMIT touched vs ambient schema state.** Tag `[s62, run286, pass, pe-budget-soft-warning, allow-negative, cross-stack, bundle-rotate-both, no-mig, test263, tables88-s61-aftermath]`.
|
||||
- **2026-06-12 S60 Run #283 (run_number 283) sha=`37122f0` PASS ~5m (PE guard 4-thông-tin mục 3 khi gửi duyệt + bypass người-soạn-trong-chuỗi-duyệt + rename heading "Đơn vị NCC/TP được chọn" — CROSS-STACK 1 BE service + 2 FE PeDetailTabs ×2 + 1 NEW test file):** Push `792c030..37122f0` 7 files: `PurchaseEvaluationWorkflowService.cs` (BE submit-guard + drafter-bypass) + `PeDetailTabs.tsx` ×2 app + `PeSubmitGuardAndBypassTests.cs` (NEW, +14 → 240→**254** expected) + 3 agent-memory `.md` (harvest-curator/investigator-codebase/test-specialist — `.claude/agent-memory/**` matches `**/*.md` glob → ignored, but `.cs`+`.tsx` present ⟹ whole-range builds, Discovery #3). GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prod `appsettings.Production.json`→`ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 11:55) — correctly did NOT FAIL, polled iter5 status=success (started ~11:54 → success 11:59:26 ≈5m). CI gate (both test proj pre-deploy ⟹ status=success ⟹ test gate 254 passed; `tasks` endpoint reports terminal as `status:success`, `conclusion` empty — trust success). **Bundle ROTATE BOTH (load-bearing, verified AFTER status=success — anti-pattern#3): admin `B1DtNT9C→akytoBnc` + user `D6uF3Mln→BzSdQmN0`** ✓ both touched (FE changed both apps). Brand `1F7DC1` preserved both HTML. Health live+ready **200/200** + admin/eoffice root 200. Smoke: PE unauth **401** + contracts unauth **401** + control `/api/zzz-not-a-route` **404** (auth gates real, routing live). **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓ (PE.MaPhieu col, not Code). sys.tables(excl mighist)=**92** (convention diff vs narrative-93, no new table — col/logic-only). **DATA INTACT (no-touch verify, sqlcmd): PE_count=3 · PE/2026/A/001 EXISTS (=1, phiếu UAT thật giữ nguyên ✓) · Suppliers=23 · WorkItems=71** — counts vs S59 (PE was 1 #275, Suppliers 22 #278) GREW from legit ongoing-UAT (this commit = FE+BE-service, NO DbInitializer/seed change → cannot resurrect/wipe; growth is user activity not deploy-induced). 0 regression. **LESSON (cross-stack submit-guard + drafter-bypass = ship-proof via run-success + test 254 + bundle-rotate-both + PE-data-preserved; the guard/bypass logic is internal handler behavior — cannot curl-assert "block submit when mục-3 incomplete" or "skip drafter in chain" without authed multi-step flow → rely on +14 PeSubmitGuardAndBypassTests in CI gate passing). SSH→sqlcmd via `iconv UTF-16LE|base64`→`powershell -EncodedCommand` (nested bash→ssh→PS strips `$vars`/mangles quotes); PE code column = `MaPhieu` NOT `Code`.** Tag `[s60, run283, pass, pe-submit-guard, drafter-bypass-in-chain, cross-stack, bundle-rotate-both, no-mig, test254, pe-a001-preserved]`. **↳đợt2 (14:14): Run #284 (run_number 284, id398) sha=`6db195d` PASS ~4m31s — GỠ hành động "Từ chối" khỏi quy trình PE (chỉ còn Duyệt/Trả lại; CROSS-STACK Domain `PurchaseEvaluationPolicy.cs` + Infra `PurchaseEvaluationWorkflowService.cs` guard + FE `PeWorkflowPanel.tsx` ×2 app + 2 NEW test `PurchaseEvaluationPolicyTests`/`PurchaseEvaluationWorkflowServiceGuardTests`, +2 → 254→256 expected: 59 Domain + 197 Infra). Push `37122f0..6db195d` 6 files (.cs+.tsx → full pipeline). Tokens empty → anon Gitea API + prod appsettings DB pw `ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 14:31) — correctly did NOT FAIL, polled iter5 status=success (14:30:51→14:35:22 ≈4m31s; CI both-proj-pre-deploy ⟹ success ⟹ 256-gate passed, `conclusion` empty trust success). Bundle ROTATE BOTH (verified AFTER status=success — anti#3): admin `akytoBnc→DSvM8h3A` + user `BzSdQmN0→Cs2Tt5n6` ✓ both touched. Health live+ready 200/200 + admin/eoffice root 200 + PE unauth 401 + control /api/zzz-not-a-route 404. NO migration — prod top=Mig 49 `AddWorkItemToPurchaseEvaluation`==repo GIỮ ✓. sys.tables(excl mighist)=92. DATA INTACT: PE_count=4 (grew from 3 @#283 — legit ongoing-UAT; BE-policy+FE-only NO seed change → cannot resurrect/wipe) · PE/2026/A/001 EXISTS (=1 phiếu UAT thật giữ ✓). 0 regression. LESSON: "Từ chối"-removal = internal policy/handler behavior, cannot curl-assert "reject action gone" without authed multi-step flow → rely on +2 PolicyTests/GuardTests in CI gate passing. Tag `[s60-dot2, run284, pass, pe-remove-reject-action, cross-stack, bundle-rotate-both, no-mig, test256, pe-a001-preserved]`.**
|
||||
- **2026-06-11 S59-CLOSE Run #280 (run_number 280) sha=`69997da` PASS ~4m24s (FINAL đóng sổ session — FE-only ×2 PeDetailTabs+PeHeaderForm bỏ ô "Tên ngân sách" manual budget UAT vòng4):** Push `f21c55d..69997da` 4 `.tsx` (PeDetailTabs+PeHeaderForm ×2 app). **Run #279 (id393) sha=`f21c55d` (NCC table-fixed UAT vòng3) = `cancelled` @18:22:33 — supersede-BENIGN:** #280 push @18:22:34 (1s gap → Gitea concurrency-cancel in-flight) + `git merge-base --is-ancestor f21c55d 69997da`=TRUE ✓ (f21c55d preserved trong HEAD, ships via #280 — verified diff f21c55d→69997da chỉ +4 PeDetail/Header file, không re-touch 12 file vòng3). Tokens empty → anon Gitea API + prod appsettings DB. Poll iter4 status=success (18:22:34→18:26:58). **Bundle ROTATE BOTH FINAL (verified AFTER success +re-confirm STABLE no transient — anti#3): admin `BSh2fG2X→BKy_8OO9` + user `D22KfpPc→XcZ6PRyA`** ✓ session-close hash, brand `1F7DC1`+"Solutions ERP" preserved ×2. Health live+ready **200/200** + admin/eoffice root 200 + PE unauth 401 + control 404. **NO migration** (FE-only, Mig 49 held). LESSON (mirror Run #385 supersede-chain): same-SHA `cancelled` mid-flight = concurrency-supersede bởi newer push (1s HEAD-move), KHÔNG build/deploy-fault → ancestor-check TRUE = benign, verify prod qua SUCCESSFUL run #280 (NOT cancelled #279), KHÔNG escalate. Tag `[s59-close, run280-pass, run279-cancelled-benign, supersede-chain, fe-budget-name-remove-x2, bundle-rotate-both-FINAL, no-mig]`. **↳FINAL-v2 (tối): `80b64dd` (Run #281 cancelled-BENIGN) gỡ "Điều khoản thanh toán" 3-form ×2 → superseded bởi `792c030` Run #282 PASS ~4m (UAT vòng6 bỏ nút "+Thêm hạng mục" PeDetailTabs ×2). Ancestor 80b64dd⊂792c030=TRUE ✓ (792c030 chỉ re-touch PeDetailTabs, KHÔNG đụng PeHeaderForm/PeWorkspaceCreateView → paymentTerms-removal survives). Verify qua #282-success. Bundle ROTATE BOTH ĐÓNG-SỔ-THẬT (AFTER success +re-confirm STABLE no transient): admin `BKy_8OO9→B1DtNT9C` + user `XcZ6PRyA→D6uF3Mln` ✓, brand `1F7DC1` ok. Health live+ready 200/200 + 2 FE root 200. NO mig (FE-only). Lần thứ 3 liên tiếp supersede-chain (#279/#281 cancelled-benign) — pattern stable.**
|
||||
- **2026-06-11 Run #278 (run_number 278) sha=`9c330d2` PASS ~3m45s (S59-đợt6 CROSS-STACK — BE SuppliersController POST hạ `[Authorize(Roles="Admin,CatalogManager")]` → class-level `[Authorize]` any-auth (anh chốt quick-add NCC đi-thầu phát sinh liên tục), PUT/DELETE GIỮ khóa Admin+CatalogManager; FE×2 PeDetailTabs AddSupplierDialog SearchableSelect+quick-create+upload-multi + PeWorkflowPanel ẩn Trả-lại/Từ-chối khi drafterUserId==currentUser):** Push `faed59f..9c330d2` 5 files: 4 FE `.tsx` (PeDetailTabs+PeWorkflowPanel ×2 app) + `SuppliersController.cs`. `.cs`+`.tsx` → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prod appsettings.Production.json→`ConnectionStrings.Default` (`vrapp/buKL3...`). Run IN-PROGRESS first poll (running) — polled iter6 status=success. **Bundle ROTATE BOTH (load-bearing FE×2, verified AFTER status=success +re-confirm stable ×2 NO transient — anti-pattern#3): admin `ex7Tc92G→BSh2fG2X` + user `DzUeSk96→D22KfpPc`** ✓ both touched. Brand `1F7DC1`+"Solutions ERP" preserved. Health live+ready **200/200** + admin/eoffice root 200. **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo ✓. **★ AUTHZ PROBE 4-điểm (the change-point — asymmetric POST-open/DELETE-locked verify) ALL PASS:** (a) unauth POST /api/suppliers (no token) = **401** ✓ (vẫn phải login, KHÔNG anonymous — class `[Authorize]` giữ); (b1) nv.test (Drafter non-admin) POST `{code:ZZCICD-TEST,type:1}` = **201** ✓ id `bc64c0c0-...` (quick-add mở OK); (b2) nv.test DELETE same-id CÙNG token = **403** ✓ (Sửa/Xóa vẫn khóa Admin+CatalogManager — method-level attr giữ); cleanup admin DELETE = **204** + GET = **404** ✓ (probe gỡ sạch). Spot sqlcmd ground-truth: **WorkItems active=71 HELD** ✓ (no resurrect) + **Suppliers active=22** ✓ (==pre-probe; DELETE là SOFT `IsDeleted=1` → active count về 22, total=23 với 1 tombstone ZZCICD `IsDeleted=1` — by-design audit, KHÔNG leak: list/GET ẩn nó). ⚠️ API `/api/suppliers` list trả 20 (paginated/filtered default page — KHÔNG authoritative, dùng sqlcmd cho count thật). Test gate (CI both proj pre-deploy ⟹ success=passed). 0 regression. **LESSON: cross-stack authz-relax verify = probe CẢ asymmetry — (i) unauth vẫn 401 (relax ≠ anonymous), (ii) target-role action mở (201), (iii) SIBLING action vẫn locked (403 same token), (iv) cleanup soft-delete → active-count về baseline + tombstone total+1 (soft-delete ≠ rác nếu list/GET ẩn). API list-count KHÔNG tin (pagination) → sqlcmd `WHERE IsDeleted=0` cho count thật.** Tag `[s59-dot6, run278, pass, supplier-post-authz-relax, asymmetric-probe-401-201-403, soft-delete-cleanup, bundle-rotate-both, no-mig, wi71-held]`.
|
||||
- **2026-06-11 Run #277 (run_number 277) sha=`faed59f` PASS ~4m09s (S59-đợt5 FE-only ×2 — NEW ui/SearchableSelect combobox gõ-lọc-bỏ-dấu + PeWorkspaceCreateView/PeHeaderForm Hạng mục+Dự án combobox + auto-fill Địa điểm từ Project.Location + PeDetailTabs paymentTerms Textarea; UAT 4-điểm screenshot 16:40):** Push `c869d26..faed59f` 8 files all `.tsx` (4 fe-admin + 4 fe-user, NEW SearchableSelect mirror ×2) → pipeline RAN. Tokens empty → anon API + prod appsettings pw. Run IN-PROGRESS first poll (running 17:40) — polled iter5 status=success (17:40:18→17:44:27). **Bundle ROTATE BOTH (verified AFTER success +re-confirm stable NO transient — anti-pattern#3): admin `BBA0KSWu→ex7Tc92G` + user `DzdTI18G→DzUeSk96`** ✓ both apps touched. Brand `1F7DC1` preserved both HTML. Health live+ready **200/200** + admin/eoffice root 200. **NO migration** (FE-only). Spot DB: **WorkItems active=71 HELD** (==#276 ✓ no resurrect — FE-only no restart risk) + PE=1 (info-only UAT leftover unchanged, NOT regression). Test gate (CI both proj pre-deploy ⟹ success=passed). 0 regression. LESSON: FE-only follow-up of a data-session needs only light WorkItems=71+PE re-confirm (no infra re-audit). SSH→sqlcmd pw-read: nested bash→ssh→PS strips `$vars` → use `iconv UTF-16LE|base64` → `powershell -EncodedCommand`. Tag `[s59-dot5, run277, pass, fe-searchableselect-x2, bundle-rotate-both, no-mig, wi71-held]`.
|
||||
- **2026-06-11 Run #276 (run_number 276) sha=`c869d26` PASS ~4m33s (S59-đợt4 FINAL — rename 71 WorkItems theo format PMH anh Kiệt FDC: BE DbInitializer seed-tuple mới MAT-n/SUB-n/MEP-SUB-n/MEP-EQU-n + FE×2 sort numeric, SQL rename ran TAY prod TRƯỚC push giữ Id):** Push `bbd1554..c869d26` 9 files: 6 FE (`PeHeaderForm`+`PeWorkspaceCreateView`+`PurchaseEvaluationsListPage` ×2 app) + `DbInitializer.cs` + `s59-rename-workitems-pmh.sql` + generated.md. `.cs`+`.tsx` → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon API + prod appsettings pw `ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 17:14) — polled iter5 status=success (17:14:14→17:18:47). **Bundle ROTATE BOTH (3 FE file both apps, verified AFTER success +re-confirm stable NO transient — anti-pattern#3): admin `DuU7OTym→BBA0KSWu` + user `DWyeTzf3→DzdTI18G`** ✓ both reachable 200, brand `1F7DC1`+title "Solutions ERP" preserved. Health live+ready **200/200** + admin/eoffice root 200 + PE unauth 401 + control 404. **NO migration** — prod top=Mig 49 `AddWorkItemToPurchaseEvaluation`==repo ✓. **★ RISK-POINT CLEARED (app restart ran SeedRealMasterDataAsync w/ NEW tuples — rename SQL ALREADY took → seed found all 71 new codes exist → added 0, NOT 142): WorkItems=ĐÚNG 71** (142=FAIL averted) + **old VT-/TP-/TB-=0** ✓ + **new MAT-/SUB-/MEP-=71** ✓ + spot `MEP-SUB-1`="1 MEP Sub MEP (Full)" EXACT ✓ + sample MAT-1/SUB-1/MEP-SUB-9/MEP-EQU-16 all present. PE=1 (info-only, UAT leftover A/001 — not resurrect). Test gate 240 (CI both proj pre-deploy ⟹ success=passed). 0 regression. **LESSON: rename-via-prod-SQL + seed-tuple-change verify = (a) target count EXACT (double = idempotent-seed re-added because SQL rename didn't take), (b) old-prefix=0 + new-prefix=full-count, (c) spot Code→Name exact match. Idempotent UNGATED seed re-runs on every restart → if hand-SQL rename succeeded BEFORE deploy, seed finds new codes present → adds 0 (safe); if rename failed → seed ADDS duplicates = 2× count = critical FAIL.** Tag `[s59-dot4, run276, pass, workitems-rename-pmh, bundle-rotate-both, no-mig, count-71-no-dup]`.
|
||||
- **2026-06-11 Run #275 (run_number 275) sha=`bbd1554` PASS ~3m44s (S59-đợt3 BE-only DbInitializer GỠ seed 15 WorkItems demo — chị Trà Sol chốt giữ đúng 71 mã PMH + `scripts/s59-wipe-demo-workitems.sql` ran TAY prod TRƯỚC push 86→71):** Push `0eafcd3..bbd1554` 2 files `DbInitializer.cs` + wipe-sql ONLY, NO FE/Mig. `.cs` → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon API + prod appsettings pw `ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 16:57) — polled iter6 status=success (16:57:41→17:01:25). **Bundle FROZEN admin `DuU7OTym` + user `DWyeTzf3`** (== #274 UNCHANGED ✓ CORRECT BE-only — verified AFTER status=success, no FE leak). **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo ✓. Health live+ready **200/200** + admin/eoffice root 200. **★ RESURRECT-VERIFY (risk point — app recycle post-deploy did NOT re-seed demo WorkItems, seed-block removal HELD): WorkItems=71 (ACTIVE=71 INACTIVE=0 DELETED=0 — hard-wipe not soft) + 4 categories EXACT: MEP 9 / Thầu phụ-Xây dựng 30 / Thiết bị 16 / Vật tư-Xây dựng 16** ✓ + **demo-codes DAO-MONG/SON-NUOC/VC-PHE-THAI = 0** ✓ (SeedRealMasterDataAsync idempotent re-ran, added 0 — 71 codes all exist). ⚠️ **PARTIAL item 5 — PE=1 không phải 0:** 1 row `PE/2026/A/001` Phase=10 created 09:46:42 **UTC = 16:46 chiều local** (CreatedAt lưu UTC — em main annotate S59-end kẻo đọc nhầm timeline; sau wipe Run #273 ~15:36 local, là phiếu UAT thật user tạo buổi test chiều, KHÔNG do deploy resurrect — BE-only bundle-frozen, DbInitializer KHÔNG seed transactional PE). INFO-flag, NOT deploy-fail. Test gate 240 (CI both proj pre-deploy ⟹ success=passed). 0 regression. **LESSON: seed-removal verify (mirror wipe-verify #273) = (a) target table count exact + category breakdown + demo-code spot-check 0 AFTER recycle (idempotent real-seed re-runs but adds 0), (b) ACTIVE/DELETED split proves hard-wipe vs soft-delete. PE=1 leftover-UAT ≠ regression: check CreatedAt timestamp vs wipe-time — pre-wipe-then-new-create is legit UAT activity, only assert PE=0 if no UAT happened between wipe and deploy.** Tag `[s59-dot3, run275, pass-partial, be-seed-removal, workitems-71-no-resurrect, bundle-frozen, no-mig, pe1-uat-leftover]`.
|
||||
- **2026-06-11 Run #273 (run_number 273) sha=`56882ac` PASS ~3m34s (S59 FE×2 PE-list tree regroup "Dự án(Năm)→Hạng mục→Phiếu" bỏ tầng NCC + prod data WIPE):** Push `1577927..56882ac` 3 files: `PurchaseEvaluationsListPage.tsx` ×2 app (SHA256 mirror identical, Panel-1 tree drop NCC tier) + `scripts/s59-wipe-testing-data.sql` (ran TAY prod TRƯỚC push, NOT in pipeline). `.tsx` present → pipeline RAN. ⚠️ GITEA_TOKEN+PROD_DB_PASSWORD empty → anon Gitea API (works, public) + read DB pw from prod `appsettings.Production.json`→`ConnectionStrings.Default`. Run IN-PROGRESS first poll (running 15:36) — polled iter5 status=success (15:36:26→15:40:00). **Bundle ROTATE BOTH (load-bearing, verified AFTER success +6s stable NO transient — anti-pattern#3): admin `DMm9rtNA→R9uGRxvw` + user `BUkOMn_Y→DikfX1RD`** ✓ both apps touched. Brand `1F7DC1` preserved both HTML. Health live+ready **200/200** + admin/eoffice root 200. **NO migration** — prod top=Mig 49 `AddWorkItemToPurchaseEvaluation`==repo ✓. sys.tables(excl mighist)=**92**. **★ WIPE-VERIFY (the risk point — app restart post-deploy did NOT resurrect demo data, DemoSeed:Disabled gate HELD): PE=0 · Contracts=0 · Notifications=0 · PESeq=0** (all wiped clean, stayed clean post-recycle) + **infra preserved: ApprovalWorkflows=7 all IsActive=1 · Projects=70 · WorkItems=86 · Users=55** — ALL counts EXACT match expected. Test gate **240** (CI both proj pre-deploy ⟹ success=passed). 0 regression. **LESSON: post-wipe deploy verify = confirm both halves — (a) demo/transactional tables stay 0 after app-pool recycle (gate held, no re-seed) AND (b) infra/master tables (AW/Projects/WorkItems/Users) untouched (wipe was surgical, not nuke). Count-exact on both sides = PASS.** Tag `[s59, run273, pass, fe-list-regroup-x2, bundle-rotate-both, prod-wipe-verify, no-mig]`.
|
||||
- **2026-06-11 Run #274 (run_number 274) sha=`0eafcd3` PASS ~4m51s (S59-đợt2 FE×2 PE-list tree 4-tầng "Năm>Dự án>Hạng mục>Phiếu" — follow-up Run #273 đổi từ 2-tầng-gộp-label sang 4-tầng explicit):** Push `56882ac..0eafcd3` 2 files `PurchaseEvaluationsListPage.tsx` ×2 app ONLY (SHA256 mirror identical `95d524ee`). `.tsx` → pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon API + prod appsettings pw. Run IN-PROGRESS first poll (running 16:37) — polled iter6 status=success (16:37:06→16:41:57). **Bundle ROTATE BOTH (verified AFTER success +re-confirm stable NO transient — anti-pattern#3): admin `R9uGRxvw→DuU7OTym` + user `DikfX1RD→DWyeTzf3`** ✓ both touched. Health live+ready **200/200** + admin/eoffice root 200. **NO migration** (FE-only). Spot-check **PE=0** held post-deploy (FE-only no restart-resurrection risk; wipe gate still HELD from #273). Test gate 240 (CI both proj pre-deploy ⟹ success=passed). 0 regression. LESSON: FE-only follow-up of a wipe-session needs only light PE=0 re-confirm (no full infra re-audit) — restart risk already cleared #273. Tag `[s59-dot2, run274, pass, fe-list-4tier-x2, bundle-rotate-both, no-mig, pe-zero-held]`.
|
||||
- **2026-06-11 Run #385→#386 SUPERSEDE-CHAIN sha=`ea793a4` CANCELLED(benign)→shipped-via `3ebaf84` #386 PASS ~4m25s (S58 brand-accent polish x2 app then PE-workitem-merge):** Target push `6e53e33..ea793a4` 8 files FE polish CẢ 2 app (Layout/TopBar/PageHeader/DataTable each — stripe đỉnh + logo-zone tint + PageHeader accent bar + thead brand-50/60), NO BE/Mig. **Run #385 (run_number 271) status=`cancelled` @14:14:22 — NOT a fail: superseded by newer push `3ebaf84` (#386 run_number 272) landed @14:14:31 (Gitea concurrency-guard cancels in-flight same-branch run).** HEAD moved ea793a4→`3ebaf84`. **Verified ea793a4 IS ancestor of 3ebaf84 + the 8 polish files NOT re-touched by 3ebaf84 → polish PRESERVED in tree, ships via #386.** #386 adds 4 PE files (PeHeaderForm/PeWorkspaceCreateView ×2 app, anh Kiệt FDC 14:06 — gộp Tên gói thầu=chọn Hạng mục) → both apps rebuilt anyway. Polled #386 to status=`success` (started 14:14:31→14:18:56). **Bundle ROTATE BOTH (load-bearing, verified AFTER #386 success — anti-pattern #3): admin `CP4CB1ym→DMm9rtNA` (css `vMtY6u47→DDlKud5i`) + user `CKjwqnGL→BUkOMn_Y` (css `CV0H5hnq→BgAUPcnL`)** ✓ both touched → both rotate. **Brand preserved both apps: `1F7DC1` in HTML + `Be Vietnam Pro`+`1f7dc1` in CSS bundle; BONUS polish landed: `brand-50`/`brand-60` Tailwind classes present in BOTH CSS bundles** (thead/tint/accent shipped). Health live+ready **200/200** + admin/eoffice root 200. **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓ (neither ea793a4 nor 3ebaf84 has Mig). Smoke PE+contracts unauth=**401** + control `/api/zzz-not-a-route`=**404** (auth gates real). Test gate (CI both proj pre-deploy ⟹ #386 success=passed). Prior today #382/#383/#384 all PASS. **LESSON (cancelled ≠ fail — supersede-chain verify): a same-SHA run flipping to `cancelled` mid-flight is almost always Gitea concurrency-supersede by a newer push, NOT a build/deploy fault → MUST (1) check tasks list for newer run + HEAD movement, (2) `git merge-base --is-ancestor` confirm target commit preserved in new HEAD, (3) `git diff target..newHEAD -- <target-files>` empty ⟹ target changes survive, (4) verify prod via the SUCCESSFUL superseding run not the cancelled one. Do NOT report FAIL/escalate on a benign supersede-cancel.** Tag `[s58, run385-cancelled-benign, run386-pass, supersede-chain, brand-polish-x2, bundle-rotate-both, no-mig]`.
|
||||
- **2026-06-11 Run #384 (run_number 270) sha=`e959f72` PASS ~4m30s (S58 FE-USER visual redesign density-first per AI_INFRA UI/UX guide — keep brand #1F7DC1/Be Vietnam Pro/slate; FE-USER-ONLY, ZERO BE/Mig/fe-admin):** Push `6c5fd26..e959f72` 1 commit 16 files: 14 fe-user (`index.css` tokens + 6 ui primitives Button/Dialog/Input/Label/Select/Textarea + 6 shell DataTable/EmptyState/Layout/PageHeader/PhaseBadge/TopBar + LoginPage) + 2 broadcasts `.md`. NO fe-admin, NO `.cs`, NO Mig. `.tsx`/`.css` present → NOT docs-skip, pipeline RAN. ⚠️ GITEA_TOKEN empty both shells → unauth public API (200, no token needed). Run IN-PROGRESS at first poll (status=running 13:51) — correctly did NOT FAIL, polled iter6 status=success (started 13:51:18 → 13:55:48). **ASYMMETRIC bundle (load-bearing) PASS: user ROTATE `BmZ3VHnm→CKjwqnGL`** (redesign shipped, verified AFTER status=success, stable on +recheck no transient) **+ admin FROZEN `CP4CB1ym`** (=#382 UNCHANGED ✓ scope-correct, NO fe-admin leak — mirror Run #378 asymmetric fe-admin-only logic, inverted). user `.js` HEAD 200 app/js 1.47MB + CSS rotate `index-CV0H5hnq.css` 200 63KB. **Brand preserved: `1F7DC1` in HTML + `Be Vietnam Pro`+`1f7dc1` in CSS bundle** ✓; title "Solutions ERP". Health live+ready **200/200** + admin/eoffice root 200. **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓. sys.tables(excl mighist)=**92** (FE-only no new table). Smoke PE unauth=**401** + control `/api/zzz`=**404** (auth gates real). Test gate **240** (CI both proj pre-deploy ⟹ success=passed). 0 regression. Prior today #382(`5998163` lock-fix)+#383(`6c5fd26` hide-modules) both PASS as noted. **LESSON (single-app FE-USER redesign — asymmetric verify, inverse of #378):** PASS criteria asymmetric — user hash MUST rotate (ship-proof) AND admin hash MUST stay frozen (scope-proof, no accidental fe-admin redeploy). admin-unchanged is POSITIVE here. Visual-only CSS-token+className redesign rotates bundle exactly like logic change (Vite content-hash byte-sensitive). SSH→sqlcmd `<>`/`NOT LIKE '__%'` quoting traps: `<` mangled by PS redirect (use `!=`/CONCAT-CHAR), `_` is LIKE-wildcard (escape `'[_][_]%'`). Tag `[s58, run384, pass, fe-user-only-redesign, asymmetric-bundle-verify, no-mig, brand-preserved]`.
|
||||
- **2026-06-16 S? Run #291 (run_number 291, id405) sha=`8c8179c` ❌ FAIL ~64s (TEST-GATE COMPILE BREAK — Department.ParentId phân cấp cây tổ chức, BE Mig + FE-admin picker; DEPLOY DID NOT RUN, prod UNCHANGED @baseline):** Push `c98030f..8c8179c` 2 commits: `0f44d97` BE (Mig `20260616032402_AddDepartmentParentId` = AddColumn `ParentId Guid? nullable` + CreateIndex `IX_Departments_ParentId`, NO new table; `GET /api/departments/tree`; Create/Update nhận parentId — `CreateDepartmentCommand` record signature CHANGED to `(string,string,Guid?,string?,Guid?)` +5th positional ParentId, `UpdateDepartmentCommand` +6th) + `8c8179c` FE-admin DepartmentsPage picker "Phòng cha". Tokens empty → anon Gitea + prod-appsettings DB pw. Task #291 status=**failure** created 10:41:14 → updated 10:42:18 = **~64s** (far < ~3min normal → early-stage fail, NOT deploy stage). Anon API can't reach `/tasks/{id}` + `/logs` (404 — need auth) + WebFetch Actions UI JS-rendered (empty) → **reproduced FAIL locally** (anti-pattern #2 no-speculate): `dotnet build SolutionErp.slnx -c Release` → **error CS7036** `tests/SolutionErp.Infrastructure.Tests/Application/MasterCatalogFilteredUniqueTests.cs(63,25)`: "no argument given that corresponds to the required parameter 'ParentId' of CreateDepartmentCommand". **Root cause: spec-change miss** — commit added `ParentId` as REQUIRED positional param but the gotcha#57 filtered-unique test line 63 still calls old 4-arg `new CreateDepartmentCommand("DUP1","Phòng ban mới", null, null)` (needs 5). grep `new CreateDepartmentCommand\(` repo-wide = ONLY this 1 broken call site; UpdateDepartmentCommand has 0 test call site (compiles). Test gate runs BEFORE build/deploy → compile-fail in test proj ⟹ whole `dotnet build slnx` (incl tests) fails ⟹ **deploy never ran**. **Prod CONFIRMED untouched @ baseline c98030f (Run #290):** admin bundle `DRob3iVl` (FROZEN=baseline ✓ NOT rotated — picker NOT shipped) · user `DxK3fCfh` (FROZEN=baseline ✓ correct, fe-user untouched) · health api live+ready **200/200** + admin/eoffice root 200 · prod `__EFMigrationsHistory` top = `20260612173224_ReplaceBudgetModuleWithPeWorkItemBudgets` (Mig 50) — **`AddDepartmentParentId` NOT applied** ✓ (deploy didn't run, DbInitializer never fired). All 4 post-deploy KEY checks correctly N/A (no ship). **ESCALATE em-main: fix = update `MasterCatalogFilteredUniqueTests.cs:63` to pass 5th arg (e.g. `..., null, null, null)`) — CLAUDE.md §7 "spec change = update test cũ + code chung commit" violated; re-push → re-verify deploy.** READ-only, did NOT fix. **LESSON: short-duration (~60s) `failure` on a BE/FE commit = test-gate or BE-build compile break, NOT deploy/transient — when anon API blocks logs, `dotnet build SolutionErp.slnx` locally reproduces exact CS error + line; a record-constructor positional-param ADD silently breaks every un-updated call site (grep `new <Command>\(` to enumerate). FAIL ⟹ deploy gated ⟹ verify prod = STILL baseline (bundles frozen + mig NOT applied) rather than skipping post-deploy entirely.** Tag `[s?, run291, FAIL, test-gate-compile-break, CS7036-CreateDepartmentCommand-5th-param, dept-parentid-tree, deploy-did-not-run, prod-unchanged-baseline, bundle-frozen-both, mig-not-applied, escalate-fix-test-line63]`.
|
||||
- **2026-06-11 Run #382 (run_number 268) sha=`5998163` PASS ~3m31s (S58 FIX the Run #381 lock NO-OP — DbInitializer.cs ONLY, BE-only, NO Mig/FE):** Push `dd117b7..5998163` 1 commit 1 file `DbInitializer.cs` (+28/-5). Fix: (1) `LockDemoSampleUsersAsync` union +20 UAT-matrix prod email (`{act,equ,fin,hra,pm,qs}.{nv,pp,tp}@`+`bod.{1,2}@`) into prior 14 named-person = 34-email list; (2) `DemoUserPassword` 11→12 chars (`User@123456`→`User@1234567`) fixing silent CreateAsync-fail vs prod `RequiredLength=12` (S56 helpdesk-inert root cause). `.cs` present → full pipeline RAN. Poll iter5 status=success (started 12:58:06 → 13:01:37). **Bundle FROZEN admin `CP4CB1ym` + user `BmZ3VHnm`** (= #381 UNCHANGED ✓ CORRECT for BE-only, verified AFTER status=success — NOT ship-fail). **NO migration** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓. sys.tables=**93** unchanged. Health live/ready 200 + admin/eoffice root 200. **THE FIX VERIFIED prod (Users table — note: custom Identity table name `Users` NOT `AspNetUsers`):** total **55** users · **21 active** · **34 inactive==34 locked-future** (== lock-list size exactly). 12-sample UAT-matrix all `active=0 locked=1` (#381 NO-OP now RESOLVED — these exist in prod + got locked ✓). Named-person 14/14 found+locked (CREATED this startup via 12-char pw fix + locked same run). **Must-stay-active 6/6** admin·catalog.manager·nv.test·chuong.phan@solution.com.vn(typo-domain)·**nv.cao+nv.truong** ALL `active=1` (IT helpdesk pool ALIVE — S56 ops-pending RESOLVED by pw fix, created this startup not in lock-list). **5 new real staff** (thanh.lethanh/anh.nguyen/tring.le/truong.le/long.nguyen) all CREATED+`active=1` ✓ (12-char pw passes RequiredLength=12). Smoke nv.test login OK (token 477) + GET /api/menus 200 + /purchase-evaluations 200. 0 regression. **LESSON: lock-by-email NO-OP (#381) was a DATA-mismatch not code-bug → S58 reconciled email-list to actual prod population (UAT-matrix created via admin UI, never in seed) + the 11-vs-12 pw bug was a SECOND latent cause silently blocking ALL non-existing-user CREATE on prod (RequiredLength=12) — same fix resurrected 16 named + 5 staff + helpdesk pool. Verify lock-fix = dump Users cohorts (active/inactive split + named exact-IN), NOT just total count.** Tag `[s58, run382, pass, fix-lock-noop, pw-11to12, be-only-bundle-frozen]`.
|
||||
- **2026-06-11 Run #381 (run_number 267) sha=`dd117b7` PASS+1PARTIAL ~4m25s (S57bis PE gắn WorkItem Mig 49 + all-role Pe perm + menu Cá nhân regroup + lock-14-demo-user — cross-stack BE+FE×2+Mig+test, +12 PeWorkItemGuardTests→240):** 2-commit push: prev `17b23a4` (governance+hmw.js → Run #380 **cancelled**, superseded — correct, no FE/BE contract change) then `dd117b7` (PRODUCT, Run 381 = the deciding run). 26 files: Mig 49 `20260611044424_AddWorkItemToPurchaseEvaluation` (3-file, PE.WorkItemId Guid? loose-Guid NO physical FK + `IX_PurchaseEvaluations_WorkItemId`) + Domain `PurchaseEvaluation.cs` + Config + Features + DbInitializer (perm + `LockDemoSampleUsersAsync` + menu regroup) + MenuKeys + 3 master controllers (write-lock Admin/CatMgr) + FE×2 (PeDetailTabs/PeHeaderForm/PeWorkspaceCreateView/menuKeys/types). **Run IN-PROGRESS at first check (status=running 12:14) — polled to terminal** (12:14:16→12:18:41 ≈4m25s success). ⚠️ poll-grep gotcha: `"status"` field sits AFTER `"display_title"` in tasks JSON → `[^}]*"display_title"` regex cut before status (showed blank all 10 iters); final FULL-object parse `\{"id":381,...deploy.yml[^}]*\}` confirmed status=success. **Bundle ROTATE BOTH** admin `4SUwDLD8→CP4CB1ym` + user `XdKzt9LL→BmZ3VHnm` (PE in both apps ✓ shipped, verified AFTER status=success). **Mig 49 applied prod** (`__EFMigrationsHistory` top = AddWorkItem... ✓ + WorkItemId col=1 + IX=1). sys.tables=**93** (col-only, no delta). Health live/ready 200 + admin/eoffice 200. **Perm seed STRONG: Pe_* CanCreate=1 = 130 rows across 13 roles** (was 3-role → all-role open landed); PeWf%=0 + AwV2%=2 (designer stays admin-only ✓ no leak). Menu regroup ✓: Personal root@30 · Off_ChamCong→Personal@1 · **Hrm_Config**→Master@25 (spec said key `HrmConfig`, real key has underscore `Hrm_Config` — verify by ParentKey/Order NOT literal Key) · Contracts@31 · Hrm_Dashboard→Hrm@1. Smoke PE unauth 401 (/purchase-evaluations + /catalogs/work-items) vs control 404 (auth real). WorkItems VT/TP/MEP/TB=71. **⚠️ PARTIAL item 7 — lock-14-users is a prod NO-OP:** `LockDemoSampleUsersAsync` SHIPPED+RAN but its 14 hardcoded emails (`bod.huynh@`,`pm.nguyen@`,`fin.do@`,`qs.hoang@`...) **DON'T EXIST in prod** — real demo set uses dept.position scheme `bod.1@`/`bod.2@`/`pm.{nv,pp,tp}@`/`fin.{nv,pp,tp}@`/`qs.{nv,pp,tp}@` (34 users ALL active, INACTIVE_TOTAL=0). Each FindByEmail→null→locked=0. Guard `nv.cao`/`nv.truong` also absent (-1, vacuously safe); catalog.manager+admin confirmed active. NOT a deploy fail (code correct) — email list stale vs this DB seed. Escalated em main: reconcile lock-list to actual `*.{nv,pp,tp}@` scheme OR confirm named-person legacy users were ever seeded. **LESSON: lock/deactivate-by-email assertion returning 0/`-1` ⟹ ALWAYS dump actual `Users` set before scoring FAIL — code may have run as no-op against mismatched data, NOT broken.** Tag `[s57bis, run381, pass-partial, mig49-pe-workitem, allrole-perm-130, lock-noop-email-mismatch]`.
|
||||
- **2026-06-09 Run #379 (run_number 265) sha=`a20cde8` PASS ~4m20s (S56 GOLIVE-HARDEN BE fixes — LeaveBalance concurrency + ItTicket authz-order + DocxRenderer null-guard + tests, ZERO FE/Mig):** Push `bef5825..a20cde8` 1 commit 13 files: 3 BE `LeaveOtApprovalFeatures.cs` (atomic ExecuteUpdate + Serializable tx vs lost-update) + `WorkflowAppsFeatures.cs` (authz reorder Forbidden-before-NotFound) + `DocxRenderer.cs` (null-guard) + 4 test files (+12 → 216→**228**) + 6 agent-memory `.md`. `.cs`+test present → NOT docs-skip, full pipeline RAN. **Run IN-PROGRESS at first check (status=running 17:51) — correctly did NOT FAIL, polled to terminal** (started 17:51:45 → updated 17:56:05 ≈4m20s status=success iter5). **Bundle FROZEN admin `4SUwDLD8` + user `XdKzt9LL`** (= #378, UNCHANGED ✓ CORRECT for BE-only — NOT ship-fail, mirror Run #243/#368; verified pre-deploy + post-success + +5s re-confirm, NO transient, NO unexpected rotation). **NO migration** — prod `__EFMigrationsHistory` top = `20260609020759_AddProjectMasterFields` (Mig 48) == repo latest, GIỮ NGUYÊN ✓ (BE-logic-only, schema untouched). sys.tables=**93** unchanged. Health live+ready **200/200** + admin/eoffice root 200. **Smoke changed-area endpoints (all gated, none crash):** `GET /it-tickets/assignable-staff` unauth=**401** · `PUT /it-tickets/{guid}/assign` unauth+body=**401** (authz-reorder fix live, route wired) · `GET /leave-balances/my` unauth=**401** (concurrency fix dll deployed) · control fake `/it-tickets/zzz-not-a-route`=**404** (proves 401s are real auth gates not catch-all). 0 regression. **Ship-proof for BE-only no-contract-change = run success + test 228 + Mig 48 unchanged + bundle frozen + health 200** (no observable API delta — fixes are internal handler logic: atomic tx / exception order / null-guard; cannot curl-assert lost-update fix, rely on +12 tests passing in CI gate). Tag `[s56, run379, pass, golive-harden, be-only-bundle-frozen, no-mig]`.
|
||||
- **2026-06-09 (S56 pre-golive verify — NO deploy, read-only audit):** Re-verified prod truth at golive gate (HEAD `bef5825` docs-only → prod correctly = Run #378). build SolutionErp.slnx 0-err + fe-admin/fe-user npm build 0-TS each + test **216** (58D+158I) exact. Prod health live+ready 200; admin root serves `4SUwDLD8` / eoffice `XdKzt9LL` (== baseline, NO drift). `__EFMigrationsHistory` top = Mig 48 == repo; 92 tables. Master-data prod spot: Projects=70 (62 real+8 demo), CAL01.Investor=N'Công ty TNHH Calofic' exact, WorkItems real=71 (VT16/TP30/MEP9/TB16) of 86, Suppliers 3/3. **LESSON — local-vs-prod FE hash divergence is EXPECTED, not ship-fail:** fresh local `npm build` produces a DIFFERENT content-hash than CI-built prod artifact (node_modules/timestamp inputs not byte-reproducible) → load-bearing check is `prod-hash == documented-baseline`, NOT `== my-local-rebuild`. Don't false-alarm on local≠prod when HEAD unchanged. Tag [s56, pre-golive-verify, prod-truth-pass, local-vs-prod-hash-lesson].
|
||||
|
||||
- **2026-06-09 Run #378 (run_number 264) sha=`7feb53e` PASS ~4m24s (S55 Phase-1 FE-Admin VISUAL redesign density-first design-system NAMGROUP-ref keep brand #1F7DC1 — FE-ADMIN-ONLY, ZERO BE/Mig/fe-user):** Push `84fa638..7feb53e` 1 commit 15 files: 13 fe-admin (`index.css` design tokens + 6 ui primitives Button/Dialog/Input/Label/Select/Textarea + 6 shell DataTable/EmptyState/Layout/PageHeader/PhaseBadge/TopBar + DashboardPage) + 2 agent-memory `.md` (frontend-designer/reviewer). NO fe-user, NO `.cs`, NO Mig. `.tsx`/`.css` present → NOT docs-skip, pipeline RAN. **Run IN-PROGRESS at first check (status=running 11:51) — correctly did NOT FAIL, polled to terminal** (started 11:51:06 → updated 11:55:30 ≈4m24s status=success; updated_at froze 11:55:30 across 3 poll iters = terminal signal before status field parsed). **THE KEY PROOF — admin bundle ROTATE `B-d6893W→4SUwDLD8`** (✓ redesign shipped, verified AFTER status=success; pre-success snapshot 11:51 still showed OLD `B-d6893W` = anti-pattern #3 timing confirmed AGAIN; re-confirm +3s post-success = stable `4SUwDLD8`, NO transient this run). **fe-user bundle UNCHANGED `XdKzt9LL`** (= #377; untouched ✓ NOT ship-fail — correct, no fe-user file in commit). Admin root **200 text/html** + serves `<title>Solutions ERP · Admin</title>` + `<div id="root">` (app loads ✓). **NO migration** — prod `__EFMigrationsHistory` top = `20260609020759_AddProjectMasterFields` (Mig 48) == repo latest, GIỮ NGUYÊN ✓ (FE-only, BE/Domain untouched). Health live+ready **200/200** (both pre- and post-deploy). Test gate **216** (CI both proj pre-deploy ⟹ success=passed; `tasks` endpoint reports terminal as `status:success`, `conclusion` NOT populated — trust CI conclusion). 0 regression. **LESSON (single-app FE redesign — asymmetric bundle verify):** when ONLY fe-admin changes, the PASS criteria is asymmetric — admin hash MUST rotate (proof shipped) AND user hash MUST stay frozen (proof scope-correct, no accidental fe-user redeploy). User-unchanged is a POSITIVE signal here (mirror of BE-only Run #243/#368 where admin+user both stay frozen). Visual-only redesign (CSS tokens + className) rotates bundle exactly like logic change — Vite content-hash byte-sensitive. Status-grep gotcha: greedy `.*?` regex failed to isolate `"status"` field mid-poll → use `grep -oE '\\{"id":378,[^}]*\\}'` to capture full object then sub-grep status. Tag `[s55, run378, pass, fe-admin-only-redesign, asymmetric-bundle-verify, no-mig]`.
|
||||
- **2026-06-09 Run #377 (run_number 263) sha=`69cb393` PASS ~4m33s (S55 HMW-P4 real master-data seed from Excel + Project +4 cols Mig 48 — cross-stack BE+FE×2+Mig+seed):** Push `f8640d6..69cb393` 1 commit 18 files: Mig 48 `20260609020759_AddProjectMasterFields` (3-file) + Domain `Project.cs` (+Year/Investor/Location/Package nullable) + `ProjectConfiguration.cs` + App `ProjectFeatures.cs` + **`DbInitializer.cs` NEW `SeedRealMasterDataAsync` (UNGATED, per-code idempotent)** + FE×2 `master/ProjectsPage.tsx` + `types/master.ts` + 1 test `MasterCatalogFilteredUniqueTests.cs` + 4 agent-memory .md. `.cs`+`.tsx`+Mig present → full pipeline RAN. **Run was IN-PROGRESS at first check (status=running 09:28) — correctly did NOT FAIL, polled to terminal** (started 09:27:19 → updated 09:31:52 ≈4m33s status=success). ⚠️ `jq` NOT in Bash-tool bash (env is bash not PS despite shell=PowerShell env-line) — parse JSON via `grep -oE '\"id\":377[^}]*'` fallback; the working first call only used `head -c` not jq. **Bundle ROTATE admin `DmjI8Cmn→B-d6893W` + user `YxL_MljK→XdKzt9LL`** (BOTH changed ✓ FE shipped both apps, verified AFTER status=success; pre-success snapshot 09:28 still showed OLD DmjI8Cmn/YxL_MljK = anti-pattern #3 timing confirmed again; re-confirm +3s post-success = stable, no transient). **Mig 48 applied prod** (`__EFMigrationsHistory` top = `...AddProjectMasterFields` ✓ + `COL_LENGTH('Projects','Investor')` EXISTS). **THE KEY CHECK — real master-data landed (4/4 spot PASS):** Projects spot6 (APVN01/ZOTE01/CAL01/MIDEA01/SAM01/TLB01)=**6** · WorkItems VT-/TP-/MEP-/TB-=**71** · Suppliers (TRUONGGIANG/TANPHU/TGN)=**3** · `CAL01.Investor` =EXACT match N'Công ty TNHH Calofic' (console showed `C<>ng` = sqlcmd codepage mangle of `ô`, NOT data corruption — confirmed via `WHERE Investor=N'...'` EXACT). Totals: Projects=**70** (62 real + 8 demo coexist ✓ ungated seed idempotent), WorkItems=**86**, 5 Projects carry Investor / 23 carry Year (Excel sparse-fill, only some rows enriched — expected). Health live+ready **200/200**. `GET /api/projects` unauth=**401** (route wired, auth gates ✓). 0 regression. **LESSON (ungated prod seed verify = count spot-checks NOT schema):** `SeedRealMasterDataAsync` runs unconditionally on every prod startup (NOT inside `if(!demoSeedDisabled)` — correct per gotcha #51 INFRASTRUCTURE-seed rule); verify = sqlcmd COUNT spot-checks of real Codes + N-literal EXACT match for unicode fields (console codepage will mangle Vietnamese diacritics → always re-assert via `=N'...'`, never trust raw sqlcmd console render). Tag `[s55, run377, pass, mig48-master-fields, real-seed-ungated, sqlcmd-codepage-lesson]`.
|
||||
- **2026-06-08 Run #376 (run_number 262) sha=`ca4b602` PASS ~4m18s (S54 IT-staff self-reassign ticket — authz Admin-OR-IT + scoped capability endpoint, cross-stack, NO migration):** Push `18d397f..ca4b602` 1 commit 13 files: BE `WorkflowAppsFeatures.cs` (NEW `GetAssignableItStaffQuery` capability + `AssignItTicketHandler` authz Admin-OR-IT) + `ItTicketsController.cs` (NEW `GET /it-tickets/assignable-staff` + `/assign` LOWERED Authorize-Roles) + FE×2 `ItTicketsPage.tsx` (SHA256-identical) + `workflowApps.ts`×2 (+2 type) + `ItTicketReassignAuthzTests.cs` (+13 → 203→**216**) + 6 agent-memory `.md`. `.cs`+`.tsx` present → NOT docs-skip, full pipeline RAN. Poll iter5 status=success (started 16:12:23 → updated 16:16:41 ≈4m18s). **Bundle ROTATE admin `DfCfHUE9→DmjI8Cmn` + user `_3S0BPJ2→YxL_MljK`** (BOTH changed ✓ FE shipped, verified AFTER status=success; pre-deploy iter0 still showed OLD DfCfHUE9/_3S0BPJ2 — correct timing anti-pattern #3). **NO migration** — prod `__EFMigrationsHistory` top = `...FilterMasterCatalogUniqueIndexesByIsDeleted` (Mig 47) == repo latest, GIỮ NGUYÊN ✓ (DepartmentId reuse). sys.tables=**93** stable (no new table). Test gate **216** (CI both proj pre-deploy ⟹ success=passed; grep undercounts InlineData — trust CI). Health live+ready 200 + admin/eoffice root 200. **Smoke NEW endpoint:** `GET /api/it-tickets/assignable-staff` unauth=**401** (route wired, [Authorize] gates) · `PUT /api/it-tickets/{guid}/assign` unauth bare=**411** then **WITH body `-d '{}'`=401** (IIS demands Content-Length before auth eval; 411 is pre-auth Length-check NOT routing-miss) · control fake route `/it-tickets/zzz`=**404** (proves 401s are real auth gates not catch-all). 0 regression. **LESSON (411 vs 401 on bodyless PUT/POST):** unauth bodyless PUT/POST to a JSON-body endpoint returns **411 Length Required** from IIS BEFORE the [Authorize] filter runs — NOT a 404/route-miss. Re-send with `-d '{}'` to force auth eval → real 401. Consistent w/ Run #367 `PUT /adjust=411` + #364 `POST /approve=411` (same pattern, now explained). Tag `[s54, run376, pass, it-reassign-authz, no-mig, 411-precheck-lesson]`.
|
||||
- **2026-06-08 Run #371 (run_number 257) sha=`30a99aa` PASS ~4m18s (S50 HMW-Wave2 P11-C Vehicle+Driver catalogs Mig 44 + gotcha #57 filtered-unique 3 HRM catalog Mig 45 — BE+FE×2+2Mig+tests):** Push `f8179c5..30a99aa` 1 commit 28 files: BE Domain `Vehicle.cs`/`Driver.cs` + App `HrmConfigFeatures.cs`+IApplicationDbContext + `HrmConfigsController` + 5 Config (Driver/Vehicle/LeaveType/OtPolicy/ShiftPattern) + DbContext + DbInitializer + MenuKeys + Mig44/45 (6 files) + FE×2 (HrmConfigsPage/Layout/menuKeys/hrm-config.ts) + `HrmConfigFilteredUniqueTests.cs` (+5 test → 181→**186**). All BE/FE/Mig, none in paths-ignore → CI ran. Poll iter3 status=success (started 10:32:58 → 10:37:16). **Bundle ROTATE admin `DPPTx2Kw→Cg9mvltU` + user `CjoUEsoV→YgqDvsqr`** (BOTH changed ✓ FE shipped, verified AFTER status=success). **NEW LESSON (timing trap):** pre-success snapshot showed transient `CVbyotwa`/`BBlyMlJH` (intermediate FE copy mid-deploy, NOT final) → re-verify post-success gave real `Cg9mvltU`/`YgqDvsqr`. Confirms anti-pattern #3 + Run #242 lesson: NEVER trust bundle hash until status=success; mid-deploy can show a 3rd transient hash. **Mig 44+45 auto-applied prod** (`__EFMigrationsHistory` top2 = FilterHrmCatalog... + AddVehicleAndDriver...). **Vehicles+Drivers tables EXIST**; sys.tables=**92** (was 90 +2, narrative-93 = convention diff, NOT missing). **gotcha #57 LIVE — all 5 idx filtered:** IX_{Vehicles,Drivers,LeaveTypes,ShiftPatterns,OtPolicies}_Code ALL `is_unique=1 filter=([IsDeleted]=(0))` (3 HRM ones LeaveType/Shift/OtPolicy were NULL pre-Mig45 → now filtered = proof applied). Health live+ready 200 + admin/eoffice index 200. New endpoint `GET /api/hrm-configs/{vehicles,drivers}` unauth=**401** (route wired, no crash) + admin auth=**200** seed 2/catalog (vehicles XE-01/XE-02, drivers TX-01/TX-02 ✓ DbInitializer infra seed ran). 0 regression. Tag `[s50, run371, pass, p11c-vehicle-driver, mig44-45, gotcha57-filtered-5idx]`.
|
||||
- **2026-06-03 Run #369 (run_number 255) sha=`350b2bf` PASS ~4m13s (S48 FE-only login subtitle a11y `text-slate-500→600`, ZERO BE/Mig):** Push range `7bbfa5a..350b2bf` 2 commits: `009dd94` DOCS/GOVERNANCE-only (9 files: STATUS/HANDOFF + 3 adap-reports + error-ledger + session-log + frontend-designer MEMORY + session-end.md cmd — ALL `.md`/`.claude/**`) + `350b2bf` CODE 2 files `fe-{admin,user}/src/pages/LoginPage.tsx` (1-line each, slate-500→600 subtitle contrast). Mixed push: `.tsx` present → **NOT path-filter skipped, full pipeline RAN** (gotcha #41 Discovery #3 — ≥1 non-ignored file in range ⟹ whole range builds; docs commit alone would skip but `.tsx` overrides). Poll iter5 status=success (started 00:06:33 → 00:10:46). **Bundle ROTATE admin `Krjvg_3j→DPPTx2Kw` + user `6sNStgxa→CjoUEsoV`** (BOTH changed ✓ FE shipped — verified AFTER status=success; pre-deploy snapshot iter0 still showed OLD `Krjvg_3j`/`6sNStgxa`, correct timing per anti-pattern #3). **NO migration** — repo 43 == prod `__EFMigrationsHistory` 43, latest both `...FilterHolidayUniqueIndexByIsDeleted` (Mig 43 unchanged, BE/Domain untouched ✓). Health live+ready 200 + admin/eoffice index 200. Test gate 181 (CI both proj pre-deploy ⟹ success=passed). 0 regression. NEW LESSON: smallest possible FE change (1-line className) still rotates bundle hash — Vite content-hash sensitive to any source byte; mixed docs+tsx push is the canonical case where docs-only-skip does NOT apply. Tag `[s48, run369, pass, fe-only-a11y, mixed-push-not-skipped]`.
|
||||
- **2026-06-01 Run #368 (run_number 254) sha=`0c5a014` PASS ~4m20s (S45 Mig 43 filter Holiday UNIQUE by IsDeleted + 3 HRM test gaps — BE+tests ONLY, ZERO FE):** Push range `dbbed15..0c5a014` 2 commits: `051b62b` Tests +27 (HrmConfigHolidayTests + EmployeeSatelliteTests + AuthorizePolicyRegressionTests-ext → baseline 154→**181**) + `0c5a014` Mig 43 `20260601064128_FilterHolidayUniqueIndexByIsDeleted` (drops+recreates `IX_Holidays_Year_Date` as filtered UNIQUE `WHERE [IsDeleted]=0`, was unfiltered) + HolidayConfiguration.cs edit + Case-7 test flip. 7 files, all BE+tests, none in paths-ignore → CI ran. Poll iter4 status=success (started 13:43:47 → 13:48:07). **Bundle hashes UNCHANGED admin `Krjvg_3j` + user `6sNStgxa`** (= #367) — CORRECT for BE-only push, NOT ship-fail (Run #243 precedent; ship-proof = Mig 43 applied, not bundle rotate). **Mig 43 auto-applied prod** (history top = `...FilterHolidayUniqueIndexByIsDeleted` ✓). **THE FIX VERIFIED prod:** `IX_Holidays_Year_Date | unique=1 | filter=([IsDeleted]=(0))` — filter_definition non-NULL = filtered UNIQUE live (soft-deleted holidays no longer collide on UNIQUE). Health live+ready 200 Healthy. `Holidays` table exists, 10 rows, 2 named idx (PK + filtered UNIQUE). Prod tables=90-by-sys.tables (index-only change, NO new table — consistent #364 delta). NEW LESSON: filtered-index migration verify = check `sys.indexes.filter_definition` non-NULL (NOT just mig-history row); index-only mig = bundle unchanged + table-count unchanged both EXPECTED. Tag `[s45, run368, pass, mig43-filtered-index, be-only-bundle-unchanged]`.
|
||||
- **2026-05-30 Run #367 (run_number 253) sha=`82d7fcf` PASS ~4m08s (S42 P11-B LeaveBalance business logic, Mig 42):** Code commit 22 files (4 BE: Domain `LeaveBalance.cs` + App `LeaveBalanceFeatures.cs`/`LeaveOtApprovalFeatures` deduction hook + `LeaveBalancesController` + IApplicationDbContext + DbContext + Config + Mig42 3-file + 2 FE `WorkflowAppDetailPage`×2 +`workflowApps.ts`×2 + 2 tests + 4 agent-memory .md). Started 11:11:40 → success iter4 11:15:48. **Bundle rotate admin `BU8FTBRi→Krjvg_3j` + user `tepE4jvR→6sNStgxa`** (both changed ✓ FE shipped, verified AFTER status=success — pre-deploy snapshot still showed old hash, correct timing). **Mig 42 `20260530034336_AddLeaveBalances` auto-applied prod** (tables 90→**91**, `LeaveBalances` EXISTS). Schema ✓: UserId/LeaveTypeId/Year/EntitledDays/UsedDays/AdjustmentDays decimal + AuditableEntity soft-delete. **UNIQUE `IX_LeaveBalances_UserId_LeaveTypeId_Year`** + **FK→LeaveTypes del=NO_ACTION** (=Restrict) ✓. New endpoint smoke: `GET /api/leave-balances/my` unauth=**401** (route live not 404) + admin auth=**200** lazy-default 5 LeaveTypes (ANNUAL12/COMPASSIONATE3/MATERNITY180/SICK30/UNPAID0, all Used=0, `remainingDays`=entitled ✓ DTO shape has remainingDays/entitledDays) + `?year=2026` admin route 401 unauth + `PUT /adjust`=411 (route reg). health live/ready 200 Healthy. **NO seed gate concern** (plain table, lazy DTO — Stage 4.6 N/A). 0 regression. Note: prev run #366 (ffb2062 docs STATUS update) was a CODE-path push w/ status=success — NOT docs-only-skipped (commit touched only .md but Gitea still ran since prior range?); actually #366 display_title is Docs but ran full → confirms agent-memory .md NOT in paths-ignore (`.claude/skills/**` ignored, `.claude/agent-memory/**` NOT). Tag `[s42, run367, pass, p11b-leavebalance, mig42]`.
|
||||
- **2026-05-30 Run #365 sha=`75df04e` PASS ~4m05s (S42 P11-A fix workflow picker 2-bug + SetWorkflow endpoint, NO mig):** 11 files BE+FE×2+test. Bundle rotate admin `BLA09-qv→6D4k-aRi` + user `CXvejOE-→DkME-974`. +4 `PUT /api/{leave,ot,travel,vehicle-bookings}/{id}/workflow` unauth=401. Test 144. NAMING RECONCILE: use real Gitea task id (#364=e7b66cd mem-labeled "#250"). Tag `[s42, run365, pass, p11a-setworkflow]`.
|
||||
- **2026-05-30 Run #364 (mem #250) sha=`e7b66cd` PASS ~4m07s (S42 P11-A wire ApproveV2+LevelOpinions 4 WorkflowApps):** 1 commit BE+FE×2+Mig41+Tests. Status=success iter3. Bundle rotate admin `cWAXid0q→BLA09-qv` + user `CX79e2kZ→CXvejOE-`. **Mig 41 auto-applied prod** (latest=`20260530021936_WireWorkflowAppsApprovalV2`). Tables 84→**90** (+5: Leave/Ot/Travel/VehicleRequest LevelOpinions + WorkflowAppCodeSequences — ALL EXIST). 4 new endpoint smoke 200 auth (leave/ot/travel/vehicle-requests) + unauth 401 (route exists) + POST .../approve=411 (route reg). health live/ready 200. **Stage 4.6 seed gate PASS** (gotcha #51): 4 WF seeded prod despite DemoSeed:Disabled — QT-NP/OT/CT/XE-V2-001 AppType=5/6/7/9, verified call-site L142-145 OUTSIDE `if(!demoSeedDisabled)` gate. Test gate 141 (CI runs both proj pre-deploy). Note: table count 90 vs spec-expected 89 = baseline-count diff, NOT missing table (all 5 present). Stale doc drift deploy.yml comments "54/17 test" (cosmetic, flag em main). Tag `[s42, run250, pass, p11a-approvev2-workflowapps]`.
|
||||
- **2026-05-28 Run #247 sha=`e54a22d` PASS 3m25s (S38 SKELETON 5-plan combo Mig 39+40 dual):** Push 1 commit mega `Domain+App+Infra+Api+FE×2`. ALL PASS. Bundle rotate admin `CGueDk22→cWAXid0q` + user `CEt0QRgX→CX79e2kZ`. Mig 39+40 dual auto-applied startup (90830→90839). 6 endpoint smoke 200 (leave/ot/travel/vehicle/it-tickets/hr-dashboard `totalEmployees=33 male=17 female=16`). 6 new tables + 8 menu seeded. 0 regression. Fastest S38 deploy. Tag `[s38, run247, pass, skeleton-combo]`.
|
||||
- **Archived Run #246 (S37 Proposal Mig 37+38 — `/api/proposals` 200 + QT-DX-V2-001 AppType=4 seed + Stage 4.6 INFRASTRUCTURE-gated correct gotcha #51) + #359/#243/#242/#241/#240 + S35/S36 startup → `archive/2026-05-q4.md` + git d2f52ba (S40 curate):** Run #359 G-O2 Meeting Mig 36 · #243 HrmConfig BE 16 endpoint (BE-only bundle unchanged anti-pattern verify) · #242 FE inline forms 5 satellite · #241 Mig 35 HRM foundation · #240 satellite CRUD. Discovery #7 path-filter eval/** + #8 collection `proj_*`. KEY absorbed in essentials/Stage sections above.
|
||||
- **[⚠️ VỊ TRÍ LẠC — entry MỚI 2026-06-11, thuộc FIFO slot giữa #384/#382 phía trên nhưng ghi lạc vào khu archive-zone này; curate-L2 ĐỪNG archive nhầm (H2 S58 P2 flagged); relocate khi curate] 2026-06-11 Run #383 (run_number 269) sha=`6c5fd26` PASS ~4m25s (S58b TẠM ẨN HRM/Văn phòng số/Cá nhân khỏi non-Admin + Danh mục xuống cuối — BE-only seed, NO Mig/FE):** Push `2aefb31..6c5fd26` 1 file `DbInitializer.cs` (+61/-5): NEW `RevokeTemporarilyHiddenModulesAsync` (set 4 CRUD=false MỌI role TRỪ Admin trên `Hrm%`+`Off%`+`Personal`, idempotent, KHÔNG xóa row) + `SeedAllRolesReviewReadPermissionsAsync` scope THU HẸP còn Master/Catalogs/Pe_* + menu `Master` Order 20→80. `.cs` present → full pipeline RAN. Run IN-PROGRESS at first check (status=running 13:36) — correctly did NOT FAIL, polled to terminal (started 13:36:15 → success 13:40:40 iter5). **Bundle FROZEN admin `CP4CB1ym` + user `BmZ3VHnm`** (= Run #382 UNCHANGED ✓ CORRECT BE-only — verified AFTER status=success, NOT ship-fail). **NO Mig** — prod `__EFMigrationsHistory` top = Mig 49 `AddWorkItemToPurchaseEvaluation` == repo, GIỮ NGUYÊN ✓. Health live/ready 200 + admin/eoffice root 200. **6 prod sqlcmd ALL PASS exact (DB SolutionErp, custom tables `MenuItems`/`Permissions`/`Roles`):** MasterOrder=**80** ✓ · HiddenReadNonAdmin=**0** ✓ (revoke landed, `Hrm%`+`Off%`+`Personal` all CRUD=false non-Admin) · HiddenReadAdmin=**29** (>0, Dev est 28, Admin GIỮ ✓) · PeCreateNonAdmin=**120** (Pe_* untouched ✓) · MasterReadNonAdmin=**48** (Master still visible ✓). **Menu-tree smoke (gotcha #44 dual-role):** nv.test `/api/menus/me` 200 → keys = Master/Suppliers/Projects/Departments + Catalogs/Catalog* + all Pe_DuyetNcc*/Pe_DuyetNccPhuongAn* — **ZERO Hrm/Hrm_*/Off/Off_*/Personal** ✓; admin counter-check VẪN CÒN Hrm/Hrm_Config*/Off/Off_*/Personal + Contracts/Budgets/System ✓ (revoke scoped non-Admin only). 0 regression. **LESSON (seed-only permission-revoke verify = sqlcmd matrix + dual-role menu-tree, NOT bundle/endpoint):** RevokeTemporarilyHiddenModulesAsync runs UNCONDITIONALLY on startup (NOT gated — correct, it's a permission-correction not demo-seed); verify = COUNT(CanRead non-Admin)=0 for revoked-prefix + COUNT Admin>0 (kept) + COUNT untouched-scope (Pe/Master) unchanged + `/api/menus/me` key-set diff between regular-user (modules gone) and admin (modules present). FE has NO PermissionGuard per-route (commit note) → direct-URL still renders trang, mức "tạm ẩn" = menu hide + permission matrix only; acceptable pre-golive. Tag `[s58b, run383, pass, revoke-hidden-modules, master-order-80, be-only-bundle-frozen, no-mig, dual-role-menutree]`.
|
||||
- **Archived Run #232 (S29 gotcha #51 catch — SeedSampleContractWorkflowV2 nested in demoSeedDisabled → empty V2 dropdown, hoist fix) → `archive/2026-05-q4.md` + git. Smart Friend ROI 4× cumulative (S22 #44 + S25 #48 + S29 ApplicableType + S29 DemoSeed).**
|
||||
@ -36,3 +36,5 @@ H2 harvest-MD-integrity auditor **SOLUTION_ERP-self**. Read-only + **propose-onl
|
||||
- **2026-06-12 (S60 @start RE-REPORT — post-S59 đóng-TRỌN):** Verdict 🟢 CLEAN cả 5 mục — tree clean HEAD `6bf28bf` (18:49:21), 11/11 agent-memory mtime ≤18:42:45 đều TRONG closeout → 0 mồ-côi. Coverage S59 14-spawn ĐỦ: H1 tooling `:35/:36` + H2 ×2 + recon inv `:73` + cicd run-coverage 10/10 #273→#282 (6 entry `:72-77` + `:71` #279/280 + extension FINAL-v2 #281/282 — 9 spawn→8 record-unit do supersede-fold, 0 run thiếu). Wave=0 · stray=0 · 0-byte=0 ×2 nơi · user-memory 23 file = index 22 + MEMORY.md 5.6KB khớp · cicd tail `0a` sạch. **2 flag GATE S59-end RESOLVED bởi em main:** `:53` bundle-live → FINAL-v2 `B1DtNT9C`/`D6uF3Mln` #282 ✓ + #275 UTC annotate `:75` ✓. #383 vẫn lạc (`:89`→`:96` shift +7 đúng arithmetic, annotation guard intact). Chore P1 carry: **cicd 56,480B/103L over-cap 3rd-session + phình 54→56.5KB/buổi** + inv 32,931B → curate-L2 (kèm relocate #383 + FIFO swap #273↔#274); watch reviewer 30,354B + impl-be 28,585B. Tag [s60-start, clean, flags-resolved, cicd-56kb]. *(em main APPEND B3 — H2-proposed, verify: 0-byte/tree-clean/size đối chiếu độc lập ✓)*
|
||||
- **2026-06-12 (S61 @start RE-REPORT — S60 đóng KHÔNG trọn):** Verdict 🟡 — S60 2 commit (37122f0 11:53 + 6db195d 14:30) KHÔNG docs-closeout (STATUS/HANDOFF/session-log đều dừng S59). Harvest-MD: 3 delta ĐÃ COMMIT bundle 37122f0 (harvest `:34` + inv ×2 `:73-75` tag s60 đúng-hết-drift + test-spec `:56` +14→254) + 1 mồ-côi cicd dirty `:71` mtime 14:37 entry-kép #283/#284 SANE (bundle-chain B1DtNT9C→akytoBnc→DSvM8h3A + user-chain khớp #282, sha khớp git, 2 test file disk-verified mtime trước commit). Coverage 5/6: **MISS reviewer die-mid-run** (commit body 37122f0 tự khai, file intact KHÔNG 0-byte) → on-behalf APPENDED S61-start (die lần 3: S57bis ×2 + S60). Đợt2 6db195d 0 sub-delta = em-main-direct evidence (16-min turnaround, test mtime 14:27) — flag không phán. Wave=0 · stray=0 · 0-byte=0 ×2 nơi · mojibake 2 hit quoted-cũ. Flags: test-spec baseline 254 stale vs **256 thật (59 Dom+197 Infra — em main dotnet test S61-start)** · CLAUDE.md "240 test" stale · inv `:51` pointer archive nhưng S52 entry chỉ ở git (cut-honest-labeled, nit) · **cicd 61KB/104L over-cap 4th session +4.5KB/buổi → curate-L2 P1 GẤP** + inv 32.7KB. Method ⭐: commit-body = nguồn spawn-evidence khi sub die không để delta (reviewer "die mid-run" tự khai trong msg 37122f0). Tag [s61-start, s60-incomplete-close, reviewer-die-3rd, cicd-61kb]. *(em main APPEND B3 — H2-proposed, verify: commit-body 37122f0 reviewer-die ✓ + test 256 tự chạy ✓ + cicd-dirty diff đối chiếu độc lập ✓)*
|
||||
- **2026-06-15 (S63 `/session-end` 5-trục GATE — em-main-solo, 0 product-sub):** **GATE PASS 5/5, 0 MISS, 0 orphan.** Session = bootstrap + S63 closeout(S60-62) + check-email + Harness 5/6 adopt + gitattributes; sub DUY NHẤT = 2 monitor (H1+H2 start+end). Coverage: 2 monitor record-proposed (không product-sub miss). Completeness 4-field. **0-byte=0** ×8 file S63-written (session-log 10264B · adap-report H5 4930B/H6 5562B · adap-request 2779B · email 3853B · .gitattributes 348B · 2 reviewer child 1838/1701B). Placement: **fe-admin/.claude GONE** + 2 child đúng `agent-memory/reviewer/` + **pointer no-overwrite (31959B preserved)** + moved-not-cut (git log → S63 `5e6dcc1`). Corruption: U+FFFD=0 ×8. Fidelity: em-main-solo honest self-gate (đúng H6.1 governance→solo + precedent S56) → no-escalate. Wave=0 (S63 no-workflow). **3 flag non-block:** (1) email body-hash `8a247984` H2 không verify scope (3 candidate Python sai formula) — **em main ĐÃ self-verify spec-canonical recompute==stored** (PowerShell), non-issue · (2) **cicd 62KB over-cap 5th-session +2.3KB/S61 → curate-L2 P1 GẤP** (carry 41→54→56→61→62KB) · (3) "CLAUDE.md count stale" = docs/CLAUDE.md FULL (root ĐÃ fresh). Tag [s63-end, gate-pass-5/5, 0-miss, em-main-solo, cicd-62kb]. *(em main APPEND B3 — H2-proposed, verify: 0-byte ×8 + pointer-31959B + tree-clean đối chiếu độc lập ✓)*
|
||||
|
||||
- **2026-06-16 (S66 @start RE-REPORT + @end GATE — em-main-solo, 0 product-sub):** @start: 0 orphan (S65 PE fan-out fully harvested+committed incl 2 empty-return subs) · 0 corruption (AS-8 clean) · Fidelity PASS (HoSoLink+Mig51/52 ground-truthed) · **🔴 cicd-monitor L1 86.8KB 2.9× cap GẤP** → em main curate **86.8→28.9KB** byte-exact sed move (Run #286→#232 → archive/2026-06.md, incl #291 forensic [lesson=gotcha#65]; baseline + 6 runs #289-#295 giữ). @end GATE 5-trục: Coverage (2 monitor spawn-record) · Completeness (4-field) · Placement (đúng agent-memory) · Corruption (moved-not-cut + email body-hash round-trip MATCH) · Fidelity PASS. NO wave-folder (no WAVE-MODE). GATE **PASS 5/5**. on-behalf em main (H2 read-only).
|
||||
|
||||
@ -35,3 +35,5 @@ H1 tooling-freshness auditor **SOLUTION_ERP-self**. Read-only + **propose-only**
|
||||
- **2026-06-11 (S59 @start RE-REPORT — ALL-4-FRESH, 0 drift, tree clean):** Bootstrap sau S58 đóng-sạch (HEAD `1577927`, tree clean). 4-mặt **TẤT CẢ FRESH, 0 drift mới** — session đầu tiên 0-patch kể từ S57bis. ①SKILL 6 project + 23 standalone **unchanged** (list standalone identical S58); 0 skill mới/đổi/mất. ②ROSTER **CLEAN 11=11=11** — disk 11 .md (README.md=doc KHÔNG đếm) = README:3/:13 "11 sub" = STATUS:24 "11"; frontmatter grep = **4 inherit (database-agent·harvest-curator·investigator-codebase·reviewer) + 7 pin claude-opus-4-8** ✅ khớp two-tier H4 (README:3 list khớp chính xác). ③PLUGIN **CLEAN 18/15/3 identical** S58 (settings.json:17-35 verbatim; 3 OFF: pr-review-toolkit:20·code-modernization:22·hookify:27), README:166 "18(15/3)" khớp, 0 new-alloc. ④DOCS **ALL-COUNT-FRESH ground-truthed từ disk:** Mig **49**=49 (disk `Persistence/Migrations/*.cs` đếm 49, cao nhất `20260611044424_AddWorkItemToPurchaseEvaluation`) · menu keys **57**=57 (`MenuKeys.cs` const đếm 57) · gotcha **60**=60 (max `### 60.`) · test 240 (S57bis+S58 log authoritative, KHÔNG attr-count) · tables 93 (cicd Run #379). CLAUDE.md root :53/:66/:133 + STATUS :14/:15/:20/:21 + README roster ALL khớp disk. **Minor narrative-lag (KHÔNG phải drift, KHÔNG patch):** STATUS:6 header "Run #382/#383/#384" thiếu #386 NHƯNG body+bundle:27 đã đúng #386 → cosmetic, defer. Carry-flag bất biến: docs/CLAUDE.md gotcha "(55)" (monthly 07-01) · schema-diagram §16+ Mig 32-49 ERD debt (~17 mig). **Method:** Bash-tool nuốt `$`-var của inline PS → phải `powershell -NoProfile -Command "& {...}"` với escape `\$`; Migrations KHÔNG ở `Infrastructure/Migrations` mà `Infrastructure/Persistence/Migrations` — verify path trước khi đếm. 0 delta đề xuất (clean baseline). Tag `[s59-start, 4-mat-all-fresh, 0-drift, clean-tree]`.
|
||||
- **2026-06-11 (S59 `/session-end` CHỐT 4-mặt — ALL-FRESH, 0 drift, em main docs-flush verified):** 6 commit code S59 (`56882ac`→`9c330d2`, Gitea Run #273→#278 — KHÁC đếm Run#38x S58, run_number reset) đã COMMIT+prod-verify; em main vừa flush docs (CHƯA commit, tree 5 MEMORY.md M + 4 docs M + 1 untracked session-log). 4-mặt **ALL-FRESH, 0 drift**: ①SKILL 6 project + 23 standalone **unchanged** (0 mới/đổi/mất); `SearchableSelect.tsx` ×2 app = code FE (UI primitive `components/ui/`), **KHÔNG phải skill/plugin** → confirm 0 new-alloc. ②ROSTER **CLEAN 11=11=11** (disk/README:3/STATUS:24); two-tier frontmatter UNCHANGED (4 inherit+7 pin). ③PLUGIN **CLEAN 18/15/3 identical** (3 OFF pr-review-toolkit·code-modernization·hookify), 0 new-alloc. ④DOCS **cross-count CONSISTENT, em main flush ĐÚNG**: gotcha **62**=62 (max `### 62.` = count 62 contiguous, #61/#62=S59 verified `gotchas.md:1099/:1111`) = STATUS:21 "62" = CLAUDE.md root:133 "62 bẫy"; bundle **`BSh2fG2X`/`D22KfpPc`** TRIANGULATED 4-source (STATUS:27 + HANDOFF:5 + session-log:4 + cicd-MEMORY:71 full Run#278 provenance — anti-pattern#3 stable-after-success verified) ✅; session-log `2026-06-11-S59-wipe-tree-pmh-uat-batch.md` EXISTS; HANDOFF:9 S59 section + HANDOFF:5 header 06-11 present; STATUS:16 master-row 71 WorkItems + STATUS:34/:48 In-Progress(none)/Recently-Done S59 present; spec `master-import-data.generated.md` 74 W-rows. **Cross-doc 0 LỆCH/SÓT.** Carry-flag bất biến: docs/CLAUDE.md gotcha "(55)" (monthly 07-01) · schema-diagram §16+ Mig 32-49 ERD debt. **Method-learning:** (a) bundle-hash KHÔNG tin 1-source — S59 triangulate 4 nguồn (đối lại S57bis bài học "session-log không ghi → unverified"); cicd-MEMORY:71 là nguồn provenance giàu nhất (Run#+sha+rotate-from+health). (b) Tool-gotcha PS: `Get-Content -Raw` + `-TotalCount` MUTUALLY EXCLUSIVE → frontmatter-read fail; dùng Grep tool `^model:` thay loop. (c) Run-number S59 reset #273-278 ≠ S58 #38x (run_number API đổi đếm cùng pipeline — KHÔNG nhầm regression). 0 delta đề xuất. Tag `[s59-end, 4-mat-all-fresh, 0-drift, bundle-triangulated-4src, searchableselect-not-skill]`.
|
||||
- **2026-06-15 (S63 start+end CHỐT 4-mặt — em-main-solo session):** @start audit + @end chốt sau S63 closeout(S60-62) + Harness 5/6 adopt + .gitattributes. **Self-report `claude-opus-4-8[1m]`** ("Opus 4.8, 1M context") = demote-pin ĂN runtime post-restart — **data-point H5:** lead + demote-sub ĐỀU Opus 4.8 lúc Fable-down (two-tier collapse single-tier như H5 mô tả). Verdict: ①SKILL 🟡 count-flush ĐÚNG (Mig 50/88/gotcha 64 ở ef-core desc:3/hist:19/total:74 + README:20/:90 + dep-audit:153) NHƯNG 2 residual ef-core `:282`+`:291` kẹt 93/49 → **em main FIXED in-session**. ②ROSTER 🟢 11=11=11, two-tier frontmatter (4 inherit+7 pin) đúng, agents/README:10 caveat H5 consistent runtime. ③PLUGIN 🟢 18/15/3 identical, **0 new-alloc** (H5/H6=governance · .gitattributes=hygiene — KHÔNG skill/plugin mới). ④DOCS 🟡 canonical FRESH (root CLAUDE.md:53/:66/:133 + STATUS + HANDOFF + agents/README khớp state THẬT) · 2 stale deep-doc defer-monthly (docs/CLAUDE.md full 58→64/93→88 + schema-diagram §16+ Mig 32-50). Method ⭐: system-reminder claudeMd header = pre-session snapshot (hiện "49 mig→93" cũ) → re-Read line thật (root=50→88 fresh), KHÔNG tin context-injection. Tag [s63, 4-mat, model-opus-confirm-h5, ef-residual-fixed, canonical-fresh]. *(em main APPEND B3 — H1-proposed, verify: self-report model + ef-core :282/:291 fix + canonical grep độc lập ✓)*
|
||||
|
||||
- **2026-06-16 (S66 @start RE-REPORT + @end CHỐT — em-main-solo session):** @start 4-mặt: skill 6/6 + standalone 23 (0 diff) · roster 11=11=11 intact · plugin 18/15/3 (0 new-alloc) · docs canonical FRESH (STATUS/HANDOFF/root-CLAUDE đã flush S65) NHƯNG ef-core SKILL stuck Mig 50 (TRUE 52) ×5 cites + skills/README ×2 + root gotcha 64→65 → em main flush hết. @end CHỐT: roster model-tier ĐỔI LỚN = adopt **Harness-8 all-inherit** (7 sub demoted claude-opus-4-8→inherit, gỡ two-tier H4 → cả 11=inherit) + agents/README codify + hmw.js comment + adap-report mới. 0 new skill/plugin. Nấc = executed-file VERIFIED-pending-restart. on-behalf em main (H1 read-only, propose→VERIFY→APPEND).
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Multi-agent SOLUTION_ERP — Master Coordination Guide (11-agent)
|
||||
|
||||
> **Architecture:** 11 sub-agents **two-tier model (Harness-4 2026-06-10)** + em main **Fable 5 (1M) Max** coordinator — **9 product/quality** (7 core + frontend-designer pink S47 + database-agent read-advisory S52) + **2 monitor INFORM-only** (`tooling-auditor` H1 + `harvest-curator` H2, 2026-06-07 Harness 1). Tier: **4 promote `model: inherit` = Fable 5 1M** (reviewer H4.3a · investigator-codebase H4.3b · database-agent H4.3b · harvest-curator H4.3c) · **7 demote pin `claude-opus-4-8`** (2 implementer · test-specialist · cicd-monitor · investigator-api · frontend-designer · tooling-auditor) · effort **Max cả 2 tier** (env machine-wide).
|
||||
> **Architecture:** 11 sub-agents **all-inherit top-tier (Harness-8 2026-06-16 — thay thế two-tier Harness-4)** + em main **Fable 5 (1M) Max** coordinator — **9 product/quality** (7 core + frontend-designer pink S47 + database-agent read-advisory S52) + **2 monitor INFORM-only** (`tooling-auditor` H1 + `harvest-curator` H2, 2026-06-07 Harness 1). Tier: **toàn bộ 11 sub `model: inherit`** (ăn top-tier model của lead — hiện Opus 4.8 1M do Fable suspended H5, tự lên Fable 5 khi về) · effort **Max** (env machine-wide). SE KHÔNG có lớp helper/gopher rẻ (cả 11 đều substantive memory-bearing → cả 11 lên inherit). *(Trước H8: 4 promote inherit + 7 demote pin `claude-opus-4-8` — lịch sử ở Upgrade 2026-06-10 + S66 dưới.)*
|
||||
> **Upgrade S52 (2026-06-08 — AI_INFRA broadcast `2026-06-08-Agent-database-codebase-agents`):** **+database-agent (read-advisory DB specialist, floor DB1–DB11)** — schema/query/migration-design-review/perf/concurrency (DB11 RowVersion vá lost-update S43). Tailor READ-tier (implementer-backend vẫn author) · color OMIT (8 standard hết) · `store_memory` strip. `codebase-agent` = **SKIP n-a** (investigator-codebase đã cover grep/audit + `csharp-lsp` Windows no-op). ✅ **verified-runtime** — spawned OK S53 (first real spawn, caught Mig 46 committed-but-unapplied-local drift) + S56 2× (pre-golive-verify schema-stream + golive-harden design+review). DB11 lost-update fix landed S56 (atomic ExecuteUpdate + Serializable tx, gotcha #58).
|
||||
> Pattern: Anthropic Building Effective Agents orchestrator-workers + Cognition "writes single-threaded" hybrid + post-deploy automated watchdog.
|
||||
> **Upgrade S39 (2026-05-29):** 4→7 agent (split investigator + implementer, +test-specialist) + budget +50% + 5 RAG MCP per agent. Reference BVAAU 7-agent config (adapted, NOT copied — SOLUTION_ERP 2-FE-app fit + 6 skill proven battle-test 38 session). Prior: S20t12 initial 3 + S21t1 +cicd-monitor.
|
||||
@ -9,6 +9,7 @@
|
||||
> **Upgrade 2026-06-10 (Harness-4 two-tier model — AI_INFRA broadcast `harness-4-model-tier-promotion` + `model-fable-5-max`):** lead = **Fable 5 (1M) Max** (user-level machine-wide, SE không project-pin) · sub two-tier theo tiêu chí H4.3 (a gate≥writer · b verdict-nuôi-quyết-định · c chống-rubber-stamp · d 1M-thật): **promote 4 giữ `inherit`** (reviewer·investigator-codebase·database-agent·harvest-curator) + **demote 7 pin `claude-opus-4-8`** (full-id no-suffix — gotcha #37 cấm `[1m]`; runtime resolve `[1m]` 1M trên máy chung per AI_INFRA s20). `hmw.js` tier-map H4.5 (role-less → `'opus'` · per-task `tier:'fable'|'opus'` override). Email-back AI_INFRA H4.7 BẮT BUỘC. Justification per-vị-trí: adap-report `2026-06-10-Governance-harness-4-model-tier-promotion.md`.
|
||||
> **Upgrade S63 (2026-06-15 — Harness-5 + 6 adopt):** **H5 model-fallback** — ⚠️ Fable 5/Mythos 5 **suspended 2026-06-12 no-ETA** → lead SE tạm **Opus 4.8 (1M) Max** (promote `inherit` tự theo → two-tier collapse single-tier Opus; demote-pin giữ; **revert-FREE** khi Fable về: đổi lead lại + spawn-test). KHÔNG sửa frontmatter · external-outage blameless KHÔNG RCA · session-start BƯỚC 0.6 check. **H6 governed-ultracode** — mode-ON: substantive task TỰ chạy HMW (KHÔNG đợi keyword "workflow"); workflow-agent default = **inherit lead** (`hmw.js` role-less `'opus'`→inherit) · role-fidelity (agentType ∈ VALID_ROLES) + memory-fidelity (memoryDelta→đúng agent-memory single-writer) ĐÃ sẵn từ HMW-engine. adap-report `2026-06-13-Governance-harness-5-...` + `2026-06-15-Agent-harness-6-...`.
|
||||
> **Upgrade S64 (2026-06-15 — Harness-7 writing-quality adopt):** sàn chất lượng viết **hướng ra ngoài** (email · broadcast · adap-report · tài-liệu-sister · **câu trả lời lead cho anh**) phải tiếng Việt rõ nghĩa, câu hoàn chỉnh, đủ dấu câu, đúng ngữ pháp (O1); nội bộ giữ lối nén §6.4/§6.5 (O2 — bất đối xứng); reviewer +**Category 6** writing-quality (O3, verified-pending-restart). Rule canonical `docs/rules.md §1.1`. adap-report `2026-06-15-Governance-harness-7-writing-quality.md`. body-hash `a4580ea9…` verified-MATCH (lesson gotcha #61: verify body-hash PHẢI đọc UTF-8 tường minh, PS5.1 default mis-decode tiếng Việt → false-mismatch).
|
||||
> **Upgrade S66 (2026-06-16 — Harness-8 all-inherit + workflow-fastest adopt):** 🔴 BẮT BUỘC (anh-chốt, mọi sister; chất lượng trên chi phí). **H8.1** — toàn bộ 11 sub-agent có memory → `model: inherit` (ăn top-tier lead), **GỠ cơ chế demote two-tier của Harness-4** (7 sub pin `claude-opus-4-8` đã flip `inherit`: 2 implementer · test-specialist · cicd-monitor · investigator-api · frontend-designer · tooling-auditor; 4 đã-inherit giữ nguyên reviewer·investigator-codebase·database-agent·harvest-curator). SE KHÔNG có helper/gopher rẻ để chừa → cả 11 lên inherit. Escape-hatch per-task `tier:'opus'` (hmw.js) GIỮ cho sweep/cost. **H8.2** — chạy workflow nhanh nhất: **song song tối đa + xuất nhanh + lead auto-HMW** cho task substantive (theo H6) — "nhanh" = parallelism, **KHÔNG phải hạ model**. **Caveat (trung thực):** runtime HIỆN KHÔNG đổi (inherit = Opus 4.8 1M vì Fable suspended H5 — trùng two-tier đã collapse); khác biệt thật khi Fable về (cả đội tự lên Fable 5 không sửa frontmatter) + H5.6 restore gọn hơn (chỉ đổi lead). Frontmatter no hot-reload → **executed-file, VERIFIED-pending-restart**. `[1m]` cấm trong frontmatter `model` (gotcha #37). adap-report `2026-06-16-Governance-harness-8-all-inherit-workflow-fastest.md`.
|
||||
|
||||
---
|
||||
|
||||
@ -25,7 +26,7 @@
|
||||
│ • Synthesize cross-agent findings + commit/push (em main only)│
|
||||
│ • Fallback solo nếu spawn fail (gotcha #53 truncate / 529) │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
↓ spawn + keep-alive (two-tier H4: 4 promote inherit Fable 5 · 7 demote pin Opus 4.8 — Max cả 2)
|
||||
↓ spawn + keep-alive (Harness-8 all-inherit: cả 11 sub `model: inherit` = top-tier lead — Max; per-task tier:'opus' escape-hatch giữ)
|
||||
── RESEARCH (READ) ────────── ── IMPLEMENT (WRITE) ──────────── ── QUALITY ──────────
|
||||
┌──────────────────┐ ┌───────┐ ┌─────────────────┐ ┌──────────┐ ┌────────┐ ┌─────────┐ ┌────────┐
|
||||
│investigator- │ │invest-│ │implementer- │ │implement-│ │test- │ │reviewer │ │cicd- │
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name: cicd-monitor
|
||||
description: |
|
||||
CI/CD pipeline + post-deploy verification specialist for SOLUTION_ERP. Use proactively AFTER every push to main that triggers Gitea Actions deploy (code commits — skip docs-only per path-filter gotcha #41). Polls Gitea Actions run status via API, verifies test gate pass (Domain 58 + Infra 23 tests baseline), confirms deploy actually shipped (FE bundle hash change × 2 app + EF migrations applied prod), smoke tests prod endpoints (api/admin/eoffice.solutions.com.vn). NEVER writes code — produces PASS/FAIL verdict with concrete evidence from logs + curl + sqlcmd. Catches deploy fail tự động không phụ thuộc em main nhớ verify.
|
||||
model: claude-opus-4-8
|
||||
model: inherit
|
||||
tools: [Read, Grep, Glob, Bash, WebFetch, mcp__rag-unified__search_memory, mcp__rag-unified__search_code, mcp__rag-unified__cross_project_search, mcp__rag-unified__list_projects]
|
||||
skills:
|
||||
- iis-deploy-runbook
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name: frontend-designer
|
||||
description: |
|
||||
Frontend DESIGN specialist cho 2 app SOLUTION_ERP (fe-admin :8082 + fe-user :8080 — React 19 + Vite 8 + TS 6 + shadcn/ui + Tailwind + TanStack Query). Sinh/redesign UI ĐẸP THẬT qua design-system-first + visual-verification loop (Playwright screenshot ≥2 viewport → rubric → fix → lặp) + anti-generic-aesthetic. Production-grade FE code + a11y WCAG-AA. Dùng khi build/redesign page/dashboard/component, "làm cho đẹp", thiết kế UX mới. Design-by-code KHÔNG Figma. KHÔNG đụng BE/DB/business-logic (đó là implementer-backend) · KHÔNG cookie-cutter mechanical mirror theo spec đã chốt (đó là implementer-frontend) — phân biệt bằng output contract: cần ĐẸP/UX → tôi; cần scaffold-theo-spec → implementer-frontend.
|
||||
model: claude-opus-4-8
|
||||
model: inherit
|
||||
effort: max
|
||||
tools: [Read, Write, Edit, Bash, Grep, Glob, Skill, WebFetch, WebSearch, mcp__rag-unified__search_memory, mcp__rag-unified__search_code, mcp__rag-unified__cross_project_search, mcp__rag-unified__list_projects]
|
||||
memory: project
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name: implementer-backend
|
||||
description: |
|
||||
WRITE specialist cho toàn bộ .NET backend SOLUTION_ERP (Domain + Application + Infrastructure + Api layer). Scaffold entity + enum + EF Configuration + Migration 3-file + DbInitializer seed + CQRS Command/Query/Validator/Handler + MediatR + Controller + DTO. Case 1+2+3+5 only (cookie-cutter mechanical scaffold, multi-file independent orchestrator-workers, isolated method test-gen handler, mass migration). DO NOT touch FE 2 app (đó là implementer-frontend). DO NOT write test assertions (đó là test-specialist). DO NOT schema design / UX decision / cross-stack bug fix reasoning (em main solo). Auto-refuses out-of-scope.
|
||||
model: claude-opus-4-8
|
||||
model: inherit
|
||||
tools: [Read, Edit, Write, Bash, Skill, Grep, Glob, mcp__rag-unified__search_memory, mcp__rag-unified__search_code, mcp__rag-unified__cross_project_search, mcp__rag-unified__list_projects]
|
||||
skills:
|
||||
- ef-core-migration
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name: implementer-frontend
|
||||
description: |
|
||||
WRITE specialist cho FE 2 app SOLUTION_ERP (fe-admin + fe-user React 19 + Vite 8 + TS 6 + shadcn/ui + TanStack Query). Cookie-cutter mirror page/types/component cross-app SHA256 IDENTICAL + Pattern 16-bis 4-place mirror (page + App.tsx route + menuKeys.ts + Layout.tsx staticMap) + declarative KIND_CONFIG Record + npm build × 2 verify. Case 1+2 only (cookie-cutter mirror cross-app, multi-file independent). DO NOT touch .NET backend (đó là implementer-backend). DO NOT schema/UX flow decision (em main solo). Auto-refuses out-of-scope.
|
||||
model: claude-opus-4-8
|
||||
model: inherit
|
||||
tools: [Read, Edit, Write, Bash, Skill, Grep, Glob, mcp__rag-unified__search_memory, mcp__rag-unified__search_code, mcp__rag-unified__cross_project_search, mcp__rag-unified__list_projects]
|
||||
skills:
|
||||
- permission-matrix
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name: investigator-api
|
||||
description: |
|
||||
Read-only EXTERNAL research specialist for SOLUTION_ERP. WebFetch/WebSearch official docs (Anthropic engineering, .NET 10 / EF Core 10 / ASP.NET, React 19 / Vite 8 / TanStack Query, shadcn/ui), NuGet + npm CVE/dependency eval, FE library evaluation (license + bundle size impact — vd FullCalendar v6 MIT verify), reference project pattern audit (NamGroup / DH_Y_DUOC / BVAAU cross-project), community sentiment research. EXTERNAL-focused — KHÔNG audit internal codebase or SQL schema (đó là investigator-codebase). NEVER writes code — only returns concise structured findings with source URLs.
|
||||
model: claude-opus-4-8
|
||||
model: inherit
|
||||
tools: [Read, Bash, WebFetch, WebSearch, mcp__rag-unified__search_memory, mcp__rag-unified__search_code, mcp__rag-unified__cross_project_search, mcp__rag-unified__list_projects]
|
||||
skills:
|
||||
- dependency-audit-erp
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name: test-specialist
|
||||
description: |
|
||||
WRITE specialist DEDICATED test layer SOLUTION_ERP (tests/SolutionErp.Domain.Tests + Infrastructure.Tests). xUnit + FluentAssertions 7.2 + EF SQLite TestApplicationDbContext (nvarchar(max)→TEXT override) + IdentityFixture. Domain policy state machine test + Infra code generator + CQRS handler test + reflection-based Authorize policy regression + UNIQUE/Conflict/soft-delete invariant. Test-before BẮT BUỘC cho bug fix + critical algo (codegen/guard/financial/security). DO NOT touch production code (Domain/App/Infra/Api/FE — đó là 2 implementer). Auto-refuses out-of-scope.
|
||||
model: claude-opus-4-8
|
||||
model: inherit
|
||||
tools: [Read, Edit, Write, Bash, Grep, Glob, mcp__rag-unified__search_memory, mcp__rag-unified__search_code, mcp__rag-unified__cross_project_search, mcp__rag-unified__list_projects]
|
||||
skills:
|
||||
- contract-workflow
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
name: tooling-auditor
|
||||
description: |
|
||||
Read-only INFORM-only TOOLING-FRESHNESS auditor cho SOLUTION_ERP (H1 — adopt AI_INFRA Harness 1, anh giao 2026-06-07; TÁCH BIỆT khỏi harvest-curator H2 vì 2 việc hay quên+nhầm khi gộp). Audit 4-MẶT mỗi session có cập-nhật ĐẦY-ĐỦ + KỊP-THỜI không: (1) skill (.claude/skills/ 6 project + ~/.claude/skills standalone — mới/đổi/stale/đã-map-vai chưa) · (2) vai-trò sub-agent (.claude/agents/ roster khớp README/CLAUDE.md/STATUS · thừa/idle/scope-drift) · (3) plugin (~/.claude/settings.json enabledPlugins user-global · installed/enabled/assigned/used) · (4) docs (CLAUDE.md·docs/STATUS·agents/README·governance phản-ánh trạng-thái THẬT · drift doc-vs-reality). Lifecycle: @session-start BÁO state + diff-vs-last (THÊM/ĐỔI/XÓA/stale); @session-end CHỐT freshness + AUDIT skill/plugin MỚI phân-bổ (new-alloc) cho em main + sub. Propose-only — em main single-writer (VERIFY→APPEND B3). KHÔNG harvest-memory (đó là harvest-curator). KHÔNG corpus/RAG/deploy (đó là cicd-monitor). KHÔNG store_memory. PHẢI dùng khi audit tooling/docs-freshness + skill/plugin-state + roster-drift đầu/cuối session.
|
||||
model: claude-opus-4-8
|
||||
model: inherit
|
||||
tools: [Read, Grep, Glob, Bash, mcp__rag-unified__search_memory, mcp__rag-unified__search_code, mcp__rag-unified__cross_project_search, mcp__rag-unified__list_projects]
|
||||
memory: project
|
||||
maxTurns: 18
|
||||
|
||||
@ -17,7 +17,7 @@ Skill này là tài liệu chuyên biệt để Claude (và developer khác) dù
|
||||
| Skill | Mục đích | Trigger ví dụ | Trạng thái |
|
||||
|---|---|---|---|
|
||||
| `dependency-audit-erp` | Scan CVE NuGet + npm 2 FE, respect pin constraint (MediatR 12.4.1, Swashbuckle 6.9.0) | "npm audit", "dotnet vulnerable", "deps scan", "nâng cấp package" | ✅ New Tier 3 |
|
||||
| `ef-core-migration` | Tạo/revert EF Core 10 migration, 3-file rule, DesignTimeDbContextFactory, **50 migration history** (Init → ReplaceBudgetModuleWithPeWorkItemBudgets Mig 50) | "thêm migration", "EF migration", "schema update", "snapshot lỗi" | ✅ Updated S61 (Mig 50 Budget→PeWorkItemBudgets) |
|
||||
| `ef-core-migration` | Tạo/revert EF Core 10 migration, 3-file rule, DesignTimeDbContextFactory, **52 migration history** (Init → AddHoSoLinkToPurchaseEvaluation Mig 52) | "thêm migration", "EF migration", "schema update", "snapshot lỗi" | ✅ Updated S65 (Mig 51 Department.ParentId + Mig 52 PE HoSoLink) |
|
||||
| `iis-deploy-runbook` | 3 IIS site + win-acme cert + gitea-runner + LibreOffice + debug 500/502/SignalR prod + **G-084 IPv4/IPv6 hardening** | "prod 500", "IIS fail", "cert hết hạn", "restart app pool", "deploy IIS", "port hijack" | ✅ Updated (G-084) |
|
||||
|
||||
## Format chuẩn 1 skill
|
||||
@ -87,5 +87,5 @@ when-to-use:
|
||||
## Related
|
||||
|
||||
- `docs/CLAUDE.md` — quick rules + full stack context
|
||||
- `docs/gotchas.md` — 64 bẫy đã gặp (latest #64 `dotnet ef database update` áp Design-DB 0-rows ≠ Dev-DB → data-migrate untested-before-prod, S61; #63 EF scaffold RenameColumn sai-semantics)
|
||||
- `docs/gotchas.md` — 65 bẫy đã gặp (latest #65 build csproj con ≠ `dotnet build SolutionErp.slnx` (gồm tests) → miss test-compile khi đổi chữ ký record command → CI CS7036 FAIL-gated, S65; #64 `dotnet ef database update` áp Design-DB 0-rows ≠ Dev-DB → data-migrate untested-before-prod)
|
||||
- `docs/changelog/migration-todos.md` — roadmap 5 phase + Tier 3
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: ef-core-migration
|
||||
description: Tạo/sửa/revert EF Core 10 migration cho SOLUTION_ERP. Dùng khi thêm entity mới, thay đổi schema, rollback migration, debug DesignTimeDbContextFactory fail. Đã có 50 migration sẵn (Init → ReplaceBudgetModuleWithPeWorkItemBudgets Mig 50, S61). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ.
|
||||
description: Tạo/sửa/revert EF Core 10 migration cho SOLUTION_ERP. Dùng khi thêm entity mới, thay đổi schema, rollback migration, debug DesignTimeDbContextFactory fail. Đã có 52 migration sẵn (Init → AddHoSoLinkToPurchaseEvaluation Mig 52, S65). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ.
|
||||
when-to-use:
|
||||
- "thêm migration"
|
||||
- "EF Core migration"
|
||||
@ -16,7 +16,7 @@ when-to-use:
|
||||
|
||||
> **Context:** .NET 10 + EF Core 10 + SQL Server. DbContext: `ApplicationDbContext` ở `Infrastructure/Persistence/`. Startup: `SolutionErp.Api`.
|
||||
|
||||
## Migration history (50 migration hiện có)
|
||||
## Migration history (52 migration hiện có)
|
||||
|
||||
| # | Name | Tables added / changed |
|
||||
|---|---|---|
|
||||
@ -70,8 +70,10 @@ when-to-use:
|
||||
| **48** | **`AddProjectMasterFields`** | **🎯 S55 — Project +4 cột nullable (Year int · Investor 250 · Location 500 · Package 300). AddColumn-only, no new table. Kèm `SeedRealMasterDataAsync` ungated nạp 62 dự án + 71 hạng mục + 3 NCC real từ Excel.** |
|
||||
| **49** | **`AddWorkItemToPurchaseEvaluation`** | **🎯 S57bis — PE.WorkItemId `Guid?` loose-Guid (KHÔNG FK vật lý — convention PE: ProjectId/SelectedSupplierId đều loose) + `IX_PurchaseEvaluations_WorkItemId`. AddColumn+CreateIndex-only, no new table. Guard = validator NotEmpty (create) + handler AnyAsync IsActive→Conflict.** |
|
||||
| **50** | **`ReplaceBudgetModuleWithPeWorkItemBudgets`** | **🎯 S61 (2026-06-13) — bảng mới `PeWorkItemBudgets` (1 record/cặp Dự án × Hạng mục, UNIQUE filtered `[IsDeleted]=0`) + **DROP module Budget cũ** (Budgets/BudgetDetails/BudgetApprovals/BudgetChangelogs…) + PE/Contracts DROP `BudgetId` + **backfill `BudgetManualAmount→BudgetPeriodAmount` TRƯỚC DropColumn** (phiếu UAT giữ số) + DELETE menu/permission `Bg_*` IN-list children-first. ⚠️ database-agent advise: KHÔNG FK vật lý PE/Contracts→Budgets → no DropForeignKey · DropIndex TRƯỚC DropColumn (SQL 5074) · IN-list thay LIKE `Bg_%`. Ngân sách giờ per-gói-thầu nhập theo role PRO/CCM. **gotcha #63** (EF scaffold RenameColumn SAI-semantics → Add+UPDATE+Drop) + **#64** (`dotnet ef database update` áp Design-DB 0-rows ≠ Dev-DB → backfill chạy thật lần đầu trên prod).** |
|
||||
| **51** | **`AddDepartmentParentId`** | **🎯 S65 — Department.ParentId `Guid?` loose-Guid (KHÔNG FK vật lý — org-tree phân cấp; `GET /departments/tree` ráp cây in-memory + rollup count theo `User.DepartmentId` + cycle-guard HashSet chặn tự-cha + vòng A→B→A). AddColumn-only, no new table.** |
|
||||
| **52** | **`AddHoSoLinkToPurchaseEvaluation`** | **🎯 S65 — PE.HoSoLink `nvarchar(1000)?` hyperlink NAS (mục "e. Link hồ sơ", FE `<a target=_blank rel=noopener>` null-safe). AddColumn-only, no new table.** |
|
||||
|
||||
Total: **88 bảng** dbo + `__EFMigrationsHistory` (re-ground S62 cicd `sys.tables` — last Mig 50 ReplaceBudgetModuleWithPeWorkItemBudgets: DROP module Budget + CREATE PeWorkItemBudgets → net 93→88). Xem `docs/database/schema-diagram.md` migration table + §11-15 module ERD (§16+ Mig 27-50 chi tiết pending).
|
||||
Total: **88 bảng** dbo + `__EFMigrationsHistory` (re-ground S62 cicd `sys.tables`; last Mig 50 net 93→88 — Mig 51+52 đều AddColumn-only, không đổi số bảng). Xem `docs/database/schema-diagram.md` migration table + §11-15 module ERD (§16+ Mig 27-52 chi tiết pending).
|
||||
|
||||
## N-stage workflow pattern (Mig 18-20 — Session 12-13)
|
||||
|
||||
@ -279,7 +281,7 @@ sqlcmd -S .\SQLEXPRESS -d SolutionErp -U vrapp -P <pw> -i migrate.sql
|
||||
|
||||
## Code pointers
|
||||
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/ApplicationDbContext.cs` — DbSet cho 88 bảng (50 migration)
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/ApplicationDbContext.cs` — DbSet cho 88 bảng (52 migration)
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/DesignTimeDbContextFactory.cs` — EF tooling factory
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/DbInitializer.cs` — seed + warn + migrate runtime + backfill (idempotent reconcile pattern)
|
||||
- `src/Backend/SolutionErp.Infrastructure/Persistence/Configurations/` — IEntityTypeConfiguration<T> per entity
|
||||
@ -288,5 +290,5 @@ sqlcmd -S .\SQLEXPRESS -d SolutionErp -U vrapp -P <pw> -i migrate.sql
|
||||
## Related
|
||||
|
||||
- `docs/database/database-guide.md` — conventions + migration workflow chi tiết
|
||||
- `docs/database/schema-diagram.md` — **ERD 88 bảng** + §11 PE + §12 ~~Budget~~ (REMOVED Mig 50) + §13 PEDeptOpinions (Mig 15) + §14 ApprovalWorkflow V2 (Mig 22-25) + §15 PE Level Opinions V2 (Mig 26); §16+ Mig 27-50 detail pending (xem migration table)
|
||||
- `docs/database/schema-diagram.md` — **ERD 88 bảng** + §11 PE + §12 ~~Budget~~ (REMOVED Mig 50) + §13 PEDeptOpinions (Mig 15) + §14 ApprovalWorkflow V2 (Mig 22-25) + §15 PE Level Opinions V2 (Mig 26); §16+ Mig 27-52 detail pending (xem migration table)
|
||||
- `docs/gotchas.md` #7, #17, #38 — migration pitfalls + Identity 4-field rename
|
||||
|
||||
@ -26,21 +26,21 @@ const VALID_ROLES = [
|
||||
'database-agent', // +S57 — S56 dùng 3× qua fail-soft WARN; read-advisory DB lens (DB1-DB11)
|
||||
]
|
||||
|
||||
// ─── H4.5 two-tier model (Harness-4 adopt 2026-06-10) ───────────────────────
|
||||
// Promote-list (gate/verdict-class — frontmatter `model: inherit` = ăn Fable 5 1M từ lead):
|
||||
// investigator-codebase (H4.3b) · reviewer (H4.3a) · database-agent (H4.3b).
|
||||
// [harvest-curator (H4.3c) cũng promote nhưng là monitor — không fan-out qua hmw.]
|
||||
// Demoted roles còn lại: frontmatter ĐÃ pin `claude-opus-4-8` → hmw KHÔNG set model (frontmatter tự lo).
|
||||
// Role-less (H6.2 governed-ultracode adopt S63): default = inherit lead-model (top-tier) — KHÔNG pin rẻ làm default.
|
||||
// Sweep/cost → per-task tier:'opus' escape-hatch (KHÔNG còn default 'opus'). Per-task tier:'fable' = force lead-tier khi hệ-trọng.
|
||||
// ─── H8 all-inherit top-tier (Harness-8 adopt 2026-06-16 — thay thế two-tier H4.5) ──
|
||||
// MỌI sub-agent có memory → frontmatter `model: inherit` = ăn top-tier lead (hiện Opus 4.8 1M do
|
||||
// Fable suspended H5; tự lên Fable 5 khi về). KHÔNG còn demote-pin `claude-opus-4-8` (H4.5 đã gỡ).
|
||||
// hmw KHÔNG set model cho role-có-frontmatter → return undefined, frontmatter (inherit) tự lo.
|
||||
// Role-less (H6.2 governed-ultracode): default = inherit lead-model (top-tier) — KHÔNG pin rẻ làm default.
|
||||
// H8.2 "workflow nhanh nhất" = song song tối đa + xuất nhanh, KHÔNG hạ model làm rẻ.
|
||||
// Escape-hatch per-task tier:'opus' GIỮ cho sweep/cost (ngoại lệ có chủ đích); tier:'fable' = force lead-tier khi hệ-trọng.
|
||||
function resolveModel(role, rawRole, tier, i) {
|
||||
if (tier === 'fable' || tier === 'opus') return tier
|
||||
if (tier) log(`⚠️ hmw: tier "${tier}" lạ (task #${i}) → bỏ qua, dùng tier-map mặc định H4.5`)
|
||||
if (tier) log(`⚠️ hmw: tier "${tier}" lạ (task #${i}) → bỏ qua, dùng mặc định H8 (inherit top-tier)`)
|
||||
// Invalid-role (typo ∉ VALID_ROLES, WARN đã log ở caller) → fail-UP inherit Fable 5 — H4.5 "chưa-phân-loại
|
||||
// → nghiêng quality" (KHÔNG rơi 'opus': task có thể là gate-class gõ nhầm tên role).
|
||||
if (!role && rawRole) return undefined
|
||||
if (!role) { log(`hmw: task #${i} role-less → inherit lead-model (H6.2 governed-ultracode; per-task tier:'opus' = escape-hatch sweep/cost)`); return undefined }
|
||||
return undefined // role có frontmatter: promote=inherit Fable 5 · demoted=pin Opus 4.8 — KHÔNG override
|
||||
return undefined // role có frontmatter: tất cả `inherit` (H8 all-inherit top-tier) — KHÔNG override
|
||||
}
|
||||
|
||||
const SCHEMA = {
|
||||
@ -91,7 +91,7 @@ const wave = (A.wave && A.wave.dir) ? A.wave : null
|
||||
if (wave) log(`hmw: WAVE-MODE on → dir=${wave.dir} (sub ghi sub-MD isolated; em main scaffold @P1; H2 harvest-curator gom @session-end B5).`)
|
||||
|
||||
phase('Execute')
|
||||
log(`HMW P2: fan-out ${A.taskList.length} task (${wave ? 'WAVE-MODE' : 'return-delta-only'}, two-tier H4.5 promote-inherit/demoted-opus, memory-pack-injected, scope=SOLUTION_ERP repo only)`)
|
||||
log(`HMW P2: fan-out ${A.taskList.length} task (${wave ? 'WAVE-MODE' : 'return-delta-only'}, H8 all-inherit top-tier, memory-pack-injected, scope=SOLUTION_ERP repo only)`)
|
||||
|
||||
const results = await parallel(A.taskList.map((t, i) => () => {
|
||||
const raw = t && t.role
|
||||
@ -137,7 +137,7 @@ const results = await parallel(A.taskList.map((t, i) => () => {
|
||||
agentType: role || undefined,
|
||||
schema: SCHEMA,
|
||||
label: (t && t.label) || `hmw:${role || 'task'}-${i}`,
|
||||
model: resolveModel(role, raw, t && t.tier, i), // H4.5 two-tier (undefined = theo frontmatter/inherit)
|
||||
model: resolveModel(role, raw, t && t.tier, i), // H8 all-inherit (undefined = theo frontmatter = inherit)
|
||||
})
|
||||
}))
|
||||
|
||||
|
||||
@ -128,9 +128,9 @@ Quy tắc:
|
||||
| [`docs/workflow-contract.md`](docs/workflow-contract.md) | State machine 9 phase HĐ + role matrix |
|
||||
| [`docs/forms-spec.md`](docs/forms-spec.md) | Catalog 8 form + quy định mã HĐ RG-001 |
|
||||
| [`docs/database/database-guide.md`](docs/database/database-guide.md) | DB conventions + migration workflow + cheatsheet |
|
||||
| [`docs/database/schema-diagram.md`](docs/database/schema-diagram.md) | ⭐ ERD + luồng DB + data flow 88 table (+ §11 PE + §12 ~~Budget~~ DROP + §13 PEDeptOpinions + §14 Contract V2 LevelOpinions; §16+ Mig 32-50 pending) |
|
||||
| [`docs/database/schema-diagram.md`](docs/database/schema-diagram.md) | ⭐ ERD + luồng DB + data flow 88 table (+ §11 PE + §12 ~~Budget~~ DROP + §13 PEDeptOpinions + §14 Contract V2 LevelOpinions; §16+ Mig 32-52 pending) |
|
||||
| [`docs/flows/README.md`](docs/flows/README.md) | Index 6 flow (auth, permission, contract, form, SLA) |
|
||||
| [`docs/gotchas.md`](docs/gotchas.md) | ⭐ 64 bẫy đã gặp — đọc trước khi debug tương tự |
|
||||
| [`docs/gotchas.md`](docs/gotchas.md) | ⭐ 65 bẫy đã gặp — đọc trước khi debug tương tự |
|
||||
| [`.claude/skills/`](.claude/skills/README.md) | 6 skill: contract-workflow, form-engine, permission-matrix, dependency-audit-erp, ef-core-migration, iis-deploy-runbook |
|
||||
| [`docs/guides/vps-setup.md`](docs/guides/vps-setup.md) | ⭐ Master runbook deploy VPS shared với VIETREPORT |
|
||||
|
||||
|
||||
@ -23,3 +23,4 @@
|
||||
| 2026-06-11 | 2026-06-11-se-to-ai_infra-harness-4-runtime-verified | se → ai_infra | outbox/ai_infra | ecf1d58797af |
|
||||
| 2026-06-15 | 2026-06-15-se-to-ai_infra-harness-5-6-adopt-report | se → ai_infra | outbox/ai_infra | 8a247984df9f |
|
||||
| 2026-06-15 | 2026-06-15-se-to-ai_infra-harness-7-adopt-report | se → ai_infra | outbox/ai_infra | 7e4f91f1ff7f |
|
||||
| 2026-06-16 | 2026-06-16-se-to-ai_infra-harness-8-adopt-status | se → ai_infra | outbox/ai_infra | fa7f690d9ce6 |
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
---
|
||||
id: 2026-06-16-se-to-ai_infra-harness-8-adopt-status
|
||||
from: se
|
||||
to: ai_infra
|
||||
category: Governance
|
||||
type: report
|
||||
date: 2026-06-16
|
||||
content_sha256: fa7f690d9ce6b6dfba659069802ab31f6f3b5753d7d7f2181c064a978b749889
|
||||
nac: sent
|
||||
---
|
||||
|
||||
# [se → ai_infra] Báo nấc adopt Harness-8 (all-inherit + workflow-fastest)
|
||||
|
||||
Chào đội AI_INFRA,
|
||||
|
||||
SOLUTION_ERP (sister `se`) đã áp broadcast `2026-06-16-Governance-harness-8-all-inherit-workflow-fastest`. Đây là báo cáo nấc trạng thái thật theo yêu cầu SELF-CHECK của broadcast.
|
||||
|
||||
## Nấc: executed-file · VERIFIED-pending-restart
|
||||
|
||||
Các file đã được đổi trên đĩa, nhưng frontmatter agent không nạp nóng giữa phiên, nên cần restart Claude Code CLI thì runtime mới có hiệu lực. Em chưa spawn-test, do đó không claim verified-runtime.
|
||||
|
||||
## Đã làm (tailored theo roster thật 11 sub của SE)
|
||||
|
||||
- **H8.1 — flip 7 sub demoted sang `inherit`:** trước H8, SE theo Harness-4 two-tier (4 sub promote `inherit` + 7 sub demote pin `claude-opus-4-8`). Em đã đổi frontmatter `model:` của đúng 7 sub bị pin sang `inherit`: implementer-backend, implementer-frontend, test-specialist, cicd-monitor, investigator-api, frontend-designer, tooling-auditor. Bốn sub vốn đã `inherit` (reviewer, investigator-codebase, database-agent, harvest-curator) giữ nguyên. Kết quả: cả 11/11 sub đều là `model: inherit`. Frontmatter dùng `inherit` thuần, không có hậu tố `[1m]` (giữ gotcha #37).
|
||||
- **SE không có lớp helper/gopher rẻ:** cả 11 sub đều là vai substantive có memory, nên không có vai nào được chừa lại ở model rẻ — cả 11 lên top-tier. Ngoại lệ helper trong broadcast không có đối tượng áp dụng tại SE; đây là điều đã nêu rõ, không phải thiếu sót.
|
||||
- **H8.2 — workflow fastest:** đã codify rule "song song tối đa + xuất nhanh + lead auto-HMW cho tác vụ đáng kể, KHÔNG hạ model làm rẻ". Cơ chế lead auto-HMW đã sẵn từ Harness-6 (governed-ultracode). Escape-hatch per-task `tier:'opus'` trong `hmw.js` được giữ cho nhu cầu sweep/cost.
|
||||
- **Codify canonical:** `agents/README.md` (cập nhật header + thêm mục Upgrade S66 đánh dấu thay thế two-tier Harness-4 + chú thích sơ đồ) và cập nhật comment `hmw.js` (logic `resolveModel` vốn đã defer theo frontmatter, nên flip frontmatter sang `inherit` là tự lan, không cần đổi logic).
|
||||
|
||||
## Caveat (trung thực, không nói quá)
|
||||
|
||||
Runtime hiện tại chưa đổi: top-tier khả dụng lúc này là Opus 4.8 (1M) do Fable đang tạm ngưng theo Harness-5, nên `inherit` hiện thời chính là Opus 4.8 (1M), trùng đúng trạng thái two-tier đã collapse từ S63. Khác biệt thật (cả đội ăn Fable 5) chỉ xuất hiện khi Fable trở lại, lúc đó cả 11 sub tự lên Fable 5 mà không cần sửa lại frontmatter. Một điểm cộng kèm theo: việc khôi phục Fable theo H5.6 giờ gọn hơn — chỉ cần đổi lead về Fable 5, không phải sửa frontmatter từng sub nữa.
|
||||
|
||||
## Tham chiếu
|
||||
|
||||
adap-report đầy đủ ở repo SE: `docs/governance/adap-reports/2026-06-16-Governance-harness-8-all-inherit-workflow-fastest.md`.
|
||||
|
||||
Trân trọng,
|
||||
se (SOLUTION_ERP)
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,54 @@
|
||||
# S66 (2026-06-16) — Session-start/end closeout: adopt Harness-8 all-inherit + cicd-monitor L1 curate + ef-core doc-flush + check-email AI_INFRA
|
||||
|
||||
> **em-main-solo, 0 product-sub spawn** (chỉ 2 monitor INFORM-only @session-start). ~17 file docs/gov/config, **0 production code** → state THẬT giữ nguyên (Mig 52 · 88 bảng · 263 test · 65 gotcha · menu 53 · bundle `BDwV5d0X`/`DbVv6rsf`). HMW-mode ON nhưng mọi việc = governance-authoring single-writer → solo (đúng H6.1: governance-authoring TRIVIAL → solo, KHÔNG fan-out).
|
||||
|
||||
**Luồng anh:** `/session-start` → bootstrap (2 monitor RE-REPORT) → anh chọn "cicd-monitor curate (P1 GẤP)" → `/check-email AI_INFRA /adap-apply` → `/session-end`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Bootstrap (`/session-start`)
|
||||
|
||||
- **Mode:** HMW-mode ON (marker `.claude/hmw-mode.on`). **Lead model:** Opus 4.8 (1M) Max — H5 fallback (Fable suspended 2026-06-12 no-ETA), đúng-kỳ-vọng.
|
||||
- **RAG:** `proj_solution_erp` alive, chunk 2425 (+2 vs S63), index stale 05-29 (known, AI_INFRA op).
|
||||
- **2 monitor RE-REPORT (background spawn):**
|
||||
- 🟫 **H1 tooling-auditor:** roster 11=11=11 + two-tier frontmatter intact + plugin 18/15/3 unchanged + 0 new-alloc. Canonical docs (STATUS/HANDOFF/root-CLAUDE counts) đã flush đúng S65. **Drift:** `ef-core-migration` SKILL stuck Mig 50 (TRUE 52) ×5 cites + `skills/README.md` ×2 + root `CLAUDE.md` gotcha 64→65. 0 GẤP.
|
||||
- ⬜ **H2 harvest-curator:** 0 orphan (S65 PE fan-out `pe-hoso-link-rename-pro` fully harvested + committed, incl 2 empty-return subs implementer-frontend:45 + reviewer:64). 0 corruption (AS-8 clean). Fidelity PASS (HoSoLink + Mig 51/52 ground-truthed on disk). **🔴 cicd-monitor L1 86.8KB (2.9× cap) P1 GẤP** + embedded guard: #383 (`:106`) là entry `[⚠️ VỊ TRÍ LẠC]` thật (KHÔNG phải #291 như brief tưởng).
|
||||
|
||||
## 2. H1 doc-flush (3 file, verified-from-disk trước khi sửa — B3)
|
||||
|
||||
- `.claude/skills/ef-core-migration/SKILL.md` ×5: frontmatter + header 50→52, **+Mig 51/52 rows** (`AddDepartmentParentId` + `AddHoSoLinkToPurchaseEvaluation`), Total note (88 giữ — cả 2 AddColumn), 2 code-pointer 27-50→27-52.
|
||||
- `.claude/skills/README.md` ×2: ef-core row 50→52/S65, gotcha 64→65 (+#65).
|
||||
- root `CLAUDE.md` ×2: gotcha cite 64→65, schema-diagram pending 32-50→32-52.
|
||||
|
||||
## 3. cicd-monitor L1 curate 86.8→28.9KB (P1 GẤP — anh chọn task đầu)
|
||||
|
||||
- **Map (đọc full 113 dòng):** KEEP head `1-77` (baseline + FIFO header + 6 runs 06-16 #289-#295); ARCHIVE body `78-107` (#286 06-13 → #232 pointer S29); KEEP footer `108-113` (Curate-trigger).
|
||||
- **2 anomaly resolved:** #291 (06-16 FAIL `:89`) — content đã narrate inline trong #292 (`:74`) + canonical gotcha #65 → archive (non-orphan). #383 (`:106` `[⚠️ VỊ TRÍ LẠC]`) — archive đúng vị trí.
|
||||
- **Method = byte-exact `sed` move** (KHÔNG retype → 0 transcription-corruption của file critical 86KB): build `.new` + archive qua `sed -n '78,107p'`, sanity-grep (6 runs kept · 1 "leak" = #292-inline-#291 benign · archive có #291+#383), inspect head/tail, RỒI swap (`mv`). 0-byte guard PASS.
|
||||
- **3 essentials-fix sau swap** (targeted Edit, baseline pristine): `:51` Mig latest 50→52 · `:53` bundle-live S69→S70 #295 (`DbVv6rsf`) · `:84` curate-log +S66 entry.
|
||||
- **Final:** L1 28.9KB (66% giảm, dưới 30KB soft-cap) + archive 58.4KB/29 records. 5 structural section verified intact. **Reliability fix** thật: spawn auto-inject ~25KB cap → trước chỉ ~30% file inject (oldest runs ở tail không load); giờ baseline + current-session inject đủ.
|
||||
|
||||
## 4. check-email AI_INFRA + adopt Harness-8 (`/adap-apply`)
|
||||
|
||||
- **check-email:** `outbox/se/` chỉ có UI/UX guide (đã processed S58, ở `inbox/ai_infra/`). **0 thư mới se-directed.** Phát hiện broadcast MỚI trong `outbox/all`: `2026-06-16-Governance-harness-8` (chưa trong adap-reports — reports dừng harness-7).
|
||||
- **Harness-8 (🔴 BẮT BUỘC mọi sister, reviewer_gate PASS_WITH_FIXES, PROJECT-FIT 6/6):**
|
||||
- **H8.1** — toàn bộ sub-agent có memory → `model: inherit`, gỡ demote two-tier H4. SE flip **7 sub** pin `claude-opus-4-8` → `inherit`: implementer-backend/-frontend, test-specialist, cicd-monitor, investigator-api, frontend-designer, tooling-auditor. 4 sub vốn inherit (reviewer, investigator-codebase, database-agent, harvest-curator) giữ. **grep xác nhận cả 11/11 = inherit.** SE không có helper/gopher rẻ → cả 11 lên top-tier.
|
||||
- **H8.2** — workflow nhanh nhất = song song tối đa + xuất nhanh + lead auto-HMW (H6), KHÔNG hạ model. Escape-hatch per-task `tier:'opus'` (hmw.js) giữ.
|
||||
- **Codify:** `agents/README.md` (header all-inherit + mục Upgrade S66 đánh dấu thay thế two-tier H4 + ASCII caption) · `hmw.js` 5 chỗ comment (logic `resolveModel` vốn `return undefined` cho role-có-frontmatter → defer frontmatter → flip là tự lan, KHÔNG đổi logic).
|
||||
- **adap-report** `docs/governance/adap-reports/2026-06-16-Governance-harness-8-all-inherit-workflow-fastest.md`.
|
||||
- **email-back** `broadcasts/outbox/ai_infra/2026-06-16-se-to-ai_infra-harness-8-adopt-status.md` — content_sha256 `fa7f690d…` tính UTF-8-explicit + **round-trip VERIFY MATCH** (gotcha #61 handled). `_index.md` OUTBOUND +1 row.
|
||||
- **Nấc:** executed-file · VERIFIED-pending-restart (frontmatter no hot-reload). Caveat: runtime chưa đổi (inherit=Opus 4.8 1M vì Fable down H5 — trùng two-tier đã collapse); khác biệt thật khi Fable về (cả đội tự lên Fable 5, không sửa frontmatter) + H5.6 restore gọn hơn (chỉ đổi lead).
|
||||
|
||||
## 5. §L AUTO-MAINTAIN
|
||||
|
||||
- **§L.a (AS-1..AS-9):** 0 RCA mới. No bug-production, no destructive, no mis-stamp (email hash MATCH). Lone Bash `wc -c` quoting-hiccup tự-recover, không phải AS-class.
|
||||
- **§L.b:** (a) STATUS Recently Done +S66 · (b) Active-Guards no change · (c) chore-flag: cicd 28.9KB ✅ giờ; inv-codebase 36.4KB + reviewer 36KB còn over (defer per H2); 0-byte clean · (d) 2 monitor spawn-record on-behalf APPEND (read-only không tự ghi) · (e) pending-request anh có SPECIFICS (tzutil/Chương/staff-pw/CNTT + restart-CLI) · (f) harvest GATE **PASS 5/5**, no wave-folder · (g) tooling CHỐT: roster model-tier ĐỔI (H8 all-inherit) + doc-flush, 0 new-alloc.
|
||||
|
||||
## 6. Lessons
|
||||
|
||||
- **Curate file critical lớn = byte-exact `sed` line-slice, KHÔNG Write-reconstruct.** Write reproduce baseline 86KB = transcription-corruption risk (fail-unsafe); `sed -n 'a,bp'` move byte-exact + build-.new-rồi-swap = fail-safe + 0 corruption. → memory `feedback_large_memory_curate_byte_exact`.
|
||||
- **`inherit` mechanism = data-driven, code-agnostic:** "two-tier" chỉ là ảo giác do data (7 file pin model rẻ), KHÔNG phải code rẽ nhánh. `hmw.js resolveModel` defer frontmatter (`return undefined`) → flip 7 dòng `model:` là cả spawn-trực-tiếp + spawn-qua-workflow cùng lên top-tier. Migration "rất gọn".
|
||||
- **H2 brief có thể nhầm chi tiết** (#291 vs #383 annotation) — em main đọc full file ground-truth trước khi act (B3 verify-before-write), bắt được #383 mới là entry `[VỊ TRÍ LẠC]` thật.
|
||||
|
||||
## 7. Commit
|
||||
Xem Phase 5 closeout — commit chain `[CLAUDE] Skill/Docs: S66 ...`. CI: chỉ `hmw.js` non-ignored (`.claude/skills/**`+`**/*.md` ignored) → push trigger CI 1 run (range-based gotcha #41), no-op deploy (hmw.js không thuộc slnx/FE build, bundles frozen).
|
||||
@ -0,0 +1,72 @@
|
||||
---
|
||||
id: 2026-06-16-Governance-harness-8-all-inherit-workflow-fastest
|
||||
from: ai_infra
|
||||
applied_by: se (SOLUTION_ERP)
|
||||
applied_date: 2026-06-16
|
||||
nac: executed-file · VERIFIED-pending-restart
|
||||
project_fit: 6/6 (áp trọn — không skip phần nào)
|
||||
source_content_sha256: cc1cedc06cd12c5daa8e2ca90fde55ba1216afeeecdc7a2137198d2100011d14
|
||||
---
|
||||
|
||||
# Adap-report — Harness-8 (all-inherit top-tier + workflow-fastest)
|
||||
|
||||
> SOLUTION_ERP (sister `se`) áp broadcast `2026-06-16-Governance-harness-8-all-inherit-workflow-fastest` của AI_INFRA. Đây là luật BẮT BUỘC (anh-chốt, mọi sister). Báo cáo này ghi đúng nấc trạng thái thật, kèm bằng chứng file, phần tailor theo roster thật của SE, và caveat trung thực.
|
||||
|
||||
## 1. Broadcast yêu cầu gì (FUNCTION-floor)
|
||||
|
||||
- **H8.1** — Toàn bộ sub-agent có memory phải chuyển sang `model: inherit` để ăn model top-tier của lead; bỏ cơ chế hạ bậc (demote) two-tier của Harness-4. Ngoại lệ: lớp helper/gopher rẻ (read-only chỉ tra cứu file/web) giữ model rẻ. Escape-hatch per-task vẫn cho hạ bậc cho một tác vụ cụ thể.
|
||||
- **H8.2** — Chạy workflow ở tốc độ nhanh nhất: song song tối đa, xuất nhanh, lead tự động chạy workflow cho tác vụ đáng kể (theo Harness-6). "Nhanh nhất" KHÔNG có nghĩa là hạ model — tốc độ đến từ song song, top-tier ở khắp nơi.
|
||||
|
||||
## 2. PROJECT-FIT — 6/6, áp trọn
|
||||
|
||||
SOLUTION_ERP dùng đầy đủ sub-agent (11 sub) và workflow (`hmw.js`), nên luật áp cho toàn bộ. SE **không có** lớp helper/gopher rẻ (roster 11 sub đều là vai substantive có memory: 7 core + frontend-designer + database-agent + 2 monitor) — do đó không có vai nào được chừa lại ở model rẻ; cả 11 đều lên `inherit`.
|
||||
|
||||
## 3. SE đã làm gì (tailored theo roster thật 11 sub)
|
||||
|
||||
### H8.1 — Flip 7 sub demoted → `inherit`
|
||||
Trước H8 (theo Harness-4 two-tier): 4 sub promote `inherit` + 7 sub demote pin `claude-opus-4-8`. SE đã đổi frontmatter `model:` của **đúng 7 sub bị pin** sang `inherit`:
|
||||
|
||||
| Sub-agent (flip) | File:line | Trước | Sau |
|
||||
|---|---|---|---|
|
||||
| implementer-backend | `.claude/agents/implementer-backend.md:5` | claude-opus-4-8 | inherit |
|
||||
| implementer-frontend | `.claude/agents/implementer-frontend.md:5` | claude-opus-4-8 | inherit |
|
||||
| test-specialist | `.claude/agents/test-specialist.md:5` | claude-opus-4-8 | inherit |
|
||||
| cicd-monitor | `.claude/agents/cicd-monitor.md:5` | claude-opus-4-8 | inherit |
|
||||
| investigator-api | `.claude/agents/investigator-api.md:5` | claude-opus-4-8 | inherit |
|
||||
| frontend-designer | `.claude/agents/frontend-designer.md:5` | claude-opus-4-8 | inherit |
|
||||
| tooling-auditor | `.claude/agents/tooling-auditor.md:5` | claude-opus-4-8 | inherit |
|
||||
|
||||
4 sub vốn đã `inherit` (reviewer · investigator-codebase · database-agent · harvest-curator) giữ nguyên. **Kết quả: cả 11/11 sub = `model: inherit`** (verify bằng `grep ^model: .claude/agents/` → 11 dòng `inherit`, 0 dòng `claude-opus-4-8`). Frontmatter dùng `inherit` thuần, KHÔNG có hậu tố `[1m]` (giữ gotcha #37).
|
||||
|
||||
### H8.2 — Workflow fastest
|
||||
Codify rule "chạy workflow nhanh nhất = song song tối đa + xuất nhanh + lead auto-HMW cho task substantive, KHÔNG hạ model". Cơ chế lead auto-HMW đã sẵn từ Harness-6 (governed-ultracode, mode-ON). Escape-hatch per-task `tier:'opus'` trong `hmw.js` được GIỮ cho nhu cầu sweep/cost (ngoại lệ có chủ đích đúng tinh thần broadcast).
|
||||
|
||||
### Codify canonical + đồng bộ engine
|
||||
- **`.claude/agents/README.md`** — rule canonical model-tier của SE (rules.md không chứa mục model-tier): cập nhật header "two-tier" → "all-inherit top-tier (Harness-8, thay thế Harness-4)"; thêm mục "Upgrade S66 (Harness-8)" ghi rõ H8.1 + H8.2 + đánh dấu thay thế two-tier; cập nhật chú thích sơ đồ ASCII. Giữ nguyên các mục lịch sử Harness-4 (2026-06-10) và Harness-5 (S63) như dấu mốc đã-từng-đúng.
|
||||
- **`.claude/workflows/hmw.js`** — cập nhật khối comment H4.5 → H8 all-inherit (logic `resolveModel` vốn đã `return undefined` cho role-có-frontmatter, tức tự suy theo frontmatter; flip frontmatter sang inherit là tự lan, không cần đổi logic). Cập nhật log-line + comment call-site.
|
||||
|
||||
## 4. Nấc trạng thái (G-011) — trung thực
|
||||
|
||||
**executed-file · VERIFIED-pending-restart.** Các file `.md` agent + `hmw.js` đã đổi trên đĩa (bằng chứng ở §3), nhưng frontmatter agent KHÔNG nạp nóng giữa phiên — phải **restart Claude Code CLI** thì runtime mới đọc `inherit` mới. Em CHƯA spawn-test nên KHÔNG claim "verified-runtime". Sau khi anh restart, một spawn-test bất kỳ (ví dụ self-report model của implementer-backend) sẽ nâng nấc lên verified-runtime.
|
||||
|
||||
## 5. SELF-CHECK của broadcast
|
||||
|
||||
- [x] Đã ghi luật Harness-8 vào nguồn rule canonical (`agents/README.md`), đánh dấu thay thế two-tier Harness-4.
|
||||
- [x] Mọi sub-agent đang pin model rẻ (7 sub) đã đổi sang `model: inherit`.
|
||||
- [x] Các vai vốn đã `inherit` (4 sub) giữ nguyên; SE không có helper/gopher rẻ nên không có vai nào cần chừa.
|
||||
- [x] Hiểu đúng "workflow nhanh nhất" = song song tối đa + xuất nhanh, KHÔNG hạ model (đã ghi rõ trong rule + comment hmw.js).
|
||||
- [x] Frontmatter `model` KHÔNG có hậu tố `[1m]` (gotcha #37) — dùng `inherit` thuần.
|
||||
- [x] Gửi email-back báo nấc trạng thái thật (executed-file, pending-restart) — xem §7.
|
||||
|
||||
## 6. Caveat (trung thực, không nói quá)
|
||||
|
||||
- **Runtime hiện tại KHÔNG đổi.** Top-tier khả dụng lúc này là Opus 4.8 (1M) vì Fable 5 đang tạm ngưng (Harness-5). Do đó `inherit` hiện thời = Opus 4.8 (1M), trùng đúng trạng thái two-tier đã collapse từ S63. Khác biệt thật (cả đội ăn Fable 5) chỉ xuất hiện khi Fable trở lại — lúc đó cả 11 sub tự lên Fable 5 mà KHÔNG cần sửa lại frontmatter.
|
||||
- **Bonus tương tác với H5.6:** việc khôi phục Fable (H5.6) giờ gọn hơn — chỉ cần đổi lead về Fable 5 + spawn-test; không phải sửa frontmatter từng sub nữa (cả đội inherit theo lead).
|
||||
- **Chi phí:** với SE, vì Fable đang down, chi phí runtime chưa tăng (vẫn Opus 4.8). Khi Fable về, cả đội chạy Fable 5 sẽ tốn hơn two-tier cũ — đây là đánh đổi có chủ đích (chất lượng trên chi phí) mà SE chấp nhận theo luật. Nếu chi phí thành vấn đề thật, SE sẽ surface qua adap-request.
|
||||
- **Phạm vi:** chỉ đổi file repo MÌNH (SE). Không đụng outbox AI_INFRA (read-only).
|
||||
|
||||
## 7. Email-back
|
||||
Đã gửi email-back cho AI_INFRA (`broadcasts/outbox/ai_infra/`) báo nấc executed-file + VERIFIED-pending-restart. (Xem `_index.md` §OUTBOUND.)
|
||||
|
||||
## 8. Phản biện / đề xuất nâng cấp
|
||||
Không có. Luật rõ ràng, viết roster-agnostic, áp thẳng vào SE không vướng. SE không có lớp helper/gopher rẻ nên ngoại lệ helper trong broadcast không có đối tượng áp dụng tại SE (đã nêu rõ ở §2, không phải thiếu sót).
|
||||
Reference in New Issue
Block a user