From 841fbac8eb2360fba323c0691f6fb0924512216d Mon Sep 17 00:00:00 2001 From: omigamedev Date: Fri, 5 Jun 2026 00:07:36 +0200 Subject: [PATCH] Add package readiness automation guard --- docs/modernization/build-inventory.md | 10 ++ docs/modernization/debt.md | 8 +- docs/modernization/roadmap.md | 14 ++- scripts/automation/package-smoke.ps1 | 16 +++ scripts/automation/package-smoke.sh | 16 +++ scripts/dev/check_package_smoke_readiness.py | 106 +++++++++++++++++++ tests/CMakeLists.txt | 5 + 7 files changed, 170 insertions(+), 5 deletions(-) create mode 100644 scripts/dev/check_package_smoke_readiness.py diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index f1fff29..e7f632c 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -74,6 +74,7 @@ ctest --preset desktop-fast-vcpkg --build-config Debug cmake --preset android-arm64 powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64 powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug +powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -ReadinessOnly cmake --fresh --preset windows-clangcl-asan python scripts/dev/clangd_nav.py symbols --file src/app_core/brush_ui.h --name execute_brush python scripts/dev/clangd_nav.py symbols --file src/app_core/brush_ui.h --name-regex "execute_.*preset" @@ -82,6 +83,7 @@ python scripts/dev/clangd_nav.py definition --file src/node_panel_brush.cpp --li python scripts/dev/clangd_nav.py references --file src/app_core/brush_ui.h --line 783 --column 45 --path-regex "src[\\/]app_core" python scripts/dev/clangd_nav.py self-test python scripts/dev/check_platform_build_targets.py +python scripts/dev/check_package_smoke_readiness.py ``` Known local toolchain state: @@ -143,6 +145,14 @@ Known local toolchain state: `panopainter_platform_build_target_matrix_self_test`, verifies the PowerShell and shell wrapper defaults include every current CMake test executable plus the required component and `pano_cli` targets. +- `package-smoke.ps1 -ReadinessOnly` and `package-smoke.sh --readiness-only` + emit the Windows AppX, Android standard/Quest/Focus APK, Apple bundle, and + WebGL package readiness matrix without first building an app artifact. The + full package smoke command still builds/checks the selected app target before + reporting the same readiness matrix. `scripts/dev/check_package_smoke_readiness.py`, + registered as `panopainter_package_smoke_readiness_self_test`, verifies both + wrappers keep the same six package kinds, blocked DEBT-0011 status, and + readiness-only mode. - Root CMake exposes named `fuzz` and `stress` CTest presets. `fuzz` currently runs deterministic parser/serializer edge tests for binary streams, image metadata, PPI, stroke scripts, and layout XML; `stress` currently runs the diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index 3207a3e..787ed8c 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -1,7 +1,7 @@ # Modernization Debt Log Status: live -Last updated: 2026-06-04 +Last updated: 2026-06-05 Every shortcut, temporary adapter, retained vendored dependency, skipped platform gate, compatibility shim, or incomplete automation path must be @@ -26,6 +26,12 @@ agent or engineer to remove them without reconstructing context from chat. the wrapper defaults against the current CMake test executables, so Android root CMake validation no longer silently skips newly extracted feature slices. Package targets remain open under DEBT-0009 and DEBT-0011. +- 2026-06-05: DEBT-0011 was narrowed. `package-smoke.ps1` and + `package-smoke.sh` now have readiness-only modes that report the same + Windows AppX, Android standard/Quest/Focus APK, Apple bundle, and WebGL + blocker matrix without requiring an app build first, and + `panopainter_package_smoke_readiness_self_test` guards package-kind parity + across both wrappers. Package target migration remains open. - 2026-06-04: DEBT-0036 was narrowed again. Canvas stroke commit, thumbnail, and object-draw history paths now query saved blend state through tested `pp_renderer_gl` capability-state dispatch; CanvasLayer equirect diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 42715d3..1754252 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -1263,9 +1263,12 @@ keeps the PowerShell and shell wrapper defaults aligned with every current CMake test executable plus required component targets. `package-smoke` now emits a structured package readiness matrix for Windows AppX, Android standard/Quest/Focus APKs, Apple bundles, and WebGL output, with -blocked prerequisites tied to DEBT-0011. App/package entrypoints still need to -consume shared targets and remain covered by debt until package validation is -migrated from legacy package projects to root CMake. +blocked prerequisites tied to DEBT-0011. It also has a readiness-only mode for +cheap package blocker inventory without building an app artifact, and +`panopainter_package_smoke_readiness_self_test` keeps the PowerShell and shell +readiness matrices aligned. App/package entrypoints still need to consume +shared targets and remain covered by debt until package validation is migrated +from legacy package projects to root CMake. Implementation tasks: @@ -1407,6 +1410,7 @@ ctest --preset desktop-fast-vcpkg --build-config Debug cmake --preset android-arm64 powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64 powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug +powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -ReadinessOnly cmake --fresh --preset windows-clangcl-asan ``` @@ -2036,7 +2040,9 @@ Results: `data/` copy and report structured package readiness for AppX, Android standard/Quest/Focus APKs, Apple bundles, and WebGL outputs. Actual package building remains blocked by DEBT-0011 until those targets are migrated to - root CMake. + root CMake. Readiness-only mode now reports the same matrix without building + the app first, and the package readiness self-test keeps wrapper package + kinds aligned. - Android arm64 configured with NDK 29.0.14206865 through the platform-build wrapper and compiled the refreshed headless component/test matrix, including the current app-core feature-surface automation tests. diff --git a/scripts/automation/package-smoke.ps1 b/scripts/automation/package-smoke.ps1 index 507f94f..e8fe3a0 100644 --- a/scripts/automation/package-smoke.ps1 +++ b/scripts/automation/package-smoke.ps1 @@ -3,6 +3,7 @@ param( [string]$Preset = "windows-msvc-default", [string]$Configuration = "Debug", [string]$Target = "PanoPainter", + [switch]$ReadinessOnly, [string[]]$PackageKinds = @( "windows-appx", "android-standard-apk", @@ -207,6 +208,21 @@ function Get-PackageReadiness { return $readiness } +if ($ReadinessOnly) { + $elapsed = [int]((Get-Date) - $started).TotalMilliseconds + [ordered]@{ + command = "package-smoke" + preset = $Preset + configuration = $Configuration + target = $Target + stage = "readiness" + exitCode = 0 + elapsedMs = $elapsed + packageReadiness = Get-PackageReadiness -Kinds $PackageKinds + } | ConvertTo-Json -Compress -Depth 5 + exit 0 +} + & cmake --build --preset $Preset --config $Configuration --target $Target $buildExitCode = $LASTEXITCODE if ($buildExitCode -ne 0) { diff --git a/scripts/automation/package-smoke.sh b/scripts/automation/package-smoke.sh index 35bcf4b..1dd5591 100644 --- a/scripts/automation/package-smoke.sh +++ b/scripts/automation/package-smoke.sh @@ -5,6 +5,14 @@ preset="${1:-linux-clang}" configuration="${2:-Debug}" target="${3:-PanoPainter}" artifact="${4:-out/build/$preset/$target}" +readiness_only=0 +if [ "${1:-}" = "--readiness-only" ]; then + readiness_only=1 + preset="${2:-linux-clang}" + configuration="${3:-Debug}" + target="${4:-PanoPainter}" + artifact="${5:-out/build/$preset/$target}" +fi start="$(date +%s)" root="$(pwd)" @@ -84,6 +92,14 @@ package_readiness_json() { printf ']' } +if [ "$readiness_only" -eq 1 ]; then + end="$(date +%s)" + elapsed_ms="$(( (end - start) * 1000 ))" + readiness="$(package_readiness_json)" + printf '{"command":"package-smoke","preset":"%s","configuration":"%s","target":"%s","stage":"readiness","exitCode":0,"elapsedMs":%s,"packageReadiness":%s}\n' "$preset" "$configuration" "$target" "$elapsed_ms" "$readiness" + exit 0 +fi + cmake --build --preset "$preset" --config "$configuration" --target "$target" build_exit="$?" if [ "$build_exit" -ne 0 ]; then diff --git a/scripts/dev/check_package_smoke_readiness.py b/scripts/dev/check_package_smoke_readiness.py new file mode 100644 index 0000000..f5954f9 --- /dev/null +++ b/scripts/dev/check_package_smoke_readiness.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +"""Verify package-smoke wrappers report the expected package readiness matrix.""" + +from __future__ import annotations + +import json +import re +import sys +from pathlib import Path + + +EXPECTED_PACKAGE_KINDS = [ + "windows-appx", + "android-standard-apk", + "android-quest-apk", + "android-focus-apk", + "apple-bundle", + "webgl", +] + + +def repo_root() -> Path: + return Path(__file__).resolve().parents[2] + + +def powershell_package_kinds(root: Path) -> list[str]: + script = (root / "scripts" / "automation" / "package-smoke.ps1").read_text(encoding="utf-8") + match = re.search(r"\[string\[\]\]\$PackageKinds\s*=\s*@\((.*?)\n\s*\)", script, re.S) + if not match: + raise RuntimeError("Could not find PackageKinds default in package-smoke.ps1") + return sorted(re.findall(r'"([^"]+)"', match.group(1))) + + +def shell_package_kinds(root: Path) -> list[str]: + script = (root / "scripts" / "automation" / "package-smoke.sh").read_text(encoding="utf-8") + return sorted(set(re.findall(r'"kind":"([^"]+)"', script))) + + +def count_regex(root: Path, patterns: dict[str, str]) -> dict[str, int]: + counts: dict[str, int] = {} + for script_name, pattern in patterns.items(): + text = (root / "scripts" / "automation" / script_name).read_text(encoding="utf-8") + counts[script_name] = len(re.findall(pattern, text)) + return counts + + +def main() -> int: + root = repo_root() + expected = sorted(EXPECTED_PACKAGE_KINDS) + ps_kinds = powershell_package_kinds(root) + sh_kinds = shell_package_kinds(root) + debt_counts = count_regex(root, { + "package-smoke.ps1": r'debt\s*=\s*"DEBT-0011"', + "package-smoke.sh": r'"debt":"DEBT-0011"', + }) + blocked_counts = count_regex(root, { + "package-smoke.ps1": r'-Status\s+"blocked"', + "package-smoke.sh": r'"status":"blocked"', + }) + readiness_mode_counts = { + "package-smoke.ps1": (root / "scripts" / "automation" / "package-smoke.ps1").read_text(encoding="utf-8").count("ReadinessOnly"), + "package-smoke.sh": (root / "scripts" / "automation" / "package-smoke.sh").read_text(encoding="utf-8").count("readiness_only"), + } + + missing = { + "package-smoke.ps1": [kind for kind in expected if kind not in ps_kinds], + "package-smoke.sh": [kind for kind in expected if kind not in sh_kinds], + } + unexpected = { + "package-smoke.ps1": [kind for kind in ps_kinds if kind not in expected], + "package-smoke.sh": [kind for kind in sh_kinds if kind not in expected], + } + debt_thresholds = { + "package-smoke.ps1": 1, + "package-smoke.sh": len(expected), + } + debt_complete = {name: count >= debt_thresholds[name] for name, count in debt_counts.items()} + blocked_complete = {name: count >= len(expected) for name, count in blocked_counts.items()} + readiness_mode_present = {name: count > 0 for name, count in readiness_mode_counts.items()} + + ok = ( + all(not values for values in missing.values()) + and all(not values for values in unexpected.values()) + and all(debt_complete.values()) + and all(blocked_complete.values()) + and all(readiness_mode_present.values()) + ) + + print(json.dumps({ + "ok": ok, + "expectedPackageKinds": expected, + "packageKinds": { + "package-smoke.ps1": ps_kinds, + "package-smoke.sh": sh_kinds, + }, + "missing": missing, + "unexpected": unexpected, + "debtComplete": debt_complete, + "blockedComplete": blocked_complete, + "readinessModePresent": readiness_mode_present, + }, separators=(",", ":"))) + return 0 if ok else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0fc43ec..2c7c69b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -10,6 +10,11 @@ add_test(NAME panopainter_platform_build_target_matrix_self_test set_tests_properties(panopainter_platform_build_target_matrix_self_test PROPERTIES LABELS "tooling;desktop-fast") +add_test(NAME panopainter_package_smoke_readiness_self_test + COMMAND "${Python3_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/scripts/dev/check_package_smoke_readiness.py") +set_tests_properties(panopainter_package_smoke_readiness_self_test PROPERTIES + LABELS "tooling;desktop-fast") + add_library(pp_test_harness INTERFACE) target_include_directories(pp_test_harness INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")