mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 12:01:13 +00:00
[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>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
# 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_sink` → `NullFrameSink()` 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_emitter` → `NullFcInboundEmitter()` in:
|
||||
FT-P-02, FT-P-04, FT-P-10.
|
||||
* `_drive_imu_replay` → `imu_replay_noop(...)` in: FT-P-07, FT-N-02.
|
||||
* `_resolve_frame_period_ms` → `default_frame_period_ms()` in:
|
||||
FT-N-03, FT-N-04.
|
||||
* `_resolve_outage_injection_frames` → `resolve_replay_subdir("outage_frames")`
|
||||
in: FT-N-03.
|
||||
* `_resolve_gt_per_frame` → `load_replay_json("gt_per_frame.json")`
|
||||
+ dataclass projection in: FT-N-01.
|
||||
* `_push_single_image_and_observe` → `load_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.
|
||||
Reference in New Issue
Block a user