Files
gps-denied-onboard/_docs/02_document/FINAL_report.md
T
Oleksandr Bezdieniezhnykh 4f122b604d [autodev] Step 13 partial: system-level cycle-1 doc sync
Updates _docs/02_document/ to capture the highest-leverage
cycle-1 deltas after 97 implementation batches:

- FINAL_report.md: revise Decision 9 to reflect the actual
  opencv-python pin (>=4.11.0.86,<4.12; D-CROSS-CVE-1
  deferred per leftover); new "Cycle 1 Implementation Status"
  section documents the _STRATEGY_REGISTRY + pre_constructed
  composition-root additions (AZ-591, AZ-618/AZ-619..AZ-624),
  AZ-332 + AZ-333 BLOCKED with parked Tier-2 follow-ups
  AZ-592 + AZ-593, AZ-589 + AZ-590 closed Won't-Fix, Step 11
  Run Tests results (3343 passed / 88 skipped / 0 failed
  local; Docker harness rehab tracked by AZ-602), and the
  deferred-reconciliation list.
- glossary.md: 5 new cycle-1 entries (_STRATEGY_REGISTRY,
  airborne_bootstrap, KltRansac as production-default Tier-1
  VIO, pre_constructed kwarg, Tier-1 task / Tier-2 task
  capability classification). Status line notes the cycle-1
  additions pending re-confirmation.
- ripple_log_cycle1.md (new): explains why per-file
  enumeration is N/A for end-of-cycle-1 sync, lists the
  three doc-update levels and their effective scope, and
  records the recommended follow-up ordering for the
  deferred component / helper / contract / test passes.

Step 13 deferred: architecture.md, module-layout.md,
system-flows.md, 14 component description.md + tests.md,
8 helper docs, 18 contract subfolders, 7 test docs (~50+
files; ~80 product tasks + ~8 helper tasks + ~36 blackbox
test tasks). Filed in FINAL_report.md and
ripple_log_cycle1.md; resume in a fresh conversation per
the 2026-05-18 LESSONS.md guidance.

State: greenfield / Step 13 / in_progress / phase 5
(system-level-updates) / cycle 1.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-19 15:40:14 +03:00

