Thin Windows shell access and bundle quiet validation

This commit is contained in:
2026-06-17 09:41:51 +02:00
parent 6d906f6288
commit 10a3c0498e
8 changed files with 104 additions and 50 deletions

View File

@@ -58,17 +58,24 @@ dependencies until each platform triplet is proven.
These commands are the current local baseline. These commands are the current local baseline.
Prefer the quiet wrapper for Codex checkpoint validation because it captures Prefer the bundled quiet wrapper for checkpoint validation. It captures full
full logs in `out/logs/quiet-validation`, emits only per-step summaries, and logs in `out/logs/quiet-validation`, writes one run summary JSON there, applies
keeps known warning/noise filters in the filters in `scripts/automation/quiet-validation-ignore.txt`, and can fold
`scripts/automation/quiet-validation-ignore.txt`: the Windows, platform-build, and Apple remote steps into one compact result:
```powershell ```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 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 -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 -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets ALL_BUILD -IncludePlatformBuild -IncludeAppleRemote powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli -TestRegex "pp_app_core|pano_cli_plan" -IncludePlatformBuild
powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli -TestRegex "pp_app_core|pano_cli_plan" -IncludePlatformBuild -IncludeAppleRemote
``` ```
Use the standalone quiet helpers only when you need to isolate those gates from
the bundled run. `platform-build.ps1 -Quiet` writes per-preset logs under
`out/logs/platform-build`. `apple-remote-build.ps1 -Quiet` writes the local SSH
session log under `out/logs/apple-remote-build` and reports the remote
`out/logs/apple-platform-build-*.log` path in its JSON output.
```powershell ```powershell
cmake --preset windows-msvc-default cmake --preset windows-msvc-default
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
@@ -160,18 +167,22 @@ Known local toolchain state:
`ssh://git@git.omar.synology.me:3022/omar/panopainter.git`, Homebrew `ssh://git@git.omar.synology.me:3022/omar/panopainter.git`, Homebrew
CMake/Ninja/Git, and full Xcode selected per command with CMake/Ninja/Git, and full Xcode selected per command with
`DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer`. The repeatable `DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer`. The repeatable
Windows-side command is: Windows-side bundled quiet command is:
```powershell ```powershell
powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.ps1 -Presets macos,ios-simulator,ios-device powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli -TestRegex "pp_app_core|pano_cli_plan" -IncludeAppleRemote
``` ```
For Apple-only isolation, run
`scripts/automation/apple-remote-build.ps1 -Quiet -Presets macos,ios-simulator,ios-device`.
The wrapper updates `~/Dev/panopainter`, initializes the source submodules The wrapper updates `~/Dev/panopainter`, initializes the source submodules
required by the headless CMake matrix, and delegates to required by the headless CMake matrix, delegates to
`scripts/automation/platform-build.sh`. macOS, iOS simulator, and iOS device `scripts/automation/platform-build.sh`, stores the local SSH transcript under
currently validate shared component/test/tool targets only; signed Apple app `out/logs/apple-remote-build`, and reports the remote Apple platform-build
bundles remain tracked by DEBT-0011 and the iOS compile-only signing shortcut log path in its JSON output. macOS, iOS simulator, and iOS device currently
is tracked by DEBT-0059. validate shared component/test/tool targets only; signed Apple app bundles
remain tracked by DEBT-0011 and the iOS compile-only signing shortcut is
tracked by DEBT-0059.
- Android standard arm64/x64, Quest arm64, and Focus/Wave arm64 headless - Android standard arm64/x64, Quest arm64, and Focus/Wave arm64 headless
configure/build pass through root CMake and the `platform-build` automation configure/build pass through root CMake and the `platform-build` automation
wrapper defaults for `pp_foundation`, `pp_assets`, wrapper defaults for `pp_foundation`, `pp_assets`,

View File

