STATUS/HANDOFF (Mig 55->56, test 339->344, gotcha 69->70, bundle jOqxW4-p/DbsznVvR Run #319, Phase +S76, In Progress->Recently Done) + gotcha #70 (FE absolute-set echo stale-echo data-loss -> useIsFetching gate) + ef-core skill Mig 56 row + session log 2026-06-19-S76 + agent-memory harvest (impl-FE stray->canonical + 4 sub diary). Curate-debt carry: reviewer 45KB + inv-codebase 35KB keep-floor-hit manual-condense. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
27 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+archive/2026-06.md. 🗺️ Lookup map (Harness-9 S70):archive/_INDEX.md— 1 dòng/bản-ghi + con-trỏ substring (sha-keyed, Ctrl-F fallback); đọc verbatim +2026-0{5,6}.gist.md(nén 4-field) theo nhu cầu.
🎯 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 via INDEX.HTML ref (
curl -s https://admin.solutions.com.vn/ | grep -oE '/assets/index-[A-Za-z0-9_-]+\.(js|css)'), NOT by GETting a hash-named asset directly. Fix: SSHRestart-WebAppPool. ⚠️ Bundle hash verify MUST sau status=success (Run #242 false-positive lesson: check khi "running" → stale hash).- 🔴 #69 (S72 Run #312 OVERTURNS prior invariant) — FE bundle hash is NON-DETERMINISTIC per rebuild.
deploy.ymlRemove-Item fe-{admin,user}\* -Exclude web.config+Copy-Item dist\*runs UNCONDITIONALLY every run (path-filter gates whole-workflow trigger, NOT per-step). Identical FE source ⟹ DIFFERENT hash each deploy (Vite/rolldown non-reproducible chunk-id). PROVEN: governance-only18fced6(0 files in fe-*/src) rotated BOTH bundles adminBgNCjwsG→fc_xkNpJ(+717b) + userCBvh0vtf→DP-tBcg0, index.htmlLast-Modifiedmatched deploy window. ⟹ "BE-only/governance ⟹ bundle MUST stay frozen" is FALSE; rotation is EXPECTED on every deploy. Bundle-rotate alone is NOT proof of FE content change — to detect real FE change, difffe-*/srcin commit/range, NOT hash delta. - ⚠️ SPA-fallback 200 trap (S72): server rewrites
/*→/index.htmlso GET/assets/index-<ANYTHING>.jsreturns 200 even for non-existent/fake hash (controlZZdoesnotexist0.js→200 confirmed). Old-hash-still-200 is MEANINGLESS as persistence signal. RELIABLE bundle signal = parse index.html<script src>/<link href>, then GET that exact path + checksize_downloadlarge (not white-screen) +Last-Modifiedin deploy window.
- 🔴 #69 (S72 Run #312 OVERTURNS prior invariant) — FE bundle hash is NON-DETERMINISTIC per rebuild.
- 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 55
20260618105426_AddCcmNoteToPeWorkItemBudget(S74-bis Run#315 sha 8655ebf; PeWorkItemBudgets +CcmNote nvarchar(1000) nullable— 1 AddColumn no new table — VERIFIED APPLIED PROD: history-top==repo, sys.columnsnvarchar maxlen=2000 null=1[2000=byte-len 1000char×2], tables88). Prev Mig 54AddPeSuggestedAndApprovedPrice(S73 #313, 5 PE price cols) + Mig 5320260617060207_AddPeUrgentAndCeoApprovalThreshold(S71 Run#308; PE +IsUrgentByPro/+IsUrgentByCcm bit-default-0 + ApprovalWorkflows +CeoApprovalThreshold decimal(18,2)-nullable, 3 AddColumn no new table — VERIFIED APPLIED PROD). Prev Mig 52AddHoSoLinkToPurchaseEvaluation(S65 PE HoSoLink hyperlink-NAS) + Mig 51AddDepartmentParentId(S65 org-tree loose-Guid) + Mig 50ReplaceBudgetModuleWithPeWorkItemBudgets(S61 net-reduce). Pathsrc/Backend/SolutionErp.Infrastructure/Persistence/Migrations/(53 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
jOqxW4-p+ cssDyECY611· userDbsznVvR+ cssJQfATaQB(Run #319 sha21d1f4eFE-only PeDetailTabs Block-A table-grid; index.htmlLast-Modifiedadmin 2026-06-19T04:31:53Z + user 04:32:45Z = deploy window; admin css ALSO rotated [Block-A real style] but user cssJQfATaQBFROZEN = asymmetric-ok gotcha#69). Prev #318: adminBhFDF9IJ/cssDuqjXB6Y· userBAkuRl3C/cssJQfATaQB. Prev #315: adminBYF5vIMJ/userCB-tiRxd. ⚠️ PER #69 (S72): bundle hash ROTATES on EVERY deploy regardless of FE change (non-deterministic rebuild). So "live hash" value is only a SNAPSHOT for THIS run — do NOT treat it as a frozen-baseline to compare next run against. To detect a real FE ship, difffe-*/srcin commit/range — NOT hash delta. ASYMMETRIC-deploy "anomaly" framing (S66) is RETIRED by #69: both apps rebuilt+rotated every deploy, asymmetry impossible to read from hashes alone. S50 mid-deploy transient lesson still holds: re-confirm hash AFTER status=success ALWAYS (anti-pattern #3). - 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)
-
(S72 Run #312 sha=
18fced6PASS ~5m16s [governance-only 26-md+hmw.js+memory-budget.json triggers-CI, ZERO prod code, Mig53-unchanged-VERIFIED-prod, tables88, health-4x200, test306-inferred, BUNDLE-BOTH-ROTATE-but-BENIGN fc_xkNpJ/DP-tBcg0 → NEW gotcha #69 (FE-hash NON-deterministic per-rebuild, deploy.yml Remove+Copy fe-* UNCONDITIONAL every run, "frozen-on-BE-only" invariant OVERTURNED, SPA-200-trap control-test, real-FE-change =git diff fe-*/srcNOT hash-delta), 0-fe-src-diff-confirms-no-accidental-ship] → gotcha #69 promoted to recurring-patterns §top; FIFO-trimmed, full verbatim git18fced6+39d55d4) -
(S71 Run #308 sha=
ebd7e1cPASS ~4m41s [FULL-STACK PE-urgent+CCM-threshold, Mig53 AddPeUrgentAndCeoApprovalThreshold VERIFIED-APPLIED-PROD 3-cols-sys-columns (IsUrgentByPro/Ccm bit0 + CeoApprovalThreshold decimal18-2-null), history-top-advance-53, tables88-addcolumn-only, bundle-BOTH-rotate BgNCjwsG/CBvh0vtf, endpoint-urgent-401-not-404, test306] → 4-axis full-stack pattern (BE+FE-both-rotate · history-top-advance + N-cols sys.columns type-verify · tables-stay-88 · endpoint-401-not-404); FIFO-trimmed, full verbatim gitebd7e1c) -
2026-06-19 S76 Run #318 (run_number 318, id=432) sha=
e33481ePASS ~4m58s (FULL-STACK: BE Mig 56AddProBudgetSplitToPeWorkItemBudget— PE ngân-sách MA-TRẬN 3 cột Dự-án|PRO|CCM, PRO split số ban-hành + điều-chỉnh + badge quyền NS theo role; anh Kiệt FDC continuation Mig 50/53/54/55. 19 files: BE 9 {Controller, App ApprovalWorkflowV2AdminFeatures+PurchaseEvaluationDtos+PeWorkItemBudgetFeatures+PurchaseEvaluationFeatures, Domain PeWorkItemBudget.cs, Config PeWorkItemBudgetConfiguration} + 3 Mig-file + FE 6 {PeDetailTabs+PeWorkflowPanel+types ×2-app, admin +ApprovalWorkflowsV2Page} + 1 test PeWorkItemBudgetTests + .gitignore. deploy 17/17 session after #297–#315 all PASS): Push HEAD=e33481e(nothing unpushed).git diff --name-only e33481e~1 e33481e -- '*Persistence/Migrations*'= 3 files (Mig 56 .cs/.Designer.cs/Snapshot) — REAL EF mig. Mig56 Up() read = 2×AddColumn<decimal>:ProAdjustmentAmount+ProInitialAmountboth decimal(18,2) precision18 scale2 nullable +migrationBuilder.Sql(UPDATE PeWorkItemBudgets SET ProInitialAmount=ProEstimateAmount WHERE ProEstimateAmount IS NOT NULL AND ProInitialAmount IS NULL)data-migrate (phiếu cũ 1-cột giữ số PRO ở cột ban-hành); Down() 2× DropColumn — matches spec exactly, AddColumn-only no new table..cs/.tsxnon-ignored → full pipeline RAN. GITEA_TOKEN+PROD_DB_PW BOTH absent env → anon Gitea API (worked, public repo) + DB pw read prodappsettings.Production.json→ConnectionStrings.Default(vrapp/buKL3TGBkD0wDDbYVw65QeX9,.\SQLEXPRESS/SolutionErp, pathC:\inetpub\solution-erp\api). Run IN-PROGRESS at spawn (running 11:03:00, exact head_sha match #318 deterministic; NOTE prompt said "Run #316" but #316=CANCELLEDae957c4— actual run fore33481e= #318 matched by head_sha NOT run_number). ★ PRE-DEPLOY DB SNAPSHOT captured BEFORE poll-loop (proves deploy hadn't shipped): prod history-top = Mig 55AddCcmNoteToPeWorkItemBudget, ProInitial+ProAdjustment cols ABSENT (only ProEstimateAmount present), tables88. Pre-poll bundle baseline (anti#3): adminBYF5vIMJ/cssX_45M1jX+ userCB-tiRxd/cssBbbo0M5H= still #315 live. Poll-loop iter6 status=success (created 11:03:00→success 11:07:58 ≈4m58s; iter1-5 running). CI gate (both proj pre-build ⟹ status=success ⟹ test 344 expected (45D+299I; +1 PeWorkItemBudgetTests vs #315's 339) passed;conclusionempty —tasksterminal=status:successdoesn't populate conclusion, trust success; 344 INFERRED gate-passes-pre-build NOT log-confirmed numeric). 🔑★ MIG 56 VERIFIED APPLIED PROD (sqlcmd-over-SSH ground-truth, POST-deploy re-query): history-top advanced Mig55→Mig5620260619024427_AddProBudgetSplitToPeWorkItemBudget== repo HEAD ✓ (DbInitializer auto-migrate-on-boot ran on app-pool recycle). BOTH cols EXIST sys.columns:ProAdjustmentAmountdecimal len9 prec18 scale2 null=1 ✓ +ProInitialAmountdecimal len9 prec18 scale2 null=1 ✓ — match Mig 56 spec. sys.tables=88 UNCHANGED — 2 AddColumn no new table ✓. ★ DATA-MIGRATE VERIFIED: 4 rowsProEstimateAmount IS NOT NULL AND ProInitialAmount=ProEstimateAmount(backfill ran on prod data) + 0 violation rowsestimate-set-but-initial-null✓ — UPDATE-Sql executed on real prod data per gotcha #64. ★ BUNDLE BOTH ROTATE (FE 2-app PeDetailTabs+PeWorkflowPanel + admin ApprovalWorkflowsV2Page ⟹ both EXPECTED per gotcha #69; verified AFTER status=success + STABLE 2nd-fetch no-transient per anti#3): admin JS ROTATEBYF5vIMJ→BhFDF9IJ+ cssX_45M1jX→DuqjXB6Y✓ (css rotated too — admin had real style change ApprovalWorkflowsV2Page) + user JS ROTATECB-tiRxd→BAkuRl3C+ cssBbbo0M5H→JQfATaQB✓. Asset reachable 200 + LARGE: admin js 1,603,616b + user js 1,507,842b (control fake/assets/index-ZZfakehash0.js→200 size 919b/895b SPA-fallback ⟹ real JS shipped, gotcha #69 SPA-200-trap distinguished by size). index.htmlLast-Modifiedadmin 04:06:36Z + user 04:07:28Z (=11:06-11:07VN deploy window) ✓. Smoke 4×200 health: api/health/ready+/health/live+ admin root + eoffice root. 0 regression. NO prod-data mutation (read-only curls + sqlcmd SELECT-only; mig-apply+backfill-UPDATE+FE-copy = expected boot/deploy side-effects). Behavioral PRO budget-matrix 3-col + role-badge = anh Kiệt UAT (em confirm Mig56+2cols+backfill+bundles shipped per spec). VERDICT PASS: green CI + test 344 + Mig 56 applied (ProInitial+ProAdjustment decimal(18,2) sys.columns ground-truth, history advanced 55→56) + tables 88 + backfill 4-rows-0-violation + bundle BOTH rotate (css too) + health 4×200. LESSON: full-stack-2-AddColumn-WITH-DATA-MIGRATE = S74-bis 4-axis + 5th-axis BACKFILL-VERIFY (count rows where new-col=source-col AND 0 violation) — gotcha #64 prod-data-UPDATE-runs-first-time confirmed real. PRE-deploy snapshot at spawn (Mig55+cols-absent) → POST-deploy (Mig56+2cols+4-backfill) = unambiguous proof, best-practice capture-baseline-before-poll when run still building. admin css ALSO rotated (real ApprovalWorkflowsV2Page style) — distinguishes from S74-bis css-frozen (tab-logic-only). Mig-applied proof =__EFMigrationsHistorytop==repo-HEAD; if stuck Mig 55 ⟹ app pool didn't recycle ⟹ FAIL even if status=success+bundle-rotated. TOOLING: bash POSIX → write PS to$LOCALAPPDATA/Temp/x.ps1+powershell.exe -File $(cygpath -w ...); Giteatasksvia Invoke-RestMethod-Body @{limit=N}hashtable; poll-loop backgrounded + grep-until FINAL; SSH→PS base64-EncodedCommandUTF-16LE for appsettings-read AND sqlcmd; sqlcmd pw inline +-W -h -1. NEVER fixed code (READ-only). Tag[s76, run318, pass, full-stack-pe-budget-matrix-3col, mig56-AddProBudgetSplitToPeWorkItemBudget-VERIFIED-APPLIED-PROD, 2-cols-sys-columns-ProInitialAmount-ProAdjustmentAmount-decimal18-2-prec18-scale2-null, history-top-advance-55-to-56, tables88-unchanged-addcolumn-only, DATA-MIGRATE-backfill-4rows-ProInitial-eq-ProEstimate-0-violation-gotcha64-prod-data-update-first-time, bundle-BOTH-rotate-BhFDF9IJ-BAkuRl3C, css-BOTH-rotate-DuqjXB6Y-JQfATaQB-admin-ApprovalWorkflowsV2Page-real-style, asset-200-large-1.6MB-vs-fake-919b-spa-trap, last-modified-deploy-window-04-06-04-07z, health-4x200, test344-inferred-plus1-PeWorkItemBudgetTests, deploy17of17, pre-deploy-db-snapshot-mig55-then-post-mig56-unambiguous, prompt-said-316-but-actual-318-matched-by-head-sha-316-cancelled, anon-gitea-api-both-token-absent, behavioral-anh-kiet-uat, 5th-axis-backfill-verify-new]. -
(S74-bis Run #315 sha=
8655ebfPASS ~4m54s [FULL-STACK Mig 55AddCcmNoteToPeWorkItemBudgetCcmNote nvarchar(1000) VERIFIED-APPLIED-PROD sys.columns maxlen2000-bytelen, history-advance-54→55, tables88-addcolumn-only, bundle-BOTH-rotate Bv3jUCNo→BYF5vIMJ/BWlMBQz6→CB-tiRxd css-frozen, asset-200-large-vs-fake-919b, health-4x200, test339, pre-deploy-snapshot-mig54-unambiguous, prompt-said-314-actual-315-head-sha] → 4-axis full-stack (BE+FE-both-rotate · history-advance+col-type-verify · tables88 · health-4x200); FIFO-trimmed, full verbatim git8655ebf) -
2026-06-19 S77 Run #319 (run_number 319, id=433) sha=
21d1f4ePASS ~4m46s (FE-ONLY: PE ngân-sách Block A → bảng lưới<table border-collapse>viền ô giống Excel [cột Khoản mục|Dự án|PRO|CCM], anh Kiệt FDC phản-hồi. 2 files ONLY:fe-admin/src/components/pe/PeDetailTabs.tsx+fe-user/.../PeDetailTabs.tsx— identical 287-line change each app. deploy 18/18 session after #297–#318 all PASS): Push HEAD=21d1f4e(nothing unpushed).git diff --name-only HEAD~1 HEAD -- '*Persistence/Migrations*'= EMPTY +-- 'src/Backend/**/*.cs'= EMPTY ⟹ confirmed FE-only NO-migration NO-BE..tsxnon-ignored → full pipeline RAN (path-filter gates whole-workflow not per-step, gotcha #69). GITEA_TOKEN absent env → anon Gitea API (worked, public repo). Real-FE-change detection per gotcha #69 =git diff fe-*/srcPOSITIVE here (genuine<table>/<thead>/<tr>grid replacing prior layout — NOT just hash-delta noise). Run IN-PROGRESS at spawn (running, exact head_sha match #319; baseline #318=e33481econfirmed in tasks-list). Pre-poll bundle baseline captured BEFORE poll-loop (anti#3): adminBhFDF9IJ/cssDuqjXB6Y+ userBAkuRl3C/cssJQfATaQB= still #318 live (matches prompt-supplied prev exactly). Poll-loop iter5 status=success (created 11:28:28→success 11:33:14 ≈4m46s; iter1-4 running). CI gate (both test proj pre-build ⟹ status=success ⟹ test 344 [45D+299I, unchanged from #318 — FE-only no test delta] passed;conclusionempty —tasksterminal=status:successdoesn't populate conclusion, trust success; 344 INFERRED gate-passes-pre-build NOT log-confirmed numeric). ★ BUNDLE BOTH JS ROTATE (FE 2-app PeDetailTabs change ⟹ both EXPECTED per gotcha #69; verified AFTER status=success + STABLE 2nd-fetch no-transient per anti#3): admin JS ROTATEBhFDF9IJ→jOqxW4-p✓ (css ALSO rotateDuqjXB6Y→DyECY611— Block-A table has real style) + user JS ROTATEBAkuRl3C→DbsznVvR✓ (cssJQfATaQBUNCHANGED — user-app style untouched; asymmetric css fine per gotcha #69). Asset reachable 200 + LARGE: admin js 1,604,226b + user js 1,508,452b (control fake/assets/index-ZZfakehash0.js→200 size 919b/895b SPA-fallback ⟹ real JS shipped, gotcha #69 SPA-200-trap distinguished by SIZE not status). index.htmlLast-Modifiedadmin 04:31:53Z + user 04:32:45Z (=11:31-11:32VN deploy window) ✓. Smoke 4×200: api/health/ready+/health/live+ admin root + eoffice root. 0 regression. NO migration/DB check (FE-only, per spec). NO prod-data mutation (read-only curls only; FE-copy = expected deploy side-effect). VERDICT PASS: green CI + test 344 + bundle BOTH JS rotate (real-FE-source-diff confirmed) + real-JS-size 1.6MB/1.5MB vs fake-919b + health 4×200. LESSON: textbook FE-ONLY = 2-axis (BE-skip · BOTH-JS-rotate + real-size-vs-SPA-trap + Last-Modified-deploy-window). Real-FE-ship proof per gotcha #69 =git diff fe-*/srcnon-empty (here genuine<table>grid) — NOT hash-delta alone (hash rotates every deploy regardless). admin css ALSO rotated (Block-A real style) but user css frozen (user-app PeDetailTabs Block-A changed too BUT user css chunk unaffected) — asymmetric css normal, don't FAIL. Pre-poll baseline capture BEFORE running-run completes = best practice (matched prompt prev #318 exactly = clean diff). TOOLING: bash POSIX → write PS to/tmp/x.ps1+powershell.exe -File $(cygpath -w ...); Giteatasksvia Invoke-RestMethod-Body @{limit=N}hashtable; poll-loop backgrounded + grep-until FINAL/POLL-DONE. NEVER fixed code (READ-only). Tag[s77, run319, pass, FE-ONLY-2file-PeDetailTabs, pe-budget-blockA-table-grid-excel, NO-migration-NO-BE-confirmed-empty-diff, bundle-BOTH-JS-rotate-jOqxW4-p-DbsznVvR, admin-css-ALSO-rotate-DyECY611-blockA-real-style, user-css-frozen-JQfATaQB-asymmetric-ok-gotcha69, real-JS-size-1.6MB-1.5MB-vs-fake-919b-spa-200-trap-by-size, last-modified-deploy-window-04-31-04-32z, health-4x200, test344-inferred-unchanged-FE-only-no-delta, deploy18of18, baseline-318-e33481e-matches-prompt-prev, real-FE-ship-proof-git-diff-fe-src-not-hash-delta-gotcha69, anon-gitea-api-token-absent, pre-poll-baseline-before-running-run-completes, no-DB-check-FE-only-per-spec]. -
(S74 Run #314 sha=
6aa4dcbPASS ~5m12s [FE-ONLY empty-candidates guard PeWorkflowPanel ×2-app, no-mig-stays-54, bundle-BOTH-js-rotate OlNyG9OD→Bv3jUCNo/DSzSLVtL→BWlMBQz6, css-frozen, asset-200-large-vs-fake-919b, health-4x200, test334, no-DB-query-needed-FE-only] → LESSON: FE-only verify lightweight, skip Mig/sqlcmd when 0 migration in diff; FIFO-trimmed, full verbatim git6aa4dcb) -
(S69b Run #307 sha=
1f8947ePASS ~4m33s [BE-ONLY GOLIVE security "Văn phòng số" public Read+Create — NEWSeedAllRolesOfficeModulePermissionsAsyncboot-after-revoke, allow-list 16 Office key upgrade-only; GOLIVE-DB-VERIFIED-16of16-across-13-roles sqlcmd prod Permissions (ALLOW-16 R∧C all roles · EXCLUDED-3 only-Admin leak0 · HRM/Personal Drafter still-0 · admin-not-downgraded), bundle-BOTH-frozen Wt54PHYl/B99fMU6X (BE-only no-rotate), no-mig-top-mig52, tables88, test292] → LESSON: BE-only golive-seed verify CORE-proof = prod Permissions DB query NOT bundle-frozen alone (seed=runtime-row-insert NOT EF-mig → no history/tables advance); FIFO-trimmed, full verbatim git1f8947e) -
(S77 #303 sha
6983609, S76 #302, S75/S74 … pre-S78 verbatim → git764fe70+ archive — FIFO trimmed to keep L1 under soft-cap) -
(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) -
(S73 Run #313 sha=
1d86abcPASS ~5m22s [FULL-STACK Mig 54AddPeSuggestedAndApprovedPricePE giá-đề-xuất PRO/CCM + CEO chọn giá-chốt + CCM duyệt-done; 5 cols VERIFIED-APPLIED-PROD sys.columns ProSuggestedMin/Max+CcmSuggested+ApprovedPriceAmount decimal(18,2)+ApprovedPriceSource nvarchar all-null, history-advance-53→54, tables88-addcolumn-only, bundle-BOTH-rotate fc_xkNpJ→OlNyG9OD/DP-tBcg0→DSzSLVtL +css, asset-200-large-vs-fake-919b, NEW-ENDPOINT-PROBE PUT /suggested-price/pro unauth→401-NOT-404 route-exists class-Authorize +ccm→401 +list→401, health-4x200, test334, prompt-said-N-actual-313-head-sha] → 4-axis full-stack + endpoint-401-not-404-probe; FIFO-trimmed, full verbatim git1d86abc) -
(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) -
(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-17 S70 Harness-9 (em-main + Stage-B
wf_a58e0d15-beb) (65.2→23.2KB): L2 dark-matter recovery — 10 oldest run-records →archive/2026-06.md(ADDITIVE, original 58378B prefix byte-exact) +archive/_INDEX.md(mục-lục substring sha-keyed, Ctrl-F fallback, no line-hint) +2026-0{5,6}.gist.md(4-field, distill-gen:1). 0-byte-loss git+13 -0+ sha (Stage Cwf_9520d8cd-4fe+ em-main self-gate, 2 reviewer no-return). Kept foundation + 2 newest full #308/#307 + stubs. - Prev curate: 2026-06-16 S66 em main (86.8→29.2KB sed Run #286→#232 incl #291 forensic) · S40 q4.
- 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.