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

13 KiB
Raw Blame History

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ù PRONgâ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
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 to " · 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, có chữ gotcha #63/#64). → over-match. Đây là giới-hạn regex flat-line, GHI RÕ. 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.