Files
panopainter/docs/modernization/tasks.md

26 KiB

Modernization Task Tracker

Status: live Last updated: 2026-06-13

This file turns the modernization roadmap into small, measurable work items. The roadmap explains direction, the debt log explains why shortcuts remain, and this tracker is the execution queue. Prefer closing one task here over adding a new broad roadmap paragraph.

Operating Rules

  • Pick one Ready task at a time unless the user asks for planning only.
  • Keep each slice small enough to validate and commit in one session.
  • Do not claim percentage progress for "narrowed" debt. Points move only when a task row is changed to Done.
  • A task is Done only when its listed checks pass, the debt log is updated or closed as applicable, and the roadmap/task score is updated.
  • If a task proves too large, split it before editing code. The original task stays Ready or becomes Blocked with the reason.
  • After a verified task is committed and pushed, reset conversation context before starting the next task when practical.
  • When the user asks for subagents or delegation, follow docs/modernization/director-workflow.md and keep each delegated task mapped to a row in this tracker.

Progress Scorecard

The current score is intentionally conservative. It should move in visible, auditable steps rather than by subjective estimates.

Area Weight Current Progress Rule
Build and CMake ownership 15 13 Root CMake owns active source lists, app/tool targets, and retained package entrypoints.
Test and automation coverage 15 9 Headless, platform, package, and focused validation commands exist and are current.
Pure component behavior ownership 15 8 Behavior lives in pp_* components and is consumed by live adapters.
Legacy adapter retirement 20 7 legacy_*_services and singleton bridges are deleted or reduced to trivial composition.
Renderer boundary and OpenGL parity 15 10 Live render/export/readback paths execute through renderer interfaces with parity checks.
Platform and package parity 10 6 Required platforms have root CMake/package validation and injected platform services.
Hardening and future backend readiness 10 2 Edge, fuzz, golden, stress, and backend-lab gates exist for high-risk paths.
Total 100 55 Only completed tasks below may change this number.

When updating Current, add a dated note under "Completed Task Log" with the task id, points moved, validation command, and commit hash.

Task States

State Meaning
Ready Clear enough for an agent to execute.
In progress Actively being changed in the current slice.
Blocked Needs a user decision, missing toolchain, or a prior task.
Done Validated, documented, committed, and pushed.

Ready Queue

MT-001 - Adopt Measurable Task Tracking

Status: Done Score: no score movement Debt: none Scope: docs/modernization/tasks.md, docs/modernization/roadmap.md

Steps:

  • Add this tracker.
  • Link it from the roadmap.
  • Make the scorecard the source for percentage claims.

Done Checks:

  • docs/modernization/roadmap.md points agents to this file.
  • The tracker has task states, scoring rules, and at least one ready queue.

Validation:

git diff -- docs\modernization\roadmap.md docs\modernization\tasks.md

ADP-001 - Remove History Bridge From Document Resize And Canvas Clear

Status: Done Score: +1 legacy adapter retirement Debt: DEBT-0020, DEBT-0027 Scope: src/legacy_document_canvas_services.*, src/app_core/document_resize.h, tests/app_core/document_resize_tests.cpp, related canvas-clear tests only

Goal:

Make document resize and canvas-clear execution consume app-core history commands directly instead of routing through legacy_history_services.

Done Checks:

  • src/legacy_document_canvas_services.* no longer includes legacy_history_services.h.
  • Resize still executes in order: resize, title update, history clear.
  • Canvas clear still records undo and marks the document unsaved when a canvas exists.
  • docs/modernization/debt.md narrows or closes the affected removal condition.

Validation:

ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_resize|pp_app_core_document_canvas|pano_cli_plan_document_resize|pano_cli_plan_canvas_clear" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli

ADP-002 - Remove History Bridge From Layer Operations

Status: Done Score: +1 legacy adapter retirement Debt: DEBT-0021 Scope: src/legacy_document_layer_services.*, src/app_core/document_layer.h, tests/app_core/document_layer_tests.cpp

Goal:

Move layer add/remove/merge/clear/rename history side effects into tested app-core execution plans so the live layer bridge no longer calls legacy_history_services.

Done Checks:

  • src/legacy_document_layer_services.* no longer includes legacy_history_services.h.
  • Layer operations still preserve undo/history behavior covered by pp_app_core_document_layer_tests.
  • pano_cli plan-layer-operation, plan-layer-menu, and plan-layer-rename JSON remains compatible.
  • docs/modernization/debt.md records the narrowed or closed layer-history adapter dependency.

