Files
solution-erp/.claude/workflows/runs/2026-06-18-h11-implement/sub-task-0.md
pqhuy1987 e70c0462d7 [CLAUDE] Docs: adopt Harness-11 engine tự-bảo-trì (3-workflow audit→implement→review)
- engine-doc canonical docs/governance/harness-11-engine.md (PHẦN A/B/C/D + 3-tier D5/D6/D7 + one-direction-lock D8 + CAVEAT honest)
- scripts/governance-detectors.ps1 (C1 broken-pointer + C2/B3 staleness + C3 vocab-fork + C4 self-exclusion + C5 resolve, NO-API DÒ+FLAG-only, runtime-proven, FP-refined 59→27)
- scripts/memory-archive-gate.ps1 (PHẦN A: hysteresis 0.85 + keep-floor 5 + 2-strike + A7 NO-API L1-eval) + budget.json archive_gate
- B1 ×11 count→canonical-pointer (root CLAUDE.md, ef-core/dep-audit SKILL, skills/README, docs/CLAUDE.md) — drift mig53→55/test306→339/gotcha68→69 RESOLVED + ef-core +Mig 54/55 rows
- cadence-wire D1 session-start §2.1.3 + D2 session-end §L.b(c) + agents/README Upgrade S75
- run-trace TRACKED: audit wf_7fdc3bd5-930 / implement wf_c5e5844e-7c1 / review wf_d7ca1ff8-942 (REVIEW PASS, completeness-gate ĐẠT)
- check-email AI_INFRA harness-11 (verify whole-file 318ff9f6 + body b2a2fc1c) + adap-report + outbox report (body 7fa1b53a)
- 0 production code; state THẬT giữ nguyên (Mig 55 · 88 bảng · 339 test · gotcha 69 · menu 54 · bundle BYF5vIMJ/CB-tiRxd)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 20:44:26 +07:00