267 lines
31 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GPS-Denied Onboard Pose Estimation — Planning Report
> Generated 2026-05-09 at the close of greenfield Plan (Step 3) — Final / Quality Checklist phase.
> Sources: `architecture.md`, `glossary.md`, `system-flows.md`, `data_model.md`, `risk_mitigations.md`, `epics.md`, `tests/traceability-matrix.md`, `tests/*.md`, `components/**/*.md`, `common-helpers/*.md`, `deployment/*.md`.
## Executive Summary
A Jetson Orin Nano Super-hosted Python+C++ companion replaces real GPS for fixed-wing UAVs in GPS-denied/spoofed environments by fusing pre-flight-cached `satellite-provider` tiles, live nav-camera frames (3 Hz), and FC IMU/attitude (100200 Hz) through a hierarchical pipeline `VIO → VPR → re-rank → matcher → AdHoP-conditional refinement → pose → state` and emits a WGS84 fix with honest 6×6 covariance + provenance label to the FC at 5 Hz, all inside a 400 ms p95 latency budget. Plan decomposes the system into **14 components + 8 common helpers**, **22 numbered system-level Mermaid flows across F1F10**, **39 acceptance criteria + 20 restrictions** with **92.4 % inclusive / 89.8 % strict test coverage**, and **19 Jira epics (AZ-244..AZ-262)** with a total estimated effort of **~295477 story points** (range across t-shirt sizes).
## Problem Statement
Fixed-wing UAVs operating in eastern/southern Ukraine must continue to navigate when the FC's GPS is denied or actively spoofed. The companion provides a drop-in replacement WGS84 fix derived from pre-cached `satellite-provider` imagery + onboard vision + FC IMU, with honest covariance and a `{satellite_anchored | visual_propagated | dead_reckoned}` provenance label, while remaining read-only against `satellite-provider` in flight (post-landing tile uploads run from the operator workstation only). Mission profile: 8 h flights, ~60 km/h cruise, ≤1 km AGL, ≤400 km² total cached area, 25 W TDP, -20 °C to +50 °C envelope.
## Architecture Overview
Single Python-with-C++-extensions monolithic process per binary track on the Jetson Orin Nano Super (8 GB shared LPDDR5, 25 W, JetPack 6.2). Cross-component coupling routes through a shared GTSAM substrate so posterior covariance is recovered natively (`Marginals.marginalCovariance`, D-C5-5 = (c)). Interface-first components live under `src/components/<component>/` with constructor-injected dependencies; per-binary CMake `BUILD_*` flags select which `Strategy` implementations are linked into each artifact (`production-binary` = OKVIS2 + KltRansac + UltraVPR + …; `research-binary` = all candidate strategies for the IT-12 comparative study). The operator-side Tile Manager (C11) is a separate binary excluded from the airborne CMake target — process-level isolation is the primary defence for ADR-004 (no in-flight `satellite-provider` I/O in either direction).
**Technology stack**: Python 3.10 + C++17, TensorRT 10.3 (JetPack 6.2 pin) / ONNX Runtime + TRT EP / pure PyTorch FP16 baseline; OpenCV ≥ 4.12.0; GTSAM iSAM2 + `IncrementalFixedLagSmoother`; FAISS HNSW; PostgreSQL 16 (`tiles` schema mirrored from `satellite-provider`); pymavlink + MAVLink 2.0 signing for ArduPilot, YAMSPy + INAV-Toolkit MSP2 for iNav.
**Deployment**: two execution tiers — Tier-1 workstation Docker (fast/cheap, AC-bound jobs that do not require Jetson hardware) and Tier-2 self-hosted Jetson runner (AC-NEW-1 / NFT-PERF / NFT-LIM); pre-flight + post-landing operator tooling runs on the operator workstation; companion image is bare JetPack 6.2 (no Docker on Tier-2 to keep INT8 calibration cache trustworthy per D-C10-6).
See `architecture.md` for the full ADR set (ADR-001..ADR-009), 12 architectural principles, and per-component intent statements.
## Component Summary
| # | Component | Purpose | Dependencies | Epic |
|---|-----------|---------|-------------|------|
| 01 | C1 VIO | Pluggable `VioStrategy` (OKVIS2 default, VINS-Mono research, KltRansac mandatory simple-baseline) producing per-frame `VioOutput` | C7, helpers (IMU preintegrator, SE3 utils) | AZ-254 |
| 02 | C2 VPR | Pre-cached satellite-tile retrieval (UltraVPR primary, MegaLoc/MixVPR/SelaVPR/EigenPlaces/NetVLAD/SALAD candidates) behind `VprStrategy` | C6, C7 | AZ-255 |
| 03 | C2.5 Re-rank | Single-pair LightGlue inlier-count rerank K=10 → N=3 | C2, C7, helper LightGlue runtime | AZ-256 |
| 04 | C3 Matcher | DISK+LightGlue cross-domain matching + RANSAC + reprojection residual filter | C2.5, C7, helper RANSAC filter | AZ-257 |
| 05 | C3.5 AdHoP | Conditional refinement when initial reprojection residual exceeds threshold | C3, C7 | AZ-258 |
| 06 | C4 Pose | OpenCV `solvePnPRansac` (IPPE) wrapped in GTSAM `Marginals` for native 6×6 covariance | C3.5, C5 (shared GTSAM substrate) | AZ-259 |
| 07 | C5 State | GTSAM iSAM2 + `IncrementalFixedLagSmoother` (K=1020); spoof-promotion gate; AC-4.5 internal smoothing | C1, C4, C8 inbound, C13 | AZ-260 |
| 08 | C6 Tile Cache | PostgreSQL btree spatial index + filesystem `./tiles/{zoom}/{x}/{y}.jpg` mirroring `satellite-provider`; FAISS HNSW VPR descriptor index | E-BOOT, E-CC-LOG, E-CC-CONF | AZ-250 |
| 09 | C7 Inference Runtime | TensorRT 10.3 engines (Polygraphy / trtexec / IBuilderConfig hybrid); ORT+TRT EP fallback; PyTorch FP16 baseline | E-BOOT, E-CC-CONF, E-CC-FDR-CLIENT | AZ-249 |
| 10 | C8 FC + GCS Adapter | `pymavlink` `GPS_INPUT` for ArduPilot (signed) + `MSP2_SENSOR_GPS` for iNav (unsigned, accepted residual risk); honest 6×6 → 2×2 covariance projection; GCS 12 Hz downsampled telemetry | C5, E-CC-CONF, E-CC-LOG | AZ-261 |
| 11 | C10 Pre-flight Cache Provisioning | Builds model-derived cache (descriptors, engines, manifest, content hashes); F2 takeoff verifier; does NOT touch `satellite-provider` (network I/O lives in C11) | C6, C7, E-CC-LOG | AZ-252 |
| 12 | C11 Tile Manager | Operator-side `TileDownloader` (pre-flight) + `TileUploader` (post-landing — no internal flight-state gate after Batch 44; gating lives in C12); excluded from airborne image | C6, E-CC-CONF, E-CC-LOG | AZ-251 |
| 13 | C12 Operator Pre-flight Orchestrator | CLI subcommands (`download`, `build-cache`, `upload-pending`, `reloc-confirm`); `PostLandingUploadOrchestrator` (gates on `flight_footer.clean_shutdown`); `OperatorReLocService` (AC-3.4 hint via `OperatorCommandTransport`); sector classification UI hook; FDR retrieval helpers | C10, C11, E-CC-LOG | AZ-253 |
| 14 | C13 Flight Data Recorder | Per-flight ≤64 GB NVM ring (estimates + IMU + emitted MAVLink + health + mid-flight tiles + ≤0.1 Hz failed-tile thumbnails); raw nav/AI-cam frames excluded | E-BOOT, E-CC-LOG, E-CC-CONF, E-CC-FDR-CLIENT | AZ-248 |
**Cross-cutting epics** (not components, but shared concerns): E-BOOT (AZ-244), E-CC-LOG (AZ-245), E-CC-CONF (AZ-246), E-CC-FDR-CLIENT (AZ-247).
**System-level test epic**: E-BBT (AZ-262) parents the FT/NFT scenarios across all components.
**Implementation order** (from dependency graph in `epics.md`):
1. **Phase 1 (foundation, parallel)**: E-BOOT (AZ-244) → E-CC-LOG (AZ-245), E-CC-CONF (AZ-246), E-CC-FDR-CLIENT (AZ-247).
2. **Phase 2 (data + runtime + recorder)**: E-C13 (AZ-248), E-C7 (AZ-249), E-C6 (AZ-250).
3. **Phase 3 (operator tooling chain)**: E-C11 (AZ-251) → E-C10 (AZ-252) → E-C12 (AZ-253).
4. **Phase 4 (perception pipeline)**: E-C1 (AZ-254), E-C2 (AZ-255) → E-C2.5 (AZ-256) → E-C3 (AZ-257) → E-C3.5 (AZ-258) → E-C4 (AZ-259).
5. **Phase 5 (state + emission)**: E-C5 (AZ-260) → E-C8 (AZ-261).
6. **Phase 6 (system tests)**: E-BBT (AZ-262) — hardens behind every other epic.
## System Flows
| Flow | Description | Key Components |
|------|-------------|---------------|
| F1 | Pre-flight cache provisioning | C11 (TileDownloader), C6, C10, C12 |
| F2 | Takeoff load (cold-start TTFF, AC-NEW-1) | C10, C7, C6, C8, C5 |
| F3 | Steady-state per-frame estimation (the F3 hot path) | C1, C2, C2.5, C3, C3.5, C4, C5, C8, C13 |
| F4 | Mid-flight tile generation + local cache write | C5 (orthorectifier subpath), C6, C13 |
| F5 | Visual blackout + spoofed-GPS failsafe (AC-NEW-8) | C1, C5, C8 (STATUSTEXT) |
| F6 | Sharp-turn / disconnected-segment re-localization | C2, C2.5, C3, C5 |
| F7 | Spoofing-promotion via EKF source-set switch (AC-NEW-2) | C5 (SourceLabelStateMachine), C8 (AP D-C8-2) |
| F8 | Companion reboot recovery | C13 (FDR replay), C5, C8 |
| F9 | GCS telemetry stream (AC-6.1) | C8 (GcsAdapter) |
| F10 | Post-landing tile upload (D-PROJ-2 contract) | C11 (TileUploader), C6, C12 |
Reference `system-flows.md` for the per-flow Mermaid sequence diagrams + flowcharts; `_docs/02_document/diagrams/components.drawio` is the visual companion for component boundaries.
## Risk Summary
| Level | Count | Key Risks |
|-------|-------|-----------|
| Critical | 0 | — |
| High | 3 | R01 (D-PROJ-2 ingest endpoint not yet shipped), R03 (MAVLink-2.0 signing handshake no precedent — IT-3 gated), R11 (AC-NEW-4/AC-NEW-7 multi-flight statistical headroom — D-PROJ-3 deferred) |
| Medium | 8 | R02 (ADR-004 process-isolation regression), R04 (TRT engine SM/JP/TRT mismatch), R05 (iSAM2 silent factor-add failure), R06 (VPR top-1 false positive), R07 (premature spoof re-promotion), R08 (tile freshness drift in active-conflict sectors), R10 (`Marginals` latency under thermal throttle), R12 (single deployment camera) |
| Low | 3 | R09 (per-flight signing key compromise), R13 (FDR queue overrun), R14 (C2.5 ↔ C3 LightGlue circular dependency — resolved via shared helper) |
**Iterations completed**: 1 (initial Step 4 risk pass; R02 enforcement scope extended, R14 resolved via helper ownership).
**All Critical/High risks mitigated**: Yes — R01 has e2e mock-suite-sat-service fixture + leftover tracking; R03 is gated by IT-3 with documented D-C8-2-FALLBACK options (ADR-008); R11 is mitigated by AC-text relaxation 2026-05-09 (Monte-Carlo-with-CI) plus D-PROJ-3 carryforward.
Reference `risk_mitigations.md` for the full register, per-risk trigger conditions, and detailed mitigations.
## Test Coverage
The test suite is organised as scenario specs (no source code yet). Per-component tests live under each component's `tests.md`; cross-component / system-level scenarios live under `_docs/02_document/tests/`.
### Per-component scenario counts (from each `components/*/tests.md`)
| Component | Component-internal tests file |
|-----------|------------------------------|
| C1 | `components/01_c1_vio/tests.md` |
| C2 | `components/02_c2_vpr/tests.md` |
| C2.5 | `components/03_c2_5_rerank/tests.md` |
| C3 | `components/04_c3_matcher/tests.md` |
| C3.5 | `components/05_c3_5_adhop/tests.md` |
| C4 | `components/06_c4_pose/tests.md` |
| C5 | `components/07_c5_state/tests.md` |
| C6 | `components/08_c6_tile_cache/tests.md` |
| C7 | `components/09_c7_inference/tests.md` |
| C8 | `components/10_c8_fc_adapter/tests.md` |
| C10 | `components/11_c10_provisioning/tests.md` |
| C11 | `components/12_c11_tilemanager/tests.md` |
| C12 | `components/13_c12_operator_orchestrator/tests.md` |
| C13 | `components/14_c13_fdr/tests.md` |
### System-level scenario suites (`_docs/02_document/tests/`)
| File | Scenario family |
|------|-----------------|
| `tests/blackbox-tests.md` | FT-P-* (positive functional) + FT-N-* (negative functional) |
| `tests/performance-tests.md` | NFT-PERF-* (Tier-2) |
| `tests/resource-limit-tests.md` | NFT-LIM-* |
| `tests/security-tests.md` | NFT-SEC-* |
| `tests/resilience-tests.md` | NFT-RES-* |
| `tests/test-data.md` | Fixture inventory (Derkachi flight + AerialVL S03 + e2e mock-suite-sat-service) |
| `tests/environment.md` | Test environment + Tier-1/Tier-2 split |
| `tests/traceability-matrix.md` | Single source of truth for AC ↔ scenario coverage |
### Acceptance Criteria + Restrictions coverage (from `tests/traceability-matrix.md`, revised 2026-05-09)
| Category | Total | Covered | PARTIAL | Not Covered | Coverage % (PARTIAL counted half) |
|----------|-------|---------|---------|-------------|------------------------------------|
| Acceptance Criteria | 39 | 35 | 2 | 2 | 92.3 % |
| Restrictions | 20 | 18 | 1 | 1 | 92.5 % |
| **Total** | **59** | **53** | **3** | **3** | **92.4 %** (strict 89.8 %) |
Both the inclusive reading (PARTIAL = covered) and the strict reading clear the 75 % gate with margin. Remaining PARTIAL / NOT COVERED rows: AC-8.6 scene-change subset (labeled change-pair dataset not available), AC-NEW-5 hot-soak chamber (physical hardware), AC-7.1 / AC-7.2 + RESTRICT-CAM-2 (no AI-camera fixture), RESTRICT-HW-2 chamber portion (paired with AC-NEW-5).
## Epic Roadmap
| Order | Epic | Component | T-shirt | Story points | Dependencies |
|-------|------|-----------|---------|--------------|-------------|
| 1 | AZ-244: E-BOOT — Bootstrap & Initial Structure | repo scaffolding | M | 1321 | — |
| 2 | AZ-245: E-CC-LOG — Structured JSON Logging | cross-cutting | S | 58 | E-BOOT |
| 3 | AZ-246: E-CC-CONF — Configuration & Composition Root | cross-cutting | S | 58 | E-BOOT |
| 4 | AZ-247: E-CC-FDR-CLIENT — FDR Producer Client | cross-cutting | M | 813 | E-BOOT, E-CC-LOG |
| 5 | AZ-248: E-C13 — Flight Data Recorder | C13 | L | 2134 | E-BOOT, E-CC-LOG, E-CC-CONF, E-CC-FDR-CLIENT |
| 6 | AZ-249: E-C7 — On-Jetson Inference Runtime | C7 | L | 2134 | E-BOOT, E-CC-CONF, E-CC-FDR-CLIENT |
| 7 | AZ-250: E-C6 — Tile Cache + Spatial Index | C6 | M | 1321 | E-BOOT, E-CC-LOG, E-CC-CONF |
| 8 | AZ-251: E-C11 — Tile Manager | C11 | M | 1321 | E-C6, E-CC-CONF, E-CC-LOG |
| 9 | AZ-252: E-C10 — Pre-flight Cache Provisioning | C10 | M | 1321 | E-C6, E-C7, E-CC-LOG |
| 10 | AZ-253: E-C12 — Operator Pre-flight Orchestrator | C12 | M | 1321 | E-C10, E-C11, E-CC-LOG |
| 11 | AZ-254: E-C1 — Visual / Visual-Inertial Odometry | C1 | XL | 3455 | E-BOOT, E-CC-FDR-CLIENT, E-C7 |
| 12 | AZ-255: E-C2 — Visual Place Recognition | C2 | L | 2134 | E-C6, E-C7, E-CC-FDR-CLIENT |
| 13 | AZ-256: E-C2.5 — Inlier-based Re-rank | C2.5 | S | 58 | E-C2, E-C7, E-C6 (shared LightGlue helper) |
| 14 | AZ-257: E-C3 — Cross-Domain Matcher | C3 | L | 2134 | E-C2.5, E-C7 |
| 15 | AZ-258: E-C3.5 — AdHoP-Conditional Refinement | C3.5 | M | 813 | E-C3, E-C7 |
| 16 | AZ-259: E-C4 — Pose Estimator | C4 | M | 1321 | E-C3.5, E-C5 (shared GTSAM substrate) |
| 17 | AZ-260: E-C5 — State Estimator | C5 | XL | 3455 | E-C1, E-C4 (shared graph), E-CC-FDR-CLIENT |
| 18 | AZ-261: E-C8 — FC + GCS Adapter | C8 | L | 2134 | E-C5, E-CC-CONF, E-CC-LOG |
| 19 | AZ-262: E-BBT — Blackbox Tests (FT/NFT scenarios) | system-level tests | M | 1321 | every component epic |
**Total estimated effort**: 295477 story points across 19 epics (sum of t-shirt-band lower / upper bounds from `epics.md`). The two XL epics (E-C1 = AZ-254 and E-C5 = AZ-260) carry ~22 % of the upper-bound estimate alone.
## Key Decisions Made
| # | Decision | Rationale | Alternatives Rejected |
|---|----------|-----------|----------------------|
| 1 | Single Python+C++ monolith per binary track (ADR-001) | Latency budget (400 ms p95) + GTSAM substrate sharing + Jetson 8 GB shared memory | Multi-process (D-C1-1-SUB-A=(b)) — too much IPC overhead; ROS — adds runtime weight without flight-controller benefit |
| 2 | Build-time exclusion of unused `Strategy` implementations via per-binary CMake `BUILD_*` flags (ADR-002) | Binary size on 8 GB shared Jetson, AC-NEW-1 30 s boot budget, accidental-selection risk | Runtime-only selection — bigger binary, larger attack surface, harder cold-start; component licenses do not drive this decision |
| 3 | Shared GTSAM substrate between C4 (pose) and C5 (state) (ADR-003, D-C5-5 = (c)) | Native posterior covariance via `Marginals.marginalCovariance`; one numerical foundation | Independent EKF in C5 + Jacobian-only covariance — cannot deliver honest 6×6 |
| 4 | Process-level isolation of operator-side Tile Manager (ADR-004) — C11 not linked into airborne image | AC-8.4 in-flight no-write; defeats reflection / config-error attack vectors | Runtime gate alone — reflection / DI bug could re-introduce code path |
| 5 | Two execution tiers (ADR-005): Tier-1 workstation Docker + Tier-2 self-hosted Jetson | Cost (Jetson runner saturated) + AC-NEW-1 must run on real hardware | Single-tier Jetson-only — too slow / expensive for pre-merge CI |
| 6 | D-CROSS-LATENCY-1 hybrid (ADR-006): K=3 baseline auto-degrades to K=2 + Jacobian covariance under thermal throttle | Preserves AC-4.1 at +50 °C ambient at the cost of ~510 % accuracy | Static K=2 — wastes covariance precision in nominal conditions; static K=3 — blows the budget under throttle |
| 7 | Spoof-promotion gate (ADR-008): re-promote only after ≥10 s `gps_health == STABLE_NON_SPOOFED` AND visual-consistency check passes | AC-NEW-2 / AC-NEW-8 floor; defends against attacker turning spoof off briefly | Time-only gate (≥30 s) — slower mission recovery, still fool-able by transient honest GPS during attack |
| 8 | Interface-first components with constructor injection (ADR-009) | Multiple interchangeable strategies on the same interface (C1 has 3, C2 has 6+, C8 has 2) — selection via composition root only | Service-locator / global registry — couples runtime to import order, breaks tests, breaks build-time exclusion |
| 9 | OpenCV pin **temporarily relaxed** to `>=4.11.0.86,<4.12` (was `>=4.12.0` per original Mode B Fact #112) | `gtsam==4.2.1` (only published wheel) is built against numpy 1.x ABI; `opencv-python>=4.12` requires numpy>=2; D-CROSS-CVE-1 follow-up tracked in `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md` and replays the `>=4.12.0` pin once gtsam ships numpy-2 wheels (or an alternative SE(3) backend is adopted) | Keep numpy>=2 — `gtsam.Pose3` SEGFAULTs; force `opencv-python>=4.12` — uninstallable; drop gtsam — loses ADR-003 honest 6×6 covariance |
| 10 | DISK + LightGlue replaces SuperPoint+SuperGlue for cross-domain matching (D-C3-1 = (a)) | License — SP+SG is Magic Leap noncommercial canonical; DISK+LightGlue is BSD-3-Clause | SuperPoint+SuperGlue — license incompatibility; XFeat — promising but unproven cross-domain |
| 11 | AC-NEW-4 / AC-NEW-7 text relaxed 2026-05-09 to Monte-Carlo-over-current-data with stated 95 % CI | D-PROJ-3 multi-flight fixture acquisition is out of scope this cycle; literal "≥100 flights" wording cannot be met | Block planning on D-PROJ-3 — cycle would not close; relaxed wording is documented residual risk in R11 |
## Open Questions
| # | Question | Impact | Assigned To |
|---|----------|--------|-------------|
| 1 | D-PROJ-2: parent-suite `satellite-provider` ingest endpoint + multi-flight voting layer not yet implemented service-side | F10 post-landing upload depends on this; R01; e2e mock-suite-sat-service fixture stands in for tests | Parent suite (cross-workspace; tracked in `_docs/_process_leftovers/2026-05-09_satellite-provider-design-tasks.md`) |
| 2 | D-PROJ-3: multi-flight fixture acquisition (Maxar Open Data Ukraine + AerialVL S03 + own multi-flight data) | AC-NEW-4 / AC-NEW-7 statistical headroom; R11 carryforward to next Plan cycle | Project lead |
| 3 | D-C8-2 runtime gate: companion-driven `MAV_CMD_SET_EKF_SOURCE_SET` switch lacks deployed precedent | R03 — IT-3 ArduPilot SITL validation is the lock gate; D-C8-2-FALLBACK options recorded in ADR-008 | Onboard team (gated by IT-3) |
| 4 | D-C2-12: DINOv2-feature-based matcher evaluation as a possible C3 backbone alternative | Could close D-C3-1 retrain cost concern; carryforward to next Plan cycle | Onboard team |
| 5 | AC-NEW-5 hot-soak chamber test (25 W @ +50 °C, 8 h, no throttle) | Physical hardware required; release-tag-blocking gate; out of scope for data-acquisition this cycle | Project lead |
| 6 | AC-7.1 / AC-7.2 / RESTRICT-CAM-2: AI-camera object localization pipeline | Out of scope for this cycle; deferred to a follow-up Plan cycle scoped to AI-camera integration | Future cycle (next Plan) |
| 7 | AC-8.6 scene-change subset: needs labeled change-pair dataset | Stale-tile match in active-conflict sectors — scene-change recall unmeasured (scale-ratio half is covered) | Future cycle |
## Artifact Index
| File | Description |
|------|-------------|
| `architecture.md` | System architecture, ADR set (ADR-001..ADR-009), 12 architectural principles, technology stack |
| `glossary.md` | Canonical project terminology (locked Phase 2a.0) |
| `system-flows.md` | F1F10 Mermaid sequence diagrams + flowcharts + per-flow data flow tables |
| `data_model.md` | PostgreSQL `tiles` (mirrored from `satellite-provider`) + flight + manifest schema; FAISS / TRT artifact layout; FDR record schema |
| `risk_mitigations.md` | 14-row risk register (R01..R14) with per-risk mitigation + contingency |
| `epics.md` | Local plan E-* IDs, t-shirt sizes, story-point ranges, dependencies, child-issue breakdowns; canonical `E-*``AZ-NN` mapping |
| `components/01_c1_vio/description.md``components/14_c13_fdr/description.md` | Per-component spec (interface, implementations, dependencies, ACs, NFRs, risks) |
| `components/01_c1_vio/tests.md``components/14_c13_fdr/tests.md` | Per-component test scenarios |
| `common-helpers/01_helper_imu_preintegrator.md``common-helpers/08_helper_descriptor_normaliser.md` | Shared helpers (IMU preintegrator, SE3 utils, LightGlue runtime, WGS converter, SHA-256 sidecar, engine filename schema, RANSAC filter, descriptor normaliser) |
| `tests/traceability-matrix.md` | AC ↔ scenario coverage; restriction ↔ scenario coverage |
| `tests/blackbox-tests.md`, `tests/performance-tests.md`, `tests/security-tests.md`, `tests/resource-limit-tests.md`, `tests/resilience-tests.md` | System-level FT / NFT scenario specs |
| `tests/test-data.md`, `tests/environment.md` | Fixture inventory + Tier-1/Tier-2 environment definition |
| `deployment/containerization.md`, `deployment/ci_cd_pipeline.md`, `deployment/environment_strategy.md`, `deployment/observability.md`, `deployment/deployment_procedures.md` | Deployment plan |
| `diagrams/components.drawio` | Component-level diagram (visual companion to `components/`) |
| `diagrams/flows/00_index.md` | Per-flow index pointing into `system-flows.md` |
## Cycle 1 Implementation Status
> Appended 2026-05-19 as part of greenfield Step 13 (Update Docs, task mode). Captures the as-built deltas from this planning report after 97 implementation batches + Step 11 Run Tests + Step 12 Test-Spec Sync. Sources: `_docs/03_implementation/implementation_completeness_cycle1_report.md`, `_docs/03_implementation/run_tests_step11_report.md`, `_docs/02_tasks/done/` (165 task specs), `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md`.
### Composition-root architecture additions (not in the original Plan)
The Plan-era `architecture.md` § ADR-009 (interface-first, constructor injection) and module-layout.md's "Composition root is `runtime_root/`" rule remain correct, but cycle 1 added two cross-cutting Tier-1 mechanisms inside `runtime_root/` that the Plan did not anticipate. Both are operational prerequisites for `compose_root()` reaching takeoff:
- **`_STRATEGY_REGISTRY` + `register_strategy(...)` API (AZ-591)** — a module-level `dict[(component_slug, strategy_name)] → factory` populated per-binary. `runtime_root.airborne_bootstrap.register_airborne_strategies()` fills 7 airborne slots (`c1_vio`, `c2_vpr`, `c2_5_rerank`, `c3_matcher`, `c3_5_adhop`, `c4_pose`, `c5_state`) with `tier="airborne"`. Without this, `compose_root()` raises `StrategyNotLinkedError` on the first config-driven strategy lookup. The registry is the runtime-side complement to ADR-002 build-time exclusion: the build chooses which strategies are even available to register, the registry chooses which one this binary serves.
- **`pre_constructed` kwarg + `build_pre_constructed(config)` (AZ-618 umbrella → subtasks AZ-619..AZ-624)** — `compose_root(config, pre_constructed=...)` now requires a 12-key dict of infrastructure objects (`c13_fdr`, `c6_descriptor_index`, `c6_tile_store`, `c7_inference`, `c3_lightglue_runtime`, `c3_feature_extractor`, `c282_ransac_filter`, `c5_wgs_converter`, `c5_se3_utils`, `c5_isam2_graph_handle`, `c5_imu_preintegrator`, `clock`). The airborne entrypoint builds these in 6 dependency-ordered phases (A=c13/clock → F=wire_main); GPU-touching builders gate on the corresponding `BUILD_*` env flag. Missing keys raise `AirborneBootstrapError` with the missing-key name; tests stub by passing the same `pre_constructed=...` kwarg.
These additions sit inside `runtime_root/`; no component crosses the import boundary AZ-507 enforces. Both still need to be folded into `architecture.md` (ADR-009 sibling notes) and `module-layout.md` § "Composition Root" — deferred to a follow-up `/document` task pass.
### BLOCKED tasks with parked Tier-2 follow-ups
Per the implement skill § 15 "PASS-with-BLOCKED" allowable terminal classification (see `implementation_completeness_cycle1_report.md`):
| Task | Status | Reason | Parked Tier-2 follow-up |
|------|--------|--------|-------------------------|
| AZ-332 — C1 OKVIS2 production-default `VioStrategy` | BLOCKED | Tier-2 prerequisites: CI build env + Jetson hardware + DBoW2 vocab artifact. Ships a Python facade + pybind11 binding skeleton; first `add_frame` raises until upstream `okvis::ThreadedSlam` wiring lands. | **AZ-592** (`_docs/02_tasks/backlog/`) |
| AZ-333 — C1 VINS-Mono research-only `VioStrategy` | BLOCKED | Tier-2 prerequisites + upstream vendoring decision (HKUST + ROS-strip vs. community fork). Same skeleton-only state as AZ-332. | **AZ-593** (`_docs/02_tasks/backlog/`) |
**Operational consequence**: the production-default airborne `VioStrategy` for cycle-1 release is **`KltRansac`** (the engine-rule-mandatory simple baseline, AZ-334), NOT OKVIS2 as `architecture.md` ADR-001 nominally implies. ADR-001 / ADR-002 remain architecturally correct (the seam exists; the build-flag gating works); the production *default selection* shifts until Tier-2 lands. The `_STRATEGY_REGISTRY` still registers the OKVIS2 + VINS-Mono slots so the registry seam stays correct — selecting them via config raises `StrategyNotAvailableError` from `vio_factory.py` until their `BUILD_*` flag is ON.
**Closed Won't-Fix during this cycle**: AZ-589 + AZ-590 (the original remediation tasks for AZ-332 + AZ-333). Both targeted upstream APIs that don't exist in the actually-checked-in OKVIS2 submodule + a non-existent VINS-Mono submodule. The post-mortem details are in `implementation_completeness_cycle1_report.md` § "Verdict — Revised 2026-05-16".
### Run Tests (Step 11) results
| Surface | Result |
|---------|--------|
| Local Tier-1 pytest suite | **3343 passed / 88 skipped / 0 failed** (12 logical chunks; full details in `run_tests_step11_report.md`) |
| Docker Tier-1 SUT Reality Gate | **NOT MET** — both harnesses (`scripts/run-tests.sh` + `e2e/docker/run-tier1.sh`) have pre-existing drift unrelated to Step 10 work (missing `ardupilot/*` + `inavflight/*` images on Docker Hub; broken Dockerfile entrypoints; unseeded tile-cache volume). Rehabilitation epic **AZ-602** owns this. |
| Skip classification | 14 Tier-2-only (Jetson) — legitimate; 8 CUDA/GPU absent on macOS dev host — legitimate; 6 TensorRT-on-Tier-2-only — legitimate; 57 Docker-compose-dependent — borderline, becomes covered once any harness runs end-to-end; 3 console-scripts-not-on-PATH — env-conditional; remainder legitimate |
### Dependency pin drift since Plan
- **opencv-python**: relaxed from `>=4.12.0` to `>=4.11.0.86,<4.12` (D-CROSS-CVE-1 deferred per `_docs/_process_leftovers/2026-05-11_d_cross_cve_1_opencv_pin_deferred.md`; root cause is the gtsam==4.2.1 / numpy<2.0 ABI lock). See revised Decision 9 above. The original CVE-2025-53644 intent stands and will replay once gtsam ships numpy-2 wheels.
### Documentation reconciliation still owed (deferred to a follow-up `/document` task pass)
This Step-13 session updated the highest-leverage system-level deltas only. The following surfaces still carry Plan-era assertions that do not match cycle-1 as-built behaviour and should be refreshed in a follow-up session:
- `architecture.md` — add ADR-009 sibling notes for `_STRATEGY_REGISTRY` + `pre_constructed`; revise OpenCV mentions (§ Technology stack, § Risks); reflect KltRansac-as-production-default in § C1 ADR commentary.
- `module-layout.md` — extend § "Composition Root" with `airborne_bootstrap` + `build_pre_constructed` ownership; AZ-618 / AZ-591 ownership rows in the runtime_root section.
- `components/01_c1_vio/description.md` — note KltRansac is the operational default while AZ-592 / AZ-593 are parked.
- `components/<NN>_<cN>/description.md` for the other 13 components — task-by-task reconciliation against the 80 product tasks in `done/`.
- `common-helpers/*.md` — task-by-task reconciliation against the 8 helper tasks in `done/`.
- `tests/*.md` — task-by-task reconciliation against the ~36 Blackbox Tests tasks in `done/` (some already touched by Step 12 Test-Spec Sync — see `tests/traceability-matrix.md` and `tests/resilience-tests.md` diffs).
## Quality Checklist Verification
All 8 checklist sections from `.cursor/skills/plan/steps/07_quality-checklist.md` pass for this cycle:
- **Blackbox Tests**: every AC + restriction in `tests/traceability-matrix.md`; restrictions verified by ≥1 scenario each (RESTRICT-CAM-2 deferred with documented mitigation); positive (FT-P) + negative (FT-N) balanced; Tier-1 Docker + Tier-2 Jetson defined in `tests/environment.md`; consumer treats system as black box (FC + GCS contracts only); CI integration in `deployment/ci_cd_pipeline.md`.
- **Architecture**: covers all `solution.md` capabilities; technology choices justified in § 2 of `architecture.md` + ADR-001..ADR-009; deployment model in `deployment/`; blackbox findings F6F10 reflected (Tier split, mock-suite-sat-service, two-binary CI emit).
- **Data Model**: every persistent entity from `architecture.md` § 4 defined in `data_model.md`; relationships have explicit FK cardinality; migration strategy is additive-only with ADR-recorded deprecation requirement; seed data = `satellite-provider` mirror of `tiles`; backward compatibility = `tiles` schema frozen on canonical columns.
- **Deployment**: containerization covers Tier-1 workstation Docker; CI/CD pipeline includes lint, test, security (SBOM diff, ASan), build, deploy stages; environment strategy covers dev / staging / production (Tier-1 + Tier-2 + Jetson production image); observability covers structured JSON logging + FDR + GCS STATUSTEXT; deployment procedures include rollback (per-flight key zeroisation, FDR rollover) and health checks (F2 takeoff verifier).
- **Components**: 14 components each follow SRP; no circular dependencies (R14 resolved via shared LightGlue helper); inter-component interfaces defined as `Protocol`/`ABC` per ADR-009; no orphan components — every component appears in at least one F1F10 flow; every blackbox scenario traceable through the component dependency graph.
- **Risks**: all High risks have mitigations + contingency (R01, R03, R11); mitigations reflected in `architecture.md` (ADR-004 enforcement scope, ADR-008 D-C8-2-FALLBACK), `tests/security-tests.md` (NFT-SEC-02 egress test), and `tests/traceability-matrix.md` (AC-text relaxation).
- **Tests**: every AC + restriction covered by ≥1 test (with PARTIAL/NOT-COVERED items having documented mitigation); 4 test types per component represented where applicable (unit/contract inside per-component `tests.md` + integration/performance/security/resilience at system level); test data management defined in `tests/test-data.md`.
- **Epics**: E-BOOT (AZ-244) "Bootstrap & Initial Structure" present; E-BBT (AZ-262) "Blackbox Tests" present; every component maps to a component epic (C1..C8, C10..C13 → AZ-254, AZ-255, AZ-256, AZ-257, AZ-258, AZ-259, AZ-260, AZ-261, AZ-252, AZ-251, AZ-253, AZ-248); dependency order matches `epics.md` "Implementation order"; acceptance criteria are measurable (per-epic IT/PT/ST IDs trace back to `traceability-matrix.md`).