Compare commits

...

9 Commits

Author SHA1 Message Date
33e7f68890 [CLAUDE] Docs: S158 closeout - adap /day probe-first (nac agreed) + bookend-close 5 vong
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Has been cancelled
Phien-LOGIC L7 window 5, vao bang /tiep. Governance/adap-only: 0 prod-code,
0 migration, 0 test moi. Test do tuoi 562 PASS (45D+517I). Counter 31->32.

VIEC
- /tiep recovery tron: San-3 5 tin-hieu MANH deu keu DUNG (corroborate WAL),
  verify: 5/5 PASS 0 lech, bien-nhan _tiep-4.md (window-ordinal 5).
- /check-email AI_INFRA: verify bang NOI DUNG - 22/22 file outbox/se co trong
  inbox, cmp 0 byte-drift => se=0 that + khong co stamp-then-edit (H18).
- /adap-apply day-wake-probe-first qua /fable-real investigator-codebase:
  nac AGREED (0 file co-che bi sua). Spec 3-muc + adap-report + 4 phan-bien
  gui nguoc hub + 1 datum dogfood (hub tu khai co 0).
  Engine BAC 2 tien-de cua lead: mo-coi 0/8 (khong phai "co squash => co mo-coi")
  va probe PHAI dung phep-2 - chung bang cua S158 noi 2 phep cho verdict NGUOC NHAU.
- Ra 6 HIGH lens-wave spec KHKK: 4 phu tron, 2 con ho (H5 W3 N chua pin =>
  N=0 van PASS; H6 §2.4:224 giu co-che IsVisible da bi chinh file do do-dia bac).
- Bookend-close 10 spawn / 5 vong. V4 nen-ngu KHONG-NHIP (shard 15/15 => IM).

VA TRONG PHIEN
- STATUS:459 RAG khai "alive" -> lat DOWN (3 phep do doc-lap: chunk_count=0
  cho ca 7 project + shared_global; canonical tu mau thuan voi :473 cach 14 dong,
  song 5 nhan phien).
- STATUS:461 bundle hash prod da chet -> 8-QYcMOg/DptYR4wL (control-am 900/876 B).
  Hai that: cicd-verify:58 dung chinh o nay lam baseline.
- STATUS:6 4->5 cua-so, counter 31->32; M-1 nhet lai nguyen van owner
  "da xong buoc thu 6 tuc CEO duyet" (ring2: grep = 0/STATUS + 0/HANDOFF).
- WAL:5 + WAL:21 tick; HANDOFF segment S155->S158 + slot (42)...(48).
- GATE 5-ANCHOR di-tru khoi WAL sang HANDOFF NEXT-em TRUOC khi §6.4 reset xoa no
  (lead-gap FLAG-4, han chot = cua ke).
- ef-core-migration SKILL: va CAU TRUC (frontmatter thoi khai bang la nguon
  "moi nhat") thay vi them row - ring1: day la lan 3 cung class.
- contract-workflow:371 "Contract V2 chua" SAI ~2,3 thang -> dinh chinh
  (ring1 thach-CLEAN thung H1).
- C12: +3 dong run= hoi-to S155/S156/S157. 2 orphan run-folder -> synthesis dang-1.
- M9 seed on-behalf 3 diary: ctx-verifier, investigator-codebase, ctx-audit.

#53 x8 - DOI-CHUNG NOI-PHIEN SACH DAU TIEN
Ep-ghi-dia KHONG giam garble (3/3 vai bi ep van garble) nhung dua thiet-hai ve 0
(2.818/5.354/7.957 B nam san); 4 vai khong ep MAT TRANG phai resume.
=> chong #53 = thiet-ke ARTIFACT, khong phai PROMPT (xac nhan lan 5).
So #53 ghi bu sau 5 nhan phien dung yen: 66 can-duoi qua S158.
+2 sub-class moi: skeleton-ruot-rong nac-2 (byte>0 ma ruot rong) va
engine-process-exit (0 delta dia).

BAY CHAN DUOC
Moi-ngam neo bang SO DONG trong file append-o-TREN da nen 3 lan. Dong 99 hom nay
la van-de MO THAT (luat nen ho) => spawn ctx-audit ma khong xu = hoac DAT-ao,
hoac dan nhan "bay cai san" len dung cau dang trinh owner. Lead khoi phuc tu git,
pin bang NOI DUNG. ring2 chung them: neo SAI NGAY TAI COMMIT SINH RA NO
(stale-at-birth), khong phai troi-do-nen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-28 20:50:58 +07:00
d7eaeceaa7 [CLAUDE] Docs: spec "Ke hoach ky ket Hop dong" S157 (khuc con thieu PE -> HD) + review 4 lang kinh
Anh giao: dieu tra quy trinh CON THIEU giua Duyet NCC va HD NTP/NCC, ra spec day
du + chia wave. Chay /fable-real invest (Fable deep-pass) roi /fable-clone
reviewer 4 lang kinh.

PHAT HIEN NEN (lead do, invest + reviewer xac nhan tu nguon goc):
- 7 phase [LEGACY] cua ContractPhase CHINH LA quy trinh ISO 9 buoc ma-hoa cung
  (khop 1:1 dung thu tu). Khung V2 sinh ra de bieu dien chinh quy trinh do.
- Khoang trong nam DUNG giua ISO-1 va ISO-2, va ISO doc CUNG KHONG CO no
  => thieu o CA HAI tang (doc + code) => spec vua la spec phan mem vua la de
  xuat bo sung ISO.

OWNER CHOT trong cua: (O-1) cau truc trinh ky GIONG, chi khac NOI DUNG => tai
dung khung duyet V2, 0 bang approval moi => truc tranh luan Q2 hom qua DONG.
(O-2) SLA chi tham khao => khong SLA-engine, khong wave SLA.
(O-3) "cho hop dong cu tu tu" => lo hong an ninh HD NGOAI SCOPE.

REVIEW 4/4 lane sach 0 chet (dong goi C2 an), 112 diem. Claim nen DUNG VUNG.
Bat 7 loi NANG, da va het trong ban nay:
1. Ten menu key `Csp*` != tien to policy `ContractSigningPlans.*` => Program.cs
   khong sinh policy => HTTP 500 luc chay. Repo DA CO test bat
   (AuthorizePolicyRegressionTests.cs:138-139). Day la loi TU-VAP-BAY-MINH-VUA-
   NHAN-DIEN: §2.4 bat dung bay Pe_* roi §2.3 van vap bang co che khac.
2. W2 day rieng tao duoc 0 phieu (wiring Designer type-10 roi khoi moi wave)
   => keo vao W1, tai pham dung §F.0 S155.
3. Thieu bang Approvals ma service duoc lenh copy CO ghi vao.
4. Changelogs thieu 4 cot => copy service khong bien dich.
5. Thieu 3 site ApprovalWorkflowV2AdminFeatures => FK Restrict no 500.
6. Status enum bat dau tu 0 => bay falsy JS.
7. 4 anchor lech, nang nhat ApprovalWorkflowLevel.cs KHONG TON TAI.

Kem: bo tieu chi dark-launch sai co che (IsVisible chi pass-through, filter la
CanRead) - thay "sqlcmd dem policy" (khong do duoc, policy in-memory) bang test
regression - OR-of-N nang tu 1 ve len 4 ve co ca am - cat CodeSequences (tai
dung WorkflowAppCodeSequence dung chung 4 module Office).

Su co #53: invest luot 1 skeleton-ruot-rong (202K tok, dia 1.661B khung rong)
=> ghi-dia-trong-luc-lam la CAN KHONG DU, phai verify RUOT. Luot 2 resume cat
con 2 muc => CLEAN 23.085B. Luot 3 tien-trinh CLI thoat, §C/§D chua ghi => lead
tu viet theo H21 (engine propose-only, spec do lead ghi).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 11:30:03 +07:00
1d6d7b9df3 wal: flush 20260728T1112 2026-07-28 11:12:16 +07:00
f086698e8e wal: flush 20260728T1058 2026-07-28 10:58:47 +07:00
5507262753 wal: flush 20260728T1045 2026-07-28 10:45:53 +07:00
659d2880b7 wal: flush 20260728T1040 2026-07-28 10:40:22 +07:00
3b6fabc085 [CLAUDE] Docs: dong no so sach S155-S157 (CURRENT line + In Progress + session log + memory)
Dong CURRENT dung yen o S153 qua 3 cua-so trong khi S155/S156/S157 da chay va
da ship prod => drift dung lop ma lead-stale-auditor sinh ra de bat. Va:

- CURRENT line moi S155->S157 (phien-LOGIC L7, 4 cua-so): PE nut XOA ship prod
  Mig 68 2 dot + A2 dieu tra quy trinh sau-CEO (verdict LAI, chan Q1-Q6) +
  lo hong an ninh HD (anh chot 07-28 "cu tu tu" = treo CO CHU DICH) + S157 UAT
  Dia diem. S153 ha xuong muc da xong.
- Them §In Progress (S155->S157); §In Progress (S117) cu giu nguyen ben duoi.
- Session log 10.700B — con-tro tu dong CURRENT nay GIAI DUOC (verify 1 hit).
- Memory moi: lop "co-che dung, du-lieu khong co" nay x6 (S157 la lan 6, chieu
  MOI: bug do NGUOI DUNG bao ma fix ngay-tho se nhan doi code da dung). Luat rut
  ra: UAT bao "khong chay" => DO DU LIEU PROD truoc, dung doc/viet code.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-28 10:00:24 +07:00
9649fc71ce wal: flush 20260728T0953 2026-07-28 09:53:29 +07:00
894f835fe3 wal: flush 20260728T0941 2026-07-28 09:41:30 +07:00
48 changed files with 4049 additions and 139 deletions

View File

@ -1,38 +1,34 @@
# WAL — auto-generated, không sửa tay
updated: 2026-07-28T08:20+07:00 | session: S157 (phiên-LOGIC L7, window 4) | branch: main
closing: S158 @2026-07-28T20:06+07:00
updated: 2026-07-28T20:06+07:00 | session: S158 (phiên-LOGIC L7, window 5) | branch: main
goal: [A ✅ ĐÓNG] PE nút XÓA phiếu — 3 commit, **cicd PASS toàn bộ** @S156. || [A2 🔴 ĐANG] **Quy trình SAU CEO duyệt** (PDF sơ đồ 21 bước) — phạm vi **b.7→21**; anh đặt tên khúc 7→12 = **"đề xuất giá trị ký kết hợp đồng"**. Invest + review xong, **CHẶN ở Q1-Q6 chờ anh**. || [B] 22 FLAG governance treo — nay **3 cửa-sổ** chưa đng.
🗜️ nén 48→39 dòng @PAUSE-3. GỠ (đã xong, chi-tiết durable nơi khác): 6 dòng arc-PE `[x]``_context` PAUSE-2 + `cicd-verify-dot2.md` · ctx-curator@PAUSE-2 + vai-bắt-lỗi-nén-WAL → `_context` PAUSE-2 · 3 dòng 🚩 `ctx-verifier`**đã xử trọn trong MIND-3** · fix-menu + cicd của nó → gộp 1 dòng.
goal: [A ✅] PE nút XÓA + [A3 ✅] UAT Địa điểm — cả hai LÊN PROD, cicd PASS. || [B 🔴 ĐANG] **Spec "KẾ HOẠCH KÝ KẾT HỢP ĐỒNG"** (khúc thiếu PE→HĐ) — spec **XONG 45.158 B**, anh xác nhận + dặn *"nhớ kỹ để turn sau chạy"*. Kế: **thi công Wave 1**. || [C] 22 FLAG governance treo — nay **5 cửa-sổ** (số cửa-sổ canonical = dòng `session:` ở trên, đng chép rời).
🗜️ nén 3 block `_mind` @PAUSE-4 (MIND-2→MIND-1→MIND-3) mới đủ chỗ MIND-4; sau nén dư 2.463 B. Luật nén HỞ — xem `_context` PAUSE-4 (2).
chain:
[x] Arc PE TRỌN: 4 invest → spec ~50 mục → reviewer `17 FLAG` (F.0 không bác được) → đợt 1 `b1bae77` **CICD PASS 6/6** → đợt 2 `4464a46` (562 PASS/0 FAIL, T27 fault-inject có răng) → fix-menu `f4494cf`. Chi-tiết: `.claude/sessions/session-7/_context-s-7.md` PAUSE-2
[x] cicd đợt 2 + `f4494cf` đóng TRỌN @S156 — lead tự đo (không giao lại `cicd-monitor` vì vai đó dừng giữa chừng): endpoint 2/2→**401** (control bịa 404) · smoke **8/8** · **D3 giao-tập-ID = 0** (37 sống ⟂ 9 xóa) · bundle rotate ×2 app LM 14:4114:42 trong cửa-sổ deploy + **4/4 byte-marker** · run 531 success 5m41s. 3 caveat khai trong file — `runs/2026-07-27-S155-pe-delete-approver/cicd-verify-dot2.md`
[x] bump `docs/STATUS.md` bảng CURRENT STATE: Mig **67→68** · test **532→562** · bundle live `BK8w3QxU`/`DYnxSI0T` (+caveat không-hồi-tố-được `4464a46`)
[x] A2 đọc PDF (`pdftoppm` KHÔNG có → render `fitz` rồi Read ảnh) + trích 21 bước → `runs/2026-07-27-S156-bch-post-ceo-flow/run.md`. Grounding 4 phép: `PE.DaDuyet=7` khớp "xong b.6" · cầu PE→HĐ CÓ SẴN `CreateContractFromEvaluationFeatures.cs` · **`shopdrawing|TVGS|duyệt mẫu` = 0 hit toàn repo** (b.8-9 đất trng) · `ContractPhase` **12 giá trị / 7 `[LEGACY]`** (🔧 lead ghi "9 phase / 6 LEGACY" = SAI cả 2 số, `ctx-verifier`+`ctx-curator` bắt, máy xác nhận)
[x] A2 `wf:` `/fable-real investigator-codebase` (Fable) 2 lượt — lượt 1 **`#53` mất return**, cứu TRỌN từ đĩa; lượt 2 resume cắt-ngắn CLEAN. `sub-invest-bch-1.md` **22.659 B** khớp return. **VERDICT `LAI`**: b.13→21 **TÁI DÙNG** Contract V2 · b.7→12 **DỰNG MỚI**. §4 wire + §5 checklist còn `[PENDING]`
[x] A2 `wf:` `/fable-clone reviewer` **`wf_1618ae3c-a17` — 4/4 lane SẠCH 0 chết** (đóng gói C2 ăn: ≤3 file/lane + ép khung rỗng lượt 1-2 + trần 25; tốn nhất 7/25). **35 điểm**: verdict `LUNG-LAY 11` · fidelity `CO-VAN-DE 10` · q2 `THIEU-PHUONG-AN 14` + thiên-vị-có-hướng · gaps `4/4 THẬT 0 dương-giả`. **Lõi `LAI` SỐNG**, đổ ở NHÃN chi-phí + CÁCH ĐẶT VẤN ĐỀ — `runs/2026-07-27-S156-bch-post-ceo-flow/review-synthesis.md`
[x] 🔴 **ANH ĐẶT TÊN khúc 7→12 = "ĐỀ XUẤT GIÁ TRỊ KÝ KẾT HỢP ĐỒNG"** — phát biểu MỤC ĐÍCH, không phải nhãn: đầu ra = **1 CON SỐ có phê duyệt**; b.8-9 = **căn cứ**, b.10-12 = **chuỗi duyệt chính con số đó** ⇒ là **PHIẾU**, không phải thư-mục đính kèm. Bỏ tên tạm "PostAward". **Hệ quả: Q2 nhánh (c) yếu hẳn · Q6 gần như tự trả lời** — lead KHÔNG tự chốt
[x] MIND-3 chèn + `ctx-curator` @PAUSE-3 `SUA — 8 điểm` (nhận CẢ 8 + 1 ngoài-trục: WAL còn "6/9 LEGACY" trong khi `run.md` đã sửa ⇒ 2-sự-thật, vá cùng lượt). **3 🚩 `ctx-verifier` XỬ TRỌN**: 3 ý MIND-1 §D nhận LẠI · trần ép nén MIND-1 5.767→3.070 B (verbatim còn trong git) · claim `sub-implementer-backend-1.md` "không còn" đính chính. `mind-check` = **dat=10 TRUOT=0**, 32.658/32.768 (dư **110 B**)
[x] A3 UAT "lấy địa chỉ lên luôn" — chẩn **DATA-không-phải-CODE** (auto-fill wire S59 chạy đúng 4 tầng; prod **57/62 dự án `Location` NULL**). Anh chốt KHÔNG backfill. Vá = cảnh báo amber. `6250f39` → Run #419 **cicd PASS 9/9** + lead re-curl khớp byte (admin `8-QYcMOg` · user `DptYR4wL`, marker 2/2)
[x] Dọn nợ sổ `3b6fabc`: STATUS dòng CURRENT S153→**S157** · +§In Progress (đứng S117 suốt 40 phiên) · session-log `2026-07-28-0930-S155-S157-*.md` 10.700 B · memory mới `feedback_mechanism_right_data_absent.md`
[x] **Spec B XONG** `d7eaece``.claude/workflows/runs/2026-07-28-S157-ke-hoach-ky-ket-hd/spec-ke-hoach-ky-ket-hd-28-07-2026.md` **45.158 B**: ① đề bài + 6 bước b.7→12 + bảng 9 mâu thuẫn ② cách wire (7 bảng Mig 69, tái dùng khung V2) ③ **5 WAVE** + acceptance đo được ④ hấp thụ 6 việc §G ⑤ kết quả review
[x] Nền spec (lead đo, invest+reviewer xác nhận): **7 phase `[LEGACY]` = quy trình ISO 9 bước mã-hoá cứng** (khớp 1:1) · khoảng trng nằm giữa ISO-1 và ISO-2, **ISO CŨNG KHÔNG CÓ** ⇒ spec vừa là spec phần mềm vừa là **đề xuất bổ sung ISO**
[x] `/fable-clone reviewer` `wf_57af0163-053`**4/4 lane sạch 0 chết**, 112 điểm (wave `SUA-TRUOC-W1` 19 · fidelity `GO-WITH-FIXES` 23 · schema `GO-WITH-FIXES` 22 · claims 48: **39Đ/4S/5KKĐ**). Claim NỀN **đứng vững**
[x] **7 lỗi nặng đã vá** trong spec — nặng nhất: tên key `Csp*` ≠ tiền-tố policy `ContractSigningPlans.*`**prod 500 chứ không 403**, repo ĐÃ CÓ test bắt (`AuthorizePolicyRegressionTests.cs:138-139`). Ca **tự-vấp-bẫy-mình-vừa-nhận-diện**
[!] 🔴🔴 **LỖ HỔNG AN NINH PROD — gotcha #82 TÁI PHÁT, KHÔNG liên quan tính năng mới**: `ContractWorkflowService.cs:48-66` nhánh Reject chạy TRƯỚC MỌI GUARD (0 role/0 approver/0 fromPhase, `SaveChanges`+`return` luôn) + `ContractsController.cs:13` **`[Authorize]` trần DUY NHẤT phủ 22 endpoint ghi** ⇒ **mọi user đăng nhập Từ-chối/Trả-lại được BẤT KỲ HĐ nào kể cả `DaPhatHanh` terminal**, kèm xoá `SlaDeadline`. Lead verify 2 tầng độc lập; đối chứng PE controller có 3 per-action policy. **Đã tách chip riêng** — chờ anh xếp ưu tiên
[!] A2 **CHẶN: Q1-Q6 chờ anh** (14 câu tổng) ⇒ §4 wire + §5 checklist chưa viết được ("trả lời khác ⇒ wire khác"). Nặng nhất **Q2 kiến-trúc khúc 8-12** — anh đã chọn "chưa chốt, cần bàn thêm"; reviewer chấm cách đặt vấn đề `THIEU-PHUONG-AN` + thiên-vị ⇒ **phải viết lại Q2 trước khi hỏi lại anh**
[ ] 🔴 invest có **1 claim SAI SỰ THẬT** phải sửa trước khi trình: "hardcoded policy fallback" → thật là `ConflictException :115-116` ⇒ HĐ từ phiếu **KẸT CỨNG `ChoDuyet`, không ai duyệt được** (nặng hơn, không degrade êm). Gốc: **invest tin skill-doc `contract-workflow` hơn ĐĨA** — doc tả fallback `WorkflowPolicyRegistry`, đĩa 0-hit ở đường transition, chỉ còn ở đường HIỂN THỊ ⇒ lệch DISPLAY⟂GUARD mà doc stale che luôn
[ ] A2 **6 việc sửa bản invest** trước khi trình anh 14 câu (`review-synthesis.md` §G): vá claim sai · siết biên `b.14→19` (không phải 13→21) · +Q vai-người-TRÌNH (`:70-79` PMH role `Procurement` bị **403** ở b.13/b.17 = lớp "cơ-chế đúng, thứ đi qua không có" **lần 5**) · +cảnh báo lỗ hổng reject · Q5 +phương án (d) `skipToFinal` **ĐÃ WIRE** mà invest bỏ sót · viết lại Q2 theo **2 trục + 3 số đo cùng đơn-vị lấy từ twin repo**
[ ] 🔴 4 lỗ "cột CÓ mà 0 ai đọc" (reviewer verify **0 dương-giả**, nhưng 2 lỗ đóng khung sai): L1 cầu PE→HĐ bỏ pin V2 · L2 `CeoApprovalThreshold` **0-consumer phía HĐ** (admin set bị ngó lơ IM LẶNG) · L3 SLA hardcode `AddDays(7)`**đổi khung**: thụt-lùi-so-V1 + lỗ toàn-V2 cả PE · L4 `AttachmentPurpose`**sai tầng**: `Purpose` là nhãn KHÔNG AI THI HÀNH, thêm enum vô nghĩa nếu không dựng cổng đọc
[ ] **Guard post-wave assertion mù 4 path hook** — chẩn-đoán chốt, thuốc đã chạy thật (`git log --name-only origin/main..HEAD -- <path>` thay `git status`); VÔ-GIA-CƯ nên dựng dòng này để khỏi rơi
[ ] STATUS phần CÒN LẠI (cần session-log): dòng CURRENT S155/S156 · row §In Progress (**đang đứng S117** — `ctx-verifier` 🚩4) · §Recently Done · counter · gotcha mới
[ ] ghi memory 3-4 datum: lớp "cơ-chế-đúng-dữ-liệu-không-có" (nay ×5, là ĐẶC-TÍNH kiến-trúc: schema chung ⟂ service riêng per-type) · phép-đo-rỗng-nghĩa · **owner-cấp-Ý-ĐỊNH-agent-cấp-HOẠT-ĐỘNG** (mới, từ vụ đặt tên) · lead điền-sẵn-kết-quả-chưa-xảy-ra
[ ] 🔴 vết lỗi lead @S156: viết `run.md` **điền SẴN kết-quả cho lượt chạy CHƯA xảy ra** (byte-count + `TOTAL=14 GAP` + verdict = BỊA). Tự bắt ngay sau Write, sửa về `[ ]`, ghi vết. Lớp `SHA-bịa` — xảy ra ngay trong lượt vừa khoe "đo-trước-tin" ⇒ chốt chặn phải là LUẬT SOI ĐƯỢC, không phải trí nhớ
[!] 🔴 **Trước khi thi công W1: rà 6 HIGH của lens-wave** — 7 vá **chưa chắc phủ trọn**. Đọc `sub-review-wave-1.md` mục HIGH, đối chiếu spec §③ WAVE 1 đã sửa, chốt cái nào còn hở
[ ] **Thi công WAVE 1** theo spec §③: 7 entity + 2 enum + 7 EF config + Mig 69 + enum slot 10 + MenuKeys 4 const **vào `All`** + seed + **Designer type-10** + **3 site `ApprovalWorkflowV2AdminFeatures.cs`**. Vai: `implementer-backend` + design-review `database-agent`
[ ] Gate rẻ trước mỗi wave (reviewer đề, lead nhận): **mở 5 anchor bất kỳ** của wave — ≥1 trượt ⇒ chấm lại toàn bộ anchor. Chưa có nhà trong bản-đồ
[ ] 🔴 4 lỗ "cột CÓ mà 0 ai đọc" (S156) — **L3 SLA `AddDays(7)` RỜI tập** theo O-2; còn L1 cầu PE→HĐ bỏ pin V2 · L2 `CeoApprovalThreshold` 0-consumer phía HĐ · L4 `AttachmentPurpose` sai tầng
[ ] 🔴🔴 **Lỗ hổng an ninh HĐ** `ContractWorkflowService.cs:48-66` Reject-trước-guard + controller class-trần — **anh chốt "cứ từ từ"**, treo CÓ CHỦ ĐÍCH (không phải quên). Wave 5 chạm HĐ ⇒ phải hỏi lại anh
[x] Kéo thư fan-out `2026-07-28-Governance-day-wake-probe-first-resume`**XONG @S158 qua `/fable-real investigator-codebase`**, nấc **`agreed`** (KHÔNG phải executed: 0 file cơ-chế bị sửa). Spec 3-mục + adap-report + 4 phản-biện gửi ngược hub
[ ] B-governance: 22 FLAG chờ (42) canonRows · (43) carry con-trỏ-vs-slug · (44) END-line-thành-luật · (E2) harvest-curator 111,1% trần
[ ] `.claude/agent-memory/reviewer/MEMORY.md` = 19.049 B **trên ngưỡng 17.1KB** — curate lượt sau
[ ] `.claude/agent-memory/reviewer/MEMORY.md` 19.049 B **trên ngưỡng 17.1KB** — curate · monthly drift-audit **2026-08-01**
next: **sửa 6 việc bản invest** theo `review-synthesis.md` §G (trọng tâm: viết lại Q2 theo 2-trục + 3 số đo từ twin repo) → trình anh bộ 14 câu sạch → chờ Q1-Q6 → mới viết §4 wire + §5 checklist. 🔸 Anh đã được hỏi thứ tự 3 việc (an-ninh / sửa-invest / §4-§5) nhưng gõ `/pause` trước khi chọn ⇒ nếu anh chỉ định khác thì theo anh.
next: **rà 6 HIGH lens-wave** (`sub-review-wave-1.md`) đối chiếu spec §③ đã sửa → chốt còn hở gì → **thi công WAVE 1**. 🔸 Nếu anh trả lời 3 câu treo (nguồn thứ 4 · 2 đường kết thúc sớm W3 · thứ tự wave) thì theo anh trước.
verify:
python scripts/session_ctx.py mind-check --session 7
grep -c 'Authorize' src/Backend/SolutionErp.Api/Controllers/ContractsController.cs
sed -n '48,66p' src/Backend/SolutionErp.Infrastructure/Services/ContractWorkflowService.cs
tail -3 .claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/review-synthesis.md
tail -3 .claude/workflows/runs/2026-07-28-S157-ke-hoach-ky-ket-hd/spec-ke-hoach-ky-ket-hd-28-07-2026.md
grep -n "^## Điểm HIGH" -A 3 .claude/workflows/runs/2026-07-28-S157-ke-hoach-ky-ket-hd/sub-review-wave-1.md
sed -n '136,142p' tests/SolutionErp.Infrastructure.Tests/Api/AuthorizePolicyRegressionTests.cs
git log --oneline -3
carry: thu-moi se=0 all=0 (dò @tiep S157 — **5/6 repo, `dyd` VẮNG trên máy** fail-soft) | `#53` @tiep-3 ×0 (`ctx-verifier` CLEAN; giả-thuyết prompt-ngắn+ép-ghi-đĩa-sớm giữ) | `[carry:ctx-t9-dogfood]` còn nợ `session-end (l)` | **`ctx-verifier` @tiep-3 `CO-CO 10 cờ`** — xử @block MIND-4 kế: C5/C6 trần `_mind` dư 110B ⇒ nén **≥2 block (MIND-2+3)** hoặc nâng trần (luật "cũ-nhất" hở ca đã-nén) · C9 gist MIND-2 PHẢI mang đính-chính (`sub-implementer-backend-1.md` CÒN SỐNG 3.499B) · C10 kéo verdict `ctx-curator` @P2/P3 về `_context` · C2 orphan-máy run S155 (bản-ghi tên `cicd-verify-dot2.md` ≠ glob `*-synthesis.md`) · C8 3 ý {gần-chốt} vô-gia-cư (liên-lane checklist · ranh-giới-task · mẫu-số+tập-bù) · C4 §4/§5 nằm `sub-invest-bch-1.md:138-139` · C3 header STATUS **ĐÃ VÁ @S157**
carry: thu-moi **se=0 all=1** (dò @pause 5/6 repo, `dyd` VẮNG trên máy; thư `all` CHƯA kéo — bookend làm) | **`#53` cửa này ×2**: `cicd-monitor` (cứu 10.666 B từ đĩa) + invest lượt 1 **`skeleton-ruột-rỗng`** (202K tok, đĩa 1.661 B khung rỗng) ⇒ 🔴 datum nâng 1 nấc: **ghi-đĩa-trong-lúc-làm là CN KHÔNG ĐỦ, phải verify RUỘT có chữ** | `ctx-curator` @PAUSE-4 `SUA — 9 điểm` nhận CẢ 9 (O-1 vắng trọn ⇒ Q2 suýt rơi im lặng · 5 chỗ verbatim trá hình lách rào-1) | `[carry:ctx-t9-dogfood]` còn nợ `session-end (l)` | **5 câu owner** = 3 carry S156 (Q3·Q6·Q11) + 2 mới (O-Q1·O-Q2), **KHÔNG chặn W1-W2**

View File

@ -1,7 +1,8 @@
# CI/CD Monitor Agent — Persistent Memory
- **07-27 verify b1bae77 (Workflow: quy-trình duyệt TẠI CHỖ + cờ F6 `AllowApproverDelete` đợt-1) [S155, MIG-BEARING deploy, CLEAN-return]:** VERDICT **PASS 6/6** — Run **#416** (id=529) success **5m31s** (12:37:18→12:42:49+07); gate **551 EXACT từ log** (45 Domain + **506** Infra, 0 fail/skip) — **+19 vs run #407 (532)**, **KHỚP CHÍNH XÁC số lead đo local (551)** = cross-check 2-nguồn. **Mig 68 `20260727033522_AddPeAllowApproverDelete` VERIFIED-APPLIED-PROD** (AddColumn `AllowApproverDelete` bit NOT NULL default `(CONVERT([bit],(0)))` trên `ApprovalWorkflowLevels`; history-TOP + `INFORMATION_SCHEMA.COLUMNS` **cả 2 cùng có ⟹ không lệch**; sys.tables **89** giữ nguyên đúng AddColumn-no-new-table). 🔑 **Reviewer FLAG F8 (mig-file rớt khỏi commit ⟹ `Invalid column name` hạ 7 module V2) LOẠI TRỪ bằng 3 lớp:** (i) pre-deploy baseline 12:38 history-top còn `AddPeApprovedBudgetSnapshot` ⟹ mig áp TRONG cửa-sổ này không phải sẵn có; (ii) smoke 8/8 HTTP 200 `Invalid column name`=0 (PE·HĐ·Đề-xuất·Nghỉ-phép·Tăng-ca·Công-tác·Đặt-xe + AwV2); (iii) **phép mạnh nhất = `GET /api/approval-workflows-v2` trả `allowApproverDelete` ×54 materialize qua EF từ DB thật** — DB thiếu cột thì chính query này đã ném. Endpoint mới `PUT /api/approval-workflows-v2/{id}` no-token → **401** + **control route bịa → 404** (discriminator sạch, 401 có nghĩa). Bundle **JS rotate CẢ 2** (admin `hHISK1Ig`→**`CiUBEEJr`** css `CBzUlgOA`→**`DX5ew0wg`** rotate; eoffice `CJeXZso2`→**`DFh7GK0t`** css `BHsBUA8e` **FROZEN** = #69-REFINE lành tính, 2 file fe-user là logic/type no-new-utility) real-size 1.670.035/1.570.257B, LM 12:41:28/12:42:22+07 **in-window**; byte-verify #77 marker `allowApproverDelete` admin ×7 / eoffice ×1 ⟹ đúng mã F6 đã ship. SPA-trap control `ct=text/html` 900/876B. health live+ready 200. Tag `[run-416, pass-6-6, mig-bearing, F8-averted-3-layer, col-materialize-x54, js-rotate-both, gate-551-khớp-local]`
- **07-28 verify `a52a91e` (PE: cảnh báo amber ô Địa điểm khi dự án thiếu Location) [S157, FE-ONLY 2-app, CLEAN-return]:** VERDICT **PASS 9/9** — Run **#419** (id=532) success **5m40s** (09:40:18→09:45:58+07); gate **562 EXACT từ log** (45 Domain + **517** Infra, 0 fail/skip) — khớp canonical `docs/STATUS.md:452` **cả TỔNG lẫn TÁCH 45/517** (khớp thành-phần > khớp tổng). NO-Mig đúng kỳ vọng: `git diff f4494cf..a52a91e -- 'src/Backend/*' '*Migrations*' | wc -l` = **0** ⇒ Mig vẫn 68, 89-table, KHÔNG query DB (không có gì để đối chiếu). 🔑 **Phép quyết định = byte-marker #77, KHÔNG tin status CI:** tải thẳng JS prod, `bytes.count(marker.encode())` 4 chuỗi VN độc lập → **2/2 app, count=2 mỗi app = KHỚP SỐ FILE/app trong diff** (`PeHeaderForm`+`PeWorkspaceCreateView`) — "đúng-BỘI-SỐ" mạnh hơn "tìm thấy ≥1", bắt được cả ca ship nửa-vời. Bundle js rotate CẢ 2 (admin `BK8w3QxU`→**`8-QYcMOg`** · eoffice `DYnxSI0T`→**`DptYR4wL`**; css `DiNJjaoo`/`BRCvEHvC` FROZEN ×2 = #69-REFINE lành tính — utility `text-amber-700`/`text-[11px]` đã có sẵn) real-size 1.675.282/1.575.513B, LM 09:44:33/09:45:30+07 in-window. 🆕 **Control âm 2 TẦNG (tái dụng):** (i) fake-hash→200 nhưng `ct=text/html` 900/876B marker=0; (ii) **hash CŨ cũng rơi về text/html ⇒ bundle cũ BIẾN MẤT khỏi đĩa** = chứng GHI-ĐÈ thật (mạnh hơn hash-delta đơn thuần). Smoke: health live+ready 200 · login 200 tok-468 · `/api/projects` 200 (đúng nguồn `location` feature đọc) · PE/menus/suppliers 200. ⚠️ **Self-correct on-disk:** viết "range=6 file" SAI (đó là số của 2 commit) — range thật **13 commit/26 file** (11 `wal:` xen giữa); đính chính ngay, BE=0 không đổi. Tag `[run-419, pass-9-9, fe-only, marker-2of2-count-exact, old-hash-gone-control, js-rotate-css-frozen, gate-562]`
- _(**S155 #416 `b1bae77` Workflow duyệt-TẠI-CHỖ + cờ F6 `AllowApproverDelete` GO 6/6** — gate 551 [45+506, khớp local 2-nguồn]; **Mig 68 `AddPeAllowApproverDelete` APPLIED-PROD** [history-top + INFORMATION_SCHEMA cùng có, 89-table]; 🔑 reviewer-FLAG F8 "mig rớt khỏi commit" loại-trừ 3 lớp — mạnh nhất = `GET /approval-workflows-v2` trả `allowApproverDelete` ×54 **materialize qua EF từ DB thật** (thiếu cột thì query đã ném) · verbatim → `archive/2026-07.md` @S157-curate)_
- _(**S135 #407 `4510cea` mã-dự-án normalize + PE attach-gate GO 5/5** — gate 532 [45+487, +4 delta-proof]; NO-Mig `git diff -- *Migrations*` EMPTY + history-top unchanged; js-rotate/css-frozen ×2 · verbatim → `archive/2026-07.md` @S155-curate)_
- _(**S134 #399 `6664a61` PE lũy-kế tạm-tính (0-mig) GO 5/5** — gate 528 [45+483, +8 PePendingAccumulation]; js+css rotate ×2 admin `BVCukFP5`/`CBzUlgOA` eoffice `DoxyEOxh`/`BHsBUA8e`; byte-verify #77 urllib-BYTES; 🔑 **ct=text/html discriminator SẠCH HƠN size-919B** [shell size drift per-build]; `body.count(marker.encode())` bulletproof cp1252 · verbatim → `archive/2026-07.md` via `_INDEX`)_
- _(**S133 #398 `d4fbced` PE budget-freeze + Mig 67 `AddPeApprovedBudgetSnapshot` APPLIED-PROD GO 5/5** — gate 520 [45+475]; 11-col ApprovedBudget\* + backfill 18/18 DaDuyet + 89-table; js+CSS rotate ×2 [badge utility-class → CSS content-hash đổi, benign #69]; python text=True crash cp1252 → text=False bytes+json.loads · verbatim → `archive/2026-07.md` via `_INDEX`)_
@ -62,7 +63,7 @@ cicd-spawn đôi khi trả memory-curation slice ("Compressing S112/S111") thay
- **Gitea:** `git.baocaogiaoduc.vn/vietreport-admin/solution-erp` · workflow `.gitea/workflows/deploy.yml` · paths-ignore 7-entry (D10 S111 #495): `['docs/**','**/*.md','.claude/skills/**','.claude/agent-memory/**','.claude/workflows/runs/**','.gitignore','scripts/**.md']`. Anon API works (public repo) when GITEA_TOKEN absent.
- **Prod:** api/admin/eoffice `.solutions.com.vn` · SSH `ssh vietreport-vps` (Administrator, id_ed25519) · IIS phys paths: API `C:\inetpub\solution-erp\api` · admin `\fe-admin` · user `\fe-user`. DB `.\SQLEXPRESS`/`SolutionErp`/`vrapp` SQL-auth. **Conn key = `ConnectionStrings.Default` (NOT `DefaultConnection`)**. DB pw = `buKL3TGBkD0wDDbYVw65QeX9` (User Id=`vrapp`; Password field has NO `vrapp/` prefix S89 login-failed when prefix included; read verbatim from prod `appsettings.Production.json` ConnectionStrings.Default when `$env:PROD_DB_PASSWORD` empty). skill-doc path `C:\inetpub\apps\SolutionErp\Api` STALE.
- **SSHPS quoting (S42):** nested bashsshpowershell mangles `$var`/`\"` use `iconv UTF-16LE | base64` `powershell -EncodedCommand $B64`; OR write ps1-file + `powershell -File $(cygpath -w)`. sqlcmd over SSH direct `-W -h -1` pw-inline. sys-catalog string-concat `COLLATE DATABASE_DEFAULT` (collation conflict).
- **Tests baseline:** **551 PASS** (45 Domain + 506 Infra · 0 fail/skip; run #416 `b1bae77` 07-27; prior climb 532/528/520/509/505/501/495/486/458/440/421). Phase 9 UAT skip OK. 🔑 **Concrete count via web-UI log `https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions/runs/{run_number}/jobs/0/logs` (~18KB, NO `/api/v1/` prefix — api/v1 runs+tasks logs BOTH 404) → per-project `Passed! - Failed: 0, Passed: N, Skipped: 0`. Delta-proof new-tests = compare prev-run count (dotnet summary hides names). status=success alone ⟹ gate-passed (tests pre-deploy).**
- **Tests baseline:** **562 PASS** (45 Domain + 517 Infra · 0 fail/skip; run #419 `a52a91e` 07-28, khớp canonical `docs/STATUS.md:452` cả tách-phần; prior climb 551/532/528/520/509/505/501/495/486/458/440/421). Phase 9 UAT skip OK. 🔑 **Concrete count via web-UI log `https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions/runs/{run_number}/jobs/0/logs` (~18KB, NO `/api/v1/` prefix — api/v1 runs+tasks logs BOTH 404) → per-project `Passed! - Failed: 0, Passed: N, Skipped: 0`. Delta-proof new-tests = compare prev-run count (dotnet summary hides names). status=success alone ⟹ gate-passed (tests pre-deploy).**
- **Mig latest repo: Mig 68 `AddPeAllowApproverDelete`** (`20260727033522`, S155 `b1bae77` AddColumn `AllowApproverDelete` bit NOT NULL def-0 trên **`ApprovalWorkflowLevels`**, no-new-table; VERIFIED-APPLIED-PROD history-top + col-present + sys.tables **89**). Prev Mig 67 `AddPeApprovedBudgetSnapshot` / 66 `AddPeApprovedPriceRange` / 65 backfill-invariant / 62 `ExpandSupplierFields` (full table docs/CLAUDE.md). Path `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/` (68 `.cs` excl Designer/Snapshot). Prod check `sqlcmd __EFMigrationsHistory ORDER BY MigrationId DESC`. **`sys.tables`(is_ms_shipped=0)=89** AddColumn/data-only/enum-additive don't change count; no-new-table commit 89 correct, don't FAIL. **NO-Mig proof = history NOT-advance + empty `git diff <base>..<head> -- '*Migrations*'`.**
- **Bundle hash live:** ship-baseline = run #416 (07-27) admin js `CiUBEEJr`/css `DX5ew0wg` · eoffice js `DFh7GK0t`/css `BHsBUA8e` (real-size 1,670,035/1,570,257b; LM 12:41:28/12:42:22+07). PER #69 TWO-MODE = SNAPSHOT-per-run NOT stable-baseline (rotate on real-src, freeze byte-id on 0-src) ALWAYS re-snapshot LIVE post-success; **ship-proof = LM-in-window + real-size (vs 900b `ct=text/html` SPA-trap) + marker-grep, NOT hash-delta**. js-rotate/css-frozen = FE-logic-no-style fingerprint (S134-refine: `ct=text/html` cleaner discriminator than 919b, shell size drifts per-build). idrun_number (head_sha-keyed).
- **Bearer:** admin `admin@solutions.com.vn/Admin@123456` (full) · UAT `nv.test@solutions.com.vn/TestUser@123456` (Drafter CCM, gotcha #44 check).

View File

@ -43,3 +43,10 @@
## Run #407 `4510cea` (2026-07-23) — moved from L1 @S155 curate, byte-exact
- **07-23 verify 4510cea (App: chuẩn-hóa mã dự-án normalize + PE attach-gate FE both-apps) [em-main spawn, return CLEAN]:** VERDICT **PASS 5/5** — Run **#407** (id=521) success ~5m36s (17:11:54→17:17:30+07); gate **532 EXACT từ log** (45 Domain + 487 Infra, 0 fail/skip) — **+4 vs prev run #406/8b6df0a (483I)** = 4 `ProjectCodeNormalizationTests` (delta-proof: dotnet summary KHÔNG in tên-test riêng → dùng delta prev-run + build-success + all-pass). NO-Mig: `git diff 8b6df0a..4510cea -- *Migrations*` EMPTY + prod history-top `AddPeApprovedBudgetSnapshot` (Mig 67, từ S133 KHÔNG phải push này) = repo-HEAD unchanged + sys.tables **89** — code-only no-drift by-construction. **Bundle JS rotate cả 2 app / CSS FROZEN cả 2** (đúng dự-đoán — PeDetailTabs.tsx ×2 = pure button-gating logic, no new Tailwind utility): admin js `DGPE6Nkb`→**`B2j1LQ-v`** css `CBzUlgOA` frozen · eoffice js `DlTwAgJj`→**`C3wbJegk`** css `BHsBUA8e` frozen; real-size 1.660.902/1.567.232B, LM 17:16:01/17:16:54+07 in-window; SPA-trap control fake-hash `index-ZZfakehash0.js`=900B **ct=text/html** (discriminator OK). smoke 4×200 (health/live+ready, admin, eoffice). Baseline shift: **Infra 464(S118)→483(run406)→487**, Mig-latest = **Mig 67** ("Mig 66" essentials-line STALE — updated). Pre-deploy snapshot captured WHILE running (đúng bài #242 verify-post-success). Tag `[run-407, pass-5-5, js-rotate-css-frozen, delta-proof-+4, code-only-no-mig]`
---
## Run #416 `b1bae77` (2026-07-27) — moved from L1 @S157 curate, byte-exact
- **07-27 verify b1bae77 (Workflow: quy-trình duyệt TẠI CHỖ + cờ F6 `AllowApproverDelete` đợt-1) [S155, MIG-BEARING deploy, CLEAN-return]:** VERDICT **PASS 6/6** — Run **#416** (id=529) success **5m31s** (12:37:18→12:42:49+07); gate **551 EXACT từ log** (45 Domain + **506** Infra, 0 fail/skip) — **+19 vs run #407 (532)**, **KHỚP CHÍNH XÁC số lead đo local (551)** = cross-check 2-nguồn. **Mig 68 `20260727033522_AddPeAllowApproverDelete` VERIFIED-APPLIED-PROD** (AddColumn `AllowApproverDelete` bit NOT NULL default `(CONVERT([bit],(0)))` trên `ApprovalWorkflowLevels`; history-TOP + `INFORMATION_SCHEMA.COLUMNS` **cả 2 cùng có ⟹ không lệch**; sys.tables **89** giữ nguyên đúng AddColumn-no-new-table). 🔑 **Reviewer FLAG F8 (mig-file rớt khỏi commit ⟹ `Invalid column name` hạ 7 module V2) LOẠI TRỪ bằng 3 lớp:** (i) pre-deploy baseline 12:38 history-top còn `AddPeApprovedBudgetSnapshot` ⟹ mig áp TRONG cửa-sổ này không phải sẵn có; (ii) smoke 8/8 HTTP 200 `Invalid column name`=0 (PE·HĐ·Đề-xuất·Nghỉ-phép·Tăng-ca·Công-tác·Đặt-xe + AwV2); (iii) **phép mạnh nhất = `GET /api/approval-workflows-v2` trả `allowApproverDelete` ×54 materialize qua EF từ DB thật** — DB thiếu cột thì chính query này đã ném. Endpoint mới `PUT /api/approval-workflows-v2/{id}` no-token → **401** + **control route bịa → 404** (discriminator sạch, 401 có nghĩa). Bundle **JS rotate CẢ 2** (admin `hHISK1Ig`→**`CiUBEEJr`** css `CBzUlgOA`→**`DX5ew0wg`** rotate; eoffice `CJeXZso2`→**`DFh7GK0t`** css `BHsBUA8e` **FROZEN** = #69-REFINE lành tính, 2 file fe-user là logic/type no-new-utility) real-size 1.670.035/1.570.257B, LM 12:41:28/12:42:22+07 **in-window**; byte-verify #77 marker `allowApproverDelete` admin ×7 / eoffice ×1 ⟹ đúng mã F6 đã ship. SPA-trap control `ct=text/html` 900/876B. health live+ready 200. Tag `[run-416, pass-6-6, mig-bearing, F8-averted-3-layer, col-materialize-x54, js-rotate-both, gate-551-khớp-local]`

View File

@ -136,4 +136,5 @@
- 2026-07-14 · S118 #389 `c808b9a` SECURITY-AUTHZ ReportsController→Reports.Read… · PASS · `2026-07.md` · substring:"S118 #389 (rn 389, id 503)"
- 2026-07-16 · S126 #394 `e9124fc` GOVERNANCE-TOOLING GO — gate 509 exact, bundl… · PASS · `2026-07.md` · substring:"S126 (2026-07-16) run 508/#394"
- 2026-07-17 · S133 #398 `d4fbced` PE budget-freeze + Mig67 AddPeApprovedBudgetS… · PASS · `2026-07.md` · substring:"S133 (07-17) verify d4fbced"
- 2026-07-17 · S134 #399 `6664a61` PE lũy-kế tạm-tính (0-mig) GO — js+css rotate… · PASS · `2026-07.md` · substring:"S134 (07-17) verify 6664a61"
- 2026-07-17 · S134 #399 `6664a61` PE lũy-kế tạm-tính (0-mig) GO — js+css rotate… · PASS · `2026-07.md` · substring:"S134 (07-17) verify 6664a61"
- 2026-07-27 · S155 #416 `b1bae77` Workflow duyet-TAI-CHO + co F6 AllowApproverDelete… · PASS · `2026-07.md` · substring:"Run #416 `b1bae77` (2026-07-27)"

View File

@ -28,3 +28,15 @@
**Vết vận-hành:** dính #53 ×1 (return kể ý-định `"Git check clean… Now writing mục E…"`, `tool_uses=22`, đĩa đã 19.437B) → resume 1× → CLEAN. 🔴 **Ghi-đĩa-trong-lúc-làm cứu trọn**; nếu gom cuối thì mất 19KB.
**Containment:** 0 residual-write. `_mind-s-7.md` giữ nguyên 14.707 B (lead single-writer). 🔴 Verify bằng `git log --name-only origin/main..HEAD -- <path>`**KHÔNG dùng `git status`**, nó mù đúng 4 path Stop-hook tự commit (`.claude/sessions/` là 1 trong 4).
## S158 (2026-07-28) @close L7 — `CTX-AUDIT: TRUOT — 13 diem` [LEAD SEED ON-BEHALF @closeout M9, theo yêu-cầu đích danh của chính mày; nguồn = `runs/2026-07-28-S158-bookend-close/sub-ctx-audit-close-S158.md` 29.734 B]
- 🔴 **Mồi-ngầm: CHẤM ĐƯỢC, và MỒI ĐÃ RƠI.** Chấm bằng **grep NỘI DUNG** (neo `:99` đã mục từ lúc sinh — không dùng). Mồi còn sống 3 anchor (`:250` bản gốc §D `{mới-nêu}` · `:237` §C · `:209` gist MIND-1 **sống sót 2 lần nén**) nhưng **0 hit ở MIND-2/3/4 §D**, 0 dòng khai — trong khi khuôn "đóng-CÓ-KHAI" tồn tại và **được dùng đúng ở ca Q2 ngay bên cạnh**.
- 🔴 **Defect GỐC chưa vá (nặng hơn cả mồi):** `session-start.md:285` §2.1.9(f) và `session-end.md:159` §L.b(vi) **vẫn dùng `git status --short`** làm post-wave assertion; `grep "name-only origin/main"` trong harness doc = **0 hit**. Guard mù đó vừa chạy **đúng 2 lần trong chính phiên này**. ⇒ mồi không chỉ rơi, nó rơi **đúng lúc thứ nó cảnh báo đang tái diễn**.
- **Nghề đo tự dùng:** kiểm containment bằng `git log --name-only origin/main..HEAD` **thay** `git status` — đúng bài chính mồi này dạy. Giữ nếp đó.
- **FLAG-2 HIGH — mở rộng vai-2:** MIND-3 §D có **11 ý** = 1 đóng-có-khai (Q2) + 2 carry + **8 RƠI IM-LẶNG** (gồm 3 ý `{gần-chốt}`). Header `_mind:140` tự khai *"MIND-4 đã nhận lại các ý còn sống"***sai 8/10**. 🔴 **Con-trỏ chỉ SAI CHIỀU tệ hơn im lặng.** Công bằng: cùng khuôn header ở MIND-2 **đúng 5/5** ⇒ hỏng ở **1 cửa quá tải (PAUSE-4)**, KHÔNG phải khuôn hỏng.
- **Cơ-chế n=2 (đường thoát không máy nào canh):** ý rời **§D (có nhãn, máy canh) → §C (không nhãn)** rồi biến mất. `mind-check` phụ-9 chỉ hỏi *"ý ĐANG ở D có nhãn chưa"*, không hỏi *"ý TỪNG ở D nay đâu"*. Mồi và `#53` đi **cùng một đường**.
- **FLAG-3 HIGH (cấu-trúc, tái mỗi phiên-logic):** `grep "_mind" session-end.md` → hit **duy nhất** là khoản gọi chính mày ⇒ **@close KHÔNG có bước refresh `_mind`**; ≥9 spawn closeout **không có chỗ vào mục E**, mà trần 92,48% chặn MIND-5 ⇒ L7 đóng với **dòng-sống thủng trọn window-5**.
- **FLAG-0 + tự đính-chính (giữ làm nếp):** nháp đầu mày chấm *"máy chạy sai mode"***SAI, tự sửa trên đĩa** (`session_ctx.py:713` `--closed` auto-on khi có `_end`; `_end` chưa có ⇒ `mode=open` đúng). Nhưng lòi ra thứ nặng hơn: `session-end.md:162` hứa *"máy TRƯỚC vai (mind-check full + closed-check §6.3-bis)"* trong khi `:383` đặt closed-check **SAU khi ghi `_end`** = sau slot vai ⇒ **phép nghiêm nhất của lớp mềm (GAP-#9) không mắt độc-lập nào đọc**, chỉ lead — người bị chấm — đọc. **GHI ⟂ KIỂM hở đúng chỗ có răng nhất.**
- **8 khoản ĐẠT** gồm kiểm-vết 2 vai anh em: vai-1 điểm (#6) verbatim **fix đã LAND thật** (6× `xem PAUSE-`, 0 lời anh dưới marker); vai-2 được lead **tái-ĐO** chứ không nhận suông.
- Tag `[s158, moi-ngam-CHAM-DUOC-va-DA-ROI, defect-goc-git-status-chua-va, con-tro-sai-chieu-te-hon-im-lang, D-sang-C-roi-bien-mat, close-thieu-refresh-mind, ghi-vuong-kiem-ho, seed-on-behalf]`

View File

@ -12,6 +12,12 @@
**Nấc THẬT:** `file-land @S153`**spawn-probe ALIVE CHƯA CÓ** (T9 phiên sau restart CLI); lượt chạy đầu = dogfood 4-cửa @T9. Wire: `tiep.md §3-ter`.
Tag `[s153, sinh-ra, owner-veto-3-vai, rename-hub-form-nghich-ly-vipix, vai-2-nap-lai-@tiep, lead-phai-nhac-lai, chua-spawn-probe]`
- **S158 (2026-07-28) @`/tiep` L7 window 5 — verdict `CO-CO 8 cờ` `[LEAD SEED ON-BEHALF @closeout M9 — mày CHẠY THẬT nhưng KHÔNG tự ghi; nguồn = `_tiep-4.md` + xác nhận H2 `grep -c S158`=0]`:** cờ NẶNG nhất **K3****7 ý mục D của MIND-3 rơi IM-LẶNG sang MIND-4, 0 khai**, trong khi header nén MIND-3 **tự khai** *"MIND-4 đã nhận lại các ý còn sống"***claim BỊ BÁC bằng grep** (`ring5`/`slot (41)`/`liên-lane`/`mẫu-số`/`vòng KIỂM`/`nhịp` = 0 hit). Đây là biến-thể mày đã học @S156 (*"LUÔN diff tập-ý D block-trên vs block-dưới"*) — nay nâng 1 nấc: **header nén TỰ TUYÊN đã bảo toàn = phải kiểm, đừng tin** (lớp `absence_looks_like_clean`).
**2 nghề rẻ mà ăn tiền, dùng lại lần 2 và trúng cả 2:** (a) **đo byte từng block** ⇒ bắt trần 92,5%, dư 2.463 B, MIND-5 cần 6.536 B, MIND-1 chỉ còn 1.868 B ⇒ **luật nén KHÔNG đủ chỗ** — lead re-đo độc lập xác nhận, thành câu chờ-owner (45); (b) **chạm ĐĨA bác chú-thích** ⇒ đóng cờ C9 cửa trước (`sub-implementer-backend-1.md` CÒN SỐNG 3.499 B).
🔴 **Cờ K1 nhỏ mà đắt:** ý *"thứ tự wave"* chỉ còn sống ở `WAL:24`, **0 hit** trong `_mind`+`_context` ⇒ WAL bị §6.4 reset là mất hẳn. Bài: ý chỉ-sống-ở-WAL = ý **sắp chết**, phải nêu để lead di-trú.
🔸 **Lead re-đo bác 1 điểm của mày (nhận):** mày báo `Gate 5 anchor` *"chưa có nhà"* — thật ra `WAL:18` đã có; nhưng `lead-gap` sau đó chứng **WAL sắp bị reset** nên kết luận *"vô gia cư"* vẫn đúng ở tầng hệ-quả.
Tag `[s158, lan-chay-2, header-nen-tu-tuyen-phai-kiem, do-byte-tung-block-lan-2, y-chi-song-o-WAL-la-y-sap-chet, seed-on-behalf]`
> **Persistent diary cross-session.** Auto-injected first ~200 lines at spawn (L1 HOT).
> Update BEFORE every stop. Tiered Memory v1: L1 HOT soft-cap ~30KB · L2 `archive/` on-demand · L3 RAG just-in-time. Keep entry ≤ 1.5K chars (gotcha #53).
> **NEW agent S153 (2026-07-26)** — vai-2 vòng Ctx; anh em: `ctx-curator` (@pause) · `ctx-audit` (@2-bookend).

View File

@ -8,6 +8,7 @@ Read-only INTERNAL audit SOLUTION_ERP. Tools: Read/Grep/Glob/Bash + 5 RAG MCP. O
- NOT: external docs/CVE/lib investigator-api · write implementer · test test-specialist · architecture decision em main
## 📌 Recent invest (1-line digest; full detail → archive/runs/git)
- **S157 (07-28) KH-ký-kết-HĐ b.712 AB đĩa, §CD PENDING lượt sau, `runs/2026-07-28-S157-ke-hoach-ky-ket-hd/sub-invest-kehoach-1.md`]:** Owner chốt O-1 *"cấu trúc trình ký GIỐNG, khác nội dung"* tái dùng khung V2, dựng 7 bảng NỘI-DUNG `ContractSigningPlan*` (Mig 69 thuần CreateTable; mig cuối=68 verify ls) + `ApplicableType=10` (slot trống `ApprovalWorkflow.cs:53-67`). 🔴 Bẫy twin MỚI: **Proposal-lite ApproveV2 PHÁ OR-of-N** `ProposalFeatures.cs:427-439` flatten global-level + `ElementAtOrDefault` match 1-user, entity không StepIndex (`Proposal.cs:27`) 2-row-cùng-Order thành AND tuần tự; KH service PHẢI copy `ContractWorkflowService.ApproveV2Async:217-394`, Proposal chỉ làm khuôn CRUD/menu/FE. Twin đo thật: Proposal BE 849 · FE 1.956 LOC · 4 bảng (Mig 38 grep CreateTable) · PE 6.5K/14.9K cận trên. `ConflictException :115-116` tự xác minh đĩa (skill contract-workflow stale fallback V1 chỉ sống đường display). ISO doc 9 bước `ContractPhase` 1-9 khớp 1:1 (7 LEGACY = ISO mã-hoá cứng); khúc b.7-12 thiếu CẢ ISO-doc lẫn code; FO-002.01 luật auto-pass-quá-01-ngày (mâu thuẫn V2 no-auto-approve; O-2 SLA=tham-khảo). #53: coordinator chặn skeleton-rỗng @202K-token cắt còn §AB, Edit-liền-tay từng mục. Tag `[s157, ke-hoach-ky-ket, proposal-lite-breaks-or-of-n, iso-9-steps-eq-contractphase]`
- **S156 (07-27) BCH post-CEO flow bước 721 0-§36 đĩa, §4-§5 PENDING lượt sau, `runs/2026-07-27-S156-bch-post-ceo-flow/sub-invest-bch-1.md`]:** Verdict **LAI** 1321 TÁI DÙNG Contract (7 dòng `[LEGACY]` `ContractPhase.cs:11-13` chính trạm 13-21 đã gỡ CỐ Ý Mig21/S17; V2 `ContractWorkflowService.cs:217-394` cookie-cutter sẵn, terminal gen-mã+DaPhatHanh) · 7-12 DỰNG MỚI (0-hit shopdrawing/TVGS, khuôn 12-bis + `ApplicableType=10` append-only). 🔴 Chuỗi "cơ-chế đúng, thứ đi qua KHÔNG " phía HĐ: cầu PE pin V1 (`CreateContractFromEvaluationFeatures.cs:68-71,108`) không nhận V2 + UpdateDraft không re-pin · `GetEligiblePhases` (`ContractFeatures.cs:334-351`) + inbox `PhaseActorRoles` (`:363-372`) 100% LEGACY-phase approver V2/BCH KHÔNG xem/inbox được ChoDuyet · `CeoApprovalThreshold` 0-consumer (bước-18 ">5 tỷ" chưa có máy) · SLA V2 hardcode `AddDays(7)` 3 site, Step không có SlaDays · notify chỉ Drafter (`:407`) · `AttachmentPurpose` thiếu ký-nháy (enum-extend 0-mig tiền lệ PE=4) · HĐ TraLai reset-toàn-phần không 4-mode. Mig 68 `AddPeAllowApproverDelete` ĐÃ land 07-27 ⇒ mig kế = 69. Bắt lead sai grounding: 12 enum/7 LEGACY (lead ghi 9/6) — lead nhận. #53 strike-1 (return bốc hơi, đĩa nguyên → lead đọc từ đĩa, không redo). Tag `[s156, bch-post-ceo, verdict-lai, eligible-phases-legacy-only, bridge-pins-v1]`
- **S155 (07-27) PE xóa-phiếu màn DUYỆT [24 finding, `runs/2026-07-27-S155-pe-delete-approver/sub-invest-be-1.md`]:** DELETE `/api/purchase-evaluations/{id}` ĐÃ CÓ (`PurchaseEvaluationsController.cs:146`, authz = class `[Authorize]` TRẦN) nhưng allow-list `{DangSoanThao,TuChoi}` (`PurchaseEvaluationFeatures.cs:1404`) chặn ChoDuyet. `Remove()`=**SOFT** gián tiếp qua `AuditingInterceptor.cs:56-62` — lớp #81-EXT indirect. Lũy kế: `PeBudgetAccumulator.cs` 2 hàm/4 call-site DUY NHẤT; ChoDuyet ăn số **2 chỗ** (`ComputeAsync:54` PrevSubmitted + `ComputePendingAsync:114` PendingSelected); `TraLai` KHÔNG triệt tiêu; `TuChoi` rơi khỏi 100% phép cộng. Query 0 dòng `IsDeleted` → dựa global `HasQueryFilter` (`PurchaseEvaluationConfiguration.cs:84`) ⇒ soft-del TỰ rớt, không sửa accumulator. Snapshot Mig67 KHÔNG re-compute. 🔴 Cascade 6 FK (`:75-80`) **không bao giờ chạy** vì soft ⇒ con `BaseEntity` ở lại = rác ẩn. **Git khảo cổ TRÚNG:** "chỗ cho hủy" = nút Từ chối, gỡ `6db195d` 12-06 S60; guard `PurchaseEvaluationWorkflowService.cs:101-106` còn sống tự trỏ "Xóa phiếu khi còn Bản nháp" = chính cái lỗ. 0 tiền lệ hủy chứng-từ in-flight; khuôn gần nhất `CancelMeetingBookingHandler` (`MeetingFeatures.cs:457`, Status=Cancelled NOT IsDeleted). Tag `[s155, pe-delete-approver, s60-tuchoi-removal-hole, soft-delete-no-cascade]`
- **S155 (07-27) PE xóa-phiếu FE/authz-slice [18 finding, `runs/2026-07-27-S155-pe-delete-approver/sub-invest-fe-2.md`]:** Khối HÀNH ĐỘNG = `components/pe/PeWorkflowPanel.tsx:458-506` **byte-identical 2 app** (md5 `02671be6…`, cùng PeDetailTabs/PeListPanel/ListPage) ⇒ sửa-1-bên-là-sót. Gate 3 tầng: `?pendingMe=1``readOnly={!pendingMe}` (`ListPage:590`/`:676`) · `next=workflow.nextPhases` BE-source (`:257`) · `blockedByV2Level` (`:99-103` isAdmin ∥ actor∈currentApproval.approvers). 🔴 Plumbing xóa ĐÃ NỐI SẴN vào màn duyệt: `onDelete={del.mutate}` truyền ở `ListPage:573`+`:668` (`api.delete('/purchase-evaluations/:id')` `:90`) nhưng nút chết vì `PeDetailTabs:445` đòi `mode==='workspace' && canEditPhase && !readOnly`; nút hiện chỉ ở `:460` `phase===DangSoanThao`. **Authz 2 tầng:** PE vùng FE = **0-hit** `usePermission|PermissionGuard` (guard chỉ sống ở Master+Users, khuôn `DepartmentsPage:101 action="Delete"`); `menuKeys.ts` KHÔNG có const `Pe_*` (chỉ root `:23`) — `Pe_*` sinh BE `MenuKeys.cs:134-141`, seed `DbInitializer:1870-1877`, FE khớp bằng regex `Layout.tsx:120` (fe-admin `:107` **LỆCH**, thiếu WfView). 🔴 `Pe_*` **KHÔNG ∈ `MenuKeys.All`**`Program.cs:82-89` không đăng-ký policy `Pe_*.{action}` (0 dynamic provider) ⇒ dùng `[Authorize(Policy="Pe_…")]` = policy-chưa-tồn-tại; **dùng được ngay = `PurchaseEvaluations.Delete`** (root ∈ All, + `GetMyMenuTreeQuery:66-72` cho `Pe_*` KẾ THỪA cờ CRUD từ root ⇒ 0 key mới, 0 migration). Ma trận enumerate `db.MenuItems` (`PermissionFeatures.cs:20`) nên ô Delete đã hiện sẵn. Q6: thêm-nút KHÔNG kích 4-place (0 route/page/staticMap `Layout.tsx:56-106`); `Pe_*` resolve nhánh regex `:119-134` KHÔNG qua staticMap. Tag `[s155, pe-delete-fe-authz, two-app-byte-identical, pe-keys-not-in-All]`
@ -65,3 +66,15 @@ Prod: `ssh vietreport-vps` powershell-wrapper `sqlcmd -S '.\SQLEXPRESS' -d Solut
## S152 (2026-07-25) — R1 retention-note không-fabricate [M9 on-behalf lead]
- **KHÔNG fabricate — uncertain thì nói "uncertain" + reason:** finding không chứng được từ đĩa/DB phải khai uncertain kèm lý-do thiếu-chứng, KHÔNG lấp bằng suy-đoán (tiền lệ tốt: A/018 S117 — verify prod-DB `Phase=ChoDuyet` trước khi phán "lũy kế đúng", thay vì đoán theo lời UAT). Claim ≠ chứng: mọi số kèm lệnh. Tag `[s152, r1-retention, no-fabricate-uncertain-reason]`
## S158 (2026-07-28) — `/fable-real` adap `day-wake-probe-first` [LEAD SEED ON-BEHALF @closeout M9 — mày chạy THẬT (Fable, 222K tok, 20 tool-use) nhưng KHÔNG tự ghi; nguồn = `runs/2026-07-28-S158-day-wake-probe-first/sub-invest-day-1.md` 25.440 B + adap-synthesis]
- **Return CLEAN 0-garble** giữa một closeout mà **7/8 lane khác đều `#53`**. Khác biệt DUY NHẤT: prompt ép **ghi đĩa từng phần trong lúc làm** + **verify RUỘT có chữ trước khi return**. ⇒ datum củng cố: chống `#53` = **thiết-kế artifact**, không phải prompt.
- 🔴 **BÁC 2 tiền-đề của LEAD — đây là giá trị chính của lượt này, không phải bản đề-xuất:**
(a) *"SE có squash ⇒ có sha mồ-côi"* → đo `cat-file -e` + `is-ancestor` trên 8 marker = **sống 8 / mồ-côi 0**; squash `session-end` chỉ gọt trailing-`wal:` **chưa push**, 6/8 sha đã push. **Vẫn giữ guard** vì tiền lệ S127 dangling có thật + chính feature `/day` tự đẻ điều kiện orphan.
(b) *"probe nên tái dùng Sàn-3"***BÁC bằng bằng-chứng CÙNG CỬA**: Sàn-3 ② HIT ⟂ anchor-delta 0 CLEAN, verdict **NGƯỢC NHAU** vì hỏi **2 câu khác nhau** (*"tồn-tại việc dở"* neo `origin/main`*"đổi so điểm dừng"* neo marker pause) ⇒ dựng phép-2 KHÔNG vi phạm B1.
**Nghề rút ra:** khi lead nêu sẵn một hướng nghiêng, cách bác mạnh nhất là **tìm một cửa mà 2 phép cho verdict ngược nhau** — mạnh hơn mọi lập luận về nguyên tắc.
- **Nghề đo đáng giữ:** anchor = **carrier-commit** `git log --diff-filter=A -1 -- <marker>` (commit ĐẦU TIÊN thêm chính file đó) — 8/8 resolve, **sống-sau-squash by construction**, và **nuốt luôn bẫy-anchor-lệch-1-nhịp** mà hub phải xử bằng bước resolve riêng. Mạnh hơn form của hub.
- **Đo BYTE, CẤM quy token** (chính lỗi làm thư hub trượt vòng r1: dán nhãn "token tự đo" lên proxy ký-tự). `tiep_reload` SE = **122.115 B / 5 nguồn**; nền SE **nhẹ hơn hub 3,6×** ⇒ đừng mượn số hub bán lợi ích.
- **2 phát hiện ngoài đề-bài, cả 2 lead xác nhận:** `docs/HANDOFF.md` segment mới nhất còn **S153** ⇒ nguồn-2 của `tiep_reload` nạp brief cũ **3 nhãn phiên** (vá @S158) · `_tiep-1.md` ghi head-sha **7 ký tự** trong khi 7 marker kia ghi đủ 40 = form drift trong cùng một loại marker.
- Tag `[s158, fable-adap, ghi-dia-cuu-return, bac-tien-de-lead-bang-cua-verdict-nguoc, carrier-commit-anchor, byte-khong-token, seed-on-behalf]`

View File

@ -26,12 +26,13 @@
- [Canonical spec over broadcast](feedback_canonical_spec_over_broadcast.md) — adap khi anh trỏ LỆNH canonical → pull command/§P/ledger, ĐỪNG phỏng-theo broadcast cô-đọng; report-before-stamp (S79)
- [Review presentation & stale config](feedback_review_presentation_and_stale_config.md) — review độc-lập bắt honesty-PRESENTATION gap + stale-config đánh-lừa reviewer; tighten-wording + re-measure TRƯỚC review (S81)
- [Derived-flush = execution](feedback_derived_flush_execution.md) — derived-doc flush khớp canonical owner-set = em-main tự làm KHÔNG gate; chỉ ĐỔI con-số/policy = quyền anh (S84)
- [Cơ-chế đúng, dữ-liệu không có](feedback_mechanism_right_data_absent.md) — lớp ×6; UAT báo "không chạy" ⇒ ĐO DỮ LIỆU PROD trước, đừng đọc/viết code (S157: auto-fill đúng, 57/62 dự án rỗng `Location`)
- [Root-cause over symptom](feedback_root_cause_over_symptom.md) — bug lặp sau band-aid → truy field/case LỆCH-quy-ước vào pattern đã-đúng = fix 1 chỗ; verify "tạo lỗi MỚI còn lặp?" (S85, #72/#73) · **+S122 anh nêu: (i) được-chỉ-1-chỗ ⇒ PHẢI grep cùng-lớp (script thứ-2 lòi ra khi anh hỏi — thoát vì MAY) · (ii) 🔴 bài-học nằm-trong-context KHÔNG tự bật (file này auto-inject mà lead vẫn vá triệu-chứng; +SHA-bịa tái-phạm sau 1 NGÀY) ⇒ chặn được = LUẬT soi-được, không phải trí-nhớ · chứng: hardcode sống 27 ngày qua 1 đợt "double-check" vì nó hỏi "logic đúng?" mà logic VẪN đúng · truy-gốc ≠ tự-sửa-gốc (harness owns → R6 hỏi hub)**
- [Cardinality change grep consumers](feedback_cardinality_change_grep_consumers.md) — đổi field single→multi = grep MỌI consumer; sửa write-site sót read-site → vỡ feature (S87/S88 PE multi-winner)
- [Prod config: inspect-before-change](feedback_prod_config_inspect_before_change.md) — đổi config prod = inspect LIVE trước (runbook STALE); backup→apply→verify-LIVE→commit; replicate mọi rule cũ + delta (S88)
- [Wipe durability — check re-seed](feedback_wipe_durability_check_reseed.md) — sau prod-wipe audit seeder: ungated per-code seed RE-ADD mỗi restart; gate sau env-flag + verify-by-restart-THẬT (S91, #75/#76)
- [Verify deployed artifact byte-level](feedback_verify_deployed_artifact_byte_level.md) — UAT "fix chưa ăn" sau deploy → curl-grep bundle prod byte-level (cache≠deploy); incognito=golden-test (S96, #77)
- [Agent return-garble recover](feedback_agent_return_garble_recover.md) — sub trả wrong-slice-of-transcript thay verdict (#53, **×60-cận-dưới qua S152 — derive-from-body, đếm-cái-chắc** [qua-S148 33 · S149 ×5 · S150 ×7/7 · S151 ×5/6 write-boundary · **S152 ×10 (7 @open + 3-chắc @close, 2 UNKNOWN-sau-compact không đếm; ring2-STRICT + trio = 4 CLEAN cùng phiên; MỚI: pin-bản-cắt 4-A — file ghi-từng-finding LUÔN hợp-lệ giữa chừng, lead pin 16.911B/30.195B mất 3 FLAG → đề END+TOTAL-line chờ owner; commit-subject `1b85713` "53"=SAI errata)** — skeleton-rỗng 2-strike → AS-17; `ngược-#53` ×3 lifetime]; S143 ×5 5/5-sub; +path-4 lead-on-behalf; **+sub-class S150 `ngược-#53`/`skeleton-ruột-rỗng` ⇒ ghi-đĩa-trong-lúc-làm = CẦN KHÔNG ĐỦ — verify byte-content**) → recover: **(0) WRITE-lane→disk-truth (git+build+test) · VERIFY-lane→em-main-re-curl+sqlcmd (2-nguồn-khớp)** → (1) diary → (2) SendMessage-resume in-session → (3) em-main solo; garble ∝ reasoning-lane; **WRITE-lane garble≠mất-code** (S114 ×5); cicd tái-phạm dai + tự-dán "CLEAN-return" sai (harvest-curator bắt S118)
- [Agent return-garble recover](feedback_agent_return_garble_recover.md) — sub trả wrong-slice-of-transcript thay verdict (#53, **×66-cận-dưới qua S158 — derive-from-body, đếm-cái-chắc** [🔴 **S158 = ĐỐI-CHỨNG NỘI-PHIÊN SẠCH đầu tiên (cùng lead/ngày, khác đúng 1 biến): ép-ghi-đĩa KHÔNG giảm garble (2/2 vẫn garble) nhưng đưa thiệt-hại về 0 B** — 4 vai không-ép mất TOÀN BỘ phải resume, 2 vai có-ép mất 0; ⇒ chống #53 = thiết-kế ARTIFACT không phải PROMPT, xác nhận lần 5 · **+2 sub-class**: `skeleton-nấc-2` (1.661B byte>0 mà ruột toàn heading ⇒ guard "verify byte tăng" KHÔNG bắt được) · `engine-process-exit` (0 delta đĩa = lượt chạy chưa từng tồn tại) · **câu garble CHỨA finding thật, đừng vứt** (ring1/ring2 chết ngay chỗ nghĩ sắc nhất) · S153-S157 CHƯA đếm được — "~27" của lead-gap neo bằng SỐ DÒNG `_mind`, ring2 bác, KHÔNG nhập tally]; [qua-S148 33 · S149 ×5 · S150 ×7/7 · S151 ×5/6 write-boundary · **S152 ×10 (7 @open + 3-chắc @close, 2 UNKNOWN-sau-compact không đếm; ring2-STRICT + trio = 4 CLEAN cùng phiên; MỚI: pin-bản-cắt 4-A — file ghi-từng-finding LUÔN hợp-lệ giữa chừng, lead pin 16.911B/30.195B mất 3 FLAG → đề END+TOTAL-line chờ owner; commit-subject `1b85713` "53"=SAI errata)** — skeleton-rỗng 2-strike → AS-17; `ngược-#53` ×3 lifetime]; S143 ×5 5/5-sub; +path-4 lead-on-behalf; **+sub-class S150 `ngược-#53`/`skeleton-ruột-rỗng` ⇒ ghi-đĩa-trong-lúc-làm = CẦN KHÔNG ĐỦ — verify byte-content**) → recover: **(0) WRITE-lane→disk-truth (git+build+test) · VERIFY-lane→em-main-re-curl+sqlcmd (2-nguồn-khớp)** → (1) diary → (2) SendMessage-resume in-session → (3) em-main solo; garble ∝ reasoning-lane; **WRITE-lane garble≠mất-code** (S114 ×5); cicd tái-phạm dai + tự-dán "CLEAN-return" sai (harvest-curator bắt S118)
- [H18 ghost-wire + stamp-integrity](feedback_h18_ghostwire_stamp_integrity.md) — hash-verify TRƯỚC khi áp broadcast (bắt stamp-then-edit THẬT → HELD + re-stamp); ghost-wire 2 class (cron-claim CronList=0 · config-key defined-but-unread); KHÔNG stamp run-id chưa chạy (S100)
- [Resume premise re-verify](feedback_resume_premise_reverify.md) — re-verify tiền-đề từ ĐĨA trước execute (header+git-date, match NỘI-DUNG KHÔNG tên-file 1:1); **S121: bảng-kế-hoạch ≠ đĩa — "không-ai-được-giao" ≠ "chưa-làm"; khẳng-định trạng-thái-đĩa = phải chạm đĩa 1 lệnh**; +bẫy `grep -c` (dòng) vs `-o|wc -l` (occurrence) trên mega-line; +bẫy Get-Content-no-Encoding no-BOM = ANSI đếm ×2-3 → báo-số-sai-owner, đính-chính-ngay (S130 E-010/AS-14); +acceptance literal tự-lão-hoá (S109/S121)
- [Permission grant = 2 layers](feedback_permission_grant_two_layers.md) — cấp/verify quyền = display-layer (menu CanRead) ⟂ API-authz-layer (controller `[Authorize(Policy)]`) 2 tầng ĐỘC-LẬP; grep authz controller đích TRƯỚC khi tin grant (menu-ẩn ≠ API-đóng; `[Authorize]` trần = lỗ hổng); reviewer-adversarial bắt, em-main-solo sót (S118, #82)

View File

@ -5,7 +5,7 @@ metadata:
node_type: memory
type: feedback
originSessionId: 67157d21-1ead-475d-9a50-cf7f07468583
modified: 2026-07-25T18:50:28.119Z
modified: 2026-07-28T13:36:55.402Z
---
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/<role>/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%.
@ -25,4 +25,26 @@ Sub-agent đôi khi trả về message CUỐI = text bước memory-curation c
🔴 **TALLY CHỐT @S152 closeout (2026-07-26) — derive-from-body, đếm CÁI-CHẮC:** 50 (qua S151) **+ 10 S152 = 60 (cận dưới)**. S152 events: **@open 7** = 6/6 first-return wave bookend (lead-stale · lead-gap · tooling · harvest · ring2 · ring1 — 100% reasoning-lane, ghi tại `bookend-synthesis.md` cùng phiên) + ring2-resume vẫn mô-tả-ý-định; **@close 3-CHẮC** = stale-close completion-slice + gap-close first-return-mid-work + ring1-close return-slice. **KHÔNG đếm (khai thẳng):** harvest-close + tooling-close hoàn thành TRƯỚC compaction lead — nhãn return không còn khôi phục được ⇒ UNKNOWN, không bịa (file đĩa 20.411B/26.451B đủ, 0 mất). **CLEAN counter-datum:** trio 3/3 + **ring2-close khuôn STRICT-4-dòng** — 4 lượt return-only/khuôn-cứng CLEAN trong chính phiên 10-garble ⇒ củng cố chiều S151: **thân-return-có-cấu-trúc sống sót; return tự-do sau khi ghi file thì không**. **Family (ngoài tally):** `ngược-#53` ×2 cùng phiên (ring1 resume-1 @open chạy-không-ghi · gap-close 0B @close) — sub-class này nay 3 events lifetime (S150 + S152 ×2), đã có AS-17 guard; countermeasure hiệu-lực = lệnh resume "**đổ-ruột-TRƯỚC-làm-tiếp**" (2/2 lần cứu trọn). **Mới @S152 (ring2 4-A):** kỷ-luật ghi-đĩa-từng-finding có TÁC-DỤNG-PHỤ — file luôn hợp-lệ giữa chừng ⇒ lead PIN bản-cắt 16.911B/30.195B mà không thấy dấu cụt ⇒ 3 FLAG ngoài tầm quyết-định (tally thoát nhờ may) ⇒ đề-xuất dòng chốt `<!-- END … TOTAL=n -->` + lead chỉ nhận pin khi grep-count == TOTAL (chờ owner).
**How to apply:** sub return text lạ (memory-curation/off-topic) → ĐỪNG tin nó fail/vô-dụng; đọc diary lấy kết-quả. Task-cần-chắc (bug-reasoning) → em-main re-do solo (reliable). Liên [[feedback_agent_kill_recovery]] · [[feedback_workflow_fanout_reliability]].
🔴 **@S158 closeout (2026-07-28) — SỔ NÀY ĐÃ ĐỨNG YÊN 5 NHÃN PHIÊN (S153→S158), `lead-gap-auditor` bắt (`gap-incident-unrecorded`, FLAG-3 MED-HIGH).** Chính class mà sổ này đẻ ra @S143 lại cắn chủ. mtime file = 2026-07-26 01:50; `grep -o "S15[3-8]"` = 0/0/0/0/0/0. Ghi bù theo đúng luật của file: **derive-from-body, đếm CÁI-CHẮC, không bịa.**
- **S158 = +6 CHẮC** (lead đếm trực tiếp, cùng phiên): `tooling-auditor` · `harvest-curator` · `lead-stale-auditor` · `lead-gap-auditor` · `ring1-audit` · `ring2-audit`**6/6 first-return**, 100% reasoning-lane (khớp correlation S103). Resume 6/6 ra kết quả đầy đủ. ⇒ **TỔNG = 66 (cận dưới) qua S158.**
- **S153-S157 = CHƯA ĐẾM ĐƯỢC, khai thẳng thay vì bịa.** `lead-gap` dẫn `_mind-s-7.md:199` ×11 + `:181` ×13 ⇒ "~27 cho L7", **nhưng `ring2-audit` bác cách đếm**: nó neo bằng **SỐ DÒNG `_mind`** — đúng thứ mà FLAG-2 của chính lead-gap vừa cấm trong cùng return. ⇒ số đó **không tái-dựng được** bằng đường khác ⇒ **KHÔNG nhập tally**. Muốn đóng: derive từ `runs/*/` + session-log S153-S157, không từ số dòng.
🔴 **COUNTER-DATUM MẠNH NHẤT TỪ TRƯỚC TỚI NAY (S158) — 5 ca cùng phiên, cùng ngày, cùng lead, khác đúng MỘT biến:**
| Vai | prompt ép ghi đĩa? | garble? | mất gì |
|---|---|---|---|
| `investigator-codebase` (Fable, 222K tok) | ✅ | KHÔNG | — |
| `tooling` · `harvest` · `lead-stale` · `lead-gap` | ❌ | ✅ ×4 | **TOÀN BỘ** — 4 lượt resume |
| `ring1-audit` · `ring2-audit` | ✅ | ✅ ×2 | **0 B** (2.818 B + 5.354 B nằm sẵn trên đĩa) |
**Ép-ghi-đĩa KHÔNG giảm tần suất garble (2/2 vẫn garble), nhưng đưa thiệt-hại về 0.** Xác nhận lần thứ 5 liên tiếp: **chống #53 = thiết-kế ARTIFACT, không phải thiết-kế PROMPT.** Đây là lần đầu có **đối-chứng nội-phiên sạch** (cùng lead, cùng ngày, chỉ khác 1 biến) thay vì so chéo phiên.
🔸 **Bonus đo được:** garble của 2 con ghi-đĩa **CHỨA finding thật** trong chính câu chết (`ring1`: *"probe NOW says run-chua-gom 4 but H2 claimed 3"* — hoá ra do LEAD tạo run-folder sau khi probe chạy; `ring2`: *"gap FLAG-3 neo bằng số dòng `_mind`, đúng thứ FLAG-2 vừa cấm"*). ⇒ **đọc câu garble, đừng vứt** — nó là lát cắt transcript tại điểm chết, thường là chỗ vai đang nghĩ sắc nhất.
🔴 **2 SUB-CLASS MỚI @S158 (`lead-gap` FLAG-3 đặt tên — cả hai sổ hiện KHÔNG bắt được):**
1. **`skeleton-ruột-rỗng` nấc-2** — invest lượt 1 đốt **202K tok**, đĩa **1.661 B khung rỗng toàn heading**. 🔴 Bản ghi S150/S151 chỉ dạy *"verify BYTE-CONTENT tăng thật"* — mà **1.661 B LÀ byte > 0 và có tăng** ⇒ guard hiện tại **KHÔNG bắt được ca này**. Phải verify **NGỮ-NGHĨA ruột** (có câu hoàn chỉnh, không chỉ heading), không chỉ byte.
2. **`engine-process-exit`** — tiến-trình CLI thoát giữa lượt, **đĩa KHÔNG đổi 1 byte** ⇒ §C/§D chưa từng ghi. Mode thứ 3, **khác cả `#53` lẫn `skeleton`**: không phải return hỏng, không phải ruột rỗng, mà là **lượt chạy chưa từng tồn tại**. Phân biệt bằng: `#53` = đĩa có + return sai · `skeleton` = đĩa có vỏ + ruột rỗng · `engine-process-exit` = **0 delta đĩa**.
🔴 **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]].
**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]].

View File

@ -0,0 +1,30 @@
---
name: feedback-mechanism-right-data-absent
description: "Lớp lỗi lặp ×6 ở SOLUTION_ERP — cơ-chế ĐÚNG nhưng thứ đi qua nó KHÔNG CÓ; UAT báo \"không chạy\" thì ĐO DỮ LIỆU trước, đừng đọc/viết code"
metadata:
node_type: memory
type: feedback
originSessionId: 85c4bae3-8755-487e-bb4b-d8d8c9135463
modified: 2026-07-28T02:57:02.204Z
---
**"Cơ-chế đúng, thứ đi qua nó không có"** — lớp lỗi đã nổ **×6** ở repo này. Khi anh/UAT báo *"cái X không tự điền / không hiện / không bắt"*, **phép đầu tiên là ĐO DỮ LIỆU PROD**, không phải đọc code rồi suy, và tuyệt đối không phải viết code mới.
**Why:** đây là **ĐẶC-TÍNH KIẾN-TRÚC**, không phải xui: schema DÙNG CHUNG ⟂ service/seed RIÊNG per-loại ⇒ một cột thêm cho loại này mặc-định **CÂM** ở loại kia trừ khi có người nối; và cột có thật thì vẫn có thể **rỗng data**. Cả 6 ca đều **build sạch + test xanh** — không có tín-hiệu máy nào kêu. Nguy nhất: viết code auto-fill "mới" khi code cũ **đã đúng và đang chạy** ⇒ tốn công, đẻ trùng-lặp, mà triệu-chứng y nguyên vì bảng vẫn rỗng.
**6 ca (ca 6 = chiều MỚI: bug do NGƯỜI DÙNG báo, fix ngây-thơ sẽ nhân đôi code đã đúng):**
1. policy tồn tại / 11-trên-13 vai `CanDelete=0`
2. endpoint PUT sống / 0 dây FE gọi
3. policy chặn đúng approver cần dùng
4. DTO thiếu field FE đang đọc
5. PMH role `Procurement` bị 403 ở b.13/b.17 (cơ-chế phân quyền đúng, vai đi qua không có quyền)
6. **@S157 PE "Địa điểm không tự lấy"** — auto-fill `Project.Location` đã wire từ S59 và **chạy đúng cả 4 tầng** (DB cột → `ProjectFeatures.cs:51` projection → FE type → `onChange` SearchableSelect); ô trống vì **prod 57/62 dự án `Location = NULL`** (chỉ 5 dự án có địa chỉ — đúng 5 dòng có địa chỉ trong Excel nhập S55).
**How to apply:**
- UAT báo "không chạy" ⇒ **sqlcmd đếm dữ liệu prod TRƯỚC** (`SELECT COUNT(*), SUM(CASE WHEN <col> IS NULL...)`). Một câu query rẻ hơn một vòng đọc code + một lần sửa nhầm.
- Rồi mới truy dây theo tầng: DB cột → DTO projection → FE type → chỗ tiêu-thụ. Đủ 4 tầng mới kết luận "wire hỏng".
- Data rỗng ⇒ **KHÔNG sửa cơ-chế**. Hỏi owner nguồn dữ liệu; hướng anh chọn @S157*"để người dùng tự cập nhật Master data, cái nào không có thì không fill"* (không backfill hàng loạt).
- Vá đúng cho ca data-rỗng = **lộ LÝ DO tại chỗ** (dòng cảnh báo trỏ nơi bổ sung), vì ô trống im lặng làm người dùng tưởng hệ-thống hỏng → đẻ báo lỗi giả. Xem [[feedback-absence-looks-like-clean]].
- Báo lại cho anh phải nói thẳng *"cơ-chế không hỏng, thiếu dữ-liệu"* — đừng để anh tưởng vừa được sửa bug.
Liên quan: [[feedback-root-cause-over-symptom]] (truy gốc thay vì vá triệu-chứng) · [[feedback-permission-grant-two-layers]] (cùng họ: 2 tầng độc-lập, tầng này đúng không suy ra tầng kia) · [[feedback-cardinality-change-grep-consumers]] (write-site đúng, read-site sót).

View File

@ -11,10 +11,10 @@
},
"_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": 31,
"last_ticked_session": "S157",
"last_ticked_head": "73166c571672b11d14682325c53fbeb22a669716",
"last_ticked_at": "2026-07-27",
"counter": 32,
"last_ticked_session": "S158",
"last_ticked_head": "6c263dde7f85c29165187d44af0e7b302b1bd969",
"last_ticked_at": "2026-07-28",
"last_audit": {
"light_at_counter": 27,
"deep_at_counter": 25,
@ -161,6 +161,11 @@
"at": "2026-07-27",
"session": "S157",
"event": "CLEAN tick (session-counter-tick.ps1 M2): counter 30->31, session S156->S157, head 76488e8->73166c5. Classify-before-tick: no regression (n=157 >= stored n=156); 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-07-28",
"session": "S158",
"event": "CLEAN tick (session-counter-tick.ps1 M2): counter 31->32, session S157->S158, head 73166c5->6c263dd. Classify-before-tick: no regression (n=158 >= stored n=157); last_ticked_head reachable (merge-base --is-ancestor exit 0). 4 fields updated, 1 history entry appended, written atomically (temp + Move-Item -Force)."
}
]
}

View File

@ -138,6 +138,55 @@
- lớp mềm: `_mind-s-7.md` block **MIND-3**
- **verdict `ctx-curator` @PAUSE-3:** xem `_mind-s-7.md` block MIND-3 mục E (vai chạy trong cửa này).
### PAUSE-4 2026-07-28T11:33:17+07:00
> anh: OK đã xong cái spec rồi đúng ko ? Nhớ kỹ cái spec này để turn sau chạy nhé.
>
> /pause
**(1) quyết-định đã CHỐT**
- 🔴 **Anh chốt cấu-trúc trình ký GIỐNG, chỉ khác NỘI DUNG** (nguyên văn: *"Đúng chính xác, cấu trúc trình ký
giống, chỉ khác nội dụng thôi."*) ⇒ phiếu "Kế hoạch ký kết HĐ" **TÁI DÙNG khung duyệt V2**, **0 bảng approval
mới**; dựng mới = NỘI DUNG phiếu. **Hệ quả: trục tranh luận Q2 của S156 ĐÓNG** — reviewer từng chấm Q2
`THIEU-PHUONG-AN` + thiên-vị, nay khỏi viết lại vì trục cơ-chế không còn.
- 🔴 **SLA chỉ THAM KHẢO** (nguyên văn: *"Cái này để tham khảo thôi, ko vấn đề j, đa số là trễ."*) ⇒ KHÔNG
SLA-engine, KHÔNG auto-approve-on-timeout, KHÔNG wave nào cho SLA; **giữ hiển thị deadline**. Lỗ L3
`AddDays(7)` hardcode **rời tập lỗ đáng làm**.
- 🔴 **"Chỗ hợp đồng cứ từ từ"** ⇒ lỗ hổng an ninh HĐ (`ContractWorkflowService.cs:48-66` Reject-trước-guard +
controller class-trần) **treo CÓ CHỦ ĐÍCH**, ghi vào STATUS đúng chữ đó để phiên sau không tự ý vá cũng không
quên. Wave 5 (cầu sang HĐ) vì thế **phải hỏi lại anh** trước khi chạy.
- **UAT Địa điểm — anh chốt KHÔNG backfill**: *"để người dùng tự cập nhật Master data, cái nào không có thì
không fill"*. Vá = cảnh báo amber lộ lý do, ship `6250f39`.
- Lead chốt kỹ-thuật thường-lệ (không đẩy lên anh): **KHÔNG resume invest lần 3** cho §C/§D — H21 ① cho phép
lead ghi spec (§A/§B chính là phần propose); resume = đốt thêm ~250K tok cho thứ lead làm được.
**(2) delta còn SỐNG**
- **Spec `spec-ke-hoach-ky-ket-hd-28-07-2026.md` 45.158 B XONG** (anh xác nhận) — 5 wave, 7 bảng Mig 69.
Review `/fable-clone` **4/4 lane sạch, 112 điểm**; **7 lỗi nặng đã vá**, nhưng verdict lens-wave là
`SUA-TRUOC-W1` với **6 HIGH** ⇒ 7 vá **chưa chắc phủ trọn 6 HIGH** — phải rà trước khi thi công W1.
- **3 việc chờ anh** (ngoài 5 câu thiết kế): nguồn thứ 4 `SOL-PRO-SP-001 Quy trình Cung ứng` chưa ai đọc ·
2 đường kết thúc sớm W3 anh từng phán PHÁ VỠ · thứ tự chạy wave.
- **5 câu thiết kế** = 3 carry S156 (Q3·Q6·Q11) + 2 MỚI sinh trong spec này (O-Q1 gate căn cứ · O-Q2 số hoá
checkbox). 14 câu S156 đã rút còn 5, **và cả 5 KHÔNG chặn W1-W2**.
- **1 thư fan-out mới** `2026-07-28-Governance-day-wake-probe-first-resume` (ai_infra, kênh `all`) — dò thấy ở
cửa này, **CHƯA kéo** (đúng luật: cửa dừng chỉ dò, bookend mới kéo bằng `/adap-apply`).
- Nợ sổ cũ: 22 FLAG governance (42)(43)(44)(E2) — nay **4 cửa-sổ** chưa động · `reviewer/MEMORY.md` 19.049 B
trên ngưỡng · monthly drift-audit **2026-08-01**.
- 🔴 **Luật nén `_mind` HỞ** (phát hiện khi thi hành chính nó): điều khoản *"nén block CŨ NHẤT trừ block-0 và
top"* trỏ MIND-1 — mà MIND-1 **đã nén rồi**; không có nhánh "cũ nhất đã nén ⇒ sang cái kế". Cửa này phải nén
**3 block** (MIND-2 → MIND-1 → MIND-3) mới đủ chỗ. Sau nén còn dư 2.463 B.
**(3) con-trỏ**
- run-folder MỚI: `.claude/workflows/runs/2026-07-28-S157-ke-hoach-ky-ket-hd/``run.md` · **`spec-ke-hoach-ky-ket-hd-28-07-2026.md` (45.158 B)** · `sub-invest-kehoach-1.md` (23.085 B, §C/§D `[PENDING]`) · 4× `sub-review-*.md` · 2 file `src-*.txt` (trích ISO doc + form FO-002.01)
- commit: `6250f39` (cảnh báo Địa điểm) · `a52a91e` (tick+STATUS) · `3b6fabc` (dọn nợ sổ sách) · `d7eaece` (spec+review)
- engine-run: `/fable-real investigator-codebase` **3 lượt** (1 `skeleton-ruột-rỗng` · 2 CLEAN · 3 chết do CLI thoát) · `/fable-clone reviewer` **`wf_57af0163-053`** 4/4 lane sạch
- cicd S157: `.claude/workflows/runs/2026-07-27-S155-pe-delete-approver/cicd-verify-s157-diadiem.md` **PASS 9/9**
- lớp mềm: `_mind-s-7.md` block **MIND-4** (30.305 B sau nén 3 block)
- **verdict `ctx-curator` @PAUSE-4:** `CTX-CURATOR: SUA — 9 điểm` — lead nhận **CẢ 9**. Nặng nhất: **(#2)** quyết
định O-1 **vắng trọn 5 mục** nháp ⇒ ý Q2 ở MIND-3 §D sẽ **rơi im lặng** thay vì đóng-có-khai · **(#6)** 5 chỗ
đóng nháy lời anh = **verbatim trá hình lách rào-1** (máy chỉ bắt dạng blockquote) · **(#7)** nhãn trần sai 2
chiều + bỏ mất phần CÒN SỐNG là luật-nén-hở. 0 tệp vai ghi, 0 commit vai.
---
## (c) STOCK-touched — máy-derive
@ -195,3 +244,6 @@
| `…/S156-bch-post-ceo-flow/sub-review-q2-3.md` | A | `THIEU-PHUONG-AN 14` + thiên-vị-có-hướng |
| `…/S156-bch-post-ceo-flow/sub-review-gaps-4.md` | A | `4/4 THẬT, 0 dương-giả` |
| `…/S156-bch-post-ceo-flow/review-synthesis.md` | A | lead-written · END `TOTAL=35 DIEM` |
> Máy-derive @PAUSE-4: `python scripts/session_ctx.py machine-block --session 7 --json` · anchor = `[CLAUDE] Docs: spec "Ke hoach ky ket Hop dong" S157 …` @2026-07-28T11:30:03+07:00 · `changed_count = 0` · `run_id = wf_1618ae3c-a17` (🔸 **stale** — run THẬT của cửa này là `wf_57af0163-053`; máy đọc run-id cũ, ghi nhận không sửa tay).
> 🔸 **Khai giới-hạn:** `changed_count = 0` **KHÔNG** nghĩa là cửa này không làm gì — anchor CHÍNH LÀ commit `d7eaece` vừa tạo, nên mọi thứ đã nằm TRONG 4 commit của cửa (`6250f39` · `a52a91e` · `3b6fabc` · `d7eaece`). Đây đúng ca mà dòng khai giới-hạn của PAUSE-2 đã cảnh báo.

View File

@ -66,140 +66,156 @@ Máy chỉ quét phần **DƯỚI** marker đóng khối luật (dòng comment c
(`_MIND_TOP_MARKER` trong scripts/session_ctx.py) -- khac khuon `FLOW-START` cua _context (khong may nao doc). -->
<!-- MIND-TOP -->
## MIND-3 — 2026-07-27T17:09:56+07:00 @ b804d96 (window 3)
## MIND-4 — 2026-07-28T11:33:17+07:00 @ d7eaece (window 4)
### A. Gói-turn
- Vào bằng `/tiep` (nhãn-phiên S156, window 3). Reconcile **0 lệch**; đóng nốt 2 mục nợ cicd bằng lead-tự-đo ⇒ arc PE **PASS 6/6**, anh xác nhận đạt (xem PAUSE-3) — số đo ở `.claude/workflows/runs/2026-07-27-S155-pe-delete-approver/cicd-verify-dot2.md`.
- Nhận việc SẢN-PHẨM mới từ ảnh PDF sơ đồ 21 bước: phạm vi **b.7→21**, lane PROJECT (BCH). Chạy trọn `/fable-real invest``/fable-clone reviewer` 4 lăng kính đúng lệnh anh.
- Anh **đặt tên nghiệp-vụ** cho khúc 7→12 = *đề xuất giá trị ký kết hợp đồng* — thứ KHÔNG lượng code nào đọc ra được (xem C).
- Vào bằng `/tiep` (nhãn S157). Reconcile **0 lệch**; `ctx-verifier` `CO-CO 10 cờ`, vá C3 trong cửa.
- UAT Địa điểm: chẩn **DATA-không-phải-CODE** (auto-fill đã wire S59 chạy đúng; dữ liệu prod rỗng), anh chốt không backfill — người dùng tự cập nhật Master data (xem PAUSE-4). Số đo + commit + verdict cicd: **con-trỏ `WAL` mục A3**.
- Việc chính: **spec "Kế hoạch ký kết Hợp đồng"** (khúc thiếu PE→HĐ) — `/fable-real invest` → lead ghi spec → `/fable-clone reviewer` 4 lăng kính → vá 7 lỗi nặng. Spec **45.158 B**, commit `d7eaece`.
- 🔴 **Anh chốt cấu trúc trình ký GIỐNG, chỉ khác nội dung** (xem PAUSE-4) ⇒ tái dùng khung duyệt V2, **0 bảng approval mới****ý `Q2 kiến-trúc khúc 8-12` ở MIND-3 §D ĐÓNG** — không rơi im lặng, đóng CÓ KHAI (spec §1.4).
- Dọn nợ sổ: STATUS dòng CURRENT S153→S157 + §In Progress (đứng S117 suốt 40 phiên) + session-log + 1 memory mới.
### B. Hướng-tiếp + nhánh-đã-loại
- Tiếp: **6 việc sửa bản invest** (`review-synthesis.md` §G) → trình anh bộ 14 câu sạch → chờ Q1-Q6 → mới viết §4 wire + §5 checklist. Song song có **lỗ hổng an ninh HĐ** đã tách chip, chờ anh xếp ưu tiên.
- Nhánh đã LOẠI: ① **viết §4/§5 theo giả-định** — anh chọn review-nền-trước (xem PAUSE-3), reviewer chứng minh chọn đúng: nền có 1 claim sai sự thật + Q2 thiên vị ⇒ wire trên nền đó là đổ công · ② **đòi invest trả trọn 4 mục 1 lượt** — loại sau khi lượt 1 chết ở phần DÀI · ③ **hỏi lại anh vai `invest`** — đề-bài "cách wire" chỉ khớp `investigator-codebase`, hỏi là ma-sát thừa.
- Tiếp: anh dặn nhớ kỹ spec để turn sau chạy (xem PAUSE-4) ⇒ cửa sau **thi công Wave 1** — 🔴 **nhưng phải đóng phần còn lại của verdict `SUA-TRUOC-W1` trước** (7 lỗi đã vá **không** phủ trọn 6 HIGH của lens-wave). **5 câu owner KHÔNG chặn W1-2** (spec bảng wave).
- SLA chỉ hiển thị tham khảo (O-2) ⇒ lỗ **L3 `AddDays(7)`** (WAL mục 4 lỗ) **rời tập lỗ đáng làm**, không chiếm wave nào — spec §1.4.
- Nhánh đã LOẠI: ① **resume invest lần 3** cho §C/§D — H21 ① cho phép lead ghi spec (§A/§B chính là phần propose); resume = đốt thêm ~250K tok cho thứ lead làm được · ② **giữ tên key `Csp*`** — lệch tiền-tố policy ⇒ prod 500 · ③ **bảng `CodeSequences` riêng** — tái dùng `WorkflowAppCodeSequence` dùng chung sẵn.
### C. Kế-hoạch (delta suy-nghĩ)
- 🔴 Delta LỚN NHẤT: **owner cấp Ý-ĐỊNH, agent chỉ cấp HOẠT-ĐỘNG**. Invest (Fable, 146K tok) + 4 lane reviewer đều tả đúng khúc 7→12 LÀM GÌ, không ai nói được nó ĐỂ LÀM GÌ — điều đó không nằm trong repo lẫn sơ đồ. Một câu đặt tên của anh (xem PAUSE-3) làm lung lay 2 câu mà 35 điểm review không chạm: Q2 nhánh (c) yếu hẳn (đẩy đúng phần CÓ phê-duyệt ra ngoài), Q6 gần như tự trả lời. ⇒ **nếp: hỏi "cái này đẻ ra?" TRƯỚC "gồm những bước nào?"**.
- Lớp *cơ-chế-đúng-thứ-đi-qua-không-có* cắn **lần 5**, lộ ra **ĐẶC-TÍNH KIẾN-TRÚC** không phải xui: schema DÙNG CHUNG ⟂ service RIÊNG per-type ⇒ **cột thêm cho một loại mặc-định CÂM ở loại khác trừ khi có người nối**. Chứng: `.claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/review-synthesis.md` §D.
- NGUỒN SỰ THẬT: doc stale **không chỉ sai — nó CHE luôn** cái lệch display⟂guard đáng ra phải lộ (ca: cùng file §B).
- Về chính mình: lead **điền sẵn kết-quả cho lượt chạy CHƯA xảy ra** (byte-count + TOTAL + verdict, đều bịa). Cơ-chế = **quán-tính điền mẫu**, không phải cẩu-thả. Cứu nhờ thói quen đọc lại thứ vừa Write, KHÔNG nhờ trí nhớ ⇒ chốt chặn phải là **luật soi được**.
- Lead sai đếm lần nữa: `ContractPhase` ghi "9 phase / 6 LEGACY", máy đếm **12 / 7**. **2 vai độc lập bắt được lead** — đúng chiều vòng KIỂM; lớp `meta-count` đã có tiền lệ. Hệ quả phụ: lead vá `run.md`**quên WAL** ⇒ số sai suýt theo `/tiep` sang cửa sau.
- Đóng gói C2 có RĂNG: 4/4 lane sạch, tốn nhiều nhất **7/25 lượt** — ép ghi khung rỗng lượt 1-2 là biến số thật.
- 🔴 Delta LỚN NHẤT: **tài liệu gốc trả lời được câu mà cả wave điều tra hôm qua không trả lời nổi.** Hôm qua chỉ có PDF ⇒ chỉ biết "khúc 7→12 không trong code". Đọc ISO doc ⇒ **nó cũng không có trong ISO** ⇒ đổi hạng mục: từ *code làm chưa xong* thành *công ty ca từng viết ra bước này*. ⇒ nếp: **hỏi "tài liệu gốc nói gì" TRƯỚC khi hỏi "code có gì"**.
- Phát hiện kèm: **7 phase `[LEGACY]` = quy trình ISO 9 bước mã-hoá cứng** (khớp 1:1 đúng thứ tự). Không phải rác — khung V2 sinh ra để biểu diễn chính chúng. Verdict `LAI` hôm qua giữ nguyên, **lý do mạnh hơn hẳn**.
- Về chính mình — ca đắt nhất phiên: **§2.4 nhận diện ĐÚNG bẫy `Pe_*`-ngoài-`All`, rồi §2.3 tự vấp đúng bẫy đó** bằng cơ chế khác (lệch TÊN thay vì factory) ⇒ prod **500 chứ không 403**; repo **đã có sẵn test bắt**. Lặp y nguyên câu cũ: *bài học nằm trong tay vẫn không tự bật* ⇒ chặn được = **luật soi được**, không phải trí nhớ.
- Về `#53`: lượt 1 invest = **`skeleton-ruột-rỗng`** (202K tok, đĩa 1.661 B khung rỗng) ⇒ **"ghi đĩa trong lúc làm" là CẦN KHÔNG ĐỦ — phải verify RUỘT có chữ**. Tinh hơn datum sáng nay 1 nấc.
- Đóng gói C2 có răng lần 2: **4/4 lane sạch 0 chết** (≤3 file/lane + ép khung rỗng + trần 25).
### D. Đang-thảo-luận
- Q2 kiến-trúc khúc 8-12 — anh đặt tên xong, nhánh (c) yếu hẳn nhưng CHƯA loại (10-12 nếu vẫn ký giấy thì (c) còn lý) {treo-chờ-anh}
- Q6 giá vào HĐ = giá chốt b.12 hay SUM PE — tên nghiệp-vụ gần như tự trả lời, vẫn thuộc tập Q1-Q6 CHẶN {treo-chờ-anh}
- Thứ tự 3 việc xếp hàng: lỗ hổng an ninh HĐ / sửa 6 chỗ invest / §4-§5 {treo-chờ-anh}
- Vét-cạn vẫn hở ⇒ **vòng KIỂM giữ nguyên** — nhận LẠI từ MIND-1, nguyên trạng-thái cũ {đang-cãi}
- Trần `mind_ctx_kb` — nhận LẠI từ MIND-1; nay có ca THẬT: cửa này buộc nén MIND-1 mới chèn nổi MIND-3 {treo-chờ-anh}
- `ring5-audit` SE-form ngay hay chờ VIPIX — nhận LẠI từ MIND-1 (slot 41) {treo-chờ-anh}
- Nhịp spawn `ctx-curator` @MỖI pause — núm hạ để sẵn, chưa owner quyết; lần đo chi-phí thứ 3 (~93K tok) {treo-chờ-anh}
- Guard post-wave mù 4 path hook — ĐÃ có nhà ở `WAL` chain ⇒ rời D, để lại con-trỏ {gần-chốt}
- Hợp-đồng liên-lane cần checklist mặt-tiếp-xúc (route · field DTO · menu-key · payload) — vẫn VÔ-GIA-CƯ {gần-chốt}
- Chia task theo **ranh-giới rõ (file HOẶC mục)** thay vì tính-năng — phát biểu lại cho khớp chứng (ca mới = cắt invest 4→2 MỤC) {gần-chốt}
- Bắt con-đo khai mẫu-số kèm tập-bù — ca thứ 5 (lead sai 12/7) {gần-chốt}
- 22 FLAG governance (42)(43)(44)(E2) — nay **3 cửa-sổ** chưa động {treo-chờ-anh}
- #53 cửa này ×1 (invest lượt 1, cứu trọn từ đĩa) vs ×13 cửa trước — giả-thuyết: prompt ngắn + ép ghi đĩa sớm {đang-cãi}
- Nguồn thứ 4 `SOL-PRO-SP-001 Quy trình Cung ứng` — reviewer phát hiện ISO bước 1 trỏ sang; chưa ai đọc, có thể phải hạ phạm vi claim *ISO không có khúc này* {treo-chờ-anh}
- 2 đường kết thúc sớm W3 (`AllowApproverFinalize` · `CeoApprovalThreshold`) — anh từng phán PHÁ VỠ ở S155, giữ hay bỏ {treo-chờ-anh}
- 5 câu thiết kế: **3 carry S156** (Q3 · Q6 · Q11) **+ 2 MỚI sinh trong spec cửa này** (O-Q1 gate căn cứ · O-Q2 số hoá checkbox); 14 câu S156 đã rút còn **5** {treo-chờ-anh}
- Lỗ hổng an ninh HĐanh chốt để từ từ (xem PAUSE-4), treo CÓ CHỦ ĐÍCH, không phải bỏ quên {treo-chờ-anh}
- 🔴 Luật nén `_mind` **HỞ**: điều khoản *"nén block CŨ NHẤT trblock-0 và top"* trỏ MIND-1 — mà MIND-1 **đã nén rồi** (3.070 B), không có nhánh "cũ nhất đã nén ⇒ sang cái kế". Kèm: sau cửa này file gần chạm trần ⇒ **mọi cửa sau đều buộc nén**. Cần vá luật **hoặc** re-tune khoá `mind_ctx_kb` (LEAD-DECIDED, chờ dogfood T9) {treo-chờ-anh}
- Gate "mở 5 anchor bất kỳ trước mỗi wave" reviewer đề — lead nhận, chưa có nhà trong bản-đồ {gần-chốt}
- 22 FLAG governance (42)(43)(44)(E2) — nay **4 cửa-sổ** chưa động {treo-chờ-anh}
### E. Dòng-sống spawn/engine-run
- `ctx-verifier` @tiep-2 (vai-2 Ctx, lần chạy đầu đời)`CO-CO — 10 cờ`, **return CLEAN**; lead verify 4/4 claim load-bearing đều đng, byte khớp`.claude/sessions/session-7/_tiep-2.md`
- `/fable-real investigator-codebase` (Fable) lượt 1 — 🔴 **return MẤT TRẮNG `#53`**, cứu TRỌN từ đĩa 7.234 B`.claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/sub-invest-bch-1.md`
- `/fable-real investigator-codebase` lượt 2 (SendMessage-resume, cắt còn 2 mục) — CLEAN `§3 15 bước · §6 14 câu`, đĩa 22.659 B khớp return`.claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/sub-invest-bch-1.md`
- `/fable-clone reviewer` `wf_1618ae3c-a17` **4/4 lane sạch 0 chết**`LUNG-LAY 11` · `CO-VAN-DE 10` · `THIEU-PHUONG-AN 14` · `4/4 THẬT 0 dương-giả`, tổng 35 điểm — `.claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/review-synthesis.md`
- 4 lane raw của review — `.claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/sub-review-verdict-1.md` · `.claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/sub-review-fidelity-2.md` · `.claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/sub-review-q2-3.md` · `.claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/sub-review-gaps-4.md`
- lượt phóng workflow ĐẦU bị guard `checkpointApproved` chặn — 0 agent, 0 token, 28ms; guard bắt lead KHAI quy-mô fan-out trước khi đốt — `.claude/workflows/hmw.js`
- cicd đợt 2 đóng nốt @S156 bằng lead-tự-đo (KHÔNG giao lại `cicd-monitor` vì chính vai đó dừng giữa chừng) — **PASS 6/6**`.claude/workflows/runs/2026-07-27-S155-pe-delete-approver/cicd-verify-dot2.md`
- `ctx-curator` @PAUSE-3`SUA — 8 điểm`, lead nhận **CẢ 8** + 1 điểm NGOÀI TRỤC (WAL còn "6/9 LEGACY" trong khi `run.md` đã sửa 12/7 ⇒ 2-sự-thật, vá cùng lượt); vai tự nêu no-self-exempt khi bắt ý về nhịp CỦA CHÍNH NÓ bị rơi — verdict ghi tại `.claude/sessions/session-7/_context-s-7.md` entry `PAUSE-3` mục (3)
- `ctx-verifier` @`_tiep-3``CO-CO — 10 cờ`, return CLEAN; C3 vá trong cửa, C5/C6 (trần) **nghiệm đúng** ở bước nén này`.claude/sessions/session-7/_tiep-3.md`
- `cicd-monitor` S157 — `PASS 9/9`; 🔴 return garble `#53`, cứu TRỌN 10.666 B từ đĩa — `.claude/workflows/runs/2026-07-27-S155-pe-delete-approver/cicd-verify-s157-diadiem.md`
- `/fable-real investigator-codebase` lượt 1 — 🔴 **`skeleton-ruột-rỗng`**: 202K tok, đĩa **1.661 B khung rỗng**`.claude/workflows/runs/2026-07-28-S157-ke-hoach-ky-ket-hd/sub-invest-kehoach-1.md`
- lượt 2 (resume, cắt còn 2 mục) — **CLEAN §A+§B**, đĩa 1.661→**23.085 B**, return khớp — cùng file trên
- lượt 3 (resume §C/§D) — tiến-trình CLI thoát, đĩa KHÔNG đổi ⇒ §C/§D chưa từng ghi; **KHÔNG resume lần 3**, lead tự viết theo H21 ①
- `/fable-clone reviewer` `wf_57af0163-053`**4/4 lane sạch 0 chết**, 112 điểm: wave `SUA-TRUOC-W1` 19 · fidelity `GO-WITH-FIXES` 23 · schema `GO-WITH-FIXES` 22 · claims **48 claim 39Đ/4S/5KKĐ** — 4 file `sub-review-*.md` cùng run-folder
- lượt phóng workflow ĐẦU bị guard `checkpointApproved` chặn — 0 agent, 0 token, 20ms — `.claude/workflows/hmw.js`
- `ctx-curator` @PAUSE-4`SUA — 9 điểm`, lead nhận **cả 9** (nặng nhất: O-1 vắng trọn ⇒ Q2 rơi im lặng · 5 chỗ verbatim trá hình lách rào-1 · nhãn trần sai 2 chiều) — verdict tại `.claude/sessions/session-7/_context-s-7.md` entry `PAUSE-4` mục (3)
## MIND-2 — 2026-07-27T14:12:00+07:00 @ 9ed65f4 (window 2)
## MIND-3 — 2026-07-27T17:09:56+07:00 @ b804d96 (window 3) 🗜️ ĐÃ NÉN @PAUSE-4
> 🗜️ Nén @PAUSE-4 (S157) — sau MIND-2+MIND-1 vẫn vượt trần 1.265 B, MIND-3 là block nén hợp lệ kế tiếp;
> nén nó cũng gỡ tình trạng "cửa nào cũng phải nén". 🔴 **VERBATIM CÒN NGUYÊN TRONG GIT** (`git show d7eaece:<path>`).
### A. Gói-turn
- Nhận việc SẢN-PHẨM đầu tiên của phiên-logic L7 (trước đó thuần governance): nút XÓA phiếu PE ở màn duyệt, từ ảnh chat UAT. Chạy trọn pipeline owner lệnh: 2 Invest → thành **4** (2 ảnh sau mở thêm lát cắt menu + versioning) → spec → review → hmw → deploy.
- **2 ĐỢT ĐÃ LÊN PROD**: `b1bae77` (nền: cờ F6 + lệnh sửa-quy-trình-tại-chỗ, CICD PASS 6/6) và `4464a46` (nút xóa + menu 3 mục + màn "Đã xóa", cicd chỉ đo được một phần).
- Test 532 → **562**; Mig 67 → **68**. Mẫu-số các con-số dưới đây: **đếm theo engine-run**, phạm vi = **cửa-sổ này (window 2)**, không phải cả phiên-logic — **5 engine-run hmw** (4 của đợt 1 + 1 của đợt 2) + **6 spawn trực-tiếp** qua Agent-tool.
- Đóng arc PE (`cicd PASS 6/6` lead tự đo). Nhận việc PDF sơ đồ 21 bước, phạm vi **b.7→21**, lane BCH.
- 🔴 **Anh ĐẶT TÊN nghiệp-vụ khúc 7→12** (xem `_context` PAUSE-3) — thứ không lượng code nào đọc ra được.
### B. Hướng-tiếp + nhánh-đã-loại
- Tiếp: **cicd đợt 2 CHẾT GIỮA CHỪNG** (file đứng yên 7.925B, mục 4-7 còn `(chưa có)`, 0 verdict) ⇒ còn nợ **4 mục**: endpoint mới sống chưa · smoke hồi-quy · bundle FE ×2 · verdict tổng. 🔴 Nhưng **trọng-tâm nguy nhất ĐÃ ĐO XONG và ĐẠT 2/2**: nhãn `Pe_*_Pending` đổi "Duyệt"→"Đang duyệt" thật, có mốc pre-deploy 14:08 còn `'Duyệt'` làm chứng `labelBackfill` chạy đúng cửa-sổ.
- Nhánh đã LOẠI: ① **đẩy sớm khi test đỏ** — owner chốt lượt 4 bác 2 phương án đẩy-một-phần (xem `run.md` §OWNER CHỐT / `PAUSE-2`) · ② **vá regex `WfView` fe-admin** — sub đo ra tiền-đề không đứng (trang chỉ có ở fe-user), thêm vào là đẻ link chết; lead chốt đường (c) giữ nguyên · ③ **giữ `[Authorize(Policy)]` trên đường xóa mới** — loại vì approver thật đều `CanDelete=0`, gắn vào là chặn đúng người cần dùng.
- LOẠI: ① viết §4/§5 theo giả-định (anh chọn review-nền-trước; reviewer chứng minh chọn đúng: nền có 1 claim
sai sự thật) · ② đòi invest trả trọn 4 mục 1 lượt (lượt 1 chết ở phần DÀI) · ③ hỏi lại anh vai `invest`.
### C. Kế-hoạch (delta suy-nghĩ)
- 🔴 Delta LỚN NHẤT: **owner cấp Ý-ĐỊNH, agent chỉ cấp HOẠT-ĐỘNG.** Invest 146K tok + 4 lane reviewer đều tả
đúng khúc 7→12 LÀM GÌ, không ai nói được nó ĐỂ LÀM GÌ — điều đó không nằm trong repo lẫn sơ đồ. Một câu đặt
tên của anh làm lung lay 2 câu mà 35 điểm review không chạm. ⇒ nếp: **hỏi "cái này đẻ ra gì?" TRƯỚC "gồm
những bước nào?"**.
- Lớp *cơ-chế-đúng-thứ-đi-qua-không-có* cắn **lần 5**, lộ là **ĐẶC-TÍNH KIẾN-TRÚC**: schema DÙNG CHUNG ⟂ service
RIÊNG per-type ⇒ cột thêm cho một loại **mặc-định CÂM** ở loại khác trừ khi có người nối.
- Doc stale **không chỉ sai — nó CHE** cái lệch display⟂guard đáng ra phải lộ.
- Về chính mình: lead **điền sẵn kết-quả cho lượt chạy CHƯA xảy ra** (byte-count + TOTAL + verdict đều bịa).
Cơ-chế = **quán-tính điền mẫu**; cứu nhờ thói quen đọc lại thứ vừa Write, KHÔNG nhờ trí nhớ.
- Lead sai đếm lần nữa (`ContractPhase` ghi 9/6, máy đếm **12/7**) — **2 vai độc lập bắt được lead**.
- **Đính chính 2 số bất-biến trong `_context-s-7.md`** (FLOW cấm sửa tại chỗ nên đây là cửa duy nhất; nợ này WAL@`HEAD~1` giao đích danh cho block MIND-2, và **bản WAL nén 14:12 đã đánh rơi nó**`ctx-curator` bắt được): `:62` "Nợ @close: bump `STATUS:6` counter 27→**28**" nay là **29** (verify `.session-counter.json` = 29, tick S155 CLEAN) · `:67` run-folder S154 "**12** file" nay là **13** (verify `ls` = 13).
- 🔴 Delta LỚN NHẤT: **một lớp lỗi lặp ĐÚNG 4 LẦN***cơ chế đúng, thứ đi qua nó không có*. (1) policy `PurchaseEvaluations.Delete` tồn tại nhưng 11/13 vai `CanDelete=0` · (2) endpoint PUT sống nhưng 0 dây FE gọi · (3) policy chặn đúng approver cần dùng · (4) DTO thiếu field FE đang đọc. Cả 4 đều **build sạch + test xanh**. Thuốc chữa KHÔNG phải "cẩn thận hơn" mà là **câu hỏi thứ hai**: cơ chế có rồi, *ai/cái gì thật sự đi qua nó?*
- Hệ quả đã áp: hợp-đồng liên-lane chốt TRƯỚC khi phóng (đợt 2) — nhưng vẫn thủng vì lead chỉ khoanh tầng **tên ROUTE**, quên tầng **tên FIELD trong DTO**. ⇒ hợp-đồng phải liệt **mọi mặt tiếp-xúc**, không chỉ mặt dễ thấy.
- Chốt chặn đã dựng: **T27** (reflection buộc mọi cờ `Allow*` trên entity có mặt trên DTO) — **fault-inject xác nhận có răng**, không phải guard tuyên-bố suông.
- Nhận thức về đo-lường: lead 2 lần suýt báo sai vì **phép đo rỗng nghĩa**`tsc -p tsconfig.json` (file references, không check gì) và glob sibling-repo sai path. Cả 2 trả "sạch". ⇒ trước khi tin một số 0, phải hỏi *phép đo này có đo gì không*.
- Nghi vấn để dành: lane FE đuối giữa chừng **3 lần liên tiếp**, mỗi lần làm xong phần KHÓ (suy luận bảo mật, đo tiền-đề) rồi hết sức ở phần DÀI (render, copy, regex) ⇒ giả thuyết: chia task FE theo **file** chắc hơn theo **tính năng**.
### D. Đang-thảo-luận
- Ý "Phép thử tự-soi của cặp H24" (MIND-1 D) **ĐÃ ĐỊNH-ĐOẠT** ⇒ RỜI khỏi D, để lại con-trỏ: `runs/2026-07-26-S154-bookend-open/sub-ring2-open-S154.md:63` {gần-chốt}
- "Guard post-wave assertion mù 4 path hook" (MIND-1 D) — chẩn-đoán đã chốt, thuốc đã chạy 1 lần thật, nhưng **VÔ-GIA-CƯ 0 dòng bản-đồ** ⇒ phải +1 dòng chain WAL kẻo rơi {gần-chốt}
- "Bắt mọi con-đo khai mẫu-số kèm tập-bù" — nay có **ca độc-lập thứ 4**, 0 ca ngược ⇒ nâng từ `đang-cãi` {gần-chốt}
- Nhịp `/pause` auto-snap + spawn `ctx-curator` mỗi lần — cùng ý đã treo ở MIND-0 và MIND-1, đang chờ owner quyết núm hạ tần suất {treo-chờ-anh}
- Chia task FE theo file thay vì theo tính năng — 3 ca đuối liên tiếp là mẫu đủ hay còn ngẫu nhiên {mới-nêu}
- Hợp-đồng liên-lane nên có **checklist mặt-tiếp-xúc** (route · field DTO · tên menu-key · shape payload) thay vì tự nhớ {gần-chốt}
- #53 ×13 trong **1 CỬA-SỔ (window 2)**; cửa-sổ 1 = ×11 (xem MIND-1) ⇒ phiên-logic L7 ≥24. Tỷ lệ cao bất thường — do prompt dài hay do lane WRITE {đang-cãi}
- 22 FLAG governance vẫn treo chờ (42)(43)(44)(E2) — đã 2 cửa-sổ chưa động {treo-chờ-anh}
### D. Đang-thảo-luận (nhãn giữ nguyên — MIND-4 đã nhận lại các ý còn sống)
- Q2 kiến-trúc khúc 8-12 {treo-chờ-anh} → **ĐÓNG @MIND-4 §A** (anh chốt tái dùng khung V2)
- Q6 giá vào HĐ · thứ tự 3 việc · trần `_mind` · nhịp `ctx-curator` · `ring5-audit` slot (41) {treo-chờ-anh}
- vòng KIỂM giữ nguyên {đang-cãi} · `#53` cửa này ×1 {đang-cãi}
- hợp-đồng liên-lane checklist · chia task theo ranh-giới rõ · con-đo khai mẫu-số {gần-chốt}
### E. Dòng-sống spawn/engine-run
- `ctx-verifier` @tiep-2 (đầu đời) `CO-CO — 10 cờ`, return CLEAN — `.claude/sessions/session-7/_tiep-2.md`
- `/fable-real investigator-codebase` 2 lượt (lượt 1 `#53` mất trắng, cứu từ đĩa; lượt 2 resume CLEAN **22.659 B**)
· `/fable-clone reviewer` `wf_1618ae3c-a17` **4/4 lane sạch**, 35 điểm, verdict `LAI` — tất cả tại
`.claude/workflows/runs/2026-07-27-S156-bch-post-ceo-flow/` (`sub-invest-bch-1.md` · 4× `sub-review-*.md` · `review-synthesis.md`)
- cicd đợt 2 đóng nốt bằng lead-tự-đo `PASS 6/6``.claude/workflows/runs/2026-07-27-S155-pe-delete-approver/cicd-verify-dot2.md`
- `ctx-curator` @PAUSE-3 — `SUA — 8 điểm`, nhận **cả 8** + 1 ngoài-trục (WAL còn "6/9 LEGACY" trong khi `run.md`
đã sửa ⇒ 2-sự-thật) — verdict tại `_context-s-7.md` entry `PAUSE-3` mục (3)
- 4 Invest — đều mất return, đều cứu TRỌN từ đĩa — `.claude/workflows/runs/2026-07-27-S155-pe-delete-approver/`: `sub-invest-be-1.md` · `sub-invest-fe-2.md` · `sub-invest-menu-3.md` · `sub-invest-wfver-4.md`
- reviewer spec — `PASS-WITH-FLAGS 17 FLAG (4H/8M/5L)`, F.0 không bác được sau 6 đường tấn công — `reviewer-spec-review.md`
- hmw **đợt 1 ×4 engine-run** (`wf_f1bfea65-ed9` · `wf_a5ee3ecb-a19` · `wf_4ea6451f-648` · `wf_07fd9304-74e`) + **đợt 2 ×1** (`wf_55f6201f-a52`)
- 🔴 `implementer-backend` wave-1 — **MẤT CẢ 2 KÊNH** (return rỗng + diary 0-byte rồi biến mất) = `skeleton-ruột-rỗng` nặng nhất từng gặp; recover bằng lane ĐĨA-TRUTH (git diff + grep + build) — `sub-implementer-backend-1.md` (file nay không còn)
- 🔴 `reviewer` wave-2 qua hmw — **sinh 0 FILE, return rỗng** ⇒ diff đợt 1 chưa hề được soi, phải chạy lại bằng Agent-tool trực tiếp — run-id `wf_a5ee3ecb-a19`
- reviewer diff đợt 1 — `PASS-WITH-FLAGS 14 FLAG` · `DEPLOY-CÓ-RỦI-RO` (F8 cổng commit) — `reviewer-diff-dot1.md`
- cicd đợt 1 — `PASS 6/6`, mig ở TOP history prod — `cicd-verify-dot1.md`
- reviewer diff đợt 2 — `FAIL 12 FLAG (2H/4M/6L)``ĐỪNG-DEPLOY` vì H1 DTO thiếu field; lead vá xong mới đẩy — `reviewer-diff-dot2.md`
- `implementer-frontend` đợt 2 (1 resume) — `tsc` sạch ×2 app, md5 mirror khớp — `sub-d2-fe-3.md`
- `test-specialist` đợt 2 — 10 test, **T26 giữ ĐỎ có chủ ý** (bug production, không nới assert) rồi lead vá bằng đảo thứ tự — `sub-d2-test-4.md`
- cicd đợt 2 — **DỪNG GIỮA CHỪNG** (7.925B, mục 4-7 rỗng, 0 verdict); phần đã đo: nhãn menu ĐẠT 2/2 — `cicd-verify-dot2.md`
- `ctx-curator` @PAUSE-2 — `SUA — 8 điểm`, lead nhận **cả 8**; nó còn bắt được **WAL bị nén giữa lượt làm rơi 2 dòng `[ ] @MIND-2`** (dùng `git show HEAD~1` làm chứng) — verdict ghi tại `_context-s-7.md` entry `PAUSE-2` mục (3)
## MIND-2 — 2026-07-27T14:12:00+07:00 @ 9ed65f4 (window 2) 🗜️ ĐÃ NÉN @PAUSE-4
## MIND-1 — 2026-07-26T19:42:22+07:00 @ 5197ce2 (window 1) 🗜️ ĐÃ NÉN @PAUSE-3
> 🗜️ Nén @PAUSE-3 (S156) vì trần `mind_ctx_kb` (26.0K + block mới 8.2K > 32.768). Luật: nén block CŨ NHẤT
> trừ block-0 và top ⇒ MIND-1 (đủ 3 block, nén hợp lệ). 🔴 **VERBATIM CÒN NGUYÊN TRONG GIT**
> (`git show <sha trước b804d96>:.claude/sessions/session-7/_mind-s-7.md`). Gist này MẤT diễn giải,
> GIỮ số load-bearing + nhãn D + con-trỏ.
> 🗜️ Nén @PAUSE-4 (S157) vì trần `mind_ctx_kb` — nén **2 block** (MIND-2 + MIND-1) mới đủ chỗ cho MIND-4;
> `ctx-verifier`@tiep-3 dự báo đúng. 🔴 **VERBATIM CÒN NGUYÊN TRONG GIT** (`git show d7eaece:<path>`).
> Gist MẤT diễn giải, GIỮ số load-bearing + nhãn D + con-trỏ.
### A. Gói-turn
- Khép trọn bootstrap L7 (bookend 6 vai → trio 3 nấc → Phase 3.5). Thu **23 FLAG raw 1 BÁC = 22 sống**
+ 1 mệnh-đề hệ-thống + 3 số xin anh. **0 byte mất** qua **`#53` ×11**. `ctx-audit` 4 FLAG **cả 4 nhắm lead**, nhận 2/4.
- Việc SẢN-PHẨM đầu của L7: **nút XÓA phiếu PE ở màn duyệt**, chia **2 ĐỢT** theo lệnh anh. Lên prod:
`b1bae77` (nền) + `4464a46` (nút+menu+màn "Đã xóa"). Test 532→**562**; Mig 67→**68**.
### B. Hướng-tiếp + nhánh-đã-loại
- Chờ anh **(42)(43)(44)** — chặn phần disposition còn lại.
- LOẠI: ① vá FLAG trước khi anh chốt · ghi memory khi `User memory` count đang LÀ vật bị đo (Mirror C1)
· ③ báo `thu-moi` bằng đếm file inbox (inbox = tích-luỹ, không phải thư mới).
- LOẠI: ① đẩy sớm khi test đỏ (anh bác 2 phương án đẩy-một-phần) · ② vá regex `WfView` fe-admin (tiền-đề
không đứng, thêm = đẻ link chết) · giữ `[Authorize(Policy)]` trên đường xóa mới (approver thật `CanDelete=0`).
### C. Kế-hoạch (delta suy-nghĩ)
- Delta lớn nhất: drift là **hàm của việc CÓ MÁY CANH hay không**, không phải lỗi kỷ-luật lead — 3/3 row ngoài
`$canonRows` lệch, 6/6 row trong tập đúng ⇒ chữa bằng mở rộng máy canh hoặc bỏ số khỏi doc.
- Lớp lỗi nối 4 ca rời: **khớp-chuỗi-phẳng trên dữ-liệu CÓ CẤU TRÚC**, đều sai về phía *trông có vẻ ổn*.
- **Lead sai 4 lần, cả 4 ở chỗ KHÔNG có máy canh**; 1 máy bắt, 2 vai bắt, 1 lộ ở cửa dng **0 cái lead tự thấy**.
Ca #4 kết-luận đúng nhưng **đúng nhờ MAY, không nhờ phép đo**.
- Đính chính bản vá của chính lead: discriminator END đúng = **"dòng cuối KHÔNG-RỖNG"**.
- Để dành: guard `§2.1.9(f)` dùng `git status`**mù đúng 4 path Stop-hook**; thay bằng `git log --name-only origin/main..HEAD -- <path>`.
- 🔴 Delta LỚN NHẤT: lớp lỗi lặp **ĐÚNG 4 LẦN trong 1 cửa***cơ chế đúng, thứ đi qua nó không có*
(policy có / 11-trên-13 vai `CanDelete=0` · endpoint sống / 0 dây FE gọi · policy chặn đúng approver cần dùng
· DTO thiếu field FE đang đọc). **Cả 4 build sạch + test xanh.** Thuốc = **câu hỏi thứ hai**: *ai/cái gì thật
sự đi qua nó?* Chốt chặn dng: **T27** (fault-inject xác nhận có răng).
- **Phép đo rỗng nghĩa**: `tsc -p tsconfig.json` (file references, không check gì) + glob sibling-repo sai path
— cả 2 trả "sạch" ⇒ trước khi tin một số 0, hỏi *phép đo này có đo gì không*.
- Hợp-đồng liên-lane thủng vì lead chỉ khoanh tầng **tên ROUTE**, quên tầng **tên FIELD trong DTO**.
### D. Đang-thảo-luận (nhãn giữ nguyên — MIND-3 nhận LẠI 3 ý từ đây)
- (42) canonRows · (43) carry con-trỏ-vs-slug · (44) `END … TOTAL=n` thành luật — cả 3 {treo-chờ-anh}
- Phép thử tự-soi cặp H24 **ĐẠT** {gần-chốt} · vòng KIỂM giữ nguyên {đang-cãi} · con-đo khai mẫu-số kèm tập-bù {đang-cãi} · guard post-wave {gần-chốt}
- Trần `mind_ctx_kb` {treo-chờ-anh} · nhịp `ctx-curator` @mỗi pause {treo-chờ-anh} · `ring5-audit` SE-form {treo-chờ-anh}
### D. Đang-thảo-luận (nhãn giữ nguyên — MIND-3/4 đã nhận lại các ý còn sống)
- Chia task FE theo **file** thay vì theo tính năng (3 ca lane FE đuối liên tiếp) {mới-nêu}
- Hợp-đồng liên-lane cần **checklist mặt-tiếp-xúc** {gần-chốt} · con-đo khai mẫu-số kèm tập-bù {gần-chốt}
- `#53` ×13 riêng cửa-sổ này (cửa 1 = ×11) {đang-cãi} · 22 FLAG governance {treo-chờ-anh}
### E. Dòng-sống spawn/engine-run
- 11 spawn bookend+trio, verdict + con-trỏ ĐẦY ĐỦ giữ tại `.claude/workflows/runs/2026-07-26-S154-bookend-open/`
(H1 `3` · H2 `6` · lead-stale `5` · lead-gap `5` · ring1 `46Đ/2T/5KC` · ring2 `17Đ/1T/1KC`+M-1 · eval `MIXED 12`
· refine `3A/8B/3E` · audit `68Đ/8T` · probe 2/2 ALIVE · 2 synthesis).
- `ctx-curator` @PAUSE-1 (đầu đời) — `SUA — 5 điểm`, nhận cả 5 — `.claude/sessions/session-7/_context-s-7.md` entry `PAUSE-1` (3).
- Verdict + con-trỏ ĐẦY ĐỦ giữ tại `.claude/workflows/runs/2026-07-27-S155-pe-delete-approver/`: 4 invest
(đều mất return, cứu trọn từ đĩa) · reviewer spec `17 FLAG` · reviewer diff đợt-1 `14 FLAG` / đợt-2
`FAIL 12 FLAG → ĐỪNG-DEPLOY` · cicd đợt-1 `PASS 6/6` · `sub-d2-fe-3.md` · `sub-d2-test-4.md` (T26 giữ ĐỎ có
chủ ý) · 5 engine-run hmw (`wf_f1bfea65-ed9` `wf_a5ee3ecb-a19` `wf_4ea6451f-648` `wf_07fd9304-74e` `wf_55f6201f-a52`).
- 🔴 `implementer-backend` wave-1 — **MẤT CẢ 2 KÊNH** (`skeleton-ruột-rỗng` nặng nhất); recover bằng lane ĐĨA-TRUTH.
**ĐÍNH CHÍNH (bản gốc ghi SAI "file này không còn"):** `sub-implementer-backend-1.md` **CÒN SỐNG, 3.499 B**
`ctx-verifier`@tiep-3 cờ C9 bắt; giữ bản sửa này, đừng chép lại câu cũ.
- `ctx-curator` @PAUSE-2 — `SUA — 8 điểm`, nhận cả 8; bắt được WAL nén giữa lượt làm rơi 2 dòng `[ ]`.
## MIND-1 — 2026-07-26T19:42:22+07:00 @ 5197ce2 (window 1) 🗜️ NÉN LẦN 2 @PAUSE-4
> 🗜️ Nén lần 1 @PAUSE-3, **nén tiếp lần 2 @PAUSE-4** (trần căng, xem MIND-4 §D "luật nén HỞ").
> 🔴 **VERBATIM CÒN NGUYÊN TRONG GIT.** Gist giữ số load-bearing + nhãn D + con-trỏ.
### A. Gói-turn
- Khép trọn bootstrap L7. Thu **22 FLAG sống** (23 raw 1 bác) + 3 số xin anh. **0 byte mất** qua **`#53` ×11**.
### B. Hướng-tiếp + nhánh-đã-loại
- LOẠI: vá FLAG trước khi anh chốt · ghi memory khi `User memory` count đang LÀ vật bị đo · báo `thu-moi` bằng
đếm file inbox (inbox = tích-luỹ, không phải thư mới).
### C. Kế-hoạch (delta suy-nghĩ)
- Delta lớn nhất: **drift là hàm của việc CÓ MÁY CANH hay không**, không phải lỗi kỷ-luật lead (3/3 row ngoài
`$canonRows` lệch, 6/6 row trong tập đúng).
- **Lead sai 4 lần, cả 4 ở chỗ KHÔNG có máy canh** — 0 cái lead tự thấy; ca #4 đúng **nhờ MAY, không nhờ phép đo**.
- Guard `§2.1.9(f)` dùng `git status` **mù đúng 4 path Stop-hook** ⇒ thay bằng `git log --name-only origin/main..HEAD`.
### D. Đang-thảo-luận (nhãn giữ nguyên)
- (42) canonRows · (43) carry con-trỏ-vs-slug · (44) `END … TOTAL=n` thành luật {treo-chờ-anh}
- vòng KIỂM giữ nguyên {đang-cãi} · trần `mind_ctx_kb` {treo-chờ-anh} · `ring5-audit` SE-form {treo-chờ-anh}
### E. Dòng-sống spawn/engine-run
- 11 spawn bookend+trio, verdict + con-trỏ ĐẦY ĐỦ tại `.claude/workflows/runs/2026-07-26-S154-bookend-open/`
(H1 `3` · H2 `6` · lead-stale `5` · lead-gap `5` · ring1 `46Đ/2T/5KC` · ring2 `17Đ/1T/1KC` · eval `MIXED 12`
· refine `3A/8B/3E` · audit `68Đ/8T`). `ctx-curator` @PAUSE-1 (đầu đời) `SUA — 5 điểm`, nhận cả 5.
## MIND-0 — 2026-07-26T19:12:14+07:00 @ 8776ca8 (window 1)

View File

@ -0,0 +1,5 @@
ts: 2026-07-28T11:33:17+07:00
head-sha: d7eaeceaa72a9ea5f8edbc596fb0d95d565aa75c
window-ordinal: 4
jsonl-hint: D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP/85c4bae3-8755-487e-bb4b-d8d8c9135463
account-label: none

View File

@ -0,0 +1,7 @@
ts: 2026-07-28T19:35:37+07:00
head-sha: 6c263dde7f85c29165187d44af0e7b302b1bd969
window-ordinal: 5
jsonl-hint: D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP/c3df5853-f04e-4534-bb6b-4075fae636ec
account-label: none
ctx-verifier: CO-CO 8 co (K1 y "thu tu wave" chi song o WAL:24, 0 hit _mind; K3 NANG NHAT = 7 y MIND-3 §D roi IM-LANG sang MIND-4 trong khi header nen MIND-3 tu khai "da nhan lai y con song" ⇒ claim BI BAC; tran _mind 92,5% ⇒ MIND-5 KHONG DU CHO, luat nen tro MIND-1 ma MIND-1 da nen roi — lead do doc-lap XAC NHAN: du 2.727 B + MIND-1 1.868 B = 4.595 < 6.536 B can)

View File

@ -368,7 +368,7 @@ Bỏ phase enum legacy 2-9. Dùng `ChoDuyet=10` đơn nhất + `CurrentWorkflowS
## Phase 9+ done (Mig 22-24 — Session 17) — V2 schema riêng + state machine 5 trạng thái
**Spec change (Session 17):** schema riêng `ApprovalWorkflowsV2` (3 bảng) song song V1 (Mig 21 vẫn live). Cấu trúc: Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua `ApproverUserId`). PE Service wire xong, Contract V2 chưa (defer Session 18+).
**Spec change (Session 17):** schema riêng `ApprovalWorkflowsV2` (3 bảng) song song V1 (Mig 21 vẫn live). Cấu trúc: Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua `ApproverUserId`). PE Service wire xong. 🔴 **ĐÍNH CHÍNH @S158** (`ring1-audit` thách-CLEAN bắt — câu cũ ở đây khai *"Contract V2 chưa (defer Session 18+)"***sai suốt ~2,3 tháng**, là **phát-biểu SAI CHỦ ĐỘNG** chứ không phải thiếu-row): **Contract V2 ĐÃ WIRE từ S29** — đĩa có `ContractLevelOpinion.cs` + `20260522052240_AddContractLevelOpinions.cs` + `ApproveV2Async` trong `ContractFeatures.cs` (Plan B Mig 32+33, cookie-cutter mirror PE V2). 🧊 *Câu cũ giữ 1 vế làm vết:* "Contract V2 chưa (defer Session 18+).
### State machine 5 trạng thái (mirror Contract sẽ áp dụng tương tự)

View File

@ -1,6 +1,6 @@
---
name: ef-core-migration
description: Tạo/sửa/revert EF Core 10 migration cho SOLUTION_ERP. Dùng khi thêm entity mới, thay đổi schema, rollback migration, debug DesignTimeDbContextFactory fail. Đã có nhiều migration (số hiện tại + mới nhất → docs/STATUS.md canonical + row cuối bảng history trong skill này — KHÔNG hardcode số ở đây, B1 anti-drift). Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ.
description: Tạo/sửa/revert EF Core 10 migration cho SOLUTION_ERP. Dùng khi thêm entity mới, thay đổi schema, rollback migration, debug DesignTimeDbContextFactory fail. Số migration hiện tại + cái mới nhất → CHỈ đọc từ 2 nguồn SỐNG - docs/STATUS.md canonical HOẶC `ls src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/*.cs`. Bảng history bên dưới là KHO LỊCH SỬ, KHÔNG phải nguồn "mới nhất". Snapshot + Designer + Migration 3-file rule bắt buộc commit đủ.
when-to-use:
- "thêm migration"
- "EF Core migration"

View File

@ -0,0 +1,188 @@
# CI/CD verify — S157 (2026-07-28) — PE cảnh báo "Địa điểm" khi dự án chưa có Location
> Agent: cicd-monitor · READ-only · file ghi TỪNG MỤC trong lúc làm (chống #53 return-garble)
> Range: `f4494cf..a52a91e` · run-folder tái dụng S155
---
## MỤC 1 — Push + path-filter (gotcha #41) ✅ ĐÃ ĐO
```
a52a91e7110b6d04a7ad26b70aa7db2c4888e160 | 2026-07-28 09:32:59 +0700 | [CLAUDE] Docs: tick counter S157 + bump header CURRENT STATE moc S153->S156
6250f39c52905579f873034c0dc04dfc3ada0287 | 2026-07-28 09:32:33 +0700 | [CLAUDE] PurchaseEvaluation: hien ly do o Dia diem trong khi du an chua co Location
```
- `git log origin/main..HEAD`**RỖNG** ⇒ push đã lên `main` thật.
- Files `6250f39` (4 file, FE 2-app mirror):
- `fe-admin/src/components/pe/PeHeaderForm.tsx`
- `fe-admin/src/components/pe/PeWorkspaceCreateView.tsx`
- `fe-user/src/components/pe/PeHeaderForm.tsx`
- `fe-user/src/components/pe/PeWorkspaceCreateView.tsx`
- Files `a52a91e` (2 file): `.claude/governance/.session-counter.json` + `docs/STATUS.md`
**Path-filter check vs 7-glob `paths-ignore`** (`docs/**`, `**/*.md`, `.claude/skills/**`, `.claude/agent-memory/**`, `.claude/workflows/runs/**`, `.gitignore`, `scripts/**.md`):
- `fe-{admin,user}/src/**` **KHÔNG khớp** glob nào ⇒ CI **PHẢI chạy**.
- `.session-counter.json` cũng thoát glob (không phải `.md`, không nằm skills/agent-memory) — nhưng Gitea đánh giá cả **range push**, có ≥1 file non-ignored ⇒ toàn range build.
**Kết luận M1: KHÔNG phải docs-only skip. Pipeline bắt buộc fire.**
---
## MỤC 2 — Gitea Actions run (đang đo)
Poll #1 @ ~09:41+07 — `.../actions/tasks?limit=6`:
| id | run# | head_sha | status | created | updated |
|---|---|---|---|---|---|
| **532** | **419** | **a52a91e7** | **running** | 2026-07-28T09:40:18+07 | 09:41:23+07 |
| 531 | 418 | f4494cfe | success | 07-27T14:36:54 | 14:42:35 |
| 529 | 416 | b1bae77c | success | 07-27T12:37:18 | 12:42:49 |
⇒ Run **ĐÃ FIRE đúng head_sha `a52a91e`** (xác nhận M1: không skip). Trạng thái lúc đo đầu = **running**, CHƯA kết luận. Đang chờ terminal.
**Marker gốc (từ `git show 6250f39`)** — chuỗi sẽ grep trong bundle prod:
`⚠ Dự án này chưa có Địa điểm trong Danh mục Dự án — nhập tay ở đây, hoặc bổ sung vào Danh mục (Dự án → Địa điểm) để các phiếu sau tự điền.`
Substring dùng để grep (an toàn minifier, nằm trong string literal): **`chưa có Địa điểm trong Danh mục`**
---
## MỤC 3 — PRE-deploy bundle snapshot (chụp TRƯỚC khi run xong) ✅ ĐÃ ĐO
Đo lúc **09:41:56 +07** (run 532 còn `running` ⇒ đây là trạng thái CŨ, chưa ship):
| app | js hash | css hash | `Last-Modified` index.html |
|---|---|---|---|
| admin.solutions.com.vn | **`BK8w3QxU`** | `DiNJjaoo` | Mon, 27 Jul 2026 07:41:15 GMT (=14:41 +07) |
| eoffice.solutions.com.vn | **`DYnxSI0T`** | `BRCvEHvC` | Mon, 27 Jul 2026 07:42:10 GMT (=14:42 +07) |
**KHỚP CHÍNH XÁC baseline STATUS S156** (`BK8w3QxU` / `DYnxSI0T`), LM trỏ đúng run #418 (`f4494cf`, xong 14:42:35 07-27). Pre-state hợp lệ để so hash sau deploy.
---
## MỤC 4 — Run terminal + TEST GATE ✅ PASS
Poll 7 vòng (09:41→09:46, ~30s/vòng), chuyển trạng thái:
`running` (iter 26) → **`success`** (iter 7 @ 09:46:00, `updated_at` 2026-07-28T09:45:58+07).
- **Run id 532 · run_number #419 · head_sha `a52a91e`**
- Start 09:40:18 → End 09:45:58 ⇒ **duration 5m40s** (nằm trong dải bình thường 4m405m40, không escalate)
- URL: `https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions/runs/419`
**Test gate — đếm CỤ THỂ từ web-UI log (17.850 bytes):**
```
Passed! - Failed: 0, Passed: 45, Skipped: 0, Total: 45 — SolutionErp.Domain.Tests.dll (164 ms)
Passed! - Failed: 0, Passed: 517, Skipped: 0, Total: 517 — SolutionErp.Infrastructure.Tests.dll (1 m 25 s)
```
**562 PASS (45 Domain + 517 Infra), 0 fail / 0 skip****KHỚP baseline canonical 562** (`docs/STATUS.md`). Grep `error |FAILED|Build FAILED` trên toàn log ⇒ **0 hit**. Gate xanh, chạy TRƯỚC build+deploy ⇒ deploy hợp lệ.
---
## MỤC 5 — Bundle rotate ×2 app ✅ ROTATE CẢ HAI
Đo lúc **09:46:12 +07** (sau khi status=success — tránh false-positive stale kiểu Run #242):
| app | js TRƯỚC | js SAU | Δ | css | `Last-Modified` (UTC → +07) |
|---|---|---|---|---|---|
| admin | `BK8w3QxU` | **`8-QYcMOg`** | ✅ ĐỔI | `DiNJjaoo` (frozen) | 28 Jul 02:44:33 GMT → **09:44:33 +07** |
| eoffice | `DYnxSI0T` | **`DptYR4wL`** | ✅ ĐỔI | `BRCvEHvC` (frozen) | 28 Jul 02:45:30 GMT → **09:45:30 +07** |
- **Cả 2 LM nằm TRONG cửa-sổ deploy** (09:40:18 09:45:58) ⇒ file thật sự được ghi đè trong run này, không phải tàn dư.
- **css FROZEN cả 2** = dấu vân tay "FE-logic-no-new-style": khối thêm chỉ dùng utility Tailwind đã có sẵn trong bundle (`text-amber-700`, `mt-1`) ⇒ content-hash CSS không đổi. Lành tính theo #69-REFINE, KHÔNG phải cờ đỏ.
- index.html size 900B/876B + `Last-Modified` mới ⇒ shell `no-cache` đã revalidate đúng.
**Deploy ĐÃ ăn tới đĩa. Hash đổi 2/2.**
---
## MỤC 6 — 🔴 BYTE-MARKER trong bundle prod (phép QUYẾT ĐỊNH, gotcha #77) ✅ 2/2
Tải THẲNG file JS prod rồi `bytes.count(marker.encode('utf-8'))` (bytes, không decode — tránh bẫy cp1252 S134):
| app | URL asset | HTTP | size THẬT | Content-Type | `Last-Modified` |
|---|---|---|---|---|---|
| admin | `/assets/index-8-QYcMOg.js` | 200 | **1.675.282 B** | `application/javascript` | 28 Jul 02:44:33 GMT |
| eoffice | `/assets/index-DptYR4wL.js` | 200 | **1.575.513 B** | `application/javascript` | 28 Jul 02:45:30 GMT |
**Đếm marker (4 chuỗi độc lập, cùng 1 câu cảnh báo):**
| chuỗi grep | admin | eoffice |
|---|---|---|
| `chưa có Địa điểm trong Danh mục` | **2** | **2** |
| `Danh mục Dự án` | **2** | **2** |
| `Dự án → Địa điểm` | **2** | **2** |
| `để các phiếu sau tự điền` | **2** | **2** |
**CÓ MẶT Ở CẢ 2 APP. count=2 khớp CHÍNH XÁC số file/app trong diff** (`PeHeaderForm.tsx` + `PeWorkspaceCreateView.tsx` = 2 chỗ nhúng chuỗi/app). Không dư, không thiếu.
**Control âm (chống đọc-nhầm SPA-fallback 200):**
| control | HTTP | size | ct | marker |
|---|---|---|---|---|
| fake hash `index-ZZfake0000.js` (admin) | 200 | 900 | **text/html** | **0** |
| fake hash `index-ZZfake0000.js` (eoffice) | 200 | 876 | **text/html** | **0** |
| hash CŨ `index-BK8w3QxU.js` (admin) | 200 | 900 | **text/html** | — |
| hash CŨ `index-DYnxSI0T.js` (eoffice) | 200 | 876 | **text/html** | — |
⇒ Control chứng minh 2 điều: (i) HTTP 200 một mình VÔ NGHĨA — discriminator thật là `ct=application/javascript` + size ~1,6MB; (ii) **bundle CŨ đã BIẾN MẤT khỏi đĩa** (rơi về SPA shell) ⇒ deploy ghi đè thật, không phải thêm file mới cạnh file cũ.
**Đây là bằng chứng mạnh nhất: mã S157 đang CHẠY THẬT trên prod cả 2 app.**
---
## MỤC 7 — Smoke 3 site sau deploy ✅ ALL GREEN
| check | kỳ vọng | thực đo | KQ |
|---|---|---|---|
| `GET /health/live` | 200 | **200 `Healthy`** | ✅ |
| `GET /health/ready` | 200 | **200 `Healthy`** | ✅ |
| `POST /api/auth/login` (admin) | 200 + token | **200**, `accessToken` 468 ký tự | ✅ |
| `GET /api/projects?pageSize=1` | 200 | **200** (374 B) | ✅ |
| `GET /api/purchase-evaluations?pageSize=1` | 200 | **200** (969 B) | ✅ |
| `GET /api/menus` | 200 | **200** (14.802 B) | ✅ |
| `GET /api/suppliers?pageSize=1` | 200 | **200** (751 B) | ✅ |
| `GET https://admin.solutions.com.vn/` | 200 | **200** (900 B shell) | ✅ |
| `GET https://eoffice.solutions.com.vn/` | 200 | **200** (876 B shell) | ✅ |
`/api/projects` 200 đặc biệt đáng ghi: đây chính là nguồn `location` mà khối cảnh báo mới đọc (`projects.data?.find(...)?.location`) ⇒ đường dữ liệu của feature còn sống.
---
## MỤC 8 — Migration: VẮNG là ĐÚNG ✅
> ⚠️ **ĐÍNH CHÍNH số của chính tôi (self-correct):** thoạt đầu tôi viết "range = 6 file" — **SAI**. Đó là số của 2 commit `6250f39`+`a52a91e` cộng lại, không phải của range. Range `f4494cf..a52a91e` thật ra gồm **13 commit** (2 commit code/docs + **11 commit `wal: flush` / `wal: pause`**) chạm **26 file**. Đo lại bằng `git diff --name-only ... | wc -l`. Kết luận BE=0 KHÔNG đổi, nhưng con số phải đúng.
`git diff --name-only f4494cf..a52a91e` = **26 file / 13 commit**; lọc `-- 'src/Backend/*' '*Migrations*'`**0 file** (đếm bằng `wc -l`, không phải mắt thường).
⇒ Không có Mig mới; **Mig vẫn 68 `AddPeAllowApproverDelete`**, `sys.tables` vẫn 89. Không query prod DB vì không có gì để đối chiếu — vắng migration ở đây là KỲ VỌNG, không phải cờ đỏ (đúng brief của lead).
BE 0 đổi ⇒ deploy này thuần FE; API vẫn `Healthy` (M7) xác nhận app pool recycle không làm gãy gì.
---
## MỤC 9 — Cross-check baseline 562 với canonical ✅ KHỚP
`docs/STATUS.md:452` (canonical): `| Tests | **562 PASS** | 45 Domain + 517 Infra · 0 fail / 0 skip · S155 +30 ...`
Log CI run #419 đo được: **45 Domain + 517 Infra = 562**, 0 fail / 0 skip.
**Trùng khít cả TỔNG lẫn TỪNG THÀNH PHẦN** (không chỉ khớp số tổng — khớp cả tách 45/517). Không có test nào bị drop âm thầm, không có skip che lỗi.
---
## VERDICT — **PASS** (9/9 mục xanh, 0 caveat)
| # | Mục | KQ |
|---|---|---|
| 1 | Push + path-filter không skip | ✅ |
| 2 | Run fire đúng `a52a91e` | ✅ |
| 3 | Pre-deploy snapshot = baseline S156 | ✅ |
| 4 | Run #419 success 5m40s + gate 562 | ✅ |
| 5 | Bundle rotate 2/2 + LM in-window | ✅ |
| 6 | 🔴 Byte-marker **2/2 app** (count=2 mỗi app) + control âm sạch | ✅ |
| 7 | Smoke 3 site + 4 endpoint + login | ✅ |
| 8 | Migration vắng = đúng (BE 0 đổi) | ✅ |
| 9 | 562 khớp canonical cả 45/517 | ✅ |
**Không có việc phải làm tiếp. Không khuyến nghị rollback.**
Ghi chú cho session sau: `text-[11px]` + `text-amber-700` KHÔNG làm rotate CSS hash ⇒ 2 utility này đã có sẵn trong bundle từ trước; css-frozen ở đây là dấu hiệu ĐÚNG của "FE logic-only", không cần điều tra.
<!-- END · TOTAL=9 MUC · VERDICT=PASS -->

View File

@ -0,0 +1,210 @@
# run — S157 · "KẾ HOẠCH KÝ KẾT HỢP ĐỒNG" — khúc CÒN THIẾU giữa Duyệt NCC và HĐ NTP/NCC
> **run-id:** `2026-07-28-S157-ke-hoach-ky-ket-hd` · mở 2026-07-28 (phiên-LOGIC L7, window 4)
> **Lệnh anh (verbatim):** *"Nhớ cái quy trình còn thiếu hôm qua ko? Cái spec cũ còn hôm qua. `/fable-real` Invest điều tra quy trình chỗ còn thiếu. Quy trình còn thiếu giữa Duyệt NCC - Kế hoạch ký kết Hợp đồng (Còn thiếu) - Hợp đồng NTP/NCC. Sau đó cho `/fable-clone` review lại thêm 1 lần cái spec đó → Ra cái spec mới đầy đủ chi tiết nhất, bao gồm cách làm. Chia wave rõ ràng. Cho tao cái plan đó và Wave chạy thế nào luôn nhé."*
> **Anh chỉ nguồn:** `D:\Dropbox\CONG_VIEC\SOLUTION\` có 2 folder **FORM** (8 file) + **QUY_TRINH** (1 file).
> **Anh chốt cùng ngày:** *"chỗ hợp đồng cứ từ từ nhé"* ⇒ lỗ hổng an ninh HĐ **KHÔNG** nằm trong run này.
---
## 0. Nguồn — 2 tài liệu gốc, LẦN ĐẦU đưa vào vòng điều tra
Wave S156 hôm qua **chỉ có PDF sơ đồ**. Run này bổ sung **2 tài liệu ISO gốc của công ty** — đây là
delta nguồn quan trọng nhất so với hôm qua.
| Nguồn | Trích ra | Vai trò |
|---|---|---|
| `QUY_TRINH\QT TRINH KY HOP DONG TP-NCC.docx` | `src-QT-TRINH-KY-HD.txt` (14.425 B · 38 para · 2 bảng) | **Quy trình ISO 9 bước** trình ký HĐ TP/NCC/Tổ đội — chuẩn đang áp dụng |
| `FORM\SOL-CCM-FO-002.01.v01 Bang kiem tra hop dong.docx` | `src-FO-002.01-bang-kiem-tra-HD.txt` (21.287 B · bảng 40r×13c) | **Tờ "Chấp thuận Hợp đồng"** — vật mang chữ ký qua từng trạm (bản giấy của workflow) |
| 7 form còn lại trong `FORM\` | *(chưa trích — 6 mẫu HĐ + RG-001 mã HĐ)* | Đã có bản parse ở `docs/forms-spec.md` (Phase 0) |
| PDF sơ đồ 21 bước | `runs/2026-07-27-S156-bch-post-ceo-flow/run.md` | Nguồn hôm qua, GIỮ NGUYÊN |
---
## 1. 🔴 GROUNDING LEAD ĐO TRƯỚC KHI PHÓNG — phát hiện lật khung vấn đề
### 1.1 Quy trình ISO 9 bước (trích `src-QT-TRINH-KY-HD.txt` bảng 2)
| # | Bước ISO | Trách nhiệm | SLA |
|---|---|---|---|
| 1 | Lựa chọn NTP/NCC | PB/BCH CT | — *(trỏ `SOL-PRO-SP-001` Quy trình Cung ứng)* |
| 2 | Soạn thảo hợp đồng | QS/NV.PB · TBP/TPB | 07 ngày |
| 3 | Góp ý nội dung | PD/PM/PRO/CCM/FIN/ACT | 07 ngày |
| 4 | Đàm phán, thương thảo | QS/NV.PB · TBP/TPB · PD/PM | 07 ngày |
| 5 | In hợp đồng *(NTP in 2 mặt, ký, đóng dấu → PD/PM/TPB ký nháy + ký cover FO-002.01)* | QS/NV.PB | 07 ngày |
| 6 | Kiểm tra *(CCM ký nháy từng HĐ + ký cover)* | CCM | 03 ngày |
| 7 | Duyệt *(xem xét + ký duyệt HĐ)* | BOD / NĐUQ | 01 ngày |
| 8 | Đóng dấu hợp đồng | HRA / ISO | — |
| 9 | Phát hành + Lưu trữ *(scan gửi CCM · gửi bản gốc NTP · lưu Server Filing System)* | PB/BCH CT · CCM | — |
### 1.2 🔴 PHÁT HIỆN A — 9 bước ISO ↔ 9 giá trị `ContractPhase` 1-9 KHỚP 1:1 ĐÚNG THỨ TỰ
Lead tự đọc `src/Backend/SolutionErp.Domain/Contracts/ContractPhase.cs` (28 dòng, đọc TRỌN):
| # ISO | Bước ISO | `ContractPhase` | Trạng thái enum |
|---|---|---|---|
| 1 | Lựa chọn NTP/NCC | `DangChon = 1` | `[LEGACY]` |
| 2 | Soạn thảo HĐ | `DangSoanThao = 2` | 🟢 **SỐNG** (Nháp) |
| 3 | Góp ý nội dung | `DangGopY = 3` | `[LEGACY]` |
| 4 | Đàm phán | `DangDamPhan = 4` | `[LEGACY]` |
| 5 | In hợp đồng / ký nháy | `DangInKy = 5` | `[LEGACY]` |
| 6 | Kiểm tra CCM | `DangKiemTraCCM = 6` | `[LEGACY]` |
| 7 | Duyệt BOD/NĐUQ | `DangTrinhKy = 7` | `[LEGACY]` |
| 8 | Đóng dấu | `DangDongDau = 8` | `[LEGACY]` |
| 9 | Phát hành + lưu trữ | `DaPhatHanh = 9` | 🟢 **SỐNG** (terminal) |
**7 phase `[LEGACY]` KHÔNG phải rác kiến trúc — chúng là quy trình ISO được mã-hoá CỨNG.**
Post-Mig 21 / Session 17 thay bằng `ChoDuyet = 10` + con-trỏ `CurrentWorkflowStepIndex` chạy trên
**workflow V2 admin-config** — tức chuyển từ *mã-hoá cứng 9 bước* sang *cấu-hình-được N bước*.
🔑 **Hệ quả lên verdict hôm qua:** verdict `LAI` (b.13→21 tái dùng V2) **KHÔNG đổi**, nhưng **lý do
mạnh hơn hẳn**: V2 sinh ra CHÍNH ĐỂ biểu diễn quy trình ISO này dưới dạng cấu hình. Hôm qua invest chỉ
lập luận được *"phase bị gỡ = trạm của b.13→21"*; nay có **tài liệu ISO gốc** chứng minh **vì sao** 9 trạm
đó tồn tại. Đây là **chứng cứ mới**, không phải diễn giải lại.
### 1.3 🔴 PHÁT HIỆN B — khoảng trống nằm ĐÚNG giữa ISO-1 và ISO-2, và ISO doc KHÔNG có nó
Quy trình ISO đi thẳng **bước 1 (Lựa chọn NTP/NCC) → bước 2 (Soạn thảo HĐ)**, KHÔNG có bước trung gian.
Sơ đồ PDF (bản `14/2026`, mới hơn) chèn **b.7→12** đúng vào chỗ đó:
```
ISO-1 Lựa chọn NTP/NCC ≡ PE "Duyệt NCC" (PE.DaDuyet=7, PDF b.1→6) 🟢 ĐÃ CÓ
└───────────── ⬛ KHOẢNG TRỐNG = "KẾ HOẠCH KÝ KẾT HỢP ĐỒNG" ⬛ ─────────────┐
PDF b.7→12: mail giao BCH · duyệt mẫu+shopdrawing với TVGS · │ 🔴 THIẾU
tổng hợp hồ sơ + so sánh giá → đề xuất GIÁ TRỊ ký HĐ · │ CẢ Ở
PMH kiểm tra → CCM kiểm tra → CEO ký / CCM đóng dấu approval │ DOC LẪN
┌─────────────────────────────────────────────────────────────────────────────┘ CODE
ISO-2 Soạn thảo HĐ ≡ Contract `DangSoanThao=2` (PDF b.13) 🟢 ĐÃ CÓ
```
**"Còn thiếu" theo nghĩa MẠNH: thiếu ở CẢ HAI tầng** — không có trong quy trình ISO đang ban hành,
và không có trong code. Không phải "code chưa làm theo doc"; là **doc cũng chưa có**.
🔴 ⇒ spec ra từ run này **vừa là spec phần mềm, vừa là đề xuất bổ sung quy trình ISO** cho anh duyệt.
### 1.4 Đối chiếu SLA — 2 nguồn, 2 độ mịn (cần hoà giải, KHÔNG tự chọn)
| Nguồn | SLA ghi | Ghi chú |
|---|---|---|
| ISO doc | 07 · 07 · 07 · 07 · 03 · 01 ngày (bước 2→7) | tổng ≈ **32 ngày** cho khúc soạn→duyệt |
| PDF sơ đồ | `10-14 ngày` (b.1→4) · `3 ngày` (BCH gửi full info) · `7-10 ngày` (b.13→18) | mịn hơn ở khúc BCH |
| Code hiện tại | `AddDays(7)` **hardcode** | lỗ L3 hôm qua — thụt lùi so V1, lỗ toàn-V2 (cả PE) |
### 1.5 Tờ `FO-002.01` = bản giấy của workflow duyệt
Bảng 40r×13c, các khối ký theo phòng: **PHÒNG BAN/DỰ ÁN (ĐỀ XUẤT)****PHÒNG CUNG ỨNG** (điều khoản HĐ ·
điều khoản thanh toán · rủi ro pháp lý) → … mỗi khối có `Họ tên` + `Ngày` + cột `Ý KIẾN`.
⇒ Ánh xạ thẳng sang `ApprovalWorkflowStep` (Phòng) × `ApprovalWorkflowLevel` (Cấp) + `LevelOpinions`
đã có sẵn ở V2 — **cần invest xác nhận độ khớp, đừng để lead tự kết luận.**
### 1.6 Nợ mang sang từ S156 — invest MỚI phải hấp thụ, không lặp lại
6 việc sửa bản invest cũ (`runs/2026-07-27-S156-bch-post-ceo-flow/review-synthesis.md` §G):
1. Claim SAI: *"hardcoded policy fallback"* → thật là **`ConflictException` `:115-116`** ⇒ HĐ sinh từ phiếu
**KẸT CỨNG `ChoDuyet`**, hỏng CỨNG. **Gốc lỗi: invest tin skill-doc hơn ĐĨA.**
2. Siết biên: vùng phase-đã-gỡ là **b.14→19**, KHÔNG phải b.13→21.
3. Thiếu Q vai người TRÌNH — `ContractWorkflowService.cs:70-79` đòi `Drafter|DeptManager`, PMH mang
`Procurement`**403** ở b.13/b.17.
4. Cảnh báo lỗ hổng reject = **việc RIÊNG**, anh đã chốt *"cứ từ từ"***NGOÀI scope run này**.
5. Q5 thiếu phương án **(d) `skipToFinal` + `AllowApproverSkipToFinal :322`** — ĐÃ WIRE, 0 code BE.
6. **Q2 phải viết lại theo 2 TRỤC + 3 số đo cùng đơn vị** (số bảng mới · LOC BE · LOC FE) **lấy từ twin
thật trong repo**, không ước cảm tính.
---
## 1.7 🔴 OWNER CHỐT TRONG CỬA (2026-07-28, anh trả lời trực tiếp báo-cáo grounding)
Lead trình 2 điểm ở §1.5 và §1.4; anh chốt **cả hai**. Đây là **quyết định owner**, không phải suy luận lead.
### (O-1) Cấu trúc trình ký — **GIỐNG**, khác duy nhất ở NỘI DUNG
> **anh (verbatim):** *"Đúng chính xác, cấu trúc trình ký giống, chỉ khác nội dụng thôi."*
⇒ Trả lời cho §1.5 (form `FO-002.01``ApprovalWorkflowStep` × `Level` × `LevelOpinions`).
🔑 **Hệ quả kiến-trúc — MẠNH, chốt trước cả khi invest trả bài:**
- Phiếu "Kế hoạch ký kết Hợp đồng" **TÁI DÙNG khung duyệt V2 đang chạy** (Quy trình > Bước=Phòng > Cấp=NV
cụ thể, OR-of-N cùng cấp, `LevelOpinions` UPSERT khi duyệt) — **giống hệt PE và Contract V2 đang làm**.
- Cái **DỰNG MỚI = NỘI DUNG phiếu** (các trường của "kế hoạch ký kết": căn cứ b.8-9 + so sánh giá +
giá trị đề xuất), **KHÔNG phải cơ-chế duyệt**.
- 🔻 **Q2 hôm qua (kiến trúc khúc 8-12, reviewer chấm `THIEU-PHUONG-AN` + thiên-vị) gần như TỰ ĐÓNG:**
tranh luận 3 phương án hôm qua xoay quanh *"có dựng cơ-chế duyệt riêng không"*. Anh vừa trả lời:
**không dựng cơ-chế mới, dùng lại khung**. ⇒ option-space thu về **chỉ còn trục NỘI DUNG**
(phiếu riêng ⟂ mở rộng PE ⟂ entity con của Contract). **Invest vẫn phải trình 3 số đo cho trục còn lại**,
nhưng KHÔNG cần bàn lại trục cơ-chế.
- Đây cũng là **đối chứng ngoài-code cho verdict `LAI`**: khung V2 gánh được vì bản GIẤY vốn cùng hình dạng.
### (O-2) SLA — **THAM KHẢO thôi**, không phải ràng buộc
> **anh (verbatim):** *"Cái này để tham khảo thôi, ko vấn đề j, đa số là trễ."*
⇒ Trả lời cho §1.4 (ISO 07/07/07/07/03/01 vs PDF 3 + 7-10 vs code hardcode `AddDays(7)`).
🔑 **Hệ quả:**
- **KHÔNG dựng SLA-engine**, KHÔNG auto-approve-on-timeout, KHÔNG cảnh báo chặn. SLA = **hiển thị tham khảo**.
- Không cần hoà giải 2 nguồn số ⇒ **gỡ một câu hỏi khỏi bộ câu hỏi trình anh**.
- 🔸 Lỗ **L3** (`AddDays(7)` hardcode, hôm qua xếp "thụt lùi so V1, lỗ toàn-V2") **TỤT ƯU TIÊN**
vẫn là số hiển thị sai, nhưng **không gây hại vận-hành** vì không ai enforce theo nó. Ghi nhận, đừng
nhét vào wave thi công của run này.
- 🔴 **Đừng đọc quá lời anh:** anh nói SLA *không quan trọng*, KHÔNG nói *bỏ hiển thị deadline*. Giữ hiển thị.
## 2. taskList snapshot
### Wave 1 — `/fable-real invest` (SINGLE deep-pass, engine-đắt Fable, KHÔNG fan-out)
```
[1] investigator-codebase (Fable, effort max)
→ §A quy trình chi tiết khúc CÒN THIẾU (đối chiếu 3 nguồn: ISO doc · PDF · FO-002.01)
→ §B cách wire vào codebase (entity · migration · CQRS · controller · FE 2-app · menu/permission)
→ §C chia WAVE thi công + checklist ĐO ĐƯỢC từng wave
→ §D 6 việc sửa của review cũ đã hấp thụ thế nào (từng cái, đối chiếu ĐĨA không tin doc)
propose-only; spec-file do LEAD ghi sau khi verify (H21 ① honest-note c)
```
### Wave 2 — `/fable-clone reviewer` ensemble 4 lane (đóng gói C2: ≤3 file/lane · ép khung rỗng lượt 1-2 · trần 25)
**Label C3 4-thành-phần — NEO TẠI ĐÂY** (panel ephemeral, không neo thì không tái lập/audit được):
| Label (neo C3) | Lăng kính | File được đọc (≤3) |
|---|---|---|
| `Gate reviewer lens-wave s157` | Wave-plan có khả thi không · acceptance có **ĐO ĐƯỢC thật** không hay chỉ nghe như đo được · wave có deploy độc lập thật không | `spec-ke-hoach-ky-ket-hd-28-07-2026.md` · `runs/2026-07-27-S155-pe-delete-approver/run.md` |
| `Gate reviewer lens-fidelity s157` | Spec có trung thực với **3 nguồn gốc** không — bịa bước / rơi bước / gán sai vai / nống biên | `spec-*.md` · `src-QT-TRINH-KY-HD.txt` · `src-FO-002.01-bang-kiem-tra-HD.txt` |
| `Gate reviewer lens-schema s157` | **7 bảng** thừa/thiếu · loose-Guid vs FK · UNIQUE filtered · enum mới có đúng không · biến thể 5 bảng | `spec-*.md` · `ApprovalWorkflow.cs` · `PurchaseEvaluation.cs` |
| `Gate reviewer lens-claims s157` | Verify ĐỘC LẬP mọi claim `file:line` trong §2 — có dương-giả không | `spec-*.md` · `ProposalFeatures.cs` · `MenuKeys.cs` |
**taskList snapshot (wave 2):** 4 lane · `role: reviewer` ×4 · `tier: 'opus'` explicit từng lane (belt-and-suspenders
theo GAP#6 — worker-tier-pin S124 đã che, nhưng lệnh này tự định nghĩa là "ensemble tier-2") · `maxTurns: 25` ·
lane RETURN-only, lead = single-writer refute+synthesize @P3/P4.
### Wave 3 — lead synthesize → `spec-ke-hoach-ky-ket-hd-28-07-2026.md` + **PLAN WAVE thi công trình anh**
---
## 3. Stages
- [x] S0 — lead trích 2 tài liệu gốc (`src-QT-TRINH-KY-HD.txt` 14.425 B · `src-FO-002.01-*.txt` 21.287 B)
- [x] S1 — lead grounding: đọc TRỌN `ContractPhase.cs`**phát hiện A** (9 ISO ↔ 9 enum khớp 1:1) +
**phát hiện B** (khoảng trống nằm giữa ISO-1 và ISO-2, thiếu ở CẢ doc lẫn code)
- [x] S2 — scaffold run-folder + `run.md` (file này)
- [x] S3 — `/fable-real investigator-codebase` deep-pass — **3 lượt, 2 sự-cố, PARTIAL-HONEST**:
· lượt 1 **`skeleton-ruột-rỗng`**: 202K tok / 35 tool-use, đĩa chỉ **1.661 B khung rỗng 4 mục `[PENDING]`**
(return garble `#53` = mẩu "Đọc tiếp 3 file S156"). **Ghi-đĩa-trong-lúc-làm = CẦN KHÔNG ĐỦ** — phải
verify RUỘT có chữ. Header ĐÃ hấp thụ O-1/O-2 ⇒ SendMessage giữa chừng ăn.
· lượt 2 (resume, **cắt còn 2 mục** theo khuôn cứu S156) → **§A + §B CLEAN**, đĩa 1.661→**23.085 B**,
return khớp đĩa.
· lượt 3 (resume §C/§D) — **tiến-trình CLI thoát giữa chừng**, agent stopped no-completion-record.
Đĩa **KHÔNG đổi** (23.085 B, mtime 10:55) ⇒ §C/§D **chưa từng được ghi**. Mất = phần chưa làm, **0 mất
dữ-liệu đã có**. **KHÔNG resume lần 3** (nguyên-nhân ngoại-cảnh, nhưng H21 ① đã cho phép: engine
propose-only, **spec do LEAD ghi**; §A/§B CHÍNH LÀ phần propose).
- [x] S4 — lead verify ĐỘC LẬP 4 claim load-bearing trên ĐĨA (không tin return):
· **B.1 Proposal-lite phá OR-of-N** → ✅ THẬT: `ProposalFeatures.cs` `SelectMany` flatten `:427-429` +
`ElementAtOrDefault` **1 row** `:433` + so đúng **1** `ApproverUserId` `:439`; comment code TỰ THÚ
*"Lite version: assume 1 step per workflow"*.
· **slot enum 10 trống** → ✅ THẬT: `ApprovalWorkflow.cs:53-67` dừng ở `TravelRequest = 9`.
· **`Off_DeXuat` 4 key ĐỀU trong `All`** → ✅ THẬT `MenuKeys.cs:171`; **`Pe_*` sinh bằng factory
`:150`/`:154` NẰM NGOÀI `All`** ⇒ policy per-action không tồn tại — bẫy claim đúng.
· **Mig cuối = 68** → ✅ khớp `docs/STATUS.md` CURRENT STATE.
- [x] S5 — lead ghi spec `spec-ke-hoach-ky-ket-hd-28-07-2026.md` (3 heading H21 ①) — §A/§B từ invest
(đã verify) + **§C wave-plan + §D do LEAD viết** (đúng H21: propose ⟂ spec).
- [ ] S6 — `/fable-clone reviewer` ensemble chấm spec
- [ ] S7 — lead refute + synthesize → trình anh
> 🔴 **Luật của run này (vết S156):** CẤM điền sẵn kết-quả cho stage chưa chạy. Byte-count · verdict ·
> TOTAL chỉ được ghi SAU khi đo thật. Mọi stage chưa chạy giữ `[ ]`.

View File

@ -0,0 +1,462 @@
# SPEC — "KẾ HOẠCH KÝ KẾT HỢP ĐỒNG" (khúc còn thiếu giữa Duyệt NCC và HĐ NTP/NCC)
> **Run:** `2026-07-28-S157-ke-hoach-ky-ket-hd` · lead-written sau verify (H21 ①: engine propose-only ⟂ lead ghi spec)
> **Nguồn propose:** `sub-invest-kehoach-1.md` §A+§B (23.085 B, `/fable-real investigator-codebase` Fable)
> **Lead verify:** 4 claim load-bearing đo lại độc lập trên đĩa — xem `run.md` S4. §C+§D dưới đây **lead viết**.
> **Trạng thái:** CHỜ `/fable-clone reviewer` chấm + **5 câu owner** chưa trả lời (không chặn Wave 1-2).
---
## ① TÍNH NĂNG / ĐỀ BÀI
### 1.1 Vấn đề
Giữa **Duyệt NCC** (module PE, kết thúc `PE.DaDuyet`) và **Hợp đồng NTP/NCC** (module Contract, bắt đầu
`DangSoanThao`) có một khúc quy trình **KHÔNG TỒN TẠI Ở CẢ HAI TẦNG**:
- **Không có trong code** — repo 0-hit `shopdrawing|TVGS|duyệt mẫu`.
- **Không có trong quy trình ISO đang ban hành** — `QT TRINH KY HOP DONG TP-NCC.docx` bảng 2 đi THẲNG
bước 1 *"Lựa chọn NTP/NCC"* → bước 2 *"Soạn thảo hợp đồng"*, **0 bước trung gian**.
- **Chỉ có trên sơ đồ PDF** `01- Quy trinh hien tai --- 14_2026` (bản mới), các bước **b.7→12**.
🔴 ⇒ **Spec này vừa là spec phần mềm, vừa là ĐỀ XUẤT BỔ SUNG QUY TRÌNH ISO.** Anh cần duyệt ở cả 2 tư cách.
### 1.2 Tên + mục đích (owner đặt)
> **anh:** *"Bước này là bước **'đề xuất giá trị ký kết hợp đồng'**"* · sau đó gọi là **"Kế hoạch ký kết Hợp đồng"**.
Đây là phát biểu **MỤC ĐÍCH**: đầu ra của khúc này = **MỘT CON SỐ CÓ PHÊ DUYỆT** (giá trị ký kết đề xuất).
b.8-9 (duyệt mẫu / shopdrawing với TVGS) = **CĂN CỨ**; b.10-12 = **chuỗi duyệt chính con số đó**.
⇒ Vật mang trong hệ thống = **một PHIẾU**, không phải thư mục đính kèm.
### 1.3 Bối cảnh kiến trúc — 2 phát hiện nền (lead đo, invest xác nhận từ nguồn gốc)
**(A) 7 phase `[LEGACY]` của `ContractPhase` CHÍNH LÀ quy trình ISO 9 bước, mã-hoá cứng.** Khớp 1:1 đúng thứ tự:
`DangChon=1`↔Lựa chọn NTP/NCC · `DangSoanThao=2`↔Soạn thảo · `DangGopY=3`↔Góp ý · `DangDamPhan=4`↔Đàm phán ·
`DangInKy=5`↔In HĐ · `DangKiemTraCCM=6`↔Kiểm tra CCM · `DangTrinhKy=7`↔Duyệt BOD · `DangDongDau=8`↔Đóng dấu ·
`DaPhatHanh=9`↔Phát hành. Post-Mig 21/S17 thay bằng `ChoDuyet=10` + con-trỏ chạy trên workflow V2 admin-config
⇒ chuyển từ *cứng 9 bước* sang *cấu-hình N bước*. **Khung V2 sinh ra CHÍNH ĐỂ biểu diễn quy trình ISO này.**
**(B) Khoảng trống nằm ĐÚNG giữa ISO-1 và ISO-2** (xem 1.1).
### 1.4 🔴 OWNER ĐÃ CHỐT (2026-07-28) — ràng buộc cứng của spec
| # | Anh nói (verbatim) | Hệ quả spec |
|---|---|---|
| **O-1** | *"Đúng chính xác, cấu trúc trình ký giống, chỉ khác nội dụng thôi."* | **TÁI DÙNG khung duyệt V2** (`ApprovalWorkflow`>Step=Phòng>Level=NV, OR-of-N, `LevelOpinions`). **0 bảng approval mới.** Dựng mới = **NỘI DUNG phiếu**. ⇒ trục tranh luận Q2 hôm qua **ĐÓNG**. |
| **O-2** | *"Cái này để tham khảo thôi, ko vấn đề j, đa số là trễ."* (SLA) | **KHÔNG SLA-engine**, không auto-approve-on-timeout, không cảnh báo chặn, **không wave nào cho SLA**. Giữ hiển thị deadline. Lỗ `AddDays(7)` hardcode = ghi nhận, ngoài scope. |
| **O-3** | *"Chỗ hợp đồng cứ từ từ nhé."* | Lỗ hổng an ninh `ContractWorkflowService.cs:48-66` + controller HĐ class-trần: **NGOÀI SCOPE**, treo có chủ đích. Wave nào chạm module Contract phải hỏi lại anh. |
### 1.5 Quy trình chi tiết — 6 bước (b.7→12)
Role hệ thống có thật (`AppRoles.cs:5-16`): `Procurement` (PMH) · `CostControl` (CCM) · `Director`+`AuthorizedSigner`
(BOD/NĐUQ) · `ProjectManager`/`Drafter` (BCH) · `HrAdmin` · `Admin`.
🔸 **"BCH dự án X" KHÔNG có model** (`Department.ManagerUserId` 0-row) ⇒ né bằng: **BCH = người tạo phiếu**
(`CreatedBy`); PMH/CCM/CEO = **đích danh user trong Level** của workflow V2 (đúng triết lý V2, **0 model mới**).
| b | Việc | Ai | Đầu vào | Đầu ra | Chuyển bước | Nhánh lỗi |
|---|---|---|---|---|---|---|
| 7 | PMH chuyển thông tin cho BCH | Procurement | PE `DaDuyet` (winners `IsWinner`, giá `SUM Quote.IsSelected`, HoSoLink) | BCH biết việc | **Pull-model**: màn *"PE đã duyệt — chờ lập KH"* lọc `Phase==DaDuyet && chưa có plan` (khuôn `CreateContractFromEvaluationFeatures.cs:173`) + notify in-app. **Email ra ngoài = ngoài scope** (SMTP TODO toàn hệ thống) | PE thiếu winner → không hiện |
| 8 | Duyệt mẫu + shopdrawing với TVGS | BCH **nhập hộ** (TVGS ngoài hệ thống) | Mẫu + shopdrawing từ NTP/NCC (offline) | Danh mục **CĂN CỨ** trong phiếu: {Kind, NCC, Status, TvgsName, ngày, scan} | Vòng đời **per-item**: `ChuaNop→DaNop→TvgsDuyet\|TvgsBac`; `TvgsBac→DaNop` (nộp lại) — 🔴 **sơ đồ KHÔNG vẽ vòng lặp này, thực tế có** | Item bị bác = đổi status + note, **KHÔNG đụng state machine phiếu** |
| 9 | Tổng hợp + so sánh giá → **ĐỀ XUẤT giá trị** | BCH (Drafter phiếu) | Căn cứ b.8 + báo giá PE (**snapshot** `PeReferenceAmount` lúc tạo — nguyên tắc freeze Mig 67) | Phiếu đủ dòng giá đề xuất per-winner + file so sánh → **TRÌNH** | Guard trình: đủ dòng giá per-winner (mirror completeness-guard PE `PurchaseEvaluationWorkflowService.cs:180-212`); căn cứ chưa đủ `TvgsDuyet`**cảnh báo mềm** (tiền lệ S62) — **O-Q1 owner quyết mềm/cứng** | Ghi chú sơ đồ *"hồ sơ sai sót → gửi mail làm rõ"* = comment + item `TvgsBac` |
| 10 | PMH kiểm tra, xác nhận giá trị | Procurement (đích danh Level) | Phiếu `ChoDuyet` Bước 1 | Duyệt → Bước 2; ý kiến vào `LevelOpinions` (UPSERT khuôn `ContractWorkflowService.cs:292-316`) | OR-of-N trong Cấp (`ApprovalWorkflow.cs:81-94`) | Trả lại → `TraLai`, hoặc 4 return-mode per-level (cờ CÓ SẴN `ApprovalWorkflowLevel.cs:116-125`) |
| 11 | CCM kiểm tra | CostControl | Bước 2 | Duyệt → Bước 3 | như trên | như trên |
| 12 | **CEO ký HOẶC CCM đóng dấu** | Director / cơ chế kết thúc sớm | Bước 3 (hoặc kết thúc tại Bước 2) | 🔴 **GIÁ TRỊ KÝ KẾT CHỐT** per-winner (`ApprovedAmount`) ghi tại **finalize choke-point** (mirror `ApplyApprovedPriceOnFinalize` PE `:973-1002` + RULE `:1008` *mọi nhánh set DaDuyet phải gọi helper*) | Terminal `DaDuyet` | Từ chối → `TuChoi`; trả lại → `TraLai` |
**Rẽ nhánh b.12 "hoặc" — 4 đường ĐỀU CÓ SẴN trong khung V2, 0 migration:**
(i) `CeoApprovalThreshold` + CCM tích "duyệt done miễn CEO" (PE `:892-929`, fail-closed: đòi threshold + role
`CostControl` + giá < ngưỡng) · (ii) `AllowApproverFinalize` per-slot (PE `:870-890`) · (iii)
`AllowApproverSkipToFinal` per-slot, CEO vẫn thật (Contract `:320-352`) · (iv) 2 workflow (/không Step CEO)
admin pin. 🔸 **Điều kiện rẽ THẬT: cả 3 nguồn IM LẶNG** **Q3 owner**; chọn đường nào **cũng không đổi schema**.
### 1.6 b.8-9 là **bảng con trong phiếu** — không phải phiếu con, không phải module riêng
do: (1) owner phát biểu b.8-9 = **căn cứ**, không phải đối tượng duyệt riêng; (2) PDF chỉ vẽ **MỘT** chuỗi
duyệt (10-12) cho cả khúc phiếu con = đẻ chuỗi duyệt thứ 2 không trên giấy; (3) vòng đời mẫu/shopdrawing
**per-item status**, không phải state machine phiếu; (4) TVGS ngoài hệ thống chỉ cần **ghi vết**.
Module riêng chỉ đáng khi mẫu/shopdrawing cần quản **độc lập với gói thầu** chưa yêu cầu.
### 1.7 Mâu thuẫn / im lặng giữa 3 nguồn (bảng tra — KHÔNG tự quyết)
| # | Điểm | ISO doc | PDF | FO-002.01 | Xử |
|---|---|---|---|---|---|
| 1 | Khúc b.712 | **KHÔNG CÓ** | (duy nhất) | không nói | Spec = đề xuất bổ sung ISO |
| 2 | SLA khúc 712 | im lặng | im lặng | im lặng | **O-2**: tham khảo, không hoà giải |
| 3 | SLA khúc | 07/07/07/07/03/01 ngày | 3d + 7-10d | 🔴 *"mỗi bộ phận 01 ngày, quá hạn **XEM NHƯ ĐÃ THÔNG QUA**"* | 3 nguồn 3 kiểu; auto-pass **mâu thuẫn mô hình duyệt-chặn V2**. O-2 chỉ ghi nhận |
| 4 | Điều kiện rẽ b.12 | | "hoặc", 0 điều kiện | không nói | **Q3 owner** |
| 5 | Nhánh trả lại 10/11/12 | không vẽ | không vẽ | không vẽ | Hệ thống sẵn `TraLai` + 4 return-mode |
| 6 | Bypass Chủ đầu | không nói | không nói | | = `Contract.BypassProcurementAndCCM` (đã ) **KHÔNG áp phiếu KH** |
| 7 | Checklist kiểm tra per-phòng (PRO: điều khoản/thanh toán/rủi ro pháp · CCM: giá vs NS) | tả lời | không | (checkbox từng mục) | Hệ thống chỉ `LevelOpinions.Comment` tự do **GAP**, **O-Q2 owner** số hoá checkbox không |
| 8 | Tên phòng/vai | PRO/CCM/BOD/NĐUQ/HRA | Procurement/CCM/CEO | PB-DA/PRO/CCM/ | Khớp `AppRoles` **0 mâu thuẫn** |
| 9 | Chuỗi FO-002.01 (ĐỀ XUẤTPROCCM) | ISO 5-7 | b.9101112 **CÙNG HÌNH** | | **Đối chứng GIẤY cho O-1** |
---
## ② CÁCH IMPLEMENT
### 2.1 ⚠️ BẪY SỐ MỘT — CẤM copy "Đề xuất" (Proposal) cho phần DUYỆT
`ProposalFeatures.cs` twin **nhỏ nhất** (849 LOC BE) nên rất cám dỗ. **Nhưng phần duyệt của nó phá OR-of-N:**
`SelectMany` flatten mọi Level xuyên Steps `:427-429` `ElementAtOrDefault(order-1)` lấy **1 row** `:433`
so đúng **1** `ApproverUserId` `:439`. Comment trong chính file **tự thú**: *"Lite version: assume 1 step per
workflow"*. Entity Proposal cũng **chỉ có `CurrentApprovalLevelOrder`, KHÔNG có `CurrentWorkflowStepIndex`**.
2 người cùng Cấp (OR-of-N hợp lệ theo `ApprovalWorkflow.cs:81-94`) bị biến thành **2 nấc TUẦN TỰ (AND)**.
nhiều người cùng cấp **chính là thứ tờ FO-002.01 cần**.
🔴 **Service PHẢI copy `ContractWorkflowService.ApproveV2Async:217-394`** (con-trỏ ĐÔI StepIndex+LevelOrder ·
`GroupBy` Order `:246` · OR-of-N `:259-260` · `LevelOpinions` UPSERT `:292-316` · skipToFinal `:320-352`).
**Proposal chỉ làm khuôn cho CRUD / DTO / menu / FE.**
> ✅ *Lead đã tự đọc `ProposalFeatures.cs:420-445` xác minh — claim ĐÚNG, không phải suy diễn.*
### 2.2 Schema — Mig **69** `AddContractSigningPlans` · **7 CreateTable, 0 ALTER bảng cũ**
Down = `DropTable ×7`, reversible sạch. Convention: PascalCase EN · **loose-Guid không FK vật lý** sang
PE/Supplier (convention PE, ghi Mig 49) · FK vật chỉ nội bộ module + sang bảng V2 dùng chung.
| # | Bảng | Cột chính | Ràng buộc |
|---|---|---|---|
| 1 | `ContractSigningPlans` (header) | `MaKeHoach?` · `PurchaseEvaluationId` (loose+IX) · `ProjectId` (denorm lọc) · `Phase int` · `ApprovalWorkflowId Guid?` · `CurrentWorkflowStepIndex int?` · `CurrentApprovalLevelOrder int?` · `DrafterUserId` · `SlaDeadline?` · `HoSoLink nvarchar(1000)?` · `GhiChu` | `AuditableEntity` + `HasQueryFilter(!IsDeleted)` (khuôn `PurchaseEvaluationConfiguration.cs:84`) |
| 2 | `ContractSigningPlanLines` (giá per-winner) | `PlanId` FK Cascade · `SupplierId` loose · **`PeReferenceAmount` decimal(18,2) SNAPSHOT lúc tạo** · `ProposedAmount` · `ApprovedAmount?` (chỉ ghi tại finalize) · `Note` | UNIQUE filtered `(PlanId, SupplierId) WHERE IsDeleted=0` (gotcha #57) |
| 3 | `ContractSigningPlanDossierItems` (căn cứ b.8-9) | `PlanId` FK Cascade · `Kind int` (MauVatLieu=1/Shopdrawing=2/Khac=99) · `SupplierId?` · `Name` · `Status int` (ChuaNop=0/DaNop=1/TvgsDuyet=2/TvgsBac=3) · `TvgsName?` · `TvgsResultAt?` · `Note` | IX (PlanId) |
| 4 | `ContractSigningPlanLevelOpinions` | `PlanId` + `ApprovalWorkflowLevelId` · `Comment nvarchar(2000)` · `SignedAt` · `SignedByUserId` · `SignedByFullName` | UNIQUE (PlanId, LevelId); FK **Cascade Plan + Restrict Level** (mirror `ContractLevelOpinions` Mig 33) |
| 5 | `ContractSigningPlanAttachments` | `PlanId` FK Cascade · FileName/Path/Size/ContentType · `Purpose int` · `DossierItemId?` | khuôn `ProposalAttachment.cs` |
| 6 | `ContractSigningPlanChangelogs` | `PlanId` · **`EntityType`** · **`EntityId`** · Action · PhaseAtChange · UserId · **`UserName`** · Summary · **`FieldChangesJson` nvarchar(max)** · `ContextNote nvarchar(2000)` | **có từ ngày 1** tiền lệ PE Mig 60/61. 🔴 **4 cột in đậm THÊM sau review** (lens-schema C1): thiếu chúng thì `LogTransitionAsync` copy sang **KHÔNG BIÊN DỊCH** (`ContractWorkflowService.cs:405` gọi `changelog.LogWorkflowTransitionAsync`) + mất index twin `(PlanId, EntityType)` |
| 7 | 🆕 `ContractSigningPlanApprovals` (lịch sử transition) | `PlanId` FK Cascade · `FromPhase` · `ToPhase` · `Decision` · `Comment` · `ApprovalWorkflowLevelId?` · `ApprovedByUserId` · `ApprovedAt` | 🔴 **THÊM sau review** (lens-schema H1): service được lệnh copy **CÓ ghi vào bảng này** `ContractWorkflowService.cs:151` `db.ContractApprovals.Add(...)`; twin PE `PurchaseEvaluation.cs:137` + index `(PeId, ApprovedAt)`. Thiếu đoạn copy trỏ bảng KHÔNG TỒN TẠI |
| ~~8~~ | ~~`ContractSigningPlanCodeSequences`~~ **CẮT** | | 🔴 **GỠ sau review** (lens-schema T1): **TÁI DÙNG `WorkflowAppCodeSequence`** bảng này **đã dùng chung cho 4 module Office**, phân biệt bằng Prefix namespaced (`"DT/LR/2026"` · `"DT/OT/2026"` · `"DX/XE/2026"` `WorkflowAppCodeSequence.cs:8-11`). Prefix `"KHKK/{YYYY}"` nhét vào = **0 va chạm**. Tính atomic đến từ **transaction SERIALIZABLE trong CodeGen service**, KHÔNG từ việc bảng thuộc riêng module (`ContractCodeSequence.cs:5` nói ) lập luận *"cắt = mất mã atomic"* của bản đầu **SAI, đã rút**. |
**Tổng vẫn 7 bảng** (thêm #7 Approvals, cắt CodeSequences). Down = `DropTable ×7`.
**Biến thể tối thiểu 6 bảng** (bỏ #6 Changelogs) **KHÔNG khuyến nghị**: Mig 60/61 chứng minh cần changelog để
backfill. *(Bản đầu đề xuất "tối thiểu 5, cắt #6+#7" — nay #7 cũ đã cắt sẵn, và lý do giữ #6 vẫn đứng.)*
**Cột chuỗi PHẢI khai độ dài** (lens-schema C3 thiếu thì EF sinh `nvarchar(max)`, **không index được, không dùng
được trong filtered-unique**): `MaKeHoach` 50 · `GhiChu` 2000 · `Name` 500 · `Note` 1000 · `TvgsName` 200 ·
`Summary` 1000 · `ContextNote` 2000 · `SignedByFullName` 200 **IsRequired** (khuôn
`ContractLevelOpinionConfiguration.cs:21-22`) · `FileName` 500 / `Path` 1000 / `ContentType` 200.
**+2 cột header THÊM sau review:**
- **`DepartmentId Guid?`** (lens-schema C5) twin `PurchaseEvaluation.cs:17`. Thiếu thì vế **`DeptManager`**
của guard trình **không so được với gì** *bất kỳ ai mang vai DeptManager trình được phiếu của phòng khác*.
`ApprovalWorkflowStep.DepartmentId` chỉ **hint của quy trình**, KHÔNG thay được phòng của phiếu.
- **`ContractId Guid?` trên `Lines`** (lens-schema C6) đường quay ngược Kế-hoạch sau b.13; twin
`PurchaseEvaluation.ContractId:31` + index. sinh **per-NCC**, `Lines` cũng **per-NCC** đây chỗ tự nhiên.
- 🔸 **`SlaDeadline?` GIỮ nhưng khai **: **FE hiển thị tham khảo, KHÔNG đăng `SlaExpiryJob`, KHÔNG
`SlaWarningSent`** (O-2 anh chốt SLA chỉ tham khảo). Khai vậy để **không** rơi vào lớp *"cột có mà 0 ai đọc"*
người đọc FE, không phải job.
**Enum:**
- `ApprovalWorkflowApplicableType` **+`ContractSigningPlan = 10`** append-only. *Lead verify: `ApprovalWorkflow.cs:53-67` dừng ở `TravelRequest = 9`, **slot 10 TRỐNG THẬT**.*
- `ContractSigningPlanPhase` **MỚI**, giá trị sạch: `DangSoanThao=1 / ChoDuyet=2 / DaDuyet=3 / TraLai=98 / TuChoi=99`.
- 🔴 **`DossierItemStatus` PHẢI bắt đầu từ 1** ( lens-schema C2): `ChuaNop=1 / DaNop=2 / TvgsDuyet=3 / TvgsBac=4`
**KHÔNG dùng 0**. Mọi enum repo bắt đầu 1 (`Office/Enums.cs:9,:19,:31,:41,:50,:58` · `ApprovalWorkflow.cs:55`),
**0 là falsy trong JS** `status ? A : B`, `if (filter.status)`, `?status=0` **rơi im lặng ở FE**.
Giữ `Khac = 99` cho `Kind` (đúng khuôn `ItTicketCategory.Other = 99`).
**KHÔNG copy 7/98 của PE** (sẹo lịch sử enum PE phiếu mới không nợ data ); giữ 98/99 cho quen mắt FE badge.
- 🔴 **KHÔNG thêm cột `SigningPlanId` lên PE** tra ngược bằng `Plans.Where(PurchaseEvaluationId==x)`.
Thêm cột = đẻ *"cột có mà 0 ai đọc"* (lớp lỗi đã cắn **6 lần** repo này).
### 2.3 CQRS + Service + Controller
**`Application/ContractSigningPlans/ContractSigningPlanFeatures.cs`** (mega-file, khuôn `ProposalFeatures.cs`):
- `CreateContractSigningPlanCommand(PeId, ApprovalWorkflowId, GhiChu?)` validator: PE tồn tại + `Phase==DaDuyet`
(mirror cầu `src/Backend/SolutionErp.Application/PurchaseEvaluations/CreateContractFromEvaluationFeatures.cs:53-54`
🔴 **đường dẫn đầy đủ, đã sửa**: file nằm `PurchaseEvaluations/` **KHÔNG phải `Contracts/`**; spec bản đầu
để tên trần khiến reviewer đoán sai thư mục trượt 1 lượt đọc lens-claims điểm củng cố 3)
+ **chưa có plan sống** (`AnyAsync(p.PeId==x && p.Phase!=TuChoi)` Conflict; cho tạo lại sau `TuChoi`)
+ workflow `ApplicableType==ContractSigningPlan` (mirror Proposal **`:258-267`** 🔴 **mở rộng khoảng, đã sửa**:
`:258-265` chỉ phần **nạp** `wfType`; **guard thật nằm ở `:266-267`** `if (wfType.Value != (int)...) throw
new ConflictException(...)`. Ai copy đúng `258-265` sẽ copy phần đọc **bỏ mất chính cái guard** lens-claims S4).
Handler **auto-sinh Lines từ winners**: `pe.Suppliers.Where(IsWinner)`, `PeReferenceAmount = SUM Quote.IsSelected`
per winner (copy đúng phép tính cầu `:56-62`, `:88-90`) **snapshot 1 lần**.
- `UpdateContractSigningPlanDraftCommand` guard `Phase ∈ {DangSoanThao, TraLai}` + **cho re-pin
`ApprovalWorkflowId`** (mirror PE; tránh vết Contract UpdateDraft KHÔNG đường re-pin).
- `Get` / `List` / `pendingMe` detail Include Lines+DossierItems+Attachments+LevelOpinions + workflow-tree
(khuôn Proposal `:161-228`); 🔴 **inbox V2 precompute TỪ NGÀY 1** (mirror PE `ResolveV2InboxIdsAsync`)
bẫy đã cắn Contract: thiếu cái này **approver không mở được phiếu đang chờ chính mình**
(`ContractFeatures.cs:363-372` legacy-only, `grep ChoDuyet` = 0 hit).
- `UpsertDossierItemCommand` / `DeleteDossierItemCommand` chỉ mở `DangSoanThao|TraLai` (căn cứ **input**
của con số đang duyệt). Attachment mở mọi phase (triết PE S147: BE không phase-guard attachment).
**`Infrastructure/Services/ContractSigningPlanWorkflowService.cs`** copy `ApproveV2Async:217-394` 2.1), adapt 3 chỗ:
1. Terminal `Phase=DaDuyet` + **`ApplyApprovedValuesOnFinalize`**: mọi Line `ApprovedAmount ??= ProposedAmount`
tại **choke-point duy nhất** + RULE grep-4-site (khuôn `PurchaseEvaluationWorkflowService.cs:1008`).
2. Port 2 nhánh kết thúc sớm: `AllowApproverFinalize` `:870-890` + `finalizeByCcmDelegation`+`CeoApprovalThreshold`
`:892-929` (tổng so ngưỡng = `SUM ProposedAmount`).
3. Reject 4 return-mode per-level (cờ sẵn tại **`Domain/ApprovalWorkflowsV2/ApprovalWorkflow.cs:116-125`**
🔴 **anchor đã sửa**: bản đầu ghi `ApprovalWorkflowLevel.cs` nhưng **KHÔNG CÓ FILE NÀO TÊN VẬY**
(Glob 0 hit; class `ApprovalWorkflowLevel` nằm TRONG `ApprovalWorkflow.cs:95`) lens-claims S2, mức MAJOR
implementer mở theo spec sẽ **file-not-found**; logic mirror PE `ApplyReturnModeAsync:368-547`)
**tối thiểu `TraLai` toàn phần** nếu muốn gọn wave đầu.
🔴 **Guard trình = `CreatedBy==actor DeptManager Admin`** **CỐ Ý KHÁC** khuôn role-based
(`ContractWorkflowService.cs:70-79` đòi `Drafter|DeptManager`) để **né lớp 403-PMH**: PMH mang role `Procurement`
nên bị chặn b.13/b.17 đúng lớp *"cơ-chế đúng, vai đi qua không có"*. Nếu owner muốn đồng nhất role-based thì
BCH users **phải được gán role `Drafter`**.
🔴 **Notify:** mirror `LogTransitionAsync` báo Drafter (`ContractWorkflowService.cs:407-427`) **+ THÊM notify đích
danh approver của Cấp kế** fix lỗ *notify-chỉ-Drafter* **ngay từ ngày 1**, đừng chép nợ.
**`Api/Controllers/ContractSigningPlansController.cs`** 🔴 **authz 2 TẦNG** (bài học #82 / S118):
class `[Authorize]` **+ per-action** `[Authorize(Policy = "ContractSigningPlans.{Read|Create|Update|Delete}")]`.
**KHÔNG chép kiểu `ContractsController.cs:12-13` class-trần** (đó chính lỗ đang treo). Policy TỰ SINH khi key
vào `MenuKeys.All` (`Program.cs:82-89` foreach `All × Actions`).
Endpoints: `GET` list/inbox · `GET {id}` · `POST` · `PUT {id}` · `POST {id}/transitions` · dossier-items CRUD ·
attachments · `DELETE {id}` (allow-list `DangSoanThao|TuChoi`, mirror PE `:1404`).
### 2.4 Menu + Permission + FE 2 app (Pattern 16-bis 4-place mirror)
- 🔴🔴 **BE `MenuKeys.cs` — TÊN KEY PHẢI TRÙNG TIỀN-TỐ POLICY** ( lỗi CHÍ MẠNG review lens-wave H2 bắt):
+4 const **`ContractSigningPlans`** / `ContractSigningPlans_List` / `_Create` / `_Inbox`
**VÀ đưa CẢ 4 vào mảng `All`**. Policy controller = **`ContractSigningPlans.{Action}`** **khớp key**.
**Bản đầu spec đặt key `Csp*` policy `ContractSigningPlans.*` LỆCH `Program.cs` KHÔNG sinh policy
`[Authorize(Policy=...)]` trỏ policy không tồn tại **HTTP 500 lúc chạy, KHÔNG phải 403**.
Repo ĐÃ lưới bắt: `tests/SolutionErp.Infrastructure.Tests/Api/AuthorizePolicyRegressionTests.cs:138-139`
ghi nguyên văn *"policy trỏ menu key KHÔNG có trong MenuKeys.All ⇒ Program.cs không sinh policy đó ⇒ 500 lúc chạy"*
lead tự đọc xác nhận test tồn tại. 🔑 **Bài học:** §2.4 bản đầu nhận diện ĐÚNG bẫy `Pe_*`, rồi §2.3 vẫn tự
vấp đúng bẫy đó bằng chế khác (lệch TÊN thay factory-ngoài-All) *bài học nằm trong tay vẫn không tự bật*.
*Lead verify `MenuKeys.cs:168`* (**anchor đã sửa từ `:171` `:171` `Personal,`**, review lens-claims S1):
`OffDeXuat`+3 con **đều trong `All`**; còn `Pe_*` sinh bằng **factory** `:150`/`:154` **NẰM NGOÀI `All`**.
**Theo khuôn `Off_DeXuat`, KHÔNG theo `Pe_*`.**
2 row canonical `docs/STATUS.md` (Menu keys · Policies = |All|×4) phải bump cùng lúc.
- **Seed `DbInitializer.cs`:** 4 dòng menu (khuôn Off_DeXuat `:1817-1820`, label VN *"Kế hoạch ký kết HĐ"* /
*"Danh sách"* / *"Tạo mới"* / *"Inbox duyệt"*) + admin-permission (`:2383` **grep MỌI site seed-permission**,
S155 ghi nhận 2 site cho vài nhóm). **Dark-launch được bằng `IsVisible=0`** rồi bật sau.
- **FE ×2 app** (duplicate CHỦ ĐÍCH), mỗi app 4 chỗ: `App.tsx` routes · `Layout.tsx` staticMap ·
`lib/menuKeys.ts` · `pages/` ×3 (khuôn bộ Proposal ~978 LOC/app: List 252 + Create 245 + Detail 386 + types 95).
Detail thêm: bảng **Lines** (đề xuất/chốt per-NCC) · bảng **DossierItems** (status chip + TVGS + scan) ·
**panel workflow** (mirror PE Panel-3 ✓/●/○) · **banner "Đến lượt bạn"** (khuôn PE `blockedByV2Level`).
- **Designer admin nhận type 10:** fe-admin `ApprovalWorkflowsV2Page.tsx` map typeCodeint `:143` + các site BE
`ApprovalWorkflowV2AdminFeatures.cs`. **Invest tự khai KHÔNG verify được** path `fe-user` matrix-view
(`WorkflowMatrixViewPage.tsx` grep 0 hit) **PHẢI grep lại lúc làm**, đừng tin line .
### 2.5 Cầu tiếp giáp b.12→13 (sửa 1 file) — ⚠️ chạm module Contract
`CreateContractFromEvaluationFeatures.cs`:
(a) đọc plan `DaDuyet` của PE thì `giaTri = line.ApprovedAmount` khớp `w.SupplierId` **thay** `SUM` `:88-90`,
ghi **ContextNote lệch** *"giá KH x vs SUM-PE y"* vào changelog `:121-140` (khuôn audit-note D4 S134);
không plan giữ `SUM` + **cảnh báo mềm** (**Q11** owner nâng cứng sau).
(b) `+param ApprovalWorkflowId?` **pin V2 cho HĐ** hiện pin V1-only `:68-71`,`:108` V2-less trình xong
**KẸT CỨNG** `ConflictException` `ContractWorkflowService.cs:115-116`.
🔴 **Đây là "chỗ hợp đồng"** anh chốt *"cứ từ từ"* **wave này phải hỏi lại anh trước khi chạy**.
---
## ③ CHECKLIST — CHIA WAVE (lead viết)
**Nguyên tắc chia:** mỗi wave **deploy độc lập được**, không để nửa tính năng chết trên prod (bài học PE nút-xóa
S155: §F.0 chứng minh đợt-1-một-mình dụng phải chia theo *"đẩy riêng thì người dùng thấy gì"*).
| Wave | Tên | Chặn bởi owner? | Deploy riêng được? |
|---|---|---|---|
| **W1** | Schema + permission (dark-launch) | không | ( hình với user) |
| **W2** | CRUD phiếu nháp + căn cứ b.8-9 | không | (bật menu, tạo được phiếu) |
| **W3** | Duyệt 3 trạm + finalize chốt giá | **Q3** (chọn chế rẽ b.12) nhưng chạy được với mặc định | (phiếu chạy trọn vòng) |
| **W4** | Gate + checklist per-phòng | **O-Q1, O-Q2** | (siết dần) |
| **W5** | Cầu sang Hợp đồng | **Q6, Q11 + anh cho phép chạm HĐ** | |
---
### WAVE 1 — Schema + permission + **Designer type-10** (vá sau review)
- **Mục tiêu:** đặt nền DB + quyền **VÀ** cho admin tạo được quy trình duyệt `type=10`.
🔴 **Designer KÉO TỪ W2 SANG ĐÂY** ( lens-wave H1): lệnh `Create` phiếu **đòi** workflow `ApplicableType=10`
tồn tại; wiring Designer type-10 **không nằm trong file-list wave nào** bản đầu **W2 đẩy riêng tạo được
0 phiếu** = tái phạm đúng §F.0 của S155 (đợt-1-một-mình dụng). Kéo sang đây còn biến W1 từ *0-giá-trị*
thành **UAT được** (admin dựng quy trình 3 bước PMHCCMCEO).
- **Vai:** `implementer-backend` · design-review `database-agent` trước khi apply migration.
- **File:** 7 entity + 2 enum (`Phase`, `DossierItemStatus`) + 7 EF Configuration + DbSets ×2 interface +
Mig 69 (3-file rule) + `ApprovalWorkflow.cs` enum **+slot 10** + `MenuKeys.cs` +4 const **vào `All`** +
`DbInitializer` menu 4 dòng + admin-permission + **fe-admin `ApprovalWorkflowsV2Page.tsx` map typeCode→10** +
🔴 **`ApprovalWorkflowV2AdminFeatures.cs` 3 SITE liệt-kê-thủ-công** ( lens-schema H2): `:911`+`:929` merge
"chữ còn sống" · `:971`+`:992` `RetainedOpinionRef` · `:1044`+`:1056` dọn chữ MỒ CÔI. **Thiếu 3 site này
admin sửa quy trình type-10 KHÔNG thấy chữ phiếu KHKK, xoá Level đang chữ FK Restrict nổ 500**
đúng lớp lỗi S155 vừa xong.
- **Acceptance ĐO ĐƯỢC:**
1. `dotnet ef migrations list` migration cuối cùng tên chứa **`AddContractSigningPlans`**.
*(🔴 sửa: bản đầu viết `69_AddContractSigningPlans` EF in `20260728xxxxxx_AddContractSigningPlans`,
**không có tiền tố `69_`** literal KHÔNG BAO GIỜ khớp. lens-wave checklistEvidence #1.)*
2. `sqlcmd -d SolutionErp -Q "SELECT COUNT(*) FROM sys.tables WHERE is_ms_shipped=0"` **89 → 96**.
*(🔴 sửa: thêm `is_ms_shipped=0` + DB đích — mốc 89 canonical đo bằng đúng vị ngữ này.)*
3. 🔴 **`dotnet test` `AuthorizePolicyRegressionTests` XANH** *(thay dòng "sqlcmd đếm policy" lens-wave H3:
policy đăng **in-memory trong `Program.cs`**, KHÔNG nằm trong DB phép **không chạy được**)*.
Test này chính thứ bắt lỗi tên-key-lệch-policy §2.4. Số học **+16 policy** (5458 key × 4) vẫn đúng.
4. `dotnet test SolutionErp.slnx` **562 + số test mới**, **0 fail**. *(🔴 "562 giữ nguyên" của bản đầu = **0 bit**
không falsify được ; lens-wave H5.)*
5. Admin tạo được 1 quy trình `type=10` 3 Bước, **pin `IsUserSelectable`**; xoá 1 Level chưa chữ OK.
6. `dotnet ef migrations script <trước> <sau>` + **script Down chạy sạch trên DB copy** (reversible thật).
- 🔴 **BỎ tiêu chí "menu không hiện" của bản đầu** (lens-wave H6 đo đĩa bác): `GetMyMenuTreeQuery.cs:96-100`
filter **CHỈ theo `CanRead`**, `IsVisible` chỉ **pass-through** `:88`; `MenuDtos.cs:13` ghi thẳng *"fe-admin vẫn
thấy"* `IsVisible=0` **KHÔNG phải cơ chế dark-launch toàn cục**, chỉ tối với fe-user. Cách đúng để giấu:
**không cấp `CanRead`** cho role thường W1.
- **Rủi ro:** seed-permission **>1 site** (S155) ⇒ grep hết. · Slot enum 10 **re-verify ngay trước khi viết**.
· 🔸 W1 **đóng băng** format mã + số bảng vào Mig 69 ⇒ *"không chặn"* chỉ đúng ở nghĩa **không chờ câu trả lời**,
**không** đúng ở nghĩa *không có quyết định nào bị khoá* (lens-wave M1). Owner nên liếc format `KHKK/{YYYY}/{Seq:D3}`
trước khi W1 chạy.
### WAVE 2 — CRUD phiếu nháp + căn cứ b.8-9 (bật menu)
- **Mục tiêu:** BCH **tạo được phiếu nháp**, điền dòng giá đề xuất + danh mục căn cứ, **chưa trình được**.
- **Vai:** `implementer-backend` (Features + Controller) · `implementer-frontend` (3 page × 2 app) ·
`test-specialist` (test-after).
- **File:** `ContractSigningPlanFeatures.cs` (Create/Update/Get/List + DossierItem CRUD + attachment) ·
`ContractSigningPlansController.cs` (**2-tầng authz**) · FE ×2 app 4 chỗ · `DbInitializer` bật `IsVisible=1`.
- **Acceptance ĐO ĐƯỢC:**
1. `POST /api/contract-signing-plans` từ PE `DaDuyet`**201**, response có `id`; DB có **N Lines = số winner**
của PE đó (`sqlcmd` đếm đối chiếu `PurchaseEvaluationSuppliers WHERE IsWinner=1`).
2. `PeReferenceAmount` mỗi Line == `SUM(Quotes WHERE IsSelected)` của đúng NCC đó (`sqlcmd` 2 câu, so khớp).
3. Tạo lần 2 trên **cùng PE****409 Conflict**.
4. Tạo từ PE **chưa `DaDuyet`****400/409** (không phải 500).
5. 🔴 **Authz 2 tầng:** user thiếu quyền gọi `POST`**403** (không phải 200/401/**500**). User có quyền → 201.
*(Phép chặn lỗ #82 tái phát — bắt buộc chạy.)* **+ gate rẻ bổ sung** (lens-claims điểm củng cố 2):
`grep -c "Authorize(Policy" ContractSigningPlansController.cs` **≥ 4**. Đối chứng: cùng lệnh trên
`ContractsController.cs` = **0 hit toàn file** ⇒ mọi endpoint HĐ chỉ cần "đăng nhập bất kỳ".
6. FE 2 app: `npm run build` PASS ×2 · SHA256 3 file mirror **IDENTICAL**.
7. Menu hiện đúng 4 mục tiếng Việt trên cả 2 app.
8. 🔴 **`dotnet test` phải có ≥1 test MỚI cho W2** (lens-wave H5: bản đầu W2 **không có dòng test nào** dù W2
đẻ controller + policy). Tối thiểu: 1 test authz-regression cho controller mới + 1 test guard `Phase!=DaDuyet`.
9. 🔸 **`DELETE` (lens-wave M6):** W2 mở `DELETE``DangSoanThao` **ngay từ wave này** — nếu để tới W3 thì
guard *"chưa có plan sống"* (409) **khoá cứng PE**: tạo nhầm 1 phiếu là không tạo lại được cho PE đó.
- **Rủi ro:** quên `HasQueryFilter(!IsDeleted)` ⇒ phiếu xóa mềm vẫn hiện. · UNIQUE filtered thiếu
`WHERE IsDeleted=0` ⇒ tạo lại sau xóa bị chặn oan (gotcha #57).
### WAVE 3 — Duyệt 3 trạm + finalize chốt giá 🔴 **wave nặng nhất**
- **Mục tiêu:** phiếu chạy trọn `DangSoanThao → ChoDuyet → DaDuyet`, chốt `ApprovedAmount`.
- **Vai:** `implementer-backend` (service) · `implementer-frontend` (panel + banner) · `test-specialist`
(**test-before cho OR-of-N** — đây là critical algorithm) · `reviewer` (adversarial trước commit).
- **File:** `ContractSigningPlanWorkflowService.cs` (copy `ApproveV2Async:217-394`) · `transitions` endpoint ·
inbox V2 precompute · notify · FE workflow panel + banner "Đến lượt bạn".
- **Acceptance ĐO ĐƯỢC:**
1. 🔴 **OR-of-N còn sống — 4 vế, THIẾU VẾ NÀO LÀ 0 BIT** *(vá lens-wave H4: bản đầu chỉ thử 1 người ⇒ **trúng-may
dưới đúng bug `ElementAtOrDefault`**, và service **bỏ hẳn guard** cũng PASS)*. Workflow có **1 Cấp 2 người (A, B)**:
(a) **2 phiếu song sinh**: phiếu-1 để **A** duyệt → tiến; phiếu-2 để **B** duyệt → **cũng tiến** (chứng OR thật,
không phải trúng thứ tự); (b) **ca âm**: người **ngoài cấp** duyệt → **403** (chứng guard còn sống);
(c) `SELECT COUNT(*) FROM ContractSigningPlanLevelOpinions WHERE PlanId=@id` = **1** (không đúp);
(d) phiếu **KHÔNG** đòi cả A và B cùng ký. Test unit + 1 lượt UAT thật.
2. **Con-trỏ đôi:** workflow **3 Bước** → sau mỗi lượt duyệt, đọc `sqlcmd` 2 cột: `CurrentWorkflowStepIndex`
đi **1→2→3**, `CurrentApprovalLevelOrder` **reset về 1 mỗi khi sang Bước mới**. *(🔴 sửa: "2 con trỏ đều đổi"
của bản đầu sai nghĩa đen — trong 1 Bước nhiều Cấp thì StepIndex **không** đổi; lens-wave M7.)*
3. **Finalize choke-point:** duyệt cấp cuối → **mọi** Line của **đúng phiếu đó**`ApprovedAmount != NULL`:
`SELECT COUNT(*) FROM ContractSigningPlanLines WHERE PlanId=@id AND ApprovedAmount IS NULL` = **0**.
*(🔴 sửa: bản đầu thiếu `AND PlanId=@id` ⇒ đếm toàn bảng ⇒ **FAIL giả vĩnh viễn** ngay khi có phiếu nháp
thứ hai tồn tại; lens-wave M7.)* Test cả 3 đường tới `DaDuyet`**grep 4-site RULE**.
⚠️ **Mâu thuẫn cần anh gỡ** (lens-wave M2 + M3): acceptance này **ép đủ 3 đường**, nhưng bảng wave khai W3
*"chạy được với mặc định"*; **và** 2 trong 3 đường (`AllowApproverFinalize` · `CeoApprovalThreshold`) từng bị
anh phán **"PHÁ VỠ"** ở S155 (owner-decision 10/11). ⇒ **W3 mặc định chỉ làm đường THƯỜNG**; 2 đường kia
**chờ anh xác nhận còn muốn không**.
4. **Inbox:** approver Cấp đang chờ gọi `GET /inbox`**thấy phiếu**; approver cấp khác → **không thấy**.
*(Phép chặn đúng lỗ Contract đang mắc.)*
5. `LevelOpinions` UPSERT: duyệt 2 lần cùng cấp → DB **1 row** (không đúp), `SignedByUserId` đúng người thật.
6. Trả lại → `TraLai`, sửa rồi gửi lại chạy **từ Cấp 1 Bước 1**.
7. Notify: approver Cấp kế **nhận** thông báo (không chỉ Drafter).
8. `dotnet test`**562 + N mới**, 0 fail.
- **Rủi ro:** 🔴 **copy nhầm Proposal** ⇒ mất OR-of-N **âm thầm** (build sạch, test cũ vẫn xanh) — acceptance #1
là lưới duy nhất bắt được. · Quên inbox precompute ⇒ lặp lại đúng lỗi Contract.
### WAVE 4 — Gate trình + checklist per-phòng ✅ **CHẶN: O-Q1, O-Q2**
- **Mục tiêu:** siết chất lượng đầu vào theo ý anh.
- **Chờ anh:** O-Q1 căn cứ b.8 chưa đủ `TvgsDuyet`**cảnh báo mềm hay chặn cứng**? · O-Q2 checkbox
FO-002.01 (PRO: điều khoản/thanh toán/rủi ro pháp lý · CCM: giá vs NS) → **số hoá thành checklist** hay
giữ **comment tự do**?
- **Acceptance (khi có câu trả lời):** trình thiếu căn cứ → đúng hành vi anh chọn (toast cảnh báo **hoặc** 409);
checklist (nếu số hoá) lưu + hiện lại đúng trên phiếu đã duyệt.
### WAVE 5 — Cầu sang Hợp đồng ✅ **CHẶN: Q6, Q11 + anh cho phép chạm HĐ**
- 🔴 **Wave này chạm module Contract — anh đã chốt *"chỗ hợp đồng cứ từ từ"*. KHÔNG tự chạy.**
- **Chờ anh:** Q6 giá vào HĐ = `ApprovedAmount` của KH (mặc định thiết kế: **KH thắng** + audit lệch) hay
vẫn `SUM`-PE? · Q11 chưa có KH duyệt thì tạo HĐ = **chặn** hay **cảnh báo**?
- **Acceptance:** HĐ tạo từ PE có KH `DaDuyet``GiaTri == SUM(ApprovedAmount)`; changelog có ContextNote lệch;
HĐ pin được workflow V2 (không còn `ConflictException` kẹt cứng).
---
### Ngoài mọi wave (ghi nhận, KHÔNG làm trong run này)
- **SLA** — O-2: chỉ hiển thị. `AddDays(7)` hardcode vẫn sai nhưng **không ai enforce** ⇒ không đáng 1 wave.
- **Lỗ hổng an ninh HĐ** (`ContractWorkflowService.cs:48-66` Reject-trước-guard + controller class-trần) —
**vẫn SỐNG trên prod**, anh chốt *"từ từ"*. Nhắc đúng 1 dòng cho khỏi quên.
- **FO-002.01 auto-pass** (*"quá hạn xem như đã thông qua"*) — mâu thuẫn mô hình duyệt-chặn V2. O-2 ⇒ ghi nhận.
---
## ④ §D — HẤP THỤ 6 việc sửa của `review-synthesis.md` §G (S156)
| # | Việc review yêu cầu | Xử lý trong spec này |
|---|---|---|
| 1 | Claim SAI *"hardcoded policy fallback"* → thật là `ConflictException:115-116` (HĐ **kẹt cứng** `ChoDuyet`) | ✅ **Đã sửa** — §2.5(b) ghi đúng: pin V1-only ⇒ HĐ V2-less **KẸT CỨNG**, hỏng **cứng** không degrade êm. Lead tự xác minh trên đĩa. |
| 2 | Siết biên `b.14→19`, không phải `b.13→21` | ✅ Spec này **không nhắc lại biên cũ**; phạm vi khai rõ = **b.7→12**, khúc 13→21 để nguyên verdict `LAI` S156. |
| 3 | Thiếu Q **vai người TRÌNH** (PMH `Procurement` bị 403 `:70-79`) | ✅ **Đã xử ở thiết kế**, không đẩy thành câu hỏi: §2.3 guard trình = `CreatedBy DeptManager Admin` **cố ý khác** khuôn role-based, kèm lối thoát nếu owner muốn đồng nhất. |
| 4 | Thêm cảnh báo lỗ hổng reject — *việc RIÊNG* | ✅ Giữ đúng 1 dòng ở "Ngoài mọi wave"; **không nhét vào wave** (anh chốt *"từ từ"*). |
| 5 | Q5 thiếu phương án **(d) `skipToFinal`** đã wire | ✅ Có mặt — §1.5 liệt **4 đường rẽ b.12**, trong đó (iii) `AllowApproverSkipToFinal` `Contract:320-352`. |
| 6 | Viết lại Q2 theo **2 trục + 3 số đo cùng đơn vị từ twin thật** | ⚠️ **Trục cơ-chế ĐÓNG bởi O-1** (anh chốt tái dùng khung) ⇒ chỉ còn **trục NỘI DUNG**. Bảng dưới. |
### Trục NỘI DUNG — 3 nhánh, 3 số cùng đơn vị
> Số twin **đo thật**: `Proposal` = **4 bảng · 849 LOC BE · 1.956 LOC FE** (invest `wc`/`grep` trực tiếp).
> Số cho từng nhánh = **ngoại suy** từ twin đó — khai rõ đâu là đo, đâu là ước.
| Nhánh | Bảng mới | LOC BE (ước) | LOC FE (ước) | Đánh giá |
|---|---|---|---|---|
| **(A) Phiếu độc lập** ⬅ *spec này chọn* | **7** (5 nếu cắt) | ~1.1001.400 | ~2.0002.400 | Vòng đời riêng, xóa/soft-delete riêng, workflow riêng type 10. **Đắt nhất về bảng, rẻ nhất về rủi ro.** |
| **(B) Mở rộng PE** (thêm cột + bảng con vào phiếu PE) | ~3 | ~600800 | ~9001.200 | Rẻ hơn, **nhưng**: PE `DaDuyet`**terminal thành công** — mở lại vòng duyệt thứ 2 trên phiếu đã đóng ⇒ phá bất-biến PE, đụng cả `budgetFrozen` snapshot Mig 67. **Rủi ro cao nhất.** |
| **(C) Entity con của Contract** | ~4 | ~700900 | ~1.1001.400 | Kéo khúc 7→12 vào module HĐ — mà anh vừa chốt **"chỗ hợp đồng cứ từ từ"**; đồng thời HĐ chưa tồn tại ở b.7-12 (HĐ mới sinh ở b.13) ⇒ **sai thứ tự nghiệp vụ**. |
**Lý do chọn (A)** — không phải vì rẻ, mà vì: nó là **PHIẾU** theo đúng phát biểu mục đích của anh (có đối tượng
được duyệt + 3 trạm + người chốt); (B) phá bất-biến của PE đang chạy ổn; (C) sai thứ tự nghiệp vụ và chạm vùng
anh vừa yêu cầu để yên. **Nếu owner ưu tiên cắt chi phí thì cắt trong (A)** (7→5 bảng), đừng đổi sang (B)/(C).
---
---
## ⑤ KẾT QUẢ REVIEW `/fable-clone reviewer` — 4 lăng kính, run `wf_57af0163-053`
**4/4 lane sạch, 0 chết, 0 rỗng** (đóng gói C2 ăn: ≤3 file/lane + ép khung rỗng lượt 1-2 + trần 25).
| Lăng kính | Verdict | Điểm |
|---|---|---|
| lens-wave (wave-plan + acceptance) | `SUA-TRUOC-W1` | 19 (6H · 8M · 5L) + 10 củng cố |
| lens-fidelity (trung thực nguồn) | `GO-WITH-FIXES` | 23 (3 CAO · 8 TRUNG · 12 THẤP) + 8 củng cố |
| lens-schema (7 bảng) | `GO-WITH-FIXES` (5 HIGH chặn W1) | 22 (5H · 7M · 3MED · 7 củng cố) |
| lens-claims (verify `file:line`) | `SPEC §② VỮNG` | **48 claim: 39Đ / 4S / 5KKĐ** |
### 🔑 Claim NỀN của spec ĐỨNG VỮNG
lens-fidelity đọc lại `src-QT-TRINH-KY-HD.txt`**XÁC NHẬN**: bảng 2 ISO = tiêu đề + **đúng 9 dòng bước**
(`:59-68`), khớp **9/9 cả tên trạm lẫn thứ tự** với `ContractPhase`; *"đi thẳng 1→2"* đúng theo nghĩa hẹp
(không dòng nào giữa `:60``:61`). **Spec không sập.**
### 🔴 Đã VÁ trong bản này (7 lỗi nặng)
1. **Tên key ≠ tiền tố policy ⇒ HTTP 500**`Csp*` vs `ContractSigningPlans.*`. Repo có sẵn test bắt
(`AuthorizePolicyRegressionTests.cs:138-139`). **Đây là lỗi tự-vấp-bẫy-mình-vừa-nhận-diện.** → §2.4
2. **W2 đẩy riêng tạo được 0 phiếu** — wiring Designer `type=10` rơi khỏi mọi wave → **kéo vào W1**
3. **Thiếu bảng `Approvals`** — service được lệnh copy CÓ ghi vào (`ContractWorkflowService.cs:151`) → thêm #7
4. **Changelogs thiếu 4 cột** (`EntityType`/`EntityId`/`UserName`/`FieldChangesJson`) ⇒ copy service **không biên dịch**
5. **3 site `ApprovalWorkflowV2AdminFeatures.cs`** chưa nêu ⇒ admin xoá Level có chữ ký → **FK Restrict nổ 500**
6. **`Status` bắt đầu từ 0** ⇒ bẫy falsy JS → đổi sang 1
7. **4 anchor lệch** — nặng nhất `ApprovalWorkflowLevel.cs` **KHÔNG TỒN TẠI** (class nằm trong `ApprovalWorkflow.cs:95`)
Kèm: bỏ tiêu chí dark-launch sai cơ chế · thay "sqlcmd đếm policy" (không đo được) bằng test regression ·
OR-of-N nâng từ 1 vế lên **4 vế có ca âm** · sửa 2 phép đo sai phạm vi · thêm độ dài 13 cột chuỗi ·
thêm `DepartmentId` + `ContractId` · cắt `CodeSequences` (tái dùng `WorkflowAppCodeSequence`).
### ⚠️ CÒN MỞ — cần anh hoặc cần đo thêm
- **Nguồn thứ 4 chưa ai đọc:** ISO bước 1 trỏ ra **`SOL-PRO-SP-001 Quy trình Cung ứng`** (`:47`, `:60`).
⇒ Câu *"khúc này KHÔNG CÓ trong quy trình ISO"* nên **hạ phạm vi** thành *"không có trong QT trình ký"*
trước khi trình anh với tư cách đề xuất sửa ISO. **Anh có file này không?**
- **W3 hai đường kết thúc sớm** (`AllowApproverFinalize` · `CeoApprovalThreshold`) — anh từng phán **"PHÁ VỠ"**
ở S155. Giữ hay bỏ?
- **5 câu owner** (O-Q1 · O-Q2 · Q3 · Q6 · Q11) vẫn nguyên.
- **5 claim chưa kiểm được** (lens-claims KKĐ): ranh CUỐI của 6 khoảng dòng · `WorkflowMatrixViewPage.tsx`
(spec đã tự gắn cờ "grep lại lúc làm" — **giữ cờ**) · mệnh đề *"HĐ V2-less kẹt cứng"* **đúng CÓ ĐIỀU KIỆN**
(phụ thuộc DB prod có `WorkflowDefinitions` active + step cho `ContractType` đó không — **chưa đo DB**).
- **Gate rẻ reviewer đề nghị, lead nhận:** trước mỗi wave, **mở 5 anchor bất kỳ** của wave đó; ≥1 anchor trượt
⇒ chấm lại toàn bộ anchor của wave. *(Anchor drift lan từ MÃ sang SPEC: comment `ApprovalWorkflow.cs:161`
ghi lệch 1 dòng, spec chép y nguyên.)*
<!-- END · 5 WAVE · 7 BANG · 4/4 LANE SACH · 112 DIEM REVIEW · 7 LOI-NANG DA-VA · 5 CAU-HOI-OWNER -->

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,68 @@
# TRICH NGUYEN-VAN: QT TRINH KY HOP DONG TP-NCC.docx
# nguon: D:\Dropbox\CONG_VIEC\SOLUTION\QUY_TRINH\QT TRINH KY HOP DONG TP-NCC.docx
# paragraphs=38 tables=2
=========== PARAGRAPHS ===========
MỤC ĐÍCH/PURPOSE:
Nhằm thống nhất các bước thực hiện trình ký Hợp đồng Thầu phụ/Nhà cung cấp/Tổ đội.
To unify the steps in the process of signing Subcontractor/Supplier/Team Contract.
Đảm bảo sự tuân thủ và vận hành Hệ thống một cách đồng nhất trên tất cả các Phòng Ban/Dự án của Công ty TNHH Xây dựng Solutions.
Ensure compliance and consistent of system operation through all Departments and Projects of Solutions Construction Co., Ltd.
PHẠM VI VÀ ĐỐI TƯỢNG ÁP DỤNG/SCOPE AND OBJECTS OF APPLICATION:
Áp dụng đối với các hợp đồng/phụ lục hợp đồng Thầu phụ/Nhà cung cấp/Tổ đội tại các Phòng ban/Dự án của Công ty TNHH Xây dựng Solutions như sau:
This procedure shall apply to Subcontractor/Supplier/Team contracts and contract appendices at the Departments and Projects of Solutions Construction Co., Ltd., as follows:
TÀI LIỆU THAM KHẢO/REFERENCES:
Tiêu chuẩn ISO 9001/ISO 9001 standard.
ĐỊNH NGHĨA, TỪ VIẾT TẮT/DEFINITIONS, ABBREVIATIONS:
SOL : Công ty TNHH Xây dựng Solutions/Solutions Construction Co., Ltd
BOD : Ban Giám đốc/Board of Directors
NĐUQ : Người được ủy quyền/Authorized person
CCM : Phòng Kiểm soát Chi phí/Cost Control Management Department
PRO : Phòng Cung ứng/Procurement Department
FIN : Phòng Tài chính/Financial Department
ACT : Phòng Kế toán/Accounting Department
EQU : Phòng Thiết bị/Equipment Department
HRA : Phòng Nhân sự - Hành chính/HRA Department
PB : Phòngban/Department
TP : Trưởng Phòng ban/Department Manager
TBP : Trưởng Bộ phận/Section Leader
NV : Nhân viên/Officer
BCH CT : Ban chỉ huy công trường/Site Management Team
PD : Giám đốc Thi công/Project Director
PM : Giám đốc Dự án/Project Manager
QS : QS công trường/QS
HĐ : Hợp đồng/Contract
HĐTG : Hợp đồng Trọn gói/Lump sum Contract
HĐNC : Hợp đồng Nhân công/Workmen Contract
NTP : Nhà thầu phụ/Subcontractor
NCC : Nhà cung cấp/Supplier
TĐ : Tổ đội/Team
QUY TRÌNH/PROCEDURE:
Lưu đồ/Flow chart
Diễn giải/Description
=========== TABLE 1 (12r x 5c) ===========
Bước / Step | Quy trình / Procedure | Trách nhiệm / Responsibilities | Biểu mẫu / Forms | Thời gian / Time
| | | |
| | PB/BCH CT | SOL-PRO-SP-001 Quy trình Cung ứng / SOL-PRO-SP-001 Procurement Procedure |
| | QS/NV.PB/ / TBP/TPB | SOL-CCM-FO-002.01.v01 / Chấp thuận Hợp đồng Contract approval cover / SOL-CCM-FO-002.02.v01 / Hợp đồng trọn gói - Nhân công, Vật tư / Lump sum contract - Labor and Material / SOL-CCM-FO-002.03.v01 / Hợp đồng trọn gói - Nhân công, Thiết bị / Lump sum contract - Labor and Equipment / SOL-CCM-FO-002.04.v01 / Hợp đồng trọn gói Điều kiện chung / Lump sum contract General conditions / SOL-CCM-FO-002.05.v01 / Hợp đồng giao khoán / Workmen contract / SOL-CCM-FO-002.06.v01 / Hợp đồng mua bán / Purchase contract / SOL-CCM-FO-002.07.v01 / Đơn đặt hàng / Purchase order / SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng / Regulation on contract and purchasing order code | 07 ngày / 07 days
| | PD/PM/PRO/ / CCM/FIN/ACT | SOL-CCM-FO-002.01.v01 / Chấp thuận Hợp đồng Contract approval cover / SOL-CCM-FO-002.02.v01 / Hợp đồng trọn gói - Nhân công, Vật tư / Lump sum contract - Labor and Material / SOL-CCM-FO-002.03.v01 / Hợp đồng trọn gói - Nhân công, Thiết bị / Lump sum contract - Labor and Equipment / SOL-CCM-FO-002.04.v01 / Hợp đồng trọn gói Điều kiện chung / Lump sum contract General conditions / SOL-CCM-FO-002.05.v01 / Hợp đồng giao khoán / Workmen contract / SOL-CCM-FO-002.06.v01 / Hợp đồng mua bán / Purchase contract / SOL-CCM-FO-002.07.v01 / Đơn đặt hàng / Purchase order / SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng / Regulation on contract and purchasing order code | 07 ngày / 07 days
| | QS/NV.PB/ / TBP/TPB/ PD/PM | SOL-CCM-FO-002.01.v01 / Chấp thuận Hợp đồng Contract approval cover / SOL-CCM-FO-002.02.v01 / Hợp đồng trọn gói - Nhân công, Vật tư / Lump sum contract - Labor and Material / SOL-CCM-FO-002.03.v01 / Hợp đồng trọn gói - Nhân công, Thiết bị / Lump sum contract - Labor and Equipment / SOL-CCM-FO-002.04.v01 / Hợp đồng trọn gói Điều kiện chung / Lump sum contract General conditions / SOL-CCM-FO-002.05.v01 / Hợp đồng giao khoán / Workmen contract / SOL-CCM-FO-002.06.v01 / Hợp đồng mua bán / Purchase contract / SOL-CCM-FO-002.07.v01 / Đơn đặt hàng / Purchase order / SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng / Regulation on contract and purchasing order code | 07 ngày / 07 days
| | NTP/NCC/TĐ | SOL-CCM-FO-002.01.v01 / Chấp thuận Hợp đồng Contract approval cover / SOL-CCM-FO-002.02.v01 / Hợp đồng trọn gói - Nhân công, Vật tư / Lump sum contract - Labor and Material / SOL-CCM-FO-002.03.v01 / Hợp đồng trọn gói - Nhân công, Thiết bị / Lump sum contract - Labor and Equipment / SOL-CCM-FO-002.04.v01 / Hợp đồng trọn gói Điều kiện chung / Lump sum contract General conditions / SOL-CCM-FO-002.05.v01 / Hợp đồng giao khoán / Workmen contract / SOL-CCM-FO-002.06.v01 / Hợp đồng mua bán / Purchase contract / SOL-CCM-FO-002.07.v01 / Đơn đặt hàng / Purchase order / SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng / Regulation on contract and purchasing order code | 07 ngày / 07 days
| | CCM | SOL-CCM-FO-002.01.v01 / Chấp thuận Hợp đồng Contract approval cover / SOL-CCM-FO-002.02.v01 / Hợp đồng trọn gói - Nhân công, Vật tư / Lump sum contract - Labor and Material / SOL-CCM-FO-002.03.v01 / Hợp đồng trọn gói - Nhân công, Thiết bị / Lump sum contract - Labor and Equipment / SOL-CCM-FO-002.04.v01 / Hợp đồng trọn gói Điều kiện chung / Lump sum contract General conditions / SOL-CCM-FO-002.05.v01 / Hợp đồng giao khoán / Workmen contract / SOL-CCM-FO-002.06.v01 / Hợp đồng mua bán / Purchase contract / SOL-CCM-FO-002.07.v01 / Đơn đặt hàng / Purchase order / SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng / Regulation on contract and purchasing order code | 03 ngày / 03 days
| | BOD/ / NĐUQ | SOL-CCM-FO-002.01.v01 / Chấp thuận Hợp đồng Contract approval cover / SOL-CCM-FO-002.02.v01 / Hợp đồng trọn gói - Nhân công, Vật tư / Lump sum contract - Labor and Material / SOL-CCM-FO-002.03.v01 / Hợp đồng trọn gói - Nhân công, Thiết bị / Lump sum contract - Labor and Equipment / SOL-CCM-FO-002.04.v01 / Hợp đồng trọn gói Điều kiện chung / Lump sum contract General conditions / SOL-CCM-FO-002.05.v01 / Hợp đồng giao khoán / Workmen contract / SOL-CCM-FO-002.06.v01 / Hợp đồng mua bán / Purchase contract / SOL-CCM-FO-002.07.v01 / Đơn đặt hàng / Purchase order / SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng / Regulation on contract and purchasing order code | 01 ngày / 01 days
| | HRA | SOL-CCM-FO-002.01.v01 / Chấp thuận Hợp đồng Contract approval cover / SOL-CCM-FO-002.02.v01 / Hợp đồng trọn gói - Nhân công, Vật tư / Lump sum contract - Labor and Material / SOL-CCM-FO-002.03.v01 / Hợp đồng trọn gói - Nhân công, Thiết bị / Lump sum contract - Labor and Equipment / SOL-CCM-FO-002.04.v01 / Hợp đồng trọn gói Điều kiện chung / Lump sum contract General conditions / SOL-CCM-FO-002.05.v01 / Hợp đồng giao khoán / Workmen contract / SOL-CCM-FO-002.06.v01 / Hợp đồng mua bán / Purchase contract / SOL-CCM-FO-002.07.v01 / Đơn đặt hàng / Purchase order / SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng / Regulation on contract and purchasing order code |
| | PB/BCH CT/ CCM | SOL-CCM-FO-002.01.v01 / Chấp thuận Hợp đồng Contract approval cover / SOL-CCM-FO-002.02.v01 / Hợp đồng trọn gói - Nhân công, Vật tư / Lump sum contract - Labor and Material / SOL-CCM-FO-002.03.v01 / Hợp đồng trọn gói - Nhân công, Thiết bị / Lump sum contract - Labor and Equipment / SOL-CCM-FO-002.04.v01 / Hợp đồng trọn gói Điều kiện chung / Lump sum contract General conditions / SOL-CCM-FO-002.05.v01 / Hợp đồng giao khoán / Workmen contract / SOL-CCM-FO-002.06.v01 / Hợp đồng mua bán / Purchase contract / SOL-CCM-FO-002.07.v01 / Đơn đặt hàng / Purchase order / SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng / Regulation on contract and purchasing order code |
| | | SOL-CCM-FO-002.01.v01 / Chấp thuận Hợp đồng Contract approval cover / SOL-CCM-FO-002.02.v01 / Hợp đồng trọn gói - Nhân công, Vật tư / Lump sum contract - Labor and Material / SOL-CCM-FO-002.03.v01 / Hợp đồng trọn gói - Nhân công, Thiết bị / Lump sum contract - Labor and Equipment / SOL-CCM-FO-002.04.v01 / Hợp đồng trọn gói Điều kiện chung / Lump sum contract General conditions / SOL-CCM-FO-002.05.v01 / Hợp đồng giao khoán / Workmen contract / SOL-CCM-FO-002.06.v01 / Hợp đồng mua bán / Purchase contract / SOL-CCM-FO-002.07.v01 / Đơn đặt hàng / Purchase order / SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng / Regulation on contract and purchasing order code |
=========== TABLE 2 (10r x 3c) ===========
BƯỚC / STEP | TRÁCH NHIỆM / RESPONSIBILITIES | NỘI DUNG CHI TIẾT / DETAIL
Lựa chọn NTP/NCC / Select NTP/NCC | PB/BCH CT | Thống nhất chọn NTP/NCC/ĐTC theo quy định. / Select NTP/NCC/ĐTC in accordance with regulations. / Tham khảo Quy trình Cung ứng để so sánh và lựa chọn NTP/NCC/TĐC đúng quy định. / Refer to the Procurement Procedure to compare and select NTP/NCC/ĐTC in accordance with regulations.
Soạn thảo hợp đồng / Draft the contract | QS/NV.PB/ / TBP/TPB | QS/NV.PB soạn dự thảo HĐ. / QS/NV.PB drafts Contract. / TBP/TPB kiểm tra các nội dung phù hợp với gói thầu và biểu mẫu HĐ. / TBP/TPB checks contents in compliance with the packages and Forms of Contract. / QS/NV.PB gởi dự thảo HĐ cho các Phòng ban để lấy ý kiến qua Email. / QS/NV.PB sends draft contract to relevant Departments for obtaining comments via email.
Góp ý nội dung / Feedback content | PD/PM/PRO/ / CCM/FIN/ACT | PM/PD góp ý về phạm vi công việc, tiến độ, chất lượng, biện pháp thi công... (đối với HĐ của BCH CT). / PD/PM comments on scope of words, construction schedule, quality, construction methods,… (for BCH CTs contract). / EQU góp ý (thuê/mua thiết bị). / EQU comments on hiring and purchasing equipment. / PRO góp ý (vật tư/thầu phụ trọn gói). / PRO comments on material and lumpsum Subcontractor. / CCM góp ý về các điều khoản liên quan đến chi phí. / CCM comments on provisions relating to cost. / ACT/FIN góp ý về điều kiện thanh toán, bảo lãnh, bảo hành. / ACT/FIN Comments on term of payments, guarantees, project warranty.
Đàm phán, thương thảo hợp đồng / Negotiate the contract terms | QS/NV.PB/ / TBP/TPB/PD/PM | PB/BCH CT đàm phán các điều khoản về chất lượng, giao hàng, giá trị HĐ, điều kiện thanh toán, tạm ứng, ... / PB/BCH CT negotiates provisions on quality, product delivery, contract value, term of payment, advance payment, etc. / Các Phòng chức năng tham gia thương thảo nếu có yêu cầu. / Departments participates in negotiation if required.
In hợp đồng / Print the contract | QS/NV.PB | NTP/NCC/TĐ in hợp đồng 2 mặt, ký, đóng dấu Hợp đồng và gửi về cho PB/BCH CT. / NTP/NCC/TĐ prints double-sided contract, signs and seals on the contract and sends to PB/BCH CT. / Cập nhật số Hợp đồng theo quy định. / Update the contract number. / PD/PM/TPB kiểm tra các điều khoản hợp đồng và ký nháy trên từng HĐ đúng theo các vị trí quy định. / PD/PM/TPB checks provisions contract and initializes on each contract. / PD/PM/TPB/TBP ký duyệt và cho ý kiến (nếu có) lên tờ cover chấp thuận HĐ (SOL-CCM-FO-002.01). / PD/PM/TPB signs and gives comments (if any) on the cover of Contract approval cover (SOL-CCM-FO-002.01). / QS/NV.PB chuyển HĐ cho CCM. / QS/NV.PB handover the contract to CCM Dept.
Kiểm tra / Review and verify | CCM | CCM kiểm tra, TP.CCM ký nháy trên từng hợp đồng; ký duyệt và cho ý kiến (nếu có) lên Chấp thuận HĐ (SOL-CCM-FO-002.01.v01). / CCM checks and initializes on each contract; signs and gives comments (if any) on the Contract approval cover (SOL-CCM-FO-002.01.v01).
Duyệt / Approve | BOD/ / NĐUQ | Xem xét và ký duyệt Hợp đồng. / Reviewing and signing the Contract.
Đóng dấu hợp đồng / Seal the contract | HRA/ISO | PB/BCH CT chuyển hợp đồng đã được ký duyệt đến HRA/ISO để đóng dấu theo quy định. / PB/BCH CT transfrom the approved contract to HRA for seal the contract in accordance with regulations.
Phát hành hợp đồng. Lưu trữ hồ sơ / Issue and archive the contract | PB/BCH CT/ / CCM | PB/BCH CT scan và gởi 01 bản gốc cho CCM. / PB/BCH CT scan and send the original contract to CCM / PB/BCH CT thông báo và chuyển bản gốc hợp đồng đã ký (theo đúng số lượng) đến NTP/NCC. / Notifying and sending originals of the signed contract (in accordance with quantity) to NTP/NCC. / Lưu trữ bản gốc hợp đồng. / Archive the original contract. / Lưu trữ trên Server theo Filing System (Hợp đồng bản cứng chính và bản scan). / Keep the contract on Filing System (hard copy and soft copy).

View File

@ -0,0 +1,202 @@
# sub-invest-kehoach-1 — "Kế hoạch ký kết Hợp đồng" (PDF b.7→12) — quy trình + wire + wave
> **Run:** `2026-07-28-S157-ke-hoach-ky-ket-hd` · agent: investigator-codebase (/fable-real, effort max)
> **Trạng thái file:** GHI TRONG LÚC LÀM — mục chưa điền ghi `[PENDING]`. Propose-only; lead ghi spec sau verify.
> **Nguồn:** run.md S157 (§1 grounding lead) · src-QT-TRINH-KY-HD.txt · src-FO-002.01 · run.md S156 · sub-invest-bch-1.md · review-synthesis.md §G.
> **Luật đo:** mọi claim load-bearing neo file:line TỰ ĐỌC. Doc/skill = giả thuyết. Đĩa thắng.
> **🔴 OWNER CHỐT GIỮA CHỪNG (run.md §1.7, nhận qua lead lúc đang điều tra):**
> **(O-1)** *"Đúng chính xác, cấu trúc trình ký giống, chỉ khác nội dụng thôi"* ⇒ phiếu KH TÁI DÙNG khung duyệt V2
> (`ApprovalWorkflow`>Step>Level OR-of-N + LevelOpinions UPSERT); DỰNG MỚI = NỘI DUNG phiếu. Trục cơ-chế Q2 ĐÓNG;
> option-space §D(6) chỉ còn trục NỘI DUNG (phiếu độc lập ⟂ mở rộng PE ⟂ entity con Contract).
> **(O-2)** *"Cái này để tham khảo thôi, ko vấn đề j, đa số là trễ"* ⇒ SLA = hiển thị tham khảo; KHÔNG SLA-engine,
> KHÔNG auto-approve-on-timeout, KHÔNG wave SLA; giữ hiển thị deadline; `AddDays(7)` hardcode = 1 dòng ghi nhận.
## §A — QUY TRÌNH CHI TIẾT khúc còn thiếu (hoà giải 3 nguồn)
### A.0 Khung — khoảng trống nằm giữa ISO-1 và ISO-2 (xác nhận Phát hiện B của lead từ nguồn gốc)
Em tự đối chiếu: ISO doc bảng 2 (`src-QT-TRINH-KY-HD.txt:60-61`) đi THẲNG "Lựa chọn NTP/NCC" → "Soạn thảo
hợp đồng", **0 bước trung gian**. PDF sơ đồ (bản 14/2026, `runs/...S156/run.md` bảng 21 bước) chèn b.7→12
đúng chỗ đó. FO-002.01 là tờ cover của KHÚC HĐ (ISO bước 5-7), không nói gì khúc 7→12.
**PDF là nguồn DUY NHẤT có khúc này** — spec ra từ đây vừa là spec phần mềm vừa là đề xuất bổ sung ISO.
Vật mang trong hệ thống = **1 PHIẾU "Kế hoạch ký kết Hợp đồng"** (owner đặt tên, đầu ra = CON SỐ có phê
duyệt), vòng đời 5-trạng-thái mirror PE, duyệt bằng **khung V2 có sẵn** (O-1).
### A.1 Bảng bước b.7→12 → ngôn ngữ hệ thống
Role hệ thống có thật (`AppRoles.cs:5-16`): Procurement (PMH/PRO) · CostControl (CCM) · Director+AuthorizedSigner
(BOD/NĐUQ) · ProjectManager/Drafter (phía BCH) · HrAdmin · Admin. "BCH dự án X" **không có model** (Q1 S156 —
`Department.ManagerUserId` 0-row, PositionLevel NULL) → phiếu KH né bằng: BCH = **người tạo phiếu** (CreatedBy),
PMH/CCM/CEO = **đích danh user trong Level** của workflow V2 (đúng triết lý V2, 0 model mới).
| b | Việc | Ai (role thật) | Đầu vào | Đầu ra | Điều kiện chuyển | Nhánh lỗi/trả lại |
|---|---|---|---|---|---|---|
| 7 | PMH mail chuyển thông tin BCH/NTP/NCC | Procurement | PE chạm `DaDuyet` (winners `IsWinner`, giá `SUM Quote.IsSelected`, HoSoLink NAS) | BCH biết việc → vào lập KH | Hệ thống = **pull-model**: màn "PE đã duyệt — chờ lập KH" lọc `Phase==DaDuyet && chưa có plan` (khuôn `CreateContractFromEvaluationFeatures.cs:173` filter `DaDuyet && ContractId==null`) + notification in-app. Email ra NGOÀI (NTP/NCC) = ngoài scope (SMTP TODO toàn hệ thống) | PE thiếu winner → không hiện trong màn (guard sẵn ở PE) |
| 8 | Duyệt mẫu + shopdrawing với TVGS | BCH nhập; TVGS = người NGOÀI hệ thống, **BCH nhập hộ kết quả** (tên TVGS + ngày + scan) — hướng (a) Q7 S156, sơ đồ không đòi account TVGS | Mẫu vật liệu + shopdrawing từ TP/NCC (offline) | Danh mục CĂN CỨ trong phiếu KH: per-item {Kind: MauVatLieu\|Shopdrawing, NCC nào, Status, TvgsName, ngày, file scan} | Vòng đời PER-ITEM: `ChuaNop→DaNop→TvgsDuyet\|TvgsBac`; `TvgsBac→DaNop` (nộp lại) — **sơ đồ KHÔNG vẽ vòng lặp này**, hệ thống phải có vì thực tế TVGS bác | Item bị bác = đổi status + note, KHÔNG đụng state machine phiếu |
| 9 | Tổng hợp hồ sơ + so sánh giá → ĐỀ XUẤT giá trị ký HĐ | BCH (= Drafter phiếu KH; role thường ProjectManager) | Căn cứ b.8 + báo giá PE (snapshot `PeReferenceAmount` per-winner lúc tạo phiếu — nguyên tắc snapshot Mig 67) | Phiếu KH điền đủ: dòng giá trị ĐỀ XUẤT per-winner + file so sánh giá → **TRÌNH** (`DangSoanThao→ChoDuyet`) | Guard trình: dòng giá đề xuất đủ per-winner (mirror completeness-guard S60 PE `PurchaseEvaluationWorkflowService.cs:180-212`); căn cứ b.8 chưa đủ TvgsDuyet → **soft-warn** (tiền lệ S62 vượt-NS-cảnh-báo-mềm) — cứng/mềm = owner quyết (O-Q1 dưới) | Ghi chú sơ đồ: "hồ sơ sai sót thiếu khối lượng, sai spec, thiếu phạm vi → gửi mail làm rõ" = comment + item TvgsBac |
| 10 | PMH kiểm tra hồ sơ so sánh giá, xác nhận giá trị | Procurement (đích danh user trong Level) | Phiếu ChoDuyet Bước 1 | Duyệt → Bước 2; ý kiến vào `LevelOpinions` (UPSERT khi duyệt — khuôn `ContractWorkflowService.cs:292-316`) | OR-of-N trong Cấp (`ApprovalWorkflow.cs:81-94`) | Trả lại → `TraLai` (reset) hoặc 4 return-mode per-level (cờ CÓ SẴN `ApprovalWorkflowLevel.cs:116-125`, service mirror PE `:421-424`) |
| 11 | CCM kiểm tra | CostControl (đích danh trong Level) | Bước 2 | Duyệt → Bước 3 | như trên | như trên |
| 12 | **CEO ký HOẶC CCM đóng dấu approval** | Director; nhánh "CCM đóng dấu" = cơ chế kết thúc sớm | Bước 3 (hoặc kết thúc tại Bước 2) | **GIÁ TRỊ KÝ KẾT CHỐT per-winner** (`ApprovedAmount`) ghi tại finalize choke-point — mirror `ApplyApprovedPriceOnFinalize` PE `:973-1002` + RULE "mọi nhánh set DaDuyet phải gọi helper" `:1008` | Terminal `DaDuyet` | Từ chối → `TuChoi` (terminal); trả lại → `TraLai` |
**Cơ chế rẽ b.12 "hoặc" — 4 đường ĐỀU CÓ SẴN trong khung V2 (O-1), 0 migration:**
(i) `CeoApprovalThreshold` + CCM tích "duyệt done miễn CEO" — PE service `:892-929` (fail-closed: đòi threshold
+ role CostControl + giá < ngưỡng); (ii) `AllowApproverFinalize` per-slot opt-out PE `:870-890`;
(iii) `AllowApproverSkipToFinal` per-slot (CEO vẫn thật) Contract `:320-352`; (iv) 2 workflow (/không
Step CEO) admin pin. Điều kiện rẽ THẬT (ngưỡng? loại gói?) = **cả 3 nguồn im lặng** Q3 owner còn treo,
nhưng chọn đường nào cũng không đổi schema.
**Tiếp giáp ra (b.12→13):** phiếu KH `DaDuyet` cầu `POST /purchase-evaluations/{id}/create-contract` hiện
(`CreateContractFromEvaluationFeatures.cs`) tạo draft `DangSoanThao` sửa cầu đọc `ApprovedAmount` từ KH
thay `SUM Quote.IsSelected` (`:88-90`) + audit lệch PE-vs-KH + gate "chưa KH duyệt thì cảnh báo/chặn"
(Q11 mềm/cứng). Khúc b.1321 = verdict LAI S156, KHÔNG bàn lại.
### A.2 b.8-9 là GÌ: **bảng con trong phiếu KH** — không phải phiếu con, không phải module riêng
Repo 0-hit `shopdrawing|TVGS|duyệt mẫu` (verify S156 §0, em không đo lại không để đo). Chọn **satellite
table `DossierItems` + attachments trong phiếu KH** vì: (1) owner phát biểu b.8-9 = **CĂN CỨ** của con số, không
phải đối tượng duyệt riêng; (2) PDF chỉ vẽ MỘT chuỗi duyệt (10-12) cho cả khúc phiếu con riêng = đẻ chuỗi duyệt
thứ 2 không trên đồ; (3) vòng đời mẫu/shopdrawing per-item status (nộp/duyệt/bác/nộp lại), không phải
state machine phiếu; (4) TVGS ngoài hệ thống chỉ cần ghi vết, không cần workflow. Module riêng chỉ đáng khi
mẫu/shopdrawing cần quản ĐỘC LẬP với gói thầu (chưa yêu cầu).
### A.3 Mâu thuẫn / im lặng giữa 3 nguồn (bảng tra)
| # | Điểm | ISO doc | PDF đồ | FO-002.01 | Xử |
|---|---|---|---|---|---|
| 1 | Khúc b.712 | **KHÔNG CÓ** (12 thẳng) | (duy nhất) | không nói | Spec = đề xuất bổ sung ISO |
| 2 | SLA khúc 712 | im lặng | im lặng (10-14d b.1-4; 3d + 7-10d b.13-18) | im lặng | **O-2: tham khảo** không hoà giải, không engine |
| 3 | SLA khúc (1319) | 07/07/07/07/03/01 ngày | 3d + 7-10d | **"mỗi bộ phận 01 ngày, quá hạn XEM NHƯ ĐÃ THÔNG QUA"** (auto-pass!) | 3 nguồn 3 kiểu; auto-pass mâu thuẫn hình duyệt chặn V2 (V2 không auto-approve; V1 từng System AutoApprove) O-2 chỉ ghi nhận |
| 4 | Điều kiện rẽ b.12 CEO vs CCM | không bước | "hoặc" KHÔNG điều kiện | không nói | Q3 owner; 4 chế sẵn (A.1) |
| 5 | Nhánh trả lại 10/11/12 | không vẽ | không vẽ | không vẽ | Hệ thống sẵn TraLai + 4 return-mode per-level |
| 6 | Bypass Chủ đầu trực tiếp | không nói | không nói | ("chuyển trực tiếp Giám đốc") | = `Contract.BypassProcurementAndCCM` (đã trong code) KHÔNG áp phiếu KH (KH chỉ sinh từ PE = TP/NCC) |
| 7 | Nội dung kiểm tra cấu trúc per-phòng (PRO: điều khoản/thanh toán/rủi ro pháp · CCM: giá vs NS/rủi ro) | tả lời | không | (checkbox từng mục) | Hệ thống chỉ `LevelOpinions.Comment` tự do checklist cấu trúc = GAP ghi nhận, không blocking (owner quyết số hoá checkbox không O-Q2) |
| 8 | Tên phòng/vai | PRO/CCM/BOD/NĐUQ/HRA | Procurement/CCM/CEO | PB-DA/PRO/CCM/ | Khớp `AppRoles`: Procurement/CostControl/Director+AuthorizedSigner/HrAdmin nhất quán, 0 mâu thuẫn |
| 9 | Chuỗi FO-002.01 (ĐỀ XUẤTPROCCM) | bước 5-7 | b.9101112 CÙNG HÌNH | | Đối chứng giấy cho O-1: khung Step(Phòng)×Level+Opinions gánh được cả 2 khúc |
**Câu hỏi owner còn treo sau run này (rút từ 14 câu S156, trừ đã chốt O-1/O-2/Q7a/Q8-ngoài-scope):**
O-Q1 gate căn cứ b.8 khi trình: mềm (khuyến nghị, tiền lệ S62) hay cứng? · O-Q2 checkbox FO-002.01 số hoá
hay comment tự do? · Q3 điều kiện rẽ b.12 (chọn chế i-iv) · Q6 xác nhận giá KH thay SUM-PE khi tạo
(mặc định thiết kế: KH thắng + audit lệch) · Q11 gate tạo-HĐ khi chưa KH duyệt: mềm/cứng.
## §B — CÁCH WIRE vào codebase (twin THẬT, file:line)
> O-1 chốt: **tái dùng khung duyệt V2** (`ApprovalWorkflows`/Steps/Levels + cột dùng chung CeoApprovalThreshold
> `ApprovalWorkflow.cs:43` + 9 cờ per-slot `ApprovalWorkflowLevel.cs:116-169`) — **0 bảng approval mới**.
> Dựng mới = NỘI DUNG phiếu. Twin đo thật: **Proposal** (BE 849 LOC · FE 1.956 LOC · 4 bảng Mig 38 — em wc/grep
> trực tiếp) = khuôn CRUD/menu; **Contract ApproveV2Async** (`ContractWorkflowService.cs:217-394`) = khuôn service;
> **PE** = khuôn finalize/giá-chốt (BE ~6.5K · FE ~14.9K = cận trên, không cần tới).
### B.1 ⚠️ Bẫy twin đo được lượt này — CẤM copy Proposal-lite cho phần DUYỆT
`ProposalFeatures.cs` ApproveProposalHandler đi **global-level-order**: flatten mọi Level xuyên Steps
(`:427-429` `SelectMany`), match `ElementAtOrDefault(order-1)` **1 row** (`:433`) + so đúng **1 user**
(`:439` `currentSlot.Level.ApproverUserId != currentUser.UserId`). 2 row cùng Order (OR-of-N hợp lệ theo
`ApprovalWorkflow.cs:81-94`) bị biến thành 2 nấc TUẦN TỰ (AND) **phá ngữ nghĩa OR-of-N**, không con trỏ
Step (entity Proposal `:27` chỉ `CurrentApprovalLevelOrder`, KHÔNG `CurrentWorkflowStepIndex`). Phiếu KH cần
3 Bước (PMHCCMCEO) **service PHẢI copy `ContractWorkflowService.ApproveV2Async:217-394`** (con trỏ đôi
StepIndex+LevelOrder, GroupBy Order `:246`, OR-of-N `:259-260`, LevelOpinions UPSERT `:292-316`, skipToFinal
`:320-352`) Proposal chỉ làm khuôn cho CRUD/DTO/menu/FE.
### B.2 Schema — Mig **69** `AddContractSigningPlans` (mig cuối hiện tại = 68 `20260727033522_AddPeAllowApproverDelete.cs`, em ls trực tiếp)
**7 CreateTable, 0 ALTER bảng cũ ⇒ Down = DropTable ×7, reversible sạch.** Convention: PascalCase EN, loose-Guid
không FK vật sang PE/Supplier (convention PE `PurchaseEvaluation` ProjectId/SelectedSupplierId đều loose,
ghi Mig 49 note), FK vật chỉ trong nội bộ module + sang bảng V2 dùng chung.
| # | Bảng | Cột chính | Ràng buộc |
|---|---|---|---|
| 1 | `ContractSigningPlans` (header) | MaKeHoach?, PurchaseEvaluationId (loose+IX), ProjectId (denorm lọc cây), Phase int, ApprovalWorkflowId Guid?, CurrentWorkflowStepIndex int?, CurrentApprovalLevelOrder int?, DrafterUserId, SlaDeadline?, SlaWarningSent, HoSoLink nvarchar(1000)? (mirror PE Mig 52), GhiChu | AuditableEntity + `HasQueryFilter(!IsDeleted)` (khuôn `PurchaseEvaluationConfiguration.cs:84`) |
| 2 | `ContractSigningPlanLines` (giá per-winner) | PlanId FK Cascade, SupplierId loose, PeReferenceAmount decimal(18,2) **snapshot lúc tạo** (nguyên tắc freeze Mig 67 không để PE sửa sau làm trôi baseline), ProposedAmount decimal(18,2), ApprovedAmount decimal(18,2)? (chỉ ghi tại finalize), Note | UNIQUE filtered (PlanId, SupplierId) WHERE IsDeleted=0 (gotcha #57) |
| 3 | `ContractSigningPlanDossierItems` (căn cứ b.8-9) | PlanId FK Cascade, Kind int (MauVatLieu=1/Shopdrawing=2/Khac=99), SupplierId? loose, Name, Status int (ChuaNop=0/DaNop=1/TvgsDuyet=2/TvgsBac=3), TvgsName nvarchar(200)?, TvgsResultAt?, Note | IX (PlanId) |
| 4 | `ContractSigningPlanLevelOpinions` | PlanId + ApprovalWorkflowLevelId, Comment nvarchar(2000), SignedAt, SignedByUserId, SignedByFullName | UNIQUE (PlanId, LevelId); FK **Cascade Plan + Restrict Level** (mirror `ContractLevelOpinions` Mig 33 / `ProposalLevelOpinionConfiguration.cs`) |
| 5 | `ContractSigningPlanAttachments` | PlanId FK Cascade, FileName/Path/Size/ContentType, Purpose int (MauVatLieu=1/Shopdrawing=2/SoSanhGia=3/Khac=99), DossierItemId? | khuôn `ProposalAttachment.cs` (20 dòng) |
| 6 | `ContractSigningPlanChangelogs` | PlanId, Action, PhaseAtChange, UserId, Summary, ContextNote | tiền lệ PE: Changelogs = nguồn transition-marker/backfill (Mig 61) từ ngày 1 |
| 7 | `ContractSigningPlanCodeSequences` | Prefix PK, LastSeq | khuôn `ProposalCodeSequence.cs` (13 dòng); format đề xuất `KHKK/{YYYY}/{Seq:D3}` **owner chốt format** |
Biến thể tối thiểu 5 bảng (bỏ #6 Changelogs + #7 CodeSequences) KHÔNG khuyến nghị: mất audit-trail transition
(tiền lệ Mig 60/61 cho thấy cần) mất phiếu atomic.
**Enum ngoài bảng:** `ApprovalWorkflowApplicableType` **+`ContractSigningPlan = 10`** append-only vào
`ApprovalWorkflow.cs:53-67` (slot 10 trống, em đọc trực tiếp; tiền lệ Mig 37 extend enum). `ContractSigningPlanPhase`
enum MỚI giá trị sạch `DangSoanThao=1/ChoDuyet=2/DaDuyet=3/TraLai=98/TuChoi=99` KHÔNG copy 7/98 của PE (sẹo
lịch sử enum PE, phiếu mới không nợ data ; 98/99 giữ cho quen mắt FE badge).
**KHÔNG thêm cột `SigningPlanId` lên PE** tra ngược bằng query `Plans.Where(PurchaseEvaluationId==x)`; thêm cột
= đẻ "cột 0 ai đọc" (lớp lỗi 6-lần của repo).
DbSets: `ApplicationDbContext` + `IApplicationDbContext` (khuôn mọi module). 3-file rule mig (Up/Down + Designer
+ Snapshot).
### B.3 CQRS + service + controller
- **`Application/ContractSigningPlans/ContractSigningPlanFeatures.cs`** (mega-file khuôn `ProposalFeatures.cs` 556 dòng):
- `CreateContractSigningPlanCommand(PeId, ApprovalWorkflowId, GhiChu?)` validator: PE tồn tại + `Phase==DaDuyet`
(mirror cầu `CreateContractFromEvaluationFeatures.cs:53-54`) + **chưa có plan sống** (`AnyAsync(p.PeId==x && p.Phase!=TuChoi)`
Conflict; cho tạo lại sau TuChoi) + workflow `ApplicableType==ContractSigningPlan` match (mirror Proposal `:258-265`).
Handler **auto-sinh Lines từ winners**: `pe.Suppliers.Where(IsWinner)` + `PeReferenceAmount = SUM Quote.IsSelected`
per winner (copy đúng phép tính cầu `:56-62` + `:88-90`) snapshot 1 lần.
- `UpdateContractSigningPlanDraftCommand` guard `Phase ∈ {DangSoanThao, TraLai}` + **cho re-pin ApprovalWorkflowId**
(mirror PE `PurchaseEvaluationFeatures.cs` re-pin chỉ Nháp/TraLai; tránh vết Contract UpdateDraft KHÔNG đường
re-pin S156 §2-bis).
- `Get`/`List`/`pendingMe` detail Include Lines+DossierItems+Attachments+LevelOpinions + workflow-tree JOIN
(khuôn Proposal `:161-228`); **inbox V2 precompute từ ngày 1** (mirror PE `ResolveV2InboxIdsAsync` bẫy S156:
Contract THIẾU cái này nên approver không inbox `ContractFeatures.cs:363-372` legacy-only).
- `UpsertDossierItemCommand` / `DeleteDossierItemCommand` BCH nhập hộ TVGS; mở cả khi ChoDuyet? **KHÔNG**
chỉ DangSoanThao/TraLai (căn cứ input của con số đang duyệt); attachment mở mọi phase (triết PE S147 BE
không phase-guard attachment).
- Attachment upload/download/delete khuôn `ProposalAttachment` + PE attachment features.
- **`Infrastructure/Services/ContractSigningPlanWorkflowService.cs`** copy `ContractWorkflowService.ApproveV2Async:217-394`
(B.1) + adapt 3 chỗ: (1) terminal `Phase=DaDuyet` + **`ApplyApprovedValuesOnFinalize`**: mọi Line
`ApprovedAmount = ApprovedAmount ?? ProposedAmount` (người duyệt cấp cuối được sửa trước khi duyệt nếu bật
`AllowApproverEditBudget`-tương-tự; khuôn choke-point + RULE grep-4-site `PurchaseEvaluationWorkflowService.cs:1008`);
(2) port 2 nhánh kết thúc sớm PE: `AllowApproverFinalize` `:870-890` + `finalizeByCcmDelegation`+`CeoApprovalThreshold`
`:892-929` (tổng so ngưỡng = `SUM ProposedAmount` các Line); (3) Reject 4 return-mode per-level (cờ sẵn
`ApprovalWorkflowLevel.cs:116-125`, logic mirror PE `ApplyReturnModeAsync:368-547`) tối thiểu TraLai toàn phần
nếu muốn gọn wave đầu. **Guard trình:** `CreatedBy==actor DeptManager Admin` CỐ Ý KHÁC khuôn role-Drafter
(`PurchaseEvaluationWorkflowService.cs:172-178` + `ContractWorkflowService.cs:70-79`) để lớp 403-PMH
(S156 §G3: role không khớp = kẹt cứng); nếu owner muốn đồng nhất role-based thì BCH users phải mang role Drafter.
**Notify:** mirror `LogTransitionAsync` notify Drafter (`ContractWorkflowService.cs:407-427`) + THÊM notify
đích danh approvers của Cấp kế (fix lỗ notify-chỉ-Drafter ngay từ ngày 1, đừng chép nợ).
- **`Api/Controllers/ContractSigningPlansController.cs`** authz **2 tầng** (bài học #82/S118): class `[Authorize]`
+ per-action `[Authorize(Policy = "ContractSigningPlans.{Read|Create|Update|Delete}")]` KHÔNG chép kiểu
`ContractsController.cs:12-13` class-trần (lỗ A1 S156). Policy TỰ SINH khi key vào `MenuKeys.All`
(`Program.cs:82-89` foreach All × Actions). Endpoints: GET list/inbox · GET {id} · POST · PUT {id} ·
POST {id}/transitions (body {targetPhase, decision, comment, returnMode?, skipToFinal?, applyLevelFinalize?,
finalizeByCcmDelegation?, approvedLines?}) · dossier-items CRUD · attachments ·
DELETE {id} (allow-list DangSoanThao|TuChoi mirror PE `PurchaseEvaluationFeatures.cs:1404`).
### B.4 Menu + permission + FE 2 app (Pattern 16-bis, twin Off_DeXuat đo thật)
- **BE:** `MenuKeys.cs` +4 const kiểu `Csp`/`Csp_List`/`Csp_Create`/`Csp_Inbox` (khuôn `OffDeXuat*` `:109-112`)
**+ đưa cả 4 vào `All` `:156-174`** (khuôn `:168` Off_DeXuat 4 key ĐỀU trong All policy sinh đủ; ĐỪNG theo
kiểu `Pe_*` factory-ngoài-All `:142-144` per-action policy sẽ chưa tồn tại bẫy S155 "policy-chưa-tồn-tại").
2 row canonical `docs/STATUS.md` (Menu keys · Policies DERIVED |All|×4) PHẢI cập nhật cùng lúc.
- **Seed:** `DbInitializer.cs` menu 4 dòng (khuôn Off_DeXuat `:1817-1820`: root parent + 3 leaf, label VN
"Kế hoạch kết "/"Danh sách"/"Tạo mới"/"Inbox duyệt") + admin-permission list (`:2383` grep đủ MỌI site
seed-permission khi làm, S155 ghi nhận 2 site cho vài nhóm); dark-launch được bằng `IsVisible=0` (cột Mig 27)
rồi bật sau.
- **FE ×2 app (duplicate CHỦ ĐÍCH):** mỗi app 4 chỗ: (1) routes `App.tsx` (khuôn fe-user `:77-79` /proposals ×3
route); (2) `components/Layout.tsx` staticMap (khuôn `:95-97` `Off_DeXuat_List: '/proposals'`…); (3) `lib/menuKeys.ts`
(khuôn `:54-57`); (4) pages ×3 (khuôn bộ Proposal 978 LOC/app: List 252 + Create 245 + Detail 386 + types 95)
Detail thêm: bảng Lines (đề xuất/chốt per-NCC) + bảng DossierItems (status chip + TVGS + scan) + panel workflow
(mirror PE Panel-3 Steps/Levels ✓/●/○) + banner "Đến lượt bạn" (khuôn PE `blockedByV2Level`).
- **Designer admin nhận type 10:** fe-admin `ApprovalWorkflowsV2Page.tsx` map typeCodeint `:143` + các site BE
`ApprovalWorkflowV2AdminFeatures.cs` đọc ApplicableType (grep "ApplicableType" toàn file khi làm S155 F6 liệt
~5 dây BE + fe-user matrix-view; **path file matrix-view fe-user em grep lượt này KHÔNG thấy
`fe-user/src/pages/WorkflowMatrixViewPage.tsx` vị trí thật cần grep lại khi implement, đừng tin line S155**).
- **Cầu tiếp giáp (sửa 1 file):** `CreateContractFromEvaluationFeatures.cs` (a) đọc plan DaDuyet của PE:
`giaTri = line.ApprovedAmount` khớp `w.SupplierId` thay SUM `:88-90`, ghi ContextNote lệch "giá KH x vs SUM-PE y"
vào 2 changelog `:121-140` (khuôn audit-note D4 S134); không plan giữ SUM + **cảnh báo mềm** (Q11 owner
nâng cứng sau); (b) +param `ApprovalWorkflowId?` pin V2 cho (hiện pin V1-only `:68-71,:108` V2-less
trình xong KẸT CỨNG `ConflictException` `ContractWorkflowService.cs:115-116`, em tự xác minh trên đĩa).
- **1 dòng bắt buộc nhắc (ngoài scope, treo theo ý anh):** lỗ Reject-trước-guard
`ContractWorkflowService.cs:48-66` + controller class-trần vẫn SỐNG trên prod anh chốt 07-28 "từ từ".
## §C — CHIA WAVE THI CÔNG + CHECKLIST ĐO ĐƯỢC
[PENDING]
## §D — HẤP THỤ 6 việc sửa review-synthesis §G
[PENDING]
<!-- TRẠNG THÁI GIỮA CHỪNG (chưa END): §A=XONG (6 bước + 9 điểm hoà giải + 5 Q treo) · §B=XONG (7 bảng Mig 69,
0 ALTER, bẫy Proposal-lite B.1) · §CD=[PENDING] lượt sau theo lệnh coordinator. TOTAL-line chỉ ghi khi đủ 4 mục. -->

View File

@ -0,0 +1,121 @@
# LĂNG KÍNH 4/4 — VERIFY ĐỘC LẬP CLAIM file:line (reviewer, S157)
Đích chấm: `spec-ke-hoach-ky-ket-hd-28-07-2026.md` §② (dòng 95-204). Phép đo: MỞ FILE THẬT trên đĩa (Read/Grep/Glob), KHÔNG dựa skill-doc, KHÔNG dựa `sub-invest-kehoach-1.md`.
## Verdict
**SPEC §② VỮNG — 39 ĐÚNG / 4 SAI (toàn bộ là lệch ANCHOR, 0 sai NỘI DUNG) / 5 KHÔNG KIỂM ĐƯỢC.**
Hai claim quyết-định-kiến-trúc (B.1 "Proposal phá OR-of-N" và "Pe_* ngoài `MenuKeys.All`") **ĐÚNG, khớp từng dòng**.
Trước khi giao implementer phải sửa 4 anchor ở mục "Claim SAI" — 1 trong 4 là **đường dẫn file KHÔNG TỒN TẠI** (implementer mở sẽ trượt).
## Claim ĐÚNG
### A. B.1 — `ProposalFeatures.cs` phá OR-of-N (claim quyết định "copy Contract, không copy Proposal")
| # | Claim gốc (spec dòng 99-104) | Đo được trên đĩa | Verdict |
|---|---|---|---|
| 1 | `SelectMany` flatten mọi Level xuyên Steps `:427-429` | `ProposalFeatures.cs:427-429` = `wf.Steps.OrderBy(s => s.Order).SelectMany(s => s.Levels.OrderBy(l => l.Order).Select(l => new { Step = s, Level = l })).ToList()` | ĐÚNG — khớp DÒNG chính xác |
| 2 | `ElementAtOrDefault(order-1)` lấy **1 row** `:433` | `:433` = `allLevels.ElementAtOrDefault(p.CurrentApprovalLevelOrder.Value - 1)` | ĐÚNG — chính xác |
| 3 | So đúng **1** `ApproverUserId` `:439` | `:439` = `if (!isAdmin && currentSlot.Level.ApproverUserId != currentUser.UserId.Value)` — so 1 Guid, KHÔNG có tập `allowedUserIds` | ĐÚNG — chính xác |
| 4 | Comment tự thú *"Lite version: assume 1 step per workflow"* | `:424` = `// Multi-step workflow: traverse step-by-step. Lite version: assume 1 step per workflow` | ĐÚNG — nguyên văn |
| 5 | Entity Proposal chỉ có `CurrentApprovalLevelOrder`, KHÔNG có `CurrentWorkflowStepIndex` | `Domain/Office/Proposal.cs:27``CurrentApprovalLevelOrder`; grep `CurrentWorkflowStepIndex` trong `**/Proposal.cs` = **0 hit** | ĐÚNG |
| 6 | Hệ quả: 2 người cùng Cấp bị biến thành 2 nấc TUẦN TỰ (AND) | **CỦNG CỐ THÊM (tôi tự đo):** `:473-481` advance = `if (CurrentApprovalLevelOrder < allLevels.Count) CurrentApprovalLevelOrder + 1` — so **Order** (1-based trong Bước) với **Count của danh sách ĐÃ FLATTEN**. Không `GroupBy(Order)` ở bất kỳ đâu ⇒ N row cùng Order = N slot tuần tự. | ĐÚNG |
| 7 | OR-of-N hợp lệ theo `ApprovalWorkflow.cs:81-94` | `Domain/ApprovalWorkflowsV2/ApprovalWorkflow.cs:81` mở *"Cấp = tập các row CÙNG Order"*, `:82` *"1 Cấp có thể có N row ⇒ N người duyệt OR-of-N"*, kết `:94` *"Cấp 2 Phòng Cung ứng có 3 người"*; `:95``public class ApprovalWorkflowLevel` | ĐÚNG — khung 81-94 khít |
**Kết luận B.1: claim ĐÚNG 7/7.** Khuyến nghị "PHẢI copy `ContractWorkflowService.ApproveV2Async`" có cơ sở đo được, không phải suy diễn.
### B. `MenuKeys.All` (claim quyết định "theo khuôn `Off_DeXuat`, không theo `Pe_*`")
| # | Claim gốc (spec dòng 181-183) | Đo được | Verdict |
|---|---|---|---|
| 8 | `OffDeXuat` + 3 con **đều trong `All`** | `MenuKeys.cs:168` = `OffDeXuat, OffDeXuatList, OffDeXuatCreate, OffDeXuatInbox,` nằm trong mảng `All` (`:156-174`) | ĐÚNG **nội dung** — nhưng anchor spec ghi `:171` là SAI (xem S1) |
| 9 | `Pe_*` sinh bằng **factory**, **NẰM NGOÀI `All`** | Factory `:134-137` (`Pe_{t}` / `_List` / `_Create` / `_Pending`), `:145-146` (`_Approved` / `_Deleted`), `:150` (`_WfView`); mảng `All` chỉ chứa root `PurchaseEvaluations` (`:162`) — **không một literal `Pe_` nào trong `All`**. Comment `:142-144` tự khai đúng chính sách này. | ĐÚNG |
| 10 | ⇒ per-action policy `Pe_*` **không tồn tại** | `Program.cs:82-89` = `foreach (var menu in MenuKeys.All) foreach (var action in MenuKeys.Actions) opts.AddPolicy($"{menu}.{action}", ...)` — policy sinh **duy nhất** từ `All` ⇒ key ngoài `All` không có policy | ĐÚNG (suy ra bằng cấu trúc, không phải phỏng đoán) |
| 11 | Policy TỰ SINH khi key vào `MenuKeys.All` (`Program.cs:82-89`) | Khớp từng dòng: `:82` foreach All · `:84` foreach Actions · `:86-87` AddPolicy · `:89` đóng | ĐÚNG — chính xác |
### C. Khuôn Contract phải copy (§2.1 + §2.3)
| # | Claim | Đo được (`Infrastructure/Services/ContractWorkflowService.cs`) | Verdict |
|---|---|---|---|
| 12 | `ApproveV2Async:217-394` | `:217` = `private async Task ApproveV2Async(`; hàm kế `LogTransitionAsync` bắt đầu `:396` ⇒ thân kết ~`:394` | ĐÚNG (đầu chính xác, đuôi khớp mốc kề) |
| 13 | `GroupBy` Order `:246` | `:246` = `currentStep.Levels.OrderBy(l => l.Order).GroupBy(l => l.Order).ToList()` | ĐÚNG — chính xác |
| 14 | OR-of-N `:259-260` | `:259` = `allowedUserIds = pendingLevelGroup.Select(l => l.ApproverUserId).ToHashSet()`, `:260` = `if (!allowedUserIds.Contains(actorUserId.Value))` | ĐÚNG — chính xác |
| 15 | `LevelOpinions` UPSERT `:292-316` | `:292` = `db.ContractLevelOpinions` (đọc bản cũ), `:300` = `.Add(new ContractLevelOpinion`, `:318` đã là comment skipToFinal ⇒ khối UPSERT nằm trọn 292-316 | ĐÚNG |
| 16 | `skipToFinal` `:320-352` | `:320` = `if (skipToFinal)`, `:332` = `lastStep.Levels...GroupBy` | ĐÚNG (đầu chính xác) |
| 17 | Guard trình role-based `:70-79` đòi `Drafter\|DeptManager` | `:70-71` điều kiện `DangSoanThao \|\| TraLai`, `:73-75` `!actorRoles.Contains(AppRoles.Drafter) && !...DeptManager`, `:77-79` `throw new ForbiddenException` | ĐÚNG — khung 70-79 khít |
| 18 | `ConflictException` `:115-116` khi HĐ V2-less trình | `:116` = `throw new ConflictException("HĐ chưa pin workflow definition hoặc workflow không có step.")` | ĐÚNG về **anchor** (xem K5 về mệnh đề nhân-quả) |
| 19 | `LogTransitionAsync` báo Drafter `:407-427` | `:396` = `private async Task LogTransitionAsync(`, `:407` = `if (contract.DrafterUserId is Guid drafterId && drafterId != actorUserId)` | ĐÚNG — notify quả thật CHỈ nhánh Drafter |
### D. Lỗ đang treo ở Contract (lý do "authz 2 tầng" + "inbox V2 từ ngày 1")
| # | Claim | Đo được | Verdict |
|---|---|---|---|
| 20 | `ContractsController.cs:12-13` class-trần | `:11` `[ApiController]` · `:12` `[Route("api/contracts")]` · `:13` `[Authorize]` **trần**; grep `Authorize\(Policy` trong file = **0 hit** ⇒ 0 per-action policy | ĐÚNG (bằng chứng mạnh hơn claim: 0 hit toàn file) |
| 21 | `ContractFeatures.cs:363-372` legacy-only | `:363` = `PhaseActorRoles = new()`, `:364-372` chỉ map `DangSoanThao … DangDongDau` rồi `};` | ĐÚNG — khung khít |
| 22 | `grep ChoDuyet` = 0 hit | Grep `ChoDuyet` trong `**/ContractFeatures.cs` = **0 occurrence / 0 file** | ĐÚNG — chính xác |
| 23 | PE có `ResolveV2InboxIdsAsync` để mirror | Grep toàn `src` = 2 hit, **chỉ** trong `PurchaseEvaluationFeatures.cs` (Contract không có) | ĐÚNG |
### E. Khuôn PE phải port (§2.3 mục 1-3)
| # | Claim | Đo được (`PurchaseEvaluationWorkflowService.cs`) | Verdict |
|---|---|---|---|
| 24 | choke-point + RULE grep-4-site, khuôn `:1008` | `:1008` = `// RULE: MỌI nhánh set Phase=DaDuyet PHẢI gọi helper này ngay TRƯỚC assignment (reviewer grep-check 4 site).`, `:1009` = `private async Task ApplyBudgetSnapshotOnFinalizeAsync(` | ĐÚNG — anchor trúng ĐÚNG dòng RULE |
| 25 | `AllowApproverFinalize` `:870-890` | `:870` = `if (matchingLevel.AllowApproverFinalize && applyLevelFinalize)` | ĐÚNG (đầu chính xác) |
| 26 | `finalizeByCcmDelegation` + `CeoApprovalThreshold` `:892-929` | `:892` = `if (finalizeByCcmDelegation)`, `:894` = `if (aw.CeoApprovalThreshold is not decimal ceoThreshold)` | ĐÚNG (đầu chính xác) |
| 27 | `ApplyReturnModeAsync:368-547` | `:368` = `private async Task<string> ApplyReturnModeAsync(` | ĐÚNG (đầu chính xác) |
| 28 | `HasQueryFilter(!IsDeleted)` khuôn `PurchaseEvaluationConfiguration.cs:84` | `:84` = `b.HasQueryFilter(x => !x.IsDeleted);` | ĐÚNG — chính xác |
### F. Menu / seed / FE (§2.4)
| # | Claim | Đo được | Verdict |
|---|---|---|---|
| 29 | Seed 4 dòng menu khuôn `DbInitializer.cs:1817-1820` | `:1817` `OffDeXuat "Đề xuất"` · `:1818` `OffDeXuatList "Danh sách"` · `:1819` `OffDeXuatCreate "Tạo mới"` · `:1820` `OffDeXuatInbox "Inbox duyệt"`**cả 3 nhãn VN spec đề xuất trùng khớp nhãn khuôn** | ĐÚNG — chính xác |
| 30 | admin-permission `:2383` | `:2383` = `MenuKeys.OffDeXuat, MenuKeys.OffDeXuatList, MenuKeys.OffDeXuatCreate, MenuKeys.OffDeXuatInbox,` | ĐÚNG — chính xác |
| 31 | `ContractLevelOpinions` FK Cascade + Restrict (Mig 33) | `ContractLevelOpinionConfiguration.cs:27` `OnDelete(DeleteBehavior.Cascade)` · `:32` `OnDelete(DeleteBehavior.Restrict)` | ĐÚNG |
| 32 | `ApprovalWorkflowsV2Page.tsx:143` map typeCode→int | `fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx:143` = `// FE typeCode → BE int (giống MenuKeys ApplicableType)` (đầu bảng `TYPE_CODE_TO_INT`, dùng ở `:257`) | ĐÚNG |
| 33 | Bộ Proposal FE ~978 LOC/app: List 252 + Create 245 + Detail 386 + types 95 | Đếm dòng thật fe-admin: `ProposalsListPage.tsx` **252** · `ProposalCreatePage.tsx` **245** · `ProposalDetailPage.tsx` **386** · `types/proposal.ts` **95** ⇒ tổng **978** | ĐÚNG — 4/4 con số khớp tuyệt đối |
### G. Enum + cầu b.12→13 (§2.2 + §2.5)
| # | Claim | Đo được | Verdict |
|---|---|---|---|
| 34 | `ApprovalWorkflow.cs:53-67` dừng ở `TravelRequest = 9`, **slot 10 trống** | `:53` = `public enum ApprovalWorkflowApplicableType`, `:66` = `TravelRequest = 9,`, `:67` = `}` — giá trị lớn nhất 9 | ĐÚNG — khung 53-67 khít, slot 10 trống thật |
| 35 | cầu `:53-54` = PE phải `DaDuyet` | `CreateContractFromEvaluationFeatures.cs:53-54` = `if (pe.Phase != PurchaseEvaluationPhase.DaDuyet) throw new ConflictException(...)` | ĐÚNG — chính xác |
| 36 | `:56-62` phép lấy winners | `:56` `winners = pe.Suppliers.Where(s => s.IsWinner).ToList()``:62` `supplierIds = winners.Select(w => w.SupplierId)` | ĐÚNG — khung khít |
| 37 | `:88-90` `SUM Quote.IsSelected` per winner | `:88-90` = `pe.Details.SelectMany(d => d.Quotes).Where(q => q.PurchaseEvaluationSupplierId == w.Id && q.IsSelected).Sum(q => q.ThanhTien)` | ĐÚNG — chính xác |
| 38 | changelog `:121-140` (chỗ ghi ContextNote lệch) | `:121-130` `ContractChangelogs.Add(...)` (ContextNote `:129`) + `:131-140` `PurchaseEvaluationChangelogs.Add(...)` (ContextNote `:139`) | ĐÚNG — khung khít, **2 changelog chứ không phải 1** (implementer nhớ ghi note vào đúng bảng) |
| 39 | pin **V1-only** `:68-71`, `:108` | `:68-71` = `activeWfId` lấy từ `db.WorkflowDefinitions … IsActive`; `:108` = `WorkflowDefinitionId = activeWfId`; **không có dòng nào set `ApprovalWorkflowId`** trong cả khối `new Contract{}` `:92-111` | ĐÚNG |
**Bonus — measured-label gate:** con số **"849 LOC BE"** (spec dòng 99) tái-lập được: đếm dòng 10 file `Proposal*.cs` trong `src/` = **đúng 849** (`ProposalFeatures.cs` 556 + Controller 86 + 4 Configuration 108 + 4 Domain 99). Nhãn "BE" cứu con số. ⚠️ Nhưng câu đặt số ngay sau **tên 1 file** ⇒ dễ đọc thành "file này 849 dòng" (thật: **556**). Đề nghị đổi thành *"twin nhỏ nhất — 849 LOC BE trải 10 file, riêng `ProposalFeatures.cs` 556"*.
## Claim SAI
Cả 4 đều là **lệch anchor / sai đường dẫn**, KHÔNG có claim nào sai về nội dung kỹ thuật. Nhưng đây đúng lớp lỗi đã cắn repo hôm qua, và 1 cái làm implementer mở-file-trượt.
| # | Claim gốc | Đo được | Mức |
|---|---|---|---|
| **S1** | *"Lead verify `MenuKeys.cs:171`: `OffDeXuat`+3 con đều trong `All`"* (spec dòng 182) | 4 key nằm ở **`MenuKeys.cs:168`**. Dòng **`:171``Personal,`** — key khác hẳn, chẳng liên quan `Off_DeXuat` | MINOR (nội dung đúng, anchor lệch 3 dòng) |
| **S2** | *"cờ sẵn `ApprovalWorkflowLevel.cs:116-125`"* (spec dòng 161) | **KHÔNG CÓ FILE NÀO TÊN `ApprovalWorkflowLevel.cs`** (Glob `**/ApprovalWorkflowLevel.cs` = 0 hit). Class `ApprovalWorkflowLevel` nằm trong `Domain/ApprovalWorkflowsV2/**ApprovalWorkflow.cs**:95`. Khoảng dòng thì ĐÚNG: `:116` `AllowReturnOneLevel` · `:119` `AllowReturnOneStep` · `:122` `AllowReturnToAssignee` · `:125` `AllowReturnToDrafter = true` | **MAJOR** — implementer mở theo spec sẽ file-not-found (tôi vừa dính đúng lỗi này khi đoán thư mục ở S5) |
| **S3** | *"DELETE allow-list `DangSoanThao\|TuChoi`, mirror PE `:1404`"* (spec dòng 177) | `PurchaseEvaluationFeatures.cs:1404`**dòng TRỐNG**. Allow-list thật ở **`:1405-1407`**. Drift này **kế thừa** từ comment trong mã: `ApprovalWorkflow.cs:161` cũng ghi `PurchaseEvaluationFeatures.cs:1404-1406` (lệch 1) | MINOR |
| **S4** | *"workflow `ApplicableType==ContractSigningPlan` (mirror Proposal `:258-265`)"* (spec dòng 144) | Khoảng `:258-265` chỉ chứa phần **nạp** `wfType` + throw NotFound. **Hai dòng quyết định nằm NGOÀI khoảng trích**: `:266-267` `if (wfType.Value != (int)ApprovalWorkflowApplicableType.ProposalGeneral) throw new ConflictException(...)`. Ai copy đúng 258-265 sẽ copy phần đọc mà **bỏ mất chính cái guard** | MINOR-nhưng-nguy (trích hụt đúng dòng load-bearing) |
## Claim KHÔNG KIỂM ĐƯỢC
| # | Claim | Vì sao chưa kết luận |
|---|---|---|
| K1 | Ranh **CUỐI** của 6 khoảng: `ApproveV2Async:…394`, `skipToFinal:…352`, `ApplyReturnModeAsync:…547`, `AllowApproverFinalize:…890`, `CcmDelegation:…929`, `UPSERT:…316` | Tôi chỉ verify **dòng đầu + mốc liền kề** (hàm/khối kế tiếp). Chưa đọc trọn ruột từng khoảng. Đầu đúng + mốc kề hợp lý ⇒ khả năng đúng cao, nhưng **chưa đo** ⇒ không tuyên ĐÚNG |
| K2 | `fe-user` `WorkflowMatrixViewPage.tsx` (spec dòng 193-194 tự khai invest KHÔNG verify được) | Tôi cũng chưa kiểm. **Spec đã tự gắn cờ "PHẢI grep lại lúc làm"** — giữ nguyên cờ đó, đừng gỡ |
| K3 | `ProposalFeatures.cs:161-228` (khuôn Get/List detail Include) | Chưa đọc — hết ưu tiên |
| K4 | Mig **69** · 7 CreateTable · 2 row `docs/STATUS.md` bump | Claim về **việc sẽ làm**, không có vật trên đĩa để chấm |
| K5 | Mệnh đề nhân-quả *"pin V1-only ⇒ HĐ V2-less trình xong **KẸT CỨNG** `:115-116`"* | Anchor ĐÚNG, nhưng `:116` ném khi **`WorkflowDefinitionId` null HOẶC def không có step**. Ở cầu này `:108` **có** set `activeWfId` (V1) ⇒ có kẹt hay không **phụ thuộc DB prod**: có tồn tại `WorkflowDefinitions` active + có step cho `ContractType` đó không. **Chưa đo DB** ⇒ mệnh đề đúng CÓ ĐIỀU KIỆN |
## Điểm CỦNG CỐ
1. **B.1 mạnh hơn spec viết.** Ngoài 3 dòng spec nêu, `ProposalFeatures.cs:473` còn so `CurrentApprovalLevelOrder` (Order 1-based **trong Bước**) với `allLevels.Count` (đếm row **đã flatten toàn workflow**) — trộn hai hệ đơn vị. Cùng lớp `#43 Step.Order ≠ index 0-based`. Thêm 1 lý do nữa để KHÔNG copy Proposal cho phần duyệt.
2. **Cat-3 authz: bằng chứng mạnh hơn claim.** Spec chỉ trỏ `ContractsController.cs:12-13`; đo thật `grep Authorize\(Policy` = **0 hit toàn file** ⇒ mọi endpoint HĐ chỉ cần "đăng nhập bất kỳ". Đúng bài học #82/S118 (menu-ẩn ≠ API-đóng). Yêu cầu "authz 2 TẦNG" của §2.3 giữ nguyên, nên nhấn thêm câu *"gate acceptance = grep `Authorize(Policy` trong controller mới phải ≥ 4 hit"*.
3. **Thêm đường dẫn vào spec, đừng để tên trần.** `CreateContractFromEvaluationFeatures.cs` thật nằm ở **`src/Backend/SolutionErp.Application/PurchaseEvaluations/`** (KHÔNG phải `.../Contracts/` như tiêu đề §2.5 "chạm module Contract" gợi ý). Spec để tên trần ⇒ tôi đoán sai thư mục và trượt 1 lượt đọc. Cùng cách chữa cho S2.
4. **§2.5 sửa 2 bảng changelog, không phải 1.** `:121-130` `ContractChangelogs``:131-140` `PurchaseEvaluationChangelogs`. Câu spec *"ghi ContextNote lệch vào changelog `:121-140`"* nên nói rõ ghi vào **bảng nào** (đề nghị: cả hai, để tra ngược từ 2 phía).
5. **Anchor drift lan từ MÃ sang SPEC.** S3 chứng minh: comment trong `ApprovalWorkflow.cs:161` ghi lệch 1 dòng, spec chép lại y nguyên. ⇒ quy tắc rẻ: mọi anchor `file:line` trong spec phải được **mở lại lúc bắt đầu wave**, vì mã đã trôi giữa lúc viết comment và lúc viết spec.
6. **Đề nghị gate rẻ cho implementer (không phải sửa mã, chỉ là phép chấm):** trước mỗi wave, chạy 1 lượt "mở 5 anchor bất kỳ trong wave đó" — nếu ≥1 anchor trượt file/dòng, chấm lại toàn bộ anchor của wave.
<!-- END · TOTAL=48 CLAIM · VERDICT=SPEC §② VỮNG — 39Đ/4S(chỉ lệch anchor)/5KKĐ, sửa 4 anchor (1 sai đường dẫn) trước khi giao implementer -->

View File

@ -0,0 +1,67 @@
# LĂNG KÍNH 2/4 — TRUNG THỰC VỚI NGUỒN GỐC
## Verdict
**GO-WITH-FIXES — chân chống KHÔNG sập, nhưng phải hạ phạm vi một câu và vá bảng §1.7 trước khi trình owner với tư cách "đề xuất sửa ISO".**
Trả lời thẳng câu (e), là câu quyết định:
1. **"9 bước ISO khớp 1:1 với 9 `ContractPhase`" — XÁC NHẬN.** Tôi đếm tay Bảng 2 của ISO: khai `(10r x 3c)`, một dòng tiêu đề *"BƯỚC / STEP | TRÁCH NHIỆM | NỘI DUNG CHI TIẾT"* (`src-QT-TRINH-KY-HD.txt:59`) rồi đúng **9** dòng bước (`:60-68`). Ánh xạ khớp cả tên trạm lẫn thứ tự, 9 trên 9: *Lựa chọn NTP/NCC* (`:60`) ↔ `DangChon`; *Soạn thảo hợp đồng* (`:61`) ↔ `DangSoanThao`; *Góp ý nội dung* (`:62`) ↔ `DangGopY`; *Đàm phán, thương thảo hợp đồng* (`:63`) ↔ `DangDamPhan`; *In hợp đồng* (`:64`) ↔ `DangInKy`; *Kiểm tra — CCM* (`:65`) ↔ `DangKiemTraCCM`; *Duyệt — BOD/NĐUQ* (`:66`) ↔ `DangTrinhKy`; *Đóng dấu hợp đồng — HRA/ISO* (`:67`) ↔ `DangDongDau`; *Phát hành hợp đồng. Lưu trữ hồ sơ* (`:68`) ↔ `DaPhatHanh`. Vế ISO chắc chắn là 9; chỗ lung lay nằm ở phía spec, xem B3.
2. **"ISO đi thẳng bước 1→2, không có bước trung gian" — XÁC NHẬN THEO NGHĨA HẸP, BÁC THEO NGHĨA RỘNG.** Trong Bảng 2 thì đúng: giữa dòng bước 1 (`:60`) và dòng bước 2 (`:61`) không có dòng nào khác. Nhưng câu spec dùng để kết luận lại rộng hơn nhiều — *"Không có trong quy trình ISO đang ban hành"* (`spec:18`) — trong khi chính bước 1 trỏ sang một quy trình khác chưa ai đọc: *"Tham khảo Quy trình Cung ứng…"* (`:60`) với biểu mẫu *"SOL-PRO-SP-001 Quy trình Cung ứng"* (`:47`). Chi tiết ở N1.
Nói gọn: **spec không sập**, vì kết luận "khoảng trống nằm giữa ISO-1 và ISO-2" vẫn đứng đối với văn bản trình ký. Cái phải sửa là **phạm vi của câu khẳng định vắng mặt** và ba ô trong bảng đối chiếu nguồn đang nói quá (B1, B2, N1). Không có điểm nào chặn Wave 1-2 về mặt kỹ thuật; các điểm CAO chặn **tư cách văn bản** gửi owner.
## Bịa
> Giới hạn tự khai: tôi chỉ cầm **2 trong 3 nguồn** (ISO docx + FO-002.01). Nguồn PDF `01- Quy trinh hien tai` KHÔNG có trong run-folder, nên mọi chi tiết b.8-9 mà spec quy cho PDF tôi **không kết luận bịa** — chỉ đánh dấu chưa kiểm được.
- **B1 — CAO — "CÙNG HÌNH" là 4 trạm đối 3 bước, không phải cùng hình.** Spec `spec-ke-hoach-ky-ket-hd-28-07-2026.md:91` (bảng §1.7 dòng 9) viết: *"Chuỗi ký FO-002.01 (ĐỀ XUẤT→PRO→CCM→GĐ) | ≈ ISO 5-7 | ≈ b.9→10→11→12 **CÙNG HÌNH** | CÓ | **Đối chứng GIẤY cho O-1**"*. Đối chiếu ISO Bảng 2: bước 5 *"In hợp đồng | QS/NV.PB"* (`src-QT-TRINH-KY-HD.txt:64`), bước 6 *"Kiểm tra | CCM"* (`:65`), bước 7 *"Duyệt | BOD/ / NĐUQ"* (`:66`). **Không có bước nào của ISO dành cho Phòng Cung ứng trong chuỗi ký** — ISO bước 5 nói thẳng *"QS/NV.PB chuyển HĐ cho CCM"* (`:64`), tức là đi từ đơn vị đề xuất sang CCM, bỏ qua PRO. Trong khi form giấy có hẳn một trạm PHÒNG CUNG ỨNG 10 dòng ký (`src-FO-002.01-bang-kiem-tra-HD.txt:21-30`) và LƯU Ý bắt buộc: *"Tất cả các loại hợp đồng còn lại phải chuyển qua Phòng Cung ứng và Phòng CCM trước."* (`:46`). ⇒ Ô "≈ ISO 5-7" và chữ "CÙNG HÌNH" khai một sự tương ứng không tồn tại (4↔3, trạm PRO không có bước ISO đối ứng). **Ghi chú quan trọng: phát hiện này lại là ĐẠN CHO spec** — nó chứng minh form giấy đã chạy chuỗi PRO→CCM→GĐ mà văn bản ISO chưa cập nhật, tức chuỗi b.10→11→12 của spec bám form giấy chặt hơn bám ISO. Sửa đúng cách là tách ô này thành 1 dòng mâu thuẫn ISO↔FO thật, chứ không phải xoá.
- **B2 — CAO — kết luận "0 mâu thuẫn" về vai không dựng được từ nguồn.** Spec `:90` (dòng 8) viết: *"Tên phòng/vai | PRO/CCM/BOD/NĐUQ/HRA | Procurement/CCM/CEO | PB-DA/PRO/CCM/GĐ | Khớp `AppRoles` — **0 mâu thuẫn**"*. Bảng định nghĩa ISO (`src-QT-TRINH-KY-HD.txt:17-39`) liệt **23 mục**, trong đó tối thiểu 6 vai có mặt trong dòng chảy nhưng không có trong danh sách 3 cột của spec: `FIN` (`:22`), `ACT` (`:23`), `EQU` (`:24`), `TBP`/`TP` (`:27-28`), `QS` (`:33`), và cặp `PD` = *"Giám đốc Thi công"* (`:31`) tách khỏi `PM` = *"Giám đốc Dự án"* (`:32`). Bước 3 ISO gọi đích danh cả cụm: *"Góp ý nội dung | PD/PM/PRO/ / CCM/FIN/ACT"* (`:62`). Muốn giữ kết luận "0 mâu thuẫn" thì phải nêu rõ phạm vi là *chỉ 3 trạm duyệt của khúc b.10-12*, chứ không phải toàn bộ tên phòng/vai.
- **B3 — TRUNG — số "7 phase" tự chọi với chính câu của nó.** Spec `:34` viết: *"**7 phase `[LEGACY]`** của `ContractPhase` CHÍNH LÀ quy trình ISO **9 bước**, mã-hoá cứng. Khớp 1:1 đúng thứ tự"* rồi liệt kê **9 cặp**`:35-37`. Bên ISO tôi đã đếm tay: Bảng 2 khai `(10r x 3c)` = 1 dòng tiêu đề + **9 dòng bước** (`src-QT-TRINH-KY-HD.txt:59-68`) ⇒ **9 là con số đúng của phía ISO**. Vậy lệch nằm ở phía spec: hoặc viết "9 phase", hoặc phải nói rõ 2 phase nào không mang nhãn `[LEGACY]`, vì "khớp 1:1" trên 9 mục mà chỉ có 7 mục ở vế trái là không đóng được.
- **B4 — TRUNG — mệnh đề thực nghiệm không nguồn, không phép kiểm.** Spec `:60` (b.8) viết: *"🔴 **sơ đồ KHÔNG vẽ vòng lặp này, thực tế có**"* cho vòng `TvgsBac→DaNop`. Đây là một khẳng định về thực tế vận hành, không kèm trích lời owner, không kèm dữ liệu, và không nêu phép kiểm nào làm nó trượt nếu sai. Nó lại thêm hẳn một cạnh chuyển-trạng-thái vào vòng đời item. Cần một câu owner xác nhận hoặc hạ xuống mức đề xuất có dấu hỏi.
- **B5 — THẤP (chỉ ghi nhận, không kết tội) — cụm b.8-9 không kiểm được bằng 2 nguồn tôi cầm.** Bộ trường *{Kind, NCC, Status, TvgsName, ngày, scan}* và vòng đời *`ChuaNop→DaNop→TvgsDuyet|TvgsBac`* (`spec:60`) không xuất hiện trong ISO lẫn FO-002.01. Điểm kiểm được: chữ **TVGS không có trong bảng ĐỊNH NGHĨA, TỪ VIẾT TẮT của ISO** (`src-QT-TRINH-KY-HD.txt:16-39`) và cũng không có trong bất kỳ bước nào của Bảng 2. Vì spec tự nhận là *"ĐỀ XUẤT BỔ SUNG QUY TRÌNH ISO"* (`spec:22`), nếu ban hành thì phải bổ sung định nghĩa TVGS vào mục 4 của QT.
## Rơi
- **R1 — TRUNG — checklist CCM rơi mất một nửa.** Spec `:89` (dòng 7) ghi checklist là *"(PRO: điều khoản/thanh toán/rủi ro pháp lý · CCM: giá vs NS)"*. Form giấy cho CCM có **hai** mục, không phải một: *"G/trị HĐ so với NS / / Rủi ro pháp lý HĐ"* (`src-FO-002.01-bang-kiem-tra-HD.txt:31`, lặp lại y hệt ở `:32-40`). Mục *"Rủi ro pháp lý HĐ"* của CCM bị rơi, trong khi chính nó là mục trùng tên với PRO — nghĩa là form cố ý bắt **hai** phòng cùng soi rủi ro pháp lý một cách độc lập. Nếu O-Q2 chốt số hoá checkbox mà bảng tra chỉ liệt 1 mục cho CCM thì sẽ dựng thiếu.
- **R2 — TRUNG — kiểm kê checklist bỏ 2 trạm trên 4.** Form có mục kiểm cho cả bốn trạm: trạm đề xuất *"PHÒNG BAN/DỰ ÁN / ĐỀ XUẤT"* với mục *"Soạn thảo / / Nội dung HĐ"* (`:15`, lặp `:16-20`); trạm *"PHÒNG CUNG ỨNG"* (`:21`); trạm *"PHÒNG CCM"* (`:31`); và trạm *"GIÁM ĐỐC / Hoặc Người được ủy quyền"* với mục *"Ký kết, phát hành"* (`:41`, lặp `:42-45`). Spec chỉ liệt 2 trạm giữa. Riêng mục của trạm giám đốc đáng chú ý vì nó gộp **ký kết và phát hành** vào một ô, tức trên giấy hai việc này là một hành vi của cùng một người.
- **R3 — THẤPTRUNG — LƯU Ý của form bị trích mất nửa sau.** Spec `:85` trích đúng vế đầu: *"mỗi bộ phận 01 ngày, quá hạn XEM NHƯ ĐÃ THÔNG QUA"*. Nguyên văn form còn vế sau: *"Nếu cần kéo dài thời gian, bộ phận kiểm tra phải thông báo cho bộ phận soạn thảo biết và theo dõi, đồng thời phải ghi chú về việc kéo dài thời gian vào phần \"Ý kiến\"."* (`src-FO-002.01-bang-kiem-tra-HD.txt:46`). Vế sau **không phải SLA-engine** — nó là ràng buộc nội dung đặt lên ô ý kiến, nên quyết định O-2 (*"không SLA-engine"*, `spec:47`) không phủ hết nó. Đây là thứ rẻ nhất để giữ: một dòng ghi chú trong `LevelOpinions.Comment`.
- **R4 — THẤP — nghĩa vụ lưu trữ bản kiểm tra.** Form kết bằng: *"Bảng kiểm tra này phải được lưu kèm với bộ hồ sơ gốc."* (`:46`). Spec §① không nhắc đường xuất hoặc lưu bảng kiểm tra số hoá kèm hồ sơ. Nếu O-Q2 chốt số hoá checkbox thì nghĩa vụ này thành yêu cầu xuất file, cần nêu trước khi chốt.
- **R5 — THẤP — toàn bộ phần đầu form (THÔNG TIN HỢP ĐỒNG) không xuất hiện trong spec §①.** Form yêu cầu: *"Phòng ban/Dự án"* (`:8`), *"Loại Hợp đồng : Chủ đầu tư | Nhà cung cấp | Thầu phụ | Tổ đội | Thiết bị thuê | Khác"* (`:9`), *"Tên đối tác"* (`:10`), *"Nội dung hợp đồng"* (`:11`). Đáng chú ý là hai lựa chọn **"Thiết bị thuê"** và **"Khác"** — chúng không nằm trong 7 loại hợp đồng của hệ thống, nên nếu phiếu kế hoạch mang trường "Loại HĐ" thì phải quyết ánh xạ hai ô này về đâu.
- **R6 — THẤP — bước 9 ISO bị rút gọn khi ánh xạ.** Spec `:36` ghi *"`DaPhatHanh=9`↔Phát hành"*. Nguyên văn ISO là *"Phát hành hợp đồng. Lưu trữ hồ sơ / Issue and archive the contract"* với 4 việc con: *"PB/BCH CT scan và gởi 01 bản gốc cho CCM"*, *"thông báo và chuyển bản gốc hợp đồng đã ký (theo đúng số lượng) đến NTP/NCC"*, *"Lưu trữ bản gốc hợp đồng"*, *"Lưu trữ trên Server theo Filing System (Hợp đồng bản cứng chính và bản scan)"* (`src-QT-TRINH-KY-HD.txt:68`). Nửa "lưu trữ" biến mất khỏi nhãn ánh xạ.
- **R7 — THẤP — kênh luân chuyển do ISO quy định là Email, spec thay bằng thông báo trong ứng dụng.** ISO bước 2 nguyên văn: *"QS/NV.PB gởi dự thảo HĐ cho các Phòng ban để lấy ý kiến qua Email."* (`:61`). Spec b.7 chốt: *"**Email ra ngoài = ngoài scope** (SMTP TODO toàn hệ thống)"* (`spec:59`). Đây là đánh đổi có khai báo nên không phải lỗi giấu, nhưng vì spec tự nhận là đề xuất sửa ISO thì phải nói rõ: bản ISO sửa đổi sẽ phải sửa luôn cụm "qua Email" ở bước 2, nếu không văn bản và phần mềm sẽ nói hai kiểu.
- **R8 — THẤP — quy định mã số bị bỏ trống cho phiếu mới.** Cột Biểu mẫu của ISO gắn *"SOL-CCM-RG-001 / Quy định mã số hợp đồng và đơn hàng"* vào **mọi** bước (`:48-56`), và bước 5 nói *"Cập nhật số Hợp đồng theo quy định."* (`:64`). Spec §① không nói phiếu Kế hoạch ký kết có mã theo quy tắc nào. Đây là câu hỏi owner rẻ, nên hỏi cùng đợt 5 câu đang treo.
- **R9 — THẤP — nguồn ISO tự vênh, spec chưa ghi nhận.** Bảng 1 gán bước 5 cho **NTP/NCC/TĐ** kèm hạn *07 ngày* (`:51`), còn Bảng 2 gán bước "In hợp đồng" cho **QS/NV.PB** (`:64`) và mô tả bên trong lại là *"NTP/NCC/TĐ in hợp đồng 2 mặt, ký, đóng dấu Hợp đồng và gửi về cho PB/BCH CT."*. Vênh này nằm ngoài khúc b.7→12 nên không chặn, nhưng nếu spec định trích ISO làm căn cứ ban hành thì nên biết là bản gốc có chỗ tự mâu thuẫn.
## Sai vai
Ba ánh xạ lõi **đúng nguyên văn**, xem mục Củng cố. Bốn điểm lệch:
- **V1 — TRUNG — "PB/BCH CT" bị thu về một mình "BCH".** ISO viết cặp này ở mọi chỗ trọng yếu: trách nhiệm bước 1 là *"PB/BCH CT"* (`src-QT-TRINH-KY-HD.txt:60``:47`), bước 8 *"PB/BCH CT chuyển hợp đồng đã được ký duyệt đến HRA/ISO"* (`:67`), bước 9 *"PB/BCH CT/ / CCM"* (`:68`). Form giấy đặt tên trạm đề xuất là *"PHÒNG BAN/DỰ ÁN"* (`src-FO-002.01-bang-kiem-tra-HD.txt:14-15`). Spec `:59` viết b.7 là *"PMH chuyển thông tin cho BCH"*`:54` chốt *"BCH = người tạo phiếu (`CreatedBy`)"*. Cơ chế `CreatedBy` thì trung tính nên chạy được cho cả hai loại đơn vị, nhưng **nhãn** thì hẹp: nếu phiếu do một Phòng ban khởi tạo (mua sắm tập trung, không thuộc công trường nào) thì cả câu chữ b.7 lẫn tên màn hình chờ lập kế hoạch đều gọi sai đối tượng. Sửa rẻ: đổi nhãn thành "Phòng ban / Ban chỉ huy công trường".
- **V2 — TRUNG — gộp PD với PM, bỏ QS và TBP/TPB.** ISO tách rõ *"PD : Giám đốc Thi công"* (`:31`) và *"PM : Giám đốc Dự án"* (`:32`) là hai chức danh khác nhau, đồng thời dùng *"QS : QS công trường"* (`:33`), *"TBP : Trưởng Bộ phận"* (`:28`), *"TP : Trưởng Phòng ban"* (`:27`) như những vai có hành vi riêng — ví dụ bước 5: *"PD/PM/TPB kiểm tra các điều khoản hợp đồng và ký nháy trên từng HĐ"**"PD/PM/TPB/TBP ký duyệt và cho ý kiến (nếu có) lên tờ cover chấp thuận HĐ"* (`:64`). Spec `:52-53` chỉ liệt `ProjectManager`/`Drafter` cho toàn bộ cụm này. Với khúc b.7→12 (BCH lập phiếu, ba trạm duyệt) thì gộp như vậy tạm chấp nhận được, nhưng phải khai là **gộp có chủ đích**, không được kết luận "0 mâu thuẫn".
- **V3 — THẤP — "CEO" không phải từ của nguồn.** ISO định nghĩa *"BOD : Ban Giám đốc/Board of Directors"* (`:18`) và *"NĐUQ : Người được ủy quyền"* (`:19`); form ghi trạm là *"GIÁM ĐỐC / Hoặc Người được ủy quyền"* (`src-FO-002.01-bang-kiem-tra-HD.txt:41`). Spec b.12 gọi *"CEO ký"* (`spec:64`). BOD là một tập thể, CEO là một cá nhân — vai hệ thống `Director` + `AuthorizedSigner` thì đúng, chỉ có chữ "CEO" là nhập từ sơ đồ PDF chứ không từ hai nguồn văn bản.
- **V4 — THẤP — trạm đóng dấu trong ISO là "HRA/ISO", hai bên chứ không một.** Nguyên văn bước 8: *"Đóng dấu hợp đồng | HRA/ISO"**"chuyển hợp đồng đã được ký duyệt đến HRA/ISO để đóng dấu theo quy định"* (`src-QT-TRINH-KY-HD.txt:67`). Spec `:90` chỉ ghi HRA. Ngoài ra form giấy **không có trạm HRA nào** (`:15-45` chỉ 4 trạm) — tức con dấu nằm ngoài bảng kiểm tra. Điều này liên quan trực tiếp tới b.12: nếu "CCM đóng dấu" trong spec `:64` là đóng dấu **hợp đồng** thì nó chọi với ISO (dấu thuộc HRA/ISO); nếu là đóng dấu **phiếu kế hoạch** thì phải nói rõ, vì hai nghĩa dẫn tới hai thiết kế khác nhau.
## Nống biên
- **N1 — CAO — khai "nguồn im lặng" ở chỗ nguồn có nói, và đây đúng là chân chống của cả spec.** Spec `:17-19` viết: *"**Không có trong quy trình ISO đang ban hành** — `QT TRINH KY HOP DONG TP-NCC.docx` bảng 2 đi THẲNG bước 1 \"Lựa chọn NTP/NCC\" → bước 2 \"Soạn thảo hợp đồng\", **0 bước trung gian**."*, và bảng §1.7 dòng 1 ghi cột ISO là *"**KHÔNG CÓ**"* (`:83`), từ đó suy ra *"Spec này vừa là spec phần mềm, vừa là ĐỀ XUẤT BỔ SUNG QUY TRÌNH ISO"* (`:22`). Nhưng chính bước 1 của ISO **trỏ ra một quy trình khác**: nội dung chi tiết viết *"Tham khảo Quy trình Cung ứng để so sánh và lựa chọn NTP/NCC/TĐC đúng quy định."* (`src-QT-TRINH-KY-HD.txt:60`), và cột Biểu mẫu của đúng dòng đó ghi *"SOL-PRO-SP-001 Quy trình Cung ứng / SOL-PRO-SP-001 Procurement Procedure"* (`:47`) — đây là biểu mẫu **duy nhất** khác cả 8 dòng còn lại, tức là một cái trỏ có chủ đích. Hệ quả: cái đo được là *"không có trong QT-TRINH-KY-HD"*, **không** phải *"không có trong quy trình ISO đang ban hành"*. Muốn giữ tư cách "đề xuất bổ sung ISO" thì phải đọc `SOL-PRO-SP-001` trước, vì khúc b.7→12 nằm ngay ranh giữa cung ứng và ký kết — đúng vùng mà văn bản kia phụ trách. Đây là nguồn thứ tư, chưa ai chạm.
- **N2 — TRUNG — bảng tự đặt luật "KHÔNG tự quyết" rồi tự quyết 3 ô.** Tiêu đề `:79` viết *"Mâu thuẫn / im lặng giữa 3 nguồn (bảng tra — **KHÔNG tự quyết**)"*. Trong bảng: dòng 3 kết *"O-2 ⇒ chỉ ghi nhận"* (`:85`), dòng 5 kết *"Hệ thống có sẵn `TraLai` + 4 return-mode"* (`:87`), dòng 6 kết *"**KHÔNG áp phiếu KH**"* (`:88`). Ba ô này đều là quyết định thiết kế, không phải tra cứu. Dòng 6 nặng nhất vì nó gạt đi quy tắc rẽ nhánh **duy nhất** mà giấy tờ đưa ra (xem N3). Đề nghị: hoặc đổi nhãn cột thành "Xử lý (đã quyết / chờ owner)", hoặc chuyển 3 ô này sang mục quyết định để owner nhìn thấy chúng là lựa chọn chứ không phải sự thật.
- **N3 — TRUNG — dùng FO-002.01 theo hai chiều ngược nhau.** Dòng 9 lấy form làm *"Đối chứng GIẤY"* rằng chuỗi duyệt của phiếu kế hoạch **cùng hình** với chuỗi trên giấy (`:91`); nhưng dòng 2 lại khai form *"im lặng"* về thời hạn của khúc 7→12 (`:84`). Nếu hai chuỗi thật sự cùng hình thì quy tắc xử lý của form — *"Mỗi bộ phận chỉ có 01 ngày để xử lý. Nếu kéo dài hơn 01 ngày mà vẫn chưa xử lý xong, thì xem như đã thông qua."* (`src-FO-002.01-bang-kiem-tra-HD.txt:46`) — chính là thứ gần nhất với một quy định thời hạn cho chuỗi đó. Không đòi hoà giải (O-2 đã chốt bỏ SLA-engine), chỉ đòi bảng đừng nói nguồn im lặng ở nơi mình vừa dùng nguồn đó làm bằng chứng.
- **N4 — THẤP — "ISO không nói" về bypass Chủ đầu tư thực ra là "ISO loại trừ".** Dòng 6 ghi cột ISO là *"không nói"* (`:88`). Phạm vi ISO nói rõ: *"Áp dụng đối với các hợp đồng/phụ lục hợp đồng **Thầu phụ/Nhà cung cấp/Tổ đội**"* (`src-QT-TRINH-KY-HD.txt:12`), tức hợp đồng Chủ đầu tư **nằm ngoài phạm vi** văn bản này — khác hẳn im lặng. Ô đúng là "ngoài phạm vi". Khác biệt này có ích: nó giải thích vì sao chỉ có form giấy mới nói tới nhánh CĐT (`src-FO-002.01-bang-kiem-tra-HD.txt:46`).
- **N5 — THẤP — mẫu tìm hẹp cho một khẳng định vắng mặt.** Spec `:17` khẳng định *"repo 0-hit `shopdrawing|TVGS|duyệt mẫu`"*. Khẳng định này có phép kiểm (chạy lại lệnh tìm) nên đạt sàn đo được, nhưng ba từ khoá tiếng Anh và một cụm tiếng Việt không phủ các biến thể khả dĩ như "bản vẽ thi công", "duyệt vật tư mẫu", "giám sát". Vắng mặt chỉ chắc bằng đúng độ rộng của mẫu tìm.
- **N6 — KHÔNG TÍNH LỖI, ghi nhận kiểm soát tốt.** Phạm vi khai là b.7→12, và §2.5 có *"Cầu tiếp giáp b.12→13 (sửa 1 file) — ⚠️ chạm module Contract"* (`:196`) tức bước ra ngoài phạm vi. Nhưng spec đã tự rào đúng chỗ: O-3 chốt *"Wave nào chạm module Contract phải hỏi lại anh"* (`:48`) và WAVE 5 đánh dấu *"CHẶN: Q6, Q11 + anh cho phép chạm HĐ"* (`:293`). Nống có khai báo và có cổng chặn thì không phải nống lén.
## Điểm CỦNG CỐ
Tám chỗ tôi cố đánh mà không đổ, ghi lại để đợt sau đừng soi lại:
1. **Số 9 của ISO đúng.** Bảng 2 = tiêu đề + 9 bước (`src-QT-TRINH-KY-HD.txt:59-68`); Bảng 1 cũng có đúng 9 dòng trách nhiệm có nội dung (`:47-55`) — hai bảng khớp nhau về số bước.
2. **Ánh xạ 9↔9 khớp cả tên trạm lẫn thứ tự** (chi tiết ở Verdict mục 1). Không có bước nào bị đảo, không có bước nào bị nhét thêm.
3. **Dãy thời hạn trích đúng từng ô.** Spec `:85` ghi *"07/07/07/07/03/01 ngày"*; Bảng 1 cho: `07 ngày` ở bước 2 (`:48`), bước 3 (`:49`), bước 4 (`:50`), bước 5 (`:51`), rồi `03 ngày` ở CCM (`:52`), `01 ngày` ở BOD/NĐUQ (`:53`), và ba bước 1/8/9 bỏ trống. Sáu trên sáu.
4. **Quy tắc quá hạn của form trích đúng nguyên văn** (`src-FO-002.01-bang-kiem-tra-HD.txt:46`), và nhận xét *"auto-pass mâu thuẫn mô hình duyệt-chặn V2"* (`spec:85`) là đúng bản chất: form cho đi tiếp khi im lặng, khung V2 thì chặn tới khi có người bấm.
5. **Ba ánh xạ vai lõi đúng từng chữ:** *"CCM : Phòng Kiểm soát Chi phí"* (`:20`) ↔ `CostControl`; *"PRO : Phòng Cung ứng"* (`:21`) ↔ `Procurement`; *"BOD : Ban Giám đốc"* + *"NĐUQ : Người được ủy quyền"* (`:18-19`) ↔ `Director` + `AuthorizedSigner`, và form gọi đúng cặp đó là *"GIÁM ĐỐC / Hoặc Người được ủy quyền"* (`src-FO-002.01-bang-kiem-tra-HD.txt:41`).
6. **Thứ tự bốn trạm trên form đúng như spec ghi.** Đọc theo thứ tự vật lý các dòng của bảng: ĐỀ XUẤT (`:15-20`) → PHÒNG CUNG ỨNG (`:21-30`) → PHÒNG CCM (`:31-40`) → GIÁM ĐỐC (`:41-45`). Chuỗi `ĐỀ XUẤT→PRO→CCM→GĐ``spec:91` không bịa thứ tự; chỗ sai chỉ là mệnh đề "cùng hình với ISO 5-7" (B1).
7. **Nhánh bypass Chủ đầu tư có thật và trích đúng.** Form: *"Đối với hợp đồng/phụ lục hợp đồng ký kết với Chủ đầu tư, Đơn vị đề xuất có thể chuyển trực tiếp hợp đồng Giám đốc."* (`:46`) — khớp `spec:88`.
8. **Lập luận §1.6 "chỉ một chuỗi duyệt" nhất quán với cả hai nguồn tôi cầm.** Form có đúng một chuỗi ký cho cả bộ hồ sơ, ISO cũng chỉ có một dòng duyệt tuyến tính; không nguồn nào vẽ chuỗi duyệt thứ hai cho mẫu hay bản vẽ. Kết luận "b.8-9 là bảng con, không phải phiếu con" (`spec:72-77`) không bị nguồn phản bác.
<!-- END · TOTAL=23 DIEM (3 CAO / 8 TRUNG / 12 THAP; +1 ghi-nhan N6 khong tinh, +8 diem cung co) · VERDICT=GO-WITH-FIXES -->

View File

@ -0,0 +1,192 @@
# LĂNG KÍNH 3/4 — SCHEMA 7 BẢNG (reviewer, S157)
Đích chấm: `spec-ke-hoach-ky-ket-hd-28-07-2026.md` §②.2 (dòng 113-136).
Nguồn đối chiếu ĐÃ ĐỌC: `src/Backend/SolutionErp.Domain/ApprovalWorkflowsV2/ApprovalWorkflow.cs` ·
`src/Backend/SolutionErp.Domain/PurchaseEvaluations/PurchaseEvaluation.cs` (+ grep xác minh trên config/service/enum).
## Verdict
**GO-WITH-FIXES** — hình dạng 7 bảng ĐÚNG HƯỚNG (loose-Guid, decimal(18,2), query-filter, FK Cascade/Restrict
đều khớp twin thật), nhưng **5 điểm HIGH phải đóng TRƯỚC Wave 1** vì chúng làm migration/CQRS/FE sai IM LẶNG
(build vẫn xanh): thiếu bảng lịch-sử-transition mà chính service được lệnh copy có ghi vào, thiếu đăng ký ở 3 site
cross-module `ApprovalWorkflowV2AdminFeatures`, thiếu 4 cột Changelog, không khai base-class cho bảng #2-#7, và
bộ số enum phase đụng khuôn FE đang được copy.
Phân bố: **5 HIGH · 7 MAJOR · 3 MEDIUM · 7 CỦNG CỐ = 22 điểm**.
## Bảng THỪA
**T1 [MAJOR] — #7 `ContractSigningPlanCodeSequences` gộp được, KHÔNG mất gì.**
Repo đã có **4 bảng giống hệt nhau về cấu trúc** `(Prefix string PK · LastSeq int · UpdatedAt)`:
`Contracts/ContractCodeSequence.cs:6-11` · `Office/ProposalCodeSequence.cs:8-13` ·
`Office/WorkflowAppCodeSequence.cs:14-19` · (+ `PurchaseEvaluationCodeSequence`, mirror khai ở
`ProposalCodeSequence.cs:4`). Trong đó `WorkflowAppCodeSequence` **đã là bảng DÙNG CHUNG cho 4 module Office**,
phân biệt nhau bằng Prefix có không-gian-tên: `"DT/LR/2026"` (nghỉ phép) · `"DT/OT/2026"` (OT) ·
`"DT/CT/2026"` (công tác) · `"DX/XE/2026"` (đặt xe) — xem `WorkflowAppCodeSequence.cs:8-11`.
Prefix `"KHKK/{YYYY}"` nhét vào bảng đó là **0 va chạm** (khoá là chuỗi, đã namespaced sẵn).
⇒ Cắt #7 ⇒ còn **6 bảng**, giảm 1 CreateTable + 1 configuration + 1 DbSet, **không mất tính atomic**.
**T2 [MAJOR] — lý do bác biến-thể-5-bảng đứng NỬA, đổ NỬA.**
- Nửa ĐỨNG: "giữ #6 Changelogs" có bằng chứng thật — Mig 60/61 phải backfill từ changelog (CLAUDE.md ghi
Mig 60 soi nhầm bảng Approvals → Mig 61 mới đúng Changelogs). Thứ tự ưu tiên spec đưa ("cắt #7 trước,
giữ #6") là ĐÚNG.
- Nửa ĐỔ: mệnh đề *"mất mã phiếu atomic"* **không suy ra được**. Tính atomic đến từ **transaction
SERIALIZABLE trong CodeGen service**, không đến từ việc bảng đó thuộc riêng module — nói rõ trong chính
comment của cả 3 bảng: `ContractCodeSequence.cs:5` · `ProposalCodeSequence.cs:7` ·
`WorkflowAppCodeSequence.cs:12-13`. Vậy "cắt #7" ⇏ "mã tay"; nó chỉ là "dùng chung bảng sequence sẵn có".
- Các bảng còn lại **KHÔNG gộp được** (đã xét từng cặp): #2 Lines (multi-winner, per-NCC) không nhét vào
header; #3 DossierItems không nhét vào #5 Attachments vì trạng thái `ChuaNop` là hàng **không có file**
gộp là phải đẻ attachment giả; #4 LevelOpinions bị máy-móc admin V2 truy vấn theo `(phiếu × Level)` nên
phải là bảng riêng có UNIQUE.
## Bảng THIẾU
**H1 [HIGH] — không có `ContractSigningPlanApprovals` (lịch sử transition), trong khi service được lệnh copy CÓ ghi vào bảng đó.**
`ContractWorkflowService.cs:151` ghi thẳng: `db.ContractApprovals.Add(new ContractApproval { ContractId = …,
FromPhase = fromPhase, ToPhase = fromPhase, … })`. Twin PE cũng có nhánh này: `PurchaseEvaluation.cs:137`
(`List<PurchaseEvaluationApproval> Approvals`) + index chuyên dụng `(PurchaseEvaluationId, ApprovedAt)`
`PurchaseEvaluationConfiguration.cs:168`; `PurchaseEvaluationApproval.cs:6-7` ghi rõ *"Lịch sử phê duyệt —
giống ContractApproval pattern"*. Spec §2.1 bắt copy `ApproveV2Async:217-394` ⇒ đoạn copy sẽ trỏ vào một
bảng KHÔNG TỒN TẠI trong danh sách 7 bảng.
⇒ Chọn 1 trong 2 và **ghi vào spec**: (i) thêm bảng #8 `…Approvals`, hoặc (ii) tuyên bố "Changelog gánh vai
Approvals" **kèm** bù cột `FromPhase/ToPhase/Decision/Comment/ApprovalWorkflowLevelId` (hiện #6 chỉ có MỘT
trường phase là `PhaseAtChange`, không có cặp from→to, không có Decision).
**H2 [HIGH] — module thứ 8 phải đăng ký ở 3 site liệt-kê-thủ-công trong `ApprovalWorkflowV2AdminFeatures.cs`; spec chỉ nói chung chung.**
File này liệt kê **từng bảng `*LevelOpinions` một** ở 3 chỗ:
`:911` + `:929` (Merge "chữ ký còn sống" — `db.ProposalLevelOpinions…` / `db.TravelRequestLevelOpinions…`) ·
`:971` + `:992` (rows.AddRange dựng `RetainedOpinionRef`) · `:1044` + `:1056` (dọn chữ ký MỒ CÔI).
Chuỗi guard S155 đứng trên dữ liệu này: `:651` *"F-5/F-5a — chặn LỊCH SỰ trước khi FK nổ"*`:733`
*"Dọn rác chữ ký MỒ CÔI trước khi xoá dòng"*.
⇒ Nếu `ContractSigningPlanLevelOpinions` không được thêm vào **cả 3 site**, admin sửa quy trình `type = 10`
sẽ **không nhìn thấy** chữ ký của phiếu KHKK, xoá Level đang có chữ ký → FK Restrict nổ **500** — đúng lớp lỗi
S155 vừa vá xong. Spec §2.4 chỉ viết *"các site BE `ApprovalWorkflowV2AdminFeatures.cs`"* (không nêu 3 site này,
chỉ nêu map typeCode) ⇒ chưa đủ để người làm không sót.
## Cột sai
**C1 [HIGH] — #6 Changelogs thiếu 4 cột so với twin.**
`PurchaseEvaluationChangelog.cs:14-22` có: `EntityType` · `EntityId` · `Action` · `PhaseAtChange` · `UserId` ·
`UserName` · `Summary` · `FieldChangesJson` · `ContextNote`. Spec #6 chỉ liệt `Action · PhaseAtChange · UserId ·
Summary · ContextNote`**thiếu `EntityType`, `EntityId`, `UserName`, `FieldChangesJson`**.
Hệ quả đo được: index twin `(PurchaseEvaluationId, EntityType)` (`PurchaseEvaluationConfiguration.cs:188`) mất
chỗ dựa; `LogTransitionAsync` (`ContractWorkflowService.cs:405`) gọi `changelog.LogWorkflowTransitionAsync(...)`
— copy service changelog sang module mới sẽ không biên dịch nếu entity thiếu trường; và mất khả năng ghi diff
trường (`FieldChangesJson`, twin khai `nvarchar(max)``PurchaseEvaluationConfiguration.cs:185`).
**C2 [MAJOR] — `Status int` bắt đầu từ **0** (`ChuaNop=0`) là lệch quy ước + bẫy JavaScript.**
Mọi enum trong repo bắt đầu ở 1: `Office/Enums.cs:9` (`Confirmed=1`) · `:19` (`Nhap=1`) · `:31` (`Nhap=1`) ·
`:41` (`Hardware=1`) · `:50` (`Low=1`) · `:58` (`Open=1`); `ApprovalWorkflow.cs:55` (`DuyetNcc=1`).
Số 0 là giá trị **falsy** trong JS ⇒ `status ? A : B`, `if (filter.status)`, `?status=0` trên query-string đều
rơi im lặng ở FE. Đề nghị `ChuaNop = 1` (giữ `Khac = 99` của `Kind` — cái đó ĐÚNG khuôn `ItTicketCategory.Other = 99`,
`Office/Enums.cs:45`).
**C3 [MAJOR] — ~13 cột chuỗi không khai độ dài ⇒ EF sinh `nvarchar(max)`.**
Spec chỉ khai 2 độ dài (`HoSoLink 1000`, `Comment 2000`). Không khai: `MaKeHoach`, `GhiChu`, `Name` (#3), `Note`
(#2/#3), `TvgsName`, `Summary`, `ContextNote`, `SignedByFullName`, `FileName/Path/ContentType` (#5), `Prefix` (#7).
Twin khai đủ: `PurchaseEvaluationConfiguration.cs:22` (`HoSoLink` 1000) · `:184` (`ContextNote` 2000) ·
`ContractLevelOpinionConfiguration.cs:21-22` (`Comment` 2000, `SignedByFullName` 200 **IsRequired**).
`nvarchar(max)` không index được và không so sánh được trong filtered-unique.
**C4 [MAJOR] — `SlaDeadline?` chưa có người đọc ⇒ đúng lớp "cột có mà 0 ai đọc" mà chính spec cấm (dòng 136).**
Thiếu `SlaWarningSent` (twin `PurchaseEvaluation.cs:26`) và thiếu index `SlaDeadline` (twin
`PurchaseEvaluationConfiguration.cs:62`). Job SLA hiện chỉ đọc/ghi cờ này trên nhánh Contract:
`SlaExpiryJob.cs:139` (`.Where(c => !c.SlaWarningSent …)`) và `:169` (`c.SlaWarningSent = true;`).
⇒ Hoặc bỏ `SlaDeadline`, hoặc thêm cờ + index + khai rõ wave nào đăng ký module vào `SlaExpiryJob`.
**C5 [MAJOR] — header thiếu `DepartmentId`, làm vế "DeptManager" của guard trình mất chỗ neo.**
Twin có: `PurchaseEvaluation.cs:17` (`Guid? DepartmentId`). Guard spec §2.3 (dòng 164) =
`CreatedBy == actor DeptManager Admin`. Không có phòng trên phiếu thì "DeptManager" không so được với gì
**bất kỳ ai mang vai DeptManager trình được phiếu của phòng khác**. `ApprovalWorkflowStep.DepartmentId`
(`ApprovalWorkflow.cs:75`) chỉ là *hint* của quy trình, không thay được phòng của phiếu.
**C6 [MAJOR] — không có đường quay ngược Kế-hoạch → Hợp-đồng sau b.13.**
Twin có `PurchaseEvaluation.ContractId` (`:31`) + index (`PurchaseEvaluationConfiguration.cs:65`).
Ở đây HĐ sinh **theo từng NCC thắng**, mà #2 Lines cũng **theo từng NCC** ⇒ chỗ tự nhiên là
`ContractSigningPlanLines.ContractId?` (+ IX). Thiếu nó thì: không trả lời được "dòng này đã ra HĐ chưa",
không chặn được tạo HĐ hai lần cho cùng một NCC, và §2.5(a) không có chỗ ghi kết quả bắc cầu.
*(Lưu ý: đây KHÁC với "cột `SigningPlanId` trên PE" mà spec bác — bác cột đó là đúng, xem G6.)*
**C7 [MEDIUM] — `PeReferenceAmount`: GIỮ snapshot (đúng), nhưng thiếu mốc thời gian + luật ghi lại.**
Xem G5 để biết vì sao snapshot thắng "đọc live". Hai chỗ hở: (i) không có `PeReferenceAmountAt`
twin dùng `ApprovedBudgetSnapshotAt` làm **cờ "đã chốt"** (`PurchaseEvaluation.cs:132`, ghi rõ ở `:120`);
(ii) spec nói *"snapshot 1 lần"* lúc tạo nhưng không nói điều gì xảy ra khi Drafter **re-pin workflow** hay
sửa nháp (§2.3 cho phép re-pin) — có sinh lại Lines không, có tính lại số không.
## Ràng buộc sai
**R1 [HIGH] — không khai lớp cơ sở (`BaseEntity` vs `AuditableEntity`) cho bảng #2-#7, trong khi #2 lại đặt UNIQUE lọc `WHERE IsDeleted=0`.**
Bộ lọc đó **đòi** cột `IsDeleted`, tức #2 buộc phải là `AuditableEntity`. Nhưng twin gần nhất của #2
`PurchaseEvaluationSupplier.cs:9``: BaseEntity` (không có xoá mềm) — và UNIQUE của nó **không lọc**:
`PurchaseEvaluationConfiguration.cs:105` `HasIndex(x => new { x.PurchaseEvaluationId, x.SupplierId }).IsUnique()`.
⇒ Nếu người làm mirror twin (BaseEntity) thì migration sinh filter trỏ vào cột không tồn tại; nếu mirror spec
(AuditableEntity) thì lệch khuôn con-của-phiếu. Spec phải khai **base class cho từng bảng**.
**R2 [MEDIUM] — bất nhất nội bộ #2 (lọc) vs #4 (không lọc), và #4 kế thừa một vi phạm #57 tiềm ẩn.**
#4 không lọc là **khớp cả 6 twin**: `ContractLevelOpinionConfiguration.cs:34` · `ProposalLevelOpinionConfiguration.cs:28` ·
`TravelRequestLevelOpinionConfiguration.cs:28` · `OtRequestLevelOpinionConfiguration.cs:28` (+ Leave, PE).
Nhưng các entity đó **là** `AuditableEntity`: `PurchaseEvaluationLevelOpinion.cs:24`, `TravelRequestLevelOpinion.cs:16`
⇒ cả họ đang ở thế "xoá mềm + UNIQUE không lọc" = gotcha #57 dạng ngủ (chỉ chưa cắn vì đường ghi là UPSERT,
không soft-delete). Kế thừa thì kế thừa **có ý thức**: ghi 1 dòng lý do trong spec, nếu không lần sau ai đó
thêm đường soft-delete chữ ký là kẹt không ký lại được.
**R3 [MEDIUM] — loose-Guid đúng convention nhưng thiếu index đi kèm.**
Spec chỉ khai IX cho `PurchaseEvaluationId`. Twin đánh index cho **mọi** loose-Guid dùng để lọc:
`ProjectId` (`:58`) · `WorkItemId` (`:61`) · `ApprovalWorkflowId` (`:64`) · `ContractId` (`:65`) ·
`SlaDeadline` (`:62`); và ở bảng con: `SupplierId` (`:106`), `PurchaseEvaluationSupplierId` (`:206`).
⇒ Bổ sung IX: `ProjectId`, `ApprovalWorkflowId`, `DrafterUserId` (header) + `SupplierId` (#2) + `PlanId` (#4/#6/#7 theo cặp).
## Điểm CỦNG CỐ
**G1 — trích dẫn `PurchaseEvaluationConfiguration.cs:84` CHÍNH XÁC ĐẾN DÒNG:** `b.HasQueryFilter(x => !x.IsDeleted);`
nằm đúng dòng 84. (Đã kiểm bằng cách đọc file, không tin lời spec.)
**G2 — `decimal(18,2)` đúng quy ước tiền tệ của repo:** `PurchaseEvaluationConfiguration.cs:23-30`
(`HasColumnType("decimal(18,2)")` cho các cột ngân sách/giá).
**G3 — "loose-Guid không FK vật lý sang PE/Supplier/Project" là quy ước THẬT, không phải suy diễn:**
`PurchaseEvaluation.cs:16` (comment `WorkItemId` — *"scalar loose-Guid (KHÔNG navigation, KHÔNG FK vật lý —
convention PE giống ProjectId/SelectedSupplierId)"*) + `PurchaseEvaluationConfiguration.cs:59-61`
(*"index lọc query, KHÔNG HasOne/FK vật lý (convention PE: chỉ ApprovalWorkflowId có FK)"*) + `:72-73`
(FK duy nhất ra ngoài module là `ApprovalWorkflowId`, `DeleteBehavior.Restrict`).
**G4 — bảng #4 mirror ĐÚNG 100% khuôn `ContractLevelOpinions`:** FK Cascade phiếu
(`ContractLevelOpinionConfiguration.cs:25-27`) + FK **Restrict** Level (`:30-32`) + UNIQUE `(phiếu, Level)` (`:34`)
+ `Comment` 2000 (`:21`). Đây là phần chắc tay nhất của §②.2. *(Kèm nghĩa vụ H2 — chọn Restrict thì phải vào 3 site admin.)*
**G5 — `PeReferenceAmount` snapshot: BÁC phương án "đọc live", giữ snapshot.** Ba căn cứ:
(i) tiền lệ cùng repo — `ApprovedPriceAmount` (`PurchaseEvaluation.cs:97`) và 11 cột `ApprovedBudget*`
(`:122-132`, Mig 67) đều là ảnh chụp tại thời điểm chốt;
(ii) nguồn live **biến động được dưới chân phiếu KHKK**: cờ F3 `AllowApproverEditDetails` cho người duyệt sửa
Hạng mục/NCC/Báo giá lúc đang duyệt (`ApprovalWorkflowLevel.cs:127-129`), cờ F6 `AllowApproverDelete` cho xoá
mềm phiếu (`:156-169`) — mà phiếu PE xoá mềm thì `HasQueryFilter` làm số live **biến mất**, snapshot thì còn;
(iii) spec **đã tự cài máy dò lệch** ở §2.5(a) (ghi ContextNote *"giá KH x vs SUM-PE y"*) ⇒ snapshot không
biến thành số mồ côi không ai đối chiếu.
**G6 — "KHÔNG thêm cột `SigningPlanId` lên PE" là quyết định ĐÚNG** (tra ngược bằng `Plans.Where(PeId == x)`);
đây đúng là lớp lỗi cột-phái-sinh-kẹt-stale (gotcha #81, `docs/gotchas.md:1343`).
**G7 (câu e, vế 2) — `ApplicableType = 10` TRỐNG THẬT, xác nhận bằng đọc mã chứ không bằng lời spec:**
`ApprovalWorkflow.cs:53-67` — enum dừng ở `TravelRequest = 9`, không có giá trị 10. Quét cả `src/` với mẫu
`= 10,` chỉ ra **một** kết quả duy nhất và nó thuộc enum KHÁC: `PurchaseEvaluationPhase.cs:24` `ChoDuyet = 10`.
⇒ Claim của spec ĐÚNG, append-only an toàn.
## Enum — điểm HIGH riêng
**E1 [HIGH] — `ContractSigningPlanPhase = 1/2/3/98/99` là bộ số THỨ BA, và nó đụng đúng khuôn FE mà §2.4 bắt copy.**
Repo đang sống hai quy ước:
- Họ PE/Contract: `PurchaseEvaluationPhase.cs:24` `ChoDuyet = 10` (+ TraLai 98 / TuChoi 99).
- Họ Office/Proposal — **chính là khuôn FE spec chọn** (§2.4: *"khuôn bộ Proposal ~978 LOC/app"*):
`Office/Enums.cs:17-24` `ProposalStatus { Nhap=1, DaGuiDuyet=2, TraLai=3, TuChoi=4, DaDuyet=5 }`
`:29-36` `WorkflowAppStatus` y hệt, **dùng chung cho 5 module** (LeaveRequest + OtRequest + TravelRequest +
VehicleBooking + ItTicket — `:27`).
Va chạm cụ thể, đo được: **giá trị 3** = `DaDuyet` ở enum mới, nhưng = `TraLai` ở khuôn FE Proposal đang được
copy. Bảng map badge/nhãn trạng thái copy nguyên si sẽ **render sai mà không có lỗi biên dịch** — đúng lớp
"xanh-giả". Lý do spec đưa (*"giữ 98/99 cho quen mắt FE badge"*) chỉ đúng với FE PE/Contract, **không đúng với
FE khuôn đã chọn**.
⇒ Hai lối ra, chọn 1 và ghi vào spec: (a) dùng đúng bộ `WorkflowAppStatus` 1-5 (hết va chạm, thêm cơ hội tái
dùng chip/badge có sẵn), hoặc (b) giữ 1/2/3/98/99 nhưng **khai nghĩa vụ viết lại toàn bộ map trạng thái** khi
copy trang Proposal, kèm 1 dòng kiểm ở checklist wave.
<!-- END · TOTAL=22 DIEM · VERDICT=GO-WITH-FIXES (5 HIGH chặn Wave 1) -->

View File

@ -0,0 +1,288 @@
# LĂNG KÍNH 1/4 — WAVE-PLAN + ACCEPTANCE (reviewer đối kháng)
> Đích chấm: `spec-ke-hoach-ky-ket-hd-28-07-2026.md` §③ (dòng 208-340).
> Đối chứng: `runs/2026-07-27-S155-pe-delete-approver/run.md` (tiền lệ chia 2 đợt đã chạy THẬT).
> 4 trục: (a) acceptance đo được thật? (b) wave deploy độc lập thật? (c) thứ tự? (d) cờ CHẶN sai?
> Ký hiệu chứng: `spec:NNN` = dòng trong file spec; `run.md:NNN` = tiền lệ S155; còn lại là đường dẫn thật trong repo.
## Verdict
**SUA-TRUOC-W1** — khung 5 wave đúng hướng và phần lớn acceptance có hình dạng đo được, **nhưng W1 và W2 chưa
deploy độc lập được như bảng khai**, và 4 phép đo trụ cột (policy · OR-of-N · test-count · dark-launch) hiện
**không thể làm cho trượt** kể cả khi implement sai. 19 điểm: **6 HIGH · 8 MED · 5 LOW** (+ 9 điểm củng cố).
Sửa 6 HIGH là spec đủ răng để phóng W1.
---
## Điểm HIGH
### H1 — W2 đẩy riêng lên prod thì **không tạo được phiếu nào**: phần wiring Designer type-10 không nằm trong wave nào
- **Chứng:** `spec:141` lệnh Create nhận `ApprovalWorkflowId` bắt buộc; `spec:143-144` validator đòi workflow có
`ApplicableType == ContractSigningPlan` (=10). `spec:192-194` khai phải sửa **Designer admin nhận type 10**
(`fe-admin/.../ApprovalWorkflowsV2Page.tsx:143` + `ApprovalWorkflowV2AdminFeatures.cs`, và phải grep lại đường
`fe-user` matrix). Nhưng danh sách file của **W1** (`spec:227-229`), **W2** (`spec:245-246`), **W3**
(`spec:265-266`) đều **không chứa 2 file đó**.
- **Hệ quả đo được:** sau khi deploy W2, admin không dựng nổi 1 `ApprovalWorkflow` type 10 ⇒ mọi `POST` đều rơi
validator ⇒ **acceptance W2#1 (`spec:248`, "→ 201") không thể đạt** trên chính prod mà nó vừa lên.
- **Đây đúng lớp lỗi tiền lệ:** `run.md:125`*"F.0 chứng minh A-E không chạy nếu thiếu F"*, tức đợt-1-một-mình
vô dụng. Spec trích đúng bài học đó ở `spec:210-211` rồi lặp lại nó ở W2.
- **Đề xuất:** đưa wiring type-10 (BE `ApprovalWorkflowV2AdminFeatures.cs` + fe-admin Designer + grep lại fe-user)
vào **W1**, và thêm acceptance W1: *admin tạo + lưu 1 quy trình type 10 →
`sqlcmd -Q "SELECT COUNT(*) FROM ApprovalWorkflows WHERE ApplicableType=10"` trả về `1`*. Việc này đồng thời
biến W1 từ "0 giá trị" thành "nền + dựng được quy trình" (xem C1 ở mục thứ tự wave).
### H2 — Tên policy trong spec **không khớp** menu key của chính spec ⇒ test hiện có sẽ ĐỎ, và trên prod là **500** chứ không phải 403
- **Chứng lệch:** `spec:181` chốt 4 key = `Csp` / `Csp_List` / `Csp_Create` / `Csp_Inbox`. `spec:173-174`
`spec:234` lại dùng policy = `ContractSigningPlans.{Read|Create|Update|Delete}`. Chính spec khai luật sinh
policy là `{menuKey}.{action}` (`spec:175`, foreach `All × Actions`) ⇒ với key `Csp` thì policy hợp lệ là
`Csp.Read`, **không tồn tại** `ContractSigningPlans.Read`.
- **Repo đã có lưới bắt đúng ca này:**
`tests/SolutionErp.Infrastructure.Tests/Api/AuthorizePolicyRegressionTests.cs:138-139`
`MenuKeys.All.Should().Contain(parts[0], $"policy \"{policy}\" của {action} trỏ menu key KHÔNG có trong MenuKeys.All ⇒ Program.cs không sinh policy đó ⇒ 500 lúc chạy (bẫy Pe_* trong spec S155 §B3)")`.
⇒ code theo `spec:173` sẽ làm test này **đỏ**, và nếu lọt thì runtime ném lỗi policy-không-đăng-ký (**500**),
không phải 403 như W2#5 kỳ vọng.
- **Đề xuất:** chốt **một** tên canonical trước khi phóng W1 (khuyến nghị giữ key ngắn `Csp` ⇒ policy `Csp.Read`
…, hoặc đổi key thành `ContractSigningPlans*` cho khớp tên dài) và ghi vào bảng hợp-đồng-liên-lane (M4).
Đây là **đúng lớp `hợp-đồng-đứt-giữa-2-bờ`** của S155: hai bờ đều "hợp lý" khi đọc riêng, chỉ chết lúc nối.
### H3 — W1 acceptance #4 đo một thứ **không tồn tại trong DB**; đó lại là dòng duy nhất canh phần authz của W1
- **Chứng:** `spec:234`*"`sqlcmd` đếm policy: `|MenuKeys.All| × 4` tăng đúng **+16**; grep
`ContractSigningPlans.Read` có trong list policy"*. Policy được đăng ký **in-memory** trong
`Program.cs` (`AddAuthorization`, chính spec khai ở `spec:175`); DB chỉ có bảng `MenuItems``Permissions`.
**Không có bảng policy nào để `sqlcmd` đếm**, cũng không có artifact "list policy" để grep.
- **Mức độ:** W1 chỉ có 6 dòng acceptance, phần authz gói trọn trong dòng này ⇒ nếu 4 key vào nhầm chỗ
(đúng bẫy `Pe_*``spec:182-183` vừa cảnh báo), **không phép đo nào của W1 phát hiện được**.
- **Con số thì đúng:** `docs/STATUS.md:453` Menu keys = **54** ⇒ 54×4 = 216 → 58×4 = 232 = **+16**. Lỗi nằm ở
**cách đo**, không ở số.
- **Đề xuất:** thay bằng 3 phép chạy được — (i) `dotnet test --filter AuthorizePolicyRegression` PASS;
(ii) `grep -c "MenuKeys.Csp" src/Backend/SolutionErp.Domain/Identity/MenuKeys.cs` trong khối `All` = 4;
(iii) 2 row canonical `docs/STATUS.md` bump `54→58``216→232` cùng commit.
### H4 — Phép "OR-of-N" của W3 **không chứng minh OR-of-N** (3 lỗ, trong đó 1 lỗ khiến service *không guard gì* cũng PASS)
- **Chứng:** `spec:268-269`*"workflow 1 Bước có 1 Cấp 2 người → **người thứ hai** duyệt được và phiếu **tiến
sang Bước kế** (không đòi cả 2 ký)"*.
- **Lỗ 1 (tự mâu thuẫn):** workflow **1 Bước** thì **không có "Bước kế"** — duyệt xong phải sang `DaDuyet`.
Người chạy acceptance sẽ hoặc bỏ vế sau, hoặc kết luận FAIL trên bản đúng.
- **Lỗ 2 (trúng may):** dưới đúng bug Proposal mà `spec:100-101` mô tả (`SelectMany` flatten +
`ElementAtOrDefault(order-1)` lấy **1 row**), trong 1 cấp 2 người thì **đúng một người** duyệt được. Nếu người
đó tình cờ là "người thứ hai" theo thứ tự flatten, **phép thử PASS trên implement hỏng**. Nhãn "người thứ hai"
cũng không định nghĩa (thứ tự tạo? thứ tự UI? thứ tự `Order` trong DB?).
- **Lỗ 3 (thiếu ca âm):** một service **bỏ hẳn guard approver** (ai cũng duyệt được) cũng PASS dòng này ⇒ phép đo
cho **0 bit** thông tin về authz. Đây đúng "phép 2-thế-giới": còn-guard và bỏ-guard cho cùng kết quả.
- **Đề xuất (thay nguyên dòng #1):** hai phiếu song sinh cùng workflow (1 Bước, 1 Cấp, người A + người B):
(i) phiếu-1 **chỉ A ký**`Phase=DaDuyet`; (ii) phiếu-2 **chỉ B ký**`Phase=DaDuyet`;
(iii) mỗi phiếu `SELECT COUNT(*) FROM ContractSigningPlanLevelOpinions WHERE PlanId=@id` = **1** (không đòi 2 chữ ký);
(iv) **ca âm bắt buộc:** người C ngoài Cấp `POST {id}/transitions`**403**, và `Phase` không đổi.
Thêm 1 ca 2-Bước để vế "tiến sang Bước kế" có đối tượng thật.
### H5 — Lưới test rỗng ở đúng hai wave cần răng nhất; W2 **không có dòng `dotnet test` nào**
- **W1 (`spec:233`):** *"562 PASS **giữ nguyên**, 0 fail (chưa có test mới)"* — W1 không thêm test, không chạm
bảng mới ⇒ tiêu chí này chỉ là regression-guard, **0 bit** về việc W1 làm đúng. Tệ hơn: nó còn là **kỳ vọng
sai** nếu code theo `spec:173` (xem H2) vì `AuthorizePolicyRegressionTests` sẽ đỏ ⇒ người chạy sẽ tưởng mình
làm hỏng thứ khác.
- **W3 (`spec:280`):** *"562 + **N mới**, 0 fail"* — `N` thả tự do ⇒ **N = 0 vẫn PASS**. Trong khi rủi ro tự khai
của chính W3 (`spec:281`) là *"copy nhầm Proposal ⇒ mất OR-of-N **âm thầm** (build sạch, test cũ vẫn xanh)"*.
Tiêu chí duy nhất có thể bắt lại đúng là tiêu chí không có sàn.
- **W2 (`spec:247-256`):** 7 dòng acceptance, **không dòng nào chạy `dotnet test`** — dù W2 chính là wave đẻ
controller + policy, tức đúng thứ mà `AuthorizePolicyRegressionTests` canh.
- **Đề xuất:** W1 = *"562 PASS **và** `AuthorizePolicyRegression` xanh"*; W2 = thêm `dotnet test` với **≥3 test
mới có tên** (Create-happy · 409-trùng-PE · 400-PE-chưa-DaDuyet); W3 = pin **N ≥ 6****liệt tên** (OR-of-N ×2
chiều · ca âm 403 · con-trỏ đôi · finalize · inbox 2 vế).
- **Ghi công bằng:** con số **562 là ĐÚNG canonical**`docs/STATUS.md:642` ghi *"test 532→562"* cho đợt PE
nút-xóa. Lỗi ở **dạng tiêu chí**, không ở con số.
### H6 — "Dark-launch, vô hình với user" **sai trên fe-admin**, và phép đo #5 sẽ trượt trên bản làm đúng
- **Chứng cơ chế (đo trên đĩa):**
`src/Backend/SolutionErp.Application/Permissions/Queries/GetMyMenuTree/GetMyMenuTreeQuery.cs:86-102`
`IsVisible` chỉ được **bơm vào DTO** (`:88`), còn **bộ lọc cuối chỉ theo `CanRead`** (`:96-100`,
`static bool HasAccess(MenuNodeDto n) => n.CanRead || n.Children.Any(HasAccess)`). Không có mệnh đề nào lọc
`IsVisible`.
`src/Backend/SolutionErp.Application/Permissions/Dtos/MenuDtos.cs:13` ghi thẳng:
*"`IsVisible = false` → ẩn khỏi response `/menus/me` FE-user, **fe-admin vẫn thấy**"* (cùng nội dung ở
`src/Backend/SolutionErp.Domain/Identity/MenuItem.cs:12`).
- **Hệ quả 1 (phép đo sai):** `spec:235`*"`GET /api/menus` không chứa `Csp`"***API vẫn trả node `Csp`**
(kèm `isVisible=false`) vì việc ẩn nằm ở phía FE. Bản implement đúng sẽ **trượt** dòng acceptance này.
- **Hệ quả 2 (cờ deploy sai):** `spec:215` khai W1 *"Deploy riêng được ✅ (vô hình với user)"* — nhưng
**fe-admin cố ý bỏ qua cờ**, mà admin chính là người UAT. Sau W1, admin thấy 4 mục menu tiếng Việt trỏ vào
route chưa tồn tại (routes tới **W2**, `spec:246`) ⇒ **4 mục menu chết** trên prod.
- **Đề xuất (chọn 1):** (a) **dời 4 dòng seed menu sang W2**, W1 chỉ giữ `MenuKeys` + policy + schema ⇒ dark thật,
không phụ thuộc cơ chế `IsVisible`; hoặc (b) giữ nguyên nhưng sửa acceptance thành *"`GET /api/menus/me` trả
node `Csp` với `isVisible=false`; fe-user KHÔNG render; **fe-admin CÓ render** — chấp nhận admin thấy mục chết
trong 1 nhịp deploy"* và sửa cột "Deploy riêng được" của W1 thành ✅*(trừ fe-admin)*.
---
## Điểm MED
### M1 — W1 khai "❌ không chặn" nhưng thực chất **đóng băng 2 quyết định của owner** vào migration
`spec:126` — format mã *"`KHKK/{YYYY}/{Seq:D3}` — **owner chốt format**"*; `spec:128-129` — *"biến thể tối thiểu
5 bảng … nếu owner muốn cắt, cắt #7 trước"*. Cả hai đều nằm **trong** phạm vi Mig 69 của W1 (`spec:227-229`),
trong khi bảng `spec:215` ghi *"Chặn bởi owner? ❌ không"*. Đổi ý sau khi Mig 69 lên prod = tốn Mig 70
(DropTable / đổi format mã). Ở W1 bảng còn rỗng nên chi phí chưa cao, nhưng sau W2 (đã có dữ liệu) thì đắt.
**Đề xuất:** cột chặn của W1 = ⚠️ (2 câu: 7-hay-5 bảng · format mã), hỏi owner **trước** khi phóng W1.
### M2 — W3 khai *"chạy được với mặc định"* nhưng acceptance **ép làm cả 3 đường**
`spec:217`: *"⚠️ Q3 (chọn cơ chế rẽ b.12) — nhưng chạy được với mặc định"*`spec:273-274`: *"Test cả **3 đường**
tới `DaDuyet` (thường · `AllowApproverFinalize` · `CeoApprovalThreshold`)"*. Nếu thật sự chạy mặc định thì 2/3
dòng acceptance **không có đối tượng để đo**; nếu phải làm cả 3 thì Q3 **đang chặn** chứ không phải cảnh báo.
**Đề xuất:** cắt acceptance về đường thường (W3a) + đẩy 2 nhánh kết-thúc-sớm sang W3b, **hoặc** đổi cờ W3 thành ✅ Q3.
### M3 — Spec port đúng 2 cơ chế mà owner **vừa phán "PHÁ VỠ"** ở tiền lệ, và không nhắc lại phán quyết đó
`run.md:114-115` (bảng *OWNER CHỐT — LƯỢT 3*): *"Cờ F5 `AllowApproverFinalize` → **PHÁ VỠ**"*,
*"`CeoApprovalThreshold` → **PHÁ VỠ**"* — đối lại `run.md:116` *"`Step.DepartmentId` → **AN TOÀN**"*.
Spec `spec:159-160` (§2.3 mục 2) lại **port cả hai** vào module mới, còn `spec:273` **ép test cả hai**.
**Tôi không suy được câu hỏi gốc từ một ô hai chữ** — có thể "phá vỡ" chỉ áp cho bất-biến của việc xóa-khi-duyệt
ở S155. **Đề xuất:** trích nguyên văn câu hỏi S155 vào spec trước khi code; nếu "phá vỡ" nói về bất-biến duyệt thì
đây là **chép nợ có chủ đích** và phải khai trong wave.
### M4 — Thiếu **bảng hợp-đồng-liên-lane**, đúng thứ tiền lệ dựng ra sau khi bị cắn
`run.md:135-137`: *"HỢP-ĐỒNG LIÊN-LANE — chốt TRƯỚC khi phóng (bài học đợt 1: **2 nửa build sạch mà không nối
được**) … Lệch một ký tự = silent drop, cả hai build vẫn xanh"*, kèm bảng canonical route API / menu key / route FE.
Spec §③ giao W2 cho `implementer-backend` + `implementer-frontend` + `test-specialist` (`spec:243-244`) mà
**không có bảng đó** — và H2 chính là **ca lệch tên đã xảy ra ngay trong spec**.
**Đề xuất:** thêm bảng canonical: route `/api/contract-signing-plans` (kebab, khuôn `/api/purchase-evaluations`
`run.md:142`) · 4 menu key · 4 policy · 3 route FE · tên field DTO mà FE đọc (`peReferenceAmount`,
`proposedAmount`, `approvedAmount`).
### M5 — Rủi ro được kê nhưng **không dòng acceptance nào bắt được**
- W2 `spec:257-258` kê 2 rủi ro: quên `HasQueryFilter(!IsDeleted)` ⇒ phiếu xóa mềm vẫn hiện; UNIQUE filtered thiếu
`WHERE IsDeleted=0` ⇒ chặn oan (gotcha #57). 7 dòng acceptance `spec:248-256` **không dòng nào chạm** 2 rủi ro này.
- W1 `spec:237` kê rủi ro *"seed-permission có >1 site (S155)"* — dòng đo gần nhất là #4, mà #4 đã hỏng (H3).
Tiền lệ ghi rất rõ điều này: `run.md:163`*"thêm key vào **CẢ HAI** danh sách permission seed `:2092-2096`
**và** `:2492-2496`"*.
**Đề xuất:** W2 thêm 2 dòng — (i) xóa mềm 1 phiếu → `GET /list` **không còn****và** `sqlcmd` thấy row
`IsDeleted=1`; (ii) xóa rồi tạo lại đúng cặp `(PlanId, SupplierId)`**201**, không 409. W1 thêm: `grep -n`
đếm site seed-permission = **2** (hoặc số thật) và cả hai đều có 4 key mới.
### M6 — `DELETE` **không thuộc wave nào**; cộng với guard 409 thì W2-một-mình **khoá cứng** PE tạo nhầm
`spec:177` khai endpoint `DELETE {id}` (allow-list `DangSoanThao|TuChoi`), nhưng file-list W2 (`spec:245`) chỉ có
*"Create/Update/Get/List + DossierItem CRUD + attachment"*, và W3 (`spec:265`) không nhắc. Trong khi `spec:143`
quy định chỉ cho tạo lại *"sau `TuChoi`"* — mà `TuChoi` chỉ đến được qua endpoint `transitions` của **W3**.
⇒ Trên prod chỉ-W2: một phiếu tạo nhầm là **không xóa được, không từ chối được**, và PE đó **vĩnh viễn không có
phiếu đúng**. Đây là "nửa tính năng chết" theo đúng định nghĩa mà `spec:210` đặt ra.
**Đề xuất:** đưa `DELETE {id}` vào **W2** + acceptance *"tạo → xóa → tạo lại cùng PE = 201"*.
### M7 — Ba phép đo của W3 sai phạm vi hoặc mơ hồ tới mức bản đúng cũng trượt
- `spec:270-271` *"sau mỗi lượt duyệt, `CurrentWorkflowStepIndex` **và** `CurrentApprovalLevelOrder` **đều đổi
đúng**"* — sai theo nghĩa đen: tiến từ Cấp 1 → Cấp 2 **trong cùng một Bước** thì `StepIndex` **không đổi**
(đó mới là hành vi đúng của con-trỏ đôi). **Đề xuất:** bảng kỳ vọng từng lượt, ví dụ 3 Bước × 2 Cấp:
`(0,1) → (0,2) → (1,1) → (1,2) → (2,1) → (2,2) → DaDuyet`.
- `spec:272-273` *"`sqlcmd COUNT(*) WHERE ApprovedAmount IS NULL` = 0"* — **thiếu `AND PlanId=@id`**: mọi phiếu
nháp hợp lệ đều có `ApprovedAmount = NULL` (`spec:121` ghi *"chỉ ghi tại finalize"*) ⇒ chỉ cần tồn tại 1 nháp là
phép đo **luôn khác 0** ⇒ FAIL giả vĩnh viễn.
- `spec:277` *"duyệt 2 lần cùng cấp → DB 1 row"* — không nêu **ai** duyệt lần 2; theo OR-of-N, sau lượt đầu thì cấp
đã qua nên người thứ hai bị chặn ⇒ **kịch bản có thể không dựng được**. **Đề xuất:** nêu rõ actor (Admin duyệt-thay
/ cùng một người bấm lại) + trạng thái phiếu tại thời điểm bấm.
### M8 — Acceptance W5 **mâu thuẫn với chính thiết kế §2.5**, và sai theo hướng **phóng đại tiền**
`spec:199` (thiết kế): *"`giaTri = line.ApprovedAmount` **khớp `w.SupplierId`** thay `SUM` `:88-90`"* — tức
**per-winner**. `spec:298` (acceptance): *"`GiaTri == SUM(ApprovedAmount)`"* — tức **cộng mọi dòng**. Với PE
liên-danh nhiều winner (Mig 58 multi-winner), code theo acceptance sẽ nhét **tổng giá của tất cả NCC** vào **từng**
hợp đồng. Direction-of-error là phóng đại giá trị HĐ ⇒ không phải lỗi làm tròn.
**Đề xuất:** sửa acceptance thành *"HĐ của NCC X → `GiaTri == ApprovedAmount` của đúng Line `SupplierId = X`"* +
1 ca 2-winner để phân biệt hai công thức.
---
## Điểm LOW
### L1 — Hai lệnh của W1 không chạy đúng như viết
`spec:231` *"`dotnet ef migrations list` → `69_AddContractSigningPlans` ở cuối"* — EF in ra
`20260728xxxxxx_AddContractSigningPlans`, **không có tiền tố `69_`**; số 69 chỉ là cách đánh số trong tài liệu.
`spec:236` *"`dotnet ef migrations script 68 69`"* — tham số là **tên** migration, không phải số thứ tự.
`spec:236` *"chạy sạch"* cũng thiếu kỳ vọng (0 lỗi + số bảng quay lại mốc cũ).
*(Số **69 là đúng**: file mới nhất trên đĩa `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/20260727033522_AddPeAllowApproverDelete.cs` = Mig 68 theo `docs/STATUS.md:642`.)*
**Đề xuất:** kỳ vọng theo tên + `sqlcmd -Q "SELECT TOP 1 MigrationId FROM __EFMigrationsHistory ORDER BY MigrationId DESC"`.
### L2 — Phép đếm bảng lệch vị-ngữ so với canonical và không nêu đo trên DB nào
`spec:232` dùng `SELECT COUNT(*) FROM sys.tables`; canonical `docs/STATUS.md:448` dùng
`sys.tables` **`is_ms_shipped=0`** (cicd Run #482 LIVE = **89**). Hai vị ngữ có thể lệch nhau, và acceptance không
nói đo trên **prod** hay **LocalDB Dev** (Dev hay lệch do migration chưa apply).
*(Con số 89 **đúng và chưa trôi** — đo: 6 migration mới nhất `20260706 → 20260727` đều **0 `CreateTable`, 0 `DropTable`**.)*
**Đề xuất:** chép nguyên vị ngữ canonical + ghi rõ DB đích + giữ **delta +7** làm bất-biến chính.
### L3 — "SHA256 3 file mirror IDENTICAL" không nêu **3 file nào**, và mâu thuẫn quy ước 2 app
`spec:255` ⟂ quy ước *"duplicate giữa 2 app là CÓ CHỦ ĐÍCH, mỗi app UX riêng"*`spec:189` (page của 2 app khác
nhau về nội dung). Tiền lệ chỉ áp mirror byte cho **đúng 1 component**: `run.md:166` — *"`PeWorkflowPanel.tsx`
phải giữ md5 giống nhau ×2 app"*.
**Đề xuất:** nêu đích danh file phải giống byte (`lib/menuKeys.ts` + `types/contractSigningPlan.ts`), bỏ page.
### L4 — W2#5 không nêu tài khoản nên "user thiếu quyền" là biến tự do
`spec:253`. **Đề xuất:** ghi rõ 2 tài khoản (ví dụ `nv.test@solutions.com.vn` = thiếu quyền → **403**;
`admin@solutions.com.vn` = có quyền → **201**), vì kết quả 401-vs-403 phụ thuộc token hợp lệ.
### L5 — Đánh số W4/W5 ngụ ý thứ tự không có thật
Cả hai chỉ phụ thuộc W3, **không phụ thuộc nhau**; và W5 mới là khúc nghiệp vụ b.12→13 mà `spec:1` đặt làm đề bài,
còn W4 là siết chất lượng. **Đề xuất:** ghi *"W4 ⟂ W5 — chạy theo thứ tự anh trả lời câu hỏi"*, tránh việc
implementer coi W4 là điều kiện tiên quyết của W5.
---
## Thứ tự wave — trả lời trực tiếp câu (c)
- **C1. W1 hiện KHÔNG phải "rẻ nhất mà đã có giá trị" — nó rẻ và có giá trị bằng 0** *(MED, đã tính trong M1/H1)*.
`spec:225` tự khai mục tiêu *"không đổi gì người dùng thấy"*. So với tiêu chuẩn thật của tiền lệ —
`run.md:125` *"đợt 1 xong là **UAT được ngay**, biết chắc nền đúng trước khi xây tiếp"* — W1 **không UAT được**.
Nó chỉ thoả tiêu chí yếu *"không để nửa tính năng chết"* bằng cách không giao gì cả.
**Đề xuất gộp 2 việc:** kéo wiring Designer type-10 (H1) vào W1 ⇒ W1 thành *"nền + admin dựng được quy trình
type 10"*, UAT được ngay bằng 1 phép thật (tạo quy trình, thấy nó trong dropdown), và **mở khoá W2**.
- **C2. Nên tách W3 làm hai** *(MED, cùng gốc M2)*: **W3a** = advance + OR-of-N + inbox precompute + panel FE +
`TraLai` toàn phần (chính `spec:162` đã chừa đường *"tối thiểu `TraLai` toàn phần nếu muốn gọn wave đầu"*) —
đủ để phiếu chạy trọn vòng, deploy được. **W3b** = 2 nhánh kết-thúc-sớm + 4 return-mode + notify approver.
Lý do: W3 hiện gánh 8 dòng acceptance và 3 cơ chế rủi ro cao trong một lần deploy; nếu vỡ thì không truy được
vỡ ở nhánh nào.
- **C3. Không nên gộp W1 với W2** *(giữ nguyên)*: migration cần `database-agent` review trước khi apply
(`spec:226`), và blast radius của Mig 69 là 7 bảng mới — tách ra vẫn đúng.
---
## Cờ CHẶN — trả lời trực tiếp câu (d)
| Wave | Spec khai | Đánh giá | Chứng |
|---|---|---|---|
| W1 | ❌ không chặn | 🔴 **SAI — đang chặn** | `spec:126` format mã *"owner chốt"* + `spec:128-129` 7-hay-5 bảng; cả hai đóng băng vào Mig 69 (M1) |
| W1 | ✅ deploy riêng, *"vô hình với user"* | 🔴 **SAI một nửa** | fe-admin cố ý bỏ qua `IsVisible` (`MenuDtos.cs:13`), query không lọc (`GetMyMenuTreeQuery.cs:96-100`) (H6) |
| W2 | ✅ deploy riêng *"bật menu, tạo được phiếu"* | 🔴 **SAI — tạo được 0 phiếu** | thiếu wiring type-10 ở mọi wave (H1) + `DELETE` vô chủ (M6) |
| W3 | ⚠️ Q3 *"chạy được với mặc định"* | 🟠 **Nhẹ hơn thực tế** | acceptance ép cả 3 đường (M2) |
| W4 | ✅ chặn O-Q1, O-Q2 | 🟢 **ĐÚNG** | `spec:287-289` — và acceptance cũng khai rõ *"khi có câu trả lời"* |
| W5 | ✅ chặn Q6, Q11 + xin phép chạm HĐ | 🟢 **ĐÚNG** | `spec:295` neo đúng lệnh owner *"chỗ hợp đồng cứ từ từ"* |
Ghi chú W4: nếu O-Q2 chốt *"số hoá thành checklist"* thì W4 **đẻ thêm schema** (bảng/cột checklist) — mà §2.2 chỉ
thiết kế 7 bảng, không có chỗ cho nó ⇒ chi phí W4 hiện **chưa bị chặn trên**. Nên ghi thẳng: *"nếu O-Q2 = số hoá
⇒ W4 kèm Mig 70"*.
---
## Điểm CỦNG CỐ
1. **Số 562 đúng canonical**`docs/STATUS.md:642` *"test 532→562"*. Không phải số bịa; phê bình của tôi ở H5
nhắm vào **dạng tiêu chí**, không nhắm con số.
2. **Số 89 bảng đúng và chưa trôi**`docs/STATUS.md:448` (re-ground S97, `sys.tables is_ms_shipped=0`, Run #482
LIVE = 89); tôi kiểm lại 6 migration mới nhất (`20260706 → 20260727`) đều **0 `CreateTable` / 0 `DropTable`**
⇒ mốc 89 vẫn sống ở Mig 68. Delta **+7** khớp đúng "7 CreateTable" của §2.2.
3. **Mig 69 là số đúng** — file mới nhất trên đĩa là `20260727033522_AddPeAllowApproverDelete` = Mig 68.
4. **Phép tính +16 policy đúng số học** — 54 key (`docs/STATUS.md:453`) × 4 → 58 × 4 = 232.
5. **`spec:182-183` bắt đúng khác biệt sống-còn** giữa `Off_DeXuat` (**trong** `MenuKeys.All`) và `Pe_*` (factory,
**ngoài** `All` ⇒ không có policy). Đây chính là bẫy mà `AuthorizePolicyRegressionTests.cs:139` đặt tên — spec
nhận diện đúng nguồn, chỉ tự vấp ở khâu đặt tên (H2).
6. **§2.1 chặn bẫy Proposal có dẫn chứng dòng thật + lead tự đọc xác minh** (`spec:99-111`), và W3#1 tuy hỏng cách
đo nhưng **đặt lưới đúng chỗ** — đây là rủi ro số một của cả run.
7. **W2#5 (403 authz 2 tầng)** — phép chặn tái phát #82/S118, kèm câu *"bắt buộc chạy, không được bỏ"*
(`spec:253-254`). Hiếm thấy trong spec; giữ nguyên, chỉ thêm tên tài khoản (L4).
8. **W3#4 (inbox) có ĐỦ hai vế***"approver Cấp đang chờ **thấy**; approver cấp khác **không thấy**"*
(`spec:275-276`). Đúng kỷ luật hai-thế-giới; nên nhân bản chính kỷ luật này sang #1 (H4).
9. **Acceptance #6 của W1 đòi chạy `Down` thật trên DB copy** (`spec:236`, *"reversible thật, không chỉ nhìn code"*)
— phản chứng thật chứ không phải đọc code đoán; cùng hạng với `spec:135-136` (cấm thêm cột `SigningPlanId` chết)
`spec:132`/`spec:238` (verify enum slot 10 **và** buộc re-verify ngay trước khi viết).
10. **Provenance trung thực**`spec:193-194` khai thẳng claim của invest **không verify được** (fe-user matrix
grep 0 hit) và buộc grep lại; `spec:325-326` tách bạch **"đo thật"** (Proposal 4 bảng · 849 LOC BE · 1.956 LOC
FE) với **"ngoại suy"** cho 3 nhánh. Tôi **không đo lại** 3 số LOC trong lượt này — nhưng đường phản chứng có
tồn tại (`wc -l` trên file twin), nên nhãn "đo thật" là hợp lệ.
<!-- END · TOTAL=19 DIEM (6H/8M/5L + 10 cung-co) · VERDICT=SUA-TRUOC-W1 -->

View File

@ -0,0 +1,46 @@
# bookend-close-synthesis — S158 (phiên-LOGIC L7, window 5)
> Lead-written, VERIFIED. Dạng-1 phẳng. Phiên vào bằng `/tiep` ⇒ **không có bookend @open** ⇒ cả 5 vòng dồn vào closeout này.
## Verdict 10 vai
| Vòng | Vai | Verdict |
|---|---|---|
| V1 | `tooling-auditor` (H1) | `PASS_WITH_FLAGS — 3 finding` — 🔴 ring1 chấm **under-count**, mặt ① phải ≥2 |
| V1 | `harvest-curator` (H2) | `GATE-PASS-6 \| GATE-FAIL-0 — 6 finding` |
| V1-KIỂM | `ring1-audit` | `38 CLAIM — 29Đ/3T/6KC` |
| V2 | `lead-stale-auditor` | `6 FLAG` (2 HIGH) |
| V2 | `lead-gap-auditor` | `5 FLAG` (2 HIGH) |
| V2-KIỂM | `ring2-audit` | `11 CLAIM — 11Đ/0T/0KC` |
| V3 | `harness-eval` | `MIXED — 18 signal` |
| V3 | `harness-refine` | `1 ACTION — BÁC 9` |
| V3-KIỂM | `harness-audit` | *(dở — `#53`, đĩa 491 B lúc chấm; resume)* |
| Ctx | `ctx-audit` | `TRUOT — 13 điểm` |
| V4 | nén-ngủ | **`không-nhịp`** — `SHARD-PROBE pending=15 / nguong=15 ⇒ IM` |
## 3 kết quả nặng nhất
**① Mồi-ngầm: CHẤM ĐƯỢC — và MỒI ĐÃ RƠI.** `ctx-audit` grep theo nội dung: mồi còn sống 3 anchor trong `_mind` (kể cả gist MIND-1 **sống sót 2 lần nén**) nhưng **0 hit ở MIND-2/3/4 §D**, 0 dòng khai — trong khi khuôn "đóng-CÓ-KHAI" được dùng **đúng ở ca Q2 ngay bên cạnh**.
🔴 **Và defect gốc mà mồi cảnh báo thì CHƯA VÁ:** `session-start.md:285` + `session-end.md:159` **vẫn `git status --short`** làm post-wave assertion (mù 4 path hook); `grep "name-only origin/main"` trong harness doc = **0 hit**. Guard mù đó **vừa chạy đúng 2 lần trong chính phiên này**. ⇒ mồi rơi **đúng lúc thứ nó cảnh báo đang tái diễn**.
**② Ý mục D có một đường thoát không máy nào canh (n=2).** MIND-3 §D **11 ý** = 1 đóng-có-khai + 2 carry + **8 rơi im lặng**. Header `_mind:140` tự khai *"MIND-4 đã nhận lại các ý còn sống"***sai 8/10**; con-trỏ **chỉ sai chiều tệ hơn im lặng**. Cơ-chế: ý rời **§D (có nhãn, máy canh) → §C (không nhãn)** rồi biến mất; `mind-check` phụ-9 chỉ hỏi *"ý ĐANG ở D có nhãn chưa"*, không hỏi *"ý TỪNG ở D nay đâu"*.
Công bằng: cùng khuôn header ở MIND-2 **đúng 5/5** ⇒ hỏng ở **1 cửa quá tải (PAUSE-4)**, không phải khuôn hỏng.
**③ GHI ⟂ KIỂM hở đúng chỗ có răng nhất.** `session-end.md:162` hứa *"máy TRƯỚC vai (mind-check full + closed-check §6.3-bis)"* nhưng `:383` đặt closed-check **SAU khi ghi `_end`** = sau slot vai ⇒ phép nghiêm nhất của lớp mềm (GAP-#9) **không mắt độc-lập nào đọc**, chỉ lead — người bị chấm — đọc. Kèm **FLAG-3**: `@close KHÔNG có bước refresh `_mind`` ⇒ ≥9 spawn closeout không có chỗ vào mục E, mà trần 92,48% chặn MIND-5 ⇒ **L7 đóng với dòng-sống thủng trọn window-5** (cấu-trúc, tái mỗi phiên-logic).
## Vòng KIỂM tự bắt lỗi mình nhiều hơn bắt lỗi con-đo
`ring1` **3/4 falsify BROKE là lỗi của chính nó**: parse non-greedy dính bẫy `]`-trong-comment (**đúng cái H1 khai đã né** ⇒ H1 né THẬT) · `comm` lệch collation python⟂shell · quên nhánh DUAL-ACCEPT `harvest/*` làm orphan ra 9. Tự kết: *"2/2 lần đầu nghi con-đo đều là lỗi tao."*
`ctx-audit` tự đính-chính nháp đầu (chấm nhầm "máy sai mode") **trên đĩa** rồi mới trả.
`refine` bác lại con-ĐO **có căn cứ**: B1 mở **cả 11 file** → 11/11 có tem `on-behalf/M9` in-content ⇒ S7 là **proxy mtime đọc sai**.
## `#53` — 7/8 lane, và đối-chứng nội-phiên sạch đầu tiên
Ép ghi đĩa **không giảm** garble (3/3 vai bị ép vẫn garble) nhưng **đưa thiệt-hại về 0** (2.818 / 5.354 / 7.957 B nằm sẵn); 4 vai không ép **mất trắng**, phải resume. Xác nhận lần 5: chống `#53` = **thiết-kế artifact**, không phải prompt.
🔸 Câu garble **chứa finding thật** ×3: `ring1` (`run-chua-gom` 3→4 do chính lead scaffold folder giữa chừng — vi phạm C1) · `ring2` (gap FLAG-3 tự mâu thuẫn FLAG-2) · `harness-audit` (**3/9 INFORM flag đến từ chính sub-file của run này** = lưới tự sinh cờ cho mình).
## Số máy (đọc, không chạy lại — §L.b(k)(v))
`measure-agent-memory` 0/23 over-30KB · `memory-archive-gate` **A7 PASS 402/402** · `crystallized-backfill` hotload **616.610 B**, headroom **174.463 tok** · `nhip-no-probe` `light 5/6 deep 7/15 ok \| tran-bo-nho 0 \| run-chua-gom 3 \| pull-cach 6 ngay` · `distill-shard-probe` `15/15 ⇒ IM` · `governance-detectors` **TOTAL 44**, INFORM 7, self-match 0.
<!-- END · 10 VAI · 5 VONG (V4 khong-nhip) · 3 KET-QUA-NANG · #53 x8 · 0 MAT DU-LIEU O 3 VAI DUOC EP GHI DIA -->

View File

@ -0,0 +1,39 @@
# harness-audit return — S158 (trio nac 3/3, con KIEM)
> Vai tu ghi dan TRONG luc lam (chong #53). Chua ket thuc = chua co dong END.
## (i) PIN — fail-closed check
- `test -d .claude/workflows/runs/2026-07-28-S158-bookend-close/` = **TON TAI**
- `harness-eval-return.md` = **6852 B** (non-empty) OK
- `harness-refine-return.md` = **14075 B** (non-empty, khop cite lead 14.075 B) OK
- `run.md` = **2569 B** (non-empty) OK
=> KHONG tu-choi. Di tiep cham.
(dang lam — chua co verdict)
---
> ⚠️ Luot-1 GARBLE (#53 — con thu 8 cua closeout). Resume: ghi DIA tung muc TRUOC, return sau.
## (iv) RE-CHAY DOC-LAP — 6 instrument (yeu cau >=2)
| # | instrument | so tao tu chay | so con-DO cite | doi-chung |
|---|---|---|---|---|
| R1 | `measure-agent-memory.ps1` | roles **23** · l1 **285.659** · l2_verb **839.440** · l2_gist **274.745** · l2_idx **81.244** · over30k **0** | y het | **BYTE-EXACT 6/6** |
| R2 | `nhip-no-probe.ps1` | `NHIP-NO: kiem light 5/6 deep 7/15 ok \| tran-bo-nho 0 over-cap l2idx 0 over \| run-chua-gom 3 \| pull-cach 6 ngay` | y het | **BYTE-IDENTICAL chuoi** |
| R3 | `distill-shard-probe.ps1` | `SHARD-PROBE: pending=15 \| nguong=15 => IM` | y het | **BYTE-IDENTICAL** |
| R4 | `memory-archive-gate.ps1` (DRY) | pointer 102+5+46+41+44+55+5+56+28+20 = **402 resolved / 0 failed** | 402/402, 0 failed | **BYTE-EXACT** (tao tu cong 10 dong) |
| R5 | `crystallized-backfill.ps1` | hotload **623.260** · RANGE [155.815..207.753] · headroom **172.247** | 616.610 / [154.152..205.537] / 174.463 | 🔴 **LECH +6.650 B / 2.216 tok** — GIAI THICH DUOC, xem duoi |
| R6 | `governance-detectors.ps1` | TOTAL **43** · INFORM **9** · self-match **0** | TOTAL 44 · INFORM 7 · self-match 0 | 🔴 **LECH 1 / +2** — xem duoi |
### R5 lech — KHONG phai con-DO sai, la san-file DI CHUYEN giua 2 lan do
- Cite noi-tai NHAT-QUAN: 616610/4=154152 · 616610/3.0=205537 · 380000205537=**174463**. => con-DO chep dung so lead dan.
- Nguyen nhan lech: 2/6 hotload source bi GHI SAU khi con-DO do (`harness-eval-return.md` mtime **20:17**):
`docs/STATUS.md` mtime **20:42** · `docs/HANDOFF.md` mtime **20:44** (lead closeout).
- Huong phat hien KHONG doi, con XAU HON: thieu-hut vs target 210.000 tu **35.537** -> **37.753 tok**.
-**Bai:** so PASTE-lane co han su dung tinh bang PHUT trong chinh phien do. Con-DO khai "5/6 truc single-lane" la khai DUNG va day la bang chung.
### R6 lech — luoi TU SINH CO CHO CHINH NO (self-reference)
- INFORM-only 9 = tron bo net **C11** (H24 FLAG-khuon). Liet ca 9: S151×3 · S152×1 · S154×2 · **S158×3**.
- 🔴 **3/9 co INFORM tro thang vao chinh run-folder nay**: `sub-ctx-audit-close-S158.md` · `sub-harvest-curator-close-S158.md` · `sub-tooling-auditor-close-S158.md`.
- Tuc la: bookend @close vua DO vua SINH THEM co cho lan do ke tiep. Cung LOP citation-trap/self-reference (doc/artifact dinh-nghia mau bi chinh detector khop-mau bat).
- Luoi tu khai loai tru `.claude/workflows/runs` o 6 path self-exclusion, nhung net C11 VAN quet runs/ => **self-exclusion khong phu C11**. Day la lech giua loi-khai-loai-tru va pham-vi-quet THAT.

View File

@ -0,0 +1,68 @@
# harness-eval return — S158 (trio nấc 1/3, con ĐO)
> Lead scribe NGAY khi vai trả (§L.b(k)(iii) — vai không có Write/Edit, phiên chết là mất return).
> Return **CLEAN, 0 garble**.
**`HARNESS-EVAL: MIXED — 18 signal`**
## Provenance (vai tự khai TRƯỚC số — 2 lane KHÔNG cân nhau)
| lane | instrument | ai chạy |
|---|---|---|
| LIVE (vai chạy tươi) | `measure-agent-memory.ps1` — 23 row JSON per-role | vai |
| PASTE (lead dán, vai KHÔNG re-run per §L.b(k)(v)) | archive-gate · crystallized-backfill · nhip-no-probe · distill-shard-probe · governance-detectors | lead |
| KHÔNG CHẠY | `mfe-eval.ps1` (đúng caveat `read_only_scope`: nó GHI `.mfe-state.json`) | — |
🔴 Vai khai thẳng: **5/6 trục single-lane** ⇒ nó phán TRÊN số lead dán, **không chứng được số đó**.
## Bảng trục
| trục | số máy in | baseline | delta | verdict |
|---|---|---|---|---|
| L1 byte vs soft-cap | 0/23 over 30.720; max `tooling-auditor` **23.464** | soft 30720 · autoinject 25600 | 0 over cả 2 | **MIXED** (S10/S11) |
| L2 index cap | `cicd-monitor` **19.484 / 20.480 = 95,14%** (headroom **996 B**) | cap 20480 · measured 18.774 | **+710 (+3,78%)** | **REGRESSION** |
| pointer A7 | **402/402 resolved, 0 failed** | — | — | **HEALTHY** |
| headroom/backfill | hotload **616.610 B** · RANGE [154.152..205.537] · headroom **174.463 tok** | target 210.000 · hotload-S153 596.316 B | headroom **35.537 tok vs target** · hotload **+20.294 B (+3,40%)** | **REGRESSION** |
| nhịp H24 | `light 5/6 deep 7/15 ok` | 6 / 15 | khớp config | **HEALTHY** |
| trần bộ-nhớ probe | `0 over-cap l2idx 0 over` | — | 0 over **nhưng l2idx 95,14%** | **MIXED** (S4) |
| distill shard | `pending=15 / nguong=15 ⇒ IM` | min 15 | **đúng biên**, headroom 1 shard | **HEALTHY** |
| độ-giữ diary | ctx-verifier mtime 2026-07-27T15:41 · inv-codebase 2026-07-28T10:56 | — | **Δ = 0 B cả hai (2/2)** | **REGRESSION** |
| coverage baseline | LIVE **23 vai** | `measured` block **17 row** | **6 vai (26,1%) không baseline** | **REGRESSION** |
| pull-lag | `pull-cach 6 ngay` | **KHÔNG có key `pull_warn_days`** | nhánh `OVERDUE:pull` chết | **N/A máy hỏng** |
| MFE | KHÔNG CHẠY | — | — | **N/A** |
| detector TOTAL | **44** · INFORM 7 · self-match 0 | không có key baseline | không ratchet được | **N/A-baseline** |
| trục TUỔI | **0/6** instrument chạm | budget tự khai "CHUA CO MAY" | — | **N/A** |
## 18 signal (rút gọn — nguyên văn ở transcript)
1. **S1** headroom 174.463 < target 210.000 thiếu **35.537 tok**; ràng-buộc = headroom.
2. **S2** hotload **+20.294 B / ~2 ngày** so mốc ghi trong `tiep_reload._note` (596.316 B) sàn-file phình tiếp.
3. **S3** `cicd-monitor` l2_index **95,14%**, headroom **996 B**, vai TĂNG-mỗi-run; budget đã dặn "near cap gist-of-index or split".
4. 🔴 **S4** probe in `l2idx 0 over` **SẠCH** cạnh 996 B headroom probe đo **OVER**, không đo **NEAR** = mặt **Goodhart-flip**.
5. **S5** diary-0-delta **2/2 sub** phiên này xác nhận từ đĩa, khớp phát hiện lead.
6. **S6** **0/23** diary được ghi trong cửa-sổ S158; mtime mới nhất toàn roster = 2026-07-28T10:56 (~8,5h TRƯỚC khi 2 sub chạy).
7. 🔴 **S7** **11/23 diary chung ĐÚNG MỘT mtime `2026-07-26T15:49`** độ-tươi của gần nửa corpus đến từ **MỘT sự-kiện ghi hàng-loạt** (dạng on-behalf), không phải 11 lượt tự-ghi.
8. **S8** `measured{}` phủ **17/23**; 6 vai thiếu row: `ctx-audit · ctx-curator · ctx-verifier · ring1-audit · ring2-audit · ring4-audit`.
9. **S9** 17 row còn lại trôi nặng: lead-gap 3.691→**19.792 (+436%)** · lead-stale 3.332→**14.078 (+323%)** · test-spec +68,4% · tooling +38,7%. Mốc so hết dùng được.
10. 🔴🔴 **S10 — HAI THƯỚC LỆCH trên `reviewer` 19.049 B:** DƯỚI cap máy-soi (74,41% autoinject / 62,01% soft) nhưng TRÊN thước **tự-khai 17,1K** ghi trong chính diary vai. **Thước 17,1K KHÔNG tồn tại trong `memory-budget.json`** **0 instrument soi nó**. Áp thử 17,1K: **9/23 vai vượt** (cicd · fe-designer · harvest · impl-be · impl-fe · inv-cb · lead-gap · reviewer · tooling) trong khi mọi instrument in **"0 over"**.
🔴 **Vai BÁC luôn claim của lead:** *không* xác nhận được "4 cửa-sổ chưa curate" mtime reviewer = **2026-07-27T13:56** nên file được ghi; vai không máy đo số cửa-sổ.
11. **S11** `tooling-auditor` **23.464/25.600 = 91,66%** autoinject (cao nhất roster) chưa chạm 30KB nên 0 máy kêu.
12. 🔴 **S12** `pull_warn_days` **VẮNG** trong `h24_cadence` trong khi **reader tồn tại** `scripts/nhip-no-probe.ps1:212/:214` nhánh `OVERDUE:pull` chết. **Đã ghi vòng trước, VẪN MỞ** (ghost-wire class-2).
13. **S13** distill `pending=15` đúng bằng ngưỡng IM hợp lệ (`-gt`); headroom **1 shard**.
14. **S14** trục TUỔI 0/6 instrument chạm; budget tự khai "CHUA CO MAY".
15. **S15** MFE không chạy fidelity không số tươi; `.mfe-state.json` **7/7 history entry đều 25/14** = state, KHÔNG phải phép đo hôm nay.
16. **S16** `.archive-strikes.json` mtime **2026-07-25T22:12 (3 ngày)** gate CHẠY hôm nay; tracked-set **20 vai ≠ 23 vai đo** (thiếu 3 ctx-*). Không phân giải được trong cửa-sổ (cấm re-run).
17. **S17** detector TOTAL 44 không baseline key không ratchet được.
18. **S18** `run-chua-gom 3` verbatim, trục harvest (H2), vai không phán.
**Tổng thô (LIVE 23 vai):** l1_hot **285.659 B** (mean ~12.420) · l2_verbatim **839.440 B** · l2_gist **274.745 B** · l2_index **81.244 B** · 10/23 archive · **13/23 L2 rỗng hoàn toàn** · 10/10 vai archive đều gist.
## Caveat vai tự nêu (chống overclaim)
1. **read-only = thiếu-tool, KHÔNG phải sandbox** vai vẫn giữ Bash. tự chạy `git status` liệt đúng 3 mục đang dirty (counter · session-log S155-S157 · adap-report) = **việc của lead**. Containment thật = **lead soát `git status` SAU lượt vai**, không phải lời vai tự khai. *(Lead xác nhận: 3 mục đó đúng là của lead.)*
2. 5/6 trục single-lane.
3. Số headroom-tương-đương của mốc (181.228 tok) **DERIVED bằng công thức instrument**, không phải dòng máy in dùng làm hướng, không làm mốc.
4. Vai nạp theo registry = ảnh-chụp lúc khởi phiên; agent MỚI không hot-reload.
5. **Đếm-về-mình**: vai tự cộng 2 lần khớp bảng 18 signal = S1..S18; 12 dòng trục = 3 HEALTHY + 4 REGRESSION + 2 MIXED + 3 N/A + 1 N/A-baseline.
`END · TOTAL=18 SIGNAL`

View File

@ -0,0 +1,93 @@
# harness-refine return — S158 (trio nac 2/3, con DE-XUAT)
> Vai tu ghi dan TRONG luc lam (chong #53). Chua ket thuc = chua co dong END.
## Fail-closed check
- INPUT PIN `harness-eval-return.md` = TON TAI, 18 signal, `HARNESS-EVAL: MIXED`. => KHONG tu-choi, di tiep.
- `reinject-ledger.md` = TON TAI, ledger THAT 0 dong (khoi tao trong S95). => CG-1 khong chan doi-tuong nao qua ledger; chot-dung phai tra tu DIARY vai.
## Dang xac-minh tren dia (khong do lai, chi mo file so noi-dung)
### V1 — S10 (thuoc 17,1K): eval SAI TIEN-DE, DUNG SO HOC
- `memory-budget.json` CO chuoi "17.1K" o **2 cho**: `_note` :185 va `measured.harvest-curator.rollout` :192 ("L1 over self-target 17.1K -> self-compact planned next session").
=> eval noi "KHONG ton tai trong memory-budget.json" = **sai theo nghia grep**; dung theo nghia **khong co KEY so + khong co reader** => ghost-wire class-2 NGUOC voi S12 (S12 = reader-khong-key; day = value-khong-key).
- Luat 17,1K la CONVENTION LAP that: co trong 5 diary (harvest-curator :9 + :5, reviewer :93, investigator-codebase, lead-gap-auditor, ring2-audit).
- Ap thuoc 17510B (=17.1*1024) len 23 L1 doc tu dia: **9/23 vuot** = cicd 20686 · fe-designer 21492 · harvest 19456 · impl-be 21987 · impl-fe 18435 · inv-cb 20646 · lead-gap 19792 · reviewer 19049 · tooling 23464. **KHOP y nguyen danh sach eval S10** => so hoc S10 XAC NHAN tu dia.
### V2 — S3/S4 cicd `_INDEX.md`: XAC NHAN 19484 B tren dia (cap 20480, headroom 996)
- Header CON nguyen dau vet attempt-1: `> 🗜️ gist-of-index @S152 (D1 queue)` => **D1@S152 DA THI-HANH**.
- Nhung header VAN chua `Total **78 records**` + van la prose dai => **A1@S153 (attempt-2) CHUA thi-hanh**.
- => doi-tuong nay da qua 2 vong de-xuat cua chinh tao (S152 D1, S153 A1). CHOT-DUNG kich hoat.
### V3 — S16 `.archive-strikes.json`: XAC NHAN tracked-set = 20 vai
- Thieu dung 3: `ctx-audit` · `ctx-curator` · `ctx-verifier` (ring1/2/4 CO trong strikes).
- Doi chieu S8 (`measured{}` thieu 6 = 3 ctx + 3 ring) => **3 vai ctx-* vo-hinh voi CA HAI may** (khong baseline, khong strike).
### V4 — SOAT CHOT-DUNG TRON 5 return truoc (S144·S151·S152·S153·S154)
Diary tao chi ghi S151/S152/S153 => **MAT S144 + S154**. Doc lai ca 5 file. Ket qua doi chieu DIA hom nay:
| item de-xuat truoc | doi-tuong | trang-thai tren dia @S158 |
|---|---|---|
| D1@S151 nen `_INDEX` cicd | cicd `_INDEX.md` | **DA LAND** 22634 -> 19322 (git c2d01f0) |
| A1@S151 drain lead-gap | lead-gap `MEMORY.md` | **DA LAND** 24185 -> 19792 + archive/ dung |
| A2@S144 drain inv-cb | inv-cb `MEMORY.md` | **DA LAND** 26624 -> 20646 (< low-water 21760) |
| A3@S151 drain harvest | harvest `MEMORY.md` | land 1 phan roi TAI PHINH 19456 |
| **A1@S153** nen header `_INDEX` | cicd `_INDEX.md` | 🔴 **CHUA LAND** header **2.164 B** byte-y-nguyen, van khai `Total 78 records` |
| **A1@S154** them heading 3 diary ctx | ctx-curator · ctx-verifier | 🔴 **CHUA LAND** ca 2 con **0 heading** (ctx-audit co 1) |
| **A2@S154** sua chu budget | `memory-budget.json` | 🔴 **CHUA LAND** con **3 lan** "first-run pending restart" |
| **A3(i)@S154** sua diary `:22` | `harness-refine/MEMORY.md` | 🔴 **CHUA LAND** `:22` con nguyen "CHUA chay lan nao" |
| **A3(ii)@S154** promote luat 2-CUA | `harness-refine/MEMORY.md` | 🔴 **CHUA LAND** grep 0 hit |
=> **5 item verified 0-byte-doi.** Co-che DAT-CHO da chung minh chay duoc (4 ca land @S151/S152) nhung lo hang S153+S154 ~**1/6**.
=> Trigger DA DANG-KY TRUOC @S154 A3 ("neu (ii) cung khong land => leo-thang CO-CHE dat-cho, khong phai noi-dung") **DA KICH**.
### V5 — thuoc 17,1K: 0 KEY + 0 READER + KHONG DINH-NGHIA
- Quet toan bo key so trong `memory-budget.json` dai 17000-17600: chi co **2 gia-tri DO** (`measured.investigator-codebase.l1_hot`=17229 · `measured.harvest-curator.l2_verbatim`=17072). **KHONG co key nguong nao.**
- Luat nam dang VAN-BAN CHUAN-TAC o 5 diary: `harvest-curator:9` (+ `:5` no tu khai vuot) · `reviewer:93` · `lead-gap-auditor:37` · `ring2-audit:56` · `investigator-codebase:58`.
- 🔴 Thuoc con **KHONG DINH-NGHIA**: "17.1KB" = 17.100 hay 17.510 B? (ca 2 cach doc deu ra dung 9/23 vuot nen so hoc eval khong doi.)
- 🔴 Thuoc DANG TON CONG THAT: `inv-cb:58` ghi "S155 (07-27) hook @19.5KB -> compact 20.7 -> ~17.1KB" — nen 3 ngay sau da **20.646 B** lai. Vai bo cong nen theo mot thuoc ma **0 may soi**.
---
## ACTION — 1 (co y IT: xem E2, hang doi dang tac)
| # | action | lop | doi-tuong file:path | trigger (so con-DO) | chot-dung | owner-gate |
|---|---|---|---|---|---|---|
| **A1** | Gom thuoc **17,1K** ve MOT cho canonical + dan NHAN trang-thai. 🔴 **Tao KHONG dat so.** Owner chon 1 trong 3: **(i) WIRE** = them key `tiers.l1_hot.self_target_bytes` de may soi duoc · **(ii) RETIRE** = go luat khoi 5 diary vi thuoc that la 25600 · **(iii) RELABEL** = giu nhung ghi ro "advisory hook-read-limit, KHONG phai cap" de 9 vai thoi bi coi la vi-pham im-lang. Lead thi-hanh 1 lan: 5 diary TRO ve cho canonical thay vi chep lai luat | ② promote | `.claude/agent-memory/memory-budget.json` (`tiers.l1_hot`) **+** 5 diary chep luat: `harvest-curator/MEMORY.md:9` · `reviewer/MEMORY.md:93` · `lead-gap-auditor/MEMORY.md:37` · `ring2-audit/MEMORY.md:56` · `investigator-codebase/MEMORY.md:58` | **S10** — tao doi-chieu `wc -c` tung file: **9/23 vuot 17,1K** (cicd 20686 · fe-designer 21492 · harvest 19456 · impl-be 21987 · impl-fe 18435 · inv-cb 20646 · lead-gap 19792 · reviewer 19049 · tooling 23464) **khop y nguyen danh sach eval**, trong khi moi may in "0 over". [V5]: **0 key so + 0 reader**; thuoc con khong dinh-nghia (17.100 hay 17.510?) va **dang ton cong that** (`inv-cb:58` nen ve ~17.1K @S155, 3 ngay sau 20.646 lai) | **attempt-1 o PHAM-VI corpus** (S154 E2 chi escalate RIENG harvest). Vong sau van chua chon 1 trong 3 nga ⇒ **CAM attempt-2**, nhap thang vao E1 gui owner | 🔴 **OWNER**. `token_governor.role_boundary_note` + `reinject-ledger.md:5`: so/nguong = quyen cap-ngan-sach cua anh. De-xuat nay **0 SO do tao chon** |
## ESCALATE — 4 (chot-dung DA KICH, CAM de-xuat lai noi-dung)
| # | doi-tuong | vi sao KHONG de-xuat nua | gui ai |
|---|---|---|---|
| **E1** | `cicd-monitor/archive/_INDEX.md` | Da **2 attempt**: D1@S151 LAND (22634 -> 19322) · **A1@S153 CHUA LAND** (header 2.164 B byte-y-nguyen, con `Total 78 records`). Diary tao `:4` tu cam-ket "CAM attempt-3". Escalate @S154 E1 **van treo**. So moi: **19.484/20.480 = 95,14%, con 996 B**; tai-moc tu san sau-curate 19.322 (git `c2d01f0`) -> 19.484 = **+162 B / 2 ngay** ⇒ [so-hoc] ~81 B/ngay ⇒ cham cap **~2026-08-09** | **LEAD** disposition: thi-hanh nguyen-van A1@S153 HOAC **HUY** va ghi ro. Neu chon nang cap 20480 ⇒ **OWNER** |
| **E2** | 🔴 **CO-CHE DAT-CHO** (khong phai 1 file) | [V4] **5 item verified 0-byte-doi** qua 2 vong (A1@S153 · A1/A2/A3i/A3ii@S154). Lo hang S153+S154 ~**1/6** trong khi S151/S152 land 4/4 ⇒ hong o **khau DAT**, khong o noi-dung. Trigger **da dang-ky truoc** @S154 A3 chinh la ca nay ⇒ bom them noi-dung luc nay = do vao hang doi dang tac | **LEAD** (co-che). Ranh: HANDOFF "NEXT em @S153" nay da 5 phien = **lead-surface ⇒ NHUONG `lead-stale-auditor`**; tao chi bao phan **corpus** 0-byte-doi |
| **E3** | `ctx-curator/MEMORY.md` · `ctx-verifier/MEMORY.md` | A1@S154 dat truoc: "vong sau van `entries=0` ⇒ leo-thang + **CHUYEN LANE tooling**, CAM de-xuat lan 2". Do lai: ca 2 con **0 heading** (ctx-audit co 1) ⇒ planner van doc `entries=0``memory-archive-gate.ps1` vinh-vien "cannot auto-drain" + value-protect chay tren 0 entry | **LEAD + LANE tooling** (goc o parser `:153`, khong o diary) |
| **E4** | `harvest-curator/MEMORY.md` | @S154 E2 da escalate OWNER voi 3 loi ra. Do lai hom nay: **19.456 B = 0 byte doi** ke tu S154. Mon no TU-KHAI 2 lan (budget `:192` tu S107 · diary `:5` tu S153) chua tra lan nao | 🔴 **OWNER** (3 loi ra deu la SO/nhip cua anh). Tao **khong chon ho so nao** |
## DA CAN-NHAC ROI BAC — 9
| # | thu da soi | phan | ly do (neo dia) |
|---|---|---|---|
| **B1** | **S7** 11/23 diary chung 1 mtime `2026-07-26T15:49` ⇒ do-tuoi gia | **BAC action** | Tao mo **ca 11 file**: **11/11 deu mang tem provenance IN-CONTENT** (`on-behalf` / `M9` / `lead seed`, 2-6 hit/file). Corpus **khong giau gi** — chi PROXY mtime doc sai. Ap dung dung luat tao tu promote @S153: *proxy mtime/ngay ⇒ CAM neo action; phai mo file so NOI-DUNG*. Ben can sua = ben DOC mtime nhu freshness ⇒ **lane instrument (eval/tooling)**, khong phai corpus |
| **B2** | **S16** `.archive-strikes.json` tracked 20 ≠ 23 (eval khai "khong phan giai duoc trong cua-so") | **BAC — phan giai DUOC, khong phai khuyet-tat** | 2 ve deu co loi giai tu dia, khong can re-run: (a) 3 vai `ctx-*` sinh **2026-07-26** (git `11db5ef`), file strikes mtime **2026-07-25T22:12****file co TRUOC 3 vai** — thieu do thu-tu-sinh; (b) "gate chay hom nay ma file 3 ngay" = **dung thiet-ke**: S152 da verify `memory-archive-gate.ps1:127 / :222-226 / :229` chi ghi strike khi `-Apply`, DRY-RUN khong ghi. File cung **khong git-tracked** (git log rong) |
| **B3** | **S8** bom 6 row thieu vao `measured{}` (3 ctx + 3 ring) | **BAC — DA QUEUED** | `docs/HANDOFF.md` muc ⑤ ghi nguyen van: monthly drift-audit **2026-08-01** + full re-sync `measured{}` (**+3 row ctx** ngoai 3 row ring) — con **4 ngay**. `memory-budget.json:2` va `:185` **cam hand-edit tung so le**. Theo `reinject-ledger.md:12` day la **build-gap**, KHONG phai floor-rot ⇒ cam vao ledger. **Ve tao GIU: sau 2026-08-01 van 17 row ⇒ luc do moi la no that** |
| **B4** | **S9** moc `measured` troi nang (lead-gap +436%, lead-stale +323%) ⇒ do them row / sua so | **BAC — cung ly do B3, va khong phai defect corpus** | Con so troi vi moc la snapshot **S107/S138/S141**, khong phai vi diary hong. Sua = re-sync **2026-08-01**. Ve agent-memory tao CO nhin: `lead-gap-auditor` 19.792 (tung **24.185** @S151 — A1 da drain THANH CONG) · `lead-stale-auditor` 14.078 — **ca 2 duoi MOI cap co day**, chi vuot thuoc 17,1K chua wire ⇒ da gop vao **A1/B6** |
| **B5** | **S3/S4** l2_index cicd near-cap 95,14% (con 996 B) + probe do OVER khong do NEAR (Goodhart-flip) | **BAC action — TRUNG E1, va ve "probe" la lane khac** | Ve **vat** (nen `_INDEX`) da het cua: 2 attempt roi, diary tao `:4` tu cam-ket **CAM attempt-3** ⇒ chuyen **E1**, khong de-xuat lan 3 (dung anti-pattern lap-vo-han). Ve **may** (probe in "l2idx 0 over" canh 996 B) = sua **INSTRUMENT****lane tooling-auditor** (dung vet S153-B4: 2 nguon khuon da nhau ⇒ diary NHUONG tooling). Tao **khong tu nang cap 20480** — doi-thuoc-thay-vi-doi-vat = Goodhart, va so = quyen owner |
| **B6** | ③ archive HANG LOAT 9 vai vuot 17,1K | **BAC — gop vao A1** | De-xuat 9 action theo mot thuoc **chua duoc owner phe + chua co key + chua dinh-nghia (17.100 hay 17.510?)** = tu-Goodhart: nen theo thuoc may khong soi roi bao "da xu ly 9 vai". Dung thu-tu = **quyet thuoc TRUOC (A1), roi moi ban toi nen** |
| **B7** | ③ archive `tooling-auditor` 23.464 = 91,66% autoinject · `frontend-designer` 21.492 · `implementer-backend` 21.987 | **BAC — chua du trigger** | (a) tooling: S154 B1 da bac vi `memory-archive-gate.ps1:205` **tu dat luat** *propose only after 2 consecutive over-cap*; vai nay **0 over-cap, strike 0** ⇒ de-xuat bay gio = dung nguong rieng de nguong may = **lan quyen dat-so owner**. Do lai: **23.464 = byte-Y-HET S154****0 su-kien moi** de lat lai. (b) fd/impl-be: tripwire cua chinh tao @S151 = hanh-dong khi headroom < **3.070 B**; nay con **4.108 B** / **3.613 B** ⇒ chua cham. fd con **dong bang** (mtime 2026-07-01, 27 ngay, 0 growth) |
| **B8** | **S12** `pull_warn_days` vang key ma reader song `nhip-no-probe.ps1:212/:214` | **BAC + NHUONG** | Doi-tuong = **config script**, khong phai agent-memory corpus ⇒ **lane tooling-auditor**. Va chinh eval khai *"da ghi vong truoc, VAN MO"* ⇒ dung ca **CHOT-DUNG** ⇒ leo-thang, cam de-xuat lan 2. Tien-le cung class da dong @S153 (budget `:8` `_session_ctx_kb_reader`) |
| **B9** | Lop ① **reinject = 0 action** va lop ④ **distill = 0 action** | **BAC CO LY DO (khong bia cho du 4 lop)** | ①: `reinject-ledger.md` **that su 0 dong** tu S95; de neo 1 reinject phai co phep do **per-item-L1-presence** — chinh ledger `:50` **tu khai day la BUILD-GAP, PARTIAL**; eval S1..S18 **khong co so nao** do presence-per-item ⇒ neo bang gi cung la bia ⇒ **fail-closed dung lop nay**. Ung-vien tao dao duoc (diary tao thieu S144+S154) la **build-gap** (`:12`: chua-tung-dung ≠ floor-rot) ⇒ cam vao ledger. ④: truc distill **HEALTHY** (`pending=15/nguong=15 => IM`, dung bien); ung-vien ④ dang gia duy nhat (`_INDEX` cicd) **bi chot-dung khoa** ⇒ E1. Bia them viec chi de du 4 lop = **nghi-thuc rong** |
## NHUONG — khong phai turf tao
- **S1 · S2 · ve headroom cua S9** (headroom 174.463 < target 210.000 · hotload +20.294 B) **`lead-gap-auditor`** (no da raise `gap-underfill`) KHONG de-xuat chong.
- **`gap-incident-unrecorded` (so #53)** turf `lead-gap-auditor`.
- **S18** `run-chua-gom 3` **H2 `harvest-curator`** · **S17** detector TOTAL 44 khong baseline **tooling** · **S14** truc TUOI 0/6 may **tooling + owner** · **S15** MFE khong chay khong co so, khong phan.
- **S5/S6** diary-0-delta 2 sub phien nay lead da tu nhan M9 seed on-behalf trong `run.md`.
## Caveat tu khai
1. **read-only = thieu-tool, KHONG sandbox** tao van co Bash va DA GHI dung **1 file**: `runs/2026-07-28-S158-bookend-close/harness-refine-return.md` (chong #53). **0 file corpus / 0 config bi cham.** Lead soat `git status` sau luot.
2. **De-xuat ≠ da-lam.** A1 propose-only, owner-gated.
3. **KHONG do lai instrument.** So tao dua ra = `wc -c` / `grep -c` / `git show | wc -c` de **XAC-MINH mo-neo** + cong-tru; moc ~2026-08-09 la **phep chieu so-hoc**, khong phai phep do.
4. **Tu-soi:** diary tao **mat 2/5 vong** (S144, S154) vong nay phai doc lai 5 return cu moi biet minh da de-xuat gi. Chinh la trieu-chung cua **E2**.
`END · TOTAL=1 ACTION`

View File

@ -0,0 +1,38 @@
# RUN — bookend @close S158 (phiên-LOGIC L7, window 5)
> `/session-end` Phase 1.5 §L.b. Phiên vào bằng `/tiep` ⇒ KHÔNG có bookend @open ⇒ mọi vòng chạy TẠI ĐÂY.
> HEAD lúc phóng = `6c263dd`. Counter đã tick S157→**S158** (31→32) ở cửa `/tiep` §2.5.
## Bối cảnh phiên (cho các vai đọc)
Phiên S158 = **1 cửa-sổ**, vào bằng `/tiep`, gồm 3 việc:
1. `/tiep` recovery trọn (Sàn-3 5 tín-hiệu · `verify:` 5/5 PASS 0 lệch · TICK · biên-nhận `_tiep-4.md`)
2. `/check-email` AI_INFRA — verify bằng NỘI DUNG: 22/22 file `outbox/se` có trong inbox, **0 byte-drift** ⇒ se=0 thật
3. `/adap-apply` thư `2026-07-28-Governance-day-wake-probe-first-resume` qua `/fable-real investigator-codebase`
→ nấc **agreed**, spec 3-mục + adap-report. **0 file cơ-chế bị sửa.**
+ rà 6 HIGH lens-wave của spec S157 (4 phủ trọn, 2 còn hở: H5 W3 `N` chưa pin · H6 §2.4:224 giữ cơ-chế đã bị bác)
## Số máy đã đo (các vai ĐỌC, KHÔNG chạy lại — §L.b(k)(v))
- `measure-agent-memory.ps1`: 0 agent L1 over-30KB
- `memory-archive-gate.ps1`: **A7 GATE PASS — 402/402 pointer resolved, 0 failed**
- `crystallized-backfill.ps1`: hotload **616.610 B** · tok RANGE [154.152..205.537] · headroom **174.463 tok** · cap 380.000
- `nhip-no-probe.ps1`: `NHIP-NO: kiem light 5/6 deep 7/15 ok | tran-bo-nho 0 over-cap l2idx 0 over | run-chua-gom 3 | pull-cach 6 ngay`
- `distill-shard-probe.ps1`: `pending=15 | nguong=15 => IM` (sleep KHÔNG kêu ⇒ V4 `không-nhịp`)
- `governance-detectors.ps1`: **TOTAL 44** · INFORM-only 7 · self-match 0
## 🔴 Phát hiện lead tự bắt lúc flush (giao vai kiểm)
**GAP-3 diary-0-delta cho CHÍNH 2 sub của phiên này:**
- `ctx-verifier` chạy ~19:30 hôm nay, `MEMORY.md` mtime **2026-07-27T15:41** ⇒ KHÔNG tự ghi
- `investigator-codebase` chạy ~19:40 (lượt Fable), `MEMORY.md` mtime **2026-07-28T10:56** = lượt S157 ⇒ KHÔNG tự ghi
⇒ lead phải M9 diary-seed on-behalf CẢ HAI trong closeout này.
## taskList snapshot
- [ ] (d)(f) `harvest-curator` — spawn-record 4-field + harvest 5-trục + close-gate DUAL-ACCEPT
- [ ] (g) `tooling-auditor` — freshness 4-mặt + new-alloc
- [ ] (j)(ii) `lead-stale-auditor` + `lead-gap-auditor` — bookend vô-điều-kiện
- [ ] (g-bis) `ring1-audit` · (j)(ii-bis) `ring2-audit` — AUTO sau con-đo
- [ ] (k) trio `harness-eval``harness-refine``harness-audit` — TUẦN TỰ
- [ ] (l) `ctx-audit` — vai-3 vòng Ctx, SAU tất cả

View File

@ -0,0 +1,293 @@
# sub-ctx-audit-close-S158 — vai-3 vòng Ctx (SOI-CHUỖI) @close
> Phiên **S158** · phiên-LOGIC **L7** · window 5 · repo SOLUTION_ERP.
> 🔴 **L7 ĐÓNG trong closeout này** ⇒ cửa DUY NHẤT để chấm chuỗi `_mind-s-7`.
> Vai = `ctx-audit` (vai-3). Propose-only: mày PHÁN, lead GHI. 0 tệp `_mind`/`_context` bị vai này chạm.
> Ghi-đĩa-TRONG-lúc-làm (chống `#53`) — file này viết dần theo tiến-trình, KHÔNG gom cuối.
---
## (0) PIN đích-danh — fail-closed: **ĐỦ, đi tiếp**
| pin | giá-trị | trạng-thái đĩa |
|---|---|---|
| `_mind` | `.claude/sessions/session-7/_mind-s-7.md` | ✅ tồn tại — **30.305 B** (khớp pin), 5 block MIND-4→MIND-0 |
| `_context` | `.claude/sessions/session-7/_context-s-7.md` | ✅ tồn tại — 22.584 B, 4 entry PAUSE-1..4 |
| run-folder | `.claude/workflows/runs/2026-07-28-S158-bookend-close/` | ✅ tồn tại — 9 tệp trước lượt này |
| lượt | `@close` | ✅ |
Glob `*mind*` trong `session-7/`: **đúng 1 tệp**, tên `_mind-s-7.md`**0 biến-thể tên-sai** (không có `_mind-s7.md` thiếu gạch). Cửa tên-tệp SẠCH.
---
## (I) MÁY TRƯỚC VAI — đọc nguyên-văn, KHÔNG re-implement
Lệnh đã chạy: `python scripts/session_ctx.py mind-check --session 7``EXIT=0`
```
verdict: dat=10 TRUOT=0 co=0 bo-qua-co-khai=0 => exit 0
```
4 mức nguyên-văn: **đạt=10 · trượt=0 · cờ=0 · bỏ-qua-có-khai=0.**
Các phép ĐẠT: (0) enclosure · (1) rào-1 verbatim · (2) rào-2 `ts:` key-line · (3) rào-3 secret · (4) con-trỏ E block-top **5/5 giải được** · (5) số-hiệu block `4,3,2,1,0` · (6) bất-biến `|block|=5` vs `p=4` · (7) trần `30305B / 32768B` · phụ-8 trần `_context` · phụ-9 cấu-trúc A-E + nhãn D.
🔴 **Máy 0 trượt 0 cờ ⇒ nghĩa-vụ thách-CLEAN của vai KÍCH HOẠT** (§(v)). Bảng dưới KHÔNG được phép dừng ở "máy nói ổn".
### 🚩 FLAG-0 (MED) — `closed-check §6.3-bis` mà `§L.b(l)` hứa là "máy TRƯỚC vai" **KHÔNG THỂ chạy trước vai** (nghịch thứ-tự có cấu-trúc)
> ⚠️ **Tự đính-chính trong lượt** (no-self-exempt áp cả cho chính vai này): bản nháp đầu của mục này chấm *"máy chạy sai mode"*. **SAI** — đã sửa. Bằng-chứng bác: `scripts/session_ctx.py:713-714` — `--closed` = *"force closed-mode (**auto-on when `_end` exists**); flag = fault-inject seam"*, và `session-end.md §6.3-bis:383` đặt closed-check **"sau khi ghi `_end`"**. `_end` của L7 **chưa tồn tại** lúc này ⇒ `mode=open` là **ĐÚNG** tại slot của vai. Giữ lại vết sửa thay vì xoá: đó là dữ-kiện thật về vai.
Nhưng khi sửa xong thì lòi ra thứ nặng hơn:
| nguồn | câu |
|---|---|
| `session-end.md:162` §L.b(l) | ctx-audit chạy **SAU (a)-(k), TRƯỚC §L.c***"**máy TRƯỚC vai** (`mind-check` full **+ closed-check §6.3-bis**)"* |
| `session-end.md:383` §6.3-bis | closed-check chạy ***sau khi ghi `_end`***; closed-mode tự siết (con-trỏ E `đang-chờ`**TRƯỢT**; tên-sai → **TRƯỢT**); *"**TRƯỢT ⇒ xử lý TRƯỚC commit chốt**"* |
§6.3-bis nằm ở **§6**, tức SAU §L. ⇒ `_end` sinh sau khi vai đã trả. **Vai KHÔNG BAO GIỜ đọc được output closed-check** — lời hứa "máy TRƯỚC vai … + closed-check" là **bất-khả-thi theo thứ-tự**, vai chỉ có thể nhận `full/open` mãi mãi.
🔴 Hệ-quả đúng trục `GHI ⟂ KIỂM` (sàn khoản 7): **phép máy NGHIÊM NHẤT của lớp mềm** (2 ca nâng CỜ→TRƯỢT, trong đó có **GAP-#9** — ca mà nếu để CỜ thì *xoá con-trỏ đang-chờ* rẻ hơn *giữ trung thực*) lại là phép **duy nhất KHÔNG có mắt độc-lập nào đọc**. Nó fire sau khi vai-3 rời cửa, và §6.3-bis giao việc xử-lý cho **chính lead** — người bị chấm. Vòng soi độc-lập hở đúng ở phép có răng nhất.
→ Đề-xuất lead (propose-only, 2 đường): **(a)** dời closed-check lên trước §L.b(l) bằng `--closed` (flag đã có sẵn, `session_ctx.py:713`) rồi đưa output cho vai; **hoặc (b)** sửa câu §L.b(l) bỏ vế "+ closed-check §6.3-bis" và **khai thẳng** rằng closed-check là phép lead-đọc-một-mình. Đường (a) đóng lỗ; đường (b) ít nhất không hứa thứ không có. **CẤM giữ nguyên chữ hiện tại** — nó mô-tả một lưới không tồn tại.
---
## (II) 🔴 MỒI-NGẦM — CHẤM ĐƯỢC. Verdict: **MỒI ĐÃ RƠI** (rơi ở lớp SỐNG, defect gốc CHƯA vá)
**Cách chấm = grep NỘI-DUNG, không dùng số dòng** (đúng phương-pháp chính vai này đã viết @open, `sub-ctx-audit-open-S154.md:199`). Neo cũ `_mind-s-7.md:99` đã **mục-từ-lúc-sinh** — không dùng, không trách nén.
Nội-dung mồi (nguyên văn @PAUSE-1):
> `- Guard post-wave assertion mù 4 path hook — sửa bằng cách soi commit của hook thay vì \`git status\` {mới-nêu}`
### Nấc 1 — mồi còn sống trong `_mind` hôm nay? **CÒN, 3 anchor**
`grep -n "post-wave\|soi commit của hook\|git status" _mind-s-7.md`:
| dòng | block | mục | dạng tồn tại |
|---|---|---|---|
| 250 | **MIND-0** | **§D** | **bản gốc, còn nhãn `{mới-nêu}`** |
| 237 | MIND-0 | §C | "nghi vấn để dành" — nêu `§2.1.9(f)`, chẩn "guard dựa vào tính trung thực của đối tượng bị giám sát" |
| 209 | **MIND-1** | **§C** | **gist sau NÉN LẦN 2**`Guard §2.1.9(f) dùng git status mù đúng 4 path Stop-hook ⇒ thay bằng git log --name-only origin/main..HEAD` |
⇒ Mồi **sống sót qua 2 lần nén** (MIND-1 nén lần 1 @PAUSE-3, nén lần 2 @PAUSE-4) — nén KHÔNG phải thủ-phạm. Ghi nhận ĐẠT cho khoản "nén giữ số load-bearing".
### Nấc 2 — mồi có được MANG TIẾP không? **KHÔNG. Rơi im-lặng từ MIND-2 trở đi**
- MIND-2 §D · MIND-3 §D · MIND-4 §D: **0 hit**. Không dòng nào khai "đã đóng", "đã chuyển", "bỏ".
- Đối chiếu chuẩn ĐÓNG-CÓ-KHAI mà chính lead đặt ra và làm được ở ca khác: MIND-4 §A ghi *"ý `Q2 kiến-trúc khúc 8-12` ở MIND-3 §D **ĐÓNG** — không rơi im lặng, **đóng CÓ KHAI**"*. ⇒ Khuôn khai tồn tại, lead biết dùng, **nhưng không áp cho mồi**.
### Nấc 3 — 🔴 cơ-chế rơi: **ĐỔI MỤC = MẤT NHÃN = MẤT TRUY-VẾT**
Mồi sinh ở **§D có nhãn** `{mới-nêu}` (MIND-0) → tới MIND-1 nó tái-xuất ở **§C (kế-hoạch/delta), KHÔNG nhãn** → sau đó biến mất.
§D là danh-sách **được máy canh** (phụ-9 kiểm "mỗi ý mục D có nhãn") và **được người rà** mỗi cửa. §C là văn-xuôi **không nhãn, không ai đối-chiếu carry**. Một ý đi từ §D sang §C là **rơi khỏi tập được canh mà không có sự-kiện xoá nào** — đúng lớp `Goodhart: rời tập-đo`. Không luật nào hiện cấm, không máy nào bắt: `mind-check` phụ-9 chỉ hỏi "ý ĐANG ở D có nhãn không", KHÔNG hỏi "ý từng ở D nay đâu".
### Nấc 4 — 🔴🔴 defect GỐC mà mồi trỏ tới: **CHƯA VÁ, VÀ VẪN ĐANG ĐƯỢC DÙNG**
Đây là phần nặng nhất. Mồi không chỉ rơi khỏi `_mind` — thứ nó cảnh báo vẫn nguyên:
| site | nội-dung HÔM NAY | trạng-thái |
|---|---|---|
| `.claude/commands/session-start.md:285` | **(f) Post-wave assertion:** chạy xong 3 con → `git status --short` → kỳ vọng 0 tracked-change ngoài run-folder | 🔴 **VẪN `git status`** |
| `.claude/commands/session-end.md:159` | **(vi) Post-wave assertion:** xong 3 con → `git status --short` → kỳ vọng 0 tracked-change ngoài run-folder | 🔴 **VẪN `git status`** |
`grep -rn "name-only origin/main" docs/governance/harness-11-engine.md`**0 hit**.
Bản vá mà mồi kê đơn (`git log --name-only origin/main..HEAD`) **không land ở bất kỳ site guard nào**.
🔴 **Và guard đó được dùng ĐÚNG 2 LẦN trong chính phiên này** — post-wave assertion là bước bắt buộc của bookend @open (§2.1.9(f)) và bookend @close (§L.b(vi)). Nghĩa là cả 2 bookend của L7 chạy containment-check bằng một phép **mù đúng 4 path mà Stop-hook tự commit** — trong đó có `.claude/sessions/` (chính là nhà của `_mind`/`_context` mà vai này đang chấm).
### VERDICT MỒI-NGẦM
**CHẤM ĐƯỢC — kết quả: MỒI RƠI (TRƯỢT cho lớp mềm), và phép thử ĐẬU (mồi làm đúng việc của nó).**
Mồi phơi ra một chuỗi 3 nấc mà không con-đo nào khác trong phiên chạm tới: **(a)** ý rời §D sang §C thì hết bị canh · **(b)** rơi im-lặng dù khuôn "đóng-có-khai" đã tồn tại và được dùng ở ca bên cạnh · **(c)** defect gốc sống nguyên 2 ngày qua 4 cửa pause, trong khi **bản vá đã được viết ra và còn nằm trong diary vai `ctx-audit`** (`.claude/agent-memory/ctx-audit/MEMORY.md`, mục Containment S154: *"Verify bằng `git log --name-only origin/main..HEAD -- <path>` — KHÔNG dùng `git status`"*).
⇒ Đây là **thực-nghiệm độc-lập** cho đúng mệnh-đề MIND-4 §C tự viết: *"bài học nằm trong tay vẫn không tự bật ⇒ chặn được = **luật soi được**, không phải trí nhớ."* Lần này lead viết mệnh-đề đó ở §C **cùng lúc** đang để chính ví-dụ của nó rơi ở §D. Bài học đã được **ghi**, chưa được **wire**.
---
## (III) KIỂM-VẾT vai-1 + vai-2 — đối-chứng CHỌN MẪU (KHÔNG lặp trọn)
Phiên CÓ cả pause lẫn tiep ⇒ vai-3 **đọc verdict 2 vai kia + thách lại 1-2 khoản**, không tự chạy lại 5-khoản/4-khoản.
### III.a — vai-1 `ctx-curator` @PAUSE-4: `SUA — 9 điểm`, lead nhận **CẢ 9**
Vết: `_context-s-7.md:185-188`. Cũng được chép làm 1 dòng mục E tại `_mind-s-7.md:112` (con-trỏ hợp lệ, không chép nội-dung) ⇒ **khoản E-phủ ĐẠT cho vai-1**.
**Mẫu thách #1 — điểm (#6) "5 chỗ verbatim trá hình lách rào-1":** đây là ca **máy MÙ có chủ-đích** (mind-check rào-1 chỉ bắt dạng blockquote `> anh:`, không bắt lời anh đóng nháy giữa dòng). Lead khai đã nhận. **Kiểm trên đĩa hôm nay:**
- `awk 'NR>62'` (chỉ phần DƯỚI marker đóng khối luật) + grep `nguyên văn|*"`**2 hit, cả 2 KHÔNG phải lời anh**: một hit trích **câu bài-học** (`"ghi đĩa trong lúc làm" là CẦN KHÔNG ĐỦ`), một hit trích **chính điều khoản luật nén** (`"nén block CŨ NHẤT trừ block-0 và top"`). Trích luật/bài-học ≠ verbatim lời anh ⇒ ngoài phạm-vi rào-1.
- `grep -c "xem PAUSE-"`**6** con-trỏ. 4 quyết-định của anh trong MIND-4 (§A:74 backfill · §A:76 cấu-trúc trình ký · §B:81 nhớ spec · §D:98 lỗ hổng HĐ) đều ở dạng **diễn-giải + `(xem PAUSE-4)`** — đúng chữ rào-1: *"Trong `_mind` chỉ được TRỎ: xem PAUSE-`<k>`"*.
- Đối-chứng chiều ngược: `_context-s-7.md:143-159` GIỮ verbatim đầy đủ (`> anh: OK đã xong cái spec rồi…` + 4 chỗ *"nguyên văn"*). **Nguồn-duy-nhất nằm đúng nhà.**
**vai-1 điểm (#6): FIX ĐÃ LAND, verify độc-lập ĐẠT.** vai-1 bắt đúng chỗ máy mù, lead vá thật, không phải nhận-suông.
**Mẫu thách #2 — điểm (#2) "O-1 vắng trọn ⇒ ý Q2 sẽ rơi im lặng":** kiểm `_mind-s-7.md:76` (MIND-4 §A) — có dòng *"⇒ ý `Q2 kiến-trúc khúc 8-12` ở MIND-3 §D **ĐÓNG** — không rơi im lặng, đóng CÓ KHAI (spec §1.4)"*, và `_mind-s-7.md:141` (MIND-3 §D) có đuôi `→ **ĐÓNG @MIND-4 §A**`. ⇒ **ĐẠT 2 chiều** (khai ở cả block đóng lẫn block gốc). vai-1 chặn được đúng 1 ca rơi-im-lặng.
🔴 **Nhưng — chính đó là mẫu-số co lại.** vai-1 cứu **1** ý (Q2) khỏi rơi im-lặng, trong khi **8** ý khác của cùng MIND-3 §D rơi im-lặng ở cùng cửa PAUSE-4 mà không ai nêu (xem §VI). Verdict `SUA — 9 điểm` + "lead nhận cả 9" **đọc thành cửa đã sạch**, thực tế cửa đó là cửa mất nhiều ý nhất của cả L7. Không phải lỗi vai-1 (trục nó = chấm block NHÁP), mà là **lỗ giữa 2 trục**: không vai nào ở cửa pause có nhiệm-vụ đối-chiếu §D-cũ vs §D-mới.
### III.b — vai-2 `ctx-verifier` @`/tiep` S158: `CO-CO 8 cờ`
Vết: `_tiep-4.md:6` (1 dòng `ctx-verifier:` đủ nội-dung 3 cờ nặng). ⚠️ Vết này **KHÔNG** có dòng `LEAD-PHAI-NHAC-LAI:` như contract §(iii) mô tả — nhưng cờ được nhắc lại bằng **nội-dung** (K1/K3 + số đo trần), tức thoả **sàn khoản 3 bằng bằng-chứng nội-dung**. Ghi nhận dạng **INFO**, không FLAG.
**Kiểm (a) — lead có NHẮC LẠI thật không:** `_tiep-4.md:6` ghi rõ *"lead đo độc-lập XÁC NHẬN: dư 2.727 B + MIND-1 1.868 B = 4.595 < 6.536 B cần"*. Lead **không nhận suông**: chạy phép đo riêng, ra 3 con số, và số đó **bác** khả-năng mở MIND-5. ⇒ **ĐẠT** (đây là dạng nhắc-lại tốt nhất: tái-đo chứ không tái-phát-biểu).
**Kiểm (b) — cờ vai-2 có được xử không:** xem §VI + §VII. K1 và K3 **đã được ghi nhận nhưng CHƯA được xử** (8 ý vẫn ở trạng thái rơi; `_mind` chưa có dòng khai). Đúng nhịp — lead ghi ở block kế, mà block kế **không mở được** vì trần. Đây chính là chỗ 2 cờ dính vào nhau (§VII).
---
## (IV) BẤT-BIẾN CHUỖI — tự đếm ĐĨA, KHÔNG tin lời khai
Đếm bằng `ls` trực tiếp trên `.claude/sessions/session-7/`:
| vật | số VAI tự đếm | số MÁY in | khớp? |
|---|---|---|---|
| `_pause-*.md` + `pause-*.md` (dual-accept) | **4** | `p (DEM DIA) = 4` | ✅ |
| mind-block `^## MIND-\d+` | **5** (4,3,2,1,0) | `\|block\| = 5` | ✅ |
| `_tiep-*.md` | **4** | (máy không đo) | — |
| `_snapshot-*.md` | **3** | (máy không đo) | 🚩 |
- **Bất-biến `|block| ∈ {p, p+1}`:** `5 ∈ {4,5}`**ĐẠT**, hai nguồn khớp, 0 lệch cần in-cả-hai-số.
- **Cân-sổ pause↔đối-ứng:** 4 pause / 4 `_tiep` ✅ 1:1. Chưa có `_end` (sinh sau, §6.3-bis) ⇒ máy khai đúng *"khong co `_end` => bo qua"*.
- **Tự-khai `markers:`/`mind-blocks=`:** chưa tồn tại (không `_end`) ⇒ **0 nguồn tự-khai để cross-check**; đĩa là nguồn duy nhất, đúng luật.
### 🚩 FLAG-1 (MED-HIGH) — `_snapshot-4` **KHÔNG TỒN TẠI**: xác nhận cờ lead nêu, và nó đắt hơn "thiếu 1 vết"
**Xác nhận, không bác.** Bằng-chứng 2 lớp:
1. Đĩa: `_snapshot-1/2/3.md` có, mỗi cái mang `kind: auto-snapshot @PAUSE-<k> (pause.md §2.6(D))` — chuỗi 1:1 với PAUSE-1/2/3. **`_snapshot-4.md` vắng.**
2. Git: `git log --all --name-only -- .claude/sessions/session-7/_snapshot-4.md`**rỗng****CHƯA TỪNG được tạo** (không phải bị xoá). PAUSE-4 vẫn commit bình thường (`6c263dd wal: pause`).
🔴 **Cái mất KHÔNG chỉ là 1 tệp vết.** `pause.md:45` §2.6(C-bis) khai thẳng lý-do thứ-tự: *"đặt TRƯỚC (D) để **secrets-sweep của auto-snap quét luôn block vừa chèn = lưới-2 sau máy-draft lưới-1**"*. Và `pause.md:53` §2.6(D) ràng auto-snapshot là bước **AUTO mỗi pause**.
⇒ PAUSE-4 không chạy (D) ⇒ **lưới-2 `secrets-sweep` KHÔNG quét MIND-4**. Mà MIND-4 là **block mới nhất, dài nhất, và là block DUY NHẤT sinh ở cửa đó**. Hai lưới độc-lập phủ `_mind` (chính là fix parity `--root` hậu-T4 ghi trong diary vai này) **rút còn một** đúng tại block cần nhất. Lớp `vắng-mặt trông giống ổn`: `mind-check` vẫn xanh 10/10 nên cửa đọc thành sạch, trong khi một trong hai lưới đã im.
*Giảm nhẹ trung thực:* rào-3 hiện **ĐẠT** ở lưới-1 (`0 hit / 4 pattern`) ⇒ **chưa có secret lọt**. FLAG này về **độ phủ của lưới**, không phải về ô nhiễm đã xảy ra. Nhưng block `_mind`**BẤT BIẾN** ⇒ nếu có lọt thì vĩnh-viễn ⇒ không được hạ xuống LOW.
→ Đề-xuất: chạy bù `python scripts/session_ctx.py secrets-sweep --root <session-7>` trước khi commit chốt L7; và soi vì sao (D) không fire ở PAUSE-4 (3/3 cửa trước fire đúng ⇒ nghi bỏ bước thủ-công, không phải hỏng máy).
---
## (V) BLOCK-0 — nội-dung THẬT, không phải scaffold-rỗng: **ĐẠT**
Đòi ≥1 mảnh khuôn/máy không tự sinh được. Có thừa:
- **Tên ý mục D (MIND-0 §D:242-250):** 9 ý có thật, mỗi ý 1 nhãn — ví-dụ ý *"Row ngoài `$canonRows`: mở rộng tập máy canh hay bỏ số + trỏ nguồn sống theo khuôn B1"* `{mới-nêu}` và ý *"Điểm mù tự-quy-chiếu của cặp H24…"* `{đang-cãi}`.
- **E-verdict cụ-thể (MIND-0 §E:254-264):** 11 dòng spawn có verdict + con-trỏ, ví-dụ `ring1-audit — 46Đ/2T/5KC trên 53 claim``harness-audit — 68Đ/8T trên 78 claim`.
- `ts`/HEAD/heading **không được tính** và cũng không cần dùng tới.
Ghi thêm: MIND-0 §C:237 chứa **nguồn của mồi-ngầm** ở dạng "nghi vấn để dành" — block-0 không những thật, nó còn là block **giàu nhất** của cả chuỗi. Trớ trêu: nó cũng là block **bị bỏ lại xa nhất** (§VI).
---
## (VI) CARRY — 🚩 FLAG-2 (HIGH): **8 ý** rơi từ MIND-3 §D, và header nén **chỉ đường SAI**
Vai-2 báo **7**. Vai-3 tái-dựng độc-lập bằng grep từng ý ⇒ **8** (7 của vai-2 + K1 "thứ tự 3 việc" mà vai-2 tách ra đếm riêng). **Xác nhận vai-2, cộng thêm phần khớp nối.**
MIND-3 §D (`:141-144`) có **11 ý**. Sổ đoạn-hậu từng ý:
| ý (MIND-3 §D) | nhãn | số phận trong MIND-4 §D | kết |
|---|---|---|---|
| Q2 kiến-trúc khúc 8-12 | treo-chờ-anh | **ĐÓNG có khai** (`:76` + `:141`) | ✅ đúng chuẩn |
| Q6 giá vào HĐ | treo-chờ-anh | nằm trong *"5 câu thiết kế… Q3·**Q6**·Q11"* (`:97`) | ✅ carry |
| trần `_mind` | treo-chờ-anh | hoá thân thành *"Luật nén `_mind` HỞ… re-tune khoá `mind_ctx_kb`"* (`:99`) | ✅ carry |
| **thứ tự 3 việc** | treo-chờ-anh | `grep "thứ tự"` → chỉ `:22`(luật A-E) `:88`(ISO) `:142`(chính nó) ⇒ **0 hit MIND-4** | 🔴 RƠI *(=K1 vai-2; vẫn sống ở `WAL:25 next:` "thứ tự wave")* |
| **nhịp `ctx-curator`** | treo-chờ-anh | `ctx-curator` trong MIND-4 chỉ còn ở **§E:112** = dòng spawn, KHÔNG phải ý thảo-luận | 🔴 RƠI |
| **`ring5-audit` slot (41)** | treo-chờ-anh | hit `:142`(chính nó) `:213`(MIND-1) `:247`(MIND-0) ⇒ **0 hit MIND-4** | 🔴 RƠI |
| **vòng KIỂM giữ nguyên** | đang-cãi | hit `:143` `:213`**0 hit MIND-4** | 🔴 RƠI |
| **`#53` cửa này ×1** | đang-cãi | topic sống ở **§C:90 + §E:106-107**, nhưng **rời §D, MẤT NHÃN** | 🔴 RƠI *(đúng cơ-chế mồi-ngầm)* |
| **hợp-đồng liên-lane checklist** | gần-chốt | hit `:144` `:176` `:180`**0 hit MIND-4 §D** | 🔴 RƠI |
| **chia task theo ranh-giới rõ** | gần-chốt | `ranh-giới` chỉ hit `:144` | 🔴 RƠI |
| **con-đo khai mẫu-số** | gần-chốt | hit `:144` `:180` `:249`**0 hit MIND-4** | 🔴 RƠI |
**Cân sổ: 11 = 1 đóng-có-khai + 2 carry + 8 RƠI IM-LẶNG.** Trong 8 ý rơi có **3 ý `{gần-chốt}`** — tức nhóm *gần ra quyết-định nhất*, đắt nhất khi mất.
### VI.a — 🔴 Header nén không chỉ im lặng, nó **CHỈ SAI ĐƯỜNG**
`_mind-s-7.md:140` — MIND-3 §D mang tiêu-đề tự-khai:
> `### D. Đang-thảo-luận (nhãn giữ nguyên — MIND-4 đã nhận lại các ý còn sống)`
Claim này **SAI với 8/10 ý còn sống**. Và vì MIND-3 **bị NÉN @PAUSE-4**, header đó đứng ngay đầu khối gist ⇒ người/vai đọc lại sẽ được **bảo đừng tìm ở đây, MIND-4 có rồi**. Đó là **con-trỏ chỉ sai chiều** — tệ hơn im lặng, vì im lặng còn khiến người ta nghi ngờ, còn câu này **mua đứt sự yên tâm**. Vai-2 bác đúng; vai-3 xác nhận + định lượng.
*Công bằng — đối chứng để không quy nạp quá tay:* MIND-2 §D:178 có header **cùng khuôn** (*"MIND-3/4 đã nhận lại các ý còn sống"*) và claim đó **ĐÚNG**: cả 5 ý của MIND-2 §D đều tìm được nhà (4 ý → MIND-3 §D `:144`; "22 FLAG governance" → MIND-4 §D `:101`). ⇒ **Khuôn header không hỏng; hỏng ở đúng hop MIND-3→MIND-4.** Đây là **sự-cố 1 cửa (PAUSE-4)**, không phải thói quen hệ-thống — và PAUSE-4 cũng chính là cửa nén 3 block + mất `_snapshot-4`. Ba dấu hiệu cùng trỏ một cửa quá tải.
### VI.b — cơ-chế chung, n=2 độc-lập: **§D → §C = mất nhãn = rời tập được canh**
Hai ca khác cửa, khác ý, cùng đường đi:
- **mồi-ngầm**: MIND-0 §D `{mới-nêu}` → MIND-1 §C (không nhãn) → biến mất.
- **`#53`**: MIND-3 §D `{đang-cãi}` → MIND-4 §C (không nhãn) → biến mất khỏi §D.
`mind-check` phụ-9 hỏi *"ý ĐANG ở §D có nhãn không"***không** hỏi *"ý TỪNG ở §D nay ở đâu"*. Nên đường thoát này **không có máy nào canh**, và cả 2 lần đều đi lọt. Đúng khuôn `Goodhart: rời tập-đo` — không ai gian, chỉ là chuyển chỗ thì hết bị đo.
→ Đề-xuất phép rẻ (propose-only, lead quyết): mỗi cửa `/pause`, diff tập ý §D block-trước vs block-mới; ý biến mất phải có **1 trong 3** đuôi: `→ĐÓNG @…` · `→chuyển §C` · `→bỏ, lý-do`. Đây là phép **so 2 danh-sách**, làm được bằng máy, không cần ngữ-nghĩa.
---
## (VII) 🚩 FLAG-3 (HIGH) — mục E **KHÔNG THỂ** phủ cửa closeout: L7 sẽ đóng với dòng-sống thủng trọn 1 window
Contract §(ii).2: mục E phải có **1 dòng / mỗi spawn + engine-run của phiên**.
Cửa closeout S158 này đã sinh (đếm đĩa run-folder `2026-07-28-S158-bookend-close/`): `tooling-auditor` · `harvest-curator` · `lead-stale` · `lead-gap` · `ring1` · `ring2` · `harness-eval` · `harness-refine` · **+ `ctx-audit` (lượt này)** — **≥9 spawn**, mỗi con đã có sub-file trên đĩa.
**Không dòng nào trong số đó có chỗ để vào `_mind`**, vì 2 lý-do chồng nhau:
1. **Không có nghi-thức:** `grep "_mind" .claude/commands/session-end.md`**hit DUY NHẤT `:162`** (chính khoản (l) gọi vai này). Nhịp refresh `_mind` chỉ sống ở `pause.md §2.6(C-bis)` = **cửa `/pause`**. `session-end` **không có bước ghi block `_mind` cuối**. ⇒ đóng phiên bằng `/session-end` (không qua `/pause`) thì **window cuối cùng LUÔN mất mục E** — lỗ **cấu-trúc**, tái mỗi phiên-logic, không phải lỗi lead phiên này.
2. **Trần chặn đường vá:** 30.305/32.768 = **92,48%**; vai-2 đo và lead **tái-đo xác nhận**: nén thêm 2 block chỉ dư **4.595 B** < **6.536 B** cần **MIND-5 không mở được**.
Hai cờ dính nhau: kể cả muốn khai, cũng không còn chỗ khai. luật nén thì **HỞ** (ý `{treo-chờ-anh}` tại `:99`, chưa ai ) **không có đường ra hợp-lệ trong phạm-vi luật hiện hành**.
🔴 Đây điểm phải đưa lên owner, không phải để lead tự chọn: 3 đường đều đổi luật **(a)** re-tune khoá `mind_ctx_kb` (LEAD-DECIDED sẵn theo `:99`, nhưng đang chờ dogfood) · **(b)** luật nén để nén được block đã-nén-rồi · **(c)** chấp nhận đóng L7 với mục E thủng window-5 **và GHI 1 dòng KHAI** trong `_end` (`markers:`) rằng dòng-sống closeout nằm run-folder chứ không `_mind`. **Đường (c) rẻ nhất và trung thực**; đường tệ nhất **đóng im lặng** lúc đó `mind-check` vẫn in `dat`, L7 khép lại trông như đủ.
---
## (VIII) ĐỐI-CHIẾU §B / §C với sổ máy — **ĐẠT**
- **§B (hướng-tiếp) vs `.claude/WAL.md:25` `next:`** WAL: *"** 6 HIGH lens-wave** (`sub-review-wave-1.md`) đối chiếu spec §③ đã sửa chốt còn hở **thi công WAVE 1**"*. `_mind` §B `:81`: *"cửa sau **thi công Wave 1** 🔴 **nhưng phải đóng phần còn lại của verdict `SUA-TRUOC-W1` trước** (7 lỗi đã **không** phủ trọn 6 HIGH)"*. **KHỚP**, kể cả điều-kiện chặn. Không phải tin-sổ-máy không lệch.
- **§C (kế-hoạch) vs bản-đồ việc** `WAL:20-24` 4 mục `[ ]` (lỗ hổng treo-có-chủ-đích · kéo thư fan-out · 22 FLAG · curate `reviewer/MEMORY.md` + drift-audit 2026-08-01). `_mind` MIND-4 §D `:98` giữ lỗ-hổng-HĐ, `:101` giữ 22 FLAG. 2 mục còn lại việc vận-hành thuần (`_context:173-174` đủ) không đòi mặt `_mind`. **0 ca "kế-hoạch tả việc không có trên bản-đồ"**, **0 ca "bản-đồ có việc mà kế-hoạch mù"** mức load-bearing.
- **Ý D đã định-đoạt chưa đổi nhãn:** 7 ý MIND-4 §D Q2 đã đóng đúng cách; 6 ý còn lại đều thực-sự chưa chốt (3 câu treo còn nguyên trong `WAL:25`). **0 ca nhãn ôi.**
- **Con-trỏ giải được:** máy 5/5 `dat`, **0 ca `đang-chờ`** không ca "mở còn chờ, đóng vẫn chờ".
---
## (IX) THÁCH-CLEAN — nghĩa-vụ §(v) đã thi hành
Máy `0 trượt 0 cờ` vai **bắt buộc** tự soi chỗ máy trước khi được nói "ổn". Đã soi **4** chỗ, **cả 4 đều ra ca thật**:
| chỗ máy | phép vai dùng | kết quả |
|---|---|---|
| carry §D xuyên block | diff 11 ý MIND-3 §D vs MIND-4 §D | **8 ý rơi** (FLAG-2) |
| mục E vs `runs/` đĩa | đếm 9 sub-file closeout vs chỗ ghi trong `_mind` | **thủng trọn window-5** (FLAG-3) |
| song-hành `_snapshot` `_pause` | `ls` + `git log` | **`_snapshot-4` chưa từng sinh** (FLAG-1) |
| ý mồi vs site guard thật | grep `session-start.md` / `session-end.md` | **defect gốc chưa vá, guard vẫn `git status`** II nấc-4) |
**KHÔNG được báo CLEAN.** Máy xanh 10/10 lớp mềm 4 lỗ đúng ca "NGUY NHẤT" contract §(v) dựng vai này để bắt.
---
## (X) BẢNG VERDICT
| # | khoản | kết | neo |
|---|---|---|---|
| 0 | PIN đích-danh | **ĐẠT** | 3/3 pin resolve, 0 tên-tệp-sai |
| I | đọc máy (không re-implement) | **ĐẠT** | `dat=10 TRUOT=0 co=0` exit 0 |
| I | closed-check nghịch thứ-tự | 🚩 **FLAG-0** MED | `session-end.md:162` vs `:383` + `session_ctx.py:713` |
| II | **mồi-ngầm** | 🔴 **MỒI RƠI** (chấm được) | `_mind:250,237,209` sống · MIND-2/3/4 §D 0 hit · `session-start.md:285` + `session-end.md:159` vẫn `git status` |
| III.a | kiểm-vết vai-1 (2 mẫu) | **ĐẠT** | `_context:185-188`; verbatim-fix landed (6× `xem PAUSE-`, 0 lời anh) |
| III.b | kiểm-vết vai-2 | **ĐẠT** (lead tái-ĐO, không nhận suông) | `_tiep-4.md:6` |
| IV | bất-biến `\|block\| ∈ {p,p+1}` | **ĐẠT** | vai đếm 5 & 4 = máy in 5 & 4 |
| IV | `_snapshot` 3/4 lưới-2 không quét MIND-4 | 🚩 **FLAG-1** MED-HIGH | `git log` rỗng; `pause.md:45,53` |
| V | block-0 nội-dung THẬT | **ĐẠT** | `_mind:242-250` ý D thật · `:254-264` E-verdict thật |
| VI | carry §D | 🚩 **FLAG-2** HIGH | 11 = 1 đóng + 2 carry + **8 rơi**; header sai `_mind:140` |
| VII | mục E phủ cửa closeout | 🚩 **FLAG-3** HIGH | `session-end` 0 bước refresh `_mind`; trần 92,48% |
| VIII | §B vs `WAL next:` · §C vs bản-đồ · nhãn · con-trỏ | **ĐẠT** ×4 | `WAL:25` `_mind:81` |
| IX | thách-CLEAN | **ĐÃ THI HÀNH** | 4/4 chỗ soi đều ra ca thật |
**TỔNG: 13 điểm — 8 ĐẠT · 4 FLAG · 1 MỒI-RƠI.**
Verdict dòng-1: `CTX-AUDIT: TRUOT — 13 diem` (TRƯỢT FLAG-2 + FLAG-3 đều **mất nội-dung lớp mềm ở cửa ĐÓNG vĩnh-viễn**, không còn cửa sau để ).
## memoryDelta (4-field — lead seed on-behalf, vai KHÔNG tự ghi)
- **datum-1 `moi-ngam-cham-duoc-va-roi`:** mồi L7 chấm được, kết = RƠI 3 nấc (rời §D→§C mất nhãn · rơi im-lặng · defect gốc `git status` chưa `session-start.md:285` + `session-end.md:159`). Phép chấm đúng = **grep nội-dung**, neo `:99` mục-từ-lúc-sinh.
- **datum-2 `D-sang-C-la-duong-thoat-khong-may-canh`:** n=2 độc-lập (mồi · `#53`). `mind-check` phụ-9 chỉ hỏi "ý ĐANG D nhãn", không hỏi "ý TỪNG D nay đâu".
- **datum-3 `header-nen-chi-sai-duong`:** claim *"MIND-4 đã nhận lại các ý còn sống"* sai 8/10 tệ hơn im lặng bảo người đọc đừng tìm. Đối chứng: cùng khuôn MIND-2 lại ĐÚNG hỏng **1 cửa quá tải (PAUSE-4)**, không phải khuôn.
- **datum-4 `closed-check-khong-mat-nao-doc`:** phép máy nghiêm nhất lớp mềm (GAP-#9) fire SAU khi vai-3 đã rời cửa chỉ lead người bị chấm đọc . GHI KIỂM hở đúng chỗ răng nhất.
---
END · TOTAL=13 DIEM

View File

@ -0,0 +1,37 @@
# harvest-curator (H2) @close S158 — `HARVEST: GATE-PASS-6 | GATE-FAIL-0 — 6 finding`
> 🔴 Lượt 1 **`#53` garble** (narration giữa chừng, 89.9K tok / 27 tool-use). Recover = SendMessage-resume → lượt 2 CLEAN.
## (d) Spawn-record 4-field (đề-xuất, lead VERIFY→APPEND B3)
**SR-1 → `agent-memory/ctx-verifier/`**`ctx-verifier` @`/tiep` §3-ter (L7 w5) · kiểm 3-lớp ctx trước khi nối mạch · nấc **verified** (`CO-CO 8 cờ`) · evidence `.claude/sessions/session-7/_tiep-4.md` (586 B, dòng `ctx-verifier:`) — vai KHÔNG sinh sub-file, verdict sống inline trong biên-nhận.
**SR-2 → `agent-memory/investigator-codebase/`**`investigator-codebase` qua `/fable-real` (H21 per-invocation, propose-only) · đọc thư adap + đo repo → F1-F4 · nấc **verified** (`FIT-DU-4 — 14 đề-xuất/4 phản-biện`, 0 file cơ-chế sửa ⇒ adap ở nấc `agreed`; bác 2 tiền-đề lead) · evidence `runs/2026-07-28-S158-day-wake-probe-first/sub-invest-day-1.md` **25.440 B đúng byte, 183 dòng**, `## §5 PHẢN-BIỆN` có thật `:165`, TOTAL-line `:183` tự cộng 4+2+3+2+3 = 14 ✔
## (f) 5-trục
| Trục | Verdict | Chứng |
|---|---|---|
| **Coverage** | **PASS** (file-level) | `find .claude docs -newermt "2026-07-28 19:00"` = 9 file, chỉ **1** sub-file + vết ctx-verifier ⇒ "đúng 2 sub" HELD, 0 silent-miss. Caveat tự khai: wave closeout (gồm chính vai) đang BAY, không đo được từ bên trong |
| **Completeness** | **PASS** | 2/2 spawn-record đủ 4 field, mọi field có ref đĩa |
| **Placement** | **PASS-with-debt** | 0 dir rỗng · chỉ 1 `.claude` (root) · 0-byte = **10/10 `.gitkeep`** di-sản · `git status .claude/agent-memory/` **rỗng** ⇒ containment H-10 sạch |
| **Corruption** | **PASS — 0 MỚI** | perl byte-mode `\xEF\xBF\xBD` trên **668** file `.md`: **16 hit / 10 file** = **khớp tuyệt-đối baseline S153 (16/10)** ⇒ delta 0. Cả 10 là self-quote/quoted-evidence. moved-not-cut **N/A-sạch** (phiên không chạm `archive/*`) |
| **Fidelity** | **STRONG — 1 FLAG kỹ-thuật (F5), KHÔNG nghi bịa** | 4/5 số load-bearing tái-lập **byte-exact**: `_snapshot` 3 vs `_pause` 4 ✔ · MIND-1 **1.868 B** / MIND-5-cần **6.536 B** ✔ · `_mind` 30.305/32.768 = 92,48% ✔ |
## 6 FINDING
**F1 — HIGH · GAP-3 diary-0-delta: XÁC NHẬN, mạnh hơn mtime.** Vai không dừng ở mtime (mtime chỉ chứng "không ghi", không chứng "không có mục"): **`grep -c S158` = 0 hit ở CẢ HAI sổ**. Mục mới nhất `ctx-verifier` = S156; `investigator-codebase` 10:56 = lượt S157. ⇒ **GAP-3 lần 7** (S123/S125→S132 · S146→S148 · S149-ring2 · S150-ring1 · S152-lớp-LƯỢT). Delta đang ở `_tiep-4.md` + run-folder = **đúng nhà tạm, sai nhà cuối** → lead M9 seed on-behalf.
**F2 — HIGH · `2026-07-28-S158-day-wake-probe-first/` = ORPHAN theo canonical.** 3 file, **0** `*-synthesis.md`. `run.md``## Kết quả` = **dạng-3, RETIRED @S123, KHÔNG NHẬN** (`tiep.md §0`:59/:75 "Run MỚI BẮT BUỘC ghi dạng-1"). 🔴 Sắc thái: **nội-dung bản-ghi-kết-quả CÓ ĐỦ** (spec + `## Kết quả` + adap-report) — thiếu đúng **tên file** theo hợp-đồng `sub-` (RAW) ⟂ `-synthesis.md` (VERIFIED). Fix rẻ: ghi `adap-synthesis.md` phẳng.
**F3 — MED · `2026-07-28-S158-bookend-close/` chưa đóng — KHÔNG tính orphan (IN-PROGRESS).** Phải đóng dạng-1 trước khi hạ màn, nếu không sang phiên sau thành orphan thật.
**F4 — MED · nợ mang sang: 2 folder phiên trước vẫn orphan.** `S155-pe-delete-approver/` (22 file) và `S157-ke-hoach-ky-ket-hd/` (9 file) — **0** `*-synthesis.md` cả hai. Đối-chứng cùng kỳ: `S156``review-synthesis.md` 9.166 B ⇒ **thói-quen không nhất-quán, không phải migration**. Sổ toàn cục: **62 folder có `run.md`**, orphan-candidate 4, trừ F3 in-flight ⇒ **3 orphan thật** = **KHỚP ĐỘC-LẬP** máy `nhip-no-probe: run-chua-gom 3`.
**F5 — MED · một câu HAI CÂY THƯỚC, lệch 264 B (lỗi của LEAD).** Trong `_tiep-4.md`: "92,5%" theo **byte thô** (30.305) còn "dư 2.727 B" theo **LF-normalized** (30.041). Chênh **264 = đúng số byte CR** (`_mind` CRLF · `_context` **0 CR** ⇒ 2 file soft-memory khác hệ xuống dòng). Máy `mind-check` in **30.305/32.768** ⇒ headroom THẬT **2.463**, **chặt hơn số lead ghi 264 B**. **KHÔNG bịa** — mọi số tái-lập được, verdict "MIND-5 không đủ chỗ" đúng dưới **CẢ HAI** thước (4.595 < 6.536 **và** 4.331 < 6.536). Đề: mọi phép trần `_mind` **bám số máy in**, đừng tự đo lại.
**F6 — INFORM · Sàn-5: 2 run phiên này CHƯA đăng-ký.** `grep "run=" .claude/WAL.md` = 0 dòng; `session-7/` 0 dòng `wf:`; chưa session-log S158. Ghi nhận lead **vừa vá hồi-tố** Sàn-5 cho S155/S156/S157 (+11 dòng) kèm lập luận đúng. Đề: session-log S158 đăng-ký 2 dòng `run=` cho `S158-day-wake-probe-first` + `S158-bookend-close`.
**Tự-khai nợ của chính vai (không tính finding):** L1 = **19.456 B > self-target 17,1 KB**; self-compact khối S126/S140/S143 vẫn DUE, defer để không cắt giữa gate.
`END · TOTAL=6 FINDING`

View File

@ -0,0 +1,67 @@
# lead-gap-auditor (H24 vai-GAP) @close S158 — `LEAD-GAP: 5 FLAG`
> 🔴 Lượt 1 **`#53` garble** (195.8K tok / 32 tool-use / 683s). Recover = SendMessage-resume → lượt 2 CLEAN.
## FLAG-1 — `gap-carry-dropped` — HIGH
**hứa ở** `_context-s-7.md:62` (PAUSE-1): *"Nợ @close: bump `STATUS:6` counter 27→28; **ghi memory 2 datum** (#53 ổn-định-theo-vai · row-ngoài-cross-check-drift); mồi-ngầm chờ `ctx-audit` chấm."*
**hiện:** 1/3 xong (counter → `a52a91e`). **2/3 VẮNG**: `grep -rl "máy canh" .claude/auto-memory/` = **0** · `grep -rn "ổn.định.theo.vai"` = **0 hit**. Cả 2 datum có nguồn thật (`sub-lead-gap-open-S154.md` + `bookend-open-synthesis.md §2/§5` — chính lead gọi nó là *"kết quả nặng ký nhất KHÔNG phải FLAG lẻ mà là mệnh đề hệ-thống"*).
**Vết chết dần theo cửa:** PAUSE-1 "2 datum" → PAUSE-3 "3 datum" → **PAUSE-4 khối "Nợ sổ cũ" chỉ còn 3 mục, 0 chữ về memory-datum**. WAL = 0 hit · session-log bảng 7 dòng = 0 dòng · danh-sách chờ-anh 7 mục = 0 mục.
**đòn-bẩy bất-đối-xứng** (chống đọc thành "owner chủ-động gác"): cùng dòng `:62`, khoản counter-bump ĐÃ thi hành và khoản `reviewer/MEMORY.md` sinh SAU lại sống tới PAUSE-4 ⇒ **không phải cả khối bị buông, đúng 2 khoản này rụng**.
**im:** 3 cửa-sổ · 2 ngày · trọn L7.
## FLAG-2 — `gap-decision-sunk` — HIGH 🔴 (chặn được bẫy sắp sập vào chính closeout này)
**hứa ở** `_context:62` *"mồi-ngầm `_mind-s-7.md:99` chờ `ctx-audit` chấm"* + `session-end.md §L.b(l)` + `.claude/agents/ctx-audit.md:71`.
**hiện: NEO ĐÃ MỤC** — mồi định danh bằng **SỐ DÒNG** trong file **append-ở-TRÊN** đã bị **nén 3 lần**. Lúc gieo file 20.474 B; nay 30.305 B, MIND-4 chèn TRÊN + MIND-2/1/3 nén ⇒ mọi dòng dịch.
`sed -n '99p'` **hôm nay** trả: *"🔴 Luật nén `_mind` HỞ … {treo-chờ-anh}"***vấn-đề MỞ THẬT @PAUSE-4, KHÔNG phải mồi**.
🔴 **Hệ-quả 2 chiều, cả 2 đều xấu, cửa duy nhất để chấm là CHÍNH closeout này** (L7 đóng, `_mind-s-7` về hưu): (a) `ctx-audit` đọc dòng 99 → chấm "mồi còn sống" ⇒ **ĐẠT-ảo**; (b) chấm đúng dòng 99 là mồi ⇒ **vấn-đề luật-nén-hở bị dán nhãn "bẫy cài sẵn" và bị gạt** — trong khi đó là **mục #2 danh-sách chờ-anh lead đang trình**.
**LEAD ĐÃ XỬ TRONG CỬA NÀY** (trước khi spawn `ctx-audit`): khôi phục từ git —
```
git show 82a0457:.claude/sessions/session-7/_mind-s-7.md | sed -n '95,103p'
```
**MỒI-NGẦM THẬT** = `- Guard post-wave assertion mù 4 path hook — sửa bằng cách soi commit của hook thay vì `git status` {mới-nêu}`
⇒ pin cho `ctx-audit` **bằng TRÍCH NỘI DUNG, KHÔNG bằng số dòng**.
🔴 **Luật rút ra:** CẤM mọi neo-bằng-số-dòng vào `_mind` (file dịch dòng mỗi block).
## FLAG-3 — `gap-incident-unrecorded` — MED-HIGH
**hiện: 2 sổ bền của lớp sự-cố đứng yên trọn L7.** `feedback_agent_return_garble_recover.md` mtime **2026-07-26 01:50**; `grep -o "S15[3-8]"` = **0/0/0/0/0/0**; index vẫn khai *"×60-cận-dưới qua S152"*. `error-ledger.md` mtime 2026-07-26 01:41; `S153..S158` = 0 hit.
Trong khi L7 đếm được trên đĩa: `_mind:199` ×11 · `:181` ×13 · MIND-3 §D ×1 · `WAL:34` ×2 ⇒ **cận-dưới ~27 sự-cố, 0 vào sổ**. *(Lead bổ sung: closeout này +4 nữa — tooling · harvest · lead-stale · lead-gap.)*
🔴 **Cái mất KHÔNG phải con số** mà là **2 failure-mode MỚI chưa có tên**:
1. **`skeleton-ruột-rỗng` nấc 2** — invest lượt 1 đốt **202K tok**, đĩa **1.661 B khung rỗng***"ghi-đĩa là CẦN KHÔNG ĐỦ, phải verify RUỘT có chữ"*. Sổ hiện chỉ có mức S150 (*"verify byte-content"*) — mà **1.661 B LÀ byte > 0** ⇒ bản ghi hiện tại **KHÔNG bắt được ca này**.
2. **`engine-process-exit`** — `_mind:109`: lượt 3 tiến-trình CLI thoát, **đĩa KHÔNG đổi** ⇒ §C/§D chưa từng ghi. Mode thứ 3, khác cả `#53` lẫn `skeleton`. 0 hit mọi sổ.
**ranh vai tự giữ:** ca lead điền sẵn kết-quả cho lượt CHƯA xảy ra (`_mind:136`) **CÓ** vết bền (session-log 3 · STATUS 2) ⇒ **KHÔNG tính vào flag này** — khai để chứng phép đo có phân biệt.
## FLAG-4 — `gap-carry-dropped` — MED-HIGH 🔴 (hạn chót = cửa kế)
**hứa ở** `spec-ke-hoach-ky-ket-hd-28-07-2026.md:458` (**spec BINDING của Wave 1 sắp thi công**): *"Gate rẻ… trước mỗi wave, mở 5 anchor bất kỳ…"*.
**hiện: lead TỰ KHAI vô gia cư và để nguyên**`WAL:18` *"Chưa có nhà trong bản-đồ"*; `_mind:100` nhãn `{gần-chốt}`. `grep -rn "5 anchor"` → 4 hit: **2 ở WAL/`_mind` (sắp bốc hơi) + 2 ở run-folder S157**. **0 hit**`HANDOFF` · `STATUS` · `migration-todos` · `commands/` · `agents/`.
🔴 **Cơ-chế xoá:** `session-end §6.4 Reset WAL` chạy **trong chính closeout này**. Sau reset gate chỉ còn 1 dòng giữa file spec 45.158 B — mà `WAL:17` giao W1 cho `implementer-backend`, người thi công đọc **§③ WAVE 1**, không đọc `:458`.
**resolve:** gate phải có 1 dòng ở nơi người thi công W1 chắc chắn đọc (`HANDOFF` NEXT-em **hoặc** `migration-todos.md` mục Wave 1) **TRƯỚC** khi §6.4 reset WAL.
## FLAG-5 — `gap-decision-sunk` — MED
**hứa ở** `spec-ctx-adopt-26-07-2026.md:27` + `sub-fable-invest-S153.md:88`: T9 = registry-probe + dogfood 4 cửa + mồi-ngầm + **đo wall-clock pause thật → điền số vào `pause.md §2.6-bis` nếu lệch >2×** + **báo hub kết quả dogfood**.
**hiện: lead thu T9 xuống còn 1 khoản.** `grep -n "^## " pause.md` → sections `1·2·2.6·2.7·3·3.5·4·5`**`§2.6-bis` KHÔNG TỒN TẠI**; `grep -n "wall-clock" pause.md` = **0** ⇒ nghĩa vụ trỏ vào một mục không có nhà, **không ai kêu**.
`ls broadcasts/outbox/ai_infra/` → thư SE→hub gần nhất `2026-07-26-…ctx-adopt-executed-va-datum.md` (**trước** khi dogfood chạy). Trọn L7 chạy **4 pause + 4 tiep + 3 vai Ctx thật** (`ctx-curator` ×4 verdict SUA 5/8/8/9 · `ctx-verifier` ×3) ⇒ **có kết quả dogfood thật, 0 thư báo hub**.
**vì sao KHÔNG phải "owner gác":** `[carry:ctx-t9-dogfood]` vẫn đang được lead khai **MỞ** ở HANDOFF + WAL cùng phiên ⇒ lead tự nhận còn nợ, chỉ là **nợ teo mất 3/4 nội dung**.
## INFORM (không nâng FLAG — repeat đã biết)
1. `gap-carry-aged` **KHÔNG fire, có khai lý do**: HANDOFF **byte-identical** trạng thái S153-closeout ⇒ số H24-2 hôm nay **bằng đúng** số @S154 (FIRE=0, streak max 4). Nguyên nhân đã bắt @S154 G-1/G-2, **chưa vá qua 5 nhãn phiên**.
2. `gap-underfill` repeat: `crystallized_backfill.target` **210.000** > headroom **174.463** ⇒ mẫu-số hỏng; `grep -rn "source_order" .claude/commands/` = **0** ⇒ bước rót thủ-công vẫn không tồn tại.
3. 22 FLAG (42)(43)(44)(E2) — **CÓ** surface (WAL:22 · session-log · MIND-4 §D) ⇒ **không sunk**. Nhưng **vắng khỏi danh-sách 7 mục chờ-anh** ⇒ cửa-sổ thứ 5 owner không được hỏi lại.
4. Lỗ hổng an ninh HĐ — **hoãn CÓ CHỦ ĐÍCH**, có vết, **KHÔNG phải gap**.
5. `reviewer/MEMORY.md` + drift-audit 2026-08-01 — đã surface, không flag.
## honest-zero có đo
`gap-owner-specifics` = **0**. Đo 4 quyết-định owner của L7 trên bề mặt bền: *"cấu trúc trình ký GIỐNG, chỉ khác nội dung"* (verbatim `_context:148`, STATUS 1 · HANDOFF 1) · *"chỗ hợp đồng cứ từ từ"* (verbatim `STATUS:646` **+** `:6`) · *"để người dùng tự cập nhật Master data…"* (verbatim `STATUS:6`) · *"nhớ kỹ spec để turn sau chạy"* (`WAL:5`). **4/4 giữ SPECIFICS** ⇒ 0 flag, và vai khai đây là **honest-zero CÓ ĐO**, không phải chưa soi.
## Phân rã class
`gap-carry-dropped` 2 · `gap-decision-sunk` 2 · `gap-incident-unrecorded` 1 · `gap-carry-aged` 0 (INFORM) · `gap-underfill` 0 (INFORM) · `gap-owner-specifics` **0 (honest-zero có đo)**.
`END · TOTAL=5 FLAG`

View File

@ -0,0 +1,64 @@
# lead-stale-auditor (H24 vai-STALE) @close S158 — `LEAD-STALE: 6 FLAG`
> 🔴 Lượt 1 **`#53` garble** (140.9K tok / 31 tool-use). Recover = SendMessage-resume → lượt 2 CLEAN.
> Xác nhận 4/4 chỗ lead tự bắt là THẬT. `_mind-s-7.md:99` khai `3.070 B`, vai đo MIND-1 = **1.894 B** (lead đo 1.868 B — cùng hướng, lệch 26 B do ranh-giới block; **cả hai bác `3.070`**).
## FLAG-1 — `view-residual-asym` — HIGH
- **view:** `docs/STATUS.md:461``Bundle hash live (prod): admin **BK8w3QxU** · user **DYnxSI0T** (đo LIVE @S156…)`
- **source:** `runs/2026-07-27-S155-pe-delete-approver/cicd-verify-s157-diadiem.md:88-89` → admin **`8-QYcMOg`** · eoffice **`DptYR4wL`**; cùng file `:125-126` **control-âm**: hash CŨ `index-BK8w3QxU.js`/`index-DYnxSI0T.js` nay trả **text/html 900 B** ⇒ bundle cũ **đã chết trên prod**. Đối chứng `STATUS:6` + session-log `:88` đều ghi cặp mới.
- **bằng-chứng một-phía:** `git show 3b6fabc -- docs/STATUS.md` chỉ có 2 hunk (`@@ -3,7 +3,9 @@` + `@@ -633,6 +635,17 @@`) ⇒ closeout S157 bump dòng CURRENT + §In Progress, **0 hunk chạm `:461`**.
- 🔴 **hại THẬT:** `cicd-verify-s157-diadiem.md:58` dùng chính ô này làm baseline (*"KHỚP CHÍNH XÁC baseline STATUS S156"*) ⇒ lượt deploy kế so với baseline chết → **hoặc báo "ĐỔI" giả, hoặc che một lần không-rotate**.
- **resolve:** `:461``8-QYcMOg`/`DptYR4wL` neo Run #419 + `6250f39`; hạ cặp cũ xuống mốc-trước.
## FLAG-2 — `view-stale-status` — HIGH
- **view:** `docs/STATUS.md:459``| RAG chunks | **2447** | re-verify S151 (list_projects — **alive**…) |`
- **source (vai đo LIVE bằng chính instrument ô tự trích):** `list_projects``proj_solution_erp.chunk_count = **0**` (0 cho **cả 7 project + shared_global**); `search_memory` ném `Qdrant connection failed … 127.0.0.1:6333 … WinError 10061 actively refused`.
**Lead re-đo độc lập, KHỚP:** `list_projects` trả `chunk_count: 0` toàn bộ 7 project + `shared_global`.
- **đối-chứng nội-bộ 2 chỗ của chính lead:** `STATUS:473` (Recently Done S153) ghi **`RAG DOWN (defer AI_INFRA)`** — *cùng file, cách 14 dòng* · `HANDOFF:7` slot **(39)** `RAG Qdrant DOWN (6333 refused, gotcha #14)`.
- **lệch:** ô canonical CURRENT STATE khai `alive`; thực-tế DOWN từ S153 ⇒ **stale suốt 5 nhãn phiên**; máy chỉ cross-check mig/gotcha nên im.
- **resolve:** lật Note `:459``🔴 DOWN từ S153 (Qdrant 6333 refused) — 2447 = last-known-good @S151`, giữ số cũ có nhãn thời-điểm. 🔸 Ô **canonical** ⇒ vai KHÔNG tự phán số, chỉ trình bằng-chứng; quyết = lead/owner.
## FLAG-3 — `view-stale-count` — MED
- **view:** `docs/STATUS.md:6` (mega-line): `… phiên-LOGIC L7, **4 cửa-sổ** …``… counter **31** …`
- **source:** `.session-counter.json``counter = 32`, `last_ticked_session = "S158"`, head `6c263dd` · `runs/…S158-bookend-close/run.md:1` + `WAL:3` = **window 5**.
- 🔸 **KHÁC cái lead đã bắt** (lead bắt §In Progress `:638` + row `:644/:645`): đây là **dòng CURRENT `:6`**, và 2 datum này **không tự khỏi** nếu closeout chỉ đổi nhãn `S155→S157` thành `S155→S158`.
## FLAG-4 — `view-residual-asym` — MED
- **view:** `.claude/WAL.md:5``[C] 22 FLAG governance treo — nay **4 cửa-sổ**.`
- **source:** `.claude/WAL.md:3` **cùng file, cách 2 dòng**`window 5`.
- **bằng-chứng một-phía:** `git log -p -- .claude/WAL.md``dcfe88f` (`wal: flush 20260728T2011`) sửa **đúng** dòng `updated:`/`closing:` (window 4→5), **để nguyên** dòng `goal:` (lần cuối ghi ở `6c263dd`, window 4).
- **lệch:** một file, một commit, hai mặt — mặt máy ghi bump, mặt người viết không.
- 🔴 **hại:** `WAL.md` nằm trong `tiep_reload.sources` (trọn file) ⇒ cửa `/tiep` kế **nạp thẳng số cửa-sổ sai**.
## FLAG-5 — `view-stale-status` — MED
- **view:** `.claude/WAL.md:21``[ ] Kéo 1 thư fan-out … bằng /adap-apply @bookend`
- **source:** `runs/…S158-day-wake-probe-first/run.md:55` `[x] adap-report … nấc **agreed**` · adap-report 6.360 B mtime **20:04**; WAL được ghi lại **20:06/20:11 = SAU đó**.
- 🔸 Cùng lớp: `WAL:34` carry `thu-moi se=0 all=1 … thư all CHƯA kéo` — mệnh-đề "CHƯA kéo" nay sai.
- **resolve:** tick `[x]` + gắn nấc **`agreed`** (🔴 đừng ghi `executed`), sửa carry `:34`.
## FLAG-6 — `view-stale-count` — LOW
- **view:** `docs/HANDOFF.md:7` — danh sách NEXT-anh đánh số dừng ở **(41)** (`ring5-audit`), khung `@S153`.
- **source:** `WAL:22` — đã cấp tới **(42)** canonRows · **(43)** carry con-trỏ-vs-slug · **(44)** END-line-thành-luật.
- 🔴 **lệch:** sổ owner-facing nói slot mới nhất = 41; sổ lead-facing đã tới 44 ⇒ **3 câu hỏi anh chưa từng xuất hiện ở nơi anh đọc**.
- Kèm số: `tiep_reload.sources` mục-2 (HANDOFF segment mới nhất) đang nạp brief khai `test 532` trong khi canonical `STATUS:457` = **562**.
- **resolve:** thêm segment `Last updated (S155S158)` + **di-trú slot (42)(43)(44)**.
## VERIFIED-CLEAN (4 mục soi mà KHÔNG ra flag — kèm lệnh, chống dương-giả)
1. **Adap không bị khai vống.** `git status --porcelain` rỗng; `git show --stat` 3 commit sau HEAD-phóng chỉ chạm `_tiep-4.md` + `runs/…day-wake-probe-first/**`**0 file trong `.claude/commands/`, `scripts/`, `memory-budget.json`**. 0 surface nói `executed`.
2. **`CLAUDE.md` "nối lại DUY-NHẤT bằng `/tiep`" = ĐÚNG.** `commands/` 19 file, **không có `day.md`**; `/day` chỉ xuất hiện dạng **đề-xuất** trong adap-report.
3. **Roster 23 khớp** 3 nguồn, 0 drift.
4. **Điểm-mù tự-quy-chiếu (bài M-1 @S153) đã soi:** `.claude/agents/lead-stale-auditor.md` §Nhịp khai đúng "bookend vô-điều-kiện + `light_every` STATS-ONLY" ⇒ không tái-phát.
## Phân-rã class (cho `jump_on_class_repeat`)
`view-residual-asym` ×2 · `view-stale-status` ×2 · `view-stale-count` ×2 · `view-stale-header` 0 · `view-stale-role-desc` 0.
🔸 Tally hiện: `view-residual-asym 5` / `view-stale-count 5` / `view-stale-status 2`**cả 3 class lượt này đều fire**; `view-stale-status` chạm ngưỡng `jump_on_class_repeat=3`. Quyết kéo audit sớm = owner/lead.
`END · TOTAL=6 FLAG`

View File

@ -0,0 +1,157 @@
# ring1-audit @close S158 — KIỂM vòng-1 (H1 `tooling-auditor` + H2 `harvest-curator`)
> Vai KIỂM độc-lập, read-only, propose-only. no-self-exempt: tao KHÔNG phải H1/H2.
> Ghi-đĩa-trong-lúc-làm (anti-`#53`). File này APPEND dần; TOTAL-line ở cuối.
## (i) PIN + fail-safe — ĐẠT
| Input | Đường-dẫn | Byte | mtime | Verdict |
|---|---|---|---|---|
| H1 | `runs/2026-07-28-S158-bookend-close/sub-tooling-auditor-close-S158.md` | 5.772 | 2026-07-28 20:18 | ✔ tươi, ruột CÓ CHỮ THẬT |
| H2 | `runs/2026-07-28-S158-bookend-close/sub-harvest-curator-close-S158.md` | 5.319 | 2026-07-28 20:22 | ✔ tươi, ruột CÓ CHỮ THẬT |
| Sổ chạy | `run.md` | 2.569 | 2026-07-28 20:08 | ✔ |
Tuần-tự C4b: file này ghi lúc ≥20:25 > mtime H1 (20:18) và H2 (20:22) ⇒ **chấm bản ĐÃ XONG**, không chấm bản đang bay.
---
## (ii) Verdict per-claim
### H1 — mặt ② vai sub-agent (claim mạnh nhất: roster 23=23=23=23)
| # | Claim H1 | Verdict | Bằng-chứng tao TỰ dựng |
|---|---|---|---|
| H1-7 | đĩa `.claude/agents/*.md` README = 23 | **ĐẠT** | `git ls-files` (nguồn KHÁC `ls`) = 23 · `find` = 23 |
| H1-8 | `hmw.js VALID_ROLES` = 23 | **ĐẠT** | block `hmw.js:22..43` (line-anchored), strip `//` ⇒ 23 |
| H1-9 | `agent-memory/*/` = 23 dir | **ĐẠT** | `find -type d -maxdepth 1` = 23 |
| H1-10 | STATUS row `\| Sub-agents \| **23** \|` | **ĐẠT** | `docs/STATUS.md:458` — pipe-row TỒN-TẠI đúng form H1 trích (không phải câu văn) |
| H1-11 | `diff` tên 3 chiều **identical** | **ĐẠT — mạnh hơn H1 khai** | 3 file tên sau `LC_ALL=C sort` **md5 TRÙNG KHÍT** `b068dbee8005c146a633d17c4a24df97` ⇒ không chỉ identical, mà byte-identical |
| H1-12 | 23/23 có mặt trong README ⇒ 0 vai mồ-côi | **ĐẠT** (caveat) | loop 23 role grep README = 0 missing. ⚠️ caveat tao tự khai: đây là **substring-presence**, chỉ chứng "có nhắc", KHÔNG chứng "có ô mô-tả riêng" |
🔴 **2 lỗi CỦA CHÍNH TAO tự bắt trong lúc dựng số này** (ghi để không ai dùng số rác của tao):
1. Parse `\[(.*?)\]` non-greedy ra **18** ⇒ suýt tố H1 khai khống 23. Nguyên-nhân: `hmw.js:39` chứa `owner-decision [2] TÁCH` — dấu `]` **trong comment** cắt sớm. Đây **đúng cái bẫy H1 khai đã né** ⇒ H1 né THẬT, tao mới là con sập.
2. `comm` in 22 tên ở **CẢ HAI** phía exclusive ⇒ trông như lệch toàn-tập. Nguyên-nhân: python `sorted()` (codepoint) ⟂ shell `sort` (locale) — **comm cần cùng collation**. Ép `LC_ALL=C` ⇒ identical.
⇒ Bài: **số của con-KIỂM cũng phải bị kiểm.** 2/2 lần vênh đầu tiên đều là lỗi tao, không phải lỗi H1.
### H2 — F4 orphan-arithmetic (claim H2 tự dán nhãn "KHỚP ĐỘC-LẬP")
| # | Claim H2 | Verdict | Bằng-chứng tao TỰ dựng |
|---|---|---|---|
| H2-16 | **62 folder có `run.md`** | **ĐẠT** | `find -maxdepth 2 -name run.md \| wc -l` = **62** (tổng dir = 65 ⇒ 3 dir không phải run) |
| H2-17 | orphan-candidate = **4** | **ĐẠT** | chạy **verbatim** loop canonical `tiep.md:44-56` (DUAL-ACCEPT) ⇒ đúng **4**, đúng 4 tên H2 kể |
| H2-18 | S155 = 22 file · S157 = 9 file · 0 synthesis cả hai | **ĐẠT** | `ls \| wc -l` 22 / 9 ✔ · loop canonical liệt cả hai ✔ |
| H2-19 | S156 CÓ `review-synthesis.md` 9.166 B | **ĐẠT** | đối-chứng cùng kỳ đứng vững ⇒ luận-điểm "thói-quen, không phải migration" có chân |
| H2-20 | **3 orphan thật** (4 1 in-flight) | **ĐẠT tại PIN của con-đo** | xem ô 🔴 dưới |
| H2-21 | "= **KHỚP ĐỘC-LẬP** máy `run-chua-gom 3`" | 🔴 **TRƯỢT (LOW-MED, kỹ-thuật — số ĐÚNG, chữ "độc-lập" over-claim)** | xem ô 🔴 dưới |
🔴 **Ca bề-mặt-đo DỊCH DƯỚI CHÂN (đúng class ring1 vẫn gặp: "sai, hay đã-được-xử?")**
Tao chạy lại `scripts/nhip-no-probe.ps1` lúc ~20:30 ⇒ in **`run-chua-gom 4`**, KHÔNG phải 3.
**KHÔNG chấm H2 TRƯỢT vì số này.** Đo mốc bằng `stat`:
- `S158-day-wake-probe-first/run.md` = **20:04**
- `S158-bookend-close/run.md` = **20:08** ← folder do LEAD tạo, chính chỗ đang ghi file này
- dòng probe canonical ghi ở `run.md:20` = `run-chua-gom **3**` (ghi lúc 20:08)
⇒ tại mốc probe chạy, tập orphan = {S155, S157, S158-day-wake} = **3**. Số 3 của H2 **hợp-lệ tại thời-điểm nó đo**; số 4 của tao hợp-lệ tại thời-điểm tao đo. **Cả hai đúng, bề-mặt dời.**
🔴 **Nhưng phần TRƯỢT thật nằm ở CHỮ, không ở SỐ (H2-21):**
H2 viết *"3 orphan thật = **KHỚP ĐỘC-LẬP** máy"*. Hai vế **trùng TẬP** thật, nhưng **không cùng cơ-chế**:
- H2 ra 3 bằng **phán-đoán**: 4 candidate 1 in-flight (F3) được **miễn**.
- Máy ra 3 bằng **chưa-thấy**: `bookend-close/` lúc đó chưa vào tập quét. `nhip-no-probe.ps1` là loop câm — **KHÔNG có khái-niệm "in-flight"**, không miễn-trừ gì hết.
⇒ máy **không hề xác-nhận** phép miễn-trừ của H2; nó chỉ tình-cờ ra cùng số vì thiếu đúng phần-tử H2 định miễn. Gọi đó là "khớp độc-lập" = **mượn uy-tín của máy cho một phán-đoán máy không phát-biểu**.
**Hệ-quả THẬT, không lý-thuyết:** ai đọc lại kỳ sau chạy probe sẽ thấy **4**, đối chiếu "3 khớp máy" ⇒ tưởng **REGRESSION** rồi đi truy 1 orphan không tồn tại. **Đúng class `H2-11 baseline-phantom` tao đã bắt @S153** — H2 tái-phạm cùng lớp: *ghim con-số bay-theo-thời-gian mà không ghim MỐC*.
**Vá rẻ (đề-xuất, lead ghi):** đổi 1 câu ⇒ *"`run-chua-gom 3` đo @20:08 TRƯỚC khi `bookend-close/` tồn tại; chạy lại sau mốc này ra 4 là ĐÚNG, không phải regression."*
### H1 — mặt ① skill (FLAG-1) · ③ plugin · ④ docs · (a) ghost-wire
| # | Claim H1 | Verdict | Bằng-chứng tao TỰ dựng |
|---|---|---|---|
| H1-1 | bảng history dừng ở **Mig 67** (`SKILL.md:89`) | **ĐẠT** | `:89` = row `\| **67** \| AddPeApprovedBudgetSnapshot` — đúng row cuối |
| H1-2 | đĩa có **68** migration, mới nhất `20260727033522_AddPeAllowApproverDelete.cs` | **ĐẠT** | `ls *.cs \| grep -v Designer` = 69 **1** `ApplicationDbContextModelSnapshot.cs` = **68** ✔ tên mới nhất khớp |
| H1-3 | grep `68\|AllowApproverDelete` trong SKILL.md = **0 hit** | **ĐẠT** | `grep -c AllowApproverDelete` = 0 |
| H1-4 | frontmatter **`:4`** tự khai hợp-đồng "row cuối = mới nhất" | 🔴 **TRƯỢT (LOW, cite-drift)** | `:4` thật = `when-to-use:`. Chuỗi hợp-đồng nằm ở **`:3`** (description) + **`:19`** (heading `## Migration history … mới nhất = row cuối bảng`). **Lập-luận ĐÚNG, neo SAI dòng** — đúng class tao bắt @S153 (H1-14 `:122``:121`) |
| H1-5 | STATUS `CURRENT STATE` đã ghi 68 | **ĐẠT** | `docs/STATUS.md:6` = `Mig 68` |
| H1-6 | skill last-touch `c2d01f0` (S152) < Mig 68 land (S155) | **ĐẠT** | `git log -1 .claude/skills/ef-core-migration/` = `c2d01f0 2026-07-26` < mig `20260727` |
| H1-13 | plugin **18 registered / 15 enabled / 3 disabled** (`pr-review-toolkit`·`code-modernization`·`hookify`) | **ĐẠT** | `json.load(~/.claude/settings.json)` (parse KHÁC grep) 18/15/3, đúng 3 tên |
| H1-14 | `model: claude-opus-5[1m]`, `effortLevel: xhigh` | **ĐẠT** | cùng phép json.load |
| H1-17 | FLAG-3 `WAL.md:21` còn `[ ]`; adap-report **6.360 B** | **ĐẠT** | `:21` nguyên-văn `[ ] Kéo **1 thư fan-out** … @bookend` · `stat` = **6360 B** đúng byte |
| H1-18 | chiều xuôi: `commands/day.md` KHÔNG tồn tại · `commands/*.md` = **19** | **ĐẠT** | `ls` = 19 · `day.md` No such file |
| H1-19 | chiều xuôi: **7 file** `.claude/`, **toàn record/spec, 0 file cơ-chế** | **ĐẠT về CHẤT — số đã DỜI** | tao đếm nay = **10 file**. +3 file *đẻ ra sau khi H1 đo* (`sub-lead-stale-close`, `sub-harvest-curator-close`, **và chính file tao đang ghi**). 🔴 Mệnh-đề load-bearing *"0 file cơ-chế"* **HELD**: 10/10 đều WAL/context/run.md/spec/sub-*, 0 command, 0 script |
| H1-21 | chiều ngược: `git status --short` 4 file cơ-chế = **rỗng**; mtime 3 file `.claude/` = **2026-07-26** | **ĐẠT** | git status rỗng thật · `pause.md` 07-26 15:25 · `tiep.md` 07-26 15:24 · `memory-budget.json` 07-26 15:44 · `session_ctx.py` 07-26 14:51 **tất cả TRƯỚC phiên này** |
| H1-15 · H1-16 · H1-20 · H1-22 · H1-23 · H1-24 | F-6 `README:225` CLOSED · FLAG-2 `docs/governance` stale · `_context-s-7:171-172` trong PAUSE-4 · C12 4 dòng `run=` · detector `:1888-1899` cấp-FILE · lỗ usemention `:1895/:1908` | **KHÔNG CHẤM (6)** | ngoài ngân-sách lượt. 🔴 Khai thẳng: **KHÔNG đọc thành ĐẠT.** Riêng C12 tao ghi nhận H1 **tự tố lỗ trong chính bản vá của mình** hành-vi đúng chiều, nhưng chưa kiểm |
### H2 — Corruption · Fidelity · Placement · evidence
| # | Claim H2 | Verdict | Bằng-chứng tao TỰ dựng |
|---|---|---|---|
| H2-22 | Corruption **16 hit / 10 file** | **ĐẠT — engine KHÁC vẫn trùng khít** | H2 dùng **perl** byte-mode; tao dùng **python `bytes.count(b'\xef\xbf\xbd')`**. Scope `.claude/` **16 hit / 10 file** TRÙNG TUYỆT ĐỐI |
| H2-24 | khớp baseline S153 (16/10) **delta 0** | **ĐẠT** | so cùng scope `.claude` apples-to-apples, không phải trùng may |
| H2-23 | *"trên **668** file `.md`"* | 🔴 **TRƯỢT (LOW, scope không khai)** | `.claude` = **676** file · `.claude`+`docs` = **1019** file **17 hit / 11 file** (dôi `docs/gotchas.md`, mtime 07-17 = **cũ**, không phải hỏng mới). Câu "668 file .md" **không nói quét từ gốc nào** người sau quét `.claude`+`docs` ra 17/11 sẽ tưởng **corruption MỚI**. Số H2 đúng; **nhãn scope thiếu** |
| H2-25 | SR-1 evidence `_tiep-4.md` **586 B**, dòng `ctx-verifier:` | **ĐẠT** | `stat` = **586 B** đúng byte · dòng `ctx-verifier:` `:6` |
| H2-26 | SR-2 evidence `sub-invest-day-1.md` **25.440 B**, **183 dòng**, `## §5 PHẢN-BIỆN` `:165` | **ĐẠT — 4/4 byte-exact** | 25440 B · 183 dòng · `:165` = `## §5 PHẢN-BIỆN + giới hạn khai thẳng` |
| H2-27 | F1: `grep -c S158` = **0 hit ở CẢ HAI sổ** | **ĐẠT** | python `.count('S158')` `ctx-verifier/MEMORY.md` = **0** · `investigator-codebase/MEMORY.md` = **0** GAP-3 THẬT, không phải mtime-suy-đoán |
| H2-28 | F5 hai-cây-thước: `_mind` **30.305** raw / **30.041** LF-norm / chênh **264 = CR** · `_context` **0 CR** · headroom thật **2.463** | **ĐẠT — 6/6 số byte-exact** | `_mind-s-7.md` raw **30305**, CR **264**, norm **30041** · `_context-s-7.md` CR **0** · 3276830305 = **2463** · lead " 2.727" = 3276830041 = **2727** |
| H2-29 | Placement: `git status .claude/agent-memory/` **rỗng** | **ĐẠT** | git status rỗng thật containment H-10 sạch |
---
## (iv) 🔴 THÁCH-CLEAN — 2 mặt, **1 CHỊU / 1 THỦNG**
### (a) Mở 1 sub H2 gọi là "harvested" → **CHỊU**
H2 khai `Fidelity STRONG` + tự dựng F5 **chống chính LEAD**. Tao đi tìm chỗ **tự nhẹ tay** **không tìm ra**:
- 6/6 số F5 tái-lập byte-exact, kể cả số làm **lead sai** (headroom 2.463 chặt hơn 2.727 lead ghi).
- 4/4 số evidence (586 · 25440 · 183 · `:165`) đúng tuyệt đối.
- F1 **không dừng ở mtime** dùng `grep -c` nội-dung tao xác nhận 0/0. Đây **tự tố GAP-3 lần 7 vào chính lane harvest của nó**.
**KHÔNG có tự-nhẹ-tay.** H2 lượt-2 **không có dấu hiệu cắt/vội**: mọi số load-bearing đều neo đĩa, `END · TOTAL=6 FINDING` đủ.
### (b) Mở 1 skill H1 "cho qua" → 🔴 **THỦNG — H1 mặt ① UNDER-COUNT**
H1 chỉ flag `ef-core-migration`, 5 skill kia cho qua. Tao mở **`contract-workflow`** (last-touch **2026-05-08**, nhất nhì, 24.452 B):
> `.claude/skills/contract-workflow/SKILL.md:371` — *"PE Service wire xong, **Contract V2 chưa (defer Session 18+)**."*
**SAI trên ĐĨA** (không chỉ sai vs CLAUDE.md tao verify bằng code thật):
- `src/Backend/SolutionErp.Domain/Contracts/ContractLevelOpinion.cs` **TỒN TẠI**
- `…/Persistence/Migrations/20260522052240_AddContractLevelOpinions.cs` **TỒN TẠI** (2026-05-22)
- `ApproveV2Async` trong `src/Backend/SolutionErp.Application/Contracts/ContractFeatures.cs`
Contract V2 **ĐÃ WIRE**; skill khai **CHƯA**. Skill đứng im từ **05-08**, migration land **05-22** **stale ~2,3 tháng**.
🔴 **Nặng hơn FLAG-1 về chất:** FLAG-1 **thiếu 1 row** (gap). Cái này **phát-biểu SAI chủ-động** ai debug duyệt đọc câu đó sẽ đi nhầm đường, đúng chỗ skill sinh ra để chỉ đường.
**Mặt ① của H1 phải là ≥2 finding, không phải 1.** Đề-xuất: nâng mặt thành FLAG-1a (ef-core row 68) + **FLAG-1b (contract-workflow:371 Contract V2)**.
### 🔴 Meta-finding: FLAG-1 là **lần thứ 3 cùng một class**
`SKILL.md:89` sẵn dấu vết: *"(row bổ sung **@S151** **ring1 TRƯỢT-1** bắt bảng dừng **66** trong khi canonical **67**)"*.
S151 ring1 bắt 66-vs-67 **bằng cách thêm 1 row** S158 H1 bắt lại **67-vs-68**.
**Thêm row là vá TRIỆU-CHỨNG.** Bảng chép số canonical `STATUS.md` **cấu-trúc đảm-bảo tái-stale mỗi lần có migration**. Đề-xuất (chỉ NÊU no-self-exempt, tao không sửa): hoặc bảng chỉ giữ **tính-chất/bài-học** trỏ STATUS cho số, hoặc thêm detector so row-cuối vs `ls Migrations/`. kiểu = hẹn gặp lại S16x.
---
## (iii) FALSIFY-LOG — 8 phép (4 HELD / 4 BROKE, **3 BROKE vào CHÍNH TAO**)
| # | Phép PHỦ-ĐỊNH cụ-thể | Kết |
|---|---|---|
| **F-1** | *"VALID_ROLES không đủ 23, H1 khai khống"* parse `\[(.*?)\]` non-greedy ra **18** | **BROKE → vào TAO.** `hmw.js:39` `owner-decision [2] TÁCH` cắt regex sớm. **Đúng cái bẫy H1 khai đã né** H1 THẬT. Line-anchor `^]` 23 |
| **F-2** | *"3 bề-mặt roster chỉ trùng SỐ chứ lệch TÊN"* `comm` 2 chiều | **BROKE → vào TAO** (lần 2): comm in 22 tên **cả hai** phía = collation python-codepoint shell-locale. Ép `LC_ALL=C` **md5 3 file TRÙNG** H1 **HELD, mạnh hơn nó khai** |
| **F-3** | *"orphan-candidate không phải 4"* tự loop `run.md` + thiếu `*-synthesis.md` ra **9** | **BROKE → vào TAO** (lần 3): tao bỏ nhánh **DUAL-ACCEPT dạng-2** (`harvest/*-synthesis.md`, C8 legacy `tiep.md:50-53`). 5 folder `2026-06-18-*` synthesis **lồng trong `harvest/`**. Chạy loop canonical verbatim **4** H2 **HELD** |
| **F-4** | *"16/10 là artifact của perl; engine khác sẽ ra số khác"* python bytes | **HELD.** python **16/10** trùng khít trên scope `.claude` |
| **F-5** | *"`run-chua-gom 3` không tái-lập được"* chạy lại probe thật | **BROKE (vào H2, LOW-MED).** Probe nay in **4**. Số 3 hợp-lệ **tại mốc 20:08**, nhưng nhãn *"KHỚP ĐỘC-LẬP"* over-claim: máy **không có** khái-niệm in-flight, ra 3 **chưa thấy** folder chứ không **miễn-trừ** |
| **F-6** | *"H2 tự nhẹ tay ở đâu đó"* soi F5 (flag chống lead) + evidence bytes | **HELD (H2 sạch).** 6/6 + 4/4 số byte-exact, kể cả số bất-lợi cho lead. Không tìm ra chỗ nhẹ tay |
| **F-7** | *"H1 neo `:4` không có chuỗi nó trích"* mở `:4` | **BROKE (vào H1, LOW).** `:4` = `when-to-use:`; chuỗi thật `:3` + `:19`. Nội-dung đúng, **neo sai dòng** |
| **F-8** | *"5 skill H1 cho qua đều fresh thật"* mở `contract-workflow` | 🔴 **BROKE (vào H1, MED).** `:371` khai *"Contract V2 chưa"* trong khi entity+migration+`ApproveV2Async` đều trên đĩa **mặt ① under-count** |
---
## (iv-b) Số TỰ TÁI-DỰNG — 17 số / **15 khớp · 2 lệch-có-lý-do**
`68` migration · `62` folder run.md · `4` orphan-candidate · `16/10` corruption · `23`×4 roster (+md5) · `18/15/3` plugin · `19` commands · `586` B · `25440` B · `183` dòng · `30305`/`264`/`30041`/`0 CR`/`2463` B · `6360` B · `0/0` hit S158.
**2 lệch:** `run-chua-gom` 3→**4** (bề-mặt dời, lead tạo folder sau khi H2 đo) · `.md` scanned 668→**676/1019** (scope không khai). **Cả 2 KHÔNG phải H2 sai số** **nhãn-mốc/nhãn-scope thiếu**.
---
## TỔNG
**38 claim — ĐẠT 29 · TRƯỢT 3 · KHÔNG-CHẤM 6.**
- **3 TRƯỢT đều lỗi RÌA (nhãn/neo), 0 lỗi số load-bearing:** H1-4 cite `:4``:3/:19` (LOW) · H2-21 "KHỚP ĐỘC-LẬP" (LOW-MED) · H2-23 scope 668 không khai (LOW).
- **1 finding MỚI ngoài claim-set (MED):** `contract-workflow/SKILL.md:371` stale H1 mặt under-count.
- **1 meta-finding:** FLAG-1 = lần **thứ 3** cùng class (ring1 S151 H1 S158); vá-bằng-thêm-row triệu-chứng.
- **#53 lượt-2 của cả H1 H2: KHÔNG thấy dấu hiệu cắt/vội.** Cả hai `END · TOTAL=` đủ, mọi số load-bearing neo được xuống đĩa. Bản thân tao cũng `#53` giữa chừng **ghi-đĩa-trong-lúc-làm cứu trọn**, 0 mất.
🔴 **no-self-exempt:** tao KHÔNG phải H1/H2. Read-only, propose-only mọi đề-xuất trên đây **NÊU**, lead single-writer quyết ghi.
`END · TOTAL=38 CLAIM`

View File

@ -0,0 +1,186 @@
# ring2-audit (vai-KIỂM vòng soi-lead H24) @close S158
> Guard AS-17: APPEND TỪNG VERDICT trong lúc làm. Mọi section kết `---`.
> PIN: `sub-lead-stale-close-S158.md` (6 FLAG, mtime 20:23) + `sub-lead-gap-close-S158.md` (5 FLAG, mtime 20:24).
> Tuần-tự C4b: file này ghi SAU cả 2 (mtime > 20:24). Xác nhận cặp H24 CÓ chạy phiên này ⇒ KHÔNG NO-OP.
## §0 — PIN + fail-safe
- [x] `sub-lead-stale-close-S158.md` tồn tại, 6.527 B, mtime 2026-07-28 20:23:17
- [x] `sub-lead-gap-close-S158.md` tồn tại, 8.384 B, mtime 2026-07-28 20:24:22
- [x] `run.md` tồn tại 2.569 B — taskList `(j)(ii)` cặp H24 + `(j)(ii-bis)` ring2 AUTO sau con-đo
- ⇒ PIN ĐỦ. Chấm tiếp.
---
## §1 — Khuôn slot + enum ĐÓNG (chống pin-bản-cắt 4-A + chống tự-chế class)
- `grep -c '^## FLAG-'` stale = **6** == `END · TOTAL=6 FLAG` ✅ · gap = **5** == `END · TOTAL=5 FLAG`
⇒ pin KHÔNG phải bản-cắt. Guard 4-A (tao tự nêu @S152) có răng cả 2 vai.
- Enum ĐÓNG `lead_self_audit.flag_classes` = 11 class. 11/11 FLAG dùng class TRONG enum, **0 tự-chế**:
stale `view-residual-asym`×2 · `view-stale-status`×2 · `view-stale-count`×2
gap `gap-carry-dropped`×2 · `gap-decision-sunk`×2 · `gap-incident-unrecorded`×1
- 🔸 Khoản `jump_on_class_repeat` nằm ở `h24_cadence` (=3), KHÔNG ở `lead_self_audit` (null).
stale §Phân-rã trích "=3" ⇒ **giá trị ĐÚNG**, chỉ khác nhánh key. Không tính lỗi.
---
## §2 — Tái-dựng số #1 (nặng nhất): RAG chunk_count — PHÉP ĐO THỨ 3
Tao tự gọi `list_projects` (chính instrument mà ô STATUS:459 tự trích):
- `proj_solution_erp` 0 · `proj_vipix_multisite` 0 · `proj_dh_y_duoc` 0 · `proj_namgroup_main` 0
`proj_ashico_erp` 0 · `proj_vipix_ai_infra` 0 · `proj_benhvien_aau` 0 · **`shared_global` 0**
-**8/8 = 0**. Khớp TUYỆT ĐỐI vai-STALE + lead. Ba phép đo độc-lập cùng kết quả.
- `STATUS:461` verbatim = `admin **BK8w3QxU** · user **DYnxSI0T**` ⇒ view-claim FLAG-1 THẬT.
-**stale FLAG-2 ĐẠT** (số load-bearing tự tái-dựng, không tin lời khai).
---
## §3 — Điểm-đáng-soi-nhất: lead khôi phục mồi-ngầm có ĐÚNG không?
Chạy lại đúng lệnh gap FLAG-2 dán:
`git show 82a0457:.claude/sessions/session-7/_mind-s-7.md | sed -n '99p'`
`- Guard post-wave assertion mù 4 path hook — sửa bằng cách soi commit của hook thay vì `git status` {mới-nêu}`
- **KHỚP TỪNG CHỮ** với cái gap dán ở dòng :24. ⇒ pin cho `ctx-audit` **ĐÚNG**.
- Chéo: `sed -n '99p'` HÔM NAY = `🔴 Luật nén _mind **HỞ** … (3.070 B) … {treo-chờ-anh}` ⇒ đúng là **vấn-đề MỞ THẬT**, không phải mồi ⇒ hệ-quả 2-chiều gap mô tả là THẬT.
- Byte: `82a0457` = **14.707 B**; nay = **30.305 B** (gap khai "nay 30.305 B" ⇒ **KHỚP**).
-**gap FLAG-2 ĐẠT** — và đây là FLAG *chặn được* một `ctx-audit` ĐẠT-ảo trong chính cửa này.
---
## §3-bis — Đường thứ 2 (mạnh hơn git-archaeology) mà gap KHÔNG dùng
Tao tìm được nguồn **định-danh mồi bằng NỘI DUNG**, không cần khảo-cổ git:
`runs/2026-07-26-S154-bookend-open/sub-ctx-audit-open-S154.md:199` — chính `ctx-audit` @open viết sẵn
cách chấm nấc-1: `grep -n "post-wave\|2\.1\.9(f)\|soi commit của hook" _mind-s-7.md`.
⇒ Mồi = **"Guard post-wave assertion"**, XÁC NHẬN ĐỘC-LẬP khôi phục của lead. Hai đường khác nhau, 1 kết quả.
🔸 **D-1 (khuyết-tật ngoài FLAG, không hạ verdict):** gap KHÔNG mở `sub-ctx-audit-open-S154.md`.
Mở thì được 2 thứ: (i) định-danh mồi khỏi phải suy từ git; (ii) **biết rủi-ro ĐẠT-ảo đã tự-giảm**
`:199` nấc-1 là **grep nội-dung**, số dòng chỉ xuất hiện ở **nấc-4** làm neo báo TRƯỢT.
⇒ nhánh (a) "ctx-audit đọc dòng 99 → ĐẠT-ảo" **overstated**: quy-trình của chính ctx-audit chặn nó.
FLAG vẫn ĐẠT (neo MỤC là sự-thật, resolve đúng, luật rút ra đúng) — chỉ SEV HIGH là hơi cao.
🔸 **Chronology tao dựng (gap không dựng):**
`82a0457` 07-26 19:28 size **14.707 B**, L99 = **Guard** (mồi) — scribe TRƯỚC pause đầu, đúng persona §43
`8d4075a` 07-27 01:01 size **20.474 B**, L98 = Guard, **L99 = "Trần `mind_ctx_kb`"** — VÀ đây đúng là
commit ĐẦU TIÊN đưa chữ "mồi-ngầm" vào `_context-s-7.md:62` (`git log -S`).
⇒ 🔴 **Neo `:99` LỆCH NGAY TẠI COMMIT SINH RA NÓ**, không phải "trôi dần sau 3 lần nén".
Trong **mọi** trạng-thái đã-commit kể từ lúc mint, `_mind:99` chưa từng trỏ đúng mồi.
⇒ Con số `20.474 B` gap khai "lúc gieo" = size tại **commit mint-neo**, KHÔNG phải lúc gieo mồi (14.707 B).
Cả 2 số tao in ra đây. **Không hạ verdict** (chỉ là nhãn sự-kiện), nhưng kết-luận của gap
*mạnh thêm 1 nấc*: luật "CẤM neo-bằng-số-dòng vào `_mind`" được chứng bằng **stale-at-birth**, không cần viện tới nén.
Bồi thêm: chính `sub-ctx-audit-open-S154.md:210` khai 3 ý chưa-chốt ở `:91 :92 :93`, mà tại `82a0457`
chúng nằm `:95-:98` ⇒ neo-số-dòng hỏng **ngay từ artifact đầu tiên**.
---
## §4 — VERDICT per-FLAG (11 FLAG = 6 stale + 5 gap)
### vai-STALE
| # | class | verdict | tao tự đối-chứng |
|---|---|---|---|
| S-1 | `view-residual-asym` | **ĐẠT** | `STATUS:461` verbatim = `BK8w3QxU`/`DYnxSI0T` ✓ · cicd `:88-89` = `8-QYcMOg`/`DptYR4wL` ✅ĐỔI ✓ · `:125-126` control-âm text/html ✓ · `:58` DÙNG ô này làm baseline ⇒ hại THẬT ✓ · `git show 3b6fabc -- docs/STATUS.md` = **đúng 2 hunk** `@@ -3,7 @@` + `@@ -633,6 @@`, cả 2 **không phủ 461** ⇒ một-phía ĐÚNG. 🔸 số `900 B` là của **admin**; eoffice = **876 B** (tao đọc `:126`) — vi-sai, không đổi kết luận. |
| S-2 | `view-stale-status` | **ĐẠT** | phép đo THỨ 3 (§2): 8/8 `chunk_count=0`. `STATUS:473` + `HANDOFF:7`(39) đối-chứng nội-bộ ✓ |
| S-3 | `view-stale-count` | **ĐẠT** | `STATUS:6` chứa **`4 cửa-sổ`** + **`counter **31**`** ✓ (tao trích đúng chuỗi) · máy: `counter=32`, `last_ticked_session=S158` ✓ · `WAL:3` = `window 5` ✓ |
| S-4 | `view-residual-asym` | **ĐẠT** | `WAL:5` (mega-line) chứa `[C] 22 FLAG governance treo — nay **4 cửa-sổ**` ✓ · `WAL:3` = `window 5` ✓ — **một file, hai mặt** xác nhận |
| S-5 | `view-stale-status` | **ĐẠT** | `runs/…day-wake-probe-first/run.md:55` = `[x] adap-report … nấc **agreed**` ✓ · adap-report **6.360 B** mtime **20:04** ✓ (khớp CẢ size lẫn giờ) · `WAL:3 updated 20:06` **> 20:04** ⇒ thứ-tự đúng · `WAL:21` vẫn `[ ]` ✓ |
| S-6 | `view-stale-count` | **ĐẠT** | `HANDOFF:7` slot max = **(41)** ✓ (tao liệt: 33-41) · `WAL:22` = (42)(43)(44) ✓ · HANDOFF có **4×** `test 532` ✓ · canonical **562** ✓. 🔴 **D-2 neo SAI:** stale ghi *"canonical `STATUS:457`=562"*`:457` thật là dòng **`| Skills | 6 |`**; 562 nằm ở **`STATUS:6`**. Giá trị đúng, **địa chỉ sai**. |
### vai-GAP
| # | class | verdict | tao tự đối-chứng |
|---|---|---|---|
| G-1 | `gap-carry-dropped` | **ĐẠT** | `_context:62` verbatim khớp ✓ · `grep -rl "máy canh" .claude/auto-memory/` = **0** ✓ · tao grep RỘNG `ổn.định.theo.vai` = **5 hit**, vị-trí: `_context:62`(lời hứa) · `_mind:238` · `bookend-open-synthesis.md:74`(nguồn) · ×2 chính file gap ⇒ **0 hit trong sổ bền** ⇒ mệnh-đề load-bearing ĐÚNG. 🔸 **D-3:** grep thứ 2 **không kèm tập-đo** ⇒ đọc trần là "0 repo-wide" = SAI (thật 5). Tái-phạm lỗi tao bắt @S150. |
| G-2 | `gap-decision-sunk` | **ĐẠT** | §3 + §3-bis: khôi phục mồi ĐÚNG TỪNG CHỮ, xác nhận 2 đường độc-lập. Kèm D-1 (SEV hơi cao) + chronology stale-at-birth. |
| G-3 | `gap-incident-unrecorded` | **ĐẠT** | `feedback_agent_return_garble_recover.md` mtime **2026-07-26 01:50** ✓ khớp · `grep -c 'S15[3-8]'` = **0** ✓ · `docs/governance/error-ledger.md` mtime **2026-07-26 01:41** ✓ khớp, S153-158 = **0** ✓. Chi tiết số 27 → §5. |
| G-4 | `gap-carry-dropped` | **ĐẠT** | spec `:458` tồn tại (thật ở `runs/2026-07-28-S157-ke-hoach-ky-ket-hd/`) ✓ · tao grep rộng: 4 hit **đúng chủ-đề** = `_mind:100` · `WAL:18` · spec`:458` · `sub-review-claims-4.md:119` ✓ khớp mô-tả "2 ephemeral + 2 run-folder S157" · **0 hit** ở HANDOFF/STATUS/migration-todos/commands/agents ✓ · `WAL:18` tự khai *"Chưa có nhà trong bản-đồ"* ✓ (3 hit khác là S114/S127, khác chủ-đề — không tính) |
| G-5 | `gap-decision-sunk` | **ĐẠT** | `grep -n '^## ' pause.md` = `1·2·2.6·2.7·3·3.5·4·5`**KHỚP TỪNG MỤC** · `§2.6-bis` KHÔNG có ✓ · `grep -c wall-clock` = **0** ✓ · outbox thật ở `broadcasts/outbox/ai_infra/`, thư SE→hub gần nhất = `2026-07-26-se-to-ai_infra-ctx-adopt-executed-va-datum.md` ✓ tồn tại đúng tên |
**TỔNG: 11/11 ĐẠT · 0 TRƯỢT · 0 KHÔNG-CHẤM-ĐƯỢC.** 3 khuyết-tật NGOÀI flag (D-1 SEV · D-2 neo sai · D-3 grep không tập-đo) + 1 self-inconsistency (§5).
---
## §5 — Số "~27 sự-cố `#53`": tái-dựng ĐƯỢC tới đâu, KHÔNG được từ đâu
Lệnh tao chạy (đọc CHÍNH các dòng gap neo, hôm nay):
- `_mind:199` = *"**0 byte mất** qua **`#53` ×11**"* ✓ resolve đúng
- `_mind:181` = *"`#53` **×13** riêng cửa-sổ này (**cửa 1 = ×11**)"* ✓ resolve đúng
- `WAL:34` = *"**`#53` cửa này ×2**: `cicd-monitor` … + invest lượt 1 `skeleton-ruột-rỗng`"* ✓
- Số học: **11 + 13 + 1 + 2 = 27** ✓ khớp.
- 🔴 Bẫy trùng-đếm tao chủ động thử: `:199`×11 có trùng `:181`×13 không? **KHÔNG**`:181` tự tách
*"riêng cửa-sổ này"* vs *"(cửa 1 = ×11)"***rời nhau**, cộng hợp lệ.
**Phán rõ 2 tầng (không cho qua, cũng không vu-oan):**
-**Tái-dựng ĐƯỢC** tầng *số học + phân-rã + neo còn resolve* + nhãn `cận-dưới ~`**hedge ĐÚNG**.
-**KHÔNG tái-dựng được** tầng *census*: 27 là **cộng 4 con số TỰ-KHAI trong thân `_mind`/WAL**,
không phải đếm sự-cố độc-lập. Tao **không có** đường đo lại 27 ca từ đĩa ⇒ ghi thẳng: **derive-from-body**.
Phần tao xác nhận ĐỘC-LẬP được: **+2 của closeout này** — CẢ HAI pin tự khai *"Lượt 1 `#53` garble"*
ở dòng :3 ⇒ 2/4 ca lead cộng thêm là **quan-sát trực-tiếp**, không phải lời-khai.
🔸 **D-4 (tự mâu-thuẫn TRONG CÙNG 1 tệp):** G-3 neo bằng **`_mind:199` / `:181`** — đúng thứ mà
**G-2 của chính nó** vừa ra luật: *"🔴 CẤM mọi neo-bằng-số-dòng vào `_mind`"*. Hôm nay 2 neo còn trúng;
**block kế là mục**. Đề: G-3 pin lại bằng trích nội dung (`#53` ×13 riêng cửa-sổ này).
---
## §6 — Falsify-log (6 phép · 2 HELD · 4 BROKE)
| # | Phép PHỦ-ĐỊNH tao thử | Kết |
|---|---|---|
| F-1 | *"gap bịa số `20.474 B` lúc gieo"* → quét size mọi commit của `_mind-s-7.md` | **BROKE (nghi-vấn của TAO sai)**`8d4075a` = **đúng 20.474 B**. Số THẬT. Nhưng lộ ra chronology §3-bis. |
| F-2 | *"lead khôi phục NHẦM mồi — tại commit mint `8d4075a`, L99 là dòng `Trần mind_ctx_kb`, KHÔNG phải Guard"* → cố lật | **HELD (khôi phục ĐÚNG)**`sub-ctx-audit-open-S154.md:199` định-danh mồi bằng **grep nội-dung** `post-wave\|soi commit của hook`; và persona §43 buộc scribe **TRƯỚC pause đầu** ⇒ trạng-thái `82a0457` (L99=Guard) mới là mốc gieo. Lật KHÔNG được. |
| F-3 | *"stale FLAG-6 neo `STATUS:457`=562 — kiểm địa chỉ"* | **BROKE (con-đo sai)**`:457` = dòng `\| Skills \| 6 \|`. 562 nằm ở `STATUS:6`. **D-2**. |
| F-4 | *"gap FLAG-1 khai `grep ổn.định.theo.vai = 0 hit`"* → chạy KHÔNG giới-hạn thư-mục | **BROKE phần literal** — repo-wide = **5 hit**. Substance vẫn HELD (0/5 nằm trong `auto-memory/`). **D-3**. |
| F-5 | *"`~27` trùng-đếm cửa 1 hai lần"* → đọc thẳng `_mind:181` | **HELD**`:181` tự tách "riêng cửa-sổ này" vs "(cửa 1 = ×11)". Cộng hợp lệ. |
| F-6 | *"lượt-2 của 2 con-đo có dấu cắt/vội sau `#53`"* → khuôn slot + END + bảng | **BROKE (nghi-vấn của TAO sai)** — 6==6 · 5==5 khớp END TOTAL; mọi FLAG đủ 3 mặt view/source/hại; 0 mục cụt. **Không có dấu vội.** |
---
## §7 — 🔴 THÁCH-CLEAN (bắt buộc): `gap-owner-specifics = 0` "honest-zero CÓ ĐO"
gap tuyên đo **4** quyết-định owner của L7, **4/4 giữ SPECIFICS** ⇒ 0 flag.
Tao KHÔNG chấm lại 4 cái nó nêu — tao soi đúng chỗ nguy: **mẫu-số có vét cạn không.**
**1 lệnh grep marker owner (`anh chốt|owner chốt|lệnh anh|anh ĐẶT TÊN|anh bác|anh VETO`) trên `_context-s-7.md` + `WAL.md`** ⇒ ra **4 hit**, trong đó **2 hit NẰM NGOÀI tập 4 của gap**:
- `_context:78`**"CHIA 2 ĐỢT (anh chốt): đợt 1 = NỀN, đợt 2 = phần người dùng chạm"**
- `_context:103`**anh chốt *"đã xong bước thứ 6 tức CEO duyệt"*** (mốc neo trọn phạm-vi A2)
**2 cái nữa ngay trong `STATUS:6`** mà gap không kể: *"cờ `AllowApproverDelete` **per-NGƯỜI** — **owner chốt (5)**"* · *"🔴 **anh ĐẶT TÊN khúc 7→12 = "đề xuất giá trị ký kết hợp đồng"**"*.
**mẫu-số thật ≥ 6-8, gap khai 4.**
**Tao tự chấm 2 cái nó bỏ sót (không mượn lời ai):**
- `2 ĐỢT``STATUS:6` giữ **`chia **2 ĐỢT** theo lệnh anh vì …`** ⇒ **CÒN specifics** (kèm cả lý do). Không flag.
- `"đã xong bước thứ 6 tức CEO duyệt"` → 🔴 `grep -c 'bước thứ 6'` = **0 / STATUS.md** · **0 / HANDOFF.md**.
Bề mặt bền chỉ còn dạng **DẪN XUẤT**: *"A2 quy trình SAU CEO duyệt (PDF 21 bước, phạm vi **b.7→21**)"*.
⇒ nguyên-văn owner **bốc hơi**, chỉ còn con số phái sinh.
**PHÁN (calibrate, KHÔNG chế flag):**
- Verdict **0** của gap tao **KHÔNG lật**: cả 2 ca ngoài-tập đều tái-dựng được ý owner từ bề mặt bền
(`b.7→21` + "SAU CEO duyệt" chở đủ nghĩa "bước 6 xong"). ⇒ `gap-owner-specifics` **ĐẠT**.
- Nhưng **lời khai coverage TRƯỢT**: *"Đo 4 quyết-định owner của L7"* đọc thành **vét cạn**, thực tế là
**mẫu chọn**, KHÔNG khai tập-bù, KHÔNG khai cách lấy mẫu. Đây là **TÁI-PHẠM đúng lỗi ring2 đã bắt @S154**
(`_mind:97-98`: *"ring2 chấm TRƯỢT khai-phạm-vi của lead-gap vì lời khai không vét cạn"*).
- **M-1 (mục yếu nhất, giao lead cân):** `bước thứ 6` = 0/0 trên 2 sổ owner-facing — mỏng nhất trong cả tập,
và nó **nằm ngoài** 4 cái gap đo ⇒ nếu lead muốn 1 vá rẻ: nhét nguyên-văn vào `STATUS:6` cạnh `b.7→21`.
---
## §8 — Enum ĐÓNG + tally máy (tái-dựng)
- 11/11 FLAG **trong** enum `lead_self_audit.flag_classes` (11 class) ⇒ **0 tự-chế**. Đã kiểm §1.
- `.session-counter.json``class_repeat.counts` = **11 key**, **11/11 kiểu `int`** (bất-biến "chỉ chứa số" còn sống).
🔸 So mốc tao escalate @S151 (counts 10-key, thiếu `gap-underfill`): nay **`gap-underfill=1` CÓ MẶT** ⇒ **D-2/S151 đã ĐÓNG**.
- Đối-chứng tally stale tự trích: `view-residual-asym **5**` ✓ · `view-stale-count **5**` ✓ · `view-stale-status **2**` ✓ — **3/3 khớp máy**.
- `jump_on_class_repeat` = **3** (sống ở `h24_cadence`, KHÔNG ở `lead_self_audit` — key đó `null`). stale trích giá trị ĐÚNG.
- 🔸 **Bất-đối-xứng 2 vai (INFORM, giao lead):** stale CÓ nêu ngưỡng jump (`view-stale-status` 2→3 = chạm).
gap **KHÔNG** nêu, dù `gap-carry-dropped` đang **7** và lượt này fire tiếp ⇒ **8**, vượt ngưỡng 3 từ lâu.
Tao KHÔNG phán jump phải nổ (state `_jump_state_S149` có thể đã tiêu-thụ) — chỉ nêu **một vai khai, một vai im**.
---
## §9 — Ranh vai tao tự giữ
- Tao KIỂM **2 con-đo**, KHÔNG tự soi lead. Mọi mục trên đều neo vào **claim của con-đo**.
- no-self-exempt: tao ≠ `lead-stale-auditor` / `lead-gap-auditor`
- Propose-only: file này read-only-với-repo (chỉ ghi chính nó trong `runs/`). Lead single-writer.
- Tuần-tự C4b: pin mtime 20:23 / 20:24 < file này tao chạy SAU cặp H24
`END · TOTAL=11 CLAIM`

View File

@ -0,0 +1,52 @@
# tooling-auditor (H1) @close S158 — `TOOLING: PASS_WITH_FLAGS — 3 finding`
> 🔴 Lượt 1 **`#53` garble** (trả câu mở đầu ý-định, 103.8K tok / 31 tool-use). Recover = SendMessage-resume in-session → lượt 2 CLEAN.
> Lead scribe (vai propose-only, không tự ghi).
## ① skill — FLAG-1 (MED, tái-phát class ring1 @S151)
`.claude/skills/ef-core-migration/SKILL.md:89` — bảng Migration history **dừng ở Mig 67**. Đĩa có **68** file migration, mới nhất `20260727033522_AddPeAllowApproverDelete.cs` (S155). Grep `68|AllowApproverDelete` trong SKILL.md = **0 hit**.
🔴 Nặng hơn "thiếu row" thường vì **chính frontmatter tự khai hợp-đồng** (`:4`): *"số hiện tại + mới nhất → docs/STATUS.md canonical + **row cuối bảng history trong skill này**"* ⇒ row-cuối ĐƯỢC khai là nguồn "mới nhất" ⇒ **đang nói dối chính hợp-đồng của nó**. STATUS `CURRENT STATE` đã ghi 68; skill lệch 1.
Chu-kỳ sót: skill last-touch `c2d01f0` (S152) < Mig 68 land (S155) **3 closeout liên tiếp không bù**.
**Vá:** thêm 1 row Mig 68 vào cuối bảng. KHÔNG đụng frontmatter (B1 no-hardcode đang đúng).
## ② vai sub-agent — PASS (0 finding)
Roster **23 = 23 = 23 = 23** khớp 4 bề-mặt, đo bằng **ĐẾM PHẦN-TỬ + `diff` tên** (không grep-theo-số):
đĩa `.claude/agents/*.md` README = 23 · `hmw.js VALID_ROLES` = 23 (anchor `^const VALID_ROLES = \[``^\]` + strip `//` bẫy parse `]` trong comment S153) · `agent-memory/*/` = 23 dir · STATUS row `| Sub-agents | **23** |`.
`diff` tên rolesdiskagent-memory = **identical 3 chiều**. 23/23 mặt trong README 0 vai mồ-côi.
## ③ plugin — PASS (0 finding, 0 delta)
`enabledPlugins` = **18 registered / 15 enabled / 3 disabled** (`pr-review-toolkit` · `code-modernization` · `hookify`) identical baseline S153. Marketplace 37 · skill standalone 23 · `model: claude-opus-5[1m]`, `effortLevel: xhigh` 0 đổi.
**Nợ F-6 S153 CLOSED-verified:** `agents/README.md:225` nay phát biểu đúng tầng *"3 site ĐANG `enabled:true`, nấc THẬT = enabled nhưng CỐ Ý KHÔNG DÙNG (`used`, không phải bit enable)"*.
## ④ docs — FLAG-2, FLAG-3
**FLAG-2 (LOW-MED)** `docs/governance/` README/index stale, **cùng vết S153 F-7, sang phiên thứ 3 chưa vá**. Không phải drift số **doc trỏ-sai lớp**. Đề: 1 lượt @closeout, **hoặc** hạ xuống backlog ngày (`2026-08-01` monthly) để thôi tái-xuất mỗi bookend 🔴 *"flag sống 3 phiên mà không ai vá = flag đã mất răng"*.
**FLAG-3 (LOW, INFORM)** `.claude/WAL.md:21` còn `[ ]` cho *"Kéo 1 thư fan-out … bằng `/adap-apply` @bookend"* **ĐÃ làm xong phiên này** (adap-report 6.360 B, nấc `agreed`). Nêu để closeout tick.
## (a) Ghost-wire `day-wake-probe-first` — CẢ HAI CHIỀU: **SẠCH**
**Chiều xuôi** (khai như-thể đã wire): **0 site**. `.claude/commands/day.md` KHÔNG tồn tại (`commands/*.md` = 19 file, không `day`). Grep `day-wake-probe-first|wake-probe|/day` toàn `.claude/` = 7 file **toàn record/spec, 0 file cơ-chế**; `docs/` = 1 (adap-report). 2 site "sống" đều khai ĐÚNG nấc.
🔴 Về `_context-s-7.md:171-172` (*"CHƯA kéo"*): nằm trong `### PAUSE-4` của section **`## (b) FLOW — append-only @pause-only`** **frozen-in-time record, KHÔNG phải bề-mặt prescriptive**. Theo luật S143, **sửa nó = giả-mạo** KHÔNG flag, KHÔNG .
**Chiều ngược** (đã wire doc khai chưa lớp H18 class-2 bắt @S146): **0 site**. `git status --short` trên `pause.md` · `tiep.md` · `memory-budget.json` · `scripts/session_ctx.py` = **rỗng**; mtime 3 file `.claude/` = 2026-07-26 (S152/S153, TRƯỚC phiên này).
**câu "0 file cơ-chế được sửa" của adap-report là ĐO ĐƯỢC, không phải tuyên-bố suông.**
## (b) C12 — detector ĐÚNG lúc bắn; nay ĐÓNG; **và lộ 1 lỗ THẬT trong chính detector**
- **Hiện tại:** session-log S155-S157 **4 dòng khớp `run=`** `:35` (câu văn, backtick) + `:40/:41/:42` (3 dòng đăng-ký).
- **Theo code** (`governance-detectors.ps1:1888-1899`): guard **cấp-FILE**, gặp 1 dòng `run=` `break` chạy lại C12 **không bắn nữa** flag ĐÓNG.
- **Bản KHÔNG Goodhart** (vai chủ động soi đúng câu hỏi này): 3 dòng `:40-42` mang **nội-dung mới có thật** (3 run-id + 3 run-folder chưa từng đăng-ký bền), khớp từng chữ remediation-text `:1916`.
- 🔴 **LỖ THẬT (INFORM, không vào TOTAL):** `:1908` skip dòng chứa `C12|governance-detectors`, nhưng guard `run=` `:1895` chạy **TRƯỚC** **không có discriminator use/mention** riêng `:35` (câu văn KỂ CHUYỆN `run=` trong backtick) **đã đủ làm im cả file** kể cả khi `:40-42` không tồn tại.
**mọi session-log tương lai chỉ cần KỂ VỀ C12 là tự-miễn-nhiễm C12.** Đây đúng lớp **citation-trap / use⟂mention**.
**Vá đề-xuất:** `:1895` loại dòng self-reference trước khi xét `$runRegRx` (dùng `$mentionRx` sẵn), **hoặc** siết `$runRegRx` thành neo `wf:.*run=` cho khớp form đã khai `:1836-1837`.
- **Caveat tác giả giữ nguyên** (`:1846-1853`): guard cấp-FILE nên *"đăng-ký run A rồi spawn B raw"* KHÔNG bắt được; đây **self-report net**. `[ok]` = *"phiên này CÓ đăng-ký"*, **KHÔNG phải** *"0 bypass"*.
## new-alloc audit: **0 action**
0 skill mới · 0 plugin mới · bảng map `README.md:216-231` vẫn phủ đúng tập hiện .
`END · TOTAL=3 FINDING`

View File

@ -0,0 +1,41 @@
# adap-synthesis — `2026-07-28-Governance-day-wake-probe-first-resume` (S158)
> Lead-written, VERIFIED. Dạng-1 phẳng (`<stage>-synthesis.md`) theo hợp-đồng `workflows/README.md:17` — RAW `sub-` ⟂ VERIFIED `-synthesis.md`.
> 🔴 **Vì sao file này tồn tại:** lead ban đầu ghi kết-quả vào `## Kết quả` trong `run.md` = **dạng-3, RETIRED @S123** ⇒ `harvest-curator` F2 xếp folder này **ORPHAN**. Nội-dung đã đủ, thiếu đúng **tên file theo hợp-đồng**. Vá bằng file này, không phải bằng cách nới luật.
## Verdict
**Nấc `agreed`** — thiết-kế chốt + spec kết-tinh, **0 file cơ-chế bị sửa**. `day.md` chưa tồn tại; `pause.md` · `tiep.md` · `session_ctx.py` · `memory-budget.json` **nguyên trạng** (`git status` rỗng, mtime 07-26 = S152/S153).
Verify độc-lập: `tooling-auditor` @close soi **ghost-wire CẢ HAI CHIỀU = 0 site**, kết luận *"câu '0 file cơ-chế được sửa' là ĐO ĐƯỢC, không phải tuyên-bố suông"*; `ring1-audit` chấm claim này **ĐẠT**.
## Engine
`/fable-real investigator-codebase` (Fable, single deep-pass, propose-only) — vai do owner GÁN qua AskUser.
Return **CLEAN 0-garble**: `FIT-DU-4 — 14 đề-xuất, 4 phản-biện`. Đĩa `sub-invest-day-1.md` **25.440 B / 183 dòng**, `## §5 PHẢN-BIỆN` `:165`, TOTAL-line `:183` tự cộng 4+2+3+2+3 = 14 ✔ (harvest-curator verify byte-exact).
🔸 Đây là **1 trong 3 lane duy nhất của phiên KHÔNG garble** — và là lane được ép ghi-đĩa từ prompt đầu.
## 2 tiền-đề của LEAD bị BÁC (ghi lại, không giấu)
1. **"SE có squash ⇒ có sha mồ-côi" — SAI.** Đo: `cat-file -e` + `is-ancestor` trên 8 marker → **sống 8 / mồ-côi 0**. Squash `session-end` chỉ gọt trailing-`wal:` **chưa push**; 6/8 sha đã push. *(Lead re-đo độc lập, khớp.)* 🔴 Guard vẫn giữ — tiền lệ S127 dangling có thật, và **chính `/day` tự đẻ điều kiện orphan**.
2. **"Probe nên tái dùng Sàn-3" — BÁC, có bằng chứng cùng-cửa.** Hai phép cho verdict **NGƯỢC NHAU** tại chính S158: Sàn-3 ② **HIT** (2 commit non-`wal:` trước `origin/main`) ⟂ anchor-delta **0 ⇒ CLEAN**. Vì hỏi **hai câu khác nhau**: *"tồn-tại việc dở"* (neo `origin/main`) ⟂ *"đổi so điểm dừng"* (neo marker pause). ⇒ dựng phép-2 hợp lệ, B1 không cấm.
## Số SE (BYTE — cố ý KHÔNG quy token)
`tiep_reload` = **122.115 B** / 5 nguồn (hub: 439.328 B / 8 file ⇒ **nền SE nhẹ hơn 3,6×**). Cửa CLEAN sẽ SKIP **86.441 B (70,8%)** + 1 spawn `ctx-verifier`.
Bẫy-một anchor: **4/4 THẬT ở SE**. Bẫy-hai mồ-côi: **0/8**. Drift marker: `_snapshot` **3/4**.
## Dogfood — SE có 1 datum, hub tự khai có 0
Cửa `/tiep` @S158 probe ra **CLEAN** (`_pause-4` head-sha `d7eaece` → carrier `6c263dd` = HEAD; cây sạch; 0 sentinel) ⇒ **lẽ ra đi đường dậy-nhẹ**, mà lead đã trả giá full.
🔸 **1 điểm dữ-liệu, KHÔNG phải bộ số.**
## Còn nợ
- Owner gật **3 chỗ chạm canonical**: `tiep.md §0` ⑤(b) r-set · `CLAUDE.md` câu *"nối lại DUY-NHẤT bằng `/tiep`"* · `check-email.md` nhịp 4→5 cửa
- Thi công (lead tự tay) + **workflow REVIEW RIÊNG** (Harness-9) + dogfood 2 cửa → gửi hub kèm run-id
## Con-trỏ
`run.md` · `sub-invest-day-1.md` (25.440 B) · `spec-day-wake-probe-first-28-07-2026.md` · `docs/governance/adap-reports/2026-07-28-Governance-day-wake-probe-first-resume.md`
<!-- END · NAC=agreed · 14 DE-XUAT · 4 PHAN-BIEN · 2 TIEN-DE-LEAD-BI-BAC · 3 CHO-OWNER -->

View File

@ -0,0 +1,64 @@
# RUN — adap `2026-07-28-Governance-day-wake-probe-first-resume` (S158)
> Engine: `/fable-real investigator-codebase` (LỆNH-A, per-invocation H21 — single top-model deep-pass, propose-only).
> Vai do anh GÁN qua AskUser @S158. Phạm-vi anh chốt: chạy CẢ `/check-email` + `/adap-apply`, **adap-apply là chính**.
> Phiên-LOGIC L7, window 5. Nhãn-phiên S158. HEAD lúc phóng = `6c263dd`.
## Bối cảnh
- **`/check-email` ĐÃ CHẠY (lead, xong):** verify bằng **NỘI DUNG** không phải tên file — 22/22 file
`AI_INFRA/broadcasts/outbox/se/` có mặt trong `broadcasts/inbox/ai_infra/`, **0 byte-drift** (`cmp`).
`se=0` là THẬT, và không có ca stamp-then-edit trên thư cũ (H18). Không có gì để kéo ở kênh directed.
- **`/adap-apply` — 1 thư fan-out pending** (kênh `all`, watermark ≤2026-07-15):
`2026-07-28-Governance-day-wake-probe-first-resume` · 13.832 B · `content_sha256: ef05b7da…`
· `reviewer_gate: PASS r3` · `nac: published`**qua cổng, hợp lệ để áp**.
## PROJECT-FIT của SE — hạng CAO NHẤT
Thư chia 4 hạng fit. SE rơi vào hạng **"Fit đủ bốn khoản"** vì có ĐỦ cả 2 nền:
- nền 17-07 (kit phiên-logic): `.claude/sessions/session-<N>/` + cặp `/pause`+`/tiep` + WAL — **CÓ**
- nền 25-07 (vòng-canh 3-vai + nạp-nền mặc-định mỗi lần nối): `ctx-curator`/`ctx-verifier`/`ctx-audit`
+ khoá `tiep_reload` trong `memory-budget.json`**CÓ** (adopt S153)
⇒ khoản tiết-kiệm lớn nhất của F1 (bỏ nạp-nền + bỏ tầng kiểm-lúc-đọc khi CLEAN) **áp dụng được trọn vẹn**.
## 🔴 Dữ-liệu dogfood SE có mà hub KHÔNG có (thư tự khai "dogfood: 0 phiên")
Chính cửa `/tiep` @S158 này là **một ca đo được**, đo TRƯỚC khi đọc thư (không phải dựng sau cho khớp):
- `_pause-4.md` head-sha = `d7eaece` · commit kế tiếp = `6c263dd` (`wal: pause`) = **HEAD hiện tại**
- `git status --porcelain` = **rỗng** · 0 checkpoint mới hơn marker · 0 sentinel `closing:` treo
⇒ Theo F3 (anchor = commit-chốt-dừng đầu tiên SAU head-sha marker), delta = **0 commit** ⇒ probe cho **CLEAN**
⇒ cửa này **lẽ ra đi đường dậy-nhẹ**, nhưng lead đã trả giá full: nạp-nền theo `tiep_reload` + spawn `ctx-verifier`.
🔸 Đây là **1 điểm dữ-liệu, không phải bộ số** — đừng đọc thành "đã dogfood xong".
## taskList snapshot (1 lane — single deep-pass)
1. `investigator-codebase` (Fable, deep-pass, **propose-only**) — đọc thư + đo repo SE thật → đề-xuất
[đề-bài · cách áp · checklist acceptance ĐO ĐƯỢC] cho 4 khoản F1-F4, tailor FORM theo SE.
🔴 Engine **KHÔNG ghi** file spec — lead verify rồi lead ghi (H21 ① honest-note (c)).
## Nấc kế (lead, sau khi engine trả)
- Lead verify propose → ghi `spec-day-wake-probe-first-28-07-2026.md` 3 heading cố-định.
- Harness-9 mandate: adap = **2 workflow** (IMPLEMENT + REVIEW RIÊNG) + report về AI_INFRA kèm run-id.
⇒ run này = nấc **propose/implement-design**; REVIEW là workflow riêng, CHƯA chạy.
- `docs/governance/adap-reports/2026-07-28-Governance-day-wake-probe-first-resume.md` — nấc G-011 + evidence.
## Stages
- [x] Lead: `/check-email` full-pass (content-verify 22/22, drift 0)
- [x] Lead: scaffold run-folder + đo dogfood-datum cửa này
- [x] `investigator-codebase` deep-pass propose — return **CLEAN 0-garble**, `FIT-DU-4 — 14 đề-xuất, 4 phản-biện`;
đĩa `sub-invest-day-1.md` **25.440 B** (ruột có chữ thật, không phải khung rỗng — verify theo bài học S157)
- [x] Lead verify + ghi spec-file 3-mục — `spec-day-wake-probe-first-28-07-2026.md`
🔴 Lead **re-đo độc lập 2 số load-bearing**, cả 2 KHỚP engine: mồ-côi **0/8** (`cat-file -e` + `is-ancestor`)
· `_snapshot` **3/4** vs `_pause` 4 (PAUSE-4 thiếu vết auto-snap)
- [x] adap-report — `docs/governance/adap-reports/2026-07-28-Governance-day-wake-probe-first-resume.md`, nấc **agreed**
- [ ] 🔴 Owner gật 3 chỗ chạm canonical (`tiep.md §0` ⑤(b) · `CLAUDE.md` · `check-email.md`)
- [ ] Thi công (lead tự tay) + **workflow REVIEW RIÊNG** (Harness-9) + dogfood 2 cửa → report hub
## Kết quả
- **Nấc đạt: `agreed`** — thiết kế chốt + spec kết tinh, **0 file cơ-chế bị sửa**.
- **Lead bị bác 2 tiền-đề** (ghi lại làm vết, không giấu): (1) "SE có squash ⇒ có sha mồ-côi" → đo ra **0/8**;
(2) "probe nên tái dùng Sàn-3" → bằng chứng cùng-cửa cho **verdict ngược nhau** ⇒ dựng phép-2 là đúng.
- **4 phản-biện gửi ngược hub** + **1 datum dogfood** (hub tự khai có 0).

View File

@ -0,0 +1,148 @@
# SPEC — Lệnh DẬY-NHẸ probe-first cho SOLUTION_ERP (adap `2026-07-28-Governance-day-wake-probe-first-resume`)
> Engine: `/fable-real investigator-codebase` (Fable, single deep-pass, propose-only) — anh GÁN vai @S158.
> Pipeline H21 ①: engine propose → **lead verify** → **lead ghi (file này)** → worker thực-thi theo spec.
> Propose đầy đủ: `sub-invest-day-1.md` (25.440 B, cùng run-folder). File này = bản lead ĐÃ VERIFY.
> 🔴 **CHƯA THI CÔNG.** 3 chỗ chạm canonical cần anh gật — xem §③ cuối.
---
## ① TÍNH-NĂNG / ĐỀ-BÀI
Thêm **một đường dậy RẺ** cho vòng đời tạm-dừng/nối-lại: khi máy **chứng minh được 0-delta** kể từ điểm dừng,
mở cửa sổ mới **không phải trả giá `/tiep` trọn** (nạp-nền + spawn vai kiểm-lúc-đọc). Mọi trường hợp khác **tự nâng**
về `/tiep` đầy đủ. Kèm **guard chống-trùng** ở bước-0 của `/pause` + `/tiep`, và **marker dậy đếm-được từ đĩa**.
**Vì sao SE cần:** SE fit hạng cao nhất của thư (có ĐỦ nền 17-07 kit phiên-logic + nền 25-07 vòng-canh 3-vai
+ `tiep_reload`) ⇒ khoản tiết-kiệm lớn nhất của F1 áp dụng trọn.
**Giá đo được ở SE (engine đo tươi, đơn-vị BYTE — 🔴 CẤM quy ra token, thư nói rõ token nằm trong dải mở):**
| Nguồn `tiep_reload` | Byte |
|---|---|
| `docs/STATUS.md` (2 đoạn khoanh) | 3.295 + 56.210 |
| `docs/HANDOFF.md` (segment mới nhất) | 4.352 |
| `.claude/WAL.md` | 5.369 |
| `_mind-s-7.md` | 30.305 |
| `_context-s-7.md` | 22.584 |
| **Tổng** | **122.115 B** |
Cửa CLEAN sẽ **SKIP 86.441 B (70,8%)** + **1 spawn `ctx-verifier`**.
🔸 So hub: hub 439.328 B / 8 file — **nền SE nhẹ hơn 3,6×**, nên lợi tuyệt-đối nhỏ hơn hub. Khai thẳng, đừng mượn số hub.
**🔴 Datum dogfood SE có mà hub KHÔNG có** (thư tự khai *"dogfood: 0 phiên"*) — đo TRƯỚC khi đọc thư:
chính cửa `/tiep` @S158 này probe ra **CLEAN** (anchor `6c263dd` = HEAD, cây sạch, 0 sentinel) ⇒ **lẽ ra đi đường dậy-nhẹ**,
mà lead đã trả giá full. **1 điểm dữ-liệu, KHÔNG phải bộ số.**
---
## ② CÁCH IMPLEMENT (per-khoản F1-F4, tailor FORM theo SE)
### 🔴 Câu khó nhất — đã có phán quyết CÓ BẰNG CHỨNG: **DỰNG PHÉP-2, KHÔNG tái dùng Sàn-3**
Lead vào cửa này **nghiêng về tái dùng Sàn-3** (sợ 2-nguồn-sự-thật, B1). **Engine bác, và bác đúng** — bằng chứng
lấy từ CHÍNH cửa S158 này, nơi hai phép cho **verdict NGƯỢC NHAU**:
- **Sàn-3 tín-hiệu ②: HIT** — `origin/main..HEAD` có 2 commit non-`wal:` (`d7eaece` spec · `3b6fabc` dọn nợ sổ). *(lead tự đo @§0, độc lập.)*
- **anchor-delta: 0 ⇒ CLEAN** — `_pause-4` head-sha `d7eaece` → carrier `6c263dd` = HEAD. *(lead tự đo, độc lập.)*
⇒ Hai phép trả lời **hai câu KHÁC NHAU**: Sàn-3 hỏi *"có tồn-tại việc dở không?"* (neo `origin/main`) ⟂ probe hỏi
*"có gì ĐỔI so với điểm dừng không?"* (neo marker pause). **Khác câu hỏi thì khác nguồn sự-thật là hợp lệ — B1 không cấm.**
**4 ràng hygiene BẮT BUỘC kèm theo** (thiếu là thủng):
1. Sentinel `closing:` **GỌI CHUNG** tín-hiệu ③ của Sàn-3 (con-trỏ, không chép logic).
2. Mọi verdict DELTA **đổ về `/tiep`**`/tiep §0` giữ độc quyền là nhà DUY NHẤT phán chữ "sạch".
3. **CẤM dùng từ-vựng "sạch"** trong `/day` (dùng `CLEAN-delta`) — chống người đọc nhầm thành phán quyết Sàn-3.
4. `/tiep §0` ⑤(b) ORPHAN-L: **r-set phải cộng `_day-*`** — thiếu thì phiên có `/day` sẽ **kêu oan**; và **RE-RUN fault-inject** block đó.
### F1 — probe rẻ, chỉ-đọc
- **NEW** `.claude/commands/day.md` — 2 nhánh, bước probe đứng **TRƯỚC**.
- **EXTEND** `scripts/session_ctx.py` + sub-command `day-probe` (`--json`). Tái dùng `_TS_KEY_RE` sẵn có
(`:48-55` đã đón trước reader loại này). 🔴 Glob **phải lọc theo TÊN FILE** kẻo ăn nhầm `_mind-s-<N>.md`.
- Chọn marker cuối bằng **dấu-thời-gian GHI TRONG file**, KHÔNG dùng mtime (Dropbox chạm lại mtime — SE chạy trong Dropbox).
- **Khoá `day_wake`** trong `memory-budget.json`, có **allowlist dirty**. 🔴 Bắt buộc gồm `.claude/governance/.session-counter.json`
— nó dirty NGAY lúc probe chạy (tick fire ở cửa vào) ⇒ thiếu allowlist thì F1 **chết nửa số ca**.
- CLEAN → nạp lõi (WAL + `_mind` mới nhất), **SKIP** nạp-nền + **SKIP** spawn `ctx-verifier`.
- Nghiêng an-toàn: probe lỗi / nghi ngờ ⇒ coi là **DELTA**.
### F2 — guard chống-trùng ở HAI lệnh cũ
- `pause.md` **§0**: marker cuối đã là `_pause-*` + probe CLEAN ⇒ **no-op**, 0 marker/0 commit/0 spawn.
🔴 **Răng thật, không phải lý thuyết:** double-pause hiện đốt **1 spawn `ctx-curator`** (~100K floor theo config).
- `tiep.md` **§-1**: probe CLEAN ⇒ route sang `/day`.
- Cửa thoát cưỡng chế `--full` ở cả hai để anh ép chạy trọn.
### F3 — anchor: **SE-form MẠNH HƠN hub**
- **Bẫy-một XÁC NHẬN 4/4 THẬT ở SE:** mỗi `_pause-i` head-sha → commit kế tiếp **chính là** `wal: pause` của nó
(`8d4075a` · `976945c` · `73166c5` · `6c263dd`) ⇒ đếm thô từ head-sha ra **DELTA-giả 100%**.
- **SE-form:** anchor = **carrier-commit** `git log --diff-filter=A -1 -- <marker>` (commit ĐẦU TIÊN thêm chính file marker).
Đo **8/8 resolve được**; **sống-sau-squash by construction**; và **nuốt luôn bẫy-một** (không cần bước resolve riêng).
`head-sha` trong marker hạ xuống làm **fallback**, guard đúp.
- **Bẫy-hai (sha mồ-côi): 0/8 ở SE hôm nay — tiền-đề của lead SAI, đã bác.**
Squash `session-end` §5.0/§5.2 **chỉ gọt trailing-`wal:` CHƯA push**; 6/8 sha đã push nên bất khả mồ-côi.
*(lead re-đo độc lập: `cat-file -e` + `is-ancestor` → **sống 8 / mồ-côi 0**.)*
🔴 **Guard VẪN BẮT BUỘC**, 3 lý do: (i) tiền lệ **S127** `f9fa77d6` dangling có thật — và nó chứng luôn rằng
`cat-file -e` **một mình THỦNG** (object còn, ancestor mất) ⇒ **phải kèm `is-ancestor`**; (ii) `6c263dd` (đang là
anchor `_pause-4` **và** `last_ticked_head`) nằm trong vùng fold-able; (iii) 🔴 **chính feature `/day` tự đẻ điều kiện
orphan** — chuỗi cửa-nhẹ Q&A sản xuất trailing-`wal:` thuần, đúng thứ squash gọt.
- Mồ-côi ⇒ verdict `anchor-lost` **khai TO** trong report + tự nâng. Hỏng-an-toàn nhưng **phải CÓ TIẾNG**.
### F4 — marker dậy đếm-được
- `_day-<i>.md` **7 trường**, khuôn `_pause-<i>`/`_tiep-<i>`. **0 commit riêng** — hook `wal-flush.ps1` path ④
(`.claude/sessions/`) chở miễn phí ⇒ **KHÔNG nới hook****KHÔNG đẻ điểm mù mới** cho Sàn-3.
- **Falsifier 2 chiều** cho tầng audit: *CLEAN-giả* (marker ghi CLEAN mà có commit thật giữa anchor và ts ⇒ FLAG)
· *luôn-DELTA* (mỗi lần tự nâng phải khai signals/`anchor-lost` ⇒ chuỗi tự-nâng dài bất thường là soi được).
- **Drift F4 SE-local đo được (gửi hub — đúng shape s109 hub kể):**
**`_snapshot` 3/4 vs contract auto-snap `pause.md §2.6(D)`** — PAUSE-4 **thiếu vết snapshot**. *(lead re-đo: snapshot 3, pause 4.)*
`_context` PAUSE **4/4 khớp**. 🔸 Hai thứ KHÔNG tính là drift: `_tiep` 3-vs-4 (write-order benign) ·
WAL "window 4" / STATUS "counter 31" (by-design ghi tại pause cửa trước).
### Phản-biện / SKIP (engine nêu, lead nhận)
1. **Không quy token** — chỉ báo byte. Đây chính là lỗi làm thư hub trượt vòng r1 (dán nhãn "token tự đo" lên proxy ký-tự).
2. **Không tái dùng Sàn-3** làm probe (đã luận ở trên).
3. **Không nới hook** để chở `_day-*` — path ④ có sẵn.
4. Lợi tuyệt-đối SE **nhỏ hơn hub 3,6×** — đừng bán bằng số hub.
### 🔎 2 phát hiện NGOÀI đề-bài (engine tự nêu — lead xác nhận cả 2)
- 🔴 **`docs/HANDOFF.md` segment mới nhất = S153**, không có segment cho S155-S157 ⇒ **nguồn-2 của `tiep_reload`
đang nạp brief cũ 3 nhãn phiên**. *(Lead đụng đúng chỗ này ở §2.6 cửa này: đọc HANDOFF thấy "Last updated: 2026-07-26 (S153)".)*
- `_tiep-1.md` head-sha ghi **7 ký tự** trong khi 7 marker còn lại ghi đủ 40 ⇒ **form drift trong cùng một loại marker**
(nếu probe so sánh chuỗi thay vì gọi git thì sẽ vấp).
---
## ③ CHECKLIST — acceptance ĐO ĐƯỢC (A1-A8, mỗi phép CÓ ĐƯỜNG TRƯỢT)
> 🔴 Sàn: phép mà **implement sai vẫn PASS** là phép **0-bit**. Thư này bị chính reviewer của hub đánh trượt **2 vòng**
> vì lỗi loại đó ⇒ mỗi dòng dưới phải nêu rõ **trượt khi nào**.
| # | Phép đo | TRƯỢT khi |
|---|---|---|
| **A1** | Chu trình `/pause` sạch → `/day` ⇒ CLEAN; `day-probe --json` in **cả `anchor` lẫn `head-sha` field** và chỉ ra chúng KHÁC nhau | Ai đó cài đếm-thô từ `head-sha` ⇒ DELTA-giả ⇒ FAIL |
| **A2** | Cây tạm: inject marker mang sha **dangling** ⇒ verdict `anchor-lost` + tự nâng | Chỉ dùng `cat-file -e` (không `is-ancestor`) ⇒ lọt ⇒ FAIL — **đúng shape S127** |
| **A3** | `/pause` sạch rồi gõ `/pause` lần 2 ⇒ **số file marker + `git log -1` bất biến** | Sinh thêm marker / commit / spawn `ctx-curator` ⇒ FAIL |
| **A4** | `/tiep` trên nền sạch ⇒ report khai **SKIP nạp-nền + SKIP `ctx-verifier`**; đĩa sinh **đúng 1 `_day-*`, 0 `_tiep-*` mới** | Vẫn nạp nền, hoặc sinh `_tiep` ⇒ FAIL |
| **A5** | Inject (a) dirty 1 byte ngoài allowlist · (b) 1 commit thường ⇒ **DELTA cả 2 chiều** | Một trong hai vẫn CLEAN ⇒ FAIL |
| **A6** | Đếm `_day-*` = N; **falsifier PHẢI FLAG** ca inject CLEAN-giả (marker CLEAN + có commit thật giữa anchor và ts) | Falsifier im ⇒ FAIL (lớp *vắng-mặt trông giống ổn*) |
| **A7** | Sau khi có `_day-*` trên đĩa, `/tiep §0` ⑤(b) ORPHAN-L **im đúng**; rồi **RE-RUN fault-inject** block ⑤(b) 2 chiều | Quên cộng `_day-*` vào r-set ⇒ ORPHAN-L **kêu oan** ⇒ FAIL |
| **A8** | `grep` report `/day`: **0 hit** con số gắn nhãn token | Có số token đơn lẻ ⇒ FAIL (lỗi r1 của hub) |
**Vai + deliverable**
- **Thi công = lead tự tay** (KHÔNG giao implementer): 3 chỗ chạm **canonical**, sai một chỗ là hỏng nghi-thức đang chạy tốt.
- **REVIEW = workflow RIÊNG** — Harness-9 mandate (adap = 2 workflow: IMPLEMENT ⟂ REVIEW độc lập) + report hub kèm run-id.
- **Dogfood 2 cửa** trước khi báo hub — hub tự khai 0 phiên, SE đừng lặp lại lỗi đó.
### 🔴 3 chỗ chạm CANONICAL — CHỜ ANH GẬT, lead KHÔNG tự làm
1. **`tiep.md §0` ⑤(b)** — sửa r-set ORPHAN-L (đụng **nhà canonical của Sàn-3**).
2. **`CLAUDE.md`** — câu *"nối lại DUY-NHẤT bằng `/tiep`"* nay có ngoại lệ `/day` ⇒ phải sửa, nếu không là **ghost-wire chiều ngược**
(chạy thật mà khai chưa — đúng lớp H18 mà `lead-stale-auditor` bắt @S146).
3. **`check-email.md`** — nhịp "4 CỬA PHIÊN" thành **5 cửa** nếu `/day` cũng dò thư.
<!-- END · 4 KHOAN F1-F4 · 8 ACCEPTANCE A1-A8 · 4 PHAN-BIEN · 2 PHAT-HIEN-NGOAI-DE · 3 CHO-ANH-GAT -->

View File

@ -0,0 +1,183 @@
# SUB — invest `/day` dậy-nhẹ probe-first (S158, `/fable-real investigator-codebase`, PROPOSE-ONLY)
> Engine ghi-trong-lúc-làm. Lead verify → lead ghi spec (H21 ① honest-note (c)). File này = findings + đề-xuất, KHÔNG phải spec, KHÔNG sửa lệnh nào.
> Thư nguồn đọc TRỌN: `AI_INFRA/broadcasts/outbox/all/2026-07-28-Governance-day-wake-probe-first-resume.md` (13.832 B, `ef05b7da…`, PASS r3, dogfood hub = 0 phiên).
## §0 VERDICT
**FIT-ĐỦ-4 — áp cả F1-F4, SKIP = 0 khoản.** SE có đủ 2 nền (17-07 kit + 25-07 vòng-canh/`tiep_reload`), có hook-carry sẵn (F4 rẻ hơn hub), có máy canonical đón sẵn ts-reader (`session_ctx.py:48-59`). 4 phép đo đề-bài đều chạy thật, trong đó **1 tiền-đề đề-bài TRẬT trên dữ-liệu hôm nay** (mồ-côi 0/8 — nhưng guard vẫn bắt buộc, lý do tự-sinh ở §1.2). Câu khó Sàn-3: **dựng phép đo thứ 2 KHÔNG vi phạm B1** — có bằng chứng cùng-một-cửa hai phép trả lời NGƯỢC nhau vì hỏi 2 câu khác nhau (§2).
---
## §1 ĐO THẬT (mọi số kèm lệnh — chạy 2026-07-28, HEAD lúc đo `eb08ac0`)
### 1.1 F3 bẫy-một — CHỨNG 4/4: đếm thô từ head-sha marker ⇒ DELTA-giả 100% ca
Lệnh: `for sha in <4 pause-sha>; do git rev-list --reverse $sha..HEAD | head -1 | xargs git log -1 --format='%h %s'; done`
| marker | head-sha (field trong file) | commit KẾ TIẾP ngay sau sha |
|---|---|---|
| `_pause-1` | `5197ce2` (= `wal: flush 20260726T1942`) | `8d4075a` **`wal: pause`** |
| `_pause-2` | `9ed65f4` | `976945c` **`wal: pause`** |
| `_pause-3` | `b804d96` | `73166c5` **`wal: pause`** |
| `_pause-4` | `d7eaece` (`[CLAUDE] Docs: spec…`) | `6c263dd` **`wal: pause`** |
⇒ Marker chụp HEAD ở `pause.md §2.6(A)` **TRƯỚC** commit-chốt `wal: pause` (bước 4) — nên commit chốt LUÔN nằm sau head-sha của chính marker. Tại cửa `/tiep` S158 (19:35, HEAD lúc đó = `6c263dd`): đếm thô `git rev-list --count d7eaece..HEAD` = **1** ⇒ DELTA-giả; neo resolve về `6c263dd`**0** ⇒ CLEAN (khớp datum lead trong `run.md`). **Bẫy-một là thật ở SE, 4/4 marker, đúng như thư tả.** Bonus khớp chéo tự nhiên: `_tiep-3.head-sha = 73166c5` = chính commit `wal: pause` chở `_pause-3` (0-delta thì HEAD lúc nối = carrier của pause trước — nhất quán).
### 1.2 F3 bẫy-hai — mồ-côi ĐO THẬT: **0/8** hôm nay; tiền-đề đề-bài TRẬT; guard VẪN BẮT BUỘC
Lệnh: `git cat-file -e $sha` + `git merge-base --is-ancestor $sha HEAD` + `git rev-list --count $sha..HEAD` trên 8 sha (4 `_pause` + 4 `_tiep`):
```
p1 5197ce2 alive ANCESTOR range=54 t1 8d4075a alive ANCESTOR range=53
p2 9ed65f4 alive ANCESTOR range=27 t2 76488e8 alive ANCESTOR range=23
p3 b804d96 alive ANCESTOR range=15 t3 73166c5 alive ANCESTOR range=14
p4 d7eaece alive ANCESTOR range=3 t4 6c263dd alive ANCESTOR range=2
```
**Vì sao 0 mồ-côi dù SE có squash:** `session-end.md §5.0/§5.2` squash **CHỈ gọt run `wal:` LIÊN-TỤC tính từ HEAD xuống, CHỈ trong khoảng chưa-push** ("KHÔNG BAO GIỜ rewrite commit đã-push"; `wal:` kẹp dưới commit thường = GIỮ). Đo: 6/8 sha đã push (`is-ancestor origin/main` = YES), 2/8 chưa push nhưng `d7eaece` là commit thường (điểm dừng phép đếm K) — nên chưa sha nào từng rơi vào vùng fold.
**Nhưng bác bỏ "vậy thì bẫy-hai n-a" — 3 bằng chứng:**
1. **Tiền lệ chết THẬT cùng-lớp:** `.session-counter.json` history ghi S127: `last_ticked_head f9fa77d6` = dangling ("object ton tai (cat-file -t = commit) nhung 0 nhanh chua no") — squash đã từng giết 1 sha được sổ trỏ; contract phải đẻ event-class `squash-benign` VÌ nó. Ca này còn chứng: **`cat-file -e` MỘT MÌNH không đủ** (object dangling vẫn pass), phải kèm `is-ancestor` — đúng floor đúp của thư, có datum SE-local.
2. **Anchor hiện tại đang nằm trong vùng fold-able:** `6c263dd` (= carrier của `_pause-4`, = `last_ticked_head` S158) là `wal: pause` chưa-push, phía trên nó lúc này chỉ toàn `wal: flush` — nếu S158 không land commit thường nào trước session-end kế, run trailing từ HEAD gồm cả `6c263dd` ⇒ fold ⇒ sha chết. Sống hay chết = **may rủi hình-dạng phiên**, không phải thiết kế.
3. **Chính feature `/day` sản xuất điều kiện orphan:** chuỗi cửa-nhẹ hỏi-đáp (use-case đích của F1) sinh toàn marker + `wal:` flush, 0 commit thường ⇒ đúng hình-dạng trailing-`wal:` thuần mà squash fold trọn ⇒ **mọi anchor của chuỗi cửa-nhẹ chết cùng lúc ở session-end**. Guard bẫy-hai là điều-kiện-tự-sinh của chính lệnh dậy — adopt F1 mà bỏ F3-hai là tự gài mìn hẹn giờ.
**SE-form mạnh hơn hub (đo 8/8 PASS):** resolve anchor = **commit-chở-marker** `git log --diff-filter=A -1 --format='%h' -- <marker-file>`:
```
_pause-1→8d4075a _pause-2→976945c _pause-3→73166c5 _pause-4→6c263dd (đều "wal: pause")
_tiep-1→c41af1c _tiep-2→054ba02 _tiep-3→877236f _tiep-4→60132e7 (đều "wal: flush …")
```
Phép này đi trên **lịch sử HIỆN TẠI** ⇒ sau squash tự re-resolve về commit fold mới ⇒ **sống-sau-squash by construction**, hết cả bẫy-một (carrier chính LÀ commit-chốt) lẫn bẫy-hai trên đường chính; field `head-sha` trong marker hạ xuống **fallback** (marker chưa từng được commit) — chỉ fallback mới cần guard đúp `cat-file -e``is-ancestor`, trượt cả hai ⇒ verdict `anchor-lost` + tự nâng, CÓ TIẾNG (đúng floor).
### 1.3 F4 counter-drift — phép tương đương s109 của hub, đo trên session-7
Đĩa (`ls .claude/sessions/session-7/`): **`_pause-*` = 4 · `_tiep-*` = 4 · `_snapshot-*` = 3** (+ `_mind` + `_context`).
| sổ khai | đĩa | verdict |
|---|---|---|
| `_context-s-7.md` khai `### PAUSE-1..4` (4 entry, ts khớp từng marker) | 4 `_pause` | **KHỚP 4/4** |
| Contract auto-snap `pause.md §2.6(D)` (mỗi pause = 1 snapshot, hiệu lực từ S148) ⇒ kỳ vọng 4 | **3** `_snapshot` (PAUSE-4 lúc 11:33 07-28 KHÔNG có `_snapshot-4`) | 🔴 **DRIFT THẬT 3/4** — sự kiện nghi-thức không để vết, cùng gốc bệnh s109 hub (hub: đĩa THỪA so sổ; SE: đĩa THIẾU so contract) |
| Đề-bài S158 (viết lúc phóng) khai "`_tiep-1..3`" | 4 `_tiep` (`_tiep-4` sinh 19:35 trong chính cửa này) | write-order class — sổ chốt trước, marker sinh sau (chính hình-dạng s109; ở đây benign vì tự giải thích được) |
| WAL header "window 4" · STATUS "counter 31" | `_tiep-4` window-ordinal **5** · counter state **32** | **by-design staleness** (WAL/STATUS chỉ ghi lúc pause/closeout) — KHÔNG đếm là drift, khai để khỏi thổi phồng |
⇒ SE có **1 counter-drift đo được** (snapshot 3/4) + 1 ca write-order benign. Marker `_day` đếm-được từ filesystem đóng đúng lỗ này cho sự kiện dậy — và phép "đếm đĩa vs sổ" ở trên chính là khuôn falsifier tái dùng được.
### 1.4 F1 — BYTE bộ nguồn `tiep_reload` (đo tươi, đúng phạm-vi khoanh trong `sources`; 🔴 BYTE, KHÔNG quy token)
| nguồn (theo khoá `tiep_reload.sources`) | phạm-vi | đo | byte |
|---|---|---|---|
| `docs/STATUS.md` | dòng CURRENT (line 6, mega-line) | python len utf-8 | **3.295** |
| `docs/STATUS.md` | bảng CURRENT STATE (line 443 → trước `## ` kế = 466) | python | **56.210** |
| `docs/HANDOFF.md` | segment "Last updated" MỚI NHẤT (line 5→11; header thật = "**🆕 Last updated:**" — có khoảng trắng, không gạch nối) | python | **4.352** |
| `.claude/WAL.md` | trọn | `wc -c` | **5.369** |
| `_mind-s-7.md` | trọn | `wc -c` | **30.305** |
| `_context-s-7.md` | trọn | `wc -c` | **22.584** |
| **TỔNG bộ rút-gọn** | 5 nguồn / 6 mảnh | | **122.115 B** |
Đối chiếu: hub khai 439.328 B / 8 file (bộ của hub); nền-FULL SE = 596.316 B (số instrument @S153 ghi trong `_note` khoá — trích config, không phải đo tươi hôm nay). Bộ `/tiep` SE đã rút-gọn sẵn từ S153 nên nhỏ hơn hub 3,6×.
**Khoản tiết-kiệm mỗi cửa dậy-CLEAN (SE-form §3):**
- **Nạp SKIP** = STATUS-seg 3.295 + 56.210 + HANDOFF-seg 4.352 + `_context` 22.584 = **86.441 B** (70,8% bộ rút-gọn)
- **Nạp GIỮ** (lõi) = WAL 5.369 + `_mind` 30.305 = **35.674 B**
- **Spawn SKIP** = 1 lượt `ctx-verifier` — chi phí theo config SE: floor ~100K tok/spawn (`pause.md §2.6(C-bis).5` + `harness_floor.rounded_up_tokens=100000`; **số config có nguồn, KHÔNG phải đo của lượt này**) + skip re-run `mind-check` (~140-300ms) + skip verify-battery 5 lệnh của WAL `verify:`.
- Token: **CẤM quy** — chỉ được nói "dải mở, sàn = byte/4" nếu buộc phải nói, kèm nguồn (đúng luật thư + tiền lệ r1 trượt).
### 1.5 Đo phụ (ăn vào thiết kế §3)
- `git status --porcelain` NGAY LÚC NÀY = ` M .claude/governance/.session-counter.json` — tick `/tiep §2.5` KHÔNG có bước commit, file NGOÀI hook-4-path ⇒ **dirty tồn qua cửa** cho tới pause/closeout kế. ⇒ probe không allowlist file này thì **mọi cửa dậy sau một cửa-vào-bằng-/tiep-rồi-đóng đều DELTA-giả** (đường dậy-nhẹ chết ~nửa số ca). Datum `run.md` "porcelain rỗng" là may của cửa-sau-PAUSE (pause bước 4 commit counter đích-danh).
- `_tiep-1.md` head-sha = **sha NGẮN 7 ký tự** (`8d4075a`), 7 marker kia full-40 ⇒ form drift trong cùng loại marker; máy đọc phải chịu sha ngắn (git chịu) — thêm 1 lý do đi đường carrier-resolution thay vì tin field.
- `session_ctx.py:48-59`: `_TS_KEY_RE` canonical + comment ĐÓN SẴN "a future latest-marker reader" + cảnh báo đích-danh: `_mind-s-<N>.md` có key-line `ts:`**reader marker PHẢI lọc theo TÊN FILE** kẻo đọc `_mind` thành marker. Máy probe = EXTEND `session_ctx.py` (khớp tiền lệ S153 "không .ps1 mới", tái dùng `_TS_KEY_RE` 1-nguồn).
- Sentinel: WAL 0 dòng `^closing:` (grep = 0) — khớp datum lead.
- 🎁 Surprise ngoài đề: **HANDOFF segment mới nhất = S153 (07-26)** — S155-S157 dọn sổ (`3b6fabc`) chỉ vá STATUS + session-log, KHÔNG thêm segment HANDOFF ⇒ nguồn 2 của `tiep_reload` đang nạp brief cũ 3 nhãn. Không thuộc scope thư này; nêu để lead biết.
---
## §2 CÂU KHÓ — probe F1 vs Sàn-3: **DỰNG PHÉP ĐO THỨ 2, KHÔNG tái dùng Sàn-3 làm chính nó** (và KHÔNG phạm B1)
**Bằng chứng quyết định (đo trên chính cửa S158):** lúc 19:35, `origin/main..HEAD` chứa `d7eaece` + `3b6fabc` = commit KHÔNG-`wal:`**Sàn-3 tín-hiệu ② HIT** (bậc MẠNH — cấm kết luận sạch). Cùng thời điểm, probe F3-resolved-anchor = `6c263dd`, delta = **0 ⇒ CLEAN**. Hai phép trả lời **NGƯỢC nhau trên cùng một cửa** — vì chúng hỏi **2 câu khác nhau**:
| | Sàn-3 (`tiep.md §0`) | probe F1 |
|---|---|---|
| Câu hỏi | "**tồn tại** việc dở không?" — tuyệt đối | "trạng-thái **có đổi so với điểm dừng** không?" — tương đối |
| Neo | `origin/main` (② ④ ⑤) / KHÔNG neo (① orphan, ORPHAN-L) | marker dừng gần nhất (anchor F3) |
| Kết luận cấp | "DỪNG SẠCH" ⟂ "HỎI LẠI ANH" | route: dậy-nhẹ ⟂ nạp-full |
| ② HIT vì việc S157 đã commit chưa push (ĐÃ ghi sổ WAL `[x]` kèm hash) | đúng chức năng nó | 0-delta: việc đó xảy ra TRƯỚC pause, đã qua kiểm-lúc-ghi |
B1 cấm **2 nguồn về CÙNG MỘT câu** — đây là 2 câu ⇒ dựng phép-2 hợp lệ. Tái-dùng-Sàn-3-làm-probe thì sai theo cả 2 hướng: (a) Sàn-3 ② neo `origin/main` ⇒ mọi phiên có việc thật chưa push (= đa số) vĩnh viễn không mở được đường nhẹ — F1 chết từ trong trứng; (b) nới Sàn-3 cho "hiểu anchor" = sửa định-nghĩa canonical của "còn việc dở" để phục vụ một câu hỏi khác — chính là làm bẩn nguồn sự thật.
**Nhưng 4 ràng B1-hygiene để 2 phép không bao giờ bị đọc thành 1 (đề-xuất thành LUẬT trong lệnh):**
1. Tín-hiệu TRÙNG thì **GỌI cùng một phép**: sentinel của probe = đúng grep `^closing:` của Sàn-3 ③ (con-trỏ, không chép biến-thể).
2. **DELTA/anchor-lost/probe-lỗi ⇒ đổ về `/tiep` trọn**, nơi Sàn-3 chạy — "sạch/không-sạch" giữ **một nhà duy nhất**.
3. **Cấm từ-vựng**: output `/day` không được chứa "sạch" / "DỪNG SẠCH" / "không có mạch dở" — verdict chỉ `CLEAN|DELTA|anchor-lost` với nghĩa khai tường-minh "0-delta so điểm dừng; WAL nguyên hiệu lực" (CLEAN ≠ sạch; cửa nhẹ vẫn ĐỌC WAL nên mục `[!]` không bị nuốt).
4. **1 chạm bắt buộc vào Sàn-3** (sửa canonical có khai, không phải nguồn-đôi): ORPHAN-L ⑤(b) đếm cân-sổ `p vs r` — cửa dậy-nhẹ TIÊU THỤ một pause mà không ghi gì vào r-set ⇒ `/tiep`/`session-start` kế **KÊU OAN** (p>r) ⇒ claw-back tiết-kiệm bằng câu hỏi thừa. Vá = +`_day-*` vào r-set (1 dòng trong máy ⑤(b)) + **RE-RUN fault-inject 2 chiều của block** (cert "đã inject @S148" mất hiệu lực khi đổi tập đếm — luật fault-injection-proves-teeth).
Điểm khớp đẹp: Sàn-3 hỏng-về-phía-hỏi-thừa, probe hỏng-về-phía-DELTA (nghiêng F1) — **cả hai cùng chiều an-toàn**, không có tổ hợp nào "im lặng bỏ việc".
---
## §3 ② CÁCH ÁP — per-khoản, file-by-file (SKIP = 0; mọi chỗ đều PROPOSE, lead ghi)
### F1 — probe rẻ chỉ-đọc → lệnh MỚI `/day` + máy `day-probe`
- **NEW `.claude/commands/day.md`** (≤3KB): §1 resolve `<N>` (khuôn `snapshot.md §0`: WAL field `session:` → mtime-max → hỏi anh 1 dòng) → chạy `python scripts/session_ctx.py day-probe --session <N> --json` (chỉ-đọc, 0 spawn, 0 write) → §2 route:
- **CLEAN** ⇒ dậy-nhẹ: đọc **WAL trọn + `_mind-s-<N>` trọn** (từ trên xuống); **SKIP** STATUS-seg + HANDOFF-seg + `_context` + spawn `ctx-verifier` + re-run `mind-check` (hợp lệ: `_mind` đã qua kiểm-lúc-ghi tại pause — `mind-check` draft+full ở `pause.md §2.6(C-bis)` bước 2/4 — 0-delta ⇒ còn nguyên giá trị); ghi marker `_day-<i>.md`; tick counter (con-trỏ `session-start §2.1.8`, B1); dò thư 2 kênh DÒ-only (con-trỏ `check-email.md §Nhịp` — cần anh gật vì thêm cửa thứ 5 vào luật nhịp); report 3-4 dòng khai verdict+anchor+skip-set-BYTE. **SKIP ≠ CẤM đọc** — cần sâu hơn thì đọc on-demand, chỉ nghi-thức mặc-định là nhẹ.
- **Ngưỡng tự-nâng SE-form:** cửa nhẹ chỉ ĐỌC/trả lời; việc đầu tiên cần Write/Edit/spawn ⇒ chạy `/tiep` trọn trước (mutate trên nền chưa reconcile = cấm).
- **DELTA / anchor-lost / probe-lỗi** ⇒ in 1 dòng signals → ghi `_day-<i>.md` (verdict + signals + route full) → chạy `/tiep` trọn. Nghiêng: mọi lỗi = DELTA.
- Arg `force`/`full` ⇒ bỏ probe, `/tiep` trọn.
- **EDIT `scripts/session_ctx.py`** +subcommand `day-probe`: chọn marker mới nhất theo **ts GHI TRONG FILE** (`_TS_KEY_RE` :59 — Dropbox chạm mtime, đúng cảnh báo thư), **glob CHỈ** `_pause-*.md|_tiep-*.md|_day-*.md` (KHÔNG `_mind`/`_context`/`_snapshot` — bẫy :48-55); 4 tín-hiệu: (s1) `rev-list --count anchor..HEAD` (s2) porcelain tracked-dirty NGOÀI allowlist (s3) `_snapshot-*` có ts mới hơn marker (checkpoint giữa đường) (s4) `^closing:` WAL (= Sàn-3 ③). JSON + exit 0 luôn (advisory — route do lệnh quyết).
- **EDIT `memory-budget.json`** +khoá `day_wake` `{allowlist_dirty: [".claude/governance/.session-counter.json"], boundary_glob: [...]}` — 1-nguồn máy đọc live, fail-loud khi vắng (khuôn `mind_ctx_kb` H24-2). Allowlist 1-file có bằng chứng §1.5; **không** allowlist rộng hơn (counter-dirt không mang work-state; mọi dirt khác = việc thật).
### F2 — guard chống-trùng bước-0 HAI LỆNH CŨ (net-new: cả 2 file hiện 0 guard — `pause.md` mở thẳng bước 1, `tiep.md` mở thẳng §0)
- **EDIT `pause.md`** +§0 (~6 dòng): chạy `day-probe`; nếu **paused-bit** (ts `_pause-max` > ts `_tiep-max`, đọc in-file ts) ∧ CLEAN ⇒ in "đã dừng rồi — 0 delta, giữ nguyên" + DỪNG. **No-op = 0 marker mới, 0 entry `_context`, 0 snapshot, 0 spawn `ctx-curator`, 0 commit** (giá double-pause hiện tại: 1 spawn ~100K-floor + 4 vật + 1 commit — guard có răng thật). `_day` KHÔNG flip paused-bit (cửa nhẹ không phải mở-mạch). `force` ép chạy trọn.
- **EDIT `tiep.md`** +§-1 route-guard TRƯỚC §0 (~5 dòng): không `full` ⇒ chạy `day-probe`; CLEAN ⇒ in 1 dòng + đi đường `/day` dậy-nhẹ (không đốt §0-§4, không nạp `tiep_reload`, không spawn `ctx-verifier`); DELTA ⇒ chạy §0 như cũ. (Gõ nhầm lệnh nào cũng không bị phạt token — đúng floor.)
### F3 — anchor ĐÚNG + còn SỐNG (SE-form: carrier-resolution)
- Anchor chính = `git log --diff-filter=A -1 --format=%H -- <marker-mới-nhất>` (đo 8/8 §1.2; sống-sau-squash by construction; tự xử cả bẫy-một). Fallback (marker chưa được commit — pause chết giữa write và commit) = field `head-sha` + guard đúp `cat-file -e``merge-base --is-ancestor` (S127 chứng cat-file-alone thủng); trượt ⇒ `anchor-lost` khai trong report + marker, tự nâng — hỏng-an-toàn CÓ TIẾNG. **CẤM** dùng ts/commit đụng WAL làm neo (WAL bị mọi flush chạm — đúng cảnh báo thư).
### F4 — marker dậy đếm-được + falsifier 2 chiều
- **`_day-<i>.md`** (~250-300B, `<i>` = max+1): 7 key-line `ts / head-sha / anchor / anchor-source(carrier|head-sha-field|none) / verdict(CLEAN|DELTA|anchor-lost) / route(nhe|full) / signals(csv|0)`. Ghi Ở CẢ 2 route (chiều luôn-DELTA cần signals nằm trên đĩa). **0 commit riêng**`_day` nằm trong `.claude/sessions/` = path ④ hook `wal-flush.ps1` ⇒ đi theo chuyến `wal:` kế **miễn phí** (SE có sẵn thứ hub phải chế; và vì KHÔNG nới path hook nào ⇒ KHÔNG kích luật Sàn-3 "path mới = tín-hiệu MẠNH mới").
- Falsifier 2 chiều (rẻ, chạy hồi tố từ đĩa+git — đề xuất nhét `governance-detectors.ps1` INFORM-only, owner-form): **CLEAN-giả** = tồn tại `_day` verdict CLEAN mà `rev-list anchor..carrier(_day)` chứa commit KHÔNG-phải-carrier ⇒ FLAG; **luôn-DELTA** = `_day` verdict DELTA/anchor-lost mà `signals` rỗng ⇒ FLAG (chuỗi tự-nâng dài soi được bằng đếm file).
### Chạm canonical phải khai (3 chỗ, đều 1-vài dòng): `tiep.md §0 ⑤(b)` r-set +`_day-*` (+re-inject) · `CLAUDE.md` câu "nối lại DUY-NHẤT bằng /tiep" → thêm vế "/day dậy-nhẹ khi probe 0-delta, DELTA tự nâng về /tiep" (không sửa = mâu thuẫn bề mặt ngay dòng H22) · `check-email.md §Nhịp` +cửa dò thứ 5 (chờ anh gật). Restart CLI sau khi thêm/sửa command (no-hot-reload — đã có tiền lệ ghi trong `pause.md`).
---
## §4 ③ CHECKLIST ACCEPTANCE — vai + deliverable + phép ĐO ĐƯỢC (mỗi phép có đường TRƯỢT thật)
| # | phép | lệnh/cách đo | TRƯỢT khi (đường hỏng có thật) |
|---|---|---|---|
| A1 | bẫy-một đóng | chu trình thật: `/pause` sạch → cửa mới `/day` ⇒ verdict CLEAN; `--json` phải in `anchor_source=carrier``anchor ≠ head-sha-field` | code đếm thô từ field ⇒ `wal: pause` lọt range ⇒ DELTA ⇒ FAIL (đây chính là bug 100%-ca nếu implement ẩu) |
| A2 | bẫy-hai có răng | fault-inject cây tạm: marker fake head-sha = object-thật-NOT-ancestor (commit trên branch tạm rồi xoá branch) + KHÔNG commit marker (ép rơi fallback) ⇒ PHẢI `anchor-lost`+route full; đối chứng sha=HEAD~1 ⇒ verdict thường | code chỉ `cat-file -e` (bỏ `is-ancestor`) ⇒ dangling PASS ⇒ verdict thường ⇒ FAIL (S127-shape) |
| A3 | F2 pause no-op | dừng sạch → gõ `/pause` lần 2 ⇒ `ls session-<N> \| wc -l` TRƯỚC/SAU bằng nhau ∧ `git log -1` không thêm commit ∧ `_context` không thêm `PAUSE-<k+1>` | thiếu guard ⇒ `_pause-<i+1>` + snapshot + commit sinh ra ⇒ count tăng ⇒ FAIL |
| A4 | F2 tiep route | dừng sạch → `/tiep` không arg ⇒ report khai SKIP {STATUS-seg·HANDOFF-seg·`_context`·`ctx-verifier`·`mind-check`} ∧ đĩa sinh đúng 1 `_day-<i>` CLEAN ∧ 0 `_tiep-<i>` mới | route thiếu ⇒ ctx-verifier spawn/`_tiep` mới xuất hiện ⇒ FAIL |
| A5 | nghiêng an-toàn 2 chiều | inject sau pause sạch: (i) sửa 1 byte file tracked không commit ⇒ `/day` DELTA signal dirty; (ii) 1 commit thường ⇒ DELTA signal commits | probe bỏ sót chiều nào ⇒ CLEAN-giả chiều đó ⇒ FAIL |
| A6 | F4 đếm được + falsifier | (i) N cửa nhẹ ⇒ `ls _day-* \| wc -l` = N; (ii) chạy 2 phép falsifier §3-F4 trên đĩa thật ⇒ 0 FLAG; (iii) inject 1 `_day` CLEAN có commit thường chen giữa ⇒ falsifier PHẢI FLAG | falsifier không FLAG ca inject ⇒ phép 0-bit ⇒ FAIL |
| A7 | ORPHAN-L không kêu oan | pause → `/day` CLEAN → (không `/tiep`) → chạy máy Sàn-3 ⑤(b) ⇒ PHẢI im; + re-run fault-inject 2 chiều block ⑤(b) (ca cũ PASS + ca `_day`-đối-ứng) | quên vá r-set ⇒ `ORPHAN-L: p>r` kêu ⇒ FAIL |
| A8 | báo số trung thực | report `/day` khai skip-set bằng BYTE đo tươi; grep report: 0 chuỗi "token" đứng cạnh số-đơn không nguồn | report in "tiết kiệm ~NK token (tự đo)" ⇒ FAIL (đúng lỗi r1 của thư) |
Vai đề xuất: implement = lead (em-main) tự tay (3 file lệnh + 1 python + 1 json — nhỏ, canonical-touch nhiều, không đáng spawn); REVIEW = workflow RIÊNG theo Harness-9 (reviewer chấm A1-A8 + soi 3 chạm canonical); dogfood = 2 cửa thật rồi mới báo hub kèm số (thư tự nhận sẽ gửi `type=update` — SE cũng đợi số của mình trước khi khoe).
## §5 PHẢN-BIỆN + giới hạn khai thẳng
1. **Tiền-đề đề-bài "SE có squash ⇒ đo mồ-côi" trật trên dữ-liệu hôm nay** (0/8 — squash scope chỉ-trailing-chưa-push): số "2/2 NOT-ancestor, range 35 rác" của hub KHÔNG tái hiện được ở SE hiện tại; bằng chứng SE cho bẫy-hai là {tiền lệ S127 + `6c263dd` fold-able + chuỗi-cửa-nhẹ tự sản xuất điều kiện} — đủ để giữ floor, không đủ để trích "SE cũng đo được N mồ-côi". Đừng ghi vào spec/report con số mồ-côi >0.
2. **Datum "porcelain rỗng" của run.md không tổng quát hoá được** — counter-dirt sau cửa-vào-`/tiep` là trạng-thái hợp lệ đang thấy NGAY LÚC NÀY; thiếu allowlist 1-file thì F1 chết nửa số ca (§1.5).
3. **Hub-floor "chọn marker bằng ts trong file" cần +1 rào SE-local:** glob phải lọc TÊN FILE (`_mind``ts:` key-line — bẫy đã được chính `session_ctx.py:48-55` tiên tri; miss = đọc `_mind` thành marker mới nhất vĩnh viễn).
4. **Giới hạn:** dogfood của chính `/day` = 0 ở cả hub lẫn SE (SE mới có 1 datum probe-tay @S158); con số "tiết kiệm 86.441B + 1 spawn/cửa" là ước-từ-cấu-hình-hiện-tại, chưa phải số chạy thật — đợi 2 cửa dogfood rồi mới có quyền trích. `_context` 22.584B sẽ PHÌNH theo phiên-logic (append-only) ⇒ tỉ trọng tiết-kiệm TĂNG dần theo tuổi phiên — chiều có lợi, nhưng vẫn là ngoại suy.
## §6 Lệnh đo để lead re-run (tự verify, đừng tin file này)
```bash
# bẫy-một (4/4): for sha in 5197ce2 9ed65f4 b804d96 d7eaece; do git rev-list --reverse $sha..HEAD | head -1 | xargs git log -1 --format='%h %s'; done
# mồ-côi (0/8): for sha in 5197ce2 9ed65f4 b804d96 d7eaece 8d4075a 76488e8 73166c5 6c263dd; do git cat-file -e $sha && git merge-base --is-ancestor $sha HEAD && echo "$sha OK"; done
# carrier (8/8): for f in .claude/sessions/session-7/_{pause,tiep}-*.md; do echo "$f -> $(git log --diff-filter=A -1 --format='%h %s' -- $f)"; done
# drift snapshot (3/4): ls .claude/sessions/session-7/ | grep -c '^_snapshot' ; grep -c '^### PAUSE-' .claude/sessions/session-7/_context-s-7.md
# byte (122.115): wc -c .claude/WAL.md .claude/sessions/session-7/_{mind,context}-s-7.md # + python slice STATUS line6/443-466, HANDOFF line5-11
# Sàn-3 ② cùng-cửa HIT: git log --format='%h %s' a52a91e..6c263dd | grep -v '^[0-9a-f]* wal:'
```
**TOTAL: 14 đề-xuất** (F1: `/day`+`day-probe`+khoá `day_wake`+ngưỡng-tự-nâng = 4 · F2: §0 pause + §-1 tiep = 2 · F3: carrier-anchor + fallback-guard-đúp + cấm-neo-WAL = 3 · F4: `_day` 7-trường + falsifier-2-chiều = 2 · chạm canonical: ⑤(b) r-set + CLAUDE.md H22 + check-email nhịp = 3) · **4 phản-biện** · SKIP = 0.

View File

@ -2,7 +2,23 @@
> **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-26 chiều (**S153** — phiên-logic 6, 1 cửa-sổ: **adopt TRỌN thư Ctx soft-memory `0df10df4` + OWNER-VETO 3-vai + RENAME hub-form + bookend 2 đầu**). Governance-only, 0 prod-code (test 532 giữ, `git diff` src/tests/fe rỗng). Chi tiết = `docs/STATUS.md` dòng CURRENT + log `changelog/sessions/2026-07-26-1600-S153-ctx-adopt-3vai-rename.md`. ⭐ Bài đắt nhất phiên: **GAP-#9** — máy tự-build của SE tái hiện đúng bẫy F-1 mà thư hub kể (closed-mode: *xoá con-trỏ trung thực* → xanh RẺ HƠN *giữ* → trượt ⇒ gradient thưởng đường SAI; vá bằng TRƯỢT). Bài phụ: **đo wall-clock phải gồm nhánh ĐẮT** (ước lệch 2.2-5.4×) · **fixture-hỏng-cho-xanh trông y hệt máy-đúng-cho-xanh** (phải soi RUỘT fixture) · **bẫy parse `]` trong comment** nuốt non array (18 vs 23).
**🆕 Last updated:** 2026-07-28 tối (**S155→S158** — phiên-LOGIC **L7**, **5 cửa-sổ**). Chi tiết = `docs/STATUS.md` dòng CURRENT + log `changelog/sessions/2026-07-28-2100-S158-adap-day-wake-bookend-close.md`.
**Tóm 5 cửa-sổ L7:** ① PE nút XÓA ship prod (Mig 68, `b1bae77`+`4464a46`, test 532→**562**) ② điều tra quy trình sau-CEO — 🔴 **nguyên văn anh chốt phạm vi:** *"đã xong bước thứ 6 tức CEO duyệt rồi nhé, chưa cần làm gì hết → Bắt đầu đến Project (Ban Chỉ Huy Công trường)"* ③ UAT Địa điểm — chẩn **DATA-không-phải-CODE**, anh chốt KHÔNG backfill (`6250f39`, Run #419 PASS 9/9) ④ **spec "Kế hoạch ký kết Hợp đồng" 45.158 B** (`d7eaece`) ⑤ **S158**: `/adap-apply` thư `day-wake-probe-first` nấc **`agreed`** + bookend-close 10 vai.
**🔴 NEXT em @S158 — GATE 5-ANCHOR (di-trú khỏi WAL trước khi §6.4 reset xoá nó):** trước khi thi công **MỖI wave** của spec KHKK, **mở 5 anchor bất kỳ** của wave đó; **≥1 anchor trượt ⇒ chấm lại TOÀN BỘ anchor** của wave. Nguồn: reviewer đề @S157 (`sub-review-claims-4.md:119`), lead nhận, ghi trong spec `:458`. 🔴 Di-trú vì `lead-gap-auditor` FLAG-4 @S158: gate chỉ sống ở WAL + `_mind` (cả hai **sắp bốc hơi** ở §6.4), `grep -rn "5 anchor"` ra **0 hit** ở HANDOFF/STATUS/migration-todos/commands/agents — mà người thi công W1 đọc **§③ WAVE 1**, không đọc dòng `:458` giữa file spec 45 KB.
**🔴 NEXT em @S158 — 2 chỗ hở spec KHKK phải vá TRƯỚC W1** (lead rà 6 HIGH lens-wave: 4 phủ trọn, 2 còn hở): **H5** — W3 acceptance #8 vẫn `562 + N mới`, `N` thả tự do ⇒ **N=0 vẫn PASS**, đúng lỗ reviewer chỉ (đòi pin **N ≥ 6** + liệt tên) · **H6** — §2.4 dòng 224 vẫn giữ *"Dark-launch được bằng `IsVisible=0`"* trong khi dòng 289-290 **cùng file** đã đo-đĩa bác cơ-chế đó ⇒ spec tự mâu thuẫn, vá 1 phía.
**🔴 NEXT anh @S158 (đánh số — anh trả lời bằng số):**
**(42)(43)(44)** — 🔴 **3 slot này đã cấp ở WAL từ S155 nhưng CHƯA BAO GIỜ xuất hiện ở HANDOFF** (lead-stale FLAG-6 @S158: sổ anh đọc dừng ở slot 41 trong khi sổ lead đã tới 44) ⇒ 3 câu dưới đây anh **chưa từng được hỏi**: **(42)** canonRows · **(43)** carry con-trỏ-vs-slug · **(44)** END-line-thành-luật.
**(45)** 🔴 **Trần `_mind` — CHẶN cửa `/pause` kế tiếp.** File 30.305/32.768 B (92,5%), dư **2.463 B** (số máy; lead tự đo LF-normalized ra 2.727 — chênh 264 = đúng byte CR, **số máy chặt hơn, bám số máy**). MIND-5 cần **~6.536 B**; block duy nhất luật cho phép nén là **MIND-1 = 1.868 B** ⇒ xoá trắng nó vẫn thiếu (4.331 < 6.536). Chọn: **vá luật nén** (cho phép sang block kế khi nhất đã nén) **hay nâng khoá `mind_ctx_kb`**? 🔸 `ctx-verifier` đã dự báo tường này từ **S156** (đo 85,5%), 2 phiên không xử.
**(46)** 🔴 **Thước "17,1K" là thước MA — chọn 1 trong 3 ngã** (`harness-refine` A1, **cố ý không đặt số** số quyền anh): **(i) WIRE** thêm key `tiers.l1_hot.self_target_bytes` để máy soi được · **(ii) RETIRE** gỡ luật khỏi 5 diary thước thật 25.600 · **(iii) RELABEL** giữ nhưng ghi "advisory". Bằng chứng **đang tốn công thật**: `investigator-codebase:58` nén về ~17,1K @S155, **3 ngày sau 20.646 B lại**; áp thước này thì **9/23 vai vượt** trong khi mọi máy in "0 over".
**(47)** `cicd-monitor/archive/_INDEX.md` **19.484/20.480 = 95,14%**, tăng ~81 B/ngày **chạm cap ~2026-08-09**. A1@S153 chưa land, `harness-refine` đã kích chốt-dừng lead {thi-hành nguyên văn | HỦY ghi }; nếu chọn **nâng cap 20.480** thì quyền anh.
**(48)** `harvest-curator/MEMORY.md` **19.456 B = 0 byte đổi kể từ S154**; món nợ **tự khai 2 lần** (budget `:192` từ S107 · diary `:5` từ S153) chưa trả lần nào 3 lối ra đều số/nhịp của anh.
🔸 **Không chặn W1-W2:** 5 câu thiết kế spec KHKK (Q3 · Q6 · Q11 + O-Q1 · O-Q2) · nguồn thứ 4 `SOL-PRO-SP-001` chưa ai đọc · 2 đường kết thúc sớm W3 (`AllowApproverFinalize` · `CeoApprovalThreshold` anh từng phán **PHÁ VỠ** @S155) · thứ tự chạy wave.
🔸 **Treo CÓ CHỦ ĐÍCH, không phải quên:** lỗ hổng an ninh (`ContractWorkflowService.cs:48-66` Reject-trước-guard + controller class-trần) anh chốt *"chỗ hợp đồng cứ từ từ"*. **Wave 5 chạm HĐ ⇒ phải hỏi lại anh trước khi chạy.**
🧊 *Segment cũ (S153) giữ nguyên bên dưới làm lineage:* 2026-07-26 chiều (**S153** phiên-logic 6, 1 cửa-sổ: **adopt TRỌN thư Ctx soft-memory `0df10df4` + OWNER-VETO 3-vai + RENAME hub-form + bookend 2 đầu**). Governance-only, 0 prod-code (test 532 giữ, `git diff` src/tests/fe rỗng). Chi tiết = `docs/STATUS.md` dòng CURRENT + log `changelog/sessions/2026-07-26-1600-S153-ctx-adopt-3vai-rename.md`. Bài đắt nhất phiên: **GAP-#9** máy tự-build của SE tái hiện đúng bẫy F-1 thư hub kể (closed-mode: *xoá con-trỏ trung thực* xanh RẺ HƠN *giữ* trượt gradient thưởng đường SAI; bằng TRƯỢT). Bài phụ: **đo wall-clock phải gồm nhánh ĐẮT** (ước lệch 2.2-5.4×) · **fixture-hỏng-cho-xanh trông y hệt máy-đúng-cho-xanh** (phải soi RUỘT fixture) · **bẫy parse `]` trong comment** nuốt non array (18 vs 23).
**Carry @S153 — 🆕 MỚI 4 slug:** `[carry:ctx-t9-dogfood]` *(T9 phiên sau restart: dogfood 4-cửa THẬT + spawn-probe CẢ 3 vai ctx + mồi-ngầm xuyên-cửa-sổ + checklist #18/#19/#20/#22/#23 + điền wall-clock nếu lệch >2×)* · `[carry:ring5-audit-gap]` *(→ slot (41): hub CÓ `ring5-audit` V5 truth-floor [Q-2 25-07], SE+VIPIX chưa)* · `[carry:hmw-width-vs-roster]` *(→ slot (40): cap 20 < roster 23 ⇒ LOUD-skip 3 lane; nâng = đổi 2 nơi cùng lúc)* · `[carry:hmw-subfile-index-collision]` *(kẽ CÒN LẠI sau S134: cùng-role 2-invocation ⇒ index reset ⇒ suýt đè sub-file đợt-1; T5 tự né bằng `-2`; fix khả dĩ = `startIndex` hoặc số-đợt trong tên)*. **GIỮ re-stamp toàn bộ carry @S152** *(26 slug — con-trỏ dòng Carry kỳ S152 bên dưới, KHÔNG chép để tránh drift; re-verify: phiên governance-only nên nhóm product/UAT 0 đổi trạng-thái)*. ĐÓNG @S153: `[carry:adap-apply-2-thu]` *(cả 2 thư TRỌN: ① probe+filing+thư-hub · ② executed + draft §6 + adap-report + thư hub `aedd7fb67405` 6-datum; inbox pending 0)*.
**🔴 NEXT anh @S153 (đánh số trả lời bằng số):** **(35)(36)(37)** veto-window 3 quyết còn lại *(trần `mind_ctx_kb`=32KB · máy-$0-mỗi-pause · nạp-nền-rút-gọn `tiep_reload`)* không veto = giữ · ~~(38)~~ **anh đã VETO + chốt hub-form 3-vai @S153** · **(39)** RAG Qdrant DOWN (6333 refused, gotcha #14 off-after-reboot; charter AI_INFRA anh tự chạy `rag-infra.ps1 -Action ensure` / để AI_INFRA / cho em chạy cross-repo?) · **(40)** `hmw_width.cap` 20 < roster 23 full-sweep LOUD-skip 3 lane cuối nâng cap hay giữ? · **(41) 🆕** `ring5-audit`: build SE-form ngay hay chờ nhịp adopt chung với VIPIX? · slot **(26)(29)(33)(34)** + (4)-(25) giữ nguyên (đọc segment S152 dưới).
> 📎 **Draft/spec vòng Ctx (F-3 H1 @close — neo con-trỏ live-doc):** SE-form + 4 quyết định + trạng thái RESOLVED §6 = [`docs/governance/ctx-soft-memory-se-draft.md`](governance/ctx-soft-memory-se-draft.md) · spec thi-hành 9-task + checklist 24-phép = [`spec-ctx-adopt-26-07-2026.md`](../.claude/workflows/runs/2026-07-26-S153-ctx-adopt/spec-ctx-adopt-26-07-2026.md) · nấc adopt = [`adap-report thư ②`](governance/adap-reports/2026-07-25-Governance-pause-tiep-upgrade-vong-ctx.md).

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,112 @@
# S155→S157 — PE nút XÓA ship prod · điều tra quy trình sau-CEO · UAT Địa điểm
> **Phiên-LOGIC L7**, 4 cửa-sổ vật-lý (2026-07-27 → 07-28), nối bằng `/pause` + `/tiep`.
> Lead: Fable 5 (S156-S157) · State cuối: Mig **68** · 89 bảng · **562 test** · gotcha 83 · counter **31**.
> Con-trỏ durable: `.claude/sessions/session-7/_context-s-7.md` (FLOW 3 entry PAUSE-1..3) · `_mind-s-7.md` (MIND-0..3).
---
## 1. PE — nút XÓA phiếu ở màn duyệt (SHIP PROD, 2 đợt)
**Nguồn:** ảnh chat UAT anh Kiệt FDC. **Owner chốt trong cửa:** cờ `AllowApproverDelete` **per-NGƯỜI** (không per-vai) · màn "Đã xóa" **chỉ xem, không khôi phục** · **vá trọn rồi đẩy** (bác 2 phương án đẩy sớm) · bỏ policy-theo-vai trên đường xóa mới, giữ 3 rào nghiệp vụ.
**Vì sao chia 2 đợt** (anh chốt, có bằng chứng): §F.0 chứng minh quyền xóa **không tới được phiếu đang treo** nếu thiếu lệnh sửa-quy-trình-tại-chỗ ⇒ đợt 1 = NỀN, đợt 2 = phần người dùng chạm.
- Mig **68** `AddPeAllowApproverDelete` — AddColumn trên `ApprovalWorkflowLevel`, **no new table** (89 giữ), reversible Down.
- Commit: `b1bae77` (nền) · `4464a46` (nút xóa + menu 3 mục + màn "Đã xóa") · `f4494cf` (fix menu sáng nhầm).
- **cicd PASS 6/6** — lead **tự đo** @S156 thay vì giao lại `cicd-monitor` (vai đó đã dừng giữa chừng ở cửa trước): endpoint 2/2 → **401** (control bịa ra 404, chứng phép đo có phân biệt) · smoke **8/8** · **D3 giao-tập-ID = 0** (37 phiếu sống ⟂ 9 phiếu xóa, không lẫn) · bundle rotate ×2 app + **4/4 byte-marker** · Run #531 success 5m41s.
- Test **532 → 562** (+30). Chi tiết: `.claude/workflows/runs/2026-07-27-S155-pe-delete-approver/cicd-verify-dot2.md`.
**Lớp lỗi lặp ĐÚNG 4 LẦN trong riêng cửa này***cơ-chế đúng, thứ đi qua nó không có*: policy tồn tại nhưng 11/13 vai `CanDelete=0` · endpoint PUT sống nhưng 0 dây FE gọi · policy chặn đúng approver cần dùng · DTO thiếu field FE đang đọc. **Cả 4 đều build sạch + test xanh.** Chốt chặn đã dựng: **T27** (fault-inject xác nhận có răng).
---
## 2. A2 — quy trình SAU khi CEO duyệt (b.7→21) · CHẶN chờ anh
**Nguồn:** PDF sơ đồ *"A. PHÊ DUYỆT GÓI MEP, KẾT CẤU THÉP"* 6 lane × 21 bước. Anh chốt *"đã xong bước thứ 6 tức CEO duyệt rồi, bắt đầu đến Project (Ban Chỉ Huy Công trường)"* ⇒ phạm vi **b.7→21**.
**🔴 Anh ĐẶT TÊN NGHIỆP-VỤ cho khúc 7→12 = "đề xuất giá trị ký kết hợp đồng".** Đây là phát-biểu **MỤC ĐÍCH**, không phải đổi nhãn: đầu ra = **1 CON SỐ có phê duyệt**; b.8-9 (duyệt mẫu / shopdrawing với TVGS) = **căn cứ**, b.10-12 = **chuỗi duyệt chính con số đó** ⇒ nó là **PHIẾU**, không phải thư-mục đính kèm. Hệ quả: Q2 nhánh (c) yếu hẳn, Q6 gần như tự trả lời. Bỏ tên tạm "PostAward" của bản invest.
**Đã chạy:**
- `/fable-real investigator-codebase` (Fable) 2 lượt — lượt 1 **`#53` mất trắng return**, cứu TRỌN từ đĩa; lượt 2 resume cắt-ngắn CLEAN, `sub-invest-bch-1.md` **22.659 B**.
- `/fable-clone reviewer` `wf_1618ae3c-a17`**4/4 lane sạch, 0 chết**, 35 điểm: verdict `LUNG-LAY 11` · fidelity `CO-VAN-DE 10` · q2 `THIEU-PHUONG-AN 14` (+ thiên-vị-có-hướng) · gaps `4/4 THẬT, 0 dương-giả`.
**Đăng-ký run (Sàn-5 — vá hồi-tố @S158):** detector `governance-detectors.ps1` **C12 raw-engine-bypass** bắt file này
nhắc `wf_`**cả file 0 dòng `run=`** ⇒ 3 run-folder của S155-S157 không có nơi đăng-ký BỀN (WAL là sổ ghi-đè, marker
`wf:` bị xoá ngay khi việc xong ⇒ hậu-kiểm cuối phiên soi WAL là **soi chỗ dấu vốn được thiết-kế để biến mất**).
Session-log = append-only ⇒ đây mới là sổ cái. Đăng-ký bù:
```
wf: S155 pe-delete-approver run=2026-07-27-S155-pe-delete-approver runId=wf_55f6201f-a52
wf: S156 bch-post-ceo-flow run=2026-07-27-S156-bch-post-ceo-flow runId=wf_1618ae3c-a17
wf: S157 ke-hoach-ky-ket-hd run=2026-07-28-S157-ke-hoach-ky-ket-hd runId=wf_57af0163-053
```
- **Verdict `LAI` SỐNG:** b.13→21 **TÁI DÙNG** Contract V2 · b.7→12 **DỰNG MỚI**. Đổ ở *nhãn chi-phí* + *cách đặt vấn đề*, không đổ ở lõi.
**Grounding 4 phép (đo, không suy):** `PE.DaDuyet = 7` khớp "xong b.6" · cầu PE→HĐ **CÓ SẴN** (`CreateContractFromEvaluationFeatures.cs`) · `shopdrawing|TVGS|duyệt mẫu` = **0 hit toàn repo** (b.8-9 là đất trắng) · `ContractPhase` **12 giá trị / 7 `[LEGACY]`** — 🔧 lead ghi nhầm "9 phase / 6 LEGACY", **2 vai độc lập bắt được**, máy xác nhận.
**CÒN NỢ trước khi trình anh — 6 việc sửa bản invest** (`review-synthesis.md` §G): vá **1 claim SAI SỰ THẬT** ("hardcoded policy fallback" → thật là `ConflictException:115-116` ⇒ HĐ tạo từ phiếu **KẸT CỨNG `ChoDuyet`**, hỏng CỨNG chứ không degrade êm; gốc: invest **tin skill-doc hơn ĐĨA**, doc stale che luôn lệch display⟂guard) · siết biên `b.14→19` · thêm Q vai-người-TRÌNH · thêm cảnh báo lỗ hổng reject · Q5 thêm phương án (d) `skipToFinal` **ĐÃ WIRE** mà invest bỏ sót · **viết lại Q2** theo 2 trục + 3 số đo cùng đơn-vị lấy từ twin repo.
---
## 3. 🔴🔴 Lỗ hổng an ninh prod — duyệt Hợp đồng (phát hiện @S156, TREO theo lệnh anh)
**KHÔNG liên quan tính năng mới** — gotcha #82 tái phát ở module Contract:
- `ContractWorkflowService.cs:48-66` — nhánh **Reject chạy TRƯỚC MỌI GUARD** (0 kiểm role, 0 kiểm approver, 0 kiểm `fromPhase`), `SaveChanges` + `return` luôn.
- `ContractsController.cs:13`**`[Authorize]` trần DUY NHẤT** phủ **22 endpoint ghi**.
**mọi user đăng nhập Từ-chối / Trả-lại được BẤT KỲ hợp đồng nào, kể cả `DaPhatHanh` (terminal)**, kèm xoá `SlaDeadline`. Lead verify **2 tầng độc lập**; đối chứng: PE controller có **3 per-action policy** (bất đối xứng rõ giữa 2 module).
**Trạng thái:** anh chốt 2026-07-28 *"chỗ hợp đồng cứ từ từ nhé"***treo có chủ đích**, không phải bị bỏ quên. Đã tách chip riêng.
---
## 4. S157 — UAT "lấy địa chỉ lên luôn" (SHIP PROD)
**Anh Kiệt 07-28, ảnh chụp form tạo phiếu:** ô **Địa điểm** trống, *"chỗ này lấy địa chỉ lên luôn giúp anh"*.
**🔴 Chẩn đoán: DATA, không phải CODE.** Cơ-chế auto-fill `Project.Location` **đã wire từ S59 và chạy đúng cả 4 tầng** — cột DB → projection `ProjectFeatures.cs:51` → FE type `master.ts:97``onChange` SearchableSelect (`PeWorkspaceCreateView.tsx:227` + `PeHeaderForm.tsx:200`, có cả logic không ghi đè khi user đã gõ tay).
Đo prod bằng sqlcmd **trước khi đụng code**:
| Đo | Kết quả |
|---|---|
| BVN01 (dự án trong ảnh) | `Location = NULL` |
| Tổng dự án | 62 |
| **Thiếu Địa điểm** | **57** |
| Có Địa điểm | 5 — CAL01 · MIDEA01 · SAM01 · TLB01 · ZOTE01 |
Đúng 5 dự án đó = đúng 5 dòng có địa chỉ trong file Excel nhập S55. **Nếu viết code auto-fill "mới" thì code sẽ chạy hoàn hảo và ô vẫn trống** — đây là lần **thứ 6** của lớp *cơ-chế đúng, thứ đi qua nó không có*.
**Anh chốt hướng:** *"để người dùng cập nhật Master data rồi sau đó fill ra phiếu, cái nào không có thì không cần fill"***KHÔNG backfill hàng loạt**.
**Vá (`6250f39`):** thêm dòng cảnh báo amber ngay dưới ô Địa điểm, chỉ hiện khi **đã chọn dự án** mà dự án đó **không có `location`** — nói thẳng lý do + trỏ chỗ bổ sung (Danh mục → Dự án → Địa điểm). Lý do làm vậy: ô trống im lặng khiến người dùng tưởng hệ-thống hỏng → đẻ báo lỗi giả (đúng ca vừa xảy ra). 4 file, **SHA256 mirror 2 app IDENTICAL**, npm build 2/2 PASS.
**Deploy verified 2 NGUỒN ĐỘC LẬP:**
- `cicd-monitor` **PASS 9/9** (`cicd-verify-s157-diadiem.md`) — Run #419 success **5m40s**, test gate **562 (45D+517I)** khớp canonical cả 2 thành-phần, bundle rotate 2/2 + `Last-Modified` nằm trong cửa-sổ deploy, byte-marker **2/2 app** (count=2 = đúng 2 chỗ nhúng/app), **control âm**: hash bịa + hash cũ đều rơi về SPA shell 900B `text/html` ⇒ bundle cũ đã **biến mất khỏi đĩa**, deploy ghi đè thật.
- **Lead tự re-curl độc lập, KHỚP TỪNG BYTE:** admin `8-QYcMOg` 1.675.282 B LM 02:44:33Z · eoffice `DptYR4wL` 1.575.513 B LM 02:45:30Z · marker 2/2.
---
## 5. Governance / harness
- **`/tiep` S157** (window 4): Sàn-3 5 tín-hiệu — 3 kêu, cả 3 khớp WAL. `verify:` **5/5 KHỚP, 0 lệch**. Tick counter **30→31 CLEAN**. Thư cross-project `se=0 all=0` (**5/6 repo — `dyd` VẮNG trên máy**, fail-soft khai rõ).
- **`ctx-verifier` @`_tiep-3`** (vai-2 vòng Ctx): `CO-CO — 10 cờ`, return CLEAN. Nặng nhất: trần `_mind` **dư 110 B** ⇒ cửa sau phải nén **≥2 block** (MIND-2 + MIND-3) chứ không phải 1 — carry cũ under-state 2 lần; kèm hở luật *"nén block cũ nhất"* khi block cũ nhất **đã nén rồi**. Cờ **C3 đã vá trong cửa** (header CURRENT STATE còn ghi mốc S153 trong khi số đã bump tới S156).
- **`#53` (return garble) cửa S157 ×1** — `cicd-monitor` **tái phạm đúng dự đoán**: return = mẩu transcript giữa chừng, không phải verdict. **Cứu TRỌN 10.666 B từ đĩa** nhờ lead ép *ghi-từng-mục-trong-lúc-làm* ngay trong prompt. Củng cố datum: **chặn được #53 = ghi-đĩa-trong-lúc-làm, KHÔNG phải prompt-đúng**.
- **Vết lỗi lead @S156:** viết `run.md` **điền SẴN kết-quả cho lượt chạy CHƯA xảy ra** (byte-count + `TOTAL=14 GAP` + verdict = bịa). Tự bắt ngay sau Write, sửa về `[ ]`. Cơ-chế = *quán-tính điền mẫu*; cứu nhờ **thói quen đọc lại thứ vừa Write**, không nhờ trí nhớ ⇒ chốt chặn phải là **luật soi được**.
- **Memory mới:** `.claude/auto-memory/feedback_mechanism_right_data_absent.md` — lớp *cơ-chế đúng / dữ-liệu không có*, nay ×6, kèm luật *"UAT báo không chạy ⇒ ĐO DỮ LIỆU PROD trước"*.
---
## 6. CÒN TREO sang phiên sau
| # | Việc | Chờ ai |
|---|---|---|
| 1 | 6 việc sửa bản invest → trình anh 14 câu → Q1-Q6 | em làm, rồi anh trả lời |
| 2 | Lỗ hổng an ninh duyệt HĐ | anh xếp ưu tiên (*"cứ từ từ"*) |
| 3 | 4 lỗ "cột CÓ mà 0 ai đọc" (L1 cầu PE→HĐ bỏ pin V2 · L2 `CeoApprovalThreshold` 0-consumer phía HĐ · L3 SLA hardcode `AddDays(7)` · L4 `AttachmentPurpose` sai tầng) | em |
| 4 | 22 FLAG governance (42)(43)(44)(E2) — **4 cửa-sổ chưa động** | anh |
| 5 | Trần `_mind` — nén ≥2 block hay nâng `mind_ctx_kb` | anh |
| 6 | `reviewer/MEMORY.md` 19.049 B trên ngưỡng 17.1 KB | em curate |
| 7 | Monthly drift-audit **2026-08-01** | em (session đầu tháng) |

View File

@ -0,0 +1,89 @@
# S158 — adap `/day` probe-first + bookend-close 5 vòng (2026-07-28 tối)
> Phiên-LOGIC **L7, window 5** (vào bằng `/tiep`). **Governance/adap-only — 0 prod-code, 0 migration, 0 test mới.**
> Test đo tươi: **562 PASS** (45 Domain + 517 Infra), 0 fail. Counter **31→32**.
## Đăng-ký run (Sàn-5 — session-log là sổ cái append-only, WAL là sổ ghi-đè)
```
wf: S158 adap-day-wake run=2026-07-28-S158-day-wake-probe-first runId=fable-real-single-lane
wf: S158 bookend-close run=2026-07-28-S158-bookend-close runId=agent-tool-multi-spawn
```
## Việc
**`/tiep` recovery trọn.** Sàn-3: 5 tín-hiệu MẠNH đều kêu **đúng** (2 orphan run-folder · 2 commit non-`wal:` · ORPHAN-L `session-7` pause=4/tiep=3) — corroborate WAL, không mâu thuẫn. `verify:` **5/5 PASS, 0 lệch**. TICK S157→S158. Biên-nhận `_tiep-4.md` (window-ordinal 5).
**`/check-email` AI_INFRA.** Verify bằng **NỘI DUNG** không phải tên file: 22/22 file `outbox/se` có trong `inbox/ai_infra`, **`cmp` 0 byte-drift** ⇒ `se=0` thật + không có stamp-then-edit (H18). Kênh `all`: 1 thư → đóng bằng adap-report cùng phiên ⇒ cuối phiên `se=0 all=0`.
**`/adap-apply` `2026-07-28-Governance-day-wake-probe-first-resume` qua `/fable-real investigator-codebase`** (vai do owner GÁN qua AskUser). Nấc **`agreed`** — **0 file cơ-chế bị sửa**; `day.md` chưa tồn tại. Spec 3-mục + adap-report + **4 phản-biện gửi ngược hub** + **1 datum dogfood** (hub tự khai có 0).
🔴 **Engine BÁC 2 tiền-đề của lead:** mồ-côi **0/8** (không phải "có squash ⇒ có mồ-côi") · probe **phải dựng phép-2**, không tái dùng Sàn-3 — chứng bằng cửa S158 nơi 2 phép cho **verdict NGƯỢC NHAU**.
**④ Rà 6 HIGH lens-wave spec KHKK:** 4 phủ trọn (H1/H2/H3/H4), **2 còn hở** → di-trú sang HANDOFF NEXT-em: **H5** W3 `N` chưa pin (N=0 vẫn PASS) · **H6** §2.4:224 còn giữ cơ-chế `IsVisible` đã bị chính file đó đo-đĩa bác ở `:289-290`.
**⑤ Bookend-close 5 vòng — 10 spawn.** V1 tooling+harvest → ring1 · V2 cặp H24 → ring2 · V3 trio eval→refine→audit · V4 nén-ngủ **`không-nhịp`** (`SHARD-PROBE pending=15/15 ⇒ IM`) · V5 floor/detector.
## 🔴 `#53` — kỷ lục phiên + ĐỐI-CHỨNG NỘI-PHIÊN SẠCH ĐẦU TIÊN
**7/8 lane garble.** Nhưng biến độc lập tách được sạch:
| Vai | ép ghi đĩa? | garble | mất |
|---|---|---|---|
| `investigator-codebase` (Fable 222K tok) | ✅ | KHÔNG | — |
| `tooling` · `harvest` · `lead-stale` · `lead-gap` | ❌ | ✅ ×4 | **TOÀN BỘ** — 4 resume |
| `ring1` · `ring2` · `refine` | ✅ | ✅ ×3 | **0 B** (2.818 / 5.354 / 7.957 B nằm sẵn) |
**Ép-ghi-đĩa KHÔNG giảm tần suất garble, nhưng đưa thiệt-hại về 0.** Xác nhận lần 5: chống `#53` = **thiết-kế ARTIFACT**, không phải PROMPT. Sổ `#53` cập nhật **66 cận-dưới qua S158**; S153-S157 **khai KHÔNG đếm được** (số "~27" của lead-gap neo bằng số dòng `_mind`, ring2 bác ⇒ không nhập tally).
🔸 **Câu garble chứa finding thật**`ring1` chết đúng lúc phát hiện `run-chua-gom` 3→4; `ring2` chết đúng lúc bắt gap FLAG-3 tự mâu thuẫn với FLAG-2 của chính nó.
## Bẫy chặn được trong cửa (đáng nhất phiên)
**Mồi-ngầm neo bằng SỐ DÒNG.** `_context:62` định danh mồi bằng `_mind-s-7.md:99`; `_mind` chèn khối mới ở TRÊN + đã nén 3 lần. Hôm nay `:99` = *"Luật nén `_mind` HỞ"***vấn-đề mở thật**, đang là câu chờ-owner (45).
⇒ Nếu spawn `ctx-audit` mà không xử: hoặc **ĐẠT-ảo**, hoặc **dán nhãn "bẫy cài sẵn" lên đúng câu đang trình owner** rồi gạt.
Lead khôi phục từ git → mồi thật = *"Guard post-wave assertion mù 4 path hook…"*, pin **bằng nội dung**.
🔴 `ring2` dựng chronology mạnh hơn: neo **SAI NGAY TẠI COMMIT SINH RA NÓ** (`8d4075a` vừa mint chữ "mồi-ngầm" vừa là chỗ L99 đã thành dòng khác) ⇒ **stale-at-birth**, không phải trôi-do-nén. Và tìm được **đường thứ 2 độc lập** xác nhận (`sub-ctx-audit-open-S154.md:199` grep theo nội dung).
**Luật:** CẤM neo mục tiêu vào số dòng của file append-ở-TRÊN.
## Findings đã VÁ trong phiên
| # | Nguồn | Vá |
|---|---|---|
| RAG khai `alive` mà DOWN | stale FLAG-2 HIGH, **3 phép đo độc lập** `chunk_count=0` cho 7 project + shared_global | `STATUS:459` lật DOWN, giữ 2447 làm last-known-good có nhãn |
| Bundle hash prod đã chết | stale FLAG-1 HIGH; `cicd-verify:58` dùng chính ô này làm baseline | `STATUS:461``8-QYcMOg`/`DptYR4wL`, control-âm 900/876 B |
| `STATUS:6` 4 cửa-sổ / counter 31 | stale FLAG-3 | → 5 cửa-sổ / 32 |
| **M-1** nguyên văn owner bốc hơi | ring2 — `grep -c 'bước thứ 6'` = 0/STATUS + 0/HANDOFF | nhét verbatim cạnh dẫn xuất `b.7→21` |
| `WAL:5` · `WAL:21` | stale FLAG-4/5 | 5 cửa-sổ · tick `[x]` nấc `agreed` |
| HANDOFF dừng S153, slot dừng (41) | stale FLAG-6 | segment S155→S158 + slot **(42)…(48)** |
| **Gate 5-anchor vô gia cư** | gap FLAG-4, hạn chót = cửa kế (§6.4 sắp xoá WAL) | di-trú sang HANDOFF **NEXT em** |
| `ef-core-migration` bảng dừng Mig 67 | H1 FLAG-1 — **lần 3 cùng class** | 🔴 vá **CẤU TRÚC**: frontmatter thôi khai bảng là nguồn "mới nhất", trỏ 2 nguồn SỐNG (ring1: thêm row = vá triệu chứng, đảm bảo stale lại ở Mig 69) |
| `contract-workflow:371` "Contract V2 chưa" | **ring1 thách-CLEAN thủng H1** — sai **~2,3 tháng**, phát-biểu SAI chủ động | đính chính: V2 đã wire từ S29, đĩa có 3 chứng |
| C12 raw-engine-bypass | detector | +3 dòng `run=` hồi-tố S155/S156/S157 |
| 2 orphan run-folder | H2 F2/F3 — lead viết dạng-3 **đã RETIRED** | `adap-synthesis.md` + `bookend-close-synthesis.md` dạng-1 phẳng |
| GAP-3 diary-0-delta ×2 | H2 F1 (`grep -c S158`=0 cả 2 sổ) + gap FLAG-1 | M9 seed on-behalf `ctx-verifier` + `investigator-codebase` |
| Sổ `#53` đứng yên 5 nhãn phiên | gap FLAG-3 `gap-incident-unrecorded` | ghi bù + **2 sub-class mới** |
## 2 sub-class `#53` mới (guard hiện KHÔNG bắt được)
1. **`skeleton-ruột-rỗng` nấc-2** — 202K tok, đĩa **1.661 B khung rỗng toàn heading**. Guard S150/S151 dạy *"verify byte-content tăng thật"* — mà **1.661 B LÀ byte > 0 và CÓ tăng** ⇒ phải verify **NGỮ-NGHĨA**, không chỉ byte.
2. **`engine-process-exit`** — CLI thoát, **0 delta đĩa** = lượt chạy chưa từng tồn tại. Phân biệt: `#53` = đĩa có + return sai · `skeleton` = vỏ có + ruột rỗng · cái này = **0 delta**.
## memory-triple
```
memory-triple: do=scripts/measure-agent-memory.ps1 · 0/23 L1 over-30KB
memory-triple: de-xuat=scripts/memory-archive-gate.ps1 DRY · A7 GATE PASS 402/402 pointer, 0 failed
memory-triple: kiem=harness-audit · (verdict ghi ở harness-audit-return.md)
memory-triple: do-record=governance-detectors TOTAL=44 (INFORM-only 7, self-match 0)
memory-triple: do-record=NHIP-NO: kiem light 5/6 deep 7/15 ok | tran-bo-nho 0 over-cap l2idx 0 over | run-chua-gom 3 | pull-cach 6 ngay
```
## Verdict các vòng
`TOOLING: PASS_WITH_FLAGS — 3` (ring1 chấm **under-count**, phải ≥2 ở mặt ①) · `HARVEST: GATE-PASS-6 | GATE-FAIL-0` · `LEAD-STALE: 6 FLAG` · `LEAD-GAP: 5 FLAG` · `RING1: 38 CLAIM — 29Đ/3T/6KC` · `RING2: 11 CLAIM — 11Đ/0T/0KC` · `HARNESS-EVAL: MIXED — 18 signal` · `HARNESS-REFINE: 1 ACTION — BÁC 9`
## Bài học nổi bật
- **Vòng KIỂM tự bắt lỗi của chính nó nhiều hơn bắt lỗi con-đo:** `ring1` 3/4 falsify BROKE là lỗi của nó (parse non-greedy dính bẫy `]`-trong-comment — **đúng cái H1 khai đã né**; `comm` lệch collation; quên nhánh DUAL-ACCEPT). Tự kết: *"2/2 lần đầu nghi con-đo đều là lỗi tao"*.
- **Con ĐỀ-XUẤT bác lại con ĐO có căn cứ:** `refine` B1 mở **cả 11 file** → 11/11 có tem `on-behalf/M9` in-content ⇒ S7 *"11 diary chung 1 mtime"***proxy mtime đọc sai**, corpus không giấu gì.
- **Thước MA tốn công thật:** "17,1K" nằm ở 5 diary, **0 key + 0 reader**; `inv-cb` nén về ~17,1K @S155, **3 ngày sau 20.646 B lại**. → câu owner (46).
- **`gap-owner-specifics = 0` verdict đúng nhưng lời khai coverage TRƯỢT** (ring2): mẫu số thật ≥6-8, gap khai 4, không khai tập bù — tái phạm đúng lỗi ring2 bắt @S154.

View File

@ -0,0 +1,86 @@
# adap-report — `2026-07-28-Governance-day-wake-probe-first-resume`
- **Repo:** SOLUTION_ERP (self = `se`) · **Phiên:** S158 (phiên-LOGIC L7, window 5) · **Ngày:** 2026-07-28
- **Broadcast:** `ai_infra``all-fit`, 13.832 B, `content_sha256: ef05b7da8d5e…`, `reviewer_gate: PASS r3`, `nac: published`
- **Engine:** `/fable-real investigator-codebase` (vai do owner GÁN qua AskUser) — single deep-pass, propose-only
- **Run-id / bằng chứng:** `.claude/workflows/runs/2026-07-28-S158-day-wake-probe-first/`
· `run.md` · `sub-invest-day-1.md` (25.440 B) · `spec-day-wake-probe-first-28-07-2026.md` (lead-verified)
## Nấc G-011: **agreed** (KHÔNG phải executed)
Thiết-kế đã chốt + kết-tinh spec 3-mục có acceptance đo được. **0 file cơ-chế được sửa**`day.md` chưa tồn tại,
`pause.md`/`tiep.md`/`session_ctx.py`/`memory-budget.json` **nguyên trạng**. 3 chỗ chạm canonical **đang chờ owner gật**.
🔴 Không claim executed khi chưa có dây nào nối — §C5 honest.
## PROJECT-FIT: **Fit đủ bốn khoản** (hạng cao nhất của thư)
SE có ĐỦ 2 nền thư đòi: kit phiên-logic 17-07 (`.claude/sessions/session-<N>/` + `/pause`+`/tiep` + WAL)
**và** vòng-canh 25-07 (3 vai `ctx-{curator,verifier,audit}` + khoá `tiep_reload`).
## Số đo THẬT của SE (đơn-vị BYTE — cố ý KHÔNG quy token)
| Hạng mục | SE | Hub (thư khai) |
|---|---|---|
| Bộ nạp-nền mỗi lần nối | **122.115 B** / 5 nguồn | 439.328 B / 8 file |
| Cửa CLEAN sẽ SKIP | **86.441 B (70,8%)** + 1 spawn `ctx-verifier` | — |
| Bẫy-một (anchor lệch 1 nhịp) | **4/4 THẬT** | có |
| Bẫy-hai (sha mồ-côi) | **0/8** | 2/2, range 35 rác |
| Drift marker | **`_snapshot` 3/4** (PAUSE-4 thiếu vết) | `_tiep` khai 2 / đĩa 3 (s109) |
🔸 Nền SE **nhẹ hơn hub 3,6×** ⇒ lợi tuyệt-đối nhỏ hơn. Khai thẳng, không mượn số hub.
🔸 Token: **dải mở**, SE không có tokenizer — cùng lập trường hub, không chốt số.
## 🔴 Phản-biện gửi ngược hub (§6 brutal-honest / §M)
**1. Bẫy-hai KHÔNG phổ quát — SE đo ra 0/8 mồ-côi.**
Thư ngụ ý *"dự án nào có squash cuối phiên thì sha marker cũ thành mồ-côi"*. SE **có** squash (`session-end` §5.0/§5.2)
nhưng squash chỉ gọt **trailing-`wal:` CHƯA push**; 6/8 sha đã push ⇒ bất khả mồ-côi. Đo: `cat-file -e` + `is-ancestor`
**sống 8 / mồ-côi 0** (lead re-đo độc lập, khớp engine).
⇒ Đề nghị hub sửa điều-kiện từ *"có squash"* thành *"có squash **chạm commit ĐÃ push**"*.
🔴 **Guard vẫn giữ nguyên bắt buộc** — 3 lý do ở spec §②F3, đáng chú ý nhất: **chính feature `/day` tự đẻ điều kiện orphan**
(chuỗi cửa-nhẹ Q&A sản xuất trailing-`wal:` thuần = đúng thứ squash gọt).
**2. Bổ sung cho F3: `cat-file -e` MỘT MÌNH là THỦNG.**
Tiền lệ SE **S127**`f9fa77d6` dangling: object **còn tồn tại** nhưng **không còn là tổ-tiên HEAD**.
Thư đã ghi đúng cả 2 lệnh, nhưng nên nói rõ **vì sao cần cả hai** — dự án nào cài mỗi `cat-file -e` sẽ lọt **im lặng**.
**3. Đề xuất nâng F3: anchor = carrier-commit, mạnh hơn form của hub.**
Thay vì "resolve commit-chốt-dừng đầu tiên sau head-sha", SE dùng
`git log --diff-filter=A -1 -- <marker-file>` — commit ĐẦU TIÊN **thêm chính file marker**.
Đo **8/8 resolve**; **sống-sau-squash by construction**; và **nuốt luôn bẫy-một** (khỏi bước resolve riêng).
**4. Khoảng trống thư chưa nói: allowlist dirty phải gồm sổ đếm của chính nghi-thức.**
Ở SE, `.claude/governance/.session-counter.json` **dirty NGAY lúc probe chạy** (tick fire ở cửa vào).
Thiếu nó trong allowlist ⇒ F1 **chết nửa số ca** mà trông như "probe hoạt động, chỉ toàn DELTA".
## Tailored (FORM của SE) vs giữ nguyên (FUNCTION-floor)
| | |
|---|---|
| **Giữ floor** | F1 probe-trước-trả-giá · F2 guard bước-0 hai lệnh cũ · F3 anchor đúng + guard mồ-côi · F4 marker đếm-được + falsifier 2 chiều |
| **Tailor** | tên `/day` giữ · marker `_day-<i>.md` 7 trường khuôn `_pause`/`_tiep` · verdict dùng `CLEAN-delta` (**CẤM** chữ "sạch" — tránh đè phán quyết Sàn-3) · probe cài vào `session_ctx.py` sẵn có, không dựng script mới |
| **SE thêm, thư không có** | 4 ràng hygiene ghép với **Sàn-3** (`tiep.md §0`) — SE có tầng này, hub không |
| **SKIP** | Không nới `wal-flush.ps1` (path ④ `.claude/sessions/` chở `_day-*` miễn phí) ⇒ **không đẻ điểm mù mới** cho Sàn-3 |
## 🔴 Quyết-định thiết-kế lớn nhất — và nó BÁC hướng nghiêng ban đầu của lead
**Probe F1 dựng PHÉP ĐO THỨ 2, KHÔNG tái dùng Sàn-3.** Lead vào cửa nghiêng về tái dùng (sợ 2-nguồn-sự-thật, B1).
Bằng chứng bác, lấy từ **chính cửa S158**, nơi 2 phép cho verdict **NGƯỢC NHAU**:
- Sàn-3 ②: **HIT** (2 commit non-`wal:` trong `origin/main..HEAD`)
- anchor-delta: **0 ⇒ CLEAN**
⇒ Hai câu hỏi khác nhau: *"tồn-tại việc dở"* (neo `origin/main`) ⟂ *"đổi so điểm dừng"* (neo marker pause).
**Khác câu hỏi thì khác nguồn sự-thật là hợp lệ — B1 không cấm.** *(Cả 2 số do lead tự đo ở §0 cửa này, trước khi engine chạy.)*
## Dogfood — SE có 1 datum, hub có 0
Thư tự khai *"dogfood: 0 phiên"*. SE đo được **1 ca thật, TRƯỚC khi đọc thư**: cửa `/tiep` @S158 này probe ra **CLEAN**
(`_pause-4` head-sha `d7eaece` → carrier `6c263dd` = HEAD; cây sạch; 0 sentinel) ⇒ **lẽ ra đi đường dậy-nhẹ**,
mà lead đã trả giá full (nạp 122.115 B + spawn `ctx-verifier`).
🔸 **1 điểm dữ-liệu, KHÔNG phải bộ số** — không được đọc thành "SE đã dogfood xong".
## Còn nợ
- [ ] Owner gật **3 chỗ chạm canonical** (`tiep.md §0` ⑤(b) r-set · `CLAUDE.md` câu "DUY-NHẤT `/tiep`" · `check-email.md` nhịp 4→5 cửa)
- [ ] Thi công (lead tự tay) + **workflow REVIEW RIÊNG** (Harness-9 mandate)
- [ ] Dogfood 2 cửa → gửi hub bản report kèm số thật + run-id