navi/backend/services
malice 2453c20669
MVUM Layer 1: per-edge annotation + accurate closure counts (#23)
* MVUM Layer 1: per-edge annotation + accurate closure counts

Annotate each network-leg segment with its MVUM access status for the selected mode,
using the Layer-0 MVUMSpatialIndex. No routing-decision or Valhalla changes.

- mvum_annotate.py (new): annotate_network_edges(coords,(lat,lon)), mode, spatial_index,
  on_date) -> [EdgeAnnotation{coord_pair_index, matched_features, mvum_status}]. Walks
  consecutive pairs, queries the index (10m buffer), applies a parallelism filter (acute
  angle to the edge <=45deg, both directions), resolves per-mode access via the existing
  check_access/get_mode_field/symbol_to_access (worst/most-restrictive across matches).
  Mode map: foot->open (skip), 2w->e_bike_class1, 4w->atv, vehicle->highclearancevehicle;
  auto is already resolved to a concrete candidate upstream.
- router.py: _route_D_network_only and _build_response annotate the network leg using the
  injected self.spatial_index (getattr-guarded; skipped + debug-logged if None), attach
  edge_mvum to the network feature, and add summary.mvum_closed_crossings +
  summary.mvum_segments_annotated.
- offroute_route.py: inject app.config[MVUM_SPATIAL_INDEX] onto the router per request.
- DirectionsPanel.jsx: warning row when mvum_closed_crossings>0.
- tests/test_mvum_annotate.py: parallel match, perpendicular reject, seasonal closure,
  symbol fallback, summary count.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Fix seasonal date default + hoist annotation, single annotate for Auto

- Default mvum_on_date to datetime.now() at annotation time so seasonal MVUM
  openings/closings actually fire in production (was effectively None -> no seasonal).
- Hoist per-edge annotation out of _route_D_network_only and _build_response into a new
  central OffrouteRouter._annotate_network_segments(result, mode), invoked once at the end
  of route() (annotate_mvum=True). _route_auto probes with annotate_mvum=False and
  annotates only the winning candidate -> Auto runs annotation once instead of up to 4x.
  Removed the inline annotation/edge_mvum/summary blocks from both scenario handlers.

Note: the central pass filters network features on properties.segment_type == "network"
(the actual tag) rather than the spec-suggested "kind", which is not a field here.

1 new test: test_route_auto_annotates_only_winner.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Matt <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-25 19:32:43 -06:00
..
navi_admin fix: include navi-offroute (8428) in navi-admin fleet list 2026-05-23 23:17:23 -06:00
navi_config Add navi-admin service (extraction #7) (#7) 2026-05-22 21:21:00 -06:00
navi_contacts Add navi-admin service (extraction #7) (#7) 2026-05-22 21:21:00 -06:00
navi_geo shared: promote dem.py to shared/ (prep for navi-offroute) (#9) 2026-05-22 22:42:47 -06:00
navi_landclass Add navi-admin service (extraction #7) (#7) 2026-05-22 21:21:00 -06:00
navi_offroute MVUM Layer 1: per-edge annotation + accurate closure counts (#23) 2026-05-25 19:32:43 -06:00
navi_places decouple: move /api/wiki-rewrite logic from recon to navi-places 2026-05-23 21:12:27 -06:00
navi_traffic Add navi-admin service (extraction #7) (#7) 2026-05-22 21:21:00 -06:00