Files
Oleksandr Bezdieniezhnykh bc40ea7300 [AZ-626] Decompose complete: 47 tasks + docs + module layout
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>
2026-05-19 11:02:01 +03:00

22 KiB
Raw Permalink Blame History

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

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.01.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.01.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.01.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 — MissionItemMissionWaypoint

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_WAYPOINTs 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_WAYPOINTs

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.01.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 MissionItems 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.