Skip to content

cockpit-server: /OSM cockpit page — slippy map over the tile material - #74

Merged
AdaWorldAPI merged 4 commits into
mainfrom
claude/q2-osm-cockpit
Jul 5, 2026
Merged

cockpit-server: /OSM cockpit page — slippy map over the tile material#74
AdaWorldAPI merged 4 commits into
mainfrom
claude/q2-osm-cockpit

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

What

The Geo-domain (0x0F) /OSM cockpit — the sibling of the FMA body-helix
cockpit. A self-contained /osm page (the /mri pattern: one inline HTML
string, no build step, no external JS).

The page

  • Pan / zoom OSM raster tiles fetched directly from the standard source
    (tile.openstreetmap.org), with OpenStreetMap attribution.
  • Click any pointGET /api/osm/locate → the panel shows the tile's
    z / x / y, the source URL, and the three HHTL tiers (HEEL / HIP / TWIG)
    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 (D-BOTHCASC).

Route: GET /osm.

Depends on

Stacks on #73 (the osm_tiles material — /api/osm/locate etc.). Merge #73
first.

Verification note

  • Embedded JS validated via node --check (3.1 KB, OK); the Rust raw-string
    delimiter is confirmed collision-free.
  • The full cargo test -p cockpit-server cannot run in my sandbox (the
    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. Flagging
    per 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

…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
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AdaWorldAPI, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 58 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d4d5a644-8112-4281-a028-32f5fb7bcd69

📥 Commits

Reviewing files that changed from the base of the PR and between 54dcce0 and 959a8c9.

📒 Files selected for processing (3)
  • crates/cockpit-server/src/main.rs
  • crates/cockpit-server/src/osm.rs
  • crates/cockpit-server/src/osm_tiles.rs

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Fix All in Cursor

❌ 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.

Comment thread crates/cockpit-server/src/osm.rs Outdated

// ── click → server-side HHTL key ──
map.addEventListener('click',async e=>{
if(drag) return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Fix in Cursor Fix in Web

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; }
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e88801c. Configure here.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +143 to +146
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),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

claude added 3 commits July 5, 2026 04:55
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
@AdaWorldAPI
AdaWorldAPI force-pushed the claude/q2-osm-cockpit branch from e88801c to 959a8c9 Compare July 5, 2026 04:56

Copy link
Copy Markdown
Owner Author

Review fixes pushed (959a8c9, rebased onto the #73 fix). All four threads:

  • Pan-end click fires locate (Bugbot Medium) — if(drag) return never applied because mouseup nulls drag before click. Now a moved flag (set on real drag) suppresses the trailing click.
  • Zoom buttons bubble to map click (Bugbot Medium) — e.stopPropagation() on both +/ (they live inside #map).
  • Click longitude not world-wrapped (codex P2) — the click path now wraps fx into [0, 2^z) before x2lon, so clicks on a repeated world copy (low zoom / across ±180°) send an in-range longitude instead of an edge-clamped one.
  • Tile-route zoom clamp (codex P2) — fixed in cockpit-server: OSM tile material — WebMercator z/x/y ↔ HHTL + tile source #73 (tile_to_hhtl ancestor fold + resolved field); this branch rebases onto it.

Embedded JS re-validated via node --check.


Generated by Claude Code

@AdaWorldAPI
AdaWorldAPI merged commit a01f3a9 into main Jul 5, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants