osm cockpit: rehydrate clicked features into their real shapes - #116
Conversation
The decode half of the .chains codec (osm-soa-bake PR #23): the bake already computed every way's z=32 vertex chain and dropped it after mean_cell — the sidecar un-discards it, and this side reads it back. - osm_features: GET /api/osm/geometry/:idx — open the .chains sidecar once (OnceLock), REFUSE it unless its slab_digest matches the mapped slab (cross-bake geometry against another bake's identities is the drift the pin exists to make loud), resolve row -> identity ordinal -> chain -> lon/lat points. 404 when no chain is stored (nodes, relations) — never 200-with-empty. - osm page: an SVG shape layer inside #tiles (inherits the map transform); classFor(tags) fills water/building/wood/green rings and strokes highways; showShape wired into the existing click detail. - osm_slab_hydrate: ARTIFACTS grows to berlin.chains — a deploy now hydrates all three artifacts (~1.42 GB cold; volume >= 2 GB). The bucket's SHA256SUMS gained the third line additively, so binaries reading only soa+books still verify. Verified in a real browser against the real Berlin bake: a genuine click on a harbour dot resolved "Westhafen I" (natural=water, water=harbour) and drew its shore ring filled; building and landuse rings and a highway polyline drawn via the page's own showFeature; a node correctly 404s; zero page errors. Gaps the POC now makes visible (by design — the POC is the falsifier): shapes are click-only rather than a base fill layer with a node/street overlay; multipolygon relations are unassembled; small rings are sub-pixel at overview zoom. Recorded in the plan's Phase 8. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NMeiLmtDKhomJNSo2ecbJw
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThe change adds a validated ChangesOSM geometry flow
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant cockpit-server
participant OSM slab
participant chains sidecar
Browser->>cockpit-server: Request geometry for selected feature
cockpit-server->>OSM slab: Validate feature row and identity
cockpit-server->>chains sidecar: Resolve ordinal chain
chains sidecar-->>cockpit-server: Return encoded vertex chain
cockpit-server-->>Browser: Return decoded coordinates
Browser->>Browser: Render polygon or polyline
Possibly related PRs
Suggested reviewers: Poem
✨ Finishing Touches📝 Generate docstrings
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 |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_be351fb9-becd-4ddb-869f-42eac801131d) |
The map was someone else's raster with our data sprinkled on top: OSM_TILE_URL pointed at tile.openstreetmap.org and SAT_TILE_URL at Esri, and the 1.42 GB Berlin bake supplied only the feature dots plus the shape of the one feature you clicked. "The map pyramid and the slab's row key are one and the same address" was true as arithmetic while every pixel was rented — and a deployed host on the OSMF tile server also runs against its usage policy. The decode half already existed (.chains holds every way's z=32 vertex chain; query_geometry reads one by row index). This serves them per tile and draws them client-side in the SVG layer #116 added. Server: - ShapeClass + class_for_tags: the semantic category is derived from the tags the bake already stored and served per shape. Shipping every shape's tags would multiply the payload by the tag fan-out for data a viewer wants about one shape at a time. FeatureGeometryOut carries the same field, so the click path and the basemap share ONE classification in Rust — the JS classFor(tags) rule is deleted, not duplicated. - simplify_cells: drops vertices landing on the same (sub)pixel, as an integer compare on the codec's own z32 grid — the display's resolution IS the tolerance, so there is no constant to tune. First/last always survive, so a ring that survives stays closed. - geometry_row_budget + query_tile_geometry, reusing overview_sample so the cascade-cell selection keeps isolated features. Reports total/sampled/returned/malformed separately: a thin basemap must read as LOD, and a corrupt sidecar must not look like an empty neighbourhood. Client: - vector is the DEFAULT basemap; the raster skins stay behind the toggle as the reference to check our render against. - The layer is retained across pan frames and rebuilt only on zoom. A pan changes the transform, not world-pixel coordinates, so rebuilding per frame would be the same n^2 append the drawnCells comment warns about. - The tile-source readout names the source actually in use. Mobile (bundled per operator request): the page was unusable on a phone. grid-template-columns:1fr 320px left the map 70px wide on a 390px viewport, and drag was bound to mousedown/mousemove with no touch-action, so the map could not be panned by finger at all. Stacked layout under a 720px breakpoint, pointer events with a tracked pointerId, and touch-action:none. Measured before/after in headless Chromium against the shipped page, with the bake endpoints stubbed (the container has no slab): before after phone map 70x844 (18% of vp) 390x490 (100%) external req 141-277 to tile.osm.org 0 touch pan does not move the map moves the map raster <img> 18-42 0 Tests: 95 passed, 0 failed. The five new ones are two-sided — class precedence is checked in both tag orders (a first-match implementation returns Green for one of them), and simplification is pinned at z4/z22/z23 so it tracks pixel_shift's real arithmetic rather than "fewer points when zoomed out". NOT verified against the real bake: this container lost the slab on restart and AWS_S3_BUCKET_NAME is unset, so the render path over real Berlin data is unverified until the deploy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NMeiLmtDKhomJNSo2ecbJw
The decode half of the
.chainscodec (companion to AdaWorldAPI/openstreetmap-website-rs#23): the bake already computed every way's z=32 vertex chain and dropped it aftermean_cell— the sidecar un-discards it, and this side reads it back. Rehydration rules come from the same business logic that encoded the cells; the consumer never re-interprets bytes (encode and decode live in one module ofosm-soa-bake).What changed
osm_features.rs—GET /api/osm/geometry/:idx: opens the.chainssidecar once (OnceLock), refuses it unless itsslab_digestmatches the mapped slab (geometry from one bake against another bake's identities is silent cross-bake corruption — the pin makes it loud), resolves row → identity ordinal → chain → lon/lat points. 404 when no chain is stored (nodes, relations) — never 200-with-empty.osm.rs— an SVG shape layer inside#tiles(inherits the map transform);classFor(tags)fills water/building/wood/green rings and strokes highways;showShapewired into the existing click detail;vector-effect: non-scaling-stroke.osm_slab_hydrate.rs—ARTIFACTSgrows toberlin.chains: a deploy now hydrates all three artifacts (~1.42 GB cold; volume ≥ 2 GB). The bucket'sSHA256SUMSgained its third line additively, so binaries reading only soa+books still verify.claude-notes/plans/2026-08-08-osm-soa-cockpit-wiring.md).Verified
cargo test --bin q2-cockpit: 90 passed, 0 failed, 3 ignored.natural=water,water=harbour) and drew its shore ring filled — the See/Ufer model on a literal water body. Building ring (8 pts), landuse ring (48 pts), highway polyline drawn via the page's ownshowFeature; a node correctly 404s; zero page errors.berlin.chains(63,777,240 B, sha256276253f0…350aae) uploaded to theberlin-v1S3 prefix; the bake is byte-deterministic (slab digest8ec93a6ee63e89d2across two runs), so the new sidecar pins to the already-published slab.Gaps the POC now shows (by design — the POC is the falsifier)
🤖 Generated with Claude Code
https://claude.ai/code/session_01NMeiLmtDKhomJNSo2ecbJw
Generated by Claude Code
Summary by CodeRabbit
New Features
Documentation