mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 15:21:14 +00:00
[AZ-894] [AZ-896] Add CSV-driven replay adapter + format docs
Replaces the tlog two-clock replay surface with a single-clock path driven by the Derkachi-schema CSV. --imu is the new required CLI arg; --tlog stays as a deprecated alias (warned + ignored when --imu set) until AZ-895 deletes it. * csv_ground_truth.py parses the 15-column schema, fails fast at startup on every documented schema fault (AC-5). * CsvReplayFcAdapter slots into ReplayInputBundle.fc_adapter alongside the tlog sibling; mirrors Invariant-5 outbound wiring; inbound bus is intentionally a no-op since the loop reads CSV directly. * _run_replay_loop branches on imu_csv_path, stamps VioOutput.emitted_at_ns from the CSV-derived frame_end_ns (AC-4), closing the AZ-848 two-clock surface for the new path. * AZ-896 ships the operator-facing format spec at _docs/02_document/contracts/replay/csv_replay_format.md plus a 20-row example CSV (AC-3 regression-locked). Tests: 11 + 12 new unit tests, plus updates to AZ-401 import-boundary and AZ-402 CLI suites. Full unit suite 2,327 passed / 86 skipped. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -491,12 +491,14 @@ def test_ac8_replay_branch_imports_only_public_apis() -> None:
|
||||
tree = ast.parse(text)
|
||||
|
||||
# Allowed deep imports: into the c8_fc_adapter component (the
|
||||
# noop transport + the JSONL sink) and into the `replay_input`
|
||||
# cross-cutting coordinator (Layer-4). Both are documented in
|
||||
# module-layout.md as the replay strategy homes.
|
||||
# noop transport + the JSONL sink + the AZ-894 CSV replay adapter)
|
||||
# and into the `replay_input` cross-cutting coordinator (Layer-4).
|
||||
# All of these are documented in module-layout.md as the replay
|
||||
# strategy homes.
|
||||
allowed_deep_prefixes = (
|
||||
"gps_denied_onboard.components.c8_fc_adapter.noop_mavlink_transport",
|
||||
"gps_denied_onboard.components.c8_fc_adapter.replay_sink",
|
||||
"gps_denied_onboard.components.c8_fc_adapter.csv_replay_adapter",
|
||||
"gps_denied_onboard.replay_input.tlog_video_adapter",
|
||||
)
|
||||
|
||||
@@ -632,9 +634,14 @@ def test_replay_branch_rejects_empty_video_path(
|
||||
build_replay_components(config)
|
||||
|
||||
|
||||
def test_replay_branch_rejects_empty_tlog_path(
|
||||
def test_replay_branch_rejects_both_inputs_empty(
|
||||
_airborne_replay_env: Path,
|
||||
) -> None:
|
||||
# AZ-894: the validation gate now accepts either imu_csv_path
|
||||
# (canonical) or tlog_path (legacy) — rejecting only when both
|
||||
# are empty. Keeping the historical name pattern (test_*_rejects_*)
|
||||
# for grep parity but renamed to reflect the new semantics.
|
||||
|
||||
# Arrange
|
||||
runtime_cfg = RuntimeConfig(camera_calibration_path=str(_airborne_replay_env))
|
||||
config = Config(
|
||||
@@ -642,6 +649,7 @@ def test_replay_branch_rejects_empty_tlog_path(
|
||||
replay=ReplayConfig(
|
||||
video_path="/dev/null/fake.mp4",
|
||||
tlog_path="",
|
||||
imu_csv_path="",
|
||||
output_path="/tmp/out.jsonl",
|
||||
pace="asap",
|
||||
target_fc_dialect="ardupilot_plane",
|
||||
@@ -650,7 +658,7 @@ def test_replay_branch_rejects_empty_tlog_path(
|
||||
)
|
||||
|
||||
# Act / Assert
|
||||
with pytest.raises(CompositionError, match="tlog_path is empty"):
|
||||
with pytest.raises(CompositionError, match="imu_csv_path is empty"):
|
||||
build_replay_components(config)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user