mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 15:01:13 +00:00
91ce1c2047
AZ-326 (3pt): operator-tool Click CLI shell at src/gps_denied_onboard/components/c12_operator_tooling/cli.py with six subcommands (download, build-cache, upload-pending, reloc-confirm, verify-ready, set-sector); SectorClassificationStore (atomic-write JSON under ~/.azaion/onboard/sector-classifications.json); freshness-table lookup driving AC-NEW-6; EXIT_* constants; AZ-266 structured-JSON log wiring to a rotating ~/.azaion/onboard/c12-tooling.log handler; operator-tool console-script entry in pyproject.toml. AZ-327 (3pt): CompanionBringup orchestrator at src/gps_denied_onboard/components/c12_operator_tooling/companion_bringup.py that opens an SSH session against the companion (paramiko per project pin), checks the four pre-flight artifacts (Manifest, expected engines, sha256 sidecars, calibration), and returns a ReadinessReport per description.md S2; CompanionUnreachableError + ContentHashMismatchError with operator-friendly remediation hints; ParamikoSshSessionFactory + RemoteSidecarVerifier (sha256sum + cat over SSH, no bytes pulled to the workstation); paramiko>=3.4,<4.0 dep added. NFR-perf-cold-start fix: PEP 562 lazy __getattr__ in c12_operator_tooling/__init__.py and flights_api/__init__.py defers HttpxFlightsApiClient (httpx), ParamikoSshSession[Factory] (paramiko + cryptography), bbox_from_waypoints / takeoff_origin_from_flight (numpy + pyproj). cli.py imports from leaf flights_api modules. operator-tool --help cold start: ~870ms -> <200ms typical, <500ms p99. Includes 73 unit tests (incl. paramiko-version-drift smoke per AZ-327 Risk 1) + console-script integration test. All 1494 repo-wide unit tests pass; 80 skips are pre-existing environment gates. Batch report: _docs/03_implementation/batch_42_cycle1_report.md. Co-authored-by: Cursor <cursoragent@cursor.com>
44 lines
1.4 KiB
Python
44 lines
1.4 KiB
Python
"""AZ-326 AC-6 — `freshness_threshold_months` returns the documented values."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from gps_denied_onboard.components.c12_operator_tooling import (
|
|
FRESHNESS_TABLE,
|
|
SectorClassification,
|
|
freshness_threshold_months,
|
|
)
|
|
|
|
|
|
class TestFreshnessTable:
|
|
def test_active_conflict_is_one_month(self) -> None:
|
|
# Act / Assert
|
|
assert freshness_threshold_months(SectorClassification.ACTIVE_CONFLICT) == 1
|
|
|
|
def test_stable_rear_is_twelve_months(self) -> None:
|
|
# Act / Assert
|
|
assert freshness_threshold_months(SectorClassification.STABLE_REAR) == 12
|
|
|
|
def test_table_covers_every_enum_value(self) -> None:
|
|
# Arrange
|
|
enum_values = set(SectorClassification)
|
|
# Assert
|
|
assert set(FRESHNESS_TABLE.keys()) == enum_values
|
|
|
|
def test_unknown_classification_raises(self) -> None:
|
|
# Arrange — synthesise an unmapped value via a subclass to bypass the
|
|
# enum check in production code (no other path can produce one).
|
|
class _Bogus:
|
|
value = "bogus"
|
|
|
|
def __hash__(self) -> int:
|
|
return hash("bogus")
|
|
|
|
def __eq__(self, other: object) -> bool:
|
|
return False
|
|
|
|
# Act / Assert
|
|
with pytest.raises(ValueError, match="unknown SectorClassification"):
|
|
freshness_threshold_months(_Bogus()) # type: ignore[arg-type]
|