125 lines
13 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 — `scripts/governance-detectors.ps1` (Harness-11 PHẦN C + B3)
> Lane **impl-detectors** · owner general-purpose (Write+Bash) · single-writer: CHỈ `scripts/governance-detectors.ps1` + file này.
> NO-API · DÒ+FLAG-only · PowerShell 5.1 · RUNTIME-proven (output thật dán §3).
## 1. Deliverable
`D:\Dropbox\CONG_VIEC\SOLUTION\SOLUTION_ERP\scripts\governance-detectors.ps1` (~355 dòng, ASCII-only body).
3 bộ dò + self-exclusion + summary. Param `$RepoRoot` (default = `Resolve-Path $PSScriptRoot\..`). Exit-code **0 luôn** (dò-only, KHÔNG fail-build). Mỗi FLAG: `[DETECTOR] severity | file:line | desc | resolve: <điều-kiện-gỡ-cờ>` (C5).
## 2. Thiết-kế từng detector
### C2/B3 — derived-staleness (ưu-tiên, value cao nhất) ✅
- **Canonical** đọc từ `docs/STATUS.md` CURRENT STATE table qua regex `^\|\s*<label>\s*\|\s*\*\*(\d+)` (số trong `**N**` đúng row Migrations/Tests/Gotchas/SQL tables). Runtime đọc đúng: **mig=55 test=339 gotcha=69 table=88**.
- **Cross-check disk** (canonical tự-nó không stale):
- `mig` = đếm `*.cs` trong **mọi** dir tên `Migrations` dưới `src` (exclude `bin|obj|node_modules` + `*Designer.cs`/`*ModelSnapshot.cs`). Recursive-search vì migration thật ở `src\Backend\SolutionErp.Infrastructure\**Persistence**\Migrations (SPEC ghi gần-đúng `...\Migrations` — đã xử robust). Runtime: disk mig=55.
- `gotcha` = max N từ `^### (\d+)\.` trong `docs/gotchas.md`. Runtime: disk gotcha=69.
- STATUS-value ≠ disk-value → FLAG `canonical-itself-stale` (HIGH). Lần này KHỚP → 0 HIGH (baseline an-toàn).
- **Derived scan** 5 file: `CLAUDE.md`(root) · `docs/CLAUDE.md` · `.claude/skills/ef-core-migration/SKILL.md` · `.claude/skills/README.md` · `.claude/skills/dependency-audit-erp/SKILL.md`. Count-token regex: `(\d+)\s*migration` · `(\d+)\s*test` · `(\d+)\s*(?:<bay>|gotcha)` · `(\d+)\s*(?:<bang>|table)`. Lệch canonical → FLAG `derived-stale` (MED nếu |lệch|≥10, else LOW).
### C1 — broken-pointer ✅
- **(a) gotcha-ref**: grep `docs/** + .claude/** *.md` bắt `gotcha[s]?\s*#?(\d+)` + bare `#(\d+)`. `gotcha #N` luôn validate (N>max → broken MED; thiếu `### N.` anchor → LOW). Bare `#N` chỉ xét trong range; `#N`>max bỏ qua (tránh nhầm Run #312/PR #). Runtime: **0 flag** — mọi gotcha-ref ≤69 và có anchor (đúng — repo sạch khoản này).
- **(b) wikilink**: scan user-memory `C:\Users\pqhuy\.claude\projects\...\memory\*.md` + in-repo `.claude/agent-memory/**`. Bắt `\[\[([a-z0-9_-]+)\]\]`; target `<name>.md` không tồn tại trong scope → dangling. User-memory KHÔNG reachable → note + agent-memory-only (lần này user-memory REACHABLE, 29 file).
### C3 — vocab-fork ✅
- Seed alias-set: `@('wave-folder','run-trace')`, `@('<Du tru PRO>','<Ngan sach PRO>')`, `@('two-tier','all-inherit')`. Mỗi set đếm file dùng từng biến-thể; ≥2 biến-thể CÙNG sống → FLAG count + sample | resolve gộp/alias-map.
### C4 — self-line exclusion (BẮT BUỘC) ✅
- Exact: `scripts/governance-detectors.ps1`, `docs/governance/harness-11-engine.md`. Dir-fragment: `\broadcasts\inbox\`, `\broadcasts\outbox\`, `\.claude\workflows\runs\`, `\.claude\workflows\scripts\`. `Test-Excluded` áp MỌI scan. Summary in `self-exclusion: N paths excluded` + assert `self in scan=0` + `leaked=0`.
### 🔴 Encoding-robustness (gotcha #30 — phát-hiện lúc RUNTIME, đã FIX)
Vòng-1 detector MISS `CLAUDE.md:133` "68 bẫy" + cả set vocab-fork `Dự trù PRO``Ngân sách PRO`. Root-cause: file `.ps1` ghi **UTF-8 KHÔNG BOM** (Write-tool); `powershell.exe -File` ở PS 5.1 decode file no-BOM bằng **codepage ANSI (1252)**, KHÔNG phải UTF-8 → literal tiếng Việt `bẫy`/`bảng`/`Dự trù` bị mojibake → KHÔNG match content UTF-8 đọc đúng (`Get-Content -Encoding UTF8`). FIX: body **ASCII-only**, mọi token tiếng Việt build từ **Unicode code-point runtime** qua helper `U @(0x62,0x1EAB,0x79)` → encoding-độc-lập. Sau fix: 71 flag (vòng-1 chỉ 53 — thiếu 18 do mojibake). Đây là minh-chứng giá-trị của mandate "viết xong PHẢI chạy thật".
## 3. RUNTIME — output thật (`powershell.exe -ExecutionPolicy Bypass -File scripts/governance-detectors.ps1`)
**Exit code: 0** · **TOTAL FLAGS: 71** (HIGH=0 · MED=33 · LOW=38).
```
===== C2/B3 - canonical resolve + disk cross-check =====
STATUS.md canonical: mig=55 test=339 gotcha=69 table=88
disk cross-check: mig=55 gotcha=69
[OK] canonical matches disk (mig + gotcha) - safe baseline for derived scan
===== C2/B3 - derived-doc staleness =====
[DETECTOR] LOW | CLAUDE.md:53 | derived-stale: writes 53 migration but canonical=55 | resolve: update to 55 OR replace with pointer '-> docs/STATUS.md' <== TRUE drift (root CLAUDE mig)
[DETECTOR] MED | CLAUDE.md:53 | derived-stale: writes 53 gotcha/bay but canonical=69 | resolve: ... <== FALSE-POS ("53" la mig-number, dinh token 'bay'? -> thuc te dong 53 KHONG co 'bay'; xem honesty #2)
[DETECTOR] MED | CLAUDE.md:66 | derived-stale: writes 306 test but canonical=339 | resolve: ... <== TRUE drift (root CLAUDE test)
[DETECTOR] MED | CLAUDE.md:80 | derived-stale: writes 45 test but canonical=339 <== FALSE-POS (45 = Domain breakdown)
[DETECTOR] MED | CLAUDE.md:81 | derived-stale: writes 261 test but canonical=339 <== FALSE-POS (261 = Infra breakdown)
[DETECTOR] MED | CLAUDE.md:84 | derived-stale: writes 6 test but canonical=339 <== FALSE-POS
[DETECTOR] MED | CLAUDE.md:90 | derived-stale: writes 2 test but canonical=339 <== FALSE-POS ('2 test project')
[DETECTOR] LOW | CLAUDE.md:133 | derived-stale: writes 68 gotcha/bay but canonical=69 | resolve: update to 69 ... <== TRUE drift (root CLAUDE '68 bay') -- VONG-1 BI MISS, sau fix encoding moi bat
[DETECTOR] MED | docs/CLAUDE.md:13 | derived-stale: writes 4 table/bang but canonical=88 <== FALSE-POS ('4 bang Budget' module-local)
[DETECTOR] LOW | docs/CLAUDE.md:70 | derived-stale: writes 93 table/bang but canonical=88 | resolve: update to 88 ... <== TRUE drift (ERD '93 bang')
[DETECTOR] MED | docs/CLAUDE.md:123 | derived-stale: writes 4 table/bang but canonical=88 <== FALSE-POS (Phase 7 '4 bang Budget')
[DETECTOR] MED | docs/CLAUDE.md:124 | derived-stale: writes 71 test but canonical=339 <== FALSE-POS (Phase 8 historical '71 test')
[DETECTOR] MED | .claude/skills/ef-core-migration/SKILL.md:3 | writes 10 migration <== FALSE-POS ('.NET Core 10 migration')
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:3 | writes 53 migration <== TRUE drift
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:19 | writes 53 migration <== TRUE drift
[DETECTOR] MED | .claude/skills/ef-core-migration/SKILL.md:34..115 | writes 1/3/4/10 table/bang <== FALSE-POS (per-migration '<n> bang module ...')
[DETECTOR] MED | .claude/skills/ef-core-migration/SKILL.md:42/86/87/154/171 | writes 1/2 migration <== FALSE-POS (mig list seq number)
[DETECTOR] MED | .claude/skills/ef-core-migration/SKILL.md:107 | writes 58/96/154 test <== FALSE-POS (per-project breakdown)
[DETECTOR] LOW | .claude/skills/ef-core-migration/SKILL.md:285 | writes 53 migration <== TRUE drift
[DETECTOR] MED | .claude/skills/README.md:20 | writes 10 migration <== FALSE-POS ('.NET Core 10')
[DETECTOR] LOW | .claude/skills/README.md:20 | writes 53 migration <== TRUE drift
[DETECTOR] LOW | .claude/skills/README.md:90 | writes 68 gotcha/bay <== TRUE drift ('68 bay')
[DETECTOR] LOW | .claude/skills/dependency-audit-erp/SKILL.md:153 | writes 68 gotcha/bay <== TRUE drift ('68 bay')
(note: count-token grep is a soft net - module-local phrases like "4 bang Budget" / "71 test (Phase 8)" can false-positive; treat LOW sev as review-not-fail)
===== C1 - broken gotcha-ref =====
(no flags -- all gotcha #N refs <= 69 and anchored; bare #N>max skipped to avoid Run#/PR# noise)
===== C1 - dangling wikilink =====
[DETECTOR] LOW | user-memory/<29 file>:* | dangling-wikilink: [[<hyphen-form>]] -> <name>.md not found in user-memory | resolve: fix link / create file (hyphen-vs-underscore fork)
... 21 user-memory dangling (vd [[feedback-implementer-truncation-mitigation]] -- file that la feedback_implementer_truncation_mitigation.md _underscore_) ...
[DETECTOR] LOW | agent-memory/pattern_*.md:* | [[pattern-...-hyphen]] -> not found ... 8 agent-memory dangling (6 hyphen-fork + 2 trong 2026-06.gist.md tro feedback_* underscore khac-scope) ...
===== C3 - vocab-fork =====
[DETECTOR] MED | multiple files | vocab-fork: wave-folder=15f vs run-trace=18f live side-by-side -- 'wave-folder' in [docs/HANDOFF.md, docs/STATUS.md] | 'run-trace' in [docs/HANDOFF.md, docs/STATUS.md] | resolve: merge / alias-map
[DETECTOR] MED | multiple files | vocab-fork: Du tru PRO=7f vs Ngan sach PRO=6f live side-by-side -- in [docs/HANDOFF.md, docs/STATUS.md] | resolve: merge / alias-map <== VONG-1 BI MISS (mojibake), sau fix moi bat
[DETECTOR] MED | multiple files | vocab-fork: two-tier=17f vs all-inherit=10f live side-by-side -- in [docs/HANDOFF.md, docs/STATUS.md] | resolve: merge / alias-map
===== Summary =====
self-exclusion: 5 paths excluded (exact+dir rules)
- excluded: scripts/governance-detectors.ps1
- excluded: docs/governance/harness-11-engine.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: 71
NOTE: DETECT-only lowering net. Exit 0 always (never fails build). FLAGs are advisory.
=== EXIT CODE: 0 ===
```
> (Output trên rút-gọn các block lặp dài; con-số tally + dòng load-bearing y-nguyên run thật. Full 71 dòng có trong stdout.)
## 4. Acceptance — verdict (số đo)
| Mục SPEC | Verdict | Bằng-chứng (file:line từ output thật) |
|---|---|---|
| (i) C2/B3 FLAG drift root CLAUDE.md **mig 53 vs 55** | ✅ PASS | `CLAUDE.md:53 ... 53 migration but canonical=55` |
| (i) **gotcha 68 vs 69** | ✅ PASS | `CLAUDE.md:133 ... 68 gotcha/bay but canonical=69` (sau encoding-fix) + `README.md:90` + `dep-audit/SKILL.md:153` |
| (i) **test 306 vs 339** | ✅ PASS | `CLAUDE.md:66 ... 306 test but canonical=339` |
| (ii) C3 FLAG vocab-fork wave↔run-trace | ✅ PASS | `wave-folder=15f vs run-trace=18f live side-by-side` |
| (iii) self-exclusion 0 self-match | ✅ PASS | `governance-detectors.ps1 in scan = 0 ; leaked = 0 ; [OK] C4 satisfied` |
| Exit-code 0 (dò-only) | ✅ PASS | `=== EXIT CODE: 0 ===` |
| NO-API | ✅ PASS | Chỉ `Select-String/Get-Content/Get-ChildItem/regex`. grep script: 0 hit `Invoke-WebRequest|curl|api|http` |
| PS 5.1 parse | ✅ PASS | `PSParser.Tokenize` 0 error |
| Bonus drift bắt thêm | | `docs/CLAUDE.md:70 93 bảng` (canon 88) + vocab-fork thứ-3 `Dự trù PRO=7f vs Ngân sách PRO=6f` (rename S65 còn 2 tên sống) |
## 5. C5 resolve-condition — đủ mọi FLAG
derived-stale → "update to M OR replace with pointer '-> docs/STATUS.md'" · canonical-itself-stale → "re-ground STATUS.md <row> to <disk>" · broken-gotcha-ref → "fix number or add gotcha to docs/gotchas.md" · dangling-wikilink → "fix link target or create file" · vocab-fork → "merge to ONE canonical term, or record alias-map".
## 6. Honest limitations (LƯỚI giảm-sót, KHÔNG khoá-cứng — đừng over-claim)
1. **C2/B3 count-token = soft net, FALSE-POSITIVE thật**: trong 41 derived-flag, ~12 TRUE drift / ~29 FP. Nguồn FP: `.NET Core 10 migration` (version), per-project test breakdown (45/261/58/96), migration list seq number (`1 migration`), module-local `4 bảng Budget`, Phase-historical `71 test`. Mitigation: NOTE cảnh-báo + sev LOW khi |lệch|<10. KHÔNG lọc cứng theo ngữ-cảnh (giòn). Người xử FLAG, KHÔNG auto-fix. **TRUE-signal (53 mig · 306 test · 68 bẫy · 93 bảng) ĐỀU có trong list** runtime-proof ĐẠT.
2. **`CLAUDE.md:53 "53 gotcha/bay"` = FP do regex tham**: token `(\d+)\s*(?:bẫy|gotcha)` bắt "53" rồi nuốt khoảng-trắng dài tới chữ "gotcha" xa hơn trên cùng dòng (dòng 53 dài, chữ `gotcha #63/#64`). over-match. Đây giới-hạn regex flat-line, GHI . Dòng 53 thật-sự stale "53 migration" (đã bắt riêng, đúng).
3. **bare `#N` gotcha-ref** cố-ý bỏ qua khi N>max (tránh nhầm Run #312/PR #) → có thể MISS broken-ref dạng `#999` thật. Trade-off ít-noise.
4. **agent-memory `2026-06.gist.md` 2 dangling** trỏ file user-memory (khác-scope) → "dangling trong agent-memory" kỹ-thuật đúng nhưng có thể cross-scope cố-ý. GHI nhận, không khẳng định tuyệt-đối broken.
5. **user-memory path hard-code** theo slug máy này; máy/CI khác → tự fallback agent-memory-only + note (đã code; chưa test máy khác).
6. **vocab-fork sample chỉ in 2 file đầu** mỗi biến-thể (gọn output); muốn full-list cần mở rộng — chấp-nhận cho lần này.
## 7. Single-writer compliance
CHỈ ghi 2 file: `scripts/governance-detectors.ps1` + sub-MD này (`runs/2026-06-18-h11-implement/sub-task-0.md`). KHÔNG đụng canonical MD (CLAUDE/README/STATUS/agents) · KHÔNG agent-memory · KHÔNG sub-MD khác · KHÔNG store_memory/RAG/HTTP/Qdrant. Detector tự-nó KHÔNG ghi file nào (FLAG ra stdout only) — auto-WRITE luật = mối-nguy #1, đã tránh tuyệt-đối.
```