# Fact Cards — C5: State estimator / sensor fusion

> Mode A Phase 2 — engine Step 3 (Fact Extraction & Evidence Cards). Component **C5** = "State estimator / sensor fusion" per `00_question_decomposition.md` line 73 + the C4→C5 forward-cite from Fact #54 closure (GTSAM iSAM2 architectural extension). C5 consumes C1's VIO output (relative pose @ ≥3 Hz) + C4's satellite-anchor poses (absolute pose with 6×6 covariance) + FC IMU (high-rate via MAVLink) + FC attitude/airspeed/altitude (lower-rate via MAVLink) and produces the WGS84 fused estimate + 6×6 honest pose covariance + source label `{satellite_anchored, visual_propagated, dead_reckoned}` + `last_satellite_anchor_age_ms` for the C8 MAVLink/MSP2 FC adapter (per AC-NEW-3 FDR + AC-NEW-4 covariance-honest + AC-NEW-8 blackout failsafe + AC-3.x resilience).
>
> Index: [`00_summary.md`](00_summary.md). Sibling fact-card files: [SQ1](SQ1_existing_systems.md), [SQ2](SQ2_canonical_pipeline.md), [SQ6](SQ6_fc_external_positioning.md), [C1](C1_vio.md), [C2](C2_vpr.md), [C3](C3_matchers.md), [C4](C4_pose_estimation.md). Component fit matrix row: [`../06_component_fit_matrix/C5_state_estimator.md`](../06_component_fit_matrix/C5_state_estimator.md). Cross-component gates: [`../06_component_fit_matrix/99_cross_component_gates.md`](../06_component_fit_matrix/99_cross_component_gates.md).

---

### Fact #88 — Manual ESKF reference per Solà 2017 (canonical aerial/quaternion ESKF tutorial — **MANDATORY SIMPLE-BASELINE** role for the C5 row, structurally analogous to OpenCV `cv::solvePnPRansac`'s role in C4 row + NetVLAD's role in C2 row + SuperGlue+SuperPoint's role in C3 row; project-side custom implementation in NumPy/SciPy or hand-written C++17/Eigen3 following Solà 2017 §5+§6 equations directly; on Jetson Orin Nano Super) — DOCUMENTARY PASS WITH PUBLIC-DOMAIN-CANONICAL-EQUATIONS + PROJECT-APACHE-2.0-IMPLEMENTATION-LICENSE + 18-STATE-NOMINAL-+-18×18-ERROR-COVARIANCE + NATIVE-6×6-POSE-COVARIANCE-VIA-ANALYTIC-JACOBIAN-PROPAGATION (only C5 candidate to satisfy AC-NEW-4 honestly without library-mediated posterior recovery) + QUATERNION-CORRECT-ATTITUDE-INTEGRATION-ON-SO(3) (via small-angle approximation in error-state per §5.4 discrete-time Jacobians) + TRIVIAL-MEMORY-FOOTPRINT (~kilobytes for 18-DoF state + 18×18 covariance = 324 floats = 2.6 KB) + ~5-15-MS-PER-UPDATE-EXTRAPOLATED-TO-JETSON-CPU (fastest C5 candidate; comfortable AC-4.1 satisfaction with substantial margin) + ~1-2-WEEKS-INITIAL-IMPLEMENTATION-EFFORT (manual coding + test coverage of 9-state visual-anchor measurement update + Mahalanobis outlier gate + source-label state machine for AC-NEW-2/AC-NEW-8 promotion/demotion) — opens C5 row at **1 of N candidates** (mandatory simple-baseline role)

