Add renderer and package readiness validation gates

This commit is contained in:
2026-06-15 19:20:56 +02:00
parent 68617e8bc4
commit f78fc3076c
23 changed files with 2350 additions and 389 deletions

View File

@@ -203,18 +203,42 @@ powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.p
target before reporting the same readiness matrix. `package-smoke.ps1
-AndroidNativeChecks` also runs the retained Android standard `native-lib`
build and Quest/Focus configure helper for selected Android package kinds,
then reports those native results beside the APK blocker matrix.
then reports those native results beside the APK readiness matrix. Both
wrappers now classify each platform gate as `validated`, `compile-only`, or
`blocked` based on local prerequisites and whether a real root CMake package
target exists.
`scripts/dev/check_package_smoke_readiness.py`, registered as
`panopainter_package_smoke_readiness_self_test`, verifies both wrappers keep
the same seven package kinds, blocked DEBT-0011 status, readiness-only mode,
the same seven package kinds, readiness status modes, readiness-only mode,
retained Android native-check prerequisite metadata, retained Linux/WebGL
CMake baseline metadata, and root CMake package validation target names.
- `scripts/dev/check_component_boundaries.py`, registered as
`panopainter_component_boundary_self_test`, checks pure component source files in
`pp_foundation`, `pp_assets`, `pp_paint`, `pp_document`, `pp_renderer_api`,
`pp_paint_renderer`, `pp_ui_core`, and `pp_app_core` for forbidden platform
SDK/backend includes, `App::I`/`Canvas::I` leakage, and disallowed `pp_*`
target dependencies before desktop-fast validation. Temporary allowed-platform
edges remain explicitly tracked by DEBT-0003 and DEBT-0008.
- `scripts/dev/check_renderer_conformance_matrix.py`, registered as
`panopainter_renderer_conformance_matrix_self_test`, verifies renderer conformance
tests are labeled with the shared `renderer-conformance` matrix profile.
- `scripts/dev/check_renderer_api_contract.py`, registered as
`panopainter_renderer_api_contract_self_test`, enforces backend-neutral boundary
rules for `pp_renderer_api` and `pp_paint_renderer`, including forbidden
backend symbols/includes in these components before renderer contract milestones.
- Root CMake exposes non-default package validation targets:
`panopainter_package_readiness`,
`panopainter_windows_app_package_smoke`,
`panopainter_windows_appx_package_readiness`,
`panopainter_apple_bundle_package_readiness`,
`panopainter_android_standard_native_package`,
`panopainter_android_standard_apk_package_readiness`,
`panopainter_android_quest_apk_package_readiness`,
`panopainter_android_focus_apk_package_readiness`,
`panopainter_android_vr_native_package_configure`, and
`panopainter_android_native_package_smoke`, and
`panopainter_linux_app_package_readiness`,
`panopainter_webgl_package_readiness`, and
`panopainter_linux_webgl_package_readiness`. These targets call the
automation scripts from CMake but do not convert APK/AppX/Linux/Apple/WebGL
package outputs to root CMake package targets yet.

View File

