From 2305c39019db2f1ec55ee78f726a5639e79dcc24 Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Sat, 1 Aug 2026 16:51:09 +0700 Subject: [PATCH] wal: flush 20260801T1651 --- .claude/WAL.md | 26 ++- .claude/agent-memory/memory-budget.json | 6 +- .claude/agent-memory/reviewer/MEMORY.md | 35 ++-- .../agent-memory/reviewer/archive/2026-07.md | 5 + .../sub-k8-dryrun.md | 54 +++++ .../sub-reviewer-gate-gd3d.md | 187 ++++++++++++++++++ .../sub-reviewer-gate-lineeditor.md | 9 + 7 files changed, 296 insertions(+), 26 deletions(-) create mode 100644 .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-k8-dryrun.md create mode 100644 .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-gd3d.md create mode 100644 .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-lineeditor.md diff --git a/.claude/WAL.md b/.claude/WAL.md index 8afc890..201d6bf 100644 --- a/.claude/WAL.md +++ b/.claude/WAL.md @@ -17,17 +17,27 @@ chain: 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 +[!] 🔴 OWNER TRẢ @S168 16:4x (verbatim: "D cây-thay-Panel-3. / Cứ mở rộng đi nhé. / Chạy dry-run hết luôn đi + rồi tao giao tiếp plan khác") ⇒ (63)(b)=**D cây-thay-Panel-3** · "mở rộng" lead KHAI CÁCH HIỂU 2-tầng: + (a)=CẢ-3-trang fe-user + (59)=mở-rộng-nguồn-tiep_reload [anh bác tầng nào thì đảo] · MANDATE MỚI: GĐ3-D + xong → CHẠY LUÔN K8 dry-run toàn trình, không dừng chờ; xong anh giao plan khác +[x] GĐ3-D SHIP-local `081557b` (3 trang Panel-3 + khuôn +bodyMaxHClass F-1, SHA-pair 7baf6247; WorkflowMatrixView + KHÔNG áp khai chủ-đích) · gate PASS-WITH-FLAGS-10/0-blocker (garble→resume; disposition từng dòng trong + sub-reviewer-gate-gd3d.md) · suite 642/0 (45D+597I) + build ×2 PASS · CHƯA push (tránh #86 — push 1 lượt) +[!] K8-BLOCKER Lines-editor vá xong CODE (UpdateContractSigningPlanLineCommand + PUT lines/{lineId} + FE select + ×2 SHA-pair 21e0ca05 + 3 Fact xanh — 2 Fact đầu fail FK ApproverUserId-cần-row-thật, đã sửa) · gate + ĐANG CHẠY NỀN → commit → push 1-lượt cùng GĐ3-D → cicd — sub-k8-dryrun.md + sub-reviewer-gate-lineeditor.md +[!] K8 dry-run: B0 PASS trọn (backup 26,6MB C:\Backups · roster LIVE 3 workflow · form-14-dòng đủ chủ · login + admin OK · catalog 86/N4 · Contracts prod 0 · dữ-liệu-test 0 → GĐ0 tạo mới) · script k8run.py (scratchpad, + state-JSON ghi ID từng bước) sẵn stages gd0→pe→khkk→bridge→hd→qd9 — CHẠY SAU KHI deploy line-editor xanh +[ ] K8-prep + dry-run toàn trình: 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 +[ ] (59) thi-hành: mở rộng tiep_reload.sources (đo trước-sau, khoanh phạm-vi từng nguồn, khai vết owner-answer) [ ] 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ả 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. +next: GĐ3-D (đọc sub-implfe-gd3 §phương-án-D → scaffold 3 trang → gate → commit → cicd) → (59) → K8 dry-run + → báo anh nhận plan mới. Drift-audit xếp sau mandate. verify: head -1 .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-implfe-gd3.md # IMPLFE-GD3: BLOCKED diff --git a/.claude/agent-memory/memory-budget.json b/.claude/agent-memory/memory-budget.json index 1face86..c57dc44 100644 --- a/.claude/agent-memory/memory-budget.json +++ b/.claude/agent-memory/memory-budget.json @@ -12,12 +12,16 @@ "tiep_reload": { "_note": "🔄 @S153 adopt 0df10df4 khoan (37) RESOLVED (b) — nap-lai NEN RUT-GON mac dinh @/tiep (OWNER-DELEGATED cung vet _mind_ctx_kb_set). Nen-full SE do tuoi @S153 = 596.316B ~ [149.079..198.772] tok (instrument-backfill S153) — nang hon nen hub (439.328B ~ 110K tok) 1.36x, nuot tron rang mem ~150K/cua cua hub-owner neu full => rut gon ~ 40-60K tok (input one-shot cache-duoc). Reader = nghi-thuc /tiep (AI doc danh sach nay qua tiep.md §3-bis TRO KHOA — B1 lenh KHONG chep danh sach); KHAI THANG: chua co script-consumer — KHAC class ghost-wire vi hanh-vi tieu thu moi luot /tiep + dogfood T9 do that. Pham-vi tung muc khoanh ngay trong sources (khuon hub 'do theo pham-vi tung muc da khoanh trong cau-hinh').", "mode": "rut-gon", + "_expand_S168": "🔄 OWNER-ANSWER @S168 2026-08-01 (slot 59; anh: 'Cứ mở rộng đi nhé' — lead khai cách hiểu 2-tầng trong turn, tầng-(59) = MỞ RỘNG danh-sách nguồn; anh bác thì revert 3 dòng cuối sources). Đo đúng-phạm-vi TRƯỚC = 132.449 B ~ [33K..44K] tok (cận-dưới < sàn 40K; mốc 120.633 B @S166 là trước khi segment HANDOFF mới land) → THÊM 3 nguồn khoanh-phạm-vi (+49.711 B) → SAU = ~182.160 B ~ [45K..61K] tok = NẰM TRỌN dải 40-60K. 🔴 3/5 nguồn gốc phình theo phiên — CẤM neo literal, nghi under/over-fill thì đo lại bằng đúng phạm-vi từng mục (bài H24-DEEP F-8 + ring2-bác @S166).", "sources": [ "docs/STATUS.md :: dong CURRENT + bang CURRENT STATE (KHONG ca file)", "docs/HANDOFF.md :: segment Last-updated MOI NHAT (KHONG ca file)", ".claude/WAL.md :: tron (<=40 dong by-design)", ".claude/sessions/session-/_mind-s-.md :: tron (doc TU TREN XUONG)", - ".claude/sessions/session-/_context-s-.md :: tron" + ".claude/sessions/session-/_context-s-.md :: tron", + ".claude/governance/ACTIVE-MARKS.md :: tron (bang marks dang hieu luc — +S168 slot 59)", + "docs/gotchas.md :: 5 section ### N. MOI NHAT (KHONG ca file — +S168 slot 59)", + "docs/changelog/migration-todos.md :: header Active-work + section Phase hien hanh (KHONG ca file — +S168 slot 59)" ] }, "hmw_width": { diff --git a/.claude/agent-memory/reviewer/MEMORY.md b/.claude/agent-memory/reviewer/MEMORY.md index 52202ab..4219a04 100644 --- a/.claude/agent-memory/reviewer/MEMORY.md +++ b/.claude/agent-memory/reviewer/MEMORY.md @@ -1,17 +1,19 @@ # Reviewer Agent — Persistent Memory -- **[→ archive/2026-07.md — verbatim ĐÃ VERIFY moved-not-cut 3/3 @S166-K5-curate] S166 gate K4b · K4a · vá F-1 (digest):** mỏ-neo XUYÊN FILE (quét file BỊ DỜI, không chỉ file đang sửa) · **tham-số-trang-trí** (đo AI ĐỌC từng param, đừng đo "route có tồn tại") · mỏ-neo tự-vô-hiệu ngay lúc land (đo SAU khi chèn) · **ô canonical sai đo được bằng 1 curl** · khuôn-nguồn 2 tầng ⇒ đo **GIÁ-TRỊ KHỞI-TẠO** không đọc chú-thích · **cây phình giữa review** ⇒ neo mốc + re-đo `--stat` TRƯỚC verdict · HIGH-nằm-ở-git (`git status --porcelain -- src tests | grep '^??'`) · khoá-cache định-danh REQUEST không định-danh URL · sợi-dây-1-argument 0 test. +- **[→ archive/2026-07.md §@S166-K5-curate — verbatim] S166 gate K4b · K4a · vá F-1 (digest):** mỏ-neo XUYÊN FILE · **tham-số-trang-trí** (đo AI ĐỌC từng param) · mỏ-neo tự-vô-hiệu ngay lúc land · ô canonical sai đo được bằng 1 curl · khuôn-nguồn 2 tầng ⇒ đo GIÁ-TRỊ KHỞI-TẠO · **cây phình giữa review** ⇒ re-đo `--stat` TRƯỚC verdict · HIGH-nằm-ở-git (`git status --porcelain -- src tests | grep '^??'`) · khoá-cache định-danh REQUEST không định-danh URL. -- **[→ archive/2026-07.md §@S167-K7-curate — verbatim ĐÃ VERIFY moved-not-cut 2/2] S166 gate K5 cây-GĐ2-8-sub-folder · gate K4c cụm-2 (digest):** bất-biến Σ do CẤU TRÚC (1 nguồn → phân hoạch TOÀN PHẦN → 1 chỗ đếm) · **phép-đo-rẻ-nhất nằm ở file RÁC của lane khác** (`menus.json` untracked = payload prod LIVE, vừa là bằng-chứng vừa là rào-commit) · chân-lý-RỖNG phải khai là rỗng · tương-đương-TỪNG-VẾ > 'cùng tập cùng thứ tự' · tiền-lệ phải đo ở BASE không đo ở cây đã sửa · 'N/N OK' chết theo phiên khi FE 0 hạ-tầng-test · **flake chỉ lộ ở LƯỢT ĐẦU và `-v q` NUỐT thông điệp assert** (lượt đầu dùng verbosity thường) · probe RED bằng đổi TEST-INPUT hợp lệ CHỈ KHI tham số xuất hiện ĐÚNG 1 chỗ (grep trước) · `Total` là vân-tay lọc-SERVER chỉ khi `CountAsync` sau `Where` trước `Skip/Take`. +- **[→ archive/2026-07.md §@S167-K7-curate — verbatim ĐÃ PROBE moved-not-cut] S166 gate K5 cây-GĐ2-8-folder · K4c cụm-2 (digest):** bất-biến Σ do CẤU TRÚC · **phép-đo-rẻ-nhất nằm ở file RÁC của lane khác** · chân-lý-RỖNG phải khai là rỗng · tương-đương-TỪNG-VẾ > 'cùng tập' · tiền-lệ đo ở BASE không ở cây đã sửa · 'N/N OK' chết theo phiên khi FE 0 hạ-tầng-test · **flake chỉ lộ ở LƯỢT ĐẦU và `-v q` NUỐT assert** · probe RED bằng đổi TEST-INPUT chỉ khi tham số xuất hiện ĐÚNG 1 chỗ · `Total` là vân-tay lọc-SERVER chỉ khi `CountAsync` sau `Where` trước `Skip/Take`. -- **[→ archive/2026-07.md §@S167-K7-curate-2 — verbatim ĐÃ VERIFY moved-not-cut] S167 gate K7 cầu KHKK→HĐ — PASS-WITH-FLAGS 10, 0 blocker (digest):** **1 con số đóng 2 câu hỏi** — baseline 622 (đo ở K4c cùng ngày) + 17 `[Fact]` đếm được = 639, đo đúng **639/0** ⇒ chứng CẢ '17 test chạy thật, không skip câm' LẪN '0 test cũ vỡ'. **Mỏ-neo tự-vô-hiệu tái phát, lan 3 nơi**: chú thích trỏ `:2516` — `git show HEAD:|grep -n`=2516 vs `grep -n` cây=**2523**, chính diff chèn 7 dòng đẩy xuống ⇒ phải đo **2 THẾ GIỚI (HEAD ⟂ cây)**, đo 1 thế giới là im. **Prod probe sửa con số của chính comment**: `/permissions/by-role/{id}`×13 vai → `Contracts.CanCreate` **1/13** ⇒ tiền-đề lỗ ĐÚNG, nhưng '13/13 role' sai (thật 12/13, Admin đã có row True) + đẻ acceptance sau-deploy `0 added + 2 upgraded`. **Răng phủ NỬA**: T11 double-click assert 4 vế nhưng `await` tuần tự ⇒ ca ĐỒNG THỜI vẫn hở (0 unique-index/RowVersion/transaction) — đừng đọc 'có T-idem' thành 'đã đóng'. **Ngoại lệ authz đúng cách**: map khớp TUYỆT ĐỐI + action ngoài map vẫn bị đòi prefix ⇒ tương-lai không tự miễn-trừ; kèm `BeSubsetOf` chống cấu-hình-chết. **SHA-identical KHÔNG bảo chứng route-identical** (3 path cứng `/contracts/${id}` trong file mirror 2 app ⇒ grep route CẢ 2). Tag `[s167, mot-so-dong-2-cau-hoi, moneo-tu-vo-hieu, probe-sua-so-cua-comment, rang-phu-nua, sha-khong-bao-chung-route]` **Evidence:** `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k7.md` +- **[→ archive/2026-07.md §@S167-K7-curate-2 — verbatim ĐÃ PROBE moved-not-cut] S167 gate K7 cầu KHKK→HĐ — PASS-WITH-FLAGS 10 (digest):** **1 con số đóng 2 câu hỏi** (639 = 622 baseline + 17 `[Fact]` ⇒ chứng CẢ 'chạy thật' LẪN '0 test cũ vỡ'). **Mỏ-neo tự-vô-hiệu** — comment trỏ `:2516` nhưng cây đã là `:2523` do chính diff đẩy xuống ⇒ phải đo **2 THẾ GIỚI (HEAD ⟂ cây)**. **Prod probe sửa con số của chính comment** (13/13 role → thật 12/13). **Răng phủ NỬA**: T11 assert 4 vế nhưng `await` tuần tự ⇒ ca ĐỒNG THỜI vẫn hở. **SHA-identical KHÔNG bảo chứng route-identical** ⇒ grep route CẢ 2 app. Tag `[s167, mot-so-dong-2-cau-hoi, moneo-tu-vo-hieu, rang-phu-nua]` -- **[→ archive/2026-07.md §@S167-K7-curate-2 — verbatim ĐÃ VERIFY moved-not-cut] S167 gate K6 admin thu-gọn — PASS-WITH-FLAGS 5 (digest):** **cây menu PROD SỐNG là thước, seed chỉ là bản vẽ** (`curl /api/menus/me` + áp CHÍNH tập key cắt regex từ file đã ship; control-âm bỏ 1 key để chứng phép đo có phân biệt). **`filterForAdmin` mới là bước MỘT** — còn `resolvePath→null` drop im lặng (#50) + group rỗng-hoá tụt xuống render như LEAF. **typo-noop**: key ẩn sai chính tả = `Set.has` false, module vẫn hiện, tsc vẫn xanh ⇒ assert TỪNG key TỒN TẠI trong cây prod. MAJOR: comment nhồi 3 số-đếm, 1 số sai ngay lúc land (số chép từ skill stale) ⇒ CẤM số-đếm trong comment. **Evidence:** `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k6.md` +- **[→ archive/2026-07.md §@S168-curate — verbatim ĐÃ PROBE moved-not-cut] S168 gate GĐ3-D cắm cây vào Panel-3 ×3 trang — PASS-WITH-FLAGS 10, 0 blocker (digest):** **khuôn dùng-lại phải ĐO LẠI theo HOST** — `max-h`/`sticky` hiệu-chỉnh cho host CŨ: cây cần 100vh−158 mà Panel-3 chỉ có 100vh−184 (InboxPage) ⇒ 2 thanh cuộn lồng; 2 trang kia thừa 5px/13px = khít đến mong manh. **Class chết ÂM THẦM khi đổi kiểu cha** (`self-start` cha `block` · `lg:sticky` con DUY NHẤT của chính scroll-container) — tsc+build KHÔNG bắt, chỉ đọc CSS-chain mới thấy. `aside` lồng `aside` CÓ `aria-label` vẫn giữ `role=complementary` ⇒ 2 landmark lồng. Prod-probe biến lo-ngại thành số: `canPe` 13/13 True ⇒ ca `!canPe` chưa xảy ra (control-âm `Permissions`/`Users` False 12/13). `{!selectedId && }` = unmount ⇒ mất state thuần (`search`) trong khi `localStorage` sống ⇒ trade-off spec khai THIẾU. Thước hỏng: python Windows đọc JSON phải khai `encoding` · `while read` bỏ dòng CUỐI khi thiếu newline · `join` text-mode đẻ CRLF vào tên file. Tag `[s168, khuon-do-lai-theo-host, class-chet-am-tham, unmount-mat-state]` -- **[→ archive/2026-07.md — verbatim ĐÃ VERIFY moved-not-cut 4/4 @S166-curate] S164/S165 gate K3 · S164 gate K1 · S162 cây-4-folder · S161-W2 KHKK-CRUD (digest):** tham-số-chết-vì-thiếu-tầng-UI (đo TẦNG-CUỐI ai GỬI) · sweep 2-cờ bất-đối-xứng · flake ⇒ "N/0 tươi" phải khai SỐ LƯỢT · giá-trị lớn nhất ở GATE QUY-TRÌNH không ở mã · **ghost-policy** (grep policy, đừng suy từ "key đã vào All") · default-lấn-ngữ-nghĩa · im-lặng-về-độ-chính-xác-của-con-số ×3/diff · **#82 ngược chiều** (FE OR nhiều key LỎNG HƠN policy khớp-CHÍNH-XÁC-1-key ⇒ tự chuốc 403) · hợp-đồng FE↔BE VỠ 6 điểm mà tsc+build+574-test XANH (2 lỗi CHE NHAU) ⇒ so ROUTE+FIELD trên ĐĨA. +- **[→ archive/2026-07.md §@S167-K7-curate-2 — verbatim] S167 gate K6 admin thu-gọn — PASS-WITH-FLAGS 5 (digest):** **cây menu PROD SỐNG là thước, seed chỉ là bản vẽ** (`curl /api/menus/me` + control-âm bỏ 1 key). **`filterForAdmin` mới là bước MỘT** — còn `resolvePath→null` drop im lặng (#50) + group rỗng-hoá render như LEAF. **typo-noop**: key ẩn sai chính tả = `Set.has` false, module vẫn hiện, tsc vẫn xanh ⇒ assert TỪNG key TỒN TẠI trong cây prod. MAJOR: CẤM số-đếm trong comment. -- **[→ archive/2026-07.md — verbatim, verify moved 5/5 @S166-curate] S159-đợt5 · S161-W1 · S155-đợt2 · S145-4lane · S143 · S139 · S134b · S133 · S146/S147/S152-D2 (digest gộp):** chú-thích-mang-SỐ phải chạy phép đếm · cookie-cutter soi CẢ phần bản gốc đã CHẶN · `tsc`+`noUnusedLocals` > grep cho claim 'đã cắt' · comment 'bên kia lo' = ĐI ĐỌC BÊN KIA · grep bằng TOKEN-SONG-SINH · `hợp-đồng-đứt-2-bờ` · đổi-chiều-assert ≠ nới-assert · bất-biến chia-đôi 2-axis chỉ cross-cut sweep bắt · `bằng-chứng-tự-huỷ-sau-squash` · re-measure acceptance từ git HEAD + no-self-exempt · 'mọi nhánh set X' phải grep assignment-qua-BIẾN (#81) · `ExecuteDelete` ngoài transaction = mất dữ liệu · xanh-giả bắt bằng phép 2-thế-giới · 3 THƯỚC-HỎNG (md5 CRLF · `grep -c` citation-trap · `grep -iF` MSYS 0-hit im lặng). +- **[→ archive/2026-07.md §@S166-curate — verbatim] S164/S165 K3 · S164 K1 · S162 cây-4-folder · S161-W2 (digest):** tham-số-chết-vì-thiếu-tầng-UI (đo TẦNG-CUỐI ai GỬI) · sweep 2-cờ bất-đối-xứng · flake ⇒ 'N/0 tươi' phải khai SỐ LƯỢT · **ghost-policy** (grep policy, đừng suy từ 'key đã vào All') · **#82 ngược chiều** (FE OR nhiều key LỎNG HƠN policy khớp-CHÍNH-XÁC-1-key ⇒ tự chuốc 403) · hợp-đồng FE↔BE VỠ 6 điểm mà tsc+build+574-test XANH ⇒ so ROUTE+FIELD trên ĐĨA. + +- **[→ archive/2026-07.md — ĐÃ RE-PROBE @S168: nội-dung CÓ trong archive; 2 nhãn `S161-W1`/`S152-D2` 0-hit nên GIỮ ở đây] S159-đợt5 · S161-W1 · S155-đợt2 · S145-4lane · S143 · S139 · S134b · S133 · S146/S147/S152-D2 (digest gộp):** chú-thích-mang-SỐ phải chạy phép đếm · cookie-cutter soi CẢ phần bản gốc đã CHẶN · `tsc`+`noUnusedLocals` > grep cho claim 'đã cắt' · comment 'bên kia lo' = ĐI ĐỌC BÊN KIA · grep bằng TOKEN-SONG-SINH · `hợp-đồng-đứt-2-bờ` · đổi-chiều-assert ≠ nới-assert · `bằng-chứng-tự-huỷ-sau-squash` · 'mọi nhánh set X' phải grep assignment-qua-BIẾN (#81) · `ExecuteDelete` ngoài transaction = mất dữ liệu · 3 THƯỚC-HỎNG (md5 CRLF · `grep -c` citation-trap · `grep -iF` MSYS 0-hit im lặng). > **Persistent diary cross-session.** Auto-injected first ~200 lines at spawn (L1 HOT). > Update BEFORE every stop. Tiered Memory v1: L1 HOT cap ~17KB (hook 24.4KB read-limit) · L2 `archive/` on-demand · L3 RAG `search_memory` just-in-time. Keep entry ≤ 1.5K chars (gotcha #53). @@ -20,18 +22,18 @@ - **[→ archive/2026-07.md @S161-curate] S160 (07-29) CHỐT-CUỐI 13-fix:** fix áp NỬA spec = dư-lượng (soi CẢ FILE khi nhận 'đã fix') · anchor-list là artifact RIÊNG phải sync · verify NGƯỢC premise · owner để-mở ⇒ finding MOOT-đúng. ## 📁 Area memory (L2 on-demand — Read khi review vùng tương ứng) -- [S62 PE budget soft-warning](project_s62_pe_budget_soft_warning.md) — PASS: hard-block→soft-warning; submit-guard intact + validator giữ `BudgetPeriodAmount>0`, row8 negative-safe (additive-only). Validator class `PurchaseEvaluationFeatures.cs:317`. +- [S62 PE budget soft-warning](project_s62_pe_budget_soft_warning.md) — hard-block→soft-warning, submit-guard intact (additive-only). - [Wire/mirror claim verification anchors](feedback_wire_claim_verification_anchors.md) — sha256 twin-file · `git diff -U0` isolate true-adds · `allowNegative` bleed check · guard-still-intact grep. - **[→ archive @S161-curate] S160 review SPEC-BỘ KHKK:** review SPEC ≠ review CODE · seeder-grant kiểu insert = NO-OP 403 im lặng ⇒ acceptance đo CỜ không đếm ROW · acceptance 'PASS SẴN' = 0-bit · choke-point 'DUY NHẤT' sai vì gán QUA BIẾN (#81). -- **S89 trio** ([sectionB](project_s89_pe_sectionb_review.md) · [endsBeforeCeo](project_s89_pe_endsbeforeceo_plan_review.md) · [finalize-note](project_s89_finalize_note_plan_review.md)) — adjustMut share race + authz-lens ≠ concurrency-lens · FE 4 render-sites plan-missed-2 · ground-truth-accurate-nhưng-gaps. +- **S89 trio** ([sectionB](project_s89_pe_sectionb_review.md) · [endsBeforeCeo](project_s89_pe_endsbeforeceo_plan_review.md) · [finalize-note](project_s89_finalize_note_plan_review.md)) — authz-lens ≠ concurrency-lens; FE 4 render-site, plan sót 2. - **S101 H18/H19 WF2 + LANE-C:** content-hash ≠ commit-SHA (hex strip/no-strip) · exact-token sweep miss paraphrase → widen concept-phrase. → `archive/2026-07.md`. -- [S103 H20+crystallized-backfill review](project_s103_h20_crystallized_backfill_review.md) — WF2 PASS; 6/6 hash recompute MATCH + 4 already-met verified. Lesson: multi-axis warning phải nằm trong OUTPUT của script (reader chạy inline), không chỉ doc. -- [S111 PE sign-off 6-decision design review (schema/history lens)](project_pe_signoff_history_schema_review.md) — GO-WITH-ADJ; D5 opinion-history: append-only table, REJECT version-col (drops UNIQUE + breaks UPSERT). -- **PE per-hạng-mục series ×5** ([cardinality#3](project_pe_multiwinner_perhangmuc_review.md) · [BE-financial](project_s114_pe_multi_ncc_perhangmuc_financial_review.md) · [spec-l3](project_pe_multi_ncc_perhangmuc_specreview.md) · [IMPL](project_s114_multi_ncc_perhangmuc_impl_review.md) · [neg-quote](project_pe_negative_quote_correctness_review.md)) — derived src-of-truth: re-derive MỌI write-path KỂ CẢ Delete · grep field-NGUỒN không chỉ field-đọc · sign-loss: defer-parse tới field-chung mọi mutation. -- [S113 Supplier import v2 close-review (owner anh Kiệt)](project_s113_supplier_import_v2_review.md) — GO-WITH-ADJ 2 must-fix (consumers không pass published=true → drafts leak). Lesson: "filter added" ≠ "drafts hidden" — grep-all-consumer + create write-path. -- [S118 Procurement master-access seeder review](project_s118_procurement_master_access_review.md) — PASS(cond); MAJOR Reports.Read leaks financials + Suppliers.Update grant ≠ edit. Lesson: menu-flag grant ≠ API capability; bare `[Authorize]` GET = open-to-all. -- [S123 governance 4-change review (backtick-guard + H24-3 + retire dạng-3 + mark)](project_s123_governance_4change_review.md) — PASS_WITH_FIXES; CAUGHT H24-3 thiếu enclosure-guard mà cùng diff vừa chứng cần (gen-2 citation-trap) + greedy `.*` lấy `(S` CUỐI≠MAX + lý-do-retire áp cho dạng-2 thì giết C8. Q5 "HOÀN-THÀNH mark" = nguỵ-biện. Q8 ENDORSE không-bump. -- [S147 Project whitespace-dupe merge verify](project_project_dupe_merge_verify.md) — 7/7 PASS(2 FK-terminology corrections); "FK Projects" COMMENT ≠ physical FK (sys.foreign_keys=0 to Projects, all loose-Guid); seed-durability FORCES survivor=no-space blanket; INNER-join+filter=silent-vanish→repoint-before-soft-delete; prod ref-dist unverifiable (Server=localhost+secret). +- [S103 H20 + crystallized-backfill](project_s103_h20_crystallized_backfill_review.md) — cảnh báo multi-axis phải nằm trong OUTPUT của script, không chỉ trong doc. +- [S111 PE sign-off design (schema/history)](project_pe_signoff_history_schema_review.md) — opinion-history append-only; REJECT version-col (phá UNIQUE + UPSERT). +- **PE per-hạng-mục ×5** ([1](project_pe_multiwinner_perhangmuc_review.md) · [2](project_s114_pe_multi_ncc_perhangmuc_financial_review.md) · [3](project_pe_multi_ncc_perhangmuc_specreview.md) · [4](project_s114_multi_ncc_perhangmuc_impl_review.md) · [5](project_pe_negative_quote_correctness_review.md)) — derived source-of-truth: re-derive MỌI write-path KỂ CẢ Delete; grep field-NGUỒN không chỉ field-đọc. +- [S113 Supplier import v2](project_s113_supplier_import_v2_review.md) — "filter added" ≠ "drafts hidden": grep-all-consumer + create write-path. +- [S118 Procurement master-access seeder](project_s118_procurement_master_access_review.md) — menu-flag grant ≠ API capability; `[Authorize]` trần = mở cho mọi user. +- [S123 governance 4-change](project_s123_governance_4change_review.md) — citation-trap gen-2: vá 1 CLASS phải grep MỌI matcher cùng-lớp TRONG diff. +- [S147 Project whitespace-dupe merge](project_project_dupe_merge_verify.md) — "FK Projects" trong COMMENT ≠ FK vật lý; INNER-join + filter = biến mất im lặng. --- @@ -94,8 +96,7 @@ Adversarial pre-commit reviewer SOLUTION_ERP. Read-only verify + live curl prod --- ## 🔄 Curate trigger -- ⚠️ **@S167-K7 curate 2 pass: 22.1KB → 19.0KB** (move verbatim K5·K4c·K7·K6 → `archive/2026-07.md` §`@S167-K7-curate` + §`-curate-2`, mỗi pass probe moved-not-cut + control-âm TRƯỚC khi cắt, 4/4 pass). **CÒN NỢ ~1.9KB** để về 17.1KB — ứng viên kế: gộp khối `📁 Area memory` (nhiều dòng L2 đã stale >2 tháng). 🔴 **no-self-exempt CÓ ÁP**: entry K7 của CHÍNH TÔI là entry to nhất (3081B, phá luật "≤1.5K/entry" của chính file này) ⇒ nén trước, không miễn cho mình. 🔴 **Bài S166-K5 TÁI PHÁT NGAY trong pass này**: digest sinh bằng script đẻ chữ hỏng câm (`'ll3/13'` thay `'13/13'`) — byte-count không bắt được, chỉ ĐỌC LẠI BẰNG MẮT mới thấy. Script sinh chữ = luôn đọc lại output. -- ✅ **NỢ CURATE @S166-K4b ĐÃ TRẢ @S166-K5** (23.4KB→~17KB): move VERBATIM 3 entry đã hẹn (K4b·K4a·vá-F-1) → `archive/2026-07.md` §`@S166-K5-curate`. Trình tự bài S102: **append archive TRƯỚC → probe 3/3 kèm control-âm → assert `line in arc` NGAY TRONG script cắt → mới cắt → hậu-kiểm L1=0/archive=1**. Bài mới: digest sinh bằng escape `\uXXXX` **đẻ chữ hỏng câm** (byte-count không bắt được) ⇒ **script sinh chữ phải ĐỌC LẠI bằng mắt**. +- ✅ **@S168 curate: 22.2KB → <17.1KB (ĐO, không đoán).** Trình tự S102 giữ nguyên: append archive TRƯỚC → probe moved-not-cut + control-âm → mới cắt. 🔴 **Bài mới:** (a) tôi ghi '~20.6KB' bằng ƯỚC LƯỢNG trong khi `wc -c` cho 22.2KB — **số trong sổ phải là số ĐO**, và baseline '19.0KB' thừa kế từ pass trước cũng đã stale; (b) probe moved-not-cut bằng token lấy từ DIGEST cho **0-hit GIẢ** (digest là paraphrase, bản gốc dùng chữ khác) ⇒ 0-hit phải **thử token thứ 2 từ thân bài** trước khi kết luận cut-not-moved — suýt giữ lại 938B vô ích; (c) **script sinh chữ lại đẻ chữ hỏng câm** (token `join` trong chuỗi làm entry vỡ đôi dòng) — đúng bài S166-K5, byte-count KHÔNG bắt, chỉ ĐỌC LẠI mới thấy. - Hook-cap **>17.1KB** (24.4KB read-limit, S109) → archive recent → L2 `archive/.md` (append additive) + `_INDEX.md` pointer. Stale >3mo → remove. - **Prev curates:** S166-K5 (probe 3/3) · S162 (2/2) · S145 · S140 · S134 · S128 · **S102 recovery: cut-not-moved ×5 `f229b07` ⇒ mọi L1-shrink kèm '→archive' BẮT BUỘC grep moved-not-cut TRƯỚC khi trust** · S116·S113·S109·S80·S71·S70·S40. diff --git a/.claude/agent-memory/reviewer/archive/2026-07.md b/.claude/agent-memory/reviewer/archive/2026-07.md index 2c4c670..4aa5300 100644 --- a/.claude/agent-memory/reviewer/archive/2026-07.md +++ b/.claude/agent-memory/reviewer/archive/2026-07.md @@ -231,3 +231,8 @@ - **S167 (08-01) gate K7 cầu KHKK→HĐ (13 file, 3 nhóm) — PASS-WITH-FLAGS 10 (2 MAJOR + 7 MINOR + 1 CLARIFY), 0 blocker:** ① 🔴 **1 con số đóng 2 câu hỏi**: baseline 622 (đo ở K4c CÙNG NGÀY) + 17 `[Fact]` mới (đếm `grep -c '^\s*\[Fact\]'`, không chép) = kỳ vọng 639, đo được **đúng 639/0** ⇒ chứng CẢ "17 test có chạy thật (không bị filter/skip câm)" LẪN "0 test cũ vỡ" — rẻ hơn 2 phép đo rời. ② **mỏ-neo tự-vô-hiệu TÁI PHÁT và lan 3 nơi** (K4b-class): 3 chú thích mới trỏ `DbInitializer.cs:2516`; `git show HEAD: | grep -n` = 2516, `grep -n` trên cây = **2523** — CHÍNH diff này chèn 7 dòng ở `:2353-2359` đẩy nó xuống ⇒ đúng lúc viết, **sai ngay khoảnh khắc land**. Bài: phải đo ở CẢ 2 THẾ GIỚI (HEAD ⟂ cây) mới thấy, đo 1 thế giới là im. ③ **prod probe sửa được con số của chính comment**: `GET /api/permissions/by-role/{id}` ×13 vai → `Contracts.CanCreate` **1/13 true (chỉ Admin)** ⇒ tiền-đề seeder ĐÚNG (Drafter/Procurement=False, lỗ THẬT), nhưng comment "403 với 13/13 role… chỉ Admin qua nhờ bypass" sai 2 vế: thật là **12/13**, và Admin **đã có row True** chứ không chỉ bypass. Cùng probe đẻ **acceptance rẻ nhất cho sau deploy: log phải là `0 added + 2 upgraded`** — lệch = có thứ khác lật quyền. Khai giới hạn: prod CHƯA deploy ⇒ chỉ chứng TIỀN-ĐỀ, không chứng seeder chạy đúng. ④ **test có răng nhưng phủ NỬA**: T11 double-click assert 4 vế (Conflict + count=1 + line trỏ HĐ đầu + `LastSeq=1` không đốt mã) — nhưng là `await` lần 1 RỒI lần 2 ⇒ chỉ phủ ca TUẦN TỰ; ca ĐỒNG THỜI vẫn hở (`:128-129` đọc-rồi-ghi trong bộ nhớ, 0 unique-index, 0 RowVersion, 0 transaction bao ngoài — transaction duy nhất là của codegen, đã commit trước). Comment test khai đúng phạm vi ⇒ KHÔNG phải lane nói quá; rủi ro là người sau đọc "T-idem có" thành "idempotency đóng". ⑤ **ngoại lệ authz đúng cách**: map `Dictionary` + `Should().Be()` khớp TUYỆT ĐỐI (không `StartsWith`/skip-list) + action ngoài map vẫn rơi `else` đòi prefix module ⇒ **action tương lai không tự miễn trừ**; kèm `Keys.Should().BeSubsetOf(byName.Keys)` chống **cấu-hình-chết** — vế "vắng-mặt trông giống ổn" mà lane TỰ đặt. ⑥ **mirror byte-identical đẻ rủi ro riêng**: 3 đường dẫn cứng `/contracts/${id}` trong file dùng chung 2 app ⇒ phải grep route ở CẢ `fe-user/App.tsx:65` và `fe-admin/App.tsx:84` (đều có, không thủng) — SHA-identical KHÔNG bảo chứng route-identical. ⑦ residual: 3 `scripts/*.ps1` dirty ngoài cả 13-file-set lẫn lead-set. Tag `[s167, mot-so-dong-2-cau-hoi, moneo-tu-vo-hieu-lan-3-noi, probe-sua-so-cua-comment, rang-phu-nua, sha-khong-bao-chung-route]` **Evidence:** `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k7.md` - **S167 (08-01) gate K6 admin thu-gọn (1 file FE, tập 12 key ẩn) — PASS-WITH-FLAGS 5 (1 MAJOR + 1 CLARIFY + 3 MINOR):** ① 🔴 **cây menu PROD SỐNG là thước, seed chỉ là bản vẽ**: `curl /api/menus/me` (token admin, 44KB) → áp CHÍNH tập key **cắt bằng regex từ file đã ship** ⇒ 200 node · 166 lá → **15 lá**, trùng tên 15/15 + control-âm bỏ `KeHoachKyKet` = 63 (+48) khớp lane. Cùng payload đóng luôn FLAG "row chèn tay": **10 `AwV2*`, 0 `AwV2_Contract`**. Khai giới hạn: endpoint đã lọc-quyền ⇒ row không có Permission thì vô hình (nhưng cũng vô hình trên sidebar ⇒ không lệch C1). ② **`filterForAdmin` mới là bước MỘT**: lá còn "THẤY" phải qua tiếp `resolvePath→null ⇒ MenuLeaf drop im lặng` (#50) và **group rỗng-hoá tụt xuống render như LEAF** (`children.length>0`) — lane bỏ cả 2, tôi đo: 0 drop · 0 rỗng-hoá. ③ **typo-noop**: key ẩn sai chính tả = `Set.has` false, module vẫn hiện, tsc vẫn xanh ⇒ phải assert từng key TỒN TẠI trong cây prod (12/12 OK; control-âm 3 key bịa đều MISS). ④ **MAJOR: comment mới nhồi 3 số-đếm, 1 số SAI ngay lúc land** — "28 leaf `Ct_`" (thật 42 lá/49 key, S155 thêm WfView/Approved/Deleted), số chép từ skill `permission-matrix` stale ⇒ đúng bệnh #84(4) "CẤM số-đếm trong comment". ⑤ **CLARIFY hệ-quả không ai khai**: prod có `Hrm/Off/Personal` `isVisible=false`, fe-user lọc `isVisible!==false` còn fe-admin KHÔNG đọc cờ đó ⇒ admin là lối vào CUỐI, ẩn nốt = 3 module mất menu ở CẢ 2 app. ⑥ display-only chứng 3 tầng: diff (grep `+` chỉ hit COMMENT) < kiến-trúc (`usePermission:15` đọc cây THÔ, chỉ 2 consumer) < curl prod 200×2 endpoint đã ẩn. Tag `[s167, thuoc-la-cay-prod, filter-moi-la-buoc-mot, typo-noop, so-dem-trong-comment]` **Evidence:** `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k6.md` + + +## @S168-curate — verbatim moved from L1 (reviewer MEMORY.md) + +- **S168 gate GĐ3-D cắm cây vào Panel-3 ×3 trang — PASS-WITH-FLAGS 10, 0 blocker (digest):** **khuôn dùng-lại phải đo LẠI theo HOST**, vì `max-h`/`sticky` của khuôn được hiệu-chỉnh cho host CŨ: `lg:max-h-[calc(100vh-16rem)]` cộng header+search = 100vh−158, còn Panel-3 chỉ có 100vh−184 ở InboxPage (dải "Vai trò" +29px) ⇒ **2 thanh cuộn lồng**; 2 trang kia thừa 5px/13px = **khít đến mức mong manh** (đổi 1 Button `h-8`→`h-10` là lật). **Class chết ÂM THẦM khi đổi kiểu cha**: `self-start` (cha `lg:block` không phải flex) + `lg:sticky` (cây là con DUY NHẤT của chính scroll-container ⇒ quãng dính ≈0) — tsc/build KHÔNG bắt được loại này, chỉ đọc CSS-chain mới thấy. **`aside` lồng `aside` CÓ `aria-label` vẫn giữ `role=complementary`** (chỉ tụt `generic` khi KHÔNG tên) ⇒ 2 landmark lồng. Prod-probe biến 1 lo-ngại thành 1 con số: `canPe` false → panel đổi câu chỉ-dẫn thành than-phiền-quyền, nhưng `/permissions/by-role` ×13 vai cho `PurchaseEvaluations.canRead`=**13/13 True** ⇒ ca chưa xảy ra (control-âm: `Permissions`/`Users` False 12/13, chỉ Admin True ⇒ phép đo có phân biệt). **`{!selectedId && }` = unmount ⇒ mất state thuần** (`search`) mà `localStorage` (`expandedSet`) vẫn sống ⇒ trade-off spec khai THIẾU. Thước hỏng gặp lại: python Windows đọc JSON UTF-8 phải khai `encoding` (cp1252 nổ) · `while read` bỏ dòng CUỐI khi file thiếu newline (mất 1/13 vai) · python `'\n'.join` ghi text-mode Windows đẻ CRLF vào tên file. Tag `[s168, khuon-do-lai-theo-host, class-chet-am-tham, probe-bien-lo-ngai-thanh-so, unmount-mat-state]` **Evidence:** `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-gd3d.md` diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-k8-dryrun.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-k8-dryrun.md new file mode 100644 index 0000000..1ab8303 --- /dev/null +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-k8-dryrun.md @@ -0,0 +1,54 @@ +K8-DRYRUN: ĐANG CHẠY — B0 PASS (backup 26,6MB + roster LIVE + login admin OK); B1.. đổ ruột liên tục bên dưới + +# sub-k8-dryrun — K8 dry-run E2E toàn trình (S168, 2026-08-01) + +> Mandate owner @S168 (verbatim): *"Chạy dry-run hết luôn đi rồi tao giao tiếp plan khác"*. +> Kịch bản = spec-cụm3 §③ K8 + bảng B0-B16 (`sub-invest-fable-b2-cum3.md` K8.1) + **vá-9..15 spec-final THẮNG nền**. +> 🔴 Vá-12 owner-ratified @S164 *"tạo PE Test SOLUTION-PE-1,2,3… không test trên phiếu thật"* ⇒ **bộ test RIÊNG** (Project+NCC+gói ZZTEST/SOLUTION-PE-{n}), **KHÔNG đụng `PE/2026/A/049`** — câu giờ-G K8.2 của bản nền coi như ĐÃ trả. +> Người bấm mọi bước hôm nay = **admin (duyệt thay — SignedByUserId track, banner "Admin duyệt thay" by-design)**; cột "Ai (thật)" trong form = roster LIVE để buổi chạy với người thật dùng lại. + +## B0 — PRE-FLIGHT (fail-closed) — ✅ PASS 16:2x-16:3x +07 + +- (i) **Backup prod:** `C:\Backups\SolutionErp\SolutionErp_preK8_S168.bak` — 27.877.888 B @ 2026-08-01 16:28 (BACKUP DATABASE 3393 pages OK). *(Script `scripts/backup-sql.ps1` default `D:\` — VPS KHÔNG có ổ D ⇒ dùng `C:\Backups`; default ĐÃ VÁ `C:\` @S168 cùng lượt.)* +- (ii) **Workflow LIVE (sqlcmd -E; ⚠️ `$env:PROD_DB_PASSWORD` KHÔNG tồn tại cả 3 scope trên VPS — persona-note stale cùng lớp F-9):** + - type-1 PE: `QT-DN-V2-001` active+selectable · 3 trạm (P1: 4NV L1 + tra.bui L2[SkipToFinal,Delete] · P2: 4NV L1 + **chuong.phan L2 [Finalize=1,SkipToFinal,Delete]** · P3: truong.nguyen [SkipToFinal]). + - type-10 KHKK: **đủ 8 nhóm N1-N8 active**; `KHKK-N4` 3 trạm 11 người (Cung ứng: 4NV+tra.bui · Kiểm soát CP: 4NV+**chuong.phan [Finalize=1]** · BGĐ: truong.nguyen) — khớp anchor OG-3/OG-9. + - type-3 HĐ: `QT-HD-V2-001` active — **1 trạm 1 người: binh.le (Bước 1 - Phòng CCM)**. +- (ii-b) Catalog: `ContractCatalogEntries` = **86** dòng; nhóm-4 mẫu B1-01 Đá · B1-02 Cát · B1-03 Cọc tràm · B1-04 Bê tông · **B1-05 Xi măng (chọn cho line test)** · B1-06 Thép. +- (iii) Dữ liệu test sẵn có: Projects ZZTEST = **0** · Suppliers TEST = **0** ⇒ TẠO MỚI qua API (GĐ0 dưới). Contracts prod = **0** (HĐ dry-run sẽ là HĐ ĐẦU TIÊN trên prod — seq cháy thuộc cặp prefix TEST, vô hại data thật). +- (iv) **Dặn team:** em KHÔNG có kênh Zalo/email — thay bằng ZZTEST-prefix mọi bản ghi + mục này để anh nhắn team *"notification phiếu ZZTEST trong hôm nay — bỏ qua"*. KHAI trade-off, không im. +- (v) Login API prod: `POST /api/auth/login` admin OK (accessToken 468c — field `accessToken` đúng bài S160). + +## B0-FORM 14 dòng {bước · người THẬT (roster LIVE) · tài khoản · ai bấm hôm nay} — vá-9 fail-closed + +| B | Ai (thật, theo roster LIVE) | Tài khoản | Hôm nay | +|---|---|---|---| +| B1-B3 | BCH drafter (đại diện Cung ứng: Nguyễn Văn Duy) | duy.nguyen@solutions.com.vn | admin (tạo thay) | +| B4 | Trạm-1 PE/KHKK — 1 trong {duy.nguyen · binh.lethanh · long.chau · phuong.nguyen} + L2 tra.bui | (4+1 tài khoản trên) | admin duyệt thay | +| B5 | Trạm-2 — 1 trong {luu.tran · nguyen.ho · binh.le · truong.letrandang} | (4 tài khoản) | admin duyệt thay | +| B6 | **TP.CCM Phan Văn Chương (Finalize)** | chuong.phan@solutions.com.vn | admin duyệt thay (tick finalize) | +| B7 | CEO Nguyễn Văn Trường (nhánh B) | truong.nguyen@solutions.com.vn | admin duyệt thay | +| B8 | BCH/Admin kiểm khóa | — | admin | +| B9 | Người có `Contracts.Create` (câu III default: Drafter/Procurement/Admin — seeder K7 CanCreate=3) | — | admin | +| B10 | Người bấm B9 | — | admin | +| B11 | Approver HĐ: **Lê Văn Bình** (QT-HD-V2-001 trạm duy nhất) | binh.le@solutions.com.vn | admin duyệt thay | +| B12 | HRA/CCM (HardCopyActorRoles) | — | admin | +| B13 | Bất kỳ + Admin (mở cây) | — | admin | +| B14 | Lead chốt sổ | — | lead | + +⇒ 14/14 dòng CÓ CHỦ — fail-closed ĐẠT (không dòng nào trống). + +## Nhật ký bước (đổ ruột liên tục — ID ghi TẠI CHỖ cho rollback vá-11/13) + +### 🔴 PHÁT HIỆN TRƯỚC GIỜ CHẠY — BLOCKER toàn trình: Lines-editor KHÔNG TỒN TẠI (vá tại chỗ @S168) + +Truy vết trước khi bấm B1 (đúng tinh thần "K8 lộ wave thiếu"): +- `ContractSigningPlanFeatures.cs` auto-gen line mồi `CatalogEntryId = null` + comment HẸN *"Người soạn gán sau qua `UpdateContractSigningPlanLineCommand`"* — **command đó chỉ tồn tại TRONG COMMENT** (grep toàn src + FE = 0 impl, 0 route, 0 call). +- `ContractSigningPlanWorkflowService.SubmitAsync` (vá-5) **CHẶN THẬT** line null: `"Còn dòng chưa gán hạng mục…"` + đếm-so-khớp nhóm. +- FE `KhkkDetailPage` cột Hạng mục tự khai *"Đường GÁN (Lines-editor) = K4b"* — nhưng K4b THẬT ship việc khác (`88e7ecf` = nối `?group=` sidebar, đo `git show --name-only`). ⇒ mảnh rơi giữa build-order. +- Hệ quả nếu không vá: **MỌI phiếu KHKK tạo sau K2 kẹt Nháp vĩnh viễn** — dry-run chết ở B3. Đây chính là chỗ cicd-K2 khai *"mục-4 chân-lý-rỗng — đo lại khi K8 đẻ phiếu thật"*. + +**Vá @S168 (BE + FE ×2 app + 3 test):** `UpdateContractSigningPlanLineCommand(PlanId, LineId, CatalogEntryId)` handler (EnsureDraftEditable + fail-fast entry sống/đúng-nhóm 409 + denorm `TenHangMuc` + changelog Line) · route `PUT /contract-signing-plans/{id}/lines/{lineId}` policy `KeHoachKyKet.Update` · FE select gán tại bảng (Nháp/TraLai, khoá dòng đã bắc cầu HĐ, options lọc `?approvalGroup=`) mirror SHA-pair `21e0ca0507d4` ×2 app · 3 Fact (dương gán→submit-QUA · âm khác-nhóm 409 · âm phase). Gate + commit riêng trước khi chạy chuỗi. + +### GĐ0 — dựng bộ test (Project + Supplier + WorkItem + PE `SOLUTION-PE-{n}`) +(đang chạy — điền dưới) diff --git a/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-gd3d.md b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-gd3d.md new file mode 100644 index 0000000..30e1db4 --- /dev/null +++ b/.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-gd3d.md @@ -0,0 +1,187 @@ +GATE-GD3D: PASS-WITH-FLAGS-10 — Đúng phương án D, khuôn nguyên vẹn (SHA-pair identical), import sạch; 0 blocker, nhưng `max-h` của khuôn vượt chiều cao Panel-3 trên InboxPage (~26px) đẻ 2 thanh cuộn lồng nhau + 2 class khuôn chết âm thầm. + +# Sub-reviewer gate GĐ3-D (S168, 2026-08-01) + +Scope: 3 file FE uncommitted, phương án D "cây thay chỗ Panel-3 khi chưa chọn HĐ". +Spec nguồn: `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-implfe-gd3.md` §1 bảng 4 phương án (D). +Vai: reviewer đối-kháng, **propose-only** — không sửa code, không commit. + +--- + +## Đo trước (baseline) + +- `git status --porcelain` toàn repo: 5 `M` — `.claude/WAL.md`, `.claude/agent-memory/memory-budget.json`, + 3 file FE. +- `git status --porcelain --untracked-files=all -- fe-admin/src fe-user/src`: **ĐÚNG 3 file**, 0 untracked. +- `git diff --stat`: mỗi file FE 13 dòng đổi (+6/−7), tổng 3 file. + +## R1 — Đúng-D (điều kiện render) → **PASS** + +Cả 3 file giữ NGUYÊN cặp điều kiện: + +``` +{!selectedId && } +{selectedId && detail.data && } +``` + +- Cây CHỈ render khi `!selectedId` — đúng D. +- Chọn HĐ → `WorkflowHistoryPanel` như cũ; vế điều kiện **không đổi một ký tự**. +- Trạng thái "đã chọn HĐ nhưng `detail` đang tải" render **RỖNG ở CẢ bản cũ lẫn bản mới** (bản cũ: `!selectedId` sai nên ô dashed tắt, `detail.data` chưa có nên panel trống) ⇒ hành vi loading giữa chừng KHÔNG đổi. +- `currentStage={3}` đúng GĐ Hợp đồng cho cả 3 trang (xem F-10 cho lưu ý riêng về InboxPage). + +## R2 — 0-đụng-khuôn → **PASS** + +`sha256sum` (16 ký tự đầu), fe-admin ⟂ fe-user: + +| File | admin | user | Kết quả | +|---|---|---|---| +| `components/pipeline/PipelineTreePanel.tsx` | `d70ac315bae485e6` | `d70ac315bae485e6` | IDENTICAL | +| `components/pipeline/PipelineStageFolders.tsx` | `bed52f39d595c86a` | `bed52f39d595c86a` | IDENTICAL | +| `hooks/usePipelineStages.ts` | `76e1823345d4e78b` | `76e1823345d4e78b` | IDENTICAL | + +`git status --porcelain` trên 4 đường dẫn khuôn = **RỖNG** ⇒ khuôn chưa bị sửa. SHA-pair identical vừa chứng mirror 2 app còn khớp, vừa chứng không ai chạm vào khuôn trong đợt này. + +## R3 — Unused-import `X` → **PASS** + +- Cây làm việc: 0 hit mã ở cả 3 file. Hit duy nhất là chuỗi `type=X` trong comment `ContractsListPage.tsx:6` (không phải icon). +- **Control-âm:** cùng regex chạy trên `git show HEAD:` cho **2 hit/file** (dòng `import … X …` + ``) ⇒ phép đo CÓ răng, không phải 0-hit vì regex hỏng. +- Không gỡ nhầm icon khác: `FileText` / `Search` / `Plus` / `Inbox` / `AlertTriangle` / `Clock` / `ClipboardList` đều còn nguyên trong dòng import mới. + +--- + +## FINDINGS + +### F-1 (MAJOR) — R4: `max-h` của khuôn hiệu-chỉnh cho host page-flow, vượt chiều cao Panel-3 trên InboxPage ⇒ 2 thanh cuộn lồng nhau + +Chiều cao TỐI ĐA của khuôn khi đặt ở lg: + +| Thành phần | File:dòng | Lớp CSS | px | +|---|---|---|---| +| Đầu panel | `PipelineTreePanel.tsx:181` | `px-3 py-2.5` (20) + `icon-chip h-7!` (28) + `border-b` (1) | 49 | +| Ô lọc | `PipelineTreePanel.tsx:204` | `p-2` (16) + `input h-8` (32) + `border-b` (1) | 49 | +| Thân cây | `PipelineTreePanel.tsx:215` | `lg:max-h-[calc(100vh-16rem)]` | 100vh − 256 | +| **Tổng** | | | **100vh − 158** | + +Chiều cao KHẢ DỤNG của Panel-3 = `100vh − 4rem` (vỏ trang) − đầu trang − dải phụ − `p-4` (32): + +| Trang | Vỏ / đầu trang | Đầu trang | Dải phụ | Khả dụng | So với 100vh−158 | +|---|---|---|---|---|---| +| `fe-user/src/pages/contracts/MyContractsPage.tsx` | `:105` / `:107` `py-3` + `Button size=md h-8` + border | 57px | 0 | 100vh − 153 | **thừa 5px** (khít) | +| `fe-admin/src/pages/contracts/ContractsListPage.tsx` | `:106` / `:107` `py-3` + h1 24px + border | 49px | 0 | 100vh − 145 | **thừa 13px** | +| `fe-user/src/pages/InboxPage.tsx` | `:166` / `:168` `py-3` + `StatPill` 34px (`:50` `px-3 py-1.5` + `h-5`) + border | 59px | **29px** — dải "Vai trò bạn đang xử lý" `:183-187` (`py-1.5` + `text-[11px]` + border) | 100vh − 184 | **THIẾU ~26px** | + +Hệ quả trên `/inbox`: `