[AZ-895] Deprecate replay auto-sync surface; file AZ-908 follow-up

Option A (minimum-deprecation, 2 SP) per user complexity-budget
decision. Auto-sync stays importable as a raising stub for one cycle
so external callers see a clean ReplayInputAdapterError instead of an
ImportError. Full physical removal is filed as AZ-908 (cycle-5+ backlog).

Production:
- auto_sync.py: 700+ LOC -> 56-line no-op stub raising
  "auto-sync removed; supply --imu CSV instead"
- tlog_video_adapter.py: 700+ LOC -> 105-line deprecated stub;
  ReplayInputAdapter.open() raises immediately, close() is a no-op
- _replay_branch.py: dropped legacy auto-sync branch +
  _build_auto_sync_config; _validate_replay_paths now requires
  imu_csv_path; replay_input_adapter_factory parameter removed
- cli/replay.py: --time-offset-ms / --skip-auto-sync / --auto-trim
  emit DeprecationWarning + stderr line; values ignored
- tlog_replay_adapter.py + tlog_ground_truth.py docstrings: AUDIT-ONLY

Tests:
- DELETED test_az405_auto_sync, test_az405_replay_input_adapter,
  test_az698_window_alignment (covered code no longer runs)
- ADDED test_az895_auto_sync_deprecated_stub (5 parametrised, pins AC-1)
- test_az402_replay_cli: deprecation warnings + ignored-value asserts
- test_az401_compose_root_replay: new imu_csv_path-required gate;
  deleted the calibration-loading test that relied on the removed
  replay_input_adapter_factory injection point
- test_derkachi_real_tlog: xfail reason refreshed to AZ-848 + AZ-883
  (AC-4 "AZ-848-scoped reason")

Docs:
- module-layout.md: replay_input file list flags deprecated modules,
  adds csv_ground_truth.py
- _dependencies_table.md: +AZ-908 row, preamble + totals updated
  (179 -> 180 tasks, 567 -> 570 SP)
- AZ-908 backlog spec added; AZ-895 spec moved todo -> done
- batch_03_cycle4_report.md written

Touched-module tests green (111 passed, 1 skipped). Full unit suite
green: 2287 passed, 85 skipped, 1 deselected (pre-existing flaky perf
test, unrelated).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-26 22:09:59 +03:00
parent fdb593a775
commit 007aa36fbf
19 changed files with 600 additions and 4213 deletions
+97 -7
View File
@@ -114,6 +114,10 @@ def _argv(files: dict[str, Path], **overrides: Any) -> list[str]:
argv: list[str] = []
for k, v in base.items():
argv.extend([k, v])
if overrides.get("skip_auto_sync"):
argv.append("--skip-auto-sync")
if overrides.get("auto_trim"):
argv.append("--auto-trim")
return argv
@@ -192,12 +196,15 @@ def test_ac3_pace_realtime(
# ----------------------------------------------------------------------
# AC-4: --time-offset-ms forwarded (None when absent)
# AC-4: --time-offset-ms deprecated (AZ-895) — ignored + warning emitted
def test_ac4_time_offset_forwarded(
_required_files: dict[str, Path], _airborne_env: None
def test_ac4_time_offset_ignored_after_az895(
_required_files: dict[str, Path],
_airborne_env: None,
capsys: pytest.CaptureFixture[str],
) -> None:
"""AZ-895: --time-offset-ms is deprecated; value is ignored, warning emitted."""
# Arrange
captured: dict[str, Config] = {}
@@ -206,13 +213,16 @@ def test_ac4_time_offset_forwarded(
return 0
# Act
rc = replay_cli.main(
_argv(_required_files, time_offset_ms=5000), shared_main=fake_main
)
with pytest.warns(DeprecationWarning, match="--time-offset-ms"):
rc = replay_cli.main(
_argv(_required_files, time_offset_ms=5000), shared_main=fake_main
)
# Assert
assert rc == EXIT_SUCCESS
assert captured["config"].replay.time_offset_ms == 5000
assert captured["config"].replay.time_offset_ms is None
err = capsys.readouterr().err
assert "--time-offset-ms is deprecated (AZ-895)" in err
def test_ac4_time_offset_none_when_absent(
@@ -233,6 +243,86 @@ def test_ac4_time_offset_none_when_absent(
assert captured["config"].replay.time_offset_ms is None
def test_az895_skip_auto_sync_ignored_and_warned(
_required_files: dict[str, Path],
_airborne_env: None,
capsys: pytest.CaptureFixture[str],
) -> None:
"""AZ-895: --skip-auto-sync deprecated; value ignored, warning emitted."""
# Arrange
captured: dict[str, Config] = {}
def fake_main(config: Config) -> int:
captured["config"] = config
return 0
# Act
with pytest.warns(DeprecationWarning, match="--skip-auto-sync"):
rc = replay_cli.main(
_argv(_required_files, skip_auto_sync=True), shared_main=fake_main
)
# Assert
assert rc == EXIT_SUCCESS
assert captured["config"].replay.skip_auto_sync_validation is False
err = capsys.readouterr().err
assert "--skip-auto-sync is deprecated (AZ-895)" in err
def test_az895_auto_trim_ignored_and_warned(
_required_files: dict[str, Path],
_airborne_env: None,
capsys: pytest.CaptureFixture[str],
) -> None:
"""AZ-895: --auto-trim deprecated; value ignored, warning emitted."""
# Arrange
captured: dict[str, Config] = {}
def fake_main(config: Config) -> int:
captured["config"] = config
return 0
# Act
with pytest.warns(DeprecationWarning, match="--auto-trim"):
rc = replay_cli.main(
_argv(_required_files, auto_trim=True), shared_main=fake_main
)
# Assert
assert rc == EXIT_SUCCESS
assert captured["config"].replay.auto_trim is False
err = capsys.readouterr().err
assert "--auto-trim is deprecated (AZ-895)" in err
def test_az895_no_deprecated_flags_no_warning(
_required_files: dict[str, Path],
_airborne_env: None,
capsys: pytest.CaptureFixture[str],
recwarn: pytest.WarningsRecorder,
) -> None:
"""No AZ-895 flag-specific deprecation warning when none of the flags are used."""
# Act
rc = replay_cli.main(_argv(_required_files), shared_main=lambda _c: 0)
# Assert
assert rc == EXIT_SUCCESS
err = capsys.readouterr().err
for flag in ("--time-offset-ms", "--skip-auto-sync", "--auto-trim"):
assert f"{flag} is deprecated" not in err, (
f"unexpected deprecation banner for {flag} when it was not passed"
)
az895_flag_warnings = [
w for w in recwarn.list
if issubclass(w.category, DeprecationWarning)
and any(
f"{flag} is deprecated" in str(w.message)
for flag in ("--time-offset-ms", "--skip-auto-sync", "--auto-trim")
)
]
assert az895_flag_warnings == []
# ----------------------------------------------------------------------
# AC-5: --mavlink-signing-key required (argparse exit 2)