mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 05:51:13 +00:00
[AZ-219] Scaffold onboard runtime project
Add the initial source, test, infrastructure, CI, configuration, and evidence-path scaffold so dependent implementation tasks have stable package and runtime boundaries. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
.git
|
||||
.github
|
||||
.cursor
|
||||
_docs
|
||||
.venv
|
||||
__pycache__
|
||||
.pytest_cache
|
||||
.ruff_cache
|
||||
.mypy_cache
|
||||
.env
|
||||
.env.*
|
||||
*.pem
|
||||
*.key
|
||||
*.secret
|
||||
data/input/*
|
||||
data/cache/*
|
||||
data/fdr/*
|
||||
data/test-results/*
|
||||
*.tlog
|
||||
*.ulg
|
||||
*.bag
|
||||
*.mcap
|
||||
*.cbor
|
||||
*.parquet
|
||||
*.mp4
|
||||
*.mov
|
||||
*.avi
|
||||
@@ -0,0 +1,10 @@
|
||||
GPSD_ENV=development
|
||||
GPSD_CONFIG_DIR=./config/development
|
||||
GPSD_CACHE_DIR=./data/cache
|
||||
GPSD_FDR_DIR=./data/fdr
|
||||
GPSD_DATABASE_URL=postgresql://gpsd:gpsd@localhost:5432/gpsd
|
||||
GPSD_MAVLINK_URL=udp:127.0.0.1:14550
|
||||
GPSD_CAMERA_SOURCE=./data/input
|
||||
GPSD_SIGNING_KEY_REF=test-key-ref
|
||||
GPSD_MAX_FDR_BYTES=104857600
|
||||
GPSD_LOG_LEVEL=info
|
||||
@@ -0,0 +1,43 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
python-quality:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -e ".[dev]"
|
||||
- name: Format check
|
||||
run: python -m black --check src tests
|
||||
- name: Lint
|
||||
run: python -m ruff check src tests
|
||||
- name: Unit tests
|
||||
run: python -m pytest tests/unit
|
||||
|
||||
replay-compose-smoke:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Validate compose files
|
||||
run: |
|
||||
docker compose -f docker-compose.yml config
|
||||
docker compose -f docker-compose.test.yml config
|
||||
- name: Collect artifact placeholders
|
||||
run: mkdir -p data/test-results e2e/reports
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: replay-evidence-placeholders
|
||||
path: |
|
||||
data/test-results
|
||||
e2e/reports
|
||||
+41
@@ -1 +1,42 @@
|
||||
.DS_Store
|
||||
.venv/
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
.pytest_cache/
|
||||
.ruff_cache/
|
||||
.mypy_cache/
|
||||
.coverage
|
||||
htmlcov/
|
||||
*.egg-info/
|
||||
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
*.pem
|
||||
*.key
|
||||
*.secret
|
||||
|
||||
data/input/*
|
||||
data/cache/*
|
||||
data/fdr/*
|
||||
data/test-results/*
|
||||
data/expected/*
|
||||
!data/input/.gitkeep
|
||||
!data/cache/.gitkeep
|
||||
!data/fdr/.gitkeep
|
||||
!data/test-results/.gitkeep
|
||||
!data/expected/.gitkeep
|
||||
|
||||
*.tlog
|
||||
*.ulg
|
||||
*.bag
|
||||
*.mcap
|
||||
*.cbor
|
||||
*.parquet
|
||||
*.mp4
|
||||
*.mov
|
||||
*.avi
|
||||
*.jpg
|
||||
*.jpeg
|
||||
*.png
|
||||
!_docs/00_problem/input_data/**
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# GPS-Denied Onboard Runtime
|
||||
|
||||
Scaffold for the Jetson-hosted GPS-denied localization runtime, replay harness, and
|
||||
deployment evidence paths.
|
||||
|
||||
The project uses a Python `src/` layout for orchestration code, with native bridge
|
||||
directories reserved for BASALT, feature matching, and TensorRT integrations.
|
||||
Generated mission data, FDR payloads, cache payloads, and raw frame dumps are kept
|
||||
out of git unless they are explicitly curated test fixtures.
|
||||
|
||||
## Local Development
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -m pip install -e ".[dev]"
|
||||
python -m pytest
|
||||
```
|
||||
|
||||
Local replay infrastructure is described in `docker-compose.yml`; CI and black-box
|
||||
test infrastructure are described in `docker-compose.test.yml`.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Batch Report
|
||||
|
||||
**Batch**: 1
|
||||
**Tasks**: AZ-219_initial_structure
|
||||
**Date**: 2026-05-03
|
||||
|
||||
## Task Results
|
||||
|
||||
| Task | Status | Files Modified | Tests | AC Coverage | Issues |
|
||||
|------|--------|----------------|-------|-------------|--------|
|
||||
| AZ-219_initial_structure | Done | 98 files | Pass | 7/7 ACs covered | None |
|
||||
|
||||
## AC Test Coverage: All covered
|
||||
|
||||
| AC Ref | Coverage |
|
||||
|--------|----------|
|
||||
| AC-1 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies source, tests, migrations, deployment, configuration, data, CI, and compose scaffold paths. |
|
||||
| AC-2 | `test_runtime_component_public_modules_are_importable` and `test_shared_contract_locations_are_importable` verify public component and shared contract namespaces. |
|
||||
| AC-3 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies compose, env template, and migration paths; compose config validation passed. |
|
||||
| AC-4 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies `.github/workflows/ci.yml`; the workflow defines format, lint, unit test, compose config, and artifact placeholder jobs. |
|
||||
| AC-5 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies unit, integration, black-box, fixture, SITL, and e2e runner paths. |
|
||||
| AC-6 | `test_scaffold_paths_cover_runtime_test_and_evidence_layout` verifies deployment scripts and evidence report paths. |
|
||||
| AC-7 | `test_ignore_rules_exclude_runtime_payloads_and_secrets` verifies secrets, raw frames, cache/FDR payloads, and test result artifacts are ignored. |
|
||||
|
||||
## Code Review Verdict: PASS
|
||||
|
||||
Review report: `_docs/03_implementation/reviews/batch_01_review.md`
|
||||
|
||||
## Auto-Fix Attempts: 0
|
||||
|
||||
## Stuck Agents: None
|
||||
|
||||
## Verification
|
||||
|
||||
- `.venv/bin/python -m black --check src tests e2e/replay` passed.
|
||||
- `.venv/bin/python -m ruff check src tests e2e/replay` passed.
|
||||
- `.venv/bin/python -m pytest` passed: 5 tests.
|
||||
- `docker compose -f docker-compose.yml config` passed.
|
||||
- `docker compose -f docker-compose.test.yml config` passed.
|
||||
|
||||
## Next Batch: AZ-220_shared_runtime_contracts
|
||||
@@ -0,0 +1,29 @@
|
||||
# Code Review Report
|
||||
|
||||
**Batch**: AZ-219_initial_structure
|
||||
**Date**: 2026-05-03
|
||||
**Verdict**: PASS
|
||||
|
||||
## Findings
|
||||
|
||||
| # | Severity | Category | File:Line | Title |
|
||||
|---|----------|----------|-----------|-------|
|
||||
| - | - | - | - | No findings |
|
||||
|
||||
## Review Notes
|
||||
|
||||
- AC-1 is satisfied by the `src/`, `migrations/`, `tests/`, `e2e/`, `deployment/`, `config/`, and `data/` scaffold plus tracked placeholders.
|
||||
- AC-2 is satisfied by importable component and shared package namespaces under `src/`.
|
||||
- AC-3 is satisfied by `docker-compose.yml`, `docker-compose.test.yml`, `.env.example`, and the initial PostGIS migration.
|
||||
- AC-4 is satisfied by `.github/workflows/ci.yml` with format, lint, unit-test, compose-config, and artifact placeholder stages.
|
||||
- AC-5 is satisfied by pytest unit scaffold coverage and black-box/SITL/e2e fixture entry-point directories.
|
||||
- AC-6 is satisfied by deployment Dockerfiles, Jetson/deployment placeholders, `e2e/reports/`, and `deployment/scripts/collect_evidence.sh`.
|
||||
- AC-7 is satisfied by `.gitignore`, `.dockerignore`, and non-secret environment templates excluding generated runtime payloads and credentials.
|
||||
|
||||
## Verification
|
||||
|
||||
- `.venv/bin/python -m black --check src tests e2e/replay` passed.
|
||||
- `.venv/bin/python -m ruff check src tests e2e/replay` passed.
|
||||
- `.venv/bin/python -m pytest` passed: 5 tests.
|
||||
- `docker compose -f docker-compose.yml config` passed.
|
||||
- `docker compose -f docker-compose.test.yml config` passed.
|
||||
@@ -7,8 +7,8 @@ name: Implement
|
||||
status: in_progress
|
||||
tracker: jira
|
||||
sub_step:
|
||||
phase: 0
|
||||
name: awaiting-invocation
|
||||
detail: ""
|
||||
phase: 1
|
||||
name: batch-loop
|
||||
detail: "batch 1: AZ-219_initial_structure"
|
||||
retry_count: 0
|
||||
cycle: 1
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
GPSD_ENV=ci
|
||||
GPSD_LOG_LEVEL=info
|
||||
GPSD_CONFIG_DIR=./config/ci
|
||||
GPSD_CACHE_DIR=./data/cache
|
||||
GPSD_FDR_DIR=./data/fdr
|
||||
GPSD_CAMERA_SOURCE=./tests/fixtures
|
||||
@@ -0,0 +1,6 @@
|
||||
GPSD_ENV=development
|
||||
GPSD_LOG_LEVEL=debug
|
||||
GPSD_CONFIG_DIR=./config/development
|
||||
GPSD_CACHE_DIR=./data/cache
|
||||
GPSD_FDR_DIR=./data/fdr
|
||||
GPSD_CAMERA_SOURCE=./data/input
|
||||
@@ -0,0 +1,6 @@
|
||||
GPSD_ENV=jetson
|
||||
GPSD_LOG_LEVEL=info
|
||||
GPSD_CONFIG_DIR=/etc/gps-denied-onboard
|
||||
GPSD_CACHE_DIR=/var/lib/gps-denied/cache
|
||||
GPSD_FDR_DIR=/var/lib/gps-denied/fdr
|
||||
GPSD_CAMERA_SOURCE=hardware
|
||||
@@ -0,0 +1,10 @@
|
||||
GPSD_ENV=production
|
||||
GPSD_LOG_LEVEL=info
|
||||
GPSD_CONFIG_DIR=/etc/gps-denied-onboard
|
||||
GPSD_CACHE_DIR=/var/lib/gps-denied/cache
|
||||
GPSD_FDR_DIR=/var/lib/gps-denied/fdr
|
||||
GPSD_DATABASE_URL=postgresql://user:password@localhost:5432/gpsd
|
||||
GPSD_MAVLINK_URL=serial:/dev/ttyTHS1:921600
|
||||
GPSD_CAMERA_SOURCE=hardware
|
||||
GPSD_SIGNING_KEY_REF=replace-with-secret-manager-reference
|
||||
GPSD_MAX_FDR_BYTES=68719476736
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
# Compose Configuration
|
||||
|
||||
Runtime compose files live at the repository root so local and CI commands can
|
||||
use Docker defaults without extra path arguments.
|
||||
@@ -0,0 +1,19 @@
|
||||
FROM python:3.12-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN groupadd --system gpsd && useradd --system --gid gpsd --home-dir /app gpsd
|
||||
|
||||
COPY pyproject.toml README.md ./
|
||||
COPY src ./src
|
||||
COPY tests ./tests
|
||||
|
||||
RUN python -m pip install --no-cache-dir --upgrade pip \
|
||||
&& python -m pip install --no-cache-dir ".[dev]"
|
||||
|
||||
USER gpsd
|
||||
|
||||
CMD ["python", "-m", "pytest"]
|
||||
@@ -0,0 +1,18 @@
|
||||
FROM python:3.12-slim-bookworm
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN groupadd --system gpsd && useradd --system --gid gpsd --home-dir /app gpsd
|
||||
|
||||
COPY pyproject.toml README.md ./
|
||||
COPY src ./src
|
||||
|
||||
RUN python -m pip install --no-cache-dir --upgrade pip \
|
||||
&& python -m pip install --no-cache-dir .
|
||||
|
||||
USER gpsd
|
||||
|
||||
CMD ["python", "-c", "import shared.contracts; print('gps-denied runtime scaffold ready')"]
|
||||
@@ -0,0 +1,4 @@
|
||||
# Jetson Deployment Notes
|
||||
|
||||
Reserved for Jetson provisioning, thermal/resource evidence, and hardware-runner
|
||||
qualification procedures.
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
mkdir -p e2e/reports data/test-results
|
||||
printf 'Evidence collection placeholder. Wire runtime reports in deploy phase.\n'
|
||||
@@ -0,0 +1,27 @@
|
||||
services:
|
||||
postgis:
|
||||
image: postgis/postgis:16-3.4
|
||||
environment:
|
||||
POSTGRES_DB: gpsd_test
|
||||
POSTGRES_USER: gpsd
|
||||
POSTGRES_PASSWORD: gpsd
|
||||
volumes:
|
||||
- ./migrations/postgresql:/docker-entrypoint-initdb.d:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U gpsd -d gpsd_test"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
replay-tests:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: deployment/docker/Dockerfile.replay
|
||||
env_file:
|
||||
- config/ci/runtime.env
|
||||
depends_on:
|
||||
postgis:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./tests/fixtures:/app/tests/fixtures:ro
|
||||
- ./data/test-results:/app/data/test-results
|
||||
@@ -0,0 +1,34 @@
|
||||
services:
|
||||
postgis:
|
||||
image: postgis/postgis:16-3.4
|
||||
environment:
|
||||
POSTGRES_DB: gpsd
|
||||
POSTGRES_USER: gpsd
|
||||
POSTGRES_PASSWORD: gpsd
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgis-data:/var/lib/postgresql/data
|
||||
- ./migrations/postgresql:/docker-entrypoint-initdb.d:ro
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U gpsd -d gpsd"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
runtime:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: deployment/docker/Dockerfile.runtime
|
||||
env_file:
|
||||
- .env.example
|
||||
depends_on:
|
||||
postgis:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ./data/cache:/app/data/cache
|
||||
- ./data/fdr:/app/data/fdr
|
||||
- ./data/input:/app/data/input:ro
|
||||
|
||||
volumes:
|
||||
postgis-data:
|
||||
@@ -0,0 +1,4 @@
|
||||
# Replay Harness
|
||||
|
||||
Reserved for suite-level replay entry points that drive the runtime only through
|
||||
public files, MAVLink/cache/FDR interfaces, and published reports.
|
||||
@@ -0,0 +1,14 @@
|
||||
"""Replay runner entry point."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
report_path = Path("e2e/reports/replay_smoke.txt")
|
||||
report_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
report_path.write_text("replay scaffold ready\n", encoding="utf-8")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
CREATE EXTENSION IF NOT EXISTS postgis;
|
||||
@@ -0,0 +1,4 @@
|
||||
# Seed Data
|
||||
|
||||
Place deterministic development and CI seed data here. Do not add production
|
||||
mission payloads, signing material, or raw frame dumps.
|
||||
@@ -0,0 +1,32 @@
|
||||
[build-system]
|
||||
requires = ["setuptools>=69", "wheel"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "gps-denied-onboard"
|
||||
version = "0.1.0"
|
||||
description = "Jetson-hosted GPS-denied localization runtime scaffold."
|
||||
requires-python = ">=3.10"
|
||||
dependencies = []
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"black>=24.0",
|
||||
"pytest>=8.0",
|
||||
"ruff>=0.5",
|
||||
]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
pythonpath = ["src"]
|
||||
testpaths = ["tests"]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
src = ["src", "tests"]
|
||||
|
||||
[tool.black]
|
||||
line-length = 100
|
||||
target-version = ["py310"]
|
||||
@@ -0,0 +1 @@
|
||||
"""Source-root package marker for editable installs."""
|
||||
@@ -0,0 +1 @@
|
||||
"""Anchor verification component."""
|
||||
@@ -0,0 +1,10 @@
|
||||
"""Public anchor verification interfaces."""
|
||||
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
class AnchorVerifier(Protocol):
|
||||
"""Verifies retrieved candidates against camera observations."""
|
||||
|
||||
def verify(self, frame: Any, candidate: Any) -> Any:
|
||||
"""Return an anchor decision for one candidate."""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Public anchor verification type aliases."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
AnchorDecisionLike = Any
|
||||
@@ -0,0 +1 @@
|
||||
"""BASALT VIO adapter component."""
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Public BASALT VIO adapter interfaces."""
|
||||
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
class VioAdapter(Protocol):
|
||||
"""Processes frame and telemetry inputs into relative VIO state."""
|
||||
|
||||
def initialize(self) -> None:
|
||||
"""Initialize adapter resources."""
|
||||
|
||||
def process(self, frame: Any, telemetry: Any) -> Any:
|
||||
"""Process one synchronized frame/telemetry pair."""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Public BASALT VIO type aliases."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
VioStatePacketLike = Any
|
||||
@@ -0,0 +1 @@
|
||||
"""Camera ingest and calibration component."""
|
||||
@@ -0,0 +1,10 @@
|
||||
"""Public camera ingest interfaces."""
|
||||
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
class FrameProvider(Protocol):
|
||||
"""Source of navigation frames for downstream localization components."""
|
||||
|
||||
def next_frame(self) -> Any:
|
||||
"""Return the next frame packet."""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Public camera ingest type aliases."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
FramePacketLike = Any
|
||||
@@ -0,0 +1 @@
|
||||
"""Flight data recorder and observability component."""
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Public flight recorder interfaces."""
|
||||
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
class FlightRecorder(Protocol):
|
||||
"""Append-only event recorder for runtime evidence."""
|
||||
|
||||
def append_event(self, event: Any) -> None:
|
||||
"""Persist one FDR event."""
|
||||
|
||||
def export(self) -> Any:
|
||||
"""Export recorded evidence for post-flight analysis."""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Public FDR type aliases."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
FdrEventLike = Any
|
||||
@@ -0,0 +1 @@
|
||||
"""MAVLink and GCS integration component."""
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Public MAVLink gateway interfaces."""
|
||||
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
class MavlinkGateway(Protocol):
|
||||
"""Bridges FC telemetry inputs and localization GPS_INPUT outputs."""
|
||||
|
||||
def subscribe_telemetry(self) -> Any:
|
||||
"""Subscribe to flight-controller telemetry."""
|
||||
|
||||
def emit_gps_input(self, estimate: Any) -> None:
|
||||
"""Emit one localization estimate to the flight controller."""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Public MAVLink/GCS type aliases."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
TelemetrySampleLike = Any
|
||||
@@ -0,0 +1,3 @@
|
||||
# BASALT Bridge
|
||||
|
||||
Reserved for native BASALT integration code wrapped by `basalt_vio_adapter`.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Feature Matching Bridge
|
||||
|
||||
Reserved for native feature extraction, matching, and RANSAC acceleration code.
|
||||
@@ -0,0 +1,3 @@
|
||||
# TensorRT Bridge
|
||||
|
||||
Reserved for Jetson/TensorRT descriptor inference integrations.
|
||||
@@ -0,0 +1 @@
|
||||
"""Safety and anchor wrapper component."""
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Public localization state-machine interfaces."""
|
||||
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
class LocalizationStateMachine(Protocol):
|
||||
"""Coordinates VIO propagation and anchor promotion decisions."""
|
||||
|
||||
def update_vio(self, vio_state: Any) -> Any:
|
||||
"""Update the state machine with a VIO state packet."""
|
||||
|
||||
def consider_anchor(self, anchor_decision: Any) -> Any:
|
||||
"""Evaluate a verified anchor decision."""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Public safety wrapper type aliases."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
PositionEstimateLike = Any
|
||||
@@ -0,0 +1 @@
|
||||
"""Offline satellite retrieval and synchronization component."""
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Public satellite service interfaces."""
|
||||
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
class SatelliteService(Protocol):
|
||||
"""Retrieves offline VPR candidates from mission cache data."""
|
||||
|
||||
def load_index(self) -> None:
|
||||
"""Load the local descriptor index."""
|
||||
|
||||
def retrieve(self, frame: Any) -> list[Any]:
|
||||
"""Return candidate anchor records for one frame."""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Public satellite service type aliases."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
VprCandidateLike = Any
|
||||
@@ -0,0 +1 @@
|
||||
"""Shared runtime foundation packages."""
|
||||
@@ -0,0 +1 @@
|
||||
"""Runtime configuration helper namespace."""
|
||||
@@ -0,0 +1,3 @@
|
||||
"""Shared DTO and interface contract namespace."""
|
||||
|
||||
CONTRACT_VERSION = "0.1.0"
|
||||
@@ -0,0 +1 @@
|
||||
"""Shared error envelope namespace."""
|
||||
@@ -0,0 +1 @@
|
||||
"""Geospatial geometry helper namespace."""
|
||||
@@ -0,0 +1 @@
|
||||
"""Structured telemetry and health metadata namespace."""
|
||||
@@ -0,0 +1 @@
|
||||
"""Clock-domain and timestamp helper namespace."""
|
||||
@@ -0,0 +1 @@
|
||||
"""Tile cache and generated tile lifecycle component."""
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Public tile manager interfaces."""
|
||||
|
||||
from typing import Any, Protocol
|
||||
|
||||
|
||||
class TileManager(Protocol):
|
||||
"""Validates and serves local cache tile records."""
|
||||
|
||||
def validate_cache(self) -> None:
|
||||
"""Validate local cache metadata and signatures."""
|
||||
|
||||
def get_tile_window(self, footprint: Any) -> list[Any]:
|
||||
"""Return tiles intersecting a requested footprint."""
|
||||
@@ -0,0 +1,5 @@
|
||||
"""Public tile manager type aliases."""
|
||||
|
||||
from typing import Any
|
||||
|
||||
CacheTileRecordLike = Any
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
"""Black-box runner entry point.
|
||||
|
||||
Future scenarios should call only public runtime inputs and outputs: replay frames,
|
||||
telemetry, offline cache, MAVLink output, status events, and FDR artifacts.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
reports_dir = Path("data/test-results")
|
||||
reports_dir.mkdir(parents=True, exist_ok=True)
|
||||
(reports_dir / "blackbox_smoke.txt").write_text("blackbox scaffold ready\n", encoding="utf-8")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
from importlib import import_module
|
||||
from pathlib import Path
|
||||
|
||||
COMPONENT_PACKAGES = [
|
||||
"camera_ingest_calibration",
|
||||
"basalt_vio_adapter",
|
||||
"safety_anchor_wrapper",
|
||||
"satellite_service",
|
||||
"anchor_verification",
|
||||
"tile_manager",
|
||||
"mavlink_gcs_integration",
|
||||
"fdr_observability",
|
||||
]
|
||||
|
||||
SHARED_PACKAGES = [
|
||||
"shared.contracts",
|
||||
"shared.geo_geometry",
|
||||
"shared.time_sync",
|
||||
"shared.config",
|
||||
"shared.errors",
|
||||
"shared.telemetry",
|
||||
]
|
||||
|
||||
REQUIRED_PATHS = [
|
||||
"src",
|
||||
"migrations/postgresql/0001_enable_postgis.sql",
|
||||
"migrations/seed/README.md",
|
||||
"tests/unit/test_scaffold.py",
|
||||
"tests/unit/shared/.gitkeep",
|
||||
"tests/unit/camera_ingest_calibration/.gitkeep",
|
||||
"tests/unit/basalt_vio_adapter/.gitkeep",
|
||||
"tests/unit/safety_anchor_wrapper/.gitkeep",
|
||||
"tests/unit/satellite_service/.gitkeep",
|
||||
"tests/unit/anchor_verification/.gitkeep",
|
||||
"tests/unit/tile_manager/.gitkeep",
|
||||
"tests/unit/mavlink_gcs_integration/.gitkeep",
|
||||
"tests/unit/fdr_observability/.gitkeep",
|
||||
"tests/integration/contracts/.gitkeep",
|
||||
"tests/blackbox/still_image_geolocation/.gitkeep",
|
||||
"tests/fixtures/project_60_images/.gitkeep",
|
||||
"tests/sitl/plane_gps_input/.gitkeep",
|
||||
"tests/e2e/replay/.gitkeep",
|
||||
"e2e/replay/run_replay.py",
|
||||
"e2e/reports/.gitkeep",
|
||||
"deployment/docker/Dockerfile.runtime",
|
||||
"deployment/docker/Dockerfile.replay",
|
||||
"deployment/scripts/collect_evidence.sh",
|
||||
"config/development/runtime.env",
|
||||
"config/ci/runtime.env",
|
||||
"config/jetson/runtime.env",
|
||||
"config/production/runtime.env.example",
|
||||
"docker-compose.yml",
|
||||
"docker-compose.test.yml",
|
||||
".github/workflows/ci.yml",
|
||||
".env.example",
|
||||
".dockerignore",
|
||||
]
|
||||
|
||||
|
||||
def test_runtime_component_public_modules_are_importable() -> None:
|
||||
# Act
|
||||
imported_modules = [
|
||||
import_module(module_name)
|
||||
for package_name in COMPONENT_PACKAGES
|
||||
for module_name in (package_name, f"{package_name}.interfaces", f"{package_name}.types")
|
||||
]
|
||||
|
||||
# Assert
|
||||
assert len(imported_modules) == len(COMPONENT_PACKAGES) * 3
|
||||
|
||||
|
||||
def test_shared_contract_locations_are_importable() -> None:
|
||||
# Act
|
||||
imported_modules = [import_module(package_name) for package_name in SHARED_PACKAGES]
|
||||
|
||||
# Assert
|
||||
assert len(imported_modules) == len(SHARED_PACKAGES)
|
||||
|
||||
|
||||
def test_generated_runtime_data_paths_are_gitkeep_only() -> None:
|
||||
# Arrange
|
||||
data_dirs = ["input", "expected", "cache", "fdr", "test-results"]
|
||||
|
||||
# Act
|
||||
missing = [
|
||||
directory for directory in data_dirs if not Path("data", directory, ".gitkeep").is_file()
|
||||
]
|
||||
|
||||
# Assert
|
||||
assert missing == []
|
||||
|
||||
|
||||
def test_scaffold_paths_cover_runtime_test_and_evidence_layout() -> None:
|
||||
# Act
|
||||
missing = [path for path in REQUIRED_PATHS if not Path(path).exists()]
|
||||
|
||||
# Assert
|
||||
assert missing == []
|
||||
|
||||
|
||||
def test_ignore_rules_exclude_runtime_payloads_and_secrets() -> None:
|
||||
# Arrange
|
||||
required_patterns = [
|
||||
".env",
|
||||
"*.pem",
|
||||
"*.key",
|
||||
"data/input/*",
|
||||
"data/cache/*",
|
||||
"data/fdr/*",
|
||||
"data/test-results/*",
|
||||
"*.tlog",
|
||||
"*.cbor",
|
||||
"*.mp4",
|
||||
]
|
||||
|
||||
# Act
|
||||
gitignore = Path(".gitignore").read_text(encoding="utf-8")
|
||||
dockerignore = Path(".dockerignore").read_text(encoding="utf-8")
|
||||
missing_from_gitignore = [pattern for pattern in required_patterns if pattern not in gitignore]
|
||||
missing_from_dockerignore = [
|
||||
pattern for pattern in required_patterns if pattern not in dockerignore
|
||||
]
|
||||
|
||||
# Assert
|
||||
assert missing_from_gitignore == []
|
||||
assert missing_from_dockerignore == []
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user