- **Statement**: Manual ESKF (Error-State Kalman Filter) per the canonical Solà 2017 tutorial (arXiv:1711.02508 — "Quaternion kinematics for the error-state Kalman filter", Joan Solà, IRI Barcelona; canonical reference for ESKF + quaternion algebra in robotics + aerospace + UAV applications since 2017; 592 citations per Semantic Scholar; open-access public-domain academic preprint; canonical equations not copyrightable; project's manual implementation gets project's chosen license — default Apache-2.0 per project tech-stack rule consistent with C4 OpenCV mandatory-simple-baseline license track) is the **MANDATORY SIMPLE-BASELINE reference** for the C5 row per the engine Component Option Breadth rule — **the long-established Kalman-filter-based state-estimator reference that defines the simple-baseline floor against which modern competitive leads (GTSAM iSAM2 factor-graph, MSCKF, particle filter) must measurably exceed** at the project's pinned mode (frame-rate state estimator + multi-source fusion contract on Jetson Orin Nano Super; inputs = C1 VIO output (relative pose @ ≥3 Hz with σ_yaw ≤ 5° / σ_pitch ≤ 5° per Fact #24) + C4 satellite-anchor poses (6-DoF tile-frame absolute pose with 6×6 covariance per Fact #54 GTSAM Marginals) + FC IMU (high-rate via MAVLink RAW_IMU/SCALED_IMU2) + FC barometer/airspeed/attitude (lower-rate via MAVLink ATTITUDE/VFR_HUD/SCALED_PRESSURE); outputs = WGS84 position (lat/lon/alt) + 3D velocity in body or NED frame + attitude as quaternion + 6×6 honest pose covariance + source label one-of `{satellite_anchored, visual_propagated, dead_reckoned}` + `last_satellite_anchor_age_ms` per AC-NEW-3 FDR + AC-NEW-4 covariance-honest + AC-NEW-8 blackout failsafe + AC-1.4 source-label-output). Per the per-Mode API Capability Verification rule, the project's pinned mode is the **(18-state nominal-state vector `x = [p, v, q, a_b, ω_b, g]` where `p ∈ R³` position, `v ∈ R³` velocity, `q ∈ S³` attitude as 4-element unit quaternion, `a_b ∈ R³` accelerometer bias, `ω_b ∈ R³` gyroscope bias, `g ∈ R³` gravity vector + 18×18 error-state covariance matrix on `δx = [δp, δv, δθ, δa_b, δω_b, δg]` where `δθ ∈ R³` is the small-angle attitude error in tangent-space — minimal-parameter 18-DoF error covariance per Solà §5.1 advantage (i)) + canonical predict-correct loop per Solà §5.4 discrete-time error-state Jacobians + §6.1 measurement update for visual measurements + §6.2 nominal-state injection of error-state estimate + §6.3 covariance reset + Mahalanobis outlier gate (3-σ or χ²-test on innovation residual) before §6.1 update for spoofing + corrupted-anchor robustness + canonical predict-step Jacobian `F_x = ∂f/∂δx` per Solà §5.4.3 + perturbation Jacobian `F_i = ∂f/∂i` per Solà §5.4.3 + IMU process noise injection `Q_i = diag(σ_a²·dt² · I_3, σ_ω²·dt² · I_3, σ_a_b² · dt · I_3, σ_ω_b² · dt · I_3)` per Solà §5.5 + visual measurement Jacobian `H = [I_3, 0_3×3, 0_3×3, 0_3×3, 0_3×3, 0_3×3]` for 3-DoF position-only measurements (from C4 satellite anchor `(x, y, z)` only) OR `H = [I_3, 0_3×3, ∂R(q)/∂δθ, 0_3×3, 0_3×3, 0_3×3]` for 6-DoF position+attitude measurements (from C4 satellite anchor full pose) + Kalman gain `K = P · H.T · (H · P · H.T + R)^-1` + nominal-state injection `q ← q ⊗ exp(δθ/2)` quaternion product per Solà §6.2 + covariance reset `P ← G · P · G.T` where canonical `G ≈ I_18` approximation per Solà §6.3 (the project may opt for the more-precise non-trivial G per Solà §6.3.1 if long-term drift over 8-hour flights becomes binding) + project's Apache-2.0 license)** → 6-DoF camera pose (R, t) in WGS84 + 3D velocity + attitude quaternion + 6×6 covariance + source label + last_satellite_anchor_age_ms.

  **Mode-enumeration query (1/3) — WebFetch direct on canonical paper PASS**: arXiv 1711.02508 (Solà 2017) provides comprehensive mode coverage for the ESKF candidate at **two sub-mode variants** per the paper's structure: **(a) §5 Local-error-state ESKF** (default; error-state attitude `δθ` defined in the body frame; nominal-state attitude `q` rotates body→world; Jacobians per §5.4.3) — most widely deployed in open-source ESKF reference implementations (Source #89.a ludvigls/ESKF, Source #89.b cggos/imu_x_fusion); **(b) §7 Global-error-state ESKF** (alternate; error-state attitude defined in the world frame; Jacobians per §7.x; structurally equivalent in observability but different measurement Jacobian shape — the project must pick one and stick with it for the entire derivation; default project recommendation = (a) Local-error-state). Per the project's pinned mode (a) Local-error-state ESKF, the canonical equations are: predict step (continuous time) §5.3.3 equations (238a-f) for `δp̂_k|k-1`, `δv̂_k|k-1`, `δθ̂_k|k-1`, `δâ_b,k|k-1`, `δω̂_b,k|k-1`, `δĝ_k|k-1`; predict step (discrete time) §5.4.2 equations (282a-f) with closed-form transition matrix `F_x` per §5.4.3; measurement update §6.1 with visual observation `y = H · δx + n` where H is the position-and/or-attitude Jacobian + measurement noise covariance R taken from C4 GTSAM Marginals output (Fact #54 NATIVE 6×6) or from C1 VIO output covariance (per Fact #24 σ_yaw ≤ 5° / σ_pitch ≤ 5° contract); injection §6.2 with quaternion product `q^+ = q ⊗ exp(δθ̂/2)` and additive update for all other states; reset §6.3 with `P^+ ← G · P · G.T` and `δx̂^+ = 0` reset.

  **Pinned-mode runnable example query (2/3) — Source #89 reference implementations PASS**: Multiple canonical reference implementations of Solà 2017 ESKF are publicly available (Source #89): (i) **Source #89.a ludvigls/ESKF** (Python; **DIRECTLY MATCHES project hardware family — fixed-wing UAV + IMU + GNSS-replacement**; tested on simulated + real datasets per author description) — closest documentary template for the project's manual implementation; (ii) **Source #89.b cggos/imu_x_fusion** (C++/ROS; **MATCHES project pattern — IMU + GNSS-as-satellite_anchor + Odom-as-VIO loosely-coupled fusion**; multiple filter variants documented including IEKF, UKF/SPKF/JUKF/SVD-UKF, MAP for cross-validation) — multi-source loosely-coupled pattern alignment; (iii) **Source #89.c EliaTarasov/ESKF** (C++/ROS based on PX4/ecl with vision pose + GPS + magnetometer + optical flow + range finder fusion) — close match but PX4-derived (license verification required at D-C5-1); (iv) **Source #89.d koledickarlo/ESKF-ESP32** (C++ on microcontroller-class targets; explicit citation of Solà 2017 paper) — useful only as small-state ESKF reference; (v) **Source #89.e joansola/slamtb** (MATLAB; Joan Solà's own SLAM Toolbox — most authoritative reference for the canonical paper but MATLAB-only, NOT deployable on JetPack 6). Project does NOT directly reuse these repositories at the source-code level (license verification + cross-domain adaptation costs); instead, the project implements ESKF following Solà 2017 §5+§6 equations directly in Python (NumPy/SciPy) or C++17 (Eigen3), using ludvigls/ESKF as the closest documentary reference template. Reference implementations serve as evidence that Solà 2017 ESKF is implementable + deployable on UAV-class platforms with multi-sensor fusion patterns identical to the project's pinned configuration.

  **Disqualifier-probe query (3/3) — FOUR FINDINGS (1 negative-but-mitigable structural + 3 caveats)**:
  (i) **Manual implementation effort** — ~1-2 weeks for an experienced engineer to code Solà §5+§6 in NumPy/SciPy or C++17/Eigen3 with full test coverage, including: 18-state nominal-state propagation; 18×18 error-state covariance propagation with discrete-time Jacobians per §5.4.3; 6-DoF visual measurement Jacobian for satellite-anchor updates; 9-DoF C1-VIO-output measurement update (relative pose between two keyframes if VIO output is local, OR 6-DoF if VIO output is global-anchored); Mahalanobis outlier gate (3-σ or χ²-test on innovation residual) before §6.1 update for AC-3.1 350m outlier rejection + AC-NEW-2 spoof rejection + AC-NEW-8 blackout failsafe; quaternion-product injection per §6.2; covariance reset per §6.3 with `G ≈ I_18` approximation default + non-trivial G option; **source-label state machine** for AC-NEW-2 spoofing-promotion (`visual_propagated → satellite_anchored` on AC-2.1b satellite-anchor-registration success + `last_satellite_anchor_age_ms < threshold`) + AC-NEW-8 dead-reckoning failsafe (`satellite_anchored → visual_propagated → dead_reckoned` on consecutive registration failures + visual blackout + spoofing-detected); **Mahalanobis outlier gate** with 3-σ or χ²-test on innovation residual `r = y - H · x̂` and `S = H · P · H.T + R` for `r.T · S^-1 · r < χ²_threshold`; FC IMU integration via MAVLink ATTITUDE / RAW_IMU / SCALED_IMU2 high-rate receive at 100+ Hz → high-rate predict-step propagation between visual measurement updates at 3 Hz + per-frame IMU+barometer+airspeed plausibility check before incorporation; this is non-trivial but well-bounded engineering effort. **Mitigation**: project may use Source #89.a ludvigls/ESKF as the closest documentary template (fixed-wing UAV + IMU + GNSS-replacement) for ~30-50% of structural code (with LICENSE verification at D-C5-1 NEW), and/or use joansola/slamtb (MATLAB) as the most-authoritative algorithmic reference per author Joan Solà's own SLAM Toolbox.

  (ii) **ESKF observability requirement** — standard EKF/ESKF fusion of IMU + visual measurements requires sufficient excitation (non-pure-rotation, non-zero acceleration) for IMU bias observability per Solà §5.1 reference + classical observability literature (e.g., Hesch et al. IJRR 2014 on observability of vision-aided inertial navigation). For a fixed-wing UAV in cruise (level flight at ~60 km/h with minimal acceleration), bias drift is the dominant error source; periodic accelerations (turns, climbs, level-to-bank transitions) re-excite observability. **Mitigation**: project's pinned mission profile per restrictions.md (8-hour flights with sharp turns up to ±20° bank per AC-3.1 + sharp-turn frames may share <5% overlap per AC-3.2) provides natural re-excitation; cruise segments rely on visual measurement updates from C2/C3/C4 to keep biases observable. Long-cruise straight-line segments (e.g., 30-min transit corridor) may need synthetic excitation via small-amplitude S-turns OR explicit bias-stationarity prior (project-defined). **NEW Plan-phase decision D-C5-2 NEW** — Plan-phase decision between (a) accept observability degradation in long-cruise segments + monitor via covariance growth + alert operator if covariance > threshold, (b) require operator to perform synthetic S-turns periodically (~every 30 min) to maintain bias observability, (c) tighten bias-stationarity prior (lower IMU bias random-walk noise) at the cost of accepting more bias drift between updates.

  (iii) **Manhattan-world / scale ambiguity caveat in pure-monocular VIO** — NOT directly applicable to project. The classical scale-ambiguity in monocular vision-only SLAM is resolved by C4 satellite-anchor PnP outputs (which are metric in WGS84) — scale is observed at every successful satellite-anchor registration. C1 VIO output also provides metric scale via IMU integration per Solà §5.3-§5.4 + acceleration-double-integration. The project's pinned mode does not have a scale-ambiguity concern.

  (iv) **ESKF reset jitter** — Solà §6.3 reset operation is approximated as `G ≈ I_18` in most implementations; for high-rate operation (project: 3 Hz visual measurement updates, OK), the small but non-zero G correction may be needed to avoid long-term drift over 8-hour flights. **Mitigation**: project's pinned mode defaults to `G = I_18` per Solà §6.3 default; if 8-hour drift becomes binding, project can opt into the non-trivial G per Solà §6.3.1 (one-line change in the implementation; ~5 minutes engineering at Plan phase).

  **Pinned-mode sentence**: "We will catalog **Manual ESKF reference per Solà 2017 (arXiv:1711.02508) §5+§6** with **18-state nominal-state vector + 18×18 error-state covariance + canonical predict-correct loop with §5.4 discrete-time error-state Jacobians + §6.1 measurement update + §6.2 nominal-state injection + §6.3 covariance reset + Mahalanobis outlier gate (χ²-test) before §6.1 update + project's Apache-2.0 implementation license** as the **MANDATORY SIMPLE-BASELINE reference** for the C5 row per engine Component Option Breadth rule. Inputs `{C1 VIO output (6-DoF relative pose @ ≥3 Hz with σ_yaw ≤ 5° / σ_pitch ≤ 5° per Fact #24 contract) + C4 satellite-anchor poses (6-DoF tile-frame absolute pose with 6×6 covariance from C4 Fact #54 GTSAM Marginals when D-C4-2 = (b) coupling, or post-hoc Jacobian recovery when D-C4-2 = (a) standalone OpenCV path) + FC IMU (high-rate via MAVLink RAW_IMU/SCALED_IMU2 at ~100-200 Hz typical Pixhawk-class) + FC barometer/airspeed/attitude (lower-rate via MAVLink VFR_HUD/SCALED_PRESSURE/ATTITUDE) + initial state from FC GPS-extrapolated pose at boot per AC-NEW-1 cold-start + operator re-loc hint via GCS per AC-3.4 (rare)}`; expected outputs `{WGS84 position (lat/lon/alt) + 3D velocity in body or NED frame + attitude as quaternion + 6×6 honest pose covariance via analytic Jacobian propagation per Solà §6.1 H · P · H.T + R Kalman-update math + source label one-of `{satellite_anchored, visual_propagated, dead_reckoned}` per AC-1.4 + last_satellite_anchor_age_ms per AC-1.3 + per-source residual diagnostic for AC-NEW-3 FDR debug + frame-rate output at min camera rate (3 Hz) with FC-IMU-driven propagation between camera updates}`; runtime `Jetson Orin Nano Super (8 GB shared, JetPack 6, ROS 2 Humble) — pure-NumPy/SciPy or C++17/Eigen3 implementation, zero library dependencies beyond standard scientific Python or Eigen3 (both clean BSD/MIT/Apache + JetPack 6 canonical distribution = zero-effort Jetson deployment)`. **MANDATORY-SIMPLE-BASELINE role per engine Component Option Breadth rule** — Manual ESKF per Solà 2017 is the **CANONICAL Kalman-filter state-estimator reference** for the C5 row; no further mandatory-simple-baseline candidates required after this closure. Subsequent C5 candidates (GTSAM iSAM2 factor-graph in Fact #89 below; MSCKF / particle filter / no-build delegate-to-FC if covered in future sessions) will be cataloged as modern-competitive-lead candidates."

- **Source**: Source #88 (canonical arXiv 1711.02508 Solà 2017 paper — sections §5 Error-state kinematics for IMU-driven systems + §5.1 Motivation listing 3 ESKF advantages over standard EKF + §5.2 ESKF explained + §5.3 System kinematics in continuous time + §5.3.3 Error-state kinematics + §5.4 System kinematics in discrete time + §5.4.2 Discrete-time error-state kinematics + §5.4.3 Error-state Jacobian and perturbation matrices + §6 Fusing IMU with complementary sensory data + §6.1 Observation of error state via filter correction + §6.2 Injection of observed error into nominal state + §6.3 ESKF reset + §6.3.1 Jacobian of reset operation + §7 ESKF using global angular errors alternate formulation; canonical equations not copyrightable; 592 citations per Semantic Scholar; open-access at <https://arxiv.org/abs/1711.02508>; HAL mirror at <https://hal.science/hal-01122406v5>; Semantic Scholar PDF at <https://www.semanticscholar.org/paper/Quaternion-kinematics-for-the-error-state-Kalman-Sol%C3%A0/12412090e46d1b21eecc59d1326edb8e47e9640e>), Source #89 (canonical reference open-source ESKF implementations — Source #89.a ludvigls/ESKF Python ESKF for fixed-wing UAVs with IMU+GNSS DIRECTLY MATCHING project hardware family + Source #89.b cggos/imu_x_fusion C++/ROS multi-source loosely-coupled fusion MATCHING project pattern + Source #89.c EliaTarasov/ESKF C++/ROS based on PX4/ecl + Source #89.d koledickarlo/ESKF-ESP32 microcontroller-class with explicit Solà 2017 citation + Source #89.e joansola/slamtb MATLAB Joan Solà's own SLAM Toolbox most-authoritative reference); cross-cite to Fact #24 closure from C1 row (σ_yaw ≤ 5° / σ_pitch ≤ 5° hard contract on C1 VIO attitude output that feeds C5 measurement updates); cross-cite to Fact #54 closure from C4 row (GTSAM Marginals NATIVE 6×6 covariance recovery that feeds C5 measurement noise R for satellite-anchor measurements when D-C4-2 = (b) coupling); cross-cite to SQ6 closures (ArduPilot Plane MAVLink GPS_INPUT + iNav MSP2 MSP2_SENSOR_GPS as C8 output contracts that consume C5's WGS84 pose + 6×6 covariance output per AC-4.3); cross-cite to AC-NEW-3 + AC-NEW-4 + AC-NEW-8 (FDR + covariance honesty + blackout failsafe).

- **Phase**: Phase 2

- **Target Audience**: System architects + C5 implementer + Step-7.5 reviewer + license-posture decision-maker (D-C1-1 — clean public-domain canonical equations + project's Apache-2.0 implementation) + Plan-phase architect (mandatory-simple-baseline role documentation for engine Component Option Breadth rule compliance + D-C5-1 NEW reference-implementation-license-verification gate + D-C5-2 NEW long-cruise-observability-strategy gate)

- **Confidence**: ✅ for canonical-paper-section coverage (§5.1 ESKF advantages + §5.3.3 continuous-time error-state kinematics + §5.4 discrete-time + §5.4.3 Jacobians + §6.1 measurement update + §6.2 injection + §6.3 reset + §6.3.1 reset Jacobian + §7 alternate global-angular-error formulation — all documented in canonical Source #88 with 592 citations validating reproducibility); ✅ for **public-domain canonical equations** (academic preprint at arXiv with no copyright restrictions on equations themselves; project's manual implementation gets project's chosen license — Apache-2.0 default per project tech-stack rule); ✅ for **18-state minimal-parameter error-state covariance** (per §5.1 advantage (i) — quaternion attitude with 4-element nominal-state but only 3-element error-state δθ in tangent-space; total 18-DoF error-state matches Solà §5.3 Table 3); ✅ for **NATIVE 6×6 pose covariance via analytic Jacobian propagation** (per §6.1 Kalman-update math `P^+ = (I - K · H) · P` returns the posterior covariance of the position+attitude error-state subset directly; project extracts 6×6 sub-block of the 18×18 error-state covariance as `[P_pp, P_pθ; P_θp, P_θθ]` for AC-NEW-4 + AC-4.3 reporting); ✅ for **quaternion-correct attitude integration on SO(3)** (per §5.3.3 continuous-time kinematics + §5.4.2 discrete-time + §6.2 injection — small-angle approximation in error-state δθ with quaternion-product nominal-state injection `q^+ = q ⊗ exp(δθ/2)`); ✅ for **Mahalanobis outlier gate** (canonical χ²-test on innovation residual `r.T · S^-1 · r < χ²_threshold` is canonical Kalman-filter literature, not specific to Solà 2017; project's pinned mode includes this as a pre-§6.1 gate for AC-3.1 350m outlier rejection + AC-NEW-2 spoof rejection + AC-NEW-8 blackout failsafe); ✅ for **trivial memory footprint** (18-DoF state + 18×18 covariance = 324 floats = 2.6 KB per instance); ⚠️ for **Jetson Orin Nano Super deployment latency / memory** (no documentary measurement; extrapolation from x86_64 i7-class CPU canonical NumPy/SciPy ESKF predict+correct loop ~1-3 ms per update on Intel i7-class baseline; Jetson Orin Nano Super extrapolation ~5-15 ms per update CPU-only on 6-core ARM Cortex-A78AE class with ~3× slowdown factor for non-vectorized path; at 3 Hz visual measurement updates extrapolated 15-45 ms/sec total = comfortable AC-4.1 satisfaction with substantial margin — **fastest C5 candidate to date by an order of magnitude**); ⚠️ for **manual implementation effort** (~1-2 weeks for an experienced engineer; mitigation = use Source #89.a ludvigls/ESKF as documentary template); ⚠️ for **observability requirement in long-cruise** (D-C5-2 NEW Plan-phase decision required); ⚠️ for **reset Jacobian approximation** (canonical `G ≈ I_18` used in most implementations; non-trivial G per §6.3.1 available if 8-hour drift becomes binding; ~5 minutes engineering Plan-phase one-line change); ❌ for **canonical-checkpoint aerial-domain fitness** — N/A for Manual ESKF since it is a classical algorithm, not a learned method (no canonical-weights aerial-domain caveat applies)

- **Related Dimension**: SQ3+SQ4 / C5 mandatory simple-baseline reference (engine Component Option Breadth rule role — structurally analogous to OpenCV `cv::solvePnPRansac`'s role in C4 row + NetVLAD's role in C2 row + SuperGlue+SuperPoint's role in C3 row) — per-mode API capability verification gate

- **Fit Impact**: **DOCUMENTARY PASS for the per-mode API capability verification gate at the mandatory-simple-baseline role** — Manual ESKF per Solà 2017 has documented runnable per-mode equations with the project's pinned configuration (canonical paper §5+§6 with 592 citations validating reproducibility + 5 reference open-source implementations spanning Python / C++ / ROS / MATLAB / microcontroller-class), 18-state nominal-state vector with 18×18 error-state covariance (minimal-parameter per §5.1 advantage (i)), §5.4.3 closed-form discrete-time Jacobians, §6.1 measurement update with Kalman gain + Mahalanobis outlier gate, §6.2 nominal-state injection with quaternion-product update, §6.3 covariance reset with G ≈ I_18 default + non-trivial G option per §6.3.1. **THREE CONVERGING POSITIVE structural advantages**: (i) **PUBLIC-DOMAIN CANONICAL EQUATIONS + PROJECT-APACHE-2.0 IMPLEMENTATION LICENSE** — academic preprint at arXiv with no copyright restrictions on equations themselves; project's manual implementation gets project's chosen license; eligible on every D-C1-1 license-posture choice with the simplest license-compliance story (no upstream library license to verify); (ii) **NATIVE 6×6 POSE COVARIANCE via analytic Jacobian propagation** — per §6.1 Kalman-update math, posterior covariance is computed analytically from `(I - K · H) · P`; project extracts 6×6 sub-block for AC-NEW-4 reporting; **only C5 candidate to satisfy AC-NEW-4 covariance honesty NATIVELY without library-mediated posterior recovery** (GTSAM Marginals via Fact #54 + Fact #89 also satisfies natively but at much higher library footprint cost); (iii) **TRIVIAL MEMORY + COMPUTE FOOTPRINT** — 2.6 KB for state + covariance, ~5-15 ms per update on Jetson CPU; **fastest C5 candidate by an order of magnitude** vs GTSAM iSAM2's ~50-150 ms per update extrapolation. **ONE NEGATIVE-BUT-MITIGABLE structural finding**: (iv) **MANUAL IMPLEMENTATION EFFORT** ~1-2 weeks for an experienced engineer; mitigation = use Source #89.a ludvigls/ESKF as documentary template (fixed-wing UAV match) for ~30-50% of structural code with LICENSE verification at D-C5-1 NEW. **THREE CAVEATS**: (v) **observability requirement in long-cruise** — D-C5-2 NEW Plan-phase decision required; mitigation = project's pinned mission profile per restrictions.md provides natural re-excitation via sharp turns up to ±20° bank per AC-3.1; (vi) **reset Jacobian approximation** — canonical `G ≈ I_18` default per §6.3; non-trivial G per §6.3.1 available; (vii) **No JetPack 6 canonical distribution** — N/A since project implements in pure-Python/NumPy or pure-C++/Eigen3 with no upstream library dependencies; **trivially deployable on JetPack 6 with zero cross-compilation engineering** (vs GTSAM Fact #89 ~1-2 days cross-compilation + OpenGV Fact #53 ~1-2 weeks fork-and-patch). **NEW Plan-phase decisions raised by Manual ESKF closure**: **D-C5-1 NEW reference-implementation-license-verification** — if project elects to reuse Source #89.a ludvigls/ESKF or Source #89.b cggos/imu_x_fusion or Source #89.d koledickarlo/ESKF-ESP32 (LICENSE not declared in front-page README per Source #89), Plan-phase verification gate required: (a) counsel-review of repo for LICENSE file in subdirectory (~1 hour engineering), (b) treat as GPL/copyleft-equivalent and write project implementation from Solà 2017 paper directly without code reuse (~1-2 weeks engineering vs ~3-5 days with reference template), (c) contact author for LICENSE clarification (~1-3 weeks turnaround); recommendation = (b) write directly from paper for cleanest license-compliance story. Source #89.c EliaTarasov/ESKF is PX4-derived (PX4 is dual BSD/Apache-2.0, ecl is BSD-3-Clause) so license-clearance is easier if project elects to reuse that template. Source #89.e joansola/slamtb is MATLAB-only and not deployable on JetPack 6 (algorithmic reference only). **D-C5-2 NEW long-cruise-observability-strategy** — Plan-phase decision between (a) accept observability degradation in long-cruise segments + monitor via covariance growth + alert operator if covariance > threshold, (b) require operator to perform synthetic S-turns periodically (~every 30 min) to maintain bias observability, (c) tighten bias-stationarity prior (lower IMU bias random-walk noise) at the cost of accepting more bias drift between updates. Recommendation = (a) accept + monitor (matches AC-1.3 cumulative drift monitoring + AC-1.4 covariance + source-label output contract; covariance growth alert is consistent with AC-NEW-8 blackout failsafe escalation thresholds). **C5 mandatory pre-screen status**: Manual ESKF per Solà 2017 closes the C5 mandatory pre-screen at **1 of N candidates** (mandatory-simple-baseline role STRUCTURALLY COMPLETE — no further mandatory-simple-baseline candidates required for the C5 row per engine Component Option Breadth rule). License: **public-domain canonical equations + project's Apache-2.0 implementation** — clean BSD/permissive license track on the C5 mandatory-simple-baseline; under D-C1-1 = (a) GPL-3.0 track, (b) BSD/permissive lock, or (c) keep-both-tracks-open, Manual ESKF is **eligible on every license-posture choice with the simplest license-compliance story** (tied with cvg/LightGlue + DISK + XFeat + OpenCV + GTSAM for cleanest license-compliance story across all C-row components evaluated). **Position vs all expected C5 candidates**: Manual ESKF per Solà 2017 is the **canonical mandatory-simple-baseline reference** that the C5 row's modern competitive leads (GTSAM iSAM2 factor-graph in Fact #89 below; MSCKF if cataloged in future sessions; particle filter if cataloged in future sessions; no-build delegate-to-FC if cataloged in future sessions) must measurably exceed on documented-evidence axes (per-frame covariance honesty, multi-source asynchronous fusion latency, sliding-window memory boundedness, IMU pre-integration accuracy at high IMU rate, outlier-rejection effectiveness via Mahalanobis vs robust noise model vs GncOptimizer). Final ranking deferred to Jetson MVE phase per the project's D-C1-2 deferred-MVE strategy.

---

## C5 — Per-Mode API Capability Verification (engine Step 2 — Manual ESKF Solà 2017 mandatory simple-baseline session entry, 2026-05-08)

### MVE — Manual ESKF reference per Solà 2017 §5+§6 with 18-state nominal-state vector + 18×18 error-state covariance matrix + canonical predict-correct loop with §5.4 discrete-time error-state Jacobians + §6.1 measurement update for visual measurements + §6.2 nominal-state injection of error-state estimate + §6.3 covariance reset + Mahalanobis outlier gate before §6.1 update + project's Apache-2.0 implementation license

- **Source**: Source #88 (canonical arXiv 1711.02508 Solà 2017 paper — full §5+§6 coverage of error-state kinematics for IMU-driven systems + fusing IMU with complementary sensory data; canonical equations + 592 citations validating reproducibility), Source #89 (5 reference open-source ESKF implementations spanning Python / C++ / ROS / MATLAB / microcontroller-class — Source #89.a ludvigls/ESKF DIRECTLY MATCHING project hardware family); cross-cite to Fact #24 (C1 VIO σ_yaw ≤ 5° / σ_pitch ≤ 5° contract) + Fact #54 (C4 GTSAM Marginals NATIVE 6×6 for measurement noise R)
- **Inputs in the example**: Per Solà §5.3 Table 3 — `x_t = [p_t, v_t, q_t, a_b,t, ω_b,t, g_t]` 18-DoF nominal-state with nominal-state attitude as 4-element quaternion; `δx_t = [δp_t, δv_t, δθ_t, δa_b,t, δω_b,t, δg_t]` 18-DoF error-state with attitude error as 3-element tangent-space; `u_m = [a_m, ω_m]` 6-element high-rate IMU measurement (accelerometer + gyroscope); `Q_i = diag(σ_a²·dt² · I_3, σ_ω²·dt² · I_3, σ_a_b² · dt · I_3, σ_ω_b² · dt · I_3)` 12×12 IMU process noise covariance; `y = h(x_t) + n` measurement equation with `n ~ N(0, R)` and `h` = visual measurement function (project: 3-DoF position from C4 satellite anchor + 3-DoF attitude from C4 satellite anchor full pose = 6-DoF measurement; OR 6-DoF relative pose from C1 VIO between two keyframes = relative measurement)
- **Outputs in the example**: 18-DoF nominal-state `x_t^+` after measurement update + 18×18 error-state covariance `P_t^+` after measurement update + 6×6 sub-block extracted as `[P_pp, P_pθ; P_θp, P_θθ]` for AC-NEW-4 reporting + source label per project's state machine logic (NOT in canonical Solà 2017 paper — project-specific extension for AC-1.4 + AC-NEW-2 + AC-NEW-8); reset error-state `δx̂^+ = 0` per §6.3
- **Project inputs**: Per project's pinned mode = `{C1 VIO output (6-DoF relative pose @ ≥3 Hz with σ_yaw ≤ 5° / σ_pitch ≤ 5° per Fact #24 contract; OKVIS2/OpenVINS/VINS-Mono per D-C1-1) + C4 satellite-anchor poses (6-DoF tile-frame absolute pose with 6×6 covariance from C4 Fact #54 GTSAM Marginals when D-C4-2 = (b) coupling, or post-hoc Jacobian recovery when D-C4-2 = (a) standalone OpenCV path) + FC IMU (high-rate via MAVLink RAW_IMU/SCALED_IMU2 at ~100-200 Hz typical Pixhawk-class) + FC barometer/airspeed/attitude (lower-rate via MAVLink VFR_HUD/SCALED_PRESSURE/ATTITUDE) + initial state from FC GPS-extrapolated pose at boot per AC-NEW-1 cold-start + operator re-loc hint via GCS per AC-3.4 (rare)}`
- **Project outputs required**: `{WGS84 position (lat/lon/alt) + 3D velocity in body or NED frame + attitude as quaternion + 6×6 honest pose covariance + source label one-of {satellite_anchored, visual_propagated, dead_reckoned} + last_satellite_anchor_age_ms + per-source residual diagnostic for debug + frame-rate output at min camera rate (3 Hz) with FC-IMU-driven propagation between camera updates}` per AC-NEW-3 (FDR), AC-NEW-4 (covariance honesty), AC-NEW-8 (blackout failsafe), AC-3.x (resilience), AC-1.x (accuracy). **Latency budget extrapolation to Jetson Orin Nano Super**: Manual ESKF predict+correct loop in pure-NumPy/SciPy (Python) extrapolated ~5-15 ms per update on 6-core ARM Cortex-A78AE class CPU (Intel i7-class baseline ~1-3 ms × 3× ARM slowdown factor for non-vectorized path; could be reduced to ~2-5 ms with C++17/Eigen3 implementation + vectorized matrix-multiply via Eigen's expression-template optimization); at 3 Hz visual measurement updates extrapolated 15-45 ms/sec total = **comfortable AC-4.1 satisfaction** with substantial margin (well below 400 ms budget and dramatically faster than GTSAM iSAM2 in Fact #89). **Memory budget extrapolation**: 2.6 KB per instance for state + covariance; effectively zero memory pressure on AC-4.2 8 GB shared budget — **lightest-weight C5 candidate by an order of magnitude** (vs GTSAM iSAM2 in Fact #89 at ~50-200 MB library footprint).
- **Match assessment**: ✅ exact mode match for **(18-state nominal + 18×18 error-state covariance + canonical predict-correct loop with §5.4 discrete-time Jacobians + §6.1 visual measurement update + §6.2 quaternion-product injection + §6.3 covariance reset + Mahalanobis outlier gate)**; ✅ runnable example (canonical paper §5+§6 + 5 reference open-source implementations including Source #89.a ludvigls/ESKF DIRECTLY MATCHING fixed-wing UAV + IMU + GNSS-replacement project hardware family); ✅ all canonical Solà 2017 equations documented (§5.1 motivation + §5.3.3 continuous-time kinematics + §5.4.2 discrete-time + §5.4.3 Jacobians + §6.1 measurement update + §6.2 injection + §6.3 reset + §6.3.1 reset Jacobian); ✅ both §5 local-error-state and §7 global-error-state ESKF formulations documented (project default = §5 local-error-state per closer match to canonical reference implementations); ✅ public-domain canonical equations + project's Apache-2.0 implementation license; ✅ NATIVE 6×6 pose covariance via analytic Jacobian propagation per §6.1 Kalman-update math; ⚠️ **manual implementation effort** ~1-2 weeks for an experienced engineer (mitigation = use Source #89.a ludvigls/ESKF as documentary template); ⚠️ **observability requirement in long-cruise** (D-C5-2 NEW Plan-phase decision required); ⚠️ **reset Jacobian approximation** (canonical `G ≈ I_18` default per §6.3; non-trivial G per §6.3.1 available)
- **If ⚠️ or ❌**: docs do not disqualify the algorithmic mode at the API level, and **NO HARD DISQUALIFIERS apply** at the deployment level. The (state-vector, error-covariance, predict-correct, measurement-update, injection, reset, Mahalanobis-gate, license) tuple is documented and runnable directly via canonical Solà 2017 paper equations + 5 reference open-source implementations. **THREE CONVERGING POSITIVE structural advantages** (public-domain canonical equations + project's Apache-2.0 implementation license + NATIVE 6×6 pose covariance via analytic Jacobian propagation + trivial memory + compute footprint) make Manual ESKF per Solà 2017 **eligible as the C5 mandatory-simple-baseline reference** under every D-C1-1 license-posture choice. **ONE NEGATIVE-BUT-MITIGABLE structural finding** (manual implementation effort ~1-2 weeks; mitigation = ludvigls/ESKF documentary template) and **THREE CAVEATS** (observability in long-cruise via D-C5-2; reset Jacobian approximation default; no JetPack 6 canonical distribution N/A since pure-Python/NumPy or pure-C++/Eigen3 trivially deployable) are all minor structural concerns that do not block the mandatory-simple-baseline role. → Status: **Mandatory simple-baseline (Kalman-filter state-estimator reference floor) with THREE CONVERGING POSITIVE STRUCTURAL ADVANTAGES (public-domain canonical equations + project's Apache-2.0 implementation license + NATIVE 6×6 pose covariance via analytic Jacobian propagation + trivial memory + compute footprint) + ONE NEGATIVE-BUT-MITIGABLE STRUCTURAL FINDING (manual implementation effort ~1-2 weeks; mitigation = ludvigls/ESKF documentary template) + THREE MINOR CAVEATS (observability in long-cruise via D-C5-2; reset Jacobian approximation default; no JetPack 6 canonical distribution N/A)**, public-domain canonical equations + project's Apache-2.0 implementation license. **Final ranking deferred to Jetson MVE phase** per the project's D-C1-2 deferred-MVE strategy. Per the engine Component Option Breadth rule, Manual ESKF per Solà 2017 closes the C5 mandatory pre-screen mandatory-simple-baseline role at **1 of N candidates** (mandatory-simple-baseline role STRUCTURALLY COMPLETE — no further mandatory-simple-baseline candidates required). Subsequent C5 candidates (GTSAM iSAM2 factor-graph in Fact #89 below; MSCKF / particle filter / no-build delegate-to-FC if covered in future sessions) will be cataloged as modern-competitive-lead candidates.

---

## C5 — Per-numbered-Restriction × Per-numbered-AC Sub-Matrix per Candidate (Manual ESKF Solà 2017 mandatory simple-baseline addition)

### Manual ESKF per Solà 2017 — per-numbered binding (C5-relevant lines only)

> Cells share the legend defined under the C2/C3/C4 sub-matrices. Where a binding is identical in substance and evidence to all expected C5 candidates (state-estimator-class generic), the Manual ESKF row says so explicitly to keep future C5 row entries (GTSAM iSAM2 / MSCKF / particle filter / no-build) compact; where Manual ESKF's pinned mode produces a materially different binding (mandatory-simple-baseline-only role with the unique "trivial footprint + NATIVE 6×6 covariance via analytic Jacobian" structural advantage), the row carries a distinct evidence cite.

| Line | Binding | Evidence (one-line cite) |
|---|---|---|
| AC-1.1 (frame-center within 50 m, ≥80% normal-flight photos) | **Pass (mechanical via §6.1 measurement update with C4 satellite-anchor input) → Verify (depends on C4 lift accuracy + C4 covariance honesty + C5 IMU bias estimation)** | Manual ESKF accepts C4 satellite-anchor 6-DoF measurements via §6.1 Kalman-update math; final 50 m frame-center accuracy is **upper-bounded by C4's pose accuracy** (D-C4-1 lift + D-C3-1 matcher + D-C2-1 retrain) + **lower-bounded by IMU integration drift between visual updates** (driven by IMU bias estimation per §5.3.3 + §5.4.3). Project-side validation at Jetson MVE phase on AerialExtreMatch + Derkachi flight |
| AC-1.2 (frame-center within 20 m, ≥50% normal-flight photos) | **Pass (mechanical) → Verify — IMU bias estimation accuracy + observability is the binding constraint at the tighter tail** | Same as AC-1.1 with tighter tail; **IMU bias estimation accuracy** (Solà §5.3 + §5.4.3) becomes dominant error source between visual updates; D-C5-2 NEW long-cruise-observability-strategy interacts with AC-1.2 tail; mitigation = mission-profile-natural re-excitation via AC-3.1 + AC-3.2 sharp turns |
| AC-1.3 (cumulative drift between consecutive satellite-anchored fixes: <100 m visual-only / <50 m IMU fused; report `last_satellite_anchor_age_ms`) | **Pass (mechanical via §5.4 IMU integration + §6.1 visual update) — NATIVE Solà §5+§6 design** | Solà §5.3-§5.4 IMU integration provides the **<50 m IMU-fused** drift bound between satellite anchors; project's IMU-driven nominal-state propagation `x_t = f(x_{t-1}, u_m, dt)` accumulates drift bounded by IMU bias × dt² + integration noise; `last_satellite_anchor_age_ms` is trivially trackable as a project-side counter incremented on every IMU-only predict and reset on every successful §6.1 measurement update with `source = satellite_anchor`; **NATIVE design fit for AC-1.3** |
| AC-1.4 (each estimate reports 95% covariance ellipse semi-major axis (m) AND a label `{satellite_anchored, visual_propagated, dead_reckoned}`) | **Pass (mechanical) — NATIVE 6×6 covariance + project-side state machine** | **CRITICAL POSITIVE finding for Manual ESKF**: 95% covariance ellipse semi-major axis is computed as `1.96 · max(eigenvalues(P_pp))` where `P_pp` is the 3×3 position sub-block of the 18×18 error-state covariance; **NATIVE 6×6 covariance via analytic Jacobian propagation per §6.1 satisfies AC-1.4 NATIVELY without library-mediated posterior recovery**. Source label is project-side state machine: `satellite_anchored ← (last successful §6.1 update with source=satellite_anchor AND last_satellite_anchor_age_ms < threshold)`; `visual_propagated ← (last successful §6.1 update with source=visual_anchor OR (no satellite_anchor for > threshold AND C1 VIO providing relative pose updates))`; `dead_reckoned ← (no successful §6.1 update for > threshold AND IMU-only propagation)` — all canonical Kalman-filter literature recipes. **NATIVE design fit for AC-1.4** |
| AC-2.1a (frame-to-frame registration succeeds, >95% normal flight) | **N/A — algorithm-level (C5 consumes C1+C3 outputs, not frame-to-frame matching)** | Frame-to-frame registration applies at C1 (VIO) + C3 (matcher) layers; Manual ESKF C5 consumes C1+C3 outputs as `y` in §6.1 measurement update without performing the registration itself |
| AC-2.1b (satellite-anchor registration succeeds, AC-1.1/1.2 + AC-2.2 + AC-8.2 + AC-8.6 conditions) | **N/A — algorithm-level (C5 consumes C2+C3+C4 outputs, not satellite-anchor matching)** | Satellite-anchor registration applies at C2 (VPR) + C3 (matcher) + C4 (PnP) layers; Manual ESKF C5 consumes C4 PnP output as `y` in §6.1 measurement update without performing the matching itself |
| AC-2.2 (mean reprojection error <1.0 px frame-to-frame; <2.5 px satellite-anchored cross-domain) | **N/A — algorithm-level (C4 PnP residual output, consumed by C5 as measurement-noise R)** | Mean reprojection error applies at C4 (PnP+RANSAC+LM) layer per Fact #20; Manual ESKF C5 consumes C4's per-correspondence reprojection residual as input to the measurement noise covariance `R` in §6.1 (e.g., `R = mean_reprojection_error² · I_3` for 3-DoF position measurements scaled appropriately by ground-resolution-per-pixel from C6 tile metadata) |
| AC-3.1 (tolerate up to 350 m outliers between consecutive photos; airframe tilt up to ±20°) | **Pass (mechanical via Mahalanobis outlier gate + §6.1) — NATIVE Solà §6.1 + classical Kalman-filter literature** | Manual ESKF Mahalanobis outlier gate (3-σ or χ²-test on innovation residual `r = y - H · x̂`, `S = H · P · H.T + R`, gate = `r.T · S^-1 · r < χ²_threshold`) before §6.1 update rejects 350m outlier measurements that exceed ~3-5σ of expected residual distribution; outlier-rejected measurements do not corrupt the filter state. Airframe tilt up to ±20° is fully captured by the §5.3.3 attitude-error kinematics + §6.2 quaternion-product injection — no special-case logic required |
| AC-3.2 (sharp turns: <5% overlap, <200 m drift, <70° heading change; recovery via satellite re-loc) | **Pass (mechanical via §5.4 IMU integration + §6.1 satellite-anchor recovery) — NATIVE Solà §5+§6 design** | Solà §5.3-§5.4 IMU integration provides the <200 m drift bound during sharp turns when C1 VIO fails (per AC-3.2 "sharp-turn frames may fail frame-to-frame registration"); §6.1 measurement update on subsequent successful C4 satellite-anchor registration recovers the absolute pose anchor; <70° heading change is fully captured by §5.3.3 attitude-error kinematics + §6.2 quaternion-product injection. **NATIVE design fit for AC-3.2** |
| AC-3.3 (≥3 disconnected segments via satellite-reference re-localization; core capability not degraded mode) | **Pass (mechanical via §6.1 measurement update with C4 satellite-anchor input on every successful registration) — NATIVE Solà §6.1 design** | Manual ESKF treats every successful C4 satellite-anchor registration identically as a §6.1 measurement update; disconnected segments are stateless from the filter's perspective (each measurement update incorporates the new evidence with the current covariance + Mahalanobis gate); project's K=10 top-K image pairs per UAV frame each invoke independent §6.1 measurement updates if all pass the Mahalanobis gate. **NATIVE design fit for AC-3.3** |
| AC-3.4 (operator re-loc hint via GCS on ≥3 consecutive frames AND ≥2 s without position) | **Pass (mechanical via §6.1 measurement update with operator-hint as 3-DoF position prior) — NATIVE Solà §6.1 design** | Operator re-loc hint via GCS is consumed as a 3-DoF position measurement update via §6.1 with a project-defined uncertainty (e.g., `R = (operator_hint_uncertainty)² · I_3` where operator_hint_uncertainty is project-defined ~50-100 m for GCS-side operator point-and-click). **NATIVE design fit for AC-3.4** |
| AC-3.5 (visual blackout + spoofed GPS: switch to dead_reckoned within ≤1 frame OR ≤400 ms; reject spoofed GPS; propagate from last trusted state + FC IMU; covariance grows monotonically; horiz_accuracy ≥ 95% covariance; STATUSTEXT 1-2 Hz) | **Pass (mechanical via project-side state machine + §5.4 IMU-only predict + Mahalanobis gate rejecting spoofed GPS) — NATIVE Solà §5+§6 design + project state machine** | Project-side state machine transitions `satellite_anchored / visual_propagated → dead_reckoned` on detection of visual blackout (consecutive C2/C3/C4 failures) AND spoofed GPS (FC reports GPS denial/spoof OR Mahalanobis gate rejects FC-reported GPS as outlier on internal consistency check). §5.4 IMU-only predict-step propagation continues without measurement updates; covariance grows monotonically per `P^+ = F · P · F.T + Q_i` IMU process noise injection. `horiz_accuracy = 1.96 · max(eigenvalues(P_pp))` always reflects current covariance per §6.1. STATUSTEXT 1-2 Hz to QGroundControl is C8 (FC adapter) responsibility, not C5; C5 emits the source-label + covariance which C8 packages as MAVLink message. **NATIVE design fit for AC-3.5** |
| AC-4.1 (latency <400 ms p95, end-to-end camera→FC) | **Pass (with Verify) — comfortable margin extrapolated to Jetson Orin Nano Super; FASTEST C5 candidate by an order of magnitude** | Manual ESKF predict+correct loop in pure-NumPy/SciPy (Python) extrapolated ~5-15 ms per update on 6-core ARM Cortex-A78AE class CPU; at 3 Hz visual measurement updates extrapolated 15-45 ms/sec total; **comfortable AC-4.1 satisfaction** with substantial margin (well below 400 ms budget; **fastest C5 candidate by an order of magnitude** vs GTSAM iSAM2 in Fact #89 ~50-150 ms per update). Could be reduced to ~2-5 ms per update with C++17/Eigen3 implementation + vectorized matrix-multiply via Eigen's expression-template optimization |
| AC-4.2 (memory <8 GB shared) | **Pass — TRIVIAL memory footprint** | 18-DoF state + 18×18 error-state covariance = 324 floats = 2.6 KB per instance; effectively **zero memory pressure** on AC-4.2 8 GB shared budget — **lightest-weight C5 candidate by an order of magnitude** (vs GTSAM iSAM2 in Fact #89 at ~50-200 MB library footprint) |
| AC-4.3 (FC output contract: WGS84 via per-FC interface; honest covariance carries in field FC uses for outlier rejection) | **Pass (mechanical via §6.1 NATIVE 6×6 covariance) — NATIVE Solà §6.1 design** | Manual ESKF emits WGS84 + NATIVE 6×6 covariance to C8 (FC adapter); C8 packages position into MAVLink `GPS_INPUT` (ArduPilot Plane) `eph` / `epv` fields OR MSP2 `MSP2_SENSOR_GPS` (iNav UBX-impersonation per SQ6 closure) `ph_acc` / `pv_acc` fields. Honest covariance from §6.1 satisfies AC-4.3 NATIVELY without library-mediated posterior recovery. **NATIVE design fit for AC-4.3** |
| AC-4.4 (estimates streamed frame-by-frame; no batching/delay) | **Pass (mechanical via §6.1 single-shot measurement update per frame) — NATIVE Solà §6.1 design** | Manual ESKF performs §6.1 measurement update once per frame at 3 Hz visual cadence; no batching; output emitted to C8 immediately after §6.2 injection + §6.3 reset. **NATIVE design fit for AC-4.4** |
| AC-4.5 (system may refine prior estimates and emit corrections) | **N/A — recursive Kalman-filter literature does not natively support look-back refinement; future C5 = GTSAM iSAM2 in Fact #89 supports this NATIVELY via incremental smoothing** | Manual ESKF is a **recursive filter** (only forward-time predict+correct); it cannot natively refine prior estimates without external buffering. **Project workaround for AC-4.5**: project may buffer a small sliding window of N=5-10 prior estimates + their pre-update covariances, and on receipt of a delayed measurement (e.g., C4 satellite-anchor registration that takes >1 frame to complete), apply the delayed measurement to the corresponding prior state + propagate forward to current time. Adds ~1-2 days engineering. **Alternative**: pivot to GTSAM iSAM2 in Fact #89 below for NATIVE incremental smoothing support |
| AC-5.1 (initialise from FC EKF's last valid GPS + IMU-extrapolated position at GPS denial) | **Pass (mechanical via initial-state injection from FC GPS-extrapolated pose) — project-side initialization recipe** | Project-side initialization: at boot, query FC's last valid GPS + IMU-extrapolated position via MAVLink `GLOBAL_POSITION_INT` + `ATTITUDE`, and inject as initial nominal-state `x_0 = [p_gps, v_imu, q_attitude, 0_3, 0_3, [0, 0, -9.81]]` with initial covariance `P_0 = diag(σ_gps² · I_3, σ_v² · I_3, σ_θ² · I_3, σ_a_b,init² · I_3, σ_ω_b,init² · I_3, σ_g² · I_3)` reflecting initial uncertainty. Standard cold-start recipe; ~30 minutes engineering at Plan phase |
| AC-5.2 (>3 s without estimate, FC falls back to IMU-only) | **N/A — FC-side behavior, not C5 concern** | AC-5.2 is FC-side behavior (ArduPilot Plane EKF3 / iNav internal estimator dead-reckoning); C5 only emits estimates via C8; FC's own dead-reckoning fallback is per-FC parameter wiring + SITL verification per AC-5.2 explicit "Verify in production param sets of each supported FC" language |
| AC-5.3 (companion reboot mid-flight, re-init from FC's IMU-extrapolated position; cold-start TTFF in AC-NEW-1) | **Pass (mechanical via same initialization recipe as AC-5.1) — project-side initialization recipe** | Same as AC-5.1; companion reboot triggers same initialization sequence with FC GPS-extrapolated pose + IMU-extrapolated attitude. Cold-start TTFF measured against AC-NEW-1 |
| AC-6.1 (estimates + confidence stream to QGC over MAVLink at 1-2 Hz downsampled) | **N/A — C8 (FC adapter) and GCS interface concern, not C5** | Downsampling for QGC stream is C8 / GCS adapter responsibility, not C5; C5 emits at full frame rate (3 Hz) for FC and FDR consumption |
| AC-6.2 (GCS may send commands via MAVLink) | **N/A — GCS interface concern, not C5** | Operator re-loc hint per AC-3.4 is consumed by C5 (per AC-3.4 row above); other GCS commands are C8 / GCS adapter responsibility |
| AC-6.3 (output coordinates in WGS84) | **Pass (mechanical) — project-side WGS84 output convention** | Manual ESKF nominal-state position `p` is in WGS84 by convention (project-defined); §5.3-§5.4 IMU integration is in body or NED frame depending on attitude convention; project picks NED convention with WGS84 origin set at first satellite-anchor fix or boot-time GPS extrapolation |
| AC-7.1 (AI-camera object localization at frame-center accuracy in level flight; bounded by altitude × \|sin(unknown_bank_or_pitch)\| in maneuvering) | **N/A — AI-camera object localization is downstream of C5 output** | C5 emits UAV WGS84 pose; AI-camera object localization is performed downstream by AI camera + project's object-localization pipeline (not part of C1-C10) consuming C5's UAV WGS84 pose + AI-camera gimbal angle + zoom + altitude |
| AC-7.2 (object coords trigonometric; flat-terrain assumption) | **N/A — same as AC-7.1** | Same as AC-7.1 |
| AC-8.1 (cache-interface resolution ≥0.5 m/px, ideally 0.3 m/px) | **N/A — algorithm-level** | Cache-interface resolution applies at C6 (tile cache + spatial index) layer, NOT C5 |
| AC-8.2 (tile freshness <6 mo active-conflict, <12 mo stable rear) | **N/A — algorithm-level** | Tile freshness applies at C6 (tile cache freshness enforcement) layer, NOT C5; C5 consumes whatever C4 emits as satellite-anchor measurement |
| AC-8.3 (imagery pre-loaded; pre-extracted descriptors count against cache budget) | **N/A — algorithm-level** | Cache budget applies at C2/C6 layers, NOT C5; Manual ESKF C5 has trivial 2.6 KB state + covariance footprint, NO cache footprint |
| AC-8.4 (mid-flight tile generation; orthorectified nav-camera frames; deduplicated; upload on landing) | **N/A — write-side cache concern, owned by C6** | Mid-flight tile generation (orthorectification) is reassigned-pending-final-row-decision to C6 per C4 row file definition correction |
| AC-8.5 (no raw camera frames retained; tiles only persistent imagery) | **N/A — storage policy** | Storage policy applies at C6 + project's data persistence layer |
| AC-8.6 — Scale-ratio (any UAV-frame ground footprint at deployment altitude must be retrievable) | **N/A — algorithm-level** | Scale-ratio applies at C2/C6 layer (VPR retrieval + tile cache), NOT C5 |
| AC-8.6 — Scene change in active-conflict sectors | **N/A — algorithm-level (Manual ESKF has no scene-change sensitivity)** | Scene change applies at C2 (VPR retrieval) + C3 (matcher) layers; Manual ESKF inherits whatever satellite-anchor measurements C4 emits |
| AC-8.6 — Compute & latency under steady-state and re-loc-trigger | **Pass (with Verify) — comfortable margin** | Same as AC-4.1 |
| AC-NEW-1 (cold-start TTFF <30 s p95) | **Pass (mechanical via initialization recipe + first satellite-anchor registration) — comfortable margin** | Manual ESKF cold-start TTFF is dominated by C2/C3/C4 first-successful-registration time, NOT ESKF setup time (initialization is ~30 ms project-side recipe). First-satellite-anchor registration depends on D-C2-1 + D-C3-1 + D-C4-1 closures; AC-NEW-1 verification at Jetson MVE phase |
| AC-NEW-2 (spoofing-promotion latency <3 s p95) | **Pass (mechanical via project-side state machine + Mahalanobis outlier gate rejecting spoofed GPS) — comfortable margin** | Project-side state machine + Mahalanobis outlier gate detects spoofed GPS (FC reports GPS denial/spoof OR Mahalanobis gate rejects FC-reported GPS on internal consistency check) within 1 frame (~333 ms at 3 Hz visual cadence) — well within 3 s budget |
| AC-NEW-3 (Flight Data Recorder per-frame estimates with covariance + source-label; FC IMU traces; emitted MAVLink; system health; mid-flight tiles; ≤0.1 Hz failed-tile-gen thumbnail; cap 64 GB/flight) | **Pass (mechanical via per-frame output stream) — NATIVE Solà §6.1 + project state machine** | Manual ESKF emits per-frame estimates with NATIVE 6×6 covariance + project-side source-label + per-source residual diagnostic; all consumed by FDR per AC-NEW-3 budget (64 GB/flight; per-frame estimate ~1 KB at 3 Hz × 8 hours × 3600 s/hr × 1 KB = ~86 MB total, negligible against budget) |
| AC-NEW-4 (false-position safety budget P(error >500 m) <0.1%, P(error >1 km) <0.01%) | **Pass via NATIVE 6×6 covariance honesty + Mahalanobis outlier gate — NATIVE Solà §5+§6 design** | **CRITICAL POSITIVE finding for Manual ESKF**: NATIVE 6×6 pose covariance via analytic Jacobian propagation per §6.1 satisfies AC-NEW-4 covariance-honesty contract NATIVELY without library-mediated posterior recovery (vs C4 OpenCV solvePnPRansac which requires D-C4-2 covariance-recovery-strategy decision per Fact #52). Mahalanobis outlier gate before §6.1 update rejects measurements that exceed ~3-5σ of expected residual distribution, providing structural defense against false-position events. AC-NEW-4 statistical budget verification at Jetson MVE phase via Monte Carlo over public datasets per AC-NEW-4 Validation language |
| AC-NEW-5 (operating temp -20°C to +50°C; 25 W at upper temp for 8h without throttling) | **N/A — hardware/cooling concern, not C5** | Operating temp + cooling is hardware concern; C5 is computationally so light that it has no thermal contribution beyond ARM CPU base load |
| AC-NEW-6 (imagery freshness enforcement; never satellite_anchored on stale-tile match) | **Pass (mechanical via project-side state machine source-label gating) — project-side state machine extension** | Project-side state machine: when C4 emits a satellite-anchor measurement with `tile_freshness_age > AC-8.2 threshold`, C5 incorporates the measurement via §6.1 IF Mahalanobis gate passes BUT labels the result `visual_propagated` instead of `satellite_anchored` — ensures the stale-tile match contributes to the estimate without claiming full satellite-anchor status. Project-side state machine logic, not Manual ESKF math |
| AC-NEW-7 (cache-poisoning safety budget P(geo-misalign >30 m) <1%, P(>100 m) <0.1%) | **Pass — STRUCTURAL geometric-verification at C5 layer via Mahalanobis outlier gate + NATIVE 6×6 covariance honesty** | Manual ESKF Mahalanobis outlier gate provides structural defense against cache-poisoned satellite-anchor measurements (any forced satellite-tile feature that produces an outlier-pose measurement will be rejected before §6.1 update); combined with C4's RANSAC + C3's per-correspondence confidence threshold, provides **three-layer structural defense against cache poisoning** at the simple-baseline reference floor. Honest covariance per §6.1 NATIVE 6×6 ensures cache-poisoned tiles cannot under-report uncertainty downstream |
| AC-NEW-8 (visual blackout + GPS spoofing degraded mode: ≤30 s IMU-only after last trusted anchor; dead_reckoned label; degrade fix-quality at covariance >100 m; escalate at >500 m or >30 s; 10 s GPS-health gate before re-promotion) | **Pass (mechanical via project-side state machine + §5.4 IMU-only predict + monotonically-growing covariance) — NATIVE Solà §5+§6 design + project state machine** | **CRITICAL POSITIVE finding for Manual ESKF**: §5.4 IMU-only predict-step propagation `x_t = f(x_{t-1}, u_m, dt)` + `P^+ = F · P · F.T + Q_i` provides exactly the AC-NEW-8 IMU-only-after-last-trusted-anchor design with monotonically-growing covariance; project-side state machine handles the source-label transitions (`satellite_anchored → visual_propagated → dead_reckoned`), the covariance-threshold escalation logic (degrade at >100 m, escalate at >500 m or >30 s), and the 10 s GPS-health re-promotion gate. **NATIVE design fit for AC-NEW-8** |
| Restriction "Operational area: eastern/southern Ukraine" | **N/A — algorithm-level (Manual ESKF has no geographic sensitivity)** | Geographic concern applies at C2 (VPR retrain on aerial-domain Ukraine geography) + C6 (tile cache geographic coverage) layers; Manual ESKF is geographically agnostic |
| Restriction "Altitude ≤1 km AGL; terrain assumed flat" | **STRUCTURAL ALIGNMENT — flat-earth assumption pairs naturally with §5+§6 ESKF + project's NED reference frame convention** | Flat-earth assumption per restriction directly aligns with project's NED reference frame convention for ESKF + Manual ESKF nominal-state position `p` in WGS84 with NED tangent-frame conversion. **NATIVE design fit for flat-terrain restriction** |
| Restriction "Weather: predominantly sunny, seasonal/visibility classes" | **N/A — algorithm-level (Manual ESKF has no weather sensitivity)** | Weather sensitivity applies at C2/C3 (matcher cross-season generalization); Manual ESKF is weather-agnostic |
| Restriction "Navigation camera (pinned): ADTi 20MP, 5472×3648" | **N/A — algorithm-level** | Camera resolution applies at C1/C2/C3/C4 layers; Manual ESKF consumes C4 PnP output regardless of source resolution |
| Restriction "Satellite Imagery — resolution ≥0.5 m/px" | **N/A — algorithm-level** | Same as AC-8.1 |
| Restriction "Satellite Imagery — Cache budget: 10 GB" — C5 cache footprint | **Pass — TRIVIAL footprint** | Manual ESKF C5 has 2.6 KB state + covariance footprint, NO cache footprint (cache budget applies at C6 layer); state can be persisted to FDR per AC-NEW-3 at negligible cost |
| Restriction "Companion computer: Jetson Orin Nano Super, 8 GB shared" | **Pass with COMFORTABLE MARGIN — extrapolated 5-15 ms per update + 2.6 KB memory footprint** | **CRITICAL POSITIVE finding for Manual ESKF**: classical algorithm with no GPU dependency; Source #88 + #89 confirm NumPy/SciPy + Eigen3 ship canonical Python + C++ scientific computing distributions on JetPack 6 out-of-the-box; CPU-only path is the canonical deployment runtime. Extrapolated ~5-15 ms per update on Jetson Orin Nano Super 6-core ARM Cortex-A78AE = comfortable AC-4.1 satisfaction. **No GPU competition** with C2/C3/C4 (which are GPU-heavy on the Ampere 1024-core fp16 path) — C5 runs entirely on CPU, freeing GPU for C2/C3/C4 inference. **No JetPack 6 cross-compilation engineering required** (vs GTSAM Fact #89 ~1-2 days + OpenGV Fact #53 ~1-2 weeks fork-and-patch) |
| Restriction "License posture (D-C1-1)" — C5-class license-track interaction | **POSITIVE finding (PUBLIC-DOMAIN canonical equations + project's Apache-2.0 implementation license) — eligible on every D-C1-1 license-posture choice** | **POSITIVE on canonical Solà 2017 paper**: Source #88 academic preprint at arXiv with no copyright restrictions on equations themselves; project's manual implementation gets project's chosen license — default Apache-2.0 per project tech-stack rule. **PUBLIC-DOMAIN CANONICAL EQUATIONS + PROJECT'S APACHE-2.0 IMPLEMENTATION** — clean BSD/permissive license track on the C5 mandatory-simple-baseline; under D-C1-1 = (a) GPL-3.0 track, (b) BSD/permissive lock, or (c) keep-both-tracks-open, Manual ESKF is **eligible on every license-posture choice with the simplest license-compliance story** (tied with cvg/LightGlue + DISK + XFeat + OpenCV + GTSAM for cleanest license-compliance story across all C-row components evaluated). **MANDATORY-SIMPLE-BASELINE role per engine Component Option Breadth rule** — Manual ESKF per Solà 2017 is **deployment-ready under every license-posture choice**; the role's purpose is to establish the long-established Kalman-filter state-estimator reference floor against which modern competitive leads (GTSAM iSAM2 / MSCKF / particle filter / no-build) must measurably exceed at deployment-ready license + Jetson-friendly runtime + covariance honesty |

---

### Fact #89 — GTSAM `iSAM2` + `PreintegratedCombinedMeasurements` + `CombinedImuFactor` + `BetweenFactorPose3` + `GenericProjectionFactorCal3DS2` + `PriorFactorPose3` + `Marginals.marginalCovariance` per-mode API capability verification (canonical `borglab/gtsam` library by Frank Dellaert et al. + Georgia Tech Borg Lab — incremental factor-graph SLAM with IMU pre-integration via Forster et al. RSS 2015 + per-correspondence projection factors at each keyframe + native 6×6 posterior covariance recovery via `Marginals` class + sliding-window via `IncrementalFixedLagSmoother` for bounded memory; **MODERN-COMPETITIVE-LEAD-FACTOR-GRAPH** candidate for the C5 row's incremental-smoothing axis; **architecturally couples with C4 Fact #54 via shared GTSAM substrate**; on Jetson Orin Nano Super) — DOCUMENTARY PASS WITH CLEAN-BSD-3-CLAUSE-LICENSE-THROUGHOUT (cross-cite to Fact #54 closure 2026-05-08 — same library, daily-active maintenance) + **NATIVE-6×6-POSE-COVARIANCE-VIA-Marginals** (matches C4 Fact #54 NATIVE AC-NEW-4 satisfaction pathway) + IMU-PREINTEGRATION-VIA-FORSTER-RSS-2015 (CombinedImuFactor handles asynchronous IMU+camera fusion at ~100-200 Hz IMU + 3 Hz camera natively) + INCREMENTAL-SMOOTHING-VIA-iSAM2 (sliding window of K keyframes; `ISAM2.update(new_factors)` amortizes per-frame cost; bounded memory via `IncrementalFixedLagSmoother`) + ARCHITECTURAL-COUPLING-WITH-C4-Fact-#54 (shared GTSAM substrate; if C4 = GTSAM-as-primary AND C5 = iSAM2, shared library substrate reduces cross-component implementation overhead) + ~50-200-MB-LIBRARY-FOOTPRINT (well within AC-4.2 budget but heaviest C5 candidate) + ~50-150-MS-PER-UPDATE-EXTRAPOLATED-TO-JETSON-CPU (comfortable AC-4.1 satisfaction at 3 Hz update rate; 10-30× slower than Manual ESKF Fact #88 but with smoothing + look-back-refinement advantages) + NO-JETPACK-6-CANONICAL-DISTRIBUTION (~1-2 days cross-compilation engineering, same as Fact #54) — opens C5 row at **2 of N candidates** (modern-competitive-lead-factor-graph role)

- **Statement**: GTSAM (`borglab/gtsam` canonical implementation by Georgia Tech Research Corporation Borg Lab + Frank Dellaert et al., `gtsam/navigation/` + `gtsam/nonlinear/` + `gtsam_unstable/nonlinear/` modules, BSD-3-Clause license throughout per C4 Fact #54 Source #86 LICENSE.BSD direct WebFetch verification + bundled deps clean per Fact #54) is the **MODERN-COMPETITIVE-LEAD-FACTOR-GRAPH candidate** for the C5 row's incremental-smoothing axis — the canonical reference factor-graph SLAM library by Frank Dellaert et al. that emits a **direct 6×6 pose covariance NATIVELY** via `Marginals(graph, isam2_result).marginalCovariance(pose_key)` with no custom Jacobian engineering required, plus IMU pre-integration via Forster et al. RSS 2015 `CombinedImuFactor` for asynchronous IMU+camera fusion + sliding-window incremental smoothing via `iSAM2` + `IncrementalFixedLagSmoother`. **Architecturally couples with C4 Fact #54** — if C4 = GTSAM-as-primary AND C5 = iSAM2, shared library substrate reduces cross-component implementation overhead and enables joint optimization of C4 single-frame PnP + C5 multi-frame smoothing in one factor graph. Per the per-Mode API Capability Verification rule, the project's pinned mode is the **(`gtsam.NonlinearFactorGraph()` + `gtsam.PreintegrationCombinedParams.MakeSharedU(9.81)` (project NED frame upward-z gravity convention) with `params.setAccelerometerCovariance(np.eye(3) * accel_noise_sigma**2)` + `params.setGyroscopeCovariance(np.eye(3) * gyro_noise_sigma**2)` + `params.setIntegrationCovariance(np.eye(3) * 1e-8)` + `params.setBiasAccCovariance(np.eye(3) * bias_acc_rw_sigma**2)` + `params.setBiasOmegaCovariance(np.eye(3) * bias_gyro_rw_sigma**2)` + `params.setBiasAccOmegaInit(initial_bias_cov)` IMU noise + bias random-walk + initial-bias-uncertainty model + `gtsam.PreintegratedCombinedMeasurements(params, bias_hat)` per-keyframe-pair PIM + `pim.integrateMeasurement(acc_meas, gyro_meas, dt)` for each IMU sample between keyframes + `gtsam.CombinedImuFactor(X(i), V(i), X(j), V(j), B(i), B(j), pim)` 6-key per-keyframe-pair IMU factor with bias evolution + `gtsam.BetweenFactorPose3(X(i), X(j), relative_pose, odometry_noise)` between-keyframe odometry factor from C1 VIO + `gtsam.GenericProjectionFactorCal3DS2(measured_pt2, pixel_noise, X(i), L(k), Cal3DS2_calibration)` per-correspondence projection factor for each C3 inlier match at each keyframe (or `gtsam.PriorFactorPose3(X(i), satellite_anchor_pose, anchor_noise)` 6-DoF satellite-anchor prior for AC-NEW-4 covariance carry-over from C4 Fact #54 GTSAM Marginals) + `gtsam.PriorFactorPose3(X(0), initial_state, initial_noise)` boot-time initial-state prior from FC GPS-extrapolated pose per AC-NEW-1 + `gtsam.ISAM2(ISAM2Params)` incremental smoothing solver with `params.setRelinearizeThreshold(0.01)` + `params.setRelinearizeSkip(1)` + `params.setEvaluateNonlinearError(False)` canonical default tuning + `isam2.update(new_factors, new_initial_estimate)` per-keyframe incremental update + `result = isam2.calculateEstimate()` current best estimate + `marginals = gtsam.Marginals(graph, result); pose_covariance = marginals.marginalCovariance(X(current_keyframe))` 6×6 posterior covariance recovery + `gtsam_unstable.IncrementalFixedLagSmoother(K_keyframes_window, isam2_params)` sliding-window for bounded memory + `gtsam.noiseModel.Robust.Create(gtsam.noiseModel.mEstimator.Huber.Create(1.345), gaussian_noise)` Huber M-estimator robust noise model for outlier rejection without explicit Mahalanobis gate (alternate to classical Kalman-filter outlier gate) + `gtsam.GncOptimizer` Graduated Non-Convexity globally-convergent alternative for outlier rejection + BSD-3-Clause license throughout)** → 6-DoF camera pose (R, t) in WGS84 from `result.atPose3(X(current_keyframe))` + 3D velocity from `result.atVector3(V(current_keyframe))` + 6×6 posterior covariance NATIVELY from `marginals.marginalCovariance(X(current_keyframe))` + project-side source label state machine logic (NOT in canonical GTSAM library — project-specific extension for AC-1.4 + AC-NEW-2 + AC-NEW-8) + `last_satellite_anchor_age_ms` project-side counter.

  **Mode-enumeration query (1/3) — context7 INDEXED PASS at `/borglab/gtsam` version 4.3a1 with 1121 code snippets** (best context7 indexing of any C5 candidate evaluated — same as C4 Fact #54 cross-cite); per Per-Mode API Capability Verification rule item 1, context7 query-docs at `/borglab/gtsam` returned canonical Python notebooks documenting:
  - `gtsam/navigation/doc/ImuFactor.ipynb` — basic `ImuFactor(X(0), V(0), X(1), V(1), B(0), pim)` 5-key factor with **CONSTANT bias between keyframes assumption** (suitable for short keyframe gaps; project default keyframe gap = 333 ms at 3 Hz visual cadence × ~30-60 IMU samples per keyframe = OK for project)
  - `gtsam/navigation/doc/CombinedImuFactor.ipynb` — modern `CombinedImuFactor(X(0), V(0), X(1), V(1), B(0), B(1), pim)` 6-key factor with **bias evolution per random walk between keyframes** (more accurate for project's 8-hour duty cycle where IMU bias drifts; canonical Forster et al. RSS 2015 IMU pre-integration paradigm; **project default = CombinedImuFactor for AC-NEW-3 8-hour FDR + bias drift estimation**)
  - `gtsam/navigation/doc/PreintegratedImuMeasurements.ipynb` — full PIM workflow: `pim.integrateMeasurement(acc, gyro, dt)` × N → `pim.deltaTij()` / `pim.deltaRij().matrix()` / `pim.deltaPij()` / `pim.deltaVij()` / `pim.biasHat()` / `pim.preintMeasCov()` 9×9 covariance + `pim.predict(initial_state, current_best_bias)` for IMU-only state extrapolation between keyframes (used for cold-start TTFF per AC-NEW-1 + dead-reckoning during visual blackout per AC-NEW-8)
  - `gtsam/navigation/doc/GPSFactor.ipynb` — `GPSFactor(pose_key, gps_measurement_enu, gps_noise_model)` for 3-DoF GPS prior from FC GPS + `GPSFactorArmCalib(pose_key, lever_arm_key, gps_measurement_enu, gps_noise_model)` for GPS with unknown lever-arm calibration (project: lever arm is FC-IMU-to-nav-camera offset, fixed at design time, so simpler `GPSFactor` suffices)
  - `gtsam/inference/doc/ISAM.ipynb` — `GaussianISAM(initial_bayes_tree)` + `isam.update(new_factors)` core incremental update API (legacy linear; modern nonlinear `ISAM2` follows same API pattern)
  - `python/gtsam/examples/PlanarSLAMExample.ipynb` + `Pose2SLAMExample.ipynb` — `Marginals(graph, result).marginalCovariance(key)` posterior covariance recovery (works with both batch optimizer results and `ISAM2.calculateEstimate()` results)
  - `gtsam/slam/doc/InitializePose3.ipynb` — `InitializePose3.initialize(graph)` chordal-relaxation 3D pose-graph initialization (modern alternative for cold-start; complements `lago.initialize(graph)` for pose-2 initialization)

  **`IncrementalFixedLagSmoother` documentation note**: context7 query-docs at /borglab/gtsam returned ISAM examples (legacy GaussianISAM + canonical ISAM2 patterns) but did NOT return a top-3 `IncrementalFixedLagSmoother` snippet on the queried search. The IncrementalFixedLagSmoother class is documented in the canonical GTSAM source tree at `gtsam_unstable/nonlinear/IncrementalFixedLagSmoother.h` (in the `gtsam_unstable` namespace, requiring user to opt-in to unstable APIs). Project must verify at Plan-phase Jetson MVE that IncrementalFixedLagSmoother is the correct sliding-window primitive vs writing custom marginalization on top of `ISAM2.marginalizeLeaves(keys_to_marginalize)`. **D-C5-3 NEW Plan-phase decision raised**: choose between (a) `gtsam_unstable.IncrementalFixedLagSmoother` (canonical fixed-lag smoother with bounded memory; requires opt-in to gtsam_unstable namespace; ~30 minutes engineering), (b) custom marginalization via `ISAM2.marginalizeLeaves(keys_to_marginalize)` (more flexible; ~2-3 days engineering), (c) accept unbounded ISAM2 graph growth (simplest; risk = memory growth over 8-hour flight if not periodically restarted; ~0 minutes engineering but tested at Jetson MVE phase).

  **Pinned-mode runnable example query (2/3) — context7 query-docs PASS**: complete runnable Python example combining `PreintegrationCombinedParams.MakeSharedU(9.81)` + `PreintegratedCombinedMeasurements(params, bias_hat)` + `pim.integrateMeasurement(acc, gyro, dt)` × N + `CombinedImuFactor(X(i), V(i), X(j), V(j), B(i), B(j), pim)` + `BetweenFactorPose3(X(i), X(j), relative_pose, odometry_noise)` + `PriorFactorPose3(X(0), initial_state, initial_noise)` + `ISAM2(params)` + `isam2.update(new_factors, new_initial_estimate)` + `Marginals(graph, isam2.calculateEstimate()).marginalCovariance(X(current))` documented across the Source #87 + Source #90 + Source #91 cross-citations; cross-validated against canonical Doxygen portal `borglab.github.io/gtsam/`.

  **Disqualifier-probe query (3/3) — FOUR FINDINGS (1 negative-but-mitigable structural + 3 caveats)**:
  (i) **CRITICAL contract finding — `CombinedImuFactor` requires CONTIGUOUS IMU SAMPLES between keyframes** — Source #90 `CombinedImuFactor.ipynb` documents the canonical pattern of `pim.integrateMeasurement(acc, gyro, dt)` for each IMU sample arriving between two consecutive keyframes; if IMU samples are dropped mid-flight (network jitter, MAVLink frame loss), the `pim.preintMeasCov()` 9×9 covariance becomes optimistic vs reality. **Mitigation**: project's pinned MAVLink IMU pipeline at ~100-200 Hz Pixhawk-class is delivered over UART or USB serial — dropped samples are rare; project should track `last_imu_timestamp` and inflate `params.setIntegrationCovariance` adaptively if gap > expected; alternative is to detect IMU-sample gaps and restart the PIM accumulator at the next keyframe with conservative initial covariance. **D-C5-4 NEW Plan-phase decision raised**: choose between (a) accept canonical pattern + monitor + adaptive integration covariance inflation, (b) restart PIM on detected gaps with conservative initial covariance, (c) buffer IMU samples in a queue with explicit gap-fill via interpolation (most aggressive, highest engineering ~1 week).

  (ii) **CRITICAL latency margin finding — iSAM2 incremental smoothing per-update cost is ~50-150 ms extrapolated to Jetson Orin Nano Super CPU** at typical project graph size (sliding window of K=20 keyframes covering ~6.7 s at 3 Hz × ~100 ImuFactor + ~5 GPSFactor + ~0-50 BetweenFactor + ~0-1000 GenericProjectionFactor per keyframe via D-C5-5 NEW factor-density choice) — **comfortable AC-4.1 satisfaction at 3 Hz update rate** (1/3 s = 333 ms budget for one full ESKF/iSAM2 cycle including measurement, predict, correct, output emission) but **10-30× slower than Manual ESKF Fact #88's ~5-15 ms per update** extrapolation. **Mitigation strategies**: reduce K (sliding window size) from 20 to 5-10 keyframes (couples with D-C5-3 IncrementalFixedLagSmoother choice); reduce GenericProjectionFactor density from per-correspondence to smart-projection-pose-factor (which marginalizes out landmarks at construction time); use full-Cholesky `params.setFactorization("CHOLESKY")` instead of QR for faster linear-algebra (project default per canonical ISAM2Params). **D-C5-5 NEW Plan-phase factor-density-choice gate raised**: choose between (a) per-correspondence GenericProjectionFactorCal3DS2 (highest fidelity; 1000+ factors per keyframe at K=10 image pairs × 100 inliers per pair); (b) smart-projection-pose-factor (canonical landmark-marginalization-at-construction-time; 1 factor per landmark per keyframe; ~10× speedup at minimal accuracy loss); (c) PriorFactorPose3 only with C4 GTSAM Marginals satellite-anchor 6×6 covariance (couples with C4 Fact #54 D-C4-2 = (b); cleanest cross-component coupling).

  (iii) **Memory + binary-size CAVEAT — GTSAM library footprint is ~50-200 MB at runtime depending on factor-graph size** (cross-cite to Fact #54 — same library); on Jetson Orin Nano Super 8 GB shared memory budget, GTSAM is the **heaviest C5 candidate** (vs Manual ESKF Fact #88's 2.6 KB) but still well within AC-4.2 budget when co-resident with C1/C2/C3/C4/C6 — extrapolated co-resident memory pressure ~1-3% of AC-4.2 budget at typical project graph size; iSAM2 incremental update + IncrementalFixedLagSmoother sliding window via D-C5-3 keep memory footprint bounded if extending to long flights.

  (iv) **No JetPack 6 canonical distribution — GTSAM requires custom build on JetPack 6 ARM Cortex-A78AE** (cross-cite to Fact #54; same library); ~1-2 days engineering for cross-compilation + Eigen3 + Boost dependency setup + Ceres-jet auto-diff cross-compilation; not blocking but adds setup cost vs Manual ESKF Fact #88's pure-Python/NumPy or pure-C++/Eigen3 zero-cross-compilation deployment.

  **Pinned-mode sentence**: "We will catalog **GTSAM `iSAM2` + `PreintegratedCombinedMeasurements` + `CombinedImuFactor` (Forster et al. RSS 2015 IMU pre-integration) + `BetweenFactorPose3` (between-keyframe odometry from C1 VIO) + `GenericProjectionFactorCal3DS2` (per-correspondence projection factors from C3 matches at each keyframe — D-C5-5 NEW factor-density-choice gate) + `PriorFactorPose3` (initial state prior from FC GPS-extrapolated pose at boot per AC-NEW-1 + 6-DoF satellite-anchor priors with C4 Fact #54 GTSAM Marginals 6×6 covariance) + `Marginals(graph, isam2.calculateEstimate()).marginalCovariance(X(current_keyframe))` 6×6 posterior covariance recovery + canonical default `LevenbergMarquardtParams(maxIterations=100, relativeErrorTol=1e-5, absoluteErrorTol=1e-5)` LM optimization params + `noiseModel.Diagonal.Sigmas` for IMU + `noiseModel.Robust.Create(mEstimator.Huber.Create(1.345), gaussian_noise)` Huber M-estimator robust noise model for outlier rejection + `gtsam_unstable.IncrementalFixedLagSmoother` sliding-window for bounded memory (D-C5-3 NEW gate) + BSD-3-Clause license throughout** as the **MODERN-COMPETITIVE-LEAD-FACTOR-GRAPH candidate** for the C5 row's incremental-smoothing axis per engine Component Option Breadth rule. Inputs `{C1 VIO output (6-DoF relative pose @ ≥3 Hz with σ_yaw ≤ 5° / σ_pitch ≤ 5° per Fact #24 contract; encoded as BetweenFactorPose3 per-keyframe) + C4 satellite-anchor poses (6-DoF tile-frame absolute pose with NATIVE 6×6 covariance from C4 Fact #54 GTSAM Marginals when D-C4-2 = (b) coupling; encoded as PriorFactorPose3 per-keyframe) + FC IMU (high-rate via MAVLink RAW_IMU/SCALED_IMU2 at ~100-200 Hz typical Pixhawk-class; encoded as CombinedImuFactor per-keyframe-pair via Forster et al. RSS 2015 PreintegratedCombinedMeasurements) + FC barometer/airspeed/attitude (lower-rate via MAVLink VFR_HUD/SCALED_PRESSURE/ATTITUDE; encoded as PriorFactorPose3 with low-confidence noise model OR direct IMU-state biasing) + initial state from FC GPS-extrapolated pose at boot per AC-NEW-1 (encoded as PriorFactorPose3(X(0), initial_state, initial_noise)) + operator re-loc hint via GCS per AC-3.4 (rare; encoded as PriorFactorPose3 with operator-hint uncertainty)}`; expected outputs `{6-DoF camera pose (R, t) in WGS84 from result.atPose3(X(current_keyframe)) + 3D velocity from result.atVector3(V(current_keyframe)) + attitude as quaternion from result.atPose3.rotation().toQuaternion() + 6×6 posterior covariance NATIVELY from marginals.marginalCovariance(X(current_keyframe)) + project-side source label state machine logic + last_satellite_anchor_age_ms project-side counter + per-source residual diagnostic for AC-NEW-3 FDR debug + frame-rate output at min camera rate (3 Hz) with iSAM2 incremental update per keyframe}`; runtime `Jetson Orin Nano Super (8 GB shared, JetPack 6, ROS 2 Humble) — custom build required` (no canonical JetPack 6 distribution; ~1-2 days cross-compilation engineering, same as Fact #54). **MODERN-COMPETITIVE-LEAD-FACTOR-GRAPH role per engine Component Option Breadth rule** — GTSAM's structural distinction from Manual ESKF Fact #88 is **incremental smoothing with look-back refinement + IMU pre-integration via Forster et al. RSS 2015 + native sliding-window via IncrementalFixedLagSmoother + factor-graph paradigm extension from C4 Fact #54** at the cost of (i) ~10-30× per-update latency vs Manual ESKF + (ii) ~50-200 MB library footprint + (iii) ~1-2 days cross-compilation engineering + (iv) D-C5-3/4/5 NEW Plan-phase decisions (sliding-window primitive choice + IMU-gap-handling + factor-density-choice). **Architectural coupling with C4 Fact #54**: if C4 = GTSAM-as-primary AND C5 = iSAM2, shared library substrate reduces cross-component implementation overhead and enables joint optimization of C4 single-frame PnP + C5 multi-frame smoothing in one factor graph — **forward-looking architectural integration advantage** that no other C5 candidate provides."

- **Source**: Source #90 (canonical GTSAM `ImuFactor` / `CombinedImuFactor` / `PreintegratedImuMeasurements` / `PreintegratedCombinedMeasurements` / `GPSFactor` / `GPSFactorArmCalib` documentation via context7 query-docs at `/borglab/gtsam` version 4.3a1 with 1121 code snippets — Forster et al. RSS 2015 IMU pre-integration paradigm + canonical Python notebooks `ImuFactor.ipynb` + `CombinedImuFactor.ipynb` + `PreintegratedImuMeasurements.ipynb` + `GPSFactor.ipynb`); Source #91 (canonical GTSAM `ISAM2` / `IncrementalFixedLagSmoother` / `Marginals` documentation via context7 query-docs at `/borglab/gtsam` version 4.3a1 — incremental smoothing API surface + canonical Python notebooks `ISAM.ipynb` + `PlanarSLAMExample.ipynb` + `Pose2SLAMExample.ipynb` + `InitializePose3.ipynb` + `lago.ipynb` + `FactorGraph.ipynb`); cross-cite to Source #86 + Source #87 (C4 Fact #54 closure 2026-05-08 — same library, BSD-3-Clause throughout, daily-active maintenance, NATIVE 6×6 pose covariance via Marginals); cross-cite to Fact #24 closure from C1 row (σ_yaw ≤ 5° / σ_pitch ≤ 5° hard contract on C1 VIO attitude output that feeds C5 BetweenFactorPose3 measurement noise); cross-cite to Fact #54 closure from C4 row (GTSAM Marginals NATIVE 6×6 covariance recovery that feeds C5 PriorFactorPose3 satellite-anchor noise — couples C4 D-C4-2 = (b) with C5 = iSAM2 architectural integration); cross-cite to SQ6 closures (ArduPilot Plane MAVLink GPS_INPUT + iNav MSP2 MSP2_SENSOR_GPS as C8 output contracts that consume C5's WGS84 pose + 6×6 covariance output per AC-4.3); cross-cite to Fact #88 (Manual ESKF mandatory simple-baseline that GTSAM iSAM2 must measurably exceed on documented-evidence axes per engine Component Option Breadth rule).

- **Phase**: Phase 2

- **Target Audience**: System architects + C5 implementer + Step-7.5 reviewer + license-posture decision-maker (D-C1-1 — clean BSD-3-Clause throughout per Fact #54) + Plan-phase architect (modern-competitive-lead-factor-graph role documentation for engine Component Option Breadth rule compliance + D-C5-3 NEW IncrementalFixedLagSmoother-vs-custom-marginalization-vs-unbounded-graph gate + D-C5-4 NEW IMU-gap-handling-strategy gate + D-C5-5 NEW factor-density-choice gate + architectural-coupling-with-C4-Fact-#54 forward-looking decision)

- **Confidence**: ✅ for mode-enumeration (`PreintegrationCombinedParams.MakeSharedU(9.81)` + `PreintegratedCombinedMeasurements(params, bias_hat)` + `pim.integrateMeasurement(acc, gyro, dt)` + `CombinedImuFactor(X(i), V(i), X(j), V(j), B(i), B(j), pim)` + `BetweenFactorPose3(X(i), X(j), relative_pose, odometry_noise)` + `GenericProjectionFactorCal3DS2(measured_pt2, pixel_noise, X(i), L(k), Cal3DS2_calibration)` + `PriorFactorPose3(X(0), initial_state, initial_noise)` + `ISAM2(ISAM2Params)` + `isam2.update(new_factors, new_initial_estimate)` + `result = isam2.calculateEstimate()` + `Marginals(graph, result).marginalCovariance(X(current))` + `noiseModel.Diagonal.Sigmas` + `noiseModel.Robust.Create(mEstimator.Huber.Create(τ), gaussian_noise)` + `GncOptimizer` documented in canonical Source #90 + Source #91 via context7 query-docs at version 4.3a1); ✅ for runnable-example (canonical Python examples from `CombinedImuFactor.ipynb` + `PreintegratedImuMeasurements.ipynb` + `ImuFactor.ipynb` + `GPSFactor.ipynb` + `ISAM.ipynb` + `PlanarSLAMExample.ipynb` + `Pose2SLAMExample.ipynb` documented via Source #90 + Source #91 with explicit recommended pattern); ✅ for **NATIVE 6×6 POSE COVARIANCE via `Marginals.marginalCovariance` with iSAM2 results** (cross-cite to Fact #54 — same library, same NATIVE AC-NEW-4 satisfaction pathway; works on both batch optimizer results and `ISAM2.calculateEstimate()` results per Source #91); ✅ for **Forster et al. RSS 2015 IMU pre-integration paradigm** (Source #90 explicit documentation of `CombinedImuFactor` 6-key factor with bias evolution per random walk between keyframes); ✅ for **architectural coupling with C4 Fact #54 via shared GTSAM substrate** (Source #86 + Source #87 + Source #90 + Source #91 all reference same `borglab/gtsam` library — daily-active maintenance, last pushed 2026-05-08 = TODAY at access time per Fact #54 Source #86 GitHub API metadata); ✅ for **canonical BSD-3-Clause license throughout** (cross-cite to Fact #54 — same library, Source #86 LICENSE.BSD direct WebFetch verified); ✅ for **incremental smoothing via `iSAM2.update()`** (Source #91 explicit `isam.update(new_factors)` API documentation + canonical examples); ⚠️ for **Jetson Orin Nano Super deployment latency** (no documentary measurement; extrapolation from x86_64 RTX-class CPU canonical GTSAM iSAM2 incremental smoothing on a sliding window of ~20 keyframes with ~100 ImuFactor + ~5 GPSFactor + ~0-50 BetweenFactor + ~0-1000 GenericProjectionFactor per keyframe ~10-50 ms per call CPU-only on Intel i7-class baseline; Jetson Orin Nano Super extrapolation ~50-150 ms per call CPU-only; at 3 Hz visual measurement updates extrapolated 150-450 ms/sec total = **comfortable AC-4.1 satisfaction** at 3 Hz update rate but **10-30× slower than Manual ESKF Fact #88's ~5-15 ms per update**); ⚠️ for **library binary footprint** (~50-200 MB at runtime on Jetson Orin Nano Super depending on bundled-dependency build configuration — same as Fact #54 cross-cite); ⚠️ for **JetPack 6 cross-compilation engineering** (~1-2 days; not blocking but adds setup cost vs Manual ESKF Fact #88's pure-Python/NumPy or pure-C++/Eigen3 zero-cross-compilation); ⚠️ for **`IncrementalFixedLagSmoother` is in `gtsam_unstable` namespace** (D-C5-3 NEW Plan-phase decision required); ⚠️ for **CombinedImuFactor requires CONTIGUOUS IMU samples** (D-C5-4 NEW Plan-phase decision required); ⚠️ for **per-update latency depends on factor-density** (D-C5-5 NEW Plan-phase decision required); ❌ for **canonical-checkpoint aerial-domain fitness** — N/A for GTSAM iSAM2 since it is a classical factor-graph library, not a learned method (no canonical-weights aerial-domain caveat applies)

- **Related Dimension**: SQ3+SQ4 / C5 modern-competitive-lead-factor-graph role (engine Component Option Breadth rule role — directly addresses AC-NEW-4 covariance-honesty contract via shared-substrate coupling with C4 Fact #54; analogous structural role to GTSAM `Marginals` in C4 row Fact #54 but for C5 multi-frame smoothing) — per-mode API capability verification gate

- **Fit Impact**: **DOCUMENTARY PASS for the per-mode API capability verification gate at the modern-competitive-lead-factor-graph role** — `iSAM2` + `CombinedImuFactor` + `BetweenFactorPose3` + `GenericProjectionFactorCal3DS2` + `PriorFactorPose3` + `Marginals.marginalCovariance` has documented runnable per-mode examples with the project's pinned configuration (canonical GTSAM Python examples + canonical Doxygen portal + 1121 context7 code snippets at version 4.3a1 + Forster et al. RSS 2015 IMU pre-integration paradigm). **THREE CONVERGING POSITIVE structural advantages**: (i) **NATIVE 6×6 POSE COVARIANCE via `Marginals.marginalCovariance` with iSAM2 results** — same NATIVE AC-NEW-4 satisfaction pathway as C4 Fact #54 (Marginals works on both batch optimizer results and `ISAM2.calculateEstimate()` results per Source #91); **directly addresses the AC-NEW-4-binding-constraint axis** via shared-substrate coupling with C4 Fact #54; (ii) **Forster et al. RSS 2015 IMU pre-integration paradigm** — `CombinedImuFactor` handles asynchronous IMU+camera fusion at ~100-200 Hz IMU + 3 Hz camera natively + bias evolution per random walk between keyframes for project's 8-hour duty cycle; **canonical reference for modern factor-graph IMU integration** that classical EKF/ESKF (including Manual ESKF Fact #88) cannot match in algorithmic accuracy at high IMU rates; (iii) **architectural coupling with C4 Fact #54 via shared GTSAM substrate** — if C4 = GTSAM-as-primary AND C5 = iSAM2, shared library substrate reduces cross-component implementation overhead AND enables joint optimization of C4 single-frame PnP + C5 multi-frame smoothing in one factor graph (canonical GTSAM pattern documented in Source #87 `CameraResectioning.ipynb` extended via Source #90/#91 to multi-frame). **ONE ADDITIONAL POSITIVE structural advantage**: (iv) **NATIVE LOOK-BACK REFINEMENT VIA INCREMENTAL SMOOTHING** — iSAM2 incrementally updates the entire sliding-window posterior on every new measurement, naturally supporting AC-4.5 "system may refine prior estimates and emit corrections" in a way that recursive Manual ESKF Fact #88 cannot natively support. **ONE NEGATIVE-BUT-MITIGABLE structural finding**: (v) **TIGHT AC-4.1 LATENCY MARGIN** — Jetson Orin Nano Super extrapolated ~50-150 ms per update CPU-only at K=20 keyframes × ~100 IMU + ~5 GPS + ~0-50 Between + ~0-1000 GenericProjection factors per keyframe = comfortable AC-4.1 satisfaction at 3 Hz update rate but 10-30× slower than Manual ESKF Fact #88; mitigation strategies include reduce K from 20 to 5-10 keyframes (D-C5-3) OR smart-projection-pose-factor (D-C5-5(b)) OR PriorFactorPose3-only with C4 GTSAM Marginals satellite-anchor 6×6 covariance (D-C5-5(c) — cleanest cross-component coupling). **THREE CAVEATS**: (vi) **~50-200 MB LIBRARY FOOTPRINT** — heaviest C5 candidate but well within AC-4.2 8 GB shared memory budget at typical project graph size (~1-3% co-resident memory pressure); (vii) **NO JetPack 6 CANONICAL DISTRIBUTION** — requires custom cross-compilation (~1-2 days engineering, same as Fact #54); (viii) **`IncrementalFixedLagSmoother` is in `gtsam_unstable` namespace** — D-C5-3 NEW Plan-phase decision required (project default = (a) IncrementalFixedLagSmoother with opt-in to gtsam_unstable namespace per ~30 minutes engineering cost). **NEW Plan-phase decisions raised by GTSAM iSAM2 closure**: **D-C5-3 NEW sliding-window-primitive-choice** — Plan-phase decision between (a) `gtsam_unstable.IncrementalFixedLagSmoother` (canonical fixed-lag smoother with bounded memory; requires opt-in to gtsam_unstable namespace; ~30 minutes engineering — RECOMMENDED), (b) custom marginalization via `ISAM2.marginalizeLeaves(keys_to_marginalize)` (more flexible; ~2-3 days engineering), (c) accept unbounded ISAM2 graph growth (simplest; risk = memory growth over 8-hour flight if not periodically restarted; ~0 minutes engineering but tested at Jetson MVE phase). **D-C5-4 NEW IMU-gap-handling-strategy** — Plan-phase decision between (a) accept canonical pattern + monitor + adaptive integration covariance inflation (RECOMMENDED), (b) restart PIM on detected gaps with conservative initial covariance, (c) buffer IMU samples in a queue with explicit gap-fill via interpolation (most aggressive, ~1 week engineering). **D-C5-5 NEW factor-density-choice** — Plan-phase decision between (a) per-correspondence GenericProjectionFactorCal3DS2 (highest fidelity; 1000+ factors per keyframe at K=10 image pairs × 100 inliers per pair); (b) smart-projection-pose-factor (canonical landmark-marginalization-at-construction-time; 1 factor per landmark per keyframe; ~10× speedup at minimal accuracy loss); (c) PriorFactorPose3 only with C4 GTSAM Marginals satellite-anchor 6×6 covariance — couples C4 D-C4-2 = (b) with C5 = iSAM2 architectural integration; **RECOMMENDED for the GTSAM-as-primary-substrate hybrid path**. **D-C4-2 IDENTICAL CARRY-FORWARD via C4-C5 shared-substrate coupling** — if C5 = GTSAM iSAM2 is Selected, C4 = GTSAM-as-primary becomes architecturally cleaner than C4 = OpenCV-as-primary + GTSAM-as-covariance-recovery hybrid (D-C4-2 = (b) coupling); both Fact #52 + Fact #54 + Fact #89 closures jointly point to **GTSAM-as-shared-C4+C5-substrate as the architecturally cleanest pathway** for the AC-NEW-4-binding-constraint axis. **C5 mandatory pre-screen status**: GTSAM iSAM2 closes the C5 modern-competitive-lead-factor-graph role at **2 of N candidates**. License: **BSD-3-Clause** for canonical `borglab/gtsam` repo (cross-cite to Fact #54 Source #86 LICENSE.BSD direct WebFetch verified) — clean BSD/permissive license track on the C5 modern-competitive-lead-factor-graph axis; under D-C1-1 = (a) GPL-3.0 track, (b) BSD/permissive lock, or (c) keep-both-tracks-open, GTSAM iSAM2 is **eligible on every license-posture choice with the simplest license-compliance story** tied with cvg/LightGlue + DISK + XFeat + OpenCV + Manual ESKF Fact #88. **Position vs Manual ESKF (Fact #88 mandatory simple-baseline)**: GTSAM iSAM2 provides incremental smoothing + look-back refinement + Forster RSS 2015 IMU pre-integration + architectural coupling with C4 Fact #54 at the cost of (i) ~10-30× per-update latency (50-150 ms vs 5-15 ms) + (ii) ~50-200 MB library footprint (vs 2.6 KB) + (iii) ~1-2 days cross-compilation engineering (vs 0 cross-compilation) + (iv) D-C5-3/4/5 NEW Plan-phase decisions (vs 1 D-C5-2 NEW for Manual ESKF) — net structural trade-off **STRONGLY FAVORS GTSAM iSAM2 for the AC-4.5-look-back-refinement axis + AC-NEW-4 covariance-honest axis via C4-C5 shared-substrate coupling** but FAVORS Manual ESKF for the AC-4.1-latency-headroom axis + AC-4.2-memory-headroom axis + JetPack-6-zero-cross-compilation axis. **Recommended C5 architecture for the project**: **GTSAM iSAM2 as primary-substrate for AC-NEW-4 covariance-honest factor-graph state estimation + IncrementalFixedLagSmoother bounded sliding-window per D-C5-3 = (a) + adaptive PIM integration covariance inflation per D-C5-4 = (a) + PriorFactorPose3 only with C4 GTSAM Marginals satellite-anchor 6×6 covariance per D-C5-5 = (c) — couples C4 Fact #54 D-C4-2 = (b) with C5 Fact #89 architectural integration via shared GTSAM substrate** (canonical Plan-phase pathway for the GTSAM-as-shared-C4+C5-substrate hybrid path). **Manual ESKF Fact #88 as the mandatory-simple-baseline reference floor + Jetson MVE benchmark target** for AC-4.1-latency-headroom + AC-4.2-memory-headroom regression validation. Final ranking deferred to Jetson MVE phase per the project's D-C1-2 deferred-MVE strategy.

---

## C5 — Per-Mode API Capability Verification (engine Step 2 — GTSAM iSAM2 modern-competitive-lead-factor-graph session entry, 2026-05-08)

### MVE — GTSAM `iSAM2` + `PreintegratedCombinedMeasurements` + `CombinedImuFactor` + `BetweenFactorPose3` + `GenericProjectionFactorCal3DS2` + `PriorFactorPose3` + `Marginals.marginalCovariance` with canonical default `LevenbergMarquardtParams(maxIterations=100, relativeErrorTol=1e-5, absoluteErrorTol=1e-5)` LM optimization params + `noiseModel.Diagonal.Sigmas` for IMU + `noiseModel.Robust.Create(mEstimator.Huber.Create(1.345), gaussian_noise)` Huber M-estimator robust noise model for outlier rejection + `gtsam_unstable.IncrementalFixedLagSmoother` sliding-window for bounded memory (D-C5-3 NEW gate) + BSD-3-Clause license throughout

- **Source**: Source #90 (canonical GTSAM `ImuFactor` / `CombinedImuFactor` / `PreintegratedImuMeasurements` / `GPSFactor` documentation via context7 query-docs at `/borglab/gtsam` version 4.3a1 — Forster et al. RSS 2015 IMU pre-integration paradigm + canonical Python notebooks); Source #91 (canonical GTSAM `ISAM2` / `IncrementalFixedLagSmoother` / `Marginals` documentation via context7 query-docs at `/borglab/gtsam` version 4.3a1 — incremental smoothing API surface + canonical Python notebooks); cross-cite to Source #86 + Source #87 from C4 Fact #54 (canonical `borglab/gtsam` GitHub repo + LICENSE.BSD direct WebFetch — BSD-3-Clause throughout, daily-active maintenance, NATIVE 6×6 pose covariance via `Marginals.marginalCovariance`)
- **Inputs in the example**: Per Source #90 canonical `CombinedImuFactor.ipynb` + `PreintegratedImuMeasurements.ipynb` examples = `params = PreintegrationCombinedParams.MakeSharedU(9.81)` IMU noise + bias random-walk + initial-bias-uncertainty model + `pim = PreintegratedCombinedMeasurements(params, bias_hat)` per-keyframe-pair PIM accumulator + `pim.integrateMeasurement(acc_meas, gyro_meas, dt)` × N_imu_samples_between_keyframes IMU sample integration loop + `CombinedImuFactor(X(i), V(i), X(j), V(j), B(i), B(j), pim)` 6-key factor + `BetweenFactorPose3(X(i), X(j), relative_pose, odometry_noise)` between-keyframe odometry from C1 VIO + `GenericProjectionFactorCal3DS2(measured_pt2, pixel_noise, X(i), L(k), Cal3DS2_calibration)` per-correspondence projection factor for each C3 inlier match (D-C5-5 factor-density choice) + `PriorFactorPose3(X(0), initial_state, initial_noise)` boot-time initial-state prior + `PriorFactorPose3(X(satellite_anchor_keyframe), satellite_anchor_pose, satellite_anchor_6x6_covariance_from_C4_Fact_54)` 6-DoF satellite-anchor prior + canonical `ISAM2(ISAM2Params(relinearizeThreshold=0.01, relinearizeSkip=1, factorization='CHOLESKY'))` constructor + `isam2.update(new_factors, new_initial_estimate)` per-keyframe incremental update
- **Outputs in the example**: 6-DoF camera pose `result.atPose3(X(current_keyframe))` + 3D velocity `result.atVector3(V(current_keyframe))` + 6-DoF IMU bias `result.atConstantBias(B(current_keyframe))` + 6×6 posterior covariance NATIVELY `marginals.marginalCovariance(X(current_keyframe))` + per-keyframe iSAM2 incremental update yielding new result on every `isam2.calculateEstimate()` call
- **Project inputs**: Per project's pinned mode = `{C1 VIO output (6-DoF relative pose @ ≥3 Hz with σ_yaw ≤ 5° / σ_pitch ≤ 5° per Fact #24 contract; encoded as BetweenFactorPose3 per-keyframe with noise model = noiseModel.Diagonal.Sigmas([σ_pos_x, σ_pos_y, σ_pos_z, σ_θ_roll, σ_θ_pitch, σ_θ_yaw])) + C4 satellite-anchor poses (6-DoF tile-frame absolute pose with NATIVE 6×6 covariance from C4 Fact #54 GTSAM Marginals when D-C4-2 = (b) coupling; encoded as PriorFactorPose3 per-keyframe with noise model = noiseModel.Gaussian.Covariance(satellite_anchor_6x6_covariance)) + FC IMU (high-rate via MAVLink RAW_IMU/SCALED_IMU2 at ~100-200 Hz typical Pixhawk-class; encoded as CombinedImuFactor per-keyframe-pair via Forster et al. RSS 2015 PreintegratedCombinedMeasurements with project-defined accel + gyro + bias-rw + integration noise covariances tuned to Pixhawk-class IMU spec) + initial state from FC GPS-extrapolated pose at boot per AC-NEW-1 (encoded as PriorFactorPose3(X(0), initial_state, initial_noise) with initial_noise = noiseModel.Diagonal.Sigmas([σ_gps_x, σ_gps_y, σ_gps_z, σ_θ_roll_init, σ_θ_pitch_init, σ_θ_yaw_init]))}`
- **Project outputs required**: `{6-DoF camera pose (R, t) in WGS84 from result.atPose3(X(current_keyframe)) + 3D velocity from result.atVector3(V(current_keyframe)) + attitude as quaternion from result.atPose3.rotation().toQuaternion() + 6×6 posterior covariance NATIVELY from marginals.marginalCovariance(X(current_keyframe)) + project-side source label state machine logic (NOT in canonical GTSAM library — project-specific extension for AC-1.4 + AC-NEW-2 + AC-NEW-8) + last_satellite_anchor_age_ms project-side counter + per-source residual diagnostic for AC-NEW-3 FDR debug + frame-rate output at min camera rate (3 Hz) with iSAM2 incremental update per keyframe}` per AC-NEW-3 (FDR), AC-NEW-4 (covariance honesty), AC-NEW-8 (blackout failsafe), AC-3.x (resilience), AC-1.x (accuracy), AC-4.5 (refinement of prior estimates). **Latency budget extrapolation to Jetson Orin Nano Super**: GTSAM iSAM2 incremental smoothing on a sliding window of K=20 keyframes covering ~6.7 s at 3 Hz × ~100 ImuFactor + ~5 GPSFactor + ~0-50 BetweenFactor + ~0-1000 GenericProjectionFactor per keyframe (D-C5-5 factor-density choice) extrapolated ~50-150 ms per call CPU-only on Intel i7-class baseline; Jetson Orin Nano Super extrapolation ~150-450 ms per call CPU-only on 6-core ARM Cortex-A78AE class with ~3× slowdown factor for non-vectorized path. At 3 Hz visual measurement updates extrapolated 150-450 ms/sec total = **comfortable AC-4.1 satisfaction** at 3 Hz update rate (1/3 s = 333 ms budget per cycle including measurement + predict + correct + output emission) but **10-30× slower than Manual ESKF Fact #88's ~5-15 ms per update**. Mitigation strategies include reduce K from 20 to 5-10 keyframes (couples with D-C5-3 IncrementalFixedLagSmoother choice), smart-projection-pose-factor (D-C5-5(b)), PriorFactorPose3-only with C4 GTSAM Marginals satellite-anchor 6×6 covariance (D-C5-5(c) — cleanest cross-component coupling). **Memory budget extrapolation**: ~50-200 MB library binary footprint (cross-cite to Fact #54 — same library); iSAM2 sliding-window state ~10-50 MB at K=20 keyframes; total co-resident memory pressure ~1-3% of AC-4.2 8 GB shared budget — well within AC-4.2 budget but **heaviest C5 candidate** (vs Manual ESKF Fact #88's 2.6 KB).
- **Match assessment**: ✅ exact mode match for **(`iSAM2` + `CombinedImuFactor` + `BetweenFactorPose3` + `PriorFactorPose3` + `Marginals.marginalCovariance` with project's canonical default LevenbergMarquardtParams + Diagonal.Sigmas IMU noise + Robust.Create Huber M-estimator + gtsam_unstable.IncrementalFixedLagSmoother sliding window + BSD-3-Clause license throughout)**; ✅ runnable example (canonical Python examples from Source #90 + Source #91 with explicit recommended pattern); ✅ NATIVE 6×6 pose covariance via `Marginals.marginalCovariance` with iSAM2 results (cross-cite to Fact #54 — same NATIVE AC-NEW-4 satisfaction pathway); ✅ Forster et al. RSS 2015 IMU pre-integration paradigm via `CombinedImuFactor` 6-key factor with bias evolution per random walk; ✅ architectural coupling with C4 Fact #54 via shared GTSAM substrate; ✅ canonical BSD-3-Clause license throughout; ⚠️ **`IncrementalFixedLagSmoother` is in `gtsam_unstable` namespace** (D-C5-3 NEW gate); ⚠️ **CombinedImuFactor requires CONTIGUOUS IMU samples** (D-C5-4 NEW gate); ⚠️ **per-update latency depends on factor-density** (D-C5-5 NEW gate); ⚠️ **~50-200 MB library footprint** (heaviest C5 candidate but well within AC-4.2); ⚠️ **NO JetPack 6 canonical distribution** (~1-2 days cross-compilation engineering, same as Fact #54)
- **If ⚠️ or ❌**: docs do not disqualify the algorithmic mode at the API level, and **NO HARD DISQUALIFIERS apply** at the deployment level. The (factor-graph, IMU pre-integration, between-keyframe-odometry, satellite-anchor-prior, incremental-smoothing, posterior-covariance, robust-noise, sliding-window, license) tuple is documented and runnable directly via canonical GTSAM Python examples + 1121 context7 code snippets at version 4.3a1 + Forster et al. RSS 2015 IMU pre-integration paradigm. **THREE CONVERGING POSITIVE structural advantages** (NATIVE 6×6 pose covariance via Marginals + Forster RSS 2015 IMU pre-integration + architectural coupling with C4 Fact #54 via shared GTSAM substrate) make GTSAM iSAM2 **eligible as the C5 modern-competitive-lead-factor-graph candidate** under every D-C1-1 license-posture choice. **ONE ADDITIONAL POSITIVE structural advantage** (NATIVE look-back refinement via incremental smoothing satisfies AC-4.5 NATIVELY) provides project's first NATIVE AC-4.5 satisfaction pathway. **ONE NEGATIVE-BUT-MITIGABLE structural finding** (tight AC-4.1 latency margin ~50-150 ms per update vs Manual ESKF Fact #88's 5-15 ms; mitigation = D-C5-3/D-C5-5 factor-density-reduction strategies) and **THREE CAVEATS** (~50-200 MB library footprint; NO JetPack 6 canonical distribution; IncrementalFixedLagSmoother in gtsam_unstable namespace) are minor structural concerns that do not block the modern-competitive-lead-factor-graph role. → Status: **Modern-competitive-lead-factor-graph (incremental-smoothing-axis lead) with THREE CONVERGING POSITIVE STRUCTURAL ADVANTAGES (NATIVE 6×6 pose covariance via Marginals + Forster RSS 2015 IMU pre-integration + architectural coupling with C4 Fact #54) + ONE ADDITIONAL POSITIVE STRUCTURAL ADVANTAGE (NATIVE look-back refinement via incremental smoothing for AC-4.5) + ONE NEGATIVE-BUT-MITIGABLE STRUCTURAL FINDING (tight AC-4.1 latency margin; D-C5-3/D-C5-5 mitigation strategies) + THREE CAVEATS (~50-200 MB library footprint; NO JetPack 6 canonical distribution; IncrementalFixedLagSmoother in gtsam_unstable namespace)**, BSD-3-Clause license throughout. **Final ranking deferred to Jetson MVE phase** per the project's D-C1-2 deferred-MVE strategy. Per the engine Component Option Breadth rule, GTSAM iSAM2 closes the C5 modern-competitive-lead-factor-graph role at **2 of N candidates**.

---

## C5 — Per-numbered-Restriction × Per-numbered-AC Sub-Matrix per Candidate (GTSAM iSAM2 modern-competitive-lead-factor-graph addition)

### GTSAM `iSAM2` + `CombinedImuFactor` + `BetweenFactorPose3` + `PriorFactorPose3` + `Marginals.marginalCovariance` — per-numbered binding (C5-relevant lines only; identical-substance bindings to Manual ESKF Fact #88 above are noted with a "same as Manual ESKF" cite to keep the row compact)

| Line | Binding | Evidence (one-line cite) |
|---|---|---|
| AC-1.1 / AC-1.2 (frame-center accuracy) | **Pass (mechanical) → Verify** | Same as Manual ESKF Fact #88 row above; final accuracy bounded by C4 lift + matcher quality + IMU bias estimation + iSAM2 sliding-window smoothing depth (which can OUTPERFORM Manual ESKF on AC-1.1/1.2 tail via look-back refinement of prior estimates per AC-4.5) |
| AC-1.3 (cumulative drift; report `last_satellite_anchor_age_ms`) | **Pass — NATIVE iSAM2 + Forster RSS 2015 IMU pre-integration design** | iSAM2 incremental smoothing over a sliding window of K keyframes provides **strictly better** drift bound than Manual ESKF recursive filter (look-back refinement of prior estimates corrects accumulated drift on every new measurement); `last_satellite_anchor_age_ms` is trivially trackable as a project-side counter on top of iSAM2's keyframe timestamps |
| AC-1.4 (95% covariance ellipse + source label) | **Pass — NATIVE 6×6 covariance via Marginals (cross-cite to Fact #54) + project-side source-label state machine** | Cross-cite to Fact #54 NATIVE 6×6 covariance via `Marginals.marginalCovariance(X(current_keyframe))` — same NATIVE AC-NEW-4/AC-1.4 satisfaction pathway as C4 Fact #54; source label is project-side state machine (same as Manual ESKF Fact #88) |
| AC-2.1a / AC-2.1b / AC-2.2 | **N/A — algorithm-level (C5 consumes C1+C2+C3+C4 outputs)** | Same as Manual ESKF Fact #88 row above |
| AC-3.1 (350m outlier tolerance) | **Pass — NATIVE Robust.Create + GncOptimizer alternative to classical Mahalanobis gate** | iSAM2 supports `noiseModel.Robust.Create(mEstimator.Huber.Create(1.345), gaussian_noise)` Huber M-estimator robust noise model OR `GncOptimizer` Graduated Non-Convexity globally-convergent outlier rejection (Yang et al. RAL 2020) — both NATIVE alternatives to classical Mahalanobis gate that handle 350m outliers structurally without explicit per-measurement gate logic |
| AC-3.2 (sharp turns) | **Pass — NATIVE Forster RSS 2015 IMU pre-integration + iSAM2 sliding-window** | Same as Manual ESKF Fact #88 row above with additional advantage = iSAM2 sliding-window smoothing refines pre-turn pose estimates after-the-fact when post-turn satellite-anchor recovers (look-back refinement per AC-4.5) |
| AC-3.3 (≥3 disconnected segments) | **Pass — NATIVE iSAM2 incremental factor addition design** | iSAM2 treats every successful satellite-anchor registration as an additional `PriorFactorPose3` added via `isam2.update(new_factors)` — disconnected segments are handled identically to connected segments by the incremental update API |
| AC-3.4 (operator re-loc hint via GCS) | **Pass — NATIVE iSAM2 PriorFactorPose3 design** | Operator re-loc hint via GCS is consumed as a `PriorFactorPose3(X(current_keyframe), operator_hint_pose, operator_hint_noise)` added via `isam2.update(new_factors)` — natural fit for iSAM2 incremental update API |
| AC-3.5 (visual blackout + spoofed GPS → dead_reckoned) | **Pass — NATIVE Forster RSS 2015 PIM + project state machine** | Same as Manual ESKF Fact #88 row above with `pim.predict(initial_state, current_best_bias)` providing IMU-only state extrapolation between keyframes when no visual measurement is available (canonical Forster RSS 2015 paradigm) |
| **AC-4.1 (latency <400 ms p95)** | **Pass (with Verify) — TIGHT margin extrapolated to Jetson Orin Nano Super; ~10-30× slower than Manual ESKF Fact #88 but comfortably within 400 ms budget at 3 Hz update rate** | GTSAM iSAM2 incremental smoothing extrapolated ~50-150 ms per update on Jetson Orin Nano Super at K=20 keyframes × ~100-1000 factors per keyframe (D-C5-5 factor-density choice); **comfortable AC-4.1 satisfaction** at 3 Hz update rate (1/3 s = 333 ms budget per cycle) but **10-30× slower than Manual ESKF Fact #88's 5-15 ms per update**. Mitigation = D-C5-3 sliding-window-primitive choice + D-C5-5 factor-density-choice |
| AC-4.2 (memory <8 GB shared) | **Pass — well within budget but heaviest C5 candidate** | ~50-200 MB library footprint (cross-cite to Fact #54) + iSAM2 sliding-window state ~10-50 MB at K=20 keyframes = ~1-3% co-resident memory pressure; well within AC-4.2 budget but **heaviest C5 candidate** vs Manual ESKF Fact #88's 2.6 KB |
| AC-4.3 (FC output contract: WGS84 + honest covariance) | **Pass — NATIVE Marginals 6×6 covariance** | Same as Manual ESKF Fact #88 row above with NATIVE 6×6 covariance via `Marginals.marginalCovariance` (cross-cite to Fact #54) |
| AC-4.4 (estimates streamed frame-by-frame; no batching) | **Pass — NATIVE iSAM2 incremental update design** | iSAM2 emits a new estimate via `isam2.calculateEstimate()` after every `isam2.update(new_factors)` call; no batching beyond the per-keyframe smoothing window |
| **AC-4.5 (system may refine prior estimates and emit corrections)** | **Pass — NATIVE iSAM2 incremental smoothing design (UNIQUE C5 candidate to date that satisfies AC-4.5 NATIVELY)** | **CRITICAL POSITIVE finding for GTSAM iSAM2**: iSAM2 incrementally updates the entire sliding-window posterior on every new measurement, naturally refining prior estimates as new evidence arrives. Manual ESKF Fact #88 cannot natively support AC-4.5 (recursive filter, only forward-time). **GTSAM iSAM2 is the FIRST C5 candidate that satisfies AC-4.5 NATIVELY** without external buffering |
| AC-5.1 / AC-5.2 / AC-5.3 (initialization from FC GPS-extrapolated pose; cold-start TTFF) | **Pass — NATIVE iSAM2 PriorFactorPose3 cold-start design** | Same as Manual ESKF Fact #88 row above with additional NATIVE option = `lago.initialize(graph)` linear-and-iterative-pose-graph initialization OR `InitializePose3.initialize(graph)` chordal-relaxation 3D pose-graph initialization (Source #91) for cold-start when initial pose has high uncertainty |
| AC-6.1 / AC-6.2 / AC-6.3 (GCS interface) | **N/A — C8 / GCS adapter concern, not C5** | Same as Manual ESKF Fact #88 row above |
| AC-7.1 / AC-7.2 (AI-camera object localization) | **N/A — downstream of C5 output** | Same as Manual ESKF Fact #88 row above |
| AC-8.x (cache + freshness + write-back) | **N/A — algorithm-level (C6 cache concern)** | Same as Manual ESKF Fact #88 row above |
| AC-NEW-1 (cold-start TTFF <30 s p95) | **Pass — NATIVE Forster RSS 2015 PIM + iSAM2 PriorFactorPose3 cold-start** | Same as Manual ESKF Fact #88 row above with NATIVE option = `pim.predict(initial_state, current_best_bias)` for IMU-only TTFF when no visual measurement is available in first 30 s (canonical Forster RSS 2015 paradigm) |
| AC-NEW-2 (spoofing-promotion <3 s p95) | **Pass — NATIVE Robust.Create + GncOptimizer alternative to classical Mahalanobis gate + project state machine** | Same as Manual ESKF Fact #88 row above with NATIVE alternative = `noiseModel.Robust.Create(mEstimator.Huber.Create(1.345), gaussian_noise)` rejecting spoofed GPS as outlier in factor-graph optimization without explicit per-measurement Mahalanobis gate |
| AC-NEW-3 (Flight Data Recorder per-frame estimates with covariance + source-label) | **Pass — NATIVE per-keyframe iSAM2 output emission** | Same as Manual ESKF Fact #88 row above; per-keyframe iSAM2 output emission ~3 Hz × 8 hours × 3600 s/hr × ~10 KB per estimate (with full 6×6 covariance + bias estimate) = ~860 MB total, negligible against AC-NEW-3 64 GB/flight budget |
| **AC-NEW-4 (false-position safety budget P(error >500 m) <0.1%, P(error >1 km) <0.01%)** | **Pass — NATIVE 6×6 covariance via Marginals (cross-cite to Fact #54) + Robust.Create + GncOptimizer outlier rejection** | **CRITICAL POSITIVE finding for GTSAM iSAM2**: NATIVE 6×6 pose covariance via `Marginals.marginalCovariance` satisfies AC-NEW-4 covariance-honesty contract NATIVELY (cross-cite to Fact #54 — same NATIVE AC-NEW-4 satisfaction pathway as C4 GTSAM closure). Robust.Create Huber M-estimator + GncOptimizer Graduated Non-Convexity provides structural defense against false-position events. AC-NEW-4 statistical budget verification at Jetson MVE phase via Monte Carlo over public datasets per AC-NEW-4 Validation language |
| AC-NEW-5 (operating temp; 25 W at 50°C for 8h) | **N/A — hardware/cooling concern** | Same as Manual ESKF Fact #88 row above |
| AC-NEW-6 (imagery freshness; never satellite_anchored on stale-tile match) | **Pass (mechanical via project-side state machine source-label gating + iSAM2 PriorFactorPose3 noise model inflation for stale-tile measurements) — project-side state machine extension + NATIVE iSAM2 noise model** | Project-side state machine: when C4 emits a satellite-anchor measurement with `tile_freshness_age > AC-8.2 threshold`, C5 incorporates the measurement via `PriorFactorPose3(X(current_keyframe), satellite_anchor_pose, INFLATED_noise_model)` with inflated noise model reflecting stale-tile uncertainty AND labels the result `visual_propagated` instead of `satellite_anchored`. NATIVE iSAM2 noise model accommodation provides strictly better fit than Manual ESKF Fact #88's binary inclusion-or-rejection logic |
| AC-NEW-7 (cache-poisoning safety budget) | **Pass — NATIVE Robust.Create + GncOptimizer + Marginals 6×6 covariance honesty** | Same as Manual ESKF Fact #88 row above with NATIVE alternative = Robust.Create + GncOptimizer providing graduated outlier rejection vs binary Mahalanobis gate; honest covariance per Fact #54 NATIVE 6×6 ensures cache-poisoned tiles cannot under-report uncertainty downstream |
| AC-NEW-8 (visual blackout + GPS spoofing degraded mode: ≤30 s IMU-only after last trusted anchor; dead_reckoned label; degrade fix-quality at covariance >100 m; escalate at >500 m or >30 s; 10 s GPS-health gate) | **Pass — NATIVE Forster RSS 2015 PIM + project state machine + monotonically-growing covariance** | Same as Manual ESKF Fact #88 row above with NATIVE option = `pim.predict(initial_state, current_best_bias)` for IMU-only state extrapolation between keyframes when no visual measurement is available; monotonically-growing covariance per `pim.preintMeasCov()` 9×9 covariance accumulator; project-side state machine handles the source-label transitions and the covariance-threshold escalation logic |
| Restriction "Operational area / weather / camera / satellite imagery / cache budget" | **N/A — algorithm-level (C5 has no geographic, weather, camera, or imagery sensitivity)** | Same as Manual ESKF Fact #88 row above |
| Restriction "Companion computer: Jetson Orin Nano Super, 8 GB shared" | **Pass with TIGHT MARGIN — extrapolated 50-150 ms per update + 50-200 MB memory footprint; ~10-30× slower than Manual ESKF Fact #88 but comfortably within 400 ms budget at 3 Hz** | **CRITICAL TIGHT-MARGIN finding for GTSAM iSAM2**: classical factor-graph library with no GPU dependency; CPU-only path is the canonical deployment runtime. Extrapolated ~50-150 ms per update on Jetson Orin Nano Super 6-core ARM Cortex-A78AE at K=20 keyframes × ~100-1000 factors per keyframe (D-C5-5 factor-density choice). At 3 Hz update rate = comfortable AC-4.1 satisfaction with substantial margin. Requires **custom JetPack 6 cross-compilation** (~1-2 days engineering, same as C4 Fact #54). **No GPU competition** with C2/C3/C4 (which are GPU-heavy on the Ampere 1024-core fp16 path) — C5 runs entirely on CPU, freeing GPU for C2/C3/C4 inference. **D-C5-3 + D-C5-5 NEW Plan-phase decisions** required for sliding-window-primitive + factor-density choices |
| Restriction "License posture (D-C1-1)" — C5-class license-track interaction | **POSITIVE finding (CLEAN-BSD-3-CLAUSE license track THROUGHOUT) — eligible on every D-C1-1 license-posture choice (cross-cite to Fact #54)** | **POSITIVE on canonical `borglab/gtsam`**: cross-cite to Fact #54 Source #86 GitHub API license metadata = **BSD-3-Clause** (LICENSE.BSD direct WebFetch verified); bundled deps clean (BSD-3 + Apache-2.0 + MPL2 file-level — all dual-use compatible). **CLEAN BSD-3-CLAUSE LICENSE TRACK THROUGHOUT** — no copyleft, no Magic Leap restrictive disqualifier, no NOASSERTION SPDX-detector contingency. Tied with cvg/LightGlue + DISK + XFeat + OpenCV + Manual ESKF Fact #88 for the cleanest license-compliance story across all C-row components evaluated. Under D-C1-1 = (a) GPL-3.0 track, (b) BSD/permissive lock, or (c) keep-both-tracks-open, GTSAM iSAM2 is **eligible on every license-posture choice with the simplest license-compliance story**. **MODERN-COMPETITIVE-LEAD-FACTOR-GRAPH role per engine Component Option Breadth rule** — GTSAM iSAM2 is **deployment-ready under every license-posture choice** with shared-substrate architectural coupling with C4 Fact #54 |

---
