diff --git a/.claude/WAL.md b/.claude/WAL.md
index 51263467..f241ff6a 100644
--- a/.claude/WAL.md
+++ b/.claude/WAL.md
@@ -57,13 +57,18 @@ bằng 7 HD-* (data-op) + duyệt/history y KHKK (gộp Q1/Q3) + van-xả mirror
push f8f2ef96..091073f9 → CI #600 RUNNING đúng sha (gotcha #91 guard: updated_at mới,
app KHÔNG câm) · Q5-prod: QT-HD-V2-001 → 0/0 (2 HĐ pin đều ZZTEST-K8 terminal, an toàn)
⇒ type-3 user-selectable = 7 HD-* đúng "mỗi loại 1 quy trình"
-[!] cicd-monitor #600 (agent nền): test-gate 697 · Mig73-prod · bundle rotate ×2 · smoke →
- verdict PASS = anh vào kiểm được. wf agent a7b1... artifact sub-cicd-deploy-yc030.md
-[ ] NEXT-em @closeout: lật STATUS:476 row Tests 693→697 (chỉ SAU cicd-verify — B1) ·
- bật cron.archive_cleanup Gitea (chống #89 tái phát — cần restart, để sau CI xong) ·
- sổ YC-029/030 vế-thi-công · session-log · un-delete a79dd579 Dev nếu cần
+[x] cicd-monitor #600 PASS FULL 6/6 (run_number #487, ~11m): test 697 (45+652) · Mig73 prod
+ top · bundle rotate ×2 byte-match CI↔prod (eoffice BIN1bEGo · admin D2FHMRPX) · smoke
+ 200/401 · #91-guard OK. LEAD re-verify độc-lập KHỚP (bundle mới live + cũ chết-SPA + Mig73
+ prod top). ✅ PROD SỐNG — anh vào kiểm được.
+[x] STATUS row Tests canonical lật 680→697 (đúng điều-kiện "chỉ chép cicd-verify")
+[ ] NEXT-em @closeout: bật cron.archive_cleanup Gitea (chống #89 — cần restart, để lượt sau) ·
+ session-log S190 · un-delete a79dd579 Dev nếu cần · [carry:w5-host-ondeleted] ·
+ [carry:w8-delete-policy] · gotcha #92-candidate chốt (runner build-env — nay đã chứng
+ root-cause = disk, KHÔNG phải node_modules; deploy.yml tự-xóa fresh mỗi run)
-next: chờ cicd-monitor #600 → báo anh verdict deploy.
+next: BÁO ANH verdict deploy PASS + prod sống. Phiên-LOGIC L15 giữ mở (YC-026) — chờ anh
+ kiểm prod / giao việc / /pause.
verify:
commits: git log --oneline -8 # 2ae62f3f ed3b39ff 7b291014 09ebd20e 1cc16a2d + wal
diff --git a/.claude/agent-memory/cicd-monitor/MEMORY.md b/.claude/agent-memory/cicd-monitor/MEMORY.md
index c3300574..fa3e5053 100644
--- a/.claude/agent-memory/cicd-monitor/MEMORY.md
+++ b/.claude/agent-memory/cicd-monitor/MEMORY.md
@@ -1,5 +1,7 @@
# CI/CD Monitor Agent — Persistent Memory
+- **S190 (08-12) `091073f9` YC-029+YC-030 GĐ3 Duyệt HĐ (BE+2FE+**Mig 73**) — PASS TRỌN 6/6.** Deploy NGAY SAU P0 disk-0 S189: disk **25.9GB** free (lead dọn 4.7→26.6 giữ) ⇒ **disk-death KHÔNG tái**. 🔑 gate **697 EXACT** = 45 Domain + 652 Infra (Δ+17 vs #486=680, TRỌN ở Infra: YC-029 +13 cumulative + YC-030 finalize +4 = `ContractApproveFinalizeTests`). 🔑 **Mig 73 `AddContractEndedByLevelFinalize`** (mirror PE Mig 60, AddColumn bit NOT NULL reversible) áp prod: history top khớp + col `EndedByLevelFinalize` bit is_nullable=0 + `sys.tables` **97 unchanged**. 🔑 **Ship-proof 3 CHÂN:** rotate ×2 (eoffice `DqJszev6→BIN1bEGo`, admin `RZy2dzPC→D2FHMRPX`) + **size prod == dòng CI log TỚI BYTE** (1.819.492==1,819.49kB · 1.803.881==1,803.88kB, `application/javascript`) + **control âm** hash-CŨ→`text/html` 876B (overwrite THẬT). Smoke 200/401 chuẩn (login token len=468 · contracts/PE/menus). **#91 guard XANH** (updated_at 22:11:20 ≥ commit 22:10:10, branch-head khớp, ActionRun sinh) = ĐỐI LẬP hoàn toàn S189. 🔑 **PRE-snapshot chụp NGAY lúc build đang chạy** (deploy ở CUỐI ⇒ bundle+mig còn CŨ) = differential sạch. Evidence `runs/2026-08-12-S190-soltuon-dieu-chinh-hd/sub-cicd-deploy-yc030.md`. Tag `[s190, gate-697, mig73-ended-finalize, shipproof-3chan-bytematch, control-am-overwrite, disk-death-khong-tai, gotcha-91-xanh]`
+
- **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`)_
@@ -50,7 +52,7 @@ 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 **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 3 Test gate:** baseline **697 PASS** (45 Domain + 652 Infra; run #600/#487 `091073f9` 08-12; climb 697/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.
@@ -68,9 +70,9 @@ cicd-lane trả nhầm slice transcript thay verdict — **tao TÁI PHẠM dai n
- **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.
- **SSH→PS quoting (S42):** bash→ssh→powershell 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 có `/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, và **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 có trên VPS). `sys.tables`=**97**. **NO-Mig proof = history NOT-advance + empty `git diff