@@ -70,14 +70,16 @@ What is already real:
- `pp_app_core` - `pp_app_core`
Latest slice: Latest slice:
- `scripts/automation/platform-build.ps1` now supports a quiet mode that writes - `scripts/automation/quiet-validate.ps1` is now the bundled checkpoint path
per-preset configure/build logs and emits only a compact JSON summary. for Windows build/test plus optional platform and Apple remote validation,
- `scripts/automation/apple-remote-build.ps1` now supports a quiet mode that with one compact JSON summary under `out/logs/quiet-validation`.
writes the SSH session to a local log, preserves the remote platform-build - `scripts/automation/platform-build.ps1` quiet mode now writes per-preset
log path, and emits only a compact JSON summary. configure/build logs and compact JSON output so Android/headless sweeps can
- `scripts/automation/quiet-validate.ps1` can now bundle quiet platform and plug into the bundled quiet wrapper without flooding the console.
Apple remote validation into the same summary artifact through - `scripts/automation/apple-remote-build.ps1` quiet mode now writes the local
`-IncludePlatformBuild` and `-IncludeAppleRemote`. SSH session log, reports the remote `platform-build.sh` log path, and emits
compact JSON output so the bundled quiet wrapper can include the Apple gate
in the same checkpoint run.
What is still carrying too much live ownership: What is still carrying too much live ownership:

View File

@@ -78,15 +78,18 @@ Completed, blocked, and superseded task history moved to
the queue is now ordered by code movement instead. the queue is now ordered by code movement instead.
Current slice: Current slice:
- `scripts/automation/quiet-validate.ps1` now owns the recommended quiet
checkpoint path and can bundle Windows build/test, Android/platform sweeps,
and Apple remote compile gates into one compact JSON summary with
`-IncludePlatformBuild` and `-IncludeAppleRemote`.
- `scripts/automation/platform-build.ps1` now supports `-Quiet`, per-preset log - `scripts/automation/platform-build.ps1` now supports `-Quiet`, per-preset log
capture, and compact JSON-only output so Android/headless platform sweeps no capture, and compact JSON-only output so standalone Android/headless sweeps
longer flood the console during checkpoint validation. still have a targeted quiet path when they need to be isolated from the
- `scripts/automation/apple-remote-build.ps1` now supports `-Quiet`, local log bundled wrapper.
capture for the SSH session, remote log path reporting, and JSON-only output - `scripts/automation/apple-remote-build.ps1` now supports `-Quiet`, local SSH
so Apple remote compile gates no longer stream large tails by default. session log capture, remote log path reporting, and JSON-only output so the
- `scripts/automation/quiet-validate.ps1` now accepts standalone Apple gate can still be run directly when the bundled wrapper is
`-IncludePlatformBuild` and `-IncludeAppleRemote` so the existing quiet too broad.
wrapper can own the full Windows, Android/platform, and Apple summary path.
## Active Bundles ## Active Bundles

View File

@@ -315,11 +315,11 @@ if ($IncludePlatformBuild) {
"-Quiet", "-Quiet",
"-FailureTailLines", [string]$FailureTailLines "-FailureTailLines", [string]$FailureTailLines
) )
foreach ($preset in $PlatformBuildPresets) { if ($PlatformBuildPresets.Count -gt 0) {
$platformArgs += @("-Presets", $preset) $platformArgs += @("-Presets", ($PlatformBuildPresets -join ","))
} }
foreach ($target in $PlatformBuildTargets) { if ($PlatformBuildTargets.Count -gt 0) {
$platformArgs += @("-Targets", $target) $platformArgs += @("-Targets", ($PlatformBuildTargets -join ","))
} }
$result = Invoke-QuietStep ` $result = Invoke-QuietStep `
-Name "platform-build" ` -Name "platform-build" `
@@ -353,8 +353,8 @@ if ($IncludeAppleRemote) {
"-Quiet", "-Quiet",
"-FailureTailLines", [string]$FailureTailLines "-FailureTailLines", [string]$FailureTailLines
) )
foreach ($preset in $AppleRemotePresets) { if ($AppleRemotePresets.Count -gt 0) {
$appleArgs += @("-Presets", $preset) $appleArgs += @("-Presets", ($AppleRemotePresets -join ","))
} }
$result = Invoke-QuietStep ` $result = Invoke-QuietStep `
-Name "apple-remote-build" ` -Name "apple-remote-build" `

