[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>
This commit is contained in:
pqhuy1987
2026-08-11 12:13:20 +07:00
parent 92d8215a62
commit f8f2ef964c
8 changed files with 390 additions and 27 deletions

View File

@ -15,6 +15,11 @@ chain:
3 sshd orphan 6,3 core-s/5s trên máy 3-core → kill (chừa chain mình) → 0,17-0,41s ×2 lượt.
🔴 BÀI HỌC MỚI: `ssh ... | head` = ĐẺ ORPHAN SPIN phía Windows-OpenSSH — cấm head trên
ssh output dài; recycle pool + đợi cold-start ~48s trước khi đo
[!] SỰ CỐ PHỤ lộ khi ship (5): Gitea nhận push `92d8215a` vào ĐĨA nhưng tầng app KHÔNG xử lý
(0 run, `updated_at` đứng mốc cũ — cicd vòng-1 FAIL-8/11 chẩn đúng "CI chưa từng được gọi";
kèm `gitea.log` 0-byte 11,5h). ĐÃ XỬ: Restart-Service gitea (log sống lại 31,9MB) +
workflow_dispatch API 204 → run #486 head=92d8215a RUNNING — cicd đang gác vòng-2 trọn.
Nợ ghi sau verdict: gotcha #91 (phép đo updated_at ⟂ branch-head, 2 nguồn cùng API)
[!] Hàng (1)-(6) YC-028 còn: (3B) bật cron archive_cleanup Gitea + decompress Vietreport_Master
[ngoài giờ — restart gitea vài giây] · (4) disk-watch vào cicd-monitor persona + runbook ·
(5) FE tách "lỗi hệ thống"⟂"không tìm thấy" ×2 app + CÂN NHẮC AsSplitQuery cho

View File

@ -1,14 +1,16 @@
# CI/CD Monitor Agent — Persistent Memory
- **S159 (2026-07-29) đợt-1 `b5799fc` + đợt-4 `a2bbcb9` — CẢ HAI `VERDICT = PASS 9/9` `[LEAD HARVEST HỒI-TỐ @S172 — nợ MỞ 3 PHIÊN (S162→S172), do CHÍNH vai này bắt @S162 F-02 rồi không ai đóng; owner slot (71) @S172 chốt 'gom và sleep thì auto, tự quyết'. Nguồn = `runs/2026-07-29-S159-tong-quan-pipeline-menu/cicd-verify-{b5799fc,a2bbcb9}.md`, KHÔNG suy diễn]`:** 🔴 **Vì sao món này nằm lại lâu:** `MEMORY.md:9` tng khai *'verbatim→archive'* cho cụm này `git log -S` **rỗng toàn lịch sử** ⇒ vai tự đính chính @S162*'không mất hẳn, nguyên liệu còn ở run-folder'***đúng, nhưng rồi không ai gom**. Đo @S172: **0 hit ở CẢ L1 lẫn archive** cho cả 2 sha, control-dương = 3 sha anh em cùng folder **có** hit ⇒ phép grep không rỗng. ⇒ **'không mất hẳn' KHÔNG bằng 'đã về nhà'**; nợ-harvest cần một dòng ghi, không cần một lời trấn an. **Nội dung cứu được:** đợt-1 `b5799fc` (11:44) — M2b test-gate **562 EXACT** · M4 bundle rotate user `DptYR4wL``0GO8mgrG` (**điều kiện PASS bắt buộc**, đo chứ không giả định) · M5 byte-marker **3 dương + 2 âm** · M6 smoke 4/4. đợt-4 `a2bbcb9` (13:52) — M3 byte-marker **3 dương/3 âm** · **M6 RESTART-DURABILITY lần 2 (chứng bền qua ≥2 restart)** · M7 smoke 4/4. 🔴 **Arc 4 đợt là bài học hoàn chỉnh, đừng đọc lẻ:** đợt-1 PASS 9/9 → **đợt-2 `1a47a61` PARTIAL 8/9 bắt regression revoker ăn 447/494 row** → đợt-3 `2a72695` PASS 9/9 (đóng regression, chứng bằng **3 chân kiềng**) → đợt-4 PASS 9/9 (tái xác nhận durability qua restart **thứ hai**).*một PASS lẻ ở đợt-1 KHÔNG chứng được thứ mà chuỗi 4 đợt chứng*: bền qua restart phải đo **≥2 lần restart**, không phải 1. 🔑 **Nghề giữ lại (`a2bbcb9` M3):** *'đọc grep-source thô sẽ báo FAIL oan cho một control vốn ĐÚNG'* — control âm phải đọc ở tầng **render/bundle**, không đọc ở tầng source. Cùng họ với bẫy `cut` cắt UTF-8 và glob-sai mà các vòng kiểm @S172 dính. Tag `[s159, no-mo-3-phien, khong-mat-han-khac-da-ve-nha, arc-4-dot, durability-can-2-restart, control-am-doc-tang-bundle]`
- **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à tng 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]`
- **S168 (08-01) `a2b37dc..0bfadc2` GĐ3-D Panel-3 + Lines-editor KHKK (7 FE + 2 BE + 1 test, 0-mig) — PASS 6/6** (#444 6m28s · gate **644=45+599** Δ+5 = đúng 5 Fact mới · Mig GIỮ 71 · tables 97 · bundle `RgvHZkPH→DLRf9TeA` + `D65FJPGd→C7TGA4Kn`). 🔑 **BÀI TỐT NHẤT — WIRE-PROOF BẰNG THÔNG-ĐIỆP-LỖI GỌI TÊN FIELD**: PUT route mới + bearer + GUID toàn-0 trả **400 liệt kê ĐỦ 3 field `PlanId`/`LineId`/`CatalogEntryId`** ⇒ command+validator MỚI chạy end-to-end Api→Application — **mạnh hơn hẳn 401** (401 chỉ chứng route tồn tại). Kèm miễn phí: đây là chứng **pool đang phục vụ BINARY MỚI**, mạnh hơn đo `w3wp` StartTime (StartTime chỉ nói 'có restart', không nói 'code nào'). 🔑 **CHỤP PRE KỊP GIỜ = tài sản rẻ nhất**: spawn 17:10 / push 17:08 ⇒ đo PRE (bundle + marker 0-hit + route **404**) TRƯỚC khi deploy land 17:13 ⇒ có differential THẬT 404→401 và 0→1. **Vào việc là chụp PRE ngay, đừng poll trước.** 🔑 **MARKER BẤT-ĐỐI-XỨNG > marker đối-xứng**: `lg:max-h-none` = **1 (admin) : 2 (eoffice)** đúng bằng số trang Panel-3 mỗi app ⇒ xác suất trùng-hợp ~0; comment cùng chuỗi bị Vite strip nên không nhiễu. 🔑 **CSS = nhân chứng ở ARTIFACT KHÁC** (Tailwind gen `.lg\:max-h-none` 0→1 cả 2 file .css) ⟂ JS. ⚠️ `grep -P` CHẾT trên Git-Bash locale ⇒ trích byte quanh marker bằng **python `str.find`+slice**. Evidence `runs/2026-07-31-S164-4gd-khkk-fanout/sub-cicd-verify-gd3d-lineeditor.md`. Tag `[run-444, wire-proof-400-ten-field, chup-PRE-kip-gio, marker-bat-doi-xung, css-nhan-chung]`
- _(**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`)_
- _(**08-01 `aaed699` S167 K7 bridge KHKK→HĐ — PARTIAL 4/6+1**: #442 (run #441 CANCELLED), gate 639. 🔴 **PUSH-ĐÈ NUỐT DEPLOY = gotcha #86** (mục 🚨 dưới). 🔑 kiểm-tra-TIỀN-ĐỀ marker trước khi tin 0-hit (nghi unicode-escape/code-split → **bác bằng ĐO**). 🔑 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í (log lần-2 IM LẶNG do guard). ⚠️ `appcmd list wp` map PID→pool BẮT BUỘC. ⚠️ CẤM lấy Admin-qua-được tuyên grant đã ăn. 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`)_
- _(**08-01 `1c6d77a` S167 K6 admin thu-gọn menu 12-key — PASS 5/5**: #440, gate 622 delta 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` + trích byte thật TRƯỚC khi kết luận vắng-mặt**. 🔑 **COUNT-DELTA** khi literal đã tồn tại (12/12 +1). 🔑 **log CI in `dist/assets/index-<hash>.js <size>`** = nhân chứng thứ 4, tách FROZEN-lành-tính khỏi bundle-kẹt. 🔑 menu ẩn 12/12 mà route 68→68 ⇒ ẩn client KHÔNG thu quyền (#82). 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`)_
- _(**Arc S155→S166 (#416 · #419 · #422-#427 · #432 · #434-#439)** — gate 551→622. 🔑 **#439** marker differential **element-wise** (K5 vào CẢ 2 app · K4c CHỈ eoffice) + Δsize cùng chiều; ⚠️ bar 'FE route 200' KHÔNG CÓ RĂNG với SPA-fallback. 🔑 **#438** PHỦ 2 RUN 1 LƯỢT ⇒ delta khép kín; **mốc PRE đề bài SAI, bắt bằng ĐO** (mốc PRE lão hoá sau MỖI deploy); PERM row ≠ policy. 🔑 **#436** dự-đoán-TRƯỚC-khi-đo; marker = tên biến local thì 0 bit (minifier đổi). 🔴 **#435 PARTIAL** ACCEPTANCE CHÂN-LÝ-RỖNG (0 dòng cả 2 phía ⇒ `0==0` xanh mà 0 bit) → `INFORMATION_SCHEMA` · liệt-kê-TRỌN-HỌ index · **wire-proof bind-error 400**. 🔑 **#434** TAM-GIÁC 3 NGUỒN (source-parse ⟂ sqlcmd ⟂ API-materialize-qua-EF). 🔴 **#432** LUẬT CẤM `HEAD~1` → neo SHA `X^..X`; control ÂM phải ĐỘC-QUYỀN. 🔴 **#423 PARTIAL** revoker UNGATED lật 447/494 row, sót vì **đo TRƯỚC recycle** → luật 3-CHÂN-KIỀNG; #427 ĐO-CỜ không đếm ROW; #419 count = SỐ FILE trong diff. verbatim → `archive/2026-08.md` + `2026-07.md` via `_INDEX`)_
- _(**`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).
@ -24,7 +26,7 @@ Read-only CI/CD + post-deploy verifier SOLUTION_ERP. Poll Gitea Actions API, ver
## ⚠️ 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, ghi từng mục ngay khi bằng chứng, kết bằng `END … VERDICT=`; return chỉ tóm tắt.
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.
---
@ -32,13 +34,13 @@ cicd-lane trả nhầm slice transcript thay verdict — **tao TÁI PHẠM dai n
- **#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** code commit không trigger CI? Check `git diff --name-only <base>..<head>` vs **7-glob** (D10 S111 `8aa3869`): `['docs/**','**/*.md','.claude/skills/**','.claude/agent-memory/**','.claude/workflows/runs/**','.gitignore','scripts/**.md']`. Gitea evaluate push *range* 1 commit file non-ignored toàn range build. **AS-6: memory-push/run-trace HẾT trigger CI.**
- **#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** 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. verify MUST sau status=success (Run #242 false-positive: check khi "running" stale hash).
- **🔴 #69 TWO-MODE FE hash vừa thể ROTATE vừa thể FROZEN.** deploy.yml copy `dist\*` UNCONDITIONALLY mọi run 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 deploy-window + real-size + byte-marker. 🔑 FROZEN-lành-tính vs bundle-cũ-kẹt: **xem LM** in-window = re-ship byte-identical (OK) · 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-919B = trap · `application/javascript` ~1,6MB = thật); size drift per-build nên đừng neo số byte. **Hash CŨ rơi về text/html = bundle cũ biến mất khỏi đĩa = chứng 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 + dòng ĐẦU log `Applying migrations...`), (ii) đo chỉ-số đích SAU mốc đó, (iii) **control ÂM chứng checker còn sống** (thiếu (iii) thì 'fix' kiểu xoá checker cũng xanh). Data-change ngoài CI luôn re-verify SAU status=success.
- **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.
---
@ -48,8 +50,8 @@ cicd-lane trả nhầm slice transcript thay verdict — **tao TÁI PHẠM dai n
- **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 **644 PASS** (45 Domain + 599 Infra; run #444 `0bfadc2` 08-01; climb 644/639/622/621/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). Phase 9 UAT skip OK.
- **Stage 4 Post-deploy** (if SUCCESS): auth login bearer (admin + nv.test gotcha #44; token=`accessToken` route `/api/auth/login`) 3-5 endpoint smoke 2XX (incl new NEW-endpoint bodyless-POST returns **411 IIS Length-Required pre-auth NOT 404**; re-probe WITH body 401 confirms wired) FE bundle hash 2 app (per #69 = real-size-vs-fake not hash-delta) SignalR negotiate (gotcha #25) EF mig prod==repo.
- **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.
@ -64,11 +66,11 @@ cicd-lane trả nhầm slice transcript thay verdict — **tao TÁI PHẠM dai n
## 🧠 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:** api/admin/eoffice `.solutions.com.vn` · SSH `ssh vietreport-vps` (Administrator, id_ed25519) · IIS phys paths: API `C:\inetpub\solution-erp\api` · admin `\fe-admin` · user `\fe-user`. DB `.\SQLEXPRESS`/`SolutionErp`/`vrapp` SQL-auth. **Conn key = `ConnectionStrings.Default` (NOT `DefaultConnection`)**. DB pw = `buKL3TGBkD0wDDbYVw65QeX9` (User Id=`vrapp`; Password field has NO `vrapp/` prefix S89 login-failed when prefix included; read verbatim from prod `appsettings.Production.json` ConnectionStrings.Default when `$env:PROD_DB_PASSWORD` empty).
- **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; run **#482** `b275893c` 08-10; prev 644 = 45+599 @#444). 🔑 Số lấy web-UI log `https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions/runs/{run_number}/jobs/0/logs` (~18KB, KHÔNG `/api/v1/` api/v1 logs 404) mỗi project 1 dòng `Passed! - Failed: 0, Passed: N, Skipped: 0`; đối chiếu **TÁCH-PHẦN** (45/599) chứ đừng chỉ khớp tổng, **so delta với số Fact mới khai trong commit-msg**. Flaky đã khai `DeleteContractSigningPlan_SoftDeletes` xanh liên tục #439#444.
- **Mig latest repo: Mig 71 `AddKhkkApprovalGroupCatalogAndFinalizeRuntime`** (`20260731085624`, S164 K2) applied-prod #435, GIỮ qua #436-#444. Path `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/`. 🔴 Đếm phải **NEO ĐUÔI** `grep -vE 'Designer\.cs$|ModelSnapshot\.cs$'` (recipe `grep -v Snapshot` ăn nhầm Mig 67 `AddPeApprovedBudgetSnapshot`). Mạnh hơn khớp-tổng = **set-diff repo↔prod 2 chiều** (`comm -23`/`-13`, cả 2 phải rỗng). Prod: `ssh vietreport-vps` + `sqlcmd -S .\SQLEXPRESS -d SolutionErp -E` (⚠ **`$env:PROD_DB_PASSWORD` KHÔNG tồn tại trên VPS dùng `-E` Windows-auth**). `sys.tables`(is_ms_shipped=0)=**97**; AddColumn/data-only KHÔNG đổi số. **NO-Mig proof = history NOT-advance + empty `git diff <base>..<head> -- '*Migrations*'`.** Bảng mig đầy đủ skill `ef-core-migration`.
- **Bundle hash live:** baseline #444 (08-01) admin `DLRf9TeA`/`IuRRquXK` · eoffice `C7TGA4Kn`/`DesmJ6-_`. 🔑 Ship-proof rẻ nhất = so **LM prod** với dòng `dist/assets/index-<hash>.js <size>` IN TRONG LOG CI (size khớp tới từng byte: `1,767.41 kB`1767413). marker chuỗi: rolldown/Vite 8 minify ra **BACKTICK** `grep -F`. **SNAPSHOT-per-run** (#69) LUÔN re-snapshot LIVE sau status=success; ship-proof = LM-in-window + real-size + marker, KHÔNG phải hash-delta. **Control-âm tầng-2 = hash CŨ phải rơi về `text/html` ~876-900B** (SPA-fallback bundle đã bị ghi đè). id run_number (key theo head_sha).
- **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.
@ -87,13 +89,9 @@ BE ~90s · FE ×2 ~60s/app · deploy ~30s · **total ~3min code / 0s docs-only**
## 📅 Recent runs (compressed — verbatim → archive via `_INDEX.md`)
- **#447 `998ea55` S171→S172 KHKK 3-panel — GO/PASS `[LEAD SEED ON-BEHALF @closeout S172; mày CHẠY THẬT 2 lượt nhưng KHÔNG tự ghi — `grep -c S172`=0, mtime kẹt 08-01 ⇒ carry `sub-no-self-append` nay **KHÔNG còn riêng ctx-verifier**: mày CÓ Write/Edit trong tools mà vẫn 0 đường ghi ⇒ giả-thuyết "bệnh riêng 1 vai" **YẾU ĐI**]`:** gate **644** (45D+599I) Failed 0 Skipped 0 — khớp B1 **tách-phần** cả 2 project, Δ0 đúng kỳ vọng (commit chạm **0 file test**). Bundle 4/4 rotate, size **khớp log CI tới byte**, LM trong cửa-sổ, hash cũ rơi `text/html`. Mig repo 71 = prod 71, **set-diff `comm -23`/`comm -13` = 0/0 HAI CHIỀU** (mạnh hơn khớp-tổng), tables 97. Smoke 8/8.
🔑 **3 nghề mới, đều tái dùng được:** (a) **Stage 3b cặp đối-chứng MIỄN PHÍ**#446 (cây tiền-S171) vs #447 khác **đúng 1 commit** ⇒ cô-lập nhân-quả **thay được `git worktree` đã fail**; (b) **bẫy 415 = họ hàng bẫy 411** — POST `application/json` vào endpoint **multipart** bị loại ở **action-selection, TRƯỚC authz** ⇒ 415 chỉ chứng route tồn tại, **vô nghĩa cho câu hỏi authz**; re-probe đúng multipart → 401. ⇒ **luật: mọi mã pre-auth (411/415) phải re-probe đúng dạng**; (c) **wire-proof MẠNH HƠN 401 = thông-điệp-lỗi GỌI TÊN FIELD** — bearer + multipart ⇒ 400 liệt `ContractSigningPlanId` + whitelist đuôi file ⇒ chứng **binary MỚI đang phục vụ**, mạnh hơn đo `w3wp` StartTime.
🔴 **2 vế PHẢI tách, cấm nén:***không hồi-quy do S171* (chứng bằng cặp #446/#447) ⟂ ❌ *flake `Create_DifferentEvaluationType_DoesNotAffect_Other` pre-exist* **VẪN chưa chứng** — nay **0/4 log CI** tái hiện. CI xanh **không rửa sạch** flake và cũng **không xác nhận** nó (vắng-mặt bằng-chứng ≠ bằng-chứng vắng-mặt).
🔴 **Bài đắt nhất — "KHÔNG ĐO ĐƯỢC" là kết luận PHẢI TỰ NGHI:** mày kết `nv.test@` login 401 ⇒ *"credential UAT chết trên prod"* ⇒ bỏ ngỏ chân #44/#85. **SAI** — không phải credential chết mà **tra nhầm sổ**: bộ đang sống nằm ở `docs/HANDOFF.md` slot (64) (`test.drafter@`/`test.approver@`, `Test@12345678`). Lead đo lại: login 200/200 · list **200** · changelogs **404 KHÔNG 403** · attach **400 gọi tên field** · CTRL-ÂM 404 ⇒ role thường **có đủ** `KeHoachKyKet.Read`+`Update`, **gotcha #85 KHÔNG tái phát**. ⇒ **LUẬT: trước khi khai "KHÔNG ĐO ĐƯỢC", phải trả lời "đã tra hết sổ có sẵn chưa?"** (HANDOFF · STATUS · run-folder). Cùng lớp `feedback_mechanism_right_data_absent`.
🔴 **Return #53-garble:** trả câu giữa chừng *"Writing Stage 5 + Verdict"***KHÔNG mất việc**: đĩa 10.156→**24.096 B**, 0 ô `_(chờ đo)_`. Đối-chứng lần nữa cho luật S158: **chống-#53 = thiết-kế artifact đổ-ruột-liên-tục, KHÔNG phải prompt.** Tag `[s171-s172, #447, cap-doi-chung-mien-phi, bay-415-pre-auth, wire-proof-goi-ten-field, khong-do-duoc-phai-tu-nghi, 2-ve-cam-nen, doi-ruot-lien-tuc, seed-on-behalf]`
- _(**#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 #307-#494** all GO (gate 440→509): AS-6 #41 soi TỪNG file vs 7-glob · `conclusion:None` dù success ⇒ tin `status` · **411-refine** (endpoint MỚI bodyless-POST = 411 IIS pre-auth; re-probe CÓ body → 401/415 = đã wire) · **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`)_
- _(**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-*`.
@ -101,12 +99,12 @@ BE ~90s · FE ×2 ~60s/app · deploy ~30s · **total ~3min code / 0s docs-only**
## 🔄 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-01 S168 (self #444-run: 21.3KB→~16.6KB — K7/K6/K5-K4c/K4ab verbatim→`archive/2026-08.md` NEW + 4 `_INDEX` pointer; #416#439 gộp 1 arc-line; baselines gate **644** + bundle #444 + Mig 71 + `-E` Windows-auth).** ⚠️ giữ luật: script sửa MEMORY phải build chuỗi XONG → temp → `os.replace` → verify byte>0.
- **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 PRECHECK (lead-seed từ memoryDelta workflow-return VERIFY khớp artifact, C2 /pause):** `LỆCH — Q2 sai tiền-đề nhưng W1 GO 0-blocker` — 12 phiếu prod (3 DaDuyet + 8 Nháp + 1 TraLai; memory-pack "001-003 Phase=3" KHÔNG SAI — thế giới đẻ thêm 9; ký-ức đóng-băng-thời-điểm khác ký-ức hỏng, SPEC phổ-quát-hoá mốc cũ mới là chỗ gãy) · pin-lệch 0 row VỚI control: chạy CHÍNH câu audit bỏ vế phủ-định ra 12 row element-wise + bịt điểm-mù LIKE bằng đẳng-thức-đếm IS-NOT-NULL=12=JOIN-in-family · hiệu chuẩn thước bằng 2 ANCHOR đã biết (MenuItems=200, Permissions=2221) mạnh hơn count>0 · ĐO bác acceptance wave-sau: 6 ô cờ đều 0/88 trên prod ⇒ ép-false vs giữ-thật render Y HỆT, A2 phải seed local 1 level cờ=true mới có răng · #8 Finalize=8/88 = CỜ CHỊU LỰC cấm đụng. → `runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-cicd-monitor-0.md`
- _(**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]
- 2 luot verify: dot-1 (run #481, lead tu do POST vi trace dut) + cum PASS 5/5 (run #482: bundle rotate x2, seeder prod 7 HD-* + 7 menu-row, KHKK-8 control nguyen, DLL marker ContractWorkflowGuards 0->4, smoke 9/9). Bai: tu-dinh-chinh trong luot — phep do dau ra 'HD-*=0' la ARTIFACT PARSE cua chinh minh (shape {types:[{active,activeOthers,history}]}), suyt bao FAIL oan; moc PRO bundle trong de bai LAO HOA sau moi deploy, phai do live.
- _(**S188 (08-10)** #481 + cm 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 ca chính mình** suýt FAIL oan.)_

View File

@ -12,3 +12,32 @@
- _(**08-01 `88e7ecf` S166 K4a+K4b — PASS 7/7**: #438, gate 621=45+576, menu 151→**200**, perm 1584→**2221**. 🔑 **PHỦ 2 RUN 1 LƯỢT ⇒ delta khép kín**. 🔑 **MỐC PRE ĐỀ BÀI SAI, bắt bằng ĐO** (lead giao 143⇒192, đo LIVE ra 151 → truy phạm-vi thay vì hô drift) — **mốc PRE lão hoá sau MỖI deploy**. 🔑 phân rã 49+588 khớp cơ-chế 2-site skip-existing (588=49×12 role). ⚠️ **PERM row ≠ policy**. 🔑 A5 restart ×2 thật + **soi ĐIỀU KIỆN log trong source TRƯỚC khi đọc im-lặng** (`if (added>0)`). 🔴 **marker lead gợi ý BỊ BÁC BẰNG ĐO** (`Kết cấu` có sẵn ⇒ 1/1 = 0 bit). verbatim → `runs/…/sub-cicd-verify-k4ab.md`)_
---
## [ARCHIVED @S189 2026-08-11] verbatim L1 blocks (curate 27,4KB → target <17,1KB)
### S159 (verbatim)
- **S159 (2026-07-29) đợt-1 `b5799fc` + đợt-4 `a2bbcb9` — CẢ HAI `VERDICT = PASS 9/9` `[LEAD HARVEST HỒI-TỐ @S172 — nợ MỞ 3 PHIÊN (S162→S172), do CHÍNH vai này bắt @S162 F-02 rồi không ai đóng; owner slot (71) @S172 chốt 'gom và sleep thì auto, tự quyết'. Nguồn = `runs/2026-07-29-S159-tong-quan-pipeline-menu/cicd-verify-{b5799fc,a2bbcb9}.md`, KHÔNG suy diễn]`:** 🔴 **Vì sao món này nằm lại lâu:** `MEMORY.md:9` từng khai *'verbatim→archive'* cho cụm này mà `git log -S` **rỗng toàn lịch sử** ⇒ vai tự đính chính @S162*'không mất hẳn, nguyên liệu còn ở run-folder'***đúng, nhưng rồi không ai gom**. Đo @S172: **0 hit ở CẢ L1 lẫn archive** cho cả 2 sha, control-dương = 3 sha anh em cùng folder **có** hit ⇒ phép grep không rỗng. ⇒ **'không mất hẳn' KHÔNG bằng 'đã về nhà'**; nợ-harvest cần một dòng ghi, không cần một lời trấn an. **Nội dung cứu được:** đợt-1 `b5799fc` (11:44) — M2b test-gate **562 EXACT** · M4 bundle rotate user `DptYR4wL``0GO8mgrG` (**điều kiện PASS bắt buộc**, đo chứ không giả định) · M5 byte-marker **3 dương + 2 âm** · M6 smoke 4/4. đợt-4 `a2bbcb9` (13:52) — M3 byte-marker **3 dương/3 âm** · **M6 RESTART-DURABILITY lần 2 (chứng bền qua ≥2 restart)** · M7 smoke 4/4. 🔴 **Arc 4 đợt là bài học hoàn chỉnh, đừng đọc lẻ:** đợt-1 PASS 9/9 → **đợt-2 `1a47a61` PARTIAL 8/9 bắt regression revoker ăn 447/494 row** → đợt-3 `2a72695` PASS 9/9 (đóng regression, chứng bằng **3 chân kiềng**) → đợt-4 PASS 9/9 (tái xác nhận durability qua restart **thứ hai**). ⇒ *một PASS lẻ ở đợt-1 KHÔNG chứng được thứ mà chuỗi 4 đợt chứng*: bền qua restart phải đo **≥2 lần restart**, không phải 1. 🔑 **Nghề giữ lại (`a2bbcb9` M3):** *'đọc grep-source thô sẽ báo FAIL oan cho một control vốn ĐÚNG'* — control âm phải đọc ở tầng **render/bundle**, không đọc ở tầng source. Cùng họ với bẫy `cut` cắt UTF-8 và glob-sai mà các vòng kiểm @S172 dính. Tag `[s159, no-mo-3-phien, khong-mat-han-khac-da-ve-nha, arc-4-dot, durability-can-2-restart, control-am-doc-tang-bundle]`
### S168 (verbatim)
- **S168 (08-01) `a2b37dc..0bfadc2` GĐ3-D Panel-3 + Lines-editor KHKK (7 FE + 2 BE + 1 test, 0-mig) — PASS 6/6** (#444 6m28s · gate **644=45+599** Δ+5 = đúng 5 Fact mới · Mig GIỮ 71 · tables 97 · bundle `RgvHZkPH→DLRf9TeA` + `D65FJPGd→C7TGA4Kn`). 🔑 **BÀI TỐT NHẤT — WIRE-PROOF BẰNG THÔNG-ĐIỆP-LỖI GỌI TÊN FIELD**: PUT route mới + bearer + GUID toàn-0 trả **400 liệt kê ĐỦ 3 field `PlanId`/`LineId`/`CatalogEntryId`** ⇒ command+validator MỚI chạy end-to-end Api→Application — **mạnh hơn hẳn 401** (401 chỉ chứng route tồn tại). Kèm miễn phí: đây là chứng **pool đang phục vụ BINARY MỚI**, mạnh hơn đo `w3wp` StartTime (StartTime chỉ nói 'có restart', không nói 'code nào'). 🔑 **CHỤP PRE KỊP GIỜ = tài sản rẻ nhất**: spawn 17:10 / push 17:08 ⇒ đo PRE (bundle + marker 0-hit + route **404**) TRƯỚC khi deploy land 17:13 ⇒ có differential THẬT 404→401 và 0→1. **Vào việc là chụp PRE ngay, đừng poll trước.** 🔑 **MARKER BẤT-ĐỐI-XỨNG > marker đối-xứng**: `lg:max-h-none` = **1 (admin) : 2 (eoffice)** đúng bằng số trang Panel-3 mỗi app ⇒ xác suất trùng-hợp ~0; comment cùng chuỗi bị Vite strip nên không nhiễu. 🔑 **CSS = nhân chứng ở ARTIFACT KHÁC** (Tailwind gen `.lg\:max-h-none` 0→1 cả 2 file .css) ⟂ JS. ⚠️ `grep -P` CHẾT trên Git-Bash locale ⇒ trích byte quanh marker bằng **python `str.find`+slice**. Evidence `runs/2026-07-31-S164-4gd-khkk-fanout/sub-cicd-verify-gd3d-lineeditor.md`. Tag `[run-444, wire-proof-400-ten-field, chup-PRE-kip-gio, marker-bat-doi-xung, css-nhan-chung]`
### ARC (verbatim)
- _(**Arc S155→S166 (#416 · #419 · #422-#427 · #432 · #434-#439)** — gate 551→622. 🔑 **#439** marker differential **element-wise** (K5 vào CẢ 2 app · K4c CHỈ eoffice) + Δsize cùng chiều; ⚠️ bar 'FE route 200' KHÔNG CÓ RĂNG với SPA-fallback. 🔑 **#438** PHỦ 2 RUN 1 LƯỢT ⇒ delta khép kín; **mốc PRE đề bài SAI, bắt bằng ĐO** (mốc PRE lão hoá sau MỖI deploy); PERM row ≠ policy. 🔑 **#436** dự-đoán-TRƯỚC-khi-đo; marker = tên biến local thì 0 bit (minifier đổi). 🔴 **#435 PARTIAL** ACCEPTANCE CHÂN-LÝ-RỖNG (0 dòng cả 2 phía ⇒ `0==0` xanh mà 0 bit) → `INFORMATION_SCHEMA` · liệt-kê-TRỌN-HỌ index · **wire-proof bind-error 400**. 🔑 **#434** TAM-GIÁC 3 NGUỒN (source-parse ⟂ sqlcmd ⟂ API-materialize-qua-EF). 🔴 **#432** LUẬT CẤM `HEAD~1` → neo SHA `X^..X`; control ÂM phải ĐỘC-QUYỀN. 🔴 **#423 PARTIAL** revoker UNGATED lật 447/494 row, sót vì **đo TRƯỚC recycle** → luật 3-CHÂN-KIỀNG; #427 ĐO-CỜ không đếm ROW; #419 count = SỐ FILE trong diff. verbatim → `archive/2026-08.md` + `2026-07.md` via `_INDEX`)_
### 447 (verbatim)
- **#447 `998ea55` S171→S172 KHKK 3-panel — GO/PASS `[LEAD SEED ON-BEHALF @closeout S172; mày CHẠY THẬT 2 lượt nhưng KHÔNG tự ghi — `grep -c S172`=0, mtime kẹt 08-01 ⇒ carry `sub-no-self-append` nay **KHÔNG còn riêng ctx-verifier**: mày CÓ Write/Edit trong tools mà vẫn 0 đường ghi ⇒ giả-thuyết "bệnh riêng 1 vai" **YẾU ĐI**]`:** gate **644** (45D+599I) Failed 0 Skipped 0 — khớp B1 **tách-phần** cả 2 project, Δ0 đúng kỳ vọng (commit chạm **0 file test**). Bundle 4/4 rotate, size **khớp log CI tới byte**, LM trong cửa-sổ, hash cũ rơi `text/html`. Mig repo 71 = prod 71, **set-diff `comm -23`/`comm -13` = 0/0 HAI CHIỀU** (mạnh hơn khớp-tổng), tables 97. Smoke 8/8.
🔑 **3 nghề mới, đều tái dùng được:** (a) **Stage 3b cặp đối-chứng MIỄN PHÍ**#446 (cây tiền-S171) vs #447 khác **đúng 1 commit** ⇒ cô-lập nhân-quả **thay được `git worktree` đã fail**; (b) **bẫy 415 = họ hàng bẫy 411** — POST `application/json` vào endpoint **multipart** bị loại ở **action-selection, TRƯỚC authz** ⇒ 415 chỉ chứng route tồn tại, **vô nghĩa cho câu hỏi authz**; re-probe đúng multipart → 401. ⇒ **luật: mọi mã pre-auth (411/415) phải re-probe đúng dạng**; (c) **wire-proof MẠNH HƠN 401 = thông-điệp-lỗi GỌI TÊN FIELD** — bearer + multipart ⇒ 400 liệt `ContractSigningPlanId` + whitelist đuôi file ⇒ chứng **binary MỚI đang phục vụ**, mạnh hơn đo `w3wp` StartTime.
🔴 **2 vế PHẢI tách, cấm nén:***không hồi-quy do S171* (chứng bằng cặp #446/#447) ⟂ ❌ *flake `Create_DifferentEvaluationType_DoesNotAffect_Other` pre-exist* **VẪN chưa chứng** — nay **0/4 log CI** tái hiện. CI xanh **không rửa sạch** flake và cũng **không xác nhận** nó (vắng-mặt bằng-chứng ≠ bằng-chứng vắng-mặt).
🔴 **Bài đắt nhất — "KHÔNG ĐO ĐƯỢC" là kết luận PHẢI TỰ NGHI:** mày kết `nv.test@` login 401 ⇒ *"credential UAT chết trên prod"* ⇒ bỏ ngỏ chân #44/#85. **SAI** — không phải credential chết mà **tra nhầm sổ**: bộ đang sống nằm ở `docs/HANDOFF.md` slot (64) (`test.drafter@`/`test.approver@`, `Test@12345678`). Lead đo lại: login 200/200 · list **200** · changelogs **404 KHÔNG 403** · attach **400 gọi tên field** · CTRL-ÂM 404 ⇒ role thường **có đủ** `KeHoachKyKet.Read`+`Update`, **gotcha #85 KHÔNG tái phát**. ⇒ **LUẬT: trước khi khai "KHÔNG ĐO ĐƯỢC", phải trả lời "đã tra hết sổ có sẵn chưa?"** (HANDOFF · STATUS · run-folder). Cùng lớp `feedback_mechanism_right_data_absent`.
🔴 **Return #53-garble:** trả câu giữa chừng *"Writing Stage 5 + Verdict"***KHÔNG mất việc**: đĩa 10.156→**24.096 B**, 0 ô `_(chờ đo)_`. Đối-chứng lần nữa cho luật S158: **chống-#53 = thiết-kế artifact đổ-ruột-liên-tục, KHÔNG phải prompt.** Tag `[s171-s172, #447, cap-doi-chung-mien-phi, bay-415-pre-auth, wire-proof-goi-ten-field, khong-do-duoc-phai-tu-nghi, 2-ve-cam-nen, doi-ruot-lien-tuc, seed-on-behalf]`
### S182 (verbatim)
- **S182 YC-013 W0.4 PRECHECK (lead-seed từ memoryDelta workflow-return VERIFY khớp artifact, C2 /pause):** `LỆCH — Q2 sai tiền-đề nhưng W1 GO 0-blocker` — 12 phiếu prod (3 DaDuyet + 8 Nháp + 1 TraLai; memory-pack "001-003 Phase=3" KHÔNG SAI — thế giới đẻ thêm 9; ký-ức đóng-băng-thời-điểm khác ký-ức hỏng, SPEC phổ-quát-hoá mốc cũ mới là chỗ gãy) · pin-lệch 0 row VỚI control: chạy CHÍNH câu audit bỏ vế phủ-định ra 12 row element-wise + bịt điểm-mù LIKE bằng đẳng-thức-đếm IS-NOT-NULL=12=JOIN-in-family · hiệu chuẩn thước bằng 2 ANCHOR đã biết (MenuItems=200, Permissions=2221) mạnh hơn count>0 · ĐO bác acceptance wave-sau: 6 ô cờ đều 0/88 trên prod ⇒ ép-false vs giữ-thật render Y HỆT, A2 phải seed local 1 level cờ=true mới có răng · #8 Finalize=8/88 = CỜ CHỊU LỰC cấm đụng. → `runs/2026-08-08-S182-khkk-awf-mirror-ncc/sub-cicd-monitor-0.md`

View File

@ -56,3 +56,5 @@
- 2026-08-01 · S167 #440 `1c6d77a` K6 admin thu-gon menu 12-key — PASS 5/5, 0-hit marker SAI 2 lan do co-che regex (grep -F) + COUNT-DELTA + log-CI nhan-chung-4 · `2026-08.md` · substring:"S167 (08-01) `1c6d77a` K6"
- 2026-08-01 · S167 #442 `aaed699` K7 bridge KHKK->HD — PARTIAL 4/6+1, PUSH-DE NUOT DEPLOY (gotcha #86) + ancestry-proof + control-duong tien-commit · `2026-08.md` · substring:"S167 (08-01) `aaed699` K7"
- 2026-08-01 · S168 #444 `0bfadc2` GD3-D Panel-3 + Lines-editor KHKK (0-mig) — PASS 6/6, wire-proof 400 goi-ten-3-field + chup-PRE-kip-gio + marker bat-doi-xung 1:2 + CSS nhan-chung · `runs/2026-07-31-S164-4gd-khkk-fanout/sub-cicd-verify-gd3d-lineeditor.md`
- **@S189 curate → `2026-08.md` §[ARCHIVED @S189]** — verbatim 5 khối L1: `S159` (arc 4 đợt `b5799fc`/`1a47a61`/`2a72695`/`a2bbcb9`, durability-≥2-restart, control-âm-tầng-bundle) · `S168` (#444 `0bfadc2`, wire-proof-400-tên-field, chụp-PRE, marker bất-đối-xứng) · `ARC S155→S166` (#416#439, chân-lý-rỗng #435, luật cấm `HEAD~1` #432, 3-chân-kiềng #423) · `#447` (`998ea55`, cặp-đối-chứng #446/#447, bẫy-415-pre-auth, không-đo-được-phải-tự-nghi) · `S182` (YC-013 W0.4, hiệu-chuẩn-thước-2-anchor, acceptance ép-false).

View File

@ -0,0 +1,281 @@
CICD: **PARTIAL — vòng 2: 8/9 check** — SHIP THÀNH CÔNG TRỌN (run #486 success · gate **680 EXACT** · bundle rotate ×2 · marker **10/10**) ⟂ **1 FAIL: A/059 latency 6/16 mẫu > 3 s (max 8,75 s)**, gốc đo được = **RAM 4 GB bị ép / buffer pool SQL 213 MB**, KHÔNG phải code (commit 0 file BE). _(vòng 1 = FAIL 8/11: Gitea không tạo run)_
# sub-cicd-monitor — YC-028 `92d8215a` (S189)
> ARTIFACT-FIRST. Ghi từng mục NGAY khi có bằng chứng. Dòng-1 lật thành `PASS|FAIL — n/n` ở cuối.
## Stage 1 — Push + path filter
- HEAD = `92d8215a6253d749794ca7551b5f0bc453ab08e9`
- Subject: `[CLAUDE] PurchaseEvaluation: YC-028 sự cố prod A/059 — FE tách "404 thật ⟂ lỗi hệ thống" 5 site ×2 app + guard disk/orphan vào runbook+cicd-monitor`
- Commit time: `2026-08-11 11:25:51 +0700`
- `git log origin/main..HEAD` = **RỖNG** ⇒ push đã land.
- `git diff --name-only 9b3c0edb..92d8215a` = **12 file**:
- FE deploy được (8): `fe-{admin,user}/src/lib/apiError.ts` · `…/src/pages/pe/PurchaseEvaluationsListPage.tsx` · `…/src/pages/khkk/KhkkListPage.tsx` · `…/src/pages/khkk/KhkkCreatePage.tsx`
- KHÔNG deploy (4): `.claude/WAL.md` · `.claude/agents/cicd-monitor.md` · `.claude/skills/iis-deploy-runbook/SKILL.md` · `docs/governance/so-yeu-cau-chu-du-an.md`
- Path filter 7-glob (`docs/**`,`**/*.md`,`.claude/skills/**`,`.claude/agent-memory/**`,`.claude/workflows/runs/**`,`.gitignore`,`scripts/**.md`): 8 file `fe-*/src/**.{ts,tsx}` KHÔNG khớp glob nào ⇒ **CI PHẢI CHẠY** (không docs-only). ✅
**Stage 1 = PASS.**
## Stage 1b — Disk-free VPS (BƯỚC MỚI, lần chạy đầu tiên)
`ssh vietreport-vps "fsutil volume diskfree C:"` (KHÔNG dùng `| head` — luật S189):
```
Total free bytes : 30,878,273,536 ( 28.8 GB)
Total bytes : 58,948,841,472 ( 54.9 GB)
Used bytes : 27,012,255,744 ( 25.2 GB)
```
- Free = **28.8 GB** ≫ ngưỡng 5 GB. ✅ (sự cố YC-028 hôm qua: 0 byte ⇒ SQL Error -2)
**Stage 1b = PASS.**
## Stage 2 — PRE snapshot (chụp TRƯỚC khi deploy land)
Đo live lúc ~11:2x, trước khi CI xong:
| App | JS | CSS |
|---|---|---|
| admin | `index-BZ1PG34E.js` | `index-DVHtHLex.css` |
| eoffice | `index-0ObPwWFB.js` | `index-Ibv3QD_1.css` |
**Control âm + control DƯƠNG trên bundle PRE** (tải nguyên file, đếm byte UTF-8 bằng python `bytes.count`, KHÔNG `grep -P` — locale Git-Bash giết `-P`):
| Bundle | size | `Không tìm thấy phiếu` (control DƯƠNG) | `Hệ thống đang chậm hoặc lỗi khi tải phiếu` (marker) |
|---|---|---|---|
| admin `BZ1PG34E.js` | 1.813.772 B, `application/javascript` | **5** | **0** |
| eoffice `0ObPwWFB.js` | 1.728.765 B, `application/javascript` | **6** | **0** |
⇒ thước SỐNG (control dương bắt được chuỗi tiếng Việt trong bundle) ⇒ marker 0-hit = **vắng THẬT**, không phải hỏng phép đo.
Nguồn marker: `grep -rn` ra **5 site/app** (`KhkkCreatePage:252` · `KhkkListPage:240` · `PurchaseEvaluationsListPage:659,761,817`) × 2 app = 10.
## Stage 3 — Gitea run poll — 🔴 **FAIL: KHÔNG CÓ RUN NÀO ĐƯỢC TẠO**
Poll 6 vòng × ~47s (11:27:49 → 11:31:44) + tra lại 11:36. `GET /actions/tasks?limit=8` (`total_count=484`), đầu bảng:
```
598 485 9b3c0edb success push 2026-08-11T01:25:05+07:00
597 484 ef1d4fbb success push 2026-08-10T21:31:18+07:00
596 483 c7b7ca45 success push 2026-08-10T20:45:18+07:00
```
- **0 hit `92d8215a`** trong TOÀN bộ 484 task (không chỉ trang đầu).
- Trang web `…/actions` (HTML thô): 2 hit `9b3c0ed`, **0 hit `92d8215`**.
- `GET /commits/92d8215a…/status``total_count: 0`, `state: ""` (rỗng hoàn toàn).
### Tiền-đề đã kiểm (không được khai "CI fail" khi chưa loại hết)
| Nghi vấn | Phép đo | Kết quả |
|---|---|---|
| Push chưa tới remote? | `git ls-remote origin main HEAD` | `92d8215a…` trên **CẢ** `HEAD` + `refs/heads/main`**đã tới** |
| Path filter nuốt? | đọc `.gitea/workflows/deploy.yml:17-28` từ ĐĨA | đúng 7 glob; 8 file `fe-*/src/**.{ts,tsx}` **không khớp glob nào** |
| Filter hỏng nói chung? | **cặp đối-chứng** | `9b3c0edb` (docs + `.claude/governance/.session-counter.json` — file KHÔNG bị ignore) → **CÓ** run #485 ✅ · `d4799ddd` (`.claude/WAL.md` đơn độc) → **KHÔNG** run ✅ ⇒ filter chạy ĐÚNG cho commit khác |
| Runner chết? | `Get-Service gitea-runner` | `Running`**và không liên quan**: run chưa được TẠO thì runner chưa tới lượt |
| Actions bị tắt? | `app.ini:53-54` + API repo | `[actions] ENABLED = true` · `has_actions = True` |
| Push-đè nuốt (gotcha #86)? | `git log 9b3c0edb..92d8215a` | đúng **1** commit, không có push sau |
### 🔴 Nguyên nhân gốc — ĐO ĐƯỢC, không suy diễn
| Nguồn | Giá trị | Nghĩa |
|---|---|---|
| `GET /api/v1/repos/…/branches/main``commit.id` | `92d8215a6253` | Gitea đọc **từ git trên đĩa** ⇒ ref ĐÃ tiến |
| `GET /api/v1/repos/…``updated_at` | **`2026-08-11T01:25:06+07:00`** | Gitea đọc **từ DB** ⇒ vẫn là mốc push TRƯỚC (`9b3c0edb` 01:25:05) |
| reflog local `.git/logs/refs/remotes/origin/main` | `9b3c0edb → 92d8215a` @ **11:25:55** | push thật lúc 11:25:55 |
**Ref tiến trên ĐĨA nhưng tầng ứng-dụng Gitea KHÔNG hề xử lý cú push** (0 bump `updated_at`, 0 ActionRun, 0 commit-status). Đây **KHÔNG phải CI fail** — CI chưa từng được gọi. Hook còn nguyên (`hooks/post-receive` 376 B + `post-receive.d/gitea` 142 B, mtime 21/04 = chưa ai đụng) ⇒ nghi hook gọi ngược vào Gitea (`/api/internal/hook/post-receive`) bị lỗi/timeout tại thời điểm push.
🔴 **Lỗ quan-trắc đi kèm (defect ĐỘC LẬP, đo được):** `C:\gitea\log\gitea.log` = **0 byte** từ `8/11 00:00:00`, trong khi bản xoay `gitea.log.2026-08-11.001.gz` = **12,15 MB**. Gitea xoay log lúc nửa đêm rồi **không mở lại file****mất sạch log server-side 11,5 giờ qua**, đúng lúc cần chẩn. Gitea process `Id=4020` StartTime `8/10 5:09:20 AM`, CPU tích luỹ **37.380 s**.
⚠️ Em main: cú `git push` lúc 11:25:55 có in warning/error dòng nào không? Terminal của em là **nguồn DUY NHẤT còn lại** — log Gitea đã chết.
## Stage 4 — Test gate — ⬜ N/A
Baseline `docs/STATUS.md` row Tests = **680** (45 Domain + 635 Infra), Mig canonical **72**. **Không đo được vì không có run.** KHÔNG suy ra pass/fail (vắng-mặt bằng-chứng ≠ bằng-chứng vắng-mặt).
## Stage 5 — Bundle rotate + byte-marker — 🔴 **FAIL (hệ quả Stage 3)**
Đo lại LIVE lúc ~11:36 (sau push 10 phút):
| App | JS trước | JS sau | Rotate? |
|---|---|---|---|
| admin | `index-BZ1PG34E.js` | `index-BZ1PG34E.js` | ❌ **ĐỨNG IM** |
| admin CSS | `index-DVHtHLex.css` | `index-DVHtHLex.css` | ❌ |
| eoffice | `index-0ObPwWFB.js` | `index-0ObPwWFB.js` | ❌ **ĐỨNG IM** |
| eoffice CSS | `index-Ibv3QD_1.css` | `index-Ibv3QD_1.css` | ❌ |
- Byte-marker `Hệ thống đang chậm hoặc lỗi khi tải phiếu` = **0/10** (kỳ vọng 5/app). Control dương vẫn 5 & 6 ⇒ thước sống.
- ⚠️ Đây **KHÔNG** phải ca FROZEN-lành-tính (#69 mode-B): mode-B là *deploy có chạy, copy lại file byte-identical*. Ở đây **deploy chưa từng chạy** ⇒ prod đang phục vụ **code TRƯỚC bản vá YC-028**.
## Stage 6 — Smoke + hồi-quy A/059 — ✅ **PASS 5/5** (server ĐÃ KHOẺ)
| Phép đo | Kỳ vọng | Thực đo | |
|---|---|---|---|
| `GET /health/live` | 200 | **200** · 0,102 s | ✅ |
| `GET /health/ready` | 200 | **200** · 0,167 s | ✅ |
| `POST /api/auth/login` admin | 200 | **200** · 0,294 s · `accessToken` 468 ký tự | ✅ |
| **`GET /api/purchase-evaluations/F02C81D1…` (A/059)** | **200 và < 3 s** | **200** · **0,366 / 0,486 / 0,406 s** (3 lượt) · 18.313 B · `maPhieu=PE/2026/A/059` `phase=10` | ✅ |
| smoke 4 endpoint (`purchase-evaluations` · `contract-signing-plans` · `menus` · `contracts`) | 200 | 200 / 200 / 200 / 200 · 0,269 · 0,124 · 0,164 · 0,121 s | ✅ |
| **control âm** GUID toàn-0 | 404 | **404** | ✅ |
🔑 **Hồi-quy YC-028 SẠCH:** phiếu tâm sự cố trả **0,37-0,49 s**, cách ngưỡng 3 s ~7 lần và cách mốc sự cố (5-47 s) ~2 bậc độ lớn. Cộng disk 28,8 GB free ⇒ **hạ tầng đã hồi phục thật**, không phải hồi phục trên giấy.
🔑 Control âm 404 còn chứng thêm: BE **phân biệt đúng** 404-thật ⟂ lỗi-khác — đúng tiền-đề mà bản vá FE dựa vào. Bản vá đó **chưa lên prod** (Stage 5), nhưng nền BE cho nó thì đã đúng.
## VERDICT
**`FAIL — 8/11 check`** (+1 N/A). Chia 2 vế, **cấm nén**:
-**Vế hạ-tầng/hồi-quy: LÀNH.** disk 28,8 GB · health/login/smoke 9/9 · A/059 200 trong 0,4 s · control âm 404.
-**Vế ship: KHÔNG XẢY RA.** Bản vá YC-028 **chưa có trên prod**. Không phải CI đỏ — **CI chưa từng được gọi**.
| # | Check | Kết quả |
|---|---|---|
| 1 | Push tới remote (`git ls-remote`) | ✅ |
| 2 | Path filter đúng ⇒ CI phải chạy | ✅ |
| 3 | **Disk free VPS ≥ 5 GB** (bước 1b, lần chạy ĐẦU) | ✅ **28,8 GB** |
| 4 | Gitea tạo ActionRun cho `92d8215a` | 🔴 **FAIL — 0 run** |
| 5 | Bundle rotate ×2 app | 🔴 **FAIL — cả 4 file đứng im** |
| 6 | Byte-marker trong bundle mới | 🔴 **FAIL — 0/10** (control dương 5 & 6 = thước sống) |
| 7 | health live + ready | ✅ |
| 8 | login admin | ✅ |
| 9 | **A/059 200 và < 3 s** | ✅ **0,366-0,486 s** |
| 10 | smoke 4 endpoint | ✅ 4/4 |
| 11 | control âm 404 | ✅ |
| — | test gate 680 | ⬜ N/A — không có run để đọc |
### Khuyến nghị cho em main (tao READ-only, KHÔNG tự chạy)
1. **Re-trigger:** `deploy.yml:29``workflow_dispatch:` ⇒ bấm **Run workflow** trên `…/actions` (build đúng `main` = `92d8215a`). Rẻ hơn và sạch hơn commit rỗng.
2. **Vá lỗ quan-trắc:** `Restart-Service gitea` để logger mở lại file — `gitea.log` đã **0 byte suốt 11,5 h**. Không vá thì lần tái phát sau cũng **mù y hệt**.
3. **Trả lời 1 câu:**`git push` 11:25:55 có in warning gì không? Log Gitea chết rồi ⇒ terminal em là **nguồn cuối cùng**.
4. **Sau khi re-trigger:** gọi lại tao verify trọn (gate 680 + bundle rotate + marker 10/10).
### Gotcha MỚI đề nghị khắc vào `docs/gotchas.md`
> **Push land trên đĩa nhưng Gitea KHÔNG xử lý ⇒ CI câm lặng, KHÔNG có run nào để mà đỏ.**
> Phát hiện bằng **2 nguồn lệch nhau trong CÙNG một API**: `GET /repos/{r}` → `updated_at` (đọc **DB**) vs `GET /repos/{r}/branches/main` → `commit.id` (đọc **git trên đĩa**). Head khớp mà `updated_at` đứng ở push TRƯỚC ⇒ tầng ứng-dụng chưa từng thấy cú push.
> 🔴 Nguy ở chỗ **mọi tín hiệu quen đều XANH**: `git ls-remote` đúng SHA · runner `Running` · `[actions] ENABLED=true` · path filter đúng · không có push đè. Chỉ "vắng mặt một cái đáng lẽ phải có" mới tố cáo — cùng lớp `feedback_absence_looks_like_clean`.
> ⇒ **Stage 2 từ nay phải đo `repo.updated_at ≥ thời điểm push`** trước khi kết luận "đang chờ CI".
---
**END VÒNG 1 — VERDICT = FAIL (8/11 check, +1 N/A) · ship KHÔNG xảy ra · hạ-tầng lành**
---
# VÒNG 2 — sau `workflow_dispatch` → run #486
## Datum từ lead (bằng chứng, không suy đoán)
1. `Restart-Service gitea` → Running; `gitea.log` **0 B → 31.946.657 B** ⇒ lỗ quan-trắc ĐÓNG.
2. `workflow_dispatch` qua API → HTTP **204****run #486 / task 599**, `head=92d8215a`, `event=workflow_dispatch`.
3. 🔑 **Terminal push 11:25:55 SẠCH**`remote: Processed 1 references` + `9b3c0edb..92d8215a main -> main`, **0 warning/error**.
**Datum quyết định cho gotcha #91:** tầng `git-receive` chạy TRỌN (Gitea *có* nhận, *có* in `remote:`) mà tầng ứng-dụng vẫn không đẻ ActionRun ⇒ chỗ gãy nằm **SAU** receive-pack, **TRONG** notifier/queue Gitea — **không phải** hook chết câm, cũng không phải mạng. Khớp đúng chẩn vòng 1 (`updated_at` DB đứng im ⟂ branch-head trên đĩa đã tiến).
## Stage 2b — Run #486
`599 | 486 | 92d8215a | success | workflow_dispatch | 11:45:40 → 11:53:43` = **8 phút 03 giây** (nhỉnh hơn dải quen 5m3x-6m3x — hợp lý vì gitea vừa restart đang giành CPU, xem Stage 6b). ⚠️ Kiểm #86: #486 là run **CUỐI**, 0 push chen ⇒ đọc đúng run.
## Stage 3b — Test gate ✅ **680 EXACT**
Log web-UI `…/actions/runs/486/jobs/0/logs` (18.757 B):
```
Passed! - Failed: 0, Passed: 45, Skipped: 0 ← Domain
Passed! - Failed: 0, Passed: 635, Skipped: 0 ← Infrastructure
```
**45 + 635 = 680** khớp `docs/STATUS.md` **tách-phần**, Δ**0** — đúng kỳ vọng (commit 0 file test). 0 fail / 0 skip.
## Stage 4b — Bundle ✅ rotate ×2 + size khớp log CI TỚI BYTE
| App | PRE | POST | | CI log | prod thật |
|---|---|---|---|---|---|
| admin JS | `index-BZ1PG34E.js` | **`index-DxSej4Da.js`** | ✅ ĐỔI | `1,815.25 kB` | **1.815.258 B** |
| eoffice JS | `index-0ObPwWFB.js` | **`index-BcfxaUBO.js`** | ✅ ĐỔI | `1,794.78 kB` | **1.794.780 B** |
| admin CSS | `index-DVHtHLex.css` | `index-DVHtHLex.css` | ⬜ giữ | `88.39 kB` | — |
| eoffice CSS | `index-Ibv3QD_1.css` | `index-Ibv3QD_1.css` | ⬜ giữ | `94.02 kB` | — |
🔑 **CSS giữ nguyên là ĐÚNG, không phải cờ đỏ:** diff chỉ thêm chuỗi tiếng Việt + nhánh `isNotFound`, **0 class Tailwind mới** ⇒ Vite sinh CSS byte-identical ⇒ cùng hash. **JS đổi ⟂ CSS giữ = đúng hình dạng của diff** — chính nó là nhân chứng phụ.
🔑 **Ship-proof mạnh nhất:** size prod khớp dòng `dist/assets/…` trong log CI **tới từng byte** ⇒ file trên prod ĐÚNG là file build ở run #486.
**Control âm tầng-2:** hash CŨ rơi về SPA-fallback — `BZ1PG34E`**900 B `text/html`**, `0ObPwWFB`**876 B `text/html`** ⇒ bundle cũ **đã bị ghi đè khỏi đĩa**, không phải 2 bản song song.
## Stage 5b — Byte-marker ✅ **10/10**
| Bundle | marker `Hệ thống đang chậm…` | control DƯƠNG `Không tìm thấy phiếu` |
|---|---|---|
| admin `DxSej4Da` (1.815.258 B) | **5** ✅ (PRE = 0) | 5 ✅ |
| eoffice `BcfxaUBO` (1.794.780 B) | **5** ✅ (PRE = 0) | 6 ✅ |
**5/app khớp CHÍNH XÁC 5 site `grep -rn`** (KhkkCreate:252 · KhkkList:240 · PE-List:659,761,817). Differential trọn **0 → 5** hai phía + control dương sống cả trước lẫn sau ⇒ **bản vá YC-028 ĐÃ LÊN PROD THẬT**.
## Stage 1b(2) — Disk ✅ **28,2 GB** free (ngưỡng 5 GB) — lần chạy thứ 2 của bước mới
## Stage 6b — Smoke ✅ 8/8 ⟂ 🔴 **A/059 latency FAIL**
`health/ready` 200 · `login` 200 · `purchase-evaluations` 200 · `contract-signing-plans` 200 · `menus` 200 · `contracts` 200 · **control âm GUID-toàn-0 → 404** ✅ · peer `A/055` 200 **0,609 s** · `A/058` 200 **0,479 s**.
🔴 **`GET /purchase-evaluations/F02C81D1…` (A/059): 200 ở CẢ 16/16 lượt, nhưng KHÔNG đạt bar `< 3 s`.**
| Đợt | mẫu | min | median | max | **> 3 s** |
|---|---|---|---|---|---|
| ngay sau deploy (pool sinh 11:53:13) | 3 | 5,03 | 6,40 | 10,70 | 3/3 |
| đường cong warm-up | 6 | 0,436 | — | 7,06 | 2/6 *(giảm đơn điệu 7,06→2,29→0,506→0,485→0,469→0,436)* |
| **burst 1 (~12:0x)** | 8 | 0,610 | **1,034** | 6,205 | **2/8** |
| **burst 2 (sau ~2,5 phút nghỉ)** | 8 | 0,618 | **4,996** | **8,749** | **4/8** |
🔴 **Tao TỰ BÁC giả thuyết đầu của mình:** thoạt tiên quy cho cold-start (w3wp pid 9156 StartTime **11:53:13** đúng trong cửa sổ deploy) — đường cong warm-up ủng hộ. **Nhưng burst 2 XẤU HƠN burst 1** ⇒ cold-start **bị bác bằng ĐO**, không giữ lời giải thích tiện tay.
### Truy gốc — loại trừ theo runbook, từng cửa
| Nghi vấn | Đo | Kết luận |
|---|---|---|
| Disk đầy (YC-028 cũ) | 28,2 GB free | ❌ loại |
| Orphan sshd/powershell ăn core | CPU-delta 5 s ×2 lượt → chỉ `gitea` 2,2 s rồi 1,2 s; **0 sshd** đốt CPU | ❌ loại |
| `AUTO_CLOSE` bật lại (runbook §4) | `SolutionErp is_auto_close_on = **0**` | ❌ loại |
| NTFS nén `.mdf/.ldf` (gotcha #88) | SolutionErp **không nén**; nhưng **`Vietreport_Master.mdf` + `.ldf` ĐANG nén** — DB hàng xóm | ❌ loại (phát hiện kèm → báo riêng) |
| **RAM bị ép → buffer pool SQL teo** | dưới đây | ✅ **KHỚP** |
```
RAM total = 4 GB · free = 1,08 GB (27%)
SQL: Target Server Memory = 1.115.736 KB (~1,09 GB)
Total Server Memory = 218.592 KB (~213 MB) ← chỉ được 1/5 cái nó CẦN
Page life expectancy = 522 s · max server memory = 2147483647 (mặc định, KHÔNG ghim)
Top WS: gitea 317 MB (CPU 512 s kể từ restart ~11:44) · w3wp 238 MB · sqlservr 135 MB
```
**Chuỗi nhân-quả đo được:** VPS **4 GB RAM / 3 core** dùng chung với VIETREPORT → buffer pool SQL chỉ giữ **213 MB** trên **1,09 GB** nó nhắm → PLE 522 s → query nặng PE-detail **trượt cache** → đọc đĩa ⇒ **phân bố LƯỠNG CỰC đặc trưng: 0,6-1,0 s (trúng cache) HOẶC 5-8,7 s (trượt cache), gần như trống ở giữa**. Đó là hình dạng của **thiếu RAM**, không phải hình dạng của code chậm.
🔴 **KHÔNG THỂ do commit này:** `git diff 9b3c0edb..92d8215a` = **8 file FE + 4 file không deploy, 0 file BE, 0 mig** ⇒ DLL API hành vi y hệt bản chạy trước đó. **Độ trễ API không thể do code trong commit này gây ra.**
🔴 **PHẦN TAO PHẢI NHẬN:** khuyến nghị `Restart-Service gitea` (của chính tao ở vòng 1) khiến gitea nạp lại + tái chỉ mục: **317 MB RSS và 512 giây CPU trong ~25 phút (~34% một core, liên tục)**. Trên máy 4 GB/3 core nó **giành RAM+CPU với SQL đúng lúc đo****một phần con số xấu ở trên là do việc tao đề xuất**. Đổi lại lỗ quan-trắc 11,5 h đã đóng — tao vẫn cho là đáng, nhưng cái giá phải nói ra chứ không giấu vào chữ "transient".
## VERDICT VÒNG 2 — **PARTIAL 8/9**
| # | Check | |
|---|---|---|
| 1 | Run #486 tới terminal `success` | ✅ 8m03s |
| 2 | Test gate **680** (45+635) tách-phần, Δ0 | ✅ EXACT |
| 3 | Bundle JS rotate ×2 + size khớp log CI tới byte | ✅ |
| 4 | Byte-marker 10/10 (5/app · PRE=0 · control dương sống) | ✅ |
| 5 | Control âm tầng-2: hash cũ → `text/html` 900/876 B | ✅ |
| 6 | Disk free ≥ 5 GB | ✅ 28,2 GB |
| 7 | health + login | ✅ |
| 8 | smoke 4 endpoint + control âm 404 + 2 peer PE | ✅ |
| 9 | **A/059 200 và < 3 s** | 🔴 **FAIL** — 200 ở 16/16, nhưng **6/16 mẫu > 3 s**, max **8,75 s**, burst-2 median **5,0 s** |
**Hai vế, cấm nén:**
-**SHIP: THÀNH CÔNG TRỌN.** Bản vá YC-028 đã lên prod — chứng bằng marker 0→5 hai app + size khớp byte + bundle cũ bị ghi đè. Gate 680 nguyên. Vòng 1 chỉ là Gitea không tạo run, **không hề có lỗi trong code**.
- 🔴 **PERF: bar `<3 s` KHÔNG ĐẠT**, và **không** phải cold-start (burst 2 xấu hơn burst 1). Gốc đo được = **RAM 4 GB bị ép, buffer pool SQL 213 MB/1,09 GB**, nặng thêm vì gitea vừa restart. **Không phải hồi quy của commit này.**
### Khuyến nghị (tao READ-only)
1. **Đo lại A/059 sau ~30-60 phút** khi gitea nguội — còn 5-8 s thì đây là **thiếu RAM cấu trúc**, hết là transient.
2. **Ghim `max server memory` cho SQL** (đang mặc định `2147483647`): ~1.200 MB để SQL khỏi đấu RAM hỗn loạn với gitea/w3wp/runner trên máy 4 GB.
3. **Nâng RAM VPS** — 4 GB cho 3 site + SQL + Gitea + runner + LibreOffice là quá mỏng. Đây là **mặt thứ hai của YC-028**: lần trước vỡ ở ĐĨA, lần này ép ở RAM.
4. **`Vietreport_Master.mdf/.ldf` đang NTFS-nén** (gotcha #88, dư âm đợt "giải phóng dung lượng") — DB của VIETREPORT → báo đội đó `compact /u`.
5. Gotcha **#91** khắc theo vòng 1; datum #3 của lead làm nó **sắc hơn**: chết ở **notifier**, không phải receive-pack.
---
**END VÒNG 2 — VERDICT = PARTIAL (8/9) · SHIP PASS TRỌN · PERF A/059 FAIL (gốc hạ-tầng RAM, không phải code)**

File diff suppressed because one or more lines are too long

View File

@ -1421,6 +1421,40 @@ for h in resp.points: # ← .points không phải iterable trực tiếp
**Luật:** thấy `Msg 5118` / RECOVERY_PENDING sau sự cố disk **`compact <file>` kiểm cờ nén TRƯỚC** khi nghĩ tới restore backup; **CẤM bật compression trên cây thư mục SQL DATA** (freeing-space bằng nén = bẫy hẹn giờ cho mọi DB đang offline/detached). Bonus bảo mật lộ ra cùng lượt đọc errorlog: port 1433 phơi Internet, `sa` bị brute-force liên tục từ IP lạ firewall riêng.
### 89. Cache của AUTOMATION phình vô hình ăn sạch ổ C → SQL Error -2 — triệu chứng đội lốt lỗi DATA (Session 189)
**Triệu chứng:** UAT anh Kiệt: phiếu *"ko duyệt được"* rồi *"Giờ nó ko tìn thấy phiếu"* (A/059 hiện trong cây, panel đỏ "Không tìm thấy phiếu."). Đo: `fsutil` free = **20.189.184 byte** (âm vào 5GB reserve); log `[ERR] Microsoft.Data.SqlClient … OpenAsync … Error Number:-2` + `SlaExpiryJob/ItTicketSlaJob iteration failed`; file log Serilog hôm trước **biến mất** (đợt "giải phóng dung lượng" quét cùng đợt NÉN file .mdf template, vân tay #88).
**Cơ chế:** 2 kho **cache của máy móc** phình theo NHỊP CI chứ không theo hành vi người dùng nên không ai thấy: `C:\gitea\data\repo-archive` **16,49GB** (ZIP sinh mỗi lần tải archive cache thuần, Gitea tự tái tạo; cron `archive_cleanup` CHƯA bật) + `npm-cache` của SYSTEM **12,76GB** (`System32\config\systemprofile\AppData\Local` CI build FE chạy dưới SYSTEM, tích từ tháng 4). Disk 0 byte SQL không cấp phát/grow được **lệnh GHI chết trước** ("ko duyệt được"), query nặng chết theo (GET detail 500), query nhẹ lúc được lúc không FE gom mọi nhánh lỗi vào **"Không tìm thấy phiếu"** (#44) người dùng lẫn người chẩn đoán **nghi oan phiếu/DB** trong khi phiếu còn nguyên (Phase=ChoDuyet, workflow sống).
**Fix (S189):** xóa `repo-archive\*` (an toàn cache) + npm-cache + 567 `u_ex*.log` >30 ngày → free 20GB+; `ALTER DATABASE … SET AUTO_CLOSE OFF` ×3 DB (ON = mỗi connection mở lại DB ~5s — đo `COUNT(*)` 1 dòng mất 5.420ms); FE tách "404 thật ⟂ lỗi hệ thống + nút thử lại" 5 site ×2 app (`lib/apiError.ts isNotFound`). **Guard đã wire:** runbook §"Disk-free + orphan guard" + `cicd-monitor` bước 1b (`fsutil` free <5GB = FAIL). **TODO ngoài giờ:** bật `[cron.archive_cleanup]` Gitea (restart service dùng chung VIETREPORT) + `compact /u` `Vietreport_Master.mdf` (đang mở, cần OFFLINE ~10s).
**Luật:** prod "chậm / không thấy / không lưu được" **`fsutil volume diskfree C:` TRƯỚC** khi nghi data hay code thông điệp UI chỉ lớp vỏ (#44); **cache của automation phải có vòng dọn tự động**, không thì bom hẹn giờ đúng nghĩa.
### 90. `ssh … | head` cắt pipe → process Windows-OpenSSH MỒ CÔI spin full core — người chẩn đoán tự làm bẩn hiện trường (Session 189)
**Triệu chứng:** SAU khi dọn đĩa xong server **vẫn** chậm (anh: *"vẫn ko tải phiếu lên đc, vẫn chậm lắm"*): GET detail MỌI phiếu 5-15s, A/059 (5 NCC) 500-sau-29,8s ×3 lần `"A task was canceled"`, curl chờ được thì 200 sau 47,6s. SQL khai: `wait_type=ASYNC_NETWORK_IO, wait_time=3ms, elapsed=29s` CPU query chỉ **66ms**, reads ~1.500 **SQL xong việc từ lâu, client không nhận nổi data**. CPU-delta 5 giây: **3 process `sshd` = 10,6+10,5+10,5 core-giây trên máy 3 core** = bão hòa 100%.
**Cơ chế:** lệnh dạng `ssh vps '…quét nặng…' | head -N` phía local đóng pipe sau N dòng ssh client thoát, **nhưng sshd + lệnh phía Windows-OpenSSH KHÔNG chết** spin trọn core hạn. 3 lượt quét-đo bị cắt = 3 orphan = w3wp đói CPU materialize kết quả SQL chậm ×100 mọi API rùa request vượt trần hủy ~30s 500 FE "Không tìm thấy phiếu" **tiếp**, gốc disk đã chữa. Người chẩn đoán tự tạo ra tầng bệnh thứ hai bằng chính công cụ chẩn đoán.
**Fix:** kill orphan sshd 🔴 **CHỪA chuỗi tổ tiên session đang chạy** (walk `ParentProcessId` từ `$PID` lên, kill sshd chain). Sau kill: A/059 **47s→0,38s**, phiếu 0,17s, inbox 0,12s tức thì, không cần deploy .
**Luật:** (1) cần cắt output ssh thì `Select-Object -First N` **phía REMOTE**, cấm `| head` phía local; (2) recycle app pool xong phải đợi **cold-start ~48s** rồi mới đo (đo sớm = đo app đang khởi động, ra số rác); (3) mọi op đo/quét nặng trên prod tự hỏi *"op này để lại gì sau khi tôi ngắt?"* hiện trường bẩn làm phép đo sau nói dối.
### 91. Push land trên ĐĨA nhưng tầng-app Gitea CÂM → CI không có run để mà đỏ — phát hiện bằng 2 nguồn LỆCH trong CÙNG một API (Session 189)
**Triệu chứng:** push `92d8215a` terminal SẠCH (`Processed 1 references`), `git ls-remote` đúng SHA nhưng **0 ActionRun** (0 hit trong 484 task), commit-status rỗng, bundle prod đứng im. **Mọi tín hiệu quen đều XANH**: runner `Running`, `[actions] ENABLED=true`, path-filter đúng (cặp đối chứng: `9b3c0edb` run · `d4799ddd` WAL-only không run filter sống), không push đè (#86).
**Phép đo tố cáo (2 nguồn trong CÙNG API Gitea):** `GET /repos/{r}/branches/main → commit.id` (đọc **git trên đĩa**) = SHA mới `GET /repos/{r} → updated_at` (đọc **DB**) = vẫn mốc push TRƯỚC ref tiến trên đĩa nhưng **tầng ứng dụng chưa từng thấy cú push** (nghi internal hook `post-receive` lỗi/timeout đúng thời điểm). KHÔNG phải CI fail **CI chưa từng được gọi**. Cùng lớp `absence looks like clean`: chỉ "vắng mặt cái đáng-lẽ-phải-có" mới tố cáo.
**Defect quan trắc đi kèm:** `C:\gitea\log\gitea.log` **0 byte từ 00:00** (xoay log nửa đêm xong không mở lại file) server-side 11,5h đúng lúc cần chẩn. Restart service mở lại logger (31,9MB flush về).
**Fix (S189):** `Restart-Service gitea` (không đụng app phiếu eoffice/admin/api KHÔNG phụ thuộc Gitea) `workflow_dispatch` qua API (`POST /repos/{r}/actions/workflows/deploy.yml/dispatches`, token lấy từ remote-URL local, HTTP 204) run **#486** head đúng `92d8215a` ship trọn (gate 680 EXACT · bundle rotate ×2 khớp CI-log từng byte · marker 10/10).
**Cost của thuốc — ghi thật, không giấu dưới "transient":** restart Gitea kích **re-index ~25 phút** (317MB RSS + 512s CPU) tranh RAM/CPU với SQL trên máy 4GB/3-core cửa sổ đo sau đó latency bimodal 0,6s 5-8,7s (cache-miss, PLE 522s). tầng RAM cùng lượt: `sp_configure 'max server memory (MB)'` từ **2147483647 (unbounded default!)** **1200** ăn ngay không restart, PLE hồi 1123s, A/059 về 0,58s. Máy ít RAM SQL unbounded = Windows với SQL giằng RAM qua lại hạn.
**Luật:** (1) verifier tuyên "đang chờ CI" phải đo **`repo.updated_at ≥ thời-điểm-push`** trước head khớp chưa đủ; (2) sau restart service re-index/warm-up: **phép đo latency trong cửa sổ đó là số bẩn**, khai hoặc đợi lắng; (3) SQLEXPRESS trên máy nhỏ: **pin `max server memory` ngay lúc setup** (ghi vào runbook), đừng để default unbounded.
## Checklist debug bug mới
1. Build pass không? fail check using + package version compat

View File

@ -232,6 +232,20 @@ Detect by **action-signature** (NOT "AI tự phán có vi phạm không"). Scan
> **Maintenance:** append RCA on each AS-hit; promote a guard to `procedural` on its 2nd strike; mark `verified` once it holds through a session; retire by net-effect. Pointer entries only — full narrative lives in session-logs (summary-index).
## RCA `YC028-S189` — sự cố prod 2 tầng, tầng-2 do CHÍNH LEAD gây khi chẩn đoán (2026-08-11)
**Triệu chứng:** UAT anh Kiệt (Zalo): phiếu A/059 *"ko duyệt được"**"Giờ nó ko tìn thấy phiếu"* + *"check kỹ tí"*; sau đợt cứu đầu anh vẫn báo *"vẫn ko tải phiếu lên đc, vẫn chậm lắm"*.
**Tầng-1 (không do đội):** ổ C VPS **0 byte** (free 20MB vào reserve) — cache automation phình vô hình (`repo-archive` 16,49GB + `npm-cache` SYSTEM 12,76GB) → SQL `Error -2` → lệnh ghi/duyệt chết, FE gom mọi lỗi vào "Không tìm thấy phiếu" (#44 → gotcha **#89**). Xử: dọn ~30GB + `AUTO_CLOSE OFF` ×3 + FE tách 404⟂500 (commit `92d8215a`).
**Tầng-2 (LỖI LEAD — phần phải RCA):** sau khi dọn đĩa, server VẪN chậm — vì **3 sshd mồ côi do chính các lệnh quét-đo của lead** (`ssh … | head` cắt pipe, process phía Windows-OpenSSH không chết) **bão hòa 3/3 core** → mọi GET detail 5-47s (gotcha **#90**).
**5-why tầng-2:** (1) Vì sao chậm? — w3wp đói CPU, SQL `ASYNC_NETWORK_IO` chờ client. (2) Vì sao đói? — 3 sshd spin full-core. (3) Vì sao có orphan? — `| head` phía local đóng pipe sớm, ssh client thoát nhưng Windows-OpenSSH **không kill process tree**. (4) Vì sao lead không thấy sớm? — đo bằng `Get-Process` CPU **tích lũy** (thước sai — không phân biệt đang-ăn với đã-từng-ăn); chỉ khi đo **CPU-delta 5s** mới lộ. (5) Vì sao lặp ×3? — mỗi vòng quét mới lại `head`, và lead **không có phản xạ "op này ngắt rồi để lại gì?"** — người chẩn đoán tự làm bẩn hiện trường, rồi đo hiện trường bẩn và kết luận tiếp.
**Fix:** kill 3 orphan (walk `ParentProcessId` CHỪA ancestor-chain của session mình) → A/059 **47s→0,38s** đo ×2 lượt + inbox 0,12s — executed+verified. **Guard:** luật #90 3 vế (Select-Object -First N phía REMOTE · đợi cold-start ~48s sau recycle · tự hỏi op-để-lại-gì) khắc gotchas + runbook §"Disk-free + orphan guard" + `cicd-monitor` bước 1b; răng thật = cicd-monitor chạy MỖI post-push.
**Khai thêm 2 nhánh đúng-quy-trình đáng giữ:** lead **đã tự khai** với owner phần lỗi mình gây (không đợi bị bắt); và 2 lần bác-giả-thuyết bằng số (cartesian: đếm đủ 7 bảng mới kết luận · lock-mồ-côi: 0 session ôm transaction) tránh được 2 bản vá sai hướng (AsSplitQuery-vội · recycle-mù).
## RCA `SCORE-T2-S189` — TẦNG-2 chấm sai PHÉP ĐẾM (2026-08-11, bookstart L15)
**Chấm sai — TẦNG NÀO:** **TẦNG-2** (`score-counter`). **Tầng-1 (lead) = 0 lỗi**, khớp 4/4 khoản, số tái lập được (`score-count-auditor` tự chạy lại `nhip-no-probe.ps1`, khớp verbatim; 27/27 dòng `parts=10`, 0 lệch cột). 🔴 **KHÔNG** nhét nhãn *chấm sai* vào `lead_self_audit.flag_classes` — tập ĐÃ NIÊM PHONG `_sealed_P3B_S181`, máy từ chối exit 2.