# Track Specification: Per-Ticket Model Override (per_ticket_model_20260306) ## Overview Allow user to manually select which model to use for a specific ticket, overriding the default tier model. Useful for forcing smarter model on hard tickets. ## Current State Audit ### Already Implemented (DO NOT re-implement) #### Ticket Model (src/models.py) - **`Ticket` dataclass**: Has `assigned_to` but no `model_override` - **`status` field**: "todo" | "in_progress" | "completed" | "blocked" - **No model selection per ticket** #### Tier Usage (src/multi_agent_conductor.py) - **`ConductorEngine.tier_usage`**: Has per-tier model assignment ```python self.tier_usage = { "Tier 1": {"input": 0, "output": 0, "model": "gemini-3.1-pro-preview"}, "Tier 2": {"input": 0, "output": 0, "model": "gemini-3-flash-preview"}, "Tier 3": {"input": 0, "output": 0, "model": "gemini-2.5-flash-lite"}, "Tier 4": {"input": 0, "output": 0, "model": "gemini-2.5-flash-lite"}, } ``` #### Model Escalation (src/multi_agent_conductor.py) - **Already implemented in `run()`**: Escalation based on `retry_count` ```python 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] ``` ### Gaps to Fill (This Track's Scope) - No `model_override` field on Ticket - No UI for model selection per ticket - No override indicator in GUI ## Architectural Constraints ### Validation - Selected model MUST be valid and available - Model list from `cost_tracker.MODEL_PRICING` or config ### Clear Override - Override MUST be visually distinct from default - Reset option MUST return to tier default ## Architecture Reference ### Key Integration Points | File | Lines | Purpose | |------|-------|---------| | `src/models.py` | 30-50 | `Ticket` dataclass - add field | | `src/multi_agent_conductor.py` | 100-130 | Model selection logic | | `src/gui_2.py` | 2650-2750 | Ticket UI - add dropdown | ### Proposed Ticket Enhancement ```python @dataclass class Ticket: # ... existing fields ... model_override: Optional[str] = None # None = use tier default ``` ## Functional Requirements ### FR1: Model Override Field - Add `model_override: Optional[str] = None` to Ticket dataclass - Persist in track state ### FR2: Model Dropdown UI - Dropdown in ticket node showing available models - Options: None (default), gemini-2.5-flash-lite, gemini-2.5-flash, gemini-3.1-pro-preview, etc. - Only show when ticket is "todo" status ### FR3: Override Indicator - Visual indicator when override is set (different color or icon) - Show "Using: {model_name}" in ticket display ### FR4: Execution Integration - In `ConductorEngine.run()`, check `ticket.model_override` first - If set, use override; otherwise use tier default ## Non-Functional Requirements | Requirement | Constraint | |-------------|------------| | UI Response | Dropdown updates immediately | | Persistence | Override saved to state.toml | ## Testing Requirements ### Unit Tests - Test model_override field serialization - Test override takes precedence at execution ### Integration Tests - Set override, run ticket, verify correct model used ## Out of Scope - Dynamic model list from API - Cost estimation preview before execution ## Acceptance Criteria - [ ] `model_override` field added to Ticket - [ ] Model dropdown works in UI - [ ] Override saves to track state - [ ] Visual indicator shows override active - [ ] Reset option clears override - [ ] Override used during execution - [ ] 1-space indentation maintained