View File

@@ -1,10 +1,10 @@
#include "pch.h" #include "pch.h"
#include "platform_windows/windows_bootstrap_helpers.h" #include "platform_windows/windows_bootstrap_helpers.h"
#include "platform_windows/windows_runtime_shell.h"
#include "platform_windows/windows_window_shell.h" #include "platform_windows/windows_window_shell.h"
#include "app.h" #include "app.h"
#include "canvas.h"
#include "legacy_gl_runtime_dispatch.h" #include "legacy_gl_runtime_dispatch.h"
#include "legacy_preference_storage.h" #include "legacy_preference_storage.h"
#include "log.h" #include "log.h"
@@ -162,7 +162,8 @@ void setup_exception_handler(const App& app)
BT_SetPreErrHandler([](INT_PTR nErrHandlerParam){ BT_SetPreErrHandler([](INT_PTR nErrHandlerParam){
const auto* app = reinterpret_cast<const App*>(nErrHandlerParam); const auto* app = reinterpret_cast<const App*>(nErrHandlerParam);
if (Canvas::I && Canvas::I->m_unsaved) auto* canvas_document = app && app->canvas ? app->canvas->m_canvas.get() : nullptr;
if (canvas_document && canvas_document->m_unsaved)
{ {
auto t = std::time(nullptr); auto t = std::time(nullptr);
auto tm = *std::localtime(&t); auto tm = *std::localtime(&t);
@@ -170,12 +171,12 @@ void setup_exception_handler(const App& app)
oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S"); oss << std::put_time(&tm, "%d-%m-%Y %H-%M-%S");
auto path = app->data_path + "/" + app->doc_name + "-recovery (" + oss.str() + ").ppi"; auto path = app->data_path + "/" + app->doc_name + "-recovery (" + oss.str() + ").ppi";
Canvas::I->project_save_thread(path, false); canvas_document->project_save_thread(path, false);
static char abspath[MAX_PATH]; static char abspath[MAX_PATH];
GetFullPathNameA(path.c_str(), MAX_PATH, abspath, NULL); GetFullPathNameA(path.c_str(), MAX_PATH, abspath, NULL);
static char message[4096]; static char message[4096];
snprintf(message, sizeof(message), "File recovered in: %s", abspath); snprintf(message, sizeof(message), "File recovered in: %s", abspath);
MessageBoxA(retained_state().hWnd, message, "File Recovery", MB_OK | MB_ICONWARNING); MessageBoxA(main_window_handle(), message, "File Recovery", MB_OK | MB_ICONWARNING);
} }
LogRemote::I.file_close(); LogRemote::I.file_close();
}, reinterpret_cast<INT_PTR>(&app)); }, reinterpret_cast<INT_PTR>(&app));
@@ -337,7 +338,7 @@ int read_WMI_info()
if (get_int(clsObj, L"CodeIntegrityPolicyEnforcementStatus") > 0) if (get_int(clsObj, L"CodeIntegrityPolicyEnforcementStatus") > 0)
{ {
LOG("SANDBOX DETECTED"); LOG("SANDBOX DETECTED");
retained_state().sandboxed = true; set_main_window_sandboxed(true);
} }
SAFEARRAY *psaNames = NULL; SAFEARRAY *psaNames = NULL;

View File

