Viewing rides on webmap.dev — Squeeze zones + Cue events

The repo ships two export tools whose GeoJSON output loads directly into webmap.dev’s overlay pair:

Overlay (webmap.dev) Exporter Shows
Squeeze zones cue-zone-export (webmap.dev#227) Where the imported region would cue — the static zones
Cue events cue-events-export (webmap.dev#231) What one ride actually did — fired cues, their grades, delivery, and rider markers

Loaded together they close the §13 tuning loop visually: the zones say where the policy watches, the events say what happened there.

Privacy first (NFR-005). Every file below — the Overpass extract, the ride trace, the latency sidecar, and both GeoJSON exports — reveals where you ride. They all stay on your machine: *.geojson, /region.json, and /rides/ are gitignored, and webmap.dev bundles no data for the same reason — you hand it a local file per session, nothing more. Never commit any of these; tests use hand-built synthetic fixtures only.

1. Get an Overpass extract for your ride region

Both exporters take the same input the app’s “Import region…” picker does: an Overpass out geom; JSON response for your riding area’s bounding box (south, west, north, east):

QUERY='[out:json][timeout:60];
way["highway"~"^(primary|secondary|tertiary|residential|unclassified|trunk|primary_link|secondary_link|tertiary_link|living_street)$"](SOUTH,WEST,NORTH,EAST);
out geom;'
curl -sS --fail --max-time 90 -X POST --data-urlencode "data=$QUERY" \
  https://overpass-api.de/api/interpreter > region.json

The highway-class filter matches rideableHighwayClasses in the importer (and tools/osm_tag_audit.sh). The query must end in out geom; — a tags-only fetch has no geometry to export. If Overpass returns a remark field, the data is truncated and both tools refuse it; retry or shrink the bbox. Note the bbox itself is disclosed to the public Overpass endpoint — use a box comfortably larger than your actual loop.

2. Squeeze zones — export and view

Export the scored zones through the same importer/scorer the app runs:

swift run cue-zone-export region.json -o squeeze-zones.geojson

The summary line reports ways → segments → zones. Then, on webmap.dev:

  1. Open the layers control and toggle Squeeze zones on.
  2. The overlay prompts with a file picker — choose squeeze-zones.geojson.
  3. The choice persists in the browser’s localStorage for the session pattern webmap.dev uses; re-toggling the overlay re-reads your file without re-picking. Clearing site data forgets it.

A malformed or wrong-shape file is rejected at load with an error and the overlay stays empty — nothing partial is drawn or persisted.

Each zone renders as its member segment polylines; features sharing an event_id are one logical zone. Popups show severity, confidence, and the decoded reasons_bitmask (narrow lane / no shoulder or bike lane / high-speed context).

3. Cue events — export and view

After a ride, export the trace from the app (and the latency sidecar, if you want delivery facts), then join them with the region extract:

swift run cue-events-export ride-trace.json region.json \
  --latency ride-latency.json -o cue-events.geojson

Load it the same way: layers control → Cue events → file picker.

Legend (webmap.dev#231):

Marker Meaning
Green point outcome: useful
Red point outcome: false_alarm
Orange point outcome: too_late
Purple point outcome: unrecognized
Gray point ungraded (no review yet)
Dashed ring delivered: false — the cue never reached the wrist
Triangle rider marker (“unsafe here”, FR-006)

4. Reading the two overlays together

Cue-event points sit on the zone that fired them — popups on both overlays share event_id and segment_id, so a point and its zone cross-reference directly. Patterns worth acting on in the §13 loop:

5. Keeping it private

One stance, end to end: map data and ride data stay on the operator’s machines. The repo’s .gitignore guards *.geojson, /region.json, and /rides/; webmap.dev holds nothing server-side and bundles no data. If you share a screenshot, remember the base map itself shows where you ride.