From e444a7cc9cf2fd29edede7aea7d121aaaeb83178 Mon Sep 17 00:00:00 2001 From: Yorick de Wid Date: Thu, 6 Aug 2026 14:29:41 +0000 Subject: [PATCH] fix(tiles): height must be double precision, not numeric MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ST_AsMVT has no MVT value type for numeric and encodes it as a STRING. Caught by decoding a dynamic tile against its static counterpart: static : "height": 3.25 dynamic: "height": "3.25" Both incident.json and the four QuickScan layer configs feed ["get","height"] straight into fill-extrusion-height, which needs a number — every one of those layers would have rendered flat. building_tiles has always declared height as double precision, which is why the buildings source never hit this. Already applied to prod (the tables were recreated from the corrected files and repopulated); this lands the same state in git. After the fix the facade_scan tile is property-for-property and value-for-value identical to the static one. Co-Authored-By: Claude Opus 5 (1M context) --- sql/model/create_facade_scan_tiles.sql | 9 +++++++-- sql/model/create_incident_tiles.sql | 8 ++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/sql/model/create_facade_scan_tiles.sql b/sql/model/create_facade_scan_tiles.sql index 92bf7f6..0c56e3b 100644 --- a/sql/model/create_facade_scan_tiles.sql +++ b/sql/model/create_facade_scan_tiles.sql @@ -28,7 +28,12 @@ CREATE TABLE IF NOT EXISTS maplayer.facade_scan_tiles ( neighborhood_id text, district_id text, municipality_id text, - height numeric, + -- double precision, NOT numeric: ST_AsMVT has no MVT type for numeric and + -- encodes it as a STRING, which silently breaks fill-extrusion-height + -- (["get","height"] must yield a number or the layer renders flat). + -- The static tippecanoe tiles emitted a number here; building_tiles has + -- always used double precision for the same reason. + height double precision, owner text, -- report.rotation_type / report.crack_type / report.facade_scan_risk / -- data.foundation_risk_indication stored as text: ST_AsMVT emits the @@ -64,7 +69,7 @@ AS $$ f.neighborhood_id, f.district_id, f.municipality_id, - f.height, + f.height::double precision, f.owner, f.skewed_parallel_facade::text, f.skewed_perpendicular_facade::text, diff --git a/sql/model/create_incident_tiles.sql b/sql/model/create_incident_tiles.sql index e6ded5a..7ff040c 100644 --- a/sql/model/create_incident_tiles.sql +++ b/sql/model/create_incident_tiles.sql @@ -37,7 +37,11 @@ CREATE TABLE IF NOT EXISTS maplayer.incident_tiles ( -- report.foundation_damage_cause as text: ST_AsMVT emits the enum label -- either way, and text keeps this table independent of enum DDL. foundation_damage_cause text, - height numeric, + -- double precision, NOT numeric: ST_AsMVT has no MVT type for numeric and + -- encodes it as a STRING, which silently breaks fill-extrusion-height + -- (incident.json feeds ["get","height"] straight into it). The static + -- tippecanoe tiles emitted a number here. + height double precision, geom geometry(MultiPolygon, 3857) ); @@ -110,7 +114,7 @@ AS $$ d.external_id, m.external_id, i.foundation_damage_cause::text, - round(GREATEST(bh.height, 0::real)::numeric, 2), + round(GREATEST(bh.height, 0::real)::numeric, 2)::double precision, ST_Multi(ST_Transform(ba.geom, 3857)) FROM report.incident i JOIN geocoder.building_active ba ON ba.external_id = i.building_id::text