spec cleanup

This commit is contained in:
Oleksandr Bezdieniezhnykh
2025-11-30 19:08:40 +02:00
parent b12f37ab01
commit 3d034e27ee
10 changed files with 270 additions and 152 deletions
Binary file not shown.
@@ -61,8 +61,8 @@ class IFactorGraphOptimizer(ABC):
pass pass
@abstractmethod @abstractmethod
def merge_chunk_subgraphs(self, flight_id: str, source_chunk_id: str, target_chunk_id: str, transform: Sim3Transform) -> bool: def merge_chunk_subgraphs(self, flight_id: str, new_chunk_id: str, main_chunk_id: str, transform: Sim3Transform) -> bool:
"""Merges source_chunk INTO target_chunk. Source chunk subgraph is merged into target.""" """Merges new_chunk INTO main_chunk. Extends main_chunk with new_chunk's subgraph."""
pass pass
@abstractmethod @abstractmethod
@@ -523,18 +523,18 @@ bool: True if anchor added
--- ---
### `merge_chunks(chunk_id_1: str, chunk_id_2: str, transform: Sim3Transform) -> bool` ### `merge_chunk_subgraphs(flight_id: str, new_chunk_id: str, main_chunk_id: str, transform: Sim3Transform) -> bool`
**Description**: Merges two chunks using Sim(3) similarity transformation. **Description**: Merges new_chunk INTO main_chunk using Sim(3) similarity transformation. Extends main_chunk with new_chunk's frames.
**Called By**: **Called By**:
- F11 Failure Recovery Coordinator (after chunk matching) - F12 Route Chunk Manager (via merge_chunks method)
- Background optimization task
**Input**: **Input**:
```python ```python
chunk_id_1: str # Source chunk (typically newer) flight_id: str # Flight identifier
chunk_id_2: str # Target chunk (typically older, merged into) new_chunk_id: str # New chunk being merged (source, typically newer/recently anchored)
main_chunk_id: str # Main chunk being extended (destination, typically older/established)
transform: Sim3Transform: transform: Sim3Transform:
translation: np.ndarray # (3,) translation: np.ndarray # (3,)
rotation: np.ndarray # (3, 3) or quaternion rotation: np.ndarray # (3, 3) or quaternion
@@ -547,11 +547,11 @@ bool: True if merge successful
``` ```
**Processing Flow**: **Processing Flow**:
1. Verify both chunks exist and chunk_id_1 is anchored 1. Verify both chunks exist and new_chunk is anchored
2. Apply Sim(3) transform to all poses in chunk_id_1 2. Apply Sim(3) transform to all poses in new_chunk
3. Merge chunk_id_1's subgraph into chunk_id_2's subgraph 3. Merge new_chunk's subgraph into main_chunk's subgraph
4. Update frame-to-chunk mapping 4. Update frame-to-chunk mapping (new_chunk frames now belong to main_chunk)
5. Mark chunk_id_1 as merged 5. Mark new_chunk subgraph as merged (F12 handles state updates)
6. Optimize merged graph globally 6. Optimize merged graph globally
**Sim(3) Transformation**: **Sim(3) Transformation**:
@@ -560,7 +560,7 @@ bool: True if merge successful
- Preserves internal consistency of both chunks - Preserves internal consistency of both chunks
**Test Cases**: **Test Cases**:
1. **Merge anchored chunks**: Chunks merged successfully 1. **Merge anchored chunks**: new_chunk merged into main_chunk successfully
2. **Merge unanchored chunk**: Returns False 2. **Merge unanchored chunk**: Returns False
3. **Global consistency**: Merged trajectory is globally consistent 3. **Global consistency**: Merged trajectory is globally consistent
@@ -123,6 +123,24 @@ This separation ensures:
- **Chunk lifecycle and matching coordination** - **Chunk lifecycle and matching coordination**
- **Multi-chunk simultaneous processing** - **Multi-chunk simultaneous processing**
### Architecture Note: Single Responsibility Consideration
F11 has extensive responsibilities including progressive search, chunk creation coordination, chunk matching coordination (semantic + LiteSAM), chunk merging coordination, and user input handling. While this represents significant scope, these remain together in a single component because:
1. **Tight Coupling**: All recovery strategies share state (SearchSession, chunk status) and need coordinated fallback logic (progressive search → chunk matching → user input).
2. **Sequential Dependency**: Chunk semantic matching feeds into chunk LiteSAM matching, which feeds into chunk merging. Splitting these would create circular dependencies or complex event choreography.
3. **Pure Logic Pattern**: F11 remains a pure logic component (no I/O, no threads). All execution is delegated to F02.2, keeping F11 focused on decision-making rather than coordination.
4. **Single Point of Recovery Policy**: Having all recovery strategies in one component makes the fallback logic explicit and maintainable. The alternative—multiple coordinators—would require a meta-coordinator.
**Future Consideration**: If F11 grows beyond ~1000 lines or if specific recovery strategies need independent evolution, consider splitting into:
- `F11a_search_coordinator` - Progressive search, user input handling
- `F11b_chunk_recovery_coordinator` - Chunk semantic matching, LiteSAM matching, merging
For now, the component remains unified with clear internal organization (search methods, chunk methods).
## API Methods ## API Methods
### `check_confidence(vo_result: RelativePose, litesam_result: Optional[AlignmentResult]) -> ConfidenceAssessment` ### `check_confidence(vo_result: RelativePose, litesam_result: Optional[AlignmentResult]) -> ConfidenceAssessment`
@@ -518,11 +536,11 @@ bool: True if merge successful
2. Get chunk anchor frame (middle frame or best frame) 2. Get chunk anchor frame (middle frame or best frame)
3. Call F12.mark_chunk_anchored() with GPS (F12 coordinates with F10) 3. Call F12.mark_chunk_anchored() with GPS (F12 coordinates with F10)
4. **Determine merge target**: 4. **Determine merge target**:
- Target is typically the temporal predecessor (previous chunk by frame_id order) - Main chunk is typically the temporal predecessor (previous chunk by frame_id order)
- If no predecessor: merge to main trajectory (target_chunk_id="main") - If no predecessor: merge to main trajectory (main_chunk_id="main")
- F11 determines target based on chunk frame_id ordering - F11 determines main_chunk based on chunk frame_id ordering
5. Call F12.merge_chunks(target_chunk_id, chunk_id, transform) 5. Call F12.merge_chunks(main_chunk_id, chunk_id, transform)
- Note: `merge_chunks(target, source)` merges source INTO target - Note: `merge_chunks(main_chunk, new_chunk)` merges new_chunk INTO main_chunk
- chunk_id (source) is merged into target_chunk_id - chunk_id (source) is merged into target_chunk_id
6. F12 handles chunk state updates (deactivation, status updates) 6. F12 handles chunk state updates (deactivation, status updates)
7. F10 optimizes merged graph globally (via F12.merge_chunks()) 7. F10 optimizes merged graph globally (via F12.merge_chunks())
@@ -59,12 +59,16 @@ class IRouteChunkManager(ABC):
pass pass
@abstractmethod @abstractmethod
def merge_chunks(self, target_chunk_id: str, source_chunk_id: str, transform: Sim3Transform) -> bool: def merge_chunks(self, main_chunk_id: str, new_chunk_id: str, transform: Sim3Transform) -> bool:
""" """
Merges new_chunk INTO main_chunk. Extends main_chunk with new_chunk's frames.
Transactional update: Transactional update:
1. Calls F10.merge_chunk_subgraphs(). 1. Calls F10.merge_chunk_subgraphs(flight_id, new_chunk_id, main_chunk_id, transform).
2. IF success: Updates internal state (source merged/deactivated). 2. IF success: Updates internal state (new_chunk merged/deactivated).
3. Returns success status. 3. Returns success status.
Note: flight_id is obtained from the ChunkHandle stored internally for main_chunk_id.
""" """
pass pass
@@ -88,6 +92,14 @@ class IRouteChunkManager(ABC):
- **Transactional Integrity**: Ensures internal state updates are atomic with respect to Factor Graph (F10) operations. - **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. - **Implementation**: Uses "Check-Act" pattern. Calls F10 first; if F10 fails, F12 does not update state and returns error.
### Internal State Management
F12 maintains an internal dictionary of `ChunkHandle` objects keyed by `chunk_id`. Each `ChunkHandle` contains `flight_id`, allowing F12 to resolve flight context for F10 calls without requiring `flight_id` as a parameter on every method. This simplifies the API for callers while maintaining flight isolation internally.
```python
# Internal state
_chunks: Dict[str, ChunkHandle] # chunk_id -> ChunkHandle (contains flight_id)
```
### Interaction ### Interaction
- Called by **F02.2 Flight Processing Engine** and **F11 Failure Recovery Coordinator** (via F02.2 or direct delegation). - Called by **F02.2 Flight Processing Engine** and **F11 Failure Recovery Coordinator** (via F02.2 or direct delegation).
- Calls **F10 Factor Graph Optimizer**. - Calls **F10 Factor Graph Optimizer**.
@@ -311,17 +323,17 @@ gps: GPSPoint
--- ---
### `merge_chunks(target_chunk_id: str, source_chunk_id: str, transform: Sim3Transform) -> bool` ### `merge_chunks(main_chunk_id: str, new_chunk_id: str, transform: Sim3Transform) -> bool`
**Description**: Merges source_chunk INTO target_chunk. The resulting merged chunk is target_chunk. Source chunk is deactivated after merge. **Description**: Merges new_chunk INTO main_chunk. The resulting merged chunk is main_chunk (extended with new_chunk's frames). new_chunk is deactivated after merge.
**Called By**: **Called By**:
- F11 Failure Recovery Coordinator (after successful chunk matching) - F11 Failure Recovery Coordinator (after successful chunk matching)
**Input**: **Input**:
```python ```python
target_chunk_id: str # Target chunk (receives the merge, typically older/main) main_chunk_id: str # Main chunk being extended (destination, typically older/established trajectory)
source_chunk_id: str # Source chunk (being merged in, typically newer) new_chunk_id: str # New chunk being merged in (source, typically newer/recently anchored)
transform: Sim3Transform: transform: Sim3Transform:
translation: np.ndarray # (3,) translation: np.ndarray # (3,)
rotation: np.ndarray # (3, 3) or quaternion rotation: np.ndarray # (3, 3) or quaternion
@@ -330,21 +342,24 @@ transform: Sim3Transform:
**Output**: `bool` - True if merge successful **Output**: `bool` - True if merge successful
**flight_id Resolution**: F12 internally stores ChunkHandle objects keyed by chunk_id. The flight_id is extracted from the ChunkHandle for main_chunk_id when calling F10 methods.
**Processing Flow**: **Processing Flow**:
1. Call F10.merge_chunk_subgraphs(flight_id, source_chunk_id, target_chunk_id, transform) 1. Get flight_id from internally stored ChunkHandle for main_chunk_id
2. If successful: 2. Call F10.merge_chunk_subgraphs(flight_id, new_chunk_id, main_chunk_id, transform)
- Update source_chunk_id state: 3. If successful:
- Update new_chunk_id state:
- Set is_active=False - Set is_active=False
- Set matching_status="merged" - Set matching_status="merged"
- Call deactivate_chunk(source_chunk_id) - Call deactivate_chunk(new_chunk_id)
- target_chunk remains active (now contains merged frames) - main_chunk remains active (now contains merged frames)
- Persist chunk state via F03 Flight Database.save_chunk_state() - Persist chunk state via F03 Flight Database.save_chunk_state()
3. Return True 4. Return True
**Test Cases**: **Test Cases**:
1. **Merge anchored chunk**: source_chunk merged into target_chunk 1. **Merge anchored chunk**: new_chunk merged into main_chunk
2. **Source deactivated**: source_chunk marked as merged and deactivated 2. **New chunk deactivated**: new_chunk marked as merged and deactivated
3. **Target unchanged**: target_chunk remains active with new frames 3. **Main chunk extended**: main_chunk remains active with additional frames
--- ---
@@ -380,11 +395,12 @@ transform: Sim3Transform:
5. get_chunks_for_matching() → returns only chunk_2 5. get_chunks_for_matching() → returns only chunk_2
### Test 4: Chunk Merging ### Test 4: Chunk Merging
1. Create chunk_1 (frames 1-10), chunk_2 (frames 20-30) 1. Create main_chunk (frames 1-10), new_chunk (frames 20-30)
2. Anchor chunk_1 via mark_chunk_anchored() 2. Anchor new_chunk via mark_chunk_anchored()
3. merge_chunks(chunk_1, chunk_2, transform) → chunks merged 3. merge_chunks(main_chunk, new_chunk, transform) → new_chunk merged into main_chunk
4. Verify chunk_1 marked as merged and deactivated 4. Verify new_chunk marked as merged and deactivated
5. Verify F10 merge_chunks() called 5. Verify main_chunk extended with new frames
6. Verify F10.merge_chunk_subgraphs() called with correct parameters
### Test 5: Chunk Matching Status ### Test 5: Chunk Matching Status
1. Create chunk 1. Create chunk
@@ -27,7 +27,15 @@ class IResultManager(ABC):
pass pass
@abstractmethod @abstractmethod
def mark_refined(self, flight_id: str, frame_ids: List[int]) -> bool: def mark_refined(self, flight_id: str, refined_results: List[RefinedFrameResult]) -> bool:
"""
Updates results for frames that have been retrospectively improved.
Args:
flight_id: Flight identifier
refined_results: List of RefinedFrameResult containing frame_id and GPS-converted coordinates
(caller F02.2 converts ENU to GPS before calling this method)
"""
pass pass
@abstractmethod @abstractmethod
@@ -35,7 +43,15 @@ class IResultManager(ABC):
pass pass
@abstractmethod @abstractmethod
def update_results_after_chunk_merge(self, flight_id: str, merged_frames: List[int]) -> bool: def update_results_after_chunk_merge(self, flight_id: str, refined_results: List[RefinedFrameResult]) -> bool:
"""
Updates results for frames affected by chunk merge.
Args:
flight_id: Flight identifier
refined_results: List of RefinedFrameResult with GPS-converted coordinates
(caller F02.2 converts ENU to GPS before calling this method)
"""
pass pass
``` ```
@@ -141,35 +157,37 @@ FlightResults:
--- ---
### `mark_refined(flight_id: str, frame_ids: List[int]) -> bool` ### `mark_refined(flight_id: str, refined_results: List[RefinedFrameResult]) -> bool`
**Description**: Updates results for frames that have been retrospectively improved (e.g., after loop closure or chunk merge). **Description**: Updates results for frames that have been retrospectively improved (e.g., after loop closure or chunk merge).
**Called By**: **Called By**:
- F10 Factor Graph (after asynchronous refinement) - F02.2 Flight Processing Engine (after factor graph optimization)
**Input**: **Input**:
```python ```python
flight_id: str flight_id: str
frame_ids: List[int] # Frames with updated poses refined_results: List[RefinedFrameResult] # GPS-converted results from F02.2
``` ```
**Output**: `bool` **Output**: `bool`
**Note**: F14 does NOT call F10 or F13. The caller (F02.2) performs the following steps before calling mark_refined(): **Important**: F14 does NOT call F10 or F13. The caller (F02.2) performs the following steps before calling mark_refined():
1. F02.2 gets refined poses from F10.get_trajectory(flight_id) 1. F02.2 gets refined poses from F10.get_trajectory(flight_id) (ENU coordinates)
2. F02.2 converts ENU to GPS via F13.enu_to_gps(flight_id, enu_tuple) 2. F02.2 converts ENU to GPS via F13.enu_to_gps(flight_id, enu_tuple)
3. F02.2 calls F14.mark_refined() with the GPS-converted results 3. F02.2 constructs RefinedFrameResult objects with GPS coordinates
4. F02.2 calls F14.mark_refined() with the GPS-converted results
**Processing Flow**: **Processing Flow**:
1. For each frame_id in frame_ids: 1. For each refined_result in refined_results:
- Receive GPS coordinates from caller (already converted) - Extract frame_id, gps_center, confidence from RefinedFrameResult
- Update result with refined=True via F03 Flight Database (part of transaction) - Update result with refined=True via F03 Flight Database (part of transaction)
- Update waypoint via F03 Flight Database (part of transaction) - Update waypoint via F03 Flight Database (part of transaction)
- Call F15 SSE Event Streamer.send_refinement() - Call F15 SSE Event Streamer.send_refinement()
**Test Cases**: **Test Cases**:
1. Batch refinement → all frames updated and published 1. Batch refinement → all frames updated and published
2. GPS coordinates match converted values
--- ---
@@ -194,25 +212,34 @@ since: datetime
--- ---
### `update_results_after_chunk_merge(flight_id: str, merged_frames: List[int]) -> bool` ### `update_results_after_chunk_merge(flight_id: str, refined_results: List[RefinedFrameResult]) -> bool`
**Description**: Handling specific to chunk merging events. **Description**: Updates results for frames affected by chunk merging into main trajectory.
**Triggered By**: **Called By**:
- `ChunkMerged` event from F11 (F14 subscribes to this event) - F02.2 Flight Processing Engine (after chunk merge completes)
- Alternative: F02.2 Flight Processing Engine can coordinate this call after receiving ChunkMerged event
**Input**: **Input**:
```python ```python
flight_id: str flight_id: str
merged_frames: List[int] # Frames whose poses changed due to chunk merge refined_results: List[RefinedFrameResult] # GPS-converted results for merged frames
``` ```
**Output**: `bool` - True if updated successfully **Output**: `bool` - True if updated successfully
**Important**: F14 does NOT call F10, F13, or F11. F02.2 coordinates the chunk merge workflow:
1. F11 returns merge result to F02.2 (direct call return, not event)
2. F02.2 gets updated poses from F10.get_trajectory(flight_id) (ENU coordinates)
3. F02.2 converts ENU to GPS via F13.enu_to_gps(flight_id, enu_tuple)
4. F02.2 constructs RefinedFrameResult objects
5. F02.2 calls F14.update_results_after_chunk_merge() with GPS-converted results
**Processing Flow**: **Processing Flow**:
1. Similar to `mark_refined` but triggered by `ChunkMerged` event context. 1. For each refined_result in refined_results:
2. Ensures all frames in the merged chunk are updated to the global coordinate system. - Extract frame_id, gps_center, confidence from RefinedFrameResult
- Update result with refined=True via F03 Flight Database (part of transaction)
- Update waypoint via F03 Flight Database (part of transaction)
- Call F15 SSE Event Streamer.send_refinement()
**Test Cases**: **Test Cases**:
1. **Chunk merge updates**: All merged frames updated and published 1. **Chunk merge updates**: All merged frames updated and published
@@ -286,6 +313,19 @@ class FrameResult(BaseModel):
updated_at: datetime updated_at: datetime
``` ```
### RefinedFrameResult
```python
class RefinedFrameResult(BaseModel):
"""
GPS-converted frame result provided by F02.2 after coordinate transformation.
F02.2 converts ENU poses from F10 to GPS using F13 before passing to F14.
"""
frame_id: int
gps_center: GPSPoint # GPS coordinates (converted from ENU by F02.2)
confidence: float
heading: Optional[float] = None # Updated heading if available
```
### FlightResults ### FlightResults
```python ```python
class FlightStatistics(BaseModel): class FlightStatistics(BaseModel):
@@ -1,62 +1,71 @@
<mxfile host="65bd71144e"> <mxfile host="65bd71144e">
<diagram name="ASTRAL-Next Components" id="astral-next-components"> <diagram name="ASTRAL-Next Components" id="astral-next-components">
<mxGraphModel dx="771" dy="632" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="900" pageHeight="500" math="0" shadow="0"> <mxGraphModel dx="1100" dy="750" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1100" pageHeight="600" math="0" shadow="0">
<root> <root>
<mxCell id="0"/> <mxCell id="0"/>
<mxCell id="1" parent="0"/> <mxCell id="1" parent="0"/>
<mxCell id="title" value="ASTRAL-Next Component Connections" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontStyle=1;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="title" value="ASTRAL-Next Component Diagram with Jira Epic Numbers" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=16;fontStyle=1;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="280" y="10" width="300" height="25" as="geometry"/> <mxGeometry x="300" y="10" width="500" height="30" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="client" value="Client" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1565C0;strokeColor=#64B5F6;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="client" value="Client" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1565C0;strokeColor=#64B5F6;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="20" y="50" width="60" height="35" as="geometry"/> <mxGeometry x="20" y="60" width="60" height="35" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f01" value="F01 API" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f01" value="F01 API&#10;AZ-112" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#8B1A1A;strokeColor=#EF5350;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="100" y="50" width="70" height="35" as="geometry"/> <mxGeometry x="100" y="55" width="80" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f02" value="F02&#10;Flight Processor" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;fontStyle=1;" parent="1" vertex="1"> <mxCell id="f02" value="F02 Flight Processor&#10;AZ-113" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#6A1B9A;strokeColor=#BA68C8;fontColor=#ffffff;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="195" y="70" width="110" height="45" as="geometry"/> <mxGeometry x="200" y="55" width="130" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f03" value="F03 DB" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f03" value="F03 DB&#10;AZ-114" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="340" y="50" width="70" height="35" as="geometry"/> <mxGeometry x="350" y="55" width="80" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f04" value="F04&#10;Satellite Mgr" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f05" value="F05 Image Pipeline&#10;AZ-116" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="60" y="367.5" width="80" height="45" as="geometry"/> <mxGeometry x="450" y="55" width="110" height="45" as="geometry"/>
</mxCell>
<mxCell id="f05" value="F05&#10;Image Pipeline" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="550" y="45" width="80" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="satellite" value="Satellite&#10;Provider" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFB300;fontColor=#ffffff;dashed=1;" vertex="1" parent="1"> <mxCell id="satellite" value="Satellite&#10;Provider" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFB300;fontColor=#ffffff;dashed=1;" vertex="1" parent="1">
<mxGeometry x="660" y="45" width="70" height="45" as="geometry"/> <mxGeometry x="580" y="55" width="80" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f15" value="F15 SSE" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f15" value="F15 SSE&#10;AZ-126" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="20" y="120" width="60" height="35" as="geometry"/> <mxGeometry x="20" y="130" width="70" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f11" value="F11&#10;Failure Recovery" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f08" value="F08 Place Recog&#10;AZ-119" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="310" y="120" width="110" height="45" as="geometry"/> <mxGeometry x="100" y="130" width="100" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f06" value="F06&#10;Rotation" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f11" value="F11 Failure Recovery&#10;AZ-122" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="100" y="195" width="70" height="45" as="geometry"/> <mxGeometry x="220" y="130" width="120" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f07" value="F07&#10;Sequential VO" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f12" value="F12 Chunk Mgr&#10;AZ-123" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#7B1FA2;strokeColor=#BA68C8;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="200" y="195" width="90" height="45" as="geometry"/> <mxGeometry x="360" y="130" width="100" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f08" value="F08&#10;Place Recog" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f16" value="F16 Model Mgr&#10;AZ-127" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="100" y="120" width="80" height="45" as="geometry"/> <mxGeometry x="480" y="130" width="100" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f09" value="F09&#10;Metric Refine" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f06" value="F06 Rotation&#10;AZ-117" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="340" y="195" width="80" height="45" as="geometry"/> <mxGeometry x="100" y="210" width="90" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f12" value="F12&#10;Chunk Manager" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#7B1FA2;strokeColor=#BA68C8;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f07" value="F07 Sequential VO&#10;AZ-118" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="450" y="120" width="100" height="45" as="geometry"/> <mxGeometry x="210" y="210" width="110" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f10" value="F10&#10;Factor Graph" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;fontStyle=1;" parent="1" vertex="1"> <mxCell id="f09" value="F09 Metric Refine&#10;AZ-120" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1E88E5;strokeColor=#42A5F5;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="330" y="280" width="100" height="45" as="geometry"/> <mxGeometry x="340" y="210" width="110" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f13" value="F13&#10;Coord Transform" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f17" value="F17 Config Mgr&#10;AZ-128" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#424242;strokeColor=#BDBDBD;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="390" y="355" width="100" height="45" as="geometry"/> <mxGeometry x="470" y="210" width="100" height="45" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="f14" value="F14 Result Manager" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="1" vertex="1"> <mxCell id="f10" value="F10 Factor Graph&#10;AZ-121" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;fontStyle=1;" parent="1" vertex="1">
<mxGeometry x="190" y="372.5" width="120" height="35" as="geometry"/> <mxGeometry x="260" y="290" width="120" height="50" as="geometry"/>
</mxCell>
<mxCell id="f04" value="F04 Satellite Mgr&#10;AZ-115" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#CC6600;strokeColor=#FFB300;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="100" y="290" width="110" height="50" as="geometry"/>
</mxCell>
<mxCell id="f13" value="F13 Coord Transform&#10;AZ-124" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#388E3C;strokeColor=#66BB6A;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="400" y="290" width="120" height="50" as="geometry"/>
</mxCell>
<mxCell id="f14" value="F14 Result Manager&#10;AZ-125" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E65100;strokeColor=#FFA726;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="250" y="370" width="130" height="45" as="geometry"/>
</mxCell>
<mxCell id="helpers" value="H01-H08 Helpers&#10;AZ-129" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#546E7A;strokeColor=#78909C;fontColor=#ffffff;" parent="1" vertex="1">
<mxGeometry x="540" y="290" width="110" height="50" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="c1" value="HTTP" style="strokeColor=#FFFFFF;fontColor=#ffffff;fontSize=8;" edge="1" parent="1" source="client" target="f01"> <mxCell id="c1" value="HTTP" style="strokeColor=#FFFFFF;fontColor=#ffffff;fontSize=8;" edge="1" parent="1" source="client" target="f01">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
@@ -70,6 +79,9 @@
<mxCell id="c4" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f02" target="f03"> <mxCell id="c4" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f02" target="f03">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="c4b" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f02" target="f05">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="c5" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f02" target="f11"> <mxCell id="c5" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f02" target="f11">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
@@ -88,6 +100,9 @@
<mxCell id="c12" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f11" target="f12"> <mxCell id="c12" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f11" target="f12">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="c13" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f11" target="f06">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="c14" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f07" target="f10"> <mxCell id="c14" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f07" target="f10">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
@@ -100,36 +115,49 @@
<mxCell id="c17" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f10" target="f13"> <mxCell id="c17" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f10" target="f13">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="c18" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f14" target="f13"> <mxCell id="c18" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f10" target="f14">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="c19" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f14" target="f15"> <mxCell id="c19" style="strokeColor=#FFFFFF;dashed=1;" edge="1" parent="1" source="f14" target="f15">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="c20" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f08" target="f04">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="c21" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f04" target="satellite">
<mxGeometry relative="1" as="geometry"> <mxGeometry relative="1" as="geometry">
<Array as="points"> <Array as="points">
<mxPoint x="80" y="270"/> <mxPoint x="155" y="370"/>
<mxPoint x="620" y="370"/>
</Array> </Array>
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="c13" style="strokeColor=#66BB6A;dashed=1;" edge="1" parent="1" source="f11" target="f14"> <mxCell id="c22" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f07" target="f16">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="c21" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f05" target="satellite"> <mxCell id="c23" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f08" target="f16">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="legend" value="── sync - - event" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=9;fontColor=#888888;" vertex="1" parent="1"> <mxCell id="c24" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f09" target="f16">
<mxGeometry x="600" y="380" width="100" height="20" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="3" value="" style="strokeColor=#FFFFFF;endArrow=none;" edge="1" parent="1" source="f11" target="f02"> <mxCell id="c25" style="strokeColor=#FFFFFF;dashed=1;" edge="1" parent="1" source="f17" target="f16">
<mxGeometry relative="1" as="geometry"> <mxGeometry relative="1" as="geometry"/>
<mxPoint x="507.02127659574467" y="100.00000000000011" as="sourcePoint"/>
<mxPoint x="256.3829787234042" y="289.9999999999999" as="targetPoint"/>
</mxGeometry>
</mxCell> </mxCell>
<mxCell id="2" value="" style="strokeColor=#FFFFFF;fontColor=#ffffff;endArrow=none;" edge="1" parent="1" source="f04" target="f14"> <mxCell id="c26" style="strokeColor=#78909C;dashed=1;" edge="1" parent="1" source="helpers" target="f10">
<mxGeometry relative="1" as="geometry"> <mxGeometry relative="1" as="geometry"/>
<mxPoint x="715" y="121.22222222222206" as="sourcePoint"/> </mxCell>
<mxPoint x="125" y="212.9999999999999" as="targetPoint"/> <mxCell id="c27" style="strokeColor=#78909C;dashed=1;" edge="1" parent="1" source="helpers" target="f13">
</mxGeometry> <mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="c28" style="strokeColor=#FFFFFF;" edge="1" parent="1" source="f06" target="f09">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="legend" value="── sync call - - - event/config" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=10;fontColor=#888888;" vertex="1" parent="1">
<mxGeometry x="20" y="430" width="200" height="20" as="geometry"/>
</mxCell>
<mxCell id="legend2" value="Colors: Red=API | Purple=Orchestration | Blue=Visual Processing | Green=State | Orange=Data/IO | Gray=Infrastructure" style="text;html=1;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=9;fontColor=#666666;" vertex="1" parent="1">
<mxGeometry x="20" y="450" width="650" height="20" as="geometry"/>
</mxCell> </mxCell>
</root> </root>
</mxGraphModel> </mxGraphModel>
+7 -3
View File
@@ -275,7 +275,7 @@
| F11 (background) | F08 | `retrieve_candidate_tiles_for_chunk()` | **Chunk semantic matching** | | F11 (background) | F08 | `retrieve_candidate_tiles_for_chunk()` | **Chunk semantic matching** |
| F11 (background) | F06 | `try_chunk_rotation_steps()` | **Chunk rotation sweeps** | | F11 (background) | F06 | `try_chunk_rotation_steps()` | **Chunk rotation sweeps** |
| F11 (background) | F09 | `align_chunk_to_satellite()` | **Chunk LiteSAM matching** | | F11 (background) | F09 | `align_chunk_to_satellite()` | **Chunk LiteSAM matching** |
| F11 (background) | F10 | `add_chunk_anchor()` + `merge_chunk_subgraphs()` | **Chunk merging** | | F11 (background) | F12 | `mark_chunk_anchored()` + `merge_chunks(main, new)` | **Chunk merging via F12** |
| F11 (fail) | F02.2 | Returns `UserInputRequest` | Request human help (last resort) | | F11 (fail) | F02.2 | Returns `UserInputRequest` | Request human help (last resort) |
| F02.2 | F15 | `send_user_input_request()` | Send SSE event to client | | F02.2 | F15 | `send_user_input_request()` | Send SSE event to client |
@@ -314,11 +314,15 @@
| Source | Target | Method | Purpose | | Source | Target | Method | Purpose |
|--------|--------|--------|---------| |--------|--------|--------|---------|
| F10 | Internal (background) | `optimize()` | Back-propagate anchors | | F10 | Internal (background) | `optimize()` | Back-propagate anchors |
| F14 | F10 | `get_trajectory()` | Get refined poses | | F02.2 | F10 | `get_trajectory()` | Get refined poses (ENU) |
| F02.2 | F13 | `enu_to_gps()` | Convert ENU poses to GPS |
| F02.2 | F14 | `mark_refined(List[RefinedFrameResult])` | Pass GPS-converted results |
| F14 | F03 | `batch_update_waypoints()` | Batch update waypoints | | F14 | F03 | `batch_update_waypoints()` | Batch update waypoints |
| F14 | F15 | `send_refinement()` × N | Send updates | | F14 | F15 | `send_refinement()` × N | Send updates |
| F15 | Client | SSE `frame_refined` × N | Incremental updates | | F15 | Client | SSE `frame_refined` × N | Incremental updates |
**Note**: F14 does NOT call F10 or F13. F02.2 performs coordinate conversion and provides GPS results to F14.
### Chunk Matching (Background) ### Chunk Matching (Background)
| Source | Target | Method | Purpose | | Source | Target | Method | Purpose |
@@ -332,7 +336,7 @@
| F11 | F06 | `try_chunk_rotation_steps()` | Chunk rotation sweeps (12 rotations) | | F11 | F06 | `try_chunk_rotation_steps()` | Chunk rotation sweeps (12 rotations) |
| F06 | F09 | `align_chunk_to_satellite()` × 12 | Try LiteSAM for each rotation | | F06 | F09 | `align_chunk_to_satellite()` × 12 | Try LiteSAM for each rotation |
| F11 | F10 | `add_chunk_anchor()` | Anchor chunk with GPS | | F11 | F10 | `add_chunk_anchor()` | Anchor chunk with GPS |
| F11 | F10 | `merge_chunks()` | Merge chunk to main trajectory (Sim3) | | F11 | F12 | `merge_chunks(main_chunk, new_chunk)` | Merge new_chunk into main_chunk (Sim3 transform) |
| F10 | Internal | `optimize_global()` | Global optimization after merging | | F10 | Internal | `optimize_global()` | Global optimization after merging |
| F11 | F12 | `mark_chunk_anchored()` | Update chunk state | | F11 | F12 | `mark_chunk_anchored()` | Update chunk state |
+37 -32
View File
@@ -297,8 +297,8 @@ ASTRAL-Next is a GPS-denied UAV visual localization system using tri-layer match
│ │ │ │ │ │ │ │ │ │
│ │ ▼ │ │ │ │ ▼ │ │
│ │ ┌─────────────────────────────────────┐ │ │ │ │ ┌─────────────────────────────────────┐ │ │
│ │ │ F03 save_heading() via F06 │ │ │ │ │ │ F06 update_heading() → returns │ │ │
│ │ │ update_heading() │ │ │ │ │ │ F02.2 calls F03 save_heading() │ │ │
│ │ └─────────────────────────────────────┘ │ │ │ │ └─────────────────────────────────────┘ │ │
│ │ │ │ │ │ │ │
│ └────────────────────────────────────────────────────┘ │ │ └────────────────────────────────────────────────────┘ │
@@ -323,15 +323,15 @@ ASTRAL-Next is a GPS-denied UAV visual localization system using tri-layer match
**Sequence**: **Sequence**:
``` ```
┌──────────────────────────────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────────────────────────────┐
F11 Failure Recovery Coordinator F02.2 calls F11 methods (direct returns, NO EVENTS)
│ │ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. EMIT RecoveryStarted event │ │ │ │ 1. F02.2 calls F11.start_search() → returns SearchSession │ │
│ │ └─ F02.2 updates status to "recovering" │ │ │ │ F02.2 updates status to "recovering" │ │
│ └──────────────────────────────┬──────────────────────────────┘ │ │ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │ │ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 2. create_chunk_on_tracking_loss() via F12 │ │ │ │ 2. F02.2 calls F11.create_chunk_on_tracking_loss() via F12 │ │
│ │ └─ Proactive chunk creation (processing continues) │ │ │ │ └─ Proactive chunk creation (processing continues) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │ │ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │ │ ▼ │
@@ -343,10 +343,9 @@ ASTRAL-Next is a GPS-denied UAV visual localization system using tri-layer match
│ │ │ │ │ │ │ │
│ │ ┌───────────────────────────────────────────────────┐ │ │ │ │ ┌───────────────────────────────────────────────────┐ │ │
│ │ │ For grid_size in [1, 4, 9, 16, 25]: │ │ │ │ │ │ For grid_size in [1, 4, 9, 16, 25]: │ │ │
│ │ │ ├─ F04 expand_search_grid() │ │ │ │ │ │ ├─ F11.expand_search_radius() → tiles │ │ │
│ │ │ ├─ For each tile: │ │ │ │ │ │ ├─ F02.2 fetches tiles via F04 │ │ │
│ │ │ │ ├─ F04 compute_tile_bounds() │ │ │ │ │ │ ├─ F11.try_current_grid() → AlignmentResult │ │ │
│ │ │ │ └─ F09 align_to_satellite(img, tile, bounds)│ │ │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ │ │ └─ If match found: BREAK │ │ │ │ │ │ └─ If match found: BREAK │ │ │
│ │ └───────────────────────────────────────────────────┘ │ │ │ │ └───────────────────────────────────────────────────┘ │ │
@@ -357,8 +356,8 @@ ASTRAL-Next is a GPS-denied UAV visual localization system using tri-layer match
│ │ Single-image match found? │ │ │ │ Single-image match found? │ │
│ ▼ ▼ │ │ ▼ ▼ │
│ ┌─────────────────────┐ ┌────────────────────────────┐ │ │ ┌─────────────────────┐ ┌────────────────────────────┐ │
│ │ EMIT RecoverySucceeded│ │ Continue chunk building │ │ │ │ F11.mark_found() │ │ Continue chunk building │ │
│ │ Resume normal flow │ │ → Flow 7 (Chunk Building) │ │ │ │ Resume normal flow │ │ → Flow 7 (Chunk Building) │ │
│ └─────────────────────┘ │ → Flow 8 (Chunk Matching) │ │ │ └─────────────────────┘ │ → Flow 8 (Chunk Matching) │ │
│ │ (Background) │ │ │ │ (Background) │ │
│ └────────────────────────────┘ │ │ └────────────────────────────┘ │
@@ -480,28 +479,28 @@ ASTRAL-Next is a GPS-denied UAV visual localization system using tri-layer match
**Sequence**: **Sequence**:
``` ```
┌───────────────────────────────────────────────────────────────────────-──┐ ┌───────────────────────────────────────────────────────────────────────-──┐
F11 merge_chunk_to_trajectory() F02.2 orchestrates via F11.merge_chunk_to_trajectory() │
│ │ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. Get chunk frames: F12 get_chunk_frames(chunk_id) │ │ │ │ 1. Get chunk frames: F12 get_chunk_frames(new_chunk_id) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │ │ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │ │ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 2. Anchor chunk: F12 mark_chunk_anchored(chunk_id, gps) │ │ │ │ 2. Anchor chunk: F12 mark_chunk_anchored(new_chunk_id, gps) │ │
│ │ └─ F10 add_chunk_anchor(flight_id, chunk_id, frame_id, │ │ │ │ └─ F10 add_chunk_anchor(flight_id, new_chunk_id, frame_id│ │
│ │ gps, covariance) │ │ │ │ gps, covariance) │ │
│ └──────────────────────────────┬──────────────────────────────┘ │ │ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │ │ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 3. Determine target chunk (predecessor or "main") │ │ │ │ 3. Determine main chunk (predecessor or "main") │ │
│ │ └─ Returns target_chunk_id (predecessor or "main") │ │ │ │ └─ Returns main_chunk_id (predecessor or "main") │ │
│ └──────────────────────────────┬──────────────────────────────┘ │ │ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │ │ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 4. Merge: F12 merge_chunks(target_chunk_id, chunk_id, Sim3) │ │ │ │ 4. Merge: F12 merge_chunks(main_chunk_id,new_chunk_id,Sim3) │ │
│ │ ├─ F10 merge_chunk_subgraphs(flight_id, chunk_id, │ │ │ │ ├─ F10 merge_chunk_subgraphs(flight_id, new_chunk_id, │ │
│ │ │ target_chunk_id, transform) ← Apply Sim(3) │ │ │ │ │ main_chunk_id, transform) ← Apply Sim(3) │ │
│ │ ├─ F12 deactivate_chunk(chunk_id) │ │ │ │ ├─ F12 deactivate_chunk(new_chunk_id) │ │
│ │ └─ F03 save_chunk_state() │ │ │ │ └─ F03 save_chunk_state() │ │
│ └──────────────────────────────┬──────────────────────────────┘ │ │ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │ │ ▼ │
@@ -511,10 +510,11 @@ ASTRAL-Next is a GPS-denied UAV visual localization system using tri-layer match
│ └──────────────────────────────┬──────────────────────────────┘ │ │ └──────────────────────────────┬──────────────────────────────┘ │
│ ▼ │ │ ▼ │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 6. EMIT ChunkMerged event (flight_id,chunk_id,merged_frames)│ │ │ │ 6. F11 returns True → F02.2 coordinates result updates: │ │
│ │ ─ F14 subscribes → update_results_after_chunk_merge() │ │ │ │ ─ F02.2 calls F10 get_trajectory(flight_id) → ENU poses │ │
│ │ ├─ F10 get_trajectory(flight_id) → ENU poses │ │ │ │ ├─ F02.2 calls F13 enu_to_gps() for each frame │ │
│ │ ├─ F13 enu_to_gps() for each frame │ │ │ │ ├─ F02.2 constructs List[RefinedFrameResult] │ │
│ │ └─ F02.2 calls F14.update_results_after_chunk_merge() │ │
│ │ ├─ F03 save_frame_result() + update_waypoint() │ │ │ │ ├─ F03 save_frame_result() + update_waypoint() │ │
│ │ └─ F15 send_refinement() → SSE "frame_refined" × N │ │ │ │ └─ F15 send_refinement() → SSE "frame_refined" × N │ │
│ └─────────────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────┘ │
@@ -522,6 +522,7 @@ ASTRAL-Next is a GPS-denied UAV visual localization system using tri-layer match
``` ```
**Sim(3) Transform**: Translation + Rotation + Scale alignment between chunks **Sim(3) Transform**: Translation + Rotation + Scale alignment between chunks
**Note**: F14 does NOT call F10/F13. F02.2 performs coordinate conversion and passes GPS results.
--- ---
@@ -534,14 +535,18 @@ ASTRAL-Next is a GPS-denied UAV visual localization system using tri-layer match
**Sequence**: **Sequence**:
``` ```
┌──────────────────────────────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────────────────────────────┐
F11 create_user_input_request() F02.2 orchestrates via F11.create_user_input_request() │
│ │ │ │
│ ┌─────────────────────────────────────────────────────────────┐ │ │ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 1. Get UAV image for frame_id │ │ │ 1. F11.create_user_input_request() → returns UserInputRequest│
│ │ 2. Get top-5 candidates from F08 │ │ │ │ └─ Gets UAV image, top-5 candidates from F08 │ │
│ │ 3. Create UserInputRequest │ │ │ │ └─ Returns request object (does NOT call F15) │ │
│ 4. F15 send_user_input_request() → SSE "user_input_needed" │ └──────────────────────────────┬──────────────────────────────┘
│ 5. EMIT UserInputNeeded event
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ 2. F02.2 receives UserInputRequest │ │
│ │ ├─ F02.2 calls F15.send_user_input_request() │ │
│ │ │ → SSE "user_input_needed" │ │
│ │ └─ F02.2 updates status to "BLOCKED" │ │ │ │ └─ F02.2 updates status to "BLOCKED" │ │
│ └─────────────────────────────────────────────────────────────┘ │ │ └─────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────┘ └──────────────────────────────────────────────────────────────────────────┘
+13 -6
View File
@@ -87,7 +87,7 @@
## 2.10 **🤖📋AI plan**: Generate components ## 2.10 **🤖📋AI plan**: Generate components
### Execute `/2.10_gen_components` ### Execute `/2.planning/2.10_gen_components`
### Revise ### Revise
- Revise the plan, answer questions, put detailed descriptions - Revise the plan, answer questions, put detailed descriptions
@@ -97,9 +97,9 @@
save plan to `docs/02_components/00_decomposition_plan.md` save plan to `docs/02_components/00_decomposition_plan.md`
## 2.15 **🤖📋AI plan**: Components assesment ## 2.15 **🤖AI agent**: Components assesment
### Execute `/2.15_components_assesment` ### Execute `/2.planning/2.15_components_assesment`
### Revise ### Revise
- Revise the plan, answer questions, put detailed descriptions - Revise the plan, answer questions, put detailed descriptions
@@ -108,9 +108,16 @@
### plan ### plan
save plan to `docs/02_components/00_decomposition_plan.md` save plan to `docs/02_components/00_decomposition_plan.md`
## 2.20 **🤖📋AI plan**: Generate Jira Epics ## 2.20 **🤖AI agent**: Generate Jira Epics
### Execute `/2.20/_gen_epics` ### Add Jira MCP to IDE and authenticate
```
"Jira-MCP-Server": {
"url": "https://mcp.atlassian.com/v1/sse"
}
```
### Execute `/2.planning/2.20_gen_epics use jira mcp`
### Revise ### Revise
- Revise the epics, answer questions, put detailed descriptions - Revise the epics, answer questions, put detailed descriptions
@@ -128,7 +135,7 @@
## 2.40 **🤖📋AI plan**: Component Decomposition To Features ## 2.40 **🤖📋AI plan**: Component Decomposition To Features
### Execute ### Execute
For each component in `docs/02_components` run For each component in `docs/02_components` run
`/2.40_gen_features --component @docs/02_components/[##]_[component_name]/[component_name]_spec.md` `/2.planning/2.40_gen_features --component @[component_name]_spec.md`
### Revise ### Revise
- Revise the features, answer questions, put detailed descriptions - Revise the features, answer questions, put detailed descriptions