cockpit-server: /OSM cockpit page — slippy map over the tile material - #74
Conversation
…ource
The Geo-domain (0x0F) map material for the /OSM cockpit: where OSM maps come
from, and how a slippy-tile address becomes an HHTL key.
- OSM_TILE_URL — the canonical slippy-tile source
(tile.openstreetmap.org/{z}/{x}/{y}.png); the client fetches the raster, the
cockpit only computes the address (no network on the request path).
- lonlat_to_tile — WebMercator (EPSG:3857) forward, no PROJ
(asinh(tan φ) = ln(tan+sec)).
- morton_interleave / tile_to_hhtl — z/x/y quadtree → 48-bit Morton → the three
16-bit HHTL tiers (HEEL/HIP/TWIG), coarse zoom left-aligned into HEEL
(tier = level>>3). The map pyramid and the semantic cascade are ONE address
(D-BOTHCASC), per docs/MERCATOR-HHTL-HELIX-MAP.md.
- Routes: GET /api/osm/locate?lon=&lat=&z= and /api/osm/tile/:z/:x/:y — return
tile address + source URL + HHTL key.
8 unit tests (null-island center tile, Berlin=(8802,5373), east→+x/south→+y,
Morton round-trip, HHTL round-trip at native depth, coarse-zoom-in-HEEL,
adjacent-tiles-share-HEEL).
Verification note: the tile MATH is verified standalone via rustc (all
assertions pass). The full `cargo test -p cockpit-server` cannot run in this
sandbox — the crate's pre-existing `v8` transitive dep fails its build.rs
(needs gn/ninja tooling not present here); this is orthogonal to this change,
which adds only std+serde+axum code. The unit tests run under CI where the v8
toolchain is available.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
|
Warning Review limit reached
Next review available in: 58 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit e88801c. Configure here.
|
|
||
| // ── click → server-side HHTL key ── | ||
| map.addEventListener('click',async e=>{ | ||
| if(drag) return; |
There was a problem hiding this comment.
Drag guard misses pan-end clicks
Medium Severity
Ending a pan with mouseup on the map still fires a click, which runs /api/osm/locate and refreshes the HHTL panel for the release point. The handler’s if(drag) return never applies because mouseup already sets drag to null before click runs.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit e88801c. Configure here.
| document.getElementById('twig').textContent='0x'+d.hhtl.twig.toString(16).padStart(4,'0'); | ||
| document.getElementById('src').textContent=d.tile_url; | ||
| }catch(err){ document.getElementById('src').textContent='locate failed: '+err; } | ||
| }); |
There was a problem hiding this comment.
Zoom buttons bubble map clicks
Medium Severity
The zoom +/− controls sit inside #map, and their clicks bubble to the map’s click listener. Each zoom action also triggers /api/osm/locate and updates the side panel from the button’s screen position, not an intentional map pick.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit e88801c. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e88801c2d3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let hhtl = tile_to_hhtl(z, x, y); | ||
| Json(serde_json::json!({ | ||
| "z": z, "x": x, "y": y, | ||
| "tile_url": tile_url(z, x, y), |
There was a problem hiding this comment.
Clamp tile route zoom before returning metadata
/api/osm/tile/:z/:x/:y accepts any u32, but here tile_to_hhtl silently clamps z to 24 while the JSON and tile_url below still echo the original z/x/y. For inputs such as /api/osm/tile/25/16777216/0, the HHTL key is computed from the low 24 bits rather than the z=25 tile's z=24 parent, so the returned key/source describe different tiles. Reject out-of-range z/x/y or normalize them before computing and returning metadata.
Useful? React with 👍 / 👎.
| const px=e.clientX-r.left, py=e.clientY-r.top; | ||
| const w=map.clientWidth, h=map.clientHeight; | ||
| const fx=cx+(px-w/2)/256, fy=cy+(py-h/2)/256; | ||
| const lon=x2lon(fx,z), lat=y2lat(fy,z); |
There was a problem hiding this comment.
Wrap click coordinates before locating tiles
The renderer wraps horizontal tile indices when drawing repeated world copies, but this click path sends x2lon(fx,z) without wrapping fx back into [0, 2^z). At low zooms where multiple world copies are visible, or after panning across ±180°, clicks on a wrapped copy send longitudes outside [-180, 180]; /api/osm/locate then clamps them to edge tiles, so the panel's z/x/y and HHTL key do not match the tile under the cursor. Normalize fx before converting or sending it.
Useful? React with 👍 / 👎.
Review fix (Bugbot Medium + codex P2 on #73): for z > 24, tile_to_hhtl only capped z and set the left-align shift to 0, leaving x/y at the finer scale so Morton encoded the LOW 24 bits — the HHTL key didn't match the requested tile and deep tiles could alias. Now a zoom deeper than the native depth resolves to its z=24 ANCESTOR: the excess low bits of x/y are dropped (x >> (z-24)), so the key is always a valid prefix of the tile and two children of one z=24 tile share it. New `resolved_tile()` exposes the ancestor z/x/y, and /api/osm/tile/:z/:x/:y now returns a `resolved` field so the key and address never silently describe different tiles. Locate is unaffected (its z is already clamped ≤ 24). Test `over_depth_zoom_folds_to_its_native_ancestor` locks it (verified standalone via rustc: hhtl(25,2,3) == hhtl(24,1,1), ≠ the old low-bit value). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
The Geo-domain (0x0F) sibling of the FMA body-helix cockpit. A self-contained `/osm` page (the /mri page pattern — one inline HTML string, no build step, no external JS): - pan/zoom OSM raster tiles fetched directly from the standard source (tile.openstreetmap.org), with attribution; - click any point → GET /api/osm/locate → the tile's z/x/y + source URL + the three HHTL tiers (HEEL/HIP/TWIG) shown live; - the JS slippy math mirrors cockpit-server::osm_tiles; the HHTL key is resolved server-side so the map pyramid and the cascade address are one source of truth. Route: GET /osm. Verification note: the embedded JS is validated via `node --check` (3.1 KB, OK) and the Rust raw-string delimiter is confirmed collision-free. The full `cargo test -p cockpit-server` cannot run in this sandbox (pre-existing `v8` transitive dep fails its build.rs — no gn/ninja toolchain); the page handler is a trivial `Html<String>` const mirroring the existing `mri_page_handler`, wired like every other cockpit route. Stacks on #73 (the osm_tiles material it calls). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
… on click Review fixes (Bugbot + codex on #74): - Pan-end `mouseup` fired a `click` that ran /api/osm/locate for the release point; `if(drag) return` never applied because `mouseup` nulls `drag` first. Track a `moved` flag (set on real drag) and suppress the trailing click. - The zoom +/− controls live inside #map, so their clicks bubbled to the map's click→locate handler. `e.stopPropagation()` on both. - The click path sent `x2lon(fx)` without wrapping `fx` into [0,2^z); at low zoom / across ±180° that yields an out-of-range longitude the server clamps to an edge tile. Wrap `fx` modulo 2^z before converting. Embedded JS re-validated via `node --check`. (osm_tiles over-depth fix rides in from #73, which this branch now rebases onto.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
e88801c to
959a8c9
Compare
|
Review fixes pushed (
Embedded JS re-validated via Generated by Claude Code |


What
The Geo-domain (
0x0F)/OSMcockpit — the sibling of the FMA body-helixcockpit. A self-contained
/osmpage (the/mripattern: one inline HTMLstring, no build step, no external JS).
The page
(
tile.openstreetmap.org), with OpenStreetMap attribution.GET /api/osm/locate→ the panel shows the tile'sz / x / y, the source URL, and the three HHTL tiers (HEEL / HIP / TWIG)live.
cockpit-server::osm_tiles; the HHTL key isresolved server-side, so the map pyramid and the cascade address are one
source of truth (D-BOTHCASC).
Route:
GET /osm.Depends on
Stacks on #73 (the
osm_tilesmaterial —/api/osm/locateetc.). Merge #73first.
Verification note
node --check(3.1 KB, OK); the Rust raw-stringdelimiter is confirmed collision-free.
cargo test -p cockpit-servercannot run in my sandbox (thepre-existing
v8transitive dep fails itsbuild.rs— no gn/ninjatoolchain). The page handler is a trivial
Html<String>const mirroring theexisting
mri_page_handler, wired like every other cockpit route. Flaggingper q2's "say so explicitly if you can't verify end-to-end" rule — a
maintainer with the v8 toolchain (CI) compiles it.
🤖 Generated with Claude Code
https://claude.ai/code/session_01EYvNjD8M8LMNYbRy3gq2FP
Generated by Claude Code