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

7.1 KiB
Raw Permalink Blame History

Component — scan_controller

Layer: Decision + Memory Status: forward-looking design (Rust)

1. Purpose

The system's brain. A deterministic typed state machine — ZoomedOut, ZoomedIn { roi, hold_started_at }, and TargetFollow { target_id, started_at }. Owns the POI queue, timeouts, the ≤5 POIs/min operator-review cap, the confidence-scaled operator-decision window, gimbal command issuance, and the new/moved/existing/removed dispatch into mapobjects_store.

The full behaviour-tree spec — including tick scenarios and the 15 fixed-wing rules — lives in system-flows.md §F4.

2. Inputs

Input Source Cadence Notes
DetectionBatch detection_client per frame Tier 1 primitives.
MovementCandidate movement_detector per frame at both zoom-out and zoom-in (suppressed only during TargetFollow) Each candidate carries source_zoom_band.
Tier2Evidence semantic_analyzer per zoom-in hold Path / endpoint / concealment scoring.
VlmAssessment vlm_client (optional) per zoom-in endpoint hold status: disabled if VLM is off.
Operator commands operator_bridge event confirm / decline / target-follow start / target-follow release. Authenticated, signed, replay-protected upstream of this component.
UAV telemetry mavlink_layer (via mission_executor) 10 Hz target Position used for proximity-weighted POI priority and middle-waypoint computation.
Mission state mission_executor event Current waypoint, mission progress; used for sweep-vs-route alignment.
MapObjects sync state mapobjects_store event at startup + post-flight synced / cached_fallback / degraded — surfaces a health flag and (for degraded) suppresses MapObject diff classifications until corrected.

3. Outputs

Output Consumer Shape
GimbalCommand (yaw / pitch / zoom) gimbal_controller per state-machine tick or per zoom-in plan step
POI to operator operator_bridge (then telemetry_stream) enqueue / dequeue events
Middle-waypoint hint mission_executor event on operator-confirmed target
MapObjects update mapobjects_store new / moved / existing / removed dispatch
Health metric health aggregator state, pois_in_queue, pois_per_min, tick_latency_p99, last_state_change_ts, mapobjects_sync_state.

4. Key Responsibilities

  • Run the ZoomedOut / ZoomedIn / TargetFollow state machine. Transitions are explicit, typed, and fully enumerated; no ad-hoc booleans.
  • Maintain the POI queue ordered by confidence × proximity_to_current_camera × age_factor. Hard-cap output to ≤5 POIs/min surfaced to the operator.
  • Apply the confidence-scaled operator decision window (40 % → 30 s, 100 % → 120 s, linear; below 40 % the POI is not surfaced). Timeout = forget; decline = IgnoredItem entry via mapobjects_store.
  • Suppress new POIs whose (MGRS, class_group) matches an existing IgnoredItem.
  • For each new detection or movement candidate: compute the H3 cell, ask mapobjects_store to classify as new / moved / existing, and only surface non-existing entries.
  • Zoom-in candidate handling. When a MovementCandidate arrives with source_zoom_band = zoomed_in, evaluate against the current ROI: if inside, bump current-ROI confidence; if outside the ROI but inside the broader zoomed FOV, enqueue as a candidate-POI; only interrupt the current zoom-in hold if the candidate's priority exceeds the current hold's priority.
  • On operator confirmation: hand a middle-waypoint hint to mission_executor, transition to TargetFollow, and command gimbal_controller to keep the target in the centre 25 % of frame.
  • On operator decline / timeout / target loss: append (decline only) an IgnoredItem and return to ZoomedOut.
  • On mapobjects_store reporting sync_state = degraded, surface health → red and do not classify new detections (avoid corrupting the central observation log on next push); continue to surface POIs to the operator on Tier-1 + movement evidence alone.

5. Internal State

The state machine lives entirely in this component. State variables:

  • Current state: ZoomedOut | ZoomedIn { roi, hold_started_at } | TargetFollow { target_id, started_at }.
  • POI queue: ordered, with per-entry priority and queue position.
  • Per-class operator-decision-window thresholds.
  • Last-N tick timestamps for tick-latency observability.
  • Frame-rate floor monitor: when sustained FPS < 10, suppress ZoomedOut → ZoomedIn transitions and surface health → yellow.

State is in-process only; restart starts in ZoomedOut with an empty queue.

6. Failure Modes

Failure Detection Behaviour
detection_client health red health input Continue zoom-out sweep; emit no new POIs from Tier 1; movement candidates still flow.
movement_detector health red health input Continue; lose movement-candidate enqueueing.
semantic_analyzer health red health input Skip Tier 2; surface POIs with Tier-1-only evidence; flag in operator overlay.
vlm_client returns status: disabled | timeout | ipc_error | schema_invalid per-call status Surface POI without VLM evidence (fail-closed).
gimbal_controller not ready health input Stay in current state; alert; do not silently drop scan steps.
operator_bridge disconnected health input Continue zoom-out (operator UI is unreachable, but the system must not crash); pause POI surfacing; resume on reconnect. F10 lost-link ladder owns the larger response.
mapobjects_store sync degraded sync_state input Suppress diff classifications; surface POIs on Tier-1 + movement only; health → red.
Sustained FPS < 10 self-instrumented Suppress zoom-in transitions; health → yellow.
Tick-latency above budget self-instrumented Health → yellow; investigate (likely upstream consumer slowness).

7. Dependencies

In-process (input): detection_client, movement_detector, semantic_analyzer, vlm_client, operator_bridge, mission_executor, mapobjects_store. In-process (output): gimbal_controller, operator_bridge, mission_executor, mapobjects_store.

External: none directly. All external integrations are mediated by other components.

8. Non-Functional Targets

Concern Target
Tick latency ≤10 ms p99
POI enqueue → operator surface ≤1 s in normal load
POI rate to operator ≤5 POIs/min (hard cap)
Zoom-out → zoom-in transition ≤2 s including physical zoom
Zoom-in hold duration configurable; default 5 s/POI
Target-follow centre-window target inside centre 25 % of frame while visible
Frame-rate floor ≥10 fps sustained; below this, suppress zoom-in transitions

9. References

  • architecture.md §3, §5 Architectural Principles, §6 NFR, §7.6 Scan controller and POI queue, §7.12 New vs Existing / Moved / Removed Object Detection, §7.13 MapObjects Sync.
  • system-flows.md §F4 Scan controller behaviour tree (full BT spec, tick scenarios, 15 fixed-wing rules).
  • data_model.md §POI, §IgnoredItem, §MapObject.