[AZ-700] gps-denied-render-map: HTML map of estimated vs truth tracks

New operator-side console-script renders a self-contained HTML map
(folium / Leaflet) comparing the estimator's JSONL track against
the tlog ground-truth track. Pinned visual style: red truth + blue
estimated polylines, start/end markers per track, 100 m + 50 m
scale circles, optional AZ-699 accuracy-summary banner, and an
--offline-tiles mode (with optional local tile-URL template) for
Jetsons without internet.

folium is gated behind a new [operator-tools] optional-dep so the
airborne binary's cold-start NFR is unaffected (C12 binary doesn't
import the new module). 14 new unit tests pin polyline count,
marker count, scale-circle radii, summary embedding, offline-tile
behaviour, and full CLI smoke. Zero mypy --strict errors.

Refines the 2026-05-20 Jetson-only test policy: unit tests may run
locally, e2e/perf/resilience/security stay Jetson-only. Documented
in _docs/02_document/tests/environment.md (Where each tier runs)
and .cursor/rules/testing.mdc (Test environment for this project).

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-20 17:04:01 +03:00
parent dcde602f61
commit b66b68ff76
8 changed files with 943 additions and 17 deletions
@@ -0,0 +1,93 @@
# Batch 101 — Cycle 2 — AZ-700
**Date**: 2026-05-20
**Tasks**: AZ-700 (replay map visualization).
**Story points**: 3.
**Jira status**: AZ-700 → `In Testing`.
## What shipped
A new operator-side console-script `gps-denied-render-map` that
renders a self-contained HTML map (folium / Leaflet) of the
estimator's track vs the tlog ground-truth track, with start/end
markers, 100 m + 50 m scale circles, optional summary banner from
AZ-699, and an `--offline-tiles` mode for Jetsons without internet
access.
folium is gated behind a new `[operator-tools]` optional-dependency
group so the airborne binary never pays for it.
## Files changed
Production (2):
- `src/gps_denied_onboard/cli/render_map.py` (new)
- `pyproject.toml` (new optional-deps group + console script)
Tests (1):
- `tests/unit/test_az700_render_map.py` (14 tests, all PASS local)
Docs:
- `_docs/02_document/tests/environment.md` — refined the 2026-05-20
"Jetson-only" policy to: unit tests local-OK, e2e Jetson-only.
- `.cursor/rules/testing.mdc` — added the refined policy as an
always-applied agent rule.
- `_docs/02_tasks/done/AZ-700_replay_map_visualization.md`
Implementation Notes appended; moved from `todo/`.
## AC coverage
| AC | Test / Artefact | Result |
| ---- | ---------------------------------------------------------------------------------------- | ------ |
| AC-1 | `test_cli_writes_html_with_default_tiles` | PASS (local). |
| AC-2 | `test_render_map_html_emits_two_polylines`, `…emits_four_markers_and_two_circles` | PASS |
| AC-3 | `test_render_map_html_emits_two_polylines`, `…emits_four_markers_and_two_circles` | PASS — exactly 2 polylines + 4 markers + 2 scale circles. |
| AC-4 | Visual smoke on Tier-2 Jetson with operator-opened `map.html` | DEFERRED to Jetson (correctly per refined test-env policy). |
| AC-5 | `test_render_map_html_offline_tiles_omits_openstreetmap`, `…_template_uses_local_url` | PASS |
## Test run
```
tests/unit/test_az700_render_map.py 14 PASS in 2.5 s
Wider regression slice 107 PASS 1 SKIP
```
The 1 skipped test is the pre-existing AZ-698 AC-5 e2e smoke
(needs the real video in `_docs/00_problem/input_data/flight_derkachi/`).
## Strict typing
```
mypy --strict src/gps_denied_onboard/cli/render_map.py
→ Success: no issues found in 1 source file.
```
The lazy folium import uses
`# type: ignore[import-untyped, import-not-found, unused-ignore]`
so strict passes cleanly whether or not `[operator-tools]` is
installed.
## Refined test-environment policy
Mid-batch the user clarified the existing "Jetson-only across all
tiers" policy: **unit tests may run locally, e2e tests stay
Jetson-only.** Rationale: the unit suite is fully synthetic, so a
local PASS = Jetson PASS for that tier; the e2e suite is bound to
Jetson hardware / latency / SITL and a local run is meaningless.
Captured in:
- `_docs/02_document/tests/environment.md` — banner + new
"Where each tier runs (active policy)" table + Test Execution
section rewritten.
- `.cursor/rules/testing.mdc` — appended "Test environment (this
project)" section so future agent sessions cannot drift back to
running e2e locally.
## Next batch
Batch 102 — **AZ-701** (HTTP replay API service). Depends on
AZ-697 (truth source) and AZ-699 (report writer). Last task in
cycle 2.