Files
Yuzviak e81b6fdfba docs(02-05): complete CI pipeline split + AC orphan reconciliation plan
- 02-05-SUMMARY.md: full execution record for plan 02-05
- ROADMAP.md: plan progress updated (5 summaries of 7 plans complete)
- REQUIREMENTS.md: AC-06 and TEST-02 marked complete

Per-marker CI jobs and ac-traceability gate are now the CI contract.
All 21 orphan ACs annotated pending-phase-N; --check exits 0 locally.
2026-05-11 18:35:47 +03:00

13 KiB
Raw Permalink Blame History

Requirements: GPS-Denied Onboard Navigation System — Stage 2

Defined: 2026-05-10 Stage: 2 (independent iteration) Branch: stage2 (HEAD = stage1; v1.0 archived) Core Value: The flight controller must receive valid MAVLink GPS_INPUT at 5-10Hz with position accuracy ≤50m for 80% of frames — without this, the UAV cannot navigate in GPS-denied airspace.


Stage 2 Requirements

Stage 2 is a self-contained iteration. Phases are numbered 16 within this stage. Stage 1 work (its 36 v1 requirements + 7 phases) is archived in .planning/archive/v1.0/ as starting capital, not as active backlog.

The stage 1 codebase (ESKF + cuVSLAM + GPR + MAVLink + pipeline + 195 passing tests) is treated as MVP — refactoring is allowed and expected. Concept-level ideas from the parallel try02 branch are re-implemented (not merged).

ARCH — Hexagonal architecture & composition

  • ARCH-01: Codebase reorganized to src/gps_denied/components/{vio, satellite_matcher, gpr, anchor_verifier, safety_state, flight_recorder, mavlink_io, coordinate_transforms}/, each containing protocol.py + concrete implementations + (where applicable) native/ for backend bridges
  • ARCH-02: Hot-path data types (FrameState, IMUSample, PositionEstimate, VOEstimate, SatelliteAnchor) implemented as @dataclass(slots=True, frozen=True) in src/gps_denied/hot_types/; Pydantic retained only for REST/config/DB boundary schemas
  • ARCH-03: Explicit DI composition root src/gps_denied/pipeline/composition.py exposes build_pipeline(env: Literal["jetson", "x86_dev", "ci", "sitl"]) -> Pipeline that wires environment-specific implementations
  • ARCH-04: core/ retained for concentrated math (ESKF, factor graph, RANSAC, coordinate transforms) — these stay as pure-function single files, NOT split into interfaces.py + types.py + impl.py
  • ARCH-05: All component Protocols defined with typing.Protocol; concrete adapters implement them; Pipeline constructor takes Protocol-typed dependencies (no concrete imports inside pipeline orchestration)
  • ARCH-06: Per-environment YAML configuration in config/{jetson,x86_dev,ci,sitl}.yaml, loaded via pydantic-settings into a typed RuntimeConfig model passed to build_pipeline
  • ARCH-07: All 195 stage1 tests + 8 SITL skipped continue to pass after refactor; no regression in accuracy benchmarks

AC — Formal acceptance criteria document

  • AC-01: _docs/00_problem/acceptance_criteria.md rewritten with formal AC-1.x…AC-NEW-x list adapted from try02 and validated against this project's actual constraints
  • AC-02: Each AC entry includes (a) numeric thresholds, (b) validation method, (c) at least one test ID linking to tests/
  • AC-03: Position accuracy AC (50m@80%, 20m@50%, anchor age tracking, drift bounds) bound to tests/integration/accuracy/ and tests/e2e/
  • AC-04: Failure-mode AC (visual blackout, spoofing promotion, dead reckoning, ≥3 disconnected segments) bound to tests/blackbox/failure_modes/
  • AC-05: Real-time performance AC (<400ms p95 e2e, <8GB RAM, ≥5Hz GPS_INPUT output) bound to a benchmark harness producing CI-tracked metrics
  • AC-06: Traceability matrix .planning/AC-TRACEABILITY.md generated linking every AC ID → test ID(s) → implementing component(s)

SAFE — Safety anchor state machine

  • SAFE-01: components/safety_state/SafetyAnchorStateMachine owns authoritative source_label ∈ {satellite_anchored, vo_extrapolated, dead_reckoned} for every emitted PositionEstimate
  • SAFE-02: Covariance growth is monotonic in non-anchored modes; resets only on accepted satellite anchor
  • SAFE-03: anchor_age_ms recorded on every estimate; transitions to vo_extrapolated after configurable max-age threshold
  • SAFE-04: State machine receives anchor decisions from AnchorVerifier, never raw VPR top-K — bad candidates cannot poison the state
  • SAFE-05: Tile write eligibility flag exposed (can_persist_tile: bool) — false in dead_reckoned mode to prevent corrupt tile cache writes
  • SAFE-06: Unit tests cover all 9 state transitions; property-based test asserts covariance never decreases without an accepted anchor

VERIFY — Geometry-gated anchor verification

  • VERIFY-01: components/anchor_verifier/GeometryGatedAnchorVerifier accepts/rejects satellite candidate matches based on configurable gates: min inliers, max mean reprojection error (px), max homography condition number
  • VERIFY-02: Rejection reason string emitted on every reject ("too_few_inliers", "mre_above_threshold", "degenerate_homography", "freshness_expired")
  • VERIFY-03: Freshness check integrates with sector classification (active-conflict <6mo, stable-rear <12mo) — expired tiles produce freshness_expired reject
  • VERIFY-04: Verifier benchmark mode evaluates multiple matcher profiles on the same frame for offline comparison
  • VERIFY-05: Unit tests cover each gate independently; integration test with real Azaion frame verifies end-to-end accept/reject

FDR — Flight data recorder

  • FDR-01: components/flight_recorder/FlightRecorder Protocol with append_event(event) and export() -> FdrExportResult
  • FDR-02: InMemoryFlightRecorder impl with bounded segments and configurable segment+storage byte limits
  • FDR-03: DiskFlightRecorder impl writing append-only JSONL segments under data/fdr/{flight_id}/segment-NNNN.jsonl
  • FDR-04: Health states ok / degraded (≥90% storage) / critical (limit reached) exposed via health property
  • FDR-05: Pipeline emits FDR events at every state transition, anchor decision, MAVLink send, and pipeline error
  • FDR-06: AC-NEW-3 forensic-thumbnail rate (≤0.1Hz on tile-generation failures) wired through FDR with size budget enforcement

VPR — Conditional + multi-scale visual place recognition

  • VPR-01: VPR retrieval triggered conditionally — DINOv2 forward runs only on re-loc triggers (cold start, sharp turn AC-3.2, σ_xy > 50m, VO failure ≥2 frames, disconnected segment AC-3.3); steady-state uses geometric prior (IMU+VO predicted position) ranking by distance
  • VPR-02: VPR chunks decoupled from storage tiles — chunks sized to ground footprint (600-800m at deployment altitude band) with 40-50% overlap; any frame footprint falls fully inside ≥1 chunk
  • VPR-03: Multi-scale FAISS index — fine-scale (z=20-derived) + coarse-scale (z=17 or z=18) descriptor sets; coarse used in active-conflict sectors for change-robust retrieval
  • VPR-04: Dynamic top-K — K=5 in stable sectors with σ_xy ≤ 20m, K=20 in active-conflict, K=50 on expanding-window fallback
  • VPR-05: Chunking and indexing integrated into existing chunk_manager.py/gpr.py without breaking stage1 GPR API contracts
  • MAVOUT-01: Every emitted GPS_INPUT includes source_label, anchor_age_ms, covariance_semimajor_m propagated from PositionEstimate (mapped into horiz_accuracy and a custom STATUSTEXT for label/age)
  • MAVOUT-02: ODOMETRY emitter scaffolded behind feature flag (config.mavlink.odometry_enabled); flag is false in stage 2; integration test asserts ODOMETRY is intentionally absent on the wire
  • MAVOUT-03: Spoofing-promotion latency monitor — listens to GPS_RAW_INT/EKF_STATUS_REPORT/SYS_STATUS; promotes own estimate to FC primary within <3s when real-GPS health rolling avg < threshold; emits STATUSTEXT on every promotion/demotion
  • MAVOUT-04: Visual blackout handling — pipeline switches to dead_reckoned within ≤1 processed frame OR ≤400ms when camera produces no usable signal; emits VISUAL_BLACKOUT_IMU_ONLY STATUSTEXT @ 1-2Hz

FIXTURE — Real-flight integration fixture (Azaion 10.05.2026)

  • FIXTURE-01: tests/integration/azaion_flight/ integration test suite consuming Data/Azaion/10.05.2026/ (tlog + cropped EO video + MAVLink CSV)
  • FIXTURE-02: Preprocessing script scripts/prep_azaion_fixture.py producing — (a) HUD-stripped EO frames at 0.7 fps, (b) IMU/GPS/ATTITUDE CSV from tlog, (c) timestamp-aligned manifest
  • FIXTURE-03: MAVLink replay test — feed tlog through MAVLinkBridge parser, assert all GLOBAL_POSITION_INT/RAW_IMU/ATTITUDE messages decoded without error
  • FIXTURE-04: ESKF real-IMU smoke test — replay IMU samples through ESKFCore.predict, assert no NaN/Inf, bounded covariance growth
  • FIXTURE-05: VO smoke test on cropped EO frames using ORB-SLAM3 backend — assert ≥30% frame registration success
  • FIXTURE-06: GPS-denial simulation — mask GPS_RAW_INT for t∈[180s, 280s], replay rest of stream, assert pipeline switches to vo_extrapolated and back to satellite_anchored correctly
  • FIXTURE-07: Azaion fixture documented in _docs/00_problem/fixtures.md with ground-truth references and known limitations (low altitude, multirotor dynamics, HUD overlay)

TEST — Test taxonomy & infrastructure

  • TEST-01: tests/ reorganized to tests/{unit,integration,blackbox,sitl,e2e}/; existing tests redistributed by category
  • TEST-02: pyproject.toml test markers updated — pytest -m unit / -m integration / etc.; CI runs unit+integration on every push, blackbox on PR, sitl+e2e nightly
  • TEST-03: AC traceability auto-generated — pytest plugin tags each test with @pytest.mark.ac("AC-1.1"); scripts/gen_ac_traceability.py produces the matrix in .planning/AC-TRACEABILITY.md

OBS — Observability & tooling

  • OBS-01: Structured JSON logging via structlog with correlation_id (frame_id) propagated through pipeline; Pydantic logging schemas at boundaries
  • OBS-02: CLI tool gps_denied (typer-based) with subcommands — replay --tlog ... --video ..., benchmark --scenario ..., bench-ac AC-1.1 for AC-driven benchmark runs
  • OBS-03: Per-environment Docker images split — Dockerfile.x86_dev for CI/dev, Dockerfile.jetson (multi-stage with TRT engine prebuild step) for hardware

Stage 3 candidates (parking lot)

  • Mid-flight tile generation + write-back to Azaion Satellite Service (AC-8.4)
  • On-device hardware validation on Jetson Orin Nano Super
  • Dual-channel MAVLink ODOMETRY enabled (depends on ArduPilot fixes for EKF3 source switching)
  • AC-NEW-1 cold-boot time-to-first-fix bench (<30s, 50× cold reboot)
  • BASALT VIO backend evaluation (only if cuVSLAM hits a blocker)

Out of Scope (Stage 2)

  • Migration to PostgreSQL (SQLite remains embedded default; Postgres optional for ground station only)
  • Folder-per-component layout for core/ math files (ESKF/factor graph stay concentrated)
  • Real microservices with separate processes / IPC
  • Pydantic on per-frame hot path (dataclasses replace it)
  • Mobile/web ground station UI
  • Multi-UAV coordination

Traceability

Populated by roadmapper on 2026-05-10. Test IDs will be filled in by /gsd:plan-phase and /gsd:implement as each phase produces concrete tests.

REQ Phase Tests
ARCH-01 Phase 1 pending plan-phase
ARCH-02 Phase 1 pending plan-phase
ARCH-03 Phase 1 pending plan-phase
ARCH-04 Phase 1 pending plan-phase
ARCH-05 Phase 1 pending plan-phase
ARCH-06 Phase 1 pending plan-phase
ARCH-07 Phase 1 pending plan-phase
AC-01 Phase 2 pending plan-phase
AC-02 Phase 2 pending plan-phase
AC-03 Phase 2 pending plan-phase
AC-04 Phase 2 pending plan-phase
AC-05 Phase 2 pending plan-phase
AC-06 Phase 2 pending plan-phase
TEST-01 Phase 2 pending plan-phase
TEST-02 Phase 2 pending plan-phase
TEST-03 Phase 2 pending plan-phase
OBS-01 Phase 2 pending plan-phase
SAFE-01 Phase 3 pending plan-phase
SAFE-02 Phase 3 pending plan-phase
SAFE-03 Phase 3 pending plan-phase
SAFE-04 Phase 3 pending plan-phase
SAFE-05 Phase 3 pending plan-phase
SAFE-06 Phase 3 pending plan-phase
VERIFY-01 Phase 3 pending plan-phase
VERIFY-02 Phase 3 pending plan-phase
VERIFY-03 Phase 3 pending plan-phase
VERIFY-04 Phase 3 pending plan-phase
VERIFY-05 Phase 3 pending plan-phase
VPR-01 Phase 4 pending plan-phase
VPR-02 Phase 4 pending plan-phase
VPR-03 Phase 4 pending plan-phase
VPR-04 Phase 4 pending plan-phase
VPR-05 Phase 4 pending plan-phase
FDR-01 Phase 4 pending plan-phase
FDR-02 Phase 4 pending plan-phase
FDR-03 Phase 4 pending plan-phase
FDR-04 Phase 4 pending plan-phase
FDR-05 Phase 4 pending plan-phase
FDR-06 Phase 4 pending plan-phase
MAVOUT-01 Phase 5 pending plan-phase
MAVOUT-02 Phase 5 pending plan-phase
MAVOUT-03 Phase 5 pending plan-phase
MAVOUT-04 Phase 5 pending plan-phase
FIXTURE-01 Phase 6 pending plan-phase
FIXTURE-02 Phase 6 pending plan-phase
FIXTURE-03 Phase 6 pending plan-phase
FIXTURE-04 Phase 6 pending plan-phase
FIXTURE-05 Phase 6 pending plan-phase
FIXTURE-06 Phase 6 pending plan-phase
FIXTURE-07 Phase 6 pending plan-phase
OBS-02 Phase 6 pending plan-phase
OBS-03 Phase 6 pending plan-phase

Coverage: 52/52 requirements mapped. No orphans, no duplicates.