component assesment and fixes done

This commit is contained in:
Oleksandr Bezdieniezhnykh
2025-11-30 16:09:31 +02:00
parent a172b21aac
commit ce9760fcbe
22 changed files with 681 additions and 1844 deletions
@@ -38,6 +38,12 @@ class IRouteChunkManager(ABC):
@abstractmethod
def mark_chunk_anchored(self, chunk_id: str, frame_id: int, gps: GPSPoint) -> bool:
"""
Transactional update:
1. Calls F10.add_chunk_anchor().
2. IF success: Updates internal state to 'anchored'.
3. Returns success status.
"""
pass
@abstractmethod
@@ -54,7 +60,12 @@ class IRouteChunkManager(ABC):
@abstractmethod
def merge_chunks(self, target_chunk_id: str, source_chunk_id: str, transform: Sim3Transform) -> bool:
"""Merges source_chunk INTO target_chunk. Result is stored in target_chunk."""
"""
Transactional update:
1. Calls F10.merge_chunk_subgraphs().
2. IF success: Updates internal state (source merged/deactivated).
3. Returns success status.
"""
pass
@abstractmethod
@@ -63,40 +74,23 @@ class IRouteChunkManager(ABC):
@abstractmethod
def save_chunk_state(self, flight_id: str) -> bool:
"""Persist all chunk state to F03 for crash recovery."""
pass
@abstractmethod
def load_chunk_state(self, flight_id: str) -> bool:
"""Load chunk state from F03 on restart."""
pass
```
## Component Description
### Responsibilities
- **Source of truth for chunk state** (active, anchored, merged status)
- Manage chunk lifecycle (creation, activation, deactivation, merging)
- Track chunk state (frames, anchors, matching status)
- Provide chunk representations for matching (composite images, descriptors)
- Determine chunk readiness for matching (min frames, consistency)
- Persist chunk state via F03 Flight Database
- **Source of Truth**: Manages chunk states (Active, Matching, Anchored, Merged).
- **Transactional Integrity**: Ensures internal state updates are atomic with respect to Factor Graph (F10) operations.
- **Implementation**: Uses "Check-Act" pattern. Calls F10 first; if F10 fails, F12 does not update state and returns error.
### Chunk Responsibility Clarification
**F12 is the high-level chunk manager**:
- Owns chunk state (ChunkHandle with matching_status, is_active, has_anchor)
- Provides high-level queries: `get_active_chunk()`, `get_chunks_for_matching()`
- Coordinates with F10 for factor graph operations
- Persists chunk state for crash recovery
**F10 provides low-level factor graph operations** (see F10 spec):
- Subgraph creation and factor management
- Does NOT own chunk state - only factor graph data
**F11 coordinates recovery** (see F11 spec):
- Calls F12 for chunk operations
- F11 NEVER directly calls F10 chunk methods
### Interaction
- Called by **F02.2 Flight Processing Engine** and **F11 Failure Recovery Coordinator** (via F02.2 or direct delegation).
- Calls **F10 Factor Graph Optimizer**.
### Scope
- Chunk lifecycle management
@@ -108,10 +102,10 @@ class IRouteChunkManager(ABC):
### `create_chunk(flight_id: str, start_frame_id: int) -> ChunkHandle`
**Description**: Creates a new route chunk and initializes it in the factor graph.
**Description**: Initializes a new route chunk.
**Called By**:
- F02 Flight Processor (when tracking lost)
- F02.2 Flight Processing Engine (when tracking lost)
- F11 Failure Recovery Coordinator (proactive chunk creation)
**Input**:
@@ -151,10 +145,10 @@ ChunkHandle:
### `add_frame_to_chunk(chunk_id: str, frame_id: int, vo_result: RelativePose) -> bool`
**Description**: Adds a frame to an existing chunk with its VO result.
**Description**: Adds a frame to an active chunk.
**Called By**:
- F02 Flight Processor (during frame processing)
- F02.2 Flight Processing Engine (during frame processing)
**Input**:
```python
@@ -192,20 +186,9 @@ bool: True if frame added successfully
- F09 Metric Refinement (for chunk LiteSAM matching)
- F11 Failure Recovery Coordinator (chunk state queries)
**Input**:
```python
chunk_id: str
```
**Input**: `chunk_id: str`
**Output**:
```python
List[int] # Frame IDs in chunk, ordered by sequence
```
**Test Cases**:
1. **Get frames**: Returns all frames in chunk
2. **Empty chunk**: Returns empty list
3. **Ordered frames**: Frames returned in sequence order
**Output**: `List[int]` # Frame IDs in chunk, ordered by sequence
---
@@ -218,25 +201,7 @@ List[int] # Frame IDs in chunk, ordered by sequence
- F09 Metric Refinement (chunk LiteSAM matching)
- F06 Image Rotation Manager (chunk rotation)
**Input**:
```python
chunk_id: str
```
**Output**:
```python
List[np.ndarray] # Images for each frame in chunk
```
**Processing Flow**:
1. Get chunk frames via get_chunk_frames()
2. Load images from F05 Image Input Pipeline
3. Return list of images
**Test Cases**:
1. **Get images**: Returns all images in chunk
2. **Image loading**: Images loaded correctly from pipeline
3. **Order consistency**: Images match frame order
**Output**: `List[np.ndarray]` # Images for each frame in chunk
---
@@ -247,30 +212,7 @@ List[np.ndarray] # Images for each frame in chunk
**Called By**:
- F08 Global Place Recognition (chunk semantic matching)
**Input**:
```python
chunk_id: str
```
**Output**:
```python
np.ndarray: Aggregated descriptor vector (4096-dim or 8192-dim)
```
**Processing Flow**:
1. Get chunk images via get_chunk_images()
2. Call F08.compute_chunk_descriptor(chunk_images) → aggregate descriptor
3. Return composite descriptor
**Delegation**:
- Delegates to F08.compute_chunk_descriptor() for descriptor computation
- F08 handles aggregation logic (mean, VLAD, or max)
- Single source of truth for chunk descriptor computation
**Test Cases**:
1. **Compute descriptor**: Returns aggregated descriptor
2. **Multiple images**: Descriptor aggregates correctly
3. **Descriptor quality**: More robust than single-image descriptor
**Output**: `np.ndarray`: Aggregated descriptor vector (4096-dim or 8192-dim)
---
@@ -282,11 +224,6 @@ np.ndarray: Aggregated descriptor vector (4096-dim or 8192-dim)
- F11 Failure Recovery Coordinator (for tile search area)
- F04 Satellite Data Manager (for tile prefetching)
**Input**:
```python
chunk_id: str
```
**Output**:
```python
ChunkBounds:
@@ -295,58 +232,23 @@ ChunkBounds:
confidence: float
```
**Processing Flow**:
1. Get chunk trajectory from F10.get_chunk_trajectory()
2. If chunk has anchor:
- Use anchor GPS as center
- Compute radius from trajectory extent
3. If chunk unanchored:
- Estimate center from VO trajectory (relative to start)
- Use dead-reckoning estimate
- Lower confidence
4. Return ChunkBounds
**Test Cases**:
1. **Anchored chunk**: Returns accurate bounds with high confidence
2. **Unanchored chunk**: Returns estimated bounds with lower confidence
3. **Bounds calculation**: Radius computed from trajectory extent
---
### `is_chunk_ready_for_matching(chunk_id: str) -> bool`
**Description**: Determines if chunk has enough frames and consistency for matching.
**Called By**:
- F11 Failure Recovery Coordinator (before attempting matching)
- Background matching task
**Input**:
```python
chunk_id: str
```
**Output**:
```python
bool: True if chunk ready for matching
```
**Description**: Checks if a chunk has enough data (frames, spread) to attempt satellite matching.
**Criteria**:
- **Min frames**: >= 5 frames (configurable)
- **Max frames**: <= 20 frames (configurable, prevents oversized chunks)
- **Internal consistency**: VO factors have reasonable inlier counts
- **Not already matched**: matching_status != "anchored" or "merged"
**Test Cases**:
1. **Ready chunk**: 10 frames, good consistency → True
2. **Too few frames**: 3 frames → False
3. **Already anchored**: has_anchor=True → False
- Min frames: >= 5 frames (configurable)
- Max frames: <= 20 frames (configurable, prevents oversized chunks)
- Internal consistency: VO factors have reasonable inlier counts
- Not already matched: matching_status != "anchored" or "merged"
---
### `mark_chunk_anchored(chunk_id: str, frame_id: int, gps: GPSPoint) -> bool`
**Description**: Marks chunk as anchored with GPS coordinate.
**Description**: Anchors a chunk to a specific GPS coordinate (e.g., from successful satellite matching).
**Called By**:
- F11 Failure Recovery Coordinator (after successful chunk matching)
@@ -358,17 +260,15 @@ frame_id: int # Frame within chunk that was anchored
gps: GPSPoint
```
**Output**:
```python
bool: True if marked successfully
```
**Output**: `bool` - True if marked successfully
**Processing Flow**:
1. Verify chunk exists
2. Call F10.add_chunk_anchor()
3. Update chunk state (has_anchor=True, anchor_frame_id, anchor_gps)
4. Update matching_status to "anchored"
5. Trigger chunk optimization
3. If successful:
- Update chunk state (has_anchor=True, anchor_frame_id, anchor_gps)
- Update matching_status to "anchored"
- Trigger chunk optimization
**Test Cases**:
1. **Mark anchored**: Chunk state updated correctly
@@ -383,30 +283,8 @@ bool: True if marked successfully
**Called By**:
- F11 Failure Recovery Coordinator (background matching task)
- Background processing task
**Input**:
```python
flight_id: str
```
**Output**:
```python
List[ChunkHandle] # Unanchored chunks ready for matching
```
**Processing Flow**:
1. Get all chunks for flight_id
2. Filter chunks where:
- has_anchor == False
- is_chunk_ready_for_matching() == True
- matching_status == "unanchored" or "matching"
3. Return filtered list
**Test Cases**:
1. **Get unanchored chunks**: Returns ready chunks
2. **Filter criteria**: Only returns chunks meeting criteria
3. **Empty result**: Returns empty list if no ready chunks
**Output**: `List[ChunkHandle]` # Unanchored chunks ready for matching
---
@@ -415,22 +293,9 @@ List[ChunkHandle] # Unanchored chunks ready for matching
**Description**: Gets the currently active chunk for a flight.
**Called By**:
- F02 Flight Processor (before processing frame)
- F02.2 Flight Processing Engine (before processing frame)
**Input**:
```python
flight_id: str
```
**Output**:
```python
Optional[ChunkHandle] # Active chunk or None
```
**Test Cases**:
1. **Get active chunk**: Returns active chunk
2. **No active chunk**: Returns None
3. **Multiple chunks**: Returns only active chunk
**Output**: `Optional[ChunkHandle]` # Active chunk or None
---
@@ -440,27 +305,9 @@ Optional[ChunkHandle] # Active chunk or None
**Called By**:
- F11 Failure Recovery Coordinator (after chunk merged)
- F02 Flight Processor (chunk lifecycle)
- F02.2 Flight Processing Engine (chunk lifecycle)
**Input**:
```python
chunk_id: str
```
**Output**:
```python
bool: True if deactivated successfully
```
**Processing Flow**:
1. Verify chunk exists
2. Update chunk state (is_active=False)
3. Update matching_status to "merged" if merged
4. Return True
**Test Cases**:
1. **Deactivate chunk**: Chunk marked inactive
2. **After merge**: Matching status updated to "merged"
**Output**: `bool` - True if deactivated successfully
---
@@ -481,35 +328,18 @@ transform: Sim3Transform:
scale: float
```
**Output**:
```python
bool: True if merge successful
```
**Output**: `bool` - True if merge successful
**Processing Flow**:
1. Verify both chunks exist
2. Verify source_chunk_id is anchored (has_anchor=True)
3. Validate chunks can be merged (not already merged, not same chunk)
4. Call F10.merge_chunk_subgraphs(flight_id, source_chunk_id, target_chunk_id, transform)
5. Update source_chunk_id state:
- Set is_active=False
- Set matching_status="merged"
- Call deactivate_chunk(source_chunk_id)
6. target_chunk remains active (now contains merged frames)
7. Persist chunk state via F03 Flight Database.save_chunk_state()
8. Return True
**Merge Convention**:
- `merge_chunks(target, source)` → source is merged INTO target
- Result is stored in target_chunk
- source_chunk is deactivated after merge
- Example: `merge_chunks("main", "chunk_3")` merges chunk_3 into main trajectory
**Validation**:
- Both chunks must exist
- source_chunk must be anchored
- source_chunk must not already be merged
- target_chunk and source_chunk must be different
1. Call F10.merge_chunk_subgraphs(flight_id, source_chunk_id, target_chunk_id, transform)
2. If successful:
- Update source_chunk_id state:
- Set is_active=False
- Set matching_status="merged"
- Call deactivate_chunk(source_chunk_id)
- target_chunk remains active (now contains merged frames)
- Persist chunk state via F03 Flight Database.save_chunk_state()
3. Return True
**Test Cases**:
1. **Merge anchored chunk**: source_chunk merged into target_chunk
@@ -525,29 +355,7 @@ bool: True if merge successful
**Called By**:
- F11 Failure Recovery Coordinator (when chunk matching starts)
**Input**:
```python
chunk_id: str
```
**Output**:
```python
bool: True if marked successfully
```
**Processing Flow**:
1. Verify chunk exists
2. Verify chunk is unanchored (has_anchor=False)
3. Update matching_status to "matching"
4. Return True
**State Transition**:
- `unanchored``matching` (explicit transition)
**Test Cases**:
1. **Mark unanchored chunk**: Status updated to "matching"
2. **Mark already anchored chunk**: Returns False (invalid state)
3. **Mark non-existent chunk**: Returns False
**Output**: `bool` - True if marked successfully
## Integration Tests
@@ -600,14 +408,10 @@ bool: True if marked successfully
## Dependencies
### Internal Components
- **F10 Factor Graph Optimizer**: Chunk creation and factor management
- **F05 Image Input Pipeline**: Image retrieval
- **F08 Global Place Recognition**: Descriptor computation
- **F07 Sequential VO**: VO results for chunk building
- **F03 Flight Database**: Chunk state persistence
### External Dependencies
- **numpy**: Array operations
- **F10 Factor Graph Optimizer**: Critical dependency for subgraph operations (`create_chunk_subgraph`, `add_relative_factor_to_chunk`, `merge_chunk_subgraphs`).
- **F03 Flight Database**: Persistence via `save_chunk_state()`, `load_chunk_states()`.
- **F05 Image Input Pipeline**: Image retrieval via `get_image_by_sequence()` for `get_chunk_images()`.
- **F08 Global Place Recognition**: Descriptor computation via `compute_chunk_descriptor()` for `get_chunk_composite_descriptor()`.
## Data Models
@@ -649,4 +453,3 @@ class Sim3Transform(BaseModel):
rotation: np.ndarray # (3, 3) rotation matrix or (4,) quaternion
scale: float # Scale factor
```