@@ -22,12 +22,51 @@ agent or engineer to remove them without reconstructing context from chat.
routes the retained pre-dispatch state capture through local commit helpers;
the live path still owns concrete layer/action mutation until the retained
commit adapter is fully split from `Canvas`.
- 2026-06-14: `DEBT-0063` was narrowed again. Open/Browse
delete-confirmation now uses handle-based open/close in
`src/node_dialog_open.cpp` and `src/node_dialog_browse.cpp`, with
`attach_legacy_overlay_node_to_root` fallback removed; migration still pending in
remaining panel families.
- 2026-06-14: `DEBT-0063` was narrowed again. `src/node_combobox.cpp` now uses
overlay handle open/close (`open_legacy_overlay_node_with_handle` and
`close_legacy_overlay_node`) for popup lifecycle, with the older attach/close
overlay path removed in this file.
- 2026-06-14: `DEBT-0063` was narrowed again. `src/node_panel_stroke.cpp` now
routes the stroke preset/brush/dual-brush/pattern popup open-close flow through
checked overlay handles and explicit partial-open cleanup; migration is still
pending in remaining panel families.
- 2026-06-14: `DEBT-0063` was narrowed again. `src/node_panel_brush.cpp` now
routes brush popup-menu open-close flow through checked overlay handles and
handle-based close on selection.
- 2026-06-14: `DEBT-0063` was narrowed again. `src/legacy_quick_ui_services.cpp`
now converts quick brush/color popup lifecycle from raw attach+bind-destroy to
checked-overlay open/close (`open_legacy_overlay_node_with_handle` and
`close_legacy_overlay_node`) with explicit handle invalidation on closure.
- 2026-06-14: `DEBT-0063` was narrowed again. `src/node_popup_menu.h/.cpp`
now routes popup-menu close through checked overlay handles and removes direct
`close_legacy_popup_overlay(*this)` usage.
- 2026-06-14: `DEBT-0063` was narrowed again. `src/node_panel_layer.h/.cpp` now
uses shared ownership for current-layer/m_layers tracking, guards stale-layer
callback/mutation paths, and routes popup outside-click close through
`close_legacy_popup_panel`; migration remains open in other panel/dialog
families.
- 2026-06-14: `DEBT-0063` was narrowed again. `src/node_dialog_picker.cpp` now
inlines outside-click/autohide popup close through capture release, parent
detach, and guarded `on_popup_close` dispatch instead of routing that path
through `close_legacy_popup_panel(*this, on_popup_close)`.
- 2026-06-14: `DEBT-0036` was narrowed again. `Canvas::stroke_draw()` now
routes the retained main-pass request assembly through helper APIs and keeps
the live callsite focused on branch selection and pass dispatch.
- 2026-06-14: `DEBT-0064` was opened for the compositor test-local
`Texture2D::bind()` shim needed while planner tests exercise retained inline
preview helpers before tests can link a non-app legacy texture boundary.
- 2026-06-14: `DEBT-0036` was narrowed again. `Canvas::stroke_draw()` now
routes the main-pass destination texture binding declaration through
`Canvas::make_stroke_draw_main_pass_request`; `Canvas::stroke_draw()` now only
assembles execution inputs and dispatches the retained main-pass callback chain.
- 2026-06-14: `DEBT-0064` was narrowed again. Stroke-preview result copy now
routes through `pp::paint_renderer::copy_stroke_preview_result_to_texture(...)`
in `src/paint_renderer/compositor.h`, and the node-level copy wrapper,
final-composite wrapper, and pass-sequence wrapper are gone. The compositor
test-local `Texture2D::bind()` shim is also gone, while live preview still
owns concrete texture binding and remaining OpenGL copy execution.
- 2026-06-14: `DEBT-0036` was narrowed again. `Canvas::stroke_commit()` now
routes the retained request-dispatch invocation through
`execute_canvas_stroke_commit_dispatch(...)`; the wrapper still owns the
@@ -1216,6 +1255,12 @@ agent or engineer to remove them without reconstructing context from chat.
`panopainter_windows_app_package_smoke`, which calls the full Windows
`package-smoke` command from CMake so the app executable/runtime payload check
and Windows AppX blocker matrix are available from the CMake target graph.
- 2026-06-14: DEBT-0011 was narrowed again. `package-smoke.ps1` and
`package-smoke.sh` now classify package readiness as `validated`,
`compile-only`, or `blocked` instead of reporting every platform gate as
blocked, and root CMake now exposes per-platform readiness targets for
Windows AppX, Apple bundles, Android standard/Quest/Focus APKs, Linux app,
and WebGL while real package outputs remain debt-tracked.
- 2026-06-05: DEBT-0007 was narrowed. `platform-build.ps1` now resolves
`VCPKG_ROOT` for vcpkg presets from the environment or bundled Visual Studio
installs, reports the selected vcpkg root in JSON, and root CMake exposes
@@ -1726,7 +1771,7 @@ agent or engineer to remove them without reconstructing context from chat.
| DEBT-0008 | Open | Modernization | `windows-msvc-default` and `windows-msvc-vcpkg-headless` explicitly select Visual Studio 18 2026 for local validation, but non-VS2026 CMake executables on PATH may not know that generator | The local machine has VS 2026, but using an older CMake can still default to Ninja or reject the VS 2026 generator | `cmake --preset windows-msvc-default`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter`; `ctest --preset desktop-fast --build-config Debug` | The repo automation invokes or locates a CMake executable that supports `Visual Studio 18 2026`, and VS 2026 generator validation is the normal Windows path without manual tool selection |
| DEBT-0009 | Open | Modernization | Android root CMake validation currently builds headless targets only, while retained standard/Quest/Focus package CMake paths now have a refreshed CMake 3.10/C++23 baseline outside root CMake; automation queries `sdkmanager`, installs newer or missing SDK Manager NDK/CMake packages, selects the resulting pair before configure, and reports update decisions; root CMake exposes non-default platform-build and retained native package validation targets | Platform app entrypoints still live in legacy Gradle/CMake projects and need Phase 6 alignment | `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64`; `cmake --build --preset android-x64`; `cmake --build --preset android-quest-arm64`; `cmake --build --preset android-focus-arm64`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_platform_build_android_assets`; `powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard`; `powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages quest,focus -ConfigureOnly`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -ReadinessOnly -AndroidNativeChecks -PackageKinds android-standard-apk,android-quest-apk,android-focus-apk`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_android_native_package_smoke` | Android standard, Quest, and Focus/Wave package targets consume shared component targets and have package smoke commands |
| DEBT-0010 | Open | Modernization | `pp_document` is a pure layer/frame/document/undo-history model with alpha-lock metadata, snapshot construction, per-layer frame metadata, renderer-free RGBA8 face payload storage, snapshot-embedded face-payload validation, renderer-free alpha8 selection-mask storage, PPI import/export helpers, stroke-script-to-face-payload CLI automation, `pp_paint_renderer` document face/frame compositors, renderer-neutral six-face texture upload, pure six-face PNG export, pure equirectangular PNG export, pure equirectangular JPEG+XMP export, pure layer/animation-frame PNG collection export, pure depth image/depth PNG export for payload-complete snapshots, shared document-frame export readiness reporting, depth export render-plan reporting, OpenGL command-planner validation through CLI render automation, live Canvas snapshot projection through `pp_app_core`/`legacy_document_canvas_services`, captured RGBA8 payload attachment to `pp_document`, live Save/Save As/Save Version/save-before-workflow snapshot-readiness reporting before retained save execution, pure app-core PPI export for payload-complete canvas snapshots, payload-complete canvas-snapshot renderer-upload plus face-PNG export automation, live cube-face face-PNG writer execution using app-core face target planning and write/publish service dispatch with retained fallback, live PNG/JPEG equirectangular writer execution using the paint-renderer equirectangular exports plus app-core file write/publish dispatch with retained fallback, live payload-complete layer/animation-frame collection writer execution using paint-renderer PNG sequences and app-core collection write/publish dispatch with retained fallback, live payload-complete depth export execution using pure paint-renderer PNG payloads plus app-core two-payload writing with retained fallback, tested app-core document-snapshot export route policy for writer versus retained fallback including current-platform support, and live equirectangular/layer/animation-frame/depth/cube-face export snapshot/render/export-readiness reporting through the shared readiness helper plus the depth render plan, but action-command adoption, live save-writer replacement, Web and incomplete-readback collection handoff, progress/threading parity, broader renderer-owned export execution, exact GPU/golden parity, live-camera depth parity, and renderer-owned cube-face readback ownership are not yet wired | Keep extraction incremental while preserving app behavior | `ctest --preset desktop-fast --build-config Debug`; `pano_cli create-document --width 64 --height 32 --layers 2`; `pano_cli load-project --path tests\data\projects\minimal-project.ppi`; `pano_cli simulate-document-render --width 64 --height 32`; `pano_cli plan-canvas-document-snapshot --width 64 --height 32`; `pano_cli plan-canvas-document-snapshot --captured-face-payloads-per-layer 1`; `pano_cli plan-export-snapshot-route --kind layers-collection --captured-face-payloads 3 --pending-face-payloads 6`; `pp_document_tests`; `pp_document_ppi_import_tests`; `pp_document_ppi_export_tests`; `pp_paint_renderer_compositor_tests`; `pp_app_core_document_canvas_tests`; `pp_app_core_document_export_tests`; `pano_cli_simulate_document_edits_smoke`; `pano_cli_simulate_document_export_smoke`; `pano_cli_simulate_document_render_smoke`; `pano_cli_plan_canvas_document_snapshot_smoke`; `pano_cli_plan_canvas_document_snapshot_payload_smoke`; `pano_cli_plan_export_snapshot_route_pending_smoke`; `pano_cli_save_document_project_roundtrip_smoke`; `pano_cli_apply_stroke_script_roundtrip_smoke`; `pano_cli_apply_stroke_script_rejects_tiny_canvas` | Legacy document behavior is represented by `pp_document`/`pp_paint_renderer` tests and the app consumes it through a boundary/facade |
| DEBT-0011 | Open | Modernization | `package-smoke` validates the Windows CMake app artifact and launch-folder DLL payload, and reports a structured package readiness matrix for Windows AppX, Android standard/Quest/Focus APKs, Apple bundles, Linux app output, and WebGL output; the Windows app smoke passes the configure-time CMake executable so VS 2026 generator validation does not depend on `cmake` from PATH, retained Android package native CMake paths, and retained Linux/WebGL CMake baseline metadata are reachable from package validation and root CMake package-readiness targets, but Windows AppX/APK/Linux/Apple/WebGL package outputs are still `blocked` because root CMake package targets do not exist yet | Platform package targets are not migrated to root CMake yet | `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_windows_app_package_smoke`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -ReadinessOnly -AndroidNativeChecks -PackageKinds android-standard-apk,android-quest-apk,android-focus-apk`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_android_native_package_smoke`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_linux_webgl_package_readiness`; `python scripts/dev/check_package_smoke_readiness.py`; `bash -n scripts/automation/package-smoke.sh` | Package-smoke builds and validates Windows AppX, Android APK variants, Linux app, Apple bundles, and WebGL output where local toolchains are present |
| DEBT-0011 | Open | Modernization | `package-smoke` validates the Windows CMake app artifact and launch-folder DLL payload, reports a structured package readiness matrix for Windows AppX, Android standard/Quest/Focus APKs, Apple bundles, Linux app output, and WebGL output, and now classifies each package gate as `validated`, `compile-only`, or `blocked` based on local prerequisites plus root CMake package-target ownership; the Windows app smoke passes the configure-time CMake executable so VS 2026 generator validation does not depend on `cmake` from PATH, retained Android package native CMake paths, retained Linux/WebGL CMake baseline metadata, and per-platform readiness targets are reachable from package validation and root CMake package-readiness targets, but Windows AppX and Apple/WebGL outputs remain blocked where local toolchains or root package targets are missing and Android/Linux package readiness remains compile-only until root CMake owns real package targets | Platform package targets are not migrated to root CMake yet | `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 --build --preset windows-msvc-default --config Debug --target panopainter_windows_app_package_smoke`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_windows_appx_package_readiness`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_apple_bundle_package_readiness`; `powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -ReadinessOnly -AndroidNativeChecks -PackageKinds android-standard-apk,android-quest-apk,android-focus-apk`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_android_standard_apk_package_readiness`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_android_quest_apk_package_readiness`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_android_focus_apk_package_readiness`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_android_native_package_smoke`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_linux_app_package_readiness`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_webgl_package_readiness`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_linux_webgl_package_readiness`; `python scripts/dev/check_package_smoke_readiness.py`; `bash -n scripts/automation/package-smoke.sh` | Package-smoke builds and validates Windows AppX, Android APK variants, Linux app, Apple bundles, and WebGL output where local toolchains are present |
| DEBT-0012 | Open | Modernization | `pp_ui_core` uses vcpkg tinyxml2 on `windows-msvc-vcpkg-headless`, but retains `pp_vendor_tinyxml2` for default and unproven platform presets | Mobile/AppX/Apple triplets and app packaging still need validation before removing the vendored fallback | `ctest --preset desktop-fast-vcpkg --build-config Debug`; `ctest --preset desktop-fast --build-config Debug`; `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64` | All supported presets consume vcpkg tinyxml2 or document a permanent vendored exception |
| DEBT-0013 | Open | Modernization | `pp_assets`, `pp_document`, `pano_cli inspect-project`, `pano_cli load-project`, and `pano_cli save-project` validate the fixed PPI header, thumbnail/body byte layout, generated multi-layer/multi-frame PPI writing with explicit layer opacity/blend/alpha-lock/visibility metadata, per-layer frame durations, metadata-only and targeted dirty-face-payload save/load round-trips, layer/frame index, dirty-face descriptors, dirty-face PNG payload metadata, asset-level RGBA PNG payload decoding, pure document-to-PPI export, CLI document export automation, file-writing document export automation, stroke-script-generated document payload export, decoded pixel attachment to `pp_document`, live save-path snapshot-readiness reporting, and app-core canvas-snapshot-to-PPI export automation, but full legacy PPI round-trip parity and pure live save writer replacement are not yet extracted | Full PPI save parity requires staged extraction of legacy `Canvas` serialization and image/layer payload handling | `ctest --preset desktop-fast --build-config Debug`; `pp_assets_image_pixels_tests`; `pp_assets_ppi_header_tests`; `pp_document_ppi_import_tests`; `pp_document_ppi_export_tests`; `pano_cli_inspect_project_layout_smoke`; `pano_cli_load_project_metadata_smoke`; `pano_cli_save_project_roundtrip_smoke`; `pano_cli_save_project_payload_roundtrip_smoke`; `pano_cli_simulate_document_export_smoke`; `pano_cli_save_document_project_roundtrip_smoke`; `pano_cli_apply_stroke_script_roundtrip_smoke`; `pano_cli_apply_stroke_script_rejects_tiny_canvas` | Full PPI load/save fixtures cover thumbnails, decoded layer face payloads attached to documents, frames, corrupt payloads, dirty-face payload saving, arbitrary legacy canvas payload/layout combinations, and legacy app round-trip compatibility |
| DEBT-0014 | Open | Modernization | `windows-clangcl-asan` now configures as a headless Ninja/clang-cl preset and uses the release MSVC runtime required by ASan, but local builds still fail because installed clang-cl 18.1.8 is paired with VS 2026-preview STL headers that require Clang 20 or newer | Sanitizer validation should be local and repeatable, but this machine's compiler/header pairing is incompatible | `cmake --fresh --preset windows-clangcl-asan`; `cmake --build --preset windows-clangcl-asan --target pp_foundation` | Install/use Clang 20+ with the VS 2026 STL, or point the preset at a compatible VS 2022 toolchain, then make `platform-build.ps1 -Presets windows-clangcl-asan` pass for the headless matrix |
@@ -1772,11 +1817,11 @@ agent or engineer to remove them without reconstructing context from chat.
| DEBT-0055 | Open | Modernization | `src/app.h` now forward-declares retained iOS/macOS/Android/Linux/Web platform handles instead of including platform SDK headers, and full SDK includes are isolated in `src/platform_legacy/legacy_platform_services.cpp`, but the `App` singleton still stores those platform handles directly | Reduce central header platform coupling incrementally without rewriting non-Windows platform entrypoints before Phase 6 | Windows app build; Apple/Android/Linux/Web package smoke once platform root builds are active | Platform handles are owned by injected `pp_platform_*` shell state or services, and `App` has no platform SDK handle fields or platform conditional members |
| DEBT-0056 | Open | Modernization | `src/asset.h` is now Android-SDK-free and uses opaque Android asset handles behind `Asset::set_android_asset_manager`, but retained `Asset` still owns a static Android asset-manager bridge and `src/asset.cpp` still performs Android `AAssetManager` reads directly; the current `android-arm64` root preset is headless and does not expose `pp_legacy_assets_io`, though the retained Android standard package `native-lib` now builds through its refreshed C++23 CMake path | Reduce legacy asset I/O header coupling without rewriting Android asset loading before the asset manager/storage boundary exists | Windows app build; `powershell -ExecutionPolicy Bypass -File scripts\automation\platform-build.ps1 -Presets android-arm64 -Targets pp_assets`; `powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard` | Android asset loading is owned by injected asset storage/platform services or `pp_assets` file providers, with no static Android asset manager on `Asset` |
| DEBT-0061 | Open | Modernization | Desktop XR runtime selection now lives in tested `pp_platform_api` policy and prefers OpenXR, but `WindowsPlatformServices` still reports OpenXR unavailable and reaches the retained OpenVR SDK bridge as a legacy fallback; Windows runtime deployment copies `openvr_api.dll` beside `PanoPainter.exe` until that fallback is removed | Preserve current desktop VR behavior while replacing OpenVR with OpenXR behind the platform/renderer boundary | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Add an OpenXR SDK/package target, implement desktop OpenXR startup/shutdown/pose/controller submission behind `pp_platform_vr` or `PlatformServices`, validate parity with mocked/runtime smoke coverage, and remove `libs/openvr` plus the OpenVR link/include paths from root CMake |
| DEBT-0063 | Open | Modernization | The retained UI tree still exposes `Node* m_parent`, public `std::vector<std::shared_ptr<Node>> m_children`, raw `find<T>()` lookup results, `add_child<T>()` allocation through `new`, callbacks/observers that take or capture raw `Node*`, and manual `destroy()`/`m_destroyed` semantics. `pp_ui_core` now owns a tested `NodeLifetimeTree` target model with checked node handles, scoped callback connections, subtree destruction, pointer/keyboard capture release, whole-tree clear for layout reload, and mutation-safe dispatch, plus a tested `UiOverlayLifetime` popup/dialog stack model. Retained app-dialog root insertion, app-menu popup template cloning/root attachment, quick/stroke/brush panel popup root attachment, combo-box popup insertion, Open/Browse delete-confirmation dialog insertion, popup tick decoration insertion, top-toolbar panel popup insertion, repeated retained popup activation flag setup, repeated retained popup close/release execution, popup tick-decoration close callback wiring, and popup-panel outside-click release/remove/callback dispatch are now centralized in `src/legacy_ui_overlay_services.*`, but retained `Node`/`NodePopupMenu`/`NodeDialog*` still have not adopted checked handles or scoped callback ownership | Preserve current UI behavior while making panel/dialog extraction safe instead of spreading lifetime hazards into the new architecture | `pp_ui_core_layout_xml_tests`; `pp_ui_core_node_lifetime_tests`; `pp_ui_core_overlay_lifetime_tests`; future `pp_panopainter_ui_dialog_lifetime_tests`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | Retained `Node` and `pp_panopainter_ui` adopt checked node handles or equivalent non-owning references, scoped callback connection/disconnect semantics, mutation-safe event dispatch, parent/child invariants hidden behind APIs, and destroy-during-callback/capture-release/popup-close/layout-reload tests; retained `Node*` APIs are removed or isolated behind compatibility adapters |
| DEBT-0063 | Open | Modernization | `pp_ui_core` now owns tested `NodeLifetimeTree` and `UiOverlayLifetime` models for checked handles, scoped callback connections, subtree destruction, capture release, and mutation-safe dispatch. `src/node_panel_layer.h/.cpp`, `src/node_combobox.cpp`, `src/node_dialog_open.cpp`, `src/node_dialog_browse.cpp`, `src/node_panel_stroke.cpp`, `src/node_panel_brush.cpp`, `src/node_dialog_picker.cpp`, `src/legacy_quick_ui_services.cpp`, and `src/node_popup_menu.h/.cpp` now route popup/dialog/menu lifetime through checked overlay handles and handle-based close; migration remains open in other legacy panel/dialog families | Preserve current UI behavior while completing safe panel/dialog lifetime migration incrementally | `pp_ui_core_layout_xml_tests`; `pp_ui_core_node_lifetime_tests`; `pp_ui_core_overlay_lifetime_tests`; `tests/ui_core/node_lifetime_tests.cpp:destroy_subtree_clears_child_connections`; `tests/ui_core/overlay_lifetime_tests.cpp:double_close_overlay_returns_invalid_argument`; `ctest --preset desktop-fast --build-config Debug`; `cmake --build --preset windows-msvc-default --config Debug --target panopainter_app pp_ui_core_node_lifetime_tests pp_ui_core_overlay_lifetime_tests` | Remaining legacy popup/dialog families still use non-handle ownership and open lifetimes; migration stays open until their surfaces are converted, including lifecycle safety parity checks |
| DEBT-0057 | Open | Modernization | Default canvas allocation size now dispatches through `PlatformServices::default_canvas_resolution`, removing the `CANVAS_RES` platform macro from `src/canvas.h`; WebGL's retained 512 default now lives in tested `pp_platform_api` policy behind injectable `pp::platform::WebPlatformServices`, but the Web shell still reaches the default implementation through the retained fallback until a dedicated Web service is injected directly | Preserve WebGL memory behavior while moving canvas creation policy out of shared canvas headers and into the platform boundary | `pp_platform_api_tests`; `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests`; Windows app build; WebGL package smoke once root Web build exists | Default canvas resolution is owned by injected `pp_platform_*` services for every supported platform, with no WebGL branch in the legacy fallback |
| DEBT-0058 | Open | Modernization | App-level progress/message/input dialog metadata, including message-dialog OK/cancel captions, now consumes pure `pp_app_core` through `App::show_progress`, `App::message_box`, `App::input_box`, `pano_cli plan-app-dialog`, and `pp_app_core_app_dialog_tests`; live execution is centralized in `src/legacy_app_dialog_services.*`, retained root insertion now routes through `src/legacy_ui_overlay_services.*`, and whats-new dialog state persistence routes through `src/legacy_preference_storage.*`, but the bridge still creates retained `NodeProgressBar`, `NodeMessageBox`, and `NodeInputBox` instances with raw callback/lifetime ownership | Preserve current app-shell dialog behavior while moving shared dialog policy toward UI/app services | `pp_app_core_app_dialog_tests`; `pano_cli plan-app-dialog --kind progress --total -4`; `pano_cli plan-app-dialog --kind message --cancel`; `pano_cli plan-app-dialog --kind input --ok-caption Save`; `ctest --preset desktop-fast --build-config Debug`; Windows app build | Progress/message/input dialog creation, callback wiring, layout insertion, lifetime ownership, and headless automation are owned by injected app/UI services with `App` methods acting only as adapters |
| DEBT-0059 | Open | Modernization | iOS root CMake headless builds assign generated bundle identifiers and disable code signing for executable test/tool targets | The current Apple gate is compile validation for shared component targets; signed iOS app/package validation is not migrated to root CMake yet | `powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.ps1 -Presets macos,ios-simulator,ios-device`; `sh scripts/automation/platform-build.sh "ios-device"` on `panopainter-mac` | Root CMake owns the signed Apple app/package targets, package-smoke validates Apple bundles where signing material is available, and headless iOS test/tool targets are either excluded from signed package builds or use explicit test-runner signing policy |
| DEBT-0064 | Open | Modernization | `pp_paint_renderer_compositor_tests` has a test-local no-op `Texture2D::bind()` definition so retained inline stroke-preview copy helpers can be covered without linking the full app-only legacy texture implementation | `tests` are configured before `pp_legacy_engine`, and linking the app legacy texture object into this planner test would couple the renderer-neutral test target back to the app target graph | `cmake --build --preset windows-msvc-default --config Debug --target pp_paint_renderer_compositor_tests`; `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-on-failure` | Move retained preview copy behavior behind a pure callback-only test seam or split legacy texture binding into a linkable non-app test support target, then delete the test-local `Texture2D::bind()` shim |
| DEBT-0064 | Open | Modernization | Stroke-preview result copy now routes through the renderer-facing `pp::paint_renderer::copy_stroke_preview_result_to_texture(...)` callback-only contract in `src/paint_renderer/compositor.h`; the node-level copy wrapper, final-composite wrapper, and pass-sequence wrapper are removed, and `pp_paint_renderer_compositor_tests` no longer needs either a test-local `Texture2D::bind()` definition. Live preview still owns concrete texture binding and OpenGL execution around the remaining preview flow | `tests` are configured before `pp_legacy_engine`, and linking the app legacy texture object into this planner test would still couple the renderer-neutral test target back to the app target graph | `cmake --build --preset windows-msvc-default --config Debug --target pp_paint_renderer_compositor_tests`; `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-on-failure` | Keep preview-copy behavior on renderer-facing callback-only seams and move the remaining live preview copy execution behind renderer-owned services so the remaining preview flow can become fully app-texture-free |
## Closed Debt

