Commit graph

3 commits

Author SHA1 Message Date
Matt
10960ca886 fix(navi): vehicle skips off-network gate; boundary chips show for non-Drive
Vehicle is pure Valhalla road routing — Valhalla snaps endpoints to the nearest
road automatically, so the off-network classifier (OFF_NETWORK_THRESHOLD_M) is
irrelevant for it. Add an early branch in route() that sends vehicle straight to
_route_D_network_only, instead of bandaiding the threshold. Foot/MTB/ATV keep the
gate so users can intentionally pin backcountry points; Auto inherits the skip via
its recursive mode=vehicle probe. Threshold stays at 10.

Frontend: boundary-mode chips now show for all modes except Drive (vehicle).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 16:34:03 +00:00
Matt
c1f71ccdc5 feat(offroute): backend Auto mode probes [vehicle,atv,mtb,foot]
When mode="auto", OffrouteRouter._route_auto() probes AUTO_MODE_PRIORITY
(vehicle -> atv -> mtb -> foot) and returns the first mode whose network can
serve the route, tagging the result with selected_mode. route() already errors
when a mode cannot reach an endpoint, so the first status==ok is the most
road-capable feasible mode. Adds 4 isolation tests (route monkeypatched).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 08:53:23 +00:00
ae82cee46a Add navi-offroute service (extraction #8 — final) (#10)
* Add navi-offroute service (extraction #8 — the last one)

Faithful port of recon's /api/offroute (POST) + /api/mvum (GET) and the
runtime offroute modules into a new :8428 service. Closes the loop: after
this, navi-frontend talks only to navi-backend.

Ported: router.py (OffrouteRouter, EntryPointIndex, 4 route strategies,
in-Python MCP_Geometric least-cost path, Valhalla integration, per-request
osmium extract), mvum.py (MVUMReader over navi.db), cost.py, friction.py,
trails.py, and barriers.py (runtime BarrierReader/WildernessReader only).

NOT ported (per Phase A §3/§15): prototype.py (dead at runtime), barriers.py
build_*_raster (offline GDB→raster prep). DEM imported from shared/dem.py
(PR #9), not duplicated.

Behaviour-faithful changes: hardcoded paths/URLs → env vars; the
profile.offroute.* config (osm_pbf_path/postgis_dsn/densify_interval_m) →
dedicated env vars (router drops deployment_config). Both routes public (no
auth, matching recon). PADUS via libpq peer-auth DSN (dbname=padus) — NO
secret. Owns no DB.

15 hermetic tests (offroute validation + mocked-router shape + close-always;
fixture-SQLite MVUM roads/trails/fallback/null; admin auth + no-secrets +
probe shape). Full suite 119 passed / 1 skipped. Adds scikit-image + rasterio.

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

* navi-offroute: PR #10 review cleanups (4 faithful-port deviations)

1. trails.py — drop recon-era "Run the Phase B rasterization script"
   reference from the not-found error (confusing in navi-offroute context).
2. friction.py — add FileNotFoundError-before-rasterio-open check to
   match barriers/trails consistency.
3. mvum.py — remove dead try/except shapely import + warnings.warn at
   2 sites (shapely is a hard pyproject dep; the fallback was unreachable).
4. router.py — declare psutil in pyproject, drop the silent fallback;
   the MEMORY_LIMIT_GB safety check was silently disabled in prod.

Adds test_friction_reader_raises_file_not_found_when_missing (16 navi-offroute
tests; full suite 120 passed / 1 skipped).

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

---------

Co-authored-by: zvx-echo6 <mj@k7zvx.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 23:30:43 -06:00