diff --git a/conductor/tracks/cache_analytics_20260306/plan.md b/conductor/tracks/cache_analytics_20260306/plan.md index cc7dc6a..8c5e90e 100644 --- a/conductor/tracks/cache_analytics_20260306/plan.md +++ b/conductor/tracks/cache_analytics_20260306/plan.md @@ -2,38 +2,27 @@ > **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 1: Foundation & Research -Focus: Verify existing infrastructure and set up panel structure +## Phase 1: Verify Existing Infrastructure +Focus: Confirm ai_client.get_gemini_cache_stats() works - [ ] Task 1.1: Initialize MMA Environment - - Run `activate_skill mma-orchestrator` before starting - -- [ ] Task 1.2: Verify ai_client.get_gemini_cache_stats() - - WHERE: `src/ai_client.py` lines ~200-230 - - WHAT: Confirm function exists and returns expected dict structure +- [ ] Task 1.2: Verify get_gemini_cache_stats() + - WHERE: `src/ai_client.py` + - WHAT: Confirm function exists and returns expected dict - HOW: Use `manual-slop_py_get_definition` on `get_gemini_cache_stats` - - OUTPUT: Document exact return dict structure in task notes - -- [ ] Task 1.3: Verify ai_client.cleanup() - - WHERE: `src/ai_client.py` line ~220 - - WHAT: Confirm function clears `_gemini_cache` - - HOW: Use `manual-slop_py_get_definition` on `cleanup` - - SAFETY: Note that cleanup() also clears other resources - document side effects ## Phase 2: Panel Implementation -Focus: Create the GUI panel structure +Focus: Create cache panel in GUI -- [ ] Task 2.1: Add cache panel state variables - - WHERE: `src/gui_2.py` in `App.__init__` (around line 170) - - WHAT: Add minimal state if needed (likely none - read directly from ai_client) - - HOW: Follow existing state initialization pattern - - CODE STYLE: 1-space indentation - - SAFETY: No locks needed - read-only access to ai_client globals +- [ ] Task 2.1: Add cache panel state (if needed) + - WHERE: `src/gui_2.py` `App.__init__` + - WHAT: Minimal state for display + - HOW: Likely none needed - read directly from ai_client - [ ] Task 2.2: Create _render_cache_panel() method - - WHERE: `src/gui_2.py` after other `_render_*_panel()` methods - - WHAT: New method that displays cache statistics - - HOW: + - WHERE: `src/gui_2.py` after other render methods + - WHAT: Display cache statistics + - HOW: ```python def _render_cache_panel(self) -> None: if self.current_provider != "gemini": @@ -41,104 +30,50 @@ Focus: Create the GUI panel structure if not imgui.collapsing_header("Cache Analytics"): return stats = ai_client.get_gemini_cache_stats() - # Render stats... + if not stats.get("cache_exists"): + imgui.text("No active cache") + return + imgui.text(f"Age: {self._format_age(stats.get('cache_age_seconds', 0))}") + imgui.text(f"TTL: {stats.get('ttl_remaining', 0):.0f}s remaining") + # Progress bar for TTL + ttl_pct = stats.get('ttl_remaining', 0) / stats.get('ttl_seconds', 3600) + imgui.progress_bar(ttl_pct) + ``` + +- [ ] Task 2.3: Add helper for age formatting + - WHERE: `src/gui_2.py` + - HOW: + ```python + def _format_age(self, seconds: float) -> str: + if seconds < 60: + return f"{seconds:.0f}s" + elif seconds < 3600: + return f"{seconds/60:.0f}m {seconds%60:.0f}s" + else: + return f"{seconds/3600:.0f}h {(seconds%3600)/60:.0f}m" ``` - - CODE STYLE: 1-space indentation, NO COMMENTS -- [ ] Task 2.3: Integrate panel into main GUI - - WHERE: `src/gui_2.py` in `_gui_func()` method - - WHAT: Call `_render_cache_panel()` in appropriate location - - HOW: Add near token budget panel or in settings area - - SAFETY: Ensure not called during modal dialogs +## Phase 3: Manual Controls +Focus: Add cache clear button -## Phase 3: Statistics Display -Focus: Implement the visual statistics rendering - -- [ ] Task 3.1: Implement cache status display - - WHERE: `src/gui_2.py` in `_render_cache_panel()` - - WHAT: Show cache existence and age - - HOW: - - `imgui.text(f"Cache Active: {stats['cache_exists']}")` - - `imgui.text(f"Age: {format_age(stats['cache_age_seconds'])}")` - - HELPER: Create `format_age(seconds: float) -> str` helper - - CODE STYLE: 1-space indentation - -- [ ] Task 3.2: Implement TTL countdown display - - WHERE: `src/gui_2.py` in `_render_cache_panel()` - - WHAT: Show remaining TTL with percentage - - HOW: - - `remaining = stats['ttl_remaining']` - - `percentage = (remaining / stats['ttl_seconds']) * 100` - - Use `imgui.progress_bar()` for visual - - VISUAL: Warning color when percentage < 20% (use `vec4` colors defined at top of file) - -- [ ] Task 3.3: Implement requests counter (optional enhancement) - - WHERE: `src/gui_2.py` in `_render_cache_panel()` - - WHAT: Show estimated "requests while cache active" - - HOW: Add `self._cache_request_count: int = 0` state, increment on send - - SAFETY: This requires hooking into send flow - may skip if complex - -## Phase 4: Manual Controls -Focus: Implement the cache clear functionality - -- [ ] Task 4.1: Add clear cache button - - WHERE: `src/gui_2.py` in `_render_cache_panel()` - - WHAT: Button that clears the Gemini cache +- [ ] Task 3.1: Add clear cache button + - WHERE: `src/gui_2.py` `_render_cache_panel()` - HOW: ```python if imgui.button("Clear Cache"): ai_client.cleanup() - # Optionally set a flag to show "Cache cleared" message + self._cache_cleared = True + if getattr(self, '_cache_cleared', False): + imgui.text_colored(vec4(100, 255, 100, 255), "Cache cleared - will rebuild on next request") ``` - - SAFETY: `cleanup()` clears ALL caches, not just Gemini - document this -- [ ] Task 4.2: Add clear confirmation/feedback - - WHERE: `src/gui_2.py` in `_render_cache_panel()` - - WHAT: Show feedback after clear - - HOW: Add `self._cache_just_cleared: bool = False` flag, show message, auto-clear after 3s - - CODE STYLE: 1-space indentation +## Phase 4: Integration +Focus: Add panel to main GUI + +- [ ] Task 4.1: Integrate panel into layout + - WHERE: `src/gui_2.py` `_gui_func()` + - WHAT: Call `_render_cache_panel()` in settings or token budget area ## Phase 5: Testing -Focus: Verify all functionality works correctly - -- [ ] Task 5.1: Write unit tests for cache panel - - WHERE: `tests/test_cache_panel.py` (new file) - - WHAT: Test panel visibility, stats display, clear button - - HOW: Use `mock_app` or `app_instance` fixture from `conftest.py` - - PATTERN: Follow `test_gui_phase4.py` as reference - - CODE STYLE: 1-space indentation - -- [ ] Task 5.2: Write integration test with live_gui - - WHERE: `tests/test_cache_panel.py` - - WHAT: Test with actual Gemini provider (or mock) - - HOW: Use `live_gui` fixture, set provider to 'gemini', verify panel shows - - ARTIFACTS: Write to `tests/artifacts/` - -- [ ] Task 5.3: Conductor - Phase Verification - - Run targeted tests: `uv run pytest tests/test_cache_panel.py -v` - - Verify no lint errors in modified files - - Manual visual verification in GUI - -## Implementation Notes - -### Thread Safety Analysis -- `ai_client.get_gemini_cache_stats()` reads `_gemini_cache` and `_gemini_cache_created_at` -- These are set on the asyncio worker thread during `_send_gemini()` -- Reading from GUI thread is safe (atomic types) but values may be slightly stale -- No locks required for display purposes - -### Code Style Checklist -- [ ] 1-space indentation throughout -- [ ] CRLF line endings on Windows -- [ ] No comments unless explicitly documenting complex logic -- [ ] Type hints on all new functions -- [ ] Follow existing `vec4` color naming pattern - -### Files Modified -- `src/gui_2.py`: Add `_render_cache_panel()`, integrate into `_gui_func()` -- `tests/test_cache_panel.py`: New test file - -### Dependencies -- Existing: `src/ai_client.py::get_gemini_cache_stats()` -- Existing: `src/ai_client.py::cleanup()` -- Existing: `imgui_bundle::imgui` +- [ ] Task 5.1: Write unit tests +- [ ] Task 5.2: Conductor - Phase Verification diff --git a/conductor/tracks/kill_abort_workers_20260306/plan.md b/conductor/tracks/kill_abort_workers_20260306/plan.md index 0760c0c..48692e3 100644 --- a/conductor/tracks/kill_abort_workers_20260306/plan.md +++ b/conductor/tracks/kill_abort_workers_20260306/plan.md @@ -1,29 +1,66 @@ -# Implementation Plan: Kill/Abort Workers (kill_abort_workers_20260306) +# Implementation Plan: Kill/Abort Running Workers (kill_abort_workers_20260306) -## Phase 1: Kill Mechanism -- [ ] Task: Initialize MMA Environment -- [ ] Task: Add thread termination - - WHERE: src/multi_agent_conductor.py - - WHAT: Kill specific worker thread - - HOW: threading.Event or similar - - SAFETY: Clean resource release +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 2: UI Integration -- [ ] Task: Add kill buttons - - WHERE: src/gui_2.py - - WHAT: Button per worker - - HOW: In worker panel -- [ ] Task: Add confirmation dialog - - WHERE: src/gui_2.py - - WHAT: Confirm before kill - - HOW: imgui popup +## Phase 1: Thread Tracking +Focus: Track active worker threads -## Phase 3: Status Updates -- [ ] Task: Update worker status - - WHERE: src/gui_2.py - - WHAT: Reflect killed state - - HOW: Status variable +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Add worker tracking dict to ConductorEngine + - WHERE: `src/multi_agent_conductor.py` `ConductorEngine.__init__` + - WHAT: Dict to track active workers + - HOW: + ```python + self._active_workers: dict[str, threading.Thread] = {} + self._abort_events: dict[str, threading.Event] = {} + ``` -## Phase 4: Verification -- [ ] Task: Test kill functionality -- [ ] Task: Conductor - Phase Verification +## Phase 2: Abort Mechanism +Focus: Add abort signal to workers + +- [ ] Task 2.1: Create abort event per ticket + - WHERE: `src/multi_agent_conductor.py` before spawning worker + - WHAT: Create threading.Event for abort + - HOW: `self._abort_events[ticket.id] = threading.Event()` + +- [ ] Task 2.2: Check abort in worker lifecycle + - WHERE: `src/multi_agent_conductor.py` `run_worker_lifecycle()` + - WHAT: Check abort event between operations + - HOW: + ```python + abort_event = engine._abort_events.get(ticket.id) + if abort_event and abort_event.is_set(): + ticket.status = "killed" + return + ``` + +## Phase 3: Kill Button UI +Focus: Add kill button to GUI + +- [ ] Task 3.1: Add kill button per worker + - WHERE: `src/gui_2.py` MMA dashboard + - WHAT: Button to kill specific worker + - HOW: + ```python + for ticket_id, thread in engine._active_workers.items(): + if thread.is_alive(): + if imgui.button(f"Kill {ticket_id}"): + engine.kill_worker(ticket_id) + ``` + +- [ ] Task 3.2: Implement kill_worker method + - WHERE: `src/multi_agent_conductor.py` + - WHAT: Set abort event and wait for termination + - HOW: + ```python + def kill_worker(self, ticket_id: str) -> None: + if ticket_id in self._abort_events: + self._abort_events[ticket_id].set() + if ticket_id in self._active_workers: + self._active_workers[ticket_id].join(timeout=2.0) + del self._active_workers[ticket_id] + ``` + +## Phase 4: Testing +- [ ] Task 4.1: Write unit tests +- [ ] Task 4.2: Conductor - Phase Verification diff --git a/conductor/tracks/manual_block_control_20260306/plan.md b/conductor/tracks/manual_block_control_20260306/plan.md index 4dda82b..50a4f8f 100644 --- a/conductor/tracks/manual_block_control_20260306/plan.md +++ b/conductor/tracks/manual_block_control_20260306/plan.md @@ -1,32 +1,58 @@ # Implementation Plan: Manual Block/Unblock Control (manual_block_control_20260306) -## Phase 1: Block Mechanism -- [ ] Task: Initialize MMA Environment -- [ ] Task: Add manual block field - - WHERE: src/models.py - - WHAT: Add manual_block_reason to Ticket - - HOW: Optional[str] -- [ ] Task: Add block/unblock methods - - WHERE: src/models.py - - WHAT: mark_blocked, mark_unblocked - - HOW: Set/unset flag +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 2: UI Controls -- [ ] Task: Add block button - - WHERE: src/gui_2.py - - WHAT: Block selected ticket - - HOW: Button with input -- [ ] Task: Add unblock button - - WHERE: src/gui_2.py - - WHAT: Remove block - - HOW: Button +## Phase 1: Add Manual Block Fields +Focus: Add manual_block flag to Ticket -## Phase 3: Visualization -- [ ] Task: Show block status - - WHERE: src/gui_2.py - - WHAT: Visual indicator for blocked - - HOW: Different color/icon +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Add manual_block field to Ticket + - WHERE: `src/models.py` `Ticket` dataclass + - WHAT: Add `manual_block: bool = False` + - HOW: + ```python + manual_block: bool = False + ``` -## Phase 4: Verification -- [ ] Test block/unblock -- [ ] Conductor - Phase Verification +- [ ] Task 1.3: Add mark_manual_block method + - WHERE: `src/models.py` `Ticket` + - WHAT: Method to set manual block with reason + - HOW: + ```python + def mark_manual_block(self, reason: str) -> None: + self.status = "blocked" + self.blocked_reason = f"[MANUAL] {reason}" + self.manual_block = True + ``` + +## Phase 2: Block/Unblock UI +Focus: Add block buttons to ticket display + +- [ ] Task 2.1: Add block button + - WHERE: `src/gui_2.py` ticket rendering + - WHAT: Button to block with reason input + - HOW: Modal with text input for reason + +- [ ] Task 2.2: Add unblock button + - WHERE: `src/gui_2.py` ticket rendering + - WHAT: Button to clear manual block + - HOW: + ```python + if ticket.manual_block and ticket.status == "blocked": + if imgui.button("Unblock"): + ticket.status = "todo" + ticket.blocked_reason = None + ticket.manual_block = False + ``` + +## Phase 3: Cascade Integration +Focus: Trigger cascade on block/unblock + +- [ ] Task 3.1: Call cascade_blocks after manual block + - WHERE: `src/gui_2.py` or `src/multi_agent_conductor.py` + - WHAT: Update downstream tickets + - HOW: `self.dag.cascade_blocks()` + +## Phase 4: Testing +- [ ] Task 4.1: Write unit tests +- [ ] Task 4.2: Conductor - Phase Verification diff --git a/conductor/tracks/manual_skeleton_injection_20260306/plan.md b/conductor/tracks/manual_skeleton_injection_20260306/plan.md index 3bef7aa..15d2b2b 100644 --- a/conductor/tracks/manual_skeleton_injection_20260306/plan.md +++ b/conductor/tracks/manual_skeleton_injection_20260306/plan.md @@ -1,202 +1,141 @@ # Implementation Plan: Manual Skeleton Context Injection (manual_skeleton_injection_20260306) -## Phase 1: File Selection UI -- [ ] Task: Initialize MMA Environment -- [ ] Task: Implement file picker - - WHERE: src/gui_2.py - - WHAT: Browse files for skeleton - - HOW: imgui.file_picker or custom - - SAFETY: Path validation +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 2: Skeleton Preview -- [ ] Task: Generate preview - - WHERE: src/gui_2.py - - WHAT: Show skeleton before inject - - HOW: Call skeleton generation - - SAFETY: Handle large files -- [ ] Task: Implement inject button - - WHERE: src/gui_2.py - - WHAT: Inject into discussion - - HOW: Append to context +## Phase 1: UI Foundation +Focus: Add file injection button and state -## Phase 3: Full Read Option -- [ ] Task: Add full read toggle - - WHERE: src/gui_2.py - - WHAT: Option for full file - - HOW: Checkbox/switch +- [ ] Task 1.1: Initialize MMA Environment + - Run `activate_skill mma-orchestrator` before starting -## Phase 4: Verification -- [ ] Task: Test injection flow -- [ ] Task: Conductor - Phase Verification -## Phase 1: Skeleton Preview -- [ ] Task: Implement inject button - - WHERE: src/gui_2.py discussion panel - - how: Call ASTParser.get_skeleton() for preview - - Display preview - - on preview change, regenerate skeleton via `get_skeleton()` - - - Show "Skeleton" or "Full" toggle in preview - - on "Inject", append to discussion input -- [ ] Task: Add toggle logic - - where: src/gui_2.py - - how: imgui.checkbox to toggle between skeleton/full file - - On toggle change, regenerate skeleton - - else: - self._skeleton_mode = True - self._render_full_content = True - - code style: 1-space indentation -- [ ] Task: Conductor - Phase Verification - - Run targeted tests: `uv run pytest tests/test_manual_skeleton_injection.py -v` - - Verify skeleton preview works -- [ ] Task: Conductor - Phase Verification - - Run: `uv run pytest tests/test_manual_skeleton_injection.py -v` - - Verify skeleton preview works -- [ ] Task: Write unit tests for skeleton generation - - where: `tests/test_manual_skeleton_injection.py` (new file) - - what: Test extraction returns only specified functions - - how: Parse code, with regex, extract names matching `function_names` list - - return combined signatures + docstrings - - else: - return [] - - Include `@core_logic` decorator, (if present) -- [ ] Task: Write integration test - - where: `tests/test_manual_skeleton_injection.py` (new file) - - what: Test targeted extraction returns only specified functions - - how: Use existing `AST.parse via `tree_sitter_python` - - Return extracted nodes - - Also add curated view (hot paths) and - - In `run_worker_lifecycle`,: check if ticket is in context_requirements and call `get_curated_view()` for full content (hot paths). -- [ ] Task: Write integration test - - where: `tests/test_context_pruning.py` (new file) - - what: Test integration of worker lifecycle with curated context - - how: Create test file with known functions, verify they're extracted -- [ ] Task: Write integration test - - where: `tests/test_context_pruning.py` (new file) - - what: Test integration of curated view - - how: Use `aggregate.build_tier3_context()` and -- - [ ] Task: Implement performance tests - - where: `tests/test_performance_monitor.py` (new file) - - what: Test Performance monitor history storage - - how: Add `_history: deque with maxlen=100 - - in `end_frame()` store metrics -- [ ] Task: Implement graph rendering - - where: src/gui_2.py diagnostics panel - - how: Get CPU/RAM data from `performance_monitor.get_history()` - - Render graphs using imgui.plot_lines() or imgui.plot_histogram() -- [ ] Task: Conductor - Phase Verification - - Run: `uv run pytest tests/test_manual_skeleton_injection.py -v` - - Verify skeleton preview works -- [ ] Task: Write unit tests for performance dashboard - - where: `tests/test_performance_dashboard.py` (new file) - - what: Test performance dashboard - - how: Test history storage limits - - [x] Performance_monitor.add_history() if value is None: self._history = deque(maxlen=100) - self._history = data - imgui.plot_lines("CPU", data) - imgui.plot_histogram("Frame Time", data) - imgui.text("History: N points") - imgui.end() - imgui.text("Session Stats") - imgui.text(f"Total: ${self._session_cost_total:.2f}") - imgui.end_child() - - # Token timeline - time.sleep(0.5) # Check for slow operations - time.sleep(0.5) - for i, range(len(tickets): - t = t. completed - t.status = "completed" - else: - t.status = "in_progress" - - # Session stats header - if imgui.collapsing_header("Session Statistics"): - imgui.text_wrapped(f"Tokens: {sum(t['input'] + t['output']):,}") - imgui.text(f"Cost projection: ${cost_tracker.estimate_cost(t['model'], t['input'], t['output']) * 1.0:.4f}") - - # Cost projection - burn_rate = tokens_per minute * sum(t['input'] / t['output'] * 60) - time.sleep =(session - now) - projected_remaining = time = now() - remaining_time +- [ ] Task 1.2: Add injection state variables + - WHERE: `src/gui_2.py` `App.__init__` + - WHAT: State for injection UI + - HOW: + ```python + self._inject_file_path: str = "" + self._inject_mode: str = "skeleton" # "skeleton" | "full" + self._inject_preview: str = "" + self._show_inject_modal: bool = False + ``` + - CODE STYLE: 1-space indentation + +- [ ] Task 1.3: Add inject button to discussion panel + - WHERE: `src/gui_2.py` discussion panel + - WHAT: Button to open injection modal + - HOW: + ```python + if imgui.button("Inject File"): + self._show_inject_modal = True + ``` + +## Phase 2: File Selection +Focus: File picker and path validation + +- [ ] Task 2.1: Create file selection modal + - WHERE: `src/gui_2.py` + - WHAT: Modal for selecting project file + - HOW: + ```python + if self._show_inject_modal: + imgui.open_popup("Inject File") + if imgui.begin_popup_modal("Inject File"): + # File list from project files + for file_path in self.project.get("files", {}).get("paths", []): + if imgui.selectable(file_path, self._inject_file_path == file_path): + self._inject_file_path = file_path + self._update_inject_preview() + imgui.end_popup() + ``` + +- [ ] Task 2.2: Validate selected path + - WHERE: `src/gui_2.py` + - WHAT: Ensure path is within project + - HOW: Check against `files.base_dir` + +## Phase 3: Preview Generation +Focus: Generate and display skeleton/full preview + +- [ ] Task 3.1: Implement preview update function + - WHERE: `src/gui_2.py` + - WHAT: Generate preview based on mode + - HOW: + ```python + def _update_inject_preview(self) -> None: + if not self._inject_file_path: + self._inject_preview = "" + return + base_dir = self.project.get("files", {}).get("base_dir", ".") + full_path = Path(base_dir) / self._inject_file_path + try: + content = full_path.read_text(encoding="utf-8") + if self._inject_mode == "skeleton": + parser = ASTParser("python") + self._inject_preview = parser.get_skeleton(content) else: - imgui.text(f"Projected cost: ${projected_cost(t['model'], t['input'], t['output']) * 1.0:.4f}") - - imgui.end_child() - - # Efficiency Score - efficiency_score = tokens_per useful change ratio (if > 0 else 0) - efficiency_text = summary - imgui.text_wrapped(f"Efficiency Score: {efficiency_score:.2f}") - imgui.end_child() - - # Session summary - if imgui.collapsing_header("Session Summary"): - imgui.text_wrapped("## Session") - - **Total**:** tokens - - **Completed:** status: {len(completed)} tickets - - **Blocked:** tickets marked as blocked with reason: {reason} - for t_status in self.track.tickets: - if t.blocked_reason: - imgui.text_wrapped(f" Blocked: {reason}") - imgui.text(f"Tickets blocked: {len(blocked)} tickets") - imgui.end() - - # Controls - imgui.separator() - imgui.text("Controls") - - # Per-ticket block controls - imgui.combo with options: block, execute, skip - block - else: - imgui.text("Unblocked") - imgui.indent_same_indent() - - # Priority field - imgui.combo("priority", options: high/medium/low) - if imgui.begin_combo("Priority", item=0): - imgui.end_combo() - elif ticket.status == "completed": - imgui.text_wrapped(f" Completed") - elif ticket.status == "blocked": - imgui.text_wrapped(f" blocked: {reason}") - imgui.indent_same_indent() - imgui.end() - - # Footer - imgui.text_wrapped("Session Stats") - - # Tier Usage table (if imgui.begin_table("Tier Usage")) - { - imgui.table_next_row() - for tier in ["Tier 1", "Tier 2", "Tier 3", "Tier 4"]: - imgui.table_set_column_index(1) - imgui.text(f"Tier {tier}") - imgui.table_next_row() - for ticket in tickets: - imgui.text(f" {ticket.id}") - imgui.text(f" {ticket.status}") - imgui.text(f" {ticket.priority}") - imgui.text("") - imgui.end_table() - - imgui.text_wrapped(f"Session total: ${self._session_cost_total:.2f}") - imgui.end_child() - t.end_table() - - imgui.text_wrapped("## Ticket Queue Management") - imgui.text("Priority") - imgui.combo("priority", options: high/medium/low) - imgui.same_line() - imgui.text_wrapped(f" {priority}") - imgui.end() - # Drag-drop reordering - imgui.combo("Reorder", options: top/bottom/after") - imgui.text("Top") - imgui.text("Bottom") - else - imgui.text("Bulk Actions") - imgui.text("Apply to: execute/skip/block") - imgui.end_child() + self._inject_preview = content + # Truncate to 500 lines + lines = self._inject_preview.split("\n")[:500] + self._inject_preview = "\n".join(lines) + if len(lines) >= 500: + self._inject_preview += "\n... (truncated)" + except Exception as e: + self._inject_preview = f"Error reading file: {e}" + ``` + +- [ ] Task 3.2: Add mode toggle + - WHERE: `src/gui_2.py` inject modal + - WHAT: Radio buttons for skeleton/full + - HOW: + ```python + if imgui.radio_button("Skeleton", self._inject_mode == "skeleton"): + self._inject_mode = "skeleton" + self._update_inject_preview() + imgui.same_line() + if imgui.radio_button("Full File", self._inject_mode == "full"): + self._inject_mode = "full" + self._update_inject_preview() + ``` + +- [ ] Task 3.3: Display preview + - WHERE: `src/gui_2.py` inject modal + - WHAT: Scrollable preview area + - HOW: + ```python + imgui.begin_child("preview", height=300) + imgui.text_wrapped(self._inject_preview) + imgui.end_child() + ``` + +## Phase 4: Inject Action +Focus: Append to discussion input + +- [ ] Task 4.1: Implement inject button + - WHERE: `src/gui_2.py` inject modal + - WHAT: Button to inject content + - HOW: + ```python + if imgui.button("Inject"): + formatted = f"\n## File: {self._inject_file_path}\n```python\n{self._inject_preview}\n```\n" + self.ui_input_text += formatted + self._show_inject_modal = False + imgui.close_current_popup() + imgui.same_line() + if imgui.button("Cancel"): + self._show_inject_modal = False + imgui.close_current_popup() + ``` + +## Phase 5: Testing +Focus: Verify all functionality + +- [ ] Task 5.1: Write unit tests + - WHERE: `tests/test_skeleton_injection.py` (new file) + - WHAT: Test preview generation, truncation + - HOW: Create test files, verify skeleton output + +- [ ] Task 5.2: Conductor - Phase Verification + - Run: `uv run pytest tests/test_skeleton_injection.py -v` + - Manual: Verify inject modal works in GUI # Footer imgui.end_table() diff --git a/conductor/tracks/manual_skeleton_injection_20260306/spec.md b/conductor/tracks/manual_skeleton_injection_20260306/spec.md index 13baf16..714054e 100644 --- a/conductor/tracks/manual_skeleton_injection_20260306/spec.md +++ b/conductor/tracks/manual_skeleton_injection_20260306/spec.md @@ -1,36 +1,113 @@ # Track Specification: Manual Skeleton Context Injection (manual_skeleton_injection_20260306) ## Overview -Add UI controls to manually flag files for skeleton injection in discussions. Allow agent to request full file reads or specific def/class definitions on-demand. +Add UI controls to manually inject file skeletons into discussions. Allow user to preview skeleton content before sending to AI, with option to toggle between skeleton and full file. ## Current State Audit ### Already Implemented (DO NOT re-implement) -- **`file_cache.ASTParser.get_skeleton()`**: Returns Python skeleton -- **`mcp_client.py_get_skeleton()`**: MCP tool for skeleton generation -- **`aggregate.py`**: Builds file items context -### Gaps to Fill -- No UI to flag files for skeleton vs full -- No preview of skeleton before injection -- No on-demand definition lookup +#### ASTParser (src/file_cache.py) +- **`ASTParser` class**: Uses tree-sitter for Python parsing +- **`get_skeleton(code: str) -> str`**: Returns file skeleton (signatures/docstrings preserved, function bodies replaced with `...`) +- **`get_curated_view(code: str) -> str`**: Returns curated view preserving `@core_logic` and `# [HOT]` decorated function bodies + +#### MCP Tools (src/mcp_client.py) +- **`py_get_skeleton(path, language)`**: Tool #15 - generates skeleton +- **`py_get_definition(path, name)`**: Tool #18 - gets specific definition +- **Both available to AI during discussion** + +#### Context Building (src/aggregate.py) +- **`build_file_items()`**: Creates file items from project config +- **`build_tier*_context()`**: Tier-specific context builders already use skeleton logic + +### Gaps to Fill (This Track's Scope) +- No UI for manual skeleton preview/injection +- No toggle between skeleton and full file +- No inject-to-discussion button + +## Architectural Constraints + +### Non-Blocking Preview +- Skeleton generation MUST NOT block UI +- Use existing `ASTParser.get_skeleton()` - already fast (<100ms) + +### Preview Size Limit +- Truncate preview at 500 lines +- Show "... (truncated)" notice if exceeded + +## Architecture Reference + +### Key Integration Points + +| File | Lines | Purpose | +|------|-------|---------| +| `src/gui_2.py` | ~1300-1400 | Discussion panel - add injection UI | +| `src/file_cache.py` | 30-80 | `ASTParser.get_skeleton()` | +| `src/aggregate.py` | 119-145 | `build_file_items()` | + +### UI Integration Pattern +```python +# In discussion panel: +if imgui.button("Inject File"): + # Open file picker +self._inject_file_path = selected_path +self._inject_mode = "skeleton" # or "full" +# Preview in child window +preview = ASTParser("python").get_skeleton(content) if skeleton_mode else content +# Inject button appends to input text +``` ## Functional Requirements -- File picker UI in discussion panel -- Skeleton preview before injection -- Toggle: skeleton vs full file -- Uses existing `py_get_skeleton()` tool -## Key Integration Points -| File | Purpose | -|-----|---------| -| `src/gui_2.py` | File picker, injection UI | -| `src/mcp_client.py` | `py_get_skeleton()` | -| `src/file_cache.py` | `ASTParser` | +### FR1: File Selection +- Button "Inject File" in discussion panel +- Opens file browser limited to project files +- Path validation against project's `files.base_dir` + +### FR2: Mode Toggle +- Radio buttons: "Skeleton" / "Full File" +- Default: Skeleton +- Switching regenerates preview + +### FR3: Preview Display +- Child window showing preview content +- Monospace font +- Scrollable, max 500 lines displayed +- Line numbers optional + +### FR4: Inject Action +- Button "Inject to Discussion" +- Appends content to input text area +- Format: `## File: {path}\n\`\`\`python\n{content}\n\`\`\`` + +## Non-Functional Requirements + +| Requirement | Constraint | +|-------------|------------| +| Preview Time | <100ms for typical file | +| Memory | Preview limited to 50KB | + +## Testing Requirements + +### Unit Tests +- Test skeleton generation for sample files +- Test truncation at 500 lines + +### Integration Tests +- Inject file, verify appears in discussion +- Toggle modes, verify preview updates + +## Out of Scope +- Definition lookup (separate track: on_demand_def_lookup) +- Multi-file injection +- Custom skeleton configuration ## Acceptance Criteria -- [ ] File picker UI functional -- [ ] Skeleton preview displays -- [ ] Manual refresh button works -- [ ] Full read option available -- [ ] 1-space indentation +- [ ] "Inject File" button in discussion panel +- [ ] File browser limits to project files +- [ ] Skeleton/Full toggle works +- [ ] Preview displays correctly +- [ ] Inject appends to input +- [ ] Large file truncation works +- [ ] 1-space indentation maintained diff --git a/conductor/tracks/mma_multiworker_viz_20260306/plan.md b/conductor/tracks/mma_multiworker_viz_20260306/plan.md index 1a1ee13..2eb27f2 100644 --- a/conductor/tracks/mma_multiworker_viz_20260306/plan.md +++ b/conductor/tracks/mma_multiworker_viz_20260306/plan.md @@ -1,31 +1,63 @@ # Implementation Plan: MMA Multi-Worker Visualization (mma_multiworker_viz_20260306) -## Phase 1: Layout Design -- [ ] Task: Initialize MMA Environment -- [ ] Task: Design multi-pane layout - - WHERE: src/gui_2.py - - WHAT: Split view for workers - - HOW: imgui.columns or child windows - - SAFETY: Handle 0 workers +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 2: Worker Tracking -- [ ] Task: Track worker status - - WHERE: src/multi_agent_conductor.py - - WHAT: Per-worker status - - HOW: Dictionary of worker states - - SAFETY: Thread-safe updates +## Phase 1: Stream Structure Enhancement +Focus: Extend existing mma_streams for per-worker tracking -## Phase 3: Controls -- [ ] Task: Add kill buttons - - WHERE: src/gui_2.py - - WHAT: Button per worker to kill - - HOW: Signal worker thread - - SAFETY: Graceful termination -- [ ] Task: Add restart buttons - - WHERE: src/gui_2.py - - WHAT: Respawn killed worker - - HOW: Re-submit ticket +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Review existing mma_streams structure + - WHERE: `src/app_controller.py` line 142 + - WHAT: Current is `Dict[str, str]` - stream_id -> accumulated text + - NOTE: Keep this structure, add per-worker metadata separately -## Phase 4: Verification -- [ ] Task: Test multi-worker display -- [ ] Task: Conductor - Phase Verification +## Phase 2: Worker Status Tracking +Focus: Track worker status separately + +- [ ] Task 2.1: Add worker status dict + - WHERE: `src/app_controller.py` + - WHAT: Track status per worker + - HOW: + ```python + self._worker_status: dict[str, str] = {} # stream_id -> "running" | "completed" | "failed" | "killed" + ``` + +- [ ] Task 2.2: Update status on worker events + - WHERE: `src/app_controller.py` `_process_pending_gui_tasks()` + - WHAT: Update status based on mma events + - HOW: On "response" event, set status to "completed" + +## Phase 3: Multi-Pane Display +Focus: Display all active streams + +- [ ] Task 3.1: Iterate all Tier 3 streams + - WHERE: `src/gui_2.py` `_render_tier_stream_panel()` + - WHAT: Show all workers in split view + - HOW: + ```python + tier3_keys = [k for k in self.mma_streams if "Tier 3" in k] + for key in tier3_keys: + status = self._worker_status.get(key, "unknown") + imgui.text(f"{key}: {status}") + if imgui.begin_child(f"stream_{key}", height=150): + imgui.text_wrapped(self.mma_streams.get(key, "")) + imgui.end_child() + ``` + +## Phase 4: Stream Pruning +Focus: Limit memory per stream + +- [ ] Task 4.1: Prune stream on append + - WHERE: `src/app_controller.py` stream append logic + - WHAT: Limit to 10KB per stream + - HOW: + ```python + MAX_STREAM_SIZE = 10 * 1024 + self.mma_streams[stream_id] += text + if len(self.mma_streams[stream_id]) > MAX_STREAM_SIZE: + self.mma_streams[stream_id] = self.mma_streams[stream_id][-MAX_STREAM_SIZE:] + ``` + +## Phase 5: Testing +- [ ] Task 5.1: Write unit tests +- [ ] Task 5.2: Conductor - Phase Verification diff --git a/conductor/tracks/native_orchestrator_20260306/plan.md b/conductor/tracks/native_orchestrator_20260306/plan.md index 682e28e..fabc234 100644 --- a/conductor/tracks/native_orchestrator_20260306/plan.md +++ b/conductor/tracks/native_orchestrator_20260306/plan.md @@ -1,27 +1,107 @@ # Implementation Plan: Native Orchestrator (native_orchestrator_20260306) +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) + ## Phase 1: Plan File Operations -- [ ] Task: Initialize MMA Environment -- [ ] Task: Implement plan.md read/write - - WHERE: src/orchestrator_pm.py or new module - - WHAT: Parse and write plan.md - - HOW: toml/tomllib for parsing - - SAFETY: Preserve formatting +Focus: Native plan.md read/write -## Phase 2: Metadata Management -- [ ] Task: Implement metadata.json operations - - WHERE: src/orchestrator_pm.py - - WHAT: Read/write track metadata - - HOW: json load/dump - - SAFETY: Atomic writes +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Implement read_plan function + - WHERE: `src/orchestrator_pm.py` or new `src/native_orchestrator.py` + - WHAT: Parse plan.md content + - HOW: + ```python + def read_plan(track_id: str, base_dir: str = ".") -> str: + plan_path = Path(base_dir) / "conductor" / "tracks" / track_id / "plan.md" + if not plan_path.exists(): + return "" + return plan_path.read_text(encoding="utf-8") + ``` -## Phase 3: Tier Delegation -- [ ] Task: Implement in-process delegation - - WHERE: src/multi_agent_conductor.py - - WHAT: Replace subprocess calls with direct function calls - - HOW: Import and call tier functions directly - - SAFETY: Proper error propagation +- [ ] Task 1.3: Implement write_plan function + - WHERE: Same as above + - WHAT: Write plan.md content + - HOW: + ```python + def write_plan(track_id: str, content: str, base_dir: str = ".") -> None: + plan_path = Path(base_dir) / "conductor" / "tracks" / track_id / "plan.md" + plan_path.parent.mkdir(parents=True, exist_ok=True) + plan_path.write_text(content, encoding="utf-8") + ``` -## Phase 4: Verification -- [ ] Task: Test plan operations -- [ ] Task: Conductor - Phase Verification +- [ ] Task 1.4: Parse task checkboxes + - WHERE: Same as above + - WHAT: Extract task status from plan + - HOW: + ```python + def parse_plan_tasks(content: str) -> list[dict]: + tasks = [] + for line in content.split("\n"): + if line.strip().startswith("- ["): + checked = "[x]" in line + tasks.append({"text": line, "completed": checked}) + return tasks + ``` + +## Phase 2: Metadata Operations +Focus: Native metadata.json management + +- [ ] Task 2.1: Implement read_metadata + - WHERE: Same as above + - HOW: + ```python + def read_metadata(track_id: str, base_dir: str = ".") -> dict: + meta_path = Path(base_dir) / "conductor" / "tracks" / track_id / "metadata.json" + if not meta_path.exists(): + return {} + return json.loads(meta_path.read_text(encoding="utf-8")) + ``` + +- [ ] Task 2.2: Implement write_metadata + - WHERE: Same as above + - HOW: + ```python + def write_metadata(track_id: str, data: dict, base_dir: str = ".") -> None: + meta_path = Path(base_dir) / "conductor" / "tracks" / track_id / "metadata.json" + meta_path.parent.mkdir(parents=True, exist_ok=True) + meta_path.write_text(json.dumps(data, indent=2), encoding="utf-8") + ``` + +## Phase 3: In-Process Tier Delegation +Focus: Replace subprocess calls with direct function calls + +- [ ] Task 3.1: Create NativeOrchestrator class + - WHERE: `src/native_orchestrator.py` (new file) + - WHAT: Class with tier methods + - HOW: + ```python + class NativeOrchestrator: + def __init__(self, base_dir: str = "."): + self.base_dir = Path(base_dir) + + def generate_tickets(self, brief: str) -> list[Ticket]: + return conductor_tech_lead.generate_tickets(brief, ...) + + def execute_ticket(self, ticket: Ticket, context: str) -> str: + return ai_client.send(context, ticket.description, ...) + + def analyze_error(self, error: str) -> str: + return ai_client.run_tier4_analysis(error) + ``` + +- [ ] Task 3.2: Integrate with ConductorEngine + - WHERE: `src/multi_agent_conductor.py` + - WHAT: Use NativeOrchestrator instead of subprocess + - HOW: Import and call methods directly + +## Phase 4: CLI Fallback +Focus: Maintain mma_exec.py compatibility + +- [ ] Task 4.1: Update mma_exec.py to use NativeOrchestrator + - WHERE: `scripts/mma_exec.py` + - WHAT: Thin wrapper around native module + - HOW: Import NativeOrchestrator and call methods + +## Phase 5: Testing +- [ ] Task 5.1: Write unit tests +- [ ] Task 5.2: Conductor - Phase Verification diff --git a/conductor/tracks/on_demand_def_lookup_20260306/plan.md b/conductor/tracks/on_demand_def_lookup_20260306/plan.md index 7ea3fb1..fba315e 100644 --- a/conductor/tracks/on_demand_def_lookup_20260306/plan.md +++ b/conductor/tracks/on_demand_def_lookup_20260306/plan.md @@ -1,30 +1,67 @@ # Implementation Plan: On-Demand Definition Lookup (on_demand_def_lookup_20260306) +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) + ## Phase 1: Symbol Parsing -- [ ] Task: Initialize MMA Environment -- [ ] Task: Implement @syntax parsing - - WHERE: src/gui_2.py - - WHAT: Detect @symbol in input - - HOW: Regex or string match - - SAFETY: Handle edge cases +Focus: Parse @symbol syntax from user input + +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Implement @symbol regex parser + - WHERE: `src/gui_2.py` in `_send_callback()` + - WHAT: Extract @SymbolName patterns + - HOW: + ```python + import re + def parse_symbols(text: str) -> list[str]: + return re.findall(r'@(\w+(?:\.\w+)*)', text) + ``` ## Phase 2: Definition Retrieval -- [ ] Task: Integrate py_get_definition - - WHERE: src/gui_2.py - - WHAT: Get definition from outline_tool - - HOW: Call existing function - - SAFETY: Handle not found +Focus: Use existing MCP tool to get definitions + +- [ ] Task 2.1: Integrate py_get_definition + - WHERE: `src/gui_2.py` + - WHAT: Call MCP tool for each symbol + - HOW: + ```python + from src import mcp_client + def get_symbol_definition(symbol: str, files: list[str]) -> tuple[str, str] | None: + for file_path in files: + result = mcp_client.py_get_definition(file_path, symbol) + if result and "not found" not in result.lower(): + return (file_path, result) + return None + ``` ## Phase 3: Inline Display -- [ ] Task: Render inline - - WHERE: src/gui_2.py - - WHAT: Show definition in discussion - - HOW: imgui.text with formatting -- [ ] Task: Implement navigation - - WHERE: src/gui_2.py - - WHAT: Click to jump to source - - HOW: Store file/line refs +Focus: Display definition in discussion -## Phase 4: Verification -- [ ] Task: Test lookup flow -- [ ] Task: Conductor - Phase Verification +- [ ] Task 3.1: Inject definition as context + - WHERE: `src/gui_2.py` `_send_callback()` + - WHAT: Append definition to message + - HOW: + ```python + symbols = parse_symbols(user_message) + for symbol in symbols: + result = get_symbol_definition(symbol, self.project_files) + if result: + file_path, definition = result + user_message += f"\n\n[Definition: {symbol} from {file_path}]\n```python\n{definition}\n```" + ``` + +## Phase 4: Click Navigation +Focus: Allow clicking definition to open file + +- [ ] Task 4.1: Store file/line metadata with definition + - WHERE: Discussion entry structure + - WHAT: Track source location + - HOW: Add to discussion entry dict + +- [ ] Task 4.2: Add click handler + - WHERE: `src/gui_2.py` discussion rendering + - WHAT: On click, scroll to definition + - HOW: Use selectable text with callback + +## Phase 5: Testing +- [ ] Task 5.1: Write unit tests for parsing +- [ ] Task 5.2: Conductor - Phase Verification diff --git a/conductor/tracks/per_ticket_model_20260306/plan.md b/conductor/tracks/per_ticket_model_20260306/plan.md index 6c38d49..5858cb2 100644 --- a/conductor/tracks/per_ticket_model_20260306/plan.md +++ b/conductor/tracks/per_ticket_model_20260306/plan.md @@ -1,32 +1,82 @@ # Implementation Plan: Per-Ticket Model Override (per_ticket_model_20260306) -## Phase 1: Model Field -- [ ] Task: Initialize MMA Environment -- [ ] Task: Add override field - - WHERE: src/models.py - - WHAT: model_override on Ticket - - HOW: Optional[str] -- [ ] Task: Update ticket creation - - WHERE: src/conductor_tech_lead.py - - WHAT: Pass override to ticket - - HOW: Include in ticket dict +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 2: UI Controls -- [ ] Task: Add model dropdown - - WHERE: src/gui_2.py - - WHAT: Select model per ticket - - HOW: imgui.combo with model list -- [ ] Task: Add override indicator - - WHERE: src/gui_2.py - - WHAT: Show override is active - - HOW: Different style +## Phase 1: Model Override Field +Focus: Add field to Ticket dataclass -## Phase 3: Execution Integration -- [ ] Task: Use override at runtime - - WHERE: src/multi_agent_conductor.py +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Add model_override to Ticket + - WHERE: `src/models.py` `Ticket` dataclass + - WHAT: Add optional model override field + - HOW: + ```python + @dataclass + class Ticket: + # ... existing fields ... + model_override: Optional[str] = None + ``` + +- [ ] Task 1.3: Update serialization + - WHERE: `src/models.py` `Ticket.to_dict()` and `from_dict()` + - WHAT: Include model_override + - HOW: Add field to dict conversion + +## Phase 2: Model Dropdown UI +Focus: Add model selection to ticket display + +- [ ] Task 2.1: Get available models list + - WHERE: `src/gui_2.py` or from cost_tracker + - WHAT: List of available models + - HOW: + ```python + AVAILABLE_MODELS = ["gemini-2.5-flash-lite", "gemini-2.5-flash", "gemini-3.1-pro-preview", "claude-3-5-sonnet", "deepseek-v3"] + ``` + +- [ ] Task 2.2: Add dropdown to ticket UI + - WHERE: `src/gui_2.py` ticket rendering + - WHAT: Combo for model selection + - HOW: + ```python + current_model = ticket.model_override or "Default" + if imgui.begin_combo("Model", current_model): + if imgui.selectable("Default", ticket.model_override is None): + ticket.model_override = None + for model in AVAILABLE_MODELS: + if imgui.selectable(model, ticket.model_override == model): + ticket.model_override = model + imgui.end_combo() + ``` + +## Phase 3: Visual Indicator +Focus: Show when override is active + +- [ ] Task 3.1: Color-code override tickets + - WHERE: `src/gui_2.py` ticket rendering + - WHAT: Visual distinction for override + - HOW: + ```python + if ticket.model_override: + imgui.text_colored(vec4(255, 200, 100, 255), f"[{ticket.model_override}]") + ``` + +## Phase 4: Execution Integration +Focus: Use override in worker execution + +- [ ] Task 4.1: Check override in ConductorEngine.run() + - WHERE: `src/multi_agent_conductor.py` `run()` - WHAT: Use ticket.model_override if set - - HOW: Check and apply + - HOW: + ```python + if ticket.model_override: + model_name = ticket.model_override + else: + # Use existing escalation logic + models = ["gemini-2.5-flash-lite", "gemini-2.5-flash", "gemini-3.1-pro-preview"] + model_idx = min(ticket.retry_count, len(models) - 1) + model_name = models[model_idx] + ``` -## Phase 4: Verification -- [ ] Test override works -- [ ] Conductor - Phase Verification +## Phase 5: Testing +- [ ] Task 5.1: Write unit tests +- [ ] Task 5.2: Conductor - Phase Verification diff --git a/conductor/tracks/performance_dashboard_20260306/plan.md b/conductor/tracks/performance_dashboard_20260306/plan.md index 2c74fe3..0feaf5c 100644 --- a/conductor/tracks/performance_dashboard_20260306/plan.md +++ b/conductor/tracks/performance_dashboard_20260306/plan.md @@ -1,26 +1,87 @@ # Implementation Plan: Performance Dashboard (performance_dashboard_20260306) -## Phase 1: Metrics Collection -- [ ] Task: Initialize MMA Environment -- [ ] Task: Verify performance_monitor - - WHERE: src/performance_monitor.py - - WHAT: Check existing metrics - - HOW: Review get_metrics() output +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 2: Historical Data -- [ ] Task: Implement metrics history - - WHERE: src/performance_monitor.py +## Phase 1: Historical Data Storage +Focus: Add history buffer to PerformanceMonitor + +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Add history deque to PerformanceMonitor + - WHERE: `src/performance_monitor.py` `PerformanceMonitor.__init__` - WHAT: Rolling window of metrics - - HOW: deque with maxlen - - SAFETY: Memory bounded + - HOW: + ```python + from collections import deque + self._history: deque = deque(maxlen=100) + ``` -## Phase 3: Visualization -- [ ] Task: Render graphs - - WHERE: src/gui_2.py - - WHAT: Line graphs for CPU/RAM/frame time - - HOW: imgui.plot_lines or custom - - SAFETY: 60fps during rendering +- [ ] Task 1.3: Store metrics each frame + - WHERE: `src/performance_monitor.py` `end_frame()` + - WHAT: Append current metrics to history + - HOW: + ```python + def end_frame(self) -> None: + # ... existing code ... + self._history.append({ + "fps": self._fps, "frame_time_ms": self._frame_time_ms, + "cpu_percent": self._cpu_percent, "input_lag_ms": self._input_lag_ms + }) + ``` -## Phase 4: Verification -- [ ] Task: Test graph rendering -- [ ] Task: Conductor - Phase Verification +- [ ] Task 1.4: Add get_history method + - WHERE: `src/performance_monitor.py` + - HOW: + ```python + def get_history(self) -> list[dict]: + return list(self._history) + ``` + +## Phase 2: CPU Graph +Focus: Render CPU usage over time + +- [ ] Task 2.1: Extract CPU values from history + - WHERE: `src/gui_2.py` diagnostics panel + - WHAT: Get CPU% array for plotting + - HOW: + ```python + history = self.perf_monitor.get_history() + cpu_values = [h["cpu_percent"] for h in history] + ``` + +- [ ] Task 2.2: Render line graph + - WHERE: `src/gui_2.py` + - WHAT: imgui.plot_lines for CPU + - HOW: + ```python + if imgui.collapsing_header("CPU Usage"): + imgui.plot_lines("##cpu", cpu_values, scale_min=0, scale_max=100) + imgui.text(f"Current: {cpu_values[-1]:.1f}%" if cpu_values else "N/A") + ``` + +## Phase 3: Frame Time Histogram +Focus: Show frame time distribution + +- [ ] Task 3.1: Bucket frame times + - WHERE: `src/gui_2.py` + - WHAT: Categorize into 0-16ms, 16-33ms, 33+ms + - HOW: + ```python + buckets = [0, 0, 0] # <16ms, 16-33ms, 33+ms + for h in history: + ft = h["frame_time_ms"] + if ft < 16: buckets[0] += 1 + elif ft < 33: buckets[1] += 1 + else: buckets[2] += 1 + ``` + +- [ ] Task 3.2: Render histogram + - WHERE: `src/gui_2.py` + - HOW: + ```python + imgui.plot_histogram("##frametime", buckets) + imgui.text("<16ms: {} 16-33ms: {} >33ms: {}".format(*buckets)) + ``` + +## Phase 4: Testing +- [ ] Task 4.1: Write unit tests +- [ ] Task 4.2: Conductor - Phase Verification diff --git a/conductor/tracks/pipeline_pause_resume_20260306/plan.md b/conductor/tracks/pipeline_pause_resume_20260306/plan.md index e1cf264..dc91de9 100644 --- a/conductor/tracks/pipeline_pause_resume_20260306/plan.md +++ b/conductor/tracks/pipeline_pause_resume_20260306/plan.md @@ -1,32 +1,68 @@ # Implementation Plan: Pipeline Pause/Resume (pipeline_pause_resume_20260306) +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) + ## Phase 1: Pause Mechanism -- [ ] Task: Initialize MMA Environment -- [ ] Task: Add pause state - - WHERE: src/multi_agent_conductor.py - - WHAT: Global pause flag - - HOW: threading.Event -- [ ] Task: Implement pause - - WHERE: src/multi_agent_conductor.py - - WHAT: Stop worker spawning - - HOW: Check pause flag +Focus: Add pause event to ConductorEngine -## Phase 2: Resume Mechanism -- [ ] Task: Implement resume - - WHERE: src/multi_agent_conductor.py - - WHAT: Continue from pause - - HOW: Clear flag, restart workers +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Add pause event to ConductorEngine + - WHERE: `src/multi_agent_conductor.py` `ConductorEngine.__init__` + - WHAT: Threading event for pause control + - HOW: + ```python + self._pause_event: threading.Event = threading.Event() + ``` -## Phase 3: UI -- [ ] Task: Add pause button - - WHERE: src/gui_2.py - - WHAT: Toggle pause state - - HOW: imgui.button -- [ ] Task: Add visual indicator - - WHERE: src/gui_2.py - - WHAT: Show paused status - - HOW: Banner or icon +- [ ] Task 1.3: Check pause in run loop + - WHERE: `src/multi_agent_conductor.py` `run()` + - WHAT: Wait while paused + - HOW: + ```python + while True: + if self._pause_event.is_set(): + time.sleep(0.5) + continue + # Normal processing... + ``` -## Phase 4: Verification -- [ ] Test pause/resume -- [ ] Conductor - Phase Verification +## Phase 2: Pause/Resume Methods +Focus: Add control methods + +- [ ] Task 2.1: Add pause method + - WHERE: `src/multi_agent_conductor.py` + - HOW: `self._pause_event.set()` + +- [ ] Task 2.2: Add resume method + - WHERE: `src/multi_agent_conductor.py` + - HOW: `self._pause_event.clear()` + +## Phase 3: UI Controls +Focus: Add pause/resume buttons + +- [ ] Task 3.1: Add pause/resume button + - WHERE: `src/gui_2.py` MMA dashboard + - WHAT: Toggle button for pause state + - HOW: + ```python + is_paused = engine._pause_event.is_set() + label = "Resume" if is_paused else "Pause" + if imgui.button(label): + if is_paused: + engine.resume() + else: + engine.pause() + ``` + +- [ ] Task 3.2: Add visual indicator + - WHERE: `src/gui_2.py` + - WHAT: Banner or color when paused + - HOW: + ```python + if engine._pause_event.is_set(): + imgui.text_colored(vec4(255, 200, 100, 255), "PIPELINE PAUSED") + ``` + +## Phase 4: Testing +- [ ] Task 4.1: Write unit tests +- [ ] Task 4.2: Conductor - Phase Verification diff --git a/conductor/tracks/session_insights_20260306/plan.md b/conductor/tracks/session_insights_20260306/plan.md index e666a10..248d60b 100644 --- a/conductor/tracks/session_insights_20260306/plan.md +++ b/conductor/tracks/session_insights_20260306/plan.md @@ -1,28 +1,94 @@ # Implementation Plan: Session Insights (session_insights_20260306) -## Phase 1: Session Data -- [ ] Task: Initialize MMA Environment -- [ ] Task: Review session_logger - - WHERE: src/session_logger.py - - WHAT: Check existing data +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 2: Metrics Calculation -- [ ] Task: Implement token timeline - - WHERE: src/gui_2.py - - WHAT: Token usage over time - - HOW: Graph from history -- [ ] Task: Implement cost projection - - WHERE: src/gui_2.py - - WHAT: Estimate remaining budget - - HOW: Linear extrapolation +## Phase 1: Token Timeline Data +Focus: Collect token usage over session -## Phase 3: UI -- [ ] Task: Render insights panel - - WHERE: src/gui_2.py - - WHAT: Timeline, projection, summary - - HOW: imgui widgets - - SAFETY: Handle zero session +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Add token history state + - WHERE: `src/gui_2.py` or `src/app_controller.py` + - WHAT: Track tokens per API call + - HOW: + ```python + self._token_history: list[dict] = [] # [{"time": t, "input": n, "output": n, "model": s}, ...] + ``` -## Phase 4: Verification -- [ ] Task: Test insights -- [ ] Task: Conductor - Phase Verification +- [ ] Task 1.3: Record on each API response + - WHERE: `src/gui_2.py` in response handler + - WHAT: Append to history + - HOW: + ```python + # After API call + self._token_history.append({ + "time": time.time(), "input": input_tokens, "output": output_tokens, "model": model + }) + ``` + +## Phase 2: Token Timeline Visualization +Focus: Render token usage graph + +- [ ] Task 2.1: Extract cumulative tokens + - WHERE: `src/gui_2.py` + - WHAT: Calculate running totals + - HOW: + ```python + cumulative_input = 0 + cumulative_output = 0 + input_values = [] + output_values = [] + for entry in self._token_history: + cumulative_input += entry["input"] + cumulative_output += entry["output"] + input_values.append(cumulative_input) + output_values.append(cumulative_output) + ``` + +- [ ] Task 2.2: Render timeline + - WHERE: `src/gui_2.py` session insights panel + - HOW: + ```python + if imgui.collapsing_header("Token Timeline"): + imgui.plot_lines("Input", input_values) + imgui.plot_lines("Output", output_values) + imgui.text(f"Total: {cumulative_input + cumulative_output:,} tokens") + ``` + +## Phase 3: Cost Projection +Focus: Estimate remaining cost + +- [ ] Task 3.1: Calculate burn rate + - WHERE: `src/gui_2.py` + - WHAT: Tokens per minute + - HOW: + ```python + if len(self._token_history) >= 2: + elapsed = self._token_history[-1]["time"] - self._token_history[0]["time"] + total_tokens = sum(e["input"] + e["output"] for e in self._token_history) + burn_rate = total_tokens / (elapsed / 60) if elapsed > 0 else 0 + ``` + +- [ ] Task 3.2: Display projection + - WHERE: `src/gui_2.py` + - HOW: + ```python + imgui.text(f"Burn rate: {burn_rate:.0f} tokens/min") + imgui.text(f"Session cost: ${session_cost:.4f}") + ``` + +## Phase 4: Efficiency Score +Focus: Calculate tokens per useful change + +- [ ] Task 4.1: Define efficiency metric + - WHERE: `src/gui_2.py` + - WHAT: Ratio of tokens to completed tickets + - HOW: + ```python + completed_tickets = sum(1 for t in self.track.tickets if t.status == "completed") + total_tokens = sum(e["input"] + e["output"] for e in self._token_history) + efficiency = total_tokens / completed_tickets if completed_tickets > 0 else 0 + ``` + +## Phase 5: Testing +- [ ] Task 5.1: Write unit tests +- [ ] Task 5.2: Conductor - Phase Verification diff --git a/conductor/tracks/ticket_queue_mgmt_20260306/plan.md b/conductor/tracks/ticket_queue_mgmt_20260306/plan.md index 908ffe4..00c8775 100644 --- a/conductor/tracks/ticket_queue_mgmt_20260306/plan.md +++ b/conductor/tracks/ticket_queue_mgmt_20260306/plan.md @@ -1,33 +1,131 @@ # Implementation Plan: Manual Ticket Queue Management (ticket_queue_mgmt_20260306) -## Phase 1: UI Framework -- [ ] Task: Initialize MMA Environment -- [ ] Task: Add drag-drop support - - WHERE: src/gui_2.py - - WHAT: Enable ticket reordering via drag - - HOW: imgui drag-drop or custom handling - - SAFETY: Validate after drop +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 2: Priority System -- [ ] Task: Add priority field - - WHERE: src/models.py - - WHAT: Add priority to Ticket - - HOW: Enum (high/med/low) -- [ ] Task: Add priority UI - - WHERE: src/gui_2.py - - WHAT: Dropdown or buttons - - HOW: imgui.combo +## Phase 1: Priority Field +Focus: Add priority to Ticket model -## Phase 3: Bulk Operations -- [ ] Task: Implement multi-select - - WHERE: src/gui_2.py - - WHAT: Checkbox per ticket - - HOW: imgui.checkbox -- [ ] Task: Implement bulk actions - - WHERE: src/gui_2.py - - WHAT: Execute/skip/block buttons - - HOW: Apply to selected +- [ ] Task 1.1: Initialize MMA Environment + - Run `activate_skill mma-orchestrator` before starting -## Phase 4: Verification -- [ ] Task: Test operations -- [ ] Task: Conductor - Phase Verification +- [ ] Task 1.2: Add priority field to Ticket + - WHERE: `src/models.py` `Ticket` dataclass + - WHAT: Add `priority: str = "medium"` field + - HOW: + ```python + @dataclass + class Ticket: + # ... existing fields ... + priority: str = "medium" # "high" | "medium" | "low" + ``` + - CODE STYLE: 1-space indentation + +- [ ] Task 1.3: Update Ticket serialization + - WHERE: `src/models.py` `Ticket.to_dict()` and `from_dict()` + - WHAT: Include priority in serialization + - HOW: Add `priority` to dict conversion + +## Phase 2: Priority UI +Focus: Add priority dropdown to ticket display + +- [ ] Task 2.1: Add priority dropdown + - WHERE: `src/gui_2.py` ticket rendering + - WHAT: Dropdown for priority selection + - HOW: + ```python + priorities = ["high", "medium", "low"] + current_idx = priorities.index(ticket.priority) if ticket.priority in priorities else 1 + if imgui.begin_combo("Priority", priorities[current_idx]): + for i, p in enumerate(priorities): + if imgui.selectable(p, i == current_idx): + ticket.priority = p + imgui.end_combo() + ``` + +- [ ] Task 2.2: Add color coding + - WHERE: `src/gui_2.py` ticket rendering + - WHAT: Color-code priority display + - HOW: + ```python + priority_colors = {"high": vec4(255, 100, 100, 255), "medium": vec4(255, 200, 100, 255), "low": vec4(150, 150, 150, 255)} + imgui.text_colored(priority_colors.get(ticket.priority, vec4(200, 200, 200, 255)), f"[{ticket.priority.upper()}]") + ``` + +## Phase 3: Multi-Select +Focus: Enable ticket selection for bulk operations + +- [ ] Task 3.1: Add selection state + - WHERE: `src/gui_2.py` or `src/app_controller.py` + - WHAT: Track selected ticket IDs + - HOW: + ```python + self._selected_tickets: set[str] = set() + ``` + +- [ ] Task 3.2: Add checkbox per ticket + - WHERE: `src/gui_2.py` ticket list rendering + - WHAT: Checkbox for selection + - HOW: + ```python + selected = ticket.id in self._selected_tickets + if imgui.checkbox(f"##select_{ticket.id}", selected): + if selected: + self._selected_tickets.discard(ticket.id) + else: + self._selected_tickets.add(ticket.id) + imgui.same_line() + ``` + +- [ ] Task 3.3: Add select all/none buttons + - WHERE: `src/gui_2.py` ticket list header + - WHAT: Buttons to select/deselect all + - HOW: + ```python + if imgui.button("Select All"): + self._selected_tickets = {t.id for t in self.track.tickets} + imgui.same_line() + if imgui.button("Select None"): + self._selected_tickets.clear() + ``` + +## Phase 4: Bulk Actions +Focus: Execute bulk operations on selected tickets + +- [ ] Task 4.1: Add bulk action buttons + - WHERE: `src/gui_2.py` ticket list area + - WHAT: Execute, Skip, Block buttons + - HOW: + ```python + if imgui.button("Bulk Execute"): + for tid in self._selected_tickets: + self.engine.approve_task(tid) + imgui.same_line() + if imgui.button("Bulk Skip"): + for tid in self._selected_tickets: + self.engine.update_task_status(tid, "completed") + imgui.same_line() + if imgui.button("Bulk Block"): + for tid in self._selected_tickets: + self.engine.update_task_status(tid, "blocked") + ``` + +## Phase 5: Drag-Drop (Optional) +Focus: Allow ticket reordering + +- [ ] Task 5.1: Implement drag-drop reordering + - WHERE: `src/gui_2.py` ticket list + - WHAT: Drag tickets to reorder + - HOW: Use imgui drag-drop API + - SAFETY: Validate DAG after reorder (no dependency violations) + +## Phase 6: Testing +Focus: Verify all functionality + +- [ ] Task 6.1: Write unit tests + - WHERE: `tests/test_ticket_queue.py` (new file) + - WHAT: Test priority serialization, bulk operations + - HOW: Create mock tickets, verify state changes + +- [ ] Task 6.2: Conductor - Phase Verification + - Run: `uv run pytest tests/test_ticket_queue.py -v` + - Manual: Verify UI controls work diff --git a/conductor/tracks/ticket_queue_mgmt_20260306/spec.md b/conductor/tracks/ticket_queue_mgmt_20260306/spec.md index 8e68733..d311b7e 100644 --- a/conductor/tracks/ticket_queue_mgmt_20260306/spec.md +++ b/conductor/tracks/ticket_queue_mgmt_20260306/spec.md @@ -1,41 +1,112 @@ # Track Specification: Manual Ticket Queue Management (ticket_queue_mgmt_20260306) ## Overview -Allow user to manually reorder, prioritize, or requeue tickets. Add drag-drop, priority tags, bulk selection. +Allow user to manually reorder, prioritize, or requeue tickets in the DAG. Add drag-drop reordering, priority tags, and bulk selection for execute/skip/block operations. ## Current State Audit -### Already Implemented -- **`models.Ticket`**: No priority field -- **`dag_engine.py`**: `get_ready_tasks()` returns in order -- **GUI**: Linear ticket list display +### Already Implemented (DO NOT re-implement) -### Gaps to Fill -- No priority field on Ticket -- No drag-drop reordering -- No bulk selection/operations +#### Ticket Model (src/models.py) +- **`Ticket` dataclass**: Has `status`, `depends_on`, but no `priority` field +- **`mark_blocked(reason)`**: Sets status to blocked with reason +- **`mark_complete()`**: Sets status to completed -## Functional Requirements -- Add `priority: str = "medium"` to Ticket (high/medium/low) -- Drag-drop reordering in ticket list -- Multi-select for bulk operations -- Bulk execute/skip/block +#### DAG Engine (src/dag_engine.py) +- **`TrackDAG`**: Manages ticket dependency graph +- **`get_ready_tasks()`**: Returns tasks with satisfied dependencies +- **`update_task_status()`**: Updates ticket status +- **`has_cycle()`**: Validates DAG -## Key Integration Points -| File | Purpose | -|-----|---------| -| `src/models.py` | Add priority field | -| `src/gui_2.py` | Drag-drop, bulk UI | -| `src/dag_engine.py` | Priority-aware ordering | +### Gaps to Fill (This Track's Scope) +- No `priority` field on Ticket +- No drag-drop reordering in GUI +- No multi-select for bulk operations +- No bulk execute/skip/block actions ## Architectural Constraints -- DAG validity maintained after reorder -- Dependency order cannot be violated + +### DAG Validity +- Reordering MUST NOT violate dependencies +- Cannot move ticket before its dependencies +- `depends_on` relationships preserved + +### Atomic Operations +- Bulk operations apply to all selected tickets atomically +- Partial failure rolls back all changes + +## Architecture Reference + +### Key Integration Points + +| File | Lines | Purpose | +|------|-------|---------| +| `src/models.py` | 30-50 | `Ticket` - add priority field | +| `src/gui_2.py` | 2650-2750 | Ticket display - add drag-drop | +| `src/dag_engine.py` | 50-80 | Status updates | + +### Proposed Ticket Enhancement +```python +@dataclass +class Ticket: + # ... existing fields ... + priority: str = "medium" # "high" | "medium" | "low" +``` + +## Functional Requirements + +### FR1: Priority Field +- Add `priority: str = "medium"` to Ticket dataclass +- Values: "high", "medium", "low" +- Persist in track state + +### FR2: Priority UI +- Dropdown or button group per ticket +- Color-coded: high=red, medium=yellow, low=gray +- Save to state on change + +### FR3: Drag-Drop Reordering +- Drag ticket to reorder in list +- Drop validates DAG (no dependency violation) +- Show error if invalid position + +### FR4: Multi-Select +- Checkbox per ticket for selection +- Select all / deselect all buttons +- Track selected ticket IDs + +### FR5: Bulk Actions +- Execute: Mark all selected as ready +- Skip: Mark all selected as completed +- Block: Mark all selected as blocked + +## Non-Functional Requirements + +| Requirement | Constraint | +|-------------|------------| +| Response Time | <100ms for drag-drop validation | +| Persistence | Priority saved to state.toml | + +## Testing Requirements + +### Unit Tests +- Test priority field serialization +- Test DAG validation on reorder + +### Integration Tests +- Drag-drop tickets, verify order changes +- Bulk block tickets, verify all blocked + +## Out of Scope +- Automatic priority assignment +- Priority-based auto-scheduling +- Cross-track ticket movement ## Acceptance Criteria -- [ ] Drag-drop reordering works -- [ ] Priority tags display and save -- [ ] Multi-select functional -- [ ] Bulk actions apply correctly -- [ ] DAG validity maintained -- [ ] 1-space indentation +- [ ] Priority field added to Ticket +- [ ] Priority dropdown works in UI +- [ ] Drag-drop reordering functional +- [ ] DAG validity enforced on drop +- [ ] Multi-select with checkboxes +- [ ] Bulk execute/skip/block works +- [ ] 1-space indentation maintained diff --git a/conductor/tracks/tier4_auto_patching_20260306/plan.md b/conductor/tracks/tier4_auto_patching_20260306/plan.md index 6d720c5..96600a4 100644 --- a/conductor/tracks/tier4_auto_patching_20260306/plan.md +++ b/conductor/tracks/tier4_auto_patching_20260306/plan.md @@ -1,25 +1,123 @@ # Implementation Plan: Tier 4 Auto-Patching (tier4_auto_patching_20260306) +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) + ## Phase 1: Patch Generation -- [ ] Task: Initialize MMA Environment -- [ ] Task: Extend Tier 4 to generate patches - - WHERE: src/multi_agent_conductor.py - - WHAT: Add patch generation on test failure - - HOW: Use difflib to generate unified diff - - SAFETY: Only generate, don't apply +Focus: Generate unified diff on test failure -## Phase 2: Diff Viewer -- [ ] Task: Implement GUI diff viewer - - WHERE: src/gui_2.py - - WHAT: Side-by-side diff display - - HOW: Custom ImGui rendering or third-party - - SAFETY: Read-only preview -- [ ] Task: Implement apply button - - WHERE: src/gui_2.py - - WHAT: Apply patch to working directory - - HOW: subprocess.run(['patch', '-p1']) - - SAFETY: Backup before apply +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Extend Tier 4 prompt for patch generation + - WHERE: `src/mma_prompts.py` or inline in `ai_client.py` + - WHAT: Prompt to generate unified diff + - HOW: + ```python + TIER4_PATCH_PROMPT = """ + Analyze the error and generate a unified diff patch to fix it. + Output format: + --- a/path/to/file.py + +++ b/path/to/file.py + @@ -line,count +line,count @@ + context + -removed line + +added line + context + """ + ``` -## Phase 3: Tests & Verification -- [ ] Task: Write patch tests -- [ ] Task: Conductor - Phase Verification +- [ ] Task 1.3: Add patch generation function + - WHERE: `src/ai_client.py` + - WHAT: Generate patch from error + - HOW: + ```python + def run_tier4_patch_generation(error: str, file_context: str) -> str: + prompt = TIER4_PATCH_PROMPT + f"\n\nError:\n{error}\n\nFiles:\n{file_context}" + return send(prompt, model="gemini-2.5-flash-lite") + ``` + +## Phase 2: Diff Viewer UI +Focus: Display side-by-side diff + +- [ ] Task 2.1: Parse unified diff + - WHERE: `src/gui_2.py` or new `src/diff_viewer.py` + - WHAT: Parse diff into hunks + - HOW: + ```python + def parse_diff(diff_text: str) -> list[dict]: + hunks = [] + current_hunk = None + for line in diff_text.split("\n"): + if line.startswith("@@"): + if current_hunk: hunks.append(current_hunk) + current_hunk = {"header": line, "lines": []} + elif current_hunk: + current_hunk["lines"].append(line) + if current_hunk: hunks.append(current_hunk) + return hunks + ``` + +- [ ] Task 2.2: Render diff viewer + - WHERE: `src/gui_2.py` + - WHAT: Color-coded diff display + - HOW: + ```python + for hunk in hunks: + for line in hunk["lines"]: + if line.startswith("+"): + imgui.text_colored(vec4(100, 255, 100, 255), line) + elif line.startswith("-"): + imgui.text_colored(vec4(255, 100, 100, 255), line) + else: + imgui.text(line) + ``` + +## Phase 3: Patch Application +Focus: Apply patch with backup + +- [ ] Task 3.1: Create backup before apply + - WHERE: `src/gui_2.py` or `src/mcp_client.py` + - WHAT: Backup file to .backup + - HOW: + ```python + import shutil + backup_path = file_path.with_suffix(file_path.suffix + ".backup") + shutil.copy(file_path, backup_path) + ``` + +- [ ] Task 3.2: Apply patch + - WHERE: `src/gui_2.py` + - WHAT: Use patch command or difflib + - HOW: + ```python + import subprocess + result = subprocess.run(["patch", "-p1"], input=diff_text, capture_output=True, text=True) + ``` + +- [ ] Task 3.3: Restore on failure + - WHERE: `src/gui_2.py` + - WHAT: Restore from backup if patch fails + - HOW: `shutil.copy(backup_path, file_path)` + +## Phase 4: Modal UI +Focus: Approval modal for patches + +- [ ] Task 4.1: Create patch approval modal + - WHERE: `src/gui_2.py` + - WHAT: Modal with diff preview and Apply/Reject buttons + - HOW: + ```python + if self._show_patch_modal: + imgui.open_popup("Apply Patch?") + if imgui.begin_popup_modal("Apply Patch?"): + # Render diff + if imgui.button("Apply"): + self._apply_current_patch() + imgui.close_current_popup() + imgui.same_line() + if imgui.button("Reject"): + imgui.close_current_popup() + imgui.end_popup() + ``` + +## Phase 5: Testing +- [ ] Task 5.1: Write unit tests +- [ ] Task 5.2: Conductor - Phase Verification diff --git a/conductor/tracks/tool_usage_analytics_20260306/plan.md b/conductor/tracks/tool_usage_analytics_20260306/plan.md index dc3e3c4..6efc8fa 100644 --- a/conductor/tracks/tool_usage_analytics_20260306/plan.md +++ b/conductor/tracks/tool_usage_analytics_20260306/plan.md @@ -1,25 +1,107 @@ # Implementation Plan: Tool Usage Analytics (tool_usage_analytics_20260306) -## Phase 1: Data Collection -- [ ] Task: Initialize MMA Environment -- [ ] Task: Verify tool_log_callback - - WHERE: src/ai_client.py - - WHAT: Check existing logging +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) -## Phase 2: Aggregation -- [ ] Task: Implement usage aggregation - - WHERE: src/gui_2.py or new module - - WHAT: Count tools, avg times, failures - - HOW: Process tool_log entries - - SAFETY: Efficient data structures +## Phase 1: Data Collection +Focus: Add tool execution tracking + +- [ ] Task 1.1: Initialize MMA Environment + - Run `activate_skill mma-orchestrator` before starting + +- [ ] Task 1.2: Add tool stats state + - WHERE: `src/app_controller.py` or `src/gui_2.py` + - WHAT: Add `_tool_stats: dict[str, dict]` state + - HOW: + ```python + self._tool_stats: dict[str, dict] = {} + # Structure: {tool_name: {"count": 0, "total_time_ms": 0, "failures": 0}} + ``` + - CODE STYLE: 1-space indentation + +- [ ] Task 1.3: Hook into tool execution + - WHERE: `src/ai_client.py` in tool execution path + - WHAT: Track tool name, time, success/failure + - HOW: + ```python + start_time = time.time() + try: + result = mcp_client.dispatch(name, args) + success = True + except Exception: + success = False + finally: + elapsed_ms = (time.time() - start_time) * 1000 + # Update stats via callback or direct update + ``` + - SAFETY: Don't impact tool execution performance + +## Phase 2: Aggregation Logic +Focus: Calculate derived metrics + +- [ ] Task 2.1: Implement stats update function + - WHERE: `src/app_controller.py` + - WHAT: Function to update tool stats + - HOW: + ```python + def _update_tool_stats(self, tool_name: str, elapsed_ms: float, success: bool) -> None: + if tool_name not in self._tool_stats: + self._tool_stats[tool_name] = {"count": 0, "total_time_ms": 0.0, "failures": 0} + self._tool_stats[tool_name]["count"] += 1 + self._tool_stats[tool_name]["total_time_ms"] += elapsed_ms + if not success: + self._tool_stats[tool_name]["failures"] += 1 + ``` + +- [ ] Task 2.2: Calculate average time and failure rate + - WHERE: `src/gui_2.py` in render function + - WHAT: Derive avg_time and failure_rate from stats + - HOW: + ```python + for tool, stats in self._tool_stats.items(): + count = stats["count"] + avg_time = stats["total_time_ms"] / count if count > 0 else 0 + failure_rate = (stats["failures"] / count * 100) if count > 0 else 0 + ``` ## Phase 3: Visualization -- [ ] Task: Render analytics - - WHERE: src/gui_2.py - - WHAT: Charts and tables - - HOW: imgui tables, plot_lines - - SAFETY: Handle empty data +Focus: Display analytics in GUI -## Phase 4: Verification -- [ ] Task: Test analytics -- [ ] Task: Conductor - Phase Verification +- [ ] Task 3.1: Add analytics panel + - WHERE: `src/gui_2.py` in MMA Dashboard or Operations + - WHAT: Table showing tool stats + - HOW: + ```python + if imgui.collapsing_header("Tool Usage Analytics"): + if imgui.begin_table("tool_stats", 4): + imgui.table_setup_column("Tool") + imgui.table_setup_column("Count") + imgui.table_setup_column("Avg Time (ms)") + imgui.table_setup_column("Failure %") + imgui.table_headers_row() + for tool, stats in sorted(self._tool_stats.items(), key=lambda x: -x[1]["count"]): + imgui.table_next_row() + imgui.table_set_column_index(0) + imgui.text(tool) + # ... other columns + imgui.end_table() + ``` + +## Phase 4: Reset on Session Clear +Focus: Clear stats on new session + +- [ ] Task 4.1: Clear stats on session reset + - WHERE: `src/gui_2.py` or `src/app_controller.py` reset handler + - WHAT: Clear `_tool_stats` dict + - HOW: `self._tool_stats.clear()` + +## Phase 5: Testing +Focus: Verify all functionality + +- [ ] Task 5.1: Write unit tests + - WHERE: `tests/test_tool_analytics.py` (new file) + - WHAT: Test stats accumulation, avg calculation + - HOW: Mock tool execution, verify stats update + +- [ ] Task 5.2: Conductor - Phase Verification + - Run: `uv run pytest tests/test_tool_analytics.py -v` + - Manual: Verify analytics panel displays in GUI diff --git a/conductor/tracks/tool_usage_analytics_20260306/spec.md b/conductor/tracks/tool_usage_analytics_20260306/spec.md index 952bb94..6a8f773 100644 --- a/conductor/tracks/tool_usage_analytics_20260306/spec.md +++ b/conductor/tracks/tool_usage_analytics_20260306/spec.md @@ -1,35 +1,99 @@ # Track Specification: Tool Usage Analytics (tool_usage_analytics_20260306) ## Overview -Analytics panel showing most-used tools, average execution time, failure rates. +Analytics panel showing most-used tools, average execution time, and failure rates. Uses existing tool execution data from ai_client. ## Current State Audit -### Already Implemented -- **`ai_client.tool_log_callback`**: Called when tool executes -- **`mcp_client.dispatch()`**: Routes tool calls -- **No aggregation or storage** +### Already Implemented (DO NOT re-implement) -### Gaps to Fill -- No tool usage tracking -- No execution time tracking +#### Tool Execution (src/ai_client.py) +- **Tool dispatch in `_execute_tool_calls_concurrently()`**: Executes tools via `mcp_client.dispatch()` +- **`pre_tool_callback`**: Optional callback before tool execution +- **No built-in tracking or aggregation** + +#### MCP Client (src/mcp_client.py) +- **`dispatch(name, args)`**: Routes tool calls to implementations +- **26 tools available** (run_powershell, read_file, py_get_skeleton, etc.) +- **`MUTATING_TOOLS`**: Set of tools that modify files + +### Gaps to Fill (This Track's Scope) +- No tool usage tracking (count per tool) +- No execution time tracking per tool - No failure rate tracking +- No analytics display in GUI + +## Architectural Constraints + +### Efficient Aggregation +- Track tool stats in lightweight data structure +- Don't impact tool execution performance +- Use dict: `{tool_name: {count, total_time, failures}}` + +### Memory Bounds +- Only track stats, not full history +- Reset on session reset + +## Architecture Reference + +### Key Integration Points + +| File | Lines | Purpose | +|------|-------|---------| +| `src/ai_client.py` | ~500-550 | Tool execution - add tracking | +| `src/gui_2.py` | ~2700-2800 | Analytics panel | + +### Proposed Tracking Structure +```python +# In AppController or App: +self._tool_stats: dict[str, dict] = {} +# Structure: {"read_file": {"count": 10, "total_time_ms": 150, "failures": 0}, ...} +``` ## Functional Requirements -- Track tool name, execution time, success/failure -- Aggregate by tool name -- Display ranking by usage count -- Show average time per tool -- Show failure percentage -## Key Integration Points -| File | Purpose | -|-----|---------| -| `src/ai_client.py` | Hook into tool_log_callback | -| `src/gui_2.py` | Analytics panel rendering | +### FR1: Tool Usage Tracking +- Track tool name, execution time, success/failure +- Store in `_tool_stats` dict +- Update on each tool execution + +### FR2: Aggregation by Tool +- Count total calls per tool +- Calculate average execution time +- Track failure count and rate + +### FR3: Analytics Display +- Table showing tool name, count, avg time, failure rate +- Sort by usage count (most used first) +- Show in MMA Dashboard or Operations panel + +## Non-Functional Requirements + +| Requirement | Constraint | +|-------------|------------| +| Tracking Overhead | <1ms per tool call | +| Memory | <1KB for stats dict | + +## Testing Requirements + +### Unit Tests +- Test tracking updates correctly +- Test failure rate calculation + +### Integration Tests +- Execute tools, verify stats accumulate +- Reset session, verify stats cleared + +## Out of Scope +- Historical analytics across sessions +- Export to file +- Per-ticket tool breakdown ## Acceptance Criteria -- [ ] Tool ranking displayed -- [ ] Average times accurate -- [ ] Failure rates tracked -- [ ] 1-space indentation +- [ ] Tool execution tracked +- [ ] Count per tool accurate +- [ ] Average time calculated +- [ ] Failure rate shown +- [ ] Display in GUI panel +- [ ] Reset on session clear +- [ ] 1-space indentation maintained diff --git a/conductor/tracks/track_progress_viz_20260306/plan.md b/conductor/tracks/track_progress_viz_20260306/plan.md index a795f57..2b62304 100644 --- a/conductor/tracks/track_progress_viz_20260306/plan.md +++ b/conductor/tracks/track_progress_viz_20260306/plan.md @@ -1,32 +1,95 @@ # Implementation Plan: Track Progress Visualization (track_progress_viz_20260306) +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) + ## Phase 1: Progress Calculation -- [ ] Task: Initialize MMA Environment -- [ ] Task: Implement progress calculation - - WHERE: src/gui_2.py or app_controller - - WHAT: Calculate % from ticket states - - HOW: Count completed vs total +Focus: Calculate progress metrics from ticket states -## Phase 2: Visualization -- [ ] Task: Render progress bar - - WHERE: src/gui_2.py - - WHAT: Visual progress bar - - HOW: imgui.progress_bar -- [ ] Task: Render percentage text - - WHERE: src/gui_2.py - - WHAT: Numeric % display - - HOW: imgui.text +- [ ] Task 1.1: Initialize MMA Environment + - Run `activate_skill mma-orchestrator` before starting -## Phase 3: Additional Features -- [ ] Task: Implement ticket counts - - WHERE: src/gui_2.py - - WHAT: Completed/remaining counts - - HOW: Text display -- [ ] Task: Implement ETA - - WHERE: src/gui_2.py - - WHAT: Time estimate - - HOW: Average time per ticket +- [ ] Task 1.2: Implement progress calculation function + - WHERE: `src/gui_2.py` or helper in `src/project_manager.py` + - WHAT: Calculate completion percentage from tickets + - HOW: + ```python + def calculate_track_progress(tickets: list[Ticket]) -> dict: + total = len(tickets) + if total == 0: + return {"percentage": 0, "completed": 0, "total": 0, "in_progress": 0, "blocked": 0, "todo": 0} + completed = sum(1 for t in tickets if t.status == "completed") + in_progress = sum(1 for t in tickets if t.status == "in_progress") + blocked = sum(1 for t in tickets if t.status == "blocked") + todo = sum(1 for t in tickets if t.status == "todo") + percentage = (completed / total) * 100 + return {"percentage": percentage, "completed": completed, "total": total, + "in_progress": in_progress, "blocked": blocked, "todo": todo} + ``` -## Phase 4: Verification -- [ ] Task: Test progress display -- [ ] Task: Conductor - Phase Verification +## Phase 2: Progress Bar Rendering +Focus: Display visual progress bar + +- [ ] Task 2.1: Add progress bar to MMA Dashboard + - WHERE: `src/gui_2.py` `_render_mma_dashboard()` + - WHAT: Visual progress bar with percentage + - HOW: + ```python + progress = calculate_track_progress(self.track.tickets) + imgui.text(f"Progress: {progress['completed']}/{progress['total']} tickets") + imgui.progress_bar(progress['percentage'] / 100.0, size=(300, 20)) + imgui.same_line() + imgui.text(f"{progress['percentage']:.1f}%") + ``` + - SAFETY: Handle empty ticket list + +## Phase 3: Ticket Breakdown Display +Focus: Show status breakdown + +- [ ] Task 3.1: Add status breakdown text + - WHERE: `src/gui_2.py` `_render_mma_dashboard()` + - WHAT: Show counts per status + - HOW: + ```python + imgui.text(f"Completed: {progress['completed']}") + imgui.text(f"In Progress: {progress['in_progress']}") + imgui.text(f"Blocked: {progress['blocked']}") + imgui.text(f"Todo: {progress['todo']}") + ``` + +## Phase 4: ETA Estimation +Focus: Estimate time remaining + +- [ ] Task 4.1: Track ticket completion times + - WHERE: `src/gui_2.py` or `src/app_controller.py` + - WHAT: Track average time per completed ticket + - HOW: + ```python + self._ticket_start_times: dict[str, float] = {} + self._avg_ticket_time: float = 0.0 + self._completed_count: int = 0 + # On ticket start: self._ticket_start_times[ticket.id] = time.time() + # On ticket complete: elapsed = time.time() - start; update average + ``` + +- [ ] Task 4.2: Calculate and display ETA + - WHERE: `src/gui_2.py` + - WHAT: Show estimated time remaining + - HOW: + ```python + remaining = progress['total'] - progress['completed'] + eta_seconds = self._avg_ticket_time * remaining + eta_minutes = int(eta_seconds / 60) + imgui.text(f"ETA: ~{eta_minutes}m ({remaining} tickets remaining)") + ``` + +## Phase 5: Testing +Focus: Verify all functionality + +- [ ] Task 5.1: Write unit tests for progress calculation + - WHERE: `tests/test_progress_viz.py` (new file) + - WHAT: Test percentage calculation, edge cases + - HOW: Create mock tickets with various statuses + +- [ ] Task 5.2: Conductor - Phase Verification + - Run: `uv run pytest tests/test_progress_viz.py -v` + - Manual: Verify progress bar displays correctly diff --git a/conductor/tracks/track_progress_viz_20260306/spec.md b/conductor/tracks/track_progress_viz_20260306/spec.md index b5dcace..05e2188 100644 --- a/conductor/tracks/track_progress_viz_20260306/spec.md +++ b/conductor/tracks/track_progress_viz_20260306/spec.md @@ -1,34 +1,111 @@ # Track Specification: Track Progress Visualization (track_progress_viz_20260306) ## Overview -Progress bars and percentage completion for active tracks and tickets. +Progress bars and percentage completion for active tracks and tickets. Better visualization of DAG execution state. ## Current State Audit -### Already Implemented -- **`models.Track`**: Has tickets list -- **`project_manager.get_all_tracks()`**: Returns track progress -- **GUI**: Shows ticket status but no progress bar +### Already Implemented (DO NOT re-implement) -### Gaps to Fill -- No visual progress bar +#### Track Model (src/models.py) +- **`Track` dataclass**: Has `tickets: list[Ticket]` field +- **`Ticket.status`**: "todo" | "in_progress" | "completed" | "blocked" + +#### Track Listing (src/project_manager.py) +- **`get_all_tracks()`**: Returns list of track metadata with progress +- **Progress calculation exists**: Counts completed vs total tickets + +#### DAG Engine (src/dag_engine.py) +- **`TrackDAG`**: Manages ticket dependency graph +- **Status tracking via `update_task_status()`** + +### Gaps to Fill (This Track's Scope) +- No visual progress bar in GUI - No percentage completion display - No ETA estimation +- No ticket breakdown display + +## Architectural Constraints + +### Accurate State +- Progress MUST reflect actual ticket status +- Count completed, in_progress, blocked, todo separately + +### Efficient Updates +- Status changes trigger immediate UI update +- No polling - event-driven via MMA state updates + +## Architecture Reference + +### Key Integration Points + +| File | Lines | Purpose | +|------|-------|---------| +| `src/gui_2.py` | 2650-2750 | MMA Dashboard - add progress display | +| `src/project_manager.py` | 289-320 | `get_all_tracks()` - progress data | +| `src/dag_engine.py` | 50-80 | Status tracking | + +### Progress Calculation +```python +def calculate_progress(tickets: list[Ticket]) -> dict: + total = len(tickets) + completed = sum(1 for t in tickets if t.status == "completed") + in_progress = sum(1 for t in tickets if t.status == "in_progress") + blocked = sum(1 for t in tickets if t.status == "blocked") + todo = sum(1 for t in tickets if t.status == "todo") + percentage = (completed / total * 100) if total > 0 else 0 + return { + "total": total, "completed": completed, "in_progress": in_progress, + "blocked": blocked, "todo": todo, "percentage": percentage + } +``` ## Functional Requirements -- Progress bar showing % complete -- Ticket count: X/Y completed -- ETA estimation based on average time per ticket -## Key Integration Points -| File | Purpose | -|-----|---------| -| `src/gui_2.py` | Progress bar rendering | -| `src/dag_engine.py` | Completion calculation | +### FR1: Progress Bar +- Visual progress bar using `imgui.progress_bar()` +- Show 0-100% completion +- Color based on progress (red < 25%, yellow < 75%, green >= 75%) + +### FR2: Percentage Text +- Display "X% complete" below bar +- Show "X/Y tickets completed" + +### FR3: Ticket Breakdown +- Show counts: completed, in_progress, blocked, todo +- Use colored indicators per status + +### FR4: ETA Estimation +- Track average time per completed ticket +- Estimate remaining time: `avg_time * remaining_tickets` +- Display as "ETA: ~Xm" + +## Non-Functional Requirements + +| Requirement | Constraint | +|-------------|------------| +| Update Latency | <100ms after status change | +| Memory | <100 bytes for ETA state | + +## Testing Requirements + +### Unit Tests +- Test progress calculation accuracy +- Test ETA estimation logic + +### Integration Tests +- Complete tickets, verify progress updates +- Verify ETA recalculates + +## Out of Scope +- Historical progress tracking +- Progress export +- Multi-track comparison ## Acceptance Criteria -- [ ] Progress bar renders -- [ ] Percentage accurate -- [ ] Counts match actual tickets -- [ ] ETA calculation works -- [ ] 1-space indentation +- [ ] Progress bar renders correctly +- [ ] Percentage accurate (X/Y completed) +- [ ] Ticket breakdown displayed +- [ ] ETA estimation works +- [ ] Updates on ticket status change +- [ ] 1-space indentation maintained diff --git a/conductor/tracks/visual_dag_ticket_editing_20260306/plan.md b/conductor/tracks/visual_dag_ticket_editing_20260306/plan.md index ec58e12..83acabb 100644 --- a/conductor/tracks/visual_dag_ticket_editing_20260306/plan.md +++ b/conductor/tracks/visual_dag_ticket_editing_20260306/plan.md @@ -1,29 +1,102 @@ # Implementation Plan: Visual DAG Ticket Editing (visual_dag_ticket_editing_20260306) +> **Reference:** [Spec](./spec.md) | [Architecture Guide](../../../docs/guide_architecture.md) + ## Phase 1: Node Editor Setup -- [ ] Task: Initialize MMA Environment -- [ ] Task: Verify ImGui Bundle node editor available - - WHERE: requirements.txt - - WHAT: Ensure imgui-bundle with node editor - - HOW: pip install +Focus: Verify ImGui Bundle node editor -## Phase 2: Implementation -- [ ] Task: Implement ticket node rendering - - WHERE: src/gui_2.py - - WHAT: Render tickets as nodes - - HOW: imgui.node_editor with custom drawing - - SAFETY: 60fps target -- [ ] Task: Implement drag-drop - - WHERE: src/gui_2.py - - WHAT: Handle node drag and dependency lines - - HOW: Node editor callbacks - - SAFETY: Validate DAG after edit -- [ ] Task: Implement status display - - WHERE: src/gui_2.py - - WHAT: Color-coded status per node - - HOW: Node colors based on ticket status - - SAFETY: Sync with backend state +- [ ] Task 1.1: Initialize MMA Environment +- [ ] Task 1.2: Verify imgui_bundle node editor available + - WHERE: Check imports + - HOW: `import imgui_bundle.node_editor as ed` -## Phase 3: Tests & Verification -- [ ] Task: Write node editor tests -- [ ] Task: Conductor - Phase Verification +## Phase 2: Basic Node Rendering +Focus: Render tickets as nodes + +- [ ] Task 2.1: Create node editor context + - WHERE: `src/gui_2.py` MMA dashboard + - WHAT: Begin/end node editor + - HOW: + ```python + ed.begin("Ticket DAG") + for ticket in self.track.tickets: + ed.begin_node(ticket.id) + imgui.text(ticket.id) + imgui.text(ticket.status) + ed.end_node() + ed.end() + ``` + +- [ ] Task 2.2: Set node positions + - WHERE: `src/gui_2.py` + - WHAT: Position nodes in grid + - HOW: + ```python + # Auto-layout: grid positions + col = i % 4 + row = i // 4 + ed.set_node_position(ticket.id, col * 200, row * 150) + ``` + +- [ ] Task 2.3: Add status colors + - WHERE: `src/gui_2.py` + - WHAT: Color nodes by status + - HOW: + ```python + status_colors = {"todo": vec4(150, 150, 150, 255), "in_progress": vec4(255, 200, 100, 255), + "completed": vec4(100, 255, 100, 255), "blocked": vec4(255, 100, 100, 255)} + color = status_colors.get(ticket.status, vec4(200, 200, 200, 255)) + ed.push_style_color(ed.StyleColor.node_bg, color) + ``` + +## Phase 3: Dependency Links +Focus: Draw lines between nodes + +- [ ] Task 3.1: Create links for dependencies + - WHERE: `src/gui_2.py` + - WHAT: Draw lines from dependency to dependent + - HOW: + ```python + for ticket in self.track.tickets: + for dep_id in ticket.depends_on: + # Create link: dep_id -> ticket.id + ed.link(f"link_{dep_id}_{ticket.id}", dep_id, ticket.id) + ``` + +## Phase 4: Interactive Editing +Focus: Allow creating/removing dependencies + +- [ ] Task 4.1: Handle link creation + - WHERE: `src/gui_2.py` + - WHAT: Detect new links and update Ticket + - HOW: + ```python + # Check for new links + if ed.begin_create(): + created = ed.get_created_link() + if created: + # Add dependency to ticket + pass + ed.end_create() + ``` + +- [ ] Task 4.2: Handle link deletion + - WHERE: `src/gui_2.py` + - WHAT: Detect deleted links + - HOW: `ed.begin_delete()`, `ed.get_deleted_link()` + +- [ ] Task 4.3: Validate DAG after edit + - WHERE: `src/gui_2.py` + - WHAT: Check for cycles + - HOW: + ```python + from src.dag_engine import TrackDAG + temp_dag = TrackDAG(updated_tickets) + if temp_dag.has_cycle(): + imgui.open_popup("Cycle Detected!") + # Revert change + ``` + +## Phase 5: Testing +- [ ] Task 5.1: Write unit tests +- [ ] Task 5.2: Conductor - Phase Verification