# SITL Replay Fixture Builder (AZ-598) Produces the `outbound_messages__.json` + `observer__.json` fixtures consumed by the b75 `sitl_observer` module in offline FDR-replay mode (b75/b78). ## Vertical-slice scope (this batch) Only the FT-P-01 still-image accuracy scenario is supported. Other scenarios (FT-P-02 Derkachi continuous flight, FT-N-04 blackout-spoof, etc.) need their own capture flows and will land as follow-up tickets. ## Strategy Rather than spinning up a SITL container, this builder reuses the production `gps-denied-replay` CLI + `ReplayInputAdapter`: 1. Encode the 60 `AD0000NN.jpg` still images into a 1 fps MP4. 2. Generate a synthetic stationary tlog (zero-motion `RAW_IMU` + `ATTITUDE` pairs at 200 Hz) — bypasses the AZ-405 take-off pre-validator without needing real flight data. 3. Run `gps-denied-replay --video stills.mp4 --tlog stationary.tlog --time-offset-ms 0 --fdr-out fdr.jsonl` (auto-sync bypassed because the synthetic tlog has no take-off signal). 4. Read `fdr.jsonl`, filter to `kind == outbound_position_estimate`, project each into the `outbound_messages_*` schema. 5. Write the two fixture JSON files into `--output-dir`. This avoids needing new SUT-side frame-ingestion code (HTTP endpoint, file-watch source, etc.) which would otherwise be required to push individual stills to a running SUT container. ## Usage ```bash gps-denied-build-p01-fixtures \ --input-dir _docs/00_problem/input_data \ --output-dir e2e/fixtures/sitl_replay/p01 \ --fc-kind ardupilot \ --host sitl-host ``` The output directory will contain: * `stills.mp4` — the 60 images encoded at 1 fps. * `stationary.tlog` — synthetic 120-s zero-motion tlog at 200 Hz. * `fdr.jsonl` — the FDR JSONL stream from the replay run. * `outbound_messages_ardupilot_sitl-host.json` — the consumed fixture. * `observer_ardupilot_sitl-host.json` — the consumed fixture. To activate the fixtures in a scenario run: ```bash E2E_SITL_REPLAY_DIR=e2e/fixtures/sitl_replay/p01 \ pytest e2e/tests/positive/test_ft_p_01_still_image_accuracy.py ``` ## Limitations * The synthetic tlog encodes zero motion — auto-sync MUST be bypassed via `--time-offset-ms 0` (the builder does this automatically). * The FDR record `kind` is assumed to be `outbound_position_estimate` — the `--fdr-kind` CLI flag overrides if the actual schema differs. * Per-image timeout handling: if the SUT emits fewer outbound estimates than pushed frames, trailing image_ids are written as `null` entries (encoded as TimeoutError on scenario replay). * iNav adapter is NOT supported by this batch — only ArduPilot. iNav will land as a follow-up once the AP path is validated end-to-end. ## Testing Unit tests under `e2e/_unit_tests/fixtures/test_sitl_replay_builder.py` mock all external dependencies (OpenCV, pymavlink, subprocess) so the test suite runs without a real `gps-denied-replay` install. The actual end-to-end run requires the SUT to be installed (`pip install -e .` at repo root) and is documented as a manual step until CI infrastructure catches up.