# Feature: Chunk Recovery Coordination

## Description

Coordinates chunk-based recovery when tracking is lost. Creates chunks proactively, orchestrates semantic matching via F08, LiteSAM matching with rotation sweeps via F06/F09, and merges recovered chunks into the main trajectory. Includes background processing of unanchored chunks.

## Component APIs Implemented

- `create_chunk_on_tracking_loss(flight_id: str, frame_id: int) -> ChunkHandle`
- `try_chunk_semantic_matching(chunk_id: str) -> Optional[List[TileCandidate]]`
- `try_chunk_litesam_matching(chunk_id: str, candidate_tiles: List[TileCandidate]) -> Optional[ChunkAlignmentResult]`
- `merge_chunk_to_trajectory(flight_id: str, chunk_id: str, alignment_result: ChunkAlignmentResult) -> bool`
- `process_unanchored_chunks(flight_id: str) -> None`

## External Tools and Services

| Component | Usage |
|-----------|-------|
| F12 Route Chunk Manager | `create_chunk()`, `get_chunk_images()`, `get_chunk_frames()`, `mark_chunk_anchored()`, `merge_chunks()`, `get_chunks_for_matching()`, `is_chunk_ready_for_matching()`, `mark_chunk_matching()` |
| F10 Factor Graph Optimizer | Chunk creation, anchor application (via F12) |
| F04 Satellite Data Manager | Tile retrieval for matching |
| F08 Global Place Recognition | `retrieve_candidate_tiles_for_chunk()` |
| F06 Image Rotation Manager | `try_chunk_rotation_steps()` for rotation sweeps |
| F09 Metric Refinement | `align_chunk_to_satellite()` (via F06) |

## Internal Methods

| Method | Purpose |
|--------|---------|
| `_determine_merge_target(chunk_id)` | Finds temporal predecessor chunk for merging |
| `_compute_sim3_transform(alignment_result)` | Builds Sim3Transform from alignment |
| `_select_anchor_frame(chunk_id)` | Selects best frame in chunk for anchoring (middle or highest confidence) |
| `_handle_chunk_matching_failure(chunk_id)` | Decides retry vs user input request on failure |

## Rotation Sweep Strategy

- 12 rotation angles: 0°, 30°, 60°, ..., 330°
- Critical for chunks from sharp turns (unknown orientation)
- Returns best matching rotation angle in ChunkAlignmentResult

## Chunk Lifecycle States

| Status | Description |
|--------|-------------|
| `unanchored` | Chunk created, no GPS anchor |
| `matching` | Matching in progress |
| `anchored` | GPS anchor established |
| `merged` | Merged into main trajectory |

## Unit Tests

1. **create_chunk_on_tracking_loss** → Returns ChunkHandle with correct flight_id, start_frame_id, is_active=true
2. **try_chunk_semantic_matching success** → Returns List[TileCandidate] from F08
3. **try_chunk_semantic_matching no match** → Returns None
4. **try_chunk_litesam_matching match at 0°** → Returns ChunkAlignmentResult with rotation_angle=0
5. **try_chunk_litesam_matching match at 120°** → Returns ChunkAlignmentResult with rotation_angle=120
6. **try_chunk_litesam_matching no match** → Returns None after trying all rotations and tiles
7. **merge_chunk_to_trajectory** → Returns true, F12.merge_chunks called with correct parameters
8. **merge_chunk_to_trajectory determines correct merge target** → Merges to temporal predecessor
9. **_determine_merge_target no predecessor** → Returns "main" for first chunk

## Integration Tests

1. **Proactive chunk creation** → Tracking lost → chunk created immediately → processing continues in new chunk
2. **Chunk semantic matching** → Chunk with 10 frames → semantic matching finds candidates where single-frame fails
3. **Chunk LiteSAM with rotation** → Unknown orientation chunk → rotation sweep finds match at correct angle
4. **Full chunk recovery flow** → create_chunk → semantic matching → LiteSAM matching → merge
5. **Multiple chunk merging** → chunk_1 (frames 1-10), chunk_2 (frames 20-30) → both recovered and merged
6. **Background processing** → 3 unanchored chunks → process_unanchored_chunks matches and merges asynchronously
7. **Non-blocking processing** → Frame processing continues while chunk matching runs in background
8. **Chunk matching failure** → All candidates fail → user input requested for chunk