View File

@@ -0,0 +1,115 @@
# Renderer API Backend-Neutral Contract
## Purpose
`pp_renderer_api` defines the backend-neutral rendering contract used by `pp_paint_renderer`
and the higher-level app core. This document captures the minimum behavior that any
concrete backend (`pp_renderer_gl` today, Vulkan/Metal later) must preserve.
## Contract Scope
- Public interfaces:
- `pp::renderer::IRenderDevice`
- `pp::renderer::ICommandContext`
- `pp::renderer::ITexture2D`
- `pp::renderer::IRenderTarget`
- `pp::renderer::IShaderProgram`
- `pp::renderer::IMesh`
- `pp::renderer::IReadbackBuffer`
- `pp::renderer::IRenderTrace`
- `pp::renderer::Recording*` helpers in `renderer_api/recording_renderer.*`
- Validation helpers in `renderer_api.h` and shader catalog helpers in
`renderer_api/shader_catalog.*`
## Behavioral Invariants
- No exceptions are part of API control flow; failures are reported through
`pp::foundation::Status` / `pp::foundation::Result`.
- Object lifetimes remain backend-owned; API consumers pass references/handles only.
- Resource descriptors and command/state descriptors must be validated and constrained by the
helper functions.
- Backends may reject unsupported operations via explicit non-OK status but must not mutate
visible program state before reporting failure.
- Error codes and debug names are deterministic and backend-neutral (human-readable and
test-stable where feasible).
## Surface Contracts
1. `IRenderDevice`
- `backend_name()` identifies backend family.
- `features()` returns capability bits used for planner decisions.
- Resource creation methods return `Result` and report allocation/validation failures.
- `immediate_context()` is stable for the lifetime of the device object.
- `trace()` may return `nullptr`; callers must tolerate no trace provider.
2. `ICommandContext`
- State mutation (`set_viewport`, `set_scissor`, blend/depth/shader/sampler/mesh/program binds) is
explicit and backend-agnostic.
- Command methods that can fail must return status.
- `end_render_pass()` is always side-effect safe and non-throwing.
- `read_texture` / `capture_frame` readback contracts are byte-sized and descriptor-driven.
- Texture upload/copy/readback/transition methods must respect descriptor bounds and ordering rules.
3. Resource descriptors and helpers
- `TextureDesc`, `Extent2D`, `Viewport`, `ScissorRect`, `RenderPassDesc`,
`TextureUsage`, `TextureState`, `BlendState`, `DepthState`, sampler/topology enums
are shared semantic vocabulary across backends.
- Validation helpers (`validate_*`) are the compatibility fence for contract behavior.
- `PaintFeedbackPlan` and `plan_paint_feedback(...)` are the feature/algorithm decision seam
for framebuffer feedback vs ping-pong workflows.
4. Trace and recording
- `IRenderTrace` is optional and may be elided, but implementations should support scoped markers
and markers where used.
- Recording backend (`RecordingRenderDevice`, `RecordingCommandContext`) must preserve command
order and reject invalid sequences through status/command visibility.
## Feature semantics
Backends are expected to honor all feature bits consistently:
- `framebuffer_fetch`
- `explicit_texture_transitions`
- `texture_copy`
- `render_target_blit`
- `frame_capture`
- `float16_render_targets`
- `float32_render_targets`
- `float32_linear_filtering`
Feature gates must be enforced by planners before issuing backend commands.
## Existing conformance coverage
Current renderer-api conformance tests (non-backend):
- `pp_renderer_api_tests`
- `pp_renderer_api` test cases:
- `validates_texture_usage_contract`
- `validates_texture_transition_contract`
- `validates_mipmap_generation_contract`
- `validates_texture_copy_contract`
- `validates_blit_contract`
- `plans_paint_feedback_paths`
- `renderer_interfaces_support_backend_neutral_dispatch`
- `recording_renderer_*` command-sequence and validation tests
OpenGL-specific conformance remains in `pp_renderer_gl` suites:
- `pp_renderer_gl_capabilities_tests`
- `pp_renderer_gl_command_plan_tests`
- `pp_renderer_gl_gpu_readback_tests` (where GPU context is available)
- `panopainter_renderer_conformance_matrix_self_test`
- `ctest --preset renderer-conformance`
- `panopainter_renderer_api_contract_self_test` (tooling guard for renderer API and paint renderer
backend-neutral contract source purity).
## Open items for RND-007
- Ensure Vulkan/Metal planning/lifecycle tests run the same contract surfaces without backend leakage.
- Keep `pp_renderer_api` implementation/usage free from backend-only headers and raw platform state.
- Keep new backend labs opt-in until this contract and conformance matrix are complete.

View File

@@ -1836,7 +1836,7 @@ Gate:
Goal: prepare Vulkan and Metal without destabilizing the OpenGL parity path.
Status: not started. Do not start production Vulkan or Metal work until
Status: in progress. Do not start production Vulkan or Metal work until
`RND-007` and `RND-008` freeze and validate the renderer API backend contract.
`RND-009` and `RND-010` are opt-in lab targets only and must stay outside the
production app path.
@@ -1848,6 +1848,14 @@ Implementation tasks:
- `pp_renderer_metal_lab`
- Use `D:\Dev\vkpaint` as reference material for Vulkan painting experiments,
not as direct production code.
- Record and enforce the renderer API contract surface in
`docs/modernization/renderer_api_contract.md` and keep
`panopainter_renderer_api_contract_self_test` as a precondition for
`RND-007` closeout.
- Add and keep a renderer-conformance matrix fixture profile using
`renderer-conformance` labels plus `ctest --preset renderer-conformance` and
`ctest --preset desktop-gpu`, enforced by
`panopainter_renderer_conformance_matrix_self_test` before `RND-008` closeout.
- Before integration, prove:
- ping-pong compositing path
- input-attachment/subpass path where applicable