153 lines
5.8 KiB
PowerShell
153 lines
5.8 KiB
PowerShell
<#
|
||
.SYNOPSIS
|
||
Verify that a code-review report carries an anti-fake spot-check (fail-closed).
|
||
|
||
.DESCRIPTION
|
||
Enforces the "three-piece suite" item 3 (anti-fake spot check) defined in
|
||
project-review/SKILL.md Step 8.8: whole-project / feature review reports
|
||
MUST contain a "防伪抽验" field in their coverage section, and it must NOT
|
||
be "未执行" (i.e. the main agent must have sampled re-read semantic units
|
||
from the sub-agent batches). A missing field means the review never ran
|
||
the anti-fake spot check and the report would otherwise look green with no
|
||
anti-fake guarantee.
|
||
|
||
Scope handling: only whole-project and feature reviews are gated (they use
|
||
the sub-agent deep-read pipeline); change-level reviews skip.
|
||
|
||
Exit codes: 0 = spot check present and non-zero; 1 = blocking violation
|
||
(missing spot check or reported as 未执行 / zero units).
|
||
|
||
.PARAMETER Repo
|
||
Repository root. Defaults to the current directory.
|
||
|
||
.PARAMETER Report
|
||
Optional relative path (under docs/reviews/) to a specific report file.
|
||
Defaults to the newest *.md report in docs/reviews/.
|
||
|
||
.EXAMPLE
|
||
powershell -File verify-spot-check.ps1 -Repo D:\AuraSpace
|
||
powershell -File verify-spot-check.ps1 -Repo D:\AuraSpace -Report full-project-review-2026-08-18-144500.md
|
||
#>
|
||
param(
|
||
[string]$Repo = "",
|
||
[string]$Report = ""
|
||
)
|
||
|
||
$ErrorActionPreference = "Stop"
|
||
|
||
function Write-Step([string]$msg) { Write-Host " $msg" -ForegroundColor DarkGray }
|
||
function Write-Ok([string]$msg) { Write-Host " [OK] $msg" -ForegroundColor Green }
|
||
function Write-Bad([string]$msg) { Write-Host " [!!] $msg" -ForegroundColor Red }
|
||
function Write-Warn([string]$msg) { Write-Host " [!] $msg" -ForegroundColor Yellow }
|
||
|
||
# Resolve repo root ---------------------------------------------------------
|
||
if ([string]::IsNullOrWhiteSpace($Repo)) { $Repo = (Get-Location).Path }
|
||
$root = (Resolve-Path -LiteralPath $Repo).Path
|
||
$reviewsDir = Join-Path $root "docs\reviews"
|
||
|
||
Write-Host "verify-spot-check: repo = $root"
|
||
Write-Host ""
|
||
|
||
# Locate the report --------------------------------------------------------
|
||
$reportPath = ""
|
||
if (-not [string]::IsNullOrWhiteSpace($Report)) {
|
||
$reportPath = Join-Path $reviewsDir $Report
|
||
if (-not (Test-Path -LiteralPath $reportPath)) {
|
||
Write-Bad "report not found: $reportPath"
|
||
exit 1
|
||
}
|
||
} else {
|
||
if (-not (Test-Path -LiteralPath $reviewsDir)) {
|
||
Write-Warn "docs/reviews/ does not exist - no report to verify"
|
||
Write-Host "RESULT: PASS (no report)" -ForegroundColor Green
|
||
exit 0
|
||
}
|
||
$reportPath = Get-ChildItem -LiteralPath $reviewsDir -File |
|
||
Where-Object { $_.Extension -eq ".md" } |
|
||
Sort-Object LastWriteTime -Descending |
|
||
Select-Object -First 1 -ExpandProperty FullName
|
||
if (-not $reportPath) {
|
||
Write-Warn "no .md report in docs/reviews/ - nothing to verify"
|
||
Write-Host "RESULT: PASS (no report)" -ForegroundColor Green
|
||
exit 0
|
||
}
|
||
}
|
||
|
||
Write-Step "checking report: $reportPath"
|
||
|
||
# Parse scope from header (line like: 档位:standard · 范围:whole-project · 基线:...)
|
||
$content = [System.IO.File]::ReadAllText($reportPath, [System.Text.Encoding]::UTF8)
|
||
$scope = ""
|
||
$scopeLine = ($content -split "`n" | Where-Object { $_ -match "范围" } | Select-Object -First 1)
|
||
if ($scopeLine -and $scopeLine -match "范围\**[::]\s*([^\s·*]+)") {
|
||
$scope = $Matches[1].Trim()
|
||
}
|
||
|
||
# Scope gate: only change-level reviews are skipped. whole-project / feature
|
||
# AND any custom scope value (e.g. scope="evm") that still produced a coverage
|
||
# section must be checked for the anti-fake spot check.
|
||
if ($scope -eq "change-level") {
|
||
Write-Warn "scope = '$scope' is not gated on anti-fake spot check (change-level only)"
|
||
Write-Host "RESULT: PASS (scope not gated)" -ForegroundColor Green
|
||
exit 0
|
||
}
|
||
Write-Step "scope = '$scope' (gated)"
|
||
|
||
# Parse ## 覆盖度 section
|
||
$covSection = ""
|
||
$lines = $content -split "`r?`n"
|
||
for ($i = 0; $i -lt $lines.Count; $i++) {
|
||
if ($lines[$i] -match "^##\s*\**覆盖度\**") {
|
||
$j = $i + 1
|
||
$buf = @()
|
||
while ($j -lt $lines.Count -and -not ($lines[$j] -match "^##\s")) {
|
||
$buf += $lines[$j]; $j++
|
||
}
|
||
$covSection = $buf -join "`n"
|
||
break
|
||
}
|
||
}
|
||
if (-not $covSection) {
|
||
Write-Bad "no coverage section found - anti-fake spot check cannot be verified"
|
||
exit 1
|
||
}
|
||
|
||
# Anti-fake spot check field present?
|
||
$spotLine = ($covSection -split "`n" | Where-Object { $_ -match "防伪抽验" } | Select-Object -First 1)
|
||
if (-not $spotLine) {
|
||
Write-Bad "coverage section has NO anti-fake spot-check field - Step 5.5 spot check was not run (or spot_check not passed to generate_report_tool)"
|
||
Write-Step "coverage section:"
|
||
foreach ($l in ($covSection -split "`n" | Where-Object { $_.Trim() })) { Write-Step " $($l.Trim())" }
|
||
exit 1
|
||
}
|
||
|
||
# "未执行" marker means spot check never ran
|
||
if ($spotLine -match "未执行") {
|
||
Write-Bad "anti-fake spot check = NOT RUN (no semantic-unit re-read sampled)"
|
||
Write-Step $spotLine.Trim()
|
||
exit 1
|
||
}
|
||
|
||
# Present and non-zero: extract sampled counts (防伪抽验:抽样 X 文件 / Y 单元 / Z 组,假读 N ✅)
|
||
if ($spotLine -match "抽样\s*(\d+)\s*文件\s*/\s*(\d+)\s*单元") {
|
||
$filesSampled = [int]$Matches[1]
|
||
$unitsSampled = [int]$Matches[2]
|
||
if ($unitsSampled -le 0) {
|
||
Write-Bad "anti-fake spot check reported but 0 units sampled"
|
||
Write-Step $spotLine.Trim()
|
||
exit 1
|
||
}
|
||
Write-Ok "anti-fake spot check = $filesSampled files / $unitsSampled units sampled"
|
||
if ($spotLine -match "假读\s*(\d+)") {
|
||
$fake = [int]$Matches[1]
|
||
if ($fake -gt 0) {
|
||
Write-Warn "fake reads detected: $fake - confirm affected groups were re-read"
|
||
}
|
||
}
|
||
Write-Host "RESULT: PASS - anti-fake spot check verified" -ForegroundColor Green
|
||
exit 0
|
||
}
|
||
|
||
Write-Bad "unable to parse anti-fake spot-check counts from: $($spotLine.Trim())"
|
||
exit 1
|