@@ -23,7 +23,7 @@ void lock_async_render_context();
bool try_lock_async_render_context(); bool try_lock_async_render_context();
void unlock_async_render_context(); void unlock_async_render_context();
void swap_async_render_context(); void swap_async_render_context();
RetainedState& retained_state(); [[nodiscard]] VrShellState& platform_vr_state() noexcept;
} }
void destroy_window(); void destroy_window();
@@ -39,12 +39,12 @@ HWND pp_windows_main_window_handle();
HWND pp_windows_main_window_handle() HWND pp_windows_main_window_handle()
{ {
return pp::platform::windows::retained_state().hWnd; return pp::platform::windows::main_window_handle();
} }
void destroy_window() void destroy_window()
{ {
pp::platform::windows::enqueue_main_thread_task(std::packaged_task<void()>([hWnd = pp::platform::windows::retained_state().hWnd] { pp::platform::windows::enqueue_main_thread_task(std::packaged_task<void()>([hWnd = pp::platform::windows::main_window_handle()] {
pp::platform::windows::request_window_close(hWnd); pp::platform::windows::request_window_close(hWnd);
})); }));
} }
@@ -76,26 +76,39 @@ void win32_update_stylus(float dt)
void win32_update_fps(int frames) void win32_update_fps(int frames)
{ {
auto& state = pp::platform::windows::retained_state(); pp::platform::windows::enqueue_main_thread_task(std::packaged_task<void()>([
pp::platform::windows::enqueue_main_thread_task(std::packaged_task<void()>([hWnd = state.hWnd, window_title = state.window_title, &vr = state.vr, frames] { hWnd = pp::platform::windows::main_window_handle(),
pp::platform::windows::update_window_fps(hWnd, window_title, vr, frames); window_title = pp::platform::windows::main_window_title(),
vr = &pp::platform::windows::platform_vr_state(),
frames] {
pp::platform::windows::update_window_fps(hWnd, window_title, *vr, frames);
})); }));
} }
bool win32_vr_start() bool win32_vr_start()
{ {
auto& state = pp::platform::windows::retained_state(); return pp::platform::windows::start_window_vr(
return pp::platform::windows::start_window_vr(state.vr, state.sandboxed); pp::platform::windows::platform_vr_state(),
pp::platform::windows::main_window_sandboxed());
} }
void win32_vr_stop() void win32_vr_stop()
{ {
pp::platform::windows::stop_window_vr(pp::platform::windows::retained_state().vr); pp::platform::windows::stop_window_vr(pp::platform::windows::platform_vr_state());
} }
void win32_save_window_state() void win32_save_window_state()
{ {
pp::platform::windows::save_window_preferences(pp::platform::windows::retained_state().hWnd); pp::platform::windows::save_window_preferences(pp::platform::windows::main_window_handle());
}
namespace pp::platform::windows {
VrShellState& platform_vr_state() noexcept
{
return retained_state().vr;
}
} }
namespace pp::platform::windows { namespace pp::platform::windows {
@@ -781,7 +794,7 @@ PlatformServices& platform_services()
VrSessionSnapshot read_platform_vr_session_snapshot() noexcept VrSessionSnapshot read_platform_vr_session_snapshot() noexcept
{ {
return read_vr_session_snapshot(retained_state().vr); return read_vr_session_snapshot(platform_vr_state());
} }
} }

View File

@@ -152,6 +152,26 @@ WacomTablet* bound_wacom_tablet() noexcept
return retained_runtime_state().tablet; return retained_runtime_state().tablet;
} }
HWND main_window_handle() noexcept
{
return retained_state().hWnd;
}
const wchar_t* main_window_title() noexcept
{
return retained_state().window_title;
}
bool main_window_sandboxed() noexcept
{
return retained_state().sandboxed;
}
void set_main_window_sandboxed(bool sandboxed) noexcept
{
retained_state().sandboxed = sandboxed;
}
int run_main_application(int argc, char** argv) int run_main_application(int argc, char** argv)
{ {
auto& state = retained_state(); auto& state = retained_state();

View File

@@ -17,5 +17,9 @@ void bind_runtime(AppRuntime* runtime) noexcept;
[[nodiscard]] AppRuntime* bound_runtime() noexcept; [[nodiscard]] AppRuntime* bound_runtime() noexcept;
void bind_wacom_tablet(WacomTablet* tablet) noexcept; void bind_wacom_tablet(WacomTablet* tablet) noexcept;
[[nodiscard]] WacomTablet* bound_wacom_tablet() noexcept; [[nodiscard]] WacomTablet* bound_wacom_tablet() noexcept;
[[nodiscard]] HWND main_window_handle() noexcept;
[[nodiscard]] const wchar_t* main_window_title() noexcept;
[[nodiscard]] bool main_window_sandboxed() noexcept;
void set_main_window_sandboxed(bool sandboxed) noexcept;
} }