From 65c7716d62e075fee698a45f7acec8acf2de5ef2 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sat, 6 Jun 2026 10:03:01 +0200 Subject: [PATCH] Add quiet validation wrapper --- AGENTS.md | 12 + docs/modernization/build-inventory.md | 10 + docs/modernization/roadmap.md | 1 + scripts/automation/quiet-validate.ps1 | 288 ++++++++++++++++++ .../automation/quiet-validation-ignore.txt | 13 + 5 files changed, 324 insertions(+) create mode 100644 scripts/automation/quiet-validate.ps1 create mode 100644 scripts/automation/quiet-validation-ignore.txt diff --git a/AGENTS.md b/AGENTS.md index 651038b..edb8652 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,6 +42,18 @@ cmake --preset windows-msvc-default cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli ``` +Quiet checkpoint validation, preferred when working through Codex token-limited +sessions: + +```powershell +powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli -TestRegex "pp_app_core|pano_cli_plan" +``` + +The quiet wrapper writes full command logs under `out/logs/quiet-validation`, +prints only a compact summary, and applies editable warning/noise filters from +`scripts/automation/quiet-validation-ignore.txt`. If a step fails, read the +reported log file instead of rerunning with verbose output. + Focused fast validation: ```powershell diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index b1cf885..040ba93 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -58,6 +58,16 @@ dependencies until each platform triplet is proven. These commands are the current local baseline. +Prefer the quiet wrapper for Codex checkpoint validation because it captures +full logs in `out/logs/quiet-validation`, emits only per-step summaries, and +keeps known warning/noise filters in +`scripts/automation/quiet-validation-ignore.txt`: + +```powershell +powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli -TestRegex "pp_app_core|pano_cli_plan" +powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets pp_app_core_app_dialog_tests,pp_ui_core_overlay_lifetime_tests -TestRegex "pp_(app_core_app_dialog|ui_core_(node_lifetime|overlay_lifetime))" +``` + ```powershell cmake --preset windows-msvc-default cmake --build --preset windows-msvc-default --config Debug --target PanoPainter diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 9e168ce..130cd5c 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -1716,6 +1716,7 @@ cmake --build --preset windows-msvc-default --config Debug --target pp_foundatio ctest --preset desktop-fast --build-config Debug ctest --preset fuzz --build-config Debug ctest --preset stress --build-config Debug +powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli -TestRegex "pp_app_core|pano_cli_plan" powershell -ExecutionPolicy Bypass -File scripts\automation\test.ps1 -Preset desktop-fast -Configuration Debug powershell -ExecutionPolicy Bypass -File scripts\automation\build.ps1 -Preset windows-msvc-default -Configuration Debug -Target pano_cli cmake --build --preset windows-msvc-default --target panopainter_validate_shaders diff --git a/scripts/automation/quiet-validate.ps1 b/scripts/automation/quiet-validate.ps1 new file mode 100644 index 0000000..08a100f --- /dev/null +++ b/scripts/automation/quiet-validate.ps1 @@ -0,0 +1,288 @@ +[CmdletBinding()] +param( + [string]$BuildPreset = "windows-msvc-default", + [string]$Configuration = "Debug", + [string[]]$BuildTargets = @("PanoPainter", "pano_cli"), + [string]$TestPreset = "desktop-fast", + [string]$TestRegex = "", + [switch]$Configure, + [switch]$SkipBuild, + [switch]$SkipTests, + [string]$CMakeCommand = "", + [string]$CTestCommand = "", + [string]$LogDir = "out/logs/quiet-validation", + [string]$IgnoreFilterFile = "", + [string[]]$IgnorePattern = @(), + [int]$FailureTailLines = 0 +) + +$ErrorActionPreference = "Stop" + +function Resolve-CMakeCommand { + param([string]$Requested) + + if ($Requested.Length -gt 0) { + return $Requested + } + + $vsCmake = "C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" + if (Test-Path -LiteralPath $vsCmake) { + return $vsCmake + } + + return "cmake" +} + +function Resolve-CTestCommand { + param( + [string]$Requested, + [string]$ResolvedCMake + ) + + if ($Requested.Length -gt 0) { + return $Requested + } + + if ($ResolvedCMake.EndsWith("cmake.exe", [System.StringComparison]::OrdinalIgnoreCase)) { + $candidate = Join-Path -Path (Split-Path -Parent $ResolvedCMake) -ChildPath "ctest.exe" + if (Test-Path -LiteralPath $candidate) { + return $candidate + } + } + + return "ctest" +} + +function Read-IgnorePatterns { + param( + [string]$FilterFile, + [string[]]$InlinePatterns + ) + + $patterns = @() + if ($FilterFile.Length -eq 0) { + $defaultFile = Join-Path -Path $PSScriptRoot -ChildPath "quiet-validation-ignore.txt" + if (Test-Path -LiteralPath $defaultFile) { + $FilterFile = $defaultFile + } + } + + if ($FilterFile.Length -gt 0 -and (Test-Path -LiteralPath $FilterFile)) { + $patterns += Get-Content -LiteralPath $FilterFile | + Where-Object { $_.Trim().Length -gt 0 -and -not $_.TrimStart().StartsWith("#") } + } + + $patterns += $InlinePatterns + return @($patterns | Where-Object { $_ -and $_.Length -gt 0 }) +} + +function Expand-ArgumentList { + param([string[]]$Values) + + $expanded = @() + foreach ($value in $Values) { + if ($null -eq $value) { + continue + } + $expanded += $value -split "[,\s]+" | Where-Object { $_.Length -gt 0 } + } + return @($expanded) +} + +function Test-IgnoredLine { + param( + [string]$Line, + [string[]]$Patterns + ) + + foreach ($pattern in $Patterns) { + if ($Line -match $pattern) { + return $true + } + } + return $false +} + +function Measure-Log { + param( + [string]$Path, + [string[]]$IgnorePatterns + ) + + $errorPattern = "(?i)(:\s*(fatal\s+)?error\s+[A-Z0-9]+:|^LINK\s*:\s*fatal error|^CMake Error|Errors while running CTest|Unable to find executable|\*\*\*Failed)" + $warningPattern = "(?i)(:\s*warning\s+[A-Z0-9]+:|^LINK\s*:\s*warning\s+[A-Z0-9]+:|warning:)" + $ctestSummaryPattern = "(\d+)% tests passed, (\d+) tests failed out of (\d+)" + + $lineCount = 0 + $rawErrors = 0 + $rawWarnings = 0 + $visibleErrors = 0 + $visibleWarnings = 0 + $ignoredErrors = 0 + $ignoredWarnings = 0 + $testsFailed = $null + $testsTotal = $null + + if (Test-Path -LiteralPath $Path) { + foreach ($line in Get-Content -LiteralPath $Path) { + ++$lineCount + $ignored = Test-IgnoredLine -Line $line -Patterns $IgnorePatterns + if ($line -match $ctestSummaryPattern) { + $testsFailed = [int]$Matches[2] + $testsTotal = [int]$Matches[3] + } + if ($line -match $errorPattern) { + ++$rawErrors + if ($ignored) { ++$ignoredErrors } else { ++$visibleErrors } + } + if ($line -match $warningPattern) { + ++$rawWarnings + if ($ignored) { ++$ignoredWarnings } else { ++$visibleWarnings } + } + } + } + + return [ordered]@{ + lineCount = $lineCount + errors = $visibleErrors + warnings = $visibleWarnings + rawErrors = $rawErrors + rawWarnings = $rawWarnings + ignoredErrors = $ignoredErrors + ignoredWarnings = $ignoredWarnings + testsFailed = $testsFailed + testsTotal = $testsTotal + } +} + +function Invoke-QuietStep { + param( + [string]$Name, + [string]$Command, + [string[]]$Arguments, + [string]$LogPath, + [string[]]$IgnorePatterns, + [int]$FailureTailLines + ) + + $started = Get-Date + $exitCode = 0 + try { + & $Command @Arguments *> $LogPath + $exitCode = $LASTEXITCODE + if ($null -eq $exitCode) { + $exitCode = 0 + } + } + catch { + $_ | Out-File -LiteralPath $LogPath -Append -Encoding utf8 + $exitCode = 1 + } + + $elapsed = [int]((Get-Date) - $started).TotalMilliseconds + $summary = Measure-Log -Path $LogPath -IgnorePatterns $IgnorePatterns + $result = [ordered]@{ + name = $Name + exitCode = $exitCode + elapsedMs = $elapsed + log = $LogPath + summary = $summary + } + + if ($exitCode -ne 0 -and $FailureTailLines -gt 0 -and (Test-Path -LiteralPath $LogPath)) { + $result.failureTail = @(Get-Content -LiteralPath $LogPath -Tail $FailureTailLines) + } + + return $result +} + +$resolvedCMake = Resolve-CMakeCommand -Requested $CMakeCommand +$resolvedCTest = Resolve-CTestCommand -Requested $CTestCommand -ResolvedCMake $resolvedCMake +$BuildTargets = @(Expand-ArgumentList -Values $BuildTargets) +$IgnorePattern = @(Expand-ArgumentList -Values $IgnorePattern) +$ignorePatterns = Read-IgnorePatterns -FilterFile $IgnoreFilterFile -InlinePatterns $IgnorePattern + +New-Item -ItemType Directory -Force -Path $LogDir | Out-Null +$runId = Get-Date -Format "yyyyMMdd-HHmmss" +$started = Get-Date +$results = @() +$overallExitCode = 0 + +if ($Configure) { + $log = Join-Path -Path $LogDir -ChildPath "$runId-configure-$BuildPreset.log" + $result = Invoke-QuietStep ` + -Name "configure:$BuildPreset" ` + -Command $resolvedCMake ` + -Arguments @("--preset", $BuildPreset) ` + -LogPath $log ` + -IgnorePatterns $ignorePatterns ` + -FailureTailLines $FailureTailLines + $results += $result + if ($result.exitCode -ne 0 -and $overallExitCode -eq 0) { + $overallExitCode = $result.exitCode + } +} + +if (-not $SkipBuild) { + $targets = @($BuildTargets | Where-Object { $_ -and $_.Length -gt 0 }) + if ($targets.Count -gt 0) { + $safeTargets = ($targets -join "_") -replace "[^A-Za-z0-9_.-]", "_" + $log = Join-Path -Path $LogDir -ChildPath "$runId-build-$BuildPreset-$Configuration-$safeTargets.log" + $buildArgs = @("--build", "--preset", $BuildPreset, "--config", $Configuration, "--target") + $targets + $result = Invoke-QuietStep ` + -Name ("build:{0}:{1}" -f $BuildPreset, $Configuration) ` + -Command $resolvedCMake ` + -Arguments $buildArgs ` + -LogPath $log ` + -IgnorePatterns $ignorePatterns ` + -FailureTailLines $FailureTailLines + $result.targets = $targets + $results += $result + if ($result.exitCode -ne 0 -and $overallExitCode -eq 0) { + $overallExitCode = $result.exitCode + } + } +} + +if (-not $SkipTests) { + $safeRegex = if ($TestRegex.Length -gt 0) { ($TestRegex -replace "[^A-Za-z0-9_.-]", "_") } else { "all" } + $log = Join-Path -Path $LogDir -ChildPath "$runId-test-$TestPreset-$Configuration-$safeRegex.log" + $testArgs = @("--preset", $TestPreset, "--build-config", $Configuration, "--output-on-failure") + if ($TestRegex.Length -gt 0) { + $testArgs += @("-R", $TestRegex) + } + $result = Invoke-QuietStep ` + -Name ("test:{0}:{1}" -f $TestPreset, $Configuration) ` + -Command $resolvedCTest ` + -Arguments $testArgs ` + -LogPath $log ` + -IgnorePatterns $ignorePatterns ` + -FailureTailLines $FailureTailLines + if ($TestRegex.Length -gt 0) { + $result.testRegex = $TestRegex + } + $results += $result + if ($result.exitCode -ne 0 -and $overallExitCode -eq 0) { + $overallExitCode = $result.exitCode + } +} + +$elapsed = [int]((Get-Date) - $started).TotalMilliseconds +$summaryPath = Join-Path -Path $LogDir -ChildPath "$runId-summary.json" +$payload = [ordered]@{ + command = "quiet-validate" + exitCode = $overallExitCode + elapsedMs = $elapsed + buildPreset = $BuildPreset + configuration = $Configuration + testPreset = $TestPreset + logDir = $LogDir + summary = $summaryPath + ignoreFilterFile = $IgnoreFilterFile + ignorePatternCount = $ignorePatterns.Count + results = $results +} + +$payload | ConvertTo-Json -Depth 8 | Out-File -LiteralPath $summaryPath -Encoding utf8 +$payload | ConvertTo-Json -Compress -Depth 8 +exit $overallExitCode diff --git a/scripts/automation/quiet-validation-ignore.txt b/scripts/automation/quiet-validation-ignore.txt new file mode 100644 index 0000000..fcf8f95 --- /dev/null +++ b/scripts/automation/quiet-validation-ignore.txt @@ -0,0 +1,13 @@ +# Regex patterns for warnings/noise hidden from quiet validation summaries. +# The full logs still contain these lines; this file only affects visible counts. +The vcpkg manifest was disabled +warning C4201: +warning C4267: +warning C5311: +warning C4018: +warning C4244: +warning C4189: +warning C4305: +warning C4099: +warning LNK4099: PDB 'yuv\.pdb' +warning LNK4098: defaultlib 'MSVCRT' conflicts