osm basemap: split the green bucket, texture the ground cover, region as config - #121
Conversation
…ke a region a config value Three things, all found from the live deploy. 1. THE FLAT GREEN WASH. `class_for_tags` collapsed landuse|leisure|natural into one `Green` bucket, so `landuse=residential` — which covers most of a suburb — rendered as vegetation. A whole z16 viewport read as meadow. Split into `Meadow` (grass/farmland/heath), `Park` (leisure/cemetery) and `Built` (residential/industrial/commercial, grey and NOT green), with `Green` kept as the fallback so widening the specific set can never demote something to `Other`. Wire codes are APPENDED (7/8/9), never inserted: 0-6 stay a contract with the client's CLASS_ORDER, so an older client renders a new class as unknown rather than as the wrong one. One pre-existing assertion moved: `leisure=park` asserted `Green` because that WAS the collapsed behaviour. It is re-pinned to `Park` with a comment saying the behaviour changed deliberately — not a test edited for convenience. 2. MEADOWS HAD NO TEXTURE (operator). A flat fill cannot tell a meadow from a park from a lawn, and at z16 those are most of the viewport. Canvas gives this cheaply where SVG would not have: one 8x8 offscreen tile per texture, built once, handed to createPattern and reused for every polygon of that class — one pattern object per session, not per shape. Stipple for meadow, canopy strokes for wood. The pattern is deliberately NOT transform- corrected: it is created in canvas space and we translate() per tile, so the texture rides with the map instead of crawling under it while panning. 3. A REGION IS NOW CONFIG, NOT CODE. `ARTIFACTS` was hardcoded to berlin.* and the prefix to q2/bakes/berlin-v1, so a second bake needed a code change. `OSM_BAKE_REGION` now drives artifact names, S3 prefix and the volume path. The name is validated to [a-z0-9-]: it is interpolated into an S3 key AND joined onto a filesystem path, so `..` or `/` would traverse — an invalid value warns and falls back rather than building that path. Because the cache dir is region-keyed, two regions coexist on one volume and flipping between them costs no re-download. Also: the books header's `slab` digest — the same cross-bake pin `.chains` already enforces — was being DISCARDED (`Ok((_header, books))`). A codebook from a different bake was accepted silently, resolving every ordinal to some other bake's string. Now verified, and a magic mismatch is reported as an OUTDATED bake format naming expected vs found, instead of a generic "unreadable" after which every shape silently falls to `ShapeClass::Other`. Verified in headless Chromium against the shipped page, bake endpoints stubbed with the new classes: 2,698 distinct painted colours (was a flat wash), textures visible, 0 SVG nodes, 0 external requests, pan repaints, and the binary wire still 4.7x smaller than JSON on the same shapes. Docs: claude-notes/instructions/osm-bake-new-region.md — the BW runbook with measured sizing (645 MB PBF vs Berlin's 99 MB; ~9.1 GB output; budget 32 GB RAM, which is why BW cannot be baked in the dev container). 103 passed, 0 failed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NMeiLmtDKhomJNSo2ecbJw
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_f1070966-f1c6-45f6-8678-fac60959a3c1) |
|
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 (4)
📝 WalkthroughWalkthroughThe PR adds operational instructions for baking Baden-Württemberg OSM data, supports region-specific slab hydration, introduces Meadow, Park, and Built feature classes, strengthens sidecar validation, and renders new classes with textured basemap styles. ChangesOSM region and basemap updates
Estimated code review effort: 3 (Moderate) | ~25 minutes 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 |
Three findings off the live deploy. None of these is the bake-format work (see the note at the bottom) — this is the render side plus the config that a second region needs.
1. The flat green wash was my class table
class_for_tagscollapsedlanduse|leisure|naturalinto oneGreenbucket, solanduse=residential— which covers most of a suburb — rendered as vegetation. That is why a whole z16 Zehlendorf viewport read as meadow.Split into
Meadow(grass/farmland/heath),Park(leisure/cemetery),Built(residential/industrial/commercial — grey, not green), withGreenkept as the fallback so widening the specific set can never demote something toOther.Wire codes are appended (7/8/9), never inserted: 0-6 stay a contract with the client's
CLASS_ORDER, so an older client renders a new class as unknown rather than as the wrong one.One pre-existing assertion moved:
leisure=parkassertedGreenbecause that was the collapsed behaviour. Re-pinned toParkwith a comment saying the behaviour changed deliberately — flagging it rather than quietly editing a test that got in the way.2. Meadows had no texture
A flat fill cannot tell a meadow from a park from a lawn, and at z16 those are most of the viewport. Canvas gives this cheaply where the old SVG layer would not have: one 8×8 offscreen tile per texture, built once, handed to
createPatternand reused for every polygon of that class — one pattern object per session, not per shape. Stipple for meadow, canopy strokes for wood.The pattern is deliberately not transform-corrected: it is created in canvas space and we
translate()per tile, so the texture rides with the map instead of crawling underneath it while panning.3. A region is now config, not code
ARTIFACTSwas hardcoded toberlin.*and the prefix toq2/bakes/berlin-v1, so a second bake required a code change.OSM_BAKE_REGIONnow drives artifact names, S3 prefix and volume path.The name is validated to
[a-z0-9-]— it is interpolated into an S3 key and joined onto a filesystem path, so..or/would traverse; an invalid value warns and falls back rather than building that path. Because the cache dir is region-keyed, two regions coexist on one volume and flipping between them costs no re-download.Also: a discarded cross-bake pin
open_booksdidOk((_header, books))— the header'sslabdigest, the same cross-bake pin.chainsalready enforces, was thrown away. A codebook from a different bake was accepted silently, resolving every ordinal to some other bake's string. Now verified. And a magic mismatch is reported as an outdated bake format naming expected vs found, instead of a generic "unreadable" after which every shape silently falls toShapeClass::Other.Verified
Headless Chromium against the shipped page, bake endpoints stubbed with the new classes:
103 tests pass, 0 failed.
Docs:
claude-notes/instructions/osm-bake-new-region.md— the Baden-Württemberg runbook with measured sizing (645 MB PBF against Berlin's 99 MB; ~9.1 GB output; budget 32 GB RAM, which is why BW cannot be baked in the dev container).What this does NOT do
It does not produce a bake in the new format.
EdgeBlockis still written zeroed by the baker (build_row: "edges — zeroed. Reserved, never shrunk."), there are no junction/street-node rows, andBOOKS = 3is pinned so a label codebook is a fourth book and anOSMCBK\0\x02→\0\x03version bump. That work is the actual re-bake and is tracked separately.🤖 Generated with Claude Code
https://claude.ai/code/session_01NMeiLmtDKhomJNSo2ecbJw
Generated by Claude Code
Summary by CodeRabbit