41 KiB
41 KiB
Modernization Debt Log
Status: live Last updated: 2026-06-04
Every shortcut, temporary adapter, retained vendored dependency, skipped platform gate, compatibility shim, or incomplete automation path must be recorded here before it lands. Entries must be specific enough for a future agent or engineer to remove them without reconstructing context from chat.
Entry Rules
- Add an entry before merging the shortcut.
- Reference the debt id in code comments, TODOs, ADRs, or roadmap notes.
- Include an owner, reason, validation command, and removal condition.
- Do not close an entry until the removal condition is met and validated.
- Prefer deleting shortcuts over expanding this log.
Open Debt
| ID | Status | Owner | Item | Reason | Validation | Removal Condition |
|---|---|---|---|---|---|---|
| DEBT-0001 | Open | Modernization | Existing platform build files remain alongside new CMake | Required for incremental migration without losing platform coverage | Existing platform builds plus new CMake configure | Remove after all platform builds consume shared CMake targets |
| DEBT-0002 | Open | Modernization | Vendored SDK and patched libraries retained initially | Some dependencies are SDK-only, patched, or have platform-specific binaries | Dependency inventory and platform build smoke tests | Replace with vcpkg packages or document permanent vendored status after triplet evaluation |
| DEBT-0003 | Open | Modernization | Existing singletons remain during initial split; App::open_document, App::request_close, App::share_file, App::cloud_upload, App::cloud_upload_all, App::cloud_browse, App::rec_start, App::rec_stop, App::rec_clear, App::rec_export, file-menu save actions, NodeCanvas canvas hotkeys, new/open/browse dirty-document workflow prompts, new-document target/resolution/overwrite decisions, save-as document file naming and overwrite decisions, save-version target decisions, export start/menu/target naming/path decisions, share-file saved-path decisions, file/image/save/directory picker selected-path decisions, display-file external-open decisions, virtual-keyboard visibility decisions, recording lifecycle/export progress decisions, cloud-upload prompt/save-before-upload decisions, cloud-browse availability and selected-download decisions, bulk cloud-upload progress decisions, tools/options app preference decisions, app status/display and renderer diagnostic decisions, document resize decisions, layer rename/menu decisions, Tools menu/panel decisions, About menu/diagnostic decisions, main toolbar/status decisions, pano_cli classify-open, pano_cli plan-open-route, pano_cli plan-file-menu, pano_cli plan-new-document, pano_cli plan-document-file, pano_cli plan-document-version, pano_cli plan-export-start, pano_cli plan-export-menu, pano_cli plan-export-target, pano_cli plan-recording-session, pano_cli plan-app-preferences, pano_cli plan-app-status, pano_cli plan-tools-menu, pano_cli plan-tools-panel, pano_cli plan-about-menu, pano_cli plan-main-toolbar, pano_cli plan-document-resize, pano_cli plan-layer-rename, pano_cli plan-layer-menu, pano_cli plan-canvas-hotkey, pano_cli plan-share-file, pano_cli plan-picked-path, pano_cli plan-display-file, pano_cli plan-keyboard-visibility, pano_cli plan-cloud-upload, pano_cli plan-cloud-browse, pano_cli plan-cloud-upload-all, and pano_cli simulate-app-session now consume pure pp_app_core route/session/export/recording/preferences/status/share/platform-I/O/display/keyboard/cloud/resize/layer/tools/about/toolbar/canvas-command contracts, but document creation/loading, brush import execution, saving, export execution, tools/options UI execution, Tools panel creation/execution, About dialog/diagnostic execution, toolbar/status dialog/history/canvas execution, status/display UI rendering, renderer diagnostic capability adaptation, document resize execution, layer rename/menu execution, settings persistence, platform share service execution, picker service execution, display-file service execution, keyboard service execution, recording/MP4 execution, cloud upload execution, and cloud browse/download execution still reach legacy Canvas::I/UI/network/video/platform singletons |
Avoid behavior changes while introducing component boundaries | App launch and component tests; pp_app_core_document_route_tests; pp_app_core_file_menu_tests; pp_app_core_document_export_tests; pp_app_core_document_recording_tests; pp_app_core_app_preferences_tests; pp_app_core_app_status_tests; pp_app_core_tools_menu_tests; pp_app_core_about_menu_tests; pp_app_core_main_toolbar_tests; pp_app_core_document_resize_tests; pp_app_core_document_layer_tests; pp_app_core_document_sharing_tests; pp_app_core_document_platform_io_tests; pp_app_core_document_cloud_tests; pp_app_core_document_session_tests; pp_app_core_canvas_hotkey_tests; pano_cli classify-open --path D:/Paint/demo.ppi; pano_cli plan-open-route --path D:/Paint/demo.ppi --unsaved; pano_cli plan-file-menu --command save-as; pano_cli plan-new-document --work-dir D:/Paint --name demo --resolution-index 3 --target-exists; pano_cli plan-document-file --work-dir D:/Paint --name demo --target-exists; pano_cli plan-document-version --directory D:/Paint --doc-name demo.01 --existing-path D:/Paint/demo.02.ppi; pano_cli plan-export-start --requires-license --demo; pano_cli plan-export-menu --kind animation-mp4 --demo; pano_cli plan-export-target --kind file --work-dir D:/Paint --doc-name demo --extension .png; pano_cli plan-recording-session --running --frame-count 12; pano_cli plan-app-preferences --ui-scale 1.5 --display-density 2 --current-scale 1.6 --scale-option 1 --scale-option 1.5 --rtl; pano_cli plan-app-status --doc-name demo --unsaved --resolution 2048 --resolution-index 3 --zoom 1.25 --history-bytes 1572864 --recording-running --encoder-available --encoded-frames 12 --framebuffer-fetch --float32 --float32-linear --float16; pano_cli plan-tools-menu --command shortcuts; pano_cli plan-tools-panel --panel layers; pano_cli plan-about-menu --command news --version-major 2 --version-minor 5 --version-fix 7; pano_cli plan-main-toolbar --command undo --undo-count 2; pano_cli plan-document-resize --current-resolution 2048 --selected-resolution-index 4; pano_cli plan-layer-rename --old-name Base --new-name Paint; pano_cli plan-layer-menu --command merge --current-index 2 --lower-name Paint; pano_cli plan-canvas-hotkey --event key-up --key z --ctrl --undo-count 2; pano_cli plan-share-file --path D:/Paint/demo.ppi; pano_cli plan-picked-path --path D:/Paint/demo.ppi; pano_cli plan-display-file --path D:/Paint/export.png; pano_cli plan-keyboard-visibility --visible; pano_cli plan-cloud-upload --new-document --unsaved; pano_cli plan-cloud-browse --selected-file demo.ppi; pano_cli plan-cloud-upload-all --file-count 3; pano_cli simulate-app-session --unsaved --save-intent save-dirty-version; pano_cli simulate-app-session --no-canvas; ctest --preset desktop-fast --build-config Debug |
Replace singleton reaches with context/service injection at component boundaries |
| DEBT-0004 | Open | Modernization | Android, Linux, WebGL, Apple, and AppX build files remain platform-specific until root CMake alignment reaches them | Prevent platform regressions during incremental migration; raw Windows .sln/.vcxproj files were removed on 2026-05-31 by user decision |
cmake --preset windows-msvc-default; platform-specific configure/build smoke checks as each platform is migrated |
Root CMake owns every platform source list and package path |
| DEBT-0005 | Open | Modernization | Temporary local CTest harness is used before Catch2 is wired through vcpkg | vcpkg is not currently on PATH, but headless tests need to run now |
ctest --preset desktop-fast --build-config Debug |
Replace tests/test_harness.h tests with Catch2 tests once vcpkg toolchain/presets are validated |
| DEBT-0007 | Open | Modernization | vcpkg.json and windows-msvc-vcpkg-headless are validated for the headless Windows component matrix, but app targets still use vendored libraries and Android/Apple triplets are not proven |
Dependency migration must stay incremental while SDK/patched/vendor dependencies remain in use | $env:VCPKG_ROOT="C:\Program Files\Microsoft Visual Studio\2022\Community\VC\vcpkg"; cmake --preset windows-msvc-vcpkg-headless; ctest --preset desktop-fast-vcpkg --build-config Debug |
Component targets consume vcpkg packages where reliable and desktop app, Android, and Apple triplets are validated or explicitly documented as permanent vendor exceptions |
| DEBT-0008 | Open | Modernization | windows-msvc-default preset is used for local validation because the VS 2026 generator is not installed here |
The target VS 2026 preset must remain, but this machine configures with Visual Studio 17 2022 | cmake --preset windows-msvc-default; ctest --preset desktop-fast --build-config Debug |
Validate windows-vs2026-x64 on a machine with Visual Studio 2026 installed and make it the default Windows validation preset |
| DEBT-0009 | Open | Modernization | Android root CMake validation currently builds headless targets only, not APK/package variants; standard arm64/x64, Quest arm64, and Focus/Wave arm64 have named root build presets and share the refreshed platform-build component matrix |
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 |
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, and stroke-script-to-face-payload CLI automation, but it is not yet wired to legacy Canvas, legacy save, or legacy action commands |
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; pp_document_tests; pp_document_ppi_import_tests; pp_document_ppi_export_tests; pano_cli_simulate_document_edits_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 |
Legacy document behavior is represented by pp_document tests and the app consumes it through a boundary/facade |
| DEBT-0011 | Open | Modernization | package-smoke validates the Windows CMake app artifact and now reports a structured package readiness matrix for Windows AppX, Android standard/Quest/Focus APKs, Apple bundles, and WebGL output, but those 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; bash -n scripts/automation/package-smoke.sh |
Package-smoke builds and validates Windows AppX, Android APK variants, 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, and decoded pixel attachment to pp_document, but full legacy PPI round-trip parity is 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 |
| DEBT-0015 | Open | Modernization | Cursor visibility requests now consume pure pp_app_core planning through pano_cli plan-cursor-visibility, App::show_cursor/App::hide_cursor dispatch through PlatformServices without platform guards, and Windows live execution uses injected WindowsPlatformServices, but macOS cursor execution still reaches the retained fallback adapter |
Keep canvas cursor behavior stable while platform shells are extracted incrementally | pp_app_core_document_platform_io_tests; pano_cli plan-cursor-visibility --visible; ctest --preset desktop-fast --build-config Debug |
Cursor visibility execution is owned by injected pp_platform_* services for every supported platform |
| DEBT-0016 | Open | Modernization | Clipboard get/set requests now consume pure pp_app_core planning through pano_cli plan-clipboard-read and pano_cli plan-clipboard-write, and Windows live execution uses injected WindowsPlatformServices, but Apple/Android clipboard execution still reaches retained fallback adapter branches from App::clipboard_get_text and App::clipboard_set_text |
Keep picker/color text clipboard behavior stable while platform shells are extracted incrementally | pp_app_core_document_platform_io_tests; pano_cli plan-clipboard-write --text #ff00aa; ctest --preset desktop-fast --build-config Debug |
Clipboard execution is owned by injected pp_platform_* services for every supported platform |
| DEBT-0017 | Open | Modernization | Startup storage path preparation, App::clipboard_get_text, App::clipboard_set_text, App::show_cursor, App::hide_cursor, App::showKeyboard, App::hideKeyboard, App::display_file, App::share_file, native app/window close, UI-thread lifecycle hooks, render-context acquire/release/present hooks, render-target binding hooks, render platform hint hooks, render debug callback hooks, render-capture frame hooks, recording cleanup, live asset/layout reload policy, diagnostic stacktrace/crash hooks, per-frame platform hooks, App::pick_image, App::pick_file, the non-writer App::pick_file_save, App::pick_dir, and prepared-file save/download handoff now call the SDK-free pp::platform::PlatformServices interface, and Windows injects WindowsPlatformServices from src/platform_windows/windows_platform_services.*; non-Windows live implementations still use src/platform_legacy/legacy_platform_services.*, a named fallback adapter that forwards to retained Apple/Android/Linux/Web bridge functions and retained no-op branches |
Preserve behavior while moving platform execution behind a testable service boundary before platform shell implementations are injected | pp_platform_api_tests; pp_app_core_document_platform_io_tests; ctest --preset desktop-fast --build-config Debug; powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug |
Replace src/platform_legacy/legacy_platform_services.* with injected pp_platform_* service implementations owned by each non-Windows platform shell |
| DEBT-0019 | Open | Modernization | Unreferenced-parameter warnings are muted globally through pp_project_warnings with MSVC /wd4100 and Clang/GCC -Wno-unused-parameter |
Legacy callbacks, virtual hooks, serializer methods, and platform/API compatibility functions carry many intentionally unused parameters during the component split; muting this keeps stricter warning builds focused on higher-signal migration issues | cmake --build --preset windows-msvc-default --config Debug --target PanoPainter; ctest --preset desktop-fast --build-config Debug; cmake --build --preset linux-clang --target pp_foundation |
Remove /wd4100 and -Wno-unused-parameter, mark intentionally unused parameters with names/comments or [[maybe_unused]], and make the Windows app plus headless Clang/GCC tests pass without unreferenced-parameter warnings |
| DEBT-0020 | Open | Modernization | Document resize dialog state, selected-resolution planning, and execution dispatch now consume pure pp_app_core through NodeDialogResize, App::dialog_resize, pano_cli plan-document-resize, and the DocumentResizeServices boundary, and live resize shares src/legacy_document_canvas_services.* with canvas clear commands, but the shared live bridge still calls legacy Canvas::resize, updates the legacy app title, and clears legacy ActionManager history through the history bridge |
Preserve existing layer/frame GPU resize behavior while the document model and canvas execution boundary are extracted incrementally | pp_app_core_document_resize_tests; pano_cli plan-document-resize --current-resolution 2048 --selected-resolution-index 4; ctest --preset desktop-fast --build-config Debug |
Document resize execution is owned by injected document/app services with no legacy resize adapter, title shim, or direct ActionManager history clearing |
| DEBT-0021 | Open | Modernization | Layer rename planning/execution dispatch and layer panel operation planning/execution dispatch now consume pure pp_app_core through App::dialog_layer_rename, App::init_sidebar layer callbacks, pano_cli plan-layer-rename, pano_cli plan-layer-operation, DocumentLayerRenameServices, and DocumentLayerOperationServices, and the live execution adapters are centralized in src/legacy_document_layer_services.*, but that shared bridge still mutates legacy Canvas layer state, NodeLayer/NodePanelLayer, and ActionManager undo entries |
Preserve existing UI/canvas behavior while document layer commands and undo history are extracted incrementally | pp_app_core_document_layer_tests; pano_cli plan-layer-rename --old-name Base --new-name Paint; pano_cli plan-layer-operation --kind add --layer-count 2 --index 1 --name Paint; ctest --preset desktop-fast --build-config Debug |
Layer command execution is owned by the document/app command boundary with legacy Canvas/UI nodes acting only as adapters or removed entirely |
| DEBT-0022 | Open | Modernization | Animation panel frame command planning, panel action planning, panel-control/timeline execution dispatch, selected-frame click dispatch, playback tick stepping, and play-mode toggles now consume pure pp_app_core through NodePanelAnimation, pano_cli plan-animation-operation, pano_cli plan-animation-panel-action, and DocumentAnimationServices; live execution is centralized in src/legacy_document_animation_services.*, but that bridge still mutates or reads legacy Canvas/Layer frame state, canvas mode, animation-panel timeline/playback fields, and uses a temporary NodePanelAnimation friend adapter |
Preserve existing animation panel behavior while timeline/frame commands move toward the document/app command boundary | pp_app_core_document_animation_tests; pano_cli plan-animation-operation --kind add --frame-count 2 --current-frame 0; pano_cli plan-animation-operation --kind select --frame-count 3 --selected-frame 1 --layer-index 2 --layer-id 42; pano_cli plan-animation-operation --kind playback --total-duration 5 --current-frame 4 --offset 1; pano_cli plan-animation-operation --kind toggle-playback --playing; pano_cli plan-animation-panel-action --action next --total-duration 5 --current-frame 4; ctest --preset desktop-fast --build-config Debug |
Animation frame/timeline/playback execution is owned by injected document/app timeline services with no legacy Canvas/Layer/canvas-mode adapter and UI nodes acting only as adapters or removed entirely |
| DEBT-0023 | Open | Modernization | Brush/color/preset/stroke-settings UI planning, texture-list add/remove/reorder planning, stroke-panel slider/toggle/blend/reset planning, and execution dispatch now consume pure pp_app_core through App::init_sidebar, NodePanelBrush, NodePanelStroke, restored/docked floating-panel callbacks, pano_cli plan-brush-operation, pano_cli plan-brush-texture-list, pano_cli plan-brush-stroke-control, BrushUiServices, BrushTextureListServices, and BrushStrokeControlServices, and live execution is centralized in src/legacy_brush_ui_services.*, but the bridge still mutates legacy Brush/Canvas::I, loads/saves legacy brush texture images, refreshes legacy quick/stroke/color widgets, and uses a temporary NodePanelBrush friend adapter to reach private list state |
Preserve existing brush UI behavior while brush commands move toward a brush/app/asset command boundary and asset-managed texture selection | pp_app_core_brush_ui_tests; pano_cli plan-brush-operation --kind color --r 0.25 --g 0.5 --b 0.75 --a 1; pano_cli plan-brush-operation --kind pattern --path data/patterns/noise.png --thumb data/patterns/thumbs/noise.png; pano_cli plan-brush-texture-list --kind add --dir brushes --data-path data --source C:/Temp/soft.png; pano_cli plan-brush-stroke-control --kind float --setting tip-size --value 42.5; pano_cli plan-brush-stroke-control --kind blend --setting pattern --blend-mode 3; ctest --preset desktop-fast --build-config Debug |
Brush color/texture/preset/stroke-settings, texture-list, and stroke-control execution are owned by injected brush/app/asset/UI services with no legacy brush/canvas adapter or NodePanelBrush friend access |
| DEBT-0024 | Open | Modernization | Grid/heightmap/lightmap UI planning and execution dispatch now consume pure pp_app_core through NodePanelGrid, pano_cli plan-grid-operation, and the GridUiServices boundary; live execution is centralized in src/legacy_grid_ui_services.*, but the bridge still performs legacy image loading, OpenGL texture updates, nanort lightmap baking/progress, and Canvas::draw_objects commit execution |
Preserve grid/lightmap behavior while moving renderable grid commands toward app/renderer/document boundaries | pp_app_core_grid_ui_tests; pano_cli plan-grid-operation --kind render --float32 --texture-resolution 1024 --samples 32; ctest --preset desktop-fast --build-config Debug |
Grid heightmap/lightmap execution is owned by app/renderer/document services with NodePanelGrid acting only as UI adapter |
| DEBT-0025 | Open | Modernization | Quick brush/color slot and mini-state planning and execution dispatch now consume pure pp_app_core through NodePanelQuick, pano_cli plan-quick-operation, and the QuickUiServices boundary; live execution is centralized in src/legacy_quick_ui_services.*, but the bridge still mutates legacy quick UI widgets, Brush previews, color picker popup state, and preset popup state |
Preserve quick-panel behavior while quick brush/color commands move toward a brush/app command boundary with safer automation coverage | pp_app_core_quick_ui_tests; pano_cli plan-quick-operation --kind brush --current-index 0 --slot-index 2; pano_cli plan-quick-operation --kind restore --brush-index 2 --color-index 1 --fire-event; ctest --preset desktop-fast --build-config Debug |
Quick-panel selection, popup, restore, reset, brush preview, and color execution are owned by injected app/brush/UI services with no legacy quick-panel adapter |
| DEBT-0026 | Open | Modernization | Toolbar history command planning and canvas hotkey history dispatch now consume pure pp_app_core through App::init_toolbar_main, NodeCanvas, pano_cli plan-history-operation, and the HistoryUiServices boundary, and both live callers share src/legacy_history_services.* for saturated legacy history metrics and execution, but the shared live bridge still mutates legacy ActionManager stacks directly |
Preserve undo/redo/clear behavior while moving action history toward document/app command services | pp_app_core_history_ui_tests; pano_cli plan-history-operation --kind undo --undo-count 2; pano_cli plan-history-operation --kind clear --undo-count 2 --redo-count 1 --memory-bytes 4096; ctest --preset desktop-fast --build-config Debug |
Undo/redo/clear execution is owned by injected document/app history services with no legacy ActionManager adapter |
| DEBT-0027 | Open | Modernization | Canvas draw-tool toolbar command, canvas input mode switching, active-state planning/execution dispatch, and canvas keyboard/touch command planning now consume pure pp_app_core through App::init_toolbar_draw, App::update, NodeCanvas, pano_cli plan-canvas-tool, pano_cli plan-canvas-tool-state, pano_cli plan-canvas-hotkey, CanvasToolServices, and CanvasHotkeyServices, and live toolbar/input/hotkey execution is centralized in src/legacy_canvas_tool_services.*, but the bridge still mutates or reads legacy Canvas mode state, pen picking state, touch-lock state, transform copy/cut action objects, ActionManager, legacy save UI, legacy stroke size controls, and cursor/UI singletons |
Preserve current toolbar, stylus eraser, keyboard, and touch command behavior while canvas input/tools move toward an app/document command boundary | pp_app_core_canvas_tool_ui_tests; pp_app_core_canvas_hotkey_tests; pano_cli plan-canvas-tool --kind copy; pano_cli plan-canvas-tool-state --mode draw --picking --touch-lock; pano_cli plan-canvas-hotkey --event key-up --key z --ctrl --undo-count 2; pano_cli plan-canvas-hotkey --event key-up --key s --ctrl --shift; ctest --preset desktop-fast --build-config Debug |
Canvas tool selection, toolbar state refresh, picking, touch lock, stylus eraser/key mode switching, hotkey/touch command dispatch, save hotkeys, history hotkeys, brush-size hotkeys, and transform action execution are owned by injected app/document/canvas services with no legacy toolbar/canvas adapter |
| DEBT-0028 | Open | Modernization | Canvas clear command planning and execution dispatch now consume pure pp_app_core through App::init_toolbar_main, Layer menu clear, pano_cli plan-canvas-clear, and the DocumentCanvasClearServices boundary, and toolbar/Layer-menu clear share src/legacy_document_canvas_services.*, but the shared live bridge still calls legacy Canvas::clear, which records ActionLayerClear, clears the current layer/frame, and marks legacy Canvas::I unsaved |
Preserve clear-current-layer behavior while canvas/document commands move toward document/app command services | pp_app_core_document_canvas_tests; pano_cli plan-canvas-clear --r 0 --g 0.1 --b 0.2 --a 0.3; pano_cli plan-canvas-clear --no-canvas; pano_cli plan-layer-menu --command clear --current-index 1 --current-name Paint; ctest --preset desktop-fast --build-config Debug |
Canvas clear execution, undo recording, dirty-state updates, and clear color handling are owned by injected document/app services with no legacy canvas-clear adapter |
| DEBT-0029 | Open | Modernization | Image import route planning and execution dispatch now consume pure pp_app_core through the File menu, pano_cli plan-image-import, and the DocumentImageImportServices boundary, and live File-menu import execution is centralized in src/legacy_app_shell_services.*, but the bridge still loads images with legacy Image, calls legacy Canvas::import_equirectangular, or configures legacy import transform mode directly |
Preserve current File > Import behavior while image import moves toward document/app/asset command services | pp_app_core_document_import_tests; pano_cli plan-image-import --width 4096 --height 2048; pano_cli plan-image-import --width 1024 --height 1024; ctest --preset desktop-fast --build-config Debug |
Image loading, equirectangular import, transform-placement import, and failure reporting are owned by injected document/app/asset services with File-menu callbacks acting only as adapters and no legacy image-import adapter |
| DEBT-0030 | Open | Modernization | File export menu action planning and execution dispatch now consume pure pp_app_core through the File menu, pano_cli plan-export-menu, and the DocumentExportMenuServices boundary, and live execution is centralized in src/legacy_app_shell_services.*, but the bridge still opens legacy export dialogs and then reaches legacy canvas/render/video export code |
Preserve current export menu behavior while export command execution moves toward document/app/renderer/video services | pp_app_core_document_export_tests; pano_cli plan-export-menu --kind png; pano_cli plan-export-menu --kind animation-mp4 --demo; pano_cli plan-export-menu --kind layers --no-canvas; ctest --preset desktop-fast --build-config Debug |
Export menu routing, license gating, target creation, image/layer/cube/depth/animation/timelapse execution, and error reporting are owned by injected document/app/renderer/video services with File-menu callbacks acting only as UI adapters and no legacy export adapter |
| DEBT-0031 | Open | Modernization | Top-level File menu command planning and execution dispatch now consume pure pp_app_core through App::init_menu_file, pano_cli plan-file-menu, and the FileMenuServices boundary, and live execution is centralized in src/legacy_app_shell_services.*, but the bridge still invokes legacy dialogs, platform pickers, cloud code, share code, and canvas import/export paths directly |
Preserve File menu behavior while app workflows move toward app/document/platform command services | pp_app_core_file_menu_tests; pano_cli plan-file-menu --command save-as; pano_cli plan-file-menu --command import; pano_cli plan-file-menu --command cloud-upload; ctest --preset desktop-fast --build-config Debug |
File menu routing, picker dispatch, save/share/cloud/resize/export execution, and image/project import execution are owned by injected app/document/platform services with App::init_menu_file acting only as a UI adapter and no legacy File menu adapter |
| DEBT-0032 | Open | Modernization | Layer menu command planning and execution dispatch now consume pure pp_app_core through App::init_menu_layer, pano_cli plan-layer-menu, and the DocumentLayerMenuServices boundary; Layer menu clear reuses the DocumentCanvasClearServices executor; and Layer menu rename/clear/merge now share src/legacy_document_layer_services.*, but the bridge still calls the legacy rename dialog path, NodePanelLayer::merge, and reads Canvas::I animation/layer state directly |
Preserve existing Layer menu behavior while layer commands move toward document/app services | pp_app_core_document_layer_tests; pano_cli plan-layer-menu --command clear --current-index 1 --current-name Paint; pano_cli plan-layer-menu --command merge --current-index 2 --lower-name Paint; pano_cli plan-layer-merge --layer-count 3 --from-index 2 --to-index 1; pano_cli plan-layer-merge --layer-count 3 --from-index 2 --to-index 1 --animation-duration 3; pano_cli plan-layer-menu --command rename --no-current-layer; ctest --preset desktop-fast --build-config Debug |
Layer rename, merge-down execution, animation gating, and selected-layer state are owned by injected document/app services with Layer-menu callbacks acting only as UI adapters and no legacy Layer menu adapter |
| DEBT-0033 | Open | Modernization | Tools menu planning and direct command execution dispatch now consume pure pp_app_core through App::init_menu_tools, pano_cli plan-tools-menu, pano_cli plan-tools-panel, and the ToolsMenuServices boundary, and direct command execution is centralized in src/legacy_app_shell_services.*, but live adapters still construct legacy NodePanelFloating panels, mutate legacy panel nodes, clear CanvasModeGrid, reset NodeCanvas camera state, open legacy shortcuts UI, and call the iOS SonarPen bridge directly |
Preserve current Tools menu behavior while UI shell actions move toward app/UI/platform services | pp_app_core_tools_menu_tests; pano_cli plan-tools-menu --command shortcuts; pano_cli plan-tools-panel --panel layers; pano_cli plan-tools-panel --panel animation --already-visible; ctest --preset desktop-fast --build-config Debug |
Tools panel creation, submenu routing, grid clear, camera reset, shortcuts dialog, and SonarPen dispatch are owned by injected app/UI/platform services with App::init_menu_tools acting only as a UI adapter and no legacy Tools adapter |
| DEBT-0034 | Open | Modernization | About menu command planning and execution dispatch now consume pure pp_app_core through App::init_menu_about, pano_cli plan-about-menu, and the AboutMenuServices boundary, and live execution is centralized in src/legacy_app_shell_services.*, but the bridge still opens legacy About/manual/what's-new dialogs, invokes the injected crash hook, and runs the legacy Canvas stroke performance test directly |
Preserve About menu behavior while dialogs and diagnostics move toward app/UI/platform services | pp_app_core_about_menu_tests; pano_cli plan-about-menu --command news --version-major 2 --version-minor 5 --version-fix 7; pano_cli plan-about-menu --command performance --no-canvas; ctest --preset desktop-fast --build-config Debug |
About/manual/what's-new dialog dispatch, crash-test dispatch, and performance-test execution are owned by injected app/UI/platform services with App::init_menu_about acting only as a UI adapter and no legacy About adapter |
| DEBT-0035 | Open | Modernization | Main toolbar/status command planning and execution dispatch now consume pure pp_app_core through App::init_toolbar_main, pano_cli plan-main-toolbar, and the MainToolbarServices boundary, history/canvas commands now hand off through HistoryUiServices and DocumentCanvasClearServices, and live execution is centralized in src/legacy_app_shell_services.*, but the bridge still opens legacy open/save/settings/message-box dialogs and delegates to legacy history/canvas adapters |
Preserve reachable toolbar/status behavior while app shell commands move toward app/document/UI services | pp_app_core_main_toolbar_tests; pano_cli plan-main-toolbar --command undo --undo-count 2; pano_cli plan-main-toolbar --command clear-canvas --no-canvas; ctest --preset desktop-fast --build-config Debug |
Open/save/settings/message-box routing, undo/redo/clear-history execution, and canvas-clear execution are owned by injected app/document/UI services with App::init_toolbar_main acting only as a UI adapter and no legacy toolbar adapter |
| DEBT-0036 | Open | Modernization | pp_renderer_api, pp_paint_renderer, pano_cli plan-paint-feedback, and pano_cli plan-stroke-composite can choose backend-neutral complex paint feedback strategies for fixed-function blending, framebuffer-fetch-capable renderers, or ping-pong render targets. OpenGL extension detection now stores pp::renderer::RenderDeviceFeatures through ShaderManager, using pp_renderer_gl::render_device_features as the backend conversion point. pp_paint_renderer::plan_canvas_blend_gate owns the compatibility mapping from persisted layer/brush blend indices to the extracted stroke-composite planner, and live Canvas::draw_merge plus NodeCanvas panorama rendering both call it with the stored renderer-neutral feature set for their existing shader-blend gates and destination-copy versus framebuffer-fetch decisions. pp_paint_renderer::plan_canvas_stroke_feedback also owns the current destination-feedback decision, and live Canvas::stroke_draw, thumbnail layer blending, and NodeStrokePreview brush-preview rendering use it for framebuffer-fetch versus destination-copy decisions. Actual live stroke rasterization, dual-brush compositing, pattern feedback math, thumbnail layer compositing, and brush-preview compositing still use legacy OpenGL canvas/UI execution |
Preserve current painting behavior while the renderer boundary matures for OpenGL parity and later Vulkan/Metal experiments | pp_renderer_api_tests; pp_renderer_gl_capabilities_tests; pp_paint_renderer_compositor_tests; pano_cli plan-paint-feedback --framebuffer-fetch --explicit-transitions --render-only; pano_cli plan-paint-feedback --texture-copy; pano_cli plan-stroke-composite --stroke-blend 10 --framebuffer-fetch --explicit-transitions --render-only; pano_cli plan-stroke-composite --layer-blend 4 --dual-blend --texture-copy; ctest --preset desktop-fast --build-config Debug; cmake --build --preset windows-msvc-default --config Debug --target PanoPainter |
Live stroke/layer compositing chooses its feedback path through pp_paint_renderer and renderer services, with OpenGL golden parity and Vulkan/Metal lab tests covering framebuffer-fetch and ping-pong behavior |
| DEBT-0037 | Open | Modernization | Recording lifecycle/export planning and execution dispatch now consume pure pp_app_core through App::rec_start, App::rec_stop, App::rec_clear, App::rec_export, pano_cli plan-recording-session, and the RecordingServices boundary; live execution is centralized in src/legacy_recording_services.*, but the bridge still owns legacy recording thread startup/shutdown, platform recorded-file cleanup, progress UI, PBO readback through App::rec_loop, and MP4Encoder::write_mp4 execution |
Preserve current timelapse/MP4 behavior while recording moves toward app/document/renderer/video services | pp_app_core_document_recording_tests; pano_cli plan-recording-session --running --frame-count 12; pano_cli plan-recording-session --platform-clears-files; ctest --preset desktop-fast --build-config Debug |
Recording thread lifecycle, frame readback, platform cleanup, progress reporting, and MP4 writing are owned by injected app/renderer/video services with App methods acting only as adapters |
Closed Debt
| ID | Status | Owner | Item | Reason | Validation | Removal Condition |
|---|---|---|---|---|---|---|
| DEBT-0006 | Closed | Modernization | pano_cli create-document validates and emits JSON command contracts but does not yet invoke the legacy document/app model |
The document model had not been extracted from Canvas/App yet |
ctest --preset desktop-fast --build-config Debug; pano_cli_create_document_smoke |
Closed on 2026-05-31: command now constructs a real pp_document::CanvasDocument |
| DEBT-0018 | Closed | Modernization | pp_renderer_gl owned a tested OpenGlInitialState plan for PanoPainter startup depth/blend policy, but App::init still executed the plan through direct OpenGL calls |
Preserve behavior while moving renderer policy into the backend boundary before a live IRenderDevice/command context owns startup execution |
pp_renderer_gl_capabilities_tests; ctest --preset desktop-fast --build-config Debug; powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -Preset windows-msvc-default -Configuration Debug |
Closed on 2026-06-03: pp_renderer_gl::apply_panopainter_initial_state now applies the startup state through a tested backend dispatch contract consumed by App::init |