[AZ-598] Batch 78: sitl_observer.wait_for_outbound + FT-P-01 fixture builder

Phase 1: extend sitl_observer with cursor-based `wait_for_outbound`
returning `OutboundMessage` from `outbound_messages_<fc_kind>_<host>.json`
fixtures. Three outcomes: message, TimeoutError (null entries), or
RuntimeError (missing/malformed). Fix FT-P-01 + FT-P-05 scenarios to
use `fc_kind=` kwarg.

Phase 2: FT-P-01 vertical-slice fixture builder under
`e2e/fixtures/sitl_replay_builder/`. Reuses the production
`gps-denied-replay` CLI + `ReplayInputAdapter`: encode 60 stills as
1 fps MP4 + synthetic stationary tlog (pymavlink); run replay;
project FDR outbound estimates into the schema. Avoids the
13+ cp of SUT-side frame-ingestion that a live-SITL-capture path
would have required. Live execution remains a manual operator step.

+35 unit tests (664 total, up from 637). K=3 cumulative review for
b76-b78 documents the offline-replay arc convergence.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-17 12:08:02 +03:00
parent f49d803252
commit 47ad43f913
14 changed files with 1940 additions and 8 deletions
@@ -87,7 +87,7 @@ def test_ft_p_01_still_image_accuracy(
# 2. Resolve the SITL listener for the requested FC adapter.
sitl_host = "sitl-ardupilot" if fc_adapter == "ardupilot" else "sitl-inav"
observer = sitl_observer.get_observer(fc_adapter=fc_adapter, host=sitl_host)
observer = sitl_observer.get_observer(fc_kind=fc_adapter, host=sitl_host)
sink = _resolve_frame_sink()
replayer = FrameSourceReplayer(sink)
@@ -79,7 +79,7 @@ def test_ft_p_05_sat_anchor(
# 2. Push images, collect (est_lat, est_lon, mre_px) per image.
sitl_host = "sitl-ardupilot" if fc_adapter == "ardupilot" else "sitl-inav"
observer = sitl_observer.get_observer(fc_adapter=fc_adapter, host=sitl_host)
observer = sitl_observer.get_observer(fc_kind=fc_adapter, host=sitl_host)
sink = _resolve_frame_sink()
replayer = FrameSourceReplayer(sink)