Validation:

ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_layer|pano_cli_plan_layer" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli

ADP-003 - Remove History Bridge From Document Open And Session Save

Status: Done Score: +1 legacy adapter retirement Debt: DEBT-0039, DEBT-0040, DEBT-0042 Scope: src/legacy_document_open_services.*, src/legacy_document_session_services.*, src/app_core/document_session.*, src/app_core/document_route.*, matching tests only

Goal:

Make document-open, close, save, save-before-workflow, Save As, and Save Version history effects explicit app-core outputs instead of direct legacy_history_services calls in the live bridges.

Done Checks:

  • src/legacy_document_open_services.* and src/legacy_document_session_services.* no longer include legacy_history_services.h.
  • Existing dirty-document, save-before, new-document, Save As, and Save Version plans preserve their JSON contracts.
  • The debt log is updated for every debt id listed above.

Validation:

ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_route|pp_app_core_document_session|pano_cli_plan_open_route|pano_cli_simulate_app_session|pano_cli_plan_document_file|pano_cli_plan_document_version" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli

ADP-004 - Make Dialog Creation A UI Factory Boundary

Status: Done Score: +2 legacy adapter retirement Debt: DEBT-0058, DEBT-0063 Scope: src/legacy_app_dialog_services.*, src/legacy_ui_overlay_services.*, src/app_dialogs.cpp, src/app_core/app_dialog.h, dialog tests only

Goal:

Keep app-core dialog metadata pure, but move retained NodeProgressBar/NodeMessageBox/NodeInputBox construction behind one pp_panopainter_ui or retained UI factory function. App should ask for a dialog object through an interface instead of knowing individual node creation details.

Done Checks:

  • App::show_progress, App::message_box, and App::input_box still preserve captions, cancel behavior, and keyboard behavior.
  • New factory path has focused tests or existing pp_app_core_app_dialog_tests plus a smoke command proving the live adapter still builds.
  • The debt log states exactly which raw-node lifetime hazards remain.

Validation:

ctest --preset desktop-fast --build-config Debug -R "pp_app_core_app_dialog|pano_cli_plan_app_dialog" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli

ADP-005 - Convert One Popup/Dialog Family To Checked Overlay Lifetime

Status: Done Score: +2 legacy adapter retirement Debt: DEBT-0063 Scope: choose exactly one family from src/node_dialog_open.cpp, src/node_dialog_browse.cpp, src/node_panel_quick.cpp, src/node_panel_stroke.cpp, or src/node_combobox.cpp, plus src/legacy_ui_overlay_services.*

Goal:

Adopt pp_ui_core overlay lifetime semantics for one retained popup/dialog family before trying to rewrite all retained UI nodes.

Done Checks:

  • The chosen family no longer owns open-coded root insertion, outside-click release, close callback wiring, or destroy-during-callback behavior.
  • Existing UI behavior is preserved.
  • Tests cover missing root/template handling and close/release behavior for the chosen family.
  • The debt log names the completed family and the remaining families.

Validation:

ctest --preset desktop-fast --build-config Debug -R "pp_ui_core_overlay_lifetime|pp_ui_core_node_lifetime" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter

RND-001 - Make Pure Equirectangular Export The Primary Success Path

Status: Done Score: +2 renderer boundary and OpenGL parity Debt: DEBT-0010, DEBT-0036, DEBT-0043 Scope: src/legacy_document_export_services.*, src/app_core/document_export.*, src/paint_renderer/compositor.*, tests/app_core/document_export_tests.cpp, tests/paint_renderer/compositor_tests.cpp

Goal:

For payload-complete snapshots, live PNG/JPEG equirectangular export should complete through the pure document/paint-renderer writer. Retained Canvas::export_equirectangular* should run only for unsupported Web, incomplete-readback, or writer-failure fallbacks.

Done Checks:

  • Export route reports whether the pure writer was used or why fallback was required.
  • Tests cover pure-writer success and each fallback reason.
  • Live bridge does not call retained equirectangular export after pure-writer success.
  • The debt log narrows retained equirectangular export execution.

Validation:

ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_export|pp_paint_renderer_compositor|pano_cli_plan_export_snapshot_route|pano_cli_simulate_document_export" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli

RND-002 - Make Pure Layer And Animation Collection Export Primary

Status: Done Score: +2 renderer boundary and OpenGL parity Debt: DEBT-0010, DEBT-0036, DEBT-0043 Scope: src/legacy_document_export_services.*, src/app_core/document_export.*, src/paint_renderer/compositor.*, collection export tests only

