276 lines
37 KiB
Markdown
276 lines
37 KiB
Markdown
# sub-reviewer — GATE Fidelity (Phase 3b) /sleep-recovery-memory-l2 — S170
|
||
|
||
> Anti-#53: file này ghi TỪNG MỤC ngay khi có kết luận (flush liên tục). Đọc từ trên xuống = tiến độ thật.
|
||
> Vai: GATE (lead KHÔNG tự chấm Fidelity — G-001). Verdict-only, KHÔNG sửa draft.
|
||
> Run: `2026-08-01-S169-bookend-open` · 16 draft đã qua gate (a) coverage-diff 16/16.
|
||
|
||
## Trạng thái
|
||
|
||
- [x] P1 — FIDELITY-FLAG 4 cờ (`implementer-backend--2026-05-q3`) → **FLAG ĐÚNG nhưng CHƯA ĐỦ (2 MAJOR + 2 MINOR)**
|
||
- [x] P2a — cicd-monitor--2026-05-runs → **PASS-WITH-FIXES** (3 câu hỏi lead đều ĐẠT; 1 con-trỏ CHẾT + 1 keep-vs-drop MAJOR)
|
||
- [x] P2b — test-specialist--baseline-history → **PASS-WITH-FIXES** (nhãn ĐỦ · 0 số bị sửa đẹp · nhưng CENSUS 4-lỗ THIẾU ít nhất 4, có lỗ +23)
|
||
- [x] P2c — implementer-frontend--2026-H2 → **PASS** (14/14 sống, tag NGUYÊN 14/14; auto-refuse = FE-A [cao] đặt ĐẦU; 1 MINOR nén-âm + 1 ghi-chú L1)
|
||
- [x] P2d — investigator-codebase--2026-05-q1 → **PASS-WITH-FIXES** (5/5 claim khớp nguồn; 1 MAJOR: lén sửa 7→6 field không khai)
|
||
- [x] P3 — subsection `### Bổ-sung coverage @P3-gate S170` → **HỢP LỆ VỀ MỤC ĐÍCH, GÂY HIỂU NHẦM Ở DẠNG HIỆN TẠI** (1 dòng gán verdict SAI)
|
||
|
||
---
|
||
|
||
## P1 — FIDELITY-FLAG 4 tên cờ (`implementer-backend--2026-05-q3.gist.draft.md`)
|
||
|
||
**Verdict: nhãn `⚠️ FIDELITY-FLAG … đừng cite như fact` là ĐÚNG và CẦN, nhưng CHƯA ĐỦ.** Phải sửa thêm 2 điểm MAJOR + 2 MINOR trước khi chốt draft.
|
||
|
||
### 1. Sự thật trên đĩa (đo hôm nay, 2 dụng cụ độc lập)
|
||
|
||
Đọc thẳng thân 4 file migration (`src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/`):
|
||
|
||
| Mig | Tên file thật | Cột thật do migration này tạo | Bảng đích |
|
||
|---|---|---|---|
|
||
| 28 | `20260513114505_AddAdvancedOptionsToApprovalWorkflows` | `AllowApproverEditDetails` · `AllowDrafterSkipToFinal` · `AllowReturnOneLevel` · `AllowReturnOneStep` · `AllowReturnToAssignee` · `AllowReturnToDrafter` (6 cột) | `ApprovalWorkflows` |
|
||
| 29 | `20260513130144_RefactorAdvancedOptionsToPerLevelAndDrafterUser` | dời 5 cột sang `ApprovalWorkflowLevels`; riêng `AllowDrafterSkipToFinal` sang **`Users`** | Levels + **Users** |
|
||
| 30 | `20260513160703_AddAllowApproverEditBudgetToLevels` | `AllowApproverEditBudget` — **đúng 1 cột duy nhất** | `ApprovalWorkflowLevels` |
|
||
| 31 | `20260514160124_RefactorSkipToFinalToApproverLevel` | ADD `AllowApproverSkipToFinal` (Levels) + DROP `AllowDrafterSkipToFinal` (Users), **no-backfill** | Levels ← Users |
|
||
|
||
Dụng cụ 1 — `grep -rl <tên> src/Backend` (đã trừ `/obj/` + `/bin/`): 4 tên = **0 / 0 / 0 / 0**; control dương `AllowApproverSkipToFinal` = **54**; control âm `AllowXyzKhongTonTai` = **0**. Khớp draft.
|
||
|
||
Dụng cụ 2 (tôi thêm) — `git log --all --oneline -S "<tên>" -- src fe-admin fe-user`: `AllowDrafterEdit` · `AllowApproverEditSection1` · `AllowEarlyApprove` · `AllowDelegate` = **0 commit trong TOÀN BỘ lịch sử**; control dương `AllowApproverSkipToFinal` = **5 commit** (`15349e8` `0779f2d` `50e6d8c` `df52fa0` `a8027c0`), `AllowApproverEditBudget` = **5 commit** ⇒ dụng cụ có răng. Kết luận nâng cấp từ "nghi" lên **chốt: 4 tên này chưa từng tồn tại trong mã, kể cả thoáng qua rồi bị đổi tên**.
|
||
|
||
### 2. Phán từng tên (draft gộp 4 làm một — sai lớp)
|
||
|
||
| Tên trong verbatim | Phán | Đối-ứng thật |
|
||
|---|---|---|
|
||
| `AllowDrafterEdit` (gán Mig 29) | **tên viết sai — lai ghép 2 cờ thật** | phần "per-NV" thật = `AllowDrafterSkipToFinal` (bảng `Users`); phần "Edit" thật = `AllowApproverEditDetails` (Levels, và là **approver** chứ không phải drafter) |
|
||
| `AllowApproverEditSection1` (gán Mig 30) | **tên viết sai — trôi từ vựng UI** | `AllowApproverEditBudget` |
|
||
| `AllowEarlyApprove` (gán Mig 31) | **tên viết sai nhưng CÓ đối-ứng ngữ nghĩa 1-1** | `AllowApproverSkipToFinal` ("duyệt vượt thẳng tới cấp cuối" = "duyệt sớm") |
|
||
| `AllowDelegate` (gán Mig 31) | **KHÔNG có đối-ứng nào — hạng nặng nhất** | Mig 31 chỉ ADD đúng 1 cột; toàn `src/Backend` không có khái niệm uỷ-quyền duyệt (chỉ `RequestDelegate`/`RequestHandlerDelegate` của framework, 3 file) |
|
||
|
||
⇒ Trả lời câu hỏi lead: **3/4 là tên viết sai của cờ thật (drift từ vựng), 1/4 (`AllowDelegate`) không có bất kỳ đối-ứng nào — không phải "kế hoạch bị bỏ" vì pickaxe cho 0 commit, tức nó chưa từng được viết ra dòng nào.** Cả 2 lớp đều thoả "đừng cite như fact", nên nhãn không sai — nhưng nó che mất chỗ nguy hiểm nhất.
|
||
|
||
### 3. MAJOR-1 — nhãn không phủ CON SỐ "4×", mà con số mới là thứ mang tải
|
||
|
||
Câu trong verbatim (`archive/2026-05-q3.md:16`) là: *"Pattern 7 … **đã proven 4× — strong candidate Layer B promote khi unfreeze**"*, đặt cạnh luật ngay trên nó: *"Pattern proven ≥ 2× qualifies Layer B nominate"*. Nghĩa là **con số 4 là thứ kích hoạt một quyết định**, và nó được suy ra bằng cách đếm chính 4 cái tên vừa bị bác. Một tên là ma, ba tên còn lại đổ về ~3 migration ⇒ "4×" không có chứng độc lập.
|
||
|
||
Nặng hơn: draft dòng 10 tự kê đơn *«ý an-toàn để giữ: "Pattern 7 đã áp 4 lần qua Mig 29/30/31" bỏ tên cờ»*. Đơn này **giữ nguyên khẳng định và vứt đi đúng những token cho phép kiểm lại nó** — sau khi "làm sạch", câu đó thành bất-khả-bác. Thêm nữa nó tự vênh số học: 4 lần qua 3 migration. Con số này cũng đã lan sang `implementer-backend/archive/2026-06.gist.md:53` và `archive/_INDEX.md:38` dưới dạng dữ kiện trần.
|
||
|
||
**Phải sửa:** nhãn FIDELITY-FLAG nêu rõ **"4×" cũng chưa kiểm**; và bỏ/viết lại câu "ý an-toàn để giữ" ở dòng 10 — nếu muốn giữ ý thì giữ dạng không mang số, ví dụ "Pattern 7 lặp qua chuỗi Mig 28→31 (số lần chưa kiểm)".
|
||
|
||
### 4. MAJOR-2 — nhãn nêu "0-hit" nhưng KHÔNG nêu tên cờ THẬT
|
||
|
||
Draft liệt 4 **tên file migration** thật, nhưng người đọc sau cần **tên cột** thật mới có neo dùng được, và chúng chỉ cách 1 lệnh grep (đã liệt ở bảng §1). Ở dạng hiện tại, gist đóng vai trò "cảnh báo có lỗ" thay vì "vá lỗ". Trớ trêu: file gist đời cũ `implementer-backend/archive/2026-05.gist.md:11` đã ghi đúng 1 trong các tên thật (`AllowApproverSkipToFinal`) — tức bản gist MỚI, bản đi cảnh báo sai, lại nghèo thông tin hơn bản cũ.
|
||
|
||
**Phải sửa:** thêm vào nhãn danh sách cột thật kèm bảng đích (tối thiểu 4 cột: `AllowApproverEditDetails` · `AllowDrafterSkipToFinal`→`Users` · `AllowApproverEditBudget` · `AllowApproverSkipToFinal`).
|
||
|
||
### 5. MINOR-1 — gộp sai `AllowEarlyApprove` với `AllowDelegate`
|
||
|
||
Draft viết *"riêng `AllowEarlyApprove`+`AllowDelegate` chưa có đối-ứng nào ở Mig 31 (thật = `AllowApproverSkipToFinal`)"*. Sai: `AllowEarlyApprove` **có** đối-ứng 1-1 chính là `AllowApproverSkipToFinal`; chỉ `AllowDelegate` là không có gì. Gộp 2 ca khác lớp làm mất dấu đúng mục đáng ngờ nhất.
|
||
|
||
### 6. MINOR-2 — số control dương "54 file" không khai bộ lọc
|
||
|
||
Đo lại: `grep -rl AllowApproverSkipToFinal src/Backend` = **86**; **54** chỉ khi trừ `/obj/` + `/bin/`; **12** khi trừ thêm `*.Designer.cs` + `ModelSnapshot`. Cả ba đều là "phép đo" — 54 chỉ tái lập được với bộ lọc chưa được khai. Kết luận 0-hit vững dưới cả 3 bộ lọc (0/0/0) nên verdict không đổi, nhưng số nằm trong sổ trí nhớ phải đi kèm thước, không thì người sau đo ra 86 và tưởng ghi chú sai.
|
||
|
||
### 7. Điểm draft làm ĐÚNG (giữ nguyên, không được hạ)
|
||
|
||
- Có **control âm** (`AllowXyzKhongTonTai`) cạnh control dương ⇒ chứng minh phép đo còn răng, không phải 0-hit do thước hỏng. Đây là chỗ draft vượt chuẩn.
|
||
- Nhãn được **nhân đôi đúng chỗ**: §TỔNG-HỢP (dòng 10) + đầu §Entries (dòng 14) + §Phụ-lục (dòng 46, 50, 53) ⇒ không có đường trích dẫn nào thoát khỏi cảnh báo.
|
||
- Không lén "sửa đẹp" tên cờ trong thân bài: trích dẫn verbatim giữ nguyên chữ sai, đúng nguyên tắc chép-nguyên-văn.
|
||
- Draft anh em `implementer-backend--2026-05-q1.gist.draft.md` **không mang tên bịa** (diễn đạt trung tính "cờ admin bật riêng (thành Mig 30)") ⇒ không lan sang bản đồng lứa. Đã đo: 4 tên chỉ xuất hiện ở q3 draft, 3 dòng, tất cả trong ngữ cảnh nhãn.
|
||
|
||
### 8. Ghi chú lây nhiễm (ngoài phạm vi draft — việc của em-main)
|
||
|
||
Từ vựng bịa đã sống sẵn trong 4 hiện vật trí nhớ: `implementer-backend/archive/2026-05-q1.md:19` · `archive/2026-05.gist.md:11` · `archive/2026-06.gist.md:53` (số "4×") · `archive/_INDEX.md:15`.
|
||
🔴 **Cảnh báo khi dọn:** `_INDEX.md:15` dùng tên sai **bên trong con trỏ** `substring:"30 migrations** (+1 Mig 30 AllowApproverEditSection1"`. Con trỏ đó trỏ vào văn bản nguồn, nên **sửa chính tả ở đây sẽ giết con trỏ**. Luật dọn: vá chỗ **khẳng định**, không đụng chỗ **trích để định vị** (use ⟂ mention).
|
||
|
||
---
|
||
|
||
## P2a — `cicd-monitor--2026-05-runs.gist.draft.md` ↔ `archive/2026-05-runs.md` (59.861 B → 30.188 B)
|
||
|
||
**Verdict: PASS-WITH-FIXES.** Cả ba câu hỏi lead đặt ra đều ĐẠT. Nhưng có 1 con trỏ chết (cơ học, đo được) và 1 chỗ bỏ sót đáng kể.
|
||
|
||
### A. Ba câu hỏi lead — trả lời có bằng chứng
|
||
|
||
**A1. Run #217 còn sống? → CÓ.** Sống ở 4 chỗ: cụm D3 (thân bài, mang `a734bf2` + `Service:75-103` + prefix `:472` + "6/6 approval đủ 8 key"), ghi chú hợp nhất đầu §Entries, ghi chú cạnh D3, và §Phụ-lục dòng Run/sha. Con trỏ `→ substring:"a734bf2"` giải được (3 hit trong verbatim). Nội dung độc nhất của #217 — Discovery #5 (`\\SQLEXPRESS` 4 dấu) và khuôn "capture pre-call mutation state" — đều được giữ, lần lượt ở cụm D6 và D9.
|
||
|
||
**A2. Nhãn che mật khẩu chép đúng, không có mật khẩu thô? → ĐÚNG, và không có.** Verbatim dòng 48 ghi `pwd=[đã che 71b7740a — ROTATE REQUIRED]`; draft dòng 100 chép lại **đúng từng ký tự** nhãn đó. Tôi quét toàn draft các token `pwd|password|passwd|mật khẩu`: chỉ ra 4 chỗ, tất cả vô hại — tên biến môi trường `PROD_DB_PASSWORD`, hai mảnh hash bundle chứa chuỗi `PWD-g` (`QZIPWD-g`), và chính dòng nhãn che. **Không có giá trị mật khẩu thô nào.** Draft còn chủ động thêm câu răn "TUYỆT ĐỐI không tra/chép giá trị gốc từ git history" và giữ trạng thái "ROTATE REQUIRED vẫn treo" — đây là xử lý đúng và nên giữ nguyên.
|
||
|
||
**A3. Hợp nhất phần (a) tóm tắt với phần (b) đầy đủ — có chọn bản dày? → CÓ, chọn đúng bản dày.** Cấu trúc verbatim: phần (a) là "Last curate logs" (dòng 12-39, 6 Run), phần (b) là "Run entries archived" (dòng 40-181, 20 Run), phần (c) là "Key patterns extracted" (dòng 182-201). Bốn Run nằm ở cả hai phần là #202 · #203 · #210 · #219 — đúng như draft khai. Đo kích thước từng vùng: (a) 944 B / (b) 5.520 B cho #202; 1.224 B / 5.407 B cho #203; 881 B / 3.854 B cho #210; 1.410 B / 3.509 B cho #219 — phần (b) dày hơn ở cả bốn.
|
||
|
||
Ba dấu vân tay chứng minh draft lấy từ (b) chứ không phải (a):
|
||
|
||
| Dấu vân tay trong draft | Chỉ có ở | Không có ở |
|
||
|---|---|---|
|
||
| biểu thức chính quy `\[Bước (\d+) — Cấp (\d+)\]` | (b) #219, dòng 170 | (a) #219, dòng 36 |
|
||
| `Pe_DuyetNccPhuongAn` Order **6-10** | (b) #210, dòng 150 | (a) #210 chỉ ghi `Order=7` |
|
||
| 4 vị trí `...WorkflowService.cs:204` · `:258-260` · `...DetailFeatures.cs:75-76` · `...Features.cs:314-315` | (b) #202, dòng 90-96 | (a) #202, dòng 16 |
|
||
|
||
Và hai Run chỉ có ở phần (a) — #215, #217 — đều được giữ, đúng như ghi chú tự khai.
|
||
|
||
**Điểm cộng vượt chuẩn:** claim liên file "#215 bản dày nằm ở `cicd-monitor--2026-05-q3` B1" là **thật** — tôi mở q3 draft, cụm B1 có `id=329` · `cdfd542` · `test_infra 51/53` · `#216 id=330 8c05947`, dày hơn hẳn bản tóm tắt ở đây. Hơn nữa q3 B1 ghi ngược lại "bản dày = file này; `cicd-monitor--2026-05-runs` giữ bản mỏng" ⇒ **hai bờ cùng khai**, không phải một bên tự nhận. Đây là cách xử lý trùng lặp liên file đúng chuẩn, nên nhân rộng.
|
||
|
||
### B. MAJOR-1 — một con trỏ substring CHẾT (lỗi cơ học, đo được)
|
||
|
||
Draft khai `pointer-style: substring` ở đầu file, tức mỗi dòng `→ substring:"..."` phải tìm lại được trong verbatim. Tôi chạy toàn bộ 10 con trỏ của file này qua `grep -F` (khớp chuỗi, phân biệt hoa thường):
|
||
|
||
- 9/10 giải được (`098baa6` 3 hit · `f4055a1` 3 · `a734bf2` 3 · `Restart-WebAppPool` 1 · `JsonStringEnumConverter` 4 · `no state change (atomic)` 1 · `AddAdvancedOptionsToApprovalWorkflows` 1 · `ac2c859` 3 · `Key patterns extracted` 1).
|
||
- **1/10 CHẾT: `→ substring:"PRIORITY MAX REINFORCED"` (cụm D7) = 0 hit.** Verbatim dòng 178 viết `priority MAX REINFORCED` — chữ `priority` thường. Draft viết hoa toàn bộ, nên con trỏ không về được nguồn.
|
||
|
||
Cùng lỗi này lặp ở §Phụ-lục "surprise": trích dẫn `"Memory size ... **PRIORITY MAX REINFORCED**"` cũng sai kiểu chữ so với nguồn.
|
||
**Tiêu chí sửa:** đổi con trỏ về đúng chữ nguồn `priority MAX REINFORCED`, hoặc đổi sang chuỗi khác chắc chắn tồn tại; sau đó chạy lại toàn bộ con trỏ của cả 16 draft — đây là phép kiểm rẻ, chỉ một vòng `grep -F`. (Tôi đã chạy sẵn cho 5 file: 4 file kia 0 con trỏ chết, xem từng mục bên dưới.)
|
||
|
||
### C. MAJOR-2 — bỏ mất phần lớn "checklist 10 điểm", đúng thứ draft tự nhận là quý nhất
|
||
|
||
Cụm D9 tự viết: *"checklist 10 điểm ở đây là bản duy nhất liệt kê đủ 10 trong toàn batch A"* và bài học *"nén lại cái đã nén là chỗ dễ mất mã số nhất"*. Nhưng chính draft **không chép 10 mục đó**, chỉ ghi "(liệt kê đủ 10)". Đối chiếu 10 mục ở verbatim dòng 188-197 với draft:
|
||
|
||
- Còn, có ghi rõ số điểm: mục 2 (`HasDefaultValue(false)`), mục 3 (quy tắc migration 3 file), mục 10 (`[FromBody]` record đếm param).
|
||
- Còn, dạng gián tiếp: mục 7 (`AwLevelDto` + `ToDto`), mục 9 (lọc `ApproverUserId == actorId`), một phần mục 6.
|
||
- **Mất hẳn:** mục 1 "Domain entity field", mục 4 "Service handler read field", mục 8 `CreateAwLevelInput` + Update mutation handler. Đo: `CreateAwLevelInput` xuất hiện 3 lần trong verbatim, **0 lần** trong draft; `Domain entity field` và `Service handler read` cũng 1-0.
|
||
|
||
Tức bản chưng cất tự tuyên bố mình là bản duy nhất giữ đủ 10, rồi giữ khoảng 6. Nếu người sau tin câu đó và không mở verbatim, họ mất 3-4 điểm kiểm.
|
||
**Tiêu chí sửa:** hoặc chép đủ 10 mục vào cụm D9 (chúng ngắn, tổng ~10 dòng), hoặc bỏ mệnh đề "bản duy nhất liệt kê đủ 10" và ghi thẳng "đủ 10 mục chỉ có ở verbatim dòng 188-197".
|
||
|
||
### D. MINOR
|
||
|
||
- **D-1. Trích dẫn bị cắt mà không có dấu lược.** Draft ghi `"NV Test actor variant **not feasible** (scanned 20 PEs)"`; nguồn là `... (scanned 20 PEs — NV Test = Drafter not approver)`. Draft tự đóng ngoặc, biến một câu bị cắt thành câu trọn. Không sai dữ kiện, nhưng đã đặt trong ngoặc kép thì nên có dấu lược.
|
||
- **D-2. Số lần củng cố Discovery #3 vênh nhau trong chính draft.** Thân bài cụm D2 ghi "chốt sau **3 lần** củng cố"; §Phụ-lục ghi "củng cố **4 lần**: #200/#201/#202 + #210 'NOT applicable'". Nguồn tự mâu thuẫn thật (verbatim dòng 157 tiêu đề ghi "RE-CONFIRMED 4th time" rồi thân ngay dưới ghi "does NOT reinforce the anomaly hypothesis"), nên đây là **trung thành với nguồn**, không phải bịa. Nhưng nên nói thẳng "nguồn tự mâu thuẫn" thay vì để hai con số khác nhau nằm hai chỗ trong cùng một file — người đọc sẽ tưởng bản nén cẩu thả.
|
||
|
||
### E. Không phát hiện bịa hay lệch nghĩa
|
||
|
||
Mọi mã số tôi lấy mẫu đều truy được về nguồn: 4 vị trí `file:line` của Plan O (verbatim 90-96), `111/111 test baseline +3` (dòng 16, 90), 8 mục "Key patterns" khớp đúng thứ tự và đúng nội dung (dòng 184-201), backfill `48/48` và `0/13`, chuỗi test-count `84 → 103 → 104 → 106 → 108 → 111`. Bốn trích dẫn tiếng Anh trong mục "surprise" mà tôi kiểm khớp chữ đúng nguyên văn (`Anomaly is BENEFICIAL`, `all missed across 3 plan`, `no state change (atomic)`, `8 surface points checklist`). Riêng phần "🔐 secret" là xử lý mẫu mực.
|
||
|
||
---
|
||
|
||
## P2b — `test-specialist--baseline-history.gist.draft.md` ↔ `archive/baseline-history.md` (32.069 B → 27.359 B)
|
||
|
||
**Verdict: PASS-WITH-FIXES.** Hai câu hỏi lead đặt ra đều ĐẠT, và đạt tốt. Nhưng tôi tìm thêm một lỗi mà draft chưa thấy, thuộc đúng loại nó đang canh.
|
||
|
||
### A. Hai câu hỏi lead — trả lời có bằng chứng
|
||
|
||
**A1. 4 lỗ + 2 mâu thuẫn có được giữ nguyên kèm nhãn? → CÓ, nhãn đủ và đặt đúng chỗ.** Cụm TS-A dòng 19 mang nguyên câu `⚠️ mâu-thuẫn nội-tại văn-bản — KHÔNG tự sửa số @S170`, và nhãn được nhắc lại ở §TỔNG-HỢP dòng 7 — tức người đọc gặp cảnh báo trước cả khi vào thân bài. Tôi kiểm cả hai mâu thuẫn trên nguồn:
|
||
|
||
- **Mâu thuẫn (a) — có thật.** Tiêu đề verbatim dòng 24 ghi `+10 -> 519`, thân dòng 25 ghi `+9 test vào PeBudgetFreezeTests` rồi lại ghi `(464+10 khớp)`. Cách hoà giải draft đề xuất — T0 của INV-A (+1) cộng T1-T9 của INV-C (+9) — khớp với dòng 28 (INV-A dựng T0, sau INV-B thì T0 xanh). Draft ghi rõ "hoà giải KHẢ DĨ, **chưa xác minh**" ⇒ đúng mức, không tự nâng giả thuyết thành kết luận.
|
||
- **Mâu thuẫn (b) — có thật.** Verbatim dòng 18-19 (S153, 2026-07-26) ghi `baseline 509 KHÔNG đổi`, trong khi S134 (2026-07-17, trước đó 9 ngày) đã ghi 528 và S155 (2026-07-27, ngay sau) ghi 561. Con số 509 thuộc mốc S118b, tức trễ hai nấc. Draft nói rõ đây là mâu thuẫn **trong văn bản**, không phải phán quyết về baseline thật, và nêu lý do không thể phán (curator chỉ đọc file, không chạy `dotnet test`). Đây là cách khai giới hạn đúng chuẩn.
|
||
|
||
**A2. Có lén "sửa đẹp" số nào không? → KHÔNG. Tôi đối chiếu từng mắt xích.** Chuỗi gốc ở draft dòng 17 so với verbatim dòng 13: 16 mốc `254 · 263 · 286 · 292 · 306 · 334 · 339 · 344 · 351 · 354 · 366 · 371 · 374 · 377-395 · 402 · 419` — **trùng khít, kể cả các delta** (`+22/−14`, `+23`, `+6`, `+14`, `+28`, `+5`, `+5`, `+7`, `symmetric superseded`, `S78-S84 chưa ghi delta`, `+5`, `+3`, `S86-S86d`, `+7`, `+6`). Khác biệt duy nhất là một dấu hai chấm thêm vào sau `S61` — thuần hình thức.
|
||
12 mốc hậu chuỗi cũng khớp từng cái với tiêu đề entry trên đĩa: `431→434 (S92 +3)` · `440 (S97 +0)` · `440→450 (D3 +10)` · `450→458 (D4 +8)` · `458→477 (S113 +19)` · `486→495 (S116 +9)` · `495→500 (S117 +5)` · `501→505 (S118 +4)` · `505→509 (S118b +4)` · `519 (45D+474I)` · `528 (45D+483I)` · `561 (+10; 560/1; 45D+516I)`.
|
||
**Điểm tinh tế đáng khen:** ở mốc S133 draft **cố ý không viết "+10"** mà viết thành phần `Domain 45 + Infra 474` — tức nó tránh khẳng định lại chính con số đang tranh chấp, thay vì im lặng chọn một phía. Đó là xử lý đúng.
|
||
Số đếm meta cũng đúng: draft khai "16 mốc chuỗi gốc + 12 mốc hậu chuỗi" — tôi đếm lại: 16 và 12. Ghi chú `nguồn-đếm` khai "đĩa đo 30 heading `##`" — tôi chạy `grep -c "^## "` = **30**. Khớp.
|
||
|
||
### B. MAJOR — bản kiểm kê "4 LỖ" tự nhận là đủ, nhưng thiếu ít nhất 4 lỗ nữa, trong đó có lỗ lớn gấp đôi cả bốn cộng lại
|
||
|
||
Draft dùng đúng một định nghĩa "lỗ": số đầu của một mốc không nối được với số cuối của mốc liền trước. Áp lại chính định nghĩa đó lên toàn chuỗi (số liệu lấy từ chính draft, không cần mở thêm nguồn):
|
||
|
||
| Đoạn | Delta khai | Delta thật | Chênh | Draft có gắn cờ? |
|
||
|---|---|---|---|---|
|
||
| 254 → 263 (S61) | +22 rồi −14 ⇒ +8 | +9 | **+1** | ✗ |
|
||
| 402 → 419 (D2) | +6 | +17 | **+11** | ✗ |
|
||
| 419 → 431 | — | +12 | +12 | ✓ lỗ ① |
|
||
| 434 → 440 | — | +6 | +6 | ✓ lỗ ② |
|
||
| 477 → 486 | — | +9 | +9 | ✓ lỗ ③ |
|
||
| 500 → 501 | — | +1 | +1 | ✓ lỗ ④ |
|
||
| 519 → 528 (S134) | +8 (Infra 474→483) | +9 | **+1** | ✗ |
|
||
| 528 → 561 (S155) | +10, và tự khai "Infra cũ **506** nguyên vẹn" trong khi S134 để lại 483 | +33 | **+23** | ✗ |
|
||
|
||
Bốn lỗ được gắn cờ cộng lại là 28 test. Bốn lỗ **không** được gắn cờ cộng lại là 36 test, riêng đoạn S134→S155 đã là 23. Nghịch lý là draft **có chép đủ số để tự phát hiện** — nó viết `528 (45D+483I)` và `561 (45D+516I)` cạnh nhau, chỉ thiếu bước trừ.
|
||
|
||
Vì sao đây là MAJOR chứ không phải chuyện nhỏ: câu "**4 LỖ**" là một con số đóng vai "đã soi hết". Người đọc sau sẽ hiểu là ngoài bốn chỗ đó thì chuỗi liền mạch, và sẽ dùng chuỗi làm bằng chứng "không hồi quy" — đúng công dụng mà TS-A nói là ruột của file. Một lỗ 23 test nằm ngoài danh sách phá hỏng chính công dụng ấy.
|
||
|
||
**Tiêu chí sửa:** hoặc bổ sung 4 lỗ trên vào danh sách và đổi tổng, hoặc bỏ con số "4" và viết "các lỗ đã soi được (danh sách chưa chắc đủ)". Tuyệt đối không sửa số gốc — nhãn "KHÔNG tự sửa số @S170" vẫn đúng và phải giữ.
|
||
|
||
### C. Không phát hiện bịa hay lệch nghĩa
|
||
|
||
Các cụm còn lại khớp nguồn khi lấy mẫu: TS-B (T26 giữ đỏ — `PeSoftDeleteFeatures.cs:126` thêm changelog, `:142` `Remove(pe)`, `CascadeDeleteTiming.Immediate`, `Added→Detached`, `rowsInDb=0`, `SoftDeleteFixture` là fixture đầu tiên wire `AuditingInterceptor`) khớp verbatim dòng 16 gần như nguyên văn. TS-C (18/18, `inject_A` neo `## MIND-1` sau `renum`, `str.find` = −1, "fixture hỏng cho xanh trông y hệt máy đúng cho xanh") khớp dòng 19. TS-D (`GetPurchaseEvaluationQuery` mới là tên thật, spec ghi nhầm `GetPurchaseEvaluationDetailQuery`, RED thật `Failed 1/1` tại `PeBudgetFreezeTests.cs:184`) khớp dòng 28. Mười con trỏ `substring` của file này **giải được cả 10** (`Count progression` · `PeDeleteByApproverTests` · `inject_A` · `wf_d9639faa` · `PePendingAccumulationTests` · `ProcurementMasterAccessSeedTests` · `TargetParameterCountException` · `truonggiang` · `ApplyDrafterBypassOnSubmitAsync` · `ExecuteUpdateAsync`).
|
||
Tinh thần "REPORT, KHÔNG tự sửa" được giữ nhất quán ở cả bốn ca (T26 bug prod · gap `mind-check` · NRE `Code = r.Code!.Trim()` · spec sai tên query) — đúng vai.
|
||
|
||
---
|
||
|
||
## P2c — `implementer-frontend--2026-H2.gist.draft.md` ↔ `archive/2026-H2.md` (22.215 B → 29.828 B)
|
||
|
||
**Verdict: PASS.** Đây là bản chưng cất tốt nhất trong bốn cặp tôi soi. Hai câu hỏi lead đều ĐẠT, có đo.
|
||
|
||
### A. Hai câu hỏi lead
|
||
|
||
**A1. 14/14 mục moved-not-cut còn sống? → CÓ, và giữ được thứ quan trọng hơn cả nội dung: chuỗi tag.**
|
||
Verbatim có đúng **14** tiêu đề `##`. Draft gom thành 11 cụm nhưng **không mục nào bị nuốt**: 9 cụm đơn (FE-A → FE-I) + 1 khối FE-J1..J5 giữ 5 danh tính riêng, mỗi mục con có tag riêng và **con trỏ riêng** (`→ substring J1:"sub-slot-prop" · J2:"anchor-by-visible-text" · J3:"spread-conditional-before-as-cast" · J4:"sign-toggle-immediate-commit" · J5:"publish-not-update"`) + 1 cụm FE-M được ghi rõ là `[CHỈ-MỤC, không thay thế mục nào]`. Cộng lại 9 + 5 = 14.
|
||
|
||
Phép đo quyết định: tôi rút **toàn bộ chuỗi tag** từ verbatim rồi tìm từng chuỗi trong draft — **14/14 chuỗi có mặt, mỗi chuỗi 2 lần** (một ở tiêu đề cụm, một ở phụ lục coverage). Không chuỗi nào bị rút gọn hay viết lại. Đây đúng là ràng buộc mà chính draft tự đặt ở dòng 15 ("mất tag = con trỏ MEMORY trỏ vào hư không") — và nó tự giữ được lời.
|
||
|
||
**A2. Mục auto-refuse có tag cao? → CÓ, và còn hơn thế.** FE-A mang `[cao]`, đứng **vị trí đầu tiên** trong §Entries, được nhắc lại ở §TỔNG-HỢP dòng 10, và ràng buộc "mục auto-refuse (FE-A) tag {cao}" được chép thẳng vào dòng 15 để đời sau không hạ nó xuống. Phần BẤT-NGỜ của FE-A còn nói đúng lý do nên đặt cao: *"một ghi chú 'không làm gì cả' lại là mục đáng giữ nhất nhóm — nó định nghĩa cái vai này KHÔNG nhận"*. Nội dung khớp verbatim dòng 78-81 cả hai vế (việc dưới 30 phút; không hạ sàn mirror-SHA ×2 app + `npm build` ×2).
|
||
|
||
### B. Kiểm bịa / lệch nghĩa — lấy mẫu cụm nặng nhất (FE-B ↔ verbatim dòng 29-33)
|
||
|
||
Đối chiếu từng chi tiết: `setState` gọi trong lúc render ⇒ React huỷ render và render lại trước khi commit ✓ · harness bản 1 đọc `phase=3` và **control âm cũng ra 3** ⇒ phép đo mất khả năng phân biệt ✓ · vá bằng lặp tới khi state đứng yên ⇒ A ra `phase=2`, control âm giữ `3` ✓ · `KpiCard onClick setPhase :153` ✓ · `chipPhase: T|null|undefined` với `undefined` = "nghe URL" ≠ `null` = "chọn Tất cả" ✓ · reset trong render theo `navKey`, không dùng `useEffect` ✓ · BE `/deleted` thiếu `group` (`Controller:61-66` so `List:42`) ✓ · staticMap fe-user 6/6 so fe-admin 5/6 lệch có chủ đích ✓. **Không có chi tiết nào bịa, không có chi tiết nào đổi nghĩa.**
|
||
Bốn cặp SHA của K4b/K5 cũng còn: `fc3944df` · `545b4c2f` · `7a99b865` (đứng yên = đối chứng dương, xuất hiện 2 lần) · `edff9931` · `bed52f39` · hash build `index-C4F7kHKT`. Mười con trỏ `substring` **giải được cả 10**.
|
||
|
||
### C. MINOR — hai chi tiết của K4b rơi khỏi cả thân bài lẫn phụ lục
|
||
|
||
- `lastPresetGroup` (bài học CreatePage: 8 leaf chung một route nên leaf→leaf không remount ⇒ phải so `lastPresetGroup` chứ **không** so `approvalGroup`, so nhầm thì người dùng bấm đổi nhóm bị kéo ngược và ô chọn thành nút chết) — **0 hit trong draft**. Đây là một cái bẫy cụ thể, có thể tái diễn, và là mục duy nhất trong K4b không được giữ.
|
||
- `4 FLAG` (số cờ K4b báo lên lead) — 0 hit. Nhẹ hơn, nhưng là con số bàn giao.
|
||
**Tiêu chí sửa:** thêm một câu cho `lastPresetGroup` vào FE-B (mục BẤT-NGỜ hoặc BÀI-HỌC). Không bắt buộc với "4 FLAG".
|
||
|
||
### D. MINOR — bản "gist" này KHÔNG nén: nó phình 134% so với nguồn
|
||
|
||
Đo: nguồn 22.215 B; draft 29.828 B, trong đó thân bài (dòng 1-98) **21.826 B** và phụ lục token 8.002 B. Nghĩa là **riêng thân bài đã bằng 98% nguồn**, phụ lục cộng thêm 36%. So với ba file cùng đợt: `cicd-monitor--2026-05-runs` còn 50%, `investigator-codebase--2026-05-q1` còn 80%, `test-specialist--baseline-history` còn 85% — file này là ngoại lệ duy nhất đi ngược chiều (`implementer-backend--2026-05-q3` phình 214% nhưng do gánh khối FIDELITY-FLAG, có lý do riêng).
|
||
|
||
Đây **không phải lỗi trung thực** — nguồn viết dạng điện tín cực nén, draft viết lại thành câu tiếng Việt đầy đủ nên byte tăng là tất yếu, và đó chính là thứ tầng L2 cần. Nhưng nếu mục đích của tầng gist còn gồm **giảm chi phí ngữ cảnh** thì file này không đạt mục đích đó, và lead nên biết bằng số trước khi chốt. Không đề xuất cắt nội dung.
|
||
|
||
### E. Ghi chú ngoài phạm vi draft — con trỏ L1 dùng tag NGẮN HƠN tag verbatim
|
||
|
||
`implementer-frontend/MEMORY.md:46` trỏ mục S152 bằng `[s152, no-lower-bar]`, trong khi verbatim mang `[s152, auto-refuse-trivial-30min, no-lower-bar-smart-friend]`. Tìm bằng mảnh `no-lower-bar` thì vẫn nhảy được (khớp một phần chuỗi dài), nhưng tìm nguyên cụm `[s152, no-lower-bar]` thì trượt. Draft **không có lỗi** ở đây — nó giữ đúng tag nguồn; lệch nằm ở dòng móc L1. Việc của em-main: đồng bộ tag ở `MEMORY.md` với tag verbatim, hoặc chốt luật "móc L1 chỉ dùng một token, không dùng cả cụm ngoặc".
|
||
|
||
---
|
||
|
||
## P2d — `investigator-codebase--2026-05-q1.gist.draft.md` ↔ `archive/2026-05-q1.md` (20.699 B → 16.610 B)
|
||
|
||
**Verdict: PASS-WITH-FIXES.** Năm mẫu tôi bốc đều truy được về nguồn, không mẫu nào bịa. Nhưng có một chỗ draft **tự sửa số của nguồn mà không khai** — đúng loại hành vi mà chính đợt này đang cấm ở file khác.
|
||
|
||
### A. Năm claim lấy mẫu — đối chiếu từng cái
|
||
|
||
| # | Claim trong draft | Nguồn | Kết quả |
|
||
|---|---|---|---|
|
||
| 1 | `PurchaseEvaluationFeatures.cs:765` `FirstOrDefault(l => l.Order == curLevelOrder)` lấy nhầm hàng sau Mig 29 vì `Order` trùng trong cùng Cấp; vá bằng `&& l.ApproverUserId == currentUser.UserId` + fallback cho admin | verbatim dòng 39 + mục root-cause | **KHỚP** |
|
||
| 2 | `canAdjust = !readOnly && (...)` đoản mạch trước khi `isApproverChoDuyet` được xét (`:973`), nút bút chì ẩn ở `:1030`, bản vá đảo vế thành `isAdmin \|\| (!readOnly && isDrafter && isDrafterPhase) \|\| isApproverChoDuyet` và land ở `:977` | verbatim dòng 39 (`line 973`, `line 1030`) và dòng 43 (`line 977`) | **KHỚP từng số dòng** |
|
||
| 3 | Plan R: 35 PE (28 active + 7 soft) · 17 V2 (15 chưa ghim + 2 ghim) · 4 V1 (2 active + 2 inactive); ước ~620 row con = 446 + ~140 + ~37 | verbatim dòng 55, nguyên văn "446 PE children + ~140 V2 + ~37 V1 = ~620 rows" | **KHỚP** — và "~620" là chữ của nguồn, draft không tự làm tròn |
|
||
| 4 | Mốc trạng thái: khởi tạo 2026-05-11 = 44 gotcha + 14 memory + 6 skill + 27 mig + 81 test; S21 = 84 test / 29 mig / 45 gotcha / 19 memory; S22 = 104 test (+20) | verbatim dòng 15, 19, 23 | **KHỚP cả ba mốc** |
|
||
| 5 | Mật khẩu Identity đòi từ 12 ký tự (`User@123456` 11 ký tự trả 400, `TestUser@2026` đạt); sidebar `w-72 xl:w-80` an toàn còn `w-80 xl:w-96` là ngưỡng rủi ro; Designer 975 dòng; trí nhớ khai "3-panel" nhưng đo lại là 2-panel `[260px_1fr] xl:[320px_1fr]` | verbatim: mỗi token đều có mặt (`User@123456` 1 · `TestUser@2026` 1 · `w-80 xl:w-96` 1 · `975` 1 · `2-panel` 2 · `260px_1fr` 1) | **KHỚP** |
|
||
|
||
Bảy con trỏ `substring` của file này **giải được cả bảy**. Không tìm thấy tên file, số dòng hay mã băm nào không có trong nguồn.
|
||
|
||
### B. MAJOR — draft lặng lẽ sửa "7 field" thành "6 field"
|
||
|
||
Verbatim dòng 51 viết: `PeWorkflowPanel.tsx:113-124` ... **SEND ĐÚNG 7 fields** (TargetPhase + Decision + Comment + ReturnMode + ReturnTargetUserId + SkipToFinal). Nguồn nói **7** nhưng liệt kê **6**.
|
||
Draft dòng 24 viết: FE ... **gửi ĐỦ 6 field** (TargetPhase + Decision + Comment + ReturnMode + ReturnTargetUserId + SkipToFinal, ...).
|
||
|
||
Về số học thì 6 nhiều khả năng đúng: BE record giữ 3 field, "bỏ im lặng 3 field còn lại" ⇒ tổng 6. Nhưng đây vẫn là **sửa số của nguồn mà không để lại dấu**, và nó va thẳng vào chuẩn mà chính đợt này đang áp: file `test-specialist--baseline-history` được yêu cầu giữ nguyên số sai kèm nhãn `KHÔNG tự sửa số @S170`. Hai file cùng một đợt, hai chính sách ngược nhau — người đọc sau không biết con số nào trong batch là chữ của nguồn, con số nào đã bị curator chỉnh.
|
||
Cái mất đi cũng thật: nguồn tự mâu thuẫn ở chỗ này, và mâu thuẫn đó là bằng chứng cho đúng bài học của cụm B1-B ("đếm field body so với đếm field command là phép thử rẻ") — chính người viết verbatim cũng đếm nhầm.
|
||
**Tiêu chí sửa:** giữ chữ nguồn và gắn nhãn, ví dụ *"nguồn ghi '7 fields' nhưng liệt kê 6 — lấy 6 theo danh sách; số 7 chưa xác minh"*. Không được im lặng chọn một phía.
|
||
|
||
### C. Không phát hiện lỗi khác
|
||
|
||
Ba verdict phân biệt của cụm B1-A (F3 đúng · F4 hỏng ở FE · lượt thứ ba là báo động giả vì `TraLai=98` không phải `DangSoanThao`) đều giữ đúng ranh giới của nguồn, không bị gộp thành một kết luận. Cụm B1-G tự khai "vai KHÔNG spawn mà vẫn ghi entry ⇒ nguồn nhiễu khi đếm coverage" — đó là tự phê bình đúng chỗ, nên giữ.
|
||
|
||
---
|
||
|
||
## P3 — chấm subsection `### Bổ-sung coverage @P3-gate S170` (lưới token máy tự chèn)
|
||
|
||
**Verdict: HỢP LỆ VỀ MỤC ĐÍCH, NHƯNG GÂY HIỂU NHẦM Ở DẠNG HIỆN TẠI — phải sửa trước khi chốt.** Có mặt ở 9 trong 16 draft.
|
||
|
||
### A. Vì sao hợp lệ
|
||
Mục đích khai ngay ở tiêu đề: giữ **token literal** để lưới `grep` của cổng coverage-diff không báo mất. Nó nằm ở cuối, sau phụ lục, tách khỏi thân bài, và tự nhận là "lưới grep" chứ không nhận là nội dung. Chừng nào chỉ đọc nó như một danh sách token thì không sai.
|
||
|
||
### B. Vì sao gây hiểu nhầm — cơ chế, đo được, tái lập được ở 2 file độc lập
|
||
Lưới in **phần đầu của DÒNG chứa token**, không phải vùng lân cận token. Các file archive này toàn dòng khổng lồ (một entry một dòng), nên đoạn trích in ra thường **không liên quan gì đến token đứng đầu dòng**.
|
||
|
||
1. **Sai nghiêm trọng nhất — gán verdict ngược.** Trong `cicd-monitor--2026-05-runs` dòng 129: token `Run #214` được kèm đoạn trích *"**FAIL** verdict at test_infra gate — 2 Plan M edge case tests broken..."*. Đoạn đó là thân của entry **Run #215**; nó khớp chữ `Run #214` chỉ vì trong đó có câu "bundles unchanged **Run #214** baseline". Sự thật: verbatim dòng 160 ghi `Run #214 ... VERDICT=PASS`. Người đọc lướt lưới sẽ mang đi một mệnh đề sai hẳn.
|
||
2. **Xác nhận độc lập lần hai.** Trong `investigator-codebase--2026-05-q1` dòng 77: token `Mig 27` kèm đoạn trích *"7 commits total `a1a910f..ee0902a`: BE+Layout..."*. Tôi kiểm: `Mig 27` chỉ xuất hiện một lần, ở giữa dòng 63, trong ngữ cảnh nhãn sidebar dài 44 ký tự — còn đoạn in ra chính là 190 ký tự **đầu dòng 63**. Hai file khác nhau, cùng một cơ chế.
|
||
3. **Tạo cảm giác có nội dung ở chỗ trống rỗng.** Cũng ở file cicd, các token `#216` · `#222` · `#227` · `Run #215` · `Run #216` · `Run #222` đều trỏ về **cùng một dòng 7** — một ghi chú kế hoạch curate (*"~5 entries kept: Run #215 fail lesson + Run #216 fix + Run #222-#227 S26..."*). Ba Run #216/#222/#227 **không có entry nào** trong verbatim này; lưới làm chúng trông như đã được phủ.
|
||
4. **Lưới mâu thuẫn với thân bài.** Các token `Run #202` · `#203` · `#210` · `#219` đều trỏ về phần (a) tóm tắt (dòng 14/18/22/34), trong khi thân bài đã cố ý chọn phần (b) dày. Ai tra theo lưới sẽ bị dẫn về đúng bản mỏng mà bản gist vừa loại.
|
||
|
||
### C. Tiêu chí sửa (ba mức, chọn mức nào cũng đủ)
|
||
1. **Rẻ nhất:** đổi câu mở của subsection thành lời cảnh báo đúng bản chất — đại ý *"đoạn trích dưới đây là phần ĐẦU DÒNG chứa token, KHÔNG phải ngữ cảnh của token; chỉ dùng làm lưới grep, không đọc như dữ kiện"*. Câu hiện tại nói "chép NGUYÊN-VĂN context verbatim" là mô tả sai chính nó.
|
||
2. **Đúng hơn:** đổi cách sinh — in vùng lân cận token (kiểu `.{0,120}<token>.{0,120}`) kèm số dòng, thay vì đầu dòng.
|
||
3. **Bắt buộc trong mọi trường hợp:** sửa riêng dòng `Run #214` của `cicd-monitor--2026-05-runs`, vì nó không chỉ vô nghĩa mà còn khẳng định sai (FAIL cho một Run PASS).
|
||
|
||
---
|
||
|
||
FIDELITY: PASS-WITH-FIXES — flag-4-cờ=nhãn ĐÚNG nhưng CHƯA ĐỦ (3/4 tên là drift của cờ thật, `AllowDelegate` 0 đối-ứng · git pickaxe 0 commit cả 4 ⇒ chưa từng tồn tại; phải phủ cờ lên CON SỐ "4×" + bỏ đơn "giữ 4 lần bỏ tên cờ" + thêm tên cột THẬT) · 4-cặp=runs P-fixes · baseline P-fixes · frontend P · investigator P-fixes
|
||
|
||
== HẾT ==
|