mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 16:51:13 +00:00
[AZ-329] [AZ-330] [AZ-523] [AZ-524] Batch 44 atomic refactor
Implements two new C12 services and rebalances the C11/C12 boundary in one atomic commit: * AZ-329 PostLandingUploadOrchestrator — gates C11 upload on the `flight_footer` FDR record's `clean_shutdown` field; 4 refusal modes; new FdrFooterReader Protocol + LocalFdrFooterReader. * AZ-330 OperatorReLocService — AC-3.4 visual-loss re-localization hint; reuses shared LatLonAlt; OperatorCommandTransport Protocol cut (E-C8 owns the future pymavlink concrete); new FDR record kind `c12.reloc.requested`; log redaction (lat/lon 5 decimals, reason 200 chars). * AZ-523 C11 internal flight-state gate removed (SRP refactor): `confirm_flight_state` / `FlightStateSignal` use / `FlightStateNotOnGroundError` deleted from C11; TileUploader contract bumped to v2.0.0 (frozen) with migration note; AZ-317 superseded. * AZ-524 Package rename `c12_operator_tooling` → `c12_operator_orchestrator` across source, tests, pyproject, CMake, Dockerfile, compose, CI, runtime-root services class (`OperatorOrchestratorServices`) + factory function (`build_operator_orchestrator`), logger namespaces, config slug, docs, and the E-C12 epic title. Tests: 1543 passed, 80 skipped (all environment gates). Targeted AC suite (AZ-329 + AZ-330 + FdrFooterReader): 37 passed. Cold-start NFR-perf still ≤ 500 ms p99. Tracker: AZ-317 → Done (superseded); AZ-319 v2.0.0 contract bump comment; AZ-329/AZ-330 → In Testing; AZ-253 epic renamed; AZ-523 + AZ-524 created and closed as audit-trail tickets. See `_docs/03_implementation/batch_44_cycle1_report.md`. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -26,8 +26,6 @@ import pytest
|
||||
|
||||
from gps_denied_onboard.components.c11_tile_manager import (
|
||||
C11RetryConfig,
|
||||
FlightStateNotOnGroundError,
|
||||
FlightStateSignal,
|
||||
IdempotentRetryTileUploader,
|
||||
IngestStatus,
|
||||
PerTileStatus,
|
||||
@@ -76,7 +74,6 @@ class _ScriptedInner:
|
||||
self.raises = list(raise_on_call or [])
|
||||
self.calls: list[UploadRequest] = []
|
||||
self.enumerate_calls: list[Any] = []
|
||||
self.confirm_calls: int = 0
|
||||
|
||||
def upload_pending_tiles(self, request: UploadRequest) -> UploadBatchReport:
|
||||
self.calls.append(request)
|
||||
@@ -94,10 +91,6 @@ class _ScriptedInner:
|
||||
self.enumerate_calls.append(flight_id)
|
||||
return [{"sentinel": True, "flight_id": flight_id}]
|
||||
|
||||
def confirm_flight_state(self) -> FlightStateSignal:
|
||||
self.confirm_calls += 1
|
||||
return FlightStateSignal.ON_GROUND
|
||||
|
||||
|
||||
@dataclass
|
||||
class _FakeMetadataStore:
|
||||
@@ -388,39 +381,11 @@ def test_ac11_enumerate_pending_passes_through() -> None:
|
||||
assert out == [{"sentinel": True, "flight_id": fid}]
|
||||
|
||||
|
||||
def test_ac11_confirm_flight_state_passes_through() -> None:
|
||||
# Arrange
|
||||
inner = _ScriptedInner(reports=[_success(0)])
|
||||
(decorator, _logs, _store, _clk, _fdr) = _build_decorator(inner=inner)
|
||||
|
||||
# Act
|
||||
state = decorator.confirm_flight_state()
|
||||
|
||||
# Assert
|
||||
assert state == FlightStateSignal.ON_GROUND
|
||||
assert inner.confirm_calls == 1
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# AC-12 — inner exception propagates without retry
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_ac12_flight_state_not_on_ground_propagates_without_retry() -> None:
|
||||
# Arrange
|
||||
from datetime import datetime, timezone
|
||||
|
||||
err = FlightStateNotOnGroundError(FlightStateSignal.IN_FLIGHT, datetime.now(timezone.utc))
|
||||
inner = _ScriptedInner(raise_on_call=[err])
|
||||
(decorator, _logs, _store, clk, _fdr) = _build_decorator(inner=inner)
|
||||
|
||||
# Act / Assert
|
||||
with pytest.raises(FlightStateNotOnGroundError):
|
||||
decorator.upload_pending_tiles(_request())
|
||||
assert clk.sleep_calls == []
|
||||
assert len(inner.calls) == 1
|
||||
|
||||
|
||||
def test_ac12_satellite_provider_error_propagates_without_retry() -> None:
|
||||
# Arrange
|
||||
inner = _ScriptedInner(raise_on_call=[SatelliteProviderError("boom")])
|
||||
@@ -493,7 +458,6 @@ def test_ac10_factory_returns_decorated_uploader_by_default() -> None:
|
||||
http_client=_httpx.Client(transport=transport),
|
||||
tile_store=object(),
|
||||
tile_metadata_store=object(),
|
||||
flight_state_gate=object(), # type: ignore[arg-type]
|
||||
key_manager=object(), # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
@@ -516,7 +480,6 @@ def test_ac10_factory_bypasses_decorator_when_flag_set() -> None:
|
||||
http_client=_httpx.Client(transport=transport),
|
||||
tile_store=object(),
|
||||
tile_metadata_store=object(),
|
||||
flight_state_gate=object(), # type: ignore[arg-type]
|
||||
key_manager=object(), # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user