[AZ-326] [AZ-327] C12 operator-tool CLI + companion SSH bringup

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>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-13 09:34:14 +03:00
parent a06b107fc3
commit 91ce1c2047
29 changed files with 4001 additions and 34 deletions
@@ -0,0 +1,31 @@
"""AZ-326 — sanity checks on the documented EXIT_* constants."""
from __future__ import annotations
from gps_denied_onboard.components.c12_operator_tooling import exit_codes
class TestExitCodes:
def test_documented_values_are_unique(self) -> None:
# Arrange
documented = [
getattr(exit_codes, name) for name in dir(exit_codes) if name.startswith("EXIT_")
]
# Assert
assert len(documented) == len(set(documented))
def test_ok_is_zero_and_usage_is_two(self) -> None:
assert exit_codes.EXIT_OK == 0
assert exit_codes.EXIT_USAGE == 2
def test_companion_range_starts_at_ten(self) -> None:
assert 10 <= exit_codes.EXIT_COMPANION_UNREACHABLE <= 19
assert 10 <= exit_codes.EXIT_CONTENT_HASH_MISMATCH <= 19
def test_flights_api_range_starts_at_sixty(self) -> None:
# AC-3 mapping table for the flights-API surface
assert exit_codes.EXIT_FLIGHTS_API_UNREACHABLE == 60
assert exit_codes.EXIT_FLIGHTS_API_AUTH == 61
assert exit_codes.EXIT_FLIGHT_NOT_FOUND == 62
assert exit_codes.EXIT_FLIGHT_SCHEMA == 63
assert exit_codes.EXIT_EMPTY_WAYPOINTS == 64