Files
solution-erp/.claude/agent-memory/cicd-monitor/MEMORY.md
pqhuy1987 f8f2ef964c [CLAUDE] Docs: YC-028 đóng trọn — gotcha #89/#90/#91 + RCA YC028-S189 + STATUS row 88→91 + run-trace cicd 2 vòng
Sự cố prod 3 tầng (A/059 "ko tìm thấy phiếu") giải trọn trong phiên, chi tiết error-ledger RCA YC028-S189:
- T1 disk 0-byte (cache automation 30GB) → #89 · T2 orphan-sshd bão hòa 3 core (lỗi lead, tự khai) → #90
- T3 lộ khi ship: Gitea tầng-app câm nuốt push (0 run dù mọi tín hiệu xanh) → #91; restart + dispatch
  → run #486 ship trọn (gate 680 EXACT · bundle rotate ×2 · marker 10/10 — cicd-monitor 2 vòng PARTIAL 8/9)
- Vá RAM cùng lượt: sp_configure max server memory unbounded→1200MB (PLE 522→1123 · A/059 0,58s)

Sổ: +YC-028 4 tầng xử · run-trace sub-cicd-monitor-yc028.md (FAIL vòng-1 giữ nguyên làm vết,
vòng-2 append) · AS-10 cicd-monitor tự-curate memory qua Bash (persona 0 Write) = verify-KEPT
(27,4→17KB + archive/_INDEX đúng khuôn + sửa stale Mig 71→72 đúng canonical) · squash wal: theo §5.0.
Docs-only ⇒ CI skip (đã đối chứng #486 xong trước khi push — không đụng #86).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-11 12:13:20 +07:00

111 lines
17 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CI/CD Monitor Agent — Persistent Memory
- **S189 (08-11) `92d8215a` YC-028 FE tách 404⟂lỗi-hệ-thống (8 FE, **0 BE**, 0-mig) — V1 FAIL 8/11 → V2 PARTIAL 8/9.** 🔴 **V1 = KHÔNG CÓ RUN ĐỂ MÀ ĐỎ**: push land, `ls-remote` đúng sha, mà **0 ActionRun**/484 task. 🔑 **DETECTOR #91 = 2 nguồn LỆCH trong CÙNG 1 API:** `/repos/{r}``updated_at` đọc **DB** = giờ push TRƯỚC ⟂ `/branches/main``commit.id` đọc **git trên ĐĨA** = sha mới ⇒ ref tiến trên đĩa mà tầng app chưa hề thấy push. **Stage 2 từ nay ĐO `updated_at ≥ giờ push` TRƯỚC khi kết luận 'đang chờ CI'.** Terminal push SẠCH ⇒ chết ở **notifier**, không ở receive-pack. Sửa = `workflow_dispatch` (204). 🔴 Nguy vì **mọi tín hiệu quen đều XANH** ⇒ chỉ **vắng-mặt thứ đáng lẽ có** mới tố cáo. 🔑 **CẶP ĐỐI-CHỨNG dập nghi-oan filter** (commit anh em có/không file non-ignored → có/không run). 🔑 **V2 SHIP PASS TRỌN:** gate **680 EXACT** Δ0 · JS rotate ×2 + **size prod khớp log CI TỚI BYTE** · marker **0→5/app = 10/10** · hash cũ→`text/html`. 🔑 **CSS không rotate mà vẫn ĐÚNG** (0 class Tailwind mới) — **JS đổi ⟂ CSS giữ = đúng hình dạng diff**. 🔴 **V2 FAIL: A/059 6/16 mẫu >3s (max 8,75s).** **Tự bác cold-start của chính mình vì burst-2 XẤU HƠN burst-1***warm-up curve đẹp KHÔNG đủ, phải đo burst THỨ HAI*. Loại trừ runbook (disk 28,2GB · orphan 0 · `AUTO_CLOSE=0`) → **RAM 4GB ép**: SQL `Total 213MB/Target 1,09GB`, PLE 522s ⇒ **LƯỠNG CỰC 0,6-1,0s vs 5-8,7s, trống ở giữa = hình dạng THIẾU RAM, không phải code chậm**. 🔑 **Logic rẻ hơn đo: commit 0 file BE ⇒ latency không thể do commit này.** 🔴 **Tự nhận:** `Restart-Service gitea` (khuyến nghị của chính tao) làm gitea tái chỉ mục 317MB+512s CPU/25ph, giành RAM/CPU với SQL ĐÚNG lúc đo — phải nói ra, không giấu vào chữ 'transient'. Treo: ghim `max server memory` · **nâng RAM = mặt thứ 2 của YC-028 (trước vỡ ĐĨA, nay ép RAM)** · `compact /u` `Vietreport_Master.mdf` (#88). Evidence `runs/2026-08-10-S189-bookstart-open/sub-cicd-monitor-yc028.md`. Tag `[s189, gotcha-91, detector-updatedat-vs-branchhead, burst2-bac-coldstart, luong-cuc-thieu-RAM, tu-nhan]`
- _(**S159 (07-29) — 4 đợt PASS/PARTIAL** [harvest hồi-tố @S172]: đợt-2 `1a47a61` PARTIAL bắt regression revoker 447/494 row → đợt-3 đóng bằng **3 chân kiềng** → đợt-4 tái xác nhận ⇒ **durability phải đo ≥2 restart**. 🔑 **control ÂM đọc ở tầng BUNDLE, không tầng source**. verbatim → `archive/2026-08.md`)_
- _(**S168 (08-01) `0bfadc2` — PASS 6/6**: #444, gate 644 Δ+5 đúng 5 Fact mới. 🔑 **WIRE-PROOF = 400 GỌI TÊN FIELD** (mạnh hơn 401; chứng pool phục vụ BINARY MỚI mạnh hơn `w3wp` StartTime). 🔑 **CHỤP PRE NGAY khi vào việc** → differential thật 404→401, 0→1. 🔑 marker **BẤT-ĐỐI-XỨNG** · CSS = nhân chứng ARTIFACT KHÁC. verbatim → `archive/2026-08.md`)_
- _(**`aaed699` S167 K7 — PARTIAL 4/6+1**: #442 (run #441 CANCELLED). 🔴 **PUSH-ĐÈ NUỐT DEPLOY = gotcha #86**. 🔑 control-dương = chuỗi bản TIỀN-commit của CHÍNH file đang sửa. 🔑 seeder báo **2/3 upgraded** = chứng idempotent tầng-row miễn phí. ⚠️ `appcmd list wp` map PID→pool. verbatim → `archive/2026-08.md`)_
- _(**`1c6d77a` S167 K6 menu 12-key — PASS 5/5**: #440, gate 622 Δ0. 🔴 **0-hit marker SAI 2 LẦN do CƠ-CHẾ REGEX** (minify→BACKTICK · pattern-chứa-backtick qua biến làm `grep -cE` gãy IM LẶNG) ⇒ **LUẬT `grep -F`/python + trích byte thật TRƯỚC khi kết luận vắng-mặt**. 🔑 **COUNT-DELTA** khi literal đã tồn tại. 🔑 menu ẩn 12/12 mà route 68→68 ⇒ **ẩn client KHÔNG thu quyền** (#82). verbatim → `archive/2026-08.md`)_
- _(**Arc S155→S166 (#416#439)** gate 551→622. 🔑 #438 **mốc PRE trong đề bài LÃO HOÁ sau MỖI deploy — bắt bằng ĐO**. 🔑 #436 marker = tên biến local thì 0 bit. 🔴 **#435 ACCEPTANCE CHÂN-LÝ-RỖNG** (`0==0` xanh mà 0 bit). 🔑 #434 TAM-GIÁC 3 nguồn. 🔴 #432 CẤM `HEAD~1` → neo `X^..X`. 🔴 #423 revoker lật 447/494 vì **đo TRƯỚC recycle**. verbatim → `archive/2026-08.md`)_
> **Persistent diary cross-session.** Auto-injected first ~200 lines at spawn (L1 HOT).
> Update BEFORE every stop. Tiered Memory v1: L1 HOT soft-cap ~30KB · L2 `archive/` on-demand · L3 RAG `search_memory` just-in-time. Keep entry ≤ 1.5K chars (gotcha #53).
> Verbatim cũ → `archive/2026-0{5,6,7,8}.md` (+ `2026-05-{runs,q2,q3,q4}`, `.gist`) + git `d2f52ba`. 🗺️ **Lookup: `archive/_INDEX.md`** — 1 dòng/bản-ghi + con-trỏ substring (sha-keyed).
---
## 🎯 Role baseline
Read-only CI/CD + post-deploy verifier SOLUTION_ERP. Poll Gitea Actions API, verify test-gate + deploy-ship + prod health. Output PASS/FAIL + evidence <500 words. Skills: `iis-deploy-runbook` · `dependency-audit-erp` · `ef-core-migration`.
---
## ⚠️ cicd-lane return-garble tracker (#53)
cicd-lane trả nhầm slice transcript thay verdict **tao TÁI PHẠM dai nhất roster** (×5/6 qua S114; S117/S118 ×3 [[feedback_agent_return_garble_recover]]). Từng tự dán nhãn 'CLEAN-return' SAI **KHÔNG tự phong return sạch**. 🔒 **Đối-sách: ghi-đĩa TRONG LÚC LÀM** prompt KHÔNG chặn được, artifact mới chặn file trong run-folder SẢN PHẨM CHÍNH, kết bằng `END … VERDICT=`; return chỉ tóm tắt.
---
## 🚨 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`. KHÔNG revert.
- **#40 npm cache `tsc not found`** `build_fe_admin` fail post `cache: npm`. DISABLED rolled back `a21790d`. KHÔNG re-enable.
- **#41 paths-ignore docs-only skip** check `git diff --name-only <base>..<head>` vs **7-glob** `['docs/**','**/*.md','.claude/skills/**','.claude/agent-memory/**','.claude/workflows/runs/**','.gitignore','scripts/**.md']`. Gitea đọc *range* 1 file non-ignored build. **AS-6: memory-push/run-trace HẾT trigger CI.** @S189: filter ĐÚNG vẫn 0 run xem **#91** trước khi đổ tại filter.
- **#25 IIS WebSocket** `notification-hub/negotiate` 401/404 prod. Fix: WebSocket module enable `web.config` site api (skill `iis-deploy-runbook`).
- **#48 SQLite tie-break** `OrderByDescending(CreatedAt).First()` pick wrong khi 2+ `.Add()` cùng frozen-clock. Fix: discriminator filter BEFORE OrderBy.
- **Bundle hash unchanged ship FAIL (đọc #69 bên dưới trước).** Đọc hash qua INDEX.HTML (`curl -s https://admin… | grep -oE '/assets/index-[A-Za-z0-9_-]+\.(js|css)'`), KHÔNG GET thẳng asset. verify PHẢI sau `status=success` (Run #242 false-positive: đo lúc 'running' hash stale).
- **🔴 #69 TWO-MODE FE hash vừa thể ROTATE vừa thể FROZEN.** deploy.yml copy `dist\*` UNCONDITIONALLY 0-FE-change vẫn rotate (mode-A); src y hệt Vite byte-identical FROZEN (mode-B). **Cả hai lành tính ⟹ hash-delta KHÔNG phải ship-proof.** Ship-proof THẬT = `Last-Modified` in-window + real-size khớp log CI + byte-marker. LM **cũ** = deploy không chạm file (cờ đỏ).
- **⚠ SPA-fallback 200 trap (S72):** server rewrite `/*``index.html` GET `/assets/index-<BỊA>.js` vẫn **200**. Discriminator sạch = **`Content-Type`** (`text/html` ~876-900B = trap · `application/javascript` ~1,8MB = thật). **Hash CŨ rơi về text/html = bundle cũ đã bị ghi đè = control âm tầng-2.**
- **🔴 Durability: đo SAU recycle + 3 CHÂN KIỀNG** pool restart CUỐI deploy-window query DB lúc `running` = trạng thái (tao sai đúng chỗ này @#423). Khuôn: (i) chứng minh restart thật (`w3wp` StartTime in-window), (ii) đo chỉ-số đích SAU mốc đó, (iii) **control ÂM chứng checker còn sống**. @S189: w3wp mới sinh **vài request đầu là cold-start, đừng lấy làm số perf**.
- **Migration drift prod vs repo** compare `ls .../Persistence/Migrations/*.cs` vs `sqlcmd __EFMigrationsHistory`. Fix: check `Program.cs`/DbInitializer `app.MigrateDatabase()` + app pool recycle. Mig-applied proof = `__EFMigrationsHistory` top==repo-HEAD; stuck-old pool didn't recycle FAIL even if status=success+bundle-rotated.
---
## 📋 5-stage checklist (EVERY run)
- **Stage 0 RAG infra:** `Get-Service Qdrant` Running + `http://localhost:6333/healthz`. Collection `proj_solution_erp`.
- **Stage 1 Push+filter:** `git log -1 --format='%H %s'` + `git log origin/main..HEAD` empty + diff vs paths-ignore (docs-only SKIPPED-DOCS return).
- **Stage 2 Gitea poll** (max 10 iter × 60s): API `.../actions/tasks?limit=5` (NOT `/runs` 404). Match `head_sha` (NOT run_number cancelled runs shift numbering). `updated_at` stale ~2min (gotcha #46) cross-check VPS mtime. Foreground-sleep BLOCKED Windows Monitor-style busy-wait-curl-spin ~30s/iter.
- **Stage 3 Test gate:** baseline **680 PASS** (45 Domain + 635 Infra; run #486 `92d8215a` 08-11; climb 680/645/644/639/622/614/609/598/590/566/551/532/509). CI chạy cả 2 proj TRƯỚC build/deploy `status:success` = gate passed (`tasks` KHÔNG populate `conclusion` tin `status`). Local grep undercount (Theory/InlineData).
- **Stage 4 Post-deploy** (if SUCCESS): login bearer (admin + nv.test #44; token=`accessToken`) smoke 2XX (**NEW-endpoint bodyless-POST = 411 pre-auth NOT 404**; re-probe WITH body 401 = đã wire; 415 cùng lớp) bundle 2 app (#69: real-size, KHÔNG hash-delta) SignalR (#25) mig prod==repo.
- **Stage 4.6 (S29):** sqlcmd seed verify post-deploy (NOT chỉ schema) seed = runtime-row-insert (history/tables KHÔNG nhích) verify bằng DB-query, không bằng bundle-frozen.
- enum cần input SỐ (no `JsonStringEnumConverter`). INFRASTRUCTURE seed ungated / DEMO seed gated #51.
- **Stage 5 Report** PASS/FAIL + evidence + MEMORY update.
---
## ⚠️ Anti-patterns (DO NOT)
1. 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 (S80 verified — re-ground từ docs/STATUS.md canonical)
- **Gitea:** `git.baocaogiaoduc.vn/vietreport-admin/solution-erp` · workflow `.gitea/workflows/deploy.yml` · paths-ignore 7-entry (D10 S111 #495): `['docs/**','**/*.md','.claude/skills/**','.claude/agent-memory/**','.claude/workflows/runs/**','.gitignore','scripts/**.md']`. Anon API works (public repo) when GITEA_TOKEN absent.
- **Prod:** `.solutions.com.vn` (api/admin/eoffice) · `ssh vietreport-vps` · IIS `C:\inetpub\solution-erp\{api,fe-admin,fe-user}`. DB `.\SQLEXPRESS`/`SolutionErp`, key **`ConnectionStrings.Default`**. **VPS chỉ 4GB RAM/3 core, chung với VIETREPORT** (@S189 SQL buffer 213MB/1,09GB API lưỡng-cực). **SSH→PS: viết `.ps1` + `scp` + `powershell -File`**, đừng inline. 🔴 **CẤM `ssh … | head`** `Select-Object -First N` phía REMOTE.
- **SSHPS quoting (S42):** bashsshpowershell nuốt `$var`/`\"` viết `.sql`/`.ps1` rồi `scp` + `sqlcmd -i` / `powershell -File` (đừng nhét inline). sqlcmd `-W -h -1` pw-inline. sys-catalog concat `COLLATE DATABASE_DEFAULT`.
- **Tests baseline: 680 PASS** (45 Domain + 635 Infra · 0 fail/skip) xác nhận lại run **#486** `92d8215a` 08-11 (prev #482). 🔑 Số lấy web-UI log `…/actions/runs/{run_number}/jobs/0/logs` (~18KB, KHÔNG `/api/v1/`) mỗi project 1 dòng `Passed! - Failed: 0, Passed: N, Skipped: 0`; đối chiếu **TÁCH-PHẦN** (45/635) chứ đừng chỉ khớp tổng, **so delta với số Fact mới khai trong commit-msg**.
- **Mig latest repo: Mig 72 `AddMaHangMucToContractSigningPlanLines`** (`20260806070242`) đo đĩa @S189 = **72** (🧊 ô này từng kẹt **71** tới S189). 🔴 Đếm phải **NEO ĐUÔI** `grep -vE 'Designer\.cs$|ModelSnapshot\.cs$'`. Mạnh hơn khớp-tổng = **set-diff repo↔prod 2 chiều** (`comm -23`/`-13` cùng rỗng). Prod: `sqlcmd -S .\SQLEXPRESS -d SolutionErp -E` (⚠ `$env:PROD_DB_PASSWORD` KHÔNG trên VPS). `sys.tables`=**97**. **NO-Mig proof = history NOT-advance + empty `git diff <base>..<head> -- '*Migrations*'`.**
- **Bundle hash live:** baseline **#486 (08-11)** admin `DxSej4Da`/`DVHtHLex` · eoffice `BcfxaUBO`/`Ibv3QD_1` (JS 1.815.258/1.794.780 B). 🔑 Ship-proof rẻ nhất = size prod khớp dòng `dist/assets/…` TRONG LOG CI (tới byte). marker minify ra **BACKTICK** `grep -F`/python. **re-snapshot LIVE sau status=success** (#69). id run_number (key theo head_sha).
- **Prod DB anchor (POST #438, đứng im tới #444):** `MenuItems`=**200** · `Permissions`=**2221** · `Roles`=**13** · họ `Khkk%` = 56 menu / 728 perm (=56×13) · control revoker `Hrm*/Off*` CanRead=1 = **29**/377. PK `MenuItems` = **`[Key]`** (KHÔNG `MenuKey`); `Permissions(Id,RoleId,**MenuKey**,CanRead,CanCreate,CanUpdate,CanDelete)`.
- **Bearer:** admin `admin@solutions.com.vn/Admin@123456` (full) · UAT `nv.test@solutions.com.vn/TestUser@123456` (Drafter CCM, gotcha #44 check).
- **API Serilog:** sink THẬT `C:\inetpub\solution-erppi\logs\solution-erp-YYYYMMDD.log` (skill-runbook `…\Logs\log-*.txt` STALE). Level=Information (seed/revoke lines ghi). deploy xoá `logs/` chỉ còn từ deploy cuối.
## 🔑 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 opt-in wire (S22-S23)** `feedback_per_nv_permission_scope` (10 điểm). 2 điểm HAY SÓT: **(9) Lookup discrimination** (`FirstOrDefault` thêm `ApproverUserId==actorId` + admin fallback) · **(10) Controller body record count == Command record count**.
## 📊 Run stats baseline
BE ~90s · FE ×2 ~60s/app · deploy ~30s · **total ~3min code / 0s docs-only**; gần đây 5m3x-6m3x. >8min → escalate.
---
## 📅 Recent runs (compressed — verbatim → archive via `_INDEX.md`)
- _(**#447 `998ea55` KHKK 3-panel — GO/PASS**: gate 644 Δ0, **set-diff Mig 2 CHIỀU = 0/0**. 🔑 **cặp đối-chứng MIỄN PHÍ** #446/#447 khác đúng 1 commit ⇒ cô-lập nhân-quả. 🔑 **415 = họ hàng 411**: json vào endpoint multipart bị loại TRƯỚC authz ⇒ **mọi mã pre-auth phải re-probe đúng dạng**. 🔴 **'KHÔNG ĐO ĐƯỢC' phải TỰ NGHI** — khai credential chết = SAI, chỉ **tra nhầm sổ** (`docs/HANDOFF.md`). verbatim → `archive/2026-08.md`)_
- _(**S98-S132 #383-#397 + PASS-pattern library S69b→S104** all GO (gate 440→509): AS-6 #41 soi TỪNG file vs 7-glob · `conclusion:None` dù success ⇒ tin `status` · **411-refine** · **LM mới hơn cửa-sổ đã verify = detector 'có run bỏ sót'** · recipe SCHEMA-ADD / DATA-BACKFILL / DATA-SEED · #472 PROD Identity table NON-prefix `Roles`. verbatim → `archive/2026-07.md`+`2026-06.md`)_
- **Older (S83 #325 ← S29 #232) → git `d2f52ba` + `archive/2026-06.md`** (incl #291 06-16 FAIL [gotcha #65]); pre-S38 → `archive/2026-05-*`.
---
## 🔄 Curate trigger
- >~30KB → archive recent runs → L2 `archive/<period>.md` (byte-exact append) + `_INDEX.md` substring pointer. Dup failure patterns → merge. Stale >3mo → remove.
- **Last curate: 2026-08-11 S189 (self, 27.4KB→~16.6KB — S159/S168/ARC-S155-S166/#447/S182 verbatim→`archive/2026-08.md` + `_INDEX` pointer; baseline refresh gate **680**, Mig **72** (was stale 71), bundle **#486**).** ⚠️ giữ luật: script sửa MEMORY phải build chuỗi XONG → temp → `os.replace` → verify byte>0.
- **Prev:** S166 08-01 (27.3→16.5) · S162 07-30 (26.9→17) · S118 · S111 · S107 · S104 · S98 (`2026-07.md` NEW) · S80 38.8→16 · S70 65.2→23.2 · S66 · S40.
- _(**S182 YC-013 W0.4 — Q2 sai tiền-đề nhưng W1 GO**: **ký-ức đóng-băng-thời-điểm ≠ ký-ức hỏng** — chỗ gãy là SPEC phổ-quát-hoá mốc cũ. 🔑 pin-lệch 0 row **VỚI control** (bỏ vế phủ-định ra 12 row). 🔑 **hiệu chuẩn thước bằng 2 ANCHOR đã biết** mạnh hơn `count>0`. verbatim → `archive/2026-08.md`)_
## S188 (2026-08-10) — [LEAD SEED ON-BEHALF]
- _(**S188 (08-10)** #481 + cụm PASS 5/5 #482: bundle rotate ×2, seeder prod 7 HD-*, DLL marker `ContractWorkflowGuards` 0→4, smoke 9/9. 🔑 **tự đính chính trong lượt**: 'HD-*=0' là **ARTIFACT PARSE của chính mình** — suýt FAIL oan.)_