Files
solution-erp/.claude/workflows/runs/2026-07-15-S119-adap-6-broadcast/sub-task-0.md
2026-07-15 12:45:00 +07:00

182 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# sub-task-0 — LANE W1-① : `scripts/governance-detectors.ps1`
**Role:** implementer · **Run:** 2026-07-15-S119-adap-6-broadcast · **Lane:** W1-①
**File EDITed (only):** `scripts/governance-detectors.ps1` (455 → 715 lines, +267/7)
**VERDICT:** 3/3 việc DONE · fault-inject PASS 2 chiều · **TOTAL FLAGS 42 → 49** · exit 0 · non-ASCII 0
---
## 0. 🔴 4 tiền-đề trong TASK-BRIEF SAI so với đĩa (re-verify từ disk, memory `feedback_resume_premise_reverify`)
| # | Brief nói | Đĩa thật | Bằng chứng | Xử lý |
|---|---|---|---|---|
| P1 | config = `.claude/memory-budget.json` | **KHÔNG tồn tại**. Thật = `.claude/agent-memory/memory-budget.json` | `find . -iname '*memory-budget*'``./.claude/agent-memory/memory-budget.json` | Probe **2 path**, agent-memory/ TRƯỚC; in path đã resolve |
| P2 | STATUS.md:6 ⇒ in `2026-07-14` | **`2026-07-15`** | `git show 3fde8af:docs/STATUS.md` = 07-14 → commit **`4727d16`** (hôm nay 11:20:29, S119 doc-update) đổi thành 07-15 | KHÔNG sửa STATUS (cấm + = bịa). Detector in **07-15** = ĐÚNG |
| P3 | HANDOFF **chưa** backfill `[carry:*]` ⇒ 0-fire | **ĐÃ backfill — 7 khoá** | `grep -o '\[carry:[^]]*\]' docs/HANDOFF.md \| wc -l` = 8 (7 thật + 1 literal format-spec) | Vacuous **vẫn đúng** nhưng **lý-do KHÁC** (§4) |
| P4 | HANDOFF:5 ≈ 46 735 ký-tự | 46 493 ký-tự (drift nhẹ) | python `len()` | Không ảnh hưởng |
> ⚠️ `grep -c` đếm **DÒNG** không đếm **occurrence** → trên mega-line trả `1` ⇒ dễ kết luận nhầm "chưa backfill". Phải `grep -o … | wc -l`.
---
## 1. (A) GAP-3 — +2 token canonical
`Get-StatusValue` cũ resolve 4 token (:154-157). Thêm `menu` + `policy` qua map `$canonRows` (`:170-198`).
**Tên row ĐỌC TỪ ĐĨA, không đoán:**
- `menu``| Menu keys | **54** |` = `docs/STATUS.md:19` ✅ tồn tại
- `policy``| Policies | **216** |`**CHƯA có** (W2 mới thêm — spec v2:197)
**Row thiếu ⇒ FAIL-LOUD + SKIP** (không crash, không im-lặng-xanh):
```
[DETECTOR] MED | docs/STATUS.md | canonical row missing: no '| Policies | **<n>** |' row in
CURRENT STATE -> token 'policy' UNRESOLVED and SKIPPED (scanning nothing, NOT green)
```
Làm generic cho cả 6 token ⇒ row nào mất cũng kêu (0 flag mới cho 4 token cũ vì row đủ).
**stdout thật:**
```
STATUS.md canonical: mig=66 test=509 gotcha=82 table=89 menu=54 policy=MISSING
```
`menu` fire 2 flag thật: `permission-matrix/SKILL.md:3` + `:16` — “~60 menu key” vs canonical 54.
---
## 2. (B) Detector title-freshness — `H24-1`
- `anchor_patterns[]` = **MẢNG 2 DẠNG** (fix C2 quan trọng nhất của lane):
1. `\*\*Last updated:\*\*\s*(\d{4}-\d{2}-\d{2})`
2. `\*\*Status \(post Session \d+ <EM-DASH> (\d{4}-\d{2}-\d{2})\)\:\*\*`
- **Em-dash XÁC MINH BYTE, không đoán** — `grep … | xxd`:
`6f 73 74 20 53 65 73 73 69 6f 6e 20 36 20 `**`e2 80 94`**` 20 32 30 32 36…`**U+2014** ✔ (không phải hyphen)
→ build runtime `$EM_DASH = U @(0x2014)` (thân .ps1 ASCII-only, gotcha #30)
- `grep "Last updated" .claude/skills/` = **0 hit** ⇒ xác nhận: 1-regex + “không anchor ⇒ bỏ qua” **sẽ giết chính positive-control** ⇒ W4 bất-khả-thi.
### 🔴 PARSE NEO-PHẠM-VI — vì sao load-bearing (ĐO THẬT)
`docs/STATUS.md:6` = **69 870 ký-tự / 41 date-token**. Cả 3 chuỗi cấm đều **NẰM TRÊN LINE 6**:
| token | nguồn thật |
|---|---|
| `2026-08-01` | hạn audit tháng tới = **TƯƠNG-LAI** |
| `1987-03-07` | cắt từ mark-id `RC-pqhuy**1987-03-07**-2026-…` |
| `2026-20-42` | cắt từ mark-id `…-**2026-20-42**-…`**tháng 20 ngày 42** |
`grep -o '[0-9]{4}-[0-9]{2}-[0-9]{2}' | sort | tail`**`2026-20-42`**.
⇒ regex “ngày bất kỳ” lấy max ⇒ mốc-phải = rác/tương-lai ⇒ `trái < phải` **không bao giờ đúng****0 flag vĩnh viễn** = tự bóp chết positive-control mà vẫn xanh.
⇒ Fix: capture **chỉ ngày dính anchor** + `TryParseExact` (loại thẳng tháng-20/ngày-42).
- **mốc-phải** = MAX ngày-anchor hợp-lệ toàn corpus = `2026-07-15` @ `docs/STATUS.md:6`
- **`docs/_archive/` LOẠI KHỎI detector này** — snapshot đóng-băng có chủ-đích; “resolve = refresh ngày” sẽ **phá chính bản ghi lịch-sử** ⇒ flag không-thể-giải = nhiễu vĩnh-viễn.
🔴 Loại **CỤC-BỘ** (`$TitleFreshSkip`), **KHÔNG** đụng `Test-Excluded` global → C1/C3 giữ nguyên baseline (nới global = đổi baseline lane khác = vượt quyền).
Khai thật: giữ `_archive` sẽ +2 flag (47→49… thực ra 49→51). Loại đi **vẫn đạt ≥46** ⇒ không có mâu thuẫn số/đúng-đắn.
**stdout thật:**
```
anchors parsed: 5 doc(s) ; moc-phai (newest governance milestone) = 2026-07-15 from docs/STATUS.md:6
anchor 2026-07-15 docs/STATUS.md:6
anchor 2026-07-15 docs/HANDOFF.md:5
anchor 2026-05-12 docs/rag-setup-plan.md:4
anchor 2026-04-30 .claude/skills/permission-matrix/SKILL.md:16
anchor 2026-04-30 .claude/skills/form-engine/SKILL.md:15
```
`permission-matrix/SKILL.md` **FIRE** (76d behind). **KHÔNG sửa** file đó (W4 sở-hữu: fire → reviewer chứng-kiến → rồi mới vá).
> 📌 Cảnh báo cho W4: `docs/changelog/skill-audit-2026-05-late.md:43` có phán-quyết audit CŨ ghi đúng anchor này là *“section header timestamp historical, KHÔNG drift”*. H24/W4 lật lại là đổi-chính-sách có chủ-đích — nhưng nên biết là đang lật, không phải phát-hiện-mới.
---
## 3. (C) Detector carry-age — `H24-2` (INFORM-only)
- `M` = **`h24_cadence.light_every`** đọc từ `.claude/agent-memory/memory-budget.json`. **0 số nhịp hardcode.**
- Shape canonical (owner-decisions Q2): `h24_cadence: { light_every: 6, deep_every: 15, jump_on_class_repeat: 3 }`
- **dòng-carry = đoạn LOGIC**: đọc `-Raw`, split trên marker `NEXT anh|NEXT em`**45 segment** (KHÔNG `Get-Content -TotalCount`: 12 dòng vật-lý, riêng :5 = 46 493 ký-tự).
- Chuỗi tính **chỉ trên segment CÓ carry**; phiên không phát carry **không phá chuỗi**; chỉ khoá vắng trên **dòng CÓ carry** mới reset.
- Charset khoá `[a-z0-9][a-z0-9._-]*` **loại `<`** ⇒ literal **`[carry:<slug>]`** (câu văn ĐỊNH-NGHĨA quy-ước trong HANDOFF) không bị đếm = tránh **TỰ-THAM-CHIẾU** (bài học lead W0.4 #1).
- Thiếu key ⇒ **FAIL-LOUD**, **không** giả-định default.
**stdout thật (repo thật, hôm nay):**
```
config resolved: .claude/agent-memory/memory-budget.json
[DETECTOR] MED | .claude/agent-memory/memory-budget.json | h24_cadence missing - W2 chua land
=> carry-age cadence UNRESOLVED, measuring NOTHING (no default is assumed ...)
HANDOFF logic-segments (NEXT anh/em) = 45 ; of those, carry-lines = 1
[inform] carry 's119-wave' streak=1 carry-line(s) ; M unresolved -> NO aged/not-aged verdict (×7 khoá)
```
### 🔴 KHAI THẬT — VACUOUS, nhưng lý-do KHÁC brief
Brief nói vacuous vì *“chưa backfill”*. **Sai.** Đã backfill 7 khoá. Vacuous vì **cấu-trúc**:
> **CHỈ CÓ ĐÚNG 1 dòng-carry** (seg#0 = `NEXT anh` của S119). Backfill chỉ đóng dấu **block hiện-tại**.
> ⇒ mọi streak = **1**. Với M ∈ {6,15,3} ⇒ **0 fire** — kể cả khi W2 land key.
**Hệ quả thiết-kế (cần lead quyết):** detector đo **streak ĐÓNG-DẤU**, không đo **tuổi thật**.
Bằng chứng cụ thể: `[carry:tra-bui-relogin]` ở seg#0 (S119); mà **seg#2 = `NEXT anh` của S118** nói đúng việc đó (*“tra.bui + 6 NV PRO đăng xuất → đăng nhập lại”*) nhưng **không được đóng dấu** ⇒ tuổi thật ≥2 phiên, detector đọc **1**.
⇒ Chỉ hết vacuous khi **mỗi phiên đóng dấu lại khoá còn mở vào block NEXT mới** (hoặc retro-stamp lịch-sử). Nếu không, streak **kẹt ở 1 vĩnh-viễn** — đây là “xanh từ commit đầu” đúng thứ H24 bảo phải nghi.
---
## 4. 🐞 BUG THẬT bắt được (nếu không fault-inject thì SHIP LỖI)
**PowerShell tên biến CASE-INSENSITIVE**`$M` (cadence) **CHÍNH LÀ** `$m` (biến loop `foreach ($m in [regex]::Matches(...))`).
Match-object **ghi đè** cadence ⇒ `($null -eq $M)` thành **false** ⇒ rẽ nhầm sang `elseif ($n -ge $M)`
```
Could not compare "1" to "[carry:bvaau]". (×7)
```
**nhánh FAIL-LOUD (= nhánh SỐNG hôm nay vì M unresolved) BỊ VỠ**, `[inform]` không in ra.
**Fix:** `$M``$CadenceM`, loop var `$m``$cm` (+ comment cảnh báo tại chỗ).
🔴 `exit 0` **che** lỗi này (detector luôn exit 0) ⇒ chỉ đọc exit-code là **không phát hiện**. Phải đọc stderr.
---
## 5. FAULT-INJECT (cây tạm `$env:TEMP\gd-fi`, chạy `-RepoRoot <cây-tạm>`)
| Ca | Inject | Kỳ vọng | stdout thật | Verdict |
|---|---|---|---|---|
| FI-1(c) | copy `permission-matrix/SKILL.md` anchor `2026-04-30` < mốc-phải | FLAG | `[DETECTOR] LOW \| .claude/skills/permission-matrix/SKILL.md:16 \| title-stale: anchor says 2026-04-30 but newest … 2026-07-15 (76d behind)` | |
| FI-1(d) | sửa anchor `2026-07-15` | hết FLAG | `title-stale flags after repair = 0` ; `moc-phai … from .claude/skills/permission-matrix/SKILL.md:16` | |
| FI-2 | `light_every=1` | 7 FLAG | `M = h24_cadence.light_every = 1 (read from config, not hardcoded)` `gap-carry-aged FLAGS = 7` | |
| FI-2 | `light_every=2` (**biên**) | 0 FLAG | `[ok] carry 's119-wave' streak=1 < M=2` `gap-carry-aged FLAGS = 0` | |
| FI-2 | `light_every=6` | 0 FLAG | `[ok] … streak=1 < M=6` `gap-carry-aged FLAGS = 0` | |
| FI-3 | `probe-garbage.md` anchor = `2026-20-42` | **không nhận** | `probe-garbage adopted as anchor? -> False` | |
| FI-3 | `probe-future.md` anchor `2026-05-01` + cùng dòng `2026-08-01` + 2 mark-id | lấy `2026-05-01` | `anchor 2026-05-01 docs/probe-future.md:3` ; `2026-08-01 -> False` ; `2026-20-42 -> False` ; `1987-03-07 -> False` | |
**FI-2 = bằng chứng acceptance (a):** đổi số trong config output đổi (7 flag 0 flag) **thật sự đọc config**, không hardcode. Biên chính xác tại `M` (1 fire, 2 không).
**Anti-Goodhart:** gate **KHÔNG** xanh sẵn baseline 42, cả 2 detector mới đều fire trên fault-inject cùng tắt khi gỡ fault.
---
## 6. M3 SCOPE — số owner-đã-ký KHÔNG đụng
`git diff -U0` dòng `-` **duy nhất** = 6 dòng canonical-resolve tôi tái-cấu-trúc + 1 dòng `countPatterns` (thêm dấu phẩy). **0 số ngoài-scope bị sửa:**
| Hằng-số | Dòng | Trạng thái |
|---|---|---|
| `$walLineCount -gt 40` (mark `RC-…12-07-2026-11-43-45`) | :459 | nguyên-văn |
| `$ratio -ge 0.5 -and $ratio -le 2.0` | :296 | nguyên-văn |
| `$maxGotcha + 50` | :335 | nguyên-văn |
| `$liveVariants.Count -ge 2` | :439 | nguyên-văn |
---
## 7. ACCEPTANCE (tính TỪ SỐ ĐO)
| # | Tiêu chí | Số đo | Verdict |
|---|---|---|---|
| (a) | config-driven; grep `memory-budget\|ConvertFrom-Json` 0 >0 | **6** hit; FI-2 đổi 1→2 ⇒ 7 flag→0 flag | ✅ PASS |
| (b) | STATUS.md:6 ⇒ in ngày anchor, không ra 3 chuỗi cấm | in **`2026-07-15`**; garbage/future = False ×3 | ⚠️ **PASS-có-caveat** (literal brief `2026-07-14` STALE 1 commit — `4727d16`; §0 P2) |
| (c) | TOTAL ≥ 46 **và** có dòng `permission-matrix/SKILL.md` | **49** (42+7); có **3** dòng permission-matrix | ✅ PASS |
| (d) | exit luôn 0 | `EXIT CODE = 0` | ✅ PASS |
| (e) | non-ASCII = 0 | **0** byte >127; BOM-less | ✅ PASS |
**+7 flag (Compare-Object, không tự đếm tay):** policy-row-missing ×1 · menu ×2 · title-stale ×3 · h24_cadence-missing ×1.
**Dropped flags = NONE** ⇒ không phá detector cũ.
---
## 8. Cần lead xử (ngoài quyền lane W1-①)
1. 🔴 **Hợp-đồng chéo W2:** W1① đọc **`h24_cadence.light_every`** tại **`.claude/agent-memory/memory-budget.json`**. W2 phải land **đúng** path + sub-key đó, nếu không ① fail-loud vĩnh-viễn. (Spec chỉ ghi basename ⇒ mơ hồ.)
2. 🔴 **W2 nâng Sub-agents 12→14** ⇒ nay `menu`/`policy` đã sống, **row `Policies` phải land CÙNG** — nếu không, flag `canonical row missing` ở lại và mọi derived-doc ghi “14” sẽ bị flag stale-vs-12 (spec v2:176 cảnh báo “detector BÃO ⇒ ≥46 thoả bằng RÁC”). Hôm nay 49 **không** chứa rác loại đó.
3. ⚠️ **carry-age vacuous cấu-trúc** (§3) — cần quy-ước đóng-dấu lại mỗi phiên, nếu không detector vô-dụng dù W2 land.
4. ⚠️ **Bug tiền-tồn ngoài lane:** `:361` `$userMemDir = 'C:\Users\pqhuy\.claude\projects\…'` **hardcode tuyệt-đối**, KHÔNG derive `$RepoRoot` ⇒ chạy `-RepoRoot <cây-tạm>` **vẫn đọc user-memory thật** ⇒ fault-inject C1-wikilink không cô-lập được. Không sửa (ngoài 3 việc được giao + đổi baseline).
5. ⚠️ Acceptance (b) literal `2026-07-14` nên sửa thành **“in đúng ngày ở anchor STATUS.md:6”** (số tuyệt-đối tự-lão-hoá mỗi lần STATUS đổi ngày).