mirror of
https://github.com/azaion/autopilot.git
synced 2026-06-21 12:31:09 +00:00
bc40ea7300
Greenfield Steps 1-6 baseline for the autopilot rewrite from legacy Qt/C++ to a Rust workspace. - Remove legacy Qt/C++ tree (ai_controller, drone_controller, misc/camera, python_scaffold, root Dockerfile, autopilot.pro, legacy main.py / requirements.txt). - Add _docs/00_problem (problem, restrictions, acceptance criteria, security approach, input data + fixtures). - Add _docs/01_solution/solution_draft01. - Add _docs/02_document (architecture, system-flows, data_model, glossary, decision-rationale, deployment, 13 component descriptions, tests/ specs, FINAL_report, module-layout). - Add _docs/02_tasks/todo with 47 task specs (AZ-640..AZ-686, one bootstrap + 46 component tasks) and _dependencies_table.md. - Add .cursor/rules/artifact-srp.mdc (single-responsibility rule for canonical _docs artifacts). - Track autodev state in _docs/_autodev_state.md (Step 6 completed, ready for Step 7 Implement). Jira: bootstrap AZ-626; component epics AZ-627..AZ-639; tasks AZ-640..AZ-686. Total complexity 173 points across 12 epics. Co-authored-by: Cursor <cursoragent@cursor.com>
385 lines
22 KiB
Markdown
385 lines
22 KiB
Markdown
# autopilot — Data Model
|
||
|
||
**Status**: forward-looking design (Rust). This is the canonical entity catalogue.
|
||
|
||
The autopilot binary itself has **one** persistent store: the on-device `mapobjects_store` (engine TBD — `architecture.md §8 Q3`). Everything else is in-memory only. Mission state and the central MapObjects state are pulled from the external `missions` API on start; there is no in-process mission database. The on-device `mapobjects_store` is a working copy of the central MapObjects state for the active mission's bounding box; the central observation log is the source of truth across missions (per `architecture.md §7.13`).
|
||
|
||
---
|
||
|
||
## 1. Entity Map
|
||
|
||
```mermaid
|
||
erDiagram
|
||
Frame ||--o{ Detection : "produced by detection_client"
|
||
Frame ||--o{ MovementCandidate : "produced by movement_detector (zoom-out + zoom-in)"
|
||
Detection ||--|| BoundingBox : "bbox_normalized"
|
||
DetectionBatch ||--o{ Detection : "contains"
|
||
|
||
POI ||--o| Tier2Evidence : "zoom-in Tier 2"
|
||
POI ||--o| VlmAssessment : "Tier 3 (optional, zoom-in)"
|
||
POI }o--o| MapObject : "lookup by H3 + class"
|
||
POI }o--o| IgnoredItem : "decline_suppressed"
|
||
|
||
MapObject ||--o{ MapObjectObservation : "history (central append-only log)"
|
||
MapObjectsBundle ||--o{ MapObject : "pre-flight pull"
|
||
MapObjectsBundle ||--o{ MapObjectObservation : "post-flight push"
|
||
MapObjectsBundle ||--o{ IgnoredItem : "ignored items round-trip"
|
||
|
||
OperatorCommand ||--o| POI : "confirm/decline target"
|
||
|
||
MissionItem ||--o{ MissionWaypoint : "translates to"
|
||
MissionItem ||--o{ Geofence : "carries"
|
||
Geofence }o--o{ Coordinate : "polygon"
|
||
MissionWaypoint ||--|| Coordinate : "at"
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Perception entities
|
||
|
||
### `Frame`
|
||
|
||
A decoded video frame. Produced by `frame_ingest`; consumed by `detection_client`, `movement_detector`, `telemetry_stream`.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `seq` | u64 | Monotonic sequence number; primary key for cross-component correlation. |
|
||
| `capture_ts_monotonic_ns` | u64 | Wall-clock-independent timestamp at the earliest practical point in the pipeline. |
|
||
| `decode_ts_monotonic_ns` | u64 | When `frame_ingest` finished decoding. |
|
||
| `pixels` | `Arc<Bytes>` | Raw pixel data; consumers do not copy. |
|
||
| `width`, `height` | u32 | |
|
||
| `pix_fmt` | enum | `NV12` \| `YUV420P` \| `RGB24` (decoder dependent). |
|
||
| `ai_locked` | bool | If set, downstream consumers skip detection (operator-side or supervisor gating). |
|
||
|
||
In-memory only.
|
||
|
||
### `BoundingBox`
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `x_min`, `y_min`, `x_max`, `y_max` | f32 | Normalised to `[0.0, 1.0]` in image coordinates. |
|
||
|
||
### `Detection`
|
||
|
||
One Tier-1 detection. Mirrors the `../detections` contract; carries through to operator overlay unchanged.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `class_id` | u32 | |
|
||
| `class_name` | string | Human-readable label. |
|
||
| `confidence` | f32 | 0.0–1.0. |
|
||
| `bbox_normalized` | `BoundingBox` | |
|
||
| `mask_or_polyline` | optional bytes | For polyline classes (e.g. footpaths). |
|
||
| `source_frame_seq` | u64 | Foreign key into `Frame`. |
|
||
|
||
### `DetectionBatch`
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `frame_seq` | u64 | |
|
||
| `detections` | `Vec<Detection>` | |
|
||
| `latency_ms` | u32 | Tier-1 round-trip; observed for budget compliance. |
|
||
| `model_version` | string | Reported by `../detections`; logged on change. |
|
||
|
||
### `MovementCandidate`
|
||
|
||
A residual-motion cluster surviving ego-motion compensation in `movement_detector`.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `frame_seq` | u64 | |
|
||
| `bbox_normalized` | `BoundingBox` | |
|
||
| `residual_velocity_estimate` | optional struct | Direction + magnitude in image coords; used for prioritisation. |
|
||
| `telemetry_quality` | enum | `synced` \| `degraded` \| `unsynced` (drives whether the candidate may be surfaced at all). |
|
||
| `source_frame_ts_monotonic_ns` | u64 | |
|
||
| `source_zoom_band` | enum | `zoomed_out` \| `zoomed_in`. Drives `scan_controller`'s queueing logic (per `system-flows.md §F2`): zoom-out candidates enter the POI queue normally; zoom-in candidates may bump current-ROI confidence or enter the queue with their own priority. |
|
||
|
||
### `Tier2Evidence`
|
||
|
||
Output of `semantic_analyzer` for a single zoom-in ROI hold.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `roi_id` | uuid | Stable identifier within a zoom-in hold. |
|
||
| `path_freshness` | f32 \| null | 0.0 = no path / not applicable; 1.0 = fresh. |
|
||
| `endpoint_score` | f32 \| null | Concealed-position likelihood at an endpoint (branch pile / dark entrance). |
|
||
| `concealment_score` | f32 \| null | General concealment-POI score. |
|
||
| `recommended_next_action` | enum | `PanFollowFootpath` \| `HoldEndpoint` \| `PanBroad` \| `ReturnToZoomOut`. |
|
||
| `source_detections` | `Vec<DetectionId>` | For audit / replay. |
|
||
| `status` | enum | `ok` \| `timeout` \| `oversize` \| `error`. |
|
||
|
||
### `VlmAssessment`
|
||
|
||
Validated, structured response from `vlm_client`. Free-form VLM text is **not** a downstream API.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `label` | enum | `confirmed_concealed_position` \| `rejected` \| `inconclusive` \| `error`. |
|
||
| `confidence` | f32 | 0.0–1.0; VLM-reported or derived. |
|
||
| `evidence_spans` | `Vec<string>` | Short justifications, bounded length. |
|
||
| `reason` | string | One-line rationale; bounded length. |
|
||
| `status` | enum | `ok` \| `timeout` \| `schema_invalid` \| `ipc_error` \| `disabled`. |
|
||
| `latency_ms` | u32 | Round-trip including IPC. |
|
||
| `model_version` | string | Reported by the NanoLLM process for the loaded weights; logged on change for forensic correlation. |
|
||
|
||
`status` semantics: any value other than `ok` MUST result in `label = inconclusive` (or `error` for a critical failure). `scan_controller` MUST NOT promote a POI to a confirmed target on a non-`ok` `VlmAssessment`.
|
||
|
||
---
|
||
|
||
## 3. Decision entities
|
||
|
||
### `POI`
|
||
|
||
A Point-of-Interest enqueued by `scan_controller`. Source: a Tier-1 detection, a movement candidate from `movement_detector`, or a Tier-2 semantic finding.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `id` | uuid | Stable for the POI's lifetime. |
|
||
| `confidence` | f32 (0.0–1.0) | Composite of detection / motion / Tier-2 score. |
|
||
| `mgrs` | string | MGRS coordinate from the GPS-Denied service or autopilot GPS. |
|
||
| `class` | string | Concrete class. |
|
||
| `class_group` | enum | Per `mapobjects_store` config (e.g. `military_vehicle_group`, `concealed_position_group`, `movement_candidate`). |
|
||
| `source_detection_ids` | `Vec<DetectionId>` | For audit / replay. |
|
||
| `enqueued_at` | timestamp | For queue ageing. |
|
||
| `priority` | f32 | `confidence × proximity_to_current_camera × age_factor`. |
|
||
| `decline_suppressed` | bool | True if `(MGRS, class_group)` matches an existing `IgnoredItem`. |
|
||
| `vlm_status` | enum | Mirrors `VlmAssessment.status` (or `not_requested` / `pending`). |
|
||
| `tier2_evidence` | optional `Tier2Evidence` | |
|
||
| `deadline` | timestamp | Per the confidence-scaled operator-decision window. |
|
||
|
||
Field `queue_position` is **not** stored; it is computed at read time from `priority` + `enqueued_at`.
|
||
|
||
### `MapObject`
|
||
|
||
A persisted map entry, indexed by H3 cell. Owned by `mapobjects_store`; written on each `NEW` / `MOVED` classification, read on each new detection. The on-device `MapObject` is a **working copy** of the central state for the active mission.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `h3_cell` | u64 | H3 cell index at the configured resolution (default `res 10`, ~15 m edge). |
|
||
| `mgrs_key` | string | MGRS coordinate; together with `class` forms the hashtable composite key. |
|
||
| `class` | string | Concrete class (not the group). |
|
||
| `class_group` | string | Group used for matching during `EXISTING` / `MOVED` / `NEW` classification. |
|
||
| `gps_lat`, `gps_lon` | f64 | For distance calculation against incoming detections. |
|
||
| `size_width_m`, `size_length_m` | f32 | Bounding area on the ground. |
|
||
| `confidence` | f32 | Latest observation confidence (or running average, per implementation). |
|
||
| `first_seen`, `last_seen` | timestamp | Earliest and most recent observation; `last_seen` drives the `REMOVED` candidate diff at region-end. |
|
||
| `mission_id` | string | For the `DELETE /missions/{id}` cascade. |
|
||
| `source` | enum | `central_pulled` (came from pre-flight pull) \| `local_observed` (added during this mission). On post-flight push only `local_observed` records become new observations centrally. |
|
||
| `pending_upload` | bool | True for any `local_observed` entry not yet pushed centrally. Cleared on successful `POST /missions/{id}/mapobjects` ack. |
|
||
|
||
Persisted in `mapobjects_store` (engine TBD per `architecture.md §8 Q3`).
|
||
|
||
### `MapObjectObservation`
|
||
|
||
A single per-detection record. The on-device store appends one of these per NEW / MOVED / EXISTING / REMOVED-CANDIDATE classification; the post-flight push uploads the unflushed list to the central `missions` API. The central side stores all observations append-only as the source of truth (per `architecture.md §7.13`).
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `id` | uuid | Locally generated; stable across the mission. |
|
||
| `h3_cell` | u64 | |
|
||
| `class` | string | Concrete class. |
|
||
| `class_group` | string | Group used for the diff. |
|
||
| `mission_id` | string | |
|
||
| `uav_id` | string | Identifies the airframe; assigned at provisioning. |
|
||
| `observed_at_monotonic_ns` | u64 | Local monotonic at observation. |
|
||
| `observed_at_wallclock` | timestamp | Bound from GPS or NTP per the wall-clock policy. |
|
||
| `gps_lat`, `gps_lon` | f64 | |
|
||
| `mgrs` | string | |
|
||
| `size_width_m`, `size_length_m` | f32 | |
|
||
| `confidence` | f32 | |
|
||
| `diff_kind` | enum | `NEW` \| `MOVED` \| `EXISTING` \| `REMOVED_CANDIDATE`. |
|
||
| `photo_ref` | string \| null | URL or compact reference; uploaded out-of-band per the central API contract (Q7). |
|
||
| `raw_evidence` | json \| null | Audit payload; size-capped. |
|
||
|
||
In-memory; durably persisted in `mapobjects_store` until the post-flight push acknowledges. On the central side, `map_object_observations` is the corresponding table (see `architecture.md §7.13`).
|
||
|
||
### `MapObjectsBundle`
|
||
|
||
The wire shape for both the pre-flight pull (response body) and the post-flight push (request body) on `/missions/{id}/mapobjects`.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `schema_version` | string | Semver; mismatched versions are rejected. |
|
||
| `mission_id` | string | |
|
||
| `bbox` | `Coordinate[2]` (NW + SE) | The mission area; used by the central API to scope the response. |
|
||
| `map_objects` | `Vec<MapObject>` | Pre-flight: current view from the central store. Post-flight push uses `MapObjectObservation` instead (see below). |
|
||
| `observations` | `Vec<MapObjectObservation>` | Post-flight: the full pass diff. |
|
||
| `ignored_items` | `Vec<IgnoredItem>` | Pre-flight: union-merged from the central store. Post-flight: only items appended during this mission. |
|
||
| `as_of` | timestamp | Pre-flight: when the central store snapshot was computed. Post-flight: when the on-device flush started. |
|
||
| `freshness` | enum (pre-flight only) | `fresh` (≤ configured staleness window) \| `stale` (operator must acknowledge to use). |
|
||
|
||
### `IgnoredItem`
|
||
|
||
A scene the operator declined; consulted by `scan_controller` before promoting any future detection to a POI. Union-merged across missions on the central side (per `architecture.md §7.13` conflict resolution).
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `id` | uuid | Locally generated. |
|
||
| `mgrs` | string | Decline location. |
|
||
| `h3_cell` | u64 | For central-side indexing. |
|
||
| `class_group` | string | Class group of the declined detection. |
|
||
| `decline_time` | timestamp | Wall-clock at decline (operator-side). |
|
||
| `operator_id` | string \| null | If known from the Ground Station session. |
|
||
| `mission_id` | string | The mission during which the decline happened. |
|
||
| `retention_scope` | enum | `mission` (cleared at mission end on-device, retained centrally indexed by mission) \| `session` (cleared at session end on-device) \| `until_expiry` (carries `expires_at`). |
|
||
| `expires_at` | timestamp \| null | Required when `retention_scope = until_expiry`. |
|
||
| `source` | enum | `central_pulled` (pre-flight pull) \| `local_appended` (during this mission). Only `local_appended` is uploaded to central in the post-flight push. |
|
||
| `pending_upload` | bool | True for any `local_appended` entry not yet pushed centrally. |
|
||
|
||
Lookup key: `(MGRS, class_group)` exact match (subject to the same H3 k-ring widening as `MapObject` lookups, when configured).
|
||
|
||
Persisted in `mapobjects_store`. Central-side table: `map_object_ignored` per `architecture.md §7.13`.
|
||
|
||
---
|
||
|
||
## 4. Action / piloting entities
|
||
|
||
### `Coordinate`
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `latitude` | f64 | Geographic; degrees. |
|
||
| `longitude` | f64 | Geographic; degrees. |
|
||
| `altitude_m` | f32 | Above ground or above home, depending on usage; the carrying entity defines the frame. |
|
||
|
||
### `Geofence`
|
||
|
||
A polygon on the mission. Both INCLUSION and EXCLUSION are honoured by `mission_executor`.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `kind` | enum | `INCLUSION` \| `EXCLUSION`. |
|
||
| `vertices` | `Vec<Coordinate>` | Polygon vertices in order. |
|
||
|
||
### `MissionItem`
|
||
|
||
The business-level mission item: what the `missions` API delivers and what the operator authored. **Owned by `mission-schema`**, the artefact shared with the `missions` repo (extraction location TBD — `architecture.md §8 Q5`).
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `id` | uuid | |
|
||
| `kind` | enum | `waypoint` \| `search` \| `region_search` \| `return` \| `target_follow_breakpoint`. |
|
||
| `at` | optional `Coordinate` | For `waypoint` / `return`. |
|
||
| `region` | optional polygon | For `region_search`. |
|
||
| `cruise_speed_mps` | optional f32 | If set, `mission_executor` emits a `MAV_CMD_DO_CHANGE_SPEED` waypoint before the affected items. |
|
||
| `target_classes` | optional `Vec<string>` | Per-item search hint (e.g. `tank`, `artillery`). |
|
||
|
||
### `MissionWaypoint`
|
||
|
||
The MAVLink-level wire item: what `mavlink_layer` sends to ArduPilot / PX4. **Owned by `mavlink_layer`**.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `seq` | u16 | MAVLink mission item sequence number. |
|
||
| `frame` | enum | `MAV_FRAME_GLOBAL_RELATIVE_ALT` (system default; no terrain-following). |
|
||
| `command` | enum | One of: `MAV_CMD_NAV_TAKEOFF`, `MAV_CMD_NAV_WAYPOINT`, `MAV_CMD_NAV_LAND`, `MAV_CMD_DO_CHANGE_SPEED`, `MAV_CMD_NAV_RETURN_TO_LAUNCH`, `MAV_CMD_DO_SET_MODE`. |
|
||
| `current` | bool | True only for the very first item in a fresh upload. |
|
||
| `auto_continue` | bool | True for everything except the final item. |
|
||
| `param_1..param_4` | f32 | Command-specific. |
|
||
| `lat_deg_e7`, `lon_deg_e7` | i32 | Scaled-integer geographic coordinates. |
|
||
| `alt_m` | f32 | Above home (relative). |
|
||
|
||
### Translation contract — `MissionItem` → `MissionWaypoint`
|
||
|
||
Owner: `mission_executor`, variant-aware (multirotor / fixed-wing).
|
||
|
||
| Source `MissionItem.kind` | Resulting `MissionWaypoint`(s) |
|
||
|---|---|
|
||
| `waypoint` | exactly one `MAV_CMD_NAV_WAYPOINT` |
|
||
| `region_search` | sequence of `MAV_CMD_NAV_WAYPOINT`s computed per the sweep pattern (`architecture.md §8 Q1`) |
|
||
| `return` | one `MAV_CMD_NAV_RETURN_TO_LAUNCH` (or `MAV_CMD_NAV_LAND` at the explicit return point) |
|
||
| `target_follow_breakpoint` | (none) — used only as a structural marker for re-upload; not sent to MAVLink |
|
||
| (cruise speed carried by a `MissionItem`) | one `MAV_CMD_DO_CHANGE_SPEED` placed **before** the affected `MAV_CMD_NAV_WAYPOINT`s |
|
||
|
||
Multirotor variants prepend `MAV_CMD_NAV_TAKEOFF` and append `MAV_CMD_NAV_LAND`. Fixed-wing variants do neither (the airframe is RC-launched and put into AUTO by the operator); they only upload + start the mission.
|
||
|
||
The cruise-speed translation is required to **reach the autopilot**. If a `MissionItem` declares a cruise speed, the corresponding `MAV_CMD_DO_CHANGE_SPEED` MUST be present in the uploaded sequence with the speed in `param_1`. Conformance test in `deployment/ci_cd_pipeline.md §5`.
|
||
|
||
### `OperatorCommand`
|
||
|
||
Every command from the Ground Station to autopilot is wrapped in this authenticated envelope. The principle is committed (`architecture.md §5`); the exact signature scheme is open per Q9. `operator_bridge` rejects any command that fails signature validation, replay-protection check, or session validation.
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `command_id` | uuid | Idempotency key; cached for 60 s by `operator_bridge`. |
|
||
| `session_token` | string | Opaque session token issued by the Ground Station at operator login; bound to `operator_id`. |
|
||
| `sequence_number` | u64 | Monotonically increasing per-session; replay-protection. Lower-or-equal numbers per session are rejected. |
|
||
| `issued_at_wallclock` | timestamp | Operator-side wall-clock. Used for forensic audit; not used for trust decisions. |
|
||
| `kind` | enum | `confirm_poi` \| `decline_poi` \| `start_target_follow` \| `release_target_follow` \| `acknowledge_bit_degraded` \| `safety_override` \| `mission_abort`. |
|
||
| `payload` | json | Action-specific body. |
|
||
| `signature` | bytes | Signature over (`session_token`, `sequence_number`, `kind`, `payload`). Scheme TBD per Q9. |
|
||
|
||
`scan_controller` and `mission_executor` see only the validated payload; the auth envelope is opaque to them. Audit logs record `command_id`, `operator_id` (resolved from session token), `kind`, and result.
|
||
|
||
### `GimbalState`
|
||
|
||
| Field | Type | Notes |
|
||
|---|---|---|
|
||
| `yaw`, `pitch` | f32 | Degrees. |
|
||
| `zoom` | f32 | Effective focal length or zoom factor (vendor-specific). |
|
||
| `ts_monotonic_ns` | u64 | Stamp at the moment the gimbal feedback was received. |
|
||
| `command_in_flight` | bool | True between command issuance and feedback that motion completed. |
|
||
|
||
In-memory only; consumed by `frame_ingest` and `movement_detector` for telemetry-skew compensation.
|
||
|
||
---
|
||
|
||
## 5. Sync / wire formats
|
||
|
||
### MGRS sync message — wire format
|
||
|
||
The operator round trip (`telemetry_stream` ⇄ Ground Station) uses MGRS-encoded payloads in both directions. Field separator is `::`.
|
||
|
||
**Drone → Operator (detection report):**
|
||
|
||
| Position | Field | Type | Notes |
|
||
|---|---|---|---|
|
||
| 1 | `missionId` | string | Server-assigned mission UUID. |
|
||
| 2 | `MGRS(encoded)` | string | MGRS coordinate (compact, military-grid). |
|
||
| 3 | `class` | string | Concrete detection class. |
|
||
| 4 | `confidence` | f32 | 0.0–1.0. |
|
||
| 5 | `size_width_m` | f32 | Ground-projected width. |
|
||
| 6 | `size_length_m` | f32 | Ground-projected length. |
|
||
| 7 | `photo_metadata` | string | URL or compact reference to the snapshot frame. |
|
||
| 8 | `flags` | bitmask | Reserved (e.g. `target_follow_active`, `vlm_used`, `movement_origin`). |
|
||
|
||
**Operator → Drone (command / acknowledgment):**
|
||
|
||
| Position | Field | Type | Notes |
|
||
|---|---|---|---|
|
||
| 1 | `missionId` | string | Must match the drone-side mission. |
|
||
| 2 | `Encoded(GroundMGRS :: Time)` | string | Operator's ground location + decision timestamp. |
|
||
| 3 | (variable) | … | Action-specific payload (POI ID, action enum, follow-toggle, etc.). |
|
||
| N | `missionId2` | string | Echo of `missionId` for stream-multiplexing safety. |
|
||
|
||
The exact serialisation of position 3 (action payload) is left to the Ground Station API contract (open question; see `architecture.md §8 Q2`).
|
||
|
||
---
|
||
|
||
## 6. Persistence and lifecycle
|
||
|
||
| Entity | Persisted? | Where | Lifecycle |
|
||
|---|---|---|---|
|
||
| `Frame`, `Detection`, `DetectionBatch`, `MovementCandidate`, `Tier2Evidence`, `VlmAssessment`, `GimbalState` | no | in-memory | per frame / per ROI / per command — dropped on state change. |
|
||
| `POI` | no | in-memory inside `scan_controller` | enqueued, surfaced, decided (confirm / decline / timeout), then dropped. |
|
||
| `MapObject` | yes | `mapobjects_store` (working copy of central state) | mission-scoped on-device; appended to central observation log via post-flight push (F8); cleared on `DELETE /missions/{id}` cascade. |
|
||
| `MapObjectObservation` | yes | `mapobjects_store` until acknowledged centrally | per-detection append-log; durable across in-flight crash; cleared per record on `POST /missions/{id}/mapobjects` ack. |
|
||
| `IgnoredItem` | yes | `mapobjects_store` (working copy + post-flight upload of locally-appended items) | per `retention_scope`; central side union-merged. |
|
||
| `MissionItem` | no in autopilot | source of truth is the `missions` API | pulled on start; refreshed on middle-waypoint POST. |
|
||
| `MissionWaypoint` | no | in-memory inside `mavlink_layer` | re-derived from `MissionItem`s on each upload / re-upload. |
|
||
| `OperatorCommand` | partial | command-id cache (60 s) for idempotency; full audit log persisted on disk | per-command; audit-retained per configured policy. |
|
||
|
||
---
|
||
|
||
## 7. Versioning and contracts
|
||
|
||
| Contract | Owner | Versioning |
|
||
|---|---|---|
|
||
| `mission-schema` (the `MissionItem` shape) | shared between `autopilot` and `missions` repos; extraction location TBD (`architecture.md §8 Q5`) | semantic versioning; `mission_client` validates `schema_version` on fetch. |
|
||
| MapObjects bundle schema (`MapObjectsBundle` for pull/push, `MapObjectObservation` for the central observation log) | shared between `autopilot` and `missions` repos as part of the §7.13 endpoint extension | semantic versioning; `mission_client` validates `schema_version`; central side rejects mismatches with 4xx (`architecture.md §8 Q7`). |
|
||
| `../detections` gRPC contract | `../detections` repo (per `../_docs/03_detections.md`) | versioned; `detection_client` rejects schema mismatches (`architecture.md §8 Q4`). |
|
||
| `VlmAssessment` schema | autopilot-internal (this document is the source of truth) | versioned; `vlm_client` rejects schema-invalid responses. The `model_version` field correlates assessments with VLM weights. |
|
||
| MGRS sync wire format | autopilot-internal (this document is the source of truth) | versioned; field-position changes are breaking. |
|
||
| MAVLink command surface | per `architecture.md §7.7` | adding messages requires explicit design review. |
|
||
| `OperatorCommand` envelope (signature scheme) | open per `architecture.md §8 Q9` | once chosen, versioned; both Ground Station and `operator_bridge` must agree. |
|