116 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
Readytask 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
Doneonly 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
Readyor becomesBlockedwith 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.mdand 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 | 11 | 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.mdpoints 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 includeslegacy_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.mdnarrows 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 includeslegacy_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, andplan-layer-renameJSON remains compatible.docs/modernization/debt.mdrecords 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.*andsrc/legacy_document_session_services.*no longer includelegacy_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, andApp::input_boxstill preserve captions, cancel behavior, and keyboard behavior.- New factory path has focused tests or existing
pp_app_core_app_dialog_testsplus 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 Debughas 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
RND-005 - Add Desktop GPU Preview 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 next non-default desktop-gpu golden/readback test for the preview
parity lane so the renderer parity coverage is not limited to the existing
clear-readback fixture.
Done Checks:
ctest --preset desktop-gpu --build-config Debughas more than one real GPU readback gate.- The test is skipped with a clear message when no GPU/context is available.
- The roadmap and debt log describe the GPU readback coverage and what remains.
Validation:
ctest --preset desktop-gpu --build-config Debug --output-on-failure
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
Completed Task Log:
| Date | Task | Score | Validation | Commit |
|---|---|---|---|---|
| 2026-06-13 | RND-005 | +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_paint_renderer_compositor |
pp_paint_renderer_stroke_execution" --output-on-failure` |
RND-006 - Add Desktop GPU Compositor 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 next desktop-gpu readback gate for the compositor path so the
OpenGL parity lane covers a second live render target, not just the existing
clear/preview fixtures.
Done Checks:
ctest --preset desktop-gpu --build-config Debughas a compositor readback gate in addition to the existing GPU fixtures.- The test is skipped with a clear message when no GPU/context is available.
- The roadmap and debt log describe the compositor output the gate covers and what remains.
Validation:
ctest --preset desktop-gpu --build-config Debug --output-on-failure
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
Completed Task Log:
| Date | Task | Validation | Commit |
|---|---|---|---|
| 2026-06-13 | RND-006 | ctest --preset desktop-gpu --build-config Debug --output-on-failure; `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor |
pp_paint_renderer_stroke_execution" --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-0062is 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-0060is 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/openvrandopenvr_api.dlldeployment are removed.DEBT-0061is 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-fastand vcpkg headless presets. DEBT-0005is closed.
LATER-003 - Live Stroke Rasterization Through Renderer Services
Status: Done
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.
STR-020 - Extract Stroke Draw Main Pass Texture Dispatch
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline Canvas::stroke_draw() main-pass texture dispatch bundle into
a retained helper so the callsite keeps only branch selection plus concrete
texture/sampler wiring.
Done Checks:
Canvas::stroke_draw()no longer builds the main-pass texture dispatch bundle inline.- Regression coverage proves the extracted helper preserves main-pass texture callback order.
docs/modernization/debt.mdrecords the reduced stroke-draw texture dispatch surface.
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
Completed Task Log
| Date | Task | Score | Validation | Commit |
|---|---|---|---|---|
| 2026-06-13 | STR-020 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-on-failure` |
STR-021 - Extract Stroke Draw Live Pass Sampler Dispatch
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline Canvas::stroke_draw() live-pass sampler dispatch bundle into
a retained helper so the callsite keeps only branch selection plus concrete
sampler wiring.
Done Checks:
Canvas::stroke_draw()no longer builds the live-pass sampler dispatch bundle inline.- Regression coverage proves the extracted helper preserves sampler callback order.
docs/modernization/debt.mdrecords the reduced live-pass sampler surface.
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
Completed Task Log
| Date | Task | Score | Validation | Commit |
|---|---|---|---|---|
| 2026-06-13 | STR-021 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-on-failure` |
STR-022 - Extract Stroke Draw Dual Brush Tip Dispatch
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline dual-pass brush-tip dispatch bundle in Canvas::stroke_draw()
into a retained helper so the dual-brush branch keeps only concrete texture
object wiring and branch selection.
Done Checks:
Canvas::stroke_draw()no longer builds the dual-pass brush-tip dispatch bundle inline.- Regression coverage proves the extracted helper preserves dual-brush tip callback order.
docs/modernization/debt.mdrecords the reduced dual-pass texture-dispatch surface.
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
Completed Task Log
| Date | Task | Score | Validation | Commit |
|---|---|---|---|---|
| 2026-06-13 | STR-022 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-on-failure` |
| 2026-06-13 | STR-023 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-on-failure` |
| 2026-06-13 | STR-024 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-on-failure` |
| 2026-06-13 | STR-025 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-on-failure` |
| 2026-06-13 | STR-028 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-on-failure` |
| 2026-06-13 | STR-030 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-on-failure` |
STR-023 - Extract Stroke Draw Dual Pass Frame Orchestration
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline execute_legacy_canvas_stroke_dual_pass_frame_callbacks(...)
lambda body in Canvas::stroke_draw() into a retained helper so the dual-pass
branch owns only concrete shader, sampler, and framebuffer wiring.
Done Checks:
Canvas::stroke_draw()no longer contains the inline dual-pass frame callback body.- Regression coverage proves the extracted helper preserves dual-pass frame callback order and face execution.
docs/modernization/debt.mdrecords the reduced dual-pass frame surface.
Closeout: 07b188de
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
STR-024 - Extract Stroke Draw Dual Pass Frame Callback Body
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline body passed to execute_legacy_canvas_stroke_dual_pass_frame_callbacks(...)
into a retained helper so the dual-pass branch owns only concrete callback
selection and framebuffer wiring.
Done Checks:
Canvas::stroke_draw()no longer contains the inline dual-pass frame callback body.- Regression coverage proves the extracted helper preserves callback order and face-state updates.
docs/modernization/debt.mdrecords the reduced dual-pass frame-callback surface.
Closeout: b1d6e5e2
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
STR-025 - Extract Stroke Draw Dual Pass Frame Request Wrapper
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the remaining dual-pass frame request assembly in Canvas::stroke_draw()
into a retained helper so the branch keeps only concrete callbacks and frame
execution wiring.
Done Checks:
Canvas::stroke_draw()no longer spells the dual-pass frame request inline.- Regression coverage proves the extracted helper preserves dual-pass request wiring.
docs/modernization/debt.mdrecords the reduced dual-pass request surface.
Closeout: 77ac50b9
Closeout: 77ac50b9
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
STR-026 - Extract Stroke Draw Dual Pass Shader Setup Wrapper
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline dual-pass shader setup lambda in Canvas::stroke_draw() into
a retained helper so the dual-pass branch owns only concrete shader selection
and framebuffer wiring.
Done Checks:
Canvas::stroke_draw()no longer contains the inline dual-pass shader setup lambda.- Regression coverage proves the extracted helper preserves shader setup behavior.
docs/modernization/debt.mdrecords the reduced dual-pass shader-setup surface.
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
Completed Task Log
| Date | Task | Score | Validation | Commit |
|---|---|---|---|---|
| 2026-06-13 | STR-026 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-onfailure` |
STR-027 - Extract Stroke Draw Pad Destination Dispatch
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline pad-stroke destination texture dispatch lambda in
Canvas::stroke_draw() into a retained helper so the pad branch keeps only
concrete texture wiring and copy timing.
Done Checks:
Canvas::stroke_draw()no longer contains the inline pad-stroke destination texture dispatch lambda.- Regression coverage proves the extracted helper preserves pad destination bind/unbind order.
docs/modernization/debt.mdrecords the reduced pad-stroke dispatch surface.
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
Completed Task Log
| Date | Task | Score | Validation | Commit |
|---|---|---|---|---|
| 2026-06-13 | STR-027 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-onfailure` |
STR-028 - Extract Stroke Draw Pad Face Orchestration
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline pad-stroke face execution block in Canvas::stroke_draw() into
a retained helper so the pad branch keeps only concrete brush-shape, texture,
and framebuffer wiring.
Done Checks:
Canvas::stroke_draw()no longer contains the inline pad-face block aroundexecute_legacy_canvas_stroke_pad_face_callbacks(...).- Regression coverage proves the extracted helper preserves pad-face order and copy behavior.
docs/modernization/debt.mdrecords the reduced pad callback surface.
Closeout: 3478219a
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
STR-029 - Extract Stroke Draw Pad Copy Callback Body
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline pad-stroke copy callback body in Canvas::stroke_draw() into
a retained helper so the pad branch owns only concrete copy-region wiring.
Done Checks:
Canvas::stroke_draw()no longer contains the inline pad-stroke copy callback body.- Regression coverage proves the extracted helper preserves pad copy-region behavior.
docs/modernization/debt.mdrecords the reduced pad copy-callback surface.
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
STR-030 - Extract Stroke Draw Pad Face Callback Body
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the inline pad-face callback body in Canvas::stroke_draw() into a
retained helper so the pad branch owns only concrete face selection and
texture/copy wiring.
Done Checks:
Canvas::stroke_draw()no longer contains the inline pad-face callback body.- Regression coverage proves the extracted helper preserves pad-face callback order and copy behavior.
docs/modernization/debt.mdrecords the reduced pad-face callback surface.
Closeout: e507fe27
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
Completed Task Log
| Date | Task | Score | Validation | Commit |
|---|---|---|---|---|
| 2026-06-13 | STR-029 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-onfailure` |
| 2026-06-13 | STR-030 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-onfailure` |
Progress Notes:
- 2026-06-13:
NodeStrokePreview::draw_stroke_immediate()now routes final composite execution and preview copy-back through a retained local wrapper, leaving the call site with only sequence wiring. - 2026-06-13:
Canvas::stroke_draw()now routes dual-brush tip dispatch through retained helper overloads, so the face-index callback wiring is no longer built inline in the dual-pass branch. - 2026-06-13:
Canvas::stroke_draw()now routes pad destination texture dispatch through retained helper overloads, so the face-index callback wiring is no longer built inline in the pad branch. - 2026-06-13:
Canvas::stroke_draw()now routes its main live-pass bind, execute, and unbind sequence throughexecute_legacy_canvas_stroke_main_pass(...); the retained adapter still owns the concrete sampler and texture callbacks. - 2026-06-13:
Canvas::stroke_draw_mix()now routes retained mix-pass request wiring throughmake_legacy_canvas_stroke_mix_pass_request(...); the legacy path still owns the concrete framebuffer setup and per-plane GL callbacks. - 2026-06-13:
Canvas::stroke_draw_mix()now routes its retained mix-pass execution shell throughexecute_legacy_canvas_stroke_mix_pass_with_setup(...)with a concrete request builder; the live path still owns the OpenGL setup and per-plane texture wiring. - 2026-06-13:
Canvas::stroke_draw_mix()now routes the setup/end shell throughmake_legacy_canvas_stroke_mix_pass_setup(...); the live path still owns the concrete framebuffer bind and GL capability toggles. - 2026-06-13:
Canvas::stroke_draw_mix()now routes the full retained mix-pass shell throughexecute_legacy_canvas_stroke_mix_pass_with_setup(...); the live path still owns the concrete framebuffer bind and GL capability toggles. - 2026-06-13:
Canvas::stroke_draw_mix()now routes the retained mix-pass shell throughexecute_legacy_canvas_stroke_mix_pass_shell(...); the live path still owns the concrete framebuffer bind and GL capability toggles. - 2026-06-13:
Canvas::stroke_draw_mix()now routes the combined setup and request bundle throughmake_legacy_canvas_stroke_mix_pass_shell(...); the live path still owns the concrete framebuffer bind and GL capability toggles. - 2026-06-13:
Canvas::stroke_draw_mix()now routes the combined setup, request bundle, and shell execution throughmake_legacy_canvas_stroke_mix_pass_shell(...)plusexecute_legacy_canvas_stroke_mix_pass_shell(...); the live path still owns the concrete framebuffer bind and GL capability toggles. - 2026-06-13:
Canvas::stroke_draw()live-pass sampler wiring now reuses a retained helper builder, and the stroke execution tests cover it.STR-004is now done after the final pad-destination helper extraction and tracker closeout. - 2026-06-13:
STR-004closed the last inline stroke dispatch glue.LATER-003remains at the binding-only tail. - 2026-06-13:
Canvas::stroke_draw_mix()now routes the retained shell execution through a local wrapper aroundexecute_legacy_canvas_stroke_mix_pass_shell(...); the live path still owns the concrete mixer framebuffer setup and GL capability toggles. - 2026-06-13:
Canvas::stroke_draw_mix()now calls the retained mix-pass executor directly instead of a local wrapper shell helper; the live path still owns the concrete mixer framebuffer setup and GL capability toggles. - 2026-06-13:
Canvas::stroke_draw_mix()now routes the remaining mixer framebuffer/capability shell through a local helper, leaving the call site with only mix-pass planning and helper invocation. - 2026-06-13:
retained_stroke_mix_pass_shell_builder_preserves_combined_wiringnow also exercises the direct shell executor path, locking the combined mix shell boundary with call-order regression coverage. - 2026-06-13:
retained_stroke_mix_pass_shell_executor_preserves_combined_wiringnow covers the direct shell executor path separately, keeping the shell boundary regression isolated from the builder coverage. - 2026-06-13:
Canvas::stroke_draw_mix()no longer computes an unused mix-plane plan in the live shell path; the remaining code is the retained shell setup and executor call. - 2026-06-13:
Canvas::stroke_draw_mix()now routes the remaining framebuffer setup callbacks through a local helper, leaving the method with only shell assembly and executor dispatch. - 2026-06-13:
Canvas::stroke_draw_mix()now keeps just the retained shell assembly and executor dispatch at the callsite; the framebuffer setup callbacks are isolated in the helper. - 2026-06-13:
Canvas::stroke_commit()now routes the large retained callback bundle through a local helper, leaving the callsite with sequence planning and helper invocation. - 2026-06-13:
Canvas::stroke_commit()now keeps the commit callback bundle in a local helper, leaving the callsite with sequence planning and retained callback invocation only. - 2026-06-13:
Canvas::stroke_commit()now routes the commit-input texture role switch through a local helper, so the callsite no longer owns that inline texture binding bundle. - 2026-06-13:
Canvas::stroke_commit()now routes the commit-input texture role switch through a retained service helper, so the callsite only supplies concrete face bindings. - 2026-06-13:
Canvas::stroke_draw_samples()now reuses a retained destination texture dispatch helper for the live sample path;Canvasstill owns the concrete face textures and callback execution. - 2026-06-13:
pp_paint_renderer_stroke_execution_testsnow also covers the new retained main-pass texture dispatch helper builder and its pattern/mixer wiring. Next slice should target another narrowstroke_draw()seam or stop once the remaining inline code is just trivial binding glue. - 2026-06-13:
pp_paint_renderer_stroke_execution_testsnow covers the new retained sampler dispatch helper builder and its pattern bind/unbind wiring. Next slice should target another narrowstroke_draw()seam or another helper-builder regression without reopening landed texture or dual-pass helpers. - 2026-06-13:
Canvas::stroke_draw()live-pass sampler dispatch now reuses a retained helper builder for brush-tip, destination, pattern, and mixer sampler callbacks; the live adapter still owns the concrete sampler objects. Next slice should target another narrowstroke_draw()seam without reopening landed texture or dual-pass helpers. - 2026-06-13:
Canvas::stroke_draw()main-pass texture dispatch now reuses retained helper builders for texture-unit, brush-tip, pattern, and mixer callback wiring; the live adapter still owns the concrete textures and sampler state. Next slice should target the remaining inlinestroke_draw()dispatch construction or another narrow seam without reopening landed pad or dual-pass helpers. - 2026-06-13:
Canvas::stroke_draw()dual-brush replay now reuses the new retained brush-tip texture dispatch helper for binding and unbinding; the live adapter still owns the concrete brush texture object and live-pass execution. Next slice should target another narrowstroke_draw()seam without reopening landed pad or sample helpers. - 2026-06-13:
Canvas::stroke_draw()dual-brush replay now routes shader setup, brush-tip texture binding, live-pass execution, and brush-tip unbinding throughexecute_legacy_canvas_stroke_dual_pass(...); the live adapter still owns the concrete texture callbacks and face-frame replay. Next slice should target another narrowstroke_draw()seam without reopening landed pad or sample helpers. - 2026-06-13:
Canvas::stroke_draw()now routes the pad-stroke destination texture dispatch through a local helper lambda, so the repeated bind/unbind callback construction is centralized while the pad executor still owns the face loop and copy timing. Next slice should target another narrow canvas stroke execution seam without reopening landed pad or sample helpers. - 2026-06-13:
Canvas::stroke_draw_mix()now routes mix-pass plane planning throughplan_legacy_canvas_stroke_mix_pass_planes(...)and wraps retained framebuffer setup/teardown withexecute_legacy_canvas_stroke_mix_pass_with_setup(...); the live adapter still owns concrete sampler, texture, and draw callbacks.pp_paint_renderer_stroke_execution_testsnow covers the default dirty-union path for live-pass face-framebuffer execution. Next slice should target the remaining Canvas stroke execution seam without reopening the landed mix-pass setup helper. - 2026-06-13:
Canvas::draw_merge()now routes per-plane merge-target clear, blend-state gating, and optional checkerboard prepass throughexecute_legacy_canvas_draw_merge_plane_setup(...); per-layer iteration, temporary-stroke branches, and concrete framebuffer ownership remain local toCanvas. Next slice should target another narrow draw-merge execution seam without reopening landed plane-setup, temporary-composite, layer-blend, final-plane, or texture-alpha helpers. - 2026-06-13:
Canvas::draw_merge()now routes the standard per-layer texture-alpha pass throughexecute_legacy_canvas_draw_merge_layer_texture(...); temporary-stroke branches, per-plane iteration, and concrete RTT ownership remain local toCanvas. Next slice should target another narrow draw-merge execution seam without reopening landed temporary-composite, layer-blend, final-plane, or texture-alpha helpers. - 2026-06-13:
Canvas::draw_merge()temporary composite setup now routes throughexecute_canvas_draw_merge_temporary_composite(...); the retained path still owns the concrete setup, sampler, texture, draw, and unbind callbacks. Next slice should target another narrow draw-merge seam without reopening the landed temporary-composite helper. - 2026-06-13:
Canvas::draw_merge()temporary erase and paint branch wiring now routes throughexecute_legacy_canvas_draw_merge_temporary_composite(...); the retained path still owns the concrete setup, sampler, texture, draw, and unbind callbacks. Next slice should target another narrow draw-merge seam without reopening the landed temporary-composite helper. - 2026-06-13:
Canvas::draw_merge()now routes the remaining temporary erase and paint callback bundle throughexecute_legacy_canvas_draw_merge_temporary_composite(...); only the branch selection remains inline. Next slice should target another narrow draw-merge seam without reopening the landed temporary-composite helper. - 2026-06-13:
Canvas::draw_merge()now routes the layer-composite shell through a local wrapper aroundexecute_legacy_canvas_draw_merge_layer_composite(...); only the final branch selection remains inline. Next slice should target another narrow draw-merge seam without reopening the landed temporary-composite helper. - 2026-06-13:
Canvas::draw_merge()now routes the layer texture, layer blend, and final-plane composite callbacks through local wrappers around the retained helpers; the remaining work in this lane is now just branch selection glue. - 2026-06-13:
pp_paint_renderer_stroke_execution_testsnow also covers retained frame-plan assembly for previous-sample projection mode and zoom scaling. Next slice should target the remaining preview/Canvas stroke execution seam or another narrow renderer boundary without reopening the landed stroke-frame planner coverage. - 2026-06-13:
NodeStrokePreviewlive-pass orchestration now routes throughexecute_legacy_stroke_preview_live_pass(...), andpp_paint_renderer_stroke_execution_testsnow covers live-pass clear, traversal, and final copy ordering. Next slice should target the remaining preview or Canvas stroke execution seam without reopening the landed live-pass helper. - 2026-06-13:
NodeStrokePreview::draw_stroke_immediate()now routes retained preview feedback/material/composite planning plus stroke-shader uniform assembly throughplan_legacy_node_stroke_preview_pass_orchestration(...); compositor coverage now locks destination-feedback fallback, composite-slot intent, and the retained pattern/dual shader-uniform handoff. The preview node still owns brush object mutation, retainedStrokepopulation, and the concrete GL pass callbacks. Next slice should target another narrow preview execution seam without reopening the landed preview setup, mix, pass-sequence, or final-composite helpers. - 2026-06-13:
NodeStrokePreview::draw_stroke_immediate()now routes preview stroke max-size fallback, dual-preview max-size derivation, pattern-scale flips, and Bezier preview-point generation throughplan_legacy_node_stroke_preview_stroke_setup(...); compositor coverage now also locks the retained stroke-setup curve/pressure intent and pass-sequence request-validation short-circuit behavior. The preview node still owns brush object mutation, camera wiring, retainedStrokepopulation, and live GL execution. Next slice should target the remaining higher-level preview pass orchestration seam without reopening landed sample, mix, pass-sequence, or final-composite helpers. - 2026-06-13:
Canvas::draw_merge()per-layer blend composite now routes merge-RTT unbind, shader setup, optional destination-copy feedback, draw, and cleanup ordering throughexecute_legacy_canvas_draw_merge_layer_blend(...); temporary-stroke branch selection, layer iteration, and final merged-plane redraw ownership remain local toCanvas. Next slice should target the remaining end-of-plane merged-texture copy/grid/final-redraw seam or another similarly narrow final composite boundary without reopening landed temporary-composite or per-layer blend helpers. - 2026-06-13:
Canvas::draw_merge()end-of-plane merged-texture copy, optional checkerboard redraw, and final merged-texture composite ordering now route throughexecute_legacy_canvas_draw_merge_final_plane_composite(...); per-plane iteration and concrete framebuffer, sampler, texture, and draw callbacks remain local toCanvas. Next slice should target another narrow retained draw-merge boundary without reopening landed temporary-composite, layer-blend, or final-plane helpers. - 2026-06-13:
Canvas::draw_merge()erase live temporary-stroke composite now routes retained setup, sampler bind, texture bind, draw, and texture unbind ordering throughexecute_legacy_canvas_stroke_temporary_composite(...); both live temporary composite branches now share the same retained execution helper whileCanvaskeeps only concrete GL object callbacks and broader final composite ownership. Next slice should target the remaining final composite seam without reopening landed sample, mix, dirty, or framebuffer helpers. - 2026-06-13:
NodeStrokePreview::stroke_draw_mix()now routes retained mix-pass shader setup plus framebuffer/state/input/draw ordering throughexecute_legacy_node_stroke_preview_mix_pass(...), with compositor coverage locking the retained callback order and shader-plan handoff. The preview node keeps only the concrete GL save/restore, texture-object bind, and plane-draw callbacks. Next slice should target another retained preview or canvas stroke seam without reopening the landed preview sample, material-planning, pass-sequence, or final-composite helpers. - 2026-06-13:
NodeStrokePreview::draw_stroke_immediate()now routes dual-pass/background/main-pass/final-composite/copy-back ordering throughexecute_legacy_node_stroke_preview_pass_sequence(...); the remaining local preview ownership is concentrated aroundstroke_draw_mix()setup/execution. Next slice should target that final mix-pass setup/execution seam without reopening landed sample, binding, material-planning, or final-composite helpers. - 2026-06-13:
Canvas::draw_merge()non-erase live temporary-stroke composite ordering now routes throughexecute_legacy_canvas_stroke_temporary_composite(...); erase-path and broader final composite ownership still remain local toCanvas. Next slice should target the erase temporary composite branch or another similarly narrow final composite seam without reopening landed sample, mix, dirty, or framebuffer helpers. - 2026-06-13:
Canvas::draw_merge()temporary paint branch execution now routes throughmake_legacy_canvas_draw_merge_temporary_paint_composite(...); the live path still owns the concrete layer RTT, mixer RTT, sampler, and plane callbacks. - 2026-06-13:
Canvas::stroke_draw_samples()now routes face-indexed destination bind/copy/unbind and brush upload/draw throughexecute_legacy_canvas_stroke_face_sample_polygon(...); the retained sample executor now owns the face-aware dispatch contract whileCanvaskeeps only the concrete GL object callbacks. Next slice should target any remaining final temporary-texture composite setup without reopening landed sample, mix, sampler, dirty, face, or pad helpers. - 2026-06-13:
pp_paint_renderer_stroke_execution_testsnow also covers direct retained frame-sample callback ordering plusexecute_legacy_canvas_stroke_frame_samples_with_dirty_tracking(...)timing/state semantics, including pre-update dirty visibility andprevious_pass_dirty_boxoverride behavior. Next test slice should target the next header-level preview live sample ordering surface without reopening production files. - 2026-06-13:
Canvas::stroke_draw_mix()now routes visible-plane filtering, retained sampler/texture-slot binding, and final plane draw ordering throughexecute_legacy_canvas_stroke_mix_pass(...); mixer framebuffer/state setup and per-plane shader material/MVP preparation remain local toCanvas. Next slice should target the remainingstroke_draw_samples()callback body or any final temporary-texture composite setup without reopening landed sample, sampler, dirty, face, or pad helpers.
STR-019 - Extract Stroke Draw Mix Mixer State And Copy Ordering
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: DEBT-0036
Scope: src/canvas.cpp, src/legacy_canvas_stroke_execution_services.h, tests/paint_renderer/compositor_tests.cpp
Goal:
Move the remaining stroke_draw_mix() mixer-framebuffer state and copy-order
callbacks into a retained helper so Canvas::stroke_draw_mix() keeps only
branch selection plus concrete GL object wiring.
Done Checks:
Canvas::stroke_draw_mix()no longer owns the remaining mixer framebuffer state and copy ordering inline.- Regression coverage proves the extracted helper preserves the mixer-state callback order.
docs/modernization/debt.mdrecords the reduced stroke-mix shell surface.
Validation:
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
Completed Task Log
| Date | Task | Score | Validation | Commit |
|---|---|---|---|---|
| 2026-06-13 | STR-019 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor | pp_paint_renderer_stroke_execution" --output-on-failure` |
- 2026-06-13:
pp_paint_renderer_stroke_execution_testsnow also covers retained preview background capture ordering, final composite ordering, and preview texture-copy bind-before-copy behavior vialegacy_canvas_stroke_preview_services.h. Next test slice should target the next header-level preview live sample or mix-pass ordering surface without reopening production files. - 2026-06-13:
Canvas::stroke_draw_samples()now routes polygon triangulation, sample-point assembly, and the retained destination-copy / upload / draw helper handoff throughexecute_legacy_canvas_stroke_sample_polygon(...); direct GL callback wiring and the remaining live draw ownership stay local toCanvas. Next slice should target the remaining callback body or final temporary-texture composite setup without reopening the landed sampler, dirty, face, or pad helpers. - 2026-06-13:
NodeStrokePreview::stroke_draw_mix()now routes mixer framebuffer bind/unbind, viewport/scissor/blend state, texture-slot binding, and final plane draw through one local helper; material planning and shader uniform setup remain local to the preview node. Next slice should target the remaining mix-pass material/setup orchestration without reopening the landed preview live-pass, binding, sample, or final composite helpers. - 2026-06-13:
NodeStrokePreview::stroke_draw_mix()now routes retained mix-pass material planning plus composite/pattern/dual uniform payload assembly throughplan_legacy_node_stroke_preview_mix_pass(...), with compositor coverage locking the retained preview mix adapter semantics for composite-pass patterning and dual state. Mixer framebuffer ownership, retained shader execution, texture binding, and final draw/copy ordering remain local to the preview node. Next slice should target the remaining mix-pass execution ownership without reopening the landed preview live-pass, binding, sample, or final composite helpers. - 2026-06-13:
pp_paint_renderer_stroke_execution_testsnow also covers retained texture-dispatch activation order and sampler-dispatch routing across brush tip, destination, pattern, and mixer helper inputs. Next test slice should extend the dedicated lane into frame-sample loop ordering or preview-side retained helper coverage. - 2026-06-13: Added
pp_paint_renderer_stroke_execution_testsas a dedicated retained stroke execution-helper target covering texture-input binding order, sample destination-copy behavior, live-pass face-framebuffer dirty tracking, and pad-face destination-copy behavior. Next test slice should extend this target toward the newer sampler-dispatch helpers or preview-side retained execution helpers. - 2026-06-13:
Canvas::stroke_drawlive-pass sampler bind/unbind plus semantic texture-input dispatch now routes through retained stroke execution helpers; concrete GL object mapping, framebuffer ownership, shader timing, and final draw execution remain local toCanvas. Next slice should target the remaining live draw execution boundary insidestroke_draw_samples()or the final temporary-texture composite setup without reopening the landed dirty, face-framebuffer, pad, or texture-intent helpers. - 2026-06-13:
NodeStrokePreview::stroke_draw_samples()now routes destination bind/unbind, framebuffer copy callback wrapping, sample-point assembly, and brush-vertex upload/draw through one local helper; mixer-pass state execution and higher-level pass orchestration remain local to the preview node. Next slice should target the remaining mixer-pass state/copy ordering without reopening the landed preview live-pass, binding, or final composite helpers. - 2026-06-13:
Canvas::stroke_drawmain, 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 toCanvas. 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_drawmain and dual live-pass per-face framebuffer begin/end execution plus pad-face array assembly now route throughlegacy_canvas_stroke_execution_services.h; shader activation timing, texture/sampler binding, framebuffer ownership, and final draw execution remain local toCanvas. 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_drawcurrent and dual stroke per-face framebuffer/sample callback ordering now routes throughlegacy_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_drawcurrent and dual stroke dirty-box mutation now routes throughlegacy_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_commitnow routes retained commit input texture/sampler binding, erase/composite draw dispatch, committed-copy, and dilate draw throughlegacy_canvas_stroke_commit_services.h; history readback,ActionStrokepopulation, and layer dirty-box mutation remain local to Canvas. - 2026-06-13:
pp_paint_rendererowns tested Canvas stroke commit sequencing and commit texture slot intent. Next slice should wirelegacy_canvas_stroke_commit_services.hintoCanvas::stroke_commitwhile 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 |
| 2026-06-13 | STR-004 | +1 renderer boundary and OpenGL parity | ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure; MSBuild.exe out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64 |
5c03b130 |
Task Template
Use this shape when adding a new task:
### STR-004 - Collapse Remaining Stroke Dispatch Glue
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_execution_services.h`,
`tests/paint_renderer/stroke_execution_tests.cpp`
Goal:
Remove the last inline `Canvas::stroke_draw()` dispatch construction that is
still just wiring. Keep the live adapter owning concrete GL objects, but move
the remaining helper-builder glue into retained stroke-execution helpers or
delete it if the callsite can consume a smaller already-tested helper.
Done Checks:
- `Canvas::stroke_draw()` has no ad hoc `LegacyCanvasStroke*Dispatch` literal
blocks for the remaining live-pass wiring.
- The helper-builder coverage tests prove the remaining dispatch helpers route
the expected callbacks.
- `docs/modernization/debt.md` records the reduced stroke-dispatch surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
### STR-005 - Extract Live Stroke Face Callback Orchestration
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_execution_services.h`,
`tests/paint_renderer/stroke_execution_tests.cpp`
Goal:
Move the remaining inline live-pass face callback orchestration in
`Canvas::stroke_draw()` into a retained helper so the live stroke path owns only
concrete GL object wiring and per-face execution callbacks. Keep the face loop
and callback order unchanged.
Done Checks:
- `Canvas::stroke_draw()` no longer contains the remaining inline face-pass
callback block around `execute_legacy_canvas_stroke_live_pass_with_face_framebuffers(...)`.
- Regression coverage proves the extracted helper preserves callback order and
face-state updates.
- `docs/modernization/debt.md` records the reduced live-stroke callback surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-005 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure`; `MSBuild.exe out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `4c9809f7` |
### STR-006 - Extract Dual Stroke Face Execution Orchestration
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_execution_services.h`,
`tests/paint_renderer/stroke_execution_tests.cpp`
Goal:
Move the inline dual-stroke face execution lambda in `Canvas::stroke_draw()`
into a retained helper so the dual-pass branch keeps only concrete shader,
texture, and framebuffer wiring. Preserve dual-pass face order and callback
behavior.
Done Checks:
- `Canvas::stroke_draw()` no longer contains the inline dual-pass face execution
lambda around `execute_legacy_canvas_stroke_live_pass_with_face_framebuffers(...)`.
- Regression coverage proves the extracted helper preserves dual-pass callback
order and face execution.
- `docs/modernization/debt.md` records the reduced dual-pass callback surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-006 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure`; `MSBuild.exe out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `ae46be9f` |
### STR-007 - Extract Main Stroke Face Loop Orchestration
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_execution_services.h`,
`tests/paint_renderer/stroke_execution_tests.cpp`
Goal:
Move the inline main-stroke face loop in `Canvas::stroke_draw()` into a
retained helper so the main-pass branch keeps only concrete shader, sampler,
and framebuffer wiring. Preserve main-pass face order and callback behavior.
Done Checks:
- `Canvas::stroke_draw()` no longer contains the inline main-pass face loop
around `execute_legacy_canvas_stroke_live_pass_with_face_framebuffers(...)`.
- Regression coverage proves the extracted helper preserves main-pass callback
order and face execution.
- `docs/modernization/debt.md` records the reduced main-pass callback surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-007 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure`; `MSBuild.exe out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `fee09e53` |
### STR-008 - Extract Pad Stroke Face Orchestration
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_execution_services.h`,
`tests/paint_renderer/stroke_execution_tests.cpp`
Goal:
Move the inline pad-stroke face execution block in `Canvas::stroke_draw()` into
a retained helper so the pad branch keeps only concrete brush-shape, texture,
and framebuffer wiring. Preserve pad-face order and copy timing.
Done Checks:
- `Canvas::stroke_draw()` no longer contains the inline pad-face block around
`execute_legacy_canvas_stroke_pad_faces(...)`.
- Regression coverage proves the extracted helper preserves pad-face order and
copy behavior.
- `docs/modernization/debt.md` records the reduced pad callback surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-008 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure`; `MSBuild.exe out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `11a62e9b` |
### STR-009 - Extract Stroke Commit Callback Orchestration
Status: Done
Score: +2 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_execution_services.h`,
`tests/paint_renderer/stroke_execution_tests.cpp`
Goal:
Move the large inline callback block in `Canvas::stroke_commit()` into a
retained helper so commit sequencing keeps only concrete layer/texture/canvas
wiring. Preserve commit ordering, history capture, and dilate sequencing.
Done Checks:
- `Canvas::stroke_commit()` no longer contains the large inline commit callback
block around `execute_legacy_canvas_stroke_commit_sequence(...)`.
- Regression coverage proves the extracted helper preserves commit ordering and
history capture.
- `docs/modernization/debt.md` records the reduced stroke-commit callback
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-on-failure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-009 | +2 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "retained_stroke_commit_callback_builder_preserves_order|retained_stroke_commit_runner_preserves_per_face_step_order" --output-on-failure`; `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `e7813c2f` |
### STR-013 - Extract Stroke Commit Face Input Binding
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/legacy_canvas_stroke_commit_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the face-indexed commit-input binding wrapper behind the retained stroke
commit service boundary so `Canvas::stroke_commit()` only supplies concrete
face bindings.
Done Checks:
- `Canvas::stroke_commit()` uses the retained face-input binding helper.
- Regression coverage proves the face-input helper forwards the sequence slots.
- `docs/modernization/debt.md` records the reduced stroke-commit face-binding
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution|pp_paint_renderer_compositor" --output-on-failure
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-013 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution|pp_paint_renderer_compositor" --output-on-failure` | `6220f333` |
### STR-014 - Extract Stroke Commit Request Assembly
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the face array assembly and commit request construction out of
`Canvas::stroke_commit()` so the callsite only triggers the retained commit
sequence with concrete state.
Done Checks:
- `Canvas::stroke_commit()` no longer builds the face array inline.
- Regression coverage proves the request assembly helper preserves dirty-face
ordering.
- `docs/modernization/debt.md` records the reduced stroke-commit request
assembly surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution|pp_paint_renderer_compositor" --output-on-failure
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-014 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution|pp_paint_renderer_compositor" --output-on-failure` | `536f2683` |
- 2026-06-13: `Canvas::stroke_commit()` now routes the retained commit request
assembly through `make_legacy_canvas_stroke_commit_request(...)`, so the
callsite only supplies concrete faces, sequence, and callbacks.
### STR-015 - Extract Stroke Commit Sequence Invocation
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `execute_legacy_canvas_stroke_commit_sequence(...)`
invocation shape out of `Canvas::stroke_commit()` so the callsite only passes
already-built retained commit state.
Done Checks:
- `Canvas::stroke_commit()` no longer spells the retained commit request
invocation inline.
- Regression coverage proves the helper preserves the retained request shape.
- `docs/modernization/debt.md` records the reduced stroke-commit invocation
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution|pp_paint_renderer_compositor" --output-on-failure
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | --- | --- | --- |
| 2026-06-13 | STR-015 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution|pp_paint_renderer_compositor" --output-on-failure` | `161900c5` |
### STR-011 - Extract Preview Main Pass Orchestration
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Extract the remaining `NodeStrokePreview::draw_stroke_immediate()` main-pass
orchestration into a retained helper boundary without changing preview output.
Done Checks:
- Main-pass live execution uses a retained helper for setup, frame execution,
and final texture copy.
- Preview regression coverage proves callback order and binding still match the
current behavior.
- `DEBT-0036` records the narrowed preview orchestration surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-011 | no score movement | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | `fa6ac4dc` |
### STR-036 - Extract Preview Main Live Pass Orchestration
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `NodeStrokePreview::draw_stroke_immediate()` main live-pass
orchestration into a retained helper so the callsite keeps only branch
selection and direct live-pass dispatch.
Closeout: `b9647847`
Done Checks:
- `NodeStrokePreview::draw_stroke_immediate()` no longer owns the main live-pass
orchestration inline.
- Regression coverage proves the helper preserves live-pass branch order and
preview copy behavior.
- `docs/modernization/debt.md` records the reduced preview live-pass surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
### STR-037 - Extract Preview Dual Pass Live Body
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `NodeStrokePreview::draw_stroke_immediate()` dual-pass live
body into a retained helper so the callsite keeps only sequence orchestration
and preview copy handling.
Closeout: `a2e805f9`
Done Checks:
- `NodeStrokePreview::draw_stroke_immediate()` no longer owns the dual-pass live
body inline.
- Regression coverage proves the helper preserves the dual-pass callback order
and preview copy behavior.
- `docs/modernization/debt.md` records the reduced dual-pass live surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
### STR-038 - Extract Preview Pass Sequence Request Assembly
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `NodeStrokePreview::draw_stroke_immediate()` pass-sequence
request assembly into a retained helper so the callsite keeps only the
sequence wrapper and final state restoration.
Closeout: `3672f9a5`
Done Checks:
- `NodeStrokePreview::draw_stroke_immediate()` no longer owns the pass-sequence
request object inline.
- Regression coverage proves the helper preserves dual/main sequence ordering
and copy behavior.
- `docs/modernization/debt.md` records the reduced preview pass-sequence
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
### STR-039 - Wire Stroke Commit Service Boundary
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_commit_services.h`, `tests/paint_renderer/stroke_execution_tests.cpp`
Goal:
Move the remaining `Canvas::stroke_commit()` service wiring behind the retained
stroke-commit helper boundary so the callsite keeps only local history and
layer mutation logic.
Closeout: `7cafaaa1`
Done Checks:
- `Canvas::stroke_commit()` no longer owns the retained commit-service wiring
inline.
- Regression coverage proves the helper preserves commit ordering and history
capture.
- `docs/modernization/debt.md` records the reduced stroke-commit service
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
### STR-040 - Extract Stroke Commit Local History And Dirty Mutation
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `tests/paint_renderer/stroke_execution_tests.cpp`
Goal:
Move the remaining local history and dirty-mutation work inside
`make_canvas_stroke_commit_callbacks()` into a retained helper so the callback
builder only forwards concrete canvas state.
Closeout: `aa53a5f9`
Done Checks:
- `make_canvas_stroke_commit_callbacks()` no longer owns the history/dirty
mutation block inline.
- Regression coverage proves the helper preserves action bookkeeping and dirty
box updates.
- `docs/modernization/debt.md` records the reduced stroke-commit history
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_stroke_execution_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
### STR-041 - Extract Preview Mix Pass Execution Ownership
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `NodeStrokePreview::stroke_draw_mix()` execution ownership
into a retained helper so the callsite keeps only the structural mix-pass
orchestration.
Closeout: `cf859cd4`
Done Checks:
- `NodeStrokePreview::stroke_draw_mix()` no longer owns the mix-pass execution
block inline.
- Regression coverage proves the helper preserves mixer framebuffer, viewport,
and draw ordering.
- `docs/modernization/debt.md` records the reduced preview mix-pass execution
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
### STR-042 - Extract Preview Main Live Sample Callback Wrapping
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `NodeStrokePreview::make_stroke_draw_immediate_main_live_pass_request()`
sample/copy callback wrapping into retained helpers so the request builder only
forwards concrete preview state.
Closeout: `2053c55b`
Done Checks:
- `make_stroke_draw_immediate_main_live_pass_request()` no longer owns the
live-pass sample/copy callback wrapping inline.
- Regression coverage proves the helper preserves live-pass sample ordering and
preview copy behavior.
- `docs/modernization/debt.md` records the reduced preview main-live-pass
callback surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
### STR-043 - Extract Preview Mixer Pass State And Copy Ordering
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `NodeStrokePreview::stroke_draw_samples()` mixer-pass state
and copy ordering into retained helpers so the callsite keeps only the final
sample dispatch.
Done Checks:
- `NodeStrokePreview::stroke_draw_mix()` no longer owns the mixer-pass
state/copy ordering inline.
- Regression coverage proves the helper preserves mixer framebuffer binding,
preview copy behavior, and mix-input ordering.
- `docs/modernization/debt.md` records the reduced preview mixer-pass surface.
Closeout: `c147c1d1`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
### STR-044 - Extract Preview Sample Pass Request Construction
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `execute_stroke_preview_sample_pass()` request construction
into a retained helper so the executor wrapper keeps only request dispatch and
dirty-bounds return handling.
Done Checks:
- `execute_stroke_preview_sample_pass()` no longer owns the sample-request
construction inline.
- Regression coverage proves the helper preserves destination binding, copy,
and brush draw ordering.
- `docs/modernization/debt.md` records the reduced preview sample-pass surface.
Closeout: `5f66d0e7`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
### STR-045 - Extract Preview Final Composite Request Construction
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `execute_stroke_preview_final_composite_pass()` request
construction into a retained helper so the final preview composite wrapper
keeps only dispatch and copy handling.
Done Checks:
- `execute_stroke_preview_final_composite_pass()` no longer owns the
final-composite request construction inline.
- Existing preview final-composite executor coverage still proves the helper
preserves shader setup, sampler binding, input binding, and draw ordering.
- `docs/modernization/debt.md` records the reduced preview final-composite
surface.
Closeout: `538441a5`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
### STR-046 - Extract Draw Merge Plane Iteration Orchestration
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `Canvas::draw_merge()` plane iteration and branch
orchestration into a retained helper so the callsite keeps only framebuffer
setup, per-plane dispatch, and final composite gating.
Done Checks:
- `Canvas::draw_merge()` no longer owns the per-plane iteration and branch
orchestration inline.
- Regression coverage proves the helper preserves plane dispatch order and
final composite gating.
- `docs/modernization/debt.md` records the reduced draw-merge plane-loop
surface.
Closeout: `d46399f4`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
```
### STR-047 - Extract Draw Merge Final Composite Gating
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `Canvas::draw_merge()` final composite gating into a
retained helper so the plane-loop helper only dispatches plane setup and layer
branches.
Done Checks:
- `execute_canvas_draw_merge_plane_iteration(...)` no longer owns the final
composite gating inline.
- Regression coverage proves the helper preserves the `use_blend` final
composite decision.
- `docs/modernization/debt.md` records the reduced draw-merge final-composite
surface.
Closeout: `a16ac39d`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
```
### STR-048 - Extract Draw Merge Branch Orchestration Body
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `Canvas::draw_merge_branch_orchestration()` body into
retained helpers so the branch wrapper keeps only branch selection and helper
dispatch.
Done Checks:
- `Canvas::draw_merge_branch_orchestration()` no longer owns the branch
execution body inline.
- Regression coverage proves the extracted helper preserves temporary erase,
temporary paint, texture, and blend execution order.
- `docs/modernization/debt.md` records the reduced draw-merge branch surface.
Closeout: `85f8af42`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
```
### STR-049 - Extract Draw Merge Temporary Paint Request Construction
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `Canvas::draw_merge_temporary_paint_branch()` request
construction into a retained helper so the temporary-paint wrapper keeps only
dispatch and execution handling.
Done Checks:
- `Canvas::draw_merge_temporary_paint_branch()` no longer owns the
temporary-paint request construction inline.
- Regression coverage proves the helper preserves temporary-paint sampler,
texture, and draw ordering.
- `docs/modernization/debt.md` records the reduced draw-merge temporary-paint
surface.
Closeout: `1a28716e`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
```
### STR-050 - Extract Draw Merge Temporary Composite Dispatch Helpers
Status: Ready
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining temporary composite dispatch bodies used by
`Canvas::draw_merge_branch_orchestration()` into retained helpers so the
branch body keeps only branch selection and helper dispatch.
Done Checks:
- `execute_canvas_draw_merge_branch_body(...)` no longer owns the temporary
erase, temporary paint, texture, and blend dispatch bodies inline.
- Regression coverage proves the extracted helpers preserve temporary erase,
temporary paint, texture, and blend execution order.
- `docs/modernization/debt.md` records the reduced draw-merge temporary
composite surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
```
### STR-051 - Extract Draw Merge Branch Dispatch Bodies
Status: Ready
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining temporary erase, texture, and blend dispatch bodies used by
`execute_canvas_draw_merge_branch_body()` into retained helpers so the branch
body keeps only helper dispatch.
Done Checks:
- `execute_canvas_draw_merge_branch_body()` no longer owns the temporary erase,
texture, and blend dispatch bodies inline.
- Regression coverage proves the extracted helpers preserve temporary erase,
texture, and blend execution order.
- `docs/modernization/debt.md` records the reduced draw-merge branch-dispatch
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
```
### STR-010 - Extract Remaining Draw Merge Composite Orchestration
### STR-016 - Extract Draw Merge Layer Composite Execution
Status: Blocked
Score: +2 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Blocked By: Helper API shape mismatch in the current per-layer composite extraction attempt
Goal:
Move the large per-layer `draw_merge()` composite execution block into a
retained helper so the callsite only supplies branch selection and concrete GL
objects.
Done Checks:
- `Canvas::draw_merge()` no longer builds the per-layer composite execution
inline.
- Regression coverage proves the extracted helper preserves per-branch order.
- `docs/modernization/debt.md` records the reduced draw-merge composite
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-016 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `b9ed78e1` |
| 2026-06-13 | STR-016 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `pending` |
| 2026-06-13 | STR-016 | +2 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `pending` |
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-016 | +2 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `pending` |
### STR-017 - Extract Draw Merge Temporary Erase Composite Branch
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining temporary erase branch inside `Canvas::draw_merge()` into a
retained helper so the callsite keeps only branch selection and concrete GL
object wiring.
Done Checks:
- `Canvas::draw_merge()` no longer builds the temporary erase composite inline.
- Regression coverage proves the extracted helper preserves erase-branch order.
- `docs/modernization/debt.md` records the reduced draw-merge erase surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-017 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `e8fdd96d` |
### STR-018 - Extract Draw Merge Temporary Paint Composite Branch
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining temporary paint branch inside `Canvas::draw_merge()` into a
retained helper so the callsite keeps only branch selection and concrete GL
object wiring.
Done Checks:
- `Canvas::draw_merge()` no longer builds the temporary paint composite inline.
- Regression coverage proves the extracted helper preserves paint-branch order.
- `docs/modernization/debt.md` records the reduced draw-merge paint surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-018 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure` | `037be1a7` |
### STR-031 - Extract Draw Merge Temporary Paint Branch
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the inline temporary paint branch in `Canvas::draw_merge()` into a
retained helper so the callsite keeps only branch selection and concrete GL
object wiring.
Done Checks:
- `Canvas::draw_merge()` no longer builds the temporary paint branch inline.
- Regression coverage proves the extracted helper preserves paint-branch order.
- `docs/modernization/debt.md` records the reduced draw-merge temporary-paint
surface.
Closeout: `91d4da09`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-031 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-onfailure` | `91d4da09` |
| 2026-06-13 | STR-032 | +2 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-onfailure`; `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `83a46770` |
### STR-032 - Extract Remaining Draw Merge Branch Orchestration
Status: Done
Score: +2 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.*`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining inline `Canvas::draw_merge()` branch orchestration into
retained helpers so the merge path keeps only concrete framebuffer, sampler,
and texture wiring. Preserve per-plane order, temporary-stroke behavior, and
final merge composition.
Done Checks:
- `Canvas::draw_merge()` no longer contains the remaining large inline branch
orchestration for temporary-stroke or blend/final-plane composition.
- Regression coverage proves the extracted helper preserves ordering and
branch behavior.
- `docs/modernization/debt.md` records the reduced draw-merge callback surface.
Closeout: `83a46770`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-onfailure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
### STR-033 - Extract Draw Merge Final Plane Composite
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.*`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the final-plane composite call in `Canvas::draw_merge()` behind a
retained helper so the merge path keeps only final-branch selection and
concrete GL object wiring.
Done Checks:
- `Canvas::draw_merge()` no longer owns the final-plane composite call inline.
- Regression coverage proves the final-plane helper preserves ordering and
checkerboard/blend behavior.
- `docs/modernization/debt.md` records the reduced final-plane composite
surface.
Closeout: `666c4dd3`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-onfailure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
### Completed Task Log
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-033 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-onfailure`; `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64` | `666c4dd3` |
| 2026-06-13 | STR-034 | +1 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure` | `3acb2da3` |
### STR-034 - Extract Stroke Draw Samples Request Assembly
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_execution_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `Canvas::stroke_draw_samples()` request assembly into a
retained helper so the callsite keeps only destination dispatch and result
handling.
Done Checks:
- `Canvas::stroke_draw_samples()` no longer owns the face-sample request
assembly inline.
- Regression coverage proves the request helper preserves destination-copy
behavior and brush upload/draw ordering.
- `docs/modernization/debt.md` records the reduced stroke-sample request
surface.
Closeout: `3acb2da3`
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure
```
### STR-035 - Extract Stroke Draw Samples Callback Body
Status: Done
Score: +1 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_stroke_execution_services.h`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining `Canvas::stroke_draw_samples()` callback body into a
retained helper so the callsite keeps only request dispatch and dirty-bounds
return handling.
Closeout: `3c3405d7`
Done Checks:
- `Canvas::stroke_draw_samples()` no longer owns the face-sample callback body
inline.
- Regression coverage proves the callback helper preserves destination-copy
behavior and brush upload/draw ordering.
- `docs/modernization/debt.md` records the reduced stroke-sample callback
surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_stroke_execution" --output-onfailure
```
### STR-012 - Extract Preview Final Composite Orchestration
Status: Done
Score: no score movement
Debt: `DEBT-0036`
Scope: `src/node_stroke_preview.cpp`, `tests/paint_renderer/compositor_tests.cpp`
Goal:
Extract the remaining preview final-composite and copy-back glue so the
preview path keeps only concrete texture binding and pass ordering.
Done Checks:
- `NodeStrokePreview::draw_stroke_immediate()` no longer owns the final
composite and preview copy-back orchestration inline.
- Regression coverage proves final composite and preview copy order.
- `DEBT-0036` records the reduced preview final-pass surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target PanoPainter
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-012 | no score movement | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure`; `cmake --build --preset windows-msvc-default --config Debug --target PanoPainter` | `718c9224` |
### PLT-003 - Align Platform Build Matrix With Phase 6 Targets
Status: Done
Score: +3 platform alignment and package parity
Debt: `DEBT-0009`, `DEBT-0011`, `DEBT-0059`
Scope: `scripts/automation/platform-build.ps1`, `scripts/automation/platform-build.sh`,
`scripts/dev/check_platform_build_targets.py`, `scripts/dev/check_package_smoke_readiness.py`,
`tests/CMakeLists.txt`, `docs/modernization/roadmap.md`
Goal:
Keep the phase-6 platform matrix explicit and self-checking by aligning the
platform-build and package-smoke wrapper defaults, their self-tests, and the
roadmap/debt notes with the current supported preset set. The wrappers should
stay the source of truth for named validation commands.
Done Checks:
- `panopainter_platform_build_target_matrix_self_test` and
`panopainter_package_smoke_readiness_self_test` cover the current platform
preset/package matrix.
- The roadmap and debt log mention the current platform-build/package-smoke
coverage and remaining platform shell gaps.
- The wrapper defaults stay synchronized with the self-tests.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "panopainter_platform_build_target_matrix_self_test|panopainter_package_smoke_readiness_self_test" --output-on-failure
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | PLT-003 | +3 platform alignment and package parity | `ctest --preset desktop-fast --build-config Debug -R "panopainter_platform_build_target_matrix_self_test|panopainter_package_smoke_readiness_self_test" --output-on-failure` | `7e09298e` |
### PLT-004 - Reduce Remaining Platform Legacy Adapter Tail
Status: Done
Score: +3 platform alignment and package parity
Debt: `DEBT-0017`, `DEBT-0052`, `DEBT-0053`
Scope: `src/platform_legacy/legacy_platform_services.*`, `src/platform_api/*`,
`src/platform_apple/*`, `src/platform_web/*`, `tests/platform_api/platform_services_tests.cpp`
Goal:
Trim one more concrete platform policy seam out of the catch-all legacy
platform adapter without destabilizing platform package or build validation.
Keep the work small, measurable, and centered on a policy that already has
test coverage in `pp_platform_api`.
Done Checks:
- One remaining platform policy surface moves out of `legacy_platform_services`
or is explicitly isolated behind a narrower adapter.
- The affected platform API tests cover the updated policy route.
- The debt log records the reduced legacy adapter surface.
Validation:
```powershell
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_platform_api_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
& .\out\build\windows-msvc-default\tests\Debug\pp_platform_api_tests.exe
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | PLT-004 | +3 platform alignment and package parity | `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_platform_api_tests.vcxproj /p:Configuration=Debug /p:Platform=x64`<br>`& .\out\build\windows-msvc-default\tests\Debug\pp_platform_api_tests.exe` | `6ba98ee` |
### PLT-005 - Split Linux FPS Title Reporting From Legacy Platform Adapter
Status: Done
Score: +1 platform alignment and package parity
Debt: `DEBT-0017`, `DEBT-0052`
Scope: `src/platform_legacy/legacy_platform_services.cpp`,
`src/platform_linux/*`, `tests/platform_api_tests.cpp` if coverage is needed
Goal:
Move Linux rendered-frame FPS title updates out of the catch-all legacy
platform adapter into a named Linux platform service boundary. Preserve the
current Linux title update behavior and keep non-Linux behavior unchanged.
Done Checks:
- `src/platform_legacy/legacy_platform_services.cpp` no longer owns the Linux
FPS-title update branch.
- Linux rendered-frame reporting still updates the title as before.
- The debt log records the reduced Linux platform tail.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | PLT-005 | +1 platform alignment and package parity | `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure`; `cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests` | `1d50bcc7` |
### PLT-006 - Split Mac Cursor Visibility From Legacy Platform Adapter
Status: Done
Score: +1 platform alignment and package parity
Debt: `DEBT-0015`, `DEBT-0017`
Scope: `src/platform_legacy/legacy_platform_services.cpp`,
`src/platform_apple/apple_platform_services.*`
Goal:
Move macOS cursor visibility handling out of the catch-all legacy platform
adapter into the Apple platform service boundary. Preserve cursor visibility
behavior and keep non-macOS behavior unchanged.
Done Checks:
- `src/platform_legacy/legacy_platform_services.cpp` no longer owns the macOS
cursor visibility branch.
- macOS cursor visibility still dispatches through the Apple service path.
- The debt log records the reduced macOS platform tail.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | PLT-006 | +1 platform alignment and package parity | `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure`; `cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests` | `fc4f5e40` |
### PLT-007 - Split Mac UI State Saving From Legacy Platform Adapter
Status: Done
Score: +1 platform alignment and package parity
Debt: `DEBT-0017`, `DEBT-0052`
Scope: `src/platform_legacy/legacy_platform_services.cpp`,
`src/platform_apple/apple_platform_services.*`
Goal:
Move macOS UI-state saving out of the catch-all legacy platform adapter into
the Apple platform service boundary. Preserve current macOS UI-state saving
behavior and keep non-macOS behavior unchanged.
Done Checks:
- `src/platform_legacy/legacy_platform_services.cpp` no longer owns the macOS
UI-state save branch.
- macOS UI-state saving still dispatches through the Apple service path.
- The debt log records the reduced macOS platform tail.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | PLT-007 | +1 platform alignment and package parity | `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure`; `cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests` | `623fdc67` |
### PLT-008 - Split Apple Clipboard Dispatch From Legacy Platform Adapter
Status: Done
Score: +1 platform alignment and package parity
Debt: `DEBT-0016`, `DEBT-0017`, `DEBT-0051`
Scope: `src/platform_legacy/legacy_platform_services.cpp`,
`src/platform_apple/apple_platform_services.*`
Goal:
Move Apple clipboard get/set dispatch out of the catch-all legacy platform
adapter into the Apple platform service boundary. Preserve clipboard behavior
and keep non-Apple behavior unchanged.
Done Checks:
- `src/platform_legacy/legacy_platform_services.cpp` no longer owns the Apple
clipboard get/set branches.
- Apple clipboard get/set still dispatches through the Apple service path.
- The debt log records the reduced Apple platform tail.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | PLT-009 | +1 platform alignment and package parity | `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure`; `cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests` | `3d999225` |
| 2026-06-13 | PLT-008 | +1 platform alignment and package parity | `ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure`; `cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests` | `2ec48965` |
### PLT-009 - Split Apple Clipboard Helpers From Legacy Platform Adapter
Status: Done
Score: +1 platform alignment and package parity
Debt: `DEBT-0016`, `DEBT-0017`, `DEBT-0051`
Scope: `src/platform_legacy/legacy_platform_services.cpp`,
`src/platform_apple/apple_platform_services.*`
Goal:
Move Apple clipboard helper methods out of the catch-all legacy platform
adapter into the Apple platform service boundary. Preserve clipboard behavior
and keep non-Apple behavior unchanged.
Done Checks:
- `src/platform_legacy/legacy_platform_services.cpp` no longer owns the Apple
clipboard helper branch.
- Apple clipboard get/set still dispatches through the Apple service path.
- The debt log records the reduced Apple platform tail.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R pp_platform_api_tests --output-on-failure
cmake --build --preset windows-msvc-default --config Debug --target pp_platform_api_tests
```
### STR-010 - Extract Remaining Draw Merge Composite Orchestration
Status: Done
Score: +2 renderer boundary and OpenGL parity
Debt: `DEBT-0036`
Scope: `src/canvas.cpp`, `src/legacy_canvas_draw_merge_services.*`,
`tests/paint_renderer/compositor_tests.cpp`
Goal:
Move the remaining inline `Canvas::draw_merge()` branch orchestration into
retained helpers so the merge path keeps only concrete framebuffer, sampler,
and texture wiring. Preserve per-plane order, temporary-stroke behavior, and
final merge composition.
Done Checks:
- `Canvas::draw_merge()` no longer contains the remaining large inline branch
orchestration for temporary-stroke or blend/final-plane composition.
- Regression coverage proves the extracted helper preserves ordering and
branch behavior.
- `docs/modernization/debt.md` records the reduced draw-merge callback surface.
Validation:
```powershell
ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor" --output-on-failure
& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\tests\pp_paint_renderer_compositor_tests.vcxproj /p:Configuration=Debug /p:Platform=x64
```
Completed Task Log:
| Date | Task | Score | Validation | Commit |
| --- | --- | ---: | --- | --- |
| 2026-06-13 | STR-010 | +2 renderer boundary and OpenGL parity | `ctest --preset desktop-fast --build-config Debug -R "pp_paint_renderer_compositor|pp_paint_renderer_stroke_execution" --output-on-failure`; `& 'C:\Program Files\Microsoft Visual Studio\18\Community\MSBuild\Current\Bin\MSBuild.exe' out\build\windows-msvc-default\PanoPainter.vcxproj /p:Configuration=Debug /p:Platform=x64` | `42bc1866` |