{ "track_id": "startup_speedup_20260606", "name": "Sloppy.py Startup Speedup", "initialized": "2026-06-06", "owner": "tier2-tech-lead", "priority": "high", "status": "active", "type": "refactor + performance", "scope": { "new_files": [ "src/startup_profiler.py", "scripts/audit_main_thread_imports.py", "scripts/audit_gui2_imports.py", "tests/test_ai_client_no_top_level_sdk_imports.py", "tests/test_hook_server_no_top_level_fastapi.py", "tests/test_app_controller_io_pool.py", "tests/test_warmup_mechanism.py", "tests/test_command_palette_no_top_level_import.py", "tests/test_theme_nerv_no_top_level_import.py", "tests/test_markdown_helper_no_top_level_import.py", "tests/test_api_hooks_warmup.py", "tests/test_main_thread_purity.py", "tests/test_startup_profiler.py", "tests/test_io_pool_endpoint.py" ], "modified_files": [ "src/ai_client.py", "src/api_hooks.py", "src/app_controller.py", "src/commands.py", "src/command_palette.py", "src/theme_2.py", "src/theme_nerv.py", "src/theme_nerv_fx.py", "src/markdown_helper.py", "src/markdown_table.py", "src/gui_2.py", "src/log_pruner.py", "src/project_manager.py" ] }, "blocked_by": [], "blocks": [], "estimated_phases": 9, "spec": "spec.md", "plan": "plan.md", "architectural_invariant": "The main thread (the one that enters immapp.run()) must NEVER import a module heavier than imgui_bundle and the lean gui_2 skeleton. Heavy modules are removed from main-thread-reachable files entirely and accessed via _require_warmed(name) at use sites, which assumes the module is in sys.modules because AppController's warmup pre-loaded it on the _io_pool. Enforced by scripts/audit_main_thread_imports.py (static CI gate) and tests/test_main_thread_purity.py (runtime audit-hook test).", "threading_constraint": "NO new threading.Thread(...) calls in src/. All background work must go through AppController._io_pool (ThreadPoolExecutor, max_workers=4, thread_name_prefix='controller-io'). The _io_pool is also the home of the heavy-module warmup jobs submitted in AppController.__init__.", "warmup_mechanism": "AppController.__init__ submits one job per heavy module to _io_pool. Each job imports its module and updates a thread-safe warmup_status dict. When the last job completes, _warmup_done_event is set and registered on_warmup_complete callbacks fire. The GUI polls warmup_status() each frame for a status-bar indicator. /api/warmup_status and /api/warmup_wait expose the state to tests and external clients. The user is notified via a toast on completion: 'All providers ready (M modules).'", "verification_criteria": [ "import src.ai_client < 50ms cold start (from ~1800ms)", "import src.gui_2 < 500ms cold start (from ~3000ms)", "import src.app_controller < 300ms cold start (from ~700ms)", "uv run sloppy.py --enable-test-hooks reaches immapp.run() in < 1.5s", "live_gui.wait_for_server(timeout=15) passes for all tests", "scripts/audit_main_thread_imports.py exits 0 (no heavy imports on main)", "tests/test_main_thread_purity.py passes (runtime audit hook confirms invariant)", "controller.wait_for_warmup(timeout=10) returns True", "All warmup modules in sys.modules after warmup completes", "User-triggered provider switch is INSTANT (proves warmup worked)", "GUI shows 'Warming up... (N/M)' then 'All imports ready' with green dot, then a toast", "GET /api/warmup_status returns {pending: [], completed: [...], failed: []}", "NO `import X` statements inside function bodies for heavy modules (grep-verified)", "No regressions in 273+ existing tests", "ZERO new threading.Thread(...) calls in src/ (after Phase 6 migration)", "Startup profile + io_pool status visible via /api/startup_profile, /api/io_pool_status" ], "links": { "backlog_entry": "conductor/tracks.md:152", "benchmark_script": "scripts/benchmark_imports.py", "audit_script": "scripts/audit_main_thread_imports.py", "related_docs": [ "docs/guide_architecture.md", "docs/guide_app_controller.md", "docs/guide_hot_reload.md", "docs/guide_testing.md" ] } }