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>
9.1 KiB
Component — mapobjects_store
Layer: Decision + Memory Status: forward-looking design (Rust); on-device working copy of the central MapObjects state, mission-bracketed
1. Purpose
On-device, H3-indexed working copy of the centrally maintained MapObjects state plus the IgnoredItems list, scoped to the active mission's bounding box. Computes new / moved / existing / removed diffs across survey passes and is the source of truth for the operator-decline suppression rule for the duration of the active mission.
This is not a private database. It is hydrated pre-flight from the central missions API (/missions/{id}/mapobjects) and the mission's full pass diff is pushed back post-flight. The central observation log + computed current view are authoritative across missions and across UAVs (architecture.md §7.13).
2. Inputs
| Input | Source | Cadence | Notes |
|---|---|---|---|
| Pre-flight pull payload | mission_client (from missions API) |
once per mission | Hydrates current_state + pending_ignored. |
| New detection / movement candidate (with MGRS + class + size) | scan_controller |
per detection | Each is classified as new / moved / existing. |
IgnoredItem append |
scan_controller (on operator decline) |
event | (MGRS, class_group) plus operator metadata. |
| End-of-pass marker | scan_controller / mission_executor |
event per pass over a region | Triggers the removed-candidate sweep. |
| Mission delete cascade | suite-level missions API hook (process-level config; not a network call) | event | Drops mission-scoped objects on mission deletion. |
| Post-flight push trigger | mission_executor |
once per mission, on terminal state | Causes mission_client to drain pending_observations + pending_ignored to the central API. |
3. Outputs
| Output | Consumer | Shape |
|---|---|---|
MapObjectClassification |
scan_controller |
new | moved | existing | removed_candidate per detection |
IgnoredItem match |
scan_controller |
suppression flag for (MGRS, class_group) |
| Pass diff | mission_client (post-flight upload) + operator_bridge (optionally surfaced in-flight) |
new / moved / removed lists per pass |
| Sync state | scan_controller, health aggregator |
synced | cached_fallback | degraded; pending_observations_count, pending_ignored_count |
4. Key Responsibilities
- Pre-flight hydrate from
mission_clientpull. Establishcurrent_stateandpending_ignored. Surfacesync_state(syncedorcached_fallbackordegraded). - Compute H3 cell for each detection at the configured resolution (default res 10, ~15 m edge).
- Build the composite key
H3_cell + class. Maintain an in-memory hashmap; persist asynchronously to disk for crash recovery. - Answer queries:
classify(detection) → new | moved | existingusing k-ring lookup and(distance_threshold_m, move_threshold_m, similar_classes)configuration. - After a region's scan-pass ends, return objects in the region that were not re-observed as
removed_candidates (the operator decides on actual removal). - Maintain the
IgnoredItemset; answer suppression queries (is_ignored(MGRS, class_group)). - Append every NEW / MOVED / EXISTING / REMOVED-CANDIDATE / IgnoredItem event to
pending_observations/pending_ignoredfor the post-flight push (in-flight central writes are forbidden — Frozen choice 6 inarchitecture.md §7.3). - Post-flight push: hand the contents of
pending_observations+pending_ignoredtomission_clientforPOST /missions/{id}/mapobjectsandPOST /missions/{id}/mapobjects/ignored. On ack, clear pending; on failure, persist for retry. - On
DELETE /missions/{id}cascade signal (received viamission_client), drop all objects scoped to that mission. The central side cascades as well.
5. Sync state machine
fresh_boot
│
├──> pre-flight pull
│ │
│ ├── 200 OK ────────────> synced
│ ├── unreachable ────────> [operator ack required]
│ │ │
│ │ ├── ack on cache ──> cached_fallback
│ │ └── abort ─────────> BIT fail
│ └── 4xx ─────────────────> BIT fail
│
├── (during flight; in-process writes only)
│ │
│ ├── pending_observations grow
│ └── pending_ignored grow
│
└── post-flight push
│
├── 200 OK on both endpoints ──> synced (pending cleared)
├── partial ────────────────────> retry per-endpoint
└── persistent failure ─────────> degraded (operator warning, manual replay)
6. Internal State
- In-memory hashmap of
(H3_cell + class) → MapObject. IgnoredItemset keyed by(MGRS, class_group).- Per-region pass tracker for removed-candidate detection.
pending_observations: ordered log of NEW / MOVED / REMOVED-CANDIDATE / EXISTING events not yet pushed centrally.pending_ignored: ordered log of IgnoredItem appends not yet pushed centrally.sync_state: enum + last-pull timestamp + last-push timestamp + last error.- Persistence layer (engine TBD — see Open Questions) for crash recovery and post-flight upload durability.
7. Failure Modes
| Failure | Detection | Behaviour |
|---|---|---|
| Pre-flight pull unreachable | network | Surface BIT degradation; operator must acknowledge cached fallback or abort. Never silent. |
| Pre-flight pull stale beyond freshness window | last-fetch-at compared to configured staleness | sync_state = degraded; operator must acknowledge or abort. |
| Persistence write failure | engine error | Log + retry; in-memory state continues authoritative for this mission; health → yellow. |
| Persistence corruption on startup | checksum / open failure | Refuse to start with stale state; require explicit recovery (engine-specific); surface to operator at startup. |
| H3 query inconsistency near cell boundaries | algorithmic | Always query the k-ring (k=2 default) so boundary objects are matched anyway. |
| Mission cascade signal lost | absent signal | DELETE /missions/{id} is the only cleanup trigger; on lost signal, mission-scoped objects accumulate. Operator-driven manual purge is acceptable. |
| Post-flight push partial success | per-endpoint status | Independent retry per endpoint; do not roll back the successful one. |
| Post-flight push persistent failure | bounded retries exhausted | sync_state = degraded; pending diff persisted on disk; operator-visible warning; manual replay supported. Mission's central data integrity at risk until replayed. |
| In-flight crash | startup detects non-empty pending_* for a terminated mission |
mission_client runs the post-flight push at startup before BIT completes for any new mission. |
8. Dependencies
In-process: scan_controller, mission_client (for pull/push round-trips), mission_executor (for post-flight trigger).
External: H3 spatial-index library (Rust crate). Persistent store engine — TBD (SQLite + H3 extension / KV / in-memory + snapshot — see Open Questions). Central API contract via mission_client's extension of the missions API (per architecture.md §7.13).
9. Non-Functional Targets
| Concern | Target |
|---|---|
| Per-detection classify latency | O(1); p99 ≤1 ms |
| Pre-flight pull time | ≤30 s for a 30 km × 30 km mission area (per architecture.md §6 NFR) |
| Post-flight push time | ≤2 min for a 60 min mission's pass diff (per architecture.md §6 NFR) |
| Persistent-store size (single mission) | bounded; configurable retention |
| Crash recovery time | ≤2 s to a usable state; in-flight crash → next-boot push of pending |
| Boundary correctness | guaranteed by k-ring query |
10. Open Questions
- Engine choice (architecture.md §8 Q3): SQLite + H3 extension / KV / in-memory + snapshot.
- Central API schema details (architecture.md §8 Q7): paging strategy, photo-reference upload mechanism, observation-history retention policy.
- Conflict resolution rules (architecture.md §8 Q8): exact projection from observation log to current view; REMOVED-claim expiry window; multi-class disambiguation.
- Optimal H3 resolution per terrain class.
- Class-group definitions (
military_vehicle_groupvsconcealed_position_groupvsmovement_candidate) — currently inscan_controllerconfig.
11. References
architecture.md §3,§5 Architectural Principles(MapObjects are mission-bracketed and centrally synchronised),§6 NFR,§7.9 MapObjects (H3 spatial index),§7.10 Sync Message Format,§7.11 Target Relocation,§7.12 New vs Existing object detection,§7.13 MapObjects Sync.system-flows.md §F7 MapObjects + ignored-items(in-flight diff),§F8 MapObjects sync (central DB, mission-bracketing).data_model.md §MapObject,§IgnoredItem,§MapObjectObservation,§MapObjectsBundle.../_docs/02_missions.md(mission cascade contract; new MapObjects endpoints).