Reconciles all orphan ACs from Plan 02-04 SUMMARY with explicit phase deferred annotations so the ac-traceability --check gate passes in CI. Phase mapping applied: - Phase 3 (SAFE/VERIFY): AC-3.5, AC-4.5, AC-5.1, AC-5.3, AC-8.2, AC-NEW-4, AC-NEW-6, AC-NEW-8 - Phase 4 (FDR/VPR): AC-2.1b, AC-3.1, AC-3.2, AC-4.2, AC-8.1, AC-8.3, AC-8.4, AC-8.5, AC-8.6 - Phase 5 (MAVOUT): AC-6.1, AC-6.2, AC-7.1, AC-7.2 python scripts/gen_ac_traceability.py --check now exits 0.
43 KiB
Acceptance Criteria
Last revised: 2026-05-11 (Phase 2 / Stage 2 rewrite from try02 skeleton, validated against Stage 2 constraints).
Revision log:
- 2026-05-11: Initial Stage 2 rewrite — adopted try02 AC vocabulary (AC-1.1..AC-8.6 + AC-NEW-1..AC-NEW-8), added per-AC schema (Statement / Numeric threshold / Rationale / Validation method / Test IDs / Implementing components / Status). Previous draft archived at
acceptance_criteria_draft.md.- 2026-05-01 (try02): AC-1.3 anchor-age reporting clarified; AC-2.1 split; AC-5.2 and AC-NEW-2 now require ArduPilot Plane SITL; AC-8.3 storage and AC-NEW-7 clarified.
- 2026-04-29 (try02): AC-3.5 and AC-NEW-8 added for visual blackout/cloud occlusion.
- 2026-04-26 (try02): AC-4.3 extended; AC-8.6 added; AC-NEW-7 added.
- 2026-04-25 (try02): initial AC list.
Schema
Every AC follows the same template:
-
AC-ID — Short title
Statement. The system shall …
Numeric threshold. Quantitative bound(s); measurement methodology.
Rationale. Risk if violated; tie-back to PROJECT.md core value.
Validation method. One of:
unit-test,integration-test,blackbox-replay,sitl-simulation,benchmark,deferred-hardware. May list more than one.Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/...paths the AC binds to.Status.
active/deferred-stage3/superseded-by(AC-Z).
Position Accuracy
-
AC-1.1 — Position accuracy (50 m @ 80 %)
Statement. The system shall determine GPS coordinates of frame centres within 50 m of true GPS for ≥80 % of photos in normal flight segments.
Numeric threshold.
error_m = ‖estimate_xy − ground_truth_xy‖(haversine, WGS84)- normal_flight_segment = nadir ±10° bank/pitch, ≥40 % overlap, daytime, no full visual blackout
- PASS iff
count(error_m < 50) / count(normal_segment_frames) ≥ 0.80 - Window: per 5-minute rolling window over the full flight
Rationale. Below this threshold the flight controller cannot safely geofence; navigation in GPS-denied airspace is impossible. This is the core-value AC.
Validation method.
integration-test+benchmarkon AerialVL S03 and Azaion 10.05.2026 fixtures.Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/safety_state/src/gps_denied/components/anchor_verifier/src/gps_denied/core/eskf.py
Status. active
-
AC-1.2 — Position accuracy (20 m @ 50 %)
Statement. The system shall determine GPS coordinates of frame centres within 20 m of true GPS for ≥50 % of photos in normal flight segments.
Numeric threshold.
- Same measurement methodology as AC-1.1
- PASS iff
count(error_m < 20) / count(normal_segment_frames) ≥ 0.50
Rationale. Stretch target for precision operations; failing this but passing AC-1.1 is an acceptable Stage 2 outcome. Violating both degrades all geofence and targeting accuracy.
Validation method.
integration-test+benchmarkon AerialVL S03 and Azaion 10.05.2026 fixtures.Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/safety_state/src/gps_denied/components/anchor_verifier/src/gps_denied/core/eskf.py
Status. active
-
AC-1.3 — Cumulative VO drift bound + anchor-age reporting
Statement. Maximum cumulative VO drift between two consecutive satellite-anchored fixes shall be <100 m (VO-only fallback) or <50 m (when IMU is fused). Every emitted estimate shall include
last_satellite_anchor_age_ms; validation results shall be binned by anchor age, and the solution draft must define the maximum anchor age after which estimates are treated as degraded (vo_extrapolatedordead_reckoned) with monotonically growing covariance.Numeric threshold.
- VO-only fallback:
drift_m < 100 m - IMU-fused:
drift_m < 50 m - Drift measured as
‖VO-extrapolated centre − next anchor centre‖at the moment of anchor fix
Rationale. Unbounded drift invalidates the position guarantee of AC-1.1. Anchor-age reporting is required for the traceability script and for Phase 3/6 observability. Cross-references: AC-NEW-1 (cold-start anchor age budget).
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/core/eskf.pysrc/gps_denied/components/safety_state/
Status. active (Phase 3 SAFE-03 wires
anchor_age_msfield; Phase 2 records the AC text only) - VO-only fallback:
-
AC-1.4 — Quantitative confidence score per estimate
Statement. The system shall report a quantitative confidence score per position estimate, comprising: the 95 % covariance ellipse semi-major axis in meters AND a categorical label
{satellite_anchored, vo_extrapolated, dead_reckoned}.Numeric threshold.
source_label ∈ {satellite_anchored, vo_extrapolated, dead_reckoned}(exhaustive; no other values permitted)cov_semi_major_m ≥ 0(non-negative real)
Rationale. Without a machine-readable label the flight controller cannot distinguish a high-quality fix from dead reckoning; the FC applies no covariance-appropriate safety margin. Cross-references: AC-NEW-8 (source_label vocab used in blackout failsafe).
Validation method.
unit-test(schema) +integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/safety_state/src/gps_denied/hot_types/position_estimate.py
Status. active
Image Processing Quality
-
AC-2.1a — VO registration rate
Statement. Frame-to-frame visual registration shall succeed for >95 % of normal flight segments (defined as: nadir flight ±10° bank/pitch, ≥40 % overlap with prior frame, daytime, usable texture, no full visual blackout).
Numeric threshold.
count(vo_success) / count(normal_segment_frames) > 0.95
Rationale. VO failure rate above 5 % causes excessive dead reckoning in steady-state conditions, violating AC-1.3 drift bound.
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/vio/src/gps_denied/pipeline/orchestrator.py
Status. active
-
AC-2.1b — Satellite-anchor registration
Statement. Cross-domain UAV-photo to satellite/cache registration is measured separately from AC-2.1a and must satisfy AC-1.1/AC-1.2 position accuracy, AC-2.2 cross-domain MRE, AC-8.2 freshness, and AC-8.6 retrieval behavior on season-matched tiles.
Numeric threshold.
- Satellite-anchor MRE: <2.5 px (see AC-2.2)
- Anchor acceptance rate: bounded by AC-1.1 (≥80 % of frames within 50 m)
Rationale. Satellite registration rate and quality must be tracked independently of VO to isolate failure modes (tile staleness vs. VO failure vs. cross-domain mismatch).
Validation method.
integration-test+benchmarkTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/satellite_matcher/src/gps_denied/components/anchor_verifier/
Status. active (pending-phase-4 (VPR-03))
-
AC-2.2 — Mean Reprojection Error
Statement. Mean Reprojection Error (MRE) shall be: <1.0 px for VO frame-to-frame homography on overlapping aerial pairs; <2.5 px for satellite-anchored cross-domain (UAV photo ↔ ortho satellite tile) registration.
Numeric threshold.
- VO MRE:
mre_px < 1.0 - Satellite MRE:
mre_px < 2.5
Rationale. MRE above these thresholds indicates degenerate homography; the resulting position shift can exceed 10 m per pixel of MRE at 0.5 m/px resolution. Exceeding satellite MRE violates AC-1.1.
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/satellite_matcher/metric_refinement.pysrc/gps_denied/components/anchor_verifier/
Status. active
- VO MRE:
Resilience & Edge Cases
-
AC-3.1 — Outlier tolerance
Statement. The system shall correctly continue work in the presence of up to 350 m outliers between two consecutive photos (caused by airframe tilt up to ±20°).
Numeric threshold.
- Maximum inter-frame displacement handled: 350 m
- System continues producing valid estimates after the outlier frame
Rationale. Fixed-wing tilt events create apparent ground displacement beyond normal VO search radius; failure to handle them causes tracking loss on routine maneuvers.
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/core/recovery.pysrc/gps_denied/components/satellite_matcher/
Status. active (pending-phase-4 (VPR-01))
-
AC-3.2 — Sharp-turn handling
Statement. The system shall correctly continue work during sharp turns where the next photo overlaps <5 % with the previous, drifts <200 m, and changes heading <70°. Sharp-turn frames are expected to fail VO and shall be handled by satellite-based re-localization (place recognition over the satellite tile cache).
Numeric threshold.
- Overlap threshold:
<5 % - Drift after turn:
<200 m - Heading change:
<70°
Rationale. Fixed-wing survey patterns include 180° turn-arounds with near-zero overlap. Without satellite re-localization the system drifts unbounded on every headland.
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/core/recovery.pysrc/gps_denied/components/satellite_matcher/src/gps_denied/core/factor_graph.py
Status. active (pending-phase-4 (VPR-01))
- Overlap threshold:
-
AC-3.3 — Disconnected segments
Statement. The system shall handle ≥3 disconnected segments per flight, connecting each new segment to the previous trajectory via global descriptor retrieval + RANSAC pose-graph relocalization. This is a core capability, not a degraded mode.
Numeric threshold.
- Minimum disconnected segments handled per flight: 3
- Each segment successfully reconnected to the global trajectory
Rationale. Multi-strip survey missions have multiple heading reversals with full visual discontinuity. If the system treats this as exceptional, it fails on every second strip.
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/core/recovery.pysrc/gps_denied/components/satellite_matcher/src/gps_denied/core/factor_graph.py
Status. active
-
AC-3.4 — Re-localization request trigger
Statement. When the system cannot determine position for ≥3 consecutive frames AND ≥2 s, it shall send a re-localization request to the ground station via telemetry. While waiting, it continues VO/IMU dead reckoning and the flight controller uses last known position + IMU extrapolation.
Numeric threshold.
- Dual trigger:
consecutive_frames_failed ≥ 3 AND time_failed_s ≥ 2 - Re-loc request must be emitted within one processing cycle of threshold crossing
Rationale. A single trigger threshold (frame count only) can fire on sub-second bursts; dual-trigger prevents spurious requests during transient VO failures.
Validation method.
blackbox-replay+sitl-simulationTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/core/recovery.pysrc/gps_denied/components/mavlink_io/pymavlink_bridge.py
Status. active
- Dual trigger:
-
AC-3.5 — Visual blackout mode switch
Statement. During temporary visual blackout where the navigation camera provides no usable ground signal (e.g., clouds/occlusion/whiteout) while GPS is denied or spoofed, the system shall switch to
{dead_reckoned}within ≤1 processed frame OR ≤400 ms, reject the spoofed GPS as an estimator input, and propagate position solely from the last trusted state + flight-controller IMU/attitude/airspeed/altitude inputs until visual or satellite anchoring recovers. During this mode, covariance shall grow monotonically,GPS_INPUT.horiz_accuracyshall not under-report the 95 % covariance semi-major axis, and QGroundControl shall receive aVISUAL_BLACKOUT_IMU_ONLYstatus at 1–2 Hz. Cross-references: AC-NEW-8 (extended blackout failsafe budget).Numeric threshold.
- Mode switch latency:
≤1 processed frame OR ≤400 ms - QGC status rate:
1–2 Hz - Covariance: monotonically non-decreasing in blackout mode
Rationale. A cloud/whiteout period removes all visual correction exactly when spoofed GPS cannot be trusted. Pretending a stale visual position remains valid is operationally dangerous.
Validation method.
blackbox-replay+sitl-simulationTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/safety_state/src/gps_denied/components/mavlink_io/pymavlink_bridge.pysrc/gps_denied/core/eskf.py
Status. active (pending-phase-3 (SAFE-02))
- Mode switch latency:
Real-Time Onboard Performance
-
AC-4.1 — End-to-end latency
Statement. End-to-end latency from camera capture to GPS coordinate output to the flight controller shall be <400 ms p95. Up to ~10 % of frames may be dropped under sustained load (skip-allowed). Heavy global VPR / cross-domain re-ranking shall be conditional, not part of the steady-state per-frame path.
Numeric threshold.
- p95 end-to-end latency:
<400 ms - Frame-drop budget:
≤10 %
Rationale. ArduPilot EKF failsafe fires after ~3 s without a GPS update at 5 Hz; 400 ms p95 keeps the GPS_INPUT stream healthy. Beyond 400 ms, EKF position uncertainty grows fast enough to trigger safety modes.
Validation method.
benchmarkTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/pipeline/orchestrator.pysrc/gps_denied/components/vio/src/gps_denied/components/satellite_matcher/
Status. active
- p95 end-to-end latency:
-
AC-4.2 — Memory budget
Statement. Memory usage shall remain below 8 GB shared on Jetson Orin Nano Super (CPU and GPU share the same 8 GB LPDDR5 pool).
Numeric threshold.
- Peak shared memory:
<8 GB
Rationale. Exceeding 8 GB triggers OOM-killer; the system crashes mid-flight. No recovery path exists without a reboot.
Validation method.
benchmarkTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/pipeline/orchestrator.pysrc/gps_denied/components/gpr/
Status. active (pending-phase-4 (FDR-01))
- Peak shared memory:
-
AC-4.3 — MAVLink output channel (GPS_INPUT primary)
Statement. The system shall output its position estimate to the flight controller via two parallel MAVLink channels, both emitted by pymavlink: Primary (
GPS_INPUTtargeting ArduPilotGPS1_TYPE=14) and Auxiliary (ODOMETRYwhen EKF emits fix with full 6-DoF covariance and quality >VISO_QUAL_MIN). FC source priorities configured so GPS_INPUT remains the failover path if ODOMETRY trips a parameter gate.v1 scope clause (added 2026-04-26): v1 ships GPS_INPUT only; the ODOMETRY auxiliary channel is intentionally disabled in v1 because feeding both
GPS_INPUTandODOMETRYfor overlapping axes triggers ArduPilot EKF3 double-fusion bugs (issues #30076 / #32506).EK3_SRC1_*=GPS+Compass; ODOMETRY emission re-enables in v1.1 once F-T9 SITL confirms PR #30080-class clean source-switching. Tests therefore assert v1 emits GPS_INPUT only and that ODOMETRY is intentionally absent on the wire.Numeric threshold.
- v1:
GPS_INPUTpresent on wire;ODOMETRYabsent - FC parameter:
GPS1_TYPE=14; quality gate:VISO_QUAL_MIN
Rationale. EKF3 double-fusion causes divergent position estimates that cannot be diagnosed in the field. v1 single-channel keeps the behavior predictable until the upstream ArduPilot fix is confirmed. (See MAVOUT-02 requirement.)
Validation method.
blackbox-replay(channel absence) +sitl-simulation(FC ingest)Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/mavlink_io/pymavlink_bridge.pysrc/gps_denied/pipeline/orchestrator.py
Status. active (v1: GPS_INPUT only; MAVOUT-02 scaffolds ODOMETRY behind feature flag)
- v1:
-
AC-4.4 — Frame-by-frame streaming
Statement. Position estimates are streamed to the flight controller frame-by-frame; the system shall not batch or delay output.
Numeric threshold.
- Every processed frame produces a
GPS_INPUTemit within the AC-4.1 latency budget - No buffering / batching of position output
Rationale. Batching introduces burst latency; ArduPilot's EKF treats inter-packet gaps as data-rate drops, degrading its own estimate quality.
Validation method.
sitl-simulationTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/mavlink_io/pymavlink_bridge.py
Status. active
- Every processed frame produces a
-
AC-4.5 — Estimate refinement / corrections
Statement. The system may refine previously calculated positions and send corrections to the flight controller as updated estimates.
Numeric threshold.
- Correction delta: no hard limit (any refinement may be sent)
- FC must not reject corrections; system must not suppress them
Rationale. Factor-graph back-end refines past poses when new satellite anchors arrive; sending the refined estimate keeps the FC's EKF state consistent with our back-end.
Validation method.
sitl-simulationTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/pipeline/orchestrator.pysrc/gps_denied/components/mavlink_io/pymavlink_bridge.py
Status. active (pending-phase-3 (SAFE-04))
Startup & Failsafe
-
AC-5.1 — Initialization from FC EKF
Statement. The system shall initialise using the last known valid GPS position from the flight controller's EKF, plus IMU-extrapolated position at the moment of GPS denial.
Numeric threshold.
- Initialization must complete before first
GPS_INPUTemit - Initial position: FC EKF position at denial onset, not a default/zero position
Rationale. Starting from zero coordinates puts the FC in a state where GPS_INPUT contradicts the last real GPS; the EKF rejects the first several estimates, creating a cold-start gap in coverage.
Validation method.
sitl-simulationTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/mavlink_io/src/gps_denied/core/recovery.py
Status. active (pending-phase-3 (SAFE-01))
- Initialization must complete before first
-
AC-5.2 — Failsafe timeout
Statement. If the system fails to produce any position estimate for >3 s, the flight controller shall fall back to IMU-only dead reckoning and the system shall log the failure. Because ArduPilot failsafe timing depends on vehicle type and parameters, this fallback behavior must be verified specifically in ArduPilot Plane SITL with the production parameter set; Copter defaults are reference evidence only.
Numeric threshold.
- Failsafe trigger:
gap_s > 3 - Validation scope: ArduPilot Plane SITL (not Copter)
Rationale. Plane and Copter have different EKF lane-switch thresholds; verifying on Copter SITL only leaves the Plane-specific failsafe path untested.
Validation method.
sitl-simulation(ArduPilot Plane SITL specifically)Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/mavlink_io/src/gps_denied/core/recovery.py
Status. active
- Failsafe trigger:
-
AC-5.3 — Mid-flight reboot recovery
Statement. On companion computer reboot mid-flight, the system shall attempt to re-initialise from the flight controller's current IMU-extrapolated position. See AC-NEW-1 for the cold-start time-to-first-fix budget.
Numeric threshold.
- Recovery attempt must start within
AC-NEW-1TTFF budget (<30 s) - Recovery position: FC IMU-extrapolated position at reboot time
Rationale. Brown-out / watchdog resets are realistic on 8-hour missions; the UAV must not enter an unrecoverable state when the companion reboots.
Validation method.
sitl-simulationTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/mavlink_io/src/gps_denied/core/recovery.py
Status. active (pending-phase-3 (SAFE-01))
- Recovery attempt must start within
Ground Station & Telemetry
-
AC-6.1 — GCS position stream
Statement. Position estimates and confidence scores shall be streamed to QGroundControl via the MAVLink telemetry link. High-rate (per-frame) content stays on the local link for forensics; the GCS link is downsampled to 1–2 Hz for situational awareness.
Numeric threshold.
- GCS stream rate:
1–2 Hz - Local forensic stream: per-frame (AC-4.1 rate)
Rationale. QGC's map view cannot render per-frame updates usefully; downsampling reduces bandwidth without losing situational awareness. Full-rate data is preserved in FDR (AC-NEW-3).
Validation method.
sitl-simulation(QGC downsample observable on the wire)Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/mavlink_io/pymavlink_bridge.py
Status. active (pending-phase-5 (MAVOUT-01))
- GCS stream rate:
-
AC-6.2 — Operator re-localization commands
Statement. The ground station can send commands to the onboard system (e.g., operator-assisted re-localization hint with approximate coordinates) via STATUSTEXT, NAMED_VALUE_FLOAT, or a custom MAVLink dialect.
Numeric threshold.
- Command must be received and acted upon within one processing cycle
- Protocol: STATUSTEXT / NAMED_VALUE_FLOAT / custom dialect (implementation choice)
Rationale. Operator-assisted re-localization is the fallback when automatic re-localization fails (AC-3.4 trigger path); without this channel the operator cannot intervene.
Validation method.
sitl-simulationTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/mavlink_io/pymavlink_bridge.py
Status. active (pending-phase-5 (MAVOUT-03))
-
AC-6.3 — WGS84 coordinate format
Statement. Output coordinates are in WGS84 format (matches GPS_INPUT spec).
Numeric threshold.
- All lat/lon fields in GPS_INPUT in WGS84 decimal degrees × 1e7 (MAVLink convention)
- No local coordinate systems exported to FC
Rationale. GPS_INPUT spec requires WGS84; using a local ENU frame crashes the EKF.
Validation method.
unit-test(WGS84 coord format)Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/mavlink_io/pymavlink_bridge.pysrc/gps_denied/core/eskf.py
Status. active
Object Localization (AI Camera)
-
AC-7.1 — AI camera localization accuracy
Statement. Other onboard AI systems may request GPS coordinates of objects detected by the AI camera. Localization accuracy is consistent with the frame-center accuracy of the GPS-Denied system in level flight (bank/pitch <5°). In maneuvering flight, ground-projection error is bounded by
altitude × |sin(unknown_bank_or_pitch)|and the system shall publish that bound alongside the estimate.Numeric threshold.
- Level flight (bank/pitch <5°): accuracy consistent with AC-1.1 / AC-1.2
- Maneuvering flight: bound reported =
altitude_m × |sin(attitude_rad)|
Rationale. Object localization inherits all position error from the GPS-Denied system plus the camera projection uncertainty; the bound must be propagated honestly.
Validation method.
unit-test(trig) +integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/coordinate_transforms/
Status. active (pending-phase-5 (MAVOUT-04))
-
AC-7.2 — AI camera trigonometric computation
Statement. The system computes object coordinates trigonometrically using: current UAV GPS position (from GPS-Denied), known AI-camera gimbal angle, zoom, and current flight altitude. Flat-terrain assumption applies.
Numeric threshold.
- Flat-terrain assumption: explicit, documented per-request
- Input: GPS-Denied position + gimbal angle + zoom + altitude (all mandatory fields)
Rationale. Without explicit flat-terrain documentation, operators may use the output for terrain-varying tasks where it is not valid.
Validation method.
unit-test(trig) +integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/coordinate_transforms/
Status. active (pending-phase-5 (MAVOUT-04))
Satellite Reference Imagery
-
AC-8.1 — Satellite imagery source and resolution
Statement. Satellite reference imagery is provided by the Azaion Suite Satellite Service (a separate component of the Suite). The runtime onboard system consumes this service through an offline tile cache interface; it does not call commercial providers directly. Required resolution at the cache interface: at least 0.5 m/pixel, ideally 0.3 m/pixel.
Numeric threshold.
- Minimum resolution:
0.5 m/px - Ideal resolution:
0.3 m/px
Rationale. Below 0.5 m/px, keypoint density drops below the minimum for reliable homography; the satellite-anchor MRE (AC-2.2) cannot be met.
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/satellite_matcher/local_tile_loader.py
Status. active (pending-phase-4 (FDR-03))
- Minimum resolution:
-
AC-8.2 — Tile freshness by sector
Statement. Satellite tiles consumed at runtime shall be: <6 months old for active-conflict sectors; <12 months old for stable rear sectors. System shall reject or downgrade-confidence on tiles older than these thresholds (see AC-NEW-6).
Numeric threshold.
- Active-conflict sectors:
age_months < 6 - Stable rear sectors:
age_months < 12
Rationale. Stale tiles in active-conflict sectors (building destruction, cratering) produce confident-but-wrong satellite anchors — worse than no anchor.
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/anchor_verifier/src/gps_denied/components/satellite_matcher/local_tile_loader.py
Status. active (pending-phase-3 (VERIFY-03))
- Active-conflict sectors:
-
AC-8.3 — Pre-flight imagery loading
Statement. Satellite imagery for the operational area shall be pre-loaded and pre-processed onto the companion computer before flight. Offline preprocessing time is not time-critical (minutes/hours). Pre-extracted tile descriptors (SuperPoint keypoints/descriptors and DINOv2-VLAD global descriptors) are part of the cache and count against the storage budget unless the solution draft defines a separate descriptor/index budget.
Numeric threshold.
- All operational-area tiles available before
GPS_INPUTis first emitted - Storage: within 64 GB FDR cap (AC-NEW-3); descriptor index explicitly budgeted
Rationale. In-flight tile downloads require connectivity that is unavailable in GPS-denied airspace.
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/satellite_matcher/local_tile_loader.pysrc/gps_denied/components/gpr/
Status. active (pending-phase-4 (FDR-02))
- All operational-area tiles available before
-
AC-8.4 — Mid-flight tile generation and write-back
Statement. During flight, the system shall continuously orthorectify navigation-camera frames into tiles aligned with the basemap projection and store them in the local cache, deduplicated so each ground sector is stored at most once (latest/highest-quality tile wins). On landing, the companion computer shall upload newly generated tiles back to the Azaion Suite Satellite Service so the next mission cache contains imagery refreshed by the previous flight.
Numeric threshold.
- Deduplication: one tile per ground sector (latest wins)
- Upload: on-landing, before next mission
- Write eligibility gated by
can_persist_tile(see SAFE-05)
Rationale. Without write-back, the cache becomes stale relative to conflict-sector ground truth after the first mission; every subsequent mission anchors against pre-conflict imagery.
Validation method.
integration-testTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/satellite_matcher/src/gps_denied/components/flight_recorder/
Status. deferred-stage3 (pending-phase-4 (FDR-05)) — mid-flight orthorectification + write-back is a Stage 3 deliverable per REQUIREMENTS.md parking lot
-
AC-8.5 — Storage policy (no raw frame retention)
Statement. The system shall not retain raw navigation-camera frames or AI-camera frames as part of normal operation. Tiles are the only persistent imagery artifact. Forensic exception: a low-rate (≤0.1 Hz) thumbnail log of frames that failed tile generation may be retained for debugging within the FDR budget (AC-NEW-3).
Numeric threshold.
- Raw frame retention: zero bytes in normal operation
- Forensic thumbnail rate:
≤0.1 Hz
Rationale. Raw nav-cam frames at 3 Hz × 8 hours exceeds any reasonable storage budget and provides no operational value once tiles exist.
Validation method.
integration-test+benchmarkTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/flight_recorder/src/gps_denied/pipeline/orchestrator.py
Status. active (pending-phase-4 (FDR-04))
-
AC-8.6 — VPR retrieval unit and change-robustness
Statement. The Visual Place Recognition (VPR) FAISS index shall be built over ground-footprint-sized "VPR chunks" (~600–800 m at deployment altitude with 40–50 % overlap), decoupled from the slippy-XYZ storage tile (z=20). VPR shall be multi-scale (fine-scale z=20-derived + coarser-scale z=17 or z=18 for active-conflict change-robustness). VPR top-K shall be dynamically sized: K=5 (stable, σ_xy ≤ 20 m), K=20 (active-conflict), K=50 (expanding-window fallback). VPR shall be invoked conditionally — not on every frame; DINOv2 forward runs only on re-loc triggers (cold start, sharp turn AC-3.2, σ_xy > 50 m, VO failure ≥2 frames, disconnected segment AC-3.3).
Numeric threshold.
- Chunk size:
600–800 mat deployment altitude - Chunk overlap:
40–50 % - Multi-scale: z=20 (fine) + z=17 or z=18 (coarse)
- Dynamic K: K=5 / K=20 / K=50 per sector/covariance
- VPR invocation: conditional on re-loc triggers only
Rationale. Unconditional DINOv2 inference at every frame violates AC-4.1 (400 ms budget). Change-robust coarse index prevents anchor failure in active-conflict sectors where the fine-scale tile may not match post-conflict ground truth.
Validation method.
integration-test+benchmarkTest IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/gpr/src/gps_denied/core/chunk_manager.py
Status. active (pending-phase-4 (VPR-01))
- Chunk size:
Extended Operational AC
AC-NEW-1 — Time-to-first-fix on cold start
-
AC-NEW-1 — Time-to-first-fix on cold start
Statement. From companion-computer boot, the system shall emit its first valid
GPS_INPUTmessage in <30 s, given an IMU-extrapolated initial position handed over from the flight controller's EKF.Numeric threshold.
- TTFF:
95th percentile < 30 s(measured over 50× cold reboots) - Implementation drivers: TRT engines built at install time; CUDA/TRT init <5 s; FAISS index loaded before MAVLink connect
Rationale. A mid-flight reboot at 60 km/h creates ~500 m IMU dead-reckoning drift in 30 s; the EKF can absorb this when the first fix arrives. Beyond 30 s the drift compounds. Cross-references: AC-1.3 (anchor-age at cold start); AC-5.3 (reboot recovery).
Validation method.
deferred-hardware(cold-boot bench requires Jetson hardware; cold-boot 50× with simulated FC-pose input)Test IDs.
- deferred_hardware
Implementing components.
src/gps_denied/pipeline/orchestrator.pysrc/gps_denied/core/models.py
Status. deferred-hardware-validation (Stage 3 on Jetson)
- TTFF:
AC-NEW-2 — Spoofing-promotion latency
-
AC-NEW-2 — Spoofing-promotion latency
Statement. When the flight controller signals GPS denial or spoofing (ArduPilot fix-loss / EKF lane-switch event), the GPS-Denied system shall promote its own estimate to the FC's primary GPS source within <3 s.
Numeric threshold.
- Promotion latency:
95th percentile < 3 s - Trigger: real-GPS health rolling average below threshold for ≥1 s
Rationale. Without this gate, the FC may continue following a spoofed real-GPS source while our valid estimate sits idle. 3 s is short enough to prevent malicious heading changes but long enough to avoid single-frame anomaly false positives.
Validation method.
sitl-simulation(ArduPilot Plane SITL: inject false GPS_RAW_INT, measure time from spoof onset to promotion)Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/mavlink_io/pymavlink_bridge.py
Status. active
- Promotion latency:
AC-NEW-3 — Flight Data Recorder storage budget
-
AC-NEW-3 — Flight Data Recorder storage budget
Statement. The system shall retain to non-volatile storage, per flight: per-frame position estimates with covariance and source-label, IMU traces from the FC at full rate, all emitted
GPS_INPUTframes, MAVLink raw stream (tlog), system health (CPU/GPU/temp/throttle), tiles generated mid-flight (AC-8.4), and a ≤0.1 Hz thumbnail log of failed-tile frames. Raw nav-cam frames and AI-cam frames are NOT retained (AC-8.5). Storage cap 64 GB / flight; recorder rolls over (oldest segment dropped first) after cap.Numeric threshold.
- Storage cap:
≤64 GB per flight - Forensic thumbnail rate:
≤0.1 Hz - Rollover policy: oldest segment dropped; rollover event logged
Rationale. Without bounded storage, an 8-hour mission fills any NVMe and silently drops forensic data. The 64 GB cap is sized for 8-hour mission with tiles + IMU + telemetry, leaving headroom for the persistent tile cache (AC-8.3).
Validation method.
integration-test(rollover behavior) +benchmark(synthetic 8-hour load) +deferred-hardware(real Jetson NVMe throughput in Stage 3)Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/flight_recorder/
Status. active (CI scope) + deferred-hardware-validation (Stage 3)
- Storage cap:
AC-NEW-4 — False-position safety budget
-
AC-NEW-4 — False-position safety budget
Statement.
- P(reported estimate error > 500 m) < 0.1 % per flight.
- P(reported estimate error > 1 km) < 0.01 % per flight.
Numeric threshold.
P(error > 500 m) < 0.001P(error > 1 km) < 0.0001- Measurement: Monte Carlo over AerialVL S03 + Mavic + Azaion 10.05.2026, ≥100 simulated flights
Rationale. A single 1-km-off GPS_INPUT can fly the UAV outside the geofence in seconds. EKF covariance must be calibrated, not optimistic; outlier rejection (Mahalanobis gate) is mandatory.
Validation method.
benchmark(Monte Carlo over AerialVL S03 + Mavic + Azaion 10.05.2026)Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/core/eskf.pysrc/gps_denied/components/anchor_verifier/
Status. active (pending-phase-3 (VERIFY-01))
AC-NEW-5 — Operational environmental envelope
-
AC-NEW-5 — Operational environmental envelope
Statement. Operating temperature −20 °C to +50 °C; vibration/shock per RTCA DO-160G low-altitude UAV-class envelope. The cooling solution shall sustain the 25 W power mode at the upper temperature bound for the full 8-hour duty cycle without thermal throttling.
Numeric threshold.
- Temperature range:
−20 °C to +50 °C - Power mode:
25 Wsustained - Duration:
8 hours - Pass: no thermal throttling events during hot-soak
Rationale. Without this, all latency/accuracy ACs are conditional on a benign thermal day. Eastern Ukraine summers easily exceed +35 °C ambient inside a UAV bay; without active cooling, Jetson throttles to 15 W and AC-4.1 (400 ms budget) collapses.
Validation method.
deferred-hardware(hot-soak chamber at +50 °C for 8 h + cold-soak at −20 °C to AC-NEW-1 TTFF)Test IDs.
- deferred_hardware
Implementing components.
- Hardware cooling assembly (outside software scope)
src/gps_denied/components/flight_recorder/(thermal event logging via FDR)
Status. deferred-hardware-validation (Stage 3 on Jetson)
- Temperature range:
AC-NEW-6 — Imagery freshness enforcement
-
AC-NEW-6 — Imagery freshness enforcement
Statement. The system shall reject (or downgrade confidence on) any satellite tile whose capture date violates AC-8.2 (>6 months old in active-conflict sectors; >12 months old in stable rear sectors). Tiles generated mid-flight (AC-8.4) and not yet uploaded to the Suite Satellite Service are timestamped with the current flight date and treated as fresh.
Numeric threshold.
- Confidence weight:
1.0within freshness budget; linearly decayed to0.0over a 30-day grace zone; hard reject beyond grace - Sector classification: provided pre-flight in operational area definition
Rationale. Stale satellite tiles are the dominant cross-view-matching failure mode in active-conflict sectors. A confident match against a stale tile is worse than no match.
Validation method.
unit-test(rejection curve) +integration-test(cache integration)Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/anchor_verifier/src/gps_denied/components/satellite_matcher/local_tile_loader.py
Status. active (pending-phase-3 (VERIFY-03))
- Confidence weight:
AC-NEW-7 — Cache-poisoning safety budget
-
AC-NEW-7 — Cache-poisoning safety budget
Statement. Per flight, across all onboard tiles written by the in-flight ortho-tile generator:
- P(onboard tile geo-misaligned > 30 m) < 1 %.
- P(onboard tile geo-misaligned > 100 m) < 0.1 %.
Component-1b (tile generator) enforces: σ_xy ≤ 5 m hard write gate (
trust_level = candidate); σ_xy ≤ 3 m for full quality; σ_xy ∈ (3, 5] m markedtrust_level = soft. Multi-flight voting (N≥2 independent flights confirm consistent geo-alignment within X m) is a Suite Satellite Service dependency for final promotion to trusted basemap. Cross-references: AC-8.4 (write-back); AC-NEW-4 (single-flight false-position budget).Numeric threshold.
P(geo-misalignment > 30 m) < 0.01P(geo-misalignment > 100 m) < 0.001- Onboard trust_level gate: σ_xy ≤ 5 m (candidate), σ_xy ≤ 3 m (full quality)
- Multi-flight voting: N≥2 flights (Service-side, deferred)
Rationale. Onboard tiles feed back into the Suite Satellite Service basemap (AC-8.4); a confidently-bad EKF pose can write a misaligned tile that becomes the next flight's satellite anchor, compounding cross-flight error beyond what AC-NEW-4 covers.
Validation method.
integration-test: onboardtrust_levelgating (σ_xy ≤ 5 m hard, ≤ 3 m full quality)deferred-hardware: multi-flight voting (N≥2 flights, Service-side voting layer outside this build)
Test IDs.
- populated by scripts/gen_ac_traceability.py (for onboard trust_level gating)
- deferred_hardware (for multi-flight voting)
Implementing components.
src/gps_denied/components/satellite_matcher/src/gps_denied/components/anchor_verifier/
Status. active (onboard gate — Stage 2); deferred-hardware-validation (multi-flight voting — Stage 3)
AC-NEW-8 — Visual blackout + GPS spoofing degraded-mode budget
-
AC-NEW-8 — Visual blackout + GPS spoofing degraded-mode budget
Statement. When the navigation camera is fully unusable for visual localization and the flight controller simultaneously reports GPS denial/spoofing, the onboard system shall:
- continue emitting
GPS_INPUTfrom IMU-only propagation for up to 30 s after the last trusted visual/satellite anchor, unless the estimator covariance exceeds the fail threshold earlier; - label every estimate
{dead_reckoned}and setfix_type=2or lower when the 95 % covariance semi-major axis exceeds 100 m; - emit
fix_type=0,horiz_accuracy=999.0, andSTATUSTEXT: VISUAL_BLACKOUT_FAILSAFEwhen the 95 % covariance semi-major axis exceeds 500 m OR visual blackout exceeds 30 s without a trusted re-anchor; - never promote spoofed real-GPS measurements back into the estimator during blackout unless the FC GPS health has been stable and non-spoofed for ≥10 s and a visual/satellite consistency check has succeeded. Cross-references: AC-1.4 (source_label vocab); AC-3.5 (blackout mode switch).
Numeric threshold.
- IMU-only emit duration:
≤30 s dead_reckoned+fix_type=2whenσ_xy > 100 mfix_type=0+horiz_accuracy=999.0+STATUSTEXT VISUAL_BLACKOUT_FAILSAFEwhenσ_xy > 500 mOR blackout > 30 s- GPS re-promotion gate: ≥10 s non-spoofed health + visual/satellite consistency check
Rationale. A cloud/whiteout period removes all visual correction exactly when spoofed GPS cannot be trusted. Honest IMU-only dead reckoning with rapidly growing uncertainty is the only safe behavior.
Validation method.
blackbox-replay+sitl-simulation(inject 5 s, 15 s, 35 s full-camera blackout while spoofing GPS_RAW_INT; assert mode transition ≤400 ms, spoofed GPS ignored, covariance grows monotonically, GPS_INPUT fields degrade at thresholds, recovery only after trusted anchor or 10 s GPS-health gate)Test IDs.
- populated by scripts/gen_ac_traceability.py
Implementing components.
src/gps_denied/components/safety_state/src/gps_denied/core/eskf.pysrc/gps_denied/components/mavlink_io/pymavlink_bridge.py
Status. active (pending-phase-3 (SAFE-02))
- continue emitting