# 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