Goal:

For payload-complete snapshots, live layer and animation-frame collection export should complete through the pure collection writer. Retained Canvas::export_layers* and Canvas::export_anim_frames* should run only for unsupported Web, incomplete-readback, or writer-failure fallbacks.

Done Checks:

  • Collection export route reports pure-writer success versus fallback reason.
  • Tests cover layer collection, animation-frame collection, and fallback.
  • The debt log narrows retained collection export execution.

Validation:

ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_export|pp_paint_renderer_compositor|pano_cli_plan_export_snapshot_route" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli

RND-003 - Replace Depth Export Readiness With Pure Depth Export Execution

Status: Done Score: +3 renderer boundary and OpenGL parity Debt: DEBT-0010, DEBT-0036, DEBT-0043 Scope: src/paint_renderer/compositor.*, src/app_core/document_export.*, src/legacy_document_export_services.*, depth tests only

Goal:

Turn the current pure depth export render plan into actual payload generation for payload-complete snapshots, then write image/depth payloads through the existing app-core two-payload writer before falling back to retained Canvas::export_depth*.

Done Checks:

  • Pure depth export produces deterministic image and depth payloads for a payload-complete snapshot.
  • Retained depth export runs only for unsupported targets, incomplete readback, or writer failure.
  • Tests cover malformed depth target inputs and byte-size validation.
  • The debt log narrows depth export readback/execution.

Validation:

ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_export|pp_paint_renderer_compositor|pano_cli_plan_export_snapshot_route" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pano_cli

RND-004 - Add First Desktop GPU Golden Gate

Status: Done Score: +2 hardening and future backend readiness Debt: DEBT-0036 Scope: tests/, CMakeLists.txt, renderer test helpers only

Goal:

Create the first non-default desktop-gpu golden/readback test that validates one OpenGL output against a deterministic fixture. Keep it opt-in so headless agents are not blocked.

Done Checks:

  • ctest --preset desktop-gpu --build-config Debug has at least one real test.
  • The test is skipped with a clear message when no GPU/context is available.
  • The roadmap and debt log describe what the golden covers and what remains.

Validation:

ctest --preset desktop-gpu --build-config Debug --output-on-failure
ctest --preset desktop-fast --build-config Debug -R "pp_renderer_gl|pp_paint_renderer" --output-on-failure

PLT-001 - Split Apple Picker/Browse Service From Legacy Platform Adapter

Status: Done Score: +2 platform and package parity Debt: DEBT-0017, DEBT-0051, DEBT-0055 Scope: src/platform_legacy/legacy_platform_services.*, new src/platform_apple/* files if needed, CMakeLists.txt, platform API tests

Goal:

Move macOS/iOS document browse roots, file picking, directory picking, and display-path formatting out of the catch-all legacy platform adapter and into a named Apple platform service boundary.

Done Checks:

  • src/platform_legacy/legacy_platform_services.* no longer owns Apple browse/picker policy.
  • Apple compile validation still passes through the remote build script.
  • The debt log narrows Apple platform shell extraction.

Validation:

ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure
powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.ps1 -Presets macos,ios-simulator,ios-device

PLT-002 - Split Web Export/Storage Policy From Legacy Platform Adapter

Status: Done Score: +2 platform and package parity Debt: DEBT-0050, DEBT-0053, DEBT-0057 Scope: src/platform_legacy/legacy_platform_services.*, new src/platform_web/* files if needed, src/platform_api/*, platform tests

Goal:

Move WebGL exported-image publishing, persistent-storage flushing, prepared-file handoff, and default canvas resolution out of the catch-all legacy platform adapter into a named Web platform service boundary.

Done Checks:

  • Web policy is injectable through pp_platform_api.
  • The legacy adapter no longer owns Web default canvas resolution or storage flush policy.
  • Package-smoke readiness still reports Web blockers explicitly.

Validation:

ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure
powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -ReadinessOnly

DEP-001 - Remove Generated fmt Overlay

Status: Done Score: +1 build and CMake ownership Debt: DEBT-0062 Scope: CMakeLists.txt, cmake/, vcpkg.json, libs/fmt or package wiring

Goal:

Use a supported fmt package or update the vendored fmt release so VS 2026 no longer needs a generated format.h overlay.

Done Checks:

  • No build-tree fmt header overlay is generated.
  • DEBT-0062 is closed.
  • Windows app and at least one focused component test build pass.

Validation:

cmake --build --preset windows-msvc-default --config Debug --target PanoPainter pp_platform_api_tests
ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure

DEP-002 - Remove Generated nanort Overlay

Status: Done Score: +1 build and CMake ownership Debt: DEBT-0060 Scope: retained Android package CMake, libs/nanort, grid/lightmap dependency wiring Goal:

Update, replace, or isolate nanort so Android package builds do not generate a patched vendor overlay.

Done Checks:

  • Android retained package CMake no longer generates a patched nanort.h.
  • DEBT-0060 is closed.
  • Standard Android retained package validation passes.

Validation:

powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter

Blocked Or Later Queue

These are real goals, but they should not be picked until prerequisite tasks above have reduced risk.

LATER-001 - Replace OpenVR With OpenXR

Status: Blocked Score: +3 platform and package parity Debt: DEBT-0061 Blocked By: OpenXR package decision and runtime availability

Done Checks:

  • OpenXR SDK/package target exists.
  • Windows platform service can start/stop desktop XR without OpenVR.
  • libs/openvr and openvr_api.dll deployment are removed.
  • DEBT-0061 is closed.

LATER-002 - Remove Catch2 Harness Debt

Status: Blocked Score: +2 test and automation coverage Debt: DEBT-0005 Blocked By: vcpkg/toolchain reliability across Windows and headless presets

Done Checks:

  • Existing local test harness is replaced or permanently justified.
  • Catch2 tests run through desktop-fast and vcpkg headless presets.
  • DEBT-0005 is closed.

LATER-003 - Live Stroke Rasterization Through Renderer Services

Status: Ready Score: +5 renderer boundary and OpenGL parity Debt: DEBT-0036

Done Checks:

  • Live stroke rasterization, dual-brush compositing, and pattern feedback choose paths through renderer services.
  • OpenGL output parity is covered by golden/readback tests.
  • Retained stroke OpenGL execution is deleted or isolated as an OpenGL backend implementation.

Progress Notes:

  • 2026-06-13: Canvas::stroke_draw main, pad, and dual live-pass texture-input binding/unbinding intent now routes through retained stroke execution helpers; sampler binding, concrete GL object mapping, framebuffer ownership, and final draw execution remain local to Canvas. Next slice should target the remaining sampler binding/teardown or the direct semantic-input-to-GL mapping callbacks without reopening the landed dirty, face-framebuffer, or pad helpers.
  • 2026-06-13: NodeStrokePreview::draw_stroke_immediate() live-pass sampler binding, dual/main pass texture binding, checkerboard/background capture wrapping, and final preview copy-back now route through named local helpers; mixer state execution and per-sample GL ordering remain local to the preview node. Next slice should target the remaining mixer-pass state/copy ordering or sample-pass destination callback wrapping without reopening the landed preview live-pass or final-composite helpers.
  • 2026-06-13: NodeStrokePreview::draw_stroke_immediate() dual-pass and main-pass frame-loop execution plus full-frame copy-back now route through shared local helpers; checkerboard/background capture ordering, texture-unit binding, mixer ownership, and final composite semantics remain local to the preview node. Next slice should target background/final-copy helpers or pass-level texture binding without reopening the new preview composite helper.
  • 2026-06-13: Canvas::stroke_draw main and dual live-pass per-face framebuffer begin/end execution plus pad-face array assembly now route through legacy_canvas_stroke_execution_services.h; shader activation timing, texture/sampler binding, framebuffer ownership, and final draw execution remain local to Canvas. Next slice should target the remaining pass-level texture binding or final composite setup without reopening the newer pad, dirty, or commit helpers.
  • 2026-06-13: Canvas::stroke_draw current and dual stroke per-face framebuffer/sample callback ordering now routes through legacy_canvas_stroke_execution_services.h; framebuffer ownership, shader uniform timing, sampler/texture binding, and draw execution remain local to Canvas. Next slice should target the remaining per-face retained state around sample execution without reopening the new pad-pass, dirty-mutation, or commit executors.
  • 2026-06-13: Canvas::stroke_draw current and dual stroke dirty-box mutation now routes through legacy_canvas_stroke_execution_services.h; framebuffer binding, shader uniform timing, sampler/texture binding, and draw execution remain local to Canvas. Next slice should wrap the retained per-face framebuffer/sample callback ordering without rewriting the new pad-pass or commit executors.
  • 2026-06-13: Canvas::stroke_commit now routes retained commit input texture/sampler binding, erase/composite draw dispatch, committed-copy, and dilate draw through legacy_canvas_stroke_commit_services.h; history readback, ActionStroke population, and layer dirty-box mutation remain local to Canvas.
  • 2026-06-13: pp_paint_renderer owns tested Canvas stroke commit sequencing and commit texture slot intent. Next slice should wire legacy_canvas_stroke_commit_services.h into Canvas::stroke_commit while keeping history/layer mutation local.

LATER-004 - Remove Catch-All Platform Legacy Adapter

Status: Blocked Score: +5 platform and package parity Debt: DEBT-0017 Blocked By: Apple/Web split tasks and per-platform package validation

Done Checks:

  • src/platform_legacy/legacy_platform_services.* is deleted or contains only compile-time unsupported stubs with debt entries.
  • Windows, Apple, Android, Linux, and Web platform services are named targets.
  • Platform-build and package-smoke report explicit pass/fail per platform.

Completed Task Log

Date Task Score Change Validation Commit
2026-06-12 RND-004 +2 hardening and future backend readiness ctest --preset desktop-gpu --build-config Debug --output-on-failure; ctest --preset desktop-fast --build-config Debug -R "pp_renderer_gl|pp_paint_renderer" --output-on-failure e37b2929
2026-06-12 DEP-002 +1 build and CMake ownership powershell -ExecutionPolicy Bypass -File scripts\automation\android-legacy-package-build.ps1 -Packages standard 648404ee
2026-06-12 RND-002 +2 renderer boundary and OpenGL parity ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_export|pp_paint_renderer_compositor|pano_cli_plan_export_snapshot_route|pano_cli_simulate_document_export" --output-on-failure 46fb8ef
2026-06-12 RND-001 +2 renderer boundary and OpenGL parity ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_export|pp_paint_renderer_compositor|pano_cli_plan_export_snapshot_route|pano_cli_simulate_document_export" --output-on-failure 46fb8ef
2026-06-12 ADP-004 +2 legacy adapter retirement VS-bundled CMake build of pp_app_core_app_dialog_tests and pano_cli; ctest --preset desktop-fast --build-config Debug -R "pp_app_core_app_dialog|pano_cli_plan_app_dialog" --output-on-failure 46fb8ef
2026-06-12 PLT-001 +2 platform and package parity VS-bundled CMake build of pp_platform_api_tests; ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure; Apple remote build blocked by unpublished fmt submodule pointer before DEP-001 correction 46fb8ef
2026-06-12 RND-003 +3 renderer boundary and OpenGL parity VS-bundled CMake build of pp_paint_renderer_compositor_tests, pp_app_core_document_export_tests, and pano_cli; ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_export|pp_paint_renderer_compositor|pano_cli_plan_export_snapshot_route" --output-on-failure 46fb8ef
2026-06-12 DEP-001 +1 build and CMake ownership VS-bundled CMake build of PanoPainter and pp_platform_api_tests; ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure 46fb8ef
2026-06-12 ADP-003 +1 legacy adapter retirement ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_route|pp_app_core_document_session|pano_cli_plan_open_route|pano_cli_simulate_app_session|pano_cli_plan_document_file|pano_cli_plan_document_version" --output-on-failure 34a9e910
2026-06-12 PLT-002 +2 platform and package parity ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure; powershell -ExecutionPolicy Bypass -File scripts\automation\package-smoke.ps1 -ReadinessOnly; ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_layer|pano_cli_plan_layer|pp_platform_api_tests" --output-on-failure 8cd38401
2026-06-12 ADP-002 +1 legacy adapter retirement ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_layer|pano_cli_plan_layer" --output-on-failure; ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_layer|pano_cli_plan_layer|pp_platform_api_tests" --output-on-failure ae242852
2026-06-12 ADP-001 +1 legacy adapter retirement ctest --preset desktop-fast --build-config Debug -R "pp_app_core_document_resize|pp_app_core_document_canvas|pano_cli_plan_document_resize|pano_cli_plan_canvas_clear" --output-on-failure; powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli -TestRegex "pp_app_core|pano_cli_plan" e489b1e2
2026-06-12 MT-001 0 git diff -- docs\modernization\roadmap.md docs\modernization\tasks.md same docs slice

Task Template

Use this shape when adding a new task:

### AREA-000 - Imperative Task Name

Status: Ready
Score: +N scorecard area
Debt: `DEBT-0000`
Scope: exact files or directories

Goal:

One paragraph describing the behavior or ownership change.

Done Checks:

- Binary, grep-able, or testable condition.
- Debt log update condition.
- Validation condition.

Validation:

```powershell
command
```