Files
gps-denied-onboard/_docs/03_implementation/batch_77_report.md
T
Oleksandr Bezdieniezhnykh f49d803252 [AZ-597] Batch 77: replay_mode helpers + 13 scenario stub rewires
Add `runner/helpers/replay_mode.py` (NullFrameSink, NullFcInboundEmitter,
default_frame_period_ms, load_replay_json, resolve_replay_subdir,
imu_replay_noop) and rewire all 13 scenarios off their local
`_resolve_*` / `_drive_*` / `_push_*` NotImplementedError stubs.

Closes the offline FDR-replay execution path. `grep raise
NotImplementedError` under `e2e/tests/` now returns zero matches. +17
unit tests (626 total, up from 608). Unit-test behaviour unchanged
(scenarios still skip via b75 sitl_replay_ready gate when
E2E_SITL_REPLAY_DIR is unset).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 09:52:05 +03:00

4.3 KiB

Batch 77 Report — replay_mode helpers + 13 scenario stub rewires (cycle 1, batch 11 of test phase)

Batch: 77 Date: 2026-05-17 Context: Test implementation (greenfield Step 10 — Implement Tests) Tasks: AZ-597 (3 cp) — 1 task (scenario stub cleanup bundle) Cycle: 1 Verdict: COMPLETE — PASS (self-reviewed; see reviews/batch_77_review.md)

Summary

Closes the offline FDR-replay path that AZ-594 (b74), AZ-595 (b75), and AZ-596 (b76) opened. After those three batches, the only remaining NotImplementedError stubs in the scenario suite were a grab-bag of local _resolve_* / _drive_* / _push_* helpers duplicated across 13 scenario files. They all reduced to the same FDR-replay pattern — either a no-op counter (frame sink, FC inbound emitter, IMU replay driver) or a JSON read from ${E2E_SITL_REPLAY_DIR}/ (per-frame GT, single-image observation, outage frames subdir).

This batch bundles those into one shared runner/helpers/replay_mode.py module + rewires the 13 scenarios off their local stubs. After the batch:

  • grep raise NotImplementedError under e2e/tests/ returns zero matches.
  • Once the SITL replay fixture builder lands (separate ticket), every scenario becomes runnable end-to-end with no further per-scenario edits.
  • Unit-test mode is unchanged — the b75 sitl_replay_ready skip gate keeps the loaders unreached when E2E_SITL_REPLAY_DIR is unset.

AZ-597 — replay_mode helpers + 13 scenario rewires (3 cp)

  • runner/helpers/replay_mode.py (new):
    • NullFrameSink — counter-only FrameSink (frames_written: int).
    • NullFcInboundEmitter — counter-only FcInboundEmitter (samples_emitted: int).
    • default_frame_period_ms() -> int + DEFAULT_FRAME_PERIOD_MS = 33 (30 fps).
    • load_replay_json(filename) — generic JSON loader. Raises FileNotFoundError (env-unset / file-missing) or ValueError (malformed, file pointer included).
    • resolve_replay_subdir(name) — directory loader. Raises FileNotFoundError (env-unset / subdir-missing).
    • imu_replay_noop(csv_path) — explicit no-op; signature mirrors imu_replay.ImuReplayer.replay for future live-mode parity.
    • Single shared _resolve_replay_root_or_raise(reason) enforces the E2E_SITL_REPLAY_DIR semantics exactly once.
  • 13 scenarios rewired (all _resolve_* / _drive_* / _push_* stubs deleted):
    • _resolve_frame_sinkNullFrameSink() in: FT-P-01, FT-P-02, FT-P-04, FT-P-05, FT-P-07, FT-P-08, FT-P-09-AP, FT-P-09-iNav, FT-P-10, FT-P-11, FT-N-01, FT-N-02, FT-N-03, FT-N-04.
    • _resolve_fc_inbound_emitterNullFcInboundEmitter() in: FT-P-02, FT-P-04, FT-P-10.
    • _drive_imu_replayimu_replay_noop(...) in: FT-P-07, FT-N-02.
    • _resolve_frame_period_msdefault_frame_period_ms() in: FT-N-03, FT-N-04.
    • _resolve_outage_injection_framesresolve_replay_subdir("outage_frames") in: FT-N-03.
    • _resolve_gt_per_frameload_replay_json("gt_per_frame.json")
      • dataclass projection in: FT-N-01.
    • _push_single_image_and_observeload_replay_json("single_image_observation.json")
      • tuple projection in: FT-P-03/14.
  • e2e/_unit_tests/test_directory_layout.py — registers the new runner/helpers/replay_mode.py path.

Out of scope (deferred)

  • The actual SITL replay fixture builder (separate ticket — will populate ${E2E_SITL_REPLAY_DIR}/ with gps_state.json, gt_per_frame.json, single_image_observation.json, outage_frames/, ekf_divergence_events.json, etc.).
  • Live MAVLink router / pymavlink plumbing (separate live-mode infrastructure ticket).

Test Results

  • New unit tests: 17 (2 null-sink, 2 null-emitter, 1 frame-period, 2 imu-replay-noop, 6 load_replay_json, 4 resolve_replay_subdir).
  • Full e2e/_unit_tests suite: 626 passed in 127 s (previous cumulative: 608 → +18 net = +17 new replay_mode tests + 1 new directory-layout parametrize entry).
  • No new linter errors.
  • grep raise NotImplementedError under e2e/tests/ returns zero matches.

State

  • Spec moved: _docs/02_tasks/todo/AZ-597_scenario_stub_cleanup.md_docs/02_tasks/done/.
  • _docs/_autodev_state.md advanced to last_completed_batch: 77.
  • last_cumulative_review remains batches_73-75; next K=3 cumulative review fires at the end of batch 78.