[AZ-263] Bootstrap: repo skeleton + Docker + CI + Alembic + Tier-1 tests

Implements the AZ-263 / E-BOOT initial structure task:

- Python src/-layout package `gps_denied_onboard/` with per-component
  interface stubs (14 components), type-only DTOs under `_types/`,
  shared helpers under `helpers/` (R14 LightGlue ownership), structured
  JSON logging, runtime composition root with env-var fail-fast gate,
  healthcheck module shared by Docker and CI smoke.
- CMake top-level + `cmake/{build_options,dependencies,strategies}.cmake`
  with the BUILD_* per-binary flags (ADR-002) and pinned external git
  refs for OKVIS2 / VINS-Mono / GTSAM / FAISS / OpenCV >=4.12.0.
- Three Dockerfiles (companion-tier1, operator-tooling,
  mock-suite-sat-service) + two compose files (dev + Tier-1 test).
- Four GitHub Actions workflows: ci.yml (lint/unit/integration/dual
  binary build/SBOM diff/security), ci-tier2.yml (self-hosted Jetson
  AC-bound NFTs), release.yml, cve-rescan.yml.
- Two CI gate scripts: `ci/sbom_diff.py` (deployment SBOM subset +
  R02 exclusion), `ci/opencv_pin_gate.py` (>=4.12.0 enforcement,
  D-CROSS-CVE-1).
- Alembic-driven Postgres 16 initial migration `0001_initial.py`
  mirroring satellite-provider tiles + flights + sector_classifications
  + manifests + engine_cache_entries (data_model.md s 2).
- Tier-1 test scaffolding: 95 passing unit tests covering every AC,
  per-component smoke tests, structured logging JSON output check,
  env-var gate check, healthcheck import check. Two CI-gated tests
  (cmake configure, actionlint) skip locally with explicit reasons.
- Batch report + code review report under `_docs/03_implementation/`.

