diff --git a/.claude/WAL.md b/.claude/WAL.md index dfee639..8afc890 100644 --- a/.claude/WAL.md +++ b/.claude/WAL.md @@ -1,47 +1,44 @@ # WAL — auto-generated, không sửa tay -updated: 2026-08-01T13:35:00+07:00 | session: S167 (L9, window 5 — /pause) | branch: main +updated: 2026-08-01T16:20:00+07:00 | session: S168 (L9, window 6 — /tiep → closeout-nợ TRẢ XONG) | branch: main -goal: CHUỖI SP-002 B4 — K1→K7 SHIP TRỌN (7/8 wave, cicd phủ hết); GĐ3-đồng-nhất BLOCKED-chờ-anh-2-quyết; K8-prep + closeout-nợ còn +goal: CHUỖI SP-002 B4 — 7/8 wave SHIP + closeout-nợ ĐÃ TRẢ @S168; GĐ3 BLOCKED-chờ-anh-2-quyết (slot 63); K8-prep + drift-audit-tháng-8 còn chain: -[x] K1→K5+K4c SHIP (6 wave, S164-S166) — 50e6d8c/0779f2d/15349e8/7a903cf/88e7ecf/ce35f90+e202393 PUSHED - · cicd 6/6 · 5/6-khỏe · 6/6 · 7/7 · 5/5 — chi tiết _context PAUSE-3/4 + sub-*-k{1..5,4a-c}.md -[x] K6 SHIP @S167 — 1c6d77a · gate PWF-5 (MAJOR-1 số-đếm-comment fixed) · cicd #440 PASS 5/5 (admin ROTATE - Ig1R5tAh · eoffice FROZEN-lành-tính cmp · marker-ÂM route-68-giữ) — sub-{reviewer-gate,cicd-verify}-k6.md -[x] K7 SHIP @S167 bridge KHKK→HĐ — aaed699 13-file (BE bridge+hội-2-khóa+seeder · FE nút+cây-TẬP-contractIds - SHA-pair-3/3 · test 639/0 Δ+17) · gate PWF-10/0-blocker (F-8 neo-số-dòng→tên-hàm fixed 3-chỗ) · cicd - PARTIAL-live-sạch (🎯 seeder log "0 added + 2 upgraded" verbatim + CanCreate 1→3 + row-13-giữ · run - aaed699 CANCELLED-cơ-chế 2-push-sát → ship #442 → ĐỀ-XUẤT GOTCHA #86) — sub-*-k7.md ×5. Nợ 0-blocker: - race-2-request (unique/RowVersion nhịp sau) · DraftData-không-carry · a11y--label + O(n·m) -[x] Governance @S167 — 628132c: slot(57)-split-_INDEX (A7 427/427-PASS-lần-đầu + fault-inject-2-chiều + - 3-script _INDEX*-glob) · slot(58)-trần-_mind-48KB (live 62,2%) · G-1-RATIFIED-stamps ×2-app · STATUS-622 - /counter-41. 4-slot owner đóng: (54)-FINAL-giữ-hiện-trạng-ANH-TỰ-TAY · (55)-GĐ3-đồng-nhất · (56)-ĐÓNG · - CLARIFY-2-Admin-để-nguyên -[!] GĐ3 cây-4-folder ĐỒNG-NHẤT — lane BLOCKED-SẠCH (0-file-chạm — sub-implfe-gd3.md §1 bảng-số): layout GĐ3 - 3-panel ≠ khuôn giấy-cuộn ⇒ prepend-19rem bóp panel 346→42px @1366 HỎNG-CÂM. 🔴 CHỜ ANH 2-QUYẾT: - (a) trang-đích fe-user {MyContractsPage · InboxPage · WorkflowMatrixViewPage} · (b) phương-án - {A-prepend-42px⛔ · B-chỉ-≥2xl · C-nới-PipelineTreePanel-thu-gọn-desktop [lane+lead NGHIÊNG C; đụng - 2-file-SHA-pair-chung-4-trang; phụ: mở=ĐẨY-hay-PHỦ] · D-cây-thay-Panel-3}. Chốt → scaffold 1-lượt - → gate → commit → cicd +[x] K1→K7 SHIP trọn 7/8 wave (S164-S167) — 50e6d8c/0779f2d/15349e8/7a903cf/88e7ecf/ce35f90+e202393/1c6d77a/aaed699 + PUSHED · suite 639/0 (45D+594I re-verify @S168) · cicd phủ hết — chi tiết _context PAUSE-3/4 + run.md ledger (tươi @S168) +[x] Governance @S167 — 628132c: slot(57)-split-_INDEX + slot(58)-trần-48KB + G-1-stamps +[x] closeout-nợ @S168 (window-6, /tiep) — TRẢ TRỌN 9 món: gotcha #86 (section + cheatsheet-34 + STATUS row) · + H24-DEEP resolve NỐT F-4/F-5/F-6/F-9/F-10/F-11 (F-1/2/3 @S166; F-8 KHÔNG-ÁP theo ring2-bác — slot 59 giữ sống + 120.633B; disposition TỪNG DÒNG ở h24-deep-synthesis.md) · STATUS :6/:472/:473/:479 tươi (639 · gotcha-86 · + counter-42 · bundle RgvHZkPH/D65FJPGd #442) · HANDOFF segment S163→S168 + slot (63) + 4-slot-đóng + carry-restamp · + CLAUDE.md mig-70/71 + bỏ-neo-phase · migration-todos active-work + nhãn-P12 + note-chuỗi-K · spec-cụm1 đính-chính + PUT-Conflict (khối @S168, chữ gốc giữ) · orphan S163+S166 harvest (2 synthesis, verdict verbatim-từ-đĩa; S159×2 + GIỮ ngủ anh-chốt) · diary ctx-verifier (3 lượt L9) + ctx-curator (3 lượt L9) seed on-behalf · tally #53 sự-kiện + L9 per-window (chốt @closeout L9) · run.md ledger 8 row mới (K3-fix + F1/K4ab/K5K4c/K6/K7/GĐ3/K8) + B4 7/8 +[x] /tiep S168 nghi-thức — Sàn-3 ①④⑤ khớp-nợ-WAL · verify 5/5 KHỚP · tick CLEAN 41→42 · NHIP-NO light 2/6 deep + 2/15 ok · thu-moi se=0 all=0 · mind-check 11Đ/0T · ctx-verifier CO-11-cờ (⑦⑨ vá liền, ⑩⑪ để MIND-5) · _tiep-5 +[!] GĐ3 cây-4-folder ĐỒNG-NHẤT — BLOCKED-SẠCH chờ anh 2-quyết HANDOFF slot (63): (a) trang-đích fe-user + {MyContractsPage · InboxPage · WorkflowMatrixViewPage} · (b) {A-42px⛔ · B-≥2xl · C-nới-PipelineTreePanel + [lane+lead NGHIÊNG C; phụ: mở=ĐẨY-hay-PHỦ] · D-cây-thay-Panel-3} — sub-implfe-gd3.md §1. Chốt → scaffold + 1-lượt → gate → commit → cicd [ ] K8-prep: form-14-người fail-closed + gói SOLUTION-PE-{n} + QĐ9-đo-2-nhánh + ZZTEST + rollback-ID. (54)-FINAL: pre-flight CHỈ check-đọc workflow-live/roster, KHÔNG dựng/sửa -[ ] closeout-nợ: gotcha #86 vào gotchas.md · diary vai (ctx-verifier + ctx-curator lead-seed) · tally #53 - derive-from-body (window-5: 8-hỏng/15-lượt=10-spawn+5-resume · window-4 nháp-8) · STATUS row S163-S167 - + HANDOFF slots (54)(55)(56)(57)(58) · spec-cụm1 PUT-Conflict thi-hành · H24-DEEP 11-FLAG resolve - (sub-lead-stale-deep-S166.md) · orphan-4-folder (S159×2-nợ-ngủ-anh-chốt + S163 + S166-h24-deep) · - run.md ledger-tụt-hậu (row-4 + 0-row-F-1) +[ ] Monthly drift-audit 2026-08-01 DUE (session-đầu-tháng — CLAUDE.md §Audit; lần trước S96 07-01) + re-sync + measured{} (6 vai ctx/ring 0-baseline) + re-chạy governance-detectors sau đợt vá S166+S168 (ring2 INFORM #6) -next: anh trả 2-quyết GĐ3 (a)+(b) → lane scaffold → gate → commit → cicd. Anh chưa trả ⇒ /tiep vào - closeout-nợ trước (2 mạch không chặn nhau). +next: anh trả slot (63) 2-quyết GĐ3 → lane scaffold → gate → commit → cicd. Anh chưa trả ⇒ /tiep sau vào + drift-audit-tháng-8 HOẶC K8-prep (check-đọc-only) — 3 mạch không chặn nhau. verify: - head -1 .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-implfe-gd3.md # IMPLFE-GD3: BLOCKED - head -1 .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-cicd-verify-k7.md # CICD-K7: PARTIAL — K7 ĐÃ LIVE - git log --format='%h %s' -4 # wal-flush* · 628132c · aaed699 K7 · 1c6d77a K6 (đều pushed) - git status --porcelain -- src fe-admin fe-user tests # RỖNG = 0 code dở - dotnet test SolutionErp.slnx --nologo # 639/0 = 45D + 594I + head -1 .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-implfe-gd3.md # IMPLFE-GD3: BLOCKED + grep -c '^### 86\.' docs/gotchas.md # 1 = gotcha #86 đã land + ls .claude/workflows/runs/2026-07-30-S163-bookend-open/bookend-open-synthesis.md \ + .claude/workflows/runs/2026-08-01-S166-h24-deep-midsession/h24-deep-synthesis.md # 2 file = orphan đóng + git status --porcelain -- src fe-admin fe-user tests # RỖNG = 0 code dở + dotnet test SolutionErp.slnx --nologo # 639/0 = 45D + 594I -notes: MANDATE PAUSE-3 sống. MIND-4 chèn xong (2-window khai-bù · curator SUA-8 áp đủ · full 11Đ/0T). - PAUSE-4 APPEND _context (verbatim 4-tin anh). Treo-không-chặn: (I)(II)(III) · OG-5 · OG-6-soát-4-ô · - 2-hở-UX-K1 · F-5-PermGuard · O-2-literal. UAT-NÓI-TRƯỚC: nút bridge sáng sau RE-LOGIN · GĐ2/GĐ3 "SẮP" - rỗng khi prod 0-phiếu/0-HĐ = đúng-spec. +notes: MANDATE PAUSE-3 sống (sổ nhớ kỹ từng đầu việc). Treo-không-chặn: (I)(II)(III) · OG-5 · OG-6-soát-4-ô · + 2-hở-UX-K1 · F-5-PermGuard · O-2-literal · nợ-K7-0-blocker (race-2-request · DraftData-không-carry · a11y+O(n·m)) + · nhóm-7-persona-sweep 21/23 · MIND-2-nén: 3-inbound/22-ý định-đoạt TRƯỚC pause-6 (ctx-verifier ⑤⑥) · nhãn ⑩⑪ + đổi ở MIND-5. F-9 persona cicd-monitor ăn từ RESTART kế. UAT-NÓI-TRƯỚC: nút bridge sáng sau RE-LOGIN · + GĐ2/GĐ3 "SẮP" rỗng khi prod 0-phiếu/0-HĐ = đúng-spec. diff --git a/.claude/agent-memory/ctx-curator/MEMORY.md b/.claude/agent-memory/ctx-curator/MEMORY.md index e8f09a9..55e5f08 100644 --- a/.claude/agent-memory/ctx-curator/MEMORY.md +++ b/.claude/agent-memory/ctx-curator/MEMORY.md @@ -1,5 +1,7 @@ # ctx-curator Agent — Persistent Memory +- **S163→S167 (2026-07-30→08-01) 3 LƯỢT L9 gộp-seed @S168 `[LEAD SEED ON-BEHALF @closeout-nợ; nguồn = `_context-s-9.md` mục (3) từng PAUSE — verdict verbatim]`:** ① **@PAUSE-1 S163 = `SUA — 9 điểm`** (lead áp cả 9; nặng nhất #2: nháp lập luật *"ý PARK giữ mỗi ý 1 dòng"* rồi **ngay dòng sau bundle 6 sub-ý vào 1 dòng** — `_context`:70). ② **@PAUSE-3 S165 = `SUA — 10 điểm`** (dòng-1 vai ghi 9, **tự đính-chính 10 trong thân** — nặng nhất #1: 2 artifact-vệt sót khỏi §E [sàn-3 sẽ kêu orphan] · #9 regression bundle-hoá 16-ý-1-dòng **nuốt chính luật mỗi-ý-1-dòng** · #4/#5 nháy-kép-paraphrase lách rào-1 — `_context`:134). ③ **@PAUSE-4 S167 = `SUA — 8 điểm`** (lead áp cả 8; nặng nhất #1 OG-6 bốc-hơi-im-lặng khỏi §D · #2/#3 carry-bó nuốt 2-nhóm-nhãn + nuốt CHÍNH luật-cấm-bó [tái-hiện #2 @PAUSE-1] · #4 PUT-Conflict đã-định-đoạt còn nhãn sống · #7 số garble "8-9/13" tự-mâu-thuẫn-§E → lead derive lại 8/15 — `_context`:165; sạch vai-đo: §E phủ 10/10 spawn, 8/8 verdict khớp dòng-1 artifact). 🔴 **PAUSE-2 S164 KHÔNG chạy** (context cạn — lead khai tại chỗ, MIND block window-2 cũng nợ; đây là khai-có-vết, đừng đọc thành lượt-thiếu-âm-thầm). **Bài xuyên 3 lượt: luật-cấm-bó tái-hiện 3 CỬA liên tiếp (#2 P1 → #9 P3 → #2/#3 P4) — "luật vừa-viết không tự áp cho đoạn chứa nó" là class bền, mày phải grep chính nháp bằng luật của nháp.** Tag `[s163-s165-s167, luot-4-5-6, sua-9-10-8, luat-cam-bo-tai-hien-3-cua, pause-2-skip-co-khai, seed-on-behalf]` + - **S153 (2026-07-26) SINH RA — vai-1 vòng Ctx `[seed on-behalf by lead @closeout M9 — mày CHƯA chạy lần nào; nguồn = đĩa]`:** sinh bởi **OWNER-VETO @S153** — anh bác phương án 1-vai-gộp, chốt trực tiếp qua AskUser *"Build đủ 3 vai như hub"* (đây là **owner chốt THẬT**, KHÔNG phải delegated — đừng ghi nhầm nhãn). Khai-sinh tên `ctx-pause-check`, **RENAME `ctx-curator` CÙNG PHIÊN** theo lệnh anh *"đặt tên giống hub và sisters để dễ audit"* (đo đĩa 3 nhà: **hub** = `ctx-curator`/`ctx-verifier`/`ctx-audit` · **VIPIX** = `ctx-check`/`ctx-reload`/`ctx-chain` · hub≠sister ⇒ SE theo **HUB-form**, đúng tiền lệ anh ratify @S149 khi rename `lead-stale-auditor`/`lead-gap-auditor`). **Việc của mày:** KIỂM **bản NHÁP** block `## MIND-` @MỖI `/pause`, **SAU** máy `mind-check --draft` (máy-$0 ~61ms lo lỗi cơ-học: 3 rào literal + số-hiệu; mày lo tầng **máy MÙ** = NGỮ-NGHĨA), **TRƯỚC** khi lead chèn vào `_mind-s-.md` — dịch-trái: lỗi bắt ở nháp là lỗi KHÔNG BAO GIỜ vào tệp bất-biến. 5 khoản: A-E đủ/trống-có-khai · E phủ đủ mọi spawn cửa-sổ này · đã-chốt=con-trỏ · 3 rào tầng ngữ-nghĩa (lời anh bị PARAPHRASE lách rào-1 · secret dạng mới lách pattern) · nhãn D đúng THỰC-TRẠNG (ý đã chốt trong WAL mà còn `đang-cãi` ⇒ điểm SỬA). **Chỗ đứng đặc biệt:** mày là **carve-out DUY NHẤT** của `pause.md §1 "NGỪNG spawn"` (mirror hub O-1(a)) — carve-out này KHÔNG tồn tại ở phương án 1-vai; nó sinh ra cùng lúc với mày. Wire: `pause.md §2.6(C-bis)` bước **2-bis**. diff --git a/.claude/agent-memory/ctx-verifier/MEMORY.md b/.claude/agent-memory/ctx-verifier/MEMORY.md index 831d06e..843c351 100644 --- a/.claude/agent-memory/ctx-verifier/MEMORY.md +++ b/.claude/agent-memory/ctx-verifier/MEMORY.md @@ -1,5 +1,7 @@ # ctx-verifier Agent — Persistent Memory +- **S165+S167+S168 (2026-07-31→08-01) 3 LƯỢT L9 gộp-seed @S168 `[LEAD SEED ON-BEHALF @closeout-nợ; nguồn từng lượt ghi trong thân — carry `ctx-verifier-no-self-append` lần 4]`:** ① **@`_tiep-2` S165 = `CO — 9 cờ`** (trần-mind 84,8% · run.md tách K1-K8 · 2-vá-WAL — nguồn `_mind-s-9` MIND-3 §E + `_tiep-2.md`). ② **@`_tiep-4` S167 = `CO — 11 cờ`** (3 áp liền: verify-trỏ-gate-K6 · STATUS-622 · chữ-B4; còn lại vào WAL-notes — nguồn `_context-s-9`:164 PAUSE-4(3); 🔴 **`_tiep-4.md` 211B RỖNG RUỘT không mang verdict** — chính mày bắt lại @S168 thành cờ ⑧). ③ **@`_tiep-5` S168 = `CO — 11 cờ`, return CLEAN 0-garble:** cờ đắt: **④ claim "PARK-1..6 nhà HANDOFF" BỊ BÁC bằng grep 0-hit + control-DƯƠNG (`carry:` = 41 hit chứng lệnh sống)** — nghề grep-với-control-dương thành khuôn · ⑤⑥ MIND-2 gánh **3 inbound-pointer / 22 ý** + số-học trần: MIND-5 vừa, **MIND-6 vượt** ⇒ nén phải xong TRƯỚC pause-6 · ⑧ → **LUẬT: verdict PHẢI vào biên-nhận ngay tại cửa** (lead áp liền @`_tiep-5` dòng 6) · ⑨ con-trỏ `_context:61` **sai-ngay-lúc-viết** (file append-only không thối theo thời gian) — class khác con-trỏ-thối. 🔸 Đính-chính đếm lượt: entry S166 dưới tự ghi "LƯỢT 4" là **thiếu S165** — chuỗi thật S156→S158→S162→S165→S166→S167→S168 = **7 lượt**. Tag `[s165-s167-s168, luot-5-6-7, grep-control-duong, inbound-3-pointer-22-y, verdict-vao-bien-nhan, sai-luc-viet, seed-on-behalf-lan-4]` + - **S166 (2026-08-01) LƯỢT 4 @`/tiep` window-4 L9 — verdict `CO — 11 cờ` `[LEAD SEED ON-BEHALF NGAY TẠI CỬA (không đợi closeout — F-01 vá nhịp); nguồn = `_tiep-3.md:6` + return CLEAN 0-garble]`:** B↔`next:` khớp 3/3 (lần đầu 0-lệch sau 4 lượt). **Cờ đắt nhất ⑥ = NÂNG CẤP luật S162 của chính mày:** S162 dạy *"nén = đối chiếu TỪNG ý D có nơi đi"*; nay thấy TRƯỚC khi nén — MIND-2 §D là **NHÀ ĐANG GÁNH 2 con-trỏ** (MIND-1 nén trỏ vào + MIND-3 carry trỏ vào, 22 dòng D) ⇒ **nén một block phải đi TÌM ai đang trỏ VÀO nó trước** (inbound-pointer check), không chỉ soát ý của chính nó. **⑨ số-học chặn trước:** nén MIND-2 theo khuôn cũ chỉ dư 6.331 B < MIND-4 dự phóng 6.776 B ⇒ THIẾU ~445 B — lời khuyên hành-động: MIND-4 viết ≤6.331 B hoặc nén sâu hơn. **⑦ class `claim > việc` bắt ở lớp mềm:** PAUSE-3 khai *"áp CẢ 10"* điểm curator, đĩa chứng bundle 12-ý-1-dòng vẫn nguyên (`_mind:103`) — luật bị phạm nằm NGAY TRONG bundle. **① nghề đọc-vớt artifact chết:** cicd-K3 2.640 B "chỉ §0 = 0/6" NHƯNG vớt mốc recycle-proof PID 5364 @17:11:25 làm thước đo deploy cho lượt re-verify — artifact chết vẫn để lại thước. ⑩ header nén tự-tuyên "18 ý" thật 19 (lần 2 class này — S158 đã dạy "header tự tuyên = phải kiểm"). Tag `[s166, lan-chay-4, inbound-pointer-check-truoc-nen, so-hoc-nen-chan-truoc, claim-ap-ca-10-thuc-mot-phan, artifact-chet-de-lai-thuoc, seed-on-behalf-tai-cua]` - **S162 (2026-07-30) LƯỢT 3 @`/tiep` window-4 L8 — verdict `CO-CO — 8 cờ` `[LEAD SEED ON-BEHALF @closeout — nguồn: đĩa `_tiep-3.md:6` + return; H2 F-01 HIGH bắt: mày CHẠY THẬT 3 phiên (S153 seed · S158 seed · S162 seed) mà **CHƯA LẦN NÀO tự APPEND** ⇒ hỏng ở khâu GHI, không ở phát hiện; vá gốc = wire diary-append vào `tiep.md §3-ter`, đã lên HANDOFF NEXT-em #1]`:** 8 cờ K1-K8. **Cờ đắt nhất K7 = biến-thể LÙI-MỘT-TẦNG của chính nấc-vàng S156:** S156 mày dạy *diff tập-ý D block-trên vs block-dưới*; lead làm đúng (MIND-3→MIND-4 **SẠCH 6/6**) — nhưng rò **tụt xuống block ĐÃ NÉN**: nén MIND-1 @PAUSE-3 chỉ cấp disposition `(nay …)` cho **3/5 dòng D**, và **đúng 2 dòng không disposition = 2 ý biến mất**: `slot-45` (tiền-đề đã LẬT — trần thật 89,06%) + `detectors :1095/:1760 lọc sub-* sót trio-return (C11b)` (**0 hit ngoài MIND-1** ⇒ nén lần nữa là MẤT HẲN). ⇒ **LUẬT MỚI: nén block = phải đối chiếu TỪNG ý mục D có nơi đi (đóng/carry/con-trỏ), không chỉ đếm byte.** **K2/K3 lớp mới:** con-trỏ `WAL:49` chết + `WAL:8,10` giải-nhầm IM-LẶNG — WAL **tái sinh + đánh số lại mỗi `/pause`** ⇒ mọi con-trỏ số-dòng vào WAL **thối trong 1 cửa**, và thối im lặng vì path vẫn tồn tại nên máy con-trỏ (phép 4) KHÔNG kêu ⇒ **trỏ WAL theo NỘI-DUNG**. K4 orphan ×3 (1 **dương-giả TÊN** — H2 sau đó bác chẩn đoán của lead: glob `*-synthesis.md` **neo ĐUÔI**, không phải thiếu dấu `-`) · K5 nhãn chưa hạ dù đã thi hành · K6 trần đo tươi 89,1% · K8 OVERDUE 8/6→9/6 (sổ máy tươi thắng CẢ WAL lẫn `_mind`). Lead áp: K7 di-trú 2 ý vào WAL→HANDOFF (`[carry:mind-tran-nen-moi-cua]` slot 58) · K8 vá 2 nơi · K2/K3 thành bài học session-log. Tag `[s162, lan-chay-3, van-chua-tu-append-3-lan, ro-tut-xuong-block-da-nen, con-tro-WAL-theo-noi-dung, glob-neo-duoi, seed-on-behalf]` diff --git a/.claude/agents/cicd-monitor.md b/.claude/agents/cicd-monitor.md index 7097a57..e722df3 100644 --- a/.claude/agents/cicd-monitor.md +++ b/.claude/agents/cicd-monitor.md @@ -1,7 +1,7 @@ --- name: cicd-monitor description: | - CI/CD pipeline + post-deploy verification specialist for SOLUTION_ERP. Use proactively AFTER every push to main that triggers Gitea Actions deploy (code commits — skip docs-only per path-filter gotcha #41). Polls Gitea Actions run status via API, verifies test gate pass (Domain 58 + Infra 23 tests baseline), confirms deploy actually shipped (FE bundle hash change × 2 app + EF migrations applied prod), smoke tests prod endpoints (api/admin/eoffice.solutions.com.vn). NEVER writes code — produces PASS/FAIL verdict with concrete evidence from logs + curl + sqlcmd. Catches deploy fail tự động không phụ thuộc em main nhớ verify. + CI/CD pipeline + post-deploy verification specialist for SOLUTION_ERP. Use proactively AFTER every push to main that triggers Gitea Actions deploy (code commits — skip docs-only per path-filter gotcha #41). Polls Gitea Actions run status via API, verifies test gate pass (baseline SỐNG → `docs/STATUS.md` row Tests — B1, KHÔNG neo số ở persona), confirms deploy actually shipped (FE bundle hash change × 2 app + EF migrations applied prod), smoke tests prod endpoints (api/admin/eoffice.solutions.com.vn). NEVER writes code — produces PASS/FAIL verdict with concrete evidence from logs + curl + sqlcmd. Catches deploy fail tự động không phụ thuộc em main nhớ verify. model: opus effort: max tools: [Read, Grep, Glob, Bash, WebFetch, mcp__rag-unified__search_memory, mcp__rag-unified__search_code, mcp__rag-unified__cross_project_search, mcp__rag-unified__list_projects] @@ -167,8 +167,8 @@ Expect: latest mig prod **match** latest mig repo (DbInitializer auto-applies on **Stage results:** | Stage | Status | Notes | |---|---|---| -| test_domain | PASS/FAIL (58 baseline) | | -| test_infra | PASS/FAIL (23 baseline) | | +| test_domain | PASS/FAIL (baseline → STATUS row Tests) | | +| test_infra | PASS/FAIL (baseline → STATUS row Tests) | | | build_be | PASS/FAIL | | | build_fe_admin | PASS/FAIL | | | build_fe_user | PASS/FAIL | | @@ -230,8 +230,8 @@ Append to "Recent runs" FIFO last 20: - https://eoffice.solutions.com.vn (FE user bundle) - **SSH VPS:** `ssh vietreport-vps` (config sẵn `~/.ssh/config` user=Administrator key=id_ed25519) - **DB prod:** `.\SQLEXPRESS` / `SolutionErp` / `vrapp` user (password trong `$env:PROD_DB_PASSWORD`) -- **Tests baseline:** 111/111 PASS (58 Domain + 53 Infra) — Phase 9 UAT iteration có thể skip per chunk -- **Migrations:** 33 (latest `AddPeLevelOpinionsForV2` Mig 33 S29 cumulative) +- **Tests baseline:** → `docs/STATUS.md` row Tests (B1 — bỏ literal @S168 H24-DEEP F-9; số 111/58/53/23 cũ chết từ lâu: :4/:171 nói Infra 23 mà :233 nói 53 = tự-mâu-thuẫn nội-bộ, mọi lượt thật chạy bằng ``) — Phase 9 UAT iteration có thể skip per chunk +- **Migrations:** → `docs/STATUS.md` row Migrations (B1 — bỏ literal @S168 cùng-lớp F-9; số 33 cũ chết từ S29) ## Common fail patterns (cross-ref `docs/gotchas.md`) diff --git a/.claude/auto-memory/feedback_agent_return_garble_recover.md b/.claude/auto-memory/feedback_agent_return_garble_recover.md index e0e71e5..2651d63 100644 --- a/.claude/auto-memory/feedback_agent_return_garble_recover.md +++ b/.claude/auto-memory/feedback_agent_return_garble_recover.md @@ -5,7 +5,7 @@ metadata: node_type: memory type: feedback originSessionId: 67157d21-1ead-475d-9a50-cf7f07468583 - modified: 2026-07-31T02:46:15.525Z + modified: 2026-08-01T09:10:41.088Z --- Sub-agent đôi khi trả về message CUỐI = text bước memory-curation của nó ("Still 18KB, let me trim...", "Memory updated, splice correct...") THAY VÌ verdict/findings của task (#53 return-channel garble). Nhưng WORK + agent-memory diary VẪN ĐÚNG (nó làm task xong, ghi diary chuẩn, chỉ return nhầm text bước cuối). **Recover: đọc `agent-memory//MEMORY.md` recent-entry lấy verdict thật — KHÔNG re-spawn** (tốn + có thể garble tiếp; hoặc em-main re-do solo cho task cần chắc). Instruction-fix spawn-prompt "🔴 message CUỐI PHẢI là verdict, KHÔNG phải memory-note" GIẢM garble nhưng KHÔNG 100%. @@ -53,4 +53,6 @@ Sub-agent đôi khi trả về message CUỐI = text bước memory-curation c 🔴 **BÀI HỌC NGANG HÀNG (không thuộc #53 nhưng cùng closeout, ghi kèm vì cùng lớp "neo mục"):** CẤM neo một mục tiêu vào **SỐ DÒNG** của file append-ở-TRÊN (`_mind`). Mồi-ngầm gieo @PAUSE-1 định danh bằng `_mind-s-7.md:99`; `ring2` dựng chronology chứng neo **SAI NGAY TẠI COMMIT SINH RA NÓ** (stale-at-birth, không phải trôi-do-nén) ⇒ trong mọi trạng-thái đã-commit, `:99` **chưa từng** trỏ đúng mồi. Neo phải bằng **TRÍCH NỘI DUNG**. Liên [[feedback_absence_looks_like_clean]]. +🔴 **@S168 GHI SỰ-KIỆN L9 (2026-08-01 — L9 CÒN MỞ, tally CHỐT @closeout L9 theo đúng luật (c) + đếm CÁI-CHẮC):** nguồn per-window = `_context-s-9` PAUSE-2/3/4 + `_mind-s-9` MIND-4 §C/§E: **window-2 (S164)** sự-kiện đã xử tại chỗ: `ngược-#53` ev#4 (B1a att-1 **0-byte/207K tok**) · skeleton-472B (B2c1 att-1) · chết-ruột-188B (c2-l3) · garble fable-lane 3/9 + opus-lane 1/13 (nhãn PAUSE-2 — chốt phải đọc đĩa từng sub-file, đừng cộng nhãn) · **window-3 (S165)** PAUSE-3 ghi "~14 return-hỏng / 17 spawn — 0 mất công" (reviewer×3-resume-điền · cicd×3 · lane-K2×4 · lane-K3×4 gồm `engine-process-exit` ×2 CÙNG-task) — số "~" là ước cùng-phiên · **window-4 (S166)** nháp-8 (chết-limit giữa /pause-dở, 0 entry PAUSE ⇒ đếm khi chốt = đọc 15 artifact K4a/K4b/K5/K4c/F-1/H24-deep) · **window-5 (S167)** MIND-4 §C **derive-from-§E: 8 return-hỏng / 15 lượt (10 spawn + 5 resume), 0 mất công** — phác-đồ chọn-nhánh-theo-CÁI-THIẾU chạy tốt (resume-điền · lead-close-on-behalf · resume-Write-trước) · **window-6 (S168)** ctx-verifier CLEAN ×1, 0 garble. ⇒ TỔNG lũy-kế **GIỮ 72 cận-dưới qua S162** — L9 cộng @/session-end L9 bằng đọc-đĩa từng sub-file. Xác nhận lần 6: chống-#53 = thiết-kế ARTIFACT (0 B mất toàn L9 dù garble là nhịp-nền). + **How to apply:** sub return text lạ (memory-curation/off-topic/câu-mở-đầu/narration-giữa-chừng) → ĐỪNG tin nó fail/vô-dụng; **đọc ĐĨA trước, rồi diary, rồi resume**. Task-cần-chắc (bug-reasoning) → em-main re-do solo (reliable). 🔴 **Với MỌI spawn reasoning-lane: ép ghi đĩa từng phần trong prompt** — không để giảm garble mà để **garble không tốn gì**. Liên [[feedback_agent_kill_recovery]] · [[feedback_workflow_fanout_reliability]] · [[feedback_return_terminates_agent]]. diff --git a/.claude/governance/.session-counter.json b/.claude/governance/.session-counter.json index 4d9301b..19ce652 100644 --- a/.claude/governance/.session-counter.json +++ b/.claude/governance/.session-counter.json @@ -11,9 +11,9 @@ }, "_tick_invariant_note": "Tick invariant (hub dede7ec5 Delta-1, verbatim): moi LAN-CHOT +1; mot cap dung-noi tang DUNG +1, khong +2, khong +0. SE form = tick-at-entry-gate idempotent-per-label (hub Delta-2 recovery-gate +1 = permitted form) - NET +1/session-label EQUIV hub +1/cap on CLOSED pairs; an OPEN pair is transiently +0 until its entry gate fires (hub blessed, 9a35405b block-1 phep dung-noi). Guard song-con = label-convention (session-start 2.1.8: new conversation = new S\u003cnn\u003e label, NEVER reuse). history[] is append-unbounded BY DESIGN =\u003e absence of a marker = never-happened (safe semantics); IF a FIFO cap is ever added, eviction MUST be handled explicitly (absence-vi-bi-day != absence-vi-chua-xay-ra - log-BOUNDED design-note dede7ec5).", "_seed_honesty": "Seeded UNTICKED on purpose. counter=0 and last_ticked_* = null mean \u0027no tick has ever happened\u0027, which is the truth at S121 - the ritual that performs the tick lands in W3. Seeding a fake first tick here would make the very first cadence reading a lie, and H24 exists to catch exactly that kind of invented number.", - "counter": 41, - "last_ticked_session": "S167", - "last_ticked_head": "dea76d605a64a61a4baf9db91b03e0ac552816ed", + "counter": 42, + "last_ticked_session": "S168", + "last_ticked_head": "3595655a5f7aa7b43c150aa8d52057bf5630746d", "last_ticked_at": "2026-08-01", "last_audit": { "light_at_counter": 40, @@ -213,6 +213,11 @@ "at": "2026-08-01", "session": "S167", "event": "CLEAN tick (session-counter-tick.ps1 M2): counter 40->41, session S166->S167, head 24ea71e->dea76d6. Classify-before-tick: no regression (n=167 >= stored n=166); last_ticked_head reachable (merge-base --is-ancestor exit 0). 4 fields updated, 1 history entry appended, written atomically (temp + Move-Item -Force)." + }, + { + "at": "2026-08-01", + "session": "S168", + "event": "CLEAN tick (session-counter-tick.ps1 M2): counter 41->42, session S167->S168, head dea76d6->3595655. Classify-before-tick: no regression (n=168 >= stored n=167); last_ticked_head reachable (merge-base --is-ancestor exit 0). 4 fields updated, 1 history entry appended, written atomically (temp + Move-Item -Force)." } ] } diff --git a/.claude/sessions/session-9/_mind-s-9.md b/.claude/sessions/session-9/_mind-s-9.md index e41ce49..5e10e42 100644 --- a/.claude/sessions/session-9/_mind-s-9.md +++ b/.claude/sessions/session-9/_mind-s-9.md @@ -104,7 +104,7 @@ Máy chỉ quét phần **DƯỚI** marker đóng khối luật (dòng comment c - 2-hở-UX-K1-FE (3-filter-BE-chưa-UI · tab-cả-fe-user) {treo-chờ-anh} - F-5 gate-K1 PermGuard CatalogsPage khuôn-4-kind-cũ {treo-chờ-anh} - Luật ý-PARK gói >1 chủ-đề phải mỗi-ý-1-dòng (tách riêng để bó không nuốt luật cấm bó — curator #3 tái-hiện PAUSE-1 #2) {mới-nêu} -- Carry nhóm mới-nêu — slot (61) liên-danh · ESCALATE (i)(ii) · 4-finding-khe: nhà MIND-2 §D + `_context`:61, không chép {mới-nêu} +- Carry nhóm mới-nêu — slot (61) liên-danh · ESCALATE (i)(ii) · 4-finding-khe: nhà MIND-2 §D + `_context`:62-64, không chép [con-trỏ :61 sai-lúc-viết, vá @tiep-5 — cờ ⑨] {mới-nêu} - Carry nhóm gần-chốt — luật END-line sub-md (nhà HANDOFF `[carry:endline-sub-md]` + slot 44) {gần-chốt} - Carry nhóm treo-chờ-anh — slot (42)(43)(46)(47)(48)(39)(40)(41)(59)(60)(62) + PARK-1..6: nhà giữ HANDOFF/MIND-2, không chép {treo-chờ-anh} @@ -120,7 +120,7 @@ Máy chỉ quét phần **DƯỚI** marker đóng khối luật (dòng comment c - gate-K7 — PASS-WITH-FLAGS 10/0-blocker (garble-0-artifact → resume Write-trước trả CLEAN; tự đo prod 13-vai) — `sub-reviewer-gate-k7.md` - cicd-K7 — PARTIAL-live-sạch (garble return; artifact trọn M0-M6) — `sub-cicd-verify-k7.md` - lane-GĐ3 — BLOCKED-SẠCH CLEAN-return 0-file-chạm — `sub-implfe-gd3.md` -- ctx-curator @pause-4 — (verdict điền sau khi vai trả) +- ctx-curator @pause-4 — SUA 8 điểm, lead áp cả 8 — verdict đầy đủ ở `_context` PAUSE-4 mục (3) [điền @tiep-5 theo giao-kèo placeholder — cờ ⑦ ctx-verifier] ## MIND-3 — 2026-07-31T18:35:00+07:00 @ 15349e8 (window 3) diff --git a/.claude/sessions/session-9/_tiep-5.md b/.claude/sessions/session-9/_tiep-5.md new file mode 100644 index 0000000..0d711c6 --- /dev/null +++ b/.claude/sessions/session-9/_tiep-5.md @@ -0,0 +1,6 @@ +ts: 2026-08-01T15:41:23+07:00 +head-sha: 3595655a5f7aa7b43c150aa8d52057bf5630746d +window-ordinal: 6 +jsonl-hint: D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP/108e4e02-6ced-4d03-b480-a52d66be7af7 +account-label: none +ctx-verifier: CO-11-co (4-khoan + ban-nap-lai OK; co-re (7)(9) va tai cua, (10)(11) de MIND-5, (4)(5)(6) va (1)(2)(3) vao WAL-notes/closeout) diff --git a/.claude/workflows/runs/2026-07-30-S163-bookend-open/bookend-open-synthesis.md b/.claude/workflows/runs/2026-07-30-S163-bookend-open/bookend-open-synthesis.md new file mode 100644 index 0000000..657ed6d --- /dev/null +++ b/.claude/workflows/runs/2026-07-30-S163-bookend-open/bookend-open-synthesis.md @@ -0,0 +1,31 @@ +# bookend-open-synthesis — S163 (L9 window-1) — RETRO-HARVEST @S168 2026-08-01 + +> 🔴 **Khai thẳng:** synthesis này ghi **HỒI-TỐ @S168** (đóng orphan-① dòng closeout-nợ WAL), KHÔNG phải lúc run @S163. +> Phương-pháp: verdict lấy **NGUYÊN-VĂN END-line từng artifact** (vớt bằng `grep -E "^END"` trên đĩa @S168), đối-chiếu chéo `_mind-s-9.md` MIND-0 §E + `_context-s-9.md` PAUSE-1 — 10/10 khớp, 0 bịa. Chi-tiết từng finding = đọc artifact gốc cùng folder; file này là MỤC-LỤC-verdict + disposition, KHÔNG chép ruột. + +## Verdict 10 vai (END-line verbatim) + +| Artifact | END-line (nguyên văn, cắt ở TOTAL/COVERAGE) | +|---|---| +| `sub-tooling-auditor-open-S163.md` | `VERDICT=PASS_WITH_FLAGS — TOTAL=9 finding — COVERAGE=4/4 mặt` | +| `sub-harvest-curator-open-S163.md` | `VERDICT=GATE-FAIL — TOTAL=6 — COVERAGE=8/8 truc` | +| `sub-lead-stale-open-S163.md` | `VERDICT=FLAGS_FOUND (SÀN, chưa phải TỔNG) — TOTAL=12 FLAG — COVERAGE=7/8 nhóm (6/7 PARTIAL · G7 governance CHƯA CHẠM)` | +| `sub-lead-gap-open-S163.md` | `VERDICT=GAP-NẶNG (3 HIGH + 1 MED) · 3 class chạm/vượt jump=3 · nghi-thức carry CHẠY-MÀ-TRƯỢT — TOTAL=4 FLAG — COVERAGE=7/7 nhóm` | +| `sub-ring1-audit-open-S163.md` | `VERDICT=PASS_WITH_FLAGS — TOTAL=15 Đ/1 T — COVERAGE=16/29 claim` | +| `sub-ring2-audit-open-S163.md` | `VERDICT=PASS_WITH_FLAGS (16/16 FLAG ĐẠT · 2 claim ngoài-FLAG TRƯỢT · 2 ô-xanh thủng) — TOTAL=16 Đ/2 T — COVERAGE=18/27 claim` | +| `harness-eval-return.md` | `VERDICT=MIXED — 23 trục — COVERAGE=5/5 instrument hợp-đồng-vai` | +| `harness-refine-return.md` | `TOTAL=2 action (① nạp-lại 0 · ② thăng-hạng 0 · ③ lưu-kho 2 · ④ chưng-cất 0) — BÁC=13 — ESCALATE=5 — NHƯỜNG=5` | +| `harness-audit-return.md` | `VERDICT=ĐẠT — TOTAL=50 Đ/2 T — RE-CHẠY=4 instrument / ≥128 số (0 lệch)` | +| `sub-ctx-audit-open-S163.md` | `VERDICT=TRUOT — TOTAL=14 — COVERAGE=4/4` | + +## Disposition delta (đến @S168 — cái gì tiêu đâu) + +- **11-mục danh-sách vá (Mirror C1, 0/11 lúc PAUSE-1):** tiêu ở window-2+ (MIND-1 §B: *"hướng-tiếp cũ đã tiêu ở window-2"* — chuỗi SP-002 nuốt mạch). +- **P3-của-H2 HOÃN (vỡ cap `_INDEX` 167B/record 328B):** giải xong @S167 `628132c` — slot (57) **split `_INDEX` THI-HÀNH** (A7 427/427 PASS + fault-inject 2-chiều). +- **2 ESCALATE harness-audit (i) hook-nuốt-agent-memory · (ii) stray-misland ×3:** CÒN TREO — nhà `_mind-s-9.md` MIND-4 §D {mới-nêu}. +- **4-finding-khe giữa 2 vai H24 (spawn song song):** CÒN TREO cùng chỗ; 1 hàng (tally #53 cũ) đã thu-về @S164 vào sổ garble. +- **Orphan S159 ×2:** anh chốt @S163 *"Bootstrap tiếp, bỏ mạch"* ⇒ nợ-ngủ có chủ (carry `synthesis-roll-s159-s160` + `harvest-orphan-s159-tongquan`) — KHÔNG xử. +- **Diary 10 vai chưa seed:** seed dần các phiên sau; 2 vai ctx seed @S168 (closeout-nợ); phần còn lại = việc closeout L9 §L.b. +- **2 mồi ctx-audit (MỒI-A slot 61 · MỒI-B slot 60) + phép-thử FLAG-1:** chấm @close L9 (chưa tới). + +END bookend-open-synthesis — VERDICT=RETRO-HARVEST-OK — TOTAL=10/10 verdict verbatim-từ-đĩa — đóng orphan-① S163 @S168 diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/run.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/run.md index 9161ae4..89e00e4 100644 --- a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/run.md +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/run.md @@ -20,8 +20,14 @@ | 3 | Chốt spec cuối — `WF review-fable b3-chot s164` | /fable-real review | ✅ **GO-WITH-SPEC-FIXES**: GO 9/10 (K8 by-design) · 8 mâu-thuẫn (3 nặng A-1/A-4/A-5) · 0 vá-đè-vá/43 · build-order K1→K2→K3→K4a→K4b→K5→K4c→K6→K7→K8 · 8 fix lead ÁP XONG | | 4.K1 | Build K1 danh mục HĐ (BE+FE+test) | wf_2569b79b p1 · wf_2e08ba77 p2 · implfe · wf_1fb9f309 | ✅ @S165: 3 lane trọn · gate `sub-reviewer-gate-k1.md` **PASS-WITH-FLAGS 9f** · F4/F7 vá + T5b · Mig 70 áp LocalDB | | 4.K2 | Build K2 (BE+FE+test) | 4 lane + lead-solo đóng | ✅ @S165: gate PASS-WITH-FLAGS 10f · commit `0779f2d` · cicd PARTIAL-5/6-deploy-khỏe (mục-4 chân-lý-rỗng chờ phiếu thật) | -| 4.K3 | Build K3 (8 wf nhóm + finalize + designer) | chẻ-nhỏ: nhịp-1-lane + nhịp-2/3-lead + FE-lane + test-lane | ✅ @S165: gate PASS-WITH-FLAGS 8f/0-blocker · commit `15349e8` · 🔴 cicd CHẾT-vì-SESSION-LIMIT 18:50 (artifact 2640B chỉ §0 ⇒ 0/6 — re-verify @S166, mốc recycle-proof w3wp PID 5364 @17:11:25) · 🔴 F-1 checkbox-opt-out = đầu việc #1 @S166 | -| 4.K4a-K8 | Build K4a→K8 theo build-order B3 | hmw | ☐ lần /tiep sau (spec-cụm2/cụm3 đóng băng) | +| 4.K3 | Build K3 (8 wf nhóm + finalize + designer) | chẻ-nhỏ: nhịp-1-lane + nhịp-2/3-lead + FE-lane + test-lane | ✅ @S165: gate PASS-WITH-FLAGS 8f/0-blocker · commit `15349e8` · cicd **re-verify @S166 6/6 PASS** (lượt đầu chết-limit 18:50, artifact 2640B §0; mốc recycle-proof w3wp PID 5364 @17:11:25) · F-1 checkbox-opt-out → row 4.F1 dưới | +| 4.F1 | F-1 checkbox opt-out `applyLevelFinalize` màn duyệt (gate-K3 MAJOR) | lead + reviewer-f1 | ✅ @S166: mirror `PeWorkflowPanel` + DTO expose cờ level + types ×2 app · commit `7a903cf` · deploy #437 (gate-K4a PRE đo post-F-1 — STATUS `:479` lineage) — `sub-reviewer-f1-checkbox.md` | +| 4.K4a+K4b | Build K4a (bộ-sinh `Khkk_G*` +49 key/+196 policy) + K4b | hmw | ✅ @S166: commit `88e7ecf` · cicd **7/7** — gate: `sub-reviewer-gate-k4a.md`/`-k4b.md` · `sub-cicd-verify-k4ab.md` | +| 4.K5+K4c | Build K5 (forward-provision `lines[].contractId ∪ pe.contractId`) + K4c | hmw | ✅ @S166: commit `ce35f90`+`e202393` · cicd **5/5** (+1 Fact K4c server-side filter) — gate: `sub-reviewer-gate-k5.md`/`-k4c.md` · `sub-cicd-verify-k5-k4c.md` | +| 4.K6 | Build K6 | hmw | ✅ @S167: gate PWF-5 (MAJOR-1 số-đếm-comment FIXED) · commit `1c6d77a` · cicd **#440 PASS 5/5** (admin ROTATE `Ig1R5tAh` · eoffice FROZEN-lành-tính cmp-byte · marker-ÂM route-68-giữ) — `sub-reviewer-gate-k6.md` · `sub-cicd-verify-k6.md` | +| 4.K7 | Build K7 bridge KHKK→HĐ (hội-2-khóa + `Line.ContractId` + grant seeder) | hmw ×5 lane | ✅ @S167: 13-file +2241/−46 · gate PWF-**10**/0-blocker (F-8 neo-số-dòng→tên-hàm FIXED ×3 chỗ) · commit `aaed699` · cicd **PARTIAL-live-sạch** (run `aaed699` CANCELLED-cơ-chế 2-push-sát → ship #442, gotcha **#86**; seeder `"0 added + 2 upgraded"` verbatim + CanCreate 1→3 + row-13-giữ) · suite **639/0** Δ+17 — `sub-implbe-k7.md` · `sub-implfe-k7.md` · `sub-test-k7.md` · `sub-reviewer-gate-k7.md` · `sub-cicd-verify-k7.md` | +| 4.GĐ3 | Lane GĐ3 cây-4-folder ĐỒNG-NHẤT (slot 55 → 63) | implfe lane | 🔴 **BLOCKED-SẠCH** @S167 (0-file-chạm): layout GĐ3 3-panel ≠ khuôn giấy-cuộn, prepend-19rem bóp panel 346→42px @1366 HỎNG-CÂM — chờ anh 2-quyết (a) trang-đích + (b) phương-án A/B/C/D — `sub-implfe-gd3.md` §1 | +| 4.K8 | Build K8 dry-run theo build-order B3 | hmw | ☐ chờ K8-prep (form 14-người fail-closed + `SOLUTION-PE-{n}` + QĐ9 + ZZTEST + rollback-ID; (54)-FINAL: pre-flight CHỈ check-đọc) | | 5 | Dry-run E2E toàn trình (K8) | theo spec-cum3 | ☐ chặn bởi B0-form 14 người | ## Stages @@ -31,5 +37,5 @@ - [x] B1b — wf_8eb13087-5f9 3/3 lane sạch (l1 FAIL 5H · l2 6/6 chịu-lực ĐÚNG +l2-F1 rào-1-PE · l3 FAIL 6H + bác 6 nghi) → `b1b-review-synthesis.md` 14 vá + OG-6/OG-7 → spec v2 (hội tụ 2-lane: admin-hide tập-key tường minh; ApprovalGroup K2-chủ + backfill=1; 8 designer có phép đo; nguồn K1 = 7 ảnh [file đĩa 6-trang không bảng]) - [x] B2 — 3 cụm TRỌN: c1 (33KB + 12 vá) · c2 (5/5 + 15 vá; l3 chết-ruột phủ-bù) · c3 (22.9KB 7/7-đúng + 16 vá) = 43 vá tổng, 3 spec final - [x] B3 — GO-WITH-SPEC-FIXES (sub-review-fable-b3.md 6 section; 3 anchor re-grep đĩa khớp; 8 fix áp vào 3 spec) — SPEC ĐÓNG BĂNG cho B4 -- [ ] B4 — fan-out build (K1+K2+K3 = 3/8 ✅ @S165: gate 9f/10f/8f, disposition trong sub-reviewer-gate-k{1,2,3}.md; K4a..K8 ☐ @S166 — vá checkbox-ma Stages @S166 theo ctx-verifier cờ④) +- [ ] B4 — fan-out build **7/8** (K1..K7 ✅ @S165-S167 — gate per-wave PASS-WITH-FLAGS 9f/10f/8f/…/PWF-5/PWF-10, disposition trong `sub-reviewer-gate-k*.md`; K8 ☐ chờ prep; lane GĐ3 BLOCKED chờ owner slot (63) — ledger cập-nhật @S168 theo ctx-verifier cờ②, trước đó B4 ghi "3/8 @S165" + 0-row-GĐ3 = bản-đồ mù việc-đang-mở) - [ ] B5 — dry-run E2E diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum1-chi-tiet-31-07-2026.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum1-chi-tiet-31-07-2026.md index 8077804..0662b38 100644 --- a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum1-chi-tiet-31-07-2026.md +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-cum1-chi-tiet-31-07-2026.md @@ -8,6 +8,7 @@ K1 master-data danh mục (86 row) · K2 phiếu mang hạng-mục + nhóm + fre 1. 🔴 **[3-lane hội tụ] Menu key PHẢI VÀO `MenuKeys.All`** — nền khai `ContractCatalog` + 8 `AwV2_KhkkN*` "ngoài All" ⇒ **0 permission row ⇒ sidebar chết** (loop grant `DbInitializer.cs:2058` nguồn = All; khuôn THẬT: 5 leaf catalog hiện hành `MenuKeys.cs:168` + 3 leaf AwV2 `:182` đều TRONG All). Fix: cả 9 key **VÀO All** + KHAI drift dạng **DELTA per-wave** (B3-A1 — cấm neo tuyệt-đối vì thứ tự ship: K1 = +1 key/+4 policy · K3 = +8 key/+32 policy; mỗi commit kèm lệnh đếm lại `MenuKeys.All` thực tế + cập nhật 2 row STATUS, đừng Goodhart giữ-số-đứng-yên). Acceptance += "login Admin THẤY leaf trong sidebar ×2 app" + 1 test seed-grant. 2. 🔴 **[L1-F5] GỠ phương án (i) tại site `:342`** — nền đọc NGƯỢC comment (`WorkflowService.cs:36-43` mô tả NGUỒN COPY và khẳng định KHKK CỐ Ý không có site gán-qua-BIẾN; `:342` nằm trong `ReturnOrRejectAsync` chỉ nhận TraLai/TuChoi literal — DaDuyet **unreachable** qua đó). GIỮ phương án (ii): test khóa khẳng định điều đó. Cấm "sửa" :342. 3. 🔴 **[L2-H2] K3 thêm việc (d): sweep cụm ép-false** — `grep -rn "AllowApproverFinalize|AllowApproverSkipToFinal"` toàn src + fe-*: gỡ đủ **CREATE ép-false server-side** `ApprovalWorkflowV2AdminFeatures.cs:380-381` + **PUT Conflict** `:591-594`/`:605-610` + **FE `levelFlagsPayload`** `ApprovalWorkflowsV2Page.tsx:247-258` (`earlyFinalizeLocked :638`) — không chỉ note `:151-152`. Test mới: "tạo version qua CreateCommand type-10 GIỮ được cờ". + > 🔄 **ĐÍNH-CHÍNH @S168 (thi-hành phán gate-K3 — `sub-reviewer-gate-k3.md`; spec ĐÓNG-BĂNG nên đính-chính bằng khối này, KHÔNG sửa chữ gốc):** site **PUT Conflict `:591-594`/`:605-610` KHÔNG GỠ** — đó là luật versioning CHUNG mọi type (409 khi sửa version đang tham-chiếu), lead GIỮ là **ĐÚNG**; vá-3 liệt nhầm nó vào cụm ép-false. Phần còn lại của vá-3 (CREATE ép-false `:380-381` server-side + FE `levelFlagsPayload` — riêng type-10 GIỮ ép-false + FE disable ô theo phán F-2 gate-K3) đã xử @K3 `15349e8`. 4. 🔴 **[L2-H3] `KhkkCreatePage` ×2 app PHẢI SỬA** (mâu thuẫn nền: command +`ApprovalGroup` required nhưng page ghi "KHÔNG-ĐỔI") — body POST thêm `approvalGroup` + picker nhóm. Acceptance += "tạo phiếu nhóm 2 **TỪ UI** ×2 app" (curl-only không đủ). 5. 🔴 **[L2-M6/L1-F6] Chốt nhất quán `CatalogEntryId`**: auto-gen line lúc tạo phiếu được mồi null NHƯNG **submit-guard CHẶN null** (mọi line phải gán hạng mục trước trình) + validator line-mới-qua-API bắt buộc có. DoD "line khác nhóm → 409" phải chạy trên phiếu CÓ line thật (chống PASS-bằng-tập-rỗng). 6. **[L2-M4] Kéo `phase-guard line-edit sau DaDuyet` từ K4b VỀ K2** — Σ `Features.cs:709-711` tính LIVE, soft-delete line làm số phiếu-đã-duyệt trôi; freeze chưa kín nếu guard nằm cụm-2. diff --git a/.claude/workflows/runs/2026-08-01-S166-h24-deep-midsession/h24-deep-synthesis.md b/.claude/workflows/runs/2026-08-01-S166-h24-deep-midsession/h24-deep-synthesis.md new file mode 100644 index 0000000..d72f6bd --- /dev/null +++ b/.claude/workflows/runs/2026-08-01-S166-h24-deep-midsession/h24-deep-synthesis.md @@ -0,0 +1,30 @@ +# h24-deep-synthesis — S166 H24 DEEP (OVERDUE 15/15) — chốt @S168 2026-08-01 + +> Verdict 3 vai (verbatim dòng-1/END từ đĩa): `LEAD-STALE-DEEP: 11 FLAG (4 HIGH/5 MED/2 LOW) — coverage 8/8 chạm, 2/8 PARTIAL ⇒ 11 = SÀN` · `LEAD-GAP-DEEP: 6 FLAG (4 HIGH / 2 MED / 0 LOW) — coverage 6/6` · ring2: `VERDICT=16 ĐẠT / 1 TRƯỢT trên 17 FLAG (stale 10Đ/1T · gap 6Đ/0T)`. +> Nhịp sau vòng: `last_audit.light_at = deep_at = 40` (khuôn S143 deep-bao-hàm-light). Bài đắt nhất (run.md): **claim ĐẢO-DẤU của vai-đo chỉ vào sổ SAU vòng-kiểm** — ring2 bác F-8 cứu slot (59). + +## Disposition 11 FLAG stale-deep — TỪNG DÒNG (không số tổng) + +| F | class | resolve | khi nào — bằng chứng | +|---|---|---|---| +| F-1 | view-residual-asym HIGH | re-ground bảng canonical STATUS `:465-472` | **@S166** 4 ô (mig 71 · tables 97 · policies 452 · menu-keys 113; detector re-run "97/71 ĐÚNG") + **@S168 vá NỐT ô Tests** — 🔴 khai thật: cell `:472` còn `**590 PASS**` tới tận @S168 (claim "vá 5-row" @S166 thật là 4-row + annotation), @S168 đặt cell = **639** (45D+594I đo tươi) | +| F-2 | view-stale-count HIGH | `:479` bundle re-stamp | **@S166** (`1yiNV4VH`/`DoULfmdT` #437, kèm luật "đừng tin ô này quá 1 deploy") → **@S168** tươi tiếp `RgvHZkPH`/`D65FJPGd` #442 (cicd-K7 M4) | +| F-3 | view-stale-count LOW | counter `:6` | **@S168** re-stamp 42 (tick S168) | +| F-4 | view-stale-count MED | `CLAUDE.md` mig | **@S168**: module-row KHKK `69`→`69, 71` + history +Mig 70/71 (K1/K2-K3) | +| F-5 | view-stale-header MED | `HANDOFF.md:5` | **@S168**: segment mới **S163→S168** (nhãn ≥ STATUS `:6`) | +| F-6 | view-stale-status MED | NEXT-em stale | **@S168**: heading cũ → 🧊 lineage + disposition-line TỪNG mục (#1 LOẠI-có-lý-do · #2 xong/ngủ · #5 ✅@S164 · #6 ✅ 2 nửa · #7 DUE) | +| F-7 | view-stale-count HIGH | slot (57) `_INDEX` | **@S167** `628132c` THI-HÀNH split (A7 427/427 PASS) — slot đóng, HANDOFF @S168 ghi | +| F-8 | view-stale-count HIGH | slot (59) `tiep_reload` | 🔴 **KHÔNG ÁP** — ring2 **TRƯỢT** FLAG này (đo sai phạm-vi `:1-117`, kết-luận lật ngược); số đúng **~120.633B ≈ 30-40K, VẪN DƯỚI sàn**; WAL đính-chính @S166, HANDOFF (59) @S168 ghi phân-xử + giữ câu hỏi SỐNG | +| F-9 | view-stale-role-desc MED | persona `cicd-monitor` | **@S168**: bỏ literal 4 site (:4/:170/:171/:233) + site-5 `Migrations: 33` cùng-lớp → trỏ STATUS (B1); **ăn từ restart kế** (hot-reload ENV-DEP) | +| F-10 | view-stale-status MED | 3-site phase mâu-thuẫn | **@S168**: `CLAUDE.md:17` bỏ-neo-phase · `migration-todos:4` active-work = chuỗi K · `:798` nhãn S160→S167 + note chuỗi-K (đóng luôn ghi-chú "K-wave vắng 0-hit/822 dòng") | +| F-11 | view-stale-status LOW | `governance/README.md:5` | **@S168**: lật nhãn `Adopted — trial ĐÃ ĐÓNG` | + +## Ring2 INFORM #1-#6 — disposition + +#1 WAL:33 sửa `180.649B-đã-đạt-dải` → đính-chính **@S166** (WAL hiện-hành sạch) + HANDOFF (59) @S168 · #2-#5 (tổng gap 27→**24** · lệnh grep khoảng-trắng · `:200`→`:201` · sed-scope · diary-size 12.551B) = **errata-of-record ghi TẠI ĐÂY**, artifact gap-file BẤT BIẾN không sửa · #6 re-run `governance-detectors.ps1` sau đợt vá = NEXT-em #4 @S168 HANDOFF (kỳ vọng FLAG `SKILL.md:93` biến mất). + +## Gap-deep 6 FLAG — khai giới-hạn + +FLAG nặng nhất (lead `_mind` đọc cụt 165/270) **vá trong phiên @S166** (run.md). Disposition 5 FLAG còn lại = đọc `sub-lead-gap-deep-S166.md` trực tiếp — retro-chốt này KHÔNG dựng lại từ trí nhớ (đếm CÁI-CHẮC). + +END h24-deep-synthesis — VERDICT=RESOLVE-TRỌN 11/11 (10 áp [S166 ×3 + S167 ×1 + S168 ×6] + 1 KHÔNG-ÁP-có-phân-xử F-8) — đóng orphan S166 @S168 diff --git a/CLAUDE.md b/CLAUDE.md index ce7ac72..dc02589 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,7 +14,7 @@ Kiến trúc: **.NET 10 Clean Architecture + 2 React FE (admin + user) + SQL Ser 1. docs/STATUS.md ← Snapshot HIỆN TẠI (phase nào, việc gì đang làm — PE module CÒN CHỈNH NHIỀU) 2. docs/HANDOFF.md ← Brief 5 phút: session trước làm gì + cảnh báo session tiếp 3. docs/PROJECT-MAP.md ← Bản đồ toàn cảnh -4. docs/changelog/migration-todos.md ← Atomic tasks theo phase (Phase 7 PE refinement mới) +4. docs/changelog/migration-todos.md ← Atomic tasks theo phase (active-work đọc TRONG file — KHÔNG neo nhãn phase ở đây, H24-DEEP F-10) 5. docs/workflow-contract.md ← ⭐ State machine 9 phase HĐ — base pattern cho PE workflow ``` @@ -59,7 +59,7 @@ Kiến trúc: **.NET 10 Clean Architecture + 2 React FE (admin + user) + SQL Ser - Audit fields: `CreatedAt`, `UpdatedAt`, `CreatedBy`, `UpdatedBy` (`BaseEntity`) - Soft delete: `IsDeleted`, `DeletedAt`, `DeletedBy` (`AuditableEntity`) - Migrations: `dotnet ef migrations add --project src/Backend/SolutionErp.Infrastructure --startup-project src/Backend/SolutionErp.Api` -- **Số migration · bảng hiện tại → [`docs/STATUS.md`](docs/STATUS.md) (canonical — KHÔNG copy số ở đây để tránh drift; Harness-11 B1).** Lịch sử mig gần đây: **+S161 Mig 69 `AddContractSigningPlans`** (module MỚI **Kế hoạch Ký kết HĐ** — 7 `CreateTable`, bảng 89→96; menu-key `KeHoachKyKet` sinh **policy** KHÔNG sinh menu-row; gotcha **#85** menu-key OR-gate FE ≠ policy per-action BE) · **+S157 Mig 68 `AddPeAllowApproverDelete`** (PE nút XÓA phiếu ở màn duyệt — AddColumn, no new table) · **+S133 Mig 67 `AddPeApprovedBudgetSnapshot`** (PE freeze ngân sách phiếu DaDuyet — snapshot 11 cột AddColumn chốt tại finalize choke-point + site-5 admin-override + backfill `Sql()` OUTER APPLY 18/18 prod, no new table; display-gate `budgetFrozen` phiếu DaDuyet đọc snapshot/phiếu mới đọc live; gotcha #81-EXT) · **+S97 Mig 60 `AddPeEndedByLevelFinalize` + Mig 61 `BackfillEndedByLevelFinalizeFromChangelog`** (PE cờ RUNTIME finalize-sớm — display đọc runtime thay suy-config; backfill Mig 60 soi nhầm bảng Approvals → Mig 61 đúng Changelogs; gotcha #78/#79) · +S74 Mig 55 `AddCcmNoteToPeWorkItemBudget` (PE CcmNote) · +S73 Mig 54 `AddPeSuggestedAndApprovedPrice` (PE giá đề xuất PRO/CCM). +S69: Mig 53 `AddPeUrgentAndCeoApprovalThreshold` — PE +IsUrgentByPro/Ccm cờ gấp PRO/CCM + ApprovalWorkflow +CeoApprovalThreshold ngưỡng CCM duyệt-final, 3 AddColumn no new table. +S65: Mig 51 `AddDepartmentParentId` Department.ParentId loose-Guid no-FK org-tree phân cấp + Mig 52 `AddHoSoLinkToPurchaseEvaluation` PE HoSoLink nvarchar(1000) hyperlink NAS — cả 2 AddColumn no new table, tables giữ 88. Phase 10 COMPLETE + Phase 11 P11-A→F done — Mig 34-42 HRM/Office/WorkflowApps/Attendance + Contract V2 (32-33) + WireWorkflowApps V2 (41) + LeaveBalance (42) + Holiday filtered-unique (43, S45) + Vehicle/Driver catalog (44, S51) + HRM-catalog filtered-unique 3× (45, S51) + ItTicket SLA (46, S52) + Master filtered-unique 3× (47, S53 gotcha #57 EXT) + Project master fields Year/Investor/Location/Package (48, S55 — AddColumn no new table, kèm nạp 62 dự án + 71 hạng mục + 3 NCC real data từ Excel qua `SeedRealMasterDataAsync` ungated idempotent) + PE gắn Hạng mục công việc WorkItemId loose-Guid KHÔNG FK vật lý (49, S57bis — AddColumn+CreateIndex, no new table) + **Mig 50 `ReplaceBudgetModuleWithPeWorkItemBudgets` (S61, 2026-06-13) — XÓA module Budget cũ, thay bằng `PeWorkItemBudgets` ngân sách per-gói-thầu (1 record/cặp Dự án × Hạng mục, nhập theo role PRO/CCM, vượt ngân sách = cảnh báo mềm cho lưu S62); backfill `BudgetManualAmount→BudgetPeriodAmount` TRƯỚC DropColumn (phiếu UAT giữ số); net bảng 93→88; gotcha #63/#64**. V2 schema history S29-era bên dưới giữ nguyên — Mig 32+33 Plan B Contract V2 cookie-cutter mirror PE Mig 22-26 (S29). Mig 26 `AddPeLevelOpinionsForV2`: bảng mới `PurchaseEvaluationLevelOpinions` UNIQUE composite (PEId, LevelId), FK Cascade Pe + Restrict Level. Section 5 "Ý kiến cấp duyệt" V2 dynamic theo workflow đã pin: forEach Step (Phòng) → forEach Level (Cấp) → forEach NV → 1 OpinionBox. Service `ApproveV2Async` UPSERT auto khi NV duyệt — Q1=1B (sync gắn với Duyệt, KHÔNG form input rời). SignedByUserId track signer thật, FE banner "Admin duyệt thay" khi !== ApproverUserId. Comment empty → "(duyệt — không ý kiến)" placeholder. Phiếu V1 legacy fallback Mig 15 4 box readOnly (data history). Mig 25 `AddIsUserSelectableToApprovalWorkflows`: ALTER `ApprovalWorkflows` +`IsUserSelectable bit` (admin pin/unpin workflow nào cho user pick lúc create phiếu, multi-select độc lập IsActive). Backfill `WHERE IsActive=1 SET 1` giữ behavior cũ. Designer +badge "Cho user chọn" + button Ghim/Bỏ ghim. Workspace filter dropdown chỉ workflows `IsUserSelectable=true`. Mig 22-24 V2 schema (Session 17): `ApprovalWorkflows`/Steps/Levels — Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua ApproverUserId, OR-of-N cùng cấp). PE.ApprovalWorkflowId pin V2. PE.CurrentApprovalLevelOrder track. State machine 5 trạng thái: Nháp / Đã gửi duyệt / Trả lại (Phase riêng TraLai=98) / Từ chối / Đã duyệt. PE Service V2 wire match `actor.Id == ApproverUserId`. Contract V2 ĐÃ WIRE (Mig 32+33 Plan B S29 — cookie-cutter mirror PE V2: `ApproveV2Async` + `ContractLevelOpinions` UPSERT + Workspace V2 Select dropdown). Mig 21 V1 flat workflow vẫn live cho phiếu cũ.) +- **Số migration · bảng hiện tại → [`docs/STATUS.md`](docs/STATUS.md) (canonical — KHÔNG copy số ở đây để tránh drift; Harness-11 B1).** Lịch sử mig gần đây: **+S164/S165 Mig 70 `AddContractCatalogEntries` (K1 SP-002 — danh mục hạng-mục HĐ 86 dòng, +1 bảng 96→97) + Mig 71 `AddKhkkApprovalGroupCatalogAndFinalizeRuntime` (K2/K3 — phiếu KHKK +nhóm duyệt N1-N8 backfill=1 + Line +hạng-mục + unique 3-cột + cờ `EndedByLevelFinalize`, 0 bảng mới)** · **+S161 Mig 69 `AddContractSigningPlans`** (module MỚI **Kế hoạch Ký kết HĐ** — 7 `CreateTable`, bảng 89→96; menu-key `KeHoachKyKet` sinh **policy** KHÔNG sinh menu-row; gotcha **#85** menu-key OR-gate FE ≠ policy per-action BE) · **+S157 Mig 68 `AddPeAllowApproverDelete`** (PE nút XÓA phiếu ở màn duyệt — AddColumn, no new table) · **+S133 Mig 67 `AddPeApprovedBudgetSnapshot`** (PE freeze ngân sách phiếu DaDuyet — snapshot 11 cột AddColumn chốt tại finalize choke-point + site-5 admin-override + backfill `Sql()` OUTER APPLY 18/18 prod, no new table; display-gate `budgetFrozen` phiếu DaDuyet đọc snapshot/phiếu mới đọc live; gotcha #81-EXT) · **+S97 Mig 60 `AddPeEndedByLevelFinalize` + Mig 61 `BackfillEndedByLevelFinalizeFromChangelog`** (PE cờ RUNTIME finalize-sớm — display đọc runtime thay suy-config; backfill Mig 60 soi nhầm bảng Approvals → Mig 61 đúng Changelogs; gotcha #78/#79) · +S74 Mig 55 `AddCcmNoteToPeWorkItemBudget` (PE CcmNote) · +S73 Mig 54 `AddPeSuggestedAndApprovedPrice` (PE giá đề xuất PRO/CCM). +S69: Mig 53 `AddPeUrgentAndCeoApprovalThreshold` — PE +IsUrgentByPro/Ccm cờ gấp PRO/CCM + ApprovalWorkflow +CeoApprovalThreshold ngưỡng CCM duyệt-final, 3 AddColumn no new table. +S65: Mig 51 `AddDepartmentParentId` Department.ParentId loose-Guid no-FK org-tree phân cấp + Mig 52 `AddHoSoLinkToPurchaseEvaluation` PE HoSoLink nvarchar(1000) hyperlink NAS — cả 2 AddColumn no new table, tables giữ 88. Phase 10 COMPLETE + Phase 11 P11-A→F done — Mig 34-42 HRM/Office/WorkflowApps/Attendance + Contract V2 (32-33) + WireWorkflowApps V2 (41) + LeaveBalance (42) + Holiday filtered-unique (43, S45) + Vehicle/Driver catalog (44, S51) + HRM-catalog filtered-unique 3× (45, S51) + ItTicket SLA (46, S52) + Master filtered-unique 3× (47, S53 gotcha #57 EXT) + Project master fields Year/Investor/Location/Package (48, S55 — AddColumn no new table, kèm nạp 62 dự án + 71 hạng mục + 3 NCC real data từ Excel qua `SeedRealMasterDataAsync` ungated idempotent) + PE gắn Hạng mục công việc WorkItemId loose-Guid KHÔNG FK vật lý (49, S57bis — AddColumn+CreateIndex, no new table) + **Mig 50 `ReplaceBudgetModuleWithPeWorkItemBudgets` (S61, 2026-06-13) — XÓA module Budget cũ, thay bằng `PeWorkItemBudgets` ngân sách per-gói-thầu (1 record/cặp Dự án × Hạng mục, nhập theo role PRO/CCM, vượt ngân sách = cảnh báo mềm cho lưu S62); backfill `BudgetManualAmount→BudgetPeriodAmount` TRƯỚC DropColumn (phiếu UAT giữ số); net bảng 93→88; gotcha #63/#64**. V2 schema history S29-era bên dưới giữ nguyên — Mig 32+33 Plan B Contract V2 cookie-cutter mirror PE Mig 22-26 (S29). Mig 26 `AddPeLevelOpinionsForV2`: bảng mới `PurchaseEvaluationLevelOpinions` UNIQUE composite (PEId, LevelId), FK Cascade Pe + Restrict Level. Section 5 "Ý kiến cấp duyệt" V2 dynamic theo workflow đã pin: forEach Step (Phòng) → forEach Level (Cấp) → forEach NV → 1 OpinionBox. Service `ApproveV2Async` UPSERT auto khi NV duyệt — Q1=1B (sync gắn với Duyệt, KHÔNG form input rời). SignedByUserId track signer thật, FE banner "Admin duyệt thay" khi !== ApproverUserId. Comment empty → "(duyệt — không ý kiến)" placeholder. Phiếu V1 legacy fallback Mig 15 4 box readOnly (data history). Mig 25 `AddIsUserSelectableToApprovalWorkflows`: ALTER `ApprovalWorkflows` +`IsUserSelectable bit` (admin pin/unpin workflow nào cho user pick lúc create phiếu, multi-select độc lập IsActive). Backfill `WHERE IsActive=1 SET 1` giữ behavior cũ. Designer +badge "Cho user chọn" + button Ghim/Bỏ ghim. Workspace filter dropdown chỉ workflows `IsUserSelectable=true`. Mig 22-24 V2 schema (Session 17): `ApprovalWorkflows`/Steps/Levels — Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua ApproverUserId, OR-of-N cùng cấp). PE.ApprovalWorkflowId pin V2. PE.CurrentApprovalLevelOrder track. State machine 5 trạng thái: Nháp / Đã gửi duyệt / Trả lại (Phase riêng TraLai=98) / Từ chối / Đã duyệt. PE Service V2 wire match `actor.Id == ApproverUserId`. Contract V2 ĐÃ WIRE (Mig 32+33 Plan B S29 — cookie-cutter mirror PE V2: `ApproveV2Async` + `ContractLevelOpinions` UPSERT + Workspace V2 Select dropdown). Mig 21 V1 flat workflow vẫn live cho phiếu cũ.) ### Modules @@ -67,7 +67,7 @@ Kiến trúc: **.NET 10 Clean Architecture + 2 React FE (admin + user) + SQL Ser |---|---|---|---| | Contract (HĐ) | `Domain/Contracts/` | 1-11 | Feature-complete (7 ContractType × 9 phase) | | PurchaseEvaluation (Duyệt NCC tiền-HĐ) | `Domain/PurchaseEvaluations/` | 12,13,15,49,50,52-61,65-68 | Feature-complete — +Hạng mục (Mig 49) +ngân sách per-gói-thầu role PRO/CCM (Mig 50) +Link hồ sơ NAS (Mig 52) +cờ gấp PRO/CCM + CCM duyệt-final theo ngưỡng (Mig 53) +giá đề xuất PRO/CCM + CCM-note (Mig 54/55) +PRO-split + ghi-chú-giá (Mig 56/57) +multi-winner liên-danh + level-finalize + NS-kỳ-CCM (Mig 58/59) +**`EndedByLevelFinalize` runtime-flag + backfill-fix (Mig 60/61, S97 — gotcha #78/#79)** +multi-NCC per-hạng-mục (Mig 65, S114 — gotcha #81) +duyệt-khoảng giá Min–Max (Mig 66, S117) +**freeze NS phiếu DaDuyet snapshot 11-cột + display-gate `budgetFrozen` (Mig 67, S133 — gotcha #81-EXT indirect-assignment)** +**lũy kế TẠM TÍNH vs CHÍNH XÁC (S134, 0-mig — `ComputePendingAsync` complementary [ChoDuyet-winner vào tạm-tính, nháp list-only] + sub-dòng amber matrix + banner màn duyệt + D4 audit-note changelog)** +**nút XÓA phiếu ở màn duyệt (Mig 68, S157/S162 — `AllowApproverDelete`, AddColumn no new table)**. Export PDF pending | -| **ContractSigningPlans (Kế hoạch Ký kết HĐ — KHKK)** | `Domain/ContractSigningPlans/` | **69** | Feature-complete — **Mig 69 `AddContractSigningPlans` (S161, 7 bảng, 89→96)**: CRUD + Dossier 15 policy (W2) · duyệt V2 3-trạm test-before RED→GREEN (W3) · đường-ống HĐ V2 (W6) · bản-cứng **1-MỐC** theo owner *(form điền đủ → duyệt nếu có → upload bản cứng = xong)* (W7) · cây 4-folder GĐ ×2 app (S162). 🔴 Gate quyền dùng **đúng key policy của endpoint** (`KeHoachKyKet`), KHÔNG OR key con — gotcha **#85** | +| **ContractSigningPlans (Kế hoạch Ký kết HĐ — KHKK)** | `Domain/ContractSigningPlans/` | **69, 71** | Feature-complete — **Mig 69 `AddContractSigningPlans` (S161, 7 bảng, 89→96)**: CRUD + Dossier 15 policy (W2) · duyệt V2 3-trạm test-before RED→GREEN (W3) · đường-ống HĐ V2 (W6) · bản-cứng **1-MỐC** theo owner *(form điền đủ → duyệt nếu có → upload bản cứng = xong)* (W7) · cây 4-folder GĐ ×2 app (S162) · **chuỗi K SP-002 @S164-S167 (Mig 71 nhóm-duyệt N1-N8 + Line hạng-mục + 8 workflow nhóm + bridge KHKK→HĐ hội-2-khóa K7 `aaed699`)**. 🔴 Gate quyền dùng **đúng key policy của endpoint** (`KeHoachKyKet`), KHÔNG OR key con — gotcha **#85** | | ~~Budget (Ngân sách dự án)~~ | — | 14 → **Mig 50 DROP** | ⚠️ **REMOVED S61** — module Budget cũ XÓA, thay bằng PE-budget-per-gói-thầu (`PeWorkItemBudgets`). FE pages/types/menu `Bg_*` gỡ hết | | Master (Supplier/Project/Department) | `Domain/Master/` | 2, 10, 48, 51, 62-64 | Feature-complete — +Project fields Year/Investor/Location/Package (Mig 48) +Department.ParentId org-tree (Mig 51) +Supplier expand 30-field/import/publish-state (Mig 62-64) | | Identity (User/Role/Permission/MenuItem) | `Domain/Identity/` | 1, 3, 11 | Feature-complete (30 demo user — 16 sample + 14 Solutions thật) | diff --git a/docs/HANDOFF.md b/docs/HANDOFF.md index 7096cfe..6e5f60c 100644 --- a/docs/HANDOFF.md +++ b/docs/HANDOFF.md @@ -2,9 +2,38 @@ > **Tiering rule (S40):** giữ **2-3 session gần nhất**. Cũ hơn → `docs/changelog/sessions/`. Full brief history pre-S40 → `docs/_archive/HANDOFF-preS40-fullhistory.md`. -**🆕 Last updated:** 2026-07-30 trưa (**S161→S162** — phiên-LOGIC **L8** window-3 `/tiep` = **5/5 wave KHKK SHIP**, window-4 `/tiep` = **cây 4-folder GĐ ship prod** + **bookend-close 5 vòng**). Chi tiết = `docs/STATUS.md` dòng CURRENT + log `docs/changelog/sessions/2026-07-30-1100-S162-cay-4-folder-gd-close.md` + run-trace `.claude/workflows/runs/2026-07-30-S162-{cay-4-folder-gd,bookend-close}/`. +**🆕 Last updated:** 2026-08-01 chiều (**S163→S168** — phiên-LOGIC **L9** windows 1-6: bookend @open S163 → chuỗi SP-002 B0→B4 **K1→K7 SHIP 7/8 wave** [K1 `50e6d8c` · K2 `0779f2d` · K3 `15349e8` · F-1 `7a903cf` · K4a+K4b `88e7ecf` · K5+K4c `ce35f90`+`e202393` · K6 `1c6d77a` #440 5/5 · **K7 bridge KHKK→HĐ `aaed699`** PARTIAL-live-sạch, suite **639/0**] → governance `628132c` → **closeout-nợ TRẢ @S168**: gotcha #86 + H24-DEEP 11-FLAG resolve trọn + orphan S163/S166 harvest + STATUS/CLAUDE/todos tươi). Chi tiết = `docs/STATUS.md` dòng CURRENT + `.claude/WAL.md` + run-trace `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/` (60+ artifact). -## 🔴 CHỜ ANH — ĐÁNH SỐ (trả lời bằng số) +## 🔴 CHỜ ANH @S168 — ĐÁNH SỐ (trả lời bằng số) + +**(63) 🔴🔴 BLOCKER MẠCH CHÍNH — GĐ3 cây-4-folder ĐỒNG-NHẤT, 2 quyết** (từ (55) anh chốt *"Nên đồng nhất"* @S167; lane scaffold **BLOCKED-SẠCH 0-file-chạm** — `runs/2026-07-31-S164-4gd-khkk-fanout/sub-implfe-gd3.md` §1 bảng-số: layout GĐ3 3-panel ≠ khuôn giấy-cuộn ⇒ prepend 19rem bóp panel 346→42px @1366 = HỎNG-CÂM): +- **(a)** trang-đích fe-user: `MyContractsPage` · `InboxPage` · `WorkflowMatrixViewPage` — áp trang nào (hay cả 3)? +- **(b)** phương-án: **A** prepend-42px ⛔ hỏng-câm · **B** chỉ-≥2xl · **C** nới-`PipelineTreePanel`-thu-gọn-desktop (**lane + lead NGHIÊNG C** — đụng 2 file SHA-pair chung 4 trang anh đã nghiệm thu (56); câu phụ: panel mở = ĐẨY content hay PHỦ lên?) · **D** cây-thay-Panel-3. +Chốt (a)+(b) → scaffold 1-lượt → gate → commit → cicd. + +**(59) 🔄 `tiep_reload` — số đo ĐÃ PHÂN-XỬ @S166 (ring2 bác F-8 stale-deep):** vai đo `:1-117` ra 180.649B *"đã đạt dải"* = **SAI PHẠM-VI**; đo ĐÚNG segment-mới-nhất = **~120.633B ≈ 30-40K tok, VẪN DƯỚI sàn 40-60K** ⇒ câu hỏi gốc còn sống: **sửa mục-tiêu xuống hay mở rộng danh-sách nguồn?** 🔴 Số SỐNG = đo tươi sau khi segment này land (CẤM neo literal — 3/5 nguồn phình mỗi phiên). + +**Slot ĐÓNG @S167 (PAUSE-4 — lời anh verbatim ở `_context-s-9.md`):** **(54) FINAL** giữ-hiện-trạng, *"Nếu điều chỉnh, tao sẽ tự tay điều chỉnh"* ⇒ K8 pre-flight CHỈ check-đọc workflow-live/roster, KHÔNG dựng/sửa · **(55)** *"Nên đồng nhất"* → thành slot (63) trên · **(56) ĐÓNG** (*"tao có view qua rồi, hiện ổn"*) · **(57)** split `_INDEX` **THI-HÀNH** @S167 `628132c` (A7 427/427 PASS lần-đầu + fault-inject 2-chiều; luật `split_rule_S167` → key `memory-budget.json`) · **(58)** trần `_mind` 32→48KB **THI-HÀNH** (live 75,4% — hết áp-lực nén-mỗi-cửa). + +**Slot cũ còn treo:** (42)(43)(44) canonRows / carry-con-trỏ / END-line · (46) thước "17,1K" ma · (47) `_INDEX` cap · (48) harvest self-compact · (39) RAG Qdrant · (40) `hmw_width.cap` 20 < roster 23 · (41) `ring5-audit` · (60) enum class "số đúng, đơn-vị không-canonical" · (61) defect liên-danh N-HĐ (đi cùng F-2/W5) · (62) fail-LOUD refresh@closeout (chạm form `_end` anh chốt). + +**Chờ-anh phụ (không chặn):** F-10 attachment owner-check 2 module · mark-read chuông cũ (mirror PE S96) · tài khoản UAT non-Admin · thư `ai_infra/all/2026-07-28-day-wake-probe-first-resume` (nấc `agreed`). + +## 🔴 NEXT em @S168+ (không cần anh gật) + +1. **K8-prep** theo spec-cụm3 (form-14-người fail-closed + gói `SOLUTION-PE-{n}` + QĐ9 đo-2-nhánh + ZZTEST + rollback-ID); (54)-FINAL: pre-flight CHỈ check-đọc. +2. **Nợ K7 0-blocker:** race-2-request-đồng-thời (unique-filtered-index vs RowVersion vs transaction-recheck — cân "máy-rộng-UI-hẹp") · DraftData-không-carry ở bridge (khác tiền-lệ PE — hỏi khi chạm K8 dry-run) · a11y ``-label + O(n·m) lớp K5 · UAT-NÓI-TRƯỚC: nút bridge sáng sau RE-LOGIN (menu-cache) · GĐ2/GĐ3 "SẮP" rỗng khi prod 0-phiếu/0-HĐ = đúng-spec. +3. **Monthly drift-audit 2026-08-01 DUE** (session-đầu-tháng — `CLAUDE.md` §Audit định kỳ; S96 chạy 07-01) + re-sync `measured{}` (6 vai ctx/ring **0-baseline** — "delta 0" với chúng = chưa từng đo). +4. Re-chạy `governance-detectors.ps1` sau đợt vá S166+S168 (ring2 INFORM #6 — kỳ vọng FLAG `SKILL.md:93` biến mất, TOTAL đổi). +5. Nhóm-7 persona sweep: 21/23 persona chưa soi số-học (stale-deep khuyến-nghị grep số trên cả 23 file; `cicd-monitor` đã vá @S168 — **ăn từ RESTART kế**, hot-reload ENV-DEP). + +**Carry @S168 (RE-STAMP — §L.b(j)(iv)):** `[carry:ctx-t9-dogfood]` · `[carry:ring5-audit-gap]` · `[carry:hmw-width-vs-roster]` · `[carry:hmw-subfile-index-collision]` · `[carry:ctx-verifier-no-self-append]` *(@S168 vẫn lead-seed — lần 4)* · `[carry:synthesis-roll-s159-s160]` + `[carry:harvest-orphan-s159-tongquan]` *(nợ-ngủ anh chốt "bỏ mạch" @S163 — GIỮ ngủ; S163/S166 đã harvest @S168)* · `[carry:endline-sub-md]` · `[carry:tra-bui-relogin]` · `[carry:tiep-reload-underfill]` *(slot 59)*. **Đóng:** ~~`[carry:mind-tran-nen-moi-cua]`~~ (slot 58 thi-hành @S167). + +🧊 *Segment trước (S161→S162) giữ nguyên bên dưới làm lineage:* + +**🧊 (Last updated cũ)** 2026-07-30 trưa (**S161→S162** — phiên-LOGIC **L8** window-3 `/tiep` = **5/5 wave KHKK SHIP**, window-4 `/tiep` = **cây 4-folder GĐ ship prod** + **bookend-close 5 vòng**). Chi tiết = `docs/STATUS.md` dòng CURRENT + log `docs/changelog/sessions/2026-07-30-1100-S162-cay-4-folder-gd-close.md` + run-trace `.claude/workflows/runs/2026-07-30-S162-{cay-4-folder-gd,bookend-close}/`. + +## 🧊 CHỜ ANH (bản S162 — lineage; trạng-thái SỐNG đọc khối @S168 trên) **(54) 🔴🔴 BLOCKER MẠCH CHÍNH — chốt NGƯỜI DUYỆT 3 trạm PRO/CCM/CEO** (chọn trong 18 user prod; em KHÔNG tự chọn người thật). Có 3 tên/email ⇒ dựng 2 workflow type-3 + type-10 qua Designer (KHÔNG SQL tay #84) → W5 cầu KHKK→HĐ → E2E toàn trình PE `PE/2026/A/045` → KHKK → HĐ → bản-cứng. 🔴 *`lead-gap-auditor` FLAG-2 HIGH @S162: món này đã im **3 cửa-sổ / 2 ngày** vì chỉ sống trong `.claude/WAL.md` — đúng file bị reset mỗi closeout; **0 hit** trên cả 4 bề mặt owner. Nay đưa lên đây, có số.* 🔄 **@S164 2026-07-31 anh note hướng (verbatim):** *"PRO/CCM/CEO -> vẫn là cách danh sách cũ trong duyệt NCC. Nhưng note ý thôi, tao giao việc tiếp."* ⇒ người duyệt 3 trạm = **lấy đúng bộ người duyệt đang cấu hình ở workflow Duyệt NCC (PE) prod**, KHÔNG cần anh chọn 3 tên mới. 🔴 Đây là **NOTE Ý, chưa phải lệnh triển khai** — chờ anh giao việc; khi triển khai vẫn qua Designer (KHÔNG SQL tay #84), đọc danh sách từ workflow PE live trước khi dựng. @@ -24,7 +53,7 @@ **Chờ-anh phụ (không chặn):** F-10 attachment owner-check 2 module · mark-read chuông cũ (mirror PE S96) · tài khoản UAT non-Admin (`nv.test` không tồn tại prod) · thư `ai_infra/all/2026-07-28-day-wake-probe-first-resume` (nấc `agreed`, executed chờ anh). -## 🔴 NEXT em @S163 (không cần anh gật) +## 🧊 NEXT em @S163 (lineage — disposition @S168: #1 LOẠI-có-lý-do [MIND-0 §B: 11/23 vai INFORM-only cấm tự-ghi, bệnh ở bước seed phía lead] · #2 S163/S166 harvest XONG @S168, S159×2 nợ-ngủ anh-chốt · #3 re-stamp ở segment @S168 · #4 còn `[carry:endline-sub-md]` · #5 ✅ @S164 · #6 ✅ 68/69 @S164 + 70/71 @S168 F-4 · #7 DUE hôm nay — xem NEXT-em @S168 trên) 1. **Vá gốc F-01 H2:** wire bước diary-append vào `tiep.md §3-ter` — `ctx-verifier` chạy 3 phiên (S153/S158/S162) mà **chưa lần nào tự ghi**, cả 3 lần đều lead-seed on-behalf ⇒ hỏng ở khâu GHI, không ở phát hiện. 2. **Retro-harvest 2 orphan** `S159-bookend-open` + `S159-tong-quan-pipeline-menu` (cái sau **ưu tiên**: là nơi duy nhất còn nguyên-liệu #422/#425 cho F-02 ⇒ 1 công đóng 2 lỗ) + `git mv review-synthesis-clone-s160.md` → `review-clone-s160-synthesis.md` (glob neo ĐUÔI). diff --git a/docs/STATUS.md b/docs/STATUS.md index e5256f4..7213d77 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -3,7 +3,7 @@ > **Update rule:** trước khi bắt đầu 1 task → ghi row `🔥 In Progress`. Xong → `✅ Recently Done`. > **Tiering rule (S40):** chỉ giữ **state hiện tại + 3 session gần nhất** ở file này. Session cũ hơn → `docs/changelog/sessions/`. Full history pre-S40 → `docs/_archive/STATUS-preS40-fullhistory.md`. (Tránh over-context — xóa double, không cắt nội dung.) -**🔥 CURRENT (S161→S167, 2026-07-31→08-01 — phiên-LOGIC **L9**: chuỗi SP-002 B0→B3 spec ĐÓNG BĂNG + **B4 K1→K5+K4c SHIP prod-verified (cicd 6/6 · 5/6-khỏe · 6/6 · 7/7 · 5/5) + F-1 checkbox opt-out SHIP `7a903cf`**; K6 lane-DONE-trên-đĩa chờ gate+commit @S167; K7 → K8-prep + closeout-nợ còn — mạch sống ở `.claude/WAL.md`; lineage L8 giữ dưới):** Mig **71** (K1 Mig70 `AddContractCatalogEntries` danh mục 86 dòng + K2 Mig71 `AddKhkkApprovalGroupCatalogAndFinalizeRuntime` — phiếu KHKK +nhóm duyệt N1-N8 backfill=1 + Line +hạng-mục + unique 3-cột) · **97 bảng** · **622 test PASS** (45D+577I — đo tươi @S167 local KHỚP CI #439 tách-phần; +1 Fact K4c `ListDeletedContractSigningPlans_FiltersByApprovalGroup_ServerSide`) · gotcha **85** · counter **41** (tick S167; H24 deep 15/15 ĐÃ TRẢ @S166 giữa-phiên — light=deep=40) · roster 23 · **MenuItems prod 142 GIỮ** (key `KeHoachKyKet` sinh **policy** không sinh menu-row — H1 bác nghi-vấn stale) · Policies **452** · Menu keys **113** (@S166 K4a +49 `Khkk_G*` bộ-sinh — canonical bảng `:470-471`, test T2 khoá drift; lineage 64/256 @K3: +`ContractCatalog` K1 [4 policy chưa endpoint tiêu thụ — khai #82] · +8 `AwV2_KhkkN1..N8`) · bundle prod → **canonical ở `:479`, KHÔNG chép số ở đây** (B1). 🔴 *Cặp `DXoYDy7R`/`o8KDluD1` từng ghi ở dòng này **chưa bao giờ là trạng-thái cuối** — `e5123ff` ship thêm 6 file FE-src SAU snapshot; đo live @S164: admin `B43R6Y17` · user `NLI5umBg`.* Contracts prod **0**. +**🔥 CURRENT (S161→S168, 2026-07-31→08-01 — phiên-LOGIC **L9**: chuỗi SP-002 B0→B3 spec ĐÓNG BĂNG + **B4 K1→K7 SHIP prod-verified 7/8 wave (cicd 6/6 · 5/6-khỏe · 6/6 · 7/7 · 5/5 · K6 #440 5/5 · K7 PARTIAL-live-sạch) + F-1 checkbox opt-out SHIP `7a903cf` + K6 `1c6d77a` + K7 bridge KHKK→HĐ `aaed699` gate PWF-10/0-blocker**; GĐ3 đồng-nhất BLOCKED-chờ-anh-2-quyết (HANDOFF slot **63**); K8-prep còn; closeout-nợ TRẢ @S168 — mạch sống ở `.claude/WAL.md`; lineage L8 giữ dưới):** Mig **71** (K1 Mig70 `AddContractCatalogEntries` danh mục 86 dòng + K2 Mig71 `AddKhkkApprovalGroupCatalogAndFinalizeRuntime` — phiếu KHKK +nhóm duyệt N1-N8 backfill=1 + Line +hạng-mục + unique 3-cột) · **97 bảng** · **639 test PASS** (45D+594I — đo tươi @S168 local, K7 Δ+17; lineage 622 @S167 45D+577I KHỚP CI #439 tách-phần, +1 Fact K4c `ListDeletedContractSigningPlans_FiltersByApprovalGroup_ServerSide`) · gotcha **86** · counter **42** (tick S168; H24 light 2/6 deep 2/15 ok — deep 15/15 ĐÃ TRẢ @S166 giữa-phiên, light=deep=40) · roster 23 · **MenuItems prod 142 GIỮ** (key `KeHoachKyKet` sinh **policy** không sinh menu-row — H1 bác nghi-vấn stale) · Policies **452** · Menu keys **113** (@S166 K4a +49 `Khkk_G*` bộ-sinh — canonical bảng `:470-471`, test T2 khoá drift; lineage 64/256 @K3: +`ContractCatalog` K1 [4 policy chưa endpoint tiêu thụ — khai #82] · +8 `AwV2_KhkkN1..N8`) · bundle prod → **canonical ở `:479`, KHÔNG chép số ở đây** (B1). 🔴 *Cặp `DXoYDy7R`/`o8KDluD1` từng ghi ở dòng này **chưa bao giờ là trạng-thái cuối** — `e5123ff` ship thêm 6 file FE-src SAU snapshot; đo live @S164: admin `B43R6Y17` · user `NLI5umBg`.* Contracts prod **0**. ① **5 wave KHKK SHIP (window-3, S161):** W1 `a8027c0` (Mig 69, 7 bảng, 89→96) · W2 `6cbc6ad` (CRUD+Dossier 15 policy) · W3 `df52fa0` (duyệt V2 3-trạm, test-before RED→GREEN) · W6 `761d818` (đường-ống HĐ V2) · W7 `3119cb9` (bản-cứng **1-MỐC** theo owner: form điền đủ → duyệt nếu có → upload bản cứng = xong). Mỗi wave: gate 5-anchor → hmw → test → reviewer → F-0 → cicd 3-chân. 3 quyết owner: mã `KHKK/{YYYY}/{Seq:D3}` · **bỏ "MB"** · GĐ4 1-mốc. ② **Cây 4-folder GĐ (window-4, S162) — `bfc7b79`, cicd PASS 5/5 Run #432:** lệnh owner *"Tạo folder: Duyệt NCC / Kế hoạch Hợp đồng. / Duyệt Hợp đồng / Hợp đồng cứng."* + AskUser chốt **DƯỚI TỪNG GÓI THẦU** + **áp CẢ trang GĐ khác**. 3 file MỚI ×2 app (`PipelineStageFolders` · `PipelineTreePanel` · `usePipelineStages`) + 3 trang ×2 app, **SHA-pair 6/6**, thuần FE 0-mig. designer SHIP-READY (tự soi ảnh bắt 4 lỗi build-không-báo) → reviewer PASS-WITH-FLAGS 8 → lead vá F-1/3/4/6/7 + F-8. 🔴 **CÒN NỢ: trang GĐ3 chưa làm** (owner nói "CẢ", lead giao 3/4 — lead-gap FLAG-3) · F-2 liên-danh N-HĐ chờ W5 · F-5 layout 19rem chờ owner nghiệm thu prod. ③ **Bookend-close 5 vòng, 10 vai:** H1 `PASS_WITH_FLAGS` 10 finding · H2 **`GATE-FAIL` 4** (⭐ `ctx-verifier` chạy thật mà **chưa bao giờ tự APPEND** diary — S153+S158 đều lead-seed; `cicd-monitor` khai "verbatim→archive" thứ `git log -S` chứng **chưa từng vào archive**) · cặp H24 **20 FLAG** (stale 16 = **SÀN** + gap 4, `gap-carry-dropped` **streak 8**) · trio memory **MIXED** (headroom 165.767 tok đơn-điệu giảm 3 mốc · light 9/6 OVERDUE · baseline `measured` 17/23) · orphan run-folder **3 xác nhận** (2 thiếu THẬT + 1 dương-giả TÊN). @@ -469,14 +469,14 @@ monthly re-tier mega-line + ef-core SKILL Mig→59 + 3 vocab-fork (2026-07-01 du | FE pages | **68** | unchanged S54 (ItTicketsPage reassign = in-place 2 app); +1 S52 AttendanceReportPage | | Policies | **452** | 🔄 **452 @S166 K4a** = All 113 × 4 (máy khoá: test T2 `KhkkGroupMenuSeedTests` đỏ nếu drift; DELTA vá-2: +4 ContractCatalog K1 · +32 AwV2_KhkkN* K3 · +196 Khkk_G* K4a). Cũ: **220 @S161** (W1 KHKK: `All` +`KeHoachKyKet` ⇒ 55 × 4 — reviewer F-2 bắt cặp-row-đôi đúng luật dòng dưới) · 🆕 **row MỚI S121** (wave adap-6-broadcast W2 — H24 GAP-3: `governance-detectors.ps1` `Get-StatusValue` resolve canonical TỪ bảng này; **KHÔNG có row ⇒ token `policy` UNRESOLVED ⇒ nửa `policy` của GAP-3 không thể fire** ⇒ detector khai FAIL-LOUD + SKIP, KHÔNG im-lặng-giả-vờ-xanh). 🔴 **DERIVED, KHÔNG độc-lập:** `Policies = |MenuKeys.All| × |MenuKeys.Actions| = 55 × 4 = 220 (@S161; trước W1 = 54 × 4 = 216)` — sinh runtime ở `src/Backend/SolutionErp.Api/Program.cs:82-89` (`foreach menu → foreach action → opts.AddPolicy($"{menu}.{action}")`), `Actions = ["Read","Create","Update","Delete"]` (`MenuKeys.cs:167`). ⇒ **row này BUỘC đổi CÙNG row `Menu keys`**: thêm 1 menu key ⇒ 55 × 4 = 220; sửa `Menu keys` mà quên `Policies` ⇒ detector flag derived-doc thay vì flag chính chỗ sai. Ground S121 bằng đếm mã-nguồn (`MenuKeys.All` = 54 entry, `public const string` = 54, khớp) — KHÔNG chép số từ spec. ⚠️ `.claude/skills/permission-matrix/SKILL.md` ghi **~240 = STALE** ⇒ W4 vá (🔴 chuỗi H24 §2(4) BẮT BUỘC: detector fire → cổng chứng-kiến → RỒI MỚI vá; vá trước = giết chứng-nhân sống) | | Menu keys | **113** | 🔄 **113 @S166 K4a** (đo RUNTIME `MenuKeys.All` — test T2; +49 `Khkk_G{2-8}`+42-leaf bộ-sinh by-construction K4a · +8 `AwV2_KhkkN1..N8` K3 · +1 `ContractCatalog` K1 trên nền 55). Cũ: **+1 S161 `KeHoachKyKet` vào `All` (W1 KHKK — policy `KeHoachKyKet.*` sinh runtime; menu-row prod KHÔNG đổi, 142 giữ)** · +1 S69 `Off_Dashboard` (landing Văn phòng số). Prev re-ground S61 (`MenuKeys.cs` const — Mig 50 gỡ 4 `Bg_*` Budget menu cũ). Prev 57 (S58) | -| Tests | **590 PASS** | 45 Domain + 545 Infra · 🔄 **+28 @S161** (5 wave KHKK: W1 566 → W2 574 → W3 580 → W6 587 → W7 590; đo tươi @S162 `dotnet test` 45+545, gate CI Run #432 khớp). ~~45 Domain + 517 Infra~~ · 0 fail / 0 skip · **S155 +30** (PE xóa-by-approver: `PeDeleteByApproverTests.cs` + T26/T27 — 🔴 **T27 khoá CẢ LỚP lỗi** *entity-có-cờ-mà-DTO-không-có* bằng reflection [mọi cờ `Allow*` trên entity phải có mặt trên DTO], **fault-inject xác nhận có răng**: tiêm bug ⇒ ĐỎ, khôi phục ⇒ xanh — không phải guard tuyên-bố suông; T26 giữ ĐỎ có chủ ý vì bug production thật, lead vá bằng đảo thứ tự chứ KHÔNG nới assert. Số 562 cross-check 2 nguồn độc-lập: log CI run #417 + `dotnet test` local @S156) · **S147 +4** (`ProjectCodeNormalizationTests` — Trim khi lưu + kiểm-trùng bỏ-dấu-cách; 🔴 **ô canonical này STALE 528/483I suốt S147→S148**, header `:6` và session-log S147 đều ghi 532/487I từ đầu — closeout S147 vá header mà quên ô canonical; H24 `lead-view-auditor` bắt @S148, lead verify 3-nguồn rồi vá) · **S134 +8** (`PePendingAccumulationTests` C1-C8 lũy-kế-TẠM-TÍNH: C1 ChoDuyet+winner vào delta-selected + PriorPes · C2 TuChoi/DaDuyet loại sạch · C3 Nháp list-only KHÔNG cộng tiền [D1] + TraLai vào delta-submitted [D2] · C4 peer-window CreatedAt · C5 delta âm signed · **C6 complementary-no-double-count exact-numbers [ComputeAsync bất động khi thêm peer non-terminal]** · C7 frozen→pending 0/null · C8 D4 changelog `[S134 pending-prior]` positive+contrast) · **S133 +11** (`PeBudgetFreezeTests` freeze-NS-at-DaDuyet: **T0 repro test-before RED→GREEN** [phiếu DaDuyet phải giữ số cũ sau `UpdatePeBudgetPro` — RED bắt 999tr @:184 pre-fix, phiếu đưa tới DaDuyet QUA service finalize mirror `PeApproverFinalizeTests` KHÔNG seed thẳng Phase] + **T1-T9** spec-coverage [snapshot các nhánh finalize + display-gate + 2 terminal-guard chặn sửa NS phiếu đã kết thúc (cả Admin) + backfill] + **site-5 AdminOverride** [reviewer catch — override thẳng → DaDuyet cũng chốt snapshot]) · **S118 +8** (PRO-perm scope-isolation **+4** `ProcurementMasterAccessSeedTests` [reflection no-prod-touch: upgrade-path Suppliers R+C+U + Master-Read · **scope-isolation** DeptManager-riêng vẫn revoke=false · insert-path no-Delete · idempotent] · ReportsController authz **+4** `AuthorizePolicyRegressionTests` [dashboard/export require Reports.Read · my-dashboard KHÔNG action-policy · class-level [Authorize] intact]) · **S117 +6** (PE endsBeforeCeo pointer-aware **+1** `PeFinalizeProjectionTests.ListPe_EndsBeforeCeo_ChoDuyet_PointerAware_PastFinalizeIsFalse` [ChoDuyet con-trỏ QUA cấp finalize → endsBeforeCeo=false, test-before RED→GREEN + EF-subquery translate smoke] · duyệt-theo-khoảng ProMinMax **+5** `PeApprovedPriceFinalizeTests` [happy set Min+Max · min==max boundary lock strict-`>` · thiếu-Max→Conflict not-finalized · min>max→Conflict · single-source+Max→Conflict wire-bug + regression Max=null] · harness `InvokeApply` 4→5 args fix TargetParameterCountException) · **S116 +9** (PE nhập giá âm: T1 ngân-sách-bất-biến khi quote-âm · T2 winnerQuoteTotal signed-sum · T3 submit-guard all-zero-blocked/pure-neg+net-zero-submittable · T4 CCM-net-threshold) · **S114 +9** (PE multi-NCC per hạng mục: `PeSelectWinnerClearTests` delete-invariant +4 [DeleteQuote/DeleteDetail re-derive IsWinner **test-before RED→GREEN** + guard-no-over-clear + UpsertQuote-update-branch coverage] + impl-lane +5 [per-hạng-mục-total · giaTri-single-partial · threshold-crossing · derive-invariant]) · **S113 +19** (Supplier import v2: `SupplierImportV2DedupTests` 13 [dedup MST-primary+Code-backstop T1-T7 · draft-on-import IsPublic · all-or-nothing · LayoutValid re-bake real-token · **null-Code→nháp FIXED** flipped-from-characterization] + `SupplierPublishAndListTests` 6 [publish-guard Code-required→409 · unpublish · list-filter published · DTO IsPublic]) · **S112 +18** (Supplier `SupplierExcelImportServiceTests` +10 [case-collation dedup có-RĂNG SQLite-BINARY-collation-nên-chứng-dedup-ở-SERVICE · fill-nulls-safe · all-or-nothing-abort · parser abs-cell-index/#REF!-null/header-fingerprint · Type-lạ→NCC · Status-emoji-strip] · PE `PeSubmitGuardAndBypassTests` 4-update→A1 [minOwn subordinate-only, pointer-stop] + 8-new [A1-happy · non-contiguous · EDGE-5 non-admin-throw/admin-pass/system-pass · opinion-history log/none]) · Prev 440: **S96 +6** (PE `PeApproverFinalizeTests` +2 [#6 finalize-opt-out→advance-CEO · #7 stale-noti-clear ExecuteUpdate] · `PeSuggestedPriceSetterAuthzTests` +4 [price-lock phase-guard after-submit — PRO/CCM ChoDuyet/DaDuyet→Conflict, Admin-override; +sửa SeedPeAsync default ChoDuyet→DangSoanThao spec-change]) · **S92 +3** (`AdminOnlyModulesRevokeTests` ẩn 5 nhóm menu chỉ Admin — non-Admin revoked-4-cờ / Admin untouched / Pe_* preserved) · **S91 +9** (ChangePassword self-service BE+test) · **S89 +3** (`PeDraftVisibilityTests` IDOR nháp riêng-tư) · **S88 +17** (D1 financials/CEO-notify/HoSoLink null-safe +11 · D2 create-contract multi-winner +6) · **S87 +25** (Mig 58 net +18: `PeMultiWinnerTests` sum + `PeSelectWinnerClearTests` multi-update + `PeSubmitGuardAndBypass` budget=0 + `PeApproverFinalizeTests` 5 auto-finalize [từng 7, −2 khi opt-in→auto rework] + `PeCcmThresholdFinalize`/`PeWorkItemBudget` collateral; Mig 59 +7 `PeCcmBudgetPeriodSetterAuthzTests` role-gate Admin|CCM/budget=0/null-clear) · **S86 +3** (`PeApproverNotifyExcludesDrafterTests` — notify "cần duyệt" loại NGƯỜI TẠO phiếu: drafter-excluded · co-approver-vẫn-nhận · drafter-vẫn-nhận-chuông-kết-quả) · **S85 +18** (PE CV PRO C5 hủy/đổi NCC winner +10 · urgent drafter-self-unset +5 · workflow-preserve bug-class S42 +3 `PeUpdateDraftWorkflowPreserveTests`) · **S83 +2** (PE require-workflow: `PeWorkItemGuardTests` ApprovalWorkflowId `NotEmpty` ×2 validator + submit-guard rewrite test 7/13 `PeSubmitGuardAndBypass` V1-submit-deprecated, no-count-change) · **S77 +10** (+7 `PeSuggestedPriceSetterAuthzTests` ghi chú PRO/CCM Mig 57 absolute-set/role-gate/null-clear/max-1000 · +3 `PeUrgentToggleAuthzTests` rewrite cờ-gấp **BẤT ĐỐI XỨNG** SET=function role / UNSET=function+DeptManager, plain-PRO-unset Forbidden) · **S76 +5** (`PeWorkItemBudgetTests` PRO split: set ProInitial+ProAdjust gồm âm · validator ProInitial≥0/ProAdjust-cho-âm · full=proFull khi CCM empty · full=CCM khi CCM present) · **S74 +5** (`PeWorkItemBudgetTests` §4b CcmNote: set CCM/Admin · null-clear absolute-set · non-priv Forbidden+no-mutate · all-3-persist) · **S73 +28** (PE opt-in finalize spec 6→11 + 10 giá-chốt `PeApprovedPriceFinalizeTests` + 13 setter-authz `PeSuggestedPriceSetterAuthzTests`) · **S69 +20** (Office-golive OfficeModulePermissionSeed 6 + PE PeCcmThresholdFinalize 5 + PeUrgentToggleAuthz 9) · **S67 +23 HRM test-after** (DepartmentTreeTests 8 cycle-guard/rollup + PeHoSoLinkTests 9 absolute-set + HrmProfilePermissionSeedTests 6 reflection-seed) → 286 · S61 +22 `PeWorkItemBudgetTests` −14 `BudgetPolicyTests` −1 → 263 · S60 +14 `PeSubmitGuardAndBypassTests` +2 spec → 256 (Domain 58→45 do drop Budget module tests) | -| Gotchas | **85** | **+S162 #85** (menu-key OR-gate FE ≠ policy per-action BE: cây 4-folder GĐ gate `['Khkk_List','Khkk_G1','KeHoachKyKet'].some(can)` NHƯNG endpoint gắn `[Authorize(Policy="KeHoachKyKet.Read")]` [`ContractSigningPlansController.cs:36`] + `MenuPermissionHandler.cs:40` so khớp **CHÍNH XÁC 1 key** — KHÔNG kế-thừa cha, KHÔNG OR key con ⇒ role `Khkk_List=1 ∧ KeHoachKyKet=0`: FE mở cổng → API **403** → folder GĐ2 hiện "—" dưới **MỌI** gói thầu, claim "gate trước fetch ⇒ 0 rác 403" **vỡ**. Bẫy: luật "OR nhiều key" **ĐÚNG ở tầng HIỂN-THỊ** [`GetMyMenuTreeQuery.cs:61-96` trả node khi con `CanRead`] nhưng **SAI ở tầng API-authz** — mặt thứ 2 của #82, lần này **menu-hiện RỘNG hơn API-cho** [#82 là chiều ngược]. Fix = gate đúng key policy CỦA endpoint; **mở controller đọc attribute TRƯỚC khi wire gate**, đừng suy từ cây menu. Reviewer bắt **trước ship**; Dev 13/13 role đều `Contracts=1 ∧ KeHoachKyKet=1` nên **chưa lộ** — lớp "chưa vỡ vì dữ-liệu hiện tại may mắn", vá ngay không đợi triệu chứng). **+S159 #84** (revoker-2-chiều: sửa data tay trên prod bị code-path ungated @restart ĐẢO NGƯỢC im lặng — grant menu SQL tay bị revoker [S92] lật 447/494 row; fix = code-first seeder + gỡ nhánh + guard 2-vế + khuôn 3-chân-kiềng; liên-quan #75/#76 chiều seeder). **+S133 #81-EXT** (instance 2 indirect-assignment, KHÔNG số mới: snapshot-NS-at-DaDuyet hook đặt ở finalize choke-point NHƯNG 2 site gán Phase TRỰC TIẾP bypass — admin-override `PurchaseEvaluationWorkflowService.cs:308` `= targetPhase` + seeder `DbInitializer:1323` `= current` → phiếu vào DaDuyet qua 2 đường này KHÔNG snapshot [frozen=0, display rơi về live = đúng bug đang vá]; reviewer adversarial bắt pre-commit, em-main + 3 invocation implement đều sót — cùng bài enumeration-writer #81; meta: field-đích có hook/derive/snapshot ⇒ grep MỌI assignment-site kể cả override/seeder). +1 S126 (**#83** số AGGREGATE session-cumulative tự-lão-hoá — audit COUNTS đổi bởi CHÍNH spawn review sau đó [2/2/0→4/4/0]; outward mời-reproduce = bảng per-lane theo run-id, KHÔNG số tổng; reviewer-gate bắt, em-main-solo sót). +1 S118 (**#82** menu-flag grant ≠ quyền API thật: display-layer [Permission `CanRead`→`GetMyMenuTree` FE-menu] ⟂ API-authz-layer [controller `[Authorize(Policy=)]`] = 2 tầng ĐỘC-LẬP; grant `Suppliers` R+C+U cho PRO nhưng `PUT/DELETE /suppliers` gate `[Authorize(Roles="Admin,CatalogManager")]` → PRO vẫn 403 sửa/xóa NCC [chỉ Publish/Import theo `Suppliers.Update` là ăn]; ngược lại `ReportsController` `[Authorize]` trần → mọi authed-user đọc `dashboard` tài-chính-HĐ ngược S92; fix gate `[Authorize(Policy="Reports.Read")]` per-method + grep controller authz TRƯỚC khi tin hiệu-lực grant; reviewer adversarial bắt, em-main-solo tin menu-flag=quyền thì sót; liên-quan #44). +1 S114 (**#81** derived-invariant re-derive ở write/select NHƯNG SÓT DELETE writer [DeleteQuote/DeleteDetail cascade] → xóa quote-selected cuối của NCC → `Supplier.IsWinner` kẹt stale [Any(IsSelected)=false] → `CreateContract Where(IsWinner)` gom NCC phantom → **HĐ giaTri=0**; fix helper `PeWinnerInvariant.ReSyncAfterQuoteRemovalAsync` gọi sau SaveChanges 2 handler; **enumeration-writer-trong-spec KHÔNG đáng tin** → grep MỌI `.Remove(`/`.Add(`/`=field` chạm entity chứa field-nguồn; chỉ **verify-adversarial-refute** bắt [invest/review/implement đều sót]; cardinality S87/S88 lên tầng mutation-path). +1 S113 (**#80** null-forgiving `!` che NRE trên external-parsed data: `SupplierExcelImportService.NewSupplier` gán `Code = r.Code!.Trim()` → NullReferenceException khi parser trả `null` cho ô cột-4 rỗng [ĐÚNG path R4 "thiếu Mã NCC → nháp"] → confirm nổ 500 CẢ batch dù preview classify New-draft KHÔNG lỗi; sibling `IsPublic=!IsNullOrWhiteSpace(row.Code)` null-safe nhưng NewSupplier thì KHÔNG; empty-string `""` chạy OK nhưng FE round-trip blank→JSON `null` → nổ. Fix `(r.Code ?? "").Trim()`. **Build 0/0 KHÔNG bắt** [`!` tắt nullable-warning]; chỉ test-before-critical bắt. Lesson: `!` null-forgiving trên dữ-liệu-parse-ngoài = mìn, dùng `?? default`). +1 S97 (**#79** backfill soi NHẦM bảng — transition-marker "[Duyệt KẾT THÚC]" nằm ở `PurchaseEvaluationChangelogs.ContextNote` KHÔNG phải `PurchaseEvaluationApprovals` → Mig 60 backfill match 0, phiếu finalize-CCM giữ flag=0 hiện sai "Đã được CEO duyệt"; fix Mig 61 query đúng bảng. PE 2 bảng lịch-sử tách vai [Approvals=ai-duyệt record :745 · Changelogs=chuyển-phase+marker LogTransition :1073]; verify marker-count prod trước khi tin backfill). +1 S97 (**#78** display-flag suy CONFIG thay RUNTIME → nói dối khi instance lệch config: `endsBeforeCeo` từ "workflow CÓ cấp finalize" thay "phiếu NÀY finalize" → phiếu lên CEO báo sai "không qua CEO"; nặng sau S97 default-flip opt-in; fix field runtime `EndedByLevelFinalize` Mig 60. Flag = "instance ĐÃ làm-gì" KHÔNG "config CÓ THỂ"). +1 S96 (**#77** SPA deploy bundle cache-lag: team thấy UI CŨ dù đã deploy + Ctrl+F5 — index.html no-cache ĐÚNG-chuẩn + JS hash-immutable nhưng browser giữ tab-SPA-mở/cache-local → verify bundle prod **BYTE-LEVEL** (curl + grep string-fix trong `/assets/index-.js`) phân-biệt cache-vs-deploy; **incognito = golden-test**; no-service-worker nên clear-site-data đủ). +2 S91 (**#76** deploy render config từ `.example` KHÔNG phải file-gitignored → prod thiếu setting tới khi điền tay · **#75** seed ungated per-code RESURRECT data đã-wipe mỗi restart → gate sau env-flag `DemoSeed:Disabled` + verify-by-restart-thật). +1 S90 (**#74** Chrome-MCP screenshot kẹt SPA-SignalR `document_idle` → PowerShell `CopyFromScreen` + Win32 lọc-process-`chrome.exe`). +2 S85 (**#72** lệch giờ +7h — DateTime lưu UTC nhưng serialize thiếu 'Z' → FE `new Date()`=local → `UtcDateTimeJsonConverter` global ép UTC-with-Z · **#73** UpdateDraft absolute-set CLEAR field SÓT khỏi pattern null-safe = bug-class S42 → guard `if (request.X is not null)`). +1 S78 **#71** (thêm enum value vào entity DÙNG-CHUNG → pollute UI/guard phân-loại theo PROXY-predicate `supplierId===null` thay vì enum tường minh; file-khi-duyệt purpose=5 lẫn "Bảng so sánh" + false-pass submit-guard → grep mọi field-proxy predicate loại value mới + build-verify TỪNG app; em-main grep no-leak bắt trước deploy). +1 S76 **#70** (FE absolute-set echo field anh-em từ server-snapshot + `invalidate()` fire-and-forget → cửa-sổ stale-echo mất-dữ-liệu khi lưu 2 ô liên-tiếp; guard `useIsFetching` gate nút Lưu tới khi refetch land; reviewer workflow bắt, impl self-review sót). +1 S72 **#69** FE bundle-hash non-deterministic + `deploy.yml` rebuild-FE-unconditional → bundle rotate kể cả commit governance (SPA-fallback-200 trap; cicd Run #312). +2 S69: **#67** Tailwind v4 accent palette thiếu stop (teal/violet/amberx/greenx chỉ 50/100/500/600/700; dùng -300 → teal/violet rơi DEFAULT Tailwind sai-hệ, amberx/greenx drop hẳn — build PASS, phải soi dist CSS) · **#68** IDE TS diagnostic giữa background-agent/workflow = snapshot dở-dang (TS server bắn mỗi save), chỉ tin build SẠCH sau-cùng (2× session này: re-skin + PE-FE đều false-alarm). Prev +1 S68 **#66** Tailwind v4 rule element thô `h1-h4{color:#0b1220}` viết NGOÀI `@layer` thắng utility `text-white` → heading render đen; fix ĐIỂM `text-white!` (important, grep dist confirm), KHÔNG move `@layer` (load-bearing ~30+ heading toàn app). Prev +1 S65 **#65** build csproj con (vd `SolutionErp.Api.csproj`) ≠ `dotnet build SolutionErp.slnx` (gồm tests) → miss test-compile khi đổi chữ ký record command (CreateDepartmentCommand +ParentId) → CI CS7036 FAIL-gated Run #291 (deploy chặn, prod nguyên — test-gate làm đúng việc). Fix: build full slnx trước push BE signature-change. Prev +2 S61: **#63** EF scaffold tự sinh `RenameColumn` SAI-semantics khi drop+add cùng type (test xanh không bắt — SQLite EnsureCreated không replay migration) · **#64** `dotnet ef database update` áp Design-DB 0-rows ≠ Dev-DB → data-migrate `Sql()` chạy thật lần đầu trên prod. Prev +2 S59 (#61 sqlcmd `-f 65001` · #62 rename natural-key UPDATE trước deploy) | +| Tests | **639 PASS** | 45 Domain + 594 Infra · 🔄 **639 @S168** (đo tươi local 45D+594I sau K7 Δ+17; chuỗi K lineage: 597 K1 → 614 K3 → 622 K4c @S167 KHỚP CI #439 tách-phần → **639** K7 — gate `639=45+594` KHỚP cicd-K7 dòng-1) · 🧊 **+28 @S161** (5 wave KHKK: W1 566 → W2 574 → W3 580 → W6 587 → W7 590; đo tươi @S162 `dotnet test` 45+545, gate CI Run #432 khớp). ~~45 Domain + 517 Infra~~ · 0 fail / 0 skip · **S155 +30** (PE xóa-by-approver: `PeDeleteByApproverTests.cs` + T26/T27 — 🔴 **T27 khoá CẢ LỚP lỗi** *entity-có-cờ-mà-DTO-không-có* bằng reflection [mọi cờ `Allow*` trên entity phải có mặt trên DTO], **fault-inject xác nhận có răng**: tiêm bug ⇒ ĐỎ, khôi phục ⇒ xanh — không phải guard tuyên-bố suông; T26 giữ ĐỎ có chủ ý vì bug production thật, lead vá bằng đảo thứ tự chứ KHÔNG nới assert. Số 562 cross-check 2 nguồn độc-lập: log CI run #417 + `dotnet test` local @S156) · **S147 +4** (`ProjectCodeNormalizationTests` — Trim khi lưu + kiểm-trùng bỏ-dấu-cách; 🔴 **ô canonical này STALE 528/483I suốt S147→S148**, header `:6` và session-log S147 đều ghi 532/487I từ đầu — closeout S147 vá header mà quên ô canonical; H24 `lead-view-auditor` bắt @S148, lead verify 3-nguồn rồi vá) · **S134 +8** (`PePendingAccumulationTests` C1-C8 lũy-kế-TẠM-TÍNH: C1 ChoDuyet+winner vào delta-selected + PriorPes · C2 TuChoi/DaDuyet loại sạch · C3 Nháp list-only KHÔNG cộng tiền [D1] + TraLai vào delta-submitted [D2] · C4 peer-window CreatedAt · C5 delta âm signed · **C6 complementary-no-double-count exact-numbers [ComputeAsync bất động khi thêm peer non-terminal]** · C7 frozen→pending 0/null · C8 D4 changelog `[S134 pending-prior]` positive+contrast) · **S133 +11** (`PeBudgetFreezeTests` freeze-NS-at-DaDuyet: **T0 repro test-before RED→GREEN** [phiếu DaDuyet phải giữ số cũ sau `UpdatePeBudgetPro` — RED bắt 999tr @:184 pre-fix, phiếu đưa tới DaDuyet QUA service finalize mirror `PeApproverFinalizeTests` KHÔNG seed thẳng Phase] + **T1-T9** spec-coverage [snapshot các nhánh finalize + display-gate + 2 terminal-guard chặn sửa NS phiếu đã kết thúc (cả Admin) + backfill] + **site-5 AdminOverride** [reviewer catch — override thẳng → DaDuyet cũng chốt snapshot]) · **S118 +8** (PRO-perm scope-isolation **+4** `ProcurementMasterAccessSeedTests` [reflection no-prod-touch: upgrade-path Suppliers R+C+U + Master-Read · **scope-isolation** DeptManager-riêng vẫn revoke=false · insert-path no-Delete · idempotent] · ReportsController authz **+4** `AuthorizePolicyRegressionTests` [dashboard/export require Reports.Read · my-dashboard KHÔNG action-policy · class-level [Authorize] intact]) · **S117 +6** (PE endsBeforeCeo pointer-aware **+1** `PeFinalizeProjectionTests.ListPe_EndsBeforeCeo_ChoDuyet_PointerAware_PastFinalizeIsFalse` [ChoDuyet con-trỏ QUA cấp finalize → endsBeforeCeo=false, test-before RED→GREEN + EF-subquery translate smoke] · duyệt-theo-khoảng ProMinMax **+5** `PeApprovedPriceFinalizeTests` [happy set Min+Max · min==max boundary lock strict-`>` · thiếu-Max→Conflict not-finalized · min>max→Conflict · single-source+Max→Conflict wire-bug + regression Max=null] · harness `InvokeApply` 4→5 args fix TargetParameterCountException) · **S116 +9** (PE nhập giá âm: T1 ngân-sách-bất-biến khi quote-âm · T2 winnerQuoteTotal signed-sum · T3 submit-guard all-zero-blocked/pure-neg+net-zero-submittable · T4 CCM-net-threshold) · **S114 +9** (PE multi-NCC per hạng mục: `PeSelectWinnerClearTests` delete-invariant +4 [DeleteQuote/DeleteDetail re-derive IsWinner **test-before RED→GREEN** + guard-no-over-clear + UpsertQuote-update-branch coverage] + impl-lane +5 [per-hạng-mục-total · giaTri-single-partial · threshold-crossing · derive-invariant]) · **S113 +19** (Supplier import v2: `SupplierImportV2DedupTests` 13 [dedup MST-primary+Code-backstop T1-T7 · draft-on-import IsPublic · all-or-nothing · LayoutValid re-bake real-token · **null-Code→nháp FIXED** flipped-from-characterization] + `SupplierPublishAndListTests` 6 [publish-guard Code-required→409 · unpublish · list-filter published · DTO IsPublic]) · **S112 +18** (Supplier `SupplierExcelImportServiceTests` +10 [case-collation dedup có-RĂNG SQLite-BINARY-collation-nên-chứng-dedup-ở-SERVICE · fill-nulls-safe · all-or-nothing-abort · parser abs-cell-index/#REF!-null/header-fingerprint · Type-lạ→NCC · Status-emoji-strip] · PE `PeSubmitGuardAndBypassTests` 4-update→A1 [minOwn subordinate-only, pointer-stop] + 8-new [A1-happy · non-contiguous · EDGE-5 non-admin-throw/admin-pass/system-pass · opinion-history log/none]) · Prev 440: **S96 +6** (PE `PeApproverFinalizeTests` +2 [#6 finalize-opt-out→advance-CEO · #7 stale-noti-clear ExecuteUpdate] · `PeSuggestedPriceSetterAuthzTests` +4 [price-lock phase-guard after-submit — PRO/CCM ChoDuyet/DaDuyet→Conflict, Admin-override; +sửa SeedPeAsync default ChoDuyet→DangSoanThao spec-change]) · **S92 +3** (`AdminOnlyModulesRevokeTests` ẩn 5 nhóm menu chỉ Admin — non-Admin revoked-4-cờ / Admin untouched / Pe_* preserved) · **S91 +9** (ChangePassword self-service BE+test) · **S89 +3** (`PeDraftVisibilityTests` IDOR nháp riêng-tư) · **S88 +17** (D1 financials/CEO-notify/HoSoLink null-safe +11 · D2 create-contract multi-winner +6) · **S87 +25** (Mig 58 net +18: `PeMultiWinnerTests` sum + `PeSelectWinnerClearTests` multi-update + `PeSubmitGuardAndBypass` budget=0 + `PeApproverFinalizeTests` 5 auto-finalize [từng 7, −2 khi opt-in→auto rework] + `PeCcmThresholdFinalize`/`PeWorkItemBudget` collateral; Mig 59 +7 `PeCcmBudgetPeriodSetterAuthzTests` role-gate Admin|CCM/budget=0/null-clear) · **S86 +3** (`PeApproverNotifyExcludesDrafterTests` — notify "cần duyệt" loại NGƯỜI TẠO phiếu: drafter-excluded · co-approver-vẫn-nhận · drafter-vẫn-nhận-chuông-kết-quả) · **S85 +18** (PE CV PRO C5 hủy/đổi NCC winner +10 · urgent drafter-self-unset +5 · workflow-preserve bug-class S42 +3 `PeUpdateDraftWorkflowPreserveTests`) · **S83 +2** (PE require-workflow: `PeWorkItemGuardTests` ApprovalWorkflowId `NotEmpty` ×2 validator + submit-guard rewrite test 7/13 `PeSubmitGuardAndBypass` V1-submit-deprecated, no-count-change) · **S77 +10** (+7 `PeSuggestedPriceSetterAuthzTests` ghi chú PRO/CCM Mig 57 absolute-set/role-gate/null-clear/max-1000 · +3 `PeUrgentToggleAuthzTests` rewrite cờ-gấp **BẤT ĐỐI XỨNG** SET=function role / UNSET=function+DeptManager, plain-PRO-unset Forbidden) · **S76 +5** (`PeWorkItemBudgetTests` PRO split: set ProInitial+ProAdjust gồm âm · validator ProInitial≥0/ProAdjust-cho-âm · full=proFull khi CCM empty · full=CCM khi CCM present) · **S74 +5** (`PeWorkItemBudgetTests` §4b CcmNote: set CCM/Admin · null-clear absolute-set · non-priv Forbidden+no-mutate · all-3-persist) · **S73 +28** (PE opt-in finalize spec 6→11 + 10 giá-chốt `PeApprovedPriceFinalizeTests` + 13 setter-authz `PeSuggestedPriceSetterAuthzTests`) · **S69 +20** (Office-golive OfficeModulePermissionSeed 6 + PE PeCcmThresholdFinalize 5 + PeUrgentToggleAuthz 9) · **S67 +23 HRM test-after** (DepartmentTreeTests 8 cycle-guard/rollup + PeHoSoLinkTests 9 absolute-set + HrmProfilePermissionSeedTests 6 reflection-seed) → 286 · S61 +22 `PeWorkItemBudgetTests` −14 `BudgetPolicyTests` −1 → 263 · S60 +14 `PeSubmitGuardAndBypassTests` +2 spec → 256 (Domain 58→45 do drop Budget module tests) | +| Gotchas | **86** | **+S168 #86** (2-push-sát → Gitea auto-CANCEL run đầu cùng-branch: CANCELLED ≠ fail — verifier đọc run CUỐI của range + bằng-chứng artifact-level; side-effect @startup chỉ 1-startup cho cả cụm push; ca thật `aaed699` ship qua #442) · **+S162 #85** (menu-key OR-gate FE ≠ policy per-action BE: cây 4-folder GĐ gate `['Khkk_List','Khkk_G1','KeHoachKyKet'].some(can)` NHƯNG endpoint gắn `[Authorize(Policy="KeHoachKyKet.Read")]` [`ContractSigningPlansController.cs:36`] + `MenuPermissionHandler.cs:40` so khớp **CHÍNH XÁC 1 key** — KHÔNG kế-thừa cha, KHÔNG OR key con ⇒ role `Khkk_List=1 ∧ KeHoachKyKet=0`: FE mở cổng → API **403** → folder GĐ2 hiện "—" dưới **MỌI** gói thầu, claim "gate trước fetch ⇒ 0 rác 403" **vỡ**. Bẫy: luật "OR nhiều key" **ĐÚNG ở tầng HIỂN-THỊ** [`GetMyMenuTreeQuery.cs:61-96` trả node khi con `CanRead`] nhưng **SAI ở tầng API-authz** — mặt thứ 2 của #82, lần này **menu-hiện RỘNG hơn API-cho** [#82 là chiều ngược]. Fix = gate đúng key policy CỦA endpoint; **mở controller đọc attribute TRƯỚC khi wire gate**, đừng suy từ cây menu. Reviewer bắt **trước ship**; Dev 13/13 role đều `Contracts=1 ∧ KeHoachKyKet=1` nên **chưa lộ** — lớp "chưa vỡ vì dữ-liệu hiện tại may mắn", vá ngay không đợi triệu chứng). **+S159 #84** (revoker-2-chiều: sửa data tay trên prod bị code-path ungated @restart ĐẢO NGƯỢC im lặng — grant menu SQL tay bị revoker [S92] lật 447/494 row; fix = code-first seeder + gỡ nhánh + guard 2-vế + khuôn 3-chân-kiềng; liên-quan #75/#76 chiều seeder). **+S133 #81-EXT** (instance 2 indirect-assignment, KHÔNG số mới: snapshot-NS-at-DaDuyet hook đặt ở finalize choke-point NHƯNG 2 site gán Phase TRỰC TIẾP bypass — admin-override `PurchaseEvaluationWorkflowService.cs:308` `= targetPhase` + seeder `DbInitializer:1323` `= current` → phiếu vào DaDuyet qua 2 đường này KHÔNG snapshot [frozen=0, display rơi về live = đúng bug đang vá]; reviewer adversarial bắt pre-commit, em-main + 3 invocation implement đều sót — cùng bài enumeration-writer #81; meta: field-đích có hook/derive/snapshot ⇒ grep MỌI assignment-site kể cả override/seeder). +1 S126 (**#83** số AGGREGATE session-cumulative tự-lão-hoá — audit COUNTS đổi bởi CHÍNH spawn review sau đó [2/2/0→4/4/0]; outward mời-reproduce = bảng per-lane theo run-id, KHÔNG số tổng; reviewer-gate bắt, em-main-solo sót). +1 S118 (**#82** menu-flag grant ≠ quyền API thật: display-layer [Permission `CanRead`→`GetMyMenuTree` FE-menu] ⟂ API-authz-layer [controller `[Authorize(Policy=)]`] = 2 tầng ĐỘC-LẬP; grant `Suppliers` R+C+U cho PRO nhưng `PUT/DELETE /suppliers` gate `[Authorize(Roles="Admin,CatalogManager")]` → PRO vẫn 403 sửa/xóa NCC [chỉ Publish/Import theo `Suppliers.Update` là ăn]; ngược lại `ReportsController` `[Authorize]` trần → mọi authed-user đọc `dashboard` tài-chính-HĐ ngược S92; fix gate `[Authorize(Policy="Reports.Read")]` per-method + grep controller authz TRƯỚC khi tin hiệu-lực grant; reviewer adversarial bắt, em-main-solo tin menu-flag=quyền thì sót; liên-quan #44). +1 S114 (**#81** derived-invariant re-derive ở write/select NHƯNG SÓT DELETE writer [DeleteQuote/DeleteDetail cascade] → xóa quote-selected cuối của NCC → `Supplier.IsWinner` kẹt stale [Any(IsSelected)=false] → `CreateContract Where(IsWinner)` gom NCC phantom → **HĐ giaTri=0**; fix helper `PeWinnerInvariant.ReSyncAfterQuoteRemovalAsync` gọi sau SaveChanges 2 handler; **enumeration-writer-trong-spec KHÔNG đáng tin** → grep MỌI `.Remove(`/`.Add(`/`=field` chạm entity chứa field-nguồn; chỉ **verify-adversarial-refute** bắt [invest/review/implement đều sót]; cardinality S87/S88 lên tầng mutation-path). +1 S113 (**#80** null-forgiving `!` che NRE trên external-parsed data: `SupplierExcelImportService.NewSupplier` gán `Code = r.Code!.Trim()` → NullReferenceException khi parser trả `null` cho ô cột-4 rỗng [ĐÚNG path R4 "thiếu Mã NCC → nháp"] → confirm nổ 500 CẢ batch dù preview classify New-draft KHÔNG lỗi; sibling `IsPublic=!IsNullOrWhiteSpace(row.Code)` null-safe nhưng NewSupplier thì KHÔNG; empty-string `""` chạy OK nhưng FE round-trip blank→JSON `null` → nổ. Fix `(r.Code ?? "").Trim()`. **Build 0/0 KHÔNG bắt** [`!` tắt nullable-warning]; chỉ test-before-critical bắt. Lesson: `!` null-forgiving trên dữ-liệu-parse-ngoài = mìn, dùng `?? default`). +1 S97 (**#79** backfill soi NHẦM bảng — transition-marker "[Duyệt KẾT THÚC]" nằm ở `PurchaseEvaluationChangelogs.ContextNote` KHÔNG phải `PurchaseEvaluationApprovals` → Mig 60 backfill match 0, phiếu finalize-CCM giữ flag=0 hiện sai "Đã được CEO duyệt"; fix Mig 61 query đúng bảng. PE 2 bảng lịch-sử tách vai [Approvals=ai-duyệt record :745 · Changelogs=chuyển-phase+marker LogTransition :1073]; verify marker-count prod trước khi tin backfill). +1 S97 (**#78** display-flag suy CONFIG thay RUNTIME → nói dối khi instance lệch config: `endsBeforeCeo` từ "workflow CÓ cấp finalize" thay "phiếu NÀY finalize" → phiếu lên CEO báo sai "không qua CEO"; nặng sau S97 default-flip opt-in; fix field runtime `EndedByLevelFinalize` Mig 60. Flag = "instance ĐÃ làm-gì" KHÔNG "config CÓ THỂ"). +1 S96 (**#77** SPA deploy bundle cache-lag: team thấy UI CŨ dù đã deploy + Ctrl+F5 — index.html no-cache ĐÚNG-chuẩn + JS hash-immutable nhưng browser giữ tab-SPA-mở/cache-local → verify bundle prod **BYTE-LEVEL** (curl + grep string-fix trong `/assets/index-.js`) phân-biệt cache-vs-deploy; **incognito = golden-test**; no-service-worker nên clear-site-data đủ). +2 S91 (**#76** deploy render config từ `.example` KHÔNG phải file-gitignored → prod thiếu setting tới khi điền tay · **#75** seed ungated per-code RESURRECT data đã-wipe mỗi restart → gate sau env-flag `DemoSeed:Disabled` + verify-by-restart-thật). +1 S90 (**#74** Chrome-MCP screenshot kẹt SPA-SignalR `document_idle` → PowerShell `CopyFromScreen` + Win32 lọc-process-`chrome.exe`). +2 S85 (**#72** lệch giờ +7h — DateTime lưu UTC nhưng serialize thiếu 'Z' → FE `new Date()`=local → `UtcDateTimeJsonConverter` global ép UTC-with-Z · **#73** UpdateDraft absolute-set CLEAR field SÓT khỏi pattern null-safe = bug-class S42 → guard `if (request.X is not null)`). +1 S78 **#71** (thêm enum value vào entity DÙNG-CHUNG → pollute UI/guard phân-loại theo PROXY-predicate `supplierId===null` thay vì enum tường minh; file-khi-duyệt purpose=5 lẫn "Bảng so sánh" + false-pass submit-guard → grep mọi field-proxy predicate loại value mới + build-verify TỪNG app; em-main grep no-leak bắt trước deploy). +1 S76 **#70** (FE absolute-set echo field anh-em từ server-snapshot + `invalidate()` fire-and-forget → cửa-sổ stale-echo mất-dữ-liệu khi lưu 2 ô liên-tiếp; guard `useIsFetching` gate nút Lưu tới khi refetch land; reviewer workflow bắt, impl self-review sót). +1 S72 **#69** FE bundle-hash non-deterministic + `deploy.yml` rebuild-FE-unconditional → bundle rotate kể cả commit governance (SPA-fallback-200 trap; cicd Run #312). +2 S69: **#67** Tailwind v4 accent palette thiếu stop (teal/violet/amberx/greenx chỉ 50/100/500/600/700; dùng -300 → teal/violet rơi DEFAULT Tailwind sai-hệ, amberx/greenx drop hẳn — build PASS, phải soi dist CSS) · **#68** IDE TS diagnostic giữa background-agent/workflow = snapshot dở-dang (TS server bắn mỗi save), chỉ tin build SẠCH sau-cùng (2× session này: re-skin + PE-FE đều false-alarm). Prev +1 S68 **#66** Tailwind v4 rule element thô `h1-h4{color:#0b1220}` viết NGOÀI `@layer` thắng utility `text-white` → heading render đen; fix ĐIỂM `text-white!` (important, grep dist confirm), KHÔNG move `@layer` (load-bearing ~30+ heading toàn app). Prev +1 S65 **#65** build csproj con (vd `SolutionErp.Api.csproj`) ≠ `dotnet build SolutionErp.slnx` (gồm tests) → miss test-compile khi đổi chữ ký record command (CreateDepartmentCommand +ParentId) → CI CS7036 FAIL-gated Run #291 (deploy chặn, prod nguyên — test-gate làm đúng việc). Fix: build full slnx trước push BE signature-change. Prev +2 S61: **#63** EF scaffold tự sinh `RenameColumn` SAI-semantics khi drop+add cùng type (test xanh không bắt — SQLite EnsureCreated không replay migration) · **#64** `dotnet ef database update` áp Design-DB 0-rows ≠ Dev-DB → data-migrate `Sql()` chạy thật lần đầu trên prod. Prev +2 S59 (#61 sqlcmd `-f 65001` · #62 rename natural-key UPDATE trước deploy) | | User memory | **31** | +S84 `feedback_derived_flush_execution` (derived→canonical flush = em-main execution KHÔNG gate user-confirm; monitor INFORM-only ≠ cần-anh-duyệt; chỉ ĐỔI-con-số/policy = quyền anh). +S79 `feedback_canonical_spec_over_broadcast` (adap pull canonical-command/§P đừng phỏng-theo broadcast + report-before-stamp dogfood + residual own-diary OK). +S75 `feedback_harness11_engine` (engine governance tự-bảo-trì + gotcha #30-via-Edit + multi-workflow-verify + git-add-specific lesson). re-ground S71 (H1 disk-count: 25 `feedback_*` + 3 `project_*`; STATUS "21" stale từ S64). +S71 `feedback_harness10_run_trace` (run-trace + 3 lesson). Prev +1 S64 `feedback_harness7_outward_writing_quality`; re-grounded S54 base 19 | | Skills | 6 | 3 domain + 3 ops | | Sub-agents | **23** | **+S153 bộ-ba vòng Ctx** (adopt thư `0df10df4` — 🔄 **OWNER-VETO @S153 hub-form 3-vai**: bản đầu (38)(a) 1-vai OWNER-DELEGATED→LEAD-DECIDED, **anh bác cùng ngày** chốt trực tiếp *"Build đủ 3 vai như hub"* qua AskUser = owner chốt THẬT cho quyết này; 🔄 **RENAME cùng phiên theo lệnh anh** *"đặt tên giống hub và sisters để dễ audit"* — tên khai-sinh `ctx-pause-check`/`ctx-reload` → **hub-form `ctx-curator`/`ctx-verifier`** [đo đĩa 3 nhà: hub = curator/verifier/audit · VIPIX = check/reload/chain · hub≠sister ⇒ SE theo HUB-form, tiền lệ rename S149 lead-*]): **`ctx-curator`** vai-1 KIỂM nháp @mỗi-`/pause` (carve-out `pause.md §1` mirror hub O-1(a)) · **`ctx-verifier`** vai-2 ĐỐI-CHIẾU+NẠP-LẠI @mỗi-`/tiep` (dòng `LEAD-PHAI-NHAC-LAI:` = bằng-chứng nội-dung) · **`ctx-audit`** vai-3 SOI-CHUỖI @2-bookend (kiểm-vết vai-1/2, hồi-tố = fallback phiên 1-cửa). Nấc: ctx-audit `file-land + registry-surfaced @S153` cho CẢ 3 vai ctx [🔄 vá @S153 FLAG-6: bản đầu chỉ cấp nấc này cho `ctx-audit` trong khi `hmw.js:42` + writeGuard + README `:27`/`:199`/`:200` chứng 2 vai mới ĐẠT CÙNG nấc — khai THIẾU vẫn là lệch] — spawn-probe ALIVE cả 3 = phiên sau restart T9; hmw VALID_ROLES 20→**23** + writeGuard :228/:235; ⚠️ **roster 23 > `hmw_width.cap` 20** ⇒ full-roster-sweep LOUD-skip 3 lane cuối — số cap = quyền anh, O-7 (câu (40) đang treo). **🔄 RENAME @S149 (anh ratify "OK đồng ý"): 5 vai đổi tên đồng-bộ sister — `tooling-harvest-audit`→`ring1-audit` · `h24-audit`→`ring2-audit` · `sleep-audit`→`ring4-audit` · `lead-view-auditor`→`lead-stale-auditor` · `lead-omission-auditor`→`lead-gap-auditor` (ring* = 2 sister TRÙNG tuyệt đối; lead-* = hub-form, VIPIX-form là prefix). Nấc **NÂNG @cùng-phiên: `registry-listed-in-session`** — harness list 5 tên MỚI + gỡ 5 tên CŨ NGAY TRONG PHIÊN S149 (không restart), **TRÁI phép đo S120/S121 no-hot-reload** (môi trường có thể đã đổi — đây là data-point ĐO ĐƯỢC, không suy). Spawn-probe vẫn CẦN để chứng instantiate (list ≠ spawn được — đúng 0.6b). Tên cũ trong narrative/runs/history = vết lịch-sử, CỐ Ý giữ.** **+S145 🔬 `ring1-audit` (18th sub — round-KIỂM vòng tooling/harvest, C4/C4b adap dot-11 khoản ① `harness-dong-du-vong:51`, owner-decision [2] TÁCH mỗi-vòng-1-con-KHÔNG-gộp). Vai-KIỂM ĐỘC-LẬP đọc OUTPUT H1 `tooling-auditor` (4-mặt freshness) + H2 `harvest-curator` (5-trục integrity), **KHÔNG re-chạy đo**: verdict per-claim ĐẠT/TRƯỢT + falsify ≥2 + **tự tái-dựng ≥1 số CÓ-THỂ-SAI** (đếm `.claude/agents/*.md` vs roster-count H1 · N-harvested/M-spawned) + **thách-CLEAN** (H1 PASS/H2 GATE-0 → mở 1 skill "fresh"+1 sub "harvested" xem thật). 🔴 no-self-exempt ≠ H1/H2 (m-3 S139). **AUTO fire-after-measure @session-end §L.b(g-bis)** — owner-chốt S145 KHÔNG consent-gate (KHÁC trio/H24), fail-safe NO-OP nếu H1/H2 không chạy phiên đó (CẤM ĐẠT-ảo); tuần-tự C4b (invocation SAU con-đo, mtime chứng). Propose-only, backstop = git-diff commit-gate (KHÔNG dựa thiếu-tool `[carry:tools-whitelist-no-teeth]`). `model: opus`+`effort: max`+`memory: project`+`maxTurns: 16`. **Vai #1/3 round-KIỂM** — `ring2-audit` (vòng soi-lead) + `ring4-audit` (vòng nén-ngủ) land dần incremental (§6 broadcast báo-nấc-per-vòng, owner S145). 🔴 **Nấc = executed-file / verified-pending-restart** — registry Agent-tool KHÔNG hot-reload (`agents/README` §Memory discipline — anchor không-số-dòng, vá cite-dòng-trống @S151 per H1 F-3), spawn-probe alive cần **restart CLI**; run-thử-thật @session-end phiên sau. Design-doc: `runs/2026-07-22-S144-adap-dot-11/C4-design-3-vai-kiem.md`.** **+S145 🔬 `ring2-audit` (19th sub — round-KIỂM vòng soi-lead H24, vai #2/3 C4/C4b). Đọc OUTPUT `lead-stale-auditor` + `lead-gap-auditor` (🔴 KIỂM 2 con-đo H24, **KHÔNG soi lead trực-tiếp**) → verdict per-FLAG + tự tái-dựng ≥1 số (flag-count · mở 1 FLAG đối-chứng source · `class_repeat` `.session-counter.json`) + **thách-CLEAN** (H24 báo ít/0 FLAG ⇒ tự soi 1 surface tìm FLAG sót — CLEAN "lead ổn" là ca nguy nhất, khớp H24 §2(1) phép-thử-nhanh). Verify vai H24 KHÔNG tự chế class ngoài enum ĐÓNG `flag_classes`. no-self-exempt ≠ lead-stale/lead-gap (m-3; tên mới @rename S149). AUTO wired `session-end §L.b(j)(ii-bis)` sau cặp H24; fail-safe NO-OP nếu H24 không chạy (nhịp/consent). `maxTurns: 16`.** **+S145 🔬 `ring4-audit` (20th sub — round-KIỂM vòng nén-ngủ, vai #3/3 C4/C4b). Đọc OUTPUT `/sleep-recovery-memory-l2` (`.gist.md` mới + Fidelity verdict + claim giảm-byte) → verdict per-claim + **tự ĐO LẠI byte** archive gốc vs gist (đối-chứng claim) + **thách-CLEAN** (Fidelity 5P/0F ⇒ mở 1 gist đối-chứng `.md` gốc xem có giữ 4-field load-bearing hay nén quá tay) + kiểm bất-biến gist-ADDITIVE (gốc byte-identical). no-self-exempt độc-lập lượt nén (m-3). AUTO wired `sleep-recovery-memory-l2.md Phase 4.5` sau nén; fail-safe NO-OP nếu 0 gist tươi. `maxTurns: 16`.** **+S141/S142 🧪🧭🧮 `harness-eval` + `harness-refine` + `harness-audit` (15th–17th sub — bộ-ba đồng-kiểm HỆ MEMORY, adopt AI_INFRA khuôn 5-câu `58e28bae` khối B, wave adap đợt-9/10; land S141 persona+seed+`hmw.js` VALID_ROLES 14→17, wiring nghi-thức S142 vòng-2 sau khi vòng-1 chết giữa chừng). Read-only INFORM-only propose-only, frontmatter **không khai Write/Edit** — 🔴 nhưng đo S143: **runtime VẪN cấp** (append cuối tool-list, 9/9 vai read-only; nhân-chứng `reviewer` đã Write+Edit thật) ⇒ đây là **tuyên-bố ý-định**, KHÔNG phải chặn-bằng-thiếu-tool; containment thật = single-writer + git-diff commit-gate · `model: opus`+`effort: max`+`memory: project`+`maxTurns: 18`. Trục = **CHÍNH HỆ MEMORY**, chạy **TUẦN TỰ** eval→refine→audit (🔴 CẤM `parallel()` — con KIỂM chạy song song sẽ chấm bản CŨ ⇒ verdict vô-nghĩa): `harness-eval` = con **ĐO** (chỉ trả số nguyên-văn từ instrument, CẤM số-từ-trí-nhớ) ⟂ `harness-refine` = con **ĐỀ-XUẤT** (4 lớp reinject/promote/archive/distill, bắt buộc có mục "đã cân-nhắc→BÁC") ⟂ `harness-audit` = con **KIỂM** (verdict ĐẠT/TRƯỢT per-claim + re-chạy ≥2 số load-bearing; PIN run-folder đích-danh, CẤM tự tìm "run mới nhất"). 🔴 **KHÔNG gộp** với H1 tooling-freshness / H2 harvest-integrity / H24 lead-surface / reviewer diff-code — 4 trục khác nhau. Nghi-thức 2-đầu-phiên **AUTO 1 vòng/phiên GIỮA 2 bookend** (`session-start §2.1.9(a)` canonical + `session-end §L.b(k)(i)` trỏ): owner chốt @S151 — em-main IN 1 dòng trạng-thái rồi CHẠY, KHÔNG chờ gật [🔄 vá @S153 FLAG-4 HIGH: ô này còn khai "consent-gated + anh gật mới chạy" sau khi owner (32) đã lật AUTO, và ngược chính `:466` cùng file; trio đã chạy THẬT 3 vòng S151/S152/S153]; skip → ghi vết WAL `trio: skipped S` (vết-2-lớp, chuỗi skip nhìn thấy được). Budget seed đo TƯƠI `measure-agent-memory.ps1`: eval 1547B · refine 1616B · audit 1513B (l2_*=0 = SEED-STATE đúng, chưa chạy lần nào). 🔸 **Nấc trung-thực = executed-file / verified-pending-restart** — 3 vai CHƯA spawn-probe lần nào (cần restart CLI + anh consent; KHÔNG được đọc thành verified-runtime).** **+S121 👁 `lead-stale-auditor` + `lead-gap-auditor` (13th+14th sub — H24 lead-self-audit, adopt broadcast `2026-07-14-Governance-harness-24`, anh chốt S119 `owner-decisions-15-07-2026`, land S121 wave-W2 `hmw.js` VALID_ROLES 12→14 CÙNG COMMIT roster+STATUS [R3-M2: lệch landing ⇒ C2/B3 flag mọi derived ghi "14" là stale-vs-12 ⇒ detector BÃO trên chính thay đổi của H24]). 2 monitor INFORM-only propose-only, cookie-cutter frontmatter monitor sẵn (`model: inherit` lúc-land [S124 re-pin → `opus`+`effort:max` cùng toàn roster] · `memory: project` · `maxTurns: 18` · 8 tool read-only, **NO Write/Edit**). Trục: `lead-stale-auditor` = **view LỆCH source** (5 class `view-*`) ⟂ `lead-gap-auditor` = **cái BỊ THIẾU** (6 class `gap-*` — +`gap-incident-unrecorded` @S143 owner-duyệt) — 🔴 **KHÔNG gộp** vào tooling-auditor(H1 tooling-freshness)/harvest-curator(H2 harvest-integrity): H24 §2(1) *"gộp là mất tiêu-điểm; cái ta cần là cặp mắt CHỈ dành cho lead"*. Class-flag = **enum ĐÓNG** `lead_self_audit.flag_classes` ở `.claude/agent-memory/memory-budget.json` (11 class = 5+6, vai CẤM tự chế — mở enum là quyền owner). Nhịp = `h24_cadence` cùng file (single-source H24 §2(3) — doc TRỎ key, KHÔNG chép số ⇒ 🔄 **đã GỠ digits `{6/15/3}` @S153** theo `ring2-audit` R-3: chép số ngay cạnh câu cấm-chép-số là **B1-copy** [số vẫn KHỚP canonical nên KHÔNG phải stale — F-6 chống vu-oan]; đọc số sống ở `memory-budget.json → h24_cadence`); 🔄 **HÌNH B @S149**: cặp soi-lead spawn **VÔ-ĐIỀU-KIỆN 2 bookend mỗi phiên** — `light_every` hạ thành **stats-only** (KHÔNG còn cổng bắn), `deep_every` GIỮ cổng nhịp [vá @S153 FLAG-5: ô này còn mô-tả bắn thuần-cadence; đối-chứng hành-vi = cặp chạy @counter 27 với light 1/6 CHƯA tới hạn]; counter `.claude/governance/.session-counter.json` (content-based `last_ticked_head`, KHÔNG blind-increment — hook `wal-flush.ps1` auto-commit `agent-memory/` mỗi turn sẽ làm hỏng đếm mù; đặt ngoài **4 path** hook CÓ CHỦ-ĐÍCH — *hook nới từ 3 lên 4 @S146 khi thêm `.claude/sessions/`; mệnh-đề "governance/ nằm ngoài" đã RE-VERIFY sau khi nới, vẫn đúng*). ✅ **verified-runtime S122** (spawn-probe toàn-roster-KHI-ĐÓ SỐNG post-restart — **N=14 tại thời-điểm S122**, chứng runtime, §Recently-Done S122; 🔸 +3 trio S141 CHƯA nằm trong phép đo này) **+ chạy THẬT S124** (dogfood 2-vai đầu-tiên, owner-triggered @counter 3) **+ S137** (light-audit consent OVERDUE 8/6 → 2 FLAG view-stale-status + 1 FLAG gap-decision-sunk). 🔸 Residual THẬT giữ: đường `hmw.js→agentType` cho 2 vai H24 chưa exercise (Agent-tool path đã chứng; workflow-path chưa) [S137 view-audit lật ⚠️→✅ khớp source, giữ residual]. 🔸 Từ-vựng "view"/"omission" chọn có chủ-đích tránh va-chạm: `governance-detectors.ps1:15` đã sở-hữu `derived-staleness`, và "GAP" quá-tải (`session-end` build-gap · `memory-selfimprove-audit.ps1` CRITERIA+GAP).** **+S107 📄 `office-document` (12th sub — Office document WRITE specialist: docx·xlsx·pptx·pdf + form-engine; floor OD1–OD10; VALID_ROLES hmw.js 9→10; anh giao trực tiếp S107 "Sub chính" Office; ✅ **verified-runtime S107 CÙNG PHIÊN** — registry hot-reload agent MỚI giữa phiên [S27 lesson thu hẹp còn EDIT-agent/command] + spawn-test PASS OD1/OD4/OD5 template thật, model self-report `claude-fable-5` [data-point #5 flip-8]; finding: 2 template `wwwroot/templates` 0-placeholder mẫu-blank).** **worker-tier-pin (owner-decision S124 2026-07-15 — thay all-inherit H8 S66, trước nữa two-tier H4; sub TOÀN-ROSTER pin cứng KHÔNG theo lead; H23-precedence ĐO S126: spawn-param THẮNG hard-pin ⇒ `/fable-real` SỐNG). Lead = **DEFAULT Opus 5 MAX** (thư `9c909007` @S149 (re-stamp 07-25 G-024a; pre `59ce1d0f`); **anh chốt ô canonical hiển-thị DEFAULT-fleet @S151** — *"cần gọi Fable tao chọn đầu mỗi phiên hoặc gọi bằng command fable-real"* ⇒ Fable = anh `/model` đầu phiên HOẶC per-invocation `/fable-real`; runtime thật = BƯỚC 0.6 probe mỗi phiên, KHÔNG ghi sổ mỗi flip — hết class stale-2-flip ring1 bắt @S150). 🧊 Lineage owner-choice/flip-chain FROZEN tới flip-8 (flip-9 S119 Opus-4.8 owner-choice + các lượt /model sau = per-session không enumerate, anti-churn S106):** em main Fable 5 (1M) Max (✅ **Fable RESTORED S98 2026-07-02** — lead self-report `claude-fable-5` + settings `claude-fable-5[1m]`; fallback-Opus H5 S62→S97 kết thúc, H5.6 hoàn tất) ⚠️ **S101 2026-07-03: runtime lead = Opus 4.8** (lead + 2 monitor + WF2 reviewer inherit đều self-report `claude-opus-4-8`; settings vẫn pin `claude-fable-5[1m]` → **Fable unavailable phiên này → H5-fallback tự-kích, revert-free, KHÔNG sửa frontmatter**; "Fable RESTORED S98" = point-in-time KHÔNG phải steady-state — inherit-chain resolve theo availability runtime; ✅ **S102 2026-07-06: Fable VỀ LẠI runtime** — lead + 2 monitor inherit self-report `claude-fable-5` → H5-fallback S101 kết thúc, pattern availability per-session xác nhận [S98 Fable → S101 Opus → S102 Fable → **S103 Opus** → **S104 Opus** (2026-07-06 Fable outage tiếp — S104 lead + 2 monitor spawn self-report `claude-opus-4-8` ×3, H5-fallback revert-free) → ✅ **S105 Fable** (2026-07-07 Fable VỀ lần 3 — lead + 2 monitor self-report `claude-fable-5` ×3, runtime-verified) → ⚠️ **S106 Opus** (2026-07-07 Fable outage lại — lead runtime self-report `claude-opus-4-8`, H5-fallback revert-free; flip-7) → ✅ **S107 Fable** (2026-07-10 Fable VỀ lần 4 — lead + 2 monitor self-report `claude-fable-5` ×3, runtime-verified; flip-8)], BƯỚC 0.6 probe mỗi phiên; per-session KHÔNG steady-state. 🔴 **[§Sub-agents = CANONICAL single-owner flip-chain — S106 gộp per anh-confirm; derived `agents/README §Architecture` · `session-start BƯỚC 0.6` · `session-end §commit-format` trỏ về đây [🔄 vá @S153 FLAG-1: 3 cite số-dòng cũ `:3`/`:37`/`:113` đo lại SAI cả 3 (đúng là `:5`/`:48`/`:315`) — vá bằng BỎ số theo luật đã áp @S151, không ĐỔI số], KHÔNG tự enumerate mỗi flip → chống churn 4-file/flip]**) · **TOÀN roster `model: opus` + `effort: max`** (worker-tier-pin S124; **A2 đo S126:** lane no-tier resolve `claude-opus-4-8` DÙ lead=Fable ⇒ pin ăn runtime, hết inherit-lead; số vai = cột giữa của chính row này — KHÔNG chép lại vào narrative, đó là cách row-14 và narrative-12 lệch nhau từ S121 tới S122; lineage: 7 demoted flip S66 → all-inherit S66–S123 [office-document S107 inherit-born] → pin S124) · effort Max. 10 product/quality + monitor INFORM-only (H1 · H2 · 2×H24 S121 · 3×trio-memory S141 · 3×round-KIỂM `ring1-audit`/`ring2-audit`/`ring4-audit` S145) — **liệt-kê NHÓM, số vai = cột giữa của chính row này**. Nấc H8 = **runtime-verified S98 (2026-07-02)** — spawn-test inherit-chain ×2 monitor self-report `claude-fable-5` (cả đội tự lên Fable khi lead restore, 0 sửa frontmatter — đúng thiết kế all-inherit). Prev two-tier H4 runtime-verified S57bis (spawn-test 2 chiều). | | RAG chunks | 🟢 **service UP** · 🔴 **SE index STALE** | 🔴 **TÁCH 2 TRỤC @S159 — 1 nhãn nhị-phân DOWN/alive che mất trục thứ hai.** ① **service-liveness = UP**: đo LIVE 2026-07-29 `list_projects` → **7/7 project chunk > 0** (`solution_erp` **2449** · vipix_multisite 7090 · dh_y_duoc 15440 · namgroup 6106 · ashico 4742 · vipix_ai_infra 4176 · benhvien_aau 3024; chỉ `shared_global` = 0); **query THẬT** `search_code` → 1 hit **có ruột** score 7.156 ⇒ collection đọc được, **không phải vỏ rỗng** (metadata một mình KHÔNG đủ — có thể là registry-cache). ② **SE index-freshness = KÉM**: `last_indexed_at` = **2026-05-29** trong khi **5 sibling re-index 2026-07-29 08:21** cùng một lượt. **Lật thẳng DOWN→alive sẽ CHÔN trục ②.** 🧊 **Nhãn "DOWN từ S153" ĐÚNG LÚC GHI** (`33e7f68`, 07-28 20:50, 3 phép đo khớp, `chunk_count=0` cả 7 project) — service **hồi phục sau ~12h** ⇒ class `view-stale-status`, **KHÔNG phải lead ghi ẩu**; đừng quy lỗi cho lượt viết vốn có bằng chứng đúng. 🔸 **Caveat giữ (H1 F-4 → ring1 T-2):** H1 tuyên `last_indexed_at` "không đáng tin" (2447→2449 nhúc nhích), `ring1` **BÁC** bằng nội-dung — coi là **đáng tin**; muốn chắc tuyệt đối thì re-index rồi xem field có nhảy không. Re-index = AI_INFRA op (cần VOYAGE_API_KEY). *(FLAG-2 `view-stale-status` HIGH — `lead-stale-auditor` @S159, `ring2` tái-dựng 8/8 số. Lead trước đó chỉ vá `:6`, sót đúng ô canonical này = **canonical-poison**, cùng lớp khác site.)* | -**Bundle hash live (prod):** admin **`1yiNV4VH`** · user/eoffice **`DoULfmdT`** — **đo LIVE @S166 ~10:0x 01/08 bởi gate-K4a (post-deploy F-1 `7a903cf`, run #437 — 2 css khớp chứng đo-đúng-site)**; K4a+K4b push kế tiếp SẼ rotate tiếp ⇒ **nguồn cập nhật ô này = cicd-verify lượt kế, đừng tin ô này quá 1 deploy** (bài "sạch lúc HH:MM" — ô này đã chết-ngay-lúc-viết 1 lần trong chính S166). 🧊 Lineage: K3 #436 admin `mySTlx42`/css `Cf3iCOOv` · eoffice `CZAYiWWa` FROZEN-hợp-lệ (diff toàn comment, cicd §5 dự-đoán-trước). 🧊 Lineage cũ (S162-S164, hash `B43R6Y17`/`NLI5umBg` đã chết): **Nguồn rotate = push `e5123ff`**, commit gắn nhãn `Docs: S162 closeout` **nhưng ship 6 file FE-src THẬT** (`PipelineStageFolders.tsx` · `PipelineTreePanel.tsx` · `usePipelineStages.ts` ×2 app) ⇒ rotate **real-src, KHÔNG phải #69-benign**; scope commit sai convention (đáng lẽ `FE-Admin`+`FE-User`, không phải `Docs`). 🔴 **Hại đo được — LỆCH 2 BỀ MẶT, không phải 1:** ô này đứng ở cặp S157 qua **2 đời deploy**, VÀ dòng `:6` ghi cặp S162 `DXoYDy7R`/`o8KDluD1` **chưa bao giờ là trạng-thái cuối** (snapshot chụp sau `bfc7b79`, trong khi `e5123ff` còn ship FE tiếp) ⇒ **cả 2 bề mặt owner đều lệch prod cùng lúc**. Đúng ca *"closeout-push kế có non-md sẽ rotate tiếp"* mà chính ô này đã tiên-liệu (precedent S99-#485 / S107) — tiên-liệu đúng, cơ-chế bắt vẫn không có. **Control-âm:** cặp S157 `8-QYcMOg`/`DptYR4wL` nay trả `text/html` **900 B** admin / **876 B** eoffice ⇒ bundle cũ đã chết. ⚠️ **CHƯA neo run-số CI** — lead chỉ curl 3 phép (2 hash live + control-âm), **không đọc Gitea Actions**; cần `cicd-monitor` xác nhận Run # + test-gate trước khi coi ô này đủ bằng-chứng. 🧊 *Mốc trước S157:* admin **`8-QYcMOg`** · user **`DptYR4wL`** (đo LIVE @S157 2026-07-28, **Run #419** `6250f39` — cicd PASS 9/9 + lead tự re-curl độc lập khớp từng byte, marker 2/2 mỗi app; **control-âm**: 2 hash CŨ `index-BK8w3QxU.js`/`index-DYnxSI0T.js` nay trả `text/html` **900 B admin / 876 B eoffice** ⇒ bundle cũ đã chết trên prod. 3 phép đo độc-lập: cicd-verify · lead re-curl · ring2-audit). 🔴 **Ô này từng đứng ở cặp `BK8w3QxU`/`DYnxSI0T` sau khi prod đã rotate** — `git show 3b6fabc -- docs/STATUS.md` chỉ có 2 hunk, **0 hunk chạm dòng này**; hại đo được: `cicd-verify-s157-diadiem.md:58` dùng chính ô này làm baseline ⇒ lượt deploy kế hoặc báo "ĐỔI" giả hoặc che một lần không-rotate (lead-stale-auditor FLAG-1 HIGH @S158). 🧊 *Mốc trước:* admin `BK8w3QxU` · user `DYnxSI0T` (S156 CI run 531 `f4494cf`; `Last-Modified` 14:41:15/14:42:10 +07 **nằm trong cửa-sổ deploy** — ship-proof, không phải hash-delta suông. Byte-verify 4/4 marker: `allowApproverDelete` 8/2 · `by-approver` 1/1 · `deleted=1` 1/1 · `view=approved` 1/1. ⚠️ **Không chứng minh hồi-tố** được bundle của riêng `4464a46` đã rotate lúc 14:12 — `f4494cf` đè lên sau 30 phút, không ai chụp snapshot khoảng giữa). 🧊 *Mốc trước:* admin `B2j1LQ-v` · user `C3wbJegk` (S147 CI #407 — re-stamp @S152: FLAG-2 lead-stale bắt ô này đứng S134 qua 5 nhãn trong khi `:6`/`:465`/HANDOFF đều S147; ring2 verify 2 lệnh độc-lập). 🧊 *Chuỗi rotate lịch-sử giữ nguyên:* (S134 — **`6664a61`** PE lũy kế TẠM TÍNH vs CHÍNH XÁC [0 mig — `ComputePendingAsync` complementary + DTO 5-field + FE sub-dòng amber + banner màn duyệt + D4 audit-note]; **Run #399** GO 5/5 5m27s gate-**528**-EXACT-từ-log rotate ×2 admin js `3NCdyODe`→**`BVCukFP5`** css `B--dUHcm`→**`CBzUlgOA`** / eoffice js `CKsoiNCI`→**`DoxyEOxh`** css `BuntB63r`→**`BHsBUA8e`** [FE-src đổi thật 6 file ⇒ rotate expected; CSS rotate = amber badge utilities, benign #69]; real-size 1.659.037/1.565.367B + LM 14:31:34/14:32:28+07 in-window; **byte-verify #77** `pendingPriorPes`=2 + `Tạm tính`=3 + `phiếu trước cùng gói thầu CHƯA duyệt`=2 PRESENT cả 2 js [control old-hash 900B text/html 0-hit — ct=text/html là discriminator sạch hơn size-919b]; Mig 67 top FROZEN + 89 bảng [0-mig by-construction]; smoke 4×200 + PE 401; lead spot-check độc-lập post-verdict: 4/4 hash khớp + marker PRESENT). **Prev S133** — admin **`3NCdyODe`** · user **`CKsoiNCI`** (S133 — **`d4fbced`** PE freeze NS phiếu DaDuyet [Mig 67 snapshot 11 cột + backfill 18/18 + FE 2-app badge 🔒 SHA-mirror `5534addb` + display-gate `budgetFrozen`]; **Run #398** GO 5/5 gate-520 rotate ×2 admin →**`3NCdyODe`** [CSS `B--dUHcm`] / user →**`CKsoiNCI`** [CSS `BuntB63r`] — prev `yCkX-2Bp`/`DKSD4p9k` @Run #397 S131-S132 [dòng-live lag S117→S133, hoist per precedent S104/S107]; **CSS cũng rotate** = badge sinh utility-class mới, benign #69; **byte-verify #77** `budgetFrozen`=1 + VN-string 🔒=1 PRESENT [old-control 0]; Mig 67 prod history-top + 11 cột + backfill 18/18 chua=0 + sys.tables **89**; smoke 4×200 + PE 401; `/tiep` S134 re-verify độc-lập 4/4: mig-top + health-200 + bundle-hash ×2 + filter 11/11). **Prev S117** — admin **`cFI7ih4a`** · user **`MxgooVZw`** (S117 — **`316a82f`** PE endsBeforeCeo pointer-aware [display-fix BE-only, phiếu chờ CEO hết báo "Kết thúc" sai] + duyệt-theo-khoảng Min–Max [Mig 66 + FE 2-app ProMinMax radio thứ 5]; **Run #387** PASS 5m36s rotate ×2 admin `Dd55jBpj`→`cFI7ih4a` / user `DVDr1UQ4`→`MxgooVZw` CSS-frozen [logic-only fingerprint]; **byte-verify #77** `ProMinMax`/`duyệt theo khoảng`/`cả Min và Max`/`Min–Max` PRESENT [bundle-cũ=0]; Mig 66 prod col decimal(18,2) + `__EFMigrationsHistory`-top + sys.tables **89**; smoke 200×3 · PE 401-secured; **#53-garble ×2** [invest-lane-1 + cicd-monitor] → SendMessage-resume + em-main curl cross-verify khớp). **Prev S116** — admin **`Dd55jBpj`** · user **`DVDr1UQ4`** (S116 — **`88368fd`** PE cho nhập giá ÂM ô báo giá [FE 2-app nút ± toggle + submit-gate `>0`→`!==0` + helper `hasRealSelectedQuote` 2-mirror `:201`/`:235`; BE submit-guard `:206` `Sum()<=0`→`All(==0)`; +9 test 486→495; **NO migration**]; **Run 386** PASS 5m28s rotate ×2 admin `D51OYyGV`→`Dd55jBpj` / user `BVdssm5S`→`DVDr1UQ4` CSS-frozen [logic-only fingerprint]; **byte-verify #77** `Đã nhập giá chào thầu`/`hoàn tiền NCC`/`phát sinh giảm`/`Đơn vị được chọn chưa có giá chào thầu` PRESENT [bundle-cũ=0]; smoke 200×3 · PE 401-secured · 89 bảng; cicd bắt bẫy snapshot-while-CI-running→poll-success TRƯỚC re-snapshot). **Prev S114** — admin **`D51OYyGV`** · user **`BVdssm5S`** (S114 — **`d436af2`** PE multi-NCC per hạng mục [Mig 65 backfill 2-chiều + BE re-key 5 financial→IsSelected + FE per-cell grid Detail×NCC 2-app SHA `ae3788e9`]; bundle rotate ×2 admin `acprMqfB`→`D51OYyGV` / user `Ck3BTDdA`→`BVdssm5S`; **byte-verify** `detailId`+`select-winner`+`hạng mục` PRESENT [bundle 1.65MB real-size]; smoke health/admin/eoffice 3/3 200 + endpoint POST select-winner bogus-401-live; **cicd garble #53 ×5 → em-main-solo curl-verify**; mig applied [API-healthy=migrations-ran-startup]). **Prev S113** — admin **`acprMqfB`** · user **`Ck3BTDdA`** (S113 — **Run #497** `5fa11b5` Supplier import v2 [Mig 64 publish/draft + dedup-MST + template + file mẫu] FE 2-app real-src rotate; JS admin `Cixlt_MA`→`acprMqfB` / user `BhBOG1dn`→`Ck3BTDdA` + CSS admin `Ds-E5neu`→`CfunQHbd` / user `Beb0Bb1h`→`DGqqHQXS`; ship-proof real-size 1.66/1.56MB + LM-in-window + **byte-verify** `Tải file mẫu`×1/`Đã công bố`×3/`Nháp (ẩn)`×4/`import/template`×1/`published`×5 PRESENT; Mig 64 prod 37/37-backfill sys.tables **89**; smoke health/admin/eoffice 200 + `import/template`-401-live + `suppliers?published=true`-401-live bogus-404-control). **Prev S112** — admin **`Cixlt_MA`** · user **`BhBOG1dn`** (S112 — **Run #496** `e100ef0` Supplier Excel-import Phase B FE 2-app [`SupplierImportDialog` NEW cả fe-admin+fe-user] + PE sign-off code-only; **real fe-src rotate — kết thúc #489→#495 non-determinism-freeze**; JS admin `BVyH-FY7`→`Cixlt_MA` / user `EDsZebvn`→`BhBOG1dn` + CSS admin `Bbtesa6B`→`Ds-E5neu` / user `BmuPz_Dy`→`Beb0Bb1h`; ship-proof real-size + Last-Modified-in-window + `"Database NCC"` marker PRESENT ×1; Mig 63 prod 2/2-col sys.tables **89**; smoke health/admin/eoffice 200 + PE-endpoint 200 + import-route preview-415/confirm-401-live bogus-404). **Prev S107** — admin **`BVyH-FY7`** · user **`EDsZebvn`** (S107 — **Run #489** `21387cd` +office-document 12th sub governance-only; **rotate benign #69-two-mode** [0 fe-src — Vite non-determinism], CSS frozen `Bbtesa6B`/`BmuPz_Dy`, real-size 1.64/1.55MB + Last-Modified-in-window 09:32/09:33 = ship-proof, Mig 62/89 frozen, smoke 200×3; hoist @S107-closeout per H1 flag D-BUNDLE-lặp — ⚠️ closeout-push kế có non-md sẽ rotate tiếp → Run #490 record nằm ở cicd MEMORY [authoritative], hoist ở bundle đầu phiên sau per precedent S99-#485). **Prev S104** — admin **`ChSNAJBK`** · user **`Bn2w1znH`** (S104 — **Run #488** `778fc98` Mig 62 Supplier expand 30-field; real-src-rotate FE 2-app SHA-mirror [form 4-section + Status select + `PathLink` 3 NAS-link], **sys.tables 89 pre==post no-new-table**, prod-verified marker grep-HIT, smoke 200×3; S104-shipped nhưng dòng-live `:27` lag tới S106 → hoist per H1 flag D-BUNDLE). **Prev S97** — admin **`mEGqlNWc`** · user **`Dnrp4PU1`** (S97 — **Run #484** `fb2dfa9` Mig 61 data-fix backfill; bundle rebuild **#69-benign** [0 FE-src change, review-workflow cicd re-snapshot LIVE → `CeTA7Z82`/`CGaAyXen` #483 đã bị #484 rebuild rotate]; backfill A/005/A/008 flag 0→1 prod-verified). **Prev #483** — admin **`CeTA7Z82`** · user **`CGaAyXen`** (S97 — **Run #483** `9e12e80` badge "✅ Đã được CEO duyệt" phiếu đi-hết-lên-CEO [PeFinalizeChip single-source + 6 call-site 2-app, đối xứng chip "⚑ Kết thúc·X"]; FE-only tận-dụng endsBeforeCeo runtime, no BE/mig; JS rotate CSS-frozen #69; byte-#77 "Đã được CEO duyệt" PRESENT cả 2 app + prev-badge additive no-regression; Mig 60 frozen; smoke 200×3 + PE-list 200). **Prev #482** — admin **`DR9q2VUy`** · user **`Bgz8u4E5`** (S97 — **Run #482** `8037fa0` endsBeforeCeo config→RUNTIME [Mig 60 `EndedByLevelFinalize`]: **Mig 60 applied prod** (history-top + col-default-0 EXISTS + backfill=0 UAT-no-marker + sys.tables **89** pre==post); **EF-ternary SQL-Server LIVE-confirmed** GET /purchase-evaluations 200 items=9 + PE-detail `31faef0d` 200 **endsBeforeCeo=False phase=7** = runtime-path chạy = **bug fixed LIVE** (NOT 500); JS rotate 2-app PeWorkflowPanel gate-diff, CSS frozen #69-REFINE; byte-#77 `endsBeforeCeo` PRESENT in-bundle; smoke 200×3. reviewer PASS 0-issue + test 440. **Prev #481** — admin **`Cf0o8dx8`** · user **`x8rppRAK`** (S97 — **Run #481** `1c8fb6a` PE finalize 2-fix [badge "không trình tới"→"Kết thúc tại {cấp}" + đảo default checkbox opt-in]; JS rotate real-FE 2-app `PeWorkflowPanel` diff, CSS frozen `Bbtesa6B`/`BmuPz_Dy` #69-REFINE logic-only; **byte-level #77** NEW `Kết thúc tại`+helper PRESENT / OLD `không trình tới`+`Đã BỎ tick` ABSENT; real-size 1.64/1.54MB; Mig 59/88-table frozen; smoke 200×3. FE-only mirror SHA `bcf812fd`, 0 BE/mig/test). **Prev S96** — admin **`COYAX-yQ`** · user **`0MU-kb4N`** (S96 — **Run #480** `0c2f9f6` price-lock; chuỗi 3 PE deploy #478 `e657faa` checkbox-opt-out → #479 `36cbf8b` chuông-stale-clear (BE-only) → #480 `0c2f9f6` khóa-giá-sau-duyệt, cicd PASS each ~5m; **FE JS rotate THẬT** (PeWorkflowPanel #478 + PeDetailTabs #480, 2-app) real-size 1.64/1.54MB vs 919b SPA-trap, CSS frozen #69-REFINE; Mig 59 frozen 0-mig; +Run #477 `ba4b8e0` NCC seed no-mig prod 21 NCC. **Verify byte-level:** prod `0MU-kb4N` CHỨA checkbox-fix ("BỎ tick"/"Đã BỎ tick") + "✅-static" cũ MẤT → checkbox "ko-được" = browser-cache KHÔNG deploy-fail). **Prev S95** — admin **`0T6vVJST`** · user **`BGXEVZO6`** (S95 — **Run #476** `18a17f5` H17 governance-only deploy; bundle rotate benign #69 CSS-frozen, prod 200×3, Mig 59 unchanged; cicd re-snapshot LIVE — pre-deploy `CkZ1MjC1`/`_-gpX7_Y`, mega-line S93 `CDn40vpV`/`CoPmPBg7` đã bị deploy trung-gian rotate từ S94). **Prev S85** — admin **`aKuNip19`** · user **`BUsL0HeQ`** (S85 — **Run #341** `49ac086` lệch-giờ TZ serialize UTC-with-Z; FE frozen #339+#341 BE-only. Chuỗi ~10 deploy #334→#341 buổi UAT anh Kiệt CV PRO: #334 `5a61254` batch CV PRO 6-fix → #335-#338 6 vòng UAT → #339 `1263c0d` workflow-preserve bug-class S42 → #341 `49ac086` TZ; #342 `d4f6021` docs+cicd BE-frozen, bundle giữ-nguyên gotcha #69-REFINE). **Prev S78** — admin **`CsJetgZH`** · user **`BVS0ApIm`** (S78 — **Run #330** `7886fd0` PE attach-file khi duyệt; bundle ROTATE từ S77 `BqKD3Y23`/`Cn-i349D` dù NO migration enum-only — gotcha #69 non-determ rebuild; cicd ship-proof byte-stable + fake-hash control). **Prev S77** — admin **`BqKD3Y23`** · user **`Cn-i349D`** (S77 — **Run #329** `e823694` banner Trả-lại; cuối chuỗi 10 deploy #320→#329 cùng ngày, cicd PASS each: #320 pill `DsSg6RRz`-era → #321 focus → #322 revert → #323 Mig57+notes `CPm4LTqm`/`BWJUAqEI` → #324 số-âm-đỏ `C6fx-0ea`/`N3sW4Div` → #325 indent `BhnNMucS`/`B1VebpXc` → #326 cờ-gấp-asymmetric `DwXqn37C`/`COXMCv7E` → #327 decouple `B0gboSAg`/`DbDg7pM-` → #328 notify (BE-only, FE frozen) → #329 banner **`BqKD3Y23`**/**`Cn-i349D`**). **Prev S76** — admin **`jOqxW4-p`** · user **`DbsznVvR`** (S76 — **Run #319** `21d1f4e` bảng lưới `` ngân sách viền-ô; chuỗi S76 cùng ngày: #318 `e33481e` feature ma-trận-3-cột + badge quyền-NS `BhFDF9IJ`/`BAkuRl3C` → #319 **`jOqxW4-p`**/**`DbsznVvR`**, cicd PASS each, smoke 3×200, Mig 56 applied prod #318). **Prev S74** — admin **`BYF5vIMJ`** · user **`CB-tiRxd`** (S74 — **Run #315** `8655ebf` Mig 55 CcmNote, cicd PASS ~4m54s: Mig 55 applied prod CcmNote nvarchar(1000) nullable · sys.tables 88 · smoke 4×200 · 0 regression). **Prev S73** — admin **`Bv3jUCNo`** · user **`BWlMBQz6`** (Run #314 `6aa4dcb` FE empty-candidates guard fix; chuỗi 2 deploy: #313 `1d86abc` feature `OlNyG9OD`/`DSzSLVtL` → #314 **`Bv3jUCNo`**/**`BWlMBQz6`**, cicd PASS each). **Prev S72** — admin **`fc_xkNpJ`** · user **`DP-tBcg0`** (Run #312 governance commit `18fced6`; bundle ROTATE do **non-deterministic hash + deploy rebuild-FE-unconditional** (gotcha #69) — 0 FE source change, prod state/DB GIỮ NGUYÊN). **Prev S69** — admin **`BgNCjwsG`** · user **`CBvh0vtf`** (Run #308 PE cờ gấp + ngưỡng CCM; chuỗi 4 deploy session: #305 Văn phòng số foundation → #306 re-skin 10 page → #307 Office golive (BE-only) `Wt54PHYl`/`B99fMU6X` → #308 **`BgNCjwsG`**/**`CBvh0vtf`**). **Prev S68** — admin **`CNUv1jxY`** · user **`CpOskeS1`** (S68 — Run #304 `37752eb` fix tên đen→trắng; chuỗi #303 `6983609` `D532XZKG`/`CuFaBoWt` → #304 **`CNUv1jxY`**/**`CpOskeS1`**, cicd PASS each). **Prev S67** — admin `CcrZqfht`/user `DniDFUB_` (S67 — 6 deploy Run #297→#302; admin rotate chuỗi #298`xkSz9BfE`→#300`PxiZQkaw`→#301`I1fpLeYw`→#302**`CcrZqfht`** · user #297`BumgrwCJ`→#300`B36hGoKd`→#301`DrQYkzh0`→#302**`DniDFUB_`**; #299 tests BE-only cả 2 frozen, cicd PASS each). **Prev S65** — admin `BDwV5d0X`/user `DbVv6rsf` (Run #293-295). Prev S62 admin `0xKYGhhf`/user `C81ZdG9G` (Run #286). **Prev S59:** admin `B1DtNT9C` · user `D6uF3Mln` (Run **#282** `792c030` FINAL — bỏ nút Thêm hạng mục; ships kèm `80b64dd` gỡ Điều khoản TT, #281 cancelled-benign ancestor-verified). Chuỗi S59 cùng ngày: #280 `69997da` (`BKy_8OO9`/`XcZ6PRyA`, ships kèm `f21c55d` table-fixed #279-cancelled) · #278 `9c330d2` self-approve+quick-add-NCC (`BSh2fG2X`/`D22KfpPc`, authz probe 4/4) · #277 `faed59f` SearchableSelect (`ex7Tc92G`/`DzUeSk96`) · #276 `c869d26` rename 71 PMH (`BBA0KSWu`/`DzdTI18G`) · #275 `bbd1554` dọn demo WorkItems (FROZEN BE-only) · #274 `0eafcd3` tree 4 tầng (`DuU7OTym`/`DWyeTzf3`) · #273 `56882ac` wipe + tree v1 (`R9uGRxvw`/`DikfX1RD`). Prev S58: Run #386 `3ebaf84` admin `DMm9rtNA`/user `BUkOMn_Y` (chi tiết session log S58). +**Bundle hash live (prod):** admin **`RgvHZkPH`** · user/eoffice **`D65FJPGd`** — **đo LIVE @S167 ~13:1x 01/08 bởi cicd-K7 (post-deploy K7 qua run #442; hash+size khớp log CI, marker 8/8 ×2 app, control-âm hash-cũ `Ig1R5tAh`→900B text/html chứng ghi-đè)**; push kế tiếp SẼ rotate tiếp ⇒ **nguồn cập nhật ô này = cicd-verify lượt kế, đừng tin ô này quá 1 deploy** (bài "sạch lúc HH:MM" — ô này đã chết-ngay-lúc-viết 1 lần trong chính S166). 🧊 Lineage gần: K6 #440 admin `Ig1R5tAh` ROTATE · eoffice FROZEN-lành-tính cmp-byte · K4a #437 admin `1yiNV4VH`/eoffice `DoULfmdT` (post-F-1, 2-css khớp chứng đo-đúng-site) · K3 #436 admin `mySTlx42`/css `Cf3iCOOv` · eoffice `CZAYiWWa` FROZEN-hợp-lệ (diff toàn comment, cicd §5 dự-đoán-trước). 🧊 Lineage cũ (S162-S164, hash `B43R6Y17`/`NLI5umBg` đã chết): **Nguồn rotate = push `e5123ff`**, commit gắn nhãn `Docs: S162 closeout` **nhưng ship 6 file FE-src THẬT** (`PipelineStageFolders.tsx` · `PipelineTreePanel.tsx` · `usePipelineStages.ts` ×2 app) ⇒ rotate **real-src, KHÔNG phải #69-benign**; scope commit sai convention (đáng lẽ `FE-Admin`+`FE-User`, không phải `Docs`). 🔴 **Hại đo được — LỆCH 2 BỀ MẶT, không phải 1:** ô này đứng ở cặp S157 qua **2 đời deploy**, VÀ dòng `:6` ghi cặp S162 `DXoYDy7R`/`o8KDluD1` **chưa bao giờ là trạng-thái cuối** (snapshot chụp sau `bfc7b79`, trong khi `e5123ff` còn ship FE tiếp) ⇒ **cả 2 bề mặt owner đều lệch prod cùng lúc**. Đúng ca *"closeout-push kế có non-md sẽ rotate tiếp"* mà chính ô này đã tiên-liệu (precedent S99-#485 / S107) — tiên-liệu đúng, cơ-chế bắt vẫn không có. **Control-âm:** cặp S157 `8-QYcMOg`/`DptYR4wL` nay trả `text/html` **900 B** admin / **876 B** eoffice ⇒ bundle cũ đã chết. ⚠️ **CHƯA neo run-số CI** — lead chỉ curl 3 phép (2 hash live + control-âm), **không đọc Gitea Actions**; cần `cicd-monitor` xác nhận Run # + test-gate trước khi coi ô này đủ bằng-chứng. 🧊 *Mốc trước S157:* admin **`8-QYcMOg`** · user **`DptYR4wL`** (đo LIVE @S157 2026-07-28, **Run #419** `6250f39` — cicd PASS 9/9 + lead tự re-curl độc lập khớp từng byte, marker 2/2 mỗi app; **control-âm**: 2 hash CŨ `index-BK8w3QxU.js`/`index-DYnxSI0T.js` nay trả `text/html` **900 B admin / 876 B eoffice** ⇒ bundle cũ đã chết trên prod. 3 phép đo độc-lập: cicd-verify · lead re-curl · ring2-audit). 🔴 **Ô này từng đứng ở cặp `BK8w3QxU`/`DYnxSI0T` sau khi prod đã rotate** — `git show 3b6fabc -- docs/STATUS.md` chỉ có 2 hunk, **0 hunk chạm dòng này**; hại đo được: `cicd-verify-s157-diadiem.md:58` dùng chính ô này làm baseline ⇒ lượt deploy kế hoặc báo "ĐỔI" giả hoặc che một lần không-rotate (lead-stale-auditor FLAG-1 HIGH @S158). 🧊 *Mốc trước:* admin `BK8w3QxU` · user `DYnxSI0T` (S156 CI run 531 `f4494cf`; `Last-Modified` 14:41:15/14:42:10 +07 **nằm trong cửa-sổ deploy** — ship-proof, không phải hash-delta suông. Byte-verify 4/4 marker: `allowApproverDelete` 8/2 · `by-approver` 1/1 · `deleted=1` 1/1 · `view=approved` 1/1. ⚠️ **Không chứng minh hồi-tố** được bundle của riêng `4464a46` đã rotate lúc 14:12 — `f4494cf` đè lên sau 30 phút, không ai chụp snapshot khoảng giữa). 🧊 *Mốc trước:* admin `B2j1LQ-v` · user `C3wbJegk` (S147 CI #407 — re-stamp @S152: FLAG-2 lead-stale bắt ô này đứng S134 qua 5 nhãn trong khi `:6`/`:465`/HANDOFF đều S147; ring2 verify 2 lệnh độc-lập). 🧊 *Chuỗi rotate lịch-sử giữ nguyên:* (S134 — **`6664a61`** PE lũy kế TẠM TÍNH vs CHÍNH XÁC [0 mig — `ComputePendingAsync` complementary + DTO 5-field + FE sub-dòng amber + banner màn duyệt + D4 audit-note]; **Run #399** GO 5/5 5m27s gate-**528**-EXACT-từ-log rotate ×2 admin js `3NCdyODe`→**`BVCukFP5`** css `B--dUHcm`→**`CBzUlgOA`** / eoffice js `CKsoiNCI`→**`DoxyEOxh`** css `BuntB63r`→**`BHsBUA8e`** [FE-src đổi thật 6 file ⇒ rotate expected; CSS rotate = amber badge utilities, benign #69]; real-size 1.659.037/1.565.367B + LM 14:31:34/14:32:28+07 in-window; **byte-verify #77** `pendingPriorPes`=2 + `Tạm tính`=3 + `phiếu trước cùng gói thầu CHƯA duyệt`=2 PRESENT cả 2 js [control old-hash 900B text/html 0-hit — ct=text/html là discriminator sạch hơn size-919b]; Mig 67 top FROZEN + 89 bảng [0-mig by-construction]; smoke 4×200 + PE 401; lead spot-check độc-lập post-verdict: 4/4 hash khớp + marker PRESENT). **Prev S133** — admin **`3NCdyODe`** · user **`CKsoiNCI`** (S133 — **`d4fbced`** PE freeze NS phiếu DaDuyet [Mig 67 snapshot 11 cột + backfill 18/18 + FE 2-app badge 🔒 SHA-mirror `5534addb` + display-gate `budgetFrozen`]; **Run #398** GO 5/5 gate-520 rotate ×2 admin →**`3NCdyODe`** [CSS `B--dUHcm`] / user →**`CKsoiNCI`** [CSS `BuntB63r`] — prev `yCkX-2Bp`/`DKSD4p9k` @Run #397 S131-S132 [dòng-live lag S117→S133, hoist per precedent S104/S107]; **CSS cũng rotate** = badge sinh utility-class mới, benign #69; **byte-verify #77** `budgetFrozen`=1 + VN-string 🔒=1 PRESENT [old-control 0]; Mig 67 prod history-top + 11 cột + backfill 18/18 chua=0 + sys.tables **89**; smoke 4×200 + PE 401; `/tiep` S134 re-verify độc-lập 4/4: mig-top + health-200 + bundle-hash ×2 + filter 11/11). **Prev S117** — admin **`cFI7ih4a`** · user **`MxgooVZw`** (S117 — **`316a82f`** PE endsBeforeCeo pointer-aware [display-fix BE-only, phiếu chờ CEO hết báo "Kết thúc" sai] + duyệt-theo-khoảng Min–Max [Mig 66 + FE 2-app ProMinMax radio thứ 5]; **Run #387** PASS 5m36s rotate ×2 admin `Dd55jBpj`→`cFI7ih4a` / user `DVDr1UQ4`→`MxgooVZw` CSS-frozen [logic-only fingerprint]; **byte-verify #77** `ProMinMax`/`duyệt theo khoảng`/`cả Min và Max`/`Min–Max` PRESENT [bundle-cũ=0]; Mig 66 prod col decimal(18,2) + `__EFMigrationsHistory`-top + sys.tables **89**; smoke 200×3 · PE 401-secured; **#53-garble ×2** [invest-lane-1 + cicd-monitor] → SendMessage-resume + em-main curl cross-verify khớp). **Prev S116** — admin **`Dd55jBpj`** · user **`DVDr1UQ4`** (S116 — **`88368fd`** PE cho nhập giá ÂM ô báo giá [FE 2-app nút ± toggle + submit-gate `>0`→`!==0` + helper `hasRealSelectedQuote` 2-mirror `:201`/`:235`; BE submit-guard `:206` `Sum()<=0`→`All(==0)`; +9 test 486→495; **NO migration**]; **Run 386** PASS 5m28s rotate ×2 admin `D51OYyGV`→`Dd55jBpj` / user `BVdssm5S`→`DVDr1UQ4` CSS-frozen [logic-only fingerprint]; **byte-verify #77** `Đã nhập giá chào thầu`/`hoàn tiền NCC`/`phát sinh giảm`/`Đơn vị được chọn chưa có giá chào thầu` PRESENT [bundle-cũ=0]; smoke 200×3 · PE 401-secured · 89 bảng; cicd bắt bẫy snapshot-while-CI-running→poll-success TRƯỚC re-snapshot). **Prev S114** — admin **`D51OYyGV`** · user **`BVdssm5S`** (S114 — **`d436af2`** PE multi-NCC per hạng mục [Mig 65 backfill 2-chiều + BE re-key 5 financial→IsSelected + FE per-cell grid Detail×NCC 2-app SHA `ae3788e9`]; bundle rotate ×2 admin `acprMqfB`→`D51OYyGV` / user `Ck3BTDdA`→`BVdssm5S`; **byte-verify** `detailId`+`select-winner`+`hạng mục` PRESENT [bundle 1.65MB real-size]; smoke health/admin/eoffice 3/3 200 + endpoint POST select-winner bogus-401-live; **cicd garble #53 ×5 → em-main-solo curl-verify**; mig applied [API-healthy=migrations-ran-startup]). **Prev S113** — admin **`acprMqfB`** · user **`Ck3BTDdA`** (S113 — **Run #497** `5fa11b5` Supplier import v2 [Mig 64 publish/draft + dedup-MST + template + file mẫu] FE 2-app real-src rotate; JS admin `Cixlt_MA`→`acprMqfB` / user `BhBOG1dn`→`Ck3BTDdA` + CSS admin `Ds-E5neu`→`CfunQHbd` / user `Beb0Bb1h`→`DGqqHQXS`; ship-proof real-size 1.66/1.56MB + LM-in-window + **byte-verify** `Tải file mẫu`×1/`Đã công bố`×3/`Nháp (ẩn)`×4/`import/template`×1/`published`×5 PRESENT; Mig 64 prod 37/37-backfill sys.tables **89**; smoke health/admin/eoffice 200 + `import/template`-401-live + `suppliers?published=true`-401-live bogus-404-control). **Prev S112** — admin **`Cixlt_MA`** · user **`BhBOG1dn`** (S112 — **Run #496** `e100ef0` Supplier Excel-import Phase B FE 2-app [`SupplierImportDialog` NEW cả fe-admin+fe-user] + PE sign-off code-only; **real fe-src rotate — kết thúc #489→#495 non-determinism-freeze**; JS admin `BVyH-FY7`→`Cixlt_MA` / user `EDsZebvn`→`BhBOG1dn` + CSS admin `Bbtesa6B`→`Ds-E5neu` / user `BmuPz_Dy`→`Beb0Bb1h`; ship-proof real-size + Last-Modified-in-window + `"Database NCC"` marker PRESENT ×1; Mig 63 prod 2/2-col sys.tables **89**; smoke health/admin/eoffice 200 + PE-endpoint 200 + import-route preview-415/confirm-401-live bogus-404). **Prev S107** — admin **`BVyH-FY7`** · user **`EDsZebvn`** (S107 — **Run #489** `21387cd` +office-document 12th sub governance-only; **rotate benign #69-two-mode** [0 fe-src — Vite non-determinism], CSS frozen `Bbtesa6B`/`BmuPz_Dy`, real-size 1.64/1.55MB + Last-Modified-in-window 09:32/09:33 = ship-proof, Mig 62/89 frozen, smoke 200×3; hoist @S107-closeout per H1 flag D-BUNDLE-lặp — ⚠️ closeout-push kế có non-md sẽ rotate tiếp → Run #490 record nằm ở cicd MEMORY [authoritative], hoist ở bundle đầu phiên sau per precedent S99-#485). **Prev S104** — admin **`ChSNAJBK`** · user **`Bn2w1znH`** (S104 — **Run #488** `778fc98` Mig 62 Supplier expand 30-field; real-src-rotate FE 2-app SHA-mirror [form 4-section + Status select + `PathLink` 3 NAS-link], **sys.tables 89 pre==post no-new-table**, prod-verified marker grep-HIT, smoke 200×3; S104-shipped nhưng dòng-live `:27` lag tới S106 → hoist per H1 flag D-BUNDLE). **Prev S97** — admin **`mEGqlNWc`** · user **`Dnrp4PU1`** (S97 — **Run #484** `fb2dfa9` Mig 61 data-fix backfill; bundle rebuild **#69-benign** [0 FE-src change, review-workflow cicd re-snapshot LIVE → `CeTA7Z82`/`CGaAyXen` #483 đã bị #484 rebuild rotate]; backfill A/005/A/008 flag 0→1 prod-verified). **Prev #483** — admin **`CeTA7Z82`** · user **`CGaAyXen`** (S97 — **Run #483** `9e12e80` badge "✅ Đã được CEO duyệt" phiếu đi-hết-lên-CEO [PeFinalizeChip single-source + 6 call-site 2-app, đối xứng chip "⚑ Kết thúc·X"]; FE-only tận-dụng endsBeforeCeo runtime, no BE/mig; JS rotate CSS-frozen #69; byte-#77 "Đã được CEO duyệt" PRESENT cả 2 app + prev-badge additive no-regression; Mig 60 frozen; smoke 200×3 + PE-list 200). **Prev #482** — admin **`DR9q2VUy`** · user **`Bgz8u4E5`** (S97 — **Run #482** `8037fa0` endsBeforeCeo config→RUNTIME [Mig 60 `EndedByLevelFinalize`]: **Mig 60 applied prod** (history-top + col-default-0 EXISTS + backfill=0 UAT-no-marker + sys.tables **89** pre==post); **EF-ternary SQL-Server LIVE-confirmed** GET /purchase-evaluations 200 items=9 + PE-detail `31faef0d` 200 **endsBeforeCeo=False phase=7** = runtime-path chạy = **bug fixed LIVE** (NOT 500); JS rotate 2-app PeWorkflowPanel gate-diff, CSS frozen #69-REFINE; byte-#77 `endsBeforeCeo` PRESENT in-bundle; smoke 200×3. reviewer PASS 0-issue + test 440. **Prev #481** — admin **`Cf0o8dx8`** · user **`x8rppRAK`** (S97 — **Run #481** `1c8fb6a` PE finalize 2-fix [badge "không trình tới"→"Kết thúc tại {cấp}" + đảo default checkbox opt-in]; JS rotate real-FE 2-app `PeWorkflowPanel` diff, CSS frozen `Bbtesa6B`/`BmuPz_Dy` #69-REFINE logic-only; **byte-level #77** NEW `Kết thúc tại`+helper PRESENT / OLD `không trình tới`+`Đã BỎ tick` ABSENT; real-size 1.64/1.54MB; Mig 59/88-table frozen; smoke 200×3. FE-only mirror SHA `bcf812fd`, 0 BE/mig/test). **Prev S96** — admin **`COYAX-yQ`** · user **`0MU-kb4N`** (S96 — **Run #480** `0c2f9f6` price-lock; chuỗi 3 PE deploy #478 `e657faa` checkbox-opt-out → #479 `36cbf8b` chuông-stale-clear (BE-only) → #480 `0c2f9f6` khóa-giá-sau-duyệt, cicd PASS each ~5m; **FE JS rotate THẬT** (PeWorkflowPanel #478 + PeDetailTabs #480, 2-app) real-size 1.64/1.54MB vs 919b SPA-trap, CSS frozen #69-REFINE; Mig 59 frozen 0-mig; +Run #477 `ba4b8e0` NCC seed no-mig prod 21 NCC. **Verify byte-level:** prod `0MU-kb4N` CHỨA checkbox-fix ("BỎ tick"/"Đã BỎ tick") + "✅-static" cũ MẤT → checkbox "ko-được" = browser-cache KHÔNG deploy-fail). **Prev S95** — admin **`0T6vVJST`** · user **`BGXEVZO6`** (S95 — **Run #476** `18a17f5` H17 governance-only deploy; bundle rotate benign #69 CSS-frozen, prod 200×3, Mig 59 unchanged; cicd re-snapshot LIVE — pre-deploy `CkZ1MjC1`/`_-gpX7_Y`, mega-line S93 `CDn40vpV`/`CoPmPBg7` đã bị deploy trung-gian rotate từ S94). **Prev S85** — admin **`aKuNip19`** · user **`BUsL0HeQ`** (S85 — **Run #341** `49ac086` lệch-giờ TZ serialize UTC-with-Z; FE frozen #339+#341 BE-only. Chuỗi ~10 deploy #334→#341 buổi UAT anh Kiệt CV PRO: #334 `5a61254` batch CV PRO 6-fix → #335-#338 6 vòng UAT → #339 `1263c0d` workflow-preserve bug-class S42 → #341 `49ac086` TZ; #342 `d4f6021` docs+cicd BE-frozen, bundle giữ-nguyên gotcha #69-REFINE). **Prev S78** — admin **`CsJetgZH`** · user **`BVS0ApIm`** (S78 — **Run #330** `7886fd0` PE attach-file khi duyệt; bundle ROTATE từ S77 `BqKD3Y23`/`Cn-i349D` dù NO migration enum-only — gotcha #69 non-determ rebuild; cicd ship-proof byte-stable + fake-hash control). **Prev S77** — admin **`BqKD3Y23`** · user **`Cn-i349D`** (S77 — **Run #329** `e823694` banner Trả-lại; cuối chuỗi 10 deploy #320→#329 cùng ngày, cicd PASS each: #320 pill `DsSg6RRz`-era → #321 focus → #322 revert → #323 Mig57+notes `CPm4LTqm`/`BWJUAqEI` → #324 số-âm-đỏ `C6fx-0ea`/`N3sW4Div` → #325 indent `BhnNMucS`/`B1VebpXc` → #326 cờ-gấp-asymmetric `DwXqn37C`/`COXMCv7E` → #327 decouple `B0gboSAg`/`DbDg7pM-` → #328 notify (BE-only, FE frozen) → #329 banner **`BqKD3Y23`**/**`Cn-i349D`**). **Prev S76** — admin **`jOqxW4-p`** · user **`DbsznVvR`** (S76 — **Run #319** `21d1f4e` bảng lưới `
` ngân sách viền-ô; chuỗi S76 cùng ngày: #318 `e33481e` feature ma-trận-3-cột + badge quyền-NS `BhFDF9IJ`/`BAkuRl3C` → #319 **`jOqxW4-p`**/**`DbsznVvR`**, cicd PASS each, smoke 3×200, Mig 56 applied prod #318). **Prev S74** — admin **`BYF5vIMJ`** · user **`CB-tiRxd`** (S74 — **Run #315** `8655ebf` Mig 55 CcmNote, cicd PASS ~4m54s: Mig 55 applied prod CcmNote nvarchar(1000) nullable · sys.tables 88 · smoke 4×200 · 0 regression). **Prev S73** — admin **`Bv3jUCNo`** · user **`BWlMBQz6`** (Run #314 `6aa4dcb` FE empty-candidates guard fix; chuỗi 2 deploy: #313 `1d86abc` feature `OlNyG9OD`/`DSzSLVtL` → #314 **`Bv3jUCNo`**/**`BWlMBQz6`**, cicd PASS each). **Prev S72** — admin **`fc_xkNpJ`** · user **`DP-tBcg0`** (Run #312 governance commit `18fced6`; bundle ROTATE do **non-deterministic hash + deploy rebuild-FE-unconditional** (gotcha #69) — 0 FE source change, prod state/DB GIỮ NGUYÊN). **Prev S69** — admin **`BgNCjwsG`** · user **`CBvh0vtf`** (Run #308 PE cờ gấp + ngưỡng CCM; chuỗi 4 deploy session: #305 Văn phòng số foundation → #306 re-skin 10 page → #307 Office golive (BE-only) `Wt54PHYl`/`B99fMU6X` → #308 **`BgNCjwsG`**/**`CBvh0vtf`**). **Prev S68** — admin **`CNUv1jxY`** · user **`CpOskeS1`** (S68 — Run #304 `37752eb` fix tên đen→trắng; chuỗi #303 `6983609` `D532XZKG`/`CuFaBoWt` → #304 **`CNUv1jxY`**/**`CpOskeS1`**, cicd PASS each). **Prev S67** — admin `CcrZqfht`/user `DniDFUB_` (S67 — 6 deploy Run #297→#302; admin rotate chuỗi #298`xkSz9BfE`→#300`PxiZQkaw`→#301`I1fpLeYw`→#302**`CcrZqfht`** · user #297`BumgrwCJ`→#300`B36hGoKd`→#301`DrQYkzh0`→#302**`DniDFUB_`**; #299 tests BE-only cả 2 frozen, cicd PASS each). **Prev S65** — admin `BDwV5d0X`/user `DbVv6rsf` (Run #293-295). Prev S62 admin `0xKYGhhf`/user `C81ZdG9G` (Run #286). **Prev S59:** admin `B1DtNT9C` · user `D6uF3Mln` (Run **#282** `792c030` FINAL — bỏ nút Thêm hạng mục; ships kèm `80b64dd` gỡ Điều khoản TT, #281 cancelled-benign ancestor-verified). Chuỗi S59 cùng ngày: #280 `69997da` (`BKy_8OO9`/`XcZ6PRyA`, ships kèm `f21c55d` table-fixed #279-cancelled) · #278 `9c330d2` self-approve+quick-add-NCC (`BSh2fG2X`/`D22KfpPc`, authz probe 4/4) · #277 `faed59f` SearchableSelect (`ex7Tc92G`/`DzUeSk96`) · #276 `c869d26` rename 71 PMH (`BBA0KSWu`/`DzdTI18G`) · #275 `bbd1554` dọn demo WorkItems (FROZEN BE-only) · #274 `0eafcd3` tree 4 tầng (`DuU7OTym`/`DWyeTzf3`) · #273 `56882ac` wipe + tree v1 (`R9uGRxvw`/`DikfX1RD`). Prev S58: Run #386 `3ebaf84` admin `DMm9rtNA`/user `BUkOMn_Y` (chi tiết session log S58). **Phase:** ✅ Phase 10 COMPLETE · ✅ **Phase 11 product backlog ĐÓNG TRỌN** · ✅ **Văn phòng số (E-Office) golive S69** (foundation PURO + re-skin 10 page + public read+create 16-key allow-list mọi role) prod-verified · ✅ **PE cờ gấp PRO/CCM + CCM duyệt-final theo ngưỡng (Mig 53 S69)** prod-verified · ✅ **PE ngân sách MA TRẬN 3 cột Dự án/PRO/CCM (bảng lưới `
`) + badge quyền-NS theo role trong Workflow Designer & flow Duyệt NCC (Mig 56 S76)** prod-verified · ✅ **PE UX batch S77 (10 deploy)** — cờ GẤP pill mọi danh sách+inbox · focus/inline+overlay decouple+"Xem mở rộng" · ô ghi chú giá đề xuất PRO/CCM (Mig 57) · số phân cách + số-âm-đỏ-ngoặc + indent mục con · cờ gấp GẮN=NV/GỠ=Trưởng phòng · chuông báo người duyệt · banner Trả-lại — prod-verified · ✅ **PE đính kèm file khi DUYỆT (S78, Run #330)** — người duyệt tải file lên lúc duyệt thay vì Trả lại; migration-free reuse-enum `ApprovalAttachment=5` — prod-verified · 🚫 Phase 9 Ops blocked (anh main coordinate — anh dừng). > ⚠️ **Count drift fixed S40:** endpoints ~223→**211**, FE pages 53→**65**, menu keys 85→**~53**. Tables **84 confirmed correct** (DbSet 77 + Identity 7). 3 số "khó fake" (mig/gotcha/git) luôn đúng. Cause: số "incremented mỗi session" over/under-count optimistic — re-ground định kỳ. diff --git a/docs/changelog/migration-todos.md b/docs/changelog/migration-todos.md index 7dd4a36..3de57b7 100644 --- a/docs/changelog/migration-todos.md +++ b/docs/changelog/migration-todos.md @@ -1,7 +1,7 @@ # Migration To-dos — Atomic Roadmap > Tick `[x]` khi xong. Phase 0-8 đã DONE — collapsed. Detail xem session -> logs trong `docs/changelog/sessions/`. Active work: Phase 9 (UAT + Ops + carry over PE PDF export + Tests Phase 3-5). +> logs trong `docs/changelog/sessions/`. **Active work (@S168): chuỗi K SP-002 (B4) — 7/8 wave K1→K7 SHIP @S164-S167, GĐ3 đồng-nhất BLOCKED chờ owner slot (63), K8-prep còn; mạch sống = `.claude/WAL.md` + STATUS dòng CURRENT (§Phase 12 dưới).** Lineage treo: Phase 9 carry-over PE PDF export. ## ✅ Phase 0-5 + Tier 3 — Done (2026-04-21..22) @@ -795,9 +795,10 @@ Cron task `solution-erp-skill-audit-monthly` fire 9:00 AM ngày 1 mỗi tháng. 6. **Permission leaf 50 NEW** — admin Designer phải seed cẩn thận tránh broken inheritance tree (gotcha #35) 7. **FullCalendar lib new dep** cho G-O2 + G-O5 + G-P1 — skill `dependency-audit-erp` chạy trước commit -## 🎯 Phase 12 — Dry-run TOÀN TRÌNH đến Hợp đồng cứng (S160-S162) — 6/8 wave DONE +## 🎯 Phase 12 — Dry-run TOÀN TRÌNH đến Hợp đồng cứng (S160→S167, nhãn cập-nhật @S168) — 6 wave nền DONE + chuỗi K SP-002 7/8 SHIP > Pipeline owner giao @S160: *"dry-run luôn cho đến hợp đồng cứng"* → plan-cha + 7 spec-wave (`runs/2026-07-29-S160-khkk-dryrun-plan/`) qua 2 vòng review (`/fable-clone` 6 lane → `/fable-real` chốt cuối GO-WITH-FIXES). **GATE 5-ANCHOR bắt buộc trước mỗi wave** (≥1 anchor trượt ⇒ chấm lại toàn bộ anchor của wave). +> 🔄 **@S168:** chuỗi K SP-002 (B4 fan-out — KHÁC bộ W1-W8 dưới) đã SHIP **K1→K7** @S164-S167 (`50e6d8c`→`aaed699`, Mig 70/71, suite **639**, bridge KHKK→HĐ live) — sổ chi-tiết = `.claude/WAL.md` + `docs/STATUS.md` dòng CURRENT + run-trace `runs/2026-07-31-S164-4gd-khkk-fanout/`. GĐ3 đồng-nhất (dòng dưới) BLOCKED chờ owner 2-quyết slot **(63)**. - [x] **W1 — Schema + Designer** `a8027c0` · Mig **69** `AddContractSigningPlans` (7 bảng, SQL tables 89→96) · cicd PASS 6/6 · suite 566 - [x] **W2 — CRUD + nhập** `6cbc6ad` · 15 action policy + Dossier + picker PE THẬT (`PE/2026/A/045`) · cicd PASS 6/6 · suite 574 @@ -808,7 +809,7 @@ Cron task `solution-erp-skill-audit-monthly` fire 9:00 AM ngày 1 mỗi tháng. - [ ] 🔴 **BLOCKER — chốt NGƯỜI DUYỆT 3 trạm PRO/CCM/CEO** (18 user prod; quyền owner, HANDOFF slot **(54)**) ⇒ dựng 2 workflow type-3 + type-10 qua **Designer UI** (KHÔNG SQL tay — gotcha #84) → verify GET matrix - [ ] **W5 — Cầu KHKK→HĐ** (spec `spec-wave-w5-cau-khkk-hd-29-07-2026.md`; §③-C **CẤM** tạo HĐ `HopDongMuaBan`) — chặn bởi BLOCKER trên. Vá luôn **F-2**: phiếu liên-danh N-HĐ hiện chỉ nối HĐ[0] (`CreateContractFromEvaluationFeatures.cs:145`) - [ ] **E2E toàn trình** PE `PE/2026/A/045` → KHKK → HĐ → bản cứng; re-curl `hasSealedCopy` đóng treo cicd N=0 (Contracts prod hiện **0**) -- [ ] **Trang GĐ3 của cây 4-folder** (owner nói *"áp CẢ các trang GĐ khác"*, lead giao 3/4 — HANDOFF slot **(55)**) +- [ ] **Trang GĐ3 của cây 4-folder** (owner nói *"áp CẢ các trang GĐ khác"*, lead giao 3/4 — HANDOFF slot **(55)**) · 🔄 @S167 anh chốt (55) *"Nên đồng nhất"* → lane scaffold BLOCKED-SẠCH 0-file-chạm chờ 2-quyết **(a)** trang-đích fe-user + **(b)** phương-án A/B/C/D (lane+lead nghiêng C) — `runs/2026-07-31-S164-4gd-khkk-fanout/sub-implfe-gd3.md` §1 + HANDOFF slot **(63)** - ⏸️ **W8 — Siết authz HĐ**: owner chốt **O-A "để mở, không siết"** @S160 (đúng ❹ *"đang phát triển → cho hiển thị hết để mọi người góp ý"*) ⇒ **gỡ khỏi dry-run**, rủi ro disclose có ý thức. Gồm cả lỗ hổng S156 (`ContractWorkflowService.cs:49-66` Reject-trước-guard + controller `[Authorize]` trần) + F-10 attachment owner-check. ## 📦 Post-launch (Phase 11+ — future, defer Phase 10 done) diff --git a/docs/gotchas.md b/docs/gotchas.md index ada5d73..8d6d782 100644 --- a/docs/gotchas.md +++ b/docs/gotchas.md @@ -1386,6 +1386,14 @@ for h in resp.points: # ← .points không phải iterable trực tiếp **Đo trước khi tin:** Dev DB 13/13 role đều có `Contracts=1 ∧ KeHoachKyKet=1` ⇒ ca này **chưa lộ**; nó chờ đúng 1 lần chỉnh ma-trận quyền. Lớp lỗi "chưa vỡ vì dữ-liệu hiện tại may mắn" phải vá ngay, không đợi triệu chứng. +### 86. Hai push sát nhau — Gitea auto-CANCEL run đầu: CANCELLED ≠ FAIL, verifier đọc run CUỐI của range (Session 167) + +**Triệu chứng:** K7 `aaed699` push xong, governance `628132c` push sát sau. Run Gitea Actions của `aaed699` chuyển **CANCELLED** → tra run theo commit thấy như deploy fail, trong khi **K7 ĐÃ LIVE**: ship qua run **#442** của push sau (checkout HEAD ⊇ K7). cicd-K7 verify artifact-level xác nhận: bundle rotate ×2 app + marker 8/8 + seeder log `"0 added + 2 upgraded"` + CanCreate 1→3 — live sạch. + +**Cơ chế:** Gitea auto-cancel run đang chạy/queued của CÙNG branch khi push mới tới ⇒ (a) **không bảo-đảm tồn tại verdict per-commit** — run-theo-commit có thể chết cơ-chế chứ không phải lỗi build; (b) kỳ vọng "N push = N deploy/restart" SAI — run đầu bị cancel KHÔNG deploy ⇒ side-effect @startup (seeder/revoker/migration) chỉ chạy **1 lần** cho cả cụm push; đếm restart theo số push là đếm ảo (liên #84 3-chân-kiềng: chứng restart phải đo `w3wp` StartTime, không đếm push). + +**Fix:** (1) Verifier đọc run **CUỐI của commit-range** (run của push mới nhất — HEAD chứa mọi commit trước), CANCELLED giữa range = cơ-chế, KHÔNG phán fail; (2) bằng-chứng ship lấy ở **artifact-level** (bundle-hash rotate + marker set + seeder log + smoke), không ở nhãn run per-commit; (3) cần verdict/side-effect per-commit riêng (vd đo seeder từng đợt) → giãn push hoặc re-run tay. Nguồn: `runs/2026-07-31-S164-4gd-khkk-fanout/sub-cicd-verify-k7.md` M0/M4. + ## Checklist debug bug mới 1. Build pass không? → fail → check using + package version compat @@ -1422,3 +1430,4 @@ for h in resp.points: # ← .points không phải iterable trực tiếp 31. Nếu `git commit -m` qua PS 5.1 báo `error: pathspec 'xxx' did not match` với message tiếng Việt có `"` → native-arg escaping vỡ tại quote kép → Write message ra file UTF-8 + `git commit -F ` (#59) 32. Nếu thao tác theo-email/code trên data prod (lock/seed/migrate) trả 0 row affected → DUMP bảng env đích trước khi nghi code — population Dev ≠ prod (seed silent-fail `IdentityResult` không throw) (#60) 33. Nếu thêm enum value vào entity DÙNG-CHUNG mà UI/guard phân-loại sai (file lẫn section / false-pass guard) → grep MỌI predicate field-proxy (`supplierId===null`...) loại value mới + build-verify TỪNG app riêng (#71) +34. Nếu Gitea Actions run CANCELLED ngay sau khi push 2 commit sát nhau → auto-cancel cùng-branch: đọc run CUỐI của range + verify artifact-level (bundle/marker/seeder-log), KHÔNG đọc CANCELLED thành deploy-fail; side-effect @startup chỉ chạy 1 lần cho cả cụm (#86) diff --git a/docs/governance/README.md b/docs/governance/README.md index 7173fd9..d66f288 100644 --- a/docs/governance/README.md +++ b/docs/governance/README.md @@ -2,7 +2,7 @@ > **Pattern:** Path B — Delegation stub (VIPIX pattern per v1.3 §4.1) > **Adopted:** 2026-05-26 -> **Status:** ✅ Active trial week 1-4 (2026-05-26 → 2026-06-23) +> **Status:** ✅ Adopted — trial week 1-4 (2026-05-26 → 2026-06-23) **ĐÃ ĐÓNG**; RAG delegation đang phục-vụ thường-trực (2 trục service-liveness / index-freshness → `docs/STATUS.md` row "RAG chunks"). *(Lật nhãn @S168 — H24-DEEP FLAG-11: header treo thì-hiện-tại cho cửa-sổ đã qua 39 ngày.)* ---