# Feature: Progressive Search

## Description

Coordinates progressive tile search when tracking is lost. Expands search grid from 1→4→9→16→25 tiles, trying LiteSAM matching at each level. Manages search session state and tracks progress.

## Component APIs Implemented

- `start_search(flight_id: str, frame_id: int, estimated_gps: GPSPoint) -> SearchSession`
- `expand_search_radius(session: SearchSession) -> List[TileCoords]`
- `try_current_grid(session: SearchSession, tiles: Dict[str, np.ndarray]) -> Optional[AlignmentResult]`
- `mark_found(session: SearchSession, result: AlignmentResult) -> bool`
- `get_search_status(session: SearchSession) -> SearchStatus`

## External Tools and Services

| Component | Usage |
|-----------|-------|
| F04 Satellite Data Manager | `expand_search_grid()`, `compute_tile_bounds()` |
| F09 Metric Refinement | `align_to_satellite()` for tile matching |

## Internal Methods

| Method | Purpose |
|--------|---------|
| `_create_search_session(flight_id, frame_id, gps)` | Initializes SearchSession with grid_size=1 |
| `_get_next_grid_size(current_size)` | Returns next size in sequence: 1→4→9→16→25 |
| `_compute_tile_sequence(session)` | Returns tiles for current grid around center GPS |
| `_try_single_tile_match(uav_image, tile, tile_bounds)` | Wraps F09 alignment call |
| `_is_match_acceptable(result, threshold)` | Validates alignment confidence meets threshold |

## Search Grid Progression

| Level | Grid Size | Tiles | New Tiles Added |
|-------|-----------|-------|-----------------|
| 1 | 1×1 | 1 | 1 |
| 2 | 2×2 | 4 | 3 |
| 3 | 3×3 | 9 | 5 |
| 4 | 4×4 | 16 | 7 |
| 5 | 5×5 | 25 | 9 |

## Unit Tests

1. **start_search** → Creates session with grid_size=1, correct center GPS
2. **expand_search_radius from 1** → Returns 3 new tiles, grid_size becomes 4
3. **expand_search_radius from 4** → Returns 5 new tiles, grid_size becomes 9
4. **expand_search_radius at max (25)** → Returns empty list, exhausted=true
5. **try_current_grid match found** → Returns AlignmentResult, session.found=true
6. **try_current_grid no match** → Returns None
7. **mark_found** → Sets session.found=true
8. **get_search_status** → Returns correct current_grid_size, found, exhausted flags

## Integration Tests

1. **Match on first grid** → start_search → try_current_grid → match found immediately
2. **Match on 3rd expansion** → Search through 1→4→9 tiles, match found at grid_size=9
3. **Full exhaustion** → All 25 tiles searched, no match, exhausted=true
4. **Concurrent searches** → Multiple flight search sessions operate independently

