Adds find_aligned_window cross-correlation (NCC, per-window unit norm)
between IMU energy and video optical-flow magnitude. Returns
AlignedWindow{tlog_start_ns, tlog_end_ns, offset_ms, confidence,
used_fallback}, with fallback to head-takeoff on low confidence to
preserve AZ-405 behavior. TlogReplayFcAdapter honors tlog_start_ns and
skips pre-window messages. New --auto-trim CLI flag, mutex with
--time-offset-ms. AC-1..AC-4 covered by unit tests; AC-5 skipped (no
real flight_derkachi.mp4 in repo). 106 tests pass in regression slice.
Zero new mypy --strict errors.
Co-authored-by: Cursor <cursoragent@cursor.com>
4.4 KiB
Batch 99 — Cycle 2 — AZ-698
Date: 2026-05-20
Tasks: AZ-698 (Tlog trim + mid-flight alignment for replay).
Story points: 5.
Jira status: AZ-698 → In Testing.
What shipped
A normalised-cross-correlation aligner that finds the video's playback window inside a longer tlog, plus the plumbing to honor that window across the replay-mode composition root, replay coordinator, replay-side FC adapter, config schema, and CLI.
find_aligned_window(tlog_path, video_path, config, ...) -> AlignedWindowinsrc/gps_denied_onboard/replay_input/auto_sync.py. Returns(tlog_start_ns, tlog_end_ns, offset_ms, confidence, used_fallback).AlignedWindowDTO +auto_trimflag +alignment_*knobs onReplayConfig/ReplayAutoSyncConfig.TlogReplayFcAdapterskips messages with_timestamp < tlog_start_nswhen seeded (AC-3).--auto-trimCLI flag ongps-denied-replay, mutually exclusive with--time-offset-ms.
Files changed
Production (8):
src/gps_denied_onboard/replay_input/interface.pysrc/gps_denied_onboard/replay_input/auto_sync.pysrc/gps_denied_onboard/replay_input/tlog_video_adapter.pysrc/gps_denied_onboard/replay_input/__init__.py(re-exportAlignedWindow)src/gps_denied_onboard/components/c8_fc_adapter/tlog_replay_adapter.pysrc/gps_denied_onboard/config/schema.pysrc/gps_denied_onboard/config/loader.pysrc/gps_denied_onboard/runtime_root/_replay_branch.pysrc/gps_denied_onboard/cli/replay.py
Tests (1 new):
tests/unit/replay_input/test_az698_window_alignment.py
Specs:
_docs/02_tasks/done/AZ-698_tlog_trim_midflight_alignment.md(moved fromtodo/, completion notes appended).
AC coverage
| AC | Test | Result |
|---|---|---|
| AC-1 | test_ac1_takeoff_aligned_offset_matches_az405_within_50ms |
PASS |
| AC-2 | test_ac2_mid_flight_alignment_locates_correct_window |
PASS |
| AC-3 | test_ac3_adapter_seek_skips_pre_window_messages, _default_no_seek_* |
PASS |
| AC-4 | test_ac4_validator_passes_for_takeoff_aligned_offset, _mid_flight_* |
PASS |
| AC-5 | test_ac5_cli_auto_trim_smoke_uses_find_aligned_window |
SKIPPED |
AC-5 skip reason: the repo's flight_derkachi.mp4 is a 134-byte placeholder,
not a real recording. Live CLI smoke is covered by AZ-699 (validation
runner) once the real video is sourced.
Test run
tests/unit/replay_input/test_az698_window_alignment.py 12 PASS 1 SKIP
tests/unit/replay_input/test_az405_auto_sync.py 14 PASS
tests/unit/replay_input/test_az405_replay_input_adapter.py 13 PASS
tests/unit/c8_fc_adapter/test_az399_tlog_replay_adapter.py 24 PASS 1 SKIP
tests/unit/replay_input/test_tlog_ground_truth.py 12 PASS
tests/unit/test_az697_gps_compare.py 10 PASS
tests/unit/calibration/test_khp20s30_factory.py 9 PASS
tests/unit/runtime_root/test_az687_pre_constructed_replay_mode.py 3 PASS
tests/unit/test_az269_config_loader.py 9 PASS
Totals: 106 passed, 2 skipped, 0 failed. No regressions in adjacent suites.
Strict typing
Baseline (pre-batch, by stash-and-rerun): 17 mypy --strict errors across
6 of the 8 touched src/ files. After batch: 17 errors — same count,
same kinds, with line numbers shifted only by added code. Zero new
strict-typing errors introduced by AZ-698. Pre-existing errors are
out-of-scope per coderule.mdc ("Pre-existing lint errors should only be
fixed if they're in the modified area" — they were not in the bytes
modified for AZ-698 ACs).
The new public symbols (find_aligned_window, AlignedWindow,
_zero_mean_normalise, _resample_uniform) carry explicit
npt.NDArray[np.float64] annotations so they don't add to the debt.
Code review verdict
Inline self-review: code paths cover the spec's scope, fallback to
head-takeoff on low confidence preserves AZ-405 behavior, adapter seek is
opt-in via constructor kwarg so the --skip-auto-sync path is untouched.
The normalised-cross-correlation switch is documented in the spec's
"Implementation Notes" appendix as the algorithmic decision of record.
Next batch
Batch 100 — AZ-699 (real-flight validation runner). Depends on AZ-697 (ground truth) and AZ-698 (alignment) — both now in testing.