Verdict: PASS_WITH_WARNINGS (two Low findings, both informational).
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-11 01:00:28 +03:00
parent 880eabcb3f
commit b12db61444
168 changed files with 3688 additions and 3 deletions
@@ -0,0 +1 @@
"""Component subpackage — one folder per interface-first component (ADR-009)."""
@@ -0,0 +1,6 @@
"""C10 Cache Provisioning component — Public API."""
from gps_denied_onboard._types.manifests import EngineCacheEntry, Manifest
from gps_denied_onboard.components.c10_provisioning.interface import CacheProvisioner
__all__ = ["CacheProvisioner", "EngineCacheEntry", "Manifest"]
@@ -0,0 +1,18 @@
"""C10 `CacheProvisioner` Protocol.
Concrete impl: engine compile + descriptors + manifest + content-hash gate. See
`_docs/02_document/components/11_c10_provisioning/`.
"""
from __future__ import annotations
from pathlib import Path
from typing import Protocol
from gps_denied_onboard._types.manifests import Manifest
class CacheProvisioner(Protocol):
"""Pre-flight cache provisioning (engine compile + descriptor batch + manifest)."""
def provision(self, flight_id: str, output_root: Path) -> Manifest: ...
@@ -0,0 +1,8 @@
"""C11 Tile Manager component — Public API."""
from gps_denied_onboard.components.c11_tile_manager.interface import (
TileDownloader,
TileUploader,
)
__all__ = ["TileDownloader", "TileUploader"]
@@ -0,0 +1,27 @@
"""C11 `TileDownloader` + `TileUploader` Protocols.
Operator-side ONLY — excluded from airborne via CMake (`BUILD_C11_TILE_MANAGER=OFF`).
See `_docs/02_document/components/12_c11_tilemanager/`.
"""
from __future__ import annotations
from collections.abc import Iterable
from pathlib import Path
from typing import Protocol
from gps_denied_onboard._types.tile import TileRecord
class TileDownloader(Protocol):
"""Pre-flight tile download from `satellite-provider`."""
def download(
self, lat_lon_box: tuple[float, float, float, float], zoom: int, output_root: Path
) -> Iterable[TileRecord]: ...
class TileUploader(Protocol):
"""Post-landing batch upload to the `satellite-provider` ingest endpoint (D-PROJ-2)."""
def upload(self, tiles: Iterable[TileRecord], flight_id: str) -> None: ...
@@ -0,0 +1,8 @@
"""C12 Operator Pre-flight Tooling component — Public API."""
from gps_denied_onboard.components.c12_operator_tooling.interface import (
CacheBuildWorkflow,
OperatorReLocService,
)
__all__ = ["CacheBuildWorkflow", "OperatorReLocService"]
@@ -0,0 +1,21 @@
"""C12 `CacheBuildWorkflow` + `OperatorReLocService` Protocols.
See `_docs/02_document/components/13_c12_operator_tooling/`.
"""
from __future__ import annotations
from pathlib import Path
from typing import Protocol
class CacheBuildWorkflow(Protocol):
"""Operator CLI workflow that orchestrates C11 download → C10 provisioning."""
def run(self, flight_id: str, output_root: Path) -> None: ...
class OperatorReLocService(Protocol):
"""Operator-side re-localization request service (GUI deferred per epic)."""
def request_relocalization(self, flight_id: str, hint: dict) -> None: ...
@@ -0,0 +1,5 @@
"""C13 FDR Writer component — Public API."""
from gps_denied_onboard.components.c13_fdr.interface import FdrWriter
__all__ = ["FdrWriter"]
@@ -0,0 +1,21 @@
"""C13 `FdrWriter` Protocol (consumer side).
Producer-side `FdrClient` lives in `gps_denied_onboard.fdr_client` (cross-cutting,
AZ-247); this consumer-side writer is owned by AZ-248 / E-C13.
"""
from __future__ import annotations
from typing import Protocol
from gps_denied_onboard.fdr_client.records import FdrRecord
class FdrWriter(Protocol):
"""FDR consumer: writer thread + segment rotation + ≤64 GB capacity cap."""
def start(self) -> None: ...
def stop(self) -> None: ...
def consume(self, record: FdrRecord) -> None: ...
@@ -0,0 +1,6 @@
"""C1 VIO component — Public API."""
from gps_denied_onboard._types.vio import VioOutput
from gps_denied_onboard.components.c1_vio.interface import VioStrategy
__all__ = ["VioOutput", "VioStrategy"]
@@ -0,0 +1,4 @@
"""pybind11 wrappers for `cpp/okvis2/`, `cpp/vins_mono/`, `cpp/klt_ransac/`.
Placeholders shipped by AZ-263; real wrappers land with the concrete strategies.
"""
@@ -0,0 +1,20 @@
"""C1 `VioStrategy` Protocol.
Concrete strategies: OKVIS2 (default), VINS-Mono (research-only), KLT/RANSAC
(mandatory simple baseline). See `_docs/02_document/components/01_c1_vio/`.
"""
from __future__ import annotations
from typing import Protocol
from gps_denied_onboard._types.nav import ImuWindow, NavCameraFrame
from gps_denied_onboard._types.vio import VioOutput
class VioStrategy(Protocol):
"""Visual-Inertial-Odometry strategy."""
def step(self, frame: NavCameraFrame, imu: ImuWindow) -> VioOutput:
"""Process a single nav-camera frame + IMU window and return a VIO update."""
...
@@ -0,0 +1,6 @@
"""C2.5 Rerank component — Public API."""
from gps_denied_onboard._types.vpr import RerankResult
from gps_denied_onboard.components.c2_5_rerank.interface import RerankStrategy
__all__ = ["RerankResult", "RerankStrategy"]
@@ -0,0 +1,17 @@
"""C2.5 `RerankStrategy` Protocol.
Default: `InlierBasedReranker` (single-pair LightGlue inlier counter, K=10 → N=3).
See `_docs/02_document/components/03_c2_5_rerank/`.
"""
from __future__ import annotations
from typing import Protocol
from gps_denied_onboard._types.vpr import RerankResult, VprResult
class RerankStrategy(Protocol):
"""Re-rank C2's top-K candidates down to N via cross-domain match scoring."""
def rerank(self, vpr_result: VprResult, n_keep: int = 3) -> RerankResult: ...
@@ -0,0 +1,6 @@
"""C2 VPR component — Public API."""
from gps_denied_onboard._types.vpr import VprQuery, VprResult
from gps_denied_onboard.components.c2_vpr.interface import VprStrategy
__all__ = ["VprQuery", "VprResult", "VprStrategy"]
@@ -0,0 +1 @@
"""Native bindings for VPR runtime — placeholder."""
@@ -0,0 +1,17 @@
"""C2 `VprStrategy` Protocol.
Concrete strategies: UltraVPR (primary), MegaLoc, MixVPR, SelaVPR, EigenPlaces,
NetVLAD, SALAD. See `_docs/02_document/components/02_c2_vpr/`.
"""
from __future__ import annotations
from typing import Protocol
from gps_denied_onboard._types.vpr import VprQuery, VprResult
class VprStrategy(Protocol):
"""Visual Place Recognition strategy: encode → retrieve top-K candidates."""
def retrieve(self, query: VprQuery, top_k: int = 10) -> VprResult: ...
@@ -0,0 +1,5 @@
"""C3.5 AdHoP Refinement component — Public API."""
from gps_denied_onboard.components.c3_5_adhop.interface import AdHoPRefinementStrategy
__all__ = ["AdHoPRefinementStrategy"]
@@ -0,0 +1,16 @@
"""C3.5 `AdHoPRefinementStrategy` Protocol.
Concrete impl: AdHoP refiner. See `_docs/02_document/components/05_c3_5_adhop/`.
"""
from __future__ import annotations
from typing import Protocol
from gps_denied_onboard._types.matching import MatchResult
class AdHoPRefinementStrategy(Protocol):
"""Conditional refinement of a `MatchResult` (geometric verification + outlier purge)."""
def refine(self, match: MatchResult) -> MatchResult: ...
@@ -0,0 +1,6 @@
"""C3 Cross-Domain Matcher component — Public API."""
from gps_denied_onboard._types.matching import MatchResult
from gps_denied_onboard.components.c3_matcher.interface import CrossDomainMatcher
__all__ = ["CrossDomainMatcher", "MatchResult"]
@@ -0,0 +1 @@
"""Native bindings for the cross-domain matcher runtime — placeholder."""
@@ -0,0 +1,19 @@
"""C3 `CrossDomainMatcher` Protocol.
Concrete impls: DISK+LightGlue (primary), ALIKED+LightGlue, XFeat. See
`_docs/02_document/components/04_c3_matcher/`.
"""
from __future__ import annotations
from typing import Protocol
from gps_denied_onboard._types.matching import MatchResult
from gps_denied_onboard._types.nav import NavCameraFrame
from gps_denied_onboard._types.tile import Tile
class CrossDomainMatcher(Protocol):
"""Match a nav-camera frame against a satellite tile."""
def match(self, frame: NavCameraFrame, tile: Tile) -> MatchResult: ...
@@ -0,0 +1,6 @@
"""C4 Pose Estimator component — Public API."""
from gps_denied_onboard._types.pose import EstimatorOutput, PoseEstimate
from gps_denied_onboard.components.c4_pose.interface import PoseEstimator
__all__ = ["EstimatorOutput", "PoseEstimate", "PoseEstimator"]
@@ -0,0 +1 @@
"""pybind11 wrapper for `cpp/gtsam_bindings/` (READ-ONLY consumer; primary owner is c5_state)."""
@@ -0,0 +1,18 @@
"""C4 `PoseEstimator` Protocol.
Concrete impl: OpenCV `solvePnPRansac` + GTSAM Marginals. See
`_docs/02_document/components/06_c4_pose/`.
"""
from __future__ import annotations
from typing import Protocol
from gps_denied_onboard._types.matching import MatchResult
from gps_denied_onboard._types.pose import PoseEstimate
class PoseEstimator(Protocol):
"""Estimate a 6-DoF pose from a verified cross-domain match."""
def estimate(self, match: MatchResult) -> PoseEstimate: ...
@@ -0,0 +1,6 @@
"""C5 State Estimator component — Public API."""
from gps_denied_onboard._types.pose import EstimatorHealth, EstimatorOutput
from gps_denied_onboard.components.c5_state.interface import StateEstimator
__all__ = ["EstimatorHealth", "EstimatorOutput", "StateEstimator"]
@@ -0,0 +1 @@
"""pybind11 wrapper for `cpp/gtsam_bindings/` (primary owner; also used READ-ONLY by c4_pose)."""
@@ -0,0 +1,23 @@
"""C5 `StateEstimator` Protocol.
Concrete impls: `GtsamIsam2StateEstimator` (production-default; iSAM2 +
IncrementalFixedLagSmoother), `EskfStateEstimator` (mandatory simple baseline).
See `_docs/02_document/components/07_c5_state/`.
"""
from __future__ import annotations
from typing import Protocol
from gps_denied_onboard._types.pose import EstimatorOutput, PoseEstimate
from gps_denied_onboard._types.vio import VioOutput
class StateEstimator(Protocol):
"""Smoothed state estimator (fuses VIO + satellite anchors + IMU)."""
def add_vio(self, vio: VioOutput) -> None: ...
def add_pose_anchor(self, anchor: PoseEstimate) -> None: ...
def latest_output(self) -> EstimatorOutput | None: ...
@@ -0,0 +1,21 @@
"""C6 Tile Cache & Vector Index component — Public API."""
from gps_denied_onboard._types.tile import (
SectorClassification,
Tile,
TileQualityMetadata,
TileRecord,
)
from gps_denied_onboard.components.c6_tile_cache.interface import (
DescriptorIndex,
TileStore,
)
__all__ = [
"DescriptorIndex",
"SectorClassification",
"Tile",
"TileQualityMetadata",
"TileRecord",
"TileStore",
]
@@ -0,0 +1 @@
"""pybind11 wrapper for `cpp/faiss_index/` — placeholder."""
@@ -0,0 +1,32 @@
"""C6 `TileStore` + `DescriptorIndex` Protocols.
Concrete impl: `PostgresFilesystemStore` (Postgres mirror + filesystem mmap +
FAISS HNSW). See `_docs/02_document/components/08_c6_tile_cache/`.
"""
from __future__ import annotations
from collections.abc import Iterable
from typing import Protocol
from gps_denied_onboard._types.tile import Tile, TileRecord
class TileStore(Protocol):
"""Tile metadata + body store (mirrors satellite-provider; cached locally)."""
def get(self, tile_id: str) -> Tile | None: ...
def query_by_lat_lon(
self, lat: float, lon: float, zoom: int, radius_m: float
) -> Iterable[TileRecord]: ...
def put(self, record: TileRecord) -> None: ...
class DescriptorIndex(Protocol):
"""Vector index over tile descriptors (FAISS HNSW concrete impl)."""
def add(self, tile_id: str, descriptor) -> None: ...
def search(self, descriptor, top_k: int) -> Iterable[tuple[str, float]]: ...
@@ -0,0 +1,6 @@
"""C7 Inference Runtime component — Public API."""
from gps_denied_onboard._types.manifests import EngineCacheEntry
from gps_denied_onboard.components.c7_inference.interface import InferenceRuntime
__all__ = ["EngineCacheEntry", "InferenceRuntime"]
@@ -0,0 +1,18 @@
"""C7 `InferenceRuntime` Protocol.
Concrete impls: `TensorrtRuntime` (production-default; TensorRT 10.3),
`OnnxTrtEpRuntime` (ONNX Runtime + TensorRT EP), `PytorchFp16Runtime` (research
baseline). See `_docs/02_document/components/09_c7_inference/`.
"""
from __future__ import annotations
from typing import Any, Protocol
class InferenceRuntime(Protocol):
"""Compiled-engine inference runtime."""
def infer(self, inputs: Any) -> Any: ...
def load(self, engine_path: str) -> None: ...
@@ -0,0 +1,10 @@
"""C8 FC + GCS Adapter component — Public API."""
from gps_denied_onboard._types.emitted import EmittedExternalPosition
from gps_denied_onboard.components.c8_fc_adapter.interface import (
FcAdapter,
GcsAdapter,
ReplaySink,
)
__all__ = ["EmittedExternalPosition", "FcAdapter", "GcsAdapter", "ReplaySink"]
@@ -0,0 +1,47 @@
"""C8 Adapter Protocols: `FcAdapter`, `GcsAdapter`, `ReplaySink`.
Concrete impls: `PymavlinkArdupilotAdapter`, `Msp2InavAdapter`,
`MavlinkGcsAdapter`, `TlogReplayFcAdapter`, `JsonlReplaySink`. See
`_docs/02_document/components/10_c8_fc_adapter/`.
"""
from __future__ import annotations
from collections.abc import Iterator
from typing import Protocol
from gps_denied_onboard._types.emitted import EmittedExternalPosition
from gps_denied_onboard._types.nav import (
AttitudeWindow,
FlightStateSignal,
GpsHealth,
ImuSample,
)
class FcAdapter(Protocol):
"""Bidirectional flight-controller adapter."""
def outbound(self, position: EmittedExternalPosition) -> None: ...
def inbound_imu(self) -> Iterator[ImuSample]: ...
def inbound_attitude(self) -> Iterator[AttitudeWindow]: ...
def inbound_gps_health(self) -> Iterator[GpsHealth]: ...
def inbound_flight_state(self) -> Iterator[FlightStateSignal]: ...
class GcsAdapter(Protocol):
"""Ground-control-station adapter (telemetry + operator commands)."""
def emit_summary(self, summary: dict) -> None: ...
def operator_commands(self) -> Iterator[dict]: ...
class ReplaySink(Protocol):
"""Replay-mode estimate sink (e.g. JSONL writer)."""
def write(self, estimate: dict) -> None: ...