Anh chốt "public văn phòng số cho all user eoffice". Mở quyền Xem + Tạo (self-service) module Office cho mọi role trên cả 2 app. - NEW SeedAllRolesOfficeModulePermissionsAsync (DbInitializer): grant CanRead+CanCreate=true cho allow-list 16 key Office, chạy SAU RevokeTemporarilyHiddenModulesAsync để THẮNG revoke (mirror đúng pattern S65 HRM public). Upgrade-only: nâng false→true trên row prod đã có, KHÔNG hạ, KHÔNG đụng CanUpdate/CanDelete. No migration (seed-logic, idempotent). - ALLOW-LIST 16: Off + Off_Dashboard + Off_DanhBa + Off_PhongHop(View/Book) + Off_DeXuat(List/Create/Inbox) + Off_DonTu(Leave/Ot/Travel) + Off_DatXe + Off_ItTicket. - GIỮ ẨN (ngoài allow-list → revoke vẫn che non-Admin): Off_PhongHop_Manage (admin CRUD phòng), Off_AttendanceReport (báo cáo chấm công — riêng tư), Off_ChamCong (Cá nhân — golive riêng). HRM (trừ Hồ sơ NS S65) + Personal VẪN ẩn (anh chỉ mở Office). - reviewer PASS 0 blocker (security): cascade-safe (Off KHÔNG phải inherit-root trong GetMyMenuTree → excluded-3 giữ false, không lan); KHÔNG mở write-path thật (Office controller dùng [Authorize] self-service + [Authorize(Roles=Admin)] cho admin-write — CanCreate chỉ mở menu + nút tạo FE, API authz độc lập menu key; quản lý phòng double-protected). - +6 test OfficeModulePermissionSeedTests (286→292) lock: allow-list read+create=true · excluded-3 stay hidden (load-bearing) · admin not demoted · no-leak HRM/Personal · upgrade-only preserves admin-raised Update/Delete. - Build slnx 0/0 · dotnet test 292 PASS. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
52 KiB
CI/CD Monitor Agent — Persistent Memory
Persistent diary cross-session. Auto-injected first ~200 lines at spawn (L1 HOT). Update BEFORE every stop. Tiered Memory v1: L1 HOT soft-cap ~30KB · L2
archive/on-demand · L3 RAGsearch_memoryjust-in-time. Keep entry ≤ 1.5K chars (gotcha #53). Full verbatim run history pre-S40 → gitd2f52ba+archive/2026-05-{runs,q2,q3,q4}.md.
🎯 Role baseline
Read-only CI/CD + post-deploy verifier SOLUTION_ERP. Polls Gitea Actions API, verifies test gate + deploy ship + prod health. Tools: Read, Grep, Glob, Bash, WebFetch + 5 RAG MCP. Output: PASS/FAIL + evidence <500 words. Skills: iis-deploy-runbook + dependency-audit-erp + ef-core-migration. Spawn ~150K — trade-off catch fail tự động.
🚨 Recurring CI/CD bug patterns (catch priority)
- #39 act_runner github.com TCP timeout — run hang "Set up job" 21s. Log
dial tcp github.com:443 i/o timeout. Fix: manual checkout bypass hardcoded.gitea/workflows/deploy.yml(pass #110). KHÔNG revert. - #40 npm cache
tsc not found—build_fe_adminfail postcache: npm. DISABLED rolled backa21790d. KHÔNG re-enable. - #41 paths-ignore docs-only skip — code commit không trigger CI? Check
git diff --name-only HEAD~1 HEADvspaths-ignore: ['docs/**','**/*.md','.claude/skills/**']. Discovery #3: Gitea evaluates push range commits — nếu ≥1 commit có non-ignored file → toàn range build (BENEFICIAL). - #25 IIS WebSocket —
notification-hub/negotiate401/404 prod. Fix: WebSocket module enableweb.configsite api (skilliis-deploy-runbook). - #48 SQLite tie-break —
OrderByDescending(CreatedAt).First()pick wrong khi 2+.Add()cùng frozen-clock. Fix: discriminator filter.Where(Summary.Contains("Chuyển phase"))BEFORE OrderBy. - Bundle hash unchanged = ship FAIL — push+action success nhưng prod không đổi. Verify
curl -s https://admin.solutions.com.vn/ | grep -oE '/assets/index-[a-z0-9]+\.js'. Fix: SSHRestart-WebAppPool. ⚠️ Bundle hash verify MUST sau status=success (Run #242 false-positive lesson: check khi "running" → stale hash). - Migration drift prod vs repo — compare
ls .../Persistence/Migrations/*.csvssqlcmd __EFMigrationsHistory. Fix: checkProgram.csapp.MigrateDatabase()+ app pool recycle.
📋 5-stage checklist (EVERY run)
- Stage 0 RAG infra:
Get-Service QdrantRunning +http://localhost:6333/healthz. Collectionproj_solution_erp(prefixproj_*7 project — Discovery #8). - Stage 1 Push+filter:
git log -1 --format='%H %s'+git log origin/main..HEADempty + diff vs paths-ignore (docs-only → SKIPPED-DOCS return). - Stage 2 Gitea poll (max 10 iter × 60s): API
.../actions/tasks?limit=5(NOT/runs404). Matchhead_sha. ⚠️ task tableupdated_atstale ~2min (gotcha #46) → cross-check VPS mtime. - Stage 3 Test gate: baseline 130 PASS (58 Domain + 72 Infra). Phase 9 UAT exception lower OK (
feedback_uat_skip_verify). - Stage 4 Post-deploy (if SUCCESS): auth login bearer (admin + nv.test gotcha #44; token=
accessTokenroute/api/auth/login) → 3-5 endpoint smoke 2XX (incl new) → FE bundle hash 2 app changed → SignalR negotiate (gotcha #25 if relevant) → EF mig prod==repo.- Stage 4.6 (S29 CRITICAL): sqlcmd seed sample verify post-deploy (NOT chỉ schema).
sqlcmd -Q "SELECT Code FROM ApprovalWorkflows WHERE Code LIKE 'QT-%-V2-%'"→ 0 rows = seed GATE BLOCKED → gotcha #51. - Discovery #4: ASP.NET 10 record enum cần numeric input unless
JsonStringEnumConverter(SOL has NO converter → FE sends numeric). #5: sqlcmd ssh Windows-auth cần\\\\SQLEXPRESS4-backslash. #6: INFRASTRUCTURE seed (Roles/Depts/Catalogs/MenuTree/AdminPerms/Templates/SampleWorkflowsV2) MUST run, NOT insideif(!demoSeedDisabled); DEMO seed (DemoUsers/Contracts/PE) OK gated → gotcha #51.
- Stage 4.6 (S29 CRITICAL): sqlcmd seed sample verify post-deploy (NOT chỉ schema).
- Stage 5 Report PASS/FAIL + evidence + MEMORY update.
⚠️ Anti-patterns (DO NOT)
- ❌ Push fix code — READ only, escalate em main · 2. ❌ Speculate fail without log · 3. ❌ Skip post-deploy bundle hash (biggest catch) · 4. ❌ Skip MEMORY · 5. ❌ Poll forever (max 10 iter) · 6. ❌ Auto-rollback (escalate + recommend) · 7. ❌ Verify docs-only (SKIPPED-DOCS return ngay)
🧠 SOLUTION_ERP CI/CD essentials (S40 verified)
- Gitea:
git.baocaogiaoduc.vn/vietreport-admin/solution-erp· workflow.gitea/workflows/deploy.yml· paths-ignore['docs/**','**/*.md','.claude/skills/**'] - Prod: api/admin/eoffice
.solutions.com.vn· SSHssh vietreport-vps(Administrator, id_ed25519) · IIS site phys paths (S42 verified): APIC:\inetpub\solution-erp\api· admin\fe-admin· user\fe-user(3 sites Started). DB.\SQLEXPRESS/SolutionErp/vrappSQL-auth. Conn string key =ConnectionStrings.Default(NOTDefaultConnection!) — read pw from prod appsettings.Production.json when$env:PROD_DB_PASSWORDempty.- SSH→PS quoting (S42 lesson): nested bash→ssh→powershell mangles
$var/\". Useiconv UTF-16LE | base64→powershell -EncodedCommand $B64. Single-quote literal paths.
- SSH→PS quoting (S42 lesson): nested bash→ssh→powershell mangles
- Tests baseline: 263 PASS (S62 Run #286 sha
7926c21spec; 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 (tasksendpoint reports terminal asstatus:success,conclusionfield NOT populated). Local grep undercounts (Theory/InlineData) — trust CI conclusion. Phase 9 UAT mode skip per chunk OK. - Mig latest repo: Mig 52
20260616035929_AddHoSoLinkToPurchaseEvaluation(S65; PE +HoSoLink hyperlink-NAS, AddColumn-only no new table). Prev Mig 51AddDepartmentParentId(S65 Department.ParentId loose-Guid org-tree, AddColumn-only) + Mig 50ReplaceBudgetModuleWithPeWorkItemBudgets(S61 Budget→PeWorkItemBudgets net-reduce). Pathsrc/Backend/SolutionErp.Infrastructure/Persistence/Migrations/(52 mig .cs non-designer total). Prod checksqlcmd __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) · UATnv.test@solutions.com.vn/TestUser@123456(Drafter CCM, gotcha #44 check) - Bundle hash live S77: admin
D532XZKG(Run #303 sha6983609— ROTATED fromCcrZqfht; EmployeesListPage employee-detail banner text-polish) · userCuFaBoWt(Run #303 sha6983609— ROTATED fromDniDFUB_; same page both apps SHA256-identicalF013B748). Prev live adminCcrZqfht/userDniDFUB_(Run #302 S76). ⚠️ 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_PASSWORDempty):vrapp/buKL3TGBkD0wDDbYVw65QeX9read fromC:\inetpub\solution-erp\api\appsettings.Production.json→ConnectionStrings.Default. ⚠️ Skill-doc pathC:\inetpub\apps\SolutionErp\Apiis STALE → real pathC:\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_WSvsSQL_Latin1_General_CP1_CI_AS) → addCOLLATE DATABASE_DEFAULTper concatenated column.
🔑 Critical config (flag commit nếu tái xuất)
Node CI 20.x (feedback_node_cicd) · MediatR 12.4.1 (gotcha #1, flag Version="14) · Swashbuckle 6.9.0 (gotcha #2) · act_runner manual checkout (#39) · npm cache DISABLED (#40, flag cache: npm)
🎯 Per-NV admin opt-in wire — 10-point checklist (cumulative S22→S23)
Cross-ref feedback_per_nv_permission_scope. Per-NV/per-Level refactor MUST verify: 1 Domain field · 2 EF HasDefaultValue(false) · 3 Mig 3-file · 4 Service read · 5 Domain+App DTO mirror · 6 Designer FE checkbox · 7 AwLevelDto+ToDto · 8 CreateAwLevelInput+Update mutation · 9 Lookup discrimination (FirstOrDefault ADD ApproverUserId==actorId + admin fallback) · 10 Controller body record count == Command record count. Bug latency 2-3 days prod silent khi miss 9-10. Scan grep -n "FirstOrDefault.*Order.*==" *.cs after OR-of-N refactor.
📊 Run stats baseline
BE (test+build) ~90s · FE × 2 ~60s/app · deploy ~30s · total ~3min code / 0s docs-only. >5min → escalate.
📅 Recent runs (FIFO — older → archive/git)
- 2026-06-17 S70 Run #306 (run_number 306, id420) sha=
c556f6cPASS ~4m42s (FE-ONLY re-skin "Văn phòng số" TOÀN MODULE 10 page PURO layout — PageHeader/KpiCard/WidgetCard apply + CSS Hồ sơ NS; presentation-only "phẫu thuật giữ nguyên logic", byte-identical logic. 20 .tsx: fe-admin 11 {AttendanceReport,InternalDirectory,ItTickets,MeetingCalendar,MeetingRooms,ProposalCreate,ProposalDetail,ProposalsList,WorkflowAppDetail,WorkflowAppsList}Page + fe-user 9 mirror (no AttendanceReport — admin-only) + 3 agent-memory .md (cicd/fe-designer/reviewer). NO BE/NO migration/NO new menu key. deploy 10/10 session after #297–#305 all PASS): Pusha8bbdae..c556f6c(1 commit, 23 files).git diff --name-only a8bbdae c556f6c -- '*Migrations*' '*Persistence*'= EMPTY ✓..tsxnon-ignored → full pipeline RAN (3.mdagent-memory match paths-ignore but co-mixed w/ 20 tsx → Discovery#3 range any-non-ignored ⟹ whole build). GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prodappsettings.Production.json→ConnectionStrings.Default(pathC:\inetpub\solution-erp\api, uidvrapplen24). Run IN-PROGRESS at spawn (status=running 09:57:54→09:58:40) — pre-deploy baseline captured BEFORE poll-loop: adminBl2o_kUq(S69 #305 live) + userBImrKQNn(S69 #305 live) — both == spec baseline (still live, deploy not yet shipped, anti#3 honored no mid-flight verify). Polled status=success (started 09:57:54 → upd 10:02:36 ≈4m42s). CI gate (both proj pre-deploy ⟹ status=success ⟹ test 286 baseline (45D+241I; FE-only ⟹ 0 BE call-site risk) passed;conclusionempty —tasksendpoint terminal=status:successkhông populateconclusion, trust success; 286 INFERRED gate-passes-pre-build invariant NOT log-confirmed). ★ BUNDLE BOTH ROTATE (FE-both-app 10-page re-skin ⟹ both MUST rotate; verified AFTER status=success + re-confirm STABLE 2nd-fetch identical no-transient — anti#3): admin ROTATEBl2o_kUq→Wt54PHYl(cssCKzdDktL→BpHtX3vS) ✓ + user ROTATEBImrKQNn→B99fMU6X(csseoxUcs8v→DXRSCQW7) ✓. BOTH required → BOTH did. Asset reachable 200: admin js 1,588,241b + user js 1,493,955b (not white). ⚠️ Prod CI hashes ≠ spec local-build (fe-userC8-p69Kn/DezuRkK9, fe-adminyFhLO2Wp/Dd2WiO6n) — EXPECTED CI-rebuild content-hash divergence (only matters NEW≠baseline, BOTH rotated confirmed). Smoke 4×200 health: api/health/ready+/health/live+ admin root + eoffice root. Office-backed API live (admin bearer): GET /api/proposals 200 · /api/it-tickets 200 · /api/meeting-rooms 200 · /api/employees 200 (data layer healthy, not 500)./api/workflow-apps→404 = WRONG-route-guess NOT regression (FE-only can't change BE routing; real route differs — leave-requests/don-tu; FE uses api-client wrapper, route grep didn't land). SPA deep-link 6 Office routes admin all 200 (/proposals, /it-tickets, /workflow-apps/leave, /directory, /meeting-calendar, /office/dashboard serve index.html — not 404/white). NO migration — prod__EFMigrationsHistorytop =20260616035929_AddHoSoLinkToPurchaseEvaluation(Mig 52) == repo HEAD GIỮ NGUYÊN ✓ (prev-2 = AddDepartmentParentId Mig51 + ReplaceBudgetModuleWithPeWorkItemBudgets Mig50 chain intact). sys.tables=88 verified (sqlcmd COUNT excl mighist — unchanged). ★ OFFICE-HIDDEN CONFIRMED (non-admin Drafter=nv.test): sqlcmdOff_Dashboardperm row ONLY for Admin (1/13 roles) ✓ + Drafter has ALL 17 Off_ keys present but EVERY one CanRead=0 ✓ → menu gates on CanRead=1 ⟹ non-admin sees NO Office menu.* ⚠️ LESSON-CORRECTION vs S69: my coarseGROUP BY COUNT(*) WHERE MenuKey LIKE 'Off%'first showed "all 13 roles ~18 Off perms" — MISLEADING; those are perm-ROWS-with-CanRead=0 (existence ≠ access). Must filterCanRead=1OR inspect per-key. MenuItems.IsVisible=1 on all Off keys = admin-side global-visible flag; user-visibility = IsVisible AND role.CanRead. Office-hidden state is AMBIENT (FE-only commit cannot touch Permissions/MenuItems seed — git diff zero BE/DbInitializer) = identical pre-c556f6c. 0 regression. NO prod-data mutation (read-only curls + sqlcmd SELECT-only). Visual per-page render = anh user UAT (em chỉ confirm bundle shipped + route không 500/trắng per spec). TOOLING (re-confirmed + NEW): Bash tool = POSIX bash → ⚠️ systempython3BROKEN (ZKBioTime Python311 on PATH →SRE module mismatchfatal) ANDjqNOT installed → MUST usepowershell.exe -NoProfile -File "C:/.../tmp/x.ps1"+Invoke-RestMethodfor ALL JSON parse (Gitea tasks matchhead_sha -eq sha); poll-loop in pure-bash w/ jq SILENTLY returns empty (no error) — verify parser works before trusting loop. SSH→PS base64-EncodedCommand(UTF-16LE) for appsettings-read AND sqlcmd; sqlcmd string-LITERAL via[char]39concat (NOT doubled-quote);-U/-Pdirect (no -ConnectionString flag);Roles/Permissions(RoleId,MenuKey,CanRead)/MenuItems([Key],IsVisible). NEVER fixed code (READ-only). Tag[s70, run306, pass, fe-only-vanphongso-reskin-10page-PURO, fe-both-app-bundle-BOTH-rotate-Wt54PHYl-B99fMU6X, asset-200-reachable, office-api-200-proposals-ittickets-meetingrooms-employees, workflow-apps-404-wrong-route-not-regression, spa-deeplink-6route-200, no-mig-top-stays-mig52, tables88-verified, office-hidden-confirmed-Off_Dashboard-admin-only-drafter-canread0, lesson-canread0-rows-not-access, ambient-not-deploy-caused, jq-absent-python3-broken-use-powershell, deploy10of10, no-regression, test286-inferred]. - 2026-06-17 S69 Run #305 (run_number 305, id419) sha=
a8bbdaePASS ~4-5m (FE BOTH-APP foundation "Văn phòng số" + index.css sync + BE menu-seed NO-mig: 3 shared component mới PageHeader/KpiCard/WidgetCard + OfficeDashboardPage landing route/office/dashboard4-place-wire BOTH apps +fe-admin/src/index.cssSYNCED (Hồ sơ NS accent tokens, rotate admin mạnh) + BE menu keyOff_Dashboard(MenuKeys.cs L100 + DbInitializer.cs L1825 seed parent=OffOrder0 LayoutDashboard); deploy 9/9 session after #297–#304 all PASS): Push764fe70..a8bbdae(1 commit, 20 files). Diff: FE 14 files (2× {PageHeader,KpiCard,WidgetCard,OfficeDashboardPage,App.tsx,Layout.tsx,menuKeys.ts} + fe-admin index.css) + BE 2 (MenuKeys.cs + DbInitializer.cs) + 4 agent-memory.md..tsx/.cs/.cssnon-ignored → full pipeline RAN (the 4**/*.mdagent-memory match paths-ignore but co-mixed w/ code → Discovery#3 range any-non-ignored ⟹ whole build). GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prodappsettings.Production.json→ConnectionStrings.Default(pathC:\inetpub\solution-erp\api, uidvrapp). Run IN-PROGRESS first 4 polls (running 09:26→09:29) — correctly did NOT verify-bundle-mid-flight (anti#3); pre-deploy baseline captured BEFORE poll-loop: adminCNUv1jxY(S78 #304 live) + userCpOskeS1(S78 #304 live) — both == spec S68 baseline (still live, deploy not yet shipped). Polled iter5 status=success (started ~09:25 → success 09:29:50 ≈4-5m). CI gate (both proj pre-deploy ⟹ status=success ⟹ test gate 286 baseline (45D+241I) passed;conclusionempty —tasksendpoint terminal=status:successdoesn't populateconclusion, trust success; 286 INFERRED from gate-passes-pre-build invariant NOT log-confirmed numerically). ★ BUNDLE BOTH ROTATE (FE-both-app + index.css sync ⟹ both MUST rotate; verified AFTER status=success +re-confirm STABLE 2nd-fetch identical no-transient — anti#3): admin ROTATECNUv1jxY→Bl2o_kUq✓ (Văn phòng số + index.css shipped) + user ROTATECpOskeS1→BImrKQNn✓ (foundation shipped). BOTH required → BOTH did. ⚠️ Prod CI hashes (Bl2o_kUq/BImrKQNn) ≠ spec local-build (TbkadgKd/DrxDysO7) — EXPECTED divergence (CI rebuilds w/ different Node/npm/dep-resolution → different content-hash; only matters NEW≠baseline, BOTH rotated confirmed ship). Spec assumption "prod khớp local nếu source-identical" holds ONLY if byte-identical build-env — it is NOT (S77 same lesson). Smoke 4×200: api/health/ready+/health/live+ admin root + eoffice root. NO migration — prod__EFMigrationsHistorytop =20260616035929_AddHoSoLinkToPurchaseEvaluation(Mig 52) == repo HEAD GIỮ NGUYÊN ✓ (git diff --name-only 764fe70 a8bbdae -- '*Migrations*'= EMPTY; menu-seed is runtime-idempotent DbInitializer NOT EF-migration → top did NOT advance). sys.tables=88 verified (sqlcmd COUNT excl mighist — unchanged, menu-seed inserts rows not tables). ★ MENU-SEED VERIFIED (NEW check this run — DbInitializer seed ungated reaches prod by design): sqlcmdSELECT [Key],ParentKey,Label,IsVisible FROM MenuItems WHERE [Key]='Off_Dashboard'→ 1 row Key=Off_DashboardParent=OffLabel="Bảng điều khiển Văn phòng số" IsVisible=1 ✓. ★ OFFICE-HIDDEN CONFIRMED (RevokeTemporarilyHiddenModulesAsync StartsWith("Off") scope — DbInitializer.cs L2172): sqlcmdSELECT r.Name FROM Permissions p JOIN Roles r ON r.Id=p.RoleId WHERE p.MenuKey='Off_Dashboard'→ ONLYAdmin(CanRead=1), 1 row / 13 roles total ✓ → non-admin NO Off_Dashboard perm → Office stays hidden (revoke executed, admin auto via All[]). 0 regression. NO prod-data mutation (read-only curls + sqlcmd SELECT-only). Visual "Dashboard landing render / Hồ sơ NS CSS" NOT verified (anh xem mắt) — only ship+rotate+health+mig-unchanged+tables88+menu-seed+office-hidden. LESSON: FE-both-app + index.css-sync + BE-menu-seed (NO-EF-mig) verify = both bundles MUST ROTATE + Mig-top + sys.tables MUST stay prev (menu-seed = DbInitializer runtime row-insert, NOT a migration → does NOT advance __EFMigrationsHistory NOR sys.tables; verify seed via direct MenuItems SELECT not via mig-count). Office-hidden = query Permissions-by-role: temporarily-hidden module has perm row ONLY for Admin (All[] auto-grant) after RevokeTemporarilyHidden runs. ⚠️ Prod CI bundle-hash ≠ local-build-hash is NORMAL — never FAIL on hash-mismatch-to-local, only FAIL if NOT-rotated-from-baseline. TOOLING (re-confirmed S78): Bash=POSIX ($var/$env:/''literal-quote mangle through bash→ssh→PS→sqlcmd layers) → write PS to.ps1+powershell -File "ABS/FWD/SLASH.ps1"; GiteatasksviaInvoke-RestMethod(matchhead_sha -eq sha,?limit=Nhonored URI-direct); SSH→PS base64-EncodedCommand(UTF-16LE iconv) for BOTH appsettings-read AND sqlcmd; ⚠️ sqlcmd string-LITERAL in query: doubled''x''BREAKS (PS single-quote-string closes early) → build literal via[char]39 + "x" + [char]39concat (NOT''); this sqlcmd build supports-U/-Pdirect (no -ConnectionString flag); table nameRolesNOTAspNetRoles,Permissions(RoleId,MenuKey,CanRead); CLIXML/Progress stdout-noise grep-filter out. NEVER fixed code (READ-only). Tag[s69, run305, pass, fe-both-app-vanphongso-foundation, shared-PageHeader-KpiCard-WidgetCard, index-css-sync-admin, bundle-BOTH-rotate-Bl2o_kUq-BImrKQNn, prod-ci-hash-NE-local-EXPECTED, be-menu-seed-Off_Dashboard-NO-mig, no-mig-top-stays-mig52, tables88-verified, menu-seed-verified-sqlcmd, office-hidden-confirmed-admin-only-1of13, sqlcmd-char39-literal-not-doubled-quote, deploy9of9, no-regression, test286-inferred]. - 2026-06-16 S78 Run #304 (run_number 304, id418) sha=
37752ebPASS ~4m (FE BOTH-APP 1-line CSS-precedence fix: "Hồ sơ NS" employee-detail banner NAME đen→trắng —<h2>rendered BLACK do unlayeredh1,h2,h3,h4{color:#0b1220}index.css thắngtext-white(Tailwind v4 @layer precedence); fix =text-white→text-white!important-modifier +text-xl font-extrabold→text-lg font-bold. 2 fileEmployeesListPage.tsxfe-user+fe-admin SHA256-IDENTICAL8BBAEC34…, 1-line each, NO BE/mig/index.css; deploy 8/8 session after #297–#303 all PASS): Push6983609..37752eb(1 commit). Diff 2 files: both.tsxonly → not in paths-ignore → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prodappsettings.Production.json→ConnectionStrings.Default(pathC:\inetpub\solution-erp\api, uidvrapplen24). Run IN-PROGRESS first 7 polls (running 19:55→19:58) — correctly did NOT verify-bundle-mid-flight (anti#3); pre-deploy baseline captured BEFORE poll-loop: adminD532XZKG(S77 #303 live) + userCuFaBoWt(S77 #303 live) — both == spec baseline (still live, deploy not yet shipped). Polled iter8 status=success (started ~19:55 → success 19:59:26 ≈4m). CI gate (both proj pre-deploy ⟹ status=success ⟹ test gate 286 baseline (45D+241I; FE-only ⟹ 0 BE call-site risk) passed;conclusionempty —tasksendpoint terminal=status:successdoesn't populateconclusion, trust success; exact CI count NOT log-confirmed numerically — Gitea logs web-UI-only anon, 286 INFERRED from gate-passes-pre-build invariant). ★ BUNDLE BOTH ROTATE (the change-point — FE-BOTH-app, both EmployeesListPage changed ⟹ both bundles MUST rotate; verified AFTER status=success +re-confirm STABLE 2nd-fetch identical no transient — anti#3): admin ROTATED532XZKG→CNUv1jxY✓ (text-white!name-color fix shipped) + user ROTATECuFaBoWt→CpOskeS1✓ (same page shipped). BOTH required per spec → BOTH did (mirror S74/S75/S76/S77 pure-FE-both-app pattern — both same-SHA256 file ⟹ both rotate; frozen sibling here = ship-fail flag). Smoke 4×200: api/health/ready+/health/live+ admin root + eoffice root. NO migration — prod__EFMigrationsHistorytop =20260616035929_AddHoSoLinkToPurchaseEvaluation(Mig 52) == repo HEAD GIỮ NGUYÊN ✓ (git diff --name-only 6983609 37752eb -- '*Migrations*' '*Persistence*'= EMPTY; FE cannot alter schema → top did NOT advance; prev-2 =AddDepartmentParentIdMig51 +ReplaceBudgetModuleWithPeWorkItemBudgetsMig50 chain intact). sys.tables=88 verified (sqlcmd COUNT excl mighist — unchanged, no schema touch). 0 regression. NO prod-data mutation (read-only curls + sqlcmd SELECT-only). Visual "tên NV trắng render đúng" NOT verified (anh xem mắt) — only ship+rotate+health+mig-unchanged+tables88; SHA256-identical-between-2-apps is a SOURCE-claim (git), not runtime DOM-equality; CSS-precedence-actually-fixed is render-time, NOT provable by curling bundle (the!importanttext is in dist css per spec-claim, but visual-black-vs-white is browser-render). LESSON: pure-FE-BOTH-app 1-line CSS-fix verify (8th consecutive deploy this session, both apps same component SHA256-identical) = both bundles MUST ROTATE (≠ asymmetric one-app where sibling frozen; ≠ BE-only where both frozen). Even a 1-linetext-white→text-white!change → new content-hash both apps. Migration top + sys.tables MUST stay = prev (FE-only). No BE call-site/DTO/endpoint smoke (no API surface — render-only). TOOLING (re-confirmed S77): Bash tool is POSIX bash (Select-String/$var/$env:unavailable inline) → write PowerShell to.ps1+ invokepowershell -File "ABSOLUTE/FORWARD/SLASH.ps1"(Bash EATS backslash intmp\x.ps1→tmpx.ps1); parse GiteatasksviaInvoke-RestMethod+native object (matchhead_sha -like sha*,limit=Nignored); SSH→PS nested-quote mangles → base64-EncodedCommand(UTF-16LE) BOTH the appsettings-read AND the sqlcmd-query (no$in B64 passes bash+ssh clean); CLIXML progress-stream on stdout harmless (data rows clean below); read DB pw from prod appsettings when PROD_DB_PW empty. NEVER fixed code (READ-only). Tag[s78, run304, pass, fe-both-app-hoso-name-color-fix-text-white-important, fe-both-2files-sha256-identical-8BBAEC34, bundle-BOTH-rotate-CNUv1jxY-CpOskeS1, css-precedence-tailwind-v4-layer, no-mig-top-stays-mig52, tables88-verified, deploy8of8, ssh-encodedcommand-base64, no-regression, test286-inferred]. - (S77 #303 sha
6983609, S76 #302, S75/S74 … pre-S78 verbatim → git764fe70+ archive — FIFO trimmed to keep L1 under soft-cap) - 2026-06-16 S77-ARCHIVED Run #303 sha=
6983609PASS ~5m (FE BOTH-APP additive "Hồ sơ NS" banner text-polish — nametext-xl font-extrabold+drop-shadow, metatext-[13px] font-medium text-white, status badge → solid status-colored pill emerald/amber/slate. 2 fileEmployeesListPage.tsxfe-user+fe-admin SHA256-IDENTICALF013B748…, NO BE/mig/index.css; +docs 2 files{dep-audit SKILL.md gotcha 64→65, root CLAUDE.md test 263→286}no-build-impact; deploy 7/7 session after #297–#302 all PASS): Push range231a7b0..6983609(2 commits). Diff 4 files: 2.tsx+CLAUDE.md+dependency-audit-erp/SKILL.md..tsx→ not in paths-ignore → full pipeline RAN (docs alone would SKIP, but tsx present ⟹ build per Discovery#3 push-range any-non-ignored ⟹ whole build). GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prodappsettings.Production.json→ConnectionStrings.Default(pathC:\inetpub\solution-erp\api). Run IN-PROGRESS first 6 polls (running 19:36→19:39) — correctly did NOT verify-bundle-mid-flight (anti#3); pre-deploy baseline captured BEFORE poll-loop: adminCcrZqfht(S76 #302 live) + userDniDFUB_(S76 #302 live) — both == spec baseline (still live, deploy not yet shipped). Polled iter6 status=success (started ~19:35 → success 19:40 ≈5m). CI gate (both proj pre-deploy ⟹ status=success ⟹ test gate 286 baseline (45D+241I; FE-only ⟹ 0 BE call-site risk) passed;conclusionempty —tasksendpoint terminal=status:successdoesn't populateconclusion, trust success; could NOT extract exact CI count — Gitea logs web-UI-only anon, 286 INFERRED from gate-passes-pre-build invariant NOT log-confirmed numerically). ★ BUNDLE BOTH ROTATE (the change-point — FE-BOTH-app, both EmployeesListPage changed ⟹ both bundles MUST rotate; verified AFTER status=success +re-confirm STABLE 2nd-fetch identical no transient — anti#3): admin ROTATECcrZqfht→D532XZKG✓ (banner polish shipped) + user ROTATEDniDFUB_→CuFaBoWt✓ (same page shipped). BOTH required per spec → BOTH did (mirror S74/S75/S76 pure-FE-both-app pattern — both same-SHA256 file ⟹ both rotate; frozen sibling here = ship-fail flag). ⚠️ Local-build hashes (fe-userSuT9mDAQ, fe-admin7ICczYiQper spec) ≠ deployed CI hashes — EXPECTED (CI rebuilds; only matters NEW≠baseline, confirmed). Smoke 4×200: api/health/ready+/health/live+ admin root + eoffice root. NO migration — prod__EFMigrationsHistorytop =20260616035929_AddHoSoLinkToPurchaseEvaluation(Mig 52) == repo HEAD GIỮ NGUYÊN ✓ (git diff --name-only 231a7b0 6983609 -- '*Migrations*' '*Persistence*'= EMPTY; FE+docs cannot alter schema → top did NOT advance; prev-2 =AddDepartmentParentIdMig51 +ReplaceBudgetModuleWithPeWorkItemBudgetsMig50 chain intact). sys.tables=88 verified (sqlcmd COUNT excl mighist — unchanged, no schema touch). 0 regression. NO prod-data mutation (read-only curls + sqlcmd SELECT-only). Visual "banner text-xl/drop-shadow/status-pill render đúng" NOT verified (anh xem mắt) — only ship+rotate+health+mig-unchanged+tables88; SHA256-identical-between-2-apps is a SOURCE-claim (git), not runtime DOM-equality. LESSON: pure-FE-BOTH-app additive verify (7th consecutive deploy this session, both apps same component SHA256-identical) = both bundles MUST ROTATE (≠ asymmetric one-app where sibling frozen; ≠ BE-only where both frozen). Docs-files in same range as tsx do NOT suppress build (range any-non-ignored ⟹ build). Migration top + sys.tables MUST stay = prev (FE-only). No BE call-site/DTO/endpoint smoke (no API surface — render-only). TOOLING (re-confirmed S76): Bash tool EATS inline$var/$env:/@{}in PS strings → write PowerShell to.ps1+ run-File; parse GiteatasksviaInvoke-RestMethod+native object (matchhead_sha -like sha*,limit=Nignored); SSH→sqlcmd base64EncodedCommand(UTF-16LE via iconv, no$in B64 passes bash clean), CLIXML progress-stream stdout harmless grep-filter out; ⚠️ thissqlcmdbuild does NOT support-ConnectionStringflag → parseUser Id/Passwordfrom conn-string via regex →-U/-P; read DB pw from prod appsettings when PROD_DB_PW empty. NEVER fixed code (READ-only). Tag[s77, run303, pass, fe-both-app-hoso-banner-textpolish, fe-both-2files-sha256-identical-F013B748, bundle-BOTH-rotate-D532XZKG-CuFaBoWt, docs-in-range-no-suppress-build, no-mig-top-stays-mig52, tables88-verified, deploy7of7, sqlcmd-no-connstring-flag-use-U-P, no-regression, test286-inferred]. - 2026-06-16 S76 Run #302 (run_number 302, id416) sha=
536dd6bPASS ~4m (FE BOTH-APP additive: PE "Link hồ sơ ổ mạng" render upgrade — đường-dẫn-ổ-mạng từ chữ+Copy →<a href=file://…>bấm-thử mở Explorer + GIỮ nút Copy dự phòng. 2 filePeDetailTabs.tsxfe-user+fe-admin SHA256-IDENTICALb415023b…, +46/−14 mỗi file, NO BE/mig/index.css/Employee-page; deploy 6/6 session after #297/#298/#299/#300/#301 all PASS): Push 2 files{fe-admin,fe-user}/src/components/pe/PeDetailTabs.tsx..tsx→ not in paths-ignore → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prodappsettings.Production.json→ConnectionStrings.Default. Run IN-PROGRESS first 6 polls (running 14:54:20→14:56:57) — correctly did NOT verify-bundle-mid-flight (anti#3); pre-deploy baseline captured BEFORE poll-loop: adminI1fpLeYw(S75 #301 live) + userDrQYkzh0(S75 #301 live) — both == spec baseline. Polled iter7 status=success (started ~14:53 → success 14:57:13 ≈4m). CI gate (both proj pre-deploy ⟹ status=success ⟹ test gate 286 baseline (45D+241I; FE-only ⟹ 0 BE call-site risk) passed;conclusionempty —tasksendpoint terminal=status:successdoesn't populateconclusion, trust success). ★ BUNDLE BOTH ROTATE (the change-point — FE-BOTH-app, both PeDetailTabs changed ⟹ both bundles MUST rotate; verified AFTER status=success +re-confirm STABLE 2nd-fetch identical no transient — anti#3): admin ROTATEI1fpLeYw→CcrZqfht✓ (file:// link shipped) + user ROTATEDrQYkzh0→DniDFUB_✓ (same component shipped). BOTH required per spec → BOTH did (mirror S74/S75 pure-FE-both-app pattern — both same-SHA256 file ⟹ both rotate; frozen sibling here = ship-fail flag). Smoke 4×200: api/health/ready+/health/live+ admin root + eoffice root. NO migration — prod__EFMigrationsHistorytop =20260616035929_AddHoSoLinkToPurchaseEvaluation(Mig 52) == repo HEAD GIỮ NGUYÊN ✓ (git diff --name-only 536dd6b~1 536dd6b -- '*Migrations*'= EMPTY; FE cannot alter schema → top did NOT advance; prev-2 =AddDepartmentParentIdMig51 +ReplaceBudgetModuleWithPeWorkItemBudgetsMig50 chain intact). sys.tables=88 verified (sqlcmd COUNT excl mighist — unchanged, no schema touch). 0 regression. NO prod-data mutation (read-only curls + sqlcmd SELECT-only). Visual "link file:// bấm mở Explorer / nút Copy" NOT verified (anh xem mắt) — only ship+rotate+health+mig-unchanged+tables88; SHA256-identical-between-2-apps is a SOURCE-claim (git), not runtime DOM-equality (file:// scheme browsers thường block từ https-origin → click có thể no-op tùy browser, đó là lý do GIỮ Copy dự phòng — không kiểm chứng được qua curl). LESSON: pure-FE-BOTH-app additive verify (6th consecutive deploy this session, both apps same component SHA256-identical) = both bundles MUST ROTATE (≠ asymmetric one-app where sibling frozen; ≠ BE-only where both frozen). Migration top + sys.tables MUST stay = prev (FE-only). No BE call-site/DTO/endpoint smoke (no API surface — render-only). TOOLING (re-confirmed S75): Bash tool EATS inline$var/$env:inpowershell -Command→ write PowerShell to.ps1+ run-File;certutil -hashfile … SHA256for SHA256 (NOT findstr-pipe — quoting breaks); parse GiteatasksviaInvoke-RestMethod+native object (matchhead_sha -eq sha,limit=Nignored); SSH→sqlcmd base64EncodedCommand(UTF-16LE, no$in B64 passes bash clean), CLIXML progress-stream stdout harmless; read DB pw from prod appsettings when PROD_DB_PW empty (pathC:\inetpub\solution-erp\api, keyConnectionStrings.Default). NEVER fixed code (READ-only). Tag[s76, run302, pass, fe-both-app-pe-link-hoso-file-scheme, fe-both-2files-sha256-identical-b415023b, bundle-BOTH-rotate-CcrZqfht-DniDFUB_, no-mig-top-stays-mig52, tables88-verified, deploy6of6, no-regression, test286]. - (S75 Run #301 sha=
6df1b2dPASS ~2.5m [FE-both-app PE Link-hồ-sơ auto-detect render, bundle-BOTH-rotate I1fpLeYw/DrQYkzh0, no-mig-mig52, tables88, test286, fastest-streak] → FIFO-trimmed, full verbatim git +archive/2026-06.md) - (S74 Run #300 sha=
91aaf05PASS [FE-both-app list-redesign flex-row, bundle-BOTH-rotate PxiZQkaw/B36hGoKd, user-unfroze-from-s71-streak, no-mig-mig52, tables88, test286, TOOLING: ps1-file-not-inline-dollar + ssh-encodedcommand-base64] → FIFO-trimmed, full verbatim git +archive/2026-06.md) - 2026-06-16 S73 Run #299 (id413) sha=
bcd619dPASS ~3m (TESTS-ONLY BE: +3 filestests/SolutionErp.Infrastructure.Tests/Application/{DepartmentTreeTests,PeHoSoLinkTests,HrmProfilePermissionSeedTests}.cs= +23→286 total (45D+241I). NO prod code, NO FE, NO migration; deploy 3/3 session after #297/#298 both success):.csnot in paths-ignore → full pipeline RAN. Run IN-PROGRESS first poll (running 14:06) → polled iter4 status=success(~14:09 ≈3m);conclusionempty (terminal=success, trust). CI test gate = the focus: gate runs BOTH test projects BEFORE build ⟹ status=success ⟹ 23 new tests passed on CI (not just local 286). Could NOT extract exact CI count — Gitearuns/413/logs+jobsendpoints all 404 anon (logs web-UI-only without auth token; GITEA_TOKEN empty). Inferred 286 from success (gate-passes-pre-build invariant) — NOT log-confirmed numerically. ★ BUNDLE BOTH-FROZEN (BE-only ⟹ neither app may rotate), verified AFTER status=success +2nd-fetch STABLE no transient (anti#3): adminxkSz9BfEFROZEN ✓ + userBumgrwCJFROZEN ✓ (==pre-deploy baseline both; rotate-on-BE-only = anomaly→none). Smoke 4×200: api/health/ready+/health/live+admin root+eoffice root. NO migration — prod__EFMigrationsHistorytop=AddHoSoLinkToPurchaseEvaluation(Mig52)==repo HEAD GIỮ NGUYÊN ✓ (prev-2 Mig51AddDepartmentParentId+Mig50ReplaceBudgetModule…chain intact; commit 0 mig files). sys.tables=88 ✓ (sqlcmd excl mighist, unchanged). 0 regression, NO prod-data mutation (read curls+SELECT-only). TOOLING LESSON (supersedes S72 #298):python3/py -3on this box = BROKEN ZKBioTime embed (AssertionError: SRE module mismatchonimport re/json) — version banner works but stdlib import dies. USE PowerShellInvoke-RestMethod+native object access (NOT ConvertFrom-Json on cached temp file — temp got stale snapshot once) to parse Gitea tasks;limit=Nparam IGNORED (returns full 299, match by id anyway). SSH→sqlcmd: nested bash→ssh→PS ate$var(S42) → useiconv UTF-16LE|base64→powershell -EncodedCommand; CLIXML progress-stream noise on stdout is harmless, data lines clean. Read DB pw from prodappsettings.Production.json→ConnectionStrings.Defaultwhen PROD_DB_PW empty (pathC:\inetpub\solution-erp\api). NEVER fixed code (READ-only). Tag[s73, run299, pass, tests-only-be, +23-test-286-CI-gate-inferred-not-logcount, bundle-both-frozen-xkSz9BfE-BumgrwCJ, no-mig-top-mig52, tables88, deploy3of3, python3-broken-use-powershell-IRM, no-regression]. - 2026-06-16 S72 Run #298 (run_number 298, id412) sha=
292d64dPASS ~4m20s (FE-Admin MIRROR "Hồ sơ Nhân sự" master-detail từ fe-user: overwrite EmployeesListPage.tsx cũ 1200→1602 dòng SHA256-IDENTICAL với fe-user + index.css +4 accent palette teal/amberx/violet/greenx + utility.icon-chip/.app-gradient-brand/.card-accent/.stat-value— FE-ADMIN-ONLY 2 files, NO BE, NO migration, NO fe-user; ASYMMETRIC NGƯỢC deploy-1 S71 #297 (đó fe-user-rotate/admin-frozen, đây admin-rotate/user-frozen)): Deploy 2/2 trong session (deploy-1 =ab4e681#297 PASS fe-userBumgrwCJ; #297=success TRƯỚC push này nên KHÔNG bị cancel — confirmed in tasks list). Push 2 filesfe-admin/src/index.css(+81) +fe-admin/src/pages/hrm/EmployeesListPage.tsx(1020+/537−, 1476-line overwrite)..tsx+.css→ not in paths-ignore → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prodappsettings.Production.json→ConnectionStrings.Default(buKL3...buKL3TGBkD0wDDbYVw65QeX9). Run IN-PROGRESS first poll (running 13:52) — correctly did NOT verify-bundle-mid-flight (anti#3); pre-deploy baseline snapshot captured BEFORE poll: adminBDwV5d0X(S68 frozen-since, must rotate) + userBumgrwCJ(S71 deploy-1 live, must stay frozen). ⚠️ POLL-PARSER BUG: mytr ','|grep -A4 '"id":412'returned empty status ×10 iter (false negative — grep -A on tr-newlined JSON misanchors) → re-queried withpython3 json.load→ status=success(started 13:51:27 → updated 13:55:47 ≈4m20s). LESSON-tooling: parse Gitea tasks JSON via python3 NOT tr/grep -A (multi-field-per-object splits wrong); always cross-check with a clean parser before trusting empty-status. CI gate (both proj pre-deploy ⟹ status=success ⟹ test gate 263 baseline (45D+218I; FE-only ⟹ 0 BE call-site risk) passed;conclusionempty — trust success). ★ BUNDLE ASYMMETRIC NGƯỢC-deploy-1 (the change-point — FE-one-app verify) ALL PASS, verified AFTER status=success +re-confirm STABLE 2nd-fetch identical no transient (anti#3): admin ROTATEBDwV5d0X→xkSz9BfE✓ (EmployeesListPage mirror + accent index.css shipped — admin un-froze from S68's BDwV5d0X frozen-streak S68→S71, now rotated correctly cho fe-admin change) + user FROZENBumgrwCJ==deploy-1-baseline ✓ (fe-user 0 files touched deploy-2 → MUST NOT rotate = correct; rotate-when-untouched = anomaly→flag). Health api live+ready 200/200 (real endpoints/health/ready+/health/live, NOT/health) + admin/eoffice root 200. NO migration — prod__EFMigrationsHistorytop =20260616035929_AddHoSoLinkToPurchaseEvaluation(Mig 52) == repo HEAD GIỮ NGUYÊN ✓ (prev-2 =AddDepartmentParentIdMig51 +ReplaceBudgetModuleWithPeWorkItemBudgetsMig50 chain intact; commit 0 mig files — FE cannot alter schema → top did NOT advance). sys.tables=88 verified (sqlcmd COUNT excl mighist — unchanged, no schema touch). 0 regression. NO prod-data mutation (read-only curls + sqlcmd SELECT-only). Visual "mirror identical / chữ xanh đậm brand-800 / accent đẹp" NOT verified (anh xem mắt) — only ship+rotate+health+mig-unchanged+tables88; SHA256-identical-with-fe-user is a SOURCE-claim (git diff), not runtime-verified by me (can't compare rendered DOM cross-app). LESSON: deploy-2 of same-session asymmetric-NGƯỢC = (a) verify prior deploy (#297) NOT cancelled by this push (it was success first — confirmed in tasks); (b) status=success ⟹ deploy ran; (c) THIS-app bundle ROTATE + OTHER-app FROZEN — direction FLIPS vs deploy-1 (deploy-1 fe-user-rotate/admin-frozen → deploy-2 admin-rotate/user-frozen); admin un-froze from multi-session frozen-streak = EXPECTED when fe-admin finally changes (frozen-streak break is normal, not anomaly); (d) migration top + sys.tables MUST stay = prev (FE-only). Re-query Gitea JSON with python3 when tr/grep parse yields empty — parser bug ≠ run-stuck. No BE call-site/DTO/endpoint smoke (no API surface). SHA256-source-identical = git-level claim, runtime-mirror-equality not provable by curl. NEVER fixed code (READ-only). Tag[s72, run298, pass, fe-admin-mirror-hoso-from-feuser, fe-admin-only-2files, bundle-asymmetric-NGUOC-admin-rotate-user-frozen, admin-unfroze-from-s68-streak, no-mig-top-stays-mig52, tables88-verified, deploy2of2-prior297-not-cancelled, poll-parser-bug-use-python3, no-regression, test263]. - 2026-06-16 S71 Run #297 (run_number 297, id411) sha=
ab4e681PASS ~4m21s (FE-User "Hồ sơ NS" cosmetic: đồng nhất font/size + chữ đentext-slate-900/800→xanh-đậmtext-brand-800cho value/tên + bỏtext-xsnhánh mono — FE-USER-ONLY 1 file, NO BE, NO migration; 4th consecutive same-page S68→S71): Push 1 filefe-user/src/pages/hrm/EmployeesListPage.tsx(className màu chữ + size, KHÔNG đụng BE/Mig/dep/fe-admin)..tsx→ full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prodappsettings.Production.json→ConnectionStrings.Default(len24). Run IN-PROGRESS first poll (running 13:43) — correctly did NOT verify-bundle-mid-flight (anti#3), pre-deploy baseline snapshot captured BEFORE poll iter0: userDbVv6rsf(S70 baseline) + adminBDwV5d0X. Polled iter5 status=success (started ~13:42 → success ~13:46:48 ≈4m21s). CI gate (both proj pre-deploy ⟹ status=success ⟹ test gate 263 baseline (45D+218I; FE-only ⟹ 0 BE call-site risk) passed;conclusionempty — trust success). ★ BUNDLE ASYMMETRIC (the change-point — FE-one-app verify) ALL PASS, verified AFTER status=success +re-confirm STABLE 2nd-fetch identical no transient (anti#3): user ROTATEDbVv6rsf→BumgrwCJ✓ (EmployeesListPage cosmetic shipped — re-rotated from S70's DbVv6rsf, 4th consecutive same-page FE-user deploy = new content-hash each, normal) + admin FROZENBDwV5d0X==baseline ✓ (fe-admin 0 files touched → MUST NOT rotate = correct; rotate-when-untouched = anomaly→flag). Health api live+ready 200/200 (⚠️/healthspec'd → 404, real endpoint/health/ready+/health/liveper iis-deploy-runbook skill — both 200, API healthy) + admin/eoffice root 200. NO migration — prod__EFMigrationsHistorytop =20260616035929_AddHoSoLinkToPurchaseEvaluation(Mig 52) == repo HEAD GIỮ NGUYÊN ✓ (commit 0 mig files —git diff --name-only | grep Migrations/= NONE; FE-only cannot alter schema → top did NOT advance; prev-2 =AddDepartmentParentIdMig51 +ReplaceBudgetModuleWithPeWorkItemBudgetsMig50 chain intact). sys.tables=88 verified (sqlcmd COUNT excl mighist — unchanged, no schema touch). 0 regression. NO prod-data mutation (read-only curls + sqlcmd SELECT-only). Visual "chữ xanh đậm/đồng nhất size" NOT verified (anh xem mắt) — only ship+rotate+health+mig-unchanged+tables88. LESSON: pure-FE-one-app cosmetic verify (4th consecutive same-page) = (a) status=success ⟹ deploy ran; (b) target-app bundle ROTATE + sibling-app FROZEN (re-rotate of same page across sessions = NORMAL, each deploy=new hash; rotate-sibling-when-untouched = anomaly); (c) migration top + sys.tables MUST stay = prev (FE cannot alter schema — advancing = bug); (d) health 200×2 (/ready+/live, NOT /health). ⚠️/health404 ≠ unhealthy — SOL uses/health/ready+/health/live(skill-doc), spec literal/healthis wrong-path; cross-check skill before flagging. No BE call-site/DTO/endpoint smoke needed (no API surface). Tokens empty: anon Gitea + prod-appsettings DB pw works. NEVER fixed code (READ-only). Tag[s71, run297, pass, fe-user-hoso-cosmetic-brand800, fe-only-1file, bundle-asymmetric-user-rotate-admin-frozen, no-mig-top-stays-mig52, tables88-verified, health-ready-not-health, no-regression, test263]. - 2026-06-16 S70 Run #295 (run_number 295, id409) sha=
456c7a7PASS ~4m21s (FE-User "Hồ sơ Nhân sự" layout 2-cột: cây tổ chức + list chồng cột trái, detail cột phải + tô màu panel chi tiết — FE-USER-ONLY 1 file, NO BE, NO migration; follow-up S69 Run #294 same page): Pushec517f7..456c7a71 filefe-user/src/pages/hrm/EmployeesListPage.tsx(309+/262−, 571-line layout rewrite)..tsx→ full pipeline RAN. Both tokens SET this run (GITEA_TOKEN+PROD_DB_PW present — unlike S65-S69 empty; DB pw still works via prodappsettings.Production.json→ConnectionStrings.DefaultbuKL3...len24). Run IN-PROGRESS first poll (running 11:36) — correctly did NOT verify-bundle-mid-flight (anti#3), polled iter6 status=success (started ~11:36 → success 11:40:46 ≈4m21s). Pre-deploy baseline snapshot iter0: userCZfo_PFZ(S69 baseline) + adminBDwV5d0X— captured BEFORE poll, correct timing. CI gate (both proj pre-deploy ⟹ status=success ⟹ test gate 263 baseline (45D+218I; FE-only ⟹ 0 BE call-site risk) passed;conclusionempty — trust success). ★ BUNDLE ASYMMETRIC (the change-point — FE-one-app verify) ALL PASS, verified AFTER status=success +re-confirm STABLE 2nd-fetch identical no transient (anti#3): user ROTATECZfo_PFZ→DbVv6rsf✓ (EmployeesListPage layout-2col shipped — re-rotated from S69's CZfo_PFZ, consecutive FE-user deploys on SAME page = new content-hash each, normal) + admin FROZENBDwV5d0X==baseline ✓ (fe-admin 0 files touched → MUST NOT rotate = correct; rotate-when-untouched = anomaly→flag). Health api live+ready 200/200 + admin/eoffice root 200. NO migration — prod__EFMigrationsHistorytop =20260616035929_AddHoSoLinkToPurchaseEvaluation(Mig 52) == repo HEAD GIỮ NGUYÊN ✓ (commit 0 mig files —git diff --name-only | grep Migrations/= NONE; FE-only cannot alter schema → top did NOT advance past S68's Mig 52; prev-2 =AddDepartmentParentIdMig51 +ReplaceBudgetModuleWithPeWorkItemBudgetsMig50 chain intact). sys.tables stays 88 by construction (no schema touch — skipped explicit count, FE-only). 0 regression. NO prod-data mutation (read-only curls + sqlcmd SELECT-only). Visual "2-cột đẹp/tô-màu" NOT verified (anh xem mắt) — only ship+rotate+health+mig-unchanged. LESSON: pure-FE-one-app verify (3rd consecutive same-page FE-user S68→S69→S70) = (a) status=success ⟹ deploy ran; (b) target-app bundle ROTATE + sibling-app FROZEN (asymmetric — re-rotate of already-rotated page across sessions is NORMAL, each deploy=new hash; rotate-sibling-when-untouched = anomaly); (c) migration top MUST stay = prev (FE cannot alter schema — advancing top on FE-only commit = bug); (d) health 200×3. No BE call-site/DTO/endpoint smoke needed (no API surface). Tokens-present vs empty: both paths work — when GITEA_TOKEN set usetokenheader, but anon also fine for public repo. NEVER fixed code (READ-only). Tag[s70, run295, pass, fe-user-hoso-2col-layout, fe-only-1file, bundle-asymmetric-user-rotate-admin-frozen, no-mig-top-stays-mig52, tables88, no-regression, test263, tokens-present]. - 2026-06-16 S68 Run #293 (run_number 293, id407) sha=
5a0aaa4PASS ~5m00s (FE-User "Hồ sơ Nhân sự" 3-panel master-detail 5-tab rewrite + PE "Link hồ sơ" hyperlink NAS + rename "Dự trù PRO"→"Ngân sách PRO" — CROSS-STACK BE Mig 52 + FE×2; 2-commit318860a(FE-User EmployeesListPage) +5a0aaa4(PE cross-stack)): Push6ce5803..5a0aaa415 files: BEPurchaseEvaluation.cs(+HoSoLink) +PurchaseEvaluationConfiguration.cs+PurchaseEvaluationFeatures.cs(Create/Update cmd +trailing optionalHoSoLink=null) +PurchaseEvaluationDtos.cs(Detail DTO +hoSoLink) + Mig 5220260616035929_AddHoSoLinkToPurchaseEvaluation(3-file) + FEEmployeesListPage.tsx(fe-user, 3-panel rewrite cây-tổ-chức+list+5-tab) + PE×2 (PeDetailTabs.tsx+PeWorkspaceCreateView.tsx+types/purchaseEvaluation.tsboth apps, mục E hyperlink + label rename)..cs+.tsx+Mig → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW empty → anon Gitea API + DB pw từ prodappsettings.Production.json→ConnectionStrings.Default(buKL3...). Run IN-PROGRESS first poll (running 11:15) — correctly did NOT verify-bundle-mid-flight (anti#3), polled iter5 status=success (started 11:13:57 → success 11:18:57 ≈5m). CI gate (both proj pre-deploy ⟹ status=success ⟹ test gate 263 baseline (45D+218I; BE Create/Update +trailing optional param=null ⟹ call-sites UNBROKEN) passed;conclusionempty — trust success). ★ MIGRATION APPLIED (the KEY): prod__EFMigrationsHistorytop =20260616035929_AddHoSoLinkToPurchaseEvaluation✓ (Mig 52; ADVANCED from prev top Mig 51AddDepartmentParentId; DbInitializer auto-migrate on startup ran — api ready=200 confirms boot OK post-mig). Mig content = AddColumnHoSoLink nvarchar(1000) maxLength=1000 NULL(AddColumn-only, NO new table → sys.tables stays 88 verified). DB-level:sys.columns WHERE object_id=OBJECT_ID('PurchaseEvaluations') AND name='HoSoLink'= 1 row ✓ (column physically present prod). ★ BUNDLE BOTH ROTATE (verified AFTER status=success +re-confirm STABLE 2nd-fetch no transient — anti#3): adminDf06fmpq→BDwV5d0X✓ (PE files shipped — was FROZEN since S67, now correctly rotated) + userDxK3fCfh→DXkyUjtQ✓ (EmployeesListPage + PE files shipped). Both required to rotate per spec → BOTH did. Health api live+ready 200/200 + admin/eoffice root 200. ★ NEW-FIELD live smoke (admin bearer, route/api/auth/loginfieldaccessTokenlen468):GET /api/purchase-evaluations/{48154149...}(phiếu thậtPE/2026/A/015) = 200 ✓ JSON detail carries"hoSoLink":null(key PRESENT, null cho phiếu cũ = backward-compat ✓ — Detail DTO wired AND Create/Update signature-change did NOT break GET path) ·GET /api/departments/tree= 200 ✓ (Phase B dependency from Mig 51, still live). 0 regression. NO prod-data mutation (read-only GETs + sqlcmd SELECT-only). LESSON: nullable-AddColumn cross-stack verify = (a)__EFMigrationsHistorytop ADVANCED to new Mig (Mig 52) + api ready=200 (auto-migrate boot OK); (b)sys.tables=88 unchanged (AddColumn ≠ new table) +sys.columnsconfirms col present; (c) Detail DTO field-presence via authed GET on a REAL phiếu —"hoSoLink":nullfor old rows proves both DTO-wiring AND backward-compat (trailing-optional Create/Update param won't break GET — confirmed 200); (d) cross-stack BE+FE×2 = BOTH bundles rotate (admin un-froze from S67). Tokens empty: anon Gitea + prod-appsettings DB pw works (Bash tool is POSIX bash NOT PS despite shell=PowerShell env —$env:/jq/python3unavailable; parse viatr ','|grep+ read pw viassh→appsettings). Tag[s68, run293, pass, pe-hosolink-mig52-applied, fe-user-hoso-3panel-rewrite, pe-link-hoso-hyperlink, rename-dutru-to-ngansach, bundle-both-rotate-admin-unfroze, hosolink-null-in-dto-backward-compat, no-new-table-88, test263]. - (S67 Run #292 [dept-parentid Mig51-applied-after-#291-fail, retry-chain CS7036-fix, bundle-asymmetric, tree-endpoint-200] + S65 #289 [hrm-hoso public-readonly seed-only, asymmetric read200/write403] → FIFO-trimmed, full verbatim git
d2f52ba+archive/2026-06.md) - Older runs (S66 #290 ← S62 #286 06-13 ← … → S29 #232) full verbatim archived → git
d2f52ba+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.
🔄 Curate trigger
-
~30KB → archive recent runs → L2
archive/<period>.md. Dup failure patterns → merge. Stale >3mo → remove. - Last curate: 2026-06-16 S66 em main (86.8→29.2KB — 2.9× over-cap fix): byte-exact
sedmove 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.