Compare commits
8 Commits
15349e8ee0
...
7a903cf108
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a903cf108 | |||
| 2cc22fde0f | |||
| 2a4a1e1b18 | |||
| 4163f42fd2 | |||
| bcb33322b9 | |||
| e2eab97a86 | |||
| 24ea71e2e8 | |||
| bd68f71e42 |
106
.claude/WAL.md
106
.claude/WAL.md
@ -1,81 +1,41 @@
|
||||
# WAL — auto-generated, không sửa tay
|
||||
updated: 2026-07-31T15:13:43+07:00 | session: S165 (L9, window 3 — /tiep; lead=Fable) | branch: main
|
||||
updated: 2026-07-31T21:52:00+07:00 | session: S165 (L9, window 3 — /pause) | branch: main
|
||||
|
||||
goal: CHUỖI 4-GĐ SP-002 — SPEC ĐÓNG BĂNG (B0→B3 trọn) · B4 BUILD BẮT ĐẦU (wave K1-BE đang chạy)
|
||||
goal: CHUỖI SP-002 B4 — K1+K2+K3 SHIP (3/8 wave); K4a→K8 + checkbox-opt-out = lần /tiep sau (mandate PAUSE-3)
|
||||
|
||||
chain:
|
||||
[x] /tiep + VÁ 12/12 + spec SP-002 nạp (6 nhịp + 3 hình) — log cũ trong _context
|
||||
[x] B0 draft → B1a invest (att-2 cứu) → B1b clone-review 3-lane → spec-tổng v2
|
||||
[x] B2 TRỌN 3 cụm: invest fable ×3 (c1 33KB · c2 5/5 · c3 22.9KB) + review 3-lane ×3 → 3 spec-cụm final,
|
||||
43 vá. Sự cố đã xử: ngược-#53 ev#4 · skeleton-472B ×1 · chết-ruột-188B ×1 (opus) — đan-xen từ đó 5/5 SẠCH
|
||||
[x] OG CHỐT TRỌN 9: 1-gộp+UI-1-1 · 2-đội-hình-cũ · 3-NĐUQ-human-gate-VĨNH-VIỄN · 7-N-phiếu+UI-1 · 8-hiển-thị ·
|
||||
9-đảo-PHÁ-VỠ-S155 · QĐ9-freeze-tái-dùng-máy-sẵn · (V)-thiết-kế-ERP-đúng+PE-test-SOLUTION-PE-{n} ·
|
||||
BACKLOG 3 mục giai-đoạn-sau (amendment · authz-nhóm · bung-gộp)
|
||||
[x] B3 fable-review chốt: GO-WITH-SPEC-FIXES (GO 9/10 · 8 mâu-thuẫn · 0 vá-đè-vá/43 · build-order
|
||||
K1→K2→K3→K4a→K4b→K5→K4c→K6→K7→K8) → 8 fix lead ÁP XONG → SPEC ĐÓNG BĂNG 4 file
|
||||
[x] B4 K1 TRỌN 3 lane (BE p1 wf_2569b79b chết-40%-schema-xong + p2 wf_2e08ba77 seeder86+CQRS+controller ·
|
||||
FE SHA-pair d71a9e3b ×2 · test wf_1fb9f309 7-test; bài giữ: git-status-trước-Write · #68 build-trọng-tài
|
||||
· TenVi sạch · 2 khoảng-hở UX FE khai [3 filter BE chưa UI · tab cả fe-user]) — chi tiết sub-*-k1.md
|
||||
[x] gate K1 PASS-WITH-FLAGS 9f (sub-reviewer-gate-k1.md; reviewer #53 ×1 → resume-sạch, artifact cứu B4-d).
|
||||
Xử @S165: F4 IncludeInactive-mặc-định-loại + T5b · F7 5-kind · F2 STATUS-delta · F9 Mig70-áp-LocalDB.
|
||||
Khai: F1 OG-6-soát-SAU · F3 authz-mirror-#82 · F5 PermGuard-nợ-khuôn-cũ · F6 IX_-NIT. Suite 598/0
|
||||
[x] commit 50e6d8c PUSH → cicd PASS 6/6 (run #434 6m31s · gate-CI 598 · Mig70 prod-top + recycle-proof ·
|
||||
seed 86 TAM-GIÁC 3-nguồn · bundle 4/4 rotate + 4-cũ-chết · smoke 8/8). cicd #53 ×2 @S165 return=memory-
|
||||
talk, artifact cứu trọn. Bài: hash local ≠ hash CI — mốc prod luôn re-snapshot LIVE
|
||||
[x] K2-BE TRỌN (p1 wf_583be7ad chết-giữa-c + p2 chết-@f-0-byte-artifact [#53 ×2 task này, ×4 @S165] +
|
||||
lead-solo đóng: 3-hằng-Scope · submit-guard vá-5-THẮNG-nền-:126 [ghost-window K2→K4b khai] ·
|
||||
controller ?group= · §e DONE-BY-DESIGN EnsureDraftEditable · 3 test cũ update-spec-3-cột).
|
||||
Build 0W/0E · suite 598/0. Artifact sub-implbe-k2.md §c-h = lead on-behalf sau verify-đĩa
|
||||
[x] K2-test TRỌN (lane chết-return + 0-artifact [#53 ×5-6 @S165 cả wave] NHƯNG file test HOÀN CHỈNH:
|
||||
GroupAndCatalogTests 824-dòng 9-Fact T-a..T-g+2 · suite 607/0 = 45D+562I · 0 đè 3-test-lead ·
|
||||
sub-test-k2.md = lead on-behalf sau verify-đĩa)
|
||||
[x] K2-FE TRỌN (p1 chết-sau-recon + markup-rò [sub-class #53 mới, lead cắt]; p2 ĐO LẠI bắt tiền-đề lead
|
||||
SAI-MỘT-PHẦN: 8 khai báo ĐÃ có call-site — diagnostics = snapshot giữa-Write #68; chỗ dở thật =
|
||||
ListPage → vá badge + cột Tổng-duyệt vá-8 + colSpan 8; cp 4-file fe-user; build ×2 PASS DORfkFnc/
|
||||
qYI2yszp; SHA-pair 5/5 + panel control-dương giữ baseline). Artifact sub-implfe-k2.md ĐẦY tự lane ghi
|
||||
[x] gate K2 PASS-WITH-FLAGS 10f (sub-reviewer-gate-k2.md; #53 ×1 → resume; phán vá-5-thắng-nền ĐÚNG +
|
||||
bác 3 nghi-vấn lead-solo). Xử: F-1 guard đếm-so-khớp (bịt hạng-mục-xoá-mềm/Guid-rác) + 2 test bịt
|
||||
(xoá-mềm-chặn + reflection ?group=) · F-2/F-5/F-7/F-8/F-9 comment-honest (lý-do-thật filtered-index
|
||||
khả-thi, thì-tương-lai K4b, Down-data-dependent, default-0-SQL-thô) · F-3 STATUS 607→609 · F-4 SKILL 97.
|
||||
Suite 609/0 (45D+564I) · npm ×2 (comment-only ⇒ bundle hash giữ) · SHA-pair ✓
|
||||
[x] commit K2 0779f2d 23-file PUSH (lần 1 FAIL PS5.1-quote-trap → -F file) → cicd-K2 PARTIAL 5/6
|
||||
deploy-KHỎE (run #435 · gate-CI 609 tách-phần · Mig71 prod-top+restart-proof · bundle 4/4 rotate ·
|
||||
smoke 6/6 ?group= wired; mục-4 backfill/Σ = CHÂN-LÝ-RỖNG prod-0-phiếu — đo lại khi K8 đẻ phiếu thật.
|
||||
cicd #53 return-garble tiếp, artifact trọn)
|
||||
[!] K3 CHẺ NHỎ sau 2 lượt engine-process-exit (p1 wf_a04124a7 + p2 Agent — cả 2 0-delta-0-artifact;
|
||||
bài: task-đọc-nhiều-trước-Write chết, task-hẹp-Write-sớm sống). Bước-0 LEAD: prod=localhost\SQLEXPRESS,
|
||||
QT-DN-V2-001 LIVE, ROSTER 3-trạm 11 người @sub-implbe-k3.md §0, chuong.phan giữ cờ.
|
||||
ĐANG CHẠY: nhịp-1-BE lane (seed 8 wf + 8 MenuKeys — đã append §1 kế-hoạch + khai L1-không-khuôn-type-10
|
||||
→mirror-ContractV2 + L2-ép-false-không-cản-seeder) ∥ K3-FE lane (resolvePath AwV2_KhkkN* + gỡ khóa
|
||||
Designer + panel ×2). XONG LEAD-SOLO: nhịp-2 port finalize (branch mirror PE :866-876 + opt-out
|
||||
applyLevelFinalize 3-tầng interface/service/controller + comment (a)(b) supersede-S155 + 2 test-callsite
|
||||
ct:) + nhịp-3 (gỡ CREATE ép-false :380 [GIỮ PUT-Conflict — luật versioning CHUNG, spec vá-3 liệt nhầm,
|
||||
lệch KHAI chờ gate soi] + rào (v) pin-đúng-nhóm regex KHKK-N[1-8]).
|
||||
✅ nhịp-1-BE DONE (seed 8 wf + 8 key; khai L1-mirror-ContractV2 + L2) · ✅ K3-FE DONE (Layout phép-âm
|
||||
PASS · gỡ khóa duyệt-sớm sạch · Panel pair 336ECCC1F86D ×2 · npm ×2 lead-verified) · ✅ BE trọng-tài
|
||||
0W/0E + 609/0. [!] K3-test lane ĐANG CHẠY (T-a..T-e finalize/opt-out/pin-nhóm/giữ-cờ)
|
||||
→ gate K3 → commit-push → cicd → /pause (mandate mới)
|
||||
[ ] 🔴 MANDATE MỚI (owner in-turn @S165 ~17:3x: "xong nốt thì /pause rồi những đầu việc tiếp theo để
|
||||
lần tiep sau làm tiếp") — SUPERSEDE "chạy 1 mạch": XONG NỐT K3 (BE p2 đang chạy → FE + test song song
|
||||
→ gate K3 → commit-push → cicd verify) rồi /pause. K4a→K4b→K5→K4c→K6→K7→K8 = lần /tiep sau.
|
||||
OG-6 = soát-SAU (giữ). Lưu ý pause tới: trần _mind 84,8% ⇒ PHẢI nén MIND-1 kèm nơi-đi 6 ý trước MIND-3.
|
||||
[ ] K8 dry-run: gói test SOLUTION-PE-{n} + B0-form 14 người thật (fail-closed) + đo freeze 2-nhánh
|
||||
[ ] closeout: seed diary vai (C2 A∖B=∅) · tally garble (+reviewer-gate ×1 @S165 resume-sạch, đếm lại cuối
|
||||
phiên) · nhãn D MIND-3 + nén MIND-1-kèm-nơi-đi-6-ý (trần 84,8%) · STATUS row S163/S164/S165
|
||||
[x] K1 danh mục 86 dòng — gate 9f · commit 50e6d8c · cicd PASS 6/6 (sub-cicd-verify-k1.md; seed 86
|
||||
TAM-GIÁC 3-nguồn prod)
|
||||
[x] K2 phiếu +nhóm +hạng-mục Mig71 — gate 10f (F-1 guard đếm-so-khớp + 2 test bịt) · commit 0779f2d ·
|
||||
cicd PARTIAL 5/6 deploy-khỏe (mục-4 chân-lý-rỗng, đo lại khi K8 đẻ phiếu — sub-cicd-verify-k2.md)
|
||||
[x] K3 8-workflow +finalize +designer 0-mig — chẻ-nhỏ sau 2 engine-exit (bài: task-hẹp-Write-sớm);
|
||||
roster LIVE lead-verify (instance SQLEXPRESS — sub-implbe-k3.md §0); gate 8f/0-blocker (3/3 phán
|
||||
lead ĐÚNG) · commit 15349e8 PUSHED · suite 614/0 (45D+569I) · +8 key AwV2_KhkkN* (All=64, policy=256)
|
||||
[x] cicd-K3 PASS 6/6 @S166 — re-spawn vai đo §1-§5 (run#436 success · gate 614 tách-phần · mig GIỮ 71 ·
|
||||
seed 8-wf shape-từng-email + finalize 2+8=10 + recycle-proof 5364→1900 · bundle admin ROTATE/eoffice
|
||||
FROZEN-giải-thích-trọn) rồi chết lần 2 → §6 smoke lead đo on-behalf 401/404/200/200 + END-line
|
||||
[!] 🔴 ĐẦU VIỆC #1 F-1 checkbox opt-out: CODE XONG @S166 (BE DTO +AllowApproverFinalize · FE panel
|
||||
actingLevel-mirror-ResolveActingLevel + checkbox + body-3-field ×2 app SHA-pair ee19ca94/eba649cc) ·
|
||||
build 0W/0E + filter-test 34/34 + npm ×2 PASS · ĐANG chờ reviewer nền (sub-reviewer-f1-checkbox.md)
|
||||
→ PASS thì commit+push
|
||||
[ ] K4a→K4b→K5→K4c→K6→K7→K8-prep theo build-order B3 + vá-số spec-cụm2/cụm3 (chi tiết PAUSE-3 mục (2):
|
||||
K4a 49-row + vá-1 route-regex CÙNG-wave + vá-7 nhãn-N2-phá-dỡ + DELTA +49key/+196policy · K4b
|
||||
searchParams + queryKey+group · K5 groups + forward-provision lines[].contractId ∪ pe.contractId ·
|
||||
K4c WfView lọc Code · K6 blacklist 12-key + fe-user-0-diff · K7 hội-2-khóa + grant Contracts.Create
|
||||
[câu III default Drafter+Procurement+Admin] + Line.ContractId-ghi-luôn · K8 form-14-người fail-closed
|
||||
+ gói SOLUTION-PE-{n} + QĐ9 đo-2-nhánh + ZZTEST + rollback-theo-ID)
|
||||
[ ] closeout-nợ: diary vai (C2) · tally #53 CHỐT (tạm ~14/17 lượt cửa-3, sub-class mới engine-process-
|
||||
exit ×2 — đếm lại từ sổ) · nhãn D MIND · STATUS row S163/S164/S165 · spec-cụm1 vá-3 đính-chính
|
||||
chữ PUT-Conflict (gate-K3 phán giữ-là-đúng) · lỗi-tự-bắt ship-607-khi-609 ghi bài
|
||||
|
||||
next: đợi K3-BE p2 → VERIFY ĐĨA → phóng K3-FE + K3-test song song → gate K3 → commit-push → cicd
|
||||
→ /pause (mandate mới). Chết giữa: relaunch-cắt-gọt §4. Lần /tiep sau: K4a (49 menu + grant, spec-cum2
|
||||
vá-1 route-regex CÙNG K4a) → K4b → K5 → K4c → K6 → K7 → K8-prep-form-14-người.
|
||||
next: /tiep → đọc sub-cicd-verify-k3.md dòng-1 + re-verify 6 mục → checkbox opt-out (đầu việc #1)
|
||||
→ K4a theo build-order.
|
||||
|
||||
verify:
|
||||
ls .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/ | wc -l # 29 @S165 sau gate-K1 (tăng theo lane — đếm tươi, đừng neo; ctx-verifier K8 vá 28→29)
|
||||
git status --porcelain | head -20 # K1 uncommitted (4 file mới + BE/FE sửa) tới khi push
|
||||
grep -c 'GO 9/10' .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-review-fable-b3.md # =1 (S165 vá verify-literal: "GO-WITH-SPEC-FIXES" là nhãn chain, KHÔNG literal trong file)
|
||||
head -1 .claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-cicd-verify-k3.md
|
||||
git log --format='%h %s' -3 # 15349e8 K3 · 0779f2d K2 · 50e6d8c K1 (đều pushed)
|
||||
dotnet test SolutionErp.slnx --nologo # 614/0 = 45D + 569I
|
||||
|
||||
notes: SPEC 4 file = spec-tổng v2 (9 QĐ + backlog-3) · spec-cum{1,2,3} final (12+15+16 vá). Câu-ranh builder:
|
||||
":342" trùng số dòng 2 file — Features.cs:342-347 PHẢI đổi ⟂ WorkflowService.cs:342 CẤM đụng (B3-B4).
|
||||
CHỜ ANH (không chặn K-wave): (I) bản-15-trang · (II) B2-14-dòng+"/"=hoặc · (III) ai-bấm-Đưa-vào-HĐ
|
||||
[default Drafter+Procurement+Admin] · OG-6 soát-SAU qua Admin CRUD [HẾT chặn — chốt @PAUSE-2, ctx-verifier
|
||||
K2 bắt câu cũ tự-mâu-thuẫn @S165] · OG-5 hỏi-khi-gặp.
|
||||
Sổ lane-chết: fable 3/9 · opus 1/13 · reviewer-gate-K1 #53 ×1 @S165 (artifact cứu B4-d, resume đang chạy).
|
||||
Engine: fable ×6 · clone ×9 · impl ×4 K1-trọn. mind-check 11Đ/0T @S165 (nợ block MIND-2 đã trả).
|
||||
notes: MANDATE PAUSE-3 (3 tin anh verbatim ở _context): xong-K3-thì-pause · K4a→K8 lần sau · sổ nhớ kỹ
|
||||
từng đầu việc đã review. Treo-không-chặn: (I)(II)(III) · OG-5 · OG-6-soát-4-ô-UI · 2-hở-UX-K1-FE ·
|
||||
F-5-PermGuard-khuôn-cũ · O-2-literal-2-nơi. _mind 93,3% ⇒ pause kế NÉN MIND-2 (khuôn nén = MIND-1).
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
**Bài học sẵn có để không lặp:** persona `lead-stale-auditor.md:51-54` từng dạy nhịp CŨ (cadence) sau khi hình-B đã đổi — ring2 bắt @S153 (M-1). ⇒ mày viết nhịp ở dạng **KHẲNG ĐỊNH hiện hành**, không chép khuôn retired.
|
||||
Tag `[s153, sinh-ra, owner-veto-3-vai, rename-hub-form, vai-1-nhap-@pause, carve-out-pause-§1, alive-3-luot-qua-s156]`
|
||||
|
||||
- [4 lớp máy MÙ khi soi nháp](feedback_machine_blind_classes.md) — nhãn-D-lặp-1-dòng · ý-D-rơi-im-lặng · lời-anh-trong-nháy-không-trỏ-PAUSE · chép-lại-WAL; soi 4 chỗ này TRƯỚC khi đọc xuôi A-E
|
||||
- [6 lớp máy MÙ @nháp](feedback_machine_blind_classes.md) — nhãn-D-lặp · ý-D-rơi-im-lặng · lời-anh-trong-nháy · chép-WAL · carry-bó-1-nhãn · §E-orphan-do-TÊN
|
||||
|
||||
> **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).
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: machine-blind-classes
|
||||
description: 4 lớp lỗi nháp `_mind` mà `mind-check --draft` LUÔN xanh nhưng ngữ-nghĩa sai — soi đúng 4 chỗ này trước, đừng đọc tuần tự
|
||||
description: 6 lớp lỗi nháp `_mind` mà `mind-check --draft` LUÔN xanh nhưng ngữ-nghĩa sai — soi đúng 6 chỗ này trước, đừng đọc tuần tự
|
||||
metadata:
|
||||
type: feedback
|
||||
---
|
||||
@ -12,5 +12,8 @@ Máy `mind-check --draft` xanh (`dat=N TRUOT=0`) KHÔNG nói gì về 4 lớp d
|
||||
3. **Lời anh trong dấu nháy + quy-kết "anh nói/anh chọn"** — rào-1 của máy chỉ bắt blockquote mở đầu `anh:`; câu trích nhúng giữa dòng lọt sạch. Nhà verbatim = `_context-s-<N>.md` entry `PAUSE-<k>`. Phân biệt: dùng làm **TÊN** (module/menu) = hợp-lệ; dùng làm **TRÍCH LỜI** = phải bỏ nháy + `xem PAUSE-<k>`.
|
||||
4. **Chép lại WAL** — nặng nhất ở mục A (dãy con-số cicd/deploy) và mục C (câu "gốc lỗi" đã có nguyên văn ở WAL). Đọc chéo WAL trước, chỗ nào ≈90% trùng thì đề con-trỏ. Ăn tiền gấp đôi khi trần `_mind` >85% vì mỗi byte thừa ép nén thêm block cũ.
|
||||
|
||||
**Why:** máy lo cơ-học/literal; 4 lớp trên đều là ngữ-nghĩa ⇒ chỉ vai bắt được, mà nháp là cửa SỬA duy nhất (block cũ bất-biến).
|
||||
**How to apply:** thứ tự soi = (2)→(3)→(4)→(1) rồi mới đọc xuôi A-E; mỗi phát hiện phải kèm con-trỏ đĩa (`_mind` dòng nào / WAL dòng nào / `_context:<line>`) để lead vá không phải đi tìm. Liên quan [[ctx-curator-run-log]].
|
||||
5. **Carry-bó: N ý cũ nén về 1 dòng + 1 nhãn** (thấy @S165/PAUSE-3, cửa dài 17 spawn — nháp bó ~16 ý: 7 slot + luật END-line + PARK-1..6 + ESCALATE ×2 + 4-finding-khe → 1 dòng `{treo-chờ-anh}`). Máy xanh vì dòng CÓ đúng 1 nhãn hợp-lệ; sai ở chỗ nhãn đó **đè lên ≥4 ý mà block trước gắn nhãn KHÁC**. 🔴 Bẫy tự-quy-chiếu: chính luật *"ý PARK gói >1 chủ-đề phải mỗi ý 1 dòng"* là một ý ĐANG NẰM TRONG bó ⇒ bó nuốt luật cấm bó. Phép soi rẻ: dòng D nào có ≥2 dấu `·` hoặc ≥2 mã định-danh (slot/PARK/ESCALATE) = nghi bó ⇒ đối chiếu nhãn từng ý ở block top của `_mind`. Sửa = tách theo NHÓM-NHÃN (thường 4 dòng), mỗi dòng trỏ `MIND-<k-1> §D` — không cần chép lại ruột.
|
||||
6. **§E orphan-do-TÊN: lane ghi dưới slug mặc định, E trỏ file khác** (thấy @S165: `sub-test-specialist-1.md` + `sub-implementer-backend-0.md` nằm trong run-folder mà 0 lần xuất hiện trong nháp; E trỏ `sub-test-k2.md` / `sub-implbe-k3.md` = bản lead-on-behalf). Máy đếm số dòng E, không đối chiếu run-folder ⇒ mù hoàn toàn. Kèm theo thường là 2 lỗi anh em: (a) 1 dòng E gộp nhiều spawn có verdict KHÁC nhau (ca thật: FE p1 chết + FE p2 relaunch + test-lane → 1 dòng), (b) mất khai **lead-on-behalf** ở dòng nào đó dù dòng bên cạnh có khai. Phép soi rẻ: `ls -la --time-style` run-folder lọc mtime > ts block trước, rồi grep TỪNG tên file trong nháp — file 0-hit = SỬA (sàn-3 `/tiep` sau sẽ kêu orphan).
|
||||
|
||||
**Why:** máy lo cơ-học/literal; 6 lớp trên đều là ngữ-nghĩa ⇒ chỉ vai bắt được, mà nháp là cửa SỬA duy nhất (block cũ bất-biến).
|
||||
**How to apply:** thứ tự soi = (6)→(5)→(2)→(3)→(4)→(1) rồi mới đọc xuôi A-E — (6) và (5) cần lệnh đĩa nên chạy sớm để đọc xuôi có sẵn dữ-liệu. Mỗi phát hiện phải kèm con-trỏ đĩa (`_mind` dòng nào / WAL dòng nào / `_context:<line>`) để lead vá không phải đi tìm. Liên quan [[ctx-curator-run-log]].
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
# ctx-verifier Agent — Persistent Memory
|
||||
|
||||
- **S166 (2026-08-01) LƯỢT 4 @`/tiep` window-4 L9 — verdict `CO — 11 cờ` `[LEAD SEED ON-BEHALF NGAY TẠI CỬA (không đợi closeout — F-01 vá nhịp); nguồn = `_tiep-3.md:6` + return CLEAN 0-garble]`:** B↔`next:` khớp 3/3 (lần đầu 0-lệch sau 4 lượt). **Cờ đắt nhất ⑥ = NÂNG CẤP luật S162 của chính mày:** S162 dạy *"nén = đối chiếu TỪNG ý D có nơi đi"*; nay thấy TRƯỚC khi nén — MIND-2 §D là **NHÀ ĐANG GÁNH 2 con-trỏ** (MIND-1 nén trỏ vào + MIND-3 carry trỏ vào, 22 dòng D) ⇒ **nén một block phải đi TÌM ai đang trỏ VÀO nó trước** (inbound-pointer check), không chỉ soát ý của chính nó. **⑨ số-học chặn trước:** nén MIND-2 theo khuôn cũ chỉ dư 6.331 B < MIND-4 dự phóng 6.776 B ⇒ THIẾU ~445 B — lời khuyên hành-động: MIND-4 viết ≤6.331 B hoặc nén sâu hơn. **⑦ class `claim > việc` bắt ở lớp mềm:** PAUSE-3 khai *"áp CẢ 10"* điểm curator, đĩa chứng bundle 12-ý-1-dòng vẫn nguyên (`_mind:103`) — luật bị phạm nằm NGAY TRONG bundle. **① nghề đọc-vớt artifact chết:** cicd-K3 2.640 B "chỉ §0 = 0/6" NHƯNG vớt mốc recycle-proof PID 5364 @17:11:25 làm thước đo deploy cho lượt re-verify — artifact chết vẫn để lại thước. ⑩ header nén tự-tuyên "18 ý" thật 19 (lần 2 class này — S158 đã dạy "header tự tuyên = phải kiểm"). Tag `[s166, lan-chay-4, inbound-pointer-check-truoc-nen, so-hoc-nen-chan-truoc, claim-ap-ca-10-thuc-mot-phan, artifact-chet-de-lai-thuoc, seed-on-behalf-tai-cua]`
|
||||
|
||||
- **S162 (2026-07-30) LƯỢT 3 @`/tiep` window-4 L8 — verdict `CO-CO — 8 cờ` `[LEAD SEED ON-BEHALF @closeout — nguồn: đĩa `_tiep-3.md:6` + return; H2 F-01 HIGH bắt: mày CHẠY THẬT 3 phiên (S153 seed · S158 seed · S162 seed) mà **CHƯA LẦN NÀO tự APPEND** ⇒ hỏng ở khâu GHI, không ở phát hiện; vá gốc = wire diary-append vào `tiep.md §3-ter`, đã lên HANDOFF NEXT-em #1]`:** 8 cờ K1-K8. **Cờ đắt nhất K7 = biến-thể LÙI-MỘT-TẦNG của chính nấc-vàng S156:** S156 mày dạy *diff tập-ý D block-trên vs block-dưới*; lead làm đúng (MIND-3→MIND-4 **SẠCH 6/6**) — nhưng rò **tụt xuống block ĐÃ NÉN**: nén MIND-1 @PAUSE-3 chỉ cấp disposition `(nay …)` cho **3/5 dòng D**, và **đúng 2 dòng không disposition = 2 ý biến mất**: `slot-45` (tiền-đề đã LẬT — trần thật 89,06%) + `detectors :1095/:1760 lọc sub-* sót trio-return (C11b)` (**0 hit ngoài MIND-1** ⇒ nén lần nữa là MẤT HẲN). ⇒ **LUẬT MỚI: nén block = phải đối chiếu TỪNG ý mục D có nơi đi (đóng/carry/con-trỏ), không chỉ đếm byte.** **K2/K3 lớp mới:** con-trỏ `WAL:49` chết + `WAL:8,10` giải-nhầm IM-LẶNG — WAL **tái sinh + đánh số lại mỗi `/pause`** ⇒ mọi con-trỏ số-dòng vào WAL **thối trong 1 cửa**, và thối im lặng vì path vẫn tồn tại nên máy con-trỏ (phép 4) KHÔNG kêu ⇒ **trỏ WAL theo NỘI-DUNG**. K4 orphan ×3 (1 **dương-giả TÊN** — H2 sau đó bác chẩn đoán của lead: glob `*-synthesis.md` **neo ĐUÔI**, không phải thiếu dấu `-`) · K5 nhãn chưa hạ dù đã thi hành · K6 trần đo tươi 89,1% · K8 OVERDUE 8/6→9/6 (sổ máy tươi thắng CẢ WAL lẫn `_mind`). Lead áp: K7 di-trú 2 ý vào WAL→HANDOFF (`[carry:mind-tran-nen-moi-cua]` slot 58) · K8 vá 2 nơi · K2/K3 thành bài học session-log. Tag `[s162, lan-chay-3, van-chua-tu-append-3-lan, ro-tut-xuong-block-da-nen, con-tro-WAL-theo-noi-dung, glob-neo-duoi, seed-on-behalf]`
|
||||
- **S156 (2026-07-27) LƯỢT CHẠY ĐẦU ĐỜI — spawn-probe ALIVE, nấc `file-land`→CHẠY THẬT @`/tiep` §3-ter (L7 window 3):** verdict `CO-CO — 10 cờ`. Nấc-vàng học được: **4 khoản của mày ĐỀU ra cờ, nhưng cờ NẶNG nhất KHÔNG nằm ở khoản nào cả** — nó là **biến-thể NGƯỢC của khoản 3**: ý mục D **rơi IM-LẶNG** giữa 2 block (MIND-1→MIND-2 mất 3 ý, 0 khai) trong khi khoản 3 chỉ dạy soi "định-đoạt mà chưa đổi nhãn". ⇒ **LUÔN diff tập-ý D block-trên vs block-dưới**, đừng chỉ đọc block top (đúng vệt `absence_looks_like_clean`). Ca đắt nhất: ý "trần `mind_ctx_kb`=32KB" {treo-chờ-anh} rơi ĐÚNG lúc nó thành ràng-buộc thật — đo ra `_mind` **85,5% trần (28.010/32.768 B), dư 4.758 B < mọi block (5.767-7.536)** ⇒ MIND-3 sẽ vượt, luật buộc nén MIND-1.
|
||||
**2 nghề rẻ mà ăn tiền:** (a) **đo byte từng block** (`python` split theo `## MIND-`) — 1 lệnh ra cờ trần + số để lead quyết nén · (b) **chạm ĐĨA để bác chú-thích lớp mềm**: §E ghi `sub-implementer-backend-1.md` "(file này không còn)" mà `ls` ra **3.499 B, commit `9c0ac68`, ruột toàn `⏳`** ⇒ nhãn đúng = `skeleton-ruột-rỗng` CÒN SỐNG. Máy `mind-check` chấm `dat` vì nó chỉ soi path TỒN TẠI — **máy đúng, chữ sai**; khoản 4 phải soi CHÚ-THÍCH chứ không chỉ đọc verdict.
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
# Reviewer Agent — Persistent Memory
|
||||
|
||||
- **S164 (07-31) gate K1 danh mục SP-002 (`ContractCatalogEntries`, Mig 70) — PASS-WITH-FLAGS 9 finding/0 blocker kỹ-thuật:** build 0W/0E + **597 test** (45D+552I) tươi. Lane khai ĐÚNG 100% ở chỗ đo được: seed **86/86** parse-máy khớp transcribe từng dòng (chỉ 8 mismatch = đúng tập lane đã khai), phân bố 5/10/5/23/14/15/13/1, SHA-pair FE `d71a9e3b…` ×2 khớp claim. **Bài thu:** ① 🔴 giá-trị lớn nhất KHÔNG nằm ở mã mà ở **GATE QUY-TRÌNH**: spec đặt PRE-gate owner (`OG-6`) + kế hoạch **tách 2 commit** (code trước, seed sau khi gật) — code đúng hết mà commit gộp là **vượt quyền owner**; seeder per-Code idempotent KHÔNG có nhánh update ⇒ gật muộn = phải UPDATE tay. ② **2 quyết-định hợp-lệ ghép lại đẻ ghost-wire**: lead bắt key vào `MenuKeys.All` (để có menu row) + spec bắt controller mirror khuôn `Roles="Admin"` ⇒ 4 policy `ContractCatalog.*` sinh ra mà **0 endpoint tiêu thụ**; ma trận CRUD chỉ điều-khiển HIỂN-THỊ, tick CanCreate vẫn 403 / bỏ tick CanRead vẫn GET được (lớp #82) — **phải đo `grep policy` chứ đừng suy từ "key đã vào All"**. ③ **default-lấn-ngữ-nghĩa**: spec `IncludeInactive?` (mặc-định-LOẠI) → code `IsActive?` (mặc-định-GỒM) ⇒ cột "ẩn khỏi picker" chỉ ẩn nếu MỌI consumer nhớ truyền tham số. ④ drift DELTA đo được (All=56, policy=224) mà `STATUS.md:6` chưa đổi ⇒ acceptance "khai cùng commit" chưa đóng. Tag `[s164, gate-quy-trinh-owner, ghost-policy-2-quyet-dinh-hop-le, default-lan-ngu-nghia, seed-doc-may]` **Evidence:** `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k1.md`. ⚠️ Sổ này **18.8KB > 17.1KB** — nợ curate lượt sau.
|
||||
- **S166 (08-01) vá F-1 ô-tích opt-out `applyLevelFinalize` KHKK — PWF 7 finding (3 MAJOR):** vá ĐÚNG kỹ thuật (mirror 2 app chứng bằng **blob-SHA in ngay trong `git diff` index-line** — rẻ hơn sha256 tay; body không rò field; cấp thường bất-biến từng bit). **Bài thu:** ① 🔴 **khuôn-nguồn có 2 tầng, chú-thích nói dối tầng dưới** — implementer trích ĐÚNG dòng JSX PE `:772-791` + nhãn "khuôn PE S96 default tick", nhưng `useState` PE `:61` = `false` (S97 owner **ĐẢO** sang opt-IN) và chính chú-thích PE `:769-771` cũng stale ⇒ **đo khuôn phải đo GIÁ-TRỊ KHỞI-TẠO, không đọc chú-thích**; tái phát S165 F-1 (đo sai tầng). ② **cây làm việc PHÌNH GIỮA LƯỢT REVIEW** — đo `git status` 2 lần cách ~40 tool-call: 5 file→7 file (+121 dòng K4a, `All` 64→113) ⇒ **verdict phải neo mốc đo + re-đo `--stat` TRƯỚC khi phát verdict**, nếu không lead commit ké code chưa qua cổng. ③ vắng-mặt-đọc-thành-sạch: `isApproved ⇒ mọi Bước 'Done'` ⇒ CEO chưa đụng vẫn "đã duyệt", dấu-vết duy nhất = THIẾU dòng "✓ ký". ④ **sợi-dây-1-argument** (projection `l.AllowApproverFinalize`) 0 test ⇒ xoá là control biến mất mà 614 test + tsc vẫn xanh. Tag `[s166, khuon-2-tang-chu-thich-noi-doi, cay-phinh-giua-review, sợi-day-1-argument]` **Evidence:** `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-f1-checkbox.md`
|
||||
|
||||
- **S162 (07-30) cây 4-folder GĐ (FE-only 2 app) — PASS-WITH-FLAGS 8 flag/0 blocker:** 🔴 class **`im-lặng-về-độ-chính-xác-của-con-số`** — 3 ca cùng lớp 1 diff, tsc+build ×2 xanh: hook VỨT `total` khi `pageSize:200` ⇒ không biết mình bị cắt, badge tụt không dấu vết · `pe.ContractId = contracts[0].Id` ⇒ phiếu liên-danh N HĐ chỉ nối 1 mà badge in như thật (**tái phát cardinality S87/S88 — field làm KHOÁ-NỐI phải đi đọc WRITE-SITE của nó**) · fallback `?? '(chưa cấp mã)'` trộn 2 nguyên nhân ⇒ **khẳng định SAI**, không phải degrade. · **#82 ngược chiều:** FE gate OR nhiều menu-key nhưng `MenuPermissionHandler.cs:40` khớp CHÍNH XÁC 1 key ⇒ OR làm gate LỎNG HƠN policy, tự chuốc 403; **gate query = ĐÚNG key policy của endpoint**. 2 endpoint cùng diff kết luận NGƯỢC nhau (`/contracts` `[Authorize]` trần ⇒ KHÔNG 403) ⇒ đo TỪNG cái. · **Nhãn ✓ không có phép đo:** rubric 'responsive ✓' mà harness grep 'grid-cols-[19rem'=0 hit ⇒ 2 trang lưới chưa từng render; **đọc `^import` của harness = cách rẻ nhất biết ảnh CHỨNG được gì**. Tag `[s162, im-lang-do-chinh-xac, total-bi-vut, contracts0-cardinality, or-key-long-hon-policy, nhan-tick-khong-phep-do]` **Evidence:** `.claude/workflows/runs/2026-07-30-S162-cay-4-folder-gd/sub-reviewer-1.md` · lead áp 5/8 flag (F-1/3/4/6/7) + F-8 sửa memory designer TRƯỚC ship `bfc7b79`; F-2 (liên-danh N-HĐ) + F-5 (layout 19rem chưa render thật) = giới-hạn khai thẳng lên HANDOFF slot (56).
|
||||
- **[→ archive/2026-07.md @S166-curate] S164/S165 (07-31) gate K3 KHKK — PWF 8 finding/0 blocker:** **tham-số-chết-vì-thiếu-tầng-UI** (BE port đủ 3 tầng + seed cờ, panel gửi body literal 2 field ⇒ trạm CEO chết 8/8) — *claim "port khuôn X" phải đo TẦNG-CUỐI, ai GỬI tham số* · **sweep 2-cờ bất-đối-xứng** (FE gỡ 2 ô, BE gỡ 1 ⇒ tick bị nuốt im lặng) · lead cãi spec ĐÚNG khi có phép đo (`grep typeEnum` = 0 hit trong thân handler) · flake 1/3 lượt ⇒ "N/0 tươi" phải khai SỐ LƯỢT · DELTA STATUS chưa khai.
|
||||
|
||||
- **[→ archive/2026-07.md @S162-curate] S161-W2 (07-29) KHKK CRUD — 2 lane viết SONG SONG:** hợp-đồng FE↔BE VỠ 6 điểm mà tsc+build+574-test đều XANH (route lệch tên · field lệch · 2 lỗi CHE NHAU); lời-khai-lane = GIẢ ĐỊNH ⇒ so ROUTE+FIELD trên ĐĨA; list-bịt-detail-mở ⇒ rào chỉ còn UX; INNER-join global-filter = picker vanish.
|
||||
- **[→ archive/2026-07.md @S165-curate] S164 (07-31) gate K1 danh mục SP-002 (Mig 70) — PWF 9 finding/0 blocker:** giá-trị lớn nhất ở **GATE QUY-TRÌNH** không ở mã (commit gộp = vượt quyền owner; seeder 0 nhánh update) · 2 quyết-định hợp-lệ ghép nhau đẻ **ghost-policy** (4 policy, 0 endpoint tiêu thụ — đo `grep policy`, đừng suy từ "key đã vào All") · **default-lấn-ngữ-nghĩa** `IncludeInactive?`→`IsActive?` · DELTA đo được mà STATUS chưa khai.
|
||||
|
||||
- **[→ archive/2026-07.md @S161-curate] S159 đợt-5 (07-29) menu 6-leaf HĐ:** chú-thích-mang-SỐ phải chạy phép đếm · cookie-cutter phải soi CẢ phần bản gốc đã CHẶN · `tsc`+`noUnusedLocals` mạnh hơn grep cho claim 'đã cắt'.
|
||||
- **[→ archive/2026-07.md @S165-curate] S162 (07-30) cây 4-folder GĐ (FE-only) — PWF 8 flag:** im-lặng-về-độ-chính-xác-của-con-số ×3 cùng diff · **#82 ngược chiều** (FE OR nhiều menu-key LỎNG HƠN policy khớp-CHÍNH-XÁC-1-key ⇒ tự chuốc 403) · nhãn ✓ không có phép đo.
|
||||
|
||||
- **[→ archive/2026-07.md @S162-curate] S161-W2 (07-29) KHKK CRUD 2-lane song song:** hợp-đồng FE↔BE VỠ 6 điểm mà tsc+build+574-test XANH (2 lỗi CHE NHAU) ⇒ so ROUTE+FIELD trên ĐĨA (lời-khai-lane = GIẢ ĐỊNH); list-bịt-detail-mở; INNER-join global-filter = picker vanish.
|
||||
|
||||
- **[→ archive/2026-07.md @S159/@S161/@S162-curate] S159-đợt5 · S161-W1 · S155-đợt2 (digest):** chú-thích-mang-SỐ phải chạy phép đếm · cookie-cutter phải soi CẢ phần bản gốc đã CHẶN · `tsc`+`noUnusedLocals` > grep cho claim 'đã cắt' · **HIGH nằm ở `git`** (mig UNTRACKED mà snapshot tracked ⇒ gate `git status --porcelain -- src tests | grep '^??'` RỖNG trước commit) · comment 'bên kia lo' = ĐI ĐỌC BÊN KIA · grep bằng TOKEN-SONG-SINH · `hợp-đồng-đứt-2-bờ` (FE khai cờ, BE DTO không có ⇒ nút chết mà build+test xanh) · re-đo đĩa TRƯỚC verdict · đổi-chiều-assert ≠ nới-assert.
|
||||
- **[→ archive/2026-07.md @S145/@S145b/@S155-curate · @S140] S145 4-lane · S143 · S139 · S134b · S133 · S146/S147/S152-D2 (digest):** bất-biến chia-đôi giữa 2 axis chỉ cross-cut sweep bắt · sweep CẢ numeric LẪN name-enum · `bằng-chứng-tự-huỷ-sau-squash` · re-measure acceptance từ git HEAD + no-self-exempt · insertion-only `grep '^-'`=0 · 'mọi nhánh set X' phải grep assignment-qua-BIẾN (#81) · `ExecuteDelete` ngoài transaction = mất dữ liệu · test đang KHOÁ chiều ngược CẤM nới assert · xanh-giả bắt bằng phép 2-thế-giới · 3 THƯỚC-HỎNG (md5 CRLF · `grep -c` citation-trap · `grep -iF` MSYS 0-hit im lặng).
|
||||
|
||||
- **[→ archive/2026-07.md @S162-curate] S161 W1 (07-29) KHKK tiền-commit (Mig 69):** HIGH nằm ở `git` chứ không ở mã — 2/3 file mig UNTRACKED mà snapshot tracked ⇒ gate `git status --porcelain -- src tests | grep '^??'` phải RỖNG ngay trước commit; comment 'bên kia lo' = ĐI ĐỌC BÊN KIA (nhãn BE thiếu ⇒ ghi chuỗi Anh vào cột DB); grep bằng TOKEN-SONG-SINH; diff sửa mã phải sửa MỌI số/neo trong chú thích.
|
||||
- **[→ archive/2026-07.md @S159-curate] S155-đợt2 (07-27) PE delete-approver DIFF #2:** class `hợp-đồng-đứt-giữa-2-bờ` (FE type khai cờ, BE DTO không có ⇒ nút chết mà build+561-test xanh) · policy-gate đo DB 11/13 vai · re-đo đĩa TRƯỚC verdict · đổi-chiều-assert ≠ nới-assert.
|
||||
- **[→ archive/2026-07.md @S155-curate] S155 ×2 · S155-đợt2 · S146 · S147 · S152-D2 (digest):** `hợp-đồng-đứt-2-bờ` (FE khai cờ, BE DTO không có ⇒ nút chết mà build+test xanh) · HIGH-ở-git (mig untracked) · `ExecuteDelete` ngoài transaction = mất dữ liệu · test đang KHOÁ chiều ngược, CẤM nới assert · xanh-giả bắt bằng phép 2-thế-giới · mã ĐỔI giữa lượt soi ⇒ re-đo đĩa TRƯỚC verdict · decouple 1 gate ⇒ truy prop dùng chung · 3 THƯỚC-HỎNG (md5 CRLF · `grep -c` citation-trap · `grep -iF` MSYS 0-hit im lặng).
|
||||
- **[→ archive/2026-07.md @S145-curate · @S145b-curate · @S140] S145 4-lane · S145a · S143 · S139·S134b·S133 (digest):** bất-biến chia-đôi giữa 2 axis chỉ cross-cut sweep bắt · 'vai-có-sổ' phải `ls` thật · sweep CẢ numeric LẪN name-enum · `bằng-chứng-tự-huỷ-sau-squash` · re-measure acceptance từ git HEAD + no-self-exempt · insertion-only `grep '^-'`=0 · 'mọi nhánh set X' phải grep assignment-qua-BIẾN (#81).
|
||||
|
||||
> **Persistent diary cross-session.** Auto-injected first ~200 lines at spawn (L1 HOT).
|
||||
> Update BEFORE every stop. Tiered Memory v1: L1 HOT cap ~17KB (hook 24.4KB read-limit) · L2 `archive/` on-demand · L3 RAG `search_memory` just-in-time. Keep entry ≤ 1.5K chars (gotcha #53).
|
||||
@ -24,7 +25,7 @@
|
||||
- [Wire/mirror claim verification anchors](feedback_wire_claim_verification_anchors.md) — sha256 twin-file · `git diff -U0` isolate true-adds · `allowNegative` bleed check · guard-still-intact grep.
|
||||
- **[→ archive/2026-07.md @S161-curate] S160 (07-29) review SPEC-BỘ dry-run KHKK:** review SPEC ≠ review CODE (lỗ ở acceptance + default-lấn-quyền) · seeder-grant kiểu insert = NO-OP 403 im lặng ⇒ acceptance phải đo CỜ không đếm ROW · acceptance 'PASS SẴN' = 0-bit · choke-point 'DUY NHẤT' sai vì gán QUA BIẾN (#81).
|
||||
- **S89 trio** ([sectionB](project_s89_pe_sectionb_review.md) · [endsBeforeCeo](project_s89_pe_endsbeforeceo_plan_review.md) · [finalize-note](project_s89_finalize_note_plan_review.md)) — adjustMut share race + authz-lens ≠ concurrency-lens · FE 4 render-sites plan-missed-2 · ground-truth-accurate-nhưng-gaps.
|
||||
- **S101 H18/H19 WF2 + LANE-C — PWC/PASS:** content-hash ≠ commit-SHA (hex strip/no-strip) · exact-token sweep misses paraphrase → widen concept-phrase. → `archive/2026-07.md`.
|
||||
- **S101 H18/H19 WF2 + LANE-C:** content-hash ≠ commit-SHA (hex strip/no-strip) · exact-token sweep miss paraphrase → widen concept-phrase. → `archive/2026-07.md`.
|
||||
- [S103 H20+crystallized-backfill review](project_s103_h20_crystallized_backfill_review.md) — WF2 PASS; 6/6 hash recompute MATCH + 4 already-met verified. Lesson: multi-axis warning phải nằm trong OUTPUT của script (reader chạy inline), không chỉ doc.
|
||||
- [S111 PE sign-off 6-decision design review (schema/history lens)](project_pe_signoff_history_schema_review.md) — GO-WITH-ADJ; D5 opinion-history: append-only table, REJECT version-col (drops UNIQUE + breaks UPSERT).
|
||||
- **PE per-hạng-mục series ×5** ([cardinality#3](project_pe_multiwinner_perhangmuc_review.md) · [BE-financial](project_s114_pe_multi_ncc_perhangmuc_financial_review.md) · [spec-l3](project_pe_multi_ncc_perhangmuc_specreview.md) · [IMPL](project_s114_multi_ncc_perhangmuc_impl_review.md) · [neg-quote](project_pe_negative_quote_correctness_review.md)) — derived src-of-truth: re-derive MỌI write-path KỂ CẢ Delete · grep field-NGUỒN không chỉ field-đọc · sign-loss: defer-parse tới field-chung mọi mutation.
|
||||
@ -47,9 +48,9 @@ Adversarial pre-commit reviewer SOLUTION_ERP. Read-only verify + live curl prod
|
||||
- **#43 Step.Order ≠ index 0-based** — `Where(s=>s.Order==i)` wrong row. Fix: EF query → in-memory `OrderBy(Order).ToList()` → index.
|
||||
- **#42 Dual schema V1/V2 — Service phải branch** — `if (entity.ApprovalWorkflowId is Guid awId) ApproveV2Async else V1Legacy`.
|
||||
- **Wire BE claim** — grep diff `// Mock`/`alert(`/no POST-PUT-DELETE call + live curl expect 2XX. Severity CRITICAL block.
|
||||
- **#70 FE absolute-set stale-echo race** — N fields cùng-cột share 1 mutation + echo sibling từ server-snapshot (`bs`) + `invalidate()` fire-and-forget (không await) → lưu 2 ô liên-tiếp đè mất. Window mở SAU `isPending=false` (btn re-enable), KHÔNG lúc in-flight. Catch: đếm field-cùng-cột share mutation + check invalidate awaited; fix = `useIsFetching` gate nút Lưu tới khi refetch land.
|
||||
- **#70 FE absolute-set stale-echo race** — N field cùng-cột share 1 mutation + echo sibling từ server-snapshot + `invalidate()` không await ⇒ lưu 2 ô liên-tiếp đè mất. Window mở SAU `isPending=false`, KHÔNG lúc in-flight. Catch: đếm field-cùng-cột share mutation + check invalidate awaited.
|
||||
- **#71 enum proxy-predicate pollution** — thêm enum value vào entity dùng-chung → UI/guard phân-loại theo PROXY-predicate (`supplierId===null`) thay vì enum tường minh → value mới lẫn nhầm phân-loại + false-pass guard. Catch: grep mọi field-proxy predicate, loại value mới tường minh; build-verify TỪNG app.
|
||||
- **Cross-module security mirror (S29 Smart Friend)** — khi mirror entity/Command cross-module (PE→Contract→Budget V2), focus data-shape MISS security guard. Pattern: `aw.ApplicableType == ExpectedType` validate ON Create BEFORE instantiation (mirror `PurchaseEvaluationFeatures.cs:62-77`). Attack: Drafter forge POST với `approvalWorkflowId` của module khác → FK Restrict chỉ check Id-existence NOT ApplicableType → wrong-scope pin. Re-verify `IsActive`+`IsUserSelectable` server-side. Password ≥12 chars. Severity MAJOR.
|
||||
- **Cross-module security mirror (S29 Smart Friend)** — mirror entity/Command cross-module (PE→Contract→Budget V2) hay focus data-shape mà MISS security guard. Luật: validate `aw.ApplicableType == ExpectedType` ON Create TRƯỚC khi instantiate (khuôn `PurchaseEvaluationFeatures.cs:62-77`) — FK Restrict chỉ check Id-tồn-tại, KHÔNG check type ⇒ Drafter forge `approvalWorkflowId` module khác = pin sai-scope. Re-verify `IsActive`+`IsUserSelectable` server-side. MAJOR.
|
||||
- **#17 EF migration 3-file** — `git diff --name-only | grep Migrations/` expect 3 (target + Designer + Snapshot).
|
||||
|
||||
---
|
||||
@ -84,11 +85,10 @@ Adversarial pre-commit reviewer SOLUTION_ERP. Read-only verify + live curl prod
|
||||
|
||||
## 📅 Recent activity (compressed — full verbatim → `archive/2026-06.md` + `archive/2026-07.md` via `archive/_INDEX.md`)
|
||||
|
||||
- **[→ archive/2026-07.md @S126/@S134] S123·S124·S125·S129·S131·S131b (digest):** follow-up phải GIỮ con-số source · số-atomic-đúng vẫn fencepost ⇒ re-derive từ raw · writer-only = NỬA-VÁ · do-token trap ⇒ re-Read full + sibling-test 2-CHIỀU · 🔴 ghi diary TRƯỚC return + vá-1-lớp phải grep MỌI matcher cùng-lớp ([topic](project_s123_governance_4change_review.md)).
|
||||
- **Digest S93→S117 (verbatim → `archive/2026-07.md`):** code-gate re-derived denom · default-flip byte-mirror SHA ×2 · Windows byte-verify = .NET · HELD stale run-id · persist-claim cần reader-side + tracked + 0-drift · outward-claim 'đã sửa X' phải cat X trước gate · gist meta-count ≠ đĩa · claim-về-code grep lại kể cả reword · nâng-nấc-quên-sync cùng-diff · verify EACH regex-alt by-hand · 2-tier guard compare SUM-EXPRESSION.
|
||||
- **[→ archive @S126/@S134] S123·S124·S125·S129·S131 (digest):** follow-up phải GIỮ con-số source · re-derive từ raw (fencepost) · writer-only = NỬA-VÁ · do-token trap ⇒ re-Read full + sibling-test 2-CHIỀU · 🔴 ghi diary TRƯỚC return + vá-1-lớp phải grep MỌI matcher cùng-lớp.
|
||||
- **Digest S93→S117 + June-2026 (verbatim → `archive/2026-07.md`):** code-gate re-derived denom · default-flip byte-mirror SHA ×2 · HELD stale run-id · persist-claim cần reader-side + tracked + 0-drift · outward-claim 'đã sửa X' phải cat X trước gate · gist meta-count ≠ đĩa · claim-về-code grep lại kể cả reword · nâng-nấc-quên-sync cùng-diff · verify EACH regex-alt by-hand · merge-distill đẻ false-specificity ⇒ QUALITY gate SAU presence · sha = self-declared NOT recompute · TRACKED = check-ignore ≠ ls-files · menu-hide ≠ API-lock.
|
||||
|
||||
- **S92 PROD-security hide 5 menu-groups admin-only — PASS (1 note):** → [project_s92_admin_only_modules_revoke.md](project_s92_admin_only_modules_revoke.md).
|
||||
- **June-2026 digest — LESSON-ONLY:** merge-distill fabricates false-specificity ⇒ QUALITY gate AFTER presence · sha = self-declared NOT recompute · fail-closed guard BEFORE terminal-state · TRACKED = check-ignore ≠ ls-files · menu-hide ≠ API-lock · single→multi stops at display-layer.
|
||||
|
||||
- **[→ archive/2026-07.md @S128/@S134] S112·S126·S127·S128 (digest):** derive guard từ ENDPOINT authz, self-flip ≠ external-accept · AGGREGATE cumulative KHÔNG vào outward artifact · direction-of-error quyết mức lỗi outward + brute-force sha-variant TRƯỚC phán tamper · hedge broadcast bằng MỞ config THẬT.
|
||||
|
||||
@ -97,12 +97,9 @@ Adversarial pre-commit reviewer SOLUTION_ERP. Read-only verify + live curl prod
|
||||
## 🔄 Curate trigger
|
||||
- Hook-cap **>17.1KB** (24.4KB read-limit — đổi từ ~30KB cũ, S109) → archive recent → L2 `archive/<period>.md` (append additive) + `_INDEX.md` substring pointer. Stale >3mo → remove.
|
||||
- **S162-curate (self, 2026-07-30, 23.9KB→<17.1KB):** move VERBATIM 2 entry S161-W2 + S161-W1 → `archive/2026-07.md` @S162-curate (probe moved-not-cut 2/2 TRƯỚC khi xoá khỏi L1, bài S102) + nén 10 dòng digest đã-archive-sẵn. KHÔNG cut-without-move.
|
||||
- **Prev curates (digest):** S145 (4 verbatim → @S145-curate, residual 17.7KB defer) · S140 · S134 (8 verbatim, seal 6/6+2) · S128 · **S102 recovery: cut-not-moved ×5 @`f229b07` ⇒ L1-shrink kèm '→archive' BẮT BUỘC grep moved-not-cut trước khi trust** · S116·S113·S109·S80·S71·S70·S40.
|
||||
- **Prev curates:** S162 (moved-not-cut probe 2/2) · S145 · S140 · S134 · S128 · **S102 recovery: cut-not-moved ×5 `f229b07` ⇒ mọi L1-shrink kèm '→archive' BẮT BUỘC grep moved-not-cut TRƯỚC khi trust** · S116·S113·S109·S80·S71·S70·S40.
|
||||
|
||||
## S152 (2026-07-25) — R1 retention-note ranh NEVER [M9 on-behalf lead]
|
||||
- **NEVER Edit/Write vào code-tree, NEVER commit, NEVER push** — vai = verdict-only (PASS/FAIL + issue file:line), sửa là việc em-main/implementer. KHAI THẬT 2 nấc: (a) ranh commit/push/code-tree **chưa từng vỡ**; (b) Write/Edit runtime CÓ cấp và ĐÃ dùng hợp lệ cho sub-file run-folder + diary-self-write (AS-10 VERIFY-KEEP, nhân-chứng S143) — tức "NEVER" áp cho ĐÍCH (code/commit/push), không phải cho tool-tồn-tại; containment thật = git-diff lead. Tag `[s152, r1-retention, never-edit-write-commit-push-target-scoped]`
|
||||
## S152 (07-25) — R1 ranh NEVER (on-behalf lead)
|
||||
- **NEVER Edit/Write code-tree · NEVER commit · NEVER push** — vai = verdict-only; sửa là việc em-main/implementer. Khai thật 2 nấc: ranh commit/push/code-tree **chưa từng vỡ**; Write/Edit runtime CÓ cấp và dùng hợp lệ cho sub-file run-folder + diary-self (AS-10). "NEVER" áp cho ĐÍCH (code/commit/push), không phải cho tool-tồn-tại; containment thật = git-diff lead. Tag `[s152, r1-retention, never-target-scoped]`
|
||||
|
||||
## S159 (2026-07-29) — review diff tổng-quan pipeline (đợt-1, run tong-quan-pipeline-menu) [LEAD SEED ON-BEHALF @S164 — H2 P2 @S163; run bị owner chốt "bỏ mạch" @S163 nhưng lane review ĐÃ chạy thật, distill giữ bài]
|
||||
- {nấc: verified (lead đọc lại sub-file 16.761B) · evidence: `runs/2026-07-29-S159-tong-quan-pipeline-menu/sub-reviewer-diff-tongquan.md`}
|
||||
- **7 FLAG (2M+5L), 4 bài giữ:** ① [M] a11y AA — 2-3 `<button>` TRÙNG tên đọc được "Chờ tôi duyệt" dẫn 3 đích khác (`UserDashboardPage.tsx:449/:495/:538`); ngữ-cảnh phân-biệt chỉ tồn tại THỊ GIÁC (`<h3>` không link chương-trình với nhóm nút) ⇒ spec AA = nợ thật không phải thẩm-mỹ. ② [M] lọt tiếng Anh: rút TOÀN BỘ chuỗi hiển-thị MỚI từ diff (`git diff | grep '^+' | grep -oE '>..<|label=|title='`) rồi soi từng chuỗi — ra đúng 2 ("Pipeline"…) = phương-pháp đo 100%-tiếng-Việt tái-dùng được. ③ [L] 2 khoá cache cho CÙNG resource (`['pipeline-pe-inbox']` mới vs `['pe-inbox']` có sẵn cùng endpoint cùng params) ⇒ 2 bản cache độc-lập, 2 màn 2 ảnh-chụp khác thời-điểm — check "khoá mới không đè khoá cũ" PASS mà vẫn nợ nhất-quán: 2 câu hỏi KHÁC nhau. ④ [L] báo lỗi 2 lần cùng sự-cố.
|
||||
- Kỹ-thuật BÁC-claim giữ: *"queryKey mới đè cache list"* → BÁC bằng liệt-kê key thật 2 phía (không giao) — bác cũng phải có chứng.
|
||||
- **[→ archive/2026-07.md @S165-curate] S159 đợt-1 (07-29) diff pipeline — 7 FLAG:** rút TOÀN BỘ chuỗi hiển-thị MỚI từ diff rồi soi từng chuỗi = phép đo 100%-tiếng-Việt · 2 queryKey cùng resource = 2 ảnh-chụp khác thời-điểm · a11y nút TRÙNG tên đọc-được · bác-claim cũng phải có chứng.
|
||||
|
||||
@ -186,3 +186,19 @@
|
||||
|
||||
- **S161 (07-29) W1 KHKK tiền-commit (Mig 69 + seeder + Designer type-10) — PWF 10 FLAG 1H/3M/4m/2L:** 🔴 **HIGH lại nằm ở `git` chứ không ở mã (S155 tái diễn):** 2/3 file Mig 69 UNTRACKED `??` mà snapshot đã tracked-M ⇒ `commit -a` nạp model 7 bảng nhưng BỎ migration; build+566 test vẫn xanh ⇒ **gate = `git status --porcelain -- src tests | grep '^??'` phải RỖNG ngay trước commit**. · **MAJOR bắt được nhờ đi NGƯỢC lời-khai FE:** comment FE tự khai "nhãn lấy từ BE `applicableTypeLabel`" ⇒ đi kiểm bờ BE: `AwLabels.Type` chỉ 3 entry, `GetValueOrDefault(type, type.ToString())` ⇒ UI hiện **"ContractSigningPlan"** tiếng Anh và `useState(\`Quy trình ${label}\`)` **GHI chuỗi Anh vào cột Name DB** — lớp *hợp-đồng-đứt-2-bờ*, tsc+build+test đều xanh. **Luật rút: câu comment dạng "bên kia lo" = ĐI ĐỌC BÊN KIA.** · seeder 5/5 PASS (call sau revoke `:2109`>`:2096`; revoker chỉ `Hrm|Off|Personal` ⇒ không lật 2-chiều; `TryGetValue` tuple `(RoleId,MenuKey)` — khuôn 1-role sẽ ném dup-key, unique-index `PermissionConfiguration:26` cứu) nhưng **acceptance "đo CỜ" chưa đo được ở đâu**: Dev DB **0 row** `Khkk*` cả MenuItems lẫn Permissions (menus 100 vs prod 142) ⇒ chưa nhánh nào từng chạy. · **`grep`-cùng-lớp bằng TOKEN-SONG-SINH** (`VehicleBookingLevelOpinions` repo-wide) mạnh hơn grep tên-mới: chứng 3/3 site đủ + 0 site thứ 4. · 2 chú thích cùng file nay SAI SỐ ("7 bảng"/"7 khối" → 8) + comment nguồn `MenuKeys.cs:37` "CỐ Ý NGOÀI All" nay sai + anchor `(:614)` trỏ dòng TRƯỚC-commit (đúng = :645) ⇒ **diff sửa mã phải sửa MỌI số/neo trong chú thích cùng file**. · STATUS.md `Menu keys 54`/`Policies 216` không đổi dù |All|=55 ⇒ derived-drift. Tag `[s161, high-o-git-khong-o-ma, hop-dong-dut-2-bo-nhan-BE, token-song-sinh-sweep, seeder-upgrade-if-exists, comment-mang-so-va-neo]`
|
||||
|
||||
---
|
||||
|
||||
## @S165-curate (2026-07-31) — moved verbatim từ L1 (hook 22.6KB > sàn 17.1KB)
|
||||
|
||||
- **S164 (07-31) gate K1 danh mục SP-002 (`ContractCatalogEntries`, Mig 70) — PASS-WITH-FLAGS 9 finding/0 blocker kỹ-thuật:** build 0W/0E + **597 test** (45D+552I) tươi. Lane khai ĐÚNG 100% ở chỗ đo được: seed **86/86** parse-máy khớp transcribe từng dòng (chỉ 8 mismatch = đúng tập lane đã khai), phân bố 5/10/5/23/14/15/13/1, SHA-pair FE `d71a9e3b…` ×2 khớp claim. **Bài thu:** ① 🔴 giá-trị lớn nhất KHÔNG nằm ở mã mà ở **GATE QUY-TRÌNH**: spec đặt PRE-gate owner (`OG-6`) + kế hoạch **tách 2 commit** (code trước, seed sau khi gật) — code đúng hết mà commit gộp là **vượt quyền owner**; seeder per-Code idempotent KHÔNG có nhánh update ⇒ gật muộn = phải UPDATE tay. ② **2 quyết-định hợp-lệ ghép lại đẻ ghost-wire**: lead bắt key vào `MenuKeys.All` (để có menu row) + spec bắt controller mirror khuôn `Roles="Admin"` ⇒ 4 policy `ContractCatalog.*` sinh ra mà **0 endpoint tiêu thụ**; ma trận CRUD chỉ điều-khiển HIỂN-THỊ, tick CanCreate vẫn 403 / bỏ tick CanRead vẫn GET được (lớp #82) — **phải đo `grep policy` chứ đừng suy từ "key đã vào All"**. ③ **default-lấn-ngữ-nghĩa**: spec `IncludeInactive?` (mặc-định-LOẠI) → code `IsActive?` (mặc-định-GỒM) ⇒ cột "ẩn khỏi picker" chỉ ẩn nếu MỌI consumer nhớ truyền tham số. ④ drift DELTA đo được (All=56, policy=224) mà `STATUS.md:6` chưa đổi ⇒ acceptance "khai cùng commit" chưa đóng. Tag `[s164, gate-quy-trinh-owner, ghost-policy-2-quyet-dinh-hop-le, default-lan-ngu-nghia, seed-doc-may]` **Evidence:** `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k1.md`. ⚠️ Sổ này **18.8KB > 17.1KB** — nợ curate lượt sau.
|
||||
|
||||
- **S162 (07-30) cây 4-folder GĐ (FE-only 2 app) — PASS-WITH-FLAGS 8 flag/0 blocker:** 🔴 class **`im-lặng-về-độ-chính-xác-của-con-số`** — 3 ca cùng lớp 1 diff, tsc+build ×2 xanh: hook VỨT `total` khi `pageSize:200` ⇒ không biết mình bị cắt, badge tụt không dấu vết · `pe.ContractId = contracts[0].Id` ⇒ phiếu liên-danh N HĐ chỉ nối 1 mà badge in như thật (**tái phát cardinality S87/S88 — field làm KHOÁ-NỐI phải đi đọc WRITE-SITE của nó**) · fallback `?? '(chưa cấp mã)'` trộn 2 nguyên nhân ⇒ **khẳng định SAI**, không phải degrade. · **#82 ngược chiều:** FE gate OR nhiều menu-key nhưng `MenuPermissionHandler.cs:40` khớp CHÍNH XÁC 1 key ⇒ OR làm gate LỎNG HƠN policy, tự chuốc 403; **gate query = ĐÚNG key policy của endpoint**. 2 endpoint cùng diff kết luận NGƯỢC nhau (`/contracts` `[Authorize]` trần ⇒ KHÔNG 403) ⇒ đo TỪNG cái. · **Nhãn ✓ không có phép đo:** rubric 'responsive ✓' mà harness grep 'grid-cols-[19rem'=0 hit ⇒ 2 trang lưới chưa từng render; **đọc `^import` của harness = cách rẻ nhất biết ảnh CHỨNG được gì**. Tag `[s162, im-lang-do-chinh-xac, total-bi-vut, contracts0-cardinality, or-key-long-hon-policy, nhan-tick-khong-phep-do]` **Evidence:** `.claude/workflows/runs/2026-07-30-S162-cay-4-folder-gd/sub-reviewer-1.md` · lead áp 5/8 flag (F-1/3/4/6/7) + F-8 sửa memory designer TRƯỚC ship `bfc7b79`; F-2 (liên-danh N-HĐ) + F-5 (layout 19rem chưa render thật) = giới-hạn khai thẳng lên HANDOFF slot (56).
|
||||
|
||||
## S159 (2026-07-29) — review diff tổng-quan pipeline (đợt-1, run tong-quan-pipeline-menu) [LEAD SEED ON-BEHALF @S164 — H2 P2 @S163; run bị owner chốt "bỏ mạch" @S163 nhưng lane review ĐÃ chạy thật, distill giữ bài]
|
||||
- {nấc: verified (lead đọc lại sub-file 16.761B) · evidence: `runs/2026-07-29-S159-tong-quan-pipeline-menu/sub-reviewer-diff-tongquan.md`}
|
||||
- **7 FLAG (2M+5L), 4 bài giữ:** ① [M] a11y AA — 2-3 `<button>` TRÙNG tên đọc được "Chờ tôi duyệt" dẫn 3 đích khác (`UserDashboardPage.tsx:449/:495/:538`); ngữ-cảnh phân-biệt chỉ tồn tại THỊ GIÁC (`<h3>` không link chương-trình với nhóm nút) ⇒ spec AA = nợ thật không phải thẩm-mỹ. ② [M] lọt tiếng Anh: rút TOÀN BỘ chuỗi hiển-thị MỚI từ diff (`git diff | grep '^+' | grep -oE '>..<|label=|title='`) rồi soi từng chuỗi — ra đúng 2 ("Pipeline"…) = phương-pháp đo 100%-tiếng-Việt tái-dùng được. ③ [L] 2 khoá cache cho CÙNG resource (`['pipeline-pe-inbox']` mới vs `['pe-inbox']` có sẵn cùng endpoint cùng params) ⇒ 2 bản cache độc-lập, 2 màn 2 ảnh-chụp khác thời-điểm — check "khoá mới không đè khoá cũ" PASS mà vẫn nợ nhất-quán: 2 câu hỏi KHÁC nhau. ④ [L] báo lỗi 2 lần cùng sự-cố.
|
||||
- Kỹ-thuật BÁC-claim giữ: *"queryKey mới đè cache list"* → BÁC bằng liệt-kê key thật 2 phía (không giao) — bác cũng phải có chứng.
|
||||
|
||||
## @S166-curate — moved verbatim từ L1 (S164/S165 gate K3)
|
||||
|
||||
- **S164/S165 (07-31) gate K3 KHKK (8 wf nhóm + port level-finalize + gỡ khoá Designer) — PWF 8 finding/0 blocker:** build 0W/0E · 614/0 (45D+569I) · npm ×2 sạch; 3/3 quyết-định lead ĐÚNG kỹ-thuật. **Bài thu:** ① 🔴 **tham-số-chết-vì-thiếu-tầng-UI** — BE port opt-out `applyLevelFinalize` đủ 3 tầng + seed cờ finalize cho TP.CCM ở CẢ 8 wf, nhưng panel KHKK POST **body literal đúng 2 field** `{action,comment}` ⇒ luôn finalize ⇒ **trạm CEO chết 8/8**, mất đúng quyền owner vừa chốt. Bắt bằng **đối-chứng khuôn-nguồn**: PE panel `useState(false)` + luôn gửi tường minh ⇒ PE opt-IN, KHKK opt-OUT ⇒ *"mirror khuôn PE"* SAI ở chiều mặc-định. **Luật: claim 'port khuôn X' phải đo TẦNG-CUỐI (ai GỬI tham số), đừng đếm tầng-BE.** ② **sweep 2-cờ bất-đối-xứng** — FE gỡ khoá CẢ 2 ô, BE chỉ gỡ 1 ⇒ tick bị NUỐT IM LẶNG (chính class comment vừa xoá đã cảnh báo, đảo chiều); **vá 1 cờ ⇒ grep cờ ANH-EM ở CẢ 2 bờ**. ③ spec liệt SAI site (bảo gỡ PUT-Conflict) — bác bằng `grep typeEnum` trong thân handler = 0 hit ⇒ luật CHUNG mọi type; **lead cãi spec ĐÚNG khi có phép đo**. ④ suite **flake 1/3 lượt** ⇒ 'N/0 tươi' phải khai SỐ LƯỢT. ⑤ DELTA STATUS chưa khai — tái phát y hệt K1 cùng phiên. Tag `[s165, tham-so-chet-thieu-tang-ui, doi-chung-khuon-nguon, sweep-2-co-bat-doi-xung, spec-liet-sai-site]` **Evidence:** `runs/2026-07-31-S164-4gd-khkk-fanout/sub-reviewer-gate-k3.md`
|
||||
|
||||
@ -239,8 +239,8 @@ MỌI agent trong roster có **4 RAG-READ MCP**: `search_memory` + `search_code`
|
||||
- **Keyword = QUYỀN, KHÔNG lệnh (T4):** "workflow"/"ultracode" mở quyền hỏi, KHÔNG auto-run. Mode-OFF + "chạy workflow" → TỪ CHỐI + nhắc `/ultra-on`. CẤM native `/effort ultracode`. *(Bài học 515K-token false-trigger.)*
|
||||
- **Scope (S1):** Workflow fan-out CHỈ repo SOLUTION_ERP — KHÔNG fan-out repo/corpus khác.
|
||||
- **Checkpoint (S2):** `hmw.js` **throw** nếu `checkpointApproved≠true` (mechanized tripwire anti-accidental). Em main BÁO {số agent·vai·task} @inform → set cờ → fan-out (KHÔNG chờ confirm từng lần; marker-ON=consent). Sub KHÔNG spawn sub (S3).
|
||||
- **VALID_ROLES (whitelist `hmw.js` — ĐỦ roster; số vai canonical → [`docs/STATUS.md`](../../docs/STATUS.md) §Sub-agents, B1 KHÔNG chép số):** `investigator-codebase` · `investigator-api` · `implementer-backend` · `implementer-frontend` · `test-specialist` · `reviewer` · `cicd-monitor` · `frontend-designer` · `database-agent` (+S57 — S56 đã dùng 3× qua fail-soft WARN) · `office-document` (+S107 — Office WRITE OD1–OD10) · `tooling-auditor` + `harvest-curator` (+S110 anh-directed — H21 roster-parity lệnh-B) · **`lead-stale-auditor` + `lead-gap-auditor` (+S121 W2 — H24 lead-self-audit)** · **`harness-eval` + `harness-refine` + `harness-audit` (+S141 — trio-memory)** · **`ring1-audit` + `ring2-audit` + `ring4-audit` (+S145 — C4/C4b round-KIỂM ×3: vòng tooling/harvest · soi-lead H24 · nén-ngủ; AUTO fire-after-measure, no-self-exempt, NO-OP nếu vòng không đo)**. 🔸 **Cả 10 monitor đều INFORM-only, lane RETURN-only** (propose-only). 🔴 **KHÔNG đọc "KHÔNG Write/Edit" thành cơ-chế chặn — đo S143:** frontmatter 9 vai read-only **không khai** `Write/Edit`, nhưng **runtime VẪN cấp**, nối ở cuối tool-list (nhân-chứng trực-tiếp: `reviewer` đã Write+Edit thật trong `runs/2026-07-22-S143-closeout-audit/`). Whitelist = **tuyên-bố ý-định**; containment THẬT = em main single-writer + git-diff commit-gate. Role lạ ∉ VALID_ROLES → `hmw.js` **THROW (STOP-HARD)** + báo owner (S4c, DIRECTED REC-3 2026-07-13); role-less null → inherit lead.
|
||||
- 🔴 **2 vai H24 = trục RIÊNG, KHÔNG gộp H1/H2:** H1 `tooling-auditor` = tooling-freshness · H2 `harvest-curator` = harvest-integrity · **H24 = soi chính LEAD** (`lead-stale-auditor` = cái CÓ-nhưng-LỆCH · `lead-gap-auditor` = cái BỊ THIẾU). Class-flag lấy từ **enum ĐÓNG** `lead_self_audit.flag_classes` (`.claude/agent-memory/memory-budget.json`) — **vai KHÔNG tự chế class**; nhịp = `h24_cadence` (cùng file), chạy **theo NHỊP** không phải mỗi phiên (`session-start §2.1.8` · `session-end §L.b(j)`).
|
||||
- **VALID_ROLES (whitelist `hmw.js` — ĐỦ roster; số vai canonical → [`docs/STATUS.md`](../../docs/STATUS.md) §Sub-agents, B1 KHÔNG chép số):** `investigator-codebase` · `investigator-api` · `implementer-backend` · `implementer-frontend` · `test-specialist` · `reviewer` · `cicd-monitor` · `frontend-designer` · `database-agent` (+S57 — S56 đã dùng 3× qua fail-soft WARN) · `office-document` (+S107 — Office WRITE OD1–OD10) · `tooling-auditor` + `harvest-curator` (+S110 anh-directed — H21 roster-parity lệnh-B) · **`lead-stale-auditor` + `lead-gap-auditor` (+S121 W2 — H24 lead-self-audit)** · **`harness-eval` + `harness-refine` + `harness-audit` (+S141 — trio-memory)** · **`ring1-audit` + `ring2-audit` + `ring4-audit` (+S145 — C4/C4b round-KIỂM ×3: vòng tooling/harvest · soi-lead H24 · nén-ngủ; AUTO fire-after-measure, no-self-exempt, NO-OP nếu vòng không đo)** · **`ctx-curator` + `ctx-verifier` + `ctx-audit` (+S153 OWNER-VETO hub-form 3-vai `0df10df4` — vòng Ctx lớp mềm `_mind`: vai-1 KIỂM-nháp @mỗi-`/pause` [carve-out duy nhất của luật "NGỪNG spawn" §1] · vai-2 ĐỐI-CHIẾU+NẠP @mỗi-`/tiep` · vai-3 SOI-CHUỖI 2 đầu phiên; cả 3 trả CHỈ văn-bản)**. 🔸 **Cả 13 monitor đều INFORM-only, lane RETURN-only** (propose-only; 13 + 10 worker = roster 23, số canonical → STATUS §Sub-agents). 🔴 **KHÔNG đọc "KHÔNG Write/Edit" thành cơ-chế chặn — đo S143:** frontmatter 9 vai read-only **không khai** `Write/Edit`, nhưng **runtime VẪN cấp**, nối ở cuối tool-list (nhân-chứng trực-tiếp: `reviewer` đã Write+Edit thật trong `runs/2026-07-22-S143-closeout-audit/`). Whitelist = **tuyên-bố ý-định**; containment THẬT = em main single-writer + git-diff commit-gate. Role lạ ∉ VALID_ROLES → `hmw.js` **THROW (STOP-HARD)** + báo owner (S4c, DIRECTED REC-3 2026-07-13); role-less null → inherit lead.
|
||||
- 🔴 **2 vai H24 = trục RIÊNG, KHÔNG gộp H1/H2:** H1 `tooling-auditor` = tooling-freshness · H2 `harvest-curator` = harvest-integrity · **H24 = soi chính LEAD** (`lead-stale-auditor` = cái CÓ-nhưng-LỆCH · `lead-gap-auditor` = cái BỊ THIẾU). Class-flag lấy từ **enum ĐÓNG** `lead_self_audit.flag_classes` (`.claude/agent-memory/memory-budget.json`) — **vai KHÔNG tự chế class**; cặp light chạy **VÔ-ĐIỀU-KIỆN mỗi bookend** (hình B @S149); chỉ **`deep`** còn cổng `h24_cadence.deep_every` (`session-start §2.1.8` · `session-end §L.b(j)`). 🧊 *Mệnh-đề cũ "theo NHỊP, không phải mỗi phiên" GỠ @S164 — trái hành-vi đo được (S154 counter≈28 · S158 counter=32 đều < `light_every` mà cặp VẪN chạy); đây là site thứ 7 của FLAG-1 sau khi 6 site trong 2 file LỆNH vá @S159 — lớp persona/doc sót lại.*
|
||||
- ⚠️ **Đổi roster = đổi 2 BỀ-MẶT ĐỘC-LẬP:** (1) file `.md` trong `.claude/agents/` → **Agent-tool registry** · (2) hằng `VALID_ROLES` trong `hmw.js` → **workflow `agentType`**. Sửa 1 quên 1 = vai **spawn được tay nhưng THROW trong workflow** (hoặc ngược lại). 🔴 **Registry = ảnh-chụp lúc khởi phiên, KHÔNG hot-reload** ⇒ vai mới cần **RESTART + spawn-probe THẬT** (`session-start §0.6b`) — `ls` + grep VALID_ROLES là **điều-kiện CẦN, KHÔNG ĐỦ**.
|
||||
- **Memory governance (M1–M5 + R1):** B1 slice-inject (agent ← slice MEMORY của đúng vai qua `args`) · M2 return-delta-only (`memoryDelta{task,verdict,learned,surprise}`) · B3 lead single-writer VERIFY→APPEND-only (no-overwrite-unverified) · B2 harvest-LIỀN sau mỗi workflow vào `agent-memory/<role>` · M5 `store_memory` strip (đã S47). **Containment = defense-in-depth** (git-diff + Qdrant chunk-count post-P2), KHÔNG allowlist đơn-độc (G-015: sub vẫn giữ Bash/Write — KHÔNG "read-only").
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
- [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, **×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)
|
||||
- [Agent return-garble recover](feedback_agent_return_garble_recover.md) — sub trả wrong-slice-of-transcript thay verdict (#53, **×72-cận-dưới qua S162 [S159-S161 chưa-đếm-được; S163+ sự-kiện ghi, chốt @closeout L9 — ≥2: lead-gap ×2, lần 1 = skeleton-nấc-2 instance #2 1.302B] — 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)
|
||||
@ -44,7 +44,11 @@
|
||||
- [Claim mạnh hơn việc đã làm](feedback_claim_stronger_than_work.md) — "đã ghi/đã archive/đã VERDICT" = CLAIM ĐO ĐƯỢC, đo trước khi viết; 0-hit phải kèm control-dương (S162 ×3 ca/1 phiên)
|
||||
- [Edit phải có trước review](feedback_edit_must_predate_review.md) — edit-cần-review (nhất là file vai reviewer) LAND TRƯỚC lượt L3 (no-self-exempt cần vật tồn-tại trong diff); spec tự-mâu-thuẫn → fix-mới thắng footer-cũ + khai trong report (anh ratify S139)
|
||||
|
||||
- [Máy rộng, UI hẹp](feedback_may_rong_ui_hep.md) — nguyên tắc owner S164 ×2 quyết định: schema/BE theo ca TỔNG QUÁT (N/gộp), UI default ca HẸP (1-1), user cần thì bung — 0 đổi máy; rào cứng 409 → rào hiển thị
|
||||
- [Pause phải nhớ kỹ plan-progress](feedback_pause_track_plan_progress.md) — owner S165: /pause giữa chuỗi wave = WAL/run.md liệt TỪNG đầu việc đã-review (wave + vá-số + finding treo), rà từng dòng OG trước khi tuyên xong (ca thật: gap checkbox OG-3 → gate F-1 MAJOR)
|
||||
|
||||
## Project — ongoing decisions / context
|
||||
- [SOL-CCM-SP-002 signing matrix](project_sol_ccm_sp002_signing_matrix.md) — spec ký HĐ (nắm-ý S164, anh dạy 4 nhịp): bảng = danh mục **LOẠI HĐ SOLUTION**, nén **8 pattern ký**; trình ký số hóa **TƯƠNG TỰ duyệt NCC** (workflow V2 trạm, role→user như note 54); ký nháy = **mực trên BẢN CỨNG** (GĐ4 in khối ký); GĐ2 = duyệt HẠNG MỤC (PE cha) → GĐ3 = ĐIỀU KHOẢN → GĐ4 bản cứng; 🔴 3 trục hạng-mục ⟂ loại-HĐ-SP002 ⟂ khuôn-form (chữ "loại HĐ" 2 nghĩa — đặt tên field tách bạch); treo: cardinality N-hạng-mục→1-HĐ
|
||||
- [H22 WAL session-continuity](project_h22_wal_session_continuity.md) — sổ WAL ≤40 + Stop-hook persist VERIFIED-RUNTIME S111 (hot-reload ENV-DEP #2/#3) + /pause·/tiep 1-đường + squash wal: + FLIP run-trace ≥3-task + D10 AS-6-taxonomy-đổi; hook PS1 KHÔNG bash (PATH 3-context); pilot kill/đổi-acc pending
|
||||
- [Model-tier evolution → worker-tier-pin S124](project_harness4_two_tier_model.md) — H4 two-tier → H8 all-inherit → **S124 worker-tier-pin (14/14 sub = opus+effort:max, lead owner-choice, Fable qua /fable-real)**; restart-lesson: EDIT-agent-tồn-tại/command cần restart (hot-reload ENV-DEP, agent-MỚI khác)
|
||||
- [H23 spawn-precedence — ĐO S126](project_h23_spawn_precedence.md) — spawn-param tier THẮNG frontmatter hard-pin ⇒ /fable-real SỐNG · worker-pin ăn runtime (no-tier=opus DÙ lead=Fable ⇒ không inherit); đo 2026-07-16 spawn-model-audit 0-mismatch
|
||||
|
||||
@ -5,7 +5,7 @@ metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: 67157d21-1ead-475d-9a50-cf7f07468583
|
||||
modified: 2026-07-28T13:36:55.402Z
|
||||
modified: 2026-07-31T02:46:15.525Z
|
||||
---
|
||||
|
||||
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%.
|
||||
@ -28,6 +28,12 @@ Sub-agent đôi khi trả về message CUỐI = text bước memory-curation c
|
||||
🔴 **@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.**
|
||||
|
||||
🔴 **@S164 thu-về (2026-07-31) — sổ lại đứng yên QUA TRỌN L8 (S159→S162), lần 2 cùng bệnh:** vế "số ×66 đã cũ" là 1 trong **4 hàng-nhường rơi khe H24 @S163** (lead-gap nhường `view-*` → lead-stale không nhặt vì xong TRƯỚC 13'; ring2 §5 chứng 4/4 nhường / 0/4 nhặt — khuyết-tật cấu-trúc thiếu bước hợp-lưu, KHÔNG lỗi vai). Ghi bù đúng luật sổ — derive-from-body, đếm CÁI-CHẮC:
|
||||
|
||||
- **S162 = +6 CHẮC** (STATUS ④ closeout L8, lead đếm cùng phiên): **6/6 sub #53, resume-từ-đĩa 6/6, mất 0 B** — xác nhận lần 5 "chống-#53 = thiết-kế ARTIFACT". ⇒ **TỔNG = 72 (cận dưới) qua S162.**
|
||||
- **S159·S160·S161 = CHƯA ĐẾM ĐƯỢC, không bịa** (cùng khuôn S153-S157): closeout các phiên đó không để lại dòng đếm khôi-phục được trong sổ nào lead chạm @S164.
|
||||
- **S163-S164 (L9 ĐANG MỞ) = GHI SỰ-KIỆN, TALLY CHỐT @CLOSEOUT** (đúng bài học (c) — nâng số giữa phiên là tự đẻ số sai): đã biết **≥2**: `lead-gap-auditor` chết #53 **×2** @S163 bookend-open, lần 1 để lại `sub-lead-gap-open-S163.md` **1.302 B ruột-toàn-heading** = **instance #2 sub-class `skeleton-nấc-2`** (sau 1.661B S158 — byte>0 nên guard "verify byte tăng" mù, phải đọc RUỘT; AS-17 2-strike-watch tiếp).
|
||||
- **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:**
|
||||
|
||||
19
.claude/auto-memory/feedback_may_rong_ui_hep.md
Normal file
19
.claude/auto-memory/feedback_may_rong_ui_hep.md
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
name: may-rong-ui-hep
|
||||
description: "Nguyên tắc owner @S164: 'máy rộng, UI hẹp' — schema/BE thiết kế cho ca tổng quát (N), giao diện mặc định ca đơn giản (1-1), user cần thì bung — 0 đổi máy"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: f7c1c007-6a03-4bf4-b46b-f6dbe9139702
|
||||
modified: 2026-07-31T05:17:44.243Z
|
||||
---
|
||||
|
||||
Owner chốt cùng 1 nguyên tắc ở 2 quyết định liên tiếp @S164 (chuỗi 4-GĐ SP-002):
|
||||
- OG-1 gộp HĐ: *"thiết kế gộp nhưng giao diện thì cho 1-1 (Khi user đổi ý thì mình làm luôn)"*
|
||||
- OG-7 N-phiếu/PE: *"PE cho nhiều, nhưng giống cái trên làm trước nhưng rào hiển thị 1-1 lại -> User cần thì bung ra"*
|
||||
|
||||
**Why:** đổi schema/migration sau khi ship = đắt + rủi ro (cardinality-change class S87/S88); đổi UI default = rẻ. Owner muốn trả giá schema MỘT LẦN cho ca tổng quát, nhưng không bắt user ăn complexity khi 90% ca là đơn giản.
|
||||
|
||||
**How to apply:** khi thiết kế field/quan hệ có 2 mức cardinality (1-1 vs 1-N, đơn vs gộp): (a) schema + BE + validator theo mức RỘNG (N); (b) UI/flow mặc định theo mức HẸP (1) — nút phụ/flag "bung" thay vì bắt chọn; (c) code viết 1 đường chung (hàm nhận list, UI truyền 1 phần tử); (d) rào chặn cứng (409) đổi thành rào hiển thị. Đề xuất lên owner: đưa default HẸP, khai máy đã RỘNG sẵn.
|
||||
|
||||
Liên quan: [[sol-ccm-sp002-signing-matrix]] · [[cardinality-change-grep-consumers]]
|
||||
15
.claude/auto-memory/feedback_pause_track_plan_progress.md
Normal file
15
.claude/auto-memory/feedback_pause_track_plan_progress.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: pause-track-plan-progress
|
||||
description: "Lời dặn owner @S165 — khi /pause phải NHỚ KỸ plan đang chạy tới đâu, từng đầu việc đã-review; bắt được lỗi giữa chừng là điểm cộng"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: feedback
|
||||
originSessionId: 95541fdb-83ef-45f2-b778-8e1c44510af3
|
||||
modified: 2026-07-31T11:23:37.814Z
|
||||
---
|
||||
|
||||
Owner @S165 (2026-07-31, giữa chuỗi K-wave SP-002): *"Chú ý kỹ các đầu việc trong plan đã đc review kỹ trong turn này"* → clarify: *"ý tao là plan các thứ đang chạy tới đâu nhớ kỹ, bắt đc lỗi thì tốt. Xong rồi thì pause đi."*
|
||||
|
||||
**Why:** plan đã qua review (spec đóng băng + checklist wave + finding gate + quan sát lane) là TÀI SẢN — pause mà ghi sổ lỏng thì lần /tiep sau tự chế lại việc, rơi đúng những đầu việc đã trả giá để tìm ra (ca thật cùng phiên: gap checkbox-opt-out chỉ lộ khi rà lại từng dòng OG-3 theo lời dặn này; sau đó gate K3 F-1 xác nhận đúng nó là MAJOR).
|
||||
|
||||
**How to apply:** (1) Khi /pause giữa chuỗi wave: WAL + run.md taskList phải liệt TỪNG wave còn lại đúng tên/vá-số theo spec đã review, kèm mọi món treo sinh ra trong run (finding khai-lệch, quan sát O-*, khoảng-hở UX đã khai) — không gộp thành "làm nốt phần còn lại". (2) Rà từng dòng OG/quyết-định owner xem có đầu việc ngầm nào chưa land trước khi tuyên wave xong. (3) [[agent-return-garble-recover]] liên quan: artifact là nguồn đầu việc, không phải return.
|
||||
67
.claude/auto-memory/project_sol_ccm_sp002_signing_matrix.md
Normal file
67
.claude/auto-memory/project_sol_ccm_sp002_signing_matrix.md
Normal file
@ -0,0 +1,67 @@
|
||||
---
|
||||
name: sol-ccm-sp002-signing-matrix
|
||||
description: "Spec SOL-CCM-SP-002.v01 (nắm-ý @S164, anh dạy 4 nhịp) — bảng = danh mục LOẠI HĐ SOLUTION, 8 pattern ký; trình ký số hóa TƯƠNG TỰ duyệt NCC (workflow trạm); ký nháy = mực trên BẢN CỨNG; GĐ2 duyệt hạng mục · GĐ3 điều khoản · GĐ4 bản cứng"
|
||||
metadata:
|
||||
node_type: memory
|
||||
type: project
|
||||
originSessionId: f7c1c007-6a03-4bf4-b46b-f6dbe9139702
|
||||
modified: 2026-07-31T03:58:08.893Z
|
||||
---
|
||||
|
||||
**SOL-CCM-SP-002.v01** (ban hành 2026-03-02, 15 trang; file gốc ở `D:\Dropbox\CONG_VIEC\SOLUTION\QUY_TRINH\`) — "Quy trình trình ký HĐ Thầu phụ/NCC/Tổ đội". Anh gửi ảnh trang 5-9 @S164 (2026-07-31), dặn **nắm Ý, KHÔNG cần chi tiết** — nạp context TRƯỚC khi giao việc. Anh dạy **4 nhịp chỉnh liên tiếp** — model dưới = bản GỘP CHỐT.
|
||||
|
||||
## Model chốt (4 GĐ — mỗi GĐ 1 câu hỏi)
|
||||
|
||||
- **GĐ1 Duyệt NCC (PE) = CHA** — *mua của ai* (gói thầu bự + NCC thắng).
|
||||
- **GĐ2 KHKK = DUYỆT HẠNG MỤC** — *mua gì, ai ký, bao nhiêu* (lời anh: *"ý tao đang nói là GĐ 2 thôi"*): bổ PE cha → N hạng-mục con; mỗi hạng mục gắn 1 dòng **danh mục SP-002** ⇒ suy ra người ký + pattern nháy. 🔸 KHKK (Mig 69) có sẵn `ContractSigningPlanLines` — khả năng "line = hạng mục" gần đúng, SOI trước khi đập dựng.
|
||||
- Hạng mục duyệt xong → **"đưa vào loại hợp đồng gì"** (chọn khuôn form) → **GĐ3 Duyệt Hợp đồng = bàn ĐIỀU KHOẢN** (*"GĐ3 ko bàn công việc hạng mục nữa"*; nền = Contract 9-phase + Forms/Clause + form-engine) — *ràng buộc thế nào*.
|
||||
- **GĐ4 bản cứng** (1-mốc đã chốt) — *giấy trắng mực đen*: in khối ký đúng pattern, ký nháy MỰC + ký chính, upload.
|
||||
|
||||
## Trình ký = TƯƠNG TỰ QUY TRÌNH DUYỆT NCC (nhịp 6 — chốt kiến trúc)
|
||||
|
||||
Chuỗi Ô1→Ô4 (ký nháy) → người ký chính **số hóa thành workflow trạm-by-trạm trong app Y NHƯ PE** (từng người bấm duyệt lần lượt), KHÔNG phải chỉ render. Bản chất vật lý các ô = **ký nháy mực trên BẢN CỨNG** (nhịp 5) — app chạy luồng số, GĐ4 in khối ký + nghi thức mực. ⇒ Tái dùng nền **workflow V2** (Quy trình > Bước > Cấp, OR-of-N, Designer, `ApplicableType` — PE/Contract/KHKK cùng nền); vai trò (TBP.CCM, QS…) map user thật kiểu note (54) *"danh sách cũ trong duyệt NCC"*.
|
||||
|
||||
**Bảng SP-002 = danh mục các LOẠI HĐ của SOLUTION** (nhịp 5 — 79 dòng nhóm theo phòng chủ trì), nén còn **8 PATTERN KÝ duy nhất** (⇒ ~8 workflow template, không phải 79):
|
||||
|
||||
| Pattern | Chuỗi nháy Ô1→Ô4 | Ký chính (NĐUQ) |
|
||||
|---|---|---|
|
||||
| A1 thiết-bị/máy-móc/vật-tư-phụ ×5 | TBP.CCM→NV.CCM→TBP.EQU→NV.EQU | TP.CCM |
|
||||
| A2 hạ-tầng/phá-dỡ ×1 + A3 DV thi-công ×9 | TBP.CCM→PD/PM→SM→QS | TP.CCM |
|
||||
| A4 văn-phòng ×5 | TBP.CCM→TPB/TBP→TBP/NV.PB→N/A | TP.CCM |
|
||||
| B1 vật-tư ×23 | TBP.PRO→NV.PRO→N/A→N/A | TP.PRO |
|
||||
| B2 thầu-phụ-XD ×13 | TP.CCM→TBP.PRO→PD/PM/SM→QS | TP.PRO |
|
||||
| B3 thầu-phụ-MEP ×15 | TP.CCM→TBP.PRO→PD/PM/SM→MEP SM | TP.PRO |
|
||||
| C1-C3 BCH ×13 (nhân-công/hoàn-thiện/khác) | TP.CCM→SM→QS | PD/PM |
|
||||
| CEO — mọi HĐ CHƯA ủy quyền | TP.CCM→TP.PRO→N/A→N/A | CEO |
|
||||
|
||||
**Quy tắc:** signer = trưởng phòng SỞ HỮU danh mục theo ngưỡng UQ, CEO = fallback · chuỗi nháy biến thiên theo bản chất (+site khi thi công · +EQU thiết bị · +MEP SM · QS chốt đuôi · N/A = trống hợp lệ 2-4 ô) · **TP.CCM nháy Ô1 mọi thầu phụ kể cả B do PRO ký** · phụ lục 3.5 bảng giá trị (KL/đơn-giá/thành-tiền + VAT 10%).
|
||||
|
||||
## 3 trục — ĐỪNG trộn (nhịp 1+2+5)
|
||||
|
||||
**hạng-mục công-việc** (instance GĐ2, con của PE) ⟂ **loại-HĐ SOLUTION** (dòng danh mục SP-002 — quyết ai ký + pattern nháy) ⟂ **khuôn form** (5 form `FORM\SOL-CCM-FO-002`: .02 trọn-gói NC+VT · .03 trọn-gói NC+TB · .05 giao-khoán · .06 mua-bán · .07 đặt-hàng; .01/.04 phụ trợ). 1 hạng mục có thể ra trọn-gói/tổ-đội/nguyên-tắc (lời anh nhịp 2). ⚠️ **Từ "loại HĐ" trong lời anh mang 2 nghĩa** (nhịp 2 = khuôn form · nhịp 5 = danh mục SP-002) — khi design phải đặt tên field tách bạch, đừng dùng chữ "loại" trần.
|
||||
|
||||
## UI mapping (hình prod eoffice @S164 — anh xác nhận "Đúng chính xác rồi đó")
|
||||
|
||||
Sidebar fe-user 4 root = 4 GĐ, mỗi root fan-out theo "loại" của GĐ: **DUYỆT NCC** (1 mục `1. NCC-TP` + 6 leaf) · **KẾ HOẠCH KÝ KẾT HĐ** (hiện 1 mục NCC-TP — 🔴 **VIỆC ANH KHOANH: fan-out ra danh mục SP-002 A1, A2, … kèm CHÚ THÍCH NGẮN**, mirror pattern GĐ3/GĐ4) · **DUYỆT HỢP ĐỒNG** (đã fan-out **7 loại HĐ**: 01 Thầu phụ · 02 Giao khoán · 03 Nhà cung cấp · 04 Dịch vụ · 05 Mua bán · 06 Nguyên tắc NCC · 07 Nguyên tắc DV = bộ 7 ContractType) · **HỢP ĐỒNG CỨNG** (7 loại "- Bảng cứng" tương ứng). Cây per-gói-thầu panel giữa giữ nguyên (BVN01 → gói → 4 folder GĐ; gói `14 Mat PVC` minh họa: PE/2026/A/049 ở GĐ1, 3 GĐ sau "SẮP"). ✅ Giải treo "HĐ nguyên tắc": là ContractType 06/07 trong hệ thống (khuôn file .docx có 5, LOẠI hệ thống có 7).
|
||||
|
||||
## Admin mapping (hình 2 @S164 — admin/system/approval-workflows-v2/DuyetNcc)
|
||||
|
||||
Anh khoanh: **(a) ẨN toàn khối menu Admin cũ** (Tổng quan → HỆ THỐNG/Quy trình HĐ), *"chỉ còn cái Quy trình duyệt (Mới) thôi"* — Admin thu về vai NƠI-CONFIG-QUY-TRÌNH, nghiệp vụ ở eOffice (⚠️ hỏi (1): có ẩn cả HỆ THỐNG Người-dùng/Vai-trò/Phân-quyền/Menu-eOffice? — ẩn = mất UI quản trị). **(b) "Thêm các chỗ duyệt đó trong mục duyệt NCC mới giống Duyệt NCC"** = nhân bản khuôn designer V2 (Bước—Phòng—Cấp, versioned + archived history) cho các luồng mới (KHKK hạng mục 8-pattern + GĐ sau — hỏi (2) danh sách chính xác). Nhóm "Quy trình duyệt (Mới)" hiện có 2 entry: Duyệt NCC (Mới) + Duyệt NCC và Giải pháp (Mới).
|
||||
|
||||
🔑 **"Danh sách cũ" note (54) = ĐỘI HÌNH THẬT trong `QT-DN-V2-001`** (đọc từ hình, v03/v02 archived): **B1 PRO** C1 = Nguyễn Thị Bích Phượng · Nguyễn Văn Duy · Châu Tạ Kim Long · Binh Le Thanh, C2 = Bùi Lê Thủy Trà · **B2 CCM (Phòng Kiểm soát Chi phí)** C1 = Hồ Thị Nữ Nguyên · Trần Xuân Lưu · Lê Trần Đăng Trưởng / Lê Văn Binh, C2 = Phan Văn Chương · **B3 Ban Giám đốc** = Nguyễn Văn Trường (CEO-trạm). Map vai SP-002 → user thật lấy từ đây, KHÔNG cần anh chọn tay; verify bản LIVE (không phải archived) trước khi wire.
|
||||
|
||||
## SCOPE CHỐT (@S164 — anh trả 2 câu + hình 3 cây toàn trình)
|
||||
|
||||
**(1) Admin:** ẩn mục nghiệp vụ cũ + 2 mục quy trình cũ, **CHỪA khối HỆ THỐNG** (anh: *"chừa lại User cũng đc"* — Người dùng/Vai trò/Phân quyền/Menu eOffice) + "Quy trình duyệt (Mới)". **(2) Fan-out THEO NHÓM DUYỆT** (anh: *"cùng 1 nhóm duyệt"*) = **8 nhóm** nén từ SP-002: A1 · A2-A3 · A4 · B1 · B2 · B3 · C(C1-C3) · CEO — mỗi nhóm 1 workflow designer trong (Mới), khuôn y Duyệt NCC. **(3) Sidebar ↔ CÂY TOÀN TRÌNH GIỐNG NHAU** (anh: *"chú ý giao diện slider bar, nên giống nhau"*; hình 3 khoanh 3 dòng "Chưa có dữ liệu" → *"Thêm các sub folder con ở đây"*): sidebar KHKK fan-out 8 nhóm ⟺ cây per-gói folder "Kế hoạch Hợp đồng" mở 8 sub-folder ĐÚNG BỘ ĐÓ; GĐ3/GĐ4 cây mở sub-folder theo **7 loại HĐ** khớp sidebar 7 mục sẵn có. Một bộ nhóm — hai mặt hiển thị. Header GĐ2 prod: *"Chốt giá per-NCC trúng thầu + căn cứ hồ sơ trước khi ký hợp đồng"*; cây 38 gói / 11 dự án (BVN01 12, CAL01 3, FLOCK01-04, RMIT01, SOVI01, VLU04.1, VRR01, ZOTE01 11).
|
||||
|
||||
## 🔴 RÀNG BUỘC KHUÔN (anh dặn @S164, hình A/B đối chiếu GĐ1-vs-GĐ2): "GIỐNG NHAU, CHỈ KHÁC FORM, ĐỪNG CHẾ THÊM"
|
||||
|
||||
**MỘT khung duy nhất = khung Duyệt NCC**, nhân cho mọi GĐ: (a) sidebar = mục con + 6 leaf (Luồng duyệt/Danh sách/Thao tác/Đang duyệt/Đã duyệt/Đã xóa); (b) cây toàn trình = gói → folder GĐ → sub-folder nhóm → card phiếu (badge trạng thái + mã + ngày + người tạo — như card PE/2026/A/044); (c) layout trang = cây trái · danh sách giữa · panel chi tiết phải. **Thứ KHÁC duy nhất giữa các GĐ = FORM phiếu** (ruột panel phải: PE = ngân sách/NCC tham gia · KHKK = mã kế hoạch/chốt giá per-NCC/hồ sơ · duyệt HĐ = điều khoản…). CẤM chế layout/khái niệm UI mới — *"lấy 1 khung sliderbar của duyệt NCC thôi"*. = luật cookie-cutter mirror (đã dùng PE→Contract→KHKK ở BE) nay CHỐT cho tầng UI: **nhân khung, đổi form**.
|
||||
|
||||
## Treo — hỏi khi design thật (đừng hỏi dồn bây giờ)
|
||||
|
||||
Cardinality gộp: N hạng-mục-đã-duyệt → 1 HĐ hay 1-1? (hỏi 2 lần chưa trả lời — bảng 3.5 nhiều dòng gợi ý gộp được) · "HĐ nguyên tắc" chưa thấy file trong FORM · B2 đánh số trùng 2 dòng "7" · A4 ô "TPB/TBP" dấu / = hoặc? · NĐUQ ngưỡng tiền ở trang chưa gửi · GĐ2 line hiện tại khớp tới đâu (`ContractSigningPlanLines`). Khi build: extract chi tiết từ file gốc QUY_TRINH qua `office-document`, KHÔNG dựng từ memory này.
|
||||
|
||||
**Vai trò:** site = PD·PM·SM·MEP-SM·QS (BCH, không phải phòng ban) · văn-phòng generic = TPB/TBP + NV.PB · thiết-bị = TBP.EQU/NV.EQU · CCM = TP>TBP>NV · PRO = TP>TBP>NV.
|
||||
|
||||
Liên quan: [[h22-wal-session-continuity]] · note (54) HANDOFF: người duyệt = danh sách cũ Duyệt NCC.
|
||||
@ -120,6 +120,7 @@ Em main PHẢI echo **TOÀN BỘ nội dung command body này** (đầy đủ Ph
|
||||
1. **M5 sentinel:** sau commit closeout → `powershell.exe -ExecutionPolicy Bypass -File scripts/closeout-sentinel.ps1 -Commit <sha-closeout> -AuditRan` — FLAG "audit đo rồi như chưa đo" nếu closeout thiếu delta role-dir/counter (positive-control 5/5 lịch sử @S149).
|
||||
2. **M7 eval-USE-side (đóng DEFER C14-2.4):** `powershell.exe -ExecutionPolicy Bypass -File scripts/applied-eval-nokey.ps1 -Selftest` → selftest 3/3 rồi đọc output nhãn `{APPLIED · DORMANT(≠MISS) · chờ-judge}`; **caveat "% = FLOOR không ceiling" nằm TRONG payload** — chép nguyên, cấm rút gọn. Ghost-wire 18-ngày (0 call-site) chết tại dòng này.
|
||||
3. **M9 diary-seed on-behalf (GAP-3 ×4):** vai INFORM-only nào CHẠY trong phiên (có sub-MD/return VERIFY được) ⇒ lead **APPEND diary vai đó TRONG CÙNG closeout** (B3; tiền lệ retro-harvest S132 + seed ring2-audit S149). Detector C11(b) soi sót.
|
||||
3-bis. **C2 checklist artifact-vs-entry (wire @S164 — quyết-định lead @S163 PAUSE-1; nguồn = H2 P5 + chuỗi seed-rớt ~1 vai/lượt S153·S158·S162):** M9 tồn tại từ S149 mà vẫn rớt 3 lần vì chạy bằng TRÍ-NHỚ — thay bằng PHÉP ĐẾM 2 cột TRƯỚC commit chốt: **cột-A** = tập VAI có artifact phiên này (`ls runs/<run-của-phiên>/sub-*.md` → rút tên vai) · **cột-B** = tập vai có entry mới trong `agent-memory/<vai>/MEMORY.md` (grep nhãn `## S<nn>` phiên này). 🔴 **A∖B ≠ ∅ ⇒ seed on-behalf NGAY (quay lại M9), CẤM commit closeout khi hiệu còn phần-tử.** H2 3-phân-loại-lại: 11/23 vai bị luật CẤM tự-ghi ⇒ lead-seed là ĐÚNG thiết kế, bệnh ở bước seed thiếu phép đếm ép — KHÔNG sửa bằng "bắt vai tự ghi". 🔸 *Vế "luật END-line" của H2-P5 CỐ Ý KHÔNG wire ở đây — đó là slot **(44)** chờ anh (chưa từng được hỏi, xem HANDOFF).*
|
||||
- **(ii-bis) 🔬 ring2-audit AUTO sau cặp H24 (vai-KIỂM vòng soi-lead, C4/C4b vai #2/3, land S145):** cặp H24 (`lead-stale-auditor` + `lead-gap-auditor`) CHẠY xong ⇒ spawn `ring2-audit` NGAY — **AUTO, KHÔNG consent** (owner S145; 🧊 *vế tương-phản cũ "KHÁC (ii) consent-gate của chính H24" ĐÃ SỤP @S146 — (ii) nay cũng AUTO, xem `:106`*). Đọc FLAG-list + class 2 vai → verdict per-FLAG + tự tái-dựng ≥1 số (flag-count / `class_repeat`) + **thách-CLEAN** (H24 báo ít/0 FLAG ⇒ tự soi 1 surface tìm FLAG sót). 🔴 no-self-exempt ≠ lead-stale/lead-gap (m-3). 🔴 Fail-safe: H24 KHÔNG chạy phiên này (**chỉ còn: chưa tới nhịp** — nhánh "không consent" chết @S146) ⇒ ring2-audit **NO-OP im-lặng**. Tuần-tự C4b (SAU cặp H24, mtime chứng). Propose-only → em main VERIFY→APPEND (git-diff backstop). Contract canonical `.claude/agents/ring2-audit.md` (B1).
|
||||
- **(iii) Flag → class:** mỗi FLAG của 2 vai **PHẢI** thuộc **enum ĐÓNG** `lead_self_audit.flag_classes`. Vai **KHÔNG tự chế class** — finding không phân-loại được ⇒ báo **verbatim** + **escalate anh** để mở rộng enum. Cập-nhật `class_repeat.counts`; class nào lặp **≥ `jump_on_class_repeat`** ⇒ **kéo audit tới sớm**.
|
||||
- **(iv) 🔴 Nghi-thức RE-STAMP carry (GAP THẬT, vá @S122):** khi ghi segment `HANDOFF` mới, **ĐÓNG DẤU LẠI `[carry:<slug>]` cho MỌI carry còn mở** — không chỉ lần đầu.
|
||||
|
||||
@ -282,7 +282,7 @@ ngược lại → counter += 1 ; last_ticked_session = S<nn> ; last_ticked_head
|
||||
- **(c) Lead scribe NGAY (single-writer):** return từng con → lead ghi `.claude/workflows/runs/<run-id>/harness-{eval,refine,audit}-return.md` **ngay khi con đó trả**, **KHÔNG đợi đủ 3**. Lý-do: 3 vai **không có Write/Edit** (chặn-bằng-thiếu-tool) nên tự-ghi-đĩa bất-khả; phiên chết giữa chừng ⇒ mất return (bài-học vòng-1 S141).
|
||||
- **(d) PIN đích-danh (fail-closed):** `harness-refine` nhận **path** `…/harness-eval-return.md`; `harness-audit` nhận **path run-folder** đang chấm. 🔴 Pin **missing/rỗng ⇒ vai TỪ-CHỐI / TRƯỢT** — **CẤM** để vai tự đi tìm "run mới nhất" (vớ bản cũ ⇒ **ĐẠT-ảo**).
|
||||
- **(e) Đóng-băng bề-mặt-đo:** cửa-sổ chạy bộ-ba nằm TRONG **Mirror C1** (§2.1.2) — KHÔNG ghi bề-mặt-đo giữa chừng; việc ghi phát sinh xếp hàng SAU verdict.
|
||||
- **(f) Post-wave assertion:** chạy xong 3 con → `git status --short` → **kỳ vọng 0 tracked-change ngoài run-folder**. Có thay-đổi lạ ⇒ vai đã ghi (residual-write) ⇒ **báo anh + revert**. (G-015: propose-only **KHÔNG** code-enforced ở kênh Bash — git-diff là backstop THẬT.)
|
||||
- **(f) Post-wave assertion:** chạy xong 3 con → `git status --short` → **kỳ vọng 0 tracked-change ngoài run-folder**. Có thay-đổi lạ ⇒ vai đã ghi (residual-write) ⇒ **báo anh + revert**. (G-015: propose-only **KHÔNG** code-enforced ở kênh Bash — git-diff là backstop THẬT.) 🔴 **TIMING quyết định răng (vá @S164 — harness-audit ESCALATE, xảy ra thật commit `7f55b4f`):** phép soát này PHẢI chạy **TRONG CÙNG TURN** với wave — Stop-hook `wal-flush.ps1` fire ở **turn-boundary** và auto-commit 4 path (trong đó `agent-memory/`) ⇒ soát ở turn SAU = soát sổ **đã bị hook nuốt thành `wal:` commit**, backstop rỗng-hoá. Nếu lỡ boundary: soát bằng `git log --name-only` trên các `wal:` commit vừa sinh thay vì `git status`.
|
||||
- **(g) KHAI ranh 2 cánh-tay (chống đọc nhầm thành "đo 2 lần"):** **script-arm** = §2.1.2/§2.1.6/§2.1.7 (các script deterministic **in SỐ**) ⟂ **sub-arm** = bộ-ba (**ĐỌC** output script-arm rồi ĐO-lại/ĐỀ-XUẤT/CHẤM). Bộ-ba **KHÔNG thay** script-arm và **KHÔNG re-implement máy đo**.
|
||||
- **(h) Đơn-vị nhịp:** "**phiên-LOGIC**" của hub map **TẠM** = nhãn-phiên `S<nn>` của SE (SE chưa adopt session-logic — cùng caveat đơn-vị với counter §2.1.8). 🔴 **KHÔNG thêm cadence-key** vào `memory-budget.json` và **KHÔNG tick** counter cho bộ-ba (nhịp bộ-ba ≠ nhịp H24 — trộn 2 đồng-hồ = hỏng cả hai).
|
||||
- **(i) [M4] Vết 2 lớp — chuỗi skip PHẢI nhìn thấy được (giữ NGUYÊN sau khi bỏ consent @S151 — auto không có nghĩa là được im):**
|
||||
|
||||
@ -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": 37,
|
||||
"last_ticked_session": "S163",
|
||||
"last_ticked_head": "6ba5cfe74709fd4aab42b1c255195ddbea99cbdb",
|
||||
"last_ticked_at": "2026-07-30",
|
||||
"counter": 39,
|
||||
"last_ticked_session": "S165",
|
||||
"last_ticked_head": "fbac66db1a138e76dc9a531e6603402c1bb92604",
|
||||
"last_ticked_at": "2026-07-31",
|
||||
"last_audit": {
|
||||
"light_at_counter": 36,
|
||||
"deep_at_counter": 25,
|
||||
@ -193,6 +193,16 @@
|
||||
"at": "2026-07-30",
|
||||
"session": "S163",
|
||||
"event": "CLEAN tick (session-counter-tick.ps1 M2): counter 36->37, session S162->S163, head 2554845->6ba5cfe. Classify-before-tick: no regression (n=163 >= stored n=162); 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-31",
|
||||
"session": "S164",
|
||||
"event": "CLEAN tick (session-counter-tick.ps1 M2): counter 37->38, session S163->S164, head 6ba5cfe->e5f53d0. Classify-before-tick: no regression (n=164 >= stored n=163); 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-31",
|
||||
"session": "S165",
|
||||
"event": "CLEAN tick (session-counter-tick.ps1 M2): counter 38->39, session S164->S165, head e5f53d0->fbac66d. Classify-before-tick: no regression (n=165 >= stored n=164); last_ticked_head reachable (merge-base --is-ancestor exit 0). 4 fields updated, 1 history entry appended, written atomically (temp + Move-Item -Force)."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -108,3 +108,32 @@
|
||||
**(1) quyết-định đã CHỐT** — 9 OG trọn (gộp+UI-1-1 · đội-hình-cũ · NĐUQ-human-gate-VĨNH-VIỄN · N-phiếu+UI-1 · hiển-thị-không-authz · đảo-PHÁ-VỠ-S155 · freeze-tái-dùng-máy · phiếu-bất-tử-ERP + PE-test SOLUTION-PE-{n} · OG-6→soát-SAU) + 🔴 MANDATE: window sau CHẠY 1 MẠCH K1-push→K8, không dừng chờ.
|
||||
**(2) delta còn SỐNG** — K1 BE+FE+TEST xong UNCOMMITTED (597/0); reviewer-gate K1 chưa chạy; K2-K8 chưa; spec 4 file ĐÓNG BĂNG + build-order trong run-folder 2026-07-31-S164-4gd-khkk-fanout (26 file); câu (I)(II)(III) treo không chặn; closeout-nợ: diary vai + tally garble (fable 3/9 · opus 1/13 · ngược-#53 ev#4 · #68 lần-3) + nhãn D + STATUS row.
|
||||
**(3) con-trỏ** — WAL (build-order + mandate) · spec: runs/.../spec-{tong,cum1,cum2,cum3}*.md · transcribe (OG-6 soát-sau) · sub-file 11 lane · _mind-s-9 CHƯA block window-2 (context cạn — khai, mind-check sẽ cờ, chèn @window-3).
|
||||
|
||||
### PAUSE-3 2026-07-31T18:35:00+07:00
|
||||
|
||||
> anh: uhm ý tao là plan các thứ đang chạy tới đâu nhớ kỹ, bắt đc lỗi thì tốt. Xong rồi thì pause đi
|
||||
|
||||
**(1) quyết-định đã CHỐT trong cửa này**
|
||||
- 🔴 MANDATE ĐỔI giữa cửa (3 tin nhắn anh, verbatim đủ): ① *"xong nốt thì /pause rồi những đầu việc tiếp theo để lần tiep sau làm tiếp nhé"* ② *"Chứ ý kỹ các đầu việc trong plan đã đc review kỹ trong rurn này nhé."* ③ (dòng quote trên — clarify ②) ⇒ SUPERSEDE mandate "chạy 1 mạch" @PAUSE-2: xong K3 thì dừng, K4a→K8 = lần `/tiep` sau, sổ phải nhớ kỹ từng đầu việc đã review.
|
||||
- K1 SHIP trọn vòng: gate 9f → commit `50e6d8c` → cicd **PASS 6/6** (seed 86 TAM-GIÁC 3-nguồn).
|
||||
- K2 SHIP trọn vòng: gate 10f (F-1 guard đếm-so-khớp) → commit `0779f2d` → cicd **PARTIAL 5/6 deploy-khỏe** (mục-4 chân-lý-rỗng — đo lại khi K8 đẻ phiếu thật).
|
||||
- K3 SHIP (local trọn, prod đang verify): 2 lượt engine-exit → CHẺ NHỎ (nhịp-1-lane seed + nhịp-2/3-lead finalize/sweep + FE-lane + test-lane 5-test) → gate **8f/0-blocker** (3/3 quyết-định lead ĐÚNG) → commit `15349e8` PUSH. Bước-0 lead tự verify ROSTER LIVE prod (`localhost\SQLEXPRESS` · QT-DN-V2-001 3-trạm 11 người · chuong.phan giữ cờ).
|
||||
- Gate-K3 phán: GIỮ PUT-Conflict đúng (spec vá-3 liệt nhầm) · GIỮ ép-false SkipToFinal type-10 + FE disable ô (F-2 vá) · seed cờ cùng-commit hợp lệ.
|
||||
|
||||
**(2) delta còn SỐNG**
|
||||
- 🔴 **Đầu việc #1 lần sau — gate-K3 F-1 MAJOR:** checkbox opt-out `applyLevelFinalize` màn duyệt KHKK chưa có UI (BE param sẵn, `?? true`) ⇒ trạm CEO tạm chỉ đi được bằng admin bỏ cờ ở Designer; vá = mirror `PeWorkflowPanel.tsx:778` + DTO expose cờ level + FE types ×2 app. BẮT BUỘC trước K8 dry-run.
|
||||
- `[!]` cicd-K3 đang chạy nền lúc pause — verdict đọc ở `sub-cicd-verify-k3.md` dòng 1 (vai ghi liên tục).
|
||||
- K4a→K8 chưa làm (build-order + vá-số spec-cụm2/cụm3 đóng băng — K4a nhớ vá-1 route-regex CÙNG wave, vá-2 DELTA +49key/+196policy, vá-7 nhãn N2 "phá dỡ"; K5 forward-provision lines[].contractId ∪ pe.contractId; K7 hội-2-khóa + grant Contracts.Create [câu III default]; K8 form 14-người fail-closed + SOLUTION-PE-{n} + QĐ9 đo 2-nhánh).
|
||||
- Treo không chặn: (I) bản-15-trang · (II) B2-14-dòng "/"=hoặc · (III) ai-bấm-Đưa-vào-HĐ · OG-5 · O-2 literal nhóm 2-nơi · 2 khoảng-hở UX K1-FE (3 filter BE chưa UI · tab cả fe-user) · F-5 PermGuard nợ khuôn cũ · spec-cụm1 vá-3 cần đính-chính chữ PUT-Conflict lần chạm sau.
|
||||
- Lỗi-tự-bắt trong cửa (ghi làm bài): ship STATUS "607" trong commit K2 khi suite thật 609 (cùng class F-3 gate) — đã sửa 614 @K3; PS5.1 quote-trap làm commit K2 fail lần 1 (→ luật `-F` file).
|
||||
- #53 tally cửa-sổ 3: ~14 lượt return-hỏng / 17 spawn (reviewer×3-resume-điền · cicd×3 · lane-K2×4 · lane-K3×4 gồm 2 engine-exit-0-delta · ctx-verifier CLEAN · K3-test CLEAN) — **0 mất công** nhờ artifact-đĩa + relaunch-cắt-gọt + lead-solo; sub-class mới: engine-process-exit ×2 cùng-task ⇒ bài task-hẹp-Write-sớm.
|
||||
|
||||
**(3) con-trỏ**
|
||||
- run-trace: `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/` (specs 4 + sub-* 20+ file: implbe/implfe/test/reviewer-gate/cicd-verify × k1/k2/k3)
|
||||
- commits: K1 `50e6d8c` · K2 `0779f2d` · K3 `15349e8` (đều pushed origin/main)
|
||||
- `ctx-curator` verdict @cửa này (§2.6(C-bis)-2bis): **`CTX-CURATOR: SUA — 10 điểm`** (dòng-1 vai ghi 9, tự đính-chính 10 trong thân) — lead áp CẢ 10 vào nháp MIND-3 (nặng nhất: #1 hai artifact-vệt `sub-test-specialist-1.md`/`sub-implementer-backend-0.md` sót khỏi §E — sàn-3 sẽ kêu orphan; #9 regression bundle-hoá 16-ý-1-dòng nuốt chính luật mỗi-ý-1-dòng; #4/#5 nháy-kép-paraphrase lách rào-1). Draft-check v2 7Đ/0T/0cờ → chèn; full 11Đ/0T sau nén MIND-1 (giữ 5-heading + 6 ý chỉ-sống-ở-đó). `_mind` 30.573B = 93,3% — cửa pause KẾ phải nén MIND-2.
|
||||
- counter: 39 (S165) · docs: STATUS 614/64-key/256-policy tươi · HANDOFF slot-58 84,8% + F-1 khai
|
||||
|
||||
```json
|
||||
{ "machine_block": "python scripts/session_ctx.py machine-block --session 9 --json", "changed_count": 0, "anchor": "15349e8 [CLAUDE] Contract: K3 SP-002 (anchor = chính commit K3 — mọi việc cửa này ĐÃ COMMIT trong 3 commit K1/K2/K3; dirty còn lại = governance, khai giới-hạn máy-chỉ-thấy-đã-commit)" }
|
||||
```
|
||||
|
||||
@ -66,6 +66,66 @@ 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-31T18:35:00+07:00 @ 15349e8 (window 3)
|
||||
|
||||
### A. Gói-turn
|
||||
|
||||
- Window-3 (S165) = `/tiep` entry (tick 39 · reconcile 5-stale · MIND-2 trả nợ · ctx-verifier CO-9-cờ) rồi chạy mandate: **K1 ship+cicd-6/6 · K2 ship+cicd-5/6-khỏe · K3 code+gate+push** (cicd-K3 chết-vì-limit lúc pause) — 3 gate PASS-WITH-FLAGS 9f/10f/8f, suite 590→614, 3 commit `50e6d8c`/`0779f2d`/`15349e8`.
|
||||
- 🔴 MANDATE ĐỔI giữa cửa: anh 3 tin nhắn (verbatim ở `_context` PAUSE-3 ①②③) — từ chạy-1-mạch sang xong-K3-thì-pause, K4a→K8 lần sau, sổ phải nhớ kỹ từng đầu việc đã review.
|
||||
- Gap tự-bắt nhờ lời dặn anh: checkbox opt-out màn duyệt (OG-3 dẫn chiếu khuôn checkbox PE S97) chưa land — gate K3 sau đó xác nhận đúng nó = F-1 MAJOR (trạm CEO chết 8/8 vì mặc-định-true).
|
||||
|
||||
### B. Hướng-tiếp + nhánh-đã-loại
|
||||
|
||||
**Đi tiếp @/tiep sau:** (1) đọc verdict cicd-K3 từ `sub-cicd-verify-k3.md` dòng-1 + re-verify phần thiếu (vai chết vì limit) · (2) đầu việc #1 = checkbox opt-out màn duyệt — acceptance: PAUSE-3 mục (2), BẮT BUỘC trước K8 · (3) K4a→K4b→K5→K4c→K6→K7→K8 theo build-order + vá-số spec-cụm2/cụm3 (chi tiết PAUSE-3 mục (2)).
|
||||
|
||||
**Nhánh đã LOẠI trong cửa này:**
|
||||
- ❌ *Vá checkbox ngay trong phiên* — theo mandate @PAUSE-3 (tin ①/③); đã khai HANDOFF (acceptance vế 2 F-1) + prod 0 phiếu KHKK thật nên rủi ro treo thấp.
|
||||
- ❌ *Gỡ PUT-Conflict theo chữ spec vá-3* — luật versioning CHUNG mọi type; gate K3 phán lead ĐÚNG; còn lại là đính-chính chữ spec (§D).
|
||||
- ❌ *Echo `AllowApproverSkipToFinal` cho type-10* — service 0 đọc cờ (K3-test O-1) ⇒ giữ ép-false + FE disable ô (gate F-2 vá) thay vì đẻ config-lie mới.
|
||||
- ❌ *Chờ cicd-K3 rồi mới pause* — vai ghi artifact liên tục; sau đó vai chết vì session-limit càng chứng chọn đúng (chờ = mất điểm dừng).
|
||||
|
||||
### C. Kế-hoạch (delta suy-nghĩ)
|
||||
|
||||
- **#53 đổi tướng:** đa số lượt spawn cửa này return-hỏng mà 0 mất công (tally tạm — chốt @closeout, xem PAUSE-3 mục (2)) — artifact-đĩa + relaunch-cắt-gọt + lead-solo nay là NẾP, không còn là recovery. Sub-class mới `engine-process-exit` ×2 CÙNG task (0-delta 0-artifact dù 35-43 tool-use) ⇒ đặc-trị: **task-hẹp-Write-sớm, thiết-kế nhét sẵn vào prompt** (task đọc-nhiều-trước-Write là mồi chết).
|
||||
- **Rà-OG-từng-dòng mạnh hơn gate:** gap F-1 do lead rà OG-3 theo lời dặn anh bắt TRƯỚC, gate xác nhận + đo độ nặng SAU. Trước mỗi lần tuyên wave xong: đọc lại từng OG/quyết-định owner tìm đầu việc ngầm.
|
||||
- **Lỗi-tự-bắt cùng-class với lỗi mình vá cho người khác:** ship STATUS 607 khi suite 609 (đúng class F-3 mình flag ở gate) ⇒ số-trong-doc chốt SAU phép đo cuối, không giữa chừng.
|
||||
- **PS5.1 quote-trap:** commit message chứa nháy kép → arg vỡ → luật mới: message qua file + `git commit -F`.
|
||||
|
||||
### D. Đang-thảo-luận
|
||||
|
||||
- Spec-cụm1 vá-3 chữ "PUT Conflict" cần đính-chính theo phán gate-K3 — sửa lần build-order chạm spec {gần-chốt}
|
||||
- O-2 literal `KHKK-N{n}` sống 2 nơi (seeder + regex rào) — thuần đặt-tên, gom 1 const khi tiện {mới-nêu}
|
||||
- Câu (I) bản-15-trang · (II) B2-14-dòng "/"=hoặc · (III) ai-bấm-Đưa-vào-HĐ [default Drafter+Procurement+Admin] {treo-chờ-anh}
|
||||
- OG-5 hỏi-khi-gặp {treo-chờ-anh}
|
||||
- OG-6 soát-SAU qua Admin CRUD — chờ anh soát 4 ô ⚠️ trên UI {treo-chờ-anh}
|
||||
- 2 khoảng-hở UX K1-FE (3 filter BE chưa UI · tab hiện cả fe-user) {treo-chờ-anh}
|
||||
- F-5 gate-K1 PermissionGuard CatalogsPage = nợ khuôn 4-kind cũ {treo-chờ-anh}
|
||||
- Carry nhóm treo-chờ-anh — slot (54)(57)(58)(60)(62)(43) + PARK-1..6: nhà + ruột giữ nguyên MIND-2 §D, không chép {treo-chờ-anh}
|
||||
- Carry nhóm mới-nêu — slot (61) liên-danh · luật ý-PARK-1-dòng · ESCALATE (i)(ii) · 4-finding-khe: giữ nguyên MIND-2 §D {mới-nêu}
|
||||
- Carry nhóm gần-chốt — luật END-line sub-md (nhà HANDOFF NEXT-em #4 + slot 44): giữ nguyên MIND-2 §D {gần-chốt}
|
||||
- Slot (55)(56)(59) — giữ nhà HANDOFF, đóng-CÓ-KHAI không lặp {treo-chờ-anh}
|
||||
|
||||
### E. Dòng-sống spawn/engine-run
|
||||
|
||||
- Nhà chung artifact: `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/` (tên file trần dưới đây nằm trong folder này) · biên-nhận entry: `.claude/sessions/session-9/_tiep-2.md`
|
||||
- ctx-verifier @entry — CO 9-cờ (trần-mind 84,8% · run.md tách K1-K8 · 2-vá-WAL) — verdict ghi `_tiep-2.md`
|
||||
- reviewer gate-K1 — PASS-WITH-FLAGS 9f (#53 → resume điền B4e-B6) — `sub-reviewer-gate-k1.md`
|
||||
- cicd-K1 — PASS 6/6 (#53 return, artifact trọn) — `sub-cicd-verify-k1.md`
|
||||
- K2-BE p1 wf_583be7ad — chết giữa §c (schema+entity land) — `sub-implbe-k2.md` §a-b
|
||||
- K2-BE p2 Agent — chết @§f 0-byte-artifact (code ~85% land) → lead-solo đóng — `sub-implbe-k2.md` §c-h (lead on-behalf)
|
||||
- K2-FE p1 (wf_9b36e4cb lane-1) — chết sau §0.b + markup-rò-artifact (sub-class #53 mới) — `sub-implfe-k2.md` §0
|
||||
- K2-FE p2 Agent — DONE (wire ListPage + cp fe-user + SHA-pair 5/5) — `sub-implfe-k2.md` §1-§4
|
||||
- K2-test (wf_9b36e4cb lane-2) — file test 9-Fact HOÀN CHỈNH; vệt lane tự ghi = `sub-test-specialist-1.md` (3.1KB, chết giữa ghi); tổng-kết = `sub-test-k2.md` (lead on-behalf sau verify-đĩa)
|
||||
- reviewer gate-K2 — PASS-WITH-FLAGS 10f (#53 → resume điền §3-§6) — `sub-reviewer-gate-k2.md`
|
||||
- cicd-K2 — PARTIAL 5/6 deploy-khỏe (mục-4 chân-lý-rỗng) — `sub-cicd-verify-k2.md`
|
||||
- K3-BE p1 wf_a04124a7 + p2 Agent — engine-process-exit ×2 (0-delta, 0-artifact-mới) — khai `sub-implbe-k3.md` header
|
||||
- K3-BE nhịp-1 lane — DONE seed-8-wf + 8-key (return đứt-giữa-câu kèm số thật 609/0) — `sub-implbe-k3.md` §1-2 + vệt lane `sub-implementer-backend-0.md`
|
||||
- K3-FE lane — DONE (chết khi GHI §2, code land đủ; lead chốt npm ×2 + SHA `336ECCC1F86D`) — `sub-implfe-k3.md`
|
||||
- K3-test lane — CLEAN return 614/0 +5-test + 3 quan-sát O-1/2/3 — `sub-test-k3.md` (tồn tại, đã kiểm)
|
||||
- reviewer gate-K3 — skeleton → resume ĐIỀN ĐỦ: PASS-WITH-FLAGS 8f/0-blocker — `sub-reviewer-gate-k3.md`
|
||||
- cicd-K3 — CHẾT-vì-SESSION-LIMIT 18:50 (artifact 2640B phần đầu còn) — `sub-cicd-verify-k3.md`; /tiep sau re-verify
|
||||
- ctx-curator @pause-3 — SUA 10 điểm (2-artifact-sót · bundle-regression · nhãn · nháy-paraphrase · tally), lead áp cả 10 — verdict ghi `_context` PAUSE-3 mục (3)
|
||||
|
||||
## MIND-2 — 2026-07-31T15:13:43+07:00 @ fbac66d (window 3)
|
||||
|
||||
### A. Gói-turn
|
||||
@ -129,60 +189,31 @@ Máy chỉ quét phần **DƯỚI** marker đóng khối luật (dòng comment c
|
||||
- wf_1fb9f309 K1-test — 7 test, suite 597/0 — `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-test-k1.md`
|
||||
- ctx-verifier @entry-w3 — spawn ngay sau block này, verdict ghi ở block kế (khai pending) — `.claude/sessions/session-9/_tiep-2.md`
|
||||
|
||||
## MIND-1 — 2026-07-30T17:35:40+07:00 @ 43b57b5 (window 1)
|
||||
## MIND-1 — 2026-07-30T17:35:40+07:00 @ 43b57b5 (window 1) [NÉN @S165 pause-3 — verbatim trong git; 6 ý chỉ-sống-ở-đây GIỮ NGUYÊN]
|
||||
|
||||
### A. Gói-turn
|
||||
|
||||
- Bookend @open đóng trọn **5 vòng / 10 vai, 10/10 END-line** — verdict từng vai xem `MIND-0` §E (bất-biến), không lặp.
|
||||
- `ctx-audit` chấm lead **TRƯỢT 14** ở trục carry (3/9 = 33%, 6 ý biến mất khỏi mọi bề mặt) → lead nạp lại đủ + vá, `mind-check` xanh lại 11/0/0.
|
||||
- Anh gõ `/pause` (xem PAUSE-1) trước khi lead kịp bắt đầu danh-sách vá ⇒ **0/11 mục đã làm**.
|
||||
- Bookend @open S163 đóng 5-vòng/10-vai; `ctx-audit` TRƯỢT-14-carry → lead nạp lại đủ; anh `/pause` trước khi chạy danh-sách vá (0/11 — nhà `.claude/workflows/runs/2026-07-30-S163-bookend-open/run.md`).
|
||||
|
||||
### B. Hướng-tiếp + nhánh-đã-loại
|
||||
|
||||
**Đi tiếp @cửa sau:** chạy danh-sách vá — nhà canonical = `run.md` mục "DANH-SÁCH VÁ — 11 mục" (`.claude/workflows/runs/2026-07-30-S163-bookend-open/run.md`), ưu tiên 5 HIGH. Rồi seed diary 10 vai. Blocker mạch chính vẫn slot (54).
|
||||
|
||||
**Nhánh đã LOẠI trong cửa này (nối tiếp 4 nhánh của `MIND-0`):**
|
||||
- ❌ *Nâng cap để cứu `_INDEX`* — `harness-refine` BÁC: đổi thước = rời tập-đo. Split hoặc chờ anh (slot 57).
|
||||
- ❌ *Coi `④ chưng-cất = 0` là lành* — `harness-audit` khai rõ đó là trục **MÙ** (0 instrument đo tuổi gist, vòng 3), không phải trục sạch.
|
||||
- ❌ *Đọc `ring4` NO-OP thành "V4 đạt"* — V4 là `không-nhịp` (SHARD-PROBE `15 = 15`, biên `-gt` strict); +1 shard là đổi trạng-thái.
|
||||
- ❌ *Giữ quy-tắc "slot đã có nhà ở HANDOFF thì không lặp vào §D"* — `ctx-audit` FLAG-3 BÁC bằng chính hành-vi của lead (kéo slot (43) từ HANDOFF lên §D). Khuôn đúng = **đóng-CÓ-KHAI**, không phải im lặng.
|
||||
- Hướng-tiếp cũ (chạy 11 mục vá) đã tiêu ở window-2 — xem WAL/`_context` PAUSE-2.
|
||||
- 4 nhánh-LOẠI (GIỮ — chỉ sống ở đây): ❌ nâng-cap cứu `_INDEX` (refine BÁC: đổi thước = rời tập-đo; slot 57) · ❌ đọc "④ chưng-cất = 0" thành lành (audit khai trục MÙ, 0 instrument) · ❌ đọc ring4-NO-OP thành "V4 đạt" (V4 = `không-nhịp`, biên `-gt` strict) · ❌ giữ quy-tắc "slot có nhà thì không lặp §D" (FLAG-3 BÁC — khuôn đúng = đóng-CÓ-KHAI).
|
||||
|
||||
### C. Kế-hoạch (delta suy-nghĩ)
|
||||
|
||||
- **Nhận thêm một họ lỗi mới, 4 ca cùng phiên:** máy trả lời **đúng câu nó được hỏi** mà việc vẫn hỏng — bundle-hoá (6 ý/1 dòng, phép nhãn vẫn xanh) · carry tên-trần (không token `[carry:]` nên detector không có gì để đếm) · `git status` mù thư-mục rỗng · hook nuốt `agent-memory` làm backstop rỗng. ⇒ Thêm detector không đóng được họ này, vì detector mới cũng là một câu hỏi mới có khoảng-mù riêng.
|
||||
- **Đổi cách đọc mọi ô PASS:** 2 ca `drift-born-sau-phép-đo` trong 1 phiên ⇒ PASS = *"sạch lúc HH:MM"*. Assertion cuối phải do lead chạy **sau khi mọi vai dừng tay**.
|
||||
- **Đổi nấc chống #53:** *"ghi đĩa trong lúc làm"* bị đọc thành *"tạo file sớm"* — 3 ca hỏng trong phiên (2 skeleton-nấc-2 + 1 heredoc nuốt §4-§6) đều tạo file rất sớm. Đặc tả đúng = **đổ nội dung liên tục**, và **verify bằng ruột không bằng byte**.
|
||||
- **Đổi cách spawn cặp vai có luật nhường-turf:** thứ tự chạy là **một phần của tính đúng đắn**; song song ⇒ 4 finding rơi vào khe. Lần sau tuần tự, hoặc thêm bước hợp-lưu.
|
||||
- **Tự soi được một lần trong cửa này:** lead viết luật "mỗi ý 1 dòng" rồi vi phạm ngay dòng sau — `ctx-curator` #2 bắt. ⇒ luật vừa-viết **không tự áp cho chính đoạn văn chứa nó**; phải grep lại chính mình.
|
||||
- (GIỮ — chỉ sống ở đây) Họ-lỗi "máy trả đúng câu nó được hỏi mà việc vẫn hỏng" 4-ca/1-phiên (bundle-hoá · carry tên-trần · git-mù-thư-mục-rỗng · hook-nuốt-agent-memory) ⇒ thêm detector KHÔNG đóng được họ này.
|
||||
- (GIỮ — chỉ sống ở đây) Luật vừa-viết KHÔNG tự áp cho đoạn văn chứa nó — phải grep lại chính mình (`ctx-curator` #2 bắt).
|
||||
- 3 ý còn lại trùng MIND-0 §C (PASS-lúc-HH:MM · chống-#53-đổ-nội-dung-liên-tục · spawn-tuần-tự-turf) — đọc MIND-0.
|
||||
|
||||
### D. Đang-thảo-luận
|
||||
|
||||
- Slot (54) người duyệt 3 trạm PRO/CCM/CEO — chặn W5 + E2E; ai đóng: anh {treo-chờ-anh}
|
||||
- Slot (57) `_INDEX` 167 B — coupling với P3 của H2; đã đẩy lên anh, chờ chọn (a) split / (b) nâng cap / (c) để vỡ {treo-chờ-anh}
|
||||
- Slot (58) trần `_mind` — số cũ SAI (98,21% không phải 89,06%), đo lại trên `_mind-s-9`; ai đóng: anh {treo-chờ-anh}
|
||||
- Slot (60) mở enum `flag_classes` thêm class "số đúng, đơn-vị không-canonical"; ai đóng: anh {treo-chờ-anh}
|
||||
- Slot (61) defect liên-danh N-HĐ chỉ nối HĐ[0] — MỒI-A của `ctx-audit`, `_mind` là nhà DUY NHẤT {mới-nêu}
|
||||
- Slot (43) carry con-trỏ-vs-slug — 3 mốc detector byte-identical; 0 chuyển-động cửa này, cái chặn là anh chưa trả lời {treo-chờ-anh}
|
||||
- Luật `refresh @closeout` NỬA CÒN LẠI (fail-LOUD `mind-refresh:` trong `_end`) — **0 nhà trên 4/4 bề mặt**, đời-3, chưa land {mới-nêu}
|
||||
- Luật END-line cho mọi `sub-*.md` — còn nhà `docs/HANDOFF.md` NEXT-em #4 + slot (44) {gần-chốt}
|
||||
- Luật ý PARK gói >1 chủ-đề phải giữ mỗi ý 1 dòng — bundle-hoá là đường thoát khỏi lưới đo {mới-nêu}
|
||||
- PARK-1: FLAG-4 "Đã duyệt" HĐ — vô gia cư {treo-chờ-anh}
|
||||
- PARK-2: cơ-chế đặt-chỗ-diary — treo 4 đời, vô gia cư {treo-chờ-anh}
|
||||
- PARK-3: nhãn "Bảng cứng" ↔ "Bản cứng" — còn nhà `docs/HANDOFF.md:44` {treo-chờ-anh}
|
||||
- PARK-4: Hộp thư hoa — vô gia cư {treo-chờ-anh}
|
||||
- PARK-5: W8-authz hồ sơ mới — vô gia cư {treo-chờ-anh}
|
||||
- PARK-6: FLAG-4 W7 UX — vô gia cư {treo-chờ-anh}
|
||||
- ESCALATE (i) backstop G-015 rỗng-hoá — hook nuốt `agent-memory` trước khi lead soát {mới-nêu}
|
||||
- ESCALATE (ii) stray `agent-cwd-relative-memory-misland` ×3/phiên — đã xoá, chưa vá gốc {mới-nêu}
|
||||
- 4 finding rơi vào khe giữa 2 vai H24 (lead spawn song song) — chưa thu về {mới-nêu}
|
||||
- Slot (55)(56)(59) có nên lặp vào §D không, khi FLAG-3 đã BÁC quy-tắc "đã có nhà thì không lặp"? Hiện giữ nhà ở `docs/HANDOFF.md:11/:13/:19` {đang-cãi}
|
||||
- 18 ý của block này đã carry ĐỦ sang MIND-2 §D (PAUSE-1 chứng 12/12 + PARK tách 6 dòng) — nhãn TỪNG Ý giữ ở MIND-2, đây chỉ con-trỏ {treo-chờ-anh}
|
||||
|
||||
### E. Dòng-sống spawn/engine-run
|
||||
|
||||
- 9 vai + `ring4` NO-OP của cửa-sổ này đã liệt ở `MIND-0` §E (bất-biến), không lặp; dưới đây chỉ phần SAU mốc đó.
|
||||
- `ctx-audit` — TRƯỢT 14 / 4-4 khoản, gieo 2 mồi + 1 phép-thử tiên-đoán — `.claude/workflows/runs/2026-07-30-S163-bookend-open/sub-ctx-audit-open-S163.md`
|
||||
- `ctx-curator` — `SUA — 9 điểm`, lead áp cả 9 trước khi chèn block này — `.claude/sessions/session-9/_context-s-9.md`
|
||||
|
||||
- `ctx-audit` — TRƯỢT 14 / 4-4 khoản — `.claude/workflows/runs/2026-07-30-S163-bookend-open/sub-ctx-audit-open-S163.md`
|
||||
- `ctx-curator` — SUA 9 điểm, lead áp cả 9 — `.claude/sessions/session-9/_context-s-9.md`
|
||||
|
||||
## MIND-0 — 2026-07-30T15:14:22+07:00 @ 6ba5cfe (window 1)
|
||||
|
||||
|
||||
5
.claude/sessions/session-9/_pause-3.md
Normal file
5
.claude/sessions/session-9/_pause-3.md
Normal file
@ -0,0 +1,5 @@
|
||||
ts: 2026-07-31T18:35:00+07:00
|
||||
head-sha: 15349e8ee054406797cc1d76c7bc3384c6768fc2
|
||||
window-ordinal: 3
|
||||
jsonl-hint: D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP/95541fdb-83ef-45f2-b778-8e1c44510af3
|
||||
account-label: none
|
||||
5
.claude/sessions/session-9/_snapshot-2.md
Normal file
5
.claude/sessions/session-9/_snapshot-2.md
Normal file
@ -0,0 +1,5 @@
|
||||
ts: 2026-07-31T21:50:00+07:00
|
||||
head-sha: 15349e8ee054406797cc1d76c7bc3384c6768fc2
|
||||
window-ordinal: 3
|
||||
jsonl-hint: D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP/95541fdb-83ef-45f2-b778-8e1c44510af3
|
||||
account-label: none
|
||||
6
.claude/sessions/session-9/_tiep-3.md
Normal file
6
.claude/sessions/session-9/_tiep-3.md
Normal file
@ -0,0 +1,6 @@
|
||||
ts: 2026-08-01T08:20:50+07:00
|
||||
head-sha: 24ea71e2e84d012afdb343d9ce08e5d5bfb8237d
|
||||
window-ordinal: 4
|
||||
jsonl-hint: D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP/dd926b1e-29ea-4452-a847-f5858396d929
|
||||
account-label: none
|
||||
ctx-verifier: CO — 11 cờ (①cicd-K3 artifact chỉ §0 ⇒ re-verify 6/6, mốc recycle-proof PID 5364 @17:11:25 · ②③④run.md checkbox-ma 3 chỗ → lead vá @S166 · ⑤42-file-not-43 · ⑥nén-MIND-2-phải-di-trú-nhãn-22-ý-D trước · ⑦PAUSE-3 "áp CẢ 10" thật áp-một-phần · ⑧slot-58 ruột "65,7% hết khẩn" LẬT→93,3% · ⑨MIND-4 phải ≤6.331B · ⑩header-nén "18 ý" thật 19 · ⑪PARK-2/PARK-5 0-hit ngoài _mind)
|
||||
@ -17,7 +17,7 @@ Skill này là tài liệu chuyên biệt để Claude (và developer khác) dù
|
||||
| Skill | Mục đích | Trigger ví dụ | Trạng thái |
|
||||
|---|---|---|---|
|
||||
| `dependency-audit-erp` | Scan CVE NuGet + npm 2 FE, respect pin constraint (MediatR 12.4.1, Swashbuckle 6.9.0) | "npm audit", "dotnet vulnerable", "deps scan", "nâng cấp package" | ✅ New Tier 3 |
|
||||
| `ef-core-migration` | Tạo/revert EF Core 10 migration, 3-file rule, DesignTimeDbContextFactory, migration history (mới nhất → row cuối bảng skill; số → `docs/STATUS.md`) | "thêm migration", "EF migration", "schema update", "snapshot lỗi" | ✅ Updated S117 (mig-ref → pointer anti-drift B1; Mig 66 AddPeApprovedPriceRange row added; số → `docs/STATUS.md`) |
|
||||
| `ef-core-migration` | Tạo/revert EF Core 10 migration, 3-file rule, DesignTimeDbContextFactory, migration history (mới nhất → row cuối bảng skill; số → `docs/STATUS.md`) | "thêm migration", "EF migration", "schema update", "snapshot lỗi" | ✅ Updated S164 (rows Mig 68 `AddPeAllowApproverDelete` + **Mig 69 `AddContractSigningPlans` 7-bảng KHKK 89→96** added; Total re-ground 96; số → `docs/STATUS.md`) |
|
||||
| `iis-deploy-runbook` | 3 IIS site + win-acme cert + gitea-runner + LibreOffice + debug 500/502/SignalR prod + **G-084 IPv4/IPv6 hardening** | "prod 500", "IIS fail", "cert hết hạn", "restart app pool", "deploy IIS", "port hijack" | ✅ Updated (G-084) |
|
||||
|
||||
## Format chuẩn 1 skill
|
||||
|
||||
@ -25,7 +25,7 @@ when-to-use:
|
||||
> - Office/HRM/… — xem `MenuKeys.cs` (mã là nguồn)
|
||||
> - 🧊 ~~Budgets root + `Bg_*`~~ — **XOÁ S61 (Mig 50)**, module Budget cũ thay bằng `PeWorkItemBudgets` (ngân-sách per-gói-thầu). Bia-mộ: `MenuKeys.cs:70` + `fe-{admin,user}/src/lib/menuKeys.ts:29`. *(Skill này liệt `Bg_*` như menu ĐANG SỐNG suốt từ S61 → S122 — stale **nặng hơn** lệch con-số vì nó mô-tả thứ **không tồn tại**; vá @S122 W4.)*
|
||||
>
|
||||
> **Inheritance roots (4 group, gotcha #35):** `Contracts` → `Ct_*`, `Workflows` → `Wf_*`, `PurchaseEvaluations` → `Pe_*`, `PeWorkflows` → `PeWf_*`. Thêm root mới có children → **PHẢI extend 3 chỗ** trong `GetMyMenuTreeQuery` (gotcha #35). *(🧊 câu cũ "Budgets KHÔNG inherit (Bg_* phải grant tay)" — gỡ theo module.)*
|
||||
> **Inheritance roots (4 group, gotcha #35):** `Contracts` → `Ct_*`, `Workflows` → `Wf_*`, `PurchaseEvaluations` → `Pe_*`, `PeWorkflows` → `PeWf_*`. Thêm root mới có children → **PHẢI extend 3 chỗ** trong `GetMyMenuTreeQuery` (gotcha #35). 🔴 **`KeHoachKyKet` (KHKK, +S161) CỐ Ý KHÔNG inherit** — switch `GetMyMenuTreeQuery.cs:71-74` vẫn đúng 4 case; 6 leaf `Khkk_*` grant TỪNG DÒNG riêng (seeder `DbInitializer.cs:2107` grant root + 6 leaf explicit, chạy SAU revoke để THẮNG). Đừng đọc "root mới" thành "tự inherit như `Ct_*`". *(🧊 câu cũ "Budgets KHÔNG inherit (Bg_* phải grant tay)" — gỡ theo module.)*
|
||||
|
||||
## Model
|
||||
|
||||
@ -39,7 +39,7 @@ User ────< UserRoles ────< Role ────< Permissions ──
|
||||
- Union (OR) nhiều role → user có quyền nếu **bất kỳ role nào** cho quyền đó
|
||||
- Admin role → **bypass** check (luôn pass mọi policy)
|
||||
|
||||
## Menu tree (seed — ~60 key sau Phase 8)
|
||||
## Menu tree (seed — số key SỐNG → `docs/STATUS.md` "Menu keys", B1 KHÔNG chép số ở đây; nguồn mã = `MenuKeys.cs` + `DbInitializer.cs`)
|
||||
|
||||
```
|
||||
Dashboard
|
||||
@ -57,10 +57,14 @@ Contracts (root inherit)
|
||||
Forms
|
||||
PurchaseEvaluations (root inherit)
|
||||
└── Pe_<Code>_<List|Create|Pending> × 2 type = 6 leaf
|
||||
Budgets (root, NO inherit — grant tay)
|
||||
├── Bg_List
|
||||
├── Bg_Create
|
||||
└── Bg_Pending
|
||||
KeHoachKyKet (root — const VÀO `All` @S161 W1 ⇒ sinh 4 policy KeHoachKyKet.{R,C,U,D}; Mig 69 KHKK)
|
||||
└── Khkk_G1 "Kế hoạch ký kết HĐ (NCC-TP)" (DbInitializer.cs:1780-1787)
|
||||
├── Khkk_WfView Luồng duyệt
|
||||
├── Khkk_List Danh sách
|
||||
├── Khkk_Create Thao tác
|
||||
├── Khkk_Pending Đang duyệt
|
||||
├── Khkk_Approved Đã duyệt
|
||||
└── Khkk_Deleted Đã xóa
|
||||
Reports
|
||||
System
|
||||
├── Users
|
||||
@ -72,6 +76,10 @@ System
|
||||
└── PeWf_<Code> × 2 type = 2 leaf
|
||||
```
|
||||
|
||||
> 🧊 ~~`Budgets (root, NO inherit)` + `Bg_List/Bg_Create/Bg_Pending`~~ — **XOÁ S61 (Mig 50)** cùng module Budget; cây trên từng liệt nó như ĐANG SỐNG tới S164 (cùng bệnh header :26 đã vá @S122 — vá header quên vá CÂY = dư-lượng bất-đối-xứng).
|
||||
> 🔸 `HopDongCung` (GĐ4 bản-cứng): const CÓ trong `MenuKeys.cs:43` nhưng **NGOÀI `All`** ⇒ **0 policy · 0 menu-row** tới khi có module (1-mốc theo owner). ĐỪNG liệt nó vào cây key sống.
|
||||
> 🔴 Gate FE cho KHKK: dùng **đúng key policy của endpoint** (`KeHoachKyKet`) — KHÔNG OR `Khkk_*` key con (gotcha **#85**: menu-hiện rộng hơn API-cho ⇒ 403 rải UI; `MenuPermissionHandler.cs:40` so khớp CHÍNH XÁC 1 key, không kế-thừa).
|
||||
|
||||
Tree hierarchy qua `ParentKey` field. Seed trong `DbInitializer.SeedMenuTreeAsync` + Pe/Wf/Bg seeders riêng.
|
||||
|
||||
## Code pointers
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
| 1a | Spec tổng quát các wave | /fable-real invest | ✅ att-2 (att-1 ngược-#53 0-byte; att-2 A-D đầy 18.277B, E/F lead-compile; spot-check 4/4) |
|
||||
| 1b | Review spec tổng quát — 3 lane `WF reviewer lens{1,2,3} s164` | /fable-clone review (tier:opus ×3) | ✅ 3/3 sạch 0-empty · 41 finding thô → synthesis 14 vá + 2 OG mới → **spec v2** |
|
||||
| 2.c1 | Cụm-1 K1+K2+K3 chi tiết — `WF invest-fable b2c1-att2 s164` | /fable-real invest | ✅ att-2 33.048B 5/5 section 17 test (att-1 skeleton-472B chết; luật ĐAN-XEN cứu) — 3 QUYẾT + 1 mâu-thuẫn OG-3 (K3 phải port finalize) + roster 1 ô ⚠️ Trưởng |
|
||||
| 2.c2/c3 | Cụm-2 K4+K5+K6 · cụm-3 K7+K8 chi tiết | /fable-real invest | ☐ |
|
||||
| 2.c2/c3 | Cụm-2 K4+K5+K6 · cụm-3 K7+K8 chi tiết | /fable-real invest | ✅ (tách 2 row 2.c2/2.c3 dưới — row kép này vá checkbox-ma @S166 theo ctx-verifier cờ③) |
|
||||
| 2.c1-r | Review cụm-1 — 3 lane `WF reviewer c1-{evi,cov,seq} s164` | /fable-clone (opus ×3) | ✅ 3/3 sạch · L1 2-blocker+GỠ-(i)-:342 · L2 FAIL 3H (menu-ngoài-All chết · ép-false ≥3 site sót · KhkkCreatePage mâu thuẫn) · L3 PWB 5H → **spec-cum1-final 12 vá + OG-9** |
|
||||
| 2.c2 | Cụm-2 K4+K5+K6 — `WF invest-fable b2c2 s164` | /fable-real invest | ✅ SẠCH 5/5 (K4 13v·K5 6v·K6 4v, 0-mig; BÁC 2 tiền-đề lead có chứng) |
|
||||
| 2.c2-r | Review cụm-2 — `WF reviewer c2-{evi,cov,seq} s164` | /fable-clone (opus ×3) | ✅ l1 PWF 2-MAJOR · l2 PWF 3H/7M · 🔴 l3 CHẾT-RUỘT 188B (opus đầu tiên gãy — phủ bù lead-note có khai) → **spec-cum2-final 15 vá** |
|
||||
@ -19,7 +19,9 @@
|
||||
| 2.c3-r | Review cụm-3 — `WF reviewer c3-{evi,cov,seq} s164` | /fable-clone (opus ×3) | ✅ 3/3 sạch · L1 7/7-ĐÚNG PWF 4M · L2 FAIL 5H (K8 chưa-chạy-được-như-viết) · L3 FAIL 4H (authz hội-2-khóa · Contracts.Create 0-vai) → **spec-cum3-final 16 vá** |
|
||||
| 3 | Chốt spec cuối — `WF review-fable b3-chot s164` | /fable-real review | ✅ **GO-WITH-SPEC-FIXES**: GO 9/10 (K8 by-design) · 8 mâu-thuẫn (3 nặng A-1/A-4/A-5) · 0 vá-đè-vá/43 · build-order K1→K2→K3→K4a→K4b→K5→K4c→K6→K7→K8 · 8 fix lead ÁP XONG |
|
||||
| 4.K1 | Build K1 danh mục HĐ (BE+FE+test) | wf_2569b79b p1 · wf_2e08ba77 p2 · implfe · wf_1fb9f309 | ✅ @S165: 3 lane trọn · gate `sub-reviewer-gate-k1.md` **PASS-WITH-FLAGS 9f** · F4/F7 vá + T5b · Mig 70 áp LocalDB |
|
||||
| 4.K2-K8 | Build K2..K8 theo build-order B3 | hmw (Opus 5 MAX) | ☐ K2 kế tiếp |
|
||||
| 4.K2 | Build K2 (BE+FE+test) | 4 lane + lead-solo đóng | ✅ @S165: gate PASS-WITH-FLAGS 10f · commit `0779f2d` · cicd PARTIAL-5/6-deploy-khỏe (mục-4 chân-lý-rỗng chờ phiếu thật) |
|
||||
| 4.K3 | Build K3 (8 wf nhóm + finalize + designer) | chẻ-nhỏ: nhịp-1-lane + nhịp-2/3-lead + FE-lane + test-lane | ✅ @S165: gate PASS-WITH-FLAGS 8f/0-blocker · commit `15349e8` · 🔴 cicd CHẾT-vì-SESSION-LIMIT 18:50 (artifact 2640B chỉ §0 ⇒ 0/6 — re-verify @S166, mốc recycle-proof w3wp PID 5364 @17:11:25) · 🔴 F-1 checkbox-opt-out = đầu việc #1 @S166 |
|
||||
| 4.K4a-K8 | Build K4a→K8 theo build-order B3 | hmw | ☐ lần /tiep sau (spec-cụm2/cụm3 đóng băng) |
|
||||
| 5 | Dry-run E2E toàn trình (K8) | theo spec-cum3 | ☐ chặn bởi B0-form 14 người |
|
||||
|
||||
## Stages
|
||||
@ -29,5 +31,5 @@
|
||||
- [x] B1b — wf_8eb13087-5f9 3/3 lane sạch (l1 FAIL 5H · l2 6/6 chịu-lực ĐÚNG +l2-F1 rào-1-PE · l3 FAIL 6H + bác 6 nghi) → `b1b-review-synthesis.md` 14 vá + OG-6/OG-7 → spec v2 (hội tụ 2-lane: admin-hide tập-key tường minh; ApprovalGroup K2-chủ + backfill=1; 8 designer có phép đo; nguồn K1 = 7 ảnh [file đĩa 6-trang không bảng])
|
||||
- [x] B2 — 3 cụm TRỌN: c1 (33KB + 12 vá) · c2 (5/5 + 15 vá; l3 chết-ruột phủ-bù) · c3 (22.9KB 7/7-đúng + 16 vá) = 43 vá tổng, 3 spec final
|
||||
- [x] B3 — GO-WITH-SPEC-FIXES (sub-review-fable-b3.md 6 section; 3 anchor re-grep đĩa khớp; 8 fix áp vào 3 spec) — SPEC ĐÓNG BĂNG cho B4
|
||||
- [ ] B4 — fan-out build (K1/8 ✅ @S165: gate PASS-WITH-FLAGS 9f, disposition trong sub-reviewer-gate-k1.md; K2..K8 ☐)
|
||||
- [ ] B4 — fan-out build (K1+K2+K3 = 3/8 ✅ @S165: gate 9f/10f/8f, disposition trong sub-reviewer-gate-k{1,2,3}.md; K4a..K8 ☐ @S166 — vá checkbox-ma Stages @S166 theo ctx-verifier cờ④)
|
||||
- [ ] B5 — dry-run E2E
|
||||
|
||||
@ -0,0 +1,167 @@
|
||||
CICD-K3: PASS — 6/6 (§1-§5 vai đo · §6 lead đo on-behalf @S166 sau khi vai chết 2 lần)
|
||||
|
||||
# cicd-monitor — verify deploy K3 SP-002 (`15349e8`)
|
||||
|
||||
> Artifact chống #53: ghi TỪNG MỤC ngay khi có bằng chứng. Kết bằng `END ... VERDICT=`.
|
||||
> Repo `D:\Dropbox\CONG_VIEC\SOLUTION\SOLUTION_ERP` · push `0779f2d..15349e8 main`.
|
||||
|
||||
## §0 — Tiền đề (đo LIVE trước khi deploy xong)
|
||||
|
||||
Commit HEAD:
|
||||
```
|
||||
15349e8ee054406797cc1d76c7bc3384c6768fc2 [CLAUDE] Contract: K3 SP-002 8 workflow nhom KHKK-N1-8 + port level-finalize + designer (0-mig) + 5 test
|
||||
git log origin/main..HEAD -> (rỗng — đã push)
|
||||
```
|
||||
|
||||
`git diff --name-only 0779f2d 15349e8` = 26 file. Phân loại vs `paths-ignore` 7-glob:
|
||||
- **CODE (13, trigger CI):** BE 6 (`ContractSigningPlansController.cs`, `ApprovalWorkflowV2AdminFeatures.cs`, `ContractSigningPlanFeatures.cs`, `IContractSigningPlanWorkflowService.cs`, `MenuKeys.cs`, `DbInitializer.cs`, `ContractSigningPlanWorkflowService.cs` = 7 thực) · FE 4 (`fe-admin/Layout.tsx`, `fe-admin/khkk/KhkkWorkflowPanel.tsx`, `fe-admin/system/ApprovalWorkflowsV2Page.tsx`, `fe-user/khkk/KhkkWorkflowPanel.tsx`) · test 2 (`ContractSigningPlanApprovalTests.cs`, `ContractSigningPlanGroupAndCatalogTests.cs`)
|
||||
- **IGNORED (13):** `docs/**` ×2 + `.claude/WAL.md` + `.claude/agent-memory/**` ×3 + `.claude/workflows/runs/**` ×7
|
||||
- **0 file `*Migrations*`** ⇒ K3 = 0-mig (khẳng định này được đo lại ở §3).
|
||||
|
||||
**Bundle PRE-deploy (đo LIVE 18:22:51 +07, lúc run #436 CÒN `running`):**
|
||||
```
|
||||
admin /assets/index-DVQEwGwf.js + /assets/index-D050EVYG.css
|
||||
eoffice /assets/index-CZAYiWWa.js + /assets/index-DX1FRk5n.css
|
||||
```
|
||||
Khớp ĐÚNG mốc post-K2 (#435) ghi ở `sub-cicd-verify-k2.md:139-142` ⇒ mốc PRE hợp lệ, chưa bị K3 ghi đè.
|
||||
|
||||
**PROD DB PRE-deploy (sqlcmd `localhost\SQLEXPRESS`, đo 18:23 +07 lúc run CÒN `running`):**
|
||||
```
|
||||
MIGTOP=20260731085624_AddKhkkApprovalGroupCatalogAndFinalizeRuntime
|
||||
MIGCOUNT=71
|
||||
WF_KHKK_N=0 <- CHƯA có workflow nhóm nào
|
||||
MENU_AwV2_KhkkN=0 <- CHƯA có menu-row nào
|
||||
MENU_TOTAL=143
|
||||
PERM_TOTAL=1576
|
||||
LEVELS_FINALIZE_ALL=2 <- cờ finalize toàn hệ TRƯỚC K3 (control nền)
|
||||
```
|
||||
⚠️ Cột PK của `MenuItems` là **`[Key]`** (KHÔNG phải `MenuKey` — `MenuItemConfiguration.cs:11 b.HasKey(x => x.Key)`;
|
||||
`MENUCOLS=Key,Label,ParentKey,Order,Icon,DisplayLabel,IsVisible`). Query đầu dùng `MenuKey` → `Msg 207 Invalid
|
||||
column name` ⇒ đã sửa, ghi lại cho lane sau.
|
||||
|
||||
**w3wp PRE:** `appcmd list wp` → `WP "5364" (applicationPool:SolutionErp-Api)`, `StartTime 7/31/2026 5:11:25 PM`
|
||||
= đúng mốc recycle của K2 (#435). ⇒ mốc-so-sánh recycle-proof cho K3.
|
||||
|
||||
---
|
||||
|
||||
## §1 — Run Gitea Actions cho `15349e8` — ✅ PASS
|
||||
|
||||
API `.../actions/tasks?limit=8` (anon, public repo). Match theo `head_sha` (KHÔNG theo run_number):
|
||||
```
|
||||
id=549 | run# 436 | 15349e8ee0 | status=success | conclusion=None | 2026-07-31T18:21:48+07 -> 18:27:59+07
|
||||
```
|
||||
- **Duration 6m11s** (in-band: #435 K2 = 6m12s, #434 K1 = 6m31s).
|
||||
- `conclusion=None` là bình thường cho endpoint `tasks` (memory: tin `status`). Gate test chạy TRƯỚC build/deploy ⇒ `success` ⟹ gate passed.
|
||||
- Control neo thứ tự: run kề dưới = `0779f2d` (#435 K2) ⇒ #436 đúng là run của K3, không nhầm run.
|
||||
- URL: https://git.baocaogiaoduc.vn/vietreport-admin/solution-erp/actions/runs/436
|
||||
|
||||
## §2 — Gate CI test 614 — ✅ PASS (khớp TỪNG VẾ, không chỉ khớp tổng)
|
||||
|
||||
Log web-UI run #436 (`.../actions/runs/436/jobs/0/logs`, 18.680 B, HTTP 200). Đọc bằng **bytes** (memory: text-mode crash cp1252); regex `Passed!.{0,120}` — nới khoảng-trắng vì log dùng **2 space** sau `Passed!`:
|
||||
```
|
||||
11:22:13Z Passed! - Failed: 0, Passed: 45, Skipped: 0, Total: 45, Duration: 157 ms - SolutionErp.Domain.Tests.dll (net10.0)
|
||||
11:24:47Z Passed! - Failed: 0, Passed: 569, Skipped: 0, Total: 569, Duration: 1 m 31 s - SolutionErp.Infrastructure.Tests.dll
|
||||
```
|
||||
- **Domain 45 + Infra 569 = 614** — khớp kỳ vọng TÁCH-PHẦN (45/569), 0 fail / 0 skip.
|
||||
- Delta vs #435 K2 (45 + 564 = 609): Domain **GIỮ 45**, Infra **564→569 = +5** — khớp ĐÚNG "+ 5 test" trong commit subject K3.
|
||||
- **Control ÂM:** `grep -c 'Failed!'` trên toàn log = **0** (nếu có project fail, dotnet in `Failed! - Failed: N…`) ⇒ 2 dòng `Passed!` là TOÀN BỘ project, không có project thứ 3 bị nuốt.
|
||||
|
||||
## §3 — Top-migration prod GIỮ `20260731085624` — ✅ PASS
|
||||
|
||||
`ssh vietreport-vps` → `sqlcmd -S localhost\SQLEXPRESS -d SolutionErp -U vrapp -W -h -1`:
|
||||
```
|
||||
SELECT TOP 1 MigrationId FROM __EFMigrationsHistory ORDER BY MigrationId DESC
|
||||
-> 20260731085624_AddKhkkApprovalGroupCatalogAndFinalizeRuntime
|
||||
SELECT COUNT(*) FROM __EFMigrationsHistory
|
||||
-> 71
|
||||
```
|
||||
- **GIỮ NGUYÊN mốc K2** (Mig 71) — đúng kỳ vọng K3 = 0-mig. MIGCOUNT 71 = 71 ở §0 ⇒ không có mig lén nào chen vào.
|
||||
- Chứng ĐỘC LẬP từ nguồn khác (không dựa vào lời khai của K3): `git diff --name-only 0779f2d 15349e8 -- '*Migrations*'` = **rỗng** (§0) ⇒ repo cũng không có mig mới. Hai nguồn (repo ⟂ prod) khớp.
|
||||
- ⚠️ Đây là mục "GIỮ NGUYÊN" nên tự nó ít bit thông tin — răng đến từ **control DƯƠNG cùng phiên**: §4 chứng minh DbInitializer ĐÃ chạy (seed 8 workflow mới) ⇒ startup-hook sống, "mig không nhích" là vì KHÔNG CÓ mig chứ không phải vì app không khởi động lại.
|
||||
|
||||
## §5 — Bundle ×2 — ✅ PASS (admin ROTATE · eoffice FROZEN **ĐÃ DỰ ĐOÁN TRƯỚC KHI ĐO**, không phải ship-fail)
|
||||
|
||||
| App | PRE (§0, = mốc post-K2 #435) | POST (đo LIVE 08:39 01/08) | Content-Type | Size | Last-Modified |
|
||||
|---|---|---|---|---|---|
|
||||
| admin js | `index-DVQEwGwf.js` | **`index-mySTlx42.js`** ROTATE | application/javascript | 1.755.009 | 31/07 11:26:24 GMT = **18:26:24 +07** |
|
||||
| admin css | `index-D050EVYG.css` | **`index-Cf3iCOOv.css`** ROTATE | text/css | 86.364 | 18:26:24 +07 |
|
||||
| eoffice js | `index-CZAYiWWa.js` | `index-CZAYiWWa.js` **FROZEN** | application/javascript | 1.671.584 | 31/07 11:27:23 GMT = **18:27:23 +07** |
|
||||
| eoffice css | `index-DX1FRk5n.css` | `index-DX1FRk5n.css` **FROZEN** | text/css | 92.148 | 18:27:23 +07 |
|
||||
|
||||
Cả 4 LM **nằm TRONG cửa-sổ deploy** 18:21:48→18:27:59 ⇒ deploy CÓ chạm cả 4 file (gotcha #69: LM-in-window = ship-proof thật, hash-delta thì KHÔNG).
|
||||
|
||||
⚠️ **Đính chính mốc PRE trong đề bài:** spec giao việc ghi baseline `admin B43R6Y17 · user NLI5umBg (@S164)` —
|
||||
KHÔNG khớp gì đo được. Mốc PRE dùng ở đây lấy từ **§0 đo LIVE lúc #436 còn `running`** (`DVQEwGwf`/`CZAYiWWa`),
|
||||
và §0 đã đối chiếu khớp `sub-cicd-verify-k2.md:139-142`. Hai nguồn độc lập ⇒ dùng mốc §0, bỏ mốc trong spec.
|
||||
|
||||
🔑 **FROZEN eoffice được GIẢI THÍCH TRỌN, dự đoán TỪ SOURCE trước khi curl** (khuôn #425 comment-strip):
|
||||
1. `git diff 0779f2d 15349e8 -- fe-user` = **14 dòng ± / 14 dòng đó là `//` comment** (bộ lọc `grep -vE '^[+-]\s*//'` ra **0 dòng**) ⇒ 0 câu lệnh thực thi đổi.
|
||||
2. Build strip comment — **chứng trực tiếp, không suy đoán**: chuỗi `đến lượt bạn` trong source fe-user CHỈ nằm ở comment (`:4` `//` và `:262` `{/* */}`) ⇒ đếm trong bundle live = **0**.
|
||||
3. Không có code-splitting che mắt: `index.html` eoffice tham chiếu **đúng 2 asset** (`index-*.js` + `index-*.css`), và marker riêng của panel `ml-7 mt-1.5 space-y-1 border-l-2 border-violet-200 pl-2` đếm **=1 trong `index-CZAYiWWa.js`** ⇒ file bị sửa NẰM TRONG bundle này, không lọt chunk khác.
|
||||
⇒ Nguồn vào đổi 0 byte thực thi ⟹ Vite ra byte-identical ⟹ hash GIỮ. FROZEN ở đây là **hệ quả bắt buộc**, nếu hash ĐỔI mới đáng nghi.
|
||||
|
||||
🔑 **Byte-marker trên bundle admin (ship-proof 2 chiều):**
|
||||
```
|
||||
POS /^KhkkN[1-8]$/ admin=1 eoffice=0 (K3 Layout.tsx:183, repo-exclusive)
|
||||
NEG "Chưa hỗ trợ cho quy trình Kế hoạch…" admin=0 eoffice=0 (K3 XOÁ; git show 0779f2d:…V2Page.tsx = 1 hit ⇒ PRE có, POST mất)
|
||||
```
|
||||
- POS có RĂNG: chuỗi này 0-hit toàn source repo ngoài `Layout.tsx:183` (hit còn lại chỉ ở `.md` run-trace, không ship) + cross-app control `eoffice=0`.
|
||||
- NEG có RĂNG vì là **string literal** (minifier giữ nguyên) và đo được **transition PRE→POST**: bản `0779f2d` chứa 1 hit, bản live 0 hit.
|
||||
- ❌ **Marker BỊ LOẠI vì không có răng:** `earlyFinalizeLocked` (admin=0). Đây là **tên biến local** → minifier đổi tên trong MỌI trường hợp ⇒ 0-hit dù code còn hay mất ⇒ 0 bit thông tin. Ghi ra để lượt sau đừng tính nhầm nó là bằng chứng.
|
||||
|
||||
## §4 — Seed 8 workflow KHKK-N1..N8 prod + cờ `chuong.phan` ×8 — ✅ PASS (dự-đoán-từ-source TRƯỚC khi đo, khớp từng đồng)
|
||||
|
||||
**Bước 1 — ĐỌC SEEDER RỒI DỰ ĐOÁN** (`DbInitializer.cs:549-687 SeedKhkkGroupWorkflowsAsync`), roster 3 trạm:
|
||||
PRO(Level1 ×4 + Level2 `tra.bui`, finalize=false) · CCM(Level1 ×4 + Level2 `chuong.phan`, **finalize=TRUE** `:579`) · BGĐ(Level1 ×1 `truong.nguyen`, Level2 rỗng→bỏ `:645`).
|
||||
⇒ Dự đoán: **8 wf × 3 step × 11 level** (4+1+4+1+1) · `chuong.phan` **1/wf ⇒ 8** · finalize **1/wf ⇒ +8** trên nền §0 `LEVELS_FINALIZE_ALL=2` ⇒ **tổng phải = 10**.
|
||||
|
||||
**Bước 2 — ĐO** (sqlcmd, file `.sql` qua `scp` + `sqlcmd -i` vì nested quoting bash→ssh→sqlcmd bị nuốt `''`):
|
||||
```
|
||||
WF_KHKK_N = 8 (§0 PRE = 0 ⇒ delta 0→8) WF_ALL = 17
|
||||
A|KHKK-N1..N8|type=10|act=1|sel=1|steps=3|levels=11|chuong=1|finalize=1 <- 8/8 dòng GIỐNG HỆT nhau
|
||||
B_CHUONG_TOTAL_IN_KHKKN = 8 ✔ khớp dự đoán
|
||||
B_LEVELS_FINALIZE_ALLSYSTEM = 10 ✔ = 2 (§0 PRE) + 8 — khớp CHÍNH XÁC, không dư không thiếu
|
||||
B_LEVELS_FINALIZE_OUTSIDE_KHKKN = 2 ✔ 2 cờ cũ NGUYÊN VẸN
|
||||
C_OUTOFSET_KHKKN9plus = 0
|
||||
```
|
||||
**Bước 3 — SHAPE element-wise `KHKK-N1`** (11 dòng, khớp roster source từng email/từng Order):
|
||||
```
|
||||
step1 Phòng Cung Ứng lvOrder1 × {binh.lethanh, duy.nguyen, long.chau, phuong.nguyen} fin=0 (OR-of-N)
|
||||
step1 lvOrder2 × {tra.bui} fin=0
|
||||
step2 P. Kiểm soát Chi phí lvOrder1 × {binh.le, luu.tran, nguyen.ho, truong.letrandang} fin=0
|
||||
step2 lvOrder2 × {chuong.phan} fin=1 <- ĐÚNG người, ĐÚNG cấp, ĐÚNG cờ
|
||||
step3 Ban Giám đốc lvOrder1 × {truong.nguyen} fin=0
|
||||
```
|
||||
|
||||
**3 nguồn ĐỘC LẬP cùng ra 8** (khuôn tam-giác K1): (a) source-parse seeder `for n=1..8` · (b) sqlcmd `WF_KHKK_N=8` · (c) **Serilog prod** `18:27:48.888 [INF] Seeded 8 KHKK group workflows (K3 SP-002)`.
|
||||
|
||||
**Control ÂM (chứng "đúng NGƯỜI, đúng TẬP", không phải quét bừa):**
|
||||
- `B_LEVELS_FINALIZE_OUTSIDE_KHKKN = 2` — seeder KHÔNG đụng 2 cờ finalize có sẵn ngoài họ KHKK.
|
||||
- `C_OUTOFSET = 0` — không đẻ `KHKK-N0/N9+` ngoài miền 1..8.
|
||||
- 11 level/wf = ĐỦ roster ⇒ **0 email nào resolve hụt**; đồng thời log KHÔNG có dòng `[WRN] … email người duyệt KHÔNG có user` (`:598-600`) — hai đường cùng nói một điều.
|
||||
|
||||
**Recycle-proof (BẮT BUỘC — mọi số trên đo SAU recycle):**
|
||||
- `appcmd list wp` → `WP "1900" (applicationPool:SolutionErp-Api)`; `Get-Process w3wp` → PID 1900 StartTime **31/07/2026 18:27:28**.
|
||||
- **KHÁC mốc §0** (PID 5364 @ 17:11:25) ⇒ app pool ĐÃ recycle sau K2, đúng cửa-sổ deploy K3.
|
||||
- Dòng **ĐẦU TIÊN** của `solution-erp-20260731.log` = `18:27:40.918 [INF] Applying migrations...` (deploy xoá `logs/`) ⇒ chứng khởi-động-lại từ nguồn thứ hai.
|
||||
- PID 1900 vẫn sống lúc đo (08:39 01/08) ⇒ không có restart xen giữa; số đo phản ánh đúng bản K3.
|
||||
|
||||
## §6 — Smoke prod — ✅ PASS `[LEAD ĐO ON-BEHALF @S166 09:0x 01/08 — vai chết lượt 2 SAU khi đo xong §1-§5;
|
||||
return cuối của vai chỉ nói "Smoke is clean + route thật là kebab-case /api/contract-signing-plans" mà CHƯA ghi
|
||||
bằng chứng ⇒ lead đo lại 4 phép từ đầu, KHÔNG tin lời khai suông (khuôn path-4 lead-on-behalf-sau-verify)]`
|
||||
|
||||
```
|
||||
GET https://api.solutions.com.vn/api/contract-signing-plans (no token) -> 401 (authz đóng đúng)
|
||||
GET https://api.solutions.com.vn/api/route-khong-ton-tai-xyz -> 404 (route rác không nuốt)
|
||||
GET https://eoffice.solutions.com.vn/ -> 200
|
||||
GET https://admin.solutions.com.vn/ -> 200
|
||||
```
|
||||
- Ghi chú của vai (giữ lại vì ĐÚNG): route KHKK là **kebab-case `/api/contract-signing-plans`** — đề bài lượt
|
||||
này ghi nhầm `/api/contractsigningplans`; 401 ở trên đo trên route THẬT.
|
||||
- Ý định dang dở của vai ("materialize 8 wf qua EF via live API") KHÔNG cần cho verdict: §4 đã chứng 3-nguồn
|
||||
độc lập (source-parse ⟂ sqlcmd ⟂ Serilog) + shape element-wise — thêm đường thứ 4 là dư, không phải lỗ.
|
||||
|
||||
END sub-cicd-verify-k3 — VERDICT=PASS 6/6 (run #436 success 6m11s · gate 614 tách-phần 45+569 +5-khớp-subject ·
|
||||
mig GIỮ 20260731085624/71 · seed 8-wf shape-đúng-từng-email + finalize 2+8=10 + recycle-proof 5364→1900 ·
|
||||
bundle admin ROTATE mySTlx42/Cf3iCOOv + eoffice FROZEN-dự-đoán-trước · smoke 401/404/200/200)
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
IMPLBE-K4A: DONE — B0-B5 lane đo, B6 + chốt = lead on-behalf @S166 (lane chết #53 sau B5, code ĐÃ LAND ĐỦ)
|
||||
|
||||
# Lane BE K4a — 49 row menu KHKK 8-nhóm + MenuKeys.All + labelBackfill + grant
|
||||
|
||||
Bắt đầu: 2026-08-01. 0-migration. Scope: `MenuKeys.cs` + `DbInitializer.cs` ONLY.
|
||||
|
||||
## Nhật ký từng bước (append sau MỖI file sửa xong)
|
||||
|
||||
- [x] B0 artifact tạo (dòng này = bằng chứng file ra đời TRƯỚC mọi Read)
|
||||
- [x] B1 đọc spec pin 2 file + re-ground anchor THẬT (đo lại, không tin số spec):
|
||||
- `DbInitializer.cs` khối menu KHKK G1: `:1950-1963` (root `:1951` + `Khkk_G1 :1956` + 6 leaf `:1958-1963`) — icon group `FileCheck`, leaf `Network/List/Plus/CheckCircle2/CheckCheck/Trash2`, Order 1-6 ✔ khớp brief
|
||||
- upsert-block THẬT (trước khi tôi sửa): `existingItems` `:2111` → foreach `:2114-2131`; nhánh key-đã-tồn-tại chỉ re-set Order rồi `continue` = `:2116-2128`
|
||||
- labelBackfill dict `:2141-2183` · apply-loop `:2184-2198` ✔
|
||||
- 2 comment stale tự-trỏ `":1893-1905"`: `:2095` và `:2149` ✔ (số THẬT sẽ đo LẠI sau khi thêm 49 row)
|
||||
- site-1 `SeedAdminPermissionsAsync` loop `MenuKeys.All` `:2246` (chỉ Admin) · site-2 `KhkkKeys()` `:2373-2377` (feed `reviewKeys :2398-2412`, CanRead mọi role, skip-existing) · site-3 `SeedKeHoachKyKetAccessAsync` `:2603` · site-4 revoker gọi `:2285`, prefix `Hrm*/Off*/Personal` `:2487-2488` → **0 match `Khkk`** (đã soi trực tiếp, đúng vá-11)
|
||||
- `MenuKeys.All` hiện đếm tay = **64** (khớp mốc brief) — số THẬT sẽ đo bằng runtime ở B6
|
||||
- `GetMyMenuTreeQuery.cs:96` `HasAccess(n) = n.CanRead || n.Children.Any(HasAccess)` ⇒ **group-key KHÔNG cần CanRead row của chính nó** (vá-10 đúng: lý-do "group cần row để render" trong invest doc là SAI) — nhưng leaf thì CẦN
|
||||
- nhãn 8 nhóm đối chiếu nguồn `danh-muc-sp002-transcribe.md:22-29` → khớp 8/8 brief, N2 CÓ vế "phá dỡ" ✔
|
||||
- [x] B2 `MenuKeys.cs` +49 key vào `All` — **CHỆCH-KHUÔN KHAI RÕ**: brief nói "+49 const", tôi làm **bộ sinh** (`KhkkGroupNumbers` + `KhkkLeafActions` + `KhkkGroup(n)`/`KhkkLeaf(n,a)` → `KhkkGroupMenuKeys` 49 phần tử) rồi `.. KhkkGroupMenuKeys` vào `All`. LÝ DO: cùng 1 bộ sinh feed CẢ 3 phía (`All` · seed menu-row · grant site-2) ⇒ khớp **by-construction**; 49 const tay = mirror 147 chuỗi ở 3 nơi, đúng loại drift làm nổ FK Permission (invariant T6 K1). Đúng đề xuất spec `sub-invest-fable-b2-cum2.md:9` ("factory mirror khuôn ContractTypeGroup"); kết quả quan sát được y hệt (49 key vào All). Khai báo ĐẶT TRƯỚC `All` vì static field initializer chạy theo thứ tự văn bản. Kèm vá-15 (2 khuôn `Ct_*`/`Pe_*` ngoài-All ⟂ Khkk/AwV2 trong-All) + ghi DELTA (+49 key/+196 policy, KHÔNG neo mốc tuyệt đối — vá-2). Build Domain riêng: **0 error / 0 warning**.
|
||||
- [x] B3 `DbInitializer.cs` tree +49 row: loop đặt sau vòng `PeWf_*`, duyệt CHÍNH `MenuKeys.KhkkGroupNumbers` × `KhkkLeafActions` (group Order=n, icon `FileCheck`; 6 leaf Order 1-6 nhãn/icon MIRROR Y G1). 2 dict nhãn: `khkkGroupLabels` (8 nhãn owner-soát, N2 CÓ "phá dỡ") + `khkkLeafMeta` — thiếu nhãn ⇒ KeyNotFound **fail-fast lúc seed** thay vì FK nổ về sau.
|
||||
- [x] B4 labelBackfill +`Khkk_G1` — LANE ĐÃ LAND (lead kiểm @S166: entry `["Khkk_G1"] = "1. Thiết bị,
|
||||
máy móc, vật tư phụ (A1)"` ở dict cuối, kèm comment "7 nhóm G2..G8 là key MỚI đi nhánh INSERT,
|
||||
không cần backfill" — đúng. ⚠️ lead suýt kết luận "thiếu entry" vì `grep | head -8` nuốt hit
|
||||
— bài phép-trích-cụt, đọc vùng dict trực tiếp mới thấy).
|
||||
- [x] B5 site-2 `KhkkKeys().Concat(MenuKeys.KhkkGroupMenuKeys)` + vá-10 (comment lý-do đúng: group-key
|
||||
KHÔNG cần CanRead row của chính nó — `GetMyMenuTreeQuery.cs:96` HasAccess đệ-quy theo con; leaf CẦN)
|
||||
+ vá-11 comment revoker (restart ×2 = phép thử, acceptance A5) + vá-13 CẢ 2 comment stale `"1893"`
|
||||
→ 0-hit (đã trỏ `:2162-2179` + mỏ neo grep `existingItems.TryGetValue`) — LANE ĐÃ LAND, lead verify
|
||||
0-hit grep + đọc vùng.
|
||||
- [x] B6 (lead on-behalf): build Infra 0-error · **full suite 614/0 exit-0 SAU diff** (Domain 45 +
|
||||
Infra 569 — DbInitializer đổi mà idempotent/revoke/permission-seed tests giữ xanh) · đếm by-source:
|
||||
`KhkkGroupNumbers[7] × (1 group + 6 leaf) = 49` key spread `.. KhkkGroupMenuKeys` vào `All:244`
|
||||
⇒ All 64→113 kỳ vọng, Policies 256→452 (+49×4=196). 🔴 Số RUNTIME (All.Count thật + policy đếm DB)
|
||||
chốt ở lane test K4a (PS5.1 không load net10 DLL — reflection từ shell bất-khả); DELTA khai đúng
|
||||
vá-2 (không neo mốc tuyệt đối, kèm lệnh đo lại).
|
||||
|
||||
END sub-implbe-k4a — VERDICT=DONE (49 key by-construction 3-phía All/seed/grant · labelBackfill G1 ·
|
||||
vá 10/11/13/15 land · suite 614/0 · runtime-count → lane test; commit = lead sau gate)
|
||||
@ -0,0 +1,229 @@
|
||||
REVIEW-F1: PASS-WITH-FLAGS 7 — 3 MAJOR (G-1 default ngược PE-live · G-2 sơ đồ nói CEO "đã duyệt" · G-6 cây phình 5→7 file, K4a bị commit ké) / 4 MINOR; 0 blocker kỹ-thuật trên 5 file F-1, 1 blocker quy-trình (G-6: tách commit trước khi push)
|
||||
|
||||
# Reviewer F-1 — ô-tích opt-out `applyLevelFinalize` panel duyệt KHKK
|
||||
|
||||
Ghi-đĩa TRONG LÚC SOI (chống #53). Đo từ ĐĨA, HEAD `24ea71e`, diff CHƯA commit.
|
||||
Phạm vi: `git diff -- src fe-user fe-admin` = **5 file M, +137 / −14**.
|
||||
|
||||
## §0 Mirror 2 app — chứng bằng blob-SHA của git (KHÔNG tin lời khai)
|
||||
|
||||
`git diff` in ra index-line của cả 2 app:
|
||||
|
||||
| Cặp file | blob TRƯỚC | blob SAU |
|
||||
|---|---|---|
|
||||
| `fe-{admin,user}/src/pages/khkk/KhkkWorkflowPanel.tsx` | `e2fa3bc` (cả hai) | `6913182` (cả hai) |
|
||||
| `fe-{admin,user}/src/types/khkk.ts` | `a99658c` (cả hai) | `1ffd79b` (cả hai) |
|
||||
|
||||
⇒ 2 cặp **byte-identical cả trước lẫn sau** (git blob = sha1 nội dung) — mirror §3.9 ĐẠT, và
|
||||
không có nhánh "sửa 1 app quên app kia". ✅
|
||||
|
||||
## §1 Ranh giới BE — cờ có tới FE bằng ĐÚNG một đường
|
||||
|
||||
- `ContractSigningPlanWorkflowLevelDto` (`ContractSigningPlanFeatures.cs:116`) +1 positional
|
||||
`bool AllowApproverFinalize`; **construction site = 1** (`:640`, grep toàn `src/Backend` cho
|
||||
đúng 3 hit: `:116` def · `:132` kiểu List · `:640` new) ⇒ không có site thứ 2 lỡ truyền `false` cứng.
|
||||
- `l.AllowApproverFinalize` đọc thẳng từ `ApprovalWorkflowLevel` của **đúng workflow đã pin**
|
||||
(cùng bảng, cùng row mà `ResolveActingLevel` sẽ chấm lúc duyệt) ⇒ không có nguồn thứ hai.
|
||||
- 0 đổi logic BE: `git diff` trên `src` chỉ 2 hunk, cả 2 nằm trong DTO + projection. ✅
|
||||
|
||||
## §2 (đề bài 1) `actingLevel` FE có mirror ĐÚNG `ResolveActingLevel` không
|
||||
|
||||
BE (`ContractSigningPlanWorkflowService.cs:463-468`):
|
||||
`own = pendingLevelGroup.FirstOrDefault(l => l.ApproverUserId == actorId)` → `if (own is not null) return own;`
|
||||
→ `if (isAdmin) return pendingLevelGroup.First();` → còn lại **ném Forbidden**.
|
||||
FE (`KhkkWorkflowPanel.tsx:135-137`):
|
||||
`currentLevels.find(l => l.approverUserId === user?.id) ?? (isAdmin ? currentLevels[0] : undefined)`.
|
||||
|
||||
| Ca | BE chấm level nào | FE chấm level nào | Khớp? |
|
||||
|---|---|---|---|
|
||||
| Actor ∈ Cấp, cấp CÓ cờ | own (có cờ) | own (có cờ) → hiện ô-tích | ✅ |
|
||||
| Actor ∈ Cấp OR-of-N, **cờ ở NGƯỜI KHÁC cùng Cấp** | own (KHÔNG cờ) ⇒ không finalize | own (KHÔNG cờ) ⇒ ẩn ô-tích, gửi `true` = no-op | ✅ (ca đề bài hỏi kỹ — không rò) |
|
||||
| Admin **có** slot riêng trong Cấp | own | own (vì `find` chạy TRƯỚC nhánh isAdmin) | ✅ |
|
||||
| Admin **không** có slot | `pendingLevelGroup.First()` | `currentLevels[0]` | ⚠️ xem §6 (thứ tự 2 truy vấn) |
|
||||
| Không phải approver, không Admin | **Forbidden 403** | `undefined` ⇒ ẩn ô-tích | ✅ (và nút Duyệt đã `disabled` bởi `blockedByLevel` `:130`) |
|
||||
| `currentLevels` **RỖNG** (phase ≠ ChoDuyet, hoặc con-trỏ null, hoặc idx ngoài biên) | không tới `ApproveV2Async` (409 `:250-251`) | `find`→undefined, `currentLevels[0]`→`undefined` ⇒ eligible=false | ✅ **không nổ** (index-out-of-range trên mảng rỗng trong JS = `undefined`, không throw) |
|
||||
| `user` chưa nạp (`user?.id` undefined) | — | `find` không khớp (`approverUserId` là `string` non-null) ⇒ undefined; `isAdmin`=false ⇒ nút Duyệt disabled | ✅ |
|
||||
|
||||
Vế **so-khớp GUID dạng chuỗi**: `user.id` sinh từ `res.data.user` (`AuthContext.tsx:53-56`, DTO login
|
||||
serialize `Guid` → chữ thường có gạch), `approverUserId` cũng là `Guid` serialize cùng kiểu ⇒ `===`
|
||||
hợp lệ; và đây là **cùng phép so đã sống từ W3** (`:127` `actorIsCurrentApprover`), không phải phép mới.
|
||||
|
||||
⇒ **Mirror ĐÚNG 6/7 ca**; ca thứ 7 (Admin duyệt-thay trên Cấp **trộn cờ**) là finding §6/G-4.
|
||||
|
||||
## §3 (đề bài 2) Body — rò field ở action khác? khớp hợp-đồng `bool?`?
|
||||
|
||||
`KhkkWorkflowPanel.tsx:151-157`:
|
||||
`{ action, comment, ...(a === Approve ? { applyLevelFinalize: eligible ? state : true } : {}) }`
|
||||
|
||||
| Action | Key có trong JSON? | Giá trị | BE nhận | Ảnh hưởng |
|
||||
|---|---|---|---|---|
|
||||
| `submit` | **KHÔNG** | — | `ApplyLevelFinalize = null` → `?? true` (`Controller:213`) | `SubmitAsync` **không nhận tham số** (`Service:122`) ⇒ vô hại |
|
||||
| `return` / `reject` | **KHÔNG** | — | như trên | `ReturnOrRejectAsync` **không nhận tham số** (`:130-136`) ⇒ vô hại |
|
||||
| `approve`, cấp thường | CÓ | `true` | `true` | `actingLevel.AllowApproverFinalize && true` = **false** ⇒ no-op (§4) |
|
||||
| `approve`, cấp có cờ, giữ tick | CÓ | `true` | `true` | finalize (đúng ý người bấm) |
|
||||
| `approve`, cấp có cờ, bỏ tick | CÓ | `false` | `false` | rơi xuống advance thường ⇒ trình tiếp (đúng mục tiêu F-1) |
|
||||
|
||||
⇒ **0 rò field** sang action khác; và ngay cả khi rò cũng không có chỗ đọc ở BE (3 nhánh kia không có tham số).
|
||||
|
||||
**absent vs null vs true** — hợp-đồng `ContractSigningPlanTransitionBody(string Action, string? Comment = null, bool? ApplyLevelFinalize = null)`:
|
||||
key vắng ⇒ System.Text.Json để `bool?` = `null` (bằng ĐÚNG giá trị mặc định khai báo, nên **không phụ thuộc**
|
||||
vào chuyện STJ có tôn trọng default-parameter-value của positional record hay không — cả hai đường đều ra `null`)
|
||||
⇒ `?? true`. FE **không bao giờ** gửi `null` tường minh (spread bỏ hẳn key, không set `undefined`).
|
||||
⇒ 3 trạng thái absent/null/true hội tụ về CÙNG một hành vi. ✅ Khớp hợp-đồng.
|
||||
|
||||
## §4 (đề bài 3) Regression cấp thường + rò ô-tích ở phase khác
|
||||
|
||||
**Cấp thường (không cờ), trước ⟂ sau vá:**
|
||||
- trước: body `{action, comment}` ⇒ BE `?? true` ⇒ `applyLevelFinalize=true`
|
||||
- sau: body `{action, comment, applyLevelFinalize: true}` ⇒ BE `true`
|
||||
⇒ **cùng một giá trị đi vào cùng một biểu thức** `if (actingLevel.AllowApproverFinalize && applyLevelFinalize)`
|
||||
(`Service:276`), mà vế trái = `false` ⇒ nhánh không vào ở CẢ HAI thế giới. Hành vi **y hệt**, không phải
|
||||
"giống về mặt cảm tính". ✅
|
||||
(Điểm yếu còn lại là của thiết kế BE, không phải của diff: no-op này chỉ đúng vì BE **AND** với cờ cấp —
|
||||
FE gửi `true` cho người không có quyền finalize là dữ liệu thừa, không phải quyền thừa.)
|
||||
|
||||
**Rò ô-tích ở phase khác — 3 lớp chặn ĐỘC LẬP, hỏng 1 lớp vẫn không rò:**
|
||||
1. `currentLevels` chỉ khác `[]` khi `isWaiting` (`:118-121`) ⇒ DaDuyet/TraLai/TuChoi/Nháp ⇒ `actingLevel=undefined` ⇒ `approverFinalizeEligible=false`.
|
||||
2. Nút "Duyệt" (đường DUY NHẤT đặt `action=Approve`) chỉ render trong `{isWaiting && (…)}` (`:312-335`).
|
||||
3. Chính JSX ô-tích đòi `action === Approve` (`:443`).
|
||||
⇒ **0 rò**. Kiểm chéo: `KhkkTransitionAction.Approve` được gán ở đúng 1 site (`:323`), grep 2 app cho thấy
|
||||
không có site thứ hai. ✅
|
||||
|
||||
**Reset trạng thái:** `setApplyLevelFinalize(true)` đặt ở `onClick` mở dialog (`:322`) ⇒ bỏ tick rồi **Huỷ**
|
||||
rồi mở lại vẫn về mặc định. (PE chỉ reset trong `onSuccess` `:288` ⇒ PE **giữ** tick sau khi Huỷ — chỗ này
|
||||
KHKK **chặt hơn** khuôn.) ✅
|
||||
|
||||
## §5 (đề bài 4) Khuôn-PE fidelity — lệch CỐ Ý vs SÓT
|
||||
|
||||
| # | Trục | PE (live) | KHKK (diff) | Phán |
|
||||
|---|---|---|---|---|
|
||||
| a | JSX ô-tích | `:772-791` | `:443-462` — cùng khung, cùng nhãn "Cấp này KẾT THÚC quy trình" | ✅ trung thành |
|
||||
| b | Câu "Nhớ chọn 1 giá chốt" | có (`:786`) | bỏ | ✅ **CỐ Ý** — KHKK 0 price-picker, BE tự chốt ở `ApplyApprovedValuesOnFinalize` |
|
||||
| c | Gửi field | luôn gửi, `!isReject && (...)` (`:259`) | chỉ gửi khi approve | ✅ tương đương (3 nhánh kia BE không đọc) |
|
||||
| d | Reset state | `onSuccess` | mở-dialog | ✅ KHKK chặt hơn |
|
||||
| e | **Default ô-tích** | **`useState(false)` = OPT-IN** (`:61`) | **`useState(true)` = OPT-OUT** (`:85`) | 🔴 **G-1 — lệch NGƯỢC khuôn LIVE** |
|
||||
| f | Nguồn eligibility | BE precompute `currentLevelOptions` chọn level theo actor (`PurchaseEvaluationFeatures.cs:1083-1085`) | FE **tự mirror** `ResolveActingLevel` | 🟡 **G-4 — nợ drift** |
|
||||
| g | Badge cấp mang cờ trong sơ đồ | có (`:441` `lv.allowApproverFinalize &&`) + làm mờ Bước/Cấp SAU (`:161-170`) | **không có** | 🔴 **G-2 — SÓT** |
|
||||
|
||||
### 🔴 G-1 (MAJOR) — default TICK ngược chiều khuôn PE ĐANG SỐNG; nhãn "khuôn PE S96" trích bản ĐÃ BỊ ĐẢO
|
||||
`fe-*/src/pages/khkk/KhkkWorkflowPanel.tsx:15-18` (header) + `:83-85` (`useState(true)`).
|
||||
Đo tại chỗ: `fe-*/src/components/pe/PeWorkflowPanel.tsx:61` = `useState(false)`, chú thích ngay trên nó:
|
||||
*"[S97 2026-07-01 — anh Kiệt FDC] … = ô-tick **OPT-IN**: default UNCHECKED → trình tiếp CEO/cấp sau; TÍCH mới KẾT THÚC tại cấp này. **Đảo opt-out S96**."*
|
||||
⇒ PE **đã đi qua đúng ngã ba này** và owner ĐẢO sang opt-IN một phiên sau S96. KHKK vừa nhặt lại **đúng vế PE đã bỏ**.
|
||||
Vì sao lọt: chú-thích PE `:769-771` (ngay trên khối JSX được trích) vẫn viết *"NAY là ô-tích BỎ được (opt-out): default tick"* — **tự nó STALE** so với `:61` cùng file ⇒ implementer trích đúng dòng nhưng trúng **chú-thích chết**. Đây là tái phát lớp *đối-chứng-khuôn-nguồn* (S165 F-1): đo khuôn ở tầng CHÚ-THÍCH thay vì tầng **giá trị khởi tạo**.
|
||||
Hệ quả hành vi: Chương bấm "Duyệt" → "Xác nhận" mà không đọc ⇒ phiếu **DaDuyet + chốt giá**, CEO không bao giờ thấy. Hướng-sai-lệch nghiêng về **ÍT phê duyệt hơn** ở đúng cổng tiền; chiều ngược lại chỉ tốn thêm 1 trạm và cứu được.
|
||||
Vế bào chữa PHẢI ghi cùng: default=`true` **giữ nguyên** hành vi BE `?? true` ⇒ **0 regression** so với trước diff, và acceptance F-1 của gate K3 chỉ đòi "mirror `PeWorkflowPanel.tsx:778`" (JSX) — implementer làm đúng chữ.
|
||||
⇒ Đây là **quyết định của owner, không phải bug**. Nhưng KHÔNG được để nhãn *"khuôn PE S96"* nói rằng PE đang làm thế.
|
||||
**Acceptance (1 trong 2):** (i) owner ratify default=tick + sửa nhãn thành *"ĐẢO NGƯỢC PE-live (PE S97 = opt-IN) — owner chốt @S166, lý do: …"*; HOẶC (ii) đổi `useState(true)`→`useState(false)` + đổi 2 câu mô tả cho khớp.
|
||||
|
||||
### 🔴 G-2 (MAJOR — carry-over, KHÔNG do diff này đẻ) — sơ đồ nói CEO "đã duyệt" trong khi CEO chưa đụng
|
||||
`KhkkWorkflowPanel.tsx:100-106` `stepStatus`: `if (isApproved) return 'Done'` cho **MỌI** Bước; `:108-114` `levelStatus` trả thẳng `s` khi `s !== 'Current'` ⇒ mọi Cấp = `'Done'`; `:234` render `ls === 'Done' && "đã duyệt"`.
|
||||
⇒ Phiếu kết thúc ở CCM Cấp 2 ⇒ Bước 3 «Ban Giám đốc» + cấp của `truong.nguyen` hiện ✓ emerald **"đã duyệt"**. Dấu vết phân biệt duy nhất = **vắng** dòng "✓ ký {giờ}" (`:238-242`) — bắt người đọc suy từ sự vắng mặt.
|
||||
PE đã giải đúng bài này: badge `allowApproverFinalize` trên chính Cấp (`:441`) + làm mờ Bước/Cấp SAU (`:161-170`), **gate bằng runtime `endsBeforeCeo`** (chú thích tại chỗ: *"bug 'CEO duyệt mà mờ'"*).
|
||||
KHKK làm được **nửa rẻ ngay bây giờ** (badge theo `allowApproverFinalize` — cờ vừa được chính diff này đưa vào DTO); nửa còn lại cần `EndedByLevelFinalize` ra DTO = **F-7 gate K3 vẫn treo**.
|
||||
Ghi thật: lỗi có từ K3 (nhánh BE + seed cờ đã land ở `15349e8`), **diff này không đẻ ra nó** — nhưng diff này biến đường kết-thúc-sớm thành đường **mặc định có UI**, nên tần suất từ hiếm → thường.
|
||||
|
||||
## §6 (đề bài 5) Gotcha #44 — có ca nào CÓ quyền mà ô-tích KHÔNG hiện?
|
||||
|
||||
Quét đủ 3 đường có thể giấu control khỏi đúng người:
|
||||
|
||||
1. **Cấp trộn cờ + Admin duyệt thay** — 🟡 **G-4 (MINOR, điều-kiện)**.
|
||||
BE lấy `pendingLevelGroup.First()` (IGrouping dựng trong `LoadStepsAsync`+`ResolvePointer`, `Service:410-442`);
|
||||
FE lấy `currentLevels[0]` (mảng dựng trong query detail `ContractSigningPlanFeatures.cs:621-643`).
|
||||
**Hai truy vấn khác nhau**, cả hai chỉ `OrderBy(l => l.Order)` — **không có khoá phụ** ⇒ thứ tự các row
|
||||
cùng `Order` do DB quyết, không có gì bảo đảm 2 lượt trả giống nhau. Lệch ⇒ FE ẩn ô-tích trong khi BE
|
||||
finalize = **mất opt-out im lặng** (đúng hình #44).
|
||||
**Vô hại trên 8 workflow seed** — đo `DbInitializer.cs:626-660`: cờ gán theo **CẤP**
|
||||
(`foreach (var (emails, finalize) in new[] { (r.Level1, false), (r.Level2, r.Level2Finalize) })` → mọi
|
||||
approver trong cùng Cấp nhận CÙNG `finalize`) ⇒ trong 1 Cấp cờ **đồng nhất** ⇒ `First()` chọn ai cũng ra
|
||||
cùng cờ; thêm nữa Cấp mang cờ chỉ có **1 người** (`chuong.phan`, `:576-580`).
|
||||
**Có hại khi admin dựng Cấp trộn cờ qua Designer** — schema cho phép (cờ là per-slot), và chính PE đã ghi
|
||||
thành chú thích cảnh báo: `PurchaseEvaluationFeatures.cs:1072-1075` *"OR-of-N approvers cùng Cấp = N rows
|
||||
cùng Order, mỗi row có Allow* riêng. Lookup KHÔNG discriminate → luôn lấy row đầu DB"*.
|
||||
Đối chiếu thiết kế: PE **không** mirror ở FE — BE trả `currentLevelOptions` đã chọn level theo actor. KHKK
|
||||
chọn mirror FE ⇒ mỗi lần `ResolveActingLevel` đổi, FE **im lặng lệch**, không có test nào kêu.
|
||||
|
||||
2. **Cấp CÓ cờ mà actor là người khác trong Cấp** — KHÔNG phải lỗi: BE cũng chấm `own` (không cờ) ⇒ 2 bờ cùng nói "không finalize" (§2 hàng 2). ✅
|
||||
|
||||
3. **Sợi dây DTO đứt** — 🟡 **G-3 (MINOR)**: `ContractSigningPlanFeatures.cs:643` `l.AllowApproverFinalize`
|
||||
là **điểm chết duy nhất** của tính năng, mà **0 test chạm nó**. Grep `tests/`: `AllowApproverFinalize` chỉ
|
||||
xuất hiện ở `ContractSigningPlanApprovalTests.cs:877-904` (hành vi service) và `:1065-1138` (create-definition);
|
||||
**0 hit** trên projection của `GetContractSigningPlanQuery`. Xoá đúng 1 argument đó ⇒ 614 test vẫn xanh,
|
||||
`tsc` vẫn xanh (field vẫn đúng kiểu, chỉ luôn `false` lúc chạy) ⇒ ô-tích **biến mất im lặng** với đúng người
|
||||
có quyền. Đúng lớp S161-W2 (*hợp-đồng FE↔BE vỡ mà build+test đều xanh*). Phase-9 test-after cho phép hoãn —
|
||||
nhưng phải hoãn **có ý thức**, vì đây là sợi dây duy nhất.
|
||||
|
||||
4. 🟡 **G-5 (MINOR) — chữ "(CEO)" là suy đoán theo seed, không theo cấu hình.**
|
||||
`:457` *"duyệt xong kế hoạch TRÌNH TIẾP lên cấp sau (CEO)"*. Đúng với 8 workflow seed (Bước 3 = Ban Giám đốc).
|
||||
Nếu admin cắm cờ ở **Cấp cuối của Bước cuối**: bỏ tick ⇒ BE rơi xuống nhánh terminal `Service:320-329` ⇒
|
||||
**vẫn `DaDuyet` ngay** (khác duy nhất: `EndedByLevelFinalize=false` + câu changelog) ⇒ ô-tích hứa "trình tiếp"
|
||||
mà phiếu đóng luôn. Test T-a có sanity chặn "cấp mang cờ = cấp cuối" **trong test**, nhưng BE **không có
|
||||
validator** cấm cấu hình đó ở Designer.
|
||||
|
||||
## §6b (đề bài 6) Header-comment — còn tự mâu thuẫn chỗ nào?
|
||||
|
||||
Quét toàn khối `:1-27` sau khi supersede:
|
||||
- `:6-8` *"KHÔNG price-picker, KHÔNG ngân sách, KHÔNG file-khi-duyệt, KHÔNG 4 return-mode"* → vẫn ĐÚNG với diff (ô-tích không phải price-picker). ✅
|
||||
- `:10-14` supersede-1 (BE đã port + Designer đã gỡ khoá) → kiểm chứng: `earlyFinalizeLocked` chỉ còn ở **2 chỗ bia-mộ** `ApprovalWorkflowsV2Page.tsx:153` + `:641` (đều là chú thích "ĐÃ BỎ HẲN"), 0 site dùng. ✅
|
||||
- `:15-18` supersede-2 → nội dung mô tả ĐÚNG việc diff làm, nhưng **nhãn "khuôn PE S96"** sai với PE-live ⇒ G-1.
|
||||
- `:20-27` *"KHÁC PE Ở CHỖ ĐẮT NHẤT: PE nhận `approvalFlow` đã có `status` … KHKK BE trả CÂY THÔ"* → vẫn đúng, và
|
||||
giờ **thiếu một vế**: từ diff này KHKK còn phải tự suy **cả level-của-actor** (thứ PE cũng nhận sẵn từ BE) —
|
||||
chính là G-4. Khối "KHÁC PE" nên nêu thêm vế đó, nếu không người sau đọc sẽ tưởng chỉ lệch ở `status`.
|
||||
- Chú thích `:132-134` mô tả mirror đúng 2 vế BE, nhưng **không khai** rằng thứ tự nhóm đến từ 2 truy vấn khác nhau (G-4).
|
||||
- Citation kiểm từng cái: `PeWorkflowPanel.tsx:259` = đúng dòng gửi `applyLevelFinalize` ✅; `:772-791` = đúng khối JSX ✅; `ContractSigningPlanWorkflowService.cs:455-469` = đúng `ResolveActingLevel` ✅. **Số dòng không bịa.**
|
||||
⇒ 0 mâu thuẫn logic còn sót; 2 chỗ **thiếu-khai** (nhãn khuôn PE · vế mirror mới) đã tính vào G-1/G-4.
|
||||
|
||||
## §6c NGOÀI ĐỀ BÀI — cây làm việc PHÌNH GIỮA LƯỢT REVIEW (đo 2 lần, cách nhau ~40 tool-call)
|
||||
|
||||
| Mốc đo | `git status --porcelain -- src fe-user fe-admin tests` | `git diff --stat` |
|
||||
|---|---|---|
|
||||
| Lúc spawn (§0) | **5 file** | **+137 / −14** |
|
||||
| Đo lại lúc viết §6c | **7 file** (+`Domain/Identity/MenuKeys.cs`, +`Infrastructure/Persistence/DbInitializer.cs`) | **+253 / −19** |
|
||||
|
||||
🔴 **G-6 (MAJOR — quy trình, chặn commit):** 2 file mới (+42 / +79 dòng) **KHÔNG thuộc spec F-1** và
|
||||
**KHÔNG nằm trong phạm vi tôi soi**. Nội dung là **K4a** (khuôn (b) menu-key nhóm): `MenuKeys.cs:81-84`
|
||||
thêm `KhkkGroupMenuKeys` rồi **spread `.. KhkkGroupMenuKeys` vào `All`** (`:244`).
|
||||
Đo hệ quả canonical: `All` hiện gồm **64 định danh tĩnh + 1 spread**; spread = `KhkkGroupNumbers` (7 số
|
||||
`[2..8]`) × (1 group + 6 `KhkkLeafActions`) = **49 key** — chính chú thích `MenuKeys.cs:79` cũng ghi *"49 key"*
|
||||
⇒ `|MenuKeys.All|` = **113**, policies DERIVED = **452**.
|
||||
⇒ Nếu commit "vá F-1" ngay bây giờ, nó **nuốt trọn** 121 dòng chưa qua cổng nào **và** đổi 2 con số canonical
|
||||
(gấp ~1,8 lần). Đây đúng lớp đã ăn đòn ở gate K1 cùng chuỗi (*commit gộp = vượt quyền owner*).
|
||||
**Acceptance:** tách 2 commit — (1) F-1 đúng 5 file; (2) K4a riêng, có gate riêng + cập nhật STATUS.
|
||||
*(Ghi thật: tôi KHÔNG soi nội dung 2 file đó; con số 113/452 là DERIVE từ hình dạng mã + chú thích tại chỗ,
|
||||
chưa chạy initializer — người ship phải tự đếm lại bằng máy trước khi ghi vào STATUS.)*
|
||||
|
||||
🟡 **G-7 (MINOR — carry-over K3 F-3, mới vá NỬA):** `docs/STATUS.md:6` (văn xuôi CURRENT) đã sửa
|
||||
*"Policies **256** · Menu keys **64**"*, nhưng **2 row canonical** vẫn ở số S161: `:470` `| Policies | **220** |`
|
||||
và `:471` `| Menu keys | **55** |`. Đó lại **đúng nơi máy đọc**: `scripts/governance-detectors.ps1:175-181`
|
||||
`Get-StatusValue` khớp `^\|\s*<label>\s*\|\s*\*\*(\d+)`, `:202-208` map `'menu'→'Menu keys'`,
|
||||
`'policy'→'Policies'` ⇒ detector đang resolve canonical **55 / 220** trong khi văn xuôi nói 64 / 256 và máy
|
||||
(sau K4a) nói 113 / 452 — **ba nguồn, ba số**. Vá prose mà bỏ row = *fix áp NỬA spec* (bài S160).
|
||||
|
||||
## §7 VERDICT
|
||||
|
||||
**PASS-WITH-FLAGS — 7 finding (3 MAJOR / 4 MINOR), 0 blocker KỸ THUẬT trên 5 file F-1, 1 blocker QUY TRÌNH (G-6).**
|
||||
|
||||
Bản vá F-1 **làm đúng việc nó nhận**: sợi dây BE→FE nối bằng đúng 1 site (§1), mirror 2 app chứng bằng
|
||||
blob-SHA (§0), `actingLevel` mirror `ResolveActingLevel` đúng 6/7 ca gồm cả OR-of-N cờ-ở-người-khác và
|
||||
`currentLevels` rỗng (§2), body không rò field sang 3 action kia và hội tụ absent/null/true (§3), cấp
|
||||
thường **bất biến từng bit đường đi** (§4), ô-tích không rò sang phase khác nhờ 3 lớp chặn độc lập (§4).
|
||||
|
||||
| # | Mức | Một dòng | Địa chỉ |
|
||||
|---|---|---|---|
|
||||
| G-1 | MAJOR | default TICK ngược chiều PE-**live** (PE S97 = opt-IN); nhãn "khuôn PE S96" trích bản đã bị owner ĐẢO — cần owner ratify hoặc lật default | `KhkkWorkflowPanel.tsx:85` + `:15-18` ⟂ `PeWorkflowPanel.tsx:61` |
|
||||
| G-2 | MAJOR (carry-over K3) | phiếu kết-thúc-sớm ⇒ sơ đồ hiện Bước «Ban Giám đốc» ✓ "đã duyệt" dù CEO chưa đụng; PE đã giải bằng badge + làm mờ | `KhkkWorkflowPanel.tsx:100-114` + `:234` ⟂ `PeWorkflowPanel.tsx:441` `:161-170` |
|
||||
| G-6 | MAJOR (quy trình) | cây phình 5→7 file giữa lượt review; K4a (+121 dòng, `All` 64→113, policies →452) sẽ bị commit ké | `MenuKeys.cs:81-84` `:244` · `DbInitializer.cs` |
|
||||
| G-3 | MINOR | 0 test chạm `l.AllowApproverFinalize` trong projection — xoá 1 argument là ô-tích biến mất mà 614 test + tsc vẫn xanh | `ContractSigningPlanFeatures.cs:643` |
|
||||
| G-4 | MINOR | FE tự mirror `ResolveActingLevel` (PE để BE precompute); Admin-fallback so `First()` giữa **2 truy vấn** không khoá phụ — vô hại trên seed (cờ đồng nhất trong Cấp), hại khi Designer trộn cờ | `KhkkWorkflowPanel.tsx:135-136` ⟂ `Service:463-465` |
|
||||
| G-5 | MINOR | chữ "(CEO)" suy theo seed; cắm cờ ở Cấp cuối Bước cuối ⇒ bỏ tick vẫn `DaDuyet` ngay, ô-tích hứa sai; BE không có validator cấm | `KhkkWorkflowPanel.tsx:457` ⟂ `Service:320-329` |
|
||||
| G-7 | MINOR (carry-over K3 F-3) | STATUS mới vá văn xuôi, 2 row canonical detector đọc vẫn 55/220 | `docs/STATUS.md:470-471` |
|
||||
|
||||
**Khuyến nghị thứ tự:** (1) tách commit theo G-6 → (2) hỏi owner G-1 (1 câu: *"Chương bấm Duyệt mà không
|
||||
đọc thì mặc định KẾT THÚC hay LÊN CEO?"*) → (3) ship F-1 → (4) G-2/G-3 vào nhịp K4 → (5) G-7 kèm lần đụng STATUS kế.
|
||||
|
||||
END sub-reviewer-f1-checkbox — TOTAL: 7 finding (3 MAJOR / 4 MINOR) · 0 blocker kỹ-thuật · 1 blocker quy-trình (G-6) · verdict PASS-WITH-FLAGS
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,22 +1,71 @@
|
||||
REVIEWER-GATE-K3: IN-PROGRESS — 0 finding (đang chạy)
|
||||
REVIEWER-GATE-K3: PASS-WITH-FLAGS — 8 finding (3 MAJOR / 5 MINOR, 0 blocker build-test)
|
||||
|
||||
# Reviewer gate K3 — 8 workflow nhóm + port finalize + designer
|
||||
|
||||
Ghi-đĩa TRONG LÚC LÀM (chống #53). Dòng-1 sẽ được cập nhật khi có verdict.
|
||||
Ghi-đĩa TRONG LÚC LÀM (chống #53). Đo từ ĐĨA, HEAD `2967c43`, 25 file M / +908 −102; 2 untracked chỉ ở `.claude/auto-memory/`.
|
||||
|
||||
## 0. Trạng thái khởi động (đo từ đĩa)
|
||||
## §1 Build / test / npm — số NGUYÊN VĂN
|
||||
|
||||
- Branch `main`, HEAD `2967c43` (wal: flush 20260731T1743).
|
||||
- `git diff --stat`: 25 file M, +908 / -102.
|
||||
- Untracked: chỉ 2 file `.claude/auto-memory/*` (memory, không phải prod-code).
|
||||
- 0 file untracked trong `src/` hoặc `tests/` → **0 migration mới** (kiểm lại ở §4).
|
||||
| Phép | Lệnh | Kết quả nguyên văn |
|
||||
|---|---|---|
|
||||
| BE build | `dotnet build SolutionErp.slnx` | `Build succeeded.` · `0 Warning(s)` · `0 Error(s)` |
|
||||
| BE test #1 | `dotnet test SolutionErp.slnx` | 🔴 `Failed! - Failed: 1, Passed: 568, Skipped: 0, Total: 569 - SolutionErp.Infrastructure.Tests.dll` |
|
||||
| BE test #2 | `dotnet test SolutionErp.slnx` | `Passed! - Failed: 0, Passed: 45, Total: 45 - Domain.Tests` + `Passed! - Failed: 0, Passed: 569, Total: 569 - Infrastructure.Tests` ⇒ **614/0** |
|
||||
| BE test #3 | `--filter ~ContractSigningPlan` | `Passed! - Failed: 0, Passed: 34, Total: 34` |
|
||||
| npm fe-admin | `npm run build` | `✓ 1961 modules transformed` · `✓ built in 19.63s` · 0 TS error |
|
||||
| npm fe-user | `npm run build` | `✓ built in 7.81s` · 0 TS error |
|
||||
|
||||
## 1. Build / test (đang chạy)
|
||||
⇒ 614/0 = 45D+569I **khớp claim ở lượt #2/#3**; lượt #1 FAIL → F-4.
|
||||
|
||||
## 2. Code-vs-spec
|
||||
## §2 Code-vs-spec K3 (5 điểm)
|
||||
|
||||
## 3. Phán 3 điểm lead tự-quyết
|
||||
1. **Seed 8 wf khớp ROSTER §0** — `DbInitializer.cs:526-688`. 3 Steps (`Phòng Cung Ứng` / `P. Kiểm soát Chi phí` / `Ban Giám đốc`), 11 email `Distinct` khớp từng dòng bảng §0 `sub-implbe-k3.md`; Cấp 1 OR-4 / OR-4 / OR-1, Cấp 2 `tra.bui` / `chuong.phan`; `AllowApproverFinalize=true` **chỉ** ở `(CCM, Cấp 2, chuong.phan)` đặt PER-ROW; idempotent `AnyAsync(w.Code == code)`; UNGATED demo-seed. ✅
|
||||
2. **Finalize qua choke-point + 2-lệnh-grep LUẬT** — chạy CẢ HAI:
|
||||
- `Phase = ContractSigningPlanPhase.DaDuyet` → `:280`, `:322` (+ `:336` là dòng doc)
|
||||
- `ApplyApprovedValuesOnFinalize` → `:279`, `:321` (+ doc/def/comment)
|
||||
⇒ **cùng khớp**: 2 site gán DaDuyet ↔ 2 site gọi helper, helper đứng NGAY TRƯỚC gán ở cả hai. ✅
|
||||
3. **Rào (v)** — `ContractSigningPlanFeatures.cs:411-420`, regex `"^KHKK-N([1-8])$"` neo 2 đầu, khớp literal seeder `$"KHKK-N{n}"` n=1..8; so với `approvalGroup` (`:395` = `request.ApprovalGroup ?? Default`); code ngoài họ → cho qua. ✅
|
||||
4. **8 key VÀO All + DELTA (đếm MÁY)** — `MenuKeys.All` = **64** (HEAD `2967c43` = **56**) ⇒ **+8**; policies DERIVED = **256** (HEAD **224**) ⇒ **+32**. 8 menu-row `DbInitializer.cs:1980-1989` order 3..10 dưới `ApprovalWorkflowsV2`. ✅ mã — ❌ khai (F-3).
|
||||
5. **FE phép-âm `Khkk_` = 0-hit + control dương** — `git diff -U0 | grep -E "^\+.*Khkk_[A-Za-z]+: *'"` = **0**; control dương cùng regex trên cả `Layout.tsx` = **6** hit ⇒ mẫu CÓ RĂNG. Nhánh mới `Layout.tsx:181` `/^KhkkN[1-8]$/` nằm TRONG `awV2Match`, đặt SAU whitelist 3 code cũ. ✅
|
||||
|
||||
## 4. Ranh giới
|
||||
## §3 Phán 3 quyết-định lead
|
||||
|
||||
## 5. Test lane
|
||||
- **(i) GIỮ PUT-Conflict (spec vá-3 bảo gỡ) — LEAD ĐÚNG, spec vá-3 LIỆT NHẦM.** `UpdateAwDefinitionCommandHandler` (`:515-649`) **0 lần** tham chiếu `typeEnum`/`ContractSigningPlan`; grep 2 token toàn file cho hit ở `:97/:125/:126/:331/:341/:349/:387` — **tất cả** thuộc list/create, KHÔNG hit nào trong thân PUT. Guard `:598-603` (echo cờ) · `:612-617` (dòng mới) · `:627-632` (bỏ người giữ cờ) là **luật versioning CHUNG mọi ApplicableType**; gỡ = nới rào cho PE/Contract/Proposal = regression ngoài scope K3. Thêm: gỡ FE-lock (đúng) đã đủ để cờ seed `true` không đẻ 409 lúc PUT vì payload nay echo giá trị THẬT.
|
||||
- **(ii) GIỮ ép-false `AllowApproverSkipToFinal` type-10 (O-1) — LEAD ĐÚNG ở BE, nhưng sweep BẤT ĐỐI XỨNG (F-2).** Tự verify: token `AllowApproverSkipToFinal` trong `ContractSigningPlanWorkflowService.cs` = **1 hit duy nhất `:47`, và là COMMENT** ⇒ service **0 lần đọc cờ**; control dương: cùng token trong `PurchaseEvaluationWorkflowService.cs` = **3 hit** (code thật) ⇒ grep có răng. Echo cờ cho type-10 = đẻ config-lie #78 mới ⇒ giữ ép-false ĐÚNG.
|
||||
- **(iii) Seed cờ cùng-commit ≠ config-lie #78 — ĐÚNG, nhánh THẬT tồn tại.** `ContractSigningPlanWorkflowService.cs:276-289`: `if (actingLevel.AllowApproverFinalize && applyLevelFinalize)` → `EndedByLevelFinalize=true` → `ApplyApprovedValuesOnFinalize(plan)` → `Phase=DaDuyet` → xoá 2 con-trỏ → log → `return`. Cờ seed CÓ máy tiêu thụ trong cùng diff. ✅ *(nhưng đường ĐI NGƯỢC — bỏ tick để trình CEO — chết ở tầng UI: F-1)*
|
||||
|
||||
## §4 Ranh giới
|
||||
|
||||
- `ReturnOrRejectAsync` (`:354+`), `ApplyApprovedValuesOnFinalize` (`:345-349`), nhánh advance thường (`:293-329`): `git diff -U0` trên service chỉ **5 hunk** = `@@-37,10` (comment) · `@@-89,0` (thêm param) · `@@-124` (truyền param) · `@@-245` (chữ ký private) · `@@-266,0 +270,21` (khối finalize MỚI) ⇒ **0 dòng nội-dung đổi** trong 3 vùng trên. ✅
|
||||
- Submit-guard K2 / file K1: không có trong `git diff --name-only`. ✅
|
||||
- **0 migration mới**: `git diff --name-only | grep -i migration` = **0**; `git status --porcelain -- src tests | grep '^??'` = **rỗng**. ✅
|
||||
- Route/menu-row NGOÀI 8 `AwV2_KhkkN*`: DbInitializer thêm đúng 8 row; Layout thêm đúng 1 nhánh regex họ `AwV2_`. ✅
|
||||
- Rào (v) chỉ ở CREATE — `UpdateContractSigningPlanCommandHandler` không chạm `ApprovalWorkflowId`/`ApprovalGroup` (0 hit trong thân) ⇒ không có lỗ update-lách. ✅
|
||||
|
||||
## §5 Test lane (mở ruột 2 test)
|
||||
|
||||
- **T-a `ApproveV2_CapMangCoKetThuc_ChotPhieuNgay_KhongTrinhTiepBuocSau`** (`ContractSigningPlanApprovalTests.cs:944-994`): đo hành-vi THẬT qua service. Sanity 3 vế TRƯỚC (`ShouldBeAt(ChoDuyet,1,2)` · `EndedByLevelFinalize=false` · `StepCountAsync == 3` kèm lý-do *"Cấp mang cờ KHÔNG được là cấp cuối — nếu là cấp cuối thì phiếu kết thúc ở CẢ HAI thế giới và test này xanh mà không chứng minh gì"* = **anti-tautology guard**). Đo SAU 5 trục: phase + 2 con-trỏ · cờ runtime · `ApprovedAmount` 3 dòng gồm ca `??=` giữ 300 · opinion signer. Kèm **chứng-nhân song sinh** `WitnessAtFlagLevel` bất động (cả cờ lẫn giá). ✅
|
||||
- **T-e `CreateAwDefinition_LoaiKhkk_GiuNguyenCoKetThucTaiCap_KhongConEpFalse`** (`:1079-1104`): 3 vế — (i) tick ⇒ `true`; (ii) không tick ⇒ `false` (chặn "bật bừa"); (iii) **đối-chứng type khác** `DuyetNcc` cũng `true` ⇒ phân biệt "gỡ ép-false" với "đổi thành ép-true". Đi qua `CreateAwDefinitionCommandHandler` THẬT. ✅
|
||||
- **0 đè test cũ**: `git diff -- tests/ | grep -c '^-[^-]'` = **2**, cả 2 là cùng một sửa cơ-học `TransitionAsync(..., CancellationToken.None)` → `(..., ct: CancellationToken.None)` (named-arg vì thêm param) — **không** nới assert nào.
|
||||
|
||||
## §6 FINDING (8)
|
||||
|
||||
**MAJOR**
|
||||
|
||||
- **F-1** `fe-{user,admin}/src/pages/khkk/KhkkWorkflowPanel.tsx:136-142` — **opt-out `applyLevelFinalize` KHÔNG có tầng UI ⇒ trạm CEO chết ở 8/8 workflow seed.** Body POST là **literal đúng 2 field** `{action, comment}`; `grep applyLevelFinalize fe-*/src` = **0 hit** ở KHKK. Controller `ContractSigningPlansController.cs:213` `?? true` ⇒ mọi lượt Chương bấm "Duyệt" đều finalize. Seeder cắm cờ cho `chuong.phan` ở **cả 8** workflow ⇒ Step 3 «Ban Giám đốc» (`truong.nguyen`) **không đường nào tới**. **Đối-chứng chứng minh đây KHÔNG phải khuôn PE**: `fe-*/src/components/pe/PeWorkflowPanel.tsx:63` = `useState(false)` + `:259` LUÔN gửi tường minh ⇒ PE mặc-định **KHÔNG** kết-thúc-sớm (opt-in tại UI); KHKK mặc-định **LUÔN** kết-thúc-sớm. Lời owner OG-3/OG-9 (*"a Chương sẽ quyết định là cái đó cần CEO ko"*) **không thực thi được từ UI**. Kèm: comment `KhkkWorkflowPanel.tsx:15-17` khẳng định *"không có gì để panel render thêm"* — tiền-đề SAI, chính wave này vừa đẻ tham số để người duyệt quyết. Acceptance: thêm ô tick opt-out ở panel (mirror `PeWorkflowPanel.tsx:778`), HOẶC khai tường minh lên HANDOFF rằng "trình CEO" hiện chỉ làm được bằng admin bỏ cờ ở Designer.
|
||||
- **F-2** `ApprovalWorkflowV2AdminFeatures.cs:387` ⟂ `fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx:263` + `:1300-1310` — **sweep ép-false bất-đối-xứng ⇒ tick bị NUỐT IM LẶNG.** FE gỡ khoá **cả 2** ô (gồm `allowApproverSkipToFinal`), BE **giữ** ép-false `SkipToFinal` cho type-10. Admin tick "Cho phép duyệt thẳng Cấp cuối" trên quy trình KHKK → CREATE lưu `false`, UI không báo gì. Đây đúng class mà comment vừa bị xoá đã cảnh báo (*"màn hình nói một đằng dữ liệu một nẻo"*), chỉ đảo chiều. **0 test phủ** (T-e chỉ đo `Finalize`). Acceptance: giữ `disabled` riêng ô SkipToFinal cho type-10, HOẶC bỏ ép-false BE + port nhánh.
|
||||
- **F-3** `docs/STATUS.md:6` — **DELTA đo được nhưng chưa khai.** Máy: `All` 56→**64** (+8); policies 224→**256** (+32); STATUS vẫn ghi "Policies **224** · Menu keys **56**". Spec cụm-1 vá-1 bắt "mỗi commit kèm lệnh đếm lại + cập nhật 2 row STATUS". **Tái phát y hệt** finding ④ của gate K1 cùng phiên.
|
||||
|
||||
**MINOR / khai-thật**
|
||||
|
||||
- **F-4** Suite **flake 1/3 lượt**: `dotnet test SolutionErp.slnx` lượt #1 `Failed: 1, Passed: 568` — `ContractSigningPlanCrudTests.DeleteContractSigningPlan_SoftDeletes_KeepsChangelog_ThenCreateAgainSucceeds` chết ở `KhkkFixture..ctor()` `:62` `EnsureCreated()` → `CallSiteRuntimeResolver`. Fixture có từ W2 ⇒ **không phải K3 đẻ**, nhưng câu "614/0 tươi" chỉ đúng 2/3 lượt — đừng khai trần.
|
||||
- **F-5** `DbInitializer.cs:665` — seeder idempotent per-Code **thuần skip, 0 nhánh UPDATE**: roster đổi (người nghỉ / đổi phòng) ⇒ phải UPDATE tay trên prod. Cùng lớp seeder SP-002 ở K1.
|
||||
- **F-6** `DbInitializer.cs:637-640` — `Description` khai *"Admin có thể chỉnh người/quyền tại chỗ hoặc tạo version mới"*: nửa sau đúng, nửa đầu **sai với cờ finalize** — `ApprovalWorkflowV2AdminFeatures.cs:598-600` chặn đổi cờ, `:627-629` chặn bỏ người giữ cờ khi sửa tại chỗ. Chuỗi này hiển thị ra UI admin.
|
||||
- **F-7** `ContractSigningPlan.cs:51` + `fe-*/src/types/khkk.ts:260` — `EndedByLevelFinalize` **được GHI nhưng chưa expose DTO** (chính FE type tự khai). Test T-a lý-giải *"FE/GĐ3 đọc cột này"* — hiện **chưa** ai đọc; ghost-window đã-khai, không phải bug, nhưng câu biện-minh mạnh hơn sự thật.
|
||||
- **F-8** `ContractSigningPlanWorkflowService.cs:37-42` + `:335-337` — 2 lệnh grep tự-kiểm in ra **gồm cả chính dòng `///` doc** (`:336`, `:337`) ⇒ người chạy sau đếm 3 vs 5 rồi tưởng lệch. Nên nêu rõ "bỏ dòng `///` khi đếm".
|
||||
|
||||
## §7 Verdict
|
||||
|
||||
**PASS-WITH-FLAGS** — build 0W/0E · suite 614/0 (lượt tươi) · npm ×2 sạch; 5/5 điểm code-vs-spec khớp; 3/3 quyết-định lead ĐÚNG về kỹ-thuật; ranh giới sạch (0 mig, 0 đổi hành-vi vùng cấm, 0 route ngoài họ). **0 blocker kỹ-thuật**, nhưng **F-1 + F-2 là nợ HÀNH-VI**: F-1 làm mất đúng cái quyền quyết mà owner vừa chốt (OG-3/OG-9); F-2 tái tạo class "UI nói một đằng DB một nẻo" ở ô còn lại. F-3 là acceptance chưa đóng. Owner/lead quyết ship-rồi-vá hay vá-trước-ship.
|
||||
|
||||
END sub-reviewer-gate-k3 — TOTAL: 8 finding (3 MAJOR / 5 MINOR) · 0 blocker build-test · verdict PASS-WITH-FLAGS
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
TEST-K4A: IN-PROGRESS
|
||||
|
||||
# Lane test K4a — test-after 49 row menu KHKK 8-nhóm (S166, 2026-08-01)
|
||||
|
||||
Agent: test-specialist. Ghi-từng-mục TRONG LÚC LÀM (luật sống-còn bài K3 engine-exit).
|
||||
Mục nào chưa chạy = ghi tiêu-đề + "CHƯA ĐO", KHÔNG điền số dự-đoán.
|
||||
|
||||
## §0 — Trạng thái khởi động
|
||||
|
||||
- [x] §0.1 ĐÃ đọc khuôn. Chốt harness: seeder là `private static` → REFLECTION.
|
||||
- `SeedMenuTreeAsync(ApplicationDbContext, ILogger)` — 2 tham số.
|
||||
- `SeedAllRolesReviewReadPermissionsAsync(ApplicationDbContext, RoleManager<Role>, ILogger)` — 3 tham số (site-2).
|
||||
- Khuôn invoke đã có sẵn ở `ContractCatalogTests.cs:459` (`InvokePrivateSeedAsync`, rm nullable) →
|
||||
dùng lại HÌNH, không chế fixture mới. Fixture = `IdentityFixture` (cần RoleManager cho site-2).
|
||||
- [x] §0.2 ĐÃ đọc BE đã land (git diff, chưa commit):
|
||||
- `MenuKeys.cs:72-84` — `KhkkGroupNumbers=[2..8]` · `KhkkLeafActions=[WfView,List,Create,Pending,Approved,Deleted]`
|
||||
· `KhkkGroupMenuKeys` = SelectMany(group → 6 leaf) · spread `.. KhkkGroupMenuKeys` vào `All:244`.
|
||||
- `DbInitializer.cs:2115-2157` — vòng seed 49 row menu (parent `KeHoachKyKet`, Order nhóm = n,
|
||||
leaf Order 1..6) + `:2235` labelBackfill `Khkk_G1` + `:2442-2446` site-2 `KhkkKeys().Concat(KhkkGroupMenuKeys)`.
|
||||
- Đếm BY-SOURCE `All` = 113 (tự cộng tay từng dòng initializer). **Chưa phải số ĐO** — sẽ đo runtime ở T1.
|
||||
- [x] §0.3 CHỒNG LẤN ĐÃ CÓ (không viết lại): `ContractCatalogTests.cs:445` T6 K1 assert
|
||||
`MenuKeys.All.Except(menuKeysInDb).Should().BeEmpty()` sau `SeedMenuTreeAsync` ⇒ invariant
|
||||
"49 key mới ĐỀU có menu-row" ĐÃ được test cũ phủ tự động (nó là phép thử của claim by-construction).
|
||||
Lane K4a KHÔNG nhân bản; thay vào đó đo cái test cũ KHÔNG đo: hình bộ sinh · đếm 56 row họ Khkk ·
|
||||
idempotent ×2 · labelBackfill · grant site-2.
|
||||
- [ ] §0.4 Baseline suite Infra đo TƯƠI — ĐANG CHẠY (nền), chưa có số
|
||||
|
||||
## §1 — Test bộ sinh đúng hình — CHƯA VIẾT
|
||||
## §2 — Test seed idempotent x2 — CHƯA VIẾT
|
||||
## §3 — Test labelBackfill đổi-label-không-nhân-row — CHƯA VIẾT
|
||||
## §4 — Test grant site-2 phủ leaf mới — CHƯA VIẾT
|
||||
## §5 — Kết quả chạy filtered — CHƯA ĐO
|
||||
## §6 — Kết quả full Infra — CHƯA ĐO
|
||||
@ -0,0 +1,156 @@
|
||||
|
||||
===== C2/B3 - canonical resolve + disk cross-check =====
|
||||
STATUS.md canonical: mig=69 test=590 gotcha=85 table=96 menu=55 policy=220
|
||||
disk cross-check: mig=71 gotcha=85
|
||||
[DETECTOR] HIGH | docs/STATUS.md | canonical-itself-stale: STATUS Migrations=**69** but disk has 71 migration .cs | resolve: re-ground STATUS.md Migrations row to 71
|
||||
|
||||
===== C2/B3 - derived-doc staleness =====
|
||||
[DETECTOR] LOW | CLAUDE.md:94 | derived-stale: writes 6 test but canonical=590 | resolve: update to 590 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/contract-workflow/SKILL.md:24 | derived-stale: writes 3 table/bang but canonical=96 | resolve: update to 96 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/contract-workflow/SKILL.md:35 | derived-stale: writes 6 test but canonical=590 | resolve: update to 590 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/contract-workflow/SKILL.md:332 | derived-stale: writes 6 test but canonical=590 | resolve: update to 590 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/contract-workflow/SKILL.md:332 | derived-stale: writes 6 test but canonical=590 | resolve: update to 590 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/contract-workflow/SKILL.md:367 | derived-stale: writes 77 test but canonical=590 | resolve: update to 590 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] MED | .claude/skills/ef-core-migration/SKILL.md:93 | derived-stale: writes 97 table/bang but canonical=96 | resolve: update to 96 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:93 | derived-stale: writes 1 table/bang but canonical=96 | resolve: update to 96 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:93 | derived-stale: writes 7 table/bang but canonical=96 | resolve: update to 96 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:102 | derived-stale: writes 2 migration but canonical=69 | resolve: update to 69 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:103 | derived-stale: writes 1 migration but canonical=69 | resolve: update to 69 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:119 | derived-stale: writes 3 table/bang but canonical=96 | resolve: update to 96 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:122 | derived-stale: writes 1 table/bang but canonical=96 | resolve: update to 96 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:170 | derived-stale: writes 1 migration but canonical=69 | resolve: update to 69 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:187 | derived-stale: writes 1 migration but canonical=69 | resolve: update to 69 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/permission-matrix/SKILL.md:60 | derived-stale: writes 4 policy but canonical=220 | resolve: update to 220 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/permission-matrix/SKILL.md:80 | derived-stale: writes 0 menu but canonical=55 | resolve: update to 55 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/skills/permission-matrix/SKILL.md:80 | derived-stale: writes 0 policy but canonical=220 | resolve: update to 220 OR replace with pointer '-> docs/STATUS.md'
|
||||
[DETECTOR] LOW | .claude/commands/session-end.md:253 | derived-stale: writes 2 test but canonical=590 | resolve: update to 590 OR replace with pointer '-> docs/STATUS.md'
|
||||
(note: count-token grep is a soft net - module-local phrases like "4 bang Budget" / "71 test (Phase 8)" can false-positive; H18-A ratio-band demotes far-from-canonical counts to LOW = review-not-fail, near-canonical stale-totals stay MED)
|
||||
|
||||
===== C1 - broken gotcha-ref =====
|
||||
[DETECTOR] MED | docs/changelog/sessions/2026-07-25-1930-S151-bootstrap-trio-auto-fixes.md:25 | broken-gotcha-ref: cites #91 but max gotcha is 85 | resolve: fix the number or add the gotcha to docs/gotchas.md
|
||||
|
||||
===== C1 - dangling wikilink =====
|
||||
[DETECTOR] LOW | user-memory/feedback_7agent_split_upgrade.md:70 | dangling-wikilink: [[feedback-multi-agent-setup]] -> feedback-multi-agent-setup.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_h18_ghostwire_stamp_integrity.md:18 | dangling-wikilink: [[faultinjection-proves-teeth]] -> faultinjection-proves-teeth.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_h18_ghostwire_stamp_integrity.md:18 | dangling-wikilink: [[canonical-spec-over-broadcast]] -> canonical-spec-over-broadcast.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_h18_ghostwire_stamp_integrity.md:18 | dangling-wikilink: [[agent-return-garble-recover]] -> agent-return-garble-recover.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_implementer_truncation_mitigation.md:81 | dangling-wikilink: [[feedback-per-chunk-commit]] -> feedback-per-chunk-commit.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_implementer_truncation_mitigation.md:81 | dangling-wikilink: [[feedback-multi-agent-setup]] -> feedback-multi-agent-setup.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_implementer_truncation_mitigation.md:81 | dangling-wikilink: [[feedback-rag-hybrid-pattern]] -> feedback-rag-hybrid-pattern.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_phase10_namgroup_port.md:72 | dangling-wikilink: [[feedback-rag-distributed-ownership]] -> feedback-rag-distributed-ownership.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_phase10_namgroup_port.md:72 | dangling-wikilink: [[feedback-multi-agent-setup]] -> feedback-multi-agent-setup.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_rag_mcp_recovery_concurrency.md:21 | dangling-wikilink: [[status-handoff-tiering]] -> status-handoff-tiering.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_rag_mcp_recovery_concurrency.md:21 | dangling-wikilink: [[aiinfra-charter-v2]] -> aiinfra-charter-v2.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_resume_premise_reverify.md:19 | dangling-wikilink: [[agent-kill-recovery]] -> agent-kill-recovery.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_resume_premise_reverify.md:19 | dangling-wikilink: [[prod-config-inspect-before-change]] -> prod-config-inspect-before-change.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_resume_premise_reverify.md:19 | dangling-wikilink: [[stale-diagnostic-background-agent]] -> stale-diagnostic-background-agent.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/feedback_status_handoff_tiering.md:18 | dangling-wikilink: [[implementer-truncation-mitigation]] -> implementer-truncation-mitigation.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/project_h22_wal_session_continuity.md:20 | dangling-wikilink: [[h18-ghostwire-stamp-integrity]] -> h18-ghostwire-stamp-integrity.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | user-memory/project_h22_wal_session_continuity.md:20 | dangling-wikilink: [[workflow-fanout-reliability]] -> workflow-fanout-reliability.md not found in user-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | agent-memory/MEMORY.md:32 | dangling-wikilink: [[feedback_agent_return_garble_recover]] -> feedback_agent_return_garble_recover.md not found in agent-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | agent-memory/feedback_machine_blind_classes.md:19 | dangling-wikilink: [[ctx-curator-run-log]] -> ctx-curator-run-log.md not found in agent-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | agent-memory/pattern_master_page_mirror.md:38 | dangling-wikilink: [[pattern-fe-mirror-2-app]] -> pattern-fe-mirror-2-app.md not found in agent-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | agent-memory/pattern_master_page_mirror.md:38 | dangling-wikilink: [[pattern-readonly-admin-mirror]] -> pattern-readonly-admin-mirror.md not found in agent-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | agent-memory/project_s103_h20_crystallized_backfill_review.md:30 | dangling-wikilink: [[wire-claim-verification-anchors]] -> wire-claim-verification-anchors.md not found in agent-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | agent-memory/project_s92_admin_only_modules_revoke.md:31 | dangling-wikilink: [[s89-pe-sectionb-review]] -> s89-pe-sectionb-review.md not found in agent-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | agent-memory/2026-06.gist.md:33 | dangling-wikilink: [[feedback_agent_kill_recovery]] -> feedback_agent_kill_recovery.md not found in agent-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
[DETECTOR] LOW | agent-memory/2026-06.gist.md:34 | dangling-wikilink: [[feedback_harness10_run_trace]] -> feedback_harness10_run_trace.md not found in agent-memory | resolve: fix the link target or create the file (note: hyphen vs underscore basename fork is common)
|
||||
|
||||
===== C3 - vocab-fork =====
|
||||
[DETECTOR] MED | multiple files | vocab-fork: wave-folder=19f vs run-trace=70f live side-by-side -- 'wave-folder' in [docs/changelog/sessions/2026-06-07-S49-harness-1-2-3-adopt.md, docs/changelog/sessions/2026-06-07-S50-harness-verified-runtime.md] | 'run-trace' in [docs/HANDOFF.md, docs/STATUS.md] | resolve: merge to ONE canonical term, or record an alias-map in docs/governance
|
||||
[DETECTOR] MED | multiple files | vocab-fork: D? tr<74> PRO=9f vs Ng<4E>n s<>ch PRO=7f live side-by-side -- 'D? tr<74> PRO' in [docs/changelog/sessions/2026-06-12-S60-S62-pe-budget-workitem-softwarning.md, docs/changelog/sessions/2026-06-16-S65-hrm-golive-employee-masterdetail-pe-link.md] | 'Ng<4E>n s<>ch PRO' in [docs/changelog/sessions/2026-06-16-S65-hrm-golive-employee-masterdetail-pe-link.md, docs/_archive/STATUS-HANDOFF-tier-S94-2026-06-29.md] | resolve: merge to ONE canonical term, or record an alias-map in docs/governance
|
||||
[DETECTOR] MED | multiple files | vocab-fork: two-tier=23f vs all-inherit=41f vs worker-tier-pin=22f live side-by-side -- 'two-tier' in [docs/STATUS.md, docs/changelog/sessions/2026-06-16-S66-closeout-harness8-cicd-curate.md] | 'all-inherit' in [docs/HANDOFF.md, docs/STATUS.md] | 'worker-tier-pin' in [docs/HANDOFF.md, docs/STATUS.md] | resolve: merge to ONE canonical term, or record an alias-map in docs/governance
|
||||
|
||||
===== C5 - WAL guardrail (H22) =====
|
||||
[DETECTOR] MED | .claude/WAL.md | wal-overflow: 41 lines > 40-line hard cap (H22 N.1 overwrite-not-append) | resolve: trim WAL to <= 40 lines: move long notes to run-folder/work-state; keep chain+next+verify only
|
||||
|
||||
===== H24-1 - title-freshness =====
|
||||
anchors parsed: 2 doc(s) ; moc-phai (newest governance milestone) = 2026-05-12 from docs/rag-setup-plan.md:4
|
||||
anchor 2026-05-12 docs/rag-setup-plan.md:4
|
||||
anchor 2026-04-30 .claude/skills/form-engine/SKILL.md:15
|
||||
[DETECTOR] LOW | .claude/skills/form-engine/SKILL.md:15 | title-stale: anchor says 2026-04-30 but newest governance milestone is 2026-05-12 (12d behind) | resolve: refresh the title/status anchor date, or state explicitly that the doc is frozen-historical
|
||||
|
||||
===== H24-3 - session-label lag =====
|
||||
[skip] no doc carries BOTH a session label and an S-heading - nothing to compare
|
||||
|
||||
===== H24-2 - carry-age (INFORM-only) =====
|
||||
config resolved: .claude/agent-memory/memory-budget.json
|
||||
M = h24_cadence.light_every = 6 (read from config, not hardcoded)
|
||||
HANDOFF logic-segments (NEXT anh/em) = 25 ; of those, carry-lines = 18
|
||||
[ok] carry 'ctx-t9-dogfood' streak=2 < M=6
|
||||
[ok] carry 'ring5-audit-gap' streak=1 < M=6
|
||||
[ok] carry 'hmw-width-vs-roster' streak=1 < M=6
|
||||
[ok] carry 'hmw-subfile-index-collision' streak=1 < M=6
|
||||
[ok] carry 'adap-apply-2-thu' streak=3 < M=6
|
||||
|
||||
===== H25-closeout-ritual (GAP-2) =====
|
||||
closeouts found: 31 in 27 close-group(s) ; scoring 3 most-recent group(s) (label-folded union-window per group)
|
||||
[ok] e5123ff S162: union (1d3d167..e5123ff] has all 4 ritual books
|
||||
[ok] 1d3d167 S159-S160: union (33e7f68..1d3d167] has all 4 ritual books
|
||||
[ok] 33e7f68 S158: union (871ac0a..33e7f68] has all 4 ritual books
|
||||
|
||||
===== H25-role-notebook (GAP-3) =====
|
||||
roster=23 ; diaries-ok=23 ; flagged=0 ; inert(defined-not-run)=0
|
||||
UNMAPPED sub-file prefixes (206) [INFORM, not flagged - measure content not name, S122]:
|
||||
apply-L1, apply-L2, apply-L3, apply-L4, apply-L5-evalcuaeval, apply-L6, cicd-verify-k1, cicd-verify-k2, cicd-verify-k3, ctx-audit-close-S158, ctx-audit-close-S162, ctx-audit-open-S154, ctx-audit-open-S159, ctx-audit-open-S163, d2-be, d2-fe, d2-test, fable-invest-S153, frontend-designer-dot4, frontend-designer-tongquan, h24-audit-S146, h24-audit-S149, harvest, harvest-close-S152, harvest-curator-close-S153, harvest-curator-close-S158, harvest-curator-close-S162, harvest-curator-open-S154, harvest-curator-open-S159, harvest-curator-open-S163, harvest-curator-S153, harvest-S150, harvest-S151, harvest-S152, implbe-k1, implbe-k2, implbe-k3, implbe-k4a, implement-A-c7, implement-CE-sessionmodel, implement-D-5vong, implfe-k1, implfe-k2, implfe-k3, impl-M1-scaffold, impl-M2-tick, impl-M3-signal, impl-M4-c11, impl-M5-sentinel, impl-runsreadme, impl-sleepcmd, invest-1-vong-def, invest-2-vong-nhip, invest-3-vong-2lo, invest-4-se-do-A, invest-5-se-do-B, invest-6-thu-bind, invest-8-thu-bind, invest-A, invest-B, invest-backlog, invest-bch, invest-be, invest-C, invest-codebase-A-mapping, invest-codebase-B-approach, invest-codebase-C-edge, invest-day, invest-fable-b1a, invest-fable-b2-cum1, invest-fable-b2-cum2, invest-fable-b2-cum3, invest-fe, invest-hoi-tu, investigator-2-spec-draft, investigator-codebase-A, investigator-codebase-B, investigator-codebase-C, investigator-codebase-D, investigator-codebase-E, invest-kehoach, invest-menu, invest-owner-gated, invest-wfver, lead-gap-close-S152, lead-gap-close-S153, lead-gap-close-S158, lead-gap-close-S162, lead-gap-deep-S151, lead-gap-open-S154, lead-gap-open-S159, lead-gap-open-S163, lead-gap-S150, lead-gap-S151, lead-gap-S152, lead-gap-S153, lead-omission, lead-omission-auditor, lead-omission-S146, lead-stale-close-S152, lead-stale-close-S153, lead-stale-close-S158, lead-stale-close-S162, lead-stale-deep-S151, lead-stale-open-S154, lead-stale-open-S159, lead-stale-open-S163, lead-stale-S150, lead-stale-S151, lead-stale-S152, lead-stale-S153, lead-view, lead-view-auditor, lead-view-S146, review-claims, reviewer-1-verdict, reviewer-3-verdict, reviewer-5vong-closure, reviewer-anchor-A-s160, reviewer-anchor-B-s160, reviewer-anchor-C-s160, reviewer-axisE, reviewer-bulk, reviewer-c1-l1, reviewer-c1-l2, reviewer-c1-l3, reviewer-c2-l1, reviewer-c2-l2, reviewer-c2-l3, reviewer-c3-l1, reviewer-c3-l2, reviewer-c3-l3, reviewer-c7, reviewer-chot-cuoi-s160, reviewer-clone-l1-b1b, reviewer-clone-l2-b1b, reviewer-clone-l3-b1b, reviewer-diff-dot4, reviewer-diff-dot5, reviewer-diff-tongquan, reviewer-f1-checkbox, reviewer-fable-spec, reviewer-gate-k1, reviewer-gate-k2, reviewer-gate-k3, reviewer-hoi-tu, reviewer-precommit-s146, reviewer-R2, reviewer-R3, reviewer-security-s160, reviewer-session-model, reviewer-wave-logic-s160, review-fable-b3, review-fidelity, review-gaps, review-gate, review-q2, review-r1, review-r2, review-r3, review-schema, review-verdict, review-wave, ring1-audit-close-S162, ring1-audit-open-S159, ring1-audit-open-S163, ring1-close-S152, ring1-close-S153, ring1-close-S158, ring1-open-S154, ring1-S150, ring1-S151, ring1-S152, ring1-S153, ring2-audit-close-S162, ring2-audit-open-S159, ring2-audit-open-S163, ring2-close-S152, ring2-close-S153, ring2-close-S158, ring2-deep-S151, ring2-open-S154, ring2-S150, ring2-S151, ring2-S152, ring2-S153, ring4-close-S152, task, test-k1, test-k2, test-k3, tooling, tooling-auditor-close-S153, tooling-auditor-close-S158, tooling-auditor-close-S162, tooling-auditor-open-S154, tooling-auditor-open-S159, tooling-auditor-open-S163, tooling-auditor-S153, tooling-close-S152, tooling-S150, tooling-S151, tooling-S152, w1-task, w2-task, w3-task
|
||||
|
||||
===== C6 - cite-2-tier (INFORM-only) =====
|
||||
C6 scanned 52 file(s) (governance-top + commands + agents; adap-reports excluded)
|
||||
C6 cite-2-tier flags = 0 [INFORM-only, LOW, NOT folded into TOTAL baseline]
|
||||
|
||||
===== H24-4 - pending-flip (INFORM-only) =====
|
||||
HANDOFF current-segment = lines 1..117 (boundary '**Prev S' at line 118)
|
||||
H24-4 pending-flip flags = 0 [INFORM-only, LOW, NOT folded; 0 = designed first-run]
|
||||
|
||||
===== H24-5 - counter-ancestor-classify (INFORM-only) =====
|
||||
[OK] OK-reachable: last_ticked_head 24ea71e2 (session S166) is an ancestor of HEAD
|
||||
[ok] counter=40 >= last_audit.light_at_counter=36
|
||||
[ok] counter=40 >= last_audit.deep_at_counter=25
|
||||
H24-5 counter-ancestor flags = 0 [INFORM-only, LOW, NOT folded into TOTAL baseline]
|
||||
|
||||
===== C9 - hmw WIDTH mirror-drift (INFORM-only) =====
|
||||
[ok] WIDTH mirror 20 == canonical hmw_width.cap 20
|
||||
C9 width-drift flags = 0 [INFORM-only, LOW, NOT folded into TOTAL baseline]
|
||||
|
||||
===== C10 - logic-session folder (INFORM-only) =====
|
||||
[ok] session-9 is OPEN (no _end/closed.md)
|
||||
C10 logic-session flags = 0 [INFORM-only, LOW, NOT folded into TOTAL baseline]
|
||||
|
||||
===== C11 - H24 FLAG-khuon + diary-delta (INFORM-only) =====
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-25-S151-h24-open-bookend/sub-lead-gap-S151.md:17 | H24 FLAG-khuon: sub-file raises FLAG-<n> but has NO conforming class-tag line "## FLAG-<n> [em-dash] `<view-/gap-...>` [em-dash] SEV" - the by-class tally cannot count an untagged flag (S148 lost 2/9 flags exactly this way) | resolve: tag EACH raised flag on its own line "## FLAG-<n> [em-dash=U+2014] `<class>` [em-dash] SEV" (class in view-*/gap-*); one conforming line un-flags the file
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-25-S151-h24-open-bookend/sub-lead-stale-deep-S151.md:20 | H24 FLAG-khuon: sub-file raises FLAG-<n> but has NO conforming class-tag line "## FLAG-<n> [em-dash] `<view-/gap-...>` [em-dash] SEV" - the by-class tally cannot count an untagged flag (S148 lost 2/9 flags exactly this way) | resolve: tag EACH raised flag on its own line "## FLAG-<n> [em-dash=U+2014] `<class>` [em-dash] SEV" (class in view-*/gap-*); one conforming line un-flags the file
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-25-S151-h24-open-bookend/sub-lead-stale-S151.md:11 | H24 FLAG-khuon: sub-file raises FLAG-<n> but has NO conforming class-tag line "## FLAG-<n> [em-dash] `<view-/gap-...>` [em-dash] SEV" - the by-class tally cannot count an untagged flag (S148 lost 2/9 flags exactly this way) | resolve: tag EACH raised flag on its own line "## FLAG-<n> [em-dash=U+2014] `<class>` [em-dash] SEV" (class in view-*/gap-*); one conforming line un-flags the file
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-25-S152-h24-open-bookend/sub-lead-stale-close-S152.md:11 | H24 FLAG-khuon: sub-file raises FLAG-<n> but has NO conforming class-tag line "## FLAG-<n> [em-dash] `<view-/gap-...>` [em-dash] SEV" - the by-class tally cannot count an untagged flag (S148 lost 2/9 flags exactly this way) | resolve: tag EACH raised flag on its own line "## FLAG-<n> [em-dash=U+2014] `<class>` [em-dash] SEV" (class in view-*/gap-*); one conforming line un-flags the file
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-29-S159-bookend-open/sub-ring2-audit-open-S159.md:41 | H24 FLAG-khuon: sub-file raises FLAG-<n> but has NO conforming class-tag line "## FLAG-<n> [em-dash] `<view-/gap-...>` [em-dash] SEV" - the by-class tally cannot count an untagged flag (S148 lost 2/9 flags exactly this way) | resolve: tag EACH raised flag on its own line "## FLAG-<n> [em-dash=U+2014] `<class>` [em-dash] SEV" (class in view-*/gap-*); one conforming line un-flags the file
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-30-S162-bookend-close/sub-ring2-audit-close-S162.md:18 | H24 FLAG-khuon: sub-file raises FLAG-<n> but has NO conforming class-tag line "## FLAG-<n> [em-dash] `<view-/gap-...>` [em-dash] SEV" - the by-class tally cannot count an untagged flag (S148 lost 2/9 flags exactly this way) | resolve: tag EACH raised flag on its own line "## FLAG-<n> [em-dash=U+2014] `<class>` [em-dash] SEV" (class in view-*/gap-*); one conforming line un-flags the file
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-30-S163-bookend-open/sub-ctx-audit-open-S163.md | diary-0-delta (GAP-3): role 'ctx-audit' produced an artifact (mtime 2026-07-30T17:32) but its diary has no newer commit (diary last commit 2026-07-30T15:13) - role ran, memory not seeded (spec M9) | resolve: lead APPEND agent-memory/ctx-audit/ on-behalf IN THE SAME session (khuon B3) and commit, so next session does not enter blind
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-30-S163-bookend-open/sub-ring1-audit-open-S163.md | diary-0-delta (GAP-3): role 'ring1-audit' produced an artifact (mtime 2026-07-30T16:34) but its diary has no newer commit (diary last commit 2026-07-30T15:13) - role ran, memory not seeded (spec M9) | resolve: lead APPEND agent-memory/ring1-audit/ on-behalf IN THE SAME session (khuon B3) and commit, so next session does not enter blind
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-30-S163-bookend-open/sub-ring2-audit-open-S163.md:39 | H24 FLAG-khuon: sub-file raises FLAG-<n> but has NO conforming class-tag line "## FLAG-<n> [em-dash] `<view-/gap-...>` [em-dash] SEV" - the by-class tally cannot count an untagged flag (S148 lost 2/9 flags exactly this way) | resolve: tag EACH raised flag on its own line "## FLAG-<n> [em-dash=U+2014] `<class>` [em-dash] SEV" (class in view-*/gap-*); one conforming line un-flags the file
|
||||
[DETECTOR] LOW | .claude/workflows/runs/2026-07-30-S163-bookend-open/sub-ring2-audit-open-S163.md | diary-0-delta (GAP-3): role 'ring2-audit' produced an artifact (mtime 2026-07-30T16:44) but its diary has no newer commit (diary last commit 2026-07-30T15:13) - role ran, memory not seeded (spec M9) | resolve: lead APPEND agent-memory/ring2-audit/ on-behalf IN THE SAME session (khuon B3) and commit, so next session does not enter blind
|
||||
C11 FLAG-khuon + diary-delta flags = 10 [INFORM-only, LOW, NOT folded into TOTAL baseline]
|
||||
|
||||
===== C12 - raw-engine-bypass (INFORM-only) =====
|
||||
[ok] 2026-07-25-1200-S149-S150-closeout-bookend-first-run.md carries a run= registration line
|
||||
[ok] 2026-07-25-1930-S151-bootstrap-trio-auto-fixes.md carries a run= registration line
|
||||
[ok] 2026-07-26-0200-S152-bookend-memops-close.md carries a run= registration line
|
||||
[ok] 2026-07-26-1600-S153-ctx-adopt-3vai-rename.md carries a run= registration line
|
||||
[ok] 2026-07-28-0930-S155-S157-pe-delete-bch-invest-diadiem.md carries a run= registration line
|
||||
[ok] 2026-07-28-2100-S158-adap-day-wake-bookend-close.md carries a run= registration line
|
||||
[ok] 2026-07-29-1440-S159-tong-quan-quy-trinh-arc2-bookend.md - no unregistered spawn mention
|
||||
[ok] 2026-07-30-1100-S162-cay-4-folder-gd-close.md carries a run= registration line
|
||||
C12 raw-engine-bypass flags = 0 [INFORM-only, LOW, NOT folded into TOTAL baseline]
|
||||
|
||||
===== Summary =====
|
||||
self-exclusion: 6 paths excluded (exact+dir rules)
|
||||
- excluded: scripts/governance-detectors.ps1
|
||||
- excluded: docs/governance/harness-11-engine.md
|
||||
- excluded: docs/governance/vocab-alias-map.md
|
||||
- excluded: broadcasts/inbox
|
||||
- excluded: broadcasts/outbox
|
||||
- excluded: .claude/workflows/runs
|
||||
self-match check: governance-detectors.ps1 in scan = 0 ; leaked excluded files in scan = 0
|
||||
[OK] 0 self-match (C4 satisfied)
|
||||
|
||||
TOTAL FLAGS: 51
|
||||
INFORM-ONLY (new nets C6 cite-2-tier + H24-4 pending-flip + H24-5 counter-ancestor-classify + C9 hmw-width-drift + C11 h24-flag-form + C12 raw-engine-bypass): 10 - counted SEPARATELY, NOT in TOTAL above (anti-Goodhart, owner-set; fold+sev-raise is post-triage)
|
||||
NOTE: DETECT-only lowering net. Exit 0 always (never fails build). FLAGs are advisory.
|
||||
@ -0,0 +1,14 @@
|
||||
# RUN 2026-08-01-S166-h24-deep-midsession — H24 DEEP-audit trả nợ OVERDUE 15/15
|
||||
|
||||
> Trigger: tick S166 → counter 40; 40 − deep_at 25 = 15 ≥ deep_every 15 ⇒ OVERDUE(deep) fire tại cửa /tiep
|
||||
> (nhip-no-probe in `kiem light 4/6 deep 15/15 OVERDUE:deep`). Chạy GIỮA phiên thay vì đợi closeout —
|
||||
> 2 vai read-only nền, không chặn mạch K-wave (mandate PAUSE-3).
|
||||
> Máy TRƯỚC vai: `detectors-output.txt` (TOTAL 51 + 10 INFORM) — vai ĐỌC, KHÔNG chạy lại.
|
||||
> Deep bao hàm light ⇒ sau vòng: set last_audit.light_at=deep_at=40 (khuôn S143).
|
||||
|
||||
## taskList
|
||||
| # | vai | trạng thái |
|
||||
|---|---|---|
|
||||
| 1 | lead-stale-auditor (deep) | spawned @S166 |
|
||||
| 2 | lead-gap-auditor (deep) | spawned @S166 |
|
||||
| 3 | ring2-audit (SAU khi 1+2 trả) | ☐ |
|
||||
@ -0,0 +1,221 @@
|
||||
LEAD-GAP-DEEP: IN-PROGRESS
|
||||
|
||||
# H24 DEEP-audit vai-GAP @S166 (2026-08-01) — soi CÁI BỊ THIẾU
|
||||
|
||||
Nợ OVERDUE(deep) 15/15 (counter 40, deep_at cũ 25). Read-only, INFORM-only, propose-only.
|
||||
Class enum ĐÓNG (họ `gap-*`) đọc từ `.claude/agent-memory/memory-budget.json` -> `lead_self_audit.flag_classes`:
|
||||
gap-carry-dropped · gap-carry-aged · gap-owner-specifics · gap-decision-sunk · gap-underfill · gap-incident-unrecorded
|
||||
|
||||
## Phương-pháp (dựng tập KỲ-VỌNG TRƯỚC, so SAU)
|
||||
Nguồn cam-kết đọc: `.claude/WAL.md` · `.claude/sessions/session-9/_context-s-9.md` · `docs/HANDOFF.md` ·
|
||||
`docs/STATUS.md` · `.claude/governance/ACTIVE-MARKS.md` · `docs/governance/error-ledger.md` ·
|
||||
`.claude/workflows/runs/2026-08-01-*` · `detectors-output.txt` (ĐỌC, không chạy lại).
|
||||
|
||||
(đang ghi từng FLAG ngay khi tìm được — chống #53)
|
||||
|
||||
---
|
||||
|
||||
## FLAG-1 — `gap-underfill` — HIGH
|
||||
|
||||
**hứa ở:** `.claude/agent-memory/memory-budget.json:18` — `tiep_reload.sources[3]` =
|
||||
`".claude/sessions/session-<N>/_mind-s-<N>.md :: tron (doc TU TREN XUONG)"` — chữ **`tron`** + **`doc TU TREN XUONG`**
|
||||
là nguồn DUY NHẤT trong 5 nguồn được viết thêm chỉ-dẫn cách đọc.
|
||||
Cam-kết thứ 2 cùng khoá: `:15` `"docs/STATUS.md :: dong CURRENT + bang CURRENT STATE (KHONG ca file)"`.
|
||||
|
||||
**hiện (đo @S166, đơn-vị = BYTE trên đĩa, lệnh dưới):**
|
||||
|
||||
| nguồn khoanh trong config | trần đúng phạm-vi | lead nạp @S166 | thiếu |
|
||||
|---|---|---|---|
|
||||
| `docs/STATUS.md` :: dòng CURRENT + **bảng CURRENT STATE** | dòng CURRENT (`:6`) + bảng `:461-485` = **62.187 B** | head-**60** (27.553 B) — chứa `:6` ✓ | **bảng CURRENT STATE = 0 B ĐỌC** (bắt đầu ở dòng **461**) |
|
||||
| `docs/HANDOFF.md` :: segment Last-updated MỚI NHẤT | `:1-40` (biên = `:41` `**🧊 (Last updated cũ)**`) = 9.486 B | head-**70** = 20.835 B | **0 — ĐỌC DƯ, không phải cụt** (khai thẳng: trục này SẠCH) |
|
||||
| `.claude/WAL.md` :: trọn | 3.389 B | trọn | 0 ✓ |
|
||||
| `_mind-s-9.md` :: **trọn (đọc TỪ TRÊN XUỐNG)** | **30.573 B / 270 dòng** | **165 dòng = 18.925 B** | **11.648 B = 38,1% KHÔNG ĐỌC** |
|
||||
| `_context-s-9.md` :: trọn | 13.781 B | trọn | 0 ✓ |
|
||||
|
||||
🔴 **Chỗ cắt KHÔNG vô-hại — nó rơi ĐÚNG vào khối được dựng để chống mất:**
|
||||
`_mind-s-9.md:192` = `## MIND-1 … [NÉN @S165 pause-3 — verbatim trong git; **6 ý chỉ-sống-ở-đây GIỮ NGUYÊN**]`.
|
||||
Dòng 165 cắt ⇒ **toàn bộ MIND-1 (`:192-217`) + toàn bộ MIND-0 (`:218-270`) = 0 byte đọc**. Trong đó:
|
||||
- `:200` 4 nhánh-ĐÃ-LOẠI *(GIỮ — chỉ sống ở đây)* — ❌ nâng-cap cứu `_INDEX` (slot 57!) · ❌ đọc "④ chưng-cất = 0" thành lành · ❌ ring4-NO-OP…
|
||||
- `:205` họ-lỗi *"máy trả đúng câu nó được hỏi mà việc vẫn hỏng"* 4-ca/1-phiên *(GIỮ — chỉ sống ở đây)*
|
||||
- `:206` luật *"luật vừa-viết KHÔNG tự áp cho đoạn văn chứa nó — phải grep lại chính mình"* *(GIỮ — chỉ sống ở đây)*
|
||||
|
||||
Tức: S165 tốn công NÉN để 6 ý này sống sót, S166 nạp lại **cắt mất đúng 6 ý đó**. Nén-để-giữ + đọc-cụt = **nén thành xoá**.
|
||||
|
||||
**im:** 1 cửa-sổ (`/tiep-3` @2026-08-01 08:29) — nhưng là lượt ĐẦU sau khi MIND-1 được nén, tức hỏng ngay lần dùng đầu tiên.
|
||||
|
||||
**hệ-quả nếu không vá:** ba ý được đánh dấu "chỉ sống ở đây" chết lặng; slot (57) `_INDEX` sẽ được cân nhắc lại
|
||||
mà KHÔNG có nhánh-đã-loại ⇒ lead có thể đề xuất lại đúng phương án `refine` đã BÁC (rời tập-đo).
|
||||
|
||||
**resolve:** hết-flag khi (a) `/tiep` đọc `_mind` HẾT 270 dòng (hoặc đọc từ DƯỚI lên nếu muốn ưu-tiên mới),
|
||||
**và** (b) khoanh-vùng STATUS được nạp đúng 2 phần (dòng CURRENT **+** bảng CURRENT STATE `:461-485`),
|
||||
hoặc owner sửa lại chữ trong `tiep_reload.sources` cho khớp cái thực nạp.
|
||||
|
||||
**lệnh đo (chạm đĩa, tái-lập được):**
|
||||
```
|
||||
wc -l -c .claude/sessions/session-9/_mind-s-9.md # 270 30573
|
||||
sed -n '1,165p' .claude/sessions/session-9/_mind-s-9.md | wc -c # 18925
|
||||
sed -n '166,270p'.claude/sessions/session-9/_mind-s-9.md | wc -c # 11648
|
||||
grep -n 'chỉ-sống-ở-đây' .claude/sessions/session-9/_mind-s-9.md # 192,200,205,206 -> ĐỀU > 165
|
||||
grep -n 'CURRENT STATE' docs/STATUS.md # 461 (head-60 khong cham toi)
|
||||
sed -n '461,485p' docs/STATUS.md | wc -c # 62187
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## FLAG-2 — `gap-decision-sunk` — HIGH
|
||||
|
||||
**hứa ở:** `.claude/sessions/session-9/_context-s-9.md:63` (PAUSE-1, 2026-07-30, khối *"(2) delta còn SỐNG"*),
|
||||
nguyên văn: *"**2 mồi `ctx-audit` gieo, chờ chấm @close:** MỒI-A **slot (61)** defect liên-danh N-HĐ · MỒI-B **slot (60)** enum."*
|
||||
⇒ hai SỐ SLOT đã được CẤP (61 và 60) = hai câu hỏi dành cho owner.
|
||||
|
||||
**hiện: VẮNG — 0 hit trên MỌI bề mặt owner đọc.**
|
||||
```
|
||||
grep -o '(60)\|(61)' docs/HANDOFF.md -> 0
|
||||
grep -o '(60)\|(61)' docs/STATUS.md -> 0
|
||||
grep -c 'MỒI-A\|MỒI-B' docs/HANDOFF.md docs/STATUS.md .claude/WAL.md -> 0 0 0
|
||||
```
|
||||
Control dương (chứng phép đo có răng): cùng lệnh trên `_mind-s-9.md` ra **1** ⇒ regex ĐÚNG, 0-hit là 0 THẬT.
|
||||
Và bảng CHỜ-ANH của `docs/HANDOFF.md` đánh số **… (57) (58) (59) → (62)** — **thủng đúng 2 số 60, 61**:
|
||||
```
|
||||
sed -n '1,40p' docs/HANDOFF.md | grep -o '\*\*([0-9]\+[a-z-]*)' | sort -u
|
||||
-> (54) (55) (56) (57) (58) (59) (62)
|
||||
```
|
||||
Slot (62) tự khai `🆕 @S164` ⇒ lead ĐÃ mở sổ CHỜ-ANH ở S164 và **nhảy qua 60/61** — không phải "quên cả khối", mà bỏ CHỌN LỌC.
|
||||
|
||||
**im:** từ PAUSE-1 `2026-07-30T17:35` → nay `2026-08-01` = **2 ngày / 3 nhãn phiên (S164,S165,S166) / 3 cửa-sổ `/tiep`**.
|
||||
Nặng thêm: mồi ghi *"chờ chấm @**close**"* mà **S163 không hề có @close** (run-folder chỉ có `2026-07-30-S163-bookend-open`,
|
||||
0 folder `*-S163-*close*`) ⇒ điều-kiện chấm mồi không bao giờ tới, và không sổ nào ghi việc đó.
|
||||
|
||||
**hệ-quả nếu không vá:** hai câu hỏi owner biến mất vĩnh viễn khi `_context` bị nén/đóng phiên-logic L9;
|
||||
tệ hơn — khoảng trống số (60)(61) sẽ bị slot MỚI tái-dụng, và khi đó **không còn dấu vết nào cho thấy có gì đã đứng ở đó**
|
||||
(đúng class `slot-index tái-dụng xoá IM-LẶNG`, auto-memory `feedback_absence_looks_like_clean`).
|
||||
|
||||
**resolve:** hết-flag khi (60) và (61) hiện diện trong khối 🔴 CHỜ ANH của `docs/HANDOFF.md` với nội-dung mồi
|
||||
(enum · defect liên-danh N-HĐ) — hoặc lead khai tường-minh "mồi đã chấm, kết-quả X, đóng slot" ở một sổ bền.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-3 — `gap-carry-dropped` — HIGH
|
||||
|
||||
🔴 **KHAI ĐƠN-VỊ TRƯỚC (bài ring2 D-4 @S159):** ô tally `gap-carry-dropped` đếm theo **consecutive-audit**,
|
||||
đang = **8** (chốt @S162). Lượt deep này nếu lead ratify thì thành **9** — **KHÔNG** phải "1" (số trong-phiên).
|
||||
Đừng chép số trong-phiên đè lên ô tally: làm thế là XOÁ LỊCH-SỬ.
|
||||
|
||||
**hứa ở:** `docs/HANDOFF.md:37` tự khai nghi-thức của chính nó —
|
||||
`**Carry @S162 (RE-STAMP — nghi-thức §L.b(j)(iv), bỏ 2 kỳ liên tiếp S159+S160 nên gap-carry-dropped lên streak 8):**`
|
||||
và `docs/HANDOFF.md:33` NEXT-em mục 3 tự nhận: *"**Nghi-thức re-stamp carry** — `gap-carry-dropped` **streak 8**,
|
||||
bỏ lần 2 ngay sau khi bị FLAG HIGH @S159 ⇒ đây là **nghi-thức hỏng**, không phải sự cố lẻ."*
|
||||
|
||||
**hiện: khối carry mới nhất VẪN mang nhãn `@S162`** — không có `Carry @S163` / `@S164` / `@S165` / `@S166`.
|
||||
```
|
||||
grep -o 'Carry @S[0-9]*' docs/HANDOFF.md -> chỉ 'Carry @S162'
|
||||
git log --format='%h %cI' -3 -- docs/HANDOFF.md
|
||||
bd68f71 2026-07-31T21:47 (S165 wal: pause) 1 dòng đổi
|
||||
15349e8 2026-07-31T18:21 (S164 K3) 1 dòng đổi
|
||||
50e6d8c 2026-07-31T15:45 (S164 K1) 7+/5-
|
||||
git diff e5123ff..HEAD -- docs/HANDOFF.md | grep -c '^[+-]' -> 16
|
||||
```
|
||||
🔴 **Đây KHÔNG phải "quên cả file vì gấp":** HANDOFF bị sửa **3 lần / 16 dòng** sau closeout S162, và **chính dòng
|
||||
carry `:37` đã bị EDIT** (nó chứa ghi-chú *"2 slug này = TÁCH từ `[carry:orphan-retro-harvest-s159]` **@S164**"*)
|
||||
— tức lead có mở đúng dòng đó ra sửa mà **vẫn không re-stamp kỳ mới**. Sửa-tại-chỗ ≠ re-stamp:
|
||||
sửa-tại-chỗ làm **tuổi carry tàng hình** với máy (streak không tăng vì không có đoạn LOGIC mới).
|
||||
|
||||
**im:** **3 nhãn phiên (S163 · S164 · S165) + phiên này S166** kể từ lần re-stamp cuối (2026-07-30 e5123ff) = **2 ngày**.
|
||||
Đây là **lần bỏ thứ 3 liên tiếp** (S159+S160 → FLAG HIGH; S163→S165 → nay).
|
||||
|
||||
**đo phụ — cái máy KHÔNG thấy** (đọc detector, KHÔNG tính lại):
|
||||
`detectors-output.txt:79-84` → `HANDOFF logic-segments = 25 ; carry-lines = 18`, in đúng **5** carry:
|
||||
`ctx-t9-dogfood` 2 · `ring5-audit-gap` 1 · `hmw-width-vs-roster` 1 · `hmw-subfile-index-collision` 1 · `adap-apply-2-thu` 3 — **tất cả [ok] < M=6**.
|
||||
Đối chiếu đĩa: khối re-stamp `:37` mang **12 slug**, cả file mang **50 slug / 234 occurrence**
|
||||
(`grep -o '\[carry:[a-z0-9-]*\]' docs/HANDOFF.md | sort -u | wc -l` = 50; `grep -o '\[carry:' … | wc -l` = 234).
|
||||
⇒ máy chấm **5/50**; `gap-carry-aged` **không thể fire** không phải vì carry trẻ, mà vì **chứng-nhân không ở trong tập-đo**.
|
||||
🔸 KHAI THẬT: hình dạng này **đã báo @S159** (Goodhart rời-tập-đo) — ghi lại đây làm **chứng streak còn sống**, KHÔNG tính là phát-hiện mới.
|
||||
|
||||
**hệ-quả nếu không vá:** nghi-thức duy nhất giữ tuổi-nợ đã hỏng 3 kỳ liên tiếp ⇒ 50 slug trên đĩa trở thành
|
||||
nợ **không có đồng hồ**; và vì detector chỉ thấy 5, mọi bản báo cáo "carry sạch" sẽ **đúng về câu chữ, sai về việc**.
|
||||
|
||||
**resolve:** hết-flag khi có 1 dòng `**Carry @S166 (RE-STAMP …)**` mới trong segment Last-updated mới nhất,
|
||||
liệt slug còn MỞ (đóng slug đã xong, ghi rõ lý do đóng) — và streak `gap-carry-dropped` được reset về 0 **bằng hành-vi**, không bằng chữ.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-4 — `gap-carry-dropped` — HIGH
|
||||
|
||||
*(scope-1: việc rớt khỏi work-state so với backlog — món **owner tự tay gác sang giai-đoạn sau** mà không sổ backlog nào nhận)*
|
||||
|
||||
**hứa ở:** `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/spec-4gd-khkk-tong-quat-31-07-2026.md:54`, nguyên văn:
|
||||
> **BACKLOG giai-đoạn-sau (owner @S164, không làm đợt này):** (1) authz-per-nhóm KHKK (OG-8) · (2) **phiếu điều chỉnh/thay thế**
|
||||
> cho chứng từ đã duyệt — khuôn amendment ERP, áp PE/KHKK/HĐ (*"Nếu xóa thì có thể làm 1 tính năng điều chỉnh phiếu để cập nhật
|
||||
> điều chỉnh/thay thế - ko xóa phiếu đã duyệt. Cái này để giai đoạn sau."*) · (3) bung-gộp UI (OG-1/OG-7 nửa sau — máy đã sẵn).
|
||||
|
||||
Mục (2) là **lời anh VERBATIM**, phạm-vi **toàn ERP** (PE + KHKK + HĐ), không riêng KHKK.
|
||||
|
||||
**hiện: VẮNG — 0 hit / 6 bề mặt, gồm cả sổ backlog chính thức.**
|
||||
```
|
||||
grep -c 'OG-8|authz-per-nhóm' -> HANDOFF 0 · STATUS 0 · WAL 0 · migration-todos 0 · _context 0 · _mind 0
|
||||
grep -c 'phiếu điều chỉnh|điều chỉnh/thay thế' -> 0 0 0 0 0 0
|
||||
grep -c 'BACKLOG giai-đoạn-sau' -> 0 0 0 0 0 0
|
||||
CONTROL-DƯƠNG (cùng regex, trên chính file nguồn):
|
||||
grep -o 'OG-8' spec-4gd…tong-quat…md | wc -l -> 2
|
||||
grep -o 'authz-per-nhóm' … | wc -l -> 3
|
||||
grep -o 'BACKLOG giai-đoạn-sau' … | wc -l -> 1
|
||||
```
|
||||
⇒ regex có răng; **0 là 0 THẬT**, không phải lỗi phép đo.
|
||||
🔴 `docs/changelog/migration-todos.md` là **nhà được chỉ định** cho loại này (`CLAUDE.md` §5-file: *"Atomic tasks theo phase"*) — và nó **rỗng** ở cả 3 mục.
|
||||
|
||||
🔴 **Phân-định với luật "vắng ≠ bỏ rơi":** anh **CÓ** chủ-động gác ("để giai đoạn sau") ⇒ **việc gác là ĐÚNG, không flag**.
|
||||
Cái bị flag là: gác **sang đâu**? "Giai đoạn sau" = phải nằm trong **sổ phase**, mà sổ phase 0 hit.
|
||||
Đây không phải "owner đang giữ trong tay" — anh đã **giao lại cho hệ-thống** và hệ-thống đánh rơi.
|
||||
|
||||
**im:** từ `2026-07-31` (S164) → nay = **2 nhãn phiên / 1 ngày**, nhưng đã **đi qua trọn 1 lượt `/pause` (PAUSE-3) + 1 lượt `/tiep` (S166)**
|
||||
— tức đã qua đúng 2 nghi-thức được thiết-kế để bắt loại này mà cả 2 đều không bắt.
|
||||
|
||||
**hệ-quả nếu không vá:** yêu-cầu tính-năng của anh (amendment/điều-chỉnh phiếu — chạm 3 module) tồn tại duy nhất trong
|
||||
1 file spec 14,7 KB ở run-folder; sang phiên-logic L10, không nghi-thức nào đọc file đó ⇒ **mất hẳn**, và lần sau anh hỏi
|
||||
"cái điều chỉnh phiếu đâu rồi" thì không sổ nào trả lời được.
|
||||
|
||||
**resolve:** hết-flag khi 3 mục backlog này có mặt trong `docs/changelog/migration-todos.md` (hoặc khối backlog của `docs/HANDOFF.md`)
|
||||
kèm nguồn `spec-4gd…:54` — và mục (2) giữ **nguyên văn câu của anh**, không tóm tắt.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-5 — `gap-owner-specifics` — MED
|
||||
|
||||
**hứa ở:** mandate PAUSE-3 (3 tin anh, verbatim `_context-s-9.md:117`) — ② *"Chứ ý kỹ các đầu việc trong plan đã đc review kỹ
|
||||
trong rurn này nhé."* ③ *"uhm ý tao là plan các thứ đang chạy tới đâu nhớ kỹ, bắt đc lỗi thì tốt."*
|
||||
Lead diễn-đạt lại ở `.claude/WAL.md:39-40`: *"sổ nhớ kỹ **từng đầu việc** đã review"*.
|
||||
Bài đã rút @S165 (auto-memory `feedback_pause_track_plan_progress`): *"liệt TỪNG đầu việc đã-review (wave + vá-số + finding treo),
|
||||
**rà từng dòng OG** trước khi tuyên xong"* — ca sinh ra nó chính là **gap checkbox OG-3 → gate F-1 MAJOR**.
|
||||
|
||||
**hiện: SPECIFICS bị nén thành SỐ ĐẾM và thành BIỆT-DANH; khoá tra-cứu (OG-n / F-n) rơi mất.**
|
||||
|
||||
*(a) Trục OG — đĩa có 10 ID, sổ bền giữ 4:*
|
||||
```
|
||||
grep -oh 'OG-[0-9]\+' runs/2026-07-31-S164-…/*.md | sort | uniq -c
|
||||
OG-1:40 OG-2:27 OG-3:25 OG-4:3 OG-5:7 OG-6:36 OG-7:22 OG-8:5 OG-9:18 OG-10:1
|
||||
bề mặt bền: HANDOFF{OG-3, OG-9} · STATUS{} · WAL{OG-5, OG-6} · _context{OG-5, OG-6} · _mind{OG-3, OG-5, OG-6}
|
||||
hợp: {OG-3, OG-5, OG-6, OG-9} = 4/10 ⇒ VẮNG: OG-1, OG-2, OG-4, OG-7, OG-8, OG-10 = 6/10
|
||||
```
|
||||
Nặng nhất: **OG-1 (40 hit)** và **OG-2 (27 hit)** — hai khoản được bàn NHIỀU NHẤT trong cả run — **0 hit** trên mọi sổ bền.
|
||||
Và `b1b-review-synthesis.md:31` ràng OG vào DoD: *"PRE-gate K1←OG-6, **K2←OG-1+OG-7**, K3←OG-2"* ⇒ đây là **điều-kiện nghiệm-thu**, không phải ghi chú.
|
||||
|
||||
*(b) Hệ-quả đo được — claim không kiểm được:* `_context-s-9.md:108` (PAUSE-2) tuyên **"9 OG trọn"** rồi liệt bằng **biệt-danh**
|
||||
(*gộp+UI-1-1 · đội-hình-cũ · NĐUQ-human-gate · N-phiếu+UI-1 · hiển-thị-không-authz · đảo-PHÁ-VỠ-S155 · freeze-tái-dùng-máy ·
|
||||
phiếu-bất-tử-ERP · OG-6→soát-SAU*) — **chỉ 1/9 có ID**. Đĩa có **10** ID.
|
||||
⇒ Không cách nào đối-chiếu "9 tuyên" với "10 trên đĩa": **1 khoản chênh mà không ai chỉ ra được là khoản nào.**
|
||||
Chính đây là điều mandate ③ *"rà từng dòng OG"* sinh ra để chặn.
|
||||
|
||||
*(c) Trục F-n — khoá KHÔNG duy-nhất:* 3 cổng gate dùng **cùng dải ID**
|
||||
(`grep -o 'F-[0-9]\+' sub-reviewer-gate-k{1,2,3}.md | sort -u` → k1: F-1..F-5,F-7 · k2: F-1..F-10 · k3: F-1..F-8 = **27 finding**).
|
||||
Sổ bền viết `WAL:41` *"**F-5**-PermGuard-khuôn-cũ"* và `_context:127` *"**F-5** PermGuard nợ khuôn cũ"* — **không tiền-tố cổng nào**,
|
||||
trong khi F-5 tồn tại ở **cả 3** cổng. Tra ngược = phải mở 3 file. (Đối-chứng: `_context:124` CÓ viết đúng *"gate-K3 F-1"* ⇒ lead
|
||||
biết cách ghi đủ, chỉ là không nhất-quán ⇒ không phải "không thể", mà là **rơi**.)
|
||||
|
||||
**im:** từ PAUSE-3 `2026-07-31T18:35` → nay = **1 ngày / 2 nhãn phiên**, đã qua 1 `/tiep`.
|
||||
|
||||
**hệ-quả nếu không vá:** K4a→K8 còn 5 wave chưa build; DoD của chúng neo vào OG-n. Vào wave sau, lead sẽ **không có OG-1/OG-2/OG-7
|
||||
trong tầm đọc** ⇒ hoặc bỏ điều-kiện nghiệm-thu, hoặc phải mở lại 26 file run-folder — đúng thứ mandate ③ ra đời để ngăn.
|
||||
|
||||
**resolve:** hết-flag khi (i) mỗi OG còn hiệu-lực có **1 dòng ID + 1 dòng nội-dung** trong sổ bền (WAL notes hoặc HANDOFF),
|
||||
và (ii) mọi tham-chiếu `F-n` trong sổ bền mang tiền-tố cổng (`gate-K2 F-5`), và (iii) claim "N OG trọn" liệt **đủ N ID**.
|
||||
|
||||
@ -0,0 +1,233 @@
|
||||
LEAD-STALE-DEEP: IN-PROGRESS
|
||||
|
||||
# H24 DEEP-audit @S166 (2026-08-01) — vai `lead-stale-auditor`
|
||||
|
||||
- Nhịp: OVERDUE(deep) tra-nợ, counter 40, deep_at cũ 25 (15/15 quá hạn)
|
||||
- Chế-độ: read-only, INFORM-only, propose-only
|
||||
- Nền máy: `detectors-output.txt` cùng folder (TOTAL 51 + 10 INFORM) — ĐỌC làm nền, KHÔNG chạy lại
|
||||
- Enum class: `lead_self_audit.flag_classes` họ `view-*` (5 class ĐÓNG)
|
||||
|
||||
## Coverage (khai TRƯỚC, cập nhật dần)
|
||||
|
||||
| # | Nhóm bề-mặt | Trạng thái |
|
||||
|---|---|---|
|
||||
| 1 | `docs/STATUS.md` CURRENT + bảng CURRENT STATE | DONE |
|
||||
| 2 | `docs/HANDOFF.md` segment mới nhất | PENDING |
|
||||
| 3 | `CLAUDE.md` root (bảng module/mig) | PENDING |
|
||||
| 4 | `.claude/agents/README.md` roster | DONE — SẠCH |
|
||||
| 5 | `docs/changelog/migration-todos.md` | PENDING |
|
||||
| 6 | Governance surfaces `docs/governance/*.md` | PENDING |
|
||||
| 7 | Mô-tả VAI `.claude/agents/*.md` | PENDING |
|
||||
| 8 | Dư-lượng bất-đối-xứng (mirror pairs) | PENDING |
|
||||
|
||||
---
|
||||
|
||||
## FLAG-1 — `view-residual-asym` — HIGH
|
||||
|
||||
**view:** `docs/STATUS.md:465-472` (bảng CURRENT STATE — ô CANONICAL theo B1)
|
||||
**source:** `docs/STATUS.md:6` (dòng CURRENT, cùng file) + đĩa
|
||||
|
||||
Wave K1→K3 (`50e6d8c`/`0779f2d`/`15349e8`, S164-S165) cập-nhật **dòng :6** đủ 5 số mới nhưng **KHÔNG chạm 1 ô nào của bảng canonical**. Một file, hai bề mặt, sửa đúng một phía.
|
||||
|
||||
| Row bảng canonical | View nói (chuỗi THẬT trên đĩa) | Source đúng | Lệch | Máy có bắt? |
|
||||
|---|---|---|---|---|
|
||||
| `:465` Migrations | `\| Migrations \| **69** \|` | **71** (đếm đĩa `Persistence/Migrations/*.cs` trừ Designer/Snapshot = 71; mới nhất `20260731085624_AddKhkkApprovalGroupCatalogAndFinalizeRuntime.cs`) | −2 | ✅ CÓ (`canonical-itself-stale`) |
|
||||
| `:466` SQL tables | `\| SQL tables \| **96** \|` | **97** (Mig 70 `AddContractCatalogEntries` = **1** `CreateTable`; Mig 71 = **0** `CreateTable`/`DropTable` ⇒ 96+1) | −1 | ❌ MÙ |
|
||||
| `:470` Policies | `\| Policies \| **220** \|` | **256** (= 64 key × 4 action; `.claude/WAL.md:13` "policy=256") | −36 | ❌ MÙ |
|
||||
| `:471` Menu keys | `\| Menu keys \| **55** \|` | **64** (ĐẾM PHẦN-TỬ mảng `MenuKeys.All`, `MenuKeys.cs` — **KHÔNG** dùng `grep -c "public const string"` ra **65**, bài S143/S150) | −9 | ❌ MÙ |
|
||||
| `:472` Tests | `\| Tests \| **590 PASS** \| 45 Domain + 545 Infra` | **614** (45D+569I — `.claude/WAL.md:13` `suite 614/0 (45D+569I)` + `:37`) | −24 | ❌ MÙ |
|
||||
|
||||
🔴 **Vì sao nguy (hơn hẳn "5 con số cũ"):** `governance-detectors.ps1` `Get-StatusValue` **resolve canonical TỪ chính bảng này** (chính row `:470` tự khai điều đó). Cross-check đĩa của máy CHỈ phủ `mig` + `gotcha` (`detectors-output.txt:4` = `disk cross-check: mig=71 gotcha=85`) ⇒ 4 trục còn lại đo bằng **thước sai** mà máy vẫn in `[ok]`. Hệ-quả đo được ngay trong lượt này: `detectors-output.txt:14` bảo `.claude/skills/ef-core-migration/SKILL.md:93` "writes **97** table but canonical=**96** → resolve: update to 96". Doc đó đang ĐÚNG (97) và máy đang đề-nghị sửa nó thành SAI. **Canonical-poison không chỉ giấu lỗi — nó chủ-động sinh lệnh sửa-ngược.**
|
||||
|
||||
**resolve:** re-ground 5 ô `:465/:466/:470/:471/:472` về 71 / 97 / 256 / 64 / 614 (bao gồm sub-số `45D+569I`), rồi chạy lại detector — kỳ vọng FLAG `SKILL.md:93` biến mất và TOTAL đổi.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-2 — `view-stale-count` — HIGH
|
||||
|
||||
**view:** `docs/STATUS.md:479` — chuỗi THẬT: `**Bundle hash live (prod):** admin **\`B43R6Y17\`** · user **\`NLI5umBg\`** … **Đo LIVE bằng curl 2026-07-31 @S164**`
|
||||
**source:** `.claude/workflows/runs/2026-07-31-S164-4gd-khkk-fanout/sub-cicd-verify-k3.md:86,88` — POST-deploy đo LIVE 31/07 18:26-18:27 +07: admin `index-mySTlx42.js` **ROTATE** · eoffice `index-CZAYiWWa.js` **FROZEN**
|
||||
|
||||
Lệch: view nói `B43R6Y17`/`NLI5umBg`, source nói `mySTlx42`/`CZAYiWWa`. **0/2 khớp.**
|
||||
|
||||
🔴 Nặng gấp đôi vì hai lẽ:
|
||||
1. `docs/STATUS.md:6` cố ý **KHÔNG chép** số bundle mà trỏ *"canonical ở `:479`"* (đúng B1) ⇒ ai tuân B1 sẽ đáp thẳng vào ô sai. Đây là **con trỏ tốt tới nội-dung hỏng** — nguy hơn số rời rạc vì nó được cả hệ tin.
|
||||
2. Chính vai cicd **đã nói ra** rồi mà chưa ai lật sổ: `sub-cicd-verify-k3.md:93-94` viết nguyên văn *"Đính chính mốc PRE trong đề bài: spec giao việc ghi baseline `admin B43R6Y17 · user NLI5umBg (@S164)` — KHÔNG khớp gì đo được"*. Phát-hiện đã tồn tại **trên đĩa**; khoảng cách nằm ở chỗ nó chưa đi từ run-folder về sổ owner-facing (đúng lớp bài S162: *nơi lead làm việc ≠ nơi anh đọc*).
|
||||
|
||||
Ghi chú danh-pháp (đừng lẫn khi vá): `:479` gọi app thứ hai là **user**, cicd gọi **eoffice** — cùng site, khác tên. Nếu vá thì thống nhất một tên, kẻo sinh vocab-fork mới.
|
||||
|
||||
**resolve:** `:479` = admin `mySTlx42` · user/eoffice `CZAYiWWa` (FROZEN, không phải ship-fail — cicd §5 dự-đoán TRƯỚC khi đo), kèm mốc 2026-07-31 18:26 +07 sau run #436. Hết flag khi hash ở `:479` khớp lần curl mới nhất.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-3 — `view-stale-count` — LOW
|
||||
|
||||
**view:** `docs/STATUS.md:6` — chuỗi THẬT: `counter **39**`
|
||||
**source:** `.claude/governance/.session-counter.json` → `counter = 40` (`last_ticked_head` = `24ea71e2…` = HEAD hiện tại, session S166; detector `H24-5` xác nhận `[OK] OK-reachable`)
|
||||
|
||||
Lệch 39 vs 40 (−1). SEV LOW **có điều kiện**: đây là stale **biết-trước** giữa phiên (S166 vừa tick, STATUS được re-stamp ở closeout). Ghi FLAG để tally by-class không mất mẫu, KHÔNG phải để đòi vá ngay.
|
||||
|
||||
🔴 Nhưng đừng đọc thành vô hại: `counter` là **đầu vào của chính nhịp H24** (`h24_cadence.deep_every`). Một sổ owner-facing trình sai counter làm owner không thấy được món nợ `deep` 15/15 mà chính lượt này đang trả. Nếu closeout quên bump, LOW này lặng lẽ sống tiếp.
|
||||
|
||||
**resolve:** re-stamp `counter 40` ở closeout S166; hoặc bỏ hẳn con số khỏi `:6` và trỏ khoá `.session-counter.json` (kiểu B1 mà `:6` đã dùng đúng cho bundle).
|
||||
|
||||
---
|
||||
|
||||
## Nhóm 4 — `.claude/agents/README.md` roster: SẠCH (đã chạm, có control)
|
||||
|
||||
NEXT-em #5 (`HANDOFF.md:33`) tố `README:242` tự xưng *"ĐỦ roster"* liệt **20 tên** / thật **23**, kèm *"10 monitor"* / thật **13** — **ĐÃ VÁ**, xác nhận bằng ĐẾM PHẦN-TỬ (không grep-theo-số, bài S143):
|
||||
|
||||
- Control đĩa: `ls .claude/agents/*.md` = **24 file**, trừ `README.md` ⇒ **23 vai**.
|
||||
- `README.md:242` (dài 1.788 B) liệt đúng **23** tên `investigator-codebase … ctx-audit`, và tự khai `Cả **13** monitor … 13 + 10 worker = roster 23` — 13+10 = 23 ✅, khớp đĩa.
|
||||
- `README.md:27` ("Roster THẬT") liệt 7 core + **16** tên rời = **23** ✅.
|
||||
- Đối-chứng nguồn thứ hai: `hmw.js:22` `VALID_ROLES` liệt cùng bộ tên (đã strip comment) ⇒ 2 bề-mặt README ⟂ hmw.js không lệch.
|
||||
- Không phát FLAG con-số-vắng-mặt: `README:3` + `:5` + `:242` cố ý **BỎ số**, chỉ trỏ `STATUS §Sub-agents` (B1) — đúng luật, không phải thiếu sót.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-4 — `view-stale-count` — MED
|
||||
|
||||
**view:** `CLAUDE.md:70` — chuỗi THẬT: `| **ContractSigningPlans (Kế hoạch Ký kết HĐ — KHKK)** | \`Domain/ContractSigningPlans/\` | **69** | … **Mig 69 \`AddContractSigningPlans\` (S161, 7 bảng, 89→96)**`
|
||||
**source:** đĩa `src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/` — `20260731085624_AddKhkkApprovalGroupCatalogAndFinalizeRuntime.cs` (**Mig 71**, chính là KHKK: nhóm duyệt N1-N8 + Line hạng-mục + unique 3-cột)
|
||||
|
||||
Lệch: ô Migration của module KHKK nói **69**, thật là **69, 71**. Và `CLAUDE.md:62` ("Lịch sử mig gần đây") dừng ở `+S161 Mig 69` — `grep "Mig 70\|Mig 71\|AddContractCatalog\|AddKhkkApproval" CLAUDE.md` = **0 hit** trên cả file.
|
||||
|
||||
🔴 Vì sao nguy: `CLAUDE.md` root là 1 trong 5 file *"đọc trước tiên"* của mỗi phiên và là thứ **auto-inject**. Nó đang dạy mỗi phiên mới rằng KHKK = 1 migration, trong khi K2 vừa thêm bảng nhóm-duyệt vào chính module đó ⇒ phiên sau đụng KHKK sẽ suy-luận schema trên bản-đồ thiếu. Đây cũng là **đợt-2 của cùng một vết**: NEXT-em #6 (`HANDOFF.md:34`) từng tố ":62/:69 thiếu mig 68+69"; 68/69 đã được nhét vào, rồi 70/71 lại rơi ra ⇒ vá-theo-số-cụ-thể chứ không vá-cơ-chế, nên vết tái sinh mỗi wave.
|
||||
|
||||
Ghi chú ranh-giới: module `ContractCatalog` (Mig 70) **không có row** trong bảng Modules — cái VẮNG là turf `lead-gap-auditor`, tôi chỉ nêu làm ngữ-cảnh, KHÔNG tính vào FLAG này.
|
||||
|
||||
**resolve:** ô `:70` ghi `69, 71`; `:62` bổ-sung Mig 70/71 (hoặc — bền hơn — cắt hẳn khối "lịch sử mig" khỏi `CLAUDE.md` và trỏ `docs/STATUS.md`, đúng câu B1 mà chính `:62` đang tự tuyên).
|
||||
|
||||
---
|
||||
|
||||
## FLAG-5 — `view-stale-header` — MED
|
||||
|
||||
**view:** `docs/HANDOFF.md:5` — chuỗi THẬT: `**🆕 Last updated:** 2026-07-30 trưa (**S161→S162** — phiên-LOGIC **L8** window-3 … window-4 …)`
|
||||
**source:** `docs/STATUS.md:6` — `**🔥 CURRENT (S161→S162 + S164/S165 2026-07-31 — phiên-LOGIC **L9** …)`; đĩa: run-folder `2026-07-30-S163-bookend-open/` + `2026-07-31-S164-4gd-khkk-fanout/`; hôm nay **2026-08-01**
|
||||
|
||||
Lệch: HANDOFF neo **S162 / L8 / 2026-07-30**, source đã sang **S166 / L9 / 2026-08-01** — trễ **4 nhãn phiên, 1 phiên-LOGIC, 2 ngày**. Kèm `:27` `## 🔴 NEXT em @S163` (nhãn S163 sống trên thân S166).
|
||||
|
||||
🔴 Vì sao nguy: `HANDOFF.md` là file thứ **2** trong "5 file đọc trước tiên" và là **segment-mới-nhất** mà `tiep_reload.sources` nạp mỗi `/tiep`. Cả 3 việc lớn của L9 (K1/K2 ship prod, K3 code+gate, Mig 70/71) **không có mặt** ở đây ⇒ phiên sau `/tiep` đọc brief 5-phút và tưởng mạch đang ở cây-4-folder S162.
|
||||
|
||||
⚠️ Ghi nhận đối-chứng để KHÔNG thổi phồng: đây là audit **giữa phiên**, HANDOFF thường re-stamp ở closeout. Nhưng S163→S165 đã ĐÓNG mà `:5` vẫn không bump ⇒ không giải thích được bằng "chưa tới closeout" — đã bỏ lỡ **ít nhất 2 closeout**.
|
||||
|
||||
**resolve:** bump `:5` sang segment L9 (S163→S166) + đổi `:27` thành `@S166`; hết flag khi nhãn ở `:5` ≥ nhãn ở `STATUS.md:6`.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-6 — `view-stale-status` — MED
|
||||
|
||||
**view:** `docs/HANDOFF.md:33` (mục NEXT-em #5) — chuỗi THẬT: `5. \`agents/README.md:242\` tự xưng "ĐỦ roster" liệt **20 tên** / thật **23** (thiếu đúng bộ-ba \`ctx-*\`, sống 9 nhãn phiên) + "10 monitor" / thật **13**. *(lead-stale FLAG-11/12)*`
|
||||
**source:** `.claude/agents/README.md:242` **hiện tại** liệt đủ **23** tên (có cả `ctx-curator`/`ctx-verifier`/`ctx-audit`) và ghi `Cả **13** monitor … 13 + 10 worker = roster 23`
|
||||
|
||||
Lệch: view treo việc như **CHƯA LÀM**, source chứng **ĐÃ LÀM XONG**. Cùng lớp cho `#6` (`:34`): vế `CLAUDE.md:62/:69 thiếu mig 68+69` cũng đã đóng (nay thiếu 70/71 — xem FLAG-4), tức mục này đúng **một nửa** mà không tách được nửa nào.
|
||||
|
||||
🔴 Vì sao nguy: khối `NEXT em (không cần anh gật)` là danh sách **tự-hành** — em-main phiên sau đọc và thi hành mà không hỏi ai. Một mục đã-xong nằm lại đó ⇒ tiêu một lượt làm việc để "vá" thứ đang đúng, hoặc tệ hơn là **vá ngược** (đây đúng cơ-chế đã thấy ở FLAG-1: máy bảo sửa `SKILL.md` 97→96). Đây là lặp lại nguyên class S140 (`view-stale-status` trên forward-pointer NEXT-em).
|
||||
|
||||
**resolve:** tick/gỡ #5, tách #6 thành phần-đã-đóng (68/69) và phần-mới (70/71); hết flag khi mọi mục còn lại trong khối NEXT-em đều chưa-thi-hành trên đĩa.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-7 — `view-stale-count` — HIGH
|
||||
|
||||
**view:** `docs/HANDOFF.md:15` slot **(57)/(51-bis)** — chuỗi THẬT: `\`cicd-monitor/archive/_INDEX.md\` đo lại @S162 = **99,18% / headroom 167 B** … Vế (c) "chấp nhận vỡ cap ~1-2 phiên nữa" thực chất **còn đúng 1 dòng append**. Chọn: **(a)** split file · **(b)** nâng cap · **(c)** để vỡ.`
|
||||
**source:** đĩa đo @S166 2026-08-01 — `.claude/agent-memory/cicd-monitor/archive/_INDEX.md` = **20.731 B** / cap `memory-budget.json` → `tiers.l2_index.cap_bytes` = **20.480** ⇒ **101,23 % · headroom −251 B**
|
||||
|
||||
Lệch: view nói *"còn đúng 1 dòng append"*, source nói **ĐÃ VỠ RỒI** (âm 251 B).
|
||||
|
||||
🔴 Vì sao nguy — và vì sao HIGH chứ không MED: đây là **slot đang CHỜ OWNER**, và cả ba lựa-chọn (a)/(b)/(c) được trình dưới giả-định *"sắp vỡ"*. Khi thực-tế đã là *"vỡ rồi"*, phương-án (c) "để vỡ" không còn là một **lựa chọn** mà là **mô-tả hiện-trạng** ⇒ owner đang được mời quyết một việc mà thời-điểm quyết đã trôi qua. Tệ hơn: chính dòng đó tự dán nhãn *"🔴 lead-stale FLAG-7 HIGH: anh đang chọn trên thước cũ"* — tức lỗi này **đã được chẩn đoán đúng tên ở S162** rồi **vá bằng cách thay số một lần**, chứ không phải bằng cách bỏ số neo. **Vá-bằng-thay-số thì 4 nhãn phiên sau lại stale y hệt** — đây là bằng chứng tái-phạm trong cùng một dòng chữ.
|
||||
|
||||
**resolve:** hoặc (i) bỏ literal `%`/`headroom` khỏi `:15` và ghi lệnh đo (kiểu slot (58) đã làm đúng), hoặc (ii) re-stamp `101,23 % / −251 B` + đổi khung câu hỏi từ "sắp vỡ, chọn gì" sang "đã vỡ, xử thế nào". Hết flag khi `:15` không còn số neo cứng, HOẶC số khớp lần đo mới nhất.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-8 — `view-stale-count` — HIGH
|
||||
|
||||
**view:** `docs/HANDOFF.md:19` slot **(59)** — chuỗi THẬT: `Khoá hẹn nạp nền **40-60K tok**, nhưng đo tươi ĐÚNG 5 nguồn đã khoanh = 71.492 B ⇒ **~20-24K tok ≈ ½ sàn**; đọc rộng nhất có thể vẫn chỉ ~35-41K. Tức **tuân 100% danh sách vẫn dưới hạn** … Sửa mục tiêu xuống, hay mở rộng danh-sách nguồn?`
|
||||
**source:** đo lại @S166 **đúng 5 phạm-vi đã khoanh** trong `memory-budget.json` → `tiep_reload.sources` (STATUS = dòng CURRENT + bảng CURRENT STATE; HANDOFF = segment mới nhất `:1-117`; WAL trọn; `_mind-s-9` trọn; `_context-s-9` trọn):
|
||||
|
||||
| Nguồn (đúng phạm-vi khoanh) | Byte |
|
||||
|---|---|
|
||||
| `docs/STATUS.md` `:6` + bảng `:461-483` | 63.402 |
|
||||
| `docs/HANDOFF.md` `:1-117` | 69.504 |
|
||||
| `.claude/WAL.md` | 3.389 |
|
||||
| `.claude/sessions/session-9/_mind-s-9.md` | 30.573 |
|
||||
| `.claude/sessions/session-9/_context-s-9.md` | 13.781 |
|
||||
| **TỔNG** | **180.649** |
|
||||
|
||||
Dải token theo đúng công-thức `honest_caveats.token_estimate` (`[bytes/4 .. bytes/3.0]`) = **~45-60K tok**.
|
||||
|
||||
Lệch: view nói **71.492 B / ~20-24K tok / "vẫn dưới hạn"**; source nói **180.649 B / ~45-60K tok** = **NẰM TRỌN trong dải mục-tiêu 40-60K**. Số lệch **2,5×** và **kết-luận đã đảo dấu**.
|
||||
|
||||
🔴 Vì sao nguy: câu hỏi trình owner là *"Sửa mục tiêu xuống, hay **mở rộng danh-sách nguồn**?"*. Nếu owner chọn "mở rộng" theo tiền-đề cũ, `/tiep` sẽ bị đẩy **vượt trần trên** 60K — tức quyết-định đúng-theo-tờ-trình lại **gây hại thật**. Đây không phải "số cũ đọc cho vui": nó là **một owner-decision đang treo với dấu ngược**. Nguyên nhân cơ-học rất rõ và sẽ còn tái diễn: 3/5 nguồn (`STATUS`, `HANDOFF`, `_mind`) **phình mỗi phiên**, nên MỌI con số neo cứng ở slot này lão-hoá theo nhịp phiên.
|
||||
|
||||
⚠️ Tự-kiểm (suýt tự bắn): lượt đầu tôi đo **trọn file** ra 424.634 B — sai, vì `tiep_reload.sources` khoanh phạm-vi *"KHÔNG cả file"* cho STATUS và HANDOFF. Số dùng ở trên là bản đo **theo đúng phạm-vi đã khoanh**. Ghi lại để người vá không lặp lỗi so-sánh nhầm đơn-vị.
|
||||
|
||||
**resolve:** re-đo và re-stamp `:19` (hoặc bỏ literal, ghi lệnh đo); và trước khi hỏi owner, nói rõ hiện đã **ĐẠT** dải mục-tiêu ⇒ câu hỏi có thể tự tiêu. Hết flag khi số ở `:19` khớp lần đo theo-phạm-vi mới nhất.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-9 — `view-stale-role-desc` — MED
|
||||
|
||||
**view:** `.claude/agents/cicd-monitor.md:4` (trường `description` — **auto-inject mỗi lượt spawn**) — chuỗi THẬT: `verifies test gate pass (**Domain 58 + Infra 23** tests baseline)`
|
||||
Cùng vết trong thân persona: `:170` `| test_domain | PASS/FAIL (**58** baseline) |` · `:171` `| test_infra | PASS/FAIL (**23** baseline) |` · `:233` `- **Tests baseline:** **111/111** PASS (**58** Domain + **53** Infra)`
|
||||
**source:** đĩa/WAL @S166 — `.claude/WAL.md:13` `suite **614**/0 (**45D+569I**)`, xác nhận lại `:37` `dotnet test SolutionErp.slnx --nologo # 614/0 = 45D + 569I`
|
||||
|
||||
Lệch: view nói Domain **58** / Infra **23** (và một chỗ khác nói Infra **53**), source nói **45 / 569**.
|
||||
|
||||
🔴 Vì sao nguy — không phải "số cũ" mà là **thước gãy trên đúng vai cầm gate**:
|
||||
1. `cicd-monitor` là vai chấm PASS/FAIL sau mỗi push. Baseline Domain **58** > thực-tế **45**: nếu vai tin baseline, trạng-thái ĐÚNG hôm nay bị đọc thành **regression −13**. Domain rơi 58→45 là **hợp lệ** (S61 gỡ `BudgetPolicyTests` cùng lúc XÓA module Budget) — nhưng persona không mang vết đó.
|
||||
2. Infra **23** vs **569** lệch **×24**. Một mốc sai cỡ đó không thể "gần đúng"; nó chứng minh trường này **đã chết từ lâu và chưa ai đọc lại** — tức mọi lượt cicd bấy nay chạy bằng `<count actual>` chứ không bằng baseline, và cái baseline chỉ còn là nhiễu.
|
||||
3. **Tự mâu-thuẫn NỘI-BỘ, bác được không cần rời file:** `:4`/`:171` nói Infra 23 nhưng `:233` nói Infra 53 (58+53=111). Hai mốc khác nhau cùng sống trong một persona ⇒ dù chưa đo đĩa cũng biết ít nhất một cái sai.
|
||||
|
||||
**resolve:** bỏ literal khỏi cả 4 site, thay bằng con-trỏ `docs/STATUS.md` row `Tests` (đúng B1 — và **bỏ số**, không **đổi số**, theo luật `agents/README.md:3` đã tự đặt cho chính họ agents). Hết flag khi `grep -n "baseline" .claude/agents/cicd-monitor.md` không còn con số test nào.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-10 — `view-stale-status` — MED
|
||||
|
||||
**view (3 site, mâu-thuẫn lẫn nhau):**
|
||||
- `CLAUDE.md:17` — chuỗi THẬT: `4. docs/changelog/migration-todos.md ← Atomic tasks theo phase (**Phase 7** PE refinement mới)`
|
||||
- `docs/changelog/migration-todos.md:4` — `Active work: **Phase 9** (UAT + Ops + carry over PE PDF export + Tests Phase 3-5).`
|
||||
- `docs/changelog/migration-todos.md:798` — `## 🎯 **Phase 12** — Dry-run TOÀN TRÌNH đến Hợp đồng cứng **(S160-S162)** — 6/8 wave DONE`
|
||||
|
||||
**source:** `docs/STATUS.md:480` — `**Phase:** ✅ Phase 10 COMPLETE · ✅ **Phase 11 product backlog ĐÓNG TRỌN** …`; và mạch SỐNG hiện tại = SP-002 B4 K1→K8 @S164-S166 (`.claude/WAL.md`, `git log` `50e6d8c`/`0779f2d`/`15349e8`)
|
||||
|
||||
Lệch: **ba** con trỏ "việc đang ở đâu" chỉ ba nơi khác nhau (Phase 7 · Phase 9 · Phase 12) và **không cái nào** khớp source (Phase 10/11 đã đóng, việc sống là chuỗi K của SP-002). Riêng nhãn phạm-vi `(S160-S162)` ở `:798` cũng đã trễ 4 nhãn phiên.
|
||||
|
||||
🔴 Vì sao nguy: `CLAUDE.md:17` nằm trong danh sách **"5 file đọc trước tiên"** — nó là câu đầu tiên một phiên mới nghe về roadmap, và nó đang nói *Phase 7*. Ba nguồn lệch nhau còn tệ hơn một nguồn sai: người đọc không có cách chọn, nên sẽ tin cái gặp trước.
|
||||
|
||||
Ghi chú ranh-giới: chuỗi K1-K3 **hoàn toàn vắng** trong `migration-todos.md` (`grep "K1\|K2\|K3\|SP-002\|Mig 70\|Mig 71"` = **0 hit**/822 dòng) — cái VẮNG đó là turf `lead-gap-auditor`; ở đây tôi chỉ tính phần **có-nhưng-lệch** (3 nhãn phase).
|
||||
|
||||
**resolve:** `CLAUDE.md:17` bỏ ngoặc-phase (trỏ file, không trỏ số phase) · `migration-todos.md:4` cập-nhật "Active work" · `:798` nới nhãn phạm-vi. Hết flag khi 3 site không còn khẳng-định phase nào khác nhau.
|
||||
|
||||
---
|
||||
|
||||
## FLAG-11 — `view-stale-status` — LOW
|
||||
|
||||
**view:** `docs/governance/README.md:5` — chuỗi THẬT: `> **Status:** ✅ Active trial week 1-4 (2026-05-26 → 2026-06-23)`
|
||||
**source:** hôm nay **2026-08-01** — cửa-sổ trial đã đóng **39 ngày**; và RAG delegation đã đi xa hơn hẳn nấc "trial" (`docs/STATUS.md:477` row `RAG chunks` đang theo dõi 2 trục service-liveness / index-freshness với số đo LIVE `solution_erp` 2449)
|
||||
|
||||
Lệch: view treo trạng-thái **"đang thử nghiệm, tuần 1-4"**, source cho thấy giai-đoạn ấy kết-thúc từ lâu và chưa ai lật nhãn. `git log -1` file này = `72bbfa5` **2026-06-02** — không ai chạm suốt 2 tháng.
|
||||
|
||||
🔴 Vì sao nguy (và vì sao vẫn chỉ LOW): tự-thân nó không lái quyết-định nào hôm nay ⇒ LOW. Nhưng nó là **ca mẫu cho một điểm mù của máy** mà tôi phải nói rõ, vì đây đúng chỗ máy im: detector `H24-1 title-freshness` chỉ parse được **2 doc** trong toàn repo (`detectors-output.txt:68` — `anchors parsed: 2 doc(s)`) và lấy mốc-phải = **2026-05-12**. Với mốc đó, một header ghi *"đến 2026-06-23"* trông **mới hơn mốc** ⇒ máy **không thể** kêu. Nói cách khác: "0 flag ở trục H24-1" ở đây KHÔNG đọc thành sạch — đúng bài S150, và lần này tôi có ca cụ-thể chứng minh.
|
||||
|
||||
⚠️ Đã loại trừ bẫy #3 (đóng-băng-có-chủ-đích): file này KHÔNG nằm trong `docs/_archive/**`, nó là README **index đang phục vụ** của thư mục governance và tự khai nấc vòng đời ("Adopted / Status") ⇒ nhãn trạng-thái ở đây có nghĩa vụ lật, khác hẳn snapshot lịch-sử.
|
||||
|
||||
**resolve:** lật `:5` sang nấc hiện-hành (vd `✅ Adopted — trial 2026-05-26→06-23 ĐÃ ĐÓNG`) hoặc ghi rõ "frozen-historical". Hết flag khi `:5` không còn mô-tả một cửa-sổ đã qua bằng thì hiện-tại.
|
||||
|
||||
---
|
||||
|
||||
## Nhóm 8 — dư-lượng bất-đối-xứng mirror `fe-admin` ⟂ `fe-user`: SẠCH (đã chạm, có control)
|
||||
|
||||
Control: `git show --name-only --format="" <sha> | grep -c "^fe-admin/\|^fe-user/"` trên đúng 3 commit của chuỗi K (`50e6d8c` K1 · `0779f2d` K2 · `15349e8` K3).
|
||||
|
||||
| Commit | fe-admin | fe-user | Phán |
|
||||
|---|---|---|---|
|
||||
| `50e6d8c` K1 | 3 | 3 | cân |
|
||||
| `0779f2d` K2 | 4 | 4 | cân — từng cặp khớp tên (`KhkkCreatePage`/`KhkkDetailPage`/`KhkkListPage`/`types/khkk.ts`) |
|
||||
| `15349e8` K3 | 3 | 1 | **lệch có lý do, KHÔNG flag** |
|
||||
|
||||
Lý do K3 lệch là **chủ-đích**: cặp mirror thật `pages/khkk/KhkkWorkflowPanel.tsx` **có mặt CẢ HAI** bên; 2 file admin dôi ra là `system/ApprovalWorkflowsV2Page.tsx` (Designer — bề mặt admin-only) và `components/Layout.tsx` (menu Designer). Đúng ghi-chú `CLAUDE.md`: duplicate giữa 2 app là CÓ CHỦ ĐÍCH, và admin có màn quản-trị mà user không có. **Đếm file thô ra "3 vs 1" trông y hệt sửa-một-phía — phải mở tên file mới phân biệt được**; ghi lại để lần sau không tạo dương-giả.
|
||||
|
||||
---
|
||||
@ -59,14 +59,15 @@ Kiến trúc: **.NET 10 Clean Architecture + 2 React FE (admin + user) + SQL Ser
|
||||
- Audit fields: `CreatedAt`, `UpdatedAt`, `CreatedBy`, `UpdatedBy` (`BaseEntity`)
|
||||
- Soft delete: `IsDeleted`, `DeletedAt`, `DeletedBy` (`AuditableEntity`)
|
||||
- Migrations: `dotnet ef migrations add <Name> --project src/Backend/SolutionErp.Infrastructure --startup-project src/Backend/SolutionErp.Api`
|
||||
- **Số migration · bảng hiện tại → [`docs/STATUS.md`](docs/STATUS.md) (canonical — KHÔNG copy số ở đây để tránh drift; Harness-11 B1).** Lịch sử mig gần đây: **+S133 Mig 67 `AddPeApprovedBudgetSnapshot`** (PE freeze ngân sách phiếu DaDuyet — snapshot 11 cột AddColumn chốt tại finalize choke-point + site-5 admin-override + backfill `Sql()` OUTER APPLY 18/18 prod, no new table; display-gate `budgetFrozen` phiếu DaDuyet đọc snapshot/phiếu mới đọc live; gotcha #81-EXT) · **+S97 Mig 60 `AddPeEndedByLevelFinalize` + Mig 61 `BackfillEndedByLevelFinalizeFromChangelog`** (PE cờ RUNTIME finalize-sớm — display đọc runtime thay suy-config; backfill Mig 60 soi nhầm bảng Approvals → Mig 61 đúng Changelogs; gotcha #78/#79) · +S74 Mig 55 `AddCcmNoteToPeWorkItemBudget` (PE CcmNote) · +S73 Mig 54 `AddPeSuggestedAndApprovedPrice` (PE giá đề xuất PRO/CCM). +S69: Mig 53 `AddPeUrgentAndCeoApprovalThreshold` — PE +IsUrgentByPro/Ccm cờ gấp PRO/CCM + ApprovalWorkflow +CeoApprovalThreshold ngưỡng CCM duyệt-final, 3 AddColumn no new table. +S65: Mig 51 `AddDepartmentParentId` Department.ParentId loose-Guid no-FK org-tree phân cấp + Mig 52 `AddHoSoLinkToPurchaseEvaluation` PE HoSoLink nvarchar(1000) hyperlink NAS — cả 2 AddColumn no new table, tables giữ 88. Phase 10 COMPLETE + Phase 11 P11-A→F done — Mig 34-42 HRM/Office/WorkflowApps/Attendance + Contract V2 (32-33) + WireWorkflowApps V2 (41) + LeaveBalance (42) + Holiday filtered-unique (43, S45) + Vehicle/Driver catalog (44, S51) + HRM-catalog filtered-unique 3× (45, S51) + ItTicket SLA (46, S52) + Master filtered-unique 3× (47, S53 gotcha #57 EXT) + Project master fields Year/Investor/Location/Package (48, S55 — AddColumn no new table, kèm nạp 62 dự án + 71 hạng mục + 3 NCC real data từ Excel qua `SeedRealMasterDataAsync` ungated idempotent) + PE gắn Hạng mục công việc WorkItemId loose-Guid KHÔNG FK vật lý (49, S57bis — AddColumn+CreateIndex, no new table) + **Mig 50 `ReplaceBudgetModuleWithPeWorkItemBudgets` (S61, 2026-06-13) — XÓA module Budget cũ, thay bằng `PeWorkItemBudgets` ngân sách per-gói-thầu (1 record/cặp Dự án × Hạng mục, nhập theo role PRO/CCM, vượt ngân sách = cảnh báo mềm cho lưu S62); backfill `BudgetManualAmount→BudgetPeriodAmount` TRƯỚC DropColumn (phiếu UAT giữ số); net bảng 93→88; gotcha #63/#64**. V2 schema history S29-era bên dưới giữ nguyên — Mig 32+33 Plan B Contract V2 cookie-cutter mirror PE Mig 22-26 (S29). Mig 26 `AddPeLevelOpinionsForV2`: bảng mới `PurchaseEvaluationLevelOpinions` UNIQUE composite (PEId, LevelId), FK Cascade Pe + Restrict Level. Section 5 "Ý kiến cấp duyệt" V2 dynamic theo workflow đã pin: forEach Step (Phòng) → forEach Level (Cấp) → forEach NV → 1 OpinionBox. Service `ApproveV2Async` UPSERT auto khi NV duyệt — Q1=1B (sync gắn với Duyệt, KHÔNG form input rời). SignedByUserId track signer thật, FE banner "Admin duyệt thay" khi !== ApproverUserId. Comment empty → "(duyệt — không ý kiến)" placeholder. Phiếu V1 legacy fallback Mig 15 4 box readOnly (data history). Mig 25 `AddIsUserSelectableToApprovalWorkflows`: ALTER `ApprovalWorkflows` +`IsUserSelectable bit` (admin pin/unpin workflow nào cho user pick lúc create phiếu, multi-select độc lập IsActive). Backfill `WHERE IsActive=1 SET 1` giữ behavior cũ. Designer +badge "Cho user chọn" + button Ghim/Bỏ ghim. Workspace filter dropdown chỉ workflows `IsUserSelectable=true`. Mig 22-24 V2 schema (Session 17): `ApprovalWorkflows`/Steps/Levels — Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua ApproverUserId, OR-of-N cùng cấp). PE.ApprovalWorkflowId pin V2. PE.CurrentApprovalLevelOrder track. State machine 5 trạng thái: Nháp / Đã gửi duyệt / Trả lại (Phase riêng TraLai=98) / Từ chối / Đã duyệt. PE Service V2 wire match `actor.Id == ApproverUserId`. Contract V2 ĐÃ WIRE (Mig 32+33 Plan B S29 — cookie-cutter mirror PE V2: `ApproveV2Async` + `ContractLevelOpinions` UPSERT + Workspace V2 Select dropdown). Mig 21 V1 flat workflow vẫn live cho phiếu cũ.)
|
||||
- **Số migration · bảng hiện tại → [`docs/STATUS.md`](docs/STATUS.md) (canonical — KHÔNG copy số ở đây để tránh drift; Harness-11 B1).** Lịch sử mig gần đây: **+S161 Mig 69 `AddContractSigningPlans`** (module MỚI **Kế hoạch Ký kết HĐ** — 7 `CreateTable`, bảng 89→96; menu-key `KeHoachKyKet` sinh **policy** KHÔNG sinh menu-row; gotcha **#85** menu-key OR-gate FE ≠ policy per-action BE) · **+S157 Mig 68 `AddPeAllowApproverDelete`** (PE nút XÓA phiếu ở màn duyệt — AddColumn, no new table) · **+S133 Mig 67 `AddPeApprovedBudgetSnapshot`** (PE freeze ngân sách phiếu DaDuyet — snapshot 11 cột AddColumn chốt tại finalize choke-point + site-5 admin-override + backfill `Sql()` OUTER APPLY 18/18 prod, no new table; display-gate `budgetFrozen` phiếu DaDuyet đọc snapshot/phiếu mới đọc live; gotcha #81-EXT) · **+S97 Mig 60 `AddPeEndedByLevelFinalize` + Mig 61 `BackfillEndedByLevelFinalizeFromChangelog`** (PE cờ RUNTIME finalize-sớm — display đọc runtime thay suy-config; backfill Mig 60 soi nhầm bảng Approvals → Mig 61 đúng Changelogs; gotcha #78/#79) · +S74 Mig 55 `AddCcmNoteToPeWorkItemBudget` (PE CcmNote) · +S73 Mig 54 `AddPeSuggestedAndApprovedPrice` (PE giá đề xuất PRO/CCM). +S69: Mig 53 `AddPeUrgentAndCeoApprovalThreshold` — PE +IsUrgentByPro/Ccm cờ gấp PRO/CCM + ApprovalWorkflow +CeoApprovalThreshold ngưỡng CCM duyệt-final, 3 AddColumn no new table. +S65: Mig 51 `AddDepartmentParentId` Department.ParentId loose-Guid no-FK org-tree phân cấp + Mig 52 `AddHoSoLinkToPurchaseEvaluation` PE HoSoLink nvarchar(1000) hyperlink NAS — cả 2 AddColumn no new table, tables giữ 88. Phase 10 COMPLETE + Phase 11 P11-A→F done — Mig 34-42 HRM/Office/WorkflowApps/Attendance + Contract V2 (32-33) + WireWorkflowApps V2 (41) + LeaveBalance (42) + Holiday filtered-unique (43, S45) + Vehicle/Driver catalog (44, S51) + HRM-catalog filtered-unique 3× (45, S51) + ItTicket SLA (46, S52) + Master filtered-unique 3× (47, S53 gotcha #57 EXT) + Project master fields Year/Investor/Location/Package (48, S55 — AddColumn no new table, kèm nạp 62 dự án + 71 hạng mục + 3 NCC real data từ Excel qua `SeedRealMasterDataAsync` ungated idempotent) + PE gắn Hạng mục công việc WorkItemId loose-Guid KHÔNG FK vật lý (49, S57bis — AddColumn+CreateIndex, no new table) + **Mig 50 `ReplaceBudgetModuleWithPeWorkItemBudgets` (S61, 2026-06-13) — XÓA module Budget cũ, thay bằng `PeWorkItemBudgets` ngân sách per-gói-thầu (1 record/cặp Dự án × Hạng mục, nhập theo role PRO/CCM, vượt ngân sách = cảnh báo mềm cho lưu S62); backfill `BudgetManualAmount→BudgetPeriodAmount` TRƯỚC DropColumn (phiếu UAT giữ số); net bảng 93→88; gotcha #63/#64**. V2 schema history S29-era bên dưới giữ nguyên — Mig 32+33 Plan B Contract V2 cookie-cutter mirror PE Mig 22-26 (S29). Mig 26 `AddPeLevelOpinionsForV2`: bảng mới `PurchaseEvaluationLevelOpinions` UNIQUE composite (PEId, LevelId), FK Cascade Pe + Restrict Level. Section 5 "Ý kiến cấp duyệt" V2 dynamic theo workflow đã pin: forEach Step (Phòng) → forEach Level (Cấp) → forEach NV → 1 OpinionBox. Service `ApproveV2Async` UPSERT auto khi NV duyệt — Q1=1B (sync gắn với Duyệt, KHÔNG form input rời). SignedByUserId track signer thật, FE banner "Admin duyệt thay" khi !== ApproverUserId. Comment empty → "(duyệt — không ý kiến)" placeholder. Phiếu V1 legacy fallback Mig 15 4 box readOnly (data history). Mig 25 `AddIsUserSelectableToApprovalWorkflows`: ALTER `ApprovalWorkflows` +`IsUserSelectable bit` (admin pin/unpin workflow nào cho user pick lúc create phiếu, multi-select độc lập IsActive). Backfill `WHERE IsActive=1 SET 1` giữ behavior cũ. Designer +badge "Cho user chọn" + button Ghim/Bỏ ghim. Workspace filter dropdown chỉ workflows `IsUserSelectable=true`. Mig 22-24 V2 schema (Session 17): `ApprovalWorkflows`/Steps/Levels — Quy trình > Bước (Phòng) > Cấp (N NV cụ thể qua ApproverUserId, OR-of-N cùng cấp). PE.ApprovalWorkflowId pin V2. PE.CurrentApprovalLevelOrder track. State machine 5 trạng thái: Nháp / Đã gửi duyệt / Trả lại (Phase riêng TraLai=98) / Từ chối / Đã duyệt. PE Service V2 wire match `actor.Id == ApproverUserId`. Contract V2 ĐÃ WIRE (Mig 32+33 Plan B S29 — cookie-cutter mirror PE V2: `ApproveV2Async` + `ContractLevelOpinions` UPSERT + Workspace V2 Select dropdown). Mig 21 V1 flat workflow vẫn live cho phiếu cũ.)
|
||||
|
||||
### Modules
|
||||
|
||||
| Module | Namespace | Migration | Trạng thái |
|
||||
|---|---|---|---|
|
||||
| Contract (HĐ) | `Domain/Contracts/` | 1-11 | Feature-complete (7 ContractType × 9 phase) |
|
||||
| PurchaseEvaluation (Duyệt NCC tiền-HĐ) | `Domain/PurchaseEvaluations/` | 12,13,15,49,50,52-61,65-67 | Feature-complete — +Hạng mục (Mig 49) +ngân sách per-gói-thầu role PRO/CCM (Mig 50) +Link hồ sơ NAS (Mig 52) +cờ gấp PRO/CCM + CCM duyệt-final theo ngưỡng (Mig 53) +giá đề xuất PRO/CCM + CCM-note (Mig 54/55) +PRO-split + ghi-chú-giá (Mig 56/57) +multi-winner liên-danh + level-finalize + NS-kỳ-CCM (Mig 58/59) +**`EndedByLevelFinalize` runtime-flag + backfill-fix (Mig 60/61, S97 — gotcha #78/#79)** +multi-NCC per-hạng-mục (Mig 65, S114 — gotcha #81) +duyệt-khoảng giá Min–Max (Mig 66, S117) +**freeze NS phiếu DaDuyet snapshot 11-cột + display-gate `budgetFrozen` (Mig 67, S133 — gotcha #81-EXT indirect-assignment)** +**lũy kế TẠM TÍNH vs CHÍNH XÁC (S134, 0-mig — `ComputePendingAsync` complementary [ChoDuyet-winner vào tạm-tính, nháp list-only] + sub-dòng amber matrix + banner màn duyệt + D4 audit-note changelog)**. Export PDF pending |
|
||||
| PurchaseEvaluation (Duyệt NCC tiền-HĐ) | `Domain/PurchaseEvaluations/` | 12,13,15,49,50,52-61,65-68 | Feature-complete — +Hạng mục (Mig 49) +ngân sách per-gói-thầu role PRO/CCM (Mig 50) +Link hồ sơ NAS (Mig 52) +cờ gấp PRO/CCM + CCM duyệt-final theo ngưỡng (Mig 53) +giá đề xuất PRO/CCM + CCM-note (Mig 54/55) +PRO-split + ghi-chú-giá (Mig 56/57) +multi-winner liên-danh + level-finalize + NS-kỳ-CCM (Mig 58/59) +**`EndedByLevelFinalize` runtime-flag + backfill-fix (Mig 60/61, S97 — gotcha #78/#79)** +multi-NCC per-hạng-mục (Mig 65, S114 — gotcha #81) +duyệt-khoảng giá Min–Max (Mig 66, S117) +**freeze NS phiếu DaDuyet snapshot 11-cột + display-gate `budgetFrozen` (Mig 67, S133 — gotcha #81-EXT indirect-assignment)** +**lũy kế TẠM TÍNH vs CHÍNH XÁC (S134, 0-mig — `ComputePendingAsync` complementary [ChoDuyet-winner vào tạm-tính, nháp list-only] + sub-dòng amber matrix + banner màn duyệt + D4 audit-note changelog)** +**nút XÓA phiếu ở màn duyệt (Mig 68, S157/S162 — `AllowApproverDelete`, AddColumn no new table)**. Export PDF pending |
|
||||
| **ContractSigningPlans (Kế hoạch Ký kết HĐ — KHKK)** | `Domain/ContractSigningPlans/` | **69** | Feature-complete — **Mig 69 `AddContractSigningPlans` (S161, 7 bảng, 89→96)**: CRUD + Dossier 15 policy (W2) · duyệt V2 3-trạm test-before RED→GREEN (W3) · đường-ống HĐ V2 (W6) · bản-cứng **1-MỐC** theo owner *(form điền đủ → duyệt nếu có → upload bản cứng = xong)* (W7) · cây 4-folder GĐ ×2 app (S162). 🔴 Gate quyền dùng **đúng key policy của endpoint** (`KeHoachKyKet`), KHÔNG OR key con — gotcha **#85** |
|
||||
| ~~Budget (Ngân sách dự án)~~ | — | 14 → **Mig 50 DROP** | ⚠️ **REMOVED S61** — module Budget cũ XÓA, thay bằng PE-budget-per-gói-thầu (`PeWorkItemBudgets`). FE pages/types/menu `Bg_*` gỡ hết |
|
||||
| Master (Supplier/Project/Department) | `Domain/Master/` | 2, 10, 48, 51, 62-64 | Feature-complete — +Project fields Year/Investor/Location/Package (Mig 48) +Department.ParentId org-tree (Mig 51) +Supplier expand 30-field/import/publish-state (Mig 62-64) |
|
||||
| Identity (User/Role/Permission/MenuItem) | `Domain/Identity/` | 1, 3, 11 | Feature-complete (30 demo user — 16 sample + 14 Solutions thật) |
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
**(57) 🔄 (51-bis) MỞ LẠI BẰNG THƯỚC TƯƠI** — `cicd-monitor/archive/_INDEX.md` đo lại @S162 = **99,18% / headroom 167 B** (KHÔNG phải 97,45% / 522 B như slot (51-bis) cũ ghi). Vế (c) "chấp nhận vỡ cap ~1-2 phiên nữa" thực chất **còn đúng 1 dòng append**. Chọn: **(a)** split file · **(b)** nâng cap · **(c)** để vỡ. 🔴 *`lead-stale` FLAG-7 HIGH: anh đang chọn trên thước cũ.*
|
||||
|
||||
**(58) 🔄 Trần **`_mind` CỦA PHIÊN-LOGIC HIỆN HÀNH** — câu hỏi thiết kế còn mở; số SỐNG đọc từ máy, CẤM neo literal/tên file ở đây.** 🔴 Số hiện-hành = chạy `python scripts/session_ctx.py mind-check --session <N>` **phép (7)** — đo @S165 SAU khi chèn MIND-2: **84,8% (27.787/32.768 B), dư 4.981 B < 1 block ⇒ cửa `/pause` kế PHẢI nén MIND-1** kèm cấp nơi-đi cho 6 ý chỉ-sống-ở-đó (4 nhánh-loại §B + 2 ý §C — `ctx-verifier` K1/K1-bis @S165; số 65,7% đời trước chết ngay khi MIND-2 chèn — đúng bẫy "sạch lúc HH:MM"). Câu hỏi cho anh GIỮ NGUYÊN nhưng hết khẩn: khi file SỐNG chạm ~90% thì **nâng khoá `mind_ctx_kb`** · **đổi luật nén** · hay **giữ nguyên** (mỗi cửa nén 1 block)? 🧊 *Lineage 2 đời số chết:* 92,5% đo trên `_mind-s-7` đóng băng (báo-động-giả, RÚT @S159) → 89,06% đo trên `_mind-s-8` cuối L8 (thật lúc đó, nhưng L8 đã `_end` ⇒ số lại chết theo file). *(lead-stale FLAG-6/8 @S163: neo tên file = class **tham-chiếu trượt khi phiên-logic sang trang** — chu kỳ 3 của cùng bệnh, cùng họ slot (45).)*
|
||||
**(58) 🔄 Trần **`_mind` CỦA PHIÊN-LOGIC HIỆN HÀNH** — câu hỏi thiết kế còn mở; số SỐNG đọc từ máy, CẤM neo literal/tên file ở đây.** 🔴 Số hiện-hành = chạy `python scripts/session_ctx.py mind-check --session <N>` **phép (7)** — đo @S165 pause-3 SAU MIND-3 + NÉN-MIND-1: **93,3% (30.573/32.768 B), dư 2.195 B ⇒ cửa `/pause` kế PHẢI nén MIND-2 kèm nơi-đi** (MIND-1 đã nén giữ 5-heading + 6 ý chỉ-sống-ở-đó — khuôn nén chuẩn cho lần sau) kèm cấp nơi-đi cho 6 ý chỉ-sống-ở-đó (4 nhánh-loại §B + 2 ý §C — `ctx-verifier` K1/K1-bis @S165; số 65,7% đời trước chết ngay khi MIND-2 chèn — đúng bẫy "sạch lúc HH:MM"). Câu hỏi cho anh GIỮ NGUYÊN nhưng hết khẩn: khi file SỐNG chạm ~90% thì **nâng khoá `mind_ctx_kb`** · **đổi luật nén** · hay **giữ nguyên** (mỗi cửa nén 1 block)? 🧊 *Lineage 2 đời số chết:* 92,5% đo trên `_mind-s-7` đóng băng (báo-động-giả, RÚT @S159) → 89,06% đo trên `_mind-s-8` cuối L8 (thật lúc đó, nhưng L8 đã `_end` ⇒ số lại chết theo file). *(lead-stale FLAG-6/8 @S163: neo tên file = class **tham-chiếu trượt khi phiên-logic sang trang** — chu kỳ 3 của cùng bệnh, cùng họ slot (45).)*
|
||||
|
||||
**(59) `tiep_reload` — mục tiêu và danh-sách nguồn KHÔNG khớp.** Khoá hẹn nạp nền **40-60K tok**, nhưng đo tươi ĐÚNG 5 nguồn đã khoanh = 71.492 B ⇒ **~20-24K tok ≈ ½ sàn**; đọc rộng nhất có thể vẫn chỉ ~35-41K. Tức **tuân 100% danh sách vẫn dưới hạn**, và `/tiep` không có bước %-print nên không máy nào thấy. Sửa mục tiêu xuống, hay mở rộng danh-sách nguồn? *(lead-gap FLAG-4)*
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Ctx soft-memory — SE-form DRAFT (adopt thư `0df10df4` pause-tiep-upgrade-vong-ctx)
|
||||
|
||||
> **Trạng thái: DRAFT chờ anh chốt 4 câu đánh số — CẤM wire trước khi anh duyệt** (cùng khuôn `session-model-se-draft.md` carry (c); chạm nghi-thức `/pause`·`/tiep` = quyền anh).
|
||||
> **Trạng thái: ✅ RATIFIED + ĐÃ WIRE @S153 (OWNER-VETO).** Anh bác (38)(a)-1-vai-gộp, chốt trực tiếp **"Build đủ 3 vai như hub"** qua AskUser ⇒ 3 vai `ctx-curator`/`ctx-verifier`/`ctx-audit` SỐNG trong roster (23, canonical → STATUS §Sub-agents) + máy `session_ctx.py mind-check` chạy mỗi cửa + wire tại `/pause §2.6(C-bis)` · `/tiep §3-ter` · bookend 2 đầu. Các câu đã định-đoạt: **(36)** hub-form spawn mỗi cửa (vai-1 @mỗi-pause = carve-out duy nhất luật "NGỪNG spawn", mirror hub O-1(a)) · **(37)(b)** nạp NỀN RÚT-GỌN theo khoá `tiep_reload` (`tiep.md §3-ter` cite "quyết (37)(b)") · **(38)(b)** 3 vai tách — marker inline dưới. 🧊 *Header cũ "DRAFT chờ anh chốt — CẤM wire" đứng từ S153→S164 SAU khi đã wire = **wired-but-declared-unwired** (ghost-wire chiều ngược, cùng class `closed.md` S146; ring1+ring2 bắt @S163 "ô xanh thủng"). Thân doc dưới GIỮ NGUYÊN dạng draft làm lineage — đọc "đề xuất" là đề-xuất-lúc-viết, không phải trạng-thái.*
|
||||
> Nguồn: broadcast `2026-07-25-Governance-pause-tiep-upgrade-vong-ctx` (sha `0df10df4` — stamp-verify OK @S153, copy `broadcasts/inbox/` root=pending). Hub tự khai: **build xong + gate xanh, dogfood CHƯA có cửa nào chạy qua** — adopt là adopt KHUÔN chưa-kiểm-chứng, lỗi phát hiện thì gửi về hub (hub-owner Q-1: "có j debug sau cũng đc").
|
||||
|
||||
## 1. Bài toán (đúng SE)
|
||||
@ -35,7 +35,7 @@ Suy-biến vô-hại: KHÔNG áp dụng cho SE (SE dùng pause nhiều — kho
|
||||
- **(35) Trần `mind_ctx_kb` = bao nhiêu?** Hub đặt 32KB (O-4, tự khai "số chủ đặt, không rút từ dữ liệu" — tệp cùng-họ lớn nhất hub mới >12KB). SE `session_ctx_kb`=64. Đề xuất: **32** (theo hub, đổi sau khi có số đo SE).
|
||||
- **(36) Nhịp phóng vai kiểm Ctx — cái núm ĐẮT NHẤT** (hub floor ~100K tok/spawn): (a-nguyên) spawn MỖI pause như hub-owner chốt · (b-tiết-kiệm) **máy-$0 chạy mỗi pause, vai chỉ spawn @2 đầu phiên** (khớp ràng "điểm dừng phải RẺ" thư goi-chot khoản 3 — đo SE: pause hiện ~5ms DÒ; +spawn = +phút+100K). Đề xuất: **(b)** — hub tự dặn "chuẩn bị sẵn núm hạ tần suất".
|
||||
- **(37) Nạp-lại-NỀN mặc định @/tiep?** Hub chọn nạp (nền hub ~110K tok). Nền SE đo tươi @S153 = **596.316B ≈ 149-199K tok** (crystallized-backfill LIVE) — nặng hơn hub. (a) nạp full mỗi tiep · (b) **nạp RÚT GỌN** (STATUS dòng CURRENT + HANDOFF segment mới nhất + WAL + `_mind` — ước ~40-60K) · (c) giữ như nay (không nạp, chỉ `_mind`+`_context`). Đề xuất: **(b)**.
|
||||
- **(38) Số vai kiểm Ctx:** (a) **1 vai `ctx-audit` gộp 3 nhịp** (kiểm@pause-draft · đối-chiếu@tiep · soi-chuỗi 2 đầu — vẫn đạt sàn 7: GHI=lead ⟂ KIỂM=vai) · (b) 3 vai tách như hub. Đề xuất: **(a)** — roster 20 đã dày, sàn chỉ đòi ghi≠kiểm; tách thêm khi lộ nghẽn.
|
||||
- **(38) Số vai kiểm Ctx:** (a) **1 vai `ctx-audit` gộp 3 nhịp** (kiểm@pause-draft · đối-chiếu@tiep · soi-chuỗi 2 đầu — vẫn đạt sàn 7: GHI=lead ⟂ KIỂM=vai) · (b) 3 vai tách như hub. Đề xuất: **(a)** — roster 20 đã dày, sàn chỉ đòi ghi≠kiểm; tách thêm khi lộ nghẽn. 🔄 **OWNER-VETO @S153: anh BÁC (a), chốt (b) 3 vai tách như hub — đã wire cả 3.** *"Roster 20" = số lúc viết; nay **23** (+3 chính vai Ctx này — số canonical → STATUS §Sub-agents). Đề-xuất (a) thua không phải vì sai sàn (ghi≠kiểm vẫn đạt) mà vì owner ưu tiên khớp khuôn hub nguyên bản.*
|
||||
|
||||
## 5. Nấc adopt + việc sau khi anh chốt
|
||||
|
||||
|
||||
@ -12,9 +12,12 @@
|
||||
// owner ĐẢO phán quyết S155 (@S164 — "a Chương quyết cái gì cần CEO") ⇒ BE **đã port nhánh finalize cho
|
||||
// KHKK ở K3 cùng wave**, và Designer type-10 đã GỠ rào (`ApprovalWorkflowsV2Page.tsx` — hằng
|
||||
// `earlyFinalizeLocked` xoá hẳn, 2 ô tick sống lại). Đừng đọc file này thành "BE không hỗ trợ".
|
||||
// Panel VẪN không có control riêng cho đường kết-thúc-sớm — nhưng vì lý do KHÁC HẲN: `AllowApproverFinalize`
|
||||
// là cấu-hình PER-CẤP do admin tick ở Designer, BE đọc lúc duyệt để quyết dừng hay trình tiếp CEO. Người
|
||||
// duyệt chỉ bấm "Duyệt" như thường; không có gì để panel render thêm.
|
||||
// 🔴 [F-1 S166 — SUPERSEDE tiếp] Câu cũ "panel không có control riêng cho đường kết-thúc-sớm" HẾT hiệu lực:
|
||||
// gate-K3 chấm nó là F-1 MAJOR (BE `?? true` mà 0 UI gửi false ⇒ trạm CEO chỉ đi được bằng admin bỏ cờ
|
||||
// Designer). Nay panel CÓ ô-tích "Cấp này KẾT THÚC" theo khuôn PE-LIVE S97 = OPT-IN (G-1 reviewer:
|
||||
// PE `useState(false)` :61 — owner đã ĐẢO opt-out S96 → opt-in S97; nhãn cũ "khuôn S96" trích trúng
|
||||
// chú-thích chết). Default KHÔNG tick ⇒ gửi false ⇒ trình tiếp; TÍCH ⇒ true ⇒ BE kết thúc tại cấp.
|
||||
// Ratify default treo 1 câu ở sổ CHỜ-ANH (lật = 1 edit); hành vi mặc định trạm CCM ĐỔI so trước-F-1.
|
||||
//
|
||||
// 🔴 KHÁC PE Ở CHỖ ĐẮT NHẤT: PE nhận `approvalFlow` đã có `status` Done/Current/Pending do BE precompute.
|
||||
// KHKK BE trả CÂY THÔ (`ContractSigningPlanFeatures.cs:112-117` + `:105-110`) — KHÔNG có `status`.
|
||||
@ -79,6 +82,13 @@ export function KhkkWorkflowPanel({
|
||||
const { user } = useAuth()
|
||||
const [action, setAction] = useState<KhkkTransitionActionValue | null>(null)
|
||||
const [comment, setComment] = useState('')
|
||||
// [F-1 S166 · G-1 reviewer] Ô-tích level-finalize theo khuôn PE-LIVE S97 = OPT-IN
|
||||
// (`PeWorkflowPanel.tsx:61` useState(false) — owner đảo opt-out S96 → opt-in S97 "cái này option
|
||||
// thôi"; đừng trích comment S96 chết ở `:769-771` file đó). Default UNCHECKED = duyệt xong TRÌNH
|
||||
// TIẾP cấp sau (fail-mode an toàn: không đọc thì phiếu vẫn lên CEO); TÍCH mới KẾT THÚC tại cấp.
|
||||
// ⚠️ Đổi hành vi mặc định trạm CCM so trước-F-1 (BE `?? true` auto-finalize) — treo 1 câu ratify
|
||||
// owner ở sổ CHỜ-ANH; lật lại = đổi 1 chữ false→true + 2 nhãn dưới.
|
||||
const [applyLevelFinalize, setApplyLevelFinalize] = useState(false)
|
||||
|
||||
const phase = plan.phase as KhkkPhaseValue
|
||||
const steps = plan.workflowSteps ?? []
|
||||
@ -125,6 +135,13 @@ export function KhkkWorkflowPanel({
|
||||
const actorInLevel = isAdmin || actorIsCurrentApprover
|
||||
const blockedByLevel = isWaiting && !actorInLevel
|
||||
|
||||
// [F-1 S166] Ô-tích opt-out hiện theo cờ của ĐÚNG level BE sẽ chấm — mirror `ResolveActingLevel`
|
||||
// (`ContractSigningPlanWorkflowService.cs:455-469`): own-level TRƯỚC (kể cả Admin có slot riêng),
|
||||
// Admin không có own ⇒ level ĐẦU nhóm cùng-order. Soi cờ của level KHÁC là hiện ô-tích nói dối.
|
||||
const actingLevel = currentLevels.find(l => l.approverUserId === user?.id)
|
||||
?? (isAdmin ? currentLevels[0] : undefined)
|
||||
const approverFinalizeEligible = actingLevel?.allowApproverFinalize === true
|
||||
|
||||
// Nút "Gửi duyệt": guard BE là `CreatedBy == actor ∨ DeptManager(cùng phòng) ∨ Admin`
|
||||
// (spec W3 §②-5). FE KHÔNG suy được vế DeptManager — `UserInfo` chỉ có {id,email,fullName,roles}
|
||||
// (`types/auth.ts:1-6`), không có phòng ban. CỐ Ý **không ẩn** nút theo vai: ẩn sẽ giấu nút với
|
||||
@ -134,8 +151,16 @@ export function KhkkWorkflowPanel({
|
||||
|
||||
const transition = useMutation({
|
||||
mutationFn: async (a: KhkkTransitionActionValue) => {
|
||||
// 🔴 BODY LITERAL theo hợp-đồng LEAD chốt: đúng 2 field `action` + `comment`.
|
||||
const body: KhkkTransitionInput = { action: a, comment: comment.trim() || null }
|
||||
// 🔴 BODY theo hợp-đồng LEAD chốt W3 (`action` + `comment`) + [F-1 S166] field thứ 3
|
||||
// `applyLevelFinalize` CHỈ đính kèm khi approve: cấp có cờ gửi giá trị ô-tích, cấp thường
|
||||
// gửi true = no-op (mirror PE `PeWorkflowPanel.tsx:259`; BE `bool? = null` ⇒ absent = true).
|
||||
const body: KhkkTransitionInput = {
|
||||
action: a,
|
||||
comment: comment.trim() || null,
|
||||
...(a === KhkkTransitionAction.Approve
|
||||
? { applyLevelFinalize: approverFinalizeEligible ? applyLevelFinalize : true }
|
||||
: {}),
|
||||
}
|
||||
const res = await api.post<KhkkTransitionResult>(
|
||||
`/contract-signing-plans/${plan.id}/transitions`,
|
||||
body,
|
||||
@ -295,7 +320,15 @@ export function KhkkWorkflowPanel({
|
||||
<button
|
||||
type="button"
|
||||
disabled={blockedByLevel}
|
||||
onClick={() => { if (!blockedByLevel) { setComment(''); setAction(KhkkTransitionAction.Approve) } }}
|
||||
onClick={() => {
|
||||
if (!blockedByLevel) {
|
||||
setComment('')
|
||||
// [F-1 S166 · G-1] reset về default KHÔNG-tick (opt-IN, khuôn PE S97) mỗi
|
||||
// lần mở dialog — lựa chọn tích là per-lượt-duyệt, không dính lần trước.
|
||||
setApplyLevelFinalize(false)
|
||||
setAction(KhkkTransitionAction.Approve)
|
||||
}
|
||||
}}
|
||||
title={blockedByLevel ? 'Cấp hiện tại chỉ người được phân công mới thao tác được.' : 'Duyệt cấp hiện tại'}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-1 rounded border px-2 py-1 text-[11px] font-bold transition',
|
||||
@ -408,6 +441,33 @@ export function KhkkWorkflowPanel({
|
||||
⚠ Kế hoạch bị khoá hoàn toàn (không sửa / không duyệt tiếp). Người soạn phải lập kế hoạch mới.
|
||||
</div>
|
||||
)}
|
||||
{/* [F-1 S166 · G-1/G-5 reviewer] Cấp cấu hình KẾT THÚC (AllowApproverFinalize) = ô-tích
|
||||
OPT-IN, khuôn PE-LIVE S97 (`PeWorkflowPanel.tsx:61` useState(false) + JSX `:772-791`;
|
||||
comment "opt-out S96" ngay trên khối JSX đó là chú-thích CHẾT — G-1 bắt đúng bẫy này):
|
||||
default KHÔNG tick = duyệt xong TRÌNH TIẾP cấp sau; TÍCH = gửi applyLevelFinalize=true
|
||||
⇒ BE kết thúc tại cấp. Không viết "(CEO)" — cấp-sau là gì tuỳ cấu hình quy trình (G-5).
|
||||
KHÁC PE: không nhắc "chọn giá chốt" — KHKK chốt giá per-dòng do BE tự làm ở finalize
|
||||
choke-point (`ApplyApprovedValuesOnFinalize`), panel không có price-picker. */}
|
||||
{action === KhkkTransitionAction.Approve && approverFinalizeEligible && (
|
||||
<div className="mb-3 rounded border border-emerald-300 bg-emerald-50 px-3 py-2 text-[12px] text-emerald-800">
|
||||
<label className="flex cursor-pointer items-start gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5"
|
||||
checked={applyLevelFinalize}
|
||||
onChange={e => setApplyLevelFinalize(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="font-medium">Cấp này KẾT THÚC quy trình</span>
|
||||
<span className="mt-0.5 block text-[11px] text-emerald-700/80">
|
||||
{applyLevelFinalize
|
||||
? 'Đã tích — duyệt xong là kế hoạch "Đã duyệt", KẾT THÚC tại cấp này, KHÔNG trình tiếp cấp sau.'
|
||||
: 'Mặc định: duyệt xong kế hoạch TRÌNH TIẾP lên cấp sau của quy trình. TÍCH vào nếu muốn KẾT THÚC ngay tại cấp này.'}
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
<Label>
|
||||
Ý kiến{commentRequired ? <span className="text-red-500"> *</span> : ' (tuỳ chọn)'}
|
||||
</Label>
|
||||
|
||||
@ -231,6 +231,9 @@ export interface KhkkWorkflowLevelDto {
|
||||
name: string | null
|
||||
approverUserId: string
|
||||
approverFullName: string | null
|
||||
// [F-1 S166] Cờ per-Cấp "được KẾT THÚC quy trình tại cấp này" (admin tick ở Designer).
|
||||
// Panel dùng để hiện ô-tích opt-out khi duyệt — mirror BE `ResolveActingLevel`.
|
||||
allowApproverFinalize: boolean
|
||||
}
|
||||
|
||||
// `ContractSigningPlanWorkflowStepDto:112-117` — chỉ có `departmentId`, KHÔNG có tên phòng.
|
||||
@ -331,6 +334,10 @@ export type KhkkTransitionActionValue =
|
||||
export interface KhkkTransitionInput {
|
||||
action: KhkkTransitionActionValue
|
||||
comment: string | null
|
||||
// [F-1 S166] Opt-out level-finalize (khuôn PE S96): chỉ gửi khi action=approve.
|
||||
// BE `ContractSigningPlanTransitionBody.ApplyLevelFinalize` là `bool? = null` — absent/true
|
||||
// = auto kết-thúc-tại-cấp khi Cấp có cờ; false = người duyệt BỎ tick ⇒ trình tiếp CEO.
|
||||
applyLevelFinalize?: boolean
|
||||
}
|
||||
|
||||
// Response 200 — 3 field, ĐÚNG tên hợp-đồng. `phase` là INT (mirror `KhkkPhase`).
|
||||
|
||||
@ -12,9 +12,12 @@
|
||||
// owner ĐẢO phán quyết S155 (@S164 — "a Chương quyết cái gì cần CEO") ⇒ BE **đã port nhánh finalize cho
|
||||
// KHKK ở K3 cùng wave**, và Designer type-10 đã GỠ rào (`ApprovalWorkflowsV2Page.tsx` — hằng
|
||||
// `earlyFinalizeLocked` xoá hẳn, 2 ô tick sống lại). Đừng đọc file này thành "BE không hỗ trợ".
|
||||
// Panel VẪN không có control riêng cho đường kết-thúc-sớm — nhưng vì lý do KHÁC HẲN: `AllowApproverFinalize`
|
||||
// là cấu-hình PER-CẤP do admin tick ở Designer, BE đọc lúc duyệt để quyết dừng hay trình tiếp CEO. Người
|
||||
// duyệt chỉ bấm "Duyệt" như thường; không có gì để panel render thêm.
|
||||
// 🔴 [F-1 S166 — SUPERSEDE tiếp] Câu cũ "panel không có control riêng cho đường kết-thúc-sớm" HẾT hiệu lực:
|
||||
// gate-K3 chấm nó là F-1 MAJOR (BE `?? true` mà 0 UI gửi false ⇒ trạm CEO chỉ đi được bằng admin bỏ cờ
|
||||
// Designer). Nay panel CÓ ô-tích "Cấp này KẾT THÚC" theo khuôn PE-LIVE S97 = OPT-IN (G-1 reviewer:
|
||||
// PE `useState(false)` :61 — owner đã ĐẢO opt-out S96 → opt-in S97; nhãn cũ "khuôn S96" trích trúng
|
||||
// chú-thích chết). Default KHÔNG tick ⇒ gửi false ⇒ trình tiếp; TÍCH ⇒ true ⇒ BE kết thúc tại cấp.
|
||||
// Ratify default treo 1 câu ở sổ CHỜ-ANH (lật = 1 edit); hành vi mặc định trạm CCM ĐỔI so trước-F-1.
|
||||
//
|
||||
// 🔴 KHÁC PE Ở CHỖ ĐẮT NHẤT: PE nhận `approvalFlow` đã có `status` Done/Current/Pending do BE precompute.
|
||||
// KHKK BE trả CÂY THÔ (`ContractSigningPlanFeatures.cs:112-117` + `:105-110`) — KHÔNG có `status`.
|
||||
@ -79,6 +82,13 @@ export function KhkkWorkflowPanel({
|
||||
const { user } = useAuth()
|
||||
const [action, setAction] = useState<KhkkTransitionActionValue | null>(null)
|
||||
const [comment, setComment] = useState('')
|
||||
// [F-1 S166 · G-1 reviewer] Ô-tích level-finalize theo khuôn PE-LIVE S97 = OPT-IN
|
||||
// (`PeWorkflowPanel.tsx:61` useState(false) — owner đảo opt-out S96 → opt-in S97 "cái này option
|
||||
// thôi"; đừng trích comment S96 chết ở `:769-771` file đó). Default UNCHECKED = duyệt xong TRÌNH
|
||||
// TIẾP cấp sau (fail-mode an toàn: không đọc thì phiếu vẫn lên CEO); TÍCH mới KẾT THÚC tại cấp.
|
||||
// ⚠️ Đổi hành vi mặc định trạm CCM so trước-F-1 (BE `?? true` auto-finalize) — treo 1 câu ratify
|
||||
// owner ở sổ CHỜ-ANH; lật lại = đổi 1 chữ false→true + 2 nhãn dưới.
|
||||
const [applyLevelFinalize, setApplyLevelFinalize] = useState(false)
|
||||
|
||||
const phase = plan.phase as KhkkPhaseValue
|
||||
const steps = plan.workflowSteps ?? []
|
||||
@ -125,6 +135,13 @@ export function KhkkWorkflowPanel({
|
||||
const actorInLevel = isAdmin || actorIsCurrentApprover
|
||||
const blockedByLevel = isWaiting && !actorInLevel
|
||||
|
||||
// [F-1 S166] Ô-tích opt-out hiện theo cờ của ĐÚNG level BE sẽ chấm — mirror `ResolveActingLevel`
|
||||
// (`ContractSigningPlanWorkflowService.cs:455-469`): own-level TRƯỚC (kể cả Admin có slot riêng),
|
||||
// Admin không có own ⇒ level ĐẦU nhóm cùng-order. Soi cờ của level KHÁC là hiện ô-tích nói dối.
|
||||
const actingLevel = currentLevels.find(l => l.approverUserId === user?.id)
|
||||
?? (isAdmin ? currentLevels[0] : undefined)
|
||||
const approverFinalizeEligible = actingLevel?.allowApproverFinalize === true
|
||||
|
||||
// Nút "Gửi duyệt": guard BE là `CreatedBy == actor ∨ DeptManager(cùng phòng) ∨ Admin`
|
||||
// (spec W3 §②-5). FE KHÔNG suy được vế DeptManager — `UserInfo` chỉ có {id,email,fullName,roles}
|
||||
// (`types/auth.ts:1-6`), không có phòng ban. CỐ Ý **không ẩn** nút theo vai: ẩn sẽ giấu nút với
|
||||
@ -134,8 +151,16 @@ export function KhkkWorkflowPanel({
|
||||
|
||||
const transition = useMutation({
|
||||
mutationFn: async (a: KhkkTransitionActionValue) => {
|
||||
// 🔴 BODY LITERAL theo hợp-đồng LEAD chốt: đúng 2 field `action` + `comment`.
|
||||
const body: KhkkTransitionInput = { action: a, comment: comment.trim() || null }
|
||||
// 🔴 BODY theo hợp-đồng LEAD chốt W3 (`action` + `comment`) + [F-1 S166] field thứ 3
|
||||
// `applyLevelFinalize` CHỈ đính kèm khi approve: cấp có cờ gửi giá trị ô-tích, cấp thường
|
||||
// gửi true = no-op (mirror PE `PeWorkflowPanel.tsx:259`; BE `bool? = null` ⇒ absent = true).
|
||||
const body: KhkkTransitionInput = {
|
||||
action: a,
|
||||
comment: comment.trim() || null,
|
||||
...(a === KhkkTransitionAction.Approve
|
||||
? { applyLevelFinalize: approverFinalizeEligible ? applyLevelFinalize : true }
|
||||
: {}),
|
||||
}
|
||||
const res = await api.post<KhkkTransitionResult>(
|
||||
`/contract-signing-plans/${plan.id}/transitions`,
|
||||
body,
|
||||
@ -295,7 +320,15 @@ export function KhkkWorkflowPanel({
|
||||
<button
|
||||
type="button"
|
||||
disabled={blockedByLevel}
|
||||
onClick={() => { if (!blockedByLevel) { setComment(''); setAction(KhkkTransitionAction.Approve) } }}
|
||||
onClick={() => {
|
||||
if (!blockedByLevel) {
|
||||
setComment('')
|
||||
// [F-1 S166 · G-1] reset về default KHÔNG-tick (opt-IN, khuôn PE S97) mỗi
|
||||
// lần mở dialog — lựa chọn tích là per-lượt-duyệt, không dính lần trước.
|
||||
setApplyLevelFinalize(false)
|
||||
setAction(KhkkTransitionAction.Approve)
|
||||
}
|
||||
}}
|
||||
title={blockedByLevel ? 'Cấp hiện tại chỉ người được phân công mới thao tác được.' : 'Duyệt cấp hiện tại'}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-1 rounded border px-2 py-1 text-[11px] font-bold transition',
|
||||
@ -408,6 +441,33 @@ export function KhkkWorkflowPanel({
|
||||
⚠ Kế hoạch bị khoá hoàn toàn (không sửa / không duyệt tiếp). Người soạn phải lập kế hoạch mới.
|
||||
</div>
|
||||
)}
|
||||
{/* [F-1 S166 · G-1/G-5 reviewer] Cấp cấu hình KẾT THÚC (AllowApproverFinalize) = ô-tích
|
||||
OPT-IN, khuôn PE-LIVE S97 (`PeWorkflowPanel.tsx:61` useState(false) + JSX `:772-791`;
|
||||
comment "opt-out S96" ngay trên khối JSX đó là chú-thích CHẾT — G-1 bắt đúng bẫy này):
|
||||
default KHÔNG tick = duyệt xong TRÌNH TIẾP cấp sau; TÍCH = gửi applyLevelFinalize=true
|
||||
⇒ BE kết thúc tại cấp. Không viết "(CEO)" — cấp-sau là gì tuỳ cấu hình quy trình (G-5).
|
||||
KHÁC PE: không nhắc "chọn giá chốt" — KHKK chốt giá per-dòng do BE tự làm ở finalize
|
||||
choke-point (`ApplyApprovedValuesOnFinalize`), panel không có price-picker. */}
|
||||
{action === KhkkTransitionAction.Approve && approverFinalizeEligible && (
|
||||
<div className="mb-3 rounded border border-emerald-300 bg-emerald-50 px-3 py-2 text-[12px] text-emerald-800">
|
||||
<label className="flex cursor-pointer items-start gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5"
|
||||
checked={applyLevelFinalize}
|
||||
onChange={e => setApplyLevelFinalize(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="font-medium">Cấp này KẾT THÚC quy trình</span>
|
||||
<span className="mt-0.5 block text-[11px] text-emerald-700/80">
|
||||
{applyLevelFinalize
|
||||
? 'Đã tích — duyệt xong là kế hoạch "Đã duyệt", KẾT THÚC tại cấp này, KHÔNG trình tiếp cấp sau.'
|
||||
: 'Mặc định: duyệt xong kế hoạch TRÌNH TIẾP lên cấp sau của quy trình. TÍCH vào nếu muốn KẾT THÚC ngay tại cấp này.'}
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
<Label>
|
||||
Ý kiến{commentRequired ? <span className="text-red-500"> *</span> : ' (tuỳ chọn)'}
|
||||
</Label>
|
||||
|
||||
@ -231,6 +231,9 @@ export interface KhkkWorkflowLevelDto {
|
||||
name: string | null
|
||||
approverUserId: string
|
||||
approverFullName: string | null
|
||||
// [F-1 S166] Cờ per-Cấp "được KẾT THÚC quy trình tại cấp này" (admin tick ở Designer).
|
||||
// Panel dùng để hiện ô-tích opt-out khi duyệt — mirror BE `ResolveActingLevel`.
|
||||
allowApproverFinalize: boolean
|
||||
}
|
||||
|
||||
// `ContractSigningPlanWorkflowStepDto:112-117` — chỉ có `departmentId`, KHÔNG có tên phòng.
|
||||
@ -331,6 +334,10 @@ export type KhkkTransitionActionValue =
|
||||
export interface KhkkTransitionInput {
|
||||
action: KhkkTransitionActionValue
|
||||
comment: string | null
|
||||
// [F-1 S166] Opt-out level-finalize (khuôn PE S96): chỉ gửi khi action=approve.
|
||||
// BE `ContractSigningPlanTransitionBody.ApplyLevelFinalize` là `bool? = null` — absent/true
|
||||
// = auto kết-thúc-tại-cấp khi Cấp có cờ; false = người duyệt BỎ tick ⇒ trình tiếp CEO.
|
||||
applyLevelFinalize?: boolean
|
||||
}
|
||||
|
||||
// Response 200 — 3 field, ĐÚNG tên hợp-đồng. `phase` là INT (mirror `KhkkPhase`).
|
||||
|
||||
@ -118,7 +118,11 @@ public record ContractSigningPlanWorkflowLevelDto(
|
||||
int Order,
|
||||
string? Name,
|
||||
Guid ApproverUserId,
|
||||
string? ApproverFullName);
|
||||
string? ApproverFullName,
|
||||
// [F-1 S166] Cờ per-Cấp cho ô-tích opt-out "Cấp này KẾT THÚC" ở panel duyệt (khuôn PE S96).
|
||||
// FE mirror `ResolveActingLevel` (own-level trước, Admin fallback level đầu nhóm) để quyết
|
||||
// hiện ô-tích — thiếu cờ này thì `applyLevelFinalize` của body transition không có UI nào gửi false.
|
||||
bool AllowApproverFinalize);
|
||||
|
||||
public record ContractSigningPlanWorkflowStepDto(
|
||||
Guid Id,
|
||||
@ -635,7 +639,8 @@ public class GetContractSigningPlanQueryHandler(IApplicationDbContext db, ICurre
|
||||
s.Id, s.Order, s.Name, s.DepartmentId,
|
||||
s.Levels.OrderBy(l => l.Order).Select(l => new ContractSigningPlanWorkflowLevelDto(
|
||||
l.Id, l.Order, l.Name, l.ApproverUserId,
|
||||
approverNames.TryGetValue(l.ApproverUserId, out var fn) ? fn : null)).ToList()));
|
||||
approverNames.TryGetValue(l.ApproverUserId, out var fn) ? fn : null,
|
||||
l.AllowApproverFinalize)).ToList()));
|
||||
|
||||
foreach (var l in s.Levels)
|
||||
levelMeta[l.Id] = (s.Order, s.Name, l.Order, l.ApproverUserId);
|
||||
|
||||
Reference in New Issue
Block a user