# naming-scan.ps1 - MAY SOI TEN, tang BO MAY (SOLUTION_ERP) # # Chuan thi hanh: docs/governance/naming-standard.md (ky S180 / 2026-08-07, wave W1). # Kiem ke may doc ten: runs/2026-08-07-S180-adap-upgrade-pack-phased/sub-w1a-mayd-octen.md # # HOP DONG CUA MAY NAY - doc truoc khi sua: # # (1) INFORM-only. LUON exit 0, ke ca khi co co. Lai ma thoat = wave W3b, # sau khi chu du an chot cau P1 (da chot PA-2). Ly do do duoc (lane F): # bat gate ma chua soak => 8-12 lop no ton keu cung luc, nguoi tuong may # hong roi tat may. # # (2) Quet 231 TEN VAT-BO-MAY, KHONG quet 1.545 tep .md. # Ly do: 5 vung dong bang = 1.131/1.545 = 73,2% kho, va 225/248 cho lech # (90,7%) nam TRONG vung mien tru => may quet .md se in "0 hit" ngay dau # va so 0 do VO NGHIA (bay-4 cua san GD-1). # Tap 231 co 0 mien tru vung, va 23 vat lech that van nam nguyen trong do. # # (3) LUON IN MAU SO canh moi con so. Phien S180 da 7 ca bay don-vi. # # (4) CAM 3 LOI CAM (R6 - lane a dat ten, ca 3 deu co that trong kho nay): # (a) liet-khong-co : governance-detectors.ps1:1109 do ten la roi chi liet # (b) -or nuot nhanh : governance-detectors.ps1:1660 chap ca _end lan closed.md # (c) [skip] im lang : governance-detectors.ps1:1622 / :1882 / mfe-eval.ps1:265 # => O DAY: moi ten nhan DUNG MOT phan quyet va LUON duoc in ten khi khac OK. # Tap vang mat = FLAG "THIEU-TAP", KHONG PHAI skip. # # (5) Pure ASCII (gotcha #30) - do 3 script .ps1 nen: 0/0/0 byte ngoai ASCII, # control-duong tren 1 tep .md tieng Viet = 58. Giu nguyen ky luat nay. # # Fault-inject: chay voi -RepoRoot de cay ten lech / go ra, khong dung kho that. [CmdletBinding()] param( [string]$RepoRoot ) $ErrorActionPreference = 'Stop' if (-not $RepoRoot -or $RepoRoot -eq '') { $RepoRoot = Split-Path -Parent $PSScriptRoot } $RepoRoot = (Resolve-Path -LiteralPath $RepoRoot).Path # ---------- hinh dang ---------- $RX_KEBAB = '^[a-z0-9]+(-[a-z0-9]+)*$' $RX_SNAKE = '^[a-z0-9]+(_[a-z0-9]+)*$' $RX_ONEOFF = '^(s[0-9]+-|plan-)' $RX_SESSFAM = '^_(tiep|pause|snapshot|context-s|mind-s|end)' $RX_SESSDIR = '^session-[0-9]+$' # ---------- so ke ---------- $script:Total = 0 $script:Ok = 0 $script:Lech = 0 $script:OneOff = 0 $script:Mien = 0 $script:Pep8 = 0 $script:MissingSets = 0 $script:LechList = @() # ---------- baseline ky-vong ---------- # NGUON DUY-NHAT = scripts/naming-baseline.json (chu du an chot phuong an (b) @S181, cau 6). # (a) Script nay chi DOC. CAM chep so nguoc vao day -- chep nguoc = de nguon-doi, # dung thu ma phuong an (b) sinh ra de chan. # (b) Nap tu $PSScriptRoot, KHONG phai $RepoRoot: fault-inject chay -RepoRoot # nhung baseline la thuoc tinh cua CHUAN, khong phai cua cay dang quet. # (c) Thieu khoa / hong tep => IN LOUD roi tra $null. CAM tra 0: so 0 se lam mau so # cua guard A2 (:99) thanh "0/0", va "0/0" doc thanh SACH. Do dung la bay # "vang mat trong giong on" ma guard A2 duoc dung len de chan. $script:BaselinePath = Join-Path $PSScriptRoot 'naming-baseline.json' $script:Baseline = $null $script:BaselineUpdated = '(khong ro)' if (Test-Path -LiteralPath $script:BaselinePath) { try { $bj = Get-Content -LiteralPath $script:BaselinePath -Raw | ConvertFrom-Json $script:Baseline = $bj.sets if ($bj._updated) { $script:BaselineUpdated = [string]$bj._updated } } catch { Write-Host ("FLAG BASELINE-HONG: doc duoc '{0}' nhung khong parse duoc JSON: {1}" -f $script:BaselinePath, $_.Exception.Message) -ForegroundColor Red } } else { Write-Host ("FLAG BASELINE-VANG: khong thay '{0}'. Moi nhom se chay KHONG co ky-vong." -f $script:BaselinePath) -ForegroundColor Red } function Get-Baseline([string]$Label) { if ($null -eq $script:Baseline) { return $null } $p = $script:Baseline.PSObject.Properties[$Label] if ($null -eq $p) { Write-Host (" FLAG BASELINE-THIEU-KHOA: '{0}' khong co trong naming-baseline.json" -f $Label) -ForegroundColor Red return $null } return [int]$p.Value } function Write-Head([string]$t) { Write-Host ''; Write-Host $t -ForegroundColor Cyan } function Add-Verdict { param([string]$Group, [string]$Name, [string]$Verdict, [string]$Note) $script:Total++ switch ($Verdict) { 'OK' { $script:Ok++ } 'PEP8' { $script:Ok++; $script:Pep8++ } 'MOT-LAN' { $script:Ok++; $script:OneOff++ } 'MIEN' { $script:Mien++ } 'LECH' { $script:Lech++ $script:LechList += [pscustomobject]@{ Group = $Group; Name = $Name; Note = $Note } } } } # Quet 1 tap. Tap vang mat => FLAG, KHONG skip im lang (luat 4c). function Scan-Set { param( [string]$Label, [string]$RelPath, # 'Item' = ca tep LAN thu muc. Bat buoc cho scripts/ va docs/governance/ vi # tap 231 dem theo don vi "muc" o hai nhom do (bay don-vi: tep != muc). [ValidateSet('File', 'Dir', 'Item')][string]$Kind, # -1 = khong truyen tay => tra cuu tu naming-baseline.json theo $Label. # KHONG dat mac dinh 0: xem ghi chu (c) o khoi nap baseline. [int]$Expect = -1, [scriptblock]$Rule, [string]$Filter = '*', [switch]$Recurse ) if ($Expect -lt 0) { $b = Get-Baseline $Label if ($null -ne $b) { $Expect = $b } } $hasExpect = ($Expect -ge 0) $full = Join-Path $RepoRoot $RelPath Write-Head ("--- NHOM: {0} [{1}]" -f $Label, $RelPath) if (-not (Test-Path -LiteralPath $full)) { $script:MissingSets++ Write-Host (" FLAG THIEU-TAP: khong tim thay '{0}'." -f $RelPath) -ForegroundColor Red if ($hasExpect) { Write-Host (" Day KHONG phai [skip]. Tap vang mat => phep do khong ton tai, mau so = 0/{0} ky vong." -f $Expect) -ForegroundColor Red } else { Write-Host " Day KHONG phai [skip]. Tap vang mat => phep do khong ton tai, va KHONG CO ky-vong lam mau so (baseline thieu) => CAM doc thanh sach." -ForegroundColor Red } Write-Host " Nguyen nhan thuong gap: thu muc vua bi doi ten => moi may neo vao no cung mu theo." return } $items = switch ($Kind) { 'File' { @(Get-ChildItem -LiteralPath $full -File -Filter $Filter -Recurse:$Recurse -ErrorAction SilentlyContinue) } 'Dir' { @(Get-ChildItem -LiteralPath $full -Directory -Recurse:$Recurse -ErrorAction SilentlyContinue) } 'Item' { @(Get-ChildItem -LiteralPath $full -Recurse:$Recurse -ErrorAction SilentlyContinue) } } $unit = switch ($Kind) { 'File' { 'tep' } 'Dir' { 'thu muc' } 'Item' { 'muc (tep + thu muc)' } } $n = $items.Count $lo = 0; $lk = 0; $lm = 0; $l1 = 0; $lp = 0 $rows = @() foreach ($it in $items) { $v = & $Rule $it $verdict = $v[0]; $note = $v[1] Add-Verdict -Group $Label -Name $it.Name -Verdict $verdict -Note $note switch ($verdict) { 'OK' { $lo++ } 'PEP8' { $lo++; $lp++ } 'MOT-LAN' { $lo++; $l1++ } 'MIEN' { $lm++ } 'LECH' { $lk++ } } if ($verdict -ne 'OK') { $rows += [pscustomobject]@{ V = $verdict; N = $it.Name; Note = $note } } } Write-Host (" mau so: {0} {1}" -f $n, $unit) -NoNewline if (-not $hasExpect) { Write-Host " [!] KHONG CO ky-vong cho nhom nay trong naming-baseline.json" -ForegroundColor Red } elseif ($n -ne $Expect) { Write-Host (" [!] lech ky vong {0} (do ngay {1}) - chuan hoac kho da doi, doc lai naming-standard.md" -f $Expect, $script:BaselineUpdated) -ForegroundColor Yellow } else { Write-Host '' } Write-Host (" OK {0}/{1} | LECH {2}/{1} | MIEN-theo-luat {3}/{1}" -f $lo, $n, $lk, $lm) if ($lp -gt 0) { Write-Host (" trong OK: {0}/{1} theo PEP-8 (*.py snake_case - DUNG, khong phai troi)" -f $lp, $n) } if ($l1 -gt 0) { Write-Host (" trong OK: {0}/{1} MOT-LAN (tien to s-/plan- = kich ban mot lan, HOP LE)" -f $l1, $n) } foreach ($r in $rows) { $c = if ($r.V -eq 'LECH') { 'Red' } else { 'DarkGray' } Write-Host (" [{0,-7}] {1} <- {2}" -f $r.V, $r.N, $r.Note) -ForegroundColor $c } } Write-Host '=== naming-scan.ps1 - MAY SOI TEN (tang bo may) ===' -ForegroundColor White Write-Host ("RepoRoot : {0}" -f $RepoRoot) Write-Host "Che do : INFORM-only. LUON exit 0 ke ca khi co co (lai ma thoat = W3b, sau P1=PA-2)." Write-Host "Chuan : docs/governance/naming-standard.md" Write-Host "Tap do : 231 ten vat-bo-may, 0 mien tru VUNG (khong quet 1.545 tep .md - bay-4)." # 1/7 - vai Scan-Set -Label 'vai' -RelPath '.claude/agents' -Kind File -Filter '*.md' -Rule { param($f) if ($f.Name -eq 'README.md') { return @('MIEN', 'quy uoc pho quat (luat L4)') } if ($f.BaseName -cmatch $RX_KEBAB) { return @('OK', '') } return @('LECH', 'ten vai phai kebab thuan; xem naming-standard.md section 1') } # 2/7 - thu muc nhat ky vai Scan-Set -Label 'nhat-ky-vai' -RelPath '.claude/agent-memory' -Kind Dir -Rule { param($d) if ($d.Name -cmatch $RX_KEBAB) { return @('OK', '') } return @('LECH', 'thu muc nhat ky phai trung ten vai (kebab thuan)') } # 3/7 - lenh Scan-Set -Label 'lenh' -RelPath '.claude/commands' -Kind File -Rule { param($f) if ($f.Name -eq 'README.md') { return @('MIEN', 'quy uoc pho quat (luat L4)') } if ($f.BaseName -cmatch $RX_KEBAB) { return @('OK', '') } return @('LECH', 'ten lenh phai kebab; xem naming-standard.md section 7') } # 4/7 - kich ban (2 quy uoc ngon ngu, luat L4). Don vi = MUC (co ca thu muc con). Scan-Set -Label 'kich-ban' -RelPath 'scripts' -Kind Item -Rule { param($f) if ($f.Name -eq 'README.md') { return @('MIEN', 'quy uoc pho quat (luat L4)') } if ($f.Name -eq '__pycache__') { return @('MIEN', 'vat sinh tu dong (luat L4)') } if ($f.Extension -eq '.py') { if ($f.BaseName -cmatch $RX_SNAKE) { return @('PEP8', 'PEP-8: *.py snake_case la DUNG') } return @('LECH', '*.py phai snake_case theo PEP-8') } if ($f.BaseName -cnotmatch $RX_KEBAB) { return @('LECH', 'kich ban khong-phai-.py phai kebab; xem naming-standard.md section 8') } if ($f.BaseName -cmatch $RX_ONEOFF) { return @('MOT-LAN', 'kich ban mot lan thuoc phien/ke hoach - HOP LE, dem rieng') } return @('OK', '') } # 5/7 - tep moc phien. BUOC -Recurse: tep nam trong session-/, khong nam o goc. Scan-Set -Label 'moc-phien' -RelPath '.claude/sessions' -Kind File -Recurse -Rule { param($f) if ($f.Name -cmatch $RX_SESSFAM) { return @('OK', '') } if ($f.Name -cmatch '^pause-') { return @('LECH', 'FORK ho cu: _pause-* la ho chuan. session_ctx.py:349-358 THA (doc ca 2 glob) => fork song mai neu khong ai goi ten') } if ($f.Name -eq 'closed.md') { return @('LECH', 'FORK dau-dong-phien: _end la ho chuan. detectors:1660 THA bang -or => doi sang ten thu BA thi phien da dong bi doc la DANG MO, co khong bao gio ban') } return @('LECH', 'tep moc phien moi BUOC BAT DAU bang _ ; xem naming-standard.md section 5') } # 6/7 - so. Don vi = MUC (co ca thu muc con adap-reports/ adap-requests/). Scan-Set -Label 'so-governance' -RelPath 'docs/governance' -Kind Item -Rule { param($f) if ($f.Name -eq 'README.md') { return @('MIEN', 'quy uoc pho quat (luat L4)') } if ($f.BaseName -cmatch $RX_KEBAB) { return @('OK', '') } return @('LECH', 'VAT LICH SU (thu da gui, mang ngay) - GIU NGUYEN theo luat L1, nhung phai duoc LIET TEN: no la chung nhan nhom nay co 2 ho') } # 7/7 - hook Scan-Set -Label 'hook' -RelPath '.claude/hooks' -Kind File -Rule { param($f) if ($f.BaseName -cmatch $RX_KEBAB) { return @('OK', '') } return @('LECH', 'hook phai kebab') } # ---------- bat bien 2 chieu ---------- Write-Head '--- BAT BIEN: .claude/agents/.md == .claude/agent-memory// ---' $agDir = Join-Path $RepoRoot '.claude/agents' $mmDir = Join-Path $RepoRoot '.claude/agent-memory' if ((Test-Path -LiteralPath $agDir) -and (Test-Path -LiteralPath $mmDir)) { $roles = @(Get-ChildItem -LiteralPath $agDir -File -Filter '*.md' | Where-Object { $_.Name -ne 'README.md' } | ForEach-Object { $_.BaseName }) $dirs = @(Get-ChildItem -LiteralPath $mmDir -Directory | ForEach-Object { $_.Name }) $noDiary = @($roles | Where-Object { $dirs -notcontains $_ }) $noPersona = @($dirs | Where-Object { $roles -notcontains $_ }) Write-Host (" mau so: {0} vai (tep persona, tru README) / {1} thu muc nhat ky" -f $roles.Count, $dirs.Count) Write-Host (" khop : {0}/{1}" -f ($roles.Count - $noDiary.Count), $roles.Count) if ($noDiary.Count -eq 0) { Write-Host ' vai THIEU thu muc nhat ky : (danh sach rong)' } else { $script:Lech += $noDiary.Count foreach ($r in $noDiary) { Write-Host (" FLAG vai THIEU nhat ky: {0} <- mfe-eval.ps1:264-267 se in 'N/A (no persistent diary)' va LOAI vai khoi phep do" -f $r) -ForegroundColor Red $script:LechList += [pscustomobject]@{ Group = 'bat-bien'; Name = $r; Note = 'thieu thu muc nhat ky' } } } if ($noPersona.Count -eq 0) { Write-Host ' nhat ky THUA (khong co persona): (danh sach rong)' } else { $script:Lech += $noPersona.Count foreach ($r in $noPersona) { Write-Host (" FLAG nhat ky THUA: {0} <- detectors:1109 se xep vao `$unmapped (LIET, KHONG CO)" -f $r) -ForegroundColor Red $script:LechList += [pscustomobject]@{ Group = 'bat-bien'; Name = $r; Note = 'thua thu muc nhat ky' } } } } else { $script:MissingSets++ Write-Host ' FLAG THIEU-TAP: thieu .claude/agents hoac .claude/agent-memory => bat bien KHONG DO DUOC.' -ForegroundColor Red } # ---------- khai tuong minh cai NGOAI tap ---------- Write-Head '--- NGOAI TAP 231 (khai tuong minh - KHONG phai [skip]) ---' $sessRoot = Join-Path $RepoRoot '.claude/sessions' if (Test-Path -LiteralPath $sessRoot) { $sd = @(Get-ChildItem -LiteralPath $sessRoot -Directory) $sdOk = @($sd | Where-Object { $_.Name -cmatch $RX_SESSDIR }) Write-Host (" thu muc phien: {0}/{1} dat hinh dang ^session-$" -f $sdOk.Count, $sd.Count) Write-Host " CO CHU DICH nam ngoai tap 231: giu mau so 231 da thoa thuan, va nhom nay DA co may ep" Write-Host " (governance-detectors.ps1:1639 + session_ctx.py:133 + 2 ban session-scaffold)." $bad = @($sd | Where-Object { $_.Name -cnotmatch $RX_SESSDIR }) foreach ($b in $bad) { Write-Host (" [LECH-ngoai-tap] {0}" -f $b.Name) -ForegroundColor Yellow } } else { Write-Host ' FLAG: .claude/sessions vang mat.' -ForegroundColor Red } # ---------- tong ---------- Write-Head '=== TONG ===' Write-Host (" mau so TONG : {0} ten vat-bo-may" -f $script:Total) Write-Host " goc 231 (do 2026-08-07 TRUOC wave W1) = 27 vai + 26 nhat ky + 19 lenh + 53 kich ban" Write-Host " + 90 moc phien + 15 so + 1 hook" Write-Host " +2 vat chinh W1 de ra: scripts/naming-scan.ps1 va docs/governance/naming-standard.md" Write-Host " => 233 sau W1. Khai ro de khong ai doc 233 thanh 'kho phinh ra' (bay-6: so do giua chung)." Write-Host (" OK : {0}/{1}" -f $script:Ok, $script:Total) Write-Host (" trong do PEP-8 : {0}/{1} (*.py snake - DUNG theo luat ngon ngu, khong phai troi)" -f $script:Pep8, $script:Total) Write-Host (" trong do MOT-LAN : {0}/{1} (kich ban mot lan - HOP LE, tin hieu ton kho chu khong phai vi pham)" -f $script:OneOff, $script:Total) Write-Host (" MIEN theo luat L4 : {0}/{1} (in ten o tung nhom - mien tru im lang va loi im lang trong giong het nhau)" -f $script:Mien, $script:Total) if ($script:Lech -gt 0) { Write-Host (" LECH : {0}/{1}" -f $script:Lech, $script:Total) -ForegroundColor Red } else { Write-Host (" LECH : 0/{0}" -f $script:Total) -ForegroundColor Green Write-Host " [!] 0 hit chi co nghia neu mau so tren KHAC 0 va tap do KHONG mien tru vung." -ForegroundColor Yellow } if ($script:MissingSets -gt 0) { Write-Host (" TAP VANG MAT : {0} <- moi tap vang lam phep do BIEN MAT, khong phai 'sach'" -f $script:MissingSets) -ForegroundColor Red } if ($script:LechList.Count -gt 0) { Write-Host '' Write-Host ' Danh sach LECH (tung ten - cam nen thanh khoang):' -ForegroundColor Red foreach ($x in $script:LechList) { Write-Host (" - [{0}] {1}" -f $x.Group, $x.Name) } } Write-Host '' Write-Host ' Ma thoat: 0 (INFORM-only theo hop dong muc 1). Co o tren KHONG lai ma thoat.' Write-Host ' Lai ma thoat thuoc wave W3b, sau khi chu du an chot phan loai co theo PA-2.' exit 0