OSM building extrusion — height by tag (headless proof)
The extruder already lifts a closed building footprint into a prism whose height comes from the OSM tag (height=<m|ft> wins, else (building:levels + roof:levels) × METRES_PER_LEVEL = 3.2 m, else DEFAULT_BUILDING_HEIGHT_M = 6 m with jitter). Path: facett_map::parse_building_height_m → Way::height_m → extrude::building_design_height (metric height scaled by the data's world span into design units) → prism lift in extrude::build. Always-on (no toggle).
What was missing → what landed
The extrusion + height-from-tag were built and unit-tested for shape (a footprint becomes a real 3D mesh), but nothing asserted height scales with the tag as data. tests/building_extrusion_proof.rs closes that — a GPU-free, pixel-free A/B:
-
Fixed 2-building layout (a short scale-anchor pins the world span so design-units-per-metre is constant); only the test building's
heighttag varies. -
Measures the extruded
Mesh3max Y (the height axis):height=10 < height=40 < height=80— strictly monotonic (taller tag → taller mesh).- same vertex count across the three — it's height, not more tessellation.
- deterministic re-extrude (tagged heights use no jitter/RNG).
-
Emits the
facett-map3d/building_extrusion_height_by_tagtest-matrix cell.
Law #1: no re-implementation — the proof drives the existing extrude::build.
2026-08-31 — the tag PARSER was the defect, and tests/no_building_spikes.rs
building_extrusion_proof only ever fed height=<a plain number>, so it could not see that the parser took the leading digit run off whatever it was given: height=99999 was a 99 999 m spike, height=25' was 25 m instead of 7.62 m, height=1;12 was a 1 m house, height=102,5 was 102 m, building:levels=3-4 was 3 levels. All five silent, all five live in korp's 3D view.
tests/no_building_spikes.rs is the mesh-level gate: each defect's rooftop Y is compared against the mesh built from the value's CORRECT reading (same osm id, same ring, so the untagged jitter is identical and the only difference is the height), plus a MAX_PLAUSIBLE_HEIGHT_M = 1000 m ceiling on the applied output, plus the untagged default pinned to 5.6119 m as a literal so correcting METRES_PER_LEVEL 3.0 → 3.2 could not move the 95.68 % of buildings that carry no height tag at all.
Full reasoning, the measurement behind 3.2, and the corpus that keeps facett's parser and osm_katana::shared::height in step: .nornir/building-height-design.md.
Next (headless-verifiable) garmin/earth steps
turn/lane arrows · collision-managed labels+shields · flight-camera pose-over-path. Night-mode / GTAO pixel A/B → bench box.