# Modernization Task Tracker Status: live Last updated: 2026-06-17 This file is the active execution queue. It is written for a coordinator that can assign bounded packets to smaller parallel workers. Completed and stale history belongs in `docs/modernization/tasks-done.md`, not here. ## Operating Rules - Prioritize working-app ownership transfer over planners, CLI commands, package-only cleanup, or test-only work. - Every coding task must remove or narrow a real retained dependency, hotspot, unsafe ownership path, or thread/runtime ambiguity. - Tests are validation and guardrails. A task that only adds tests is not a P0 modernization slice unless it directly enables a blocked ownership move. - Do not broaden worker scopes. If a task crosses file boundaries, split it into worker packets with disjoint write scopes and integrate centrally. - No new `App::I`, `Canvas::I`, owning raw `Node*`, detached worker, direct GL resource dependency, or platform SDK dependency may be introduced in moved code. - Raw pointers may remain only as documented non-owning implementation details backed by a checked owner, handle, scoped connection, or explicit lifetime contract. - Preserve current app behavior first. UI appearance, file formats, brush behavior, platform behavior, and rendering output are not to be redesigned in modernization slices. - Use CMake source ownership as the progress signal. Shrinking `PP_PANOPAINTER_*` and `PP_LEGACY_*` ownership matters more than adding new helpers around the same retained code. ## Current Audit Snapshot Validation performed during the 2026-06-17 review: - `python scripts/dev/check_component_boundaries.py`: passed. - `python scripts/dev/check_renderer_api_contract.py`: passed. Key facts: - Pure component boundaries currently pass their static checks. - Remaining architectural risk is concentrated in the working app, retained app/UI/canvas targets, singleton reach, raw node ownership, and direct GL resource usage. - `PP_PANOPAINTER_APP_SOURCES`: 47 files, about 9620 lines. - `PP_PANOPAINTER_UI_SOURCES`: 52 files, about 9051 lines. - `PP_LEGACY_PAINT_DOCUMENT_SOURCES`: 22 files, about 6277 lines. - `PP_LEGACY_APP_SOURCES`: 26 files, about 4711 lines. - `PP_LEGACY_UI_CORE_SOURCES`: 32 files, about 4304 lines. - `App::I` still appears hundreds of times in retained app/canvas/UI/resource code. - `Canvas::I` still appears hundreds of times in retained canvas modes, panels, and workflow bridges. - Raw `Node*` and callback captures remain a dominant UI lifetime risk. - Retained stroke-preview/runtime draw paths still depend on legacy render/runtime helpers, but `RTT`, `Texture2D`, `Shape`, `Shader`, `TextMesh`, and `CanvasLayer` no longer call `App::I` directly for queueing. - `AppRuntime` now owns synchronized running flags plus explicit post/reject, same-thread execution, and queue-drain behavior, but broader singleton reach and app-shell ownership remain. - Retained cloud upload/download, brush-package import, and timelapse-export async paths now route through `AppRuntime::canvas_async_task`, but dialog and execution ownership still remains in retained app/document/cloud bridges. - `App::dialog_browse()` no longer owns browse-dialog button wiring inline; the retained document-open bridge now owns that handoff in `src/legacy_document_open_services.*`. - `App::init_toolbar_main()` now delegates retained main-toolbar button wiring through `src/legacy_main_toolbar_binding_services.*`, so `src/app_layout_main_toolbar.cpp` is down to a thin root lookup and adapter call while retained toolbar execution still lives in `src/legacy_app_shell_services.*`. - `App::init_menu_file()` now delegates retained File-menu popup and export submenu wiring through `src/legacy_file_menu_binding_services.*`, so `src/app_layout_file_menu.cpp` is down to a thin trigger lookup and adapter call while retained file/export execution still lives in `src/legacy_app_shell_services.*`. - `App::init_menu_about()` now delegates retained About-menu popup wiring through `src/legacy_about_menu_binding_services.*`, so `src/app_layout_about_layer_menu.cpp` no longer owns the About callback body inline while retained About execution still lives in `src/legacy_app_shell_services.*`. - `App::init_menu_tools()` now delegates the retained Tools > Panels submenu wiring through `src/legacy_tools_menu_binding_services.*`, so `src/app_layout_tools_menu.cpp` no longer owns that floating-panel submenu body inline while retained Tools execution and options wiring remain. - `App::update()` now delegates retained app-frame layout update and canvas-toolbar refresh execution through `src/legacy_app_frame_services.*`, so `src/legacy_app_runtime_shell_services.cpp` is thinner at the frame update seam while draw-time execution still remains there. - `App::tick()` and `App::resize()` now delegate retained app-frame tick and surface-resize execution through `src/legacy_app_frame_services.*`, so `src/app_events.cpp` is thinner at the frame-execution seam while broader input/platform dispatch still remains there. - `App::ui_save()` and `App::ui_restore()` now delegate retained floating and docked panel persistence through `src/legacy_app_ui_state_services.*`, so `src/app_layout_ui_state.cpp` is down to thin preference adapters while RTL direction execution stays local. - `App::init_sidebar()` now delegates the retained color-popup open/close wiring through `src/legacy_sidebar_color_popup_services.*` with explicit `App&`, popup-root, trigger-button, and panel dependencies, so `src/app_layout_sidebar.cpp` is thinner while the retained stroke/grid/layer popup families still remain inline. ## Parallel Assignment Rules Coordinator packets for workers should include only: - task id and one-paragraph goal - exact write scope - allowed read scope - debt ids that matter - required validation command - specific `rg` or `clangd_nav.py` queries - current behavior notes needed to avoid broad rediscovery Safe parallel groups: - One worker on canvas/render execution, one worker on generic UI controls, one worker on platform CMake cleanup, and one worker on runtime queue contracts can run in parallel if write scopes remain disjoint. - Do not run two workers against `src/app_runtime.*`, `src/node.*`, `src/legacy_canvas_document_io_services.cpp`, or `src/legacy_node_stroke_preview_runtime_services.cpp` at the same time. - Do not assign both a CMake source-list move and code edits touching the same source files to separate workers unless the coordinator serializes the CMake integration. ## P0 Queue ### ARC-RUN-010 - Harden `AppRuntime` Into An Explicit Runtime Service Status: Ready Why now: Render/UI/background queues are central to memory and thread safety. The current `AppRuntime` owns several `std::jthread` workers, but runtime state is still mutable, partly unsynchronized, and app-specific. The working app still uses `App::I` as the practical access path to render/UI queues. Write scope: - `src/app_runtime.h` - `src/app_runtime.cpp` - `src/app.h` - `src/legacy_app_runtime_shell_services.cpp` - `src/app_core/app_thread.h` - `tests/app_core/app_thread_tests.cpp` Read scope: - `src/texture.cpp` - `src/rtt.cpp` - `src/shape.cpp` - `src/shader.cpp` - `src/platform_windows/windows_platform_services.cpp` Required work: - Make render/UI/prepared-file/canvas worker running state synchronized or atomic, with a single shutdown path per worker. - Add explicit runtime service methods for thread-affinity checks and post/drain/shutdown semantics. - Keep exceptions from escaping worker bodies. - Stop exposing queue usage only through `App::I` wrappers for touched call sites. - Keep behavior identical for same-thread immediate execution and blocking render/UI calls. Done when: - Touched queue state has no unsynchronized read/write ambiguity. - Worker shutdown drains or rejects queued work according to documented behavior. - Touched app code can call an explicit runtime service instead of reaching queues through singleton state. - App-thread planner tests cover shutdown, stopped-worker enqueue, same-thread execution, and queue-drain behavior that the live runtime implements. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pp_app_core_app_thread_tests -TestRegex "pp_app_core_app_thread" python scripts/dev/check_component_boundaries.py ``` Mini-model packet: Start by auditing `render_running_`, `ui_running_`, `prepared_file_running_`, `canvas_async_running_`, thread ids, and worker stop methods. Do not rewrite GL resources in this task; expose the runtime contract needed for the next task. ### ARC-RND-010 - Move GL Resource Queueing Behind Renderer Runtime Contracts Status: Ready Why now: `RTT`, `Texture2D`, `Shape`, `Shader`, `Font`, and `CanvasLayer` still use `App::I->render_task*` directly. That blocks renderer backends and hides thread affinity behind a global app singleton. Write scope: - `src/texture.cpp` - `src/texture.h` - `src/rtt.cpp` - `src/rtt.h` - `src/shape.cpp` - `src/shape.h` - `src/shader.cpp` - `src/shader.h` - `src/font.cpp` - `src/font.h` - `src/canvas_layer.cpp` - `src/canvas_layer.h` - narrow adapter files if introduced under `src/renderer_gl/` Read scope: - `src/app_runtime.*` - `src/renderer_api/*` - `src/renderer_gl/*` - `src/paint_renderer/*` Required work: - Introduce a narrow render-dispatch interface or adapter consumed by retained GL resource classes. - Convert one coherent GL resource family per slice; do not edit every file in one worker pass unless the abstraction is already integrated. - Preserve blocking versus async semantics exactly. - Do not move app policy into `pp_renderer_gl`. - Do not add future backend implementation work. Done when: - The touched GL resource family no longer calls `App::I` directly for queueing or thread checks. - Render-thread assertions use an explicit runtime/render-dispatch contract. - CMake ownership remains consistent and no pure renderer API target depends on app headers. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pp_renderer_api_tests,pp_renderer_gl_capabilities_tests -TestRegex "pp_renderer|pp_paint_renderer" python scripts/dev/check_renderer_api_contract.py ``` Mini-model packet: Start with either `Texture2D`/`RTT` or `Shape`/`Shader`, not both. Use `rg -n "App::I->render_task|is_render_thread" src/texture.* src/rtt.*` for the first slice. ### ARC-RND-011 - Split Canvas Document I/O From Render Execution Status: Ready Why now: `src/legacy_canvas_document_io_services.cpp` is still the largest working-app document/export hotspot and has the highest `App::I` concentration found in the review. It mixes license checks, worker dispatch, render readback, progress UI, platform publish/flush, and retained `Canvas` mutation. Write scope: - `src/legacy_canvas_document_io_services.cpp` - `src/legacy_canvas_document_io_services.h` - `src/legacy_document_export_services.*` - `src/app_core/document_export.h` - `src/paint_renderer/*` - focused tests under `tests/app_core` or `tests/paint_renderer` Read scope: - `src/canvas.*` - `src/canvas_layer.*` - `src/legacy_canvas_render_shell_services.*` - `src/platform_api/platform_services.h` Required work: - Pick one export/import family first: equirectangular export, cube-face export, layer/frame collection export, or project save/open async I/O. - Move orchestration into an app-core or paint-renderer service request that accepts explicit document/render/platform dependencies. - Leave retained `Canvas` as a final adapter only for data that has not moved. - Remove direct `App::I` calls from the touched path. - Preserve progress and platform publish behavior. Done when: - One live document/export path is executable through an explicit service request rather than by walking `App::I`/`Canvas::I` from the bridge. - The retained bridge is visibly thinner and has fewer reasons to know about UI, worker, platform, and renderer details at the same time. - The touched path has focused validation that exercises the new request contract and the retained adapter. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli,pp_app_core_document_export_tests,pp_paint_renderer_compositor_tests -TestRegex "document_export|paint_renderer" ``` Mini-model packet: Do not broaden into all export types. Start with the path that already has the strongest pure planning/readiness coverage, then remove only the corresponding direct app/canvas singleton reach. ### ARC-RND-012 - Make Stroke Preview A Renderer-Owned Service Status: Ready Why now: `NodeStrokePreview` has been thinned, but `src/legacy_node_stroke_preview_runtime_services.cpp` still owns static worker state, render-context handoff, preview texture lifetime, and direct app/canvas access. This is a high-risk UI/render/thread boundary. Write scope: - `src/node_stroke_preview.*` - `src/legacy_node_stroke_preview_runtime_services.*` - `src/legacy_node_stroke_preview_draw_services.*` - `src/legacy_node_stroke_preview_sample_services.*` - `src/paint_renderer/*` - `tests/paint_renderer/*` Read scope: - `src/app_runtime.*` - `src/texture.*` - `src/rtt.*` - `src/canvas.*` - `src/node_panel_stroke.*` Required work: - Move one preview execution phase behind a renderer-facing service contract. - Replace static worker/resource state for the touched phase with owned service state or explicit runtime dependency. - Remove direct `App::I`/`Canvas::I` from the touched phase. - Preserve preview output and cancellation/shutdown behavior. Done when: - The touched preview phase can be reasoned about without reading the full node implementation. - Preview worker lifetime is owned and cancellable for the touched phase. - Renderer-facing tests cover the contract without linking app texture objects. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pp_paint_renderer_compositor_tests -TestRegex "paint_renderer|stroke_preview" ``` Mini-model packet: Start with result copy, live pass request assembly, or worker lifecycle. Do not combine all preview phases in one slice. ### ARC-UI-010 - Move Generic Controls Out Of `pp_legacy_ui_core` Status: Ready Why now: Generic controls still live in `PP_LEGACY_UI_CORE_SOURCES`, keeping `pp_panopainter_ui` tied to retained app/UI targets. This is working-app UI architecture, not cosmetic cleanup. Write scope: - `src/node_button.*` - `src/node_checkbox.*` - `src/node_icon.*` - `src/node_image.*` - `src/node_scroll.*` - `src/node_slider.*` - `src/node_text.*` - `src/node_text_input.*` - `src/ui_core/*` - `cmake/PanoPainterSources.cmake` - `CMakeLists.txt` Read scope: - `src/node.*` - `src/layout.*` - app-specific `src/node_panel_*` - app-specific `src/node_dialog_*` Required work: - Move one generic control family at a time to `pp_ui_core`. - Split renderer-neutral state/event/layout logic from retained GL drawing when a control still depends on GL classes. - Keep app-specific panels and dialogs out of `pp_ui_core`. - Update CMake ownership so the source-list change is real. Done when: - At least one generic control family is owned by `pp_ui_core` or has its renderer-neutral core owned there with only a narrow retained draw adapter. - `PP_LEGACY_UI_CORE_SOURCES` shrinks. - Existing UI behavior is unchanged. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pp_ui_core_layout_xml_tests,pp_ui_core_node_lifetime_tests,pp_ui_core_overlay_lifetime_tests -TestRegex "pp_ui_core" python scripts/dev/check_component_boundaries.py ``` Mini-model packet: Start with the least app-specific control: checkbox, button, icon, image, scroll, slider, text, or text input. Do not touch panels/dialogs in the same slice. ### ARC-UI-011 - Convert UI Ownership To Checked Handles By Default Status: Ready Why now: `pp_ui_core` has checked lifetime helpers, but base `Node` and app panels still mix raw parent/manager pointers, shared child vectors, raw callback parameters, and destroy-during-callback assumptions. Write scope: - `src/node.*` - `src/layout.*` - `src/legacy_ui_overlay_services.*` - one dialog or panel family per slice under `src/node_dialog_*` or `src/node_panel_*` - `src/ui_core/node_lifetime.*` - `src/ui_core/overlay_lifetime.*` Read scope: - call sites found with `rg -n "add_child|remove_child|destroy\\(|on_.*=|Node\\*" src/node_dialog_* src/node_panel_* src/legacy_ui_* src/node.*` Required work: - Convert one popup/dialog/panel family to checked handles or scoped connections. - Remove raw lifetime assumptions from callbacks in the touched family. - Document any remaining raw `Node*` as non-owning views with owner proof. - Keep visual behavior and event ordering unchanged. Done when: - The touched UI family can close during callback dispatch without relying on dangling raw pointers. - Overlay/popup lifetime flows through `pp_ui_core` lifetime primitives by default. - New touched callbacks are scoped or handle-checked. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pp_ui_core_node_lifetime_tests,pp_ui_core_overlay_lifetime_tests -TestRegex "ui_core_(node_lifetime|overlay_lifetime)" ``` Mini-model packet: Pick one family only, such as open/browse dialogs, picker dialog, popup menu, layer panel, or stroke panel. Avoid broad `Node` redesign unless the family requires a small base helper. ### ARC-APP-010 - Reduce App Shells To Composition And Adapters Status: Ready Why now: `PP_PANOPAINTER_APP_SOURCES` is still about 9620 lines. The app shell owns workflow, dialogs, layout binding, runtime, VR, cloud, brush package, platform hooks, and retained document/export adapters. Write scope: - one `src/app_*.cpp` family per slice - matching `src/legacy_app_*` service files - matching app-core planner/service headers only when needed - `cmake/PanoPainterSources.cmake` if ownership moves Read scope: - `src/app.h` - relevant app-core headers under `src/app_core` - relevant UI node files for the touched workflow Required work: - Pick one shell family: layout menus, dialogs, startup/frame, cloud, brush package, recording, VR, or document session. - Move retained implementation into a named service with explicit dependencies. - Make the app method a thin adapter or composition call. - Do not add planner-only coverage unless the app method actually shrinks. Done when: - One app shell file loses real workflow/runtime ownership. - The new service accepts explicit `App&`, runtime, platform, UI, document, or renderer dependencies instead of reading global state internally. - The touched path has focused validation or an app build gate. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli -TestRegex "pp_app_core|pano_cli_plan" ``` Mini-model packet: Start with a single app shell family. Do not mix dialogs, layout, cloud, and VR in one worker assignment. ### ARC-PLT-010 - Finish Platform Source Ownership In CMake Status: Ready Why now: Platform implementation ownership improved, but CMake still leaks Web platform sources into `PP_PANOPAINTER_APP_SOURCES`. Platform implementation files should belong to concrete `pp_platform_*` targets, not the app source group. Write scope: - `cmake/PanoPainterSources.cmake` - `CMakeLists.txt` - `src/platform_web/*` only if build integration requires a narrow include or factory adjustment Read scope: - `webgl/CMakeLists.txt` - `src/platform_android/*` - `src/platform_linux/*` - `src/platform_apple/*` - `src/platform_api/platform_services.h` Required work: - Remove `${PP_PLATFORM_WEB_SOURCES}` from `PP_PANOPAINTER_APP_SOURCES`. - Ensure root app/platform targets link `pp_platform_web` only when needed. - Keep WebGL retained package entrypoint behavior unchanged. - Do not reintroduce `platform_legacy`. Done when: - Concrete Web platform files are not compiled as app sources in the root app source group. - The source ownership direction is visible in CMake. - Platform API boundary checks still pass. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pp_platform_api_tests -TestRegex "pp_platform_api" python scripts/dev/check_component_boundaries.py ``` Mini-model packet: Keep this structural. Do not edit platform behavior unless CMake exposes a real link or include problem. ## P1 Queue ### ARC-SAFE-010 - Remove Manual Allocation From Touched Ownership Paths Status: Ready Why now: The review found manual `new`/`delete` pockets in node loading, canvas, layer actions, Wacom/bootstrap helpers, and retained resource cleanup. Some are non-owning or placement-new cases, but touched working-app ownership paths should move to RAII containers and factories. Write scope: - one selected ownership path at a time, such as `src/legacy_ui_node_loader.*`, `src/node.*`, `src/canvas.cpp`, `src/platform_windows/windows_bootstrap_helpers.cpp`, or `src/wacom.cpp` Read scope: - immediate owner/caller files for the selected path Required work: - Replace owning raw allocation with `std::unique_ptr`, `std::shared_ptr`, `std::vector`, `std::string`, or an explicit RAII wrapper. - Preserve non-owning views only where ownership is proven. - Avoid mixing this with UI or renderer redesign. Done when: - The touched path has no owning raw `new`/`delete`. - Failure paths cannot leak. - Lifetime remains clear at call sites. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter -TestRegex "pp_ui_core|pp_app_core" ``` Mini-model packet: Start with a single obvious allocation family. `legacy_ui_node_loader` is a good first target because it is UI ownership, not rendering behavior. ### ARC-SAFE-011 - Replace Remaining Ad Hoc Workers With Runtime-Owned Services Status: Ready Why now: Most recent worker conversions use `std::jthread`, but retained worker pockets still sit in UI/dialog/cloud/grid/preview services and `std::async` remains in `Asset`. The end state requires service-owned cancellation and shutdown. Write scope: - one worker family per slice: `src/node_dialog_cloud.*`, `src/legacy_cloud_services.*`, `src/legacy_grid_ui_services.*`, `src/asset.*`, or `src/legacy_node_stroke_preview_runtime_services.*` Read scope: - `src/app_runtime.*` - corresponding app-core/cloud/grid/preview planner headers - immediate UI caller files Required work: - Move worker ownership behind a runtime/service contract. - Add cancellation or shutdown semantics for the touched worker. - Avoid capturing raw nodes across worker completion without checked handles. - Preserve progress and completion callbacks. Done when: - The touched worker cannot outlive its owner. - Shutdown behavior is explicit and validated. - UI completion handoff is handle-safe or owner-checked. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter -TestRegex "pp_app_core|pp_ui_core" ``` Mini-model packet: Pick one worker family. Do not perform broad thread cleanup across unrelated subsystems in one task. ### ARC-WKF-010 - Thin Document Session/Open/Save Bridges Status: Ready Why now: The pure document/session planners are extensive, but live bridges still own retained prompts, metadata mutation, title updates, history clearing, snapshot handoff, and legacy `Canvas` execution. Write scope: - `src/legacy_document_open_services.*` - `src/legacy_document_session_services.*` - `src/legacy_history_services.*` - focused app-core document/session headers only when needed Read scope: - `src/app_core/document_route.h` - `src/app_core/document_session.h` - `src/app_core/document_canvas.h` - `src/app.h` - `src/canvas.*` Required work: - Pick one bridge path: open-project confirmation, save-before-workflow, save-version, new-document overwrite, history clear, or title update. - Move decisions/mutations behind explicit service requests. - Keep retained prompts as adapters only. Done when: - One document workflow path has a single obvious owner for decision, execution, and metadata mutation. - The retained bridge has less direct `App::I`/`Canvas::I` reach. - Behavior is covered by existing or focused document-session validation. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli,pp_app_core_document_session_tests,pp_app_core_document_route_tests -TestRegex "document_(session|route)" ``` Mini-model packet: Do not rewrite all document flows. Pick the narrowest path that removes live bridge ownership. ### ARC-WKF-011 - Split Cloud And Brush Package Work Out Of UI Nodes Status: Ready Why now: Cloud browse/download/upload and brush package import/export still mix UI node lifetime, worker ownership, storage, network/asset behavior, and app singleton reach. Write scope: - one family per slice: `src/legacy_cloud_services.*`, `src/node_dialog_cloud.*`, `src/legacy_brush_package_import_services.*`, `src/legacy_brush_package_export_services.*`, `src/legacy_brush_preset_services.*`, `src/node_panel_brush.cpp` Read scope: - `src/app_core/document_cloud.h` - `src/app_core/brush_package_import.h` - `src/app_core/brush_package_export.h` - `src/assets/brush_package.*` - relevant panel/dialog headers Required work: - Separate worker/network/asset execution from node lifetime. - Use app-core requests and asset helpers where they already exist. - Use checked handles for UI completion callbacks. - Preserve current cloud and brush package UX. Done when: - One cloud or brush package path can be understood without reading panel or dialog internals first. - The touched UI node is a view/controller shell, not the workflow owner. - The touched worker cannot outlive its service/UI owner. Validation: ```powershell powershell -ExecutionPolicy Bypass -File scripts\automation\quiet-validate.ps1 -BuildTargets PanoPainter,pano_cli,pp_app_core_document_cloud_tests,pp_app_core_brush_package_import_tests,pp_app_core_brush_package_export_tests,pp_assets_brush_package_tests -TestRegex "document_cloud|brush_package" ``` Mini-model packet: Cloud and brush package work are separate packets. Do not assign both to one small worker. ## Deferred On Purpose - Vulkan, Metal, WebGPU, and broad future-backend implementation. - OpenXR implementation beyond boundary cleanup needed to remove OpenVR debt. - Package-only migration that does not affect root app architecture. - CLI/planner-only expansion. - Broad warning cleanup without ownership movement. - Documentation-only progress claims.