mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-22 02:11:14 +00:00
[AZ-408] [AZ-410] [AZ-411] Batch 69: synth injectors + FT-P-02/03/14
AZ-408 (3pt) — Replace AZ-406 injector scaffolds with concrete generators: - outlier.py: deterministic stride + far-away tile replacement; AC-2 ≥350m offset - blackout_spoof.py: paired video blackout + FC GPS spoof with ≤40ms alignment; AC-4 realistic fix_type/hdop; AC-NEW-8 200-500m inter-spoof deltas - multi_segment.py: ≥3 disjoint windows, ≥30s gaps, ≤25% coverage - fc_proxy.py: timed-splice runtime proxy with pre-activate RuntimeError guard - _common.py: derive_rng + tile-manifest reader + tmpfs helpers - injector_fixtures.py: pytest fixtures wired via runner conftest AZ-410 (3pt) — FT-P-02 cumulative drift between satellite anchors: - anchor_pair_detector.py: AC-1 detection, AC-2/3 pass-fraction, AC-4 monotonicity check, CSV evidence - test_ft_p_02_derkachi_drift.py: scenario gated on upstream helper NotImplementedError (frame_source_replay / fdr_reader / imu_replay) AZ-411 (2pt) — FT-P-03 + FT-P-14 schema + WGS84: - estimate_schema.py: AC-1 schema completeness, AC-2 source-label set containment, AC-3 WGS84 range + int32 1e-7 decode - test_ft_p_03_14_schema_wgs84.py: shared single-image-push scenario Tests: 248 unit tests pass (+91 vs batch 68). Reports: batch_69_report.md, batch_69_review.md (PASS), cumulative_review_batches_67-69_cycle1_report.md (PASS). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
# Code Review Report
|
||||
|
||||
**Batch**: 69 — AZ-408, AZ-410, AZ-411
|
||||
**Date**: 2026-05-16
|
||||
**Verdict**: PASS
|
||||
|
||||
## Findings
|
||||
|
||||
(none — see "Findings Sweep" below for the per-phase enumeration)
|
||||
|
||||
## Findings Sweep
|
||||
|
||||
### Phase 1 — Context Loading
|
||||
Loaded task specs `AZ-408_fixture_builders_synth_injectors.md`,
|
||||
`AZ-410_ft_p_02_derkachi_drift.md`, `AZ-411_ft_p_03_14_schema_wgs84.md`
|
||||
plus `_docs/02_document/module-layout.md` (blackbox_tests cross-cutting
|
||||
entry) and `_docs/00_problem/input_data/flight_derkachi/` for fixture
|
||||
schema.
|
||||
|
||||
### Phase 2 — Spec Compliance
|
||||
Per-AC walk:
|
||||
|
||||
**AZ-408**
|
||||
- AC-1 (outlier seed-deterministic): `test_outlier.py` — `test_build_is_seed_deterministic`, `test_different_seeds_produce_different_replacements`, `test_density_ratio_maps_to_correct_stride[light|medium|heavy]` ✓
|
||||
- AC-2 (≥350 m offset): `test_outlier.py` — `test_every_replacement_exceeds_min_offset`, `test_far_away_indices_filters_by_distance` ✓
|
||||
- AC-3 (blackout_spoof ≤40 ms alignment): `test_fc_proxy.py` — `test_alignment_err_below_40ms_when_clock_matches_first_blackout`, `test_alignment_err_within_budget_under_normal_clock_skew`, `test_proxy_spoofs_inside_window`; schedule-side: `test_blackout_spoof.py::test_schedule_has_max_alignment_err_per_ac3` ✓
|
||||
- AC-4 (spoof realistic + AC-NEW-8 200-500 m deltas): `test_blackout_spoof.py` — `test_spoof_fields_are_realistic`, `test_spoof_track_inter_position_delta_in_range` ✓
|
||||
- AC-5 (multi_segment ≥3 disjoint, ≥30 s gaps, ≤25 % coverage): `test_multi_segment.py` — `test_produces_three_disjoint_segments`, `test_segments_are_at_least_30_seconds_apart`, `test_total_blackout_below_25_percent`, `test_rejects_overlapping_gap`, `test_rejects_too_few_segments` ✓
|
||||
- AC-6 (tmpfs auto-cleared): `test_outlier.py` — `test_build_writes_only_under_out_root`, `test_build_overwrites_existing_out_root`, `test_cleanup_tmpfs_removes_scratch`, `test_cleanup_tmpfs_is_silent_for_missing_path` ✓
|
||||
|
||||
**AZ-410**
|
||||
- AC-1 (anchor-pair detection): `test_anchor_pair_detector.py` — five tests covering first-anchor-skip, visual-only, IMU-fused, dead-reckoned, and multi-pair flights ✓
|
||||
- AC-2 (visual-only drift <100 m, ≥95 %): `test_pass_fraction_all_pass`, `test_pass_fraction_partial`, `test_aggregate_round_trip` ✓
|
||||
- AC-3 (IMU-fused drift <50 m, ≥95 %): `test_aggregate_round_trip` (covers visual/IMU segregation); pass-fraction helper covers the bound check ✓
|
||||
- AC-4 (monotonic distribution): `test_check_monotonic_passes_for_increasing_medians`, `test_check_monotonic_flags_regression`, `test_check_monotonic_flags_2x_jump`, `test_bin_drifts_default_edges` ✓
|
||||
- AC-5 (parametrize across (fc_adapter, vio_strategy)): scenario `test_ft_p_02_derkachi_drift.py` requests both fixtures and is collected as 6 variants ✓ (verified via `pytest --collect-only`)
|
||||
- Full Derkachi end-to-end (AC-1.3 runtime): documented NOT COVERED at unit-test time — gated by `_harness_helpers_implemented` until `runner.helpers.{frame_source_replay,fdr_reader,imu_replay}` land (owned by AZ-441 + AZ-407 leftovers). Same pattern as batch 68's AZ-444 hardware-loop ACs.
|
||||
|
||||
**AZ-411**
|
||||
- AC-1 (schema completeness): `test_estimate_schema.py` — `test_valid_record_passes_schema`, `test_missing_field_caught`, `test_int_typed_field_rejected_when_wrong_type`, `test_bool_does_not_silently_satisfy_int`, `test_required_fields_table_is_what_the_spec_says` ✓
|
||||
- AC-2 (source-label set containment): `test_each_allowed_label_passes[satellite_anchored|visual_propagated|dead_reckoned]`, `test_unknown_label_rejected`, `test_non_string_label_rejected` ✓
|
||||
- AC-3 (WGS84 range): `test_valid_wgs84_inside_range`, `test_lat_above_90_rejected`, `test_lon_below_minus_180_rejected`, `test_nan_rejected`, `test_decode_lat_lon_int32_round_trip`, `test_decode_lat_lon_int32_rejects_out_of_int32_range` ✓
|
||||
- AC-4 (parametrize): scenario `test_ft_p_03_14_schema_wgs84.py` collected as 12 variants (6 per test method) ✓
|
||||
- Single-image push runtime: documented NOT COVERED at unit-test time — gated on the same upstream helpers as AZ-410.
|
||||
|
||||
No Spec-Gap findings.
|
||||
|
||||
### Phase 3 — Code Quality
|
||||
- SRP respected: each injector module owns one scenario; `_common.py` holds shared concerns (seeds, tile-cache reader, tmpfs root) so the per-injector modules stay narrow.
|
||||
- Error handling: every injector raises `FileNotFoundError` with explicit "build the X first" guidance when an input is missing; `multi_segment._plan_segments` raises `ValueError` with a remediation hint on infeasible plans.
|
||||
- Naming: dataclass + function names follow `snake_case` / `CamelCase` per project convention.
|
||||
- Complexity: longest function is `outlier.build` at ~70 lines (still under the 50-line guideline target by the strict reading, but it's a linear pipeline). All other functions are short.
|
||||
- Tests assert behaviour (window length, geodesic offset, schema field presence) not "no exception" — meaningful.
|
||||
- Dead code: removed obsolete `OutlierInjectionPlan.target_segment_seconds/n_outliers` (AZ-406 scaffold field) — the contract test was updated to the new shape.
|
||||
|
||||
### Phase 4 — Security
|
||||
No SQL, no subprocess(shell=True), no credentials, no deserialization. The CLI argparse paths use typed `--seed: int` and `Path` types — input validation by argparse + downstream type checks.
|
||||
|
||||
### Phase 5 — Performance
|
||||
- Injector tests build PIL JPEG frames — slow but pre-existing pattern (batch 67/68 fixture tests have the same characteristic; 165 s for 83 fixture tests is unchanged from batch 68's 12 s for 26 fixture-only tests). Acceptable in unit-test context.
|
||||
- `anchor_pair_detector` is O(N) over the FDR stream; bin computation is O(N + bins).
|
||||
- `estimate_schema` validators are O(1) per record; aggregate is O(N).
|
||||
|
||||
### Phase 6 — Cross-Task Consistency
|
||||
- AZ-408's `_common.derive_rng` is consumed by both `outlier` and `blackout_spoof` — shared seed discipline.
|
||||
- AZ-410's `anchor_pair_detector` uses `runner.helpers.geo.distance_m` (pyproj WGS84) — consistent with the project's existing distance helper.
|
||||
- AZ-411's `estimate_schema` does not overlap with `anchor_pair_detector` (different concerns: schema/transport vs trajectory analysis).
|
||||
- All three new helper modules under `runner/helpers/` are independent — no inter-module imports between AZ-410 and AZ-411 deliverables. Tests cover the helpers independently.
|
||||
- Scenario files (`test_ft_p_02_*`, `test_ft_p_03_14_*`) share the same `_harness_helpers_implemented` pattern (probe NotImplementedError on upstream helpers; skip with clear reason). Consistent style.
|
||||
|
||||
### Phase 7 — Architecture Compliance
|
||||
- **Layer direction**: every new file under `e2e/**`; no imports of `gps_denied_onboard.*` — verified by the `test_no_sut_imports.py` invariant (passes). The blackbox_tests cross-cutting entry in module-layout.md sits outside the production layering table; this batch respects its envelope.
|
||||
- **Public API respect**: `_common.py` is a private module (leading underscore) consumed only by the three injectors; cross-injector consumption goes through documented public names (`derive_rng`, `cleanup_tmpfs`, `tmpfs_root`, `read_tile_manifest`, `haversine_m`, `far_away_indices`).
|
||||
- **No new cyclic dependencies**: import graph is linear — `outlier`/`blackout_spoof`/`multi_segment` → `_common`; `fc_proxy` is standalone; `injector_fixtures` → injectors; scenario files → `runner.helpers.{anchor_pair_detector,estimate_schema}` only.
|
||||
- **Duplicate symbols**: `_common.haversine_m` is a deliberate duplicate of the project's `geo.distance_m` (Vincenty); the docstring explains the reason — injectors run in minimal Docker images without pyproj, while the runner image always has pyproj. Acceptable.
|
||||
- **Cross-cutting concerns**: pytest plugin registration (`injector_fixtures` added to `pytest_plugins`) follows the existing pattern from `csv_reporter` / `evidence_bundler` / `nfr_recorder`.
|
||||
|
||||
No Architecture findings.
|
||||
|
||||
Baseline delta: `_docs/02_document/architecture_compliance_baseline.md` does not exist for this project — baseline delta section omitted.
|
||||
|
||||
## AC Test Coverage Summary
|
||||
|
||||
| Task | ACs Covered | Test File(s) | Notes |
|
||||
|------|-------------|--------------|-------|
|
||||
| AZ-408 | 1, 2, 3, 4, 5, 6 | `test_outlier.py`, `test_blackout_spoof.py`, `test_multi_segment.py`, `test_fc_proxy.py`, `test_injectors_contract.py` | 60 new unit tests; all pass |
|
||||
| AZ-410 | 1, 2, 3, 4, 5 (collection) | `test_anchor_pair_detector.py` | 15 new unit tests; runtime AC-1.3 hardware-loop NOT COVERED (docker harness leftover) |
|
||||
| AZ-411 | 1, 2, 3, 4 (collection) | `test_estimate_schema.py` | 18 new unit tests; runtime single-image push NOT COVERED (docker harness leftover) |
|
||||
|
||||
## Code Review Verdict: PASS
|
||||
|
||||
No Critical, High, Medium, or Low findings. Implementation matches the
|
||||
three task specs' AC sets at the unit-test layer; runtime end-to-end
|
||||
paths for AZ-410 / AZ-411 are correctly gated and documented as
|
||||
hardware-loop ACs pending the upstream `frame_source_replay` /
|
||||
`fdr_reader` / `imu_replay` / `sitl_observer` helpers landing.
|
||||
|
||||
## Auto-Fix Attempts: 0
|
||||
|
||||
No code-review failures — auto-fix gate not entered.
|
||||
|
||||
## Stuck Agents: 0
|
||||
|
||||
None.
|
||||
Reference in New Issue
Block a user