From ac504cab7962e41711e38684c270cad8b0cbfa35 Mon Sep 17 00:00:00 2001 From: malice Date: Thu, 28 May 2026 00:38:15 -0600 Subject: [PATCH] =?UTF-8?q?navi-offroute:=20Auto=20bypass=20=E2=80=94=20tr?= =?UTF-8?q?ust=20=5Fauto=5Feligible=5Fmodes=20vehicle=20judgment=20(PR=204?= =?UTF-8?q?8)=20(#48)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: mj Co-authored-by: Claude Opus 4.7 (1M context) --- backend/services/navi_offroute/router.py | 38 +++++-------------- .../navi_offroute/tests/test_offroute.py | 21 +++++++++- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/backend/services/navi_offroute/router.py b/backend/services/navi_offroute/router.py index 5c916ca..044246b 100755 --- a/backend/services/navi_offroute/router.py +++ b/backend/services/navi_offroute/router.py @@ -754,26 +754,6 @@ class OffrouteRouter: return CATEGORY_ELIGIBLE_MODES.get(f"{key}:*") return None - def _bypass_eligible(self, lat: float, lon: float, - category: Optional[str], snap_cache: dict) -> bool: - """True when this endpoint is clearly ON a paved road. Gates the Valhalla bypass - in _route_auto. Two safe paths: - 1. positive OSM category hint (CATEGORY_ELIGIBLE_MODES grants "vehicle"), OR - 2. cached auto-snap is tight (<= AUTO_SNAP_TIGHT_M) AND the snapped road is a - paved highway class. - Deliberately EXCLUDES the relaxed-snap-with-flat case (d_auto <= 100m + flat - terrain), which can grant 'vehicle' eligibility up to 100m off a road — bypassing - there would silently re-snap a wilderness/park-lot click to the road and lose any - walk-then-drive leg the unified flow would have produced.""" - typed = self._eligible_modes_from_category(category) - if typed is not None: - return "vehicle" in typed - snap = snap_cache.get((lat, lon, "auto")) - if snap is None: - return False # tagged-endpoint short-circuit didn't pre-populate; safe default - return (snap["snap_distance_m"] <= AUTO_SNAP_TIGHT_M - and snap.get("road_class") in PAVED_HIGHWAY_CLASSES) - def _is_terrain_flat(self, lat: float, lon: float) -> bool: """True if the DEM is flat (max-min < FLAT_TERRAIN_DELTA_M) across the center and four cardinal points FLAT_SAMPLE_RADIUS_M away. Conservative: any DEM read @@ -859,15 +839,15 @@ class OffrouteRouter: seed_set = sorted(start_eligible | end_eligible) # === Valhalla bypass: pure road↔road skips the raster pipeline entirely === - # When BOTH endpoints are clearly ON a paved road -- by vehicle-eligible category hint - # OR a tight (<=5m) auto-snap to a paved highway (_bypass_eligible) -- the trip is - # on-road end-to-end, so hand it to the same inline-Valhalla path explicit vehicle - # requests use, saving the ~7.5s raster build + unified A*. Untagged raw-coordinate - # clicks now qualify via the tight-snap path; the relaxed (<=100m) snap is excluded so - # an off-road click isn't silently re-snapped to the road. Boundary-mode MVUM - # exclusions aren't applied here (urban roads aren't MVUM-gated). - if (self._bypass_eligible(start_lat, start_lon, start_category, snap_cache) - and self._bypass_eligible(end_lat, end_lon, end_category, snap_cache)): + # Fires when both endpoints have "vehicle" in _auto_eligible_modes's judgment (computed + # above) -- covers tagged road categories AND raw map clicks that land tight OR + # relaxed+flat+paved near a road. The _is_terrain_flat check inside + # _spatial_eligible_modes gates out wilderness/mountain false positives, so a relaxed + # (<=100m) snap only grants vehicle on benign flat ground (lot/shoulder/field) where a + # pure road route is the right answer. Hands off to the same inline-Valhalla path + # explicit vehicle requests use, saving the ~7.5s raster build + unified A*. Boundary-mode + # MVUM exclusions aren't applied here (urban roads aren't MVUM-gated). + if "vehicle" in start_eligible and "vehicle" in end_eligible: _bt0 = time.perf_counter() bypass = self._route_D_network_only(start_lat, start_lon, end_lat, end_lon, "vehicle") if bypass.get("status") == "ok": diff --git a/backend/services/navi_offroute/tests/test_offroute.py b/backend/services/navi_offroute/tests/test_offroute.py index 3881161..e5f7462 100644 --- a/backend/services/navi_offroute/tests/test_offroute.py +++ b/backend/services/navi_offroute/tests/test_offroute.py @@ -1405,15 +1405,32 @@ def test_route_auto_untagged_tight_snap_fires_bypass(monkeypatch): assert out["summary"]["auto_bypass"] is True -def test_route_auto_untagged_relaxed_snap_skips_bypass(monkeypatch): +def test_route_auto_untagged_relaxed_snap_fires_bypass(monkeypatch): + # PR #48: a relaxed (50m) snap that still grants "vehicle" (paved + flat-terrain grace in + # _spatial_eligible_modes) now fires the bypass -- we trust _auto_eligible_modes's judgment. r = object.__new__(OffrouteRouter) monkeypatch.setattr(OffrouteRouter, "_spatial_eligible_modes", _spatial_relaxed_paved) + monkeypatch.setattr(OffrouteRouter, "_fetch_auto_rasters", _bp_fetch_should_not_run) + monkeypatch.setattr(_p4router.requests, "post", lambda *a, **k: _BypassOKResp()) + out = r._route_auto(42.5558, -114.4701, 42.5644, -114.4631, "pragmatic") # no categories + assert out["status"] == "ok" + assert out["selected_mode"] == "vehicle" + assert out["summary"]["auto_bypass"] is True + + +def test_route_auto_untagged_no_vehicle_in_eligibility_skips_bypass(monkeypatch): + # Safety gate (preserved from PR #47 test 6): when _spatial_eligible_modes withholds + # "vehicle" -- e.g. _is_terrain_flat rejected a non-flat wilderness click near a road -- + # the bypass declines and the unified flow runs (preserving any walk-then-drive plan). + r = object.__new__(OffrouteRouter) + monkeypatch.setattr(OffrouteRouter, "_spatial_eligible_modes", + lambda self, lat, lon, cache: frozenset({"foot"})) monkeypatch.setattr(OffrouteRouter, "_route_D_network_only", lambda *a, **k: (_ for _ in ()).throw(AssertionError("D must not run"))) monkeypatch.setattr(OffrouteRouter, "_fetch_auto_rasters", _bp_fetch_sentinel) out = r._route_auto(42.5558, -114.4701, 42.5644, -114.4631, "pragmatic") # no categories assert out["status"] == "error" - assert "Failed to load terrain" in out["message"] # relaxed snap rejected -> unified flow + assert "Failed to load terrain" in out["message"] # no vehicle -> unified flow def test_route_auto_e2e_http_in_town_fires_bypass(client, monkeypatch):