BDOT10k mislabels 5 845 km² of the Baltic as a lake (source bug, not ours) #43

Open
opened 2026-08-03 08:16:03 +00:00 by art-bot · 1 comment
Collaborator

Noticed while measuring #36. The mislabelling is in BDOT10k, not in our import — worth
saying up front, because the shape of it looks exactly like a botched union on our side.

What

map_water_bodies_<z> carries a 5 845 km² polygon named Morze Bałtyckie, classed
lake. It is the largest "lake" in the database by a factor of 29 and it is a chunk of the
Baltic.

conf/plmap.yaml's water_bodies query is WHERE rodzaj <> 'woda morska' and maps
everything surviving to river (woda płynąca) or lake. That is correct, and the source
is what is wrong. In the pl_ptwp staging table, loaded natively from the county
GeoPackages with nothing of ours applied:

      nazwa      |    rodzaj    | n  |  km2
-----------------+--------------+----+-------
 Morze Bałtyckie | woda morska  | 16 | 70995
 Morze Bałtyckie | woda stojąca |  1 |  5845   <- one row, wrong rodzaj
 Jamno           | woda stojąca |  5 |    65

Sixteen rows say marine, one says standing water. The odd one out is teryt 3209
(powiat koszaliński), centroid 54.56 N 15.79 E, and it lies 426 m from Jezioro Jamno —
which is the lagoon just north of Koszalin that is very nearly touching the sea. So the
guess that the lake infected the sea with its lakeness is probably right, and it happened
upstream of us: one county's delivery has a slab of the Baltic attributed as woda
stojąca
.

Why it matters a little

  • It is drawn in the same blue as the sea, so nothing is visibly wrong today. This is a
    data-quality and attribute-correctness problem, not a rendering one.
  • It survives to z5 (66 km wide, so nothing generalization does will remove it) and is 5 845
    km² of polygon in every water_bodies tile along that coast.
  • Anything that ever reasons about water_class — a label, a marine/inland split, an
    area statistic — gets it wrong. #40's bridging work reads this layer.

Options, in increasing order of dishonesty

  1. Report it to GUGiK. It is their bug and we are a downstream consumer with a precise
    reproduction.
  2. Exclude by geometry, not by attribute — e.g. drop water_bodies polygons that touch
    the country mask's seaward edge. Principled, and would catch the next one.
  3. Name-match Morze Bałtyckie. One line, effective, and the kind of hard-coded patch
    that conf/semap.yaml's objekttypnr 2648 comment warns about: the IN list that drives
    the WHERE is the same list the CASE branches on precisely so an unmapped case drops
    out visibly instead of being painted the wrong colour. A name check would be the
    opposite of that.

Worth checking whether the same row also reaches cover (which reads the same pl_ptwp
staging table, unioned per class per county) before picking one — cover maps PTWP to its
own water classes by a different route and may or may not inherit the same error.

Noticed while measuring #36. **The mislabelling is in BDOT10k, not in our import** — worth saying up front, because the shape of it looks exactly like a botched union on our side. ## What `map_water_bodies_<z>` carries a 5 845 km² polygon named **Morze Bałtyckie**, classed `lake`. It is the largest "lake" in the database by a factor of 29 and it is a chunk of the Baltic. `conf/plmap.yaml`'s `water_bodies` query is `WHERE rodzaj <> 'woda morska'` and maps everything surviving to `river` (*woda płynąca*) or `lake`. That is correct, and the source is what is wrong. In the `pl_ptwp` staging table, loaded natively from the county GeoPackages with nothing of ours applied: ``` nazwa | rodzaj | n | km2 -----------------+--------------+----+------- Morze Bałtyckie | woda morska | 16 | 70995 Morze Bałtyckie | woda stojąca | 1 | 5845 <- one row, wrong rodzaj Jamno | woda stojąca | 5 | 65 ``` Sixteen rows say marine, one says standing water. The odd one out is **teryt 3209** (powiat koszaliński), centroid 54.56 N 15.79 E, and it lies **426 m from Jezioro Jamno** — which is the lagoon just north of Koszalin that is very nearly touching the sea. So the guess that the lake infected the sea with its lakeness is probably right, and it happened upstream of us: one county's delivery has a slab of the Baltic attributed as *woda stojąca*. ## Why it matters a little - It is drawn in the same blue as the sea, so **nothing is visibly wrong today**. This is a data-quality and attribute-correctness problem, not a rendering one. - It survives to z5 (66 km wide, so nothing generalization does will remove it) and is 5 845 km² of polygon in every `water_bodies` tile along that coast. - Anything that ever reasons about `water_class` — a label, a `marine`/`inland` split, an area statistic — gets it wrong. #40's bridging work reads this layer. ## Options, in increasing order of dishonesty 1. **Report it to GUGiK.** It is their bug and we are a downstream consumer with a precise reproduction. 2. **Exclude by geometry, not by attribute** — e.g. drop `water_bodies` polygons that touch the country mask's seaward edge. Principled, and would catch the next one. 3. **Name-match `Morze Bałtyckie`.** One line, effective, and the kind of hard-coded patch that `conf/semap.yaml`'s objekttypnr 2648 comment warns about: the `IN` list that drives the `WHERE` is the same list the `CASE` branches on precisely so an unmapped case drops out *visibly* instead of being painted the wrong colour. A name check would be the opposite of that. Worth checking whether the same row also reaches `cover` (which reads the same `pl_ptwp` staging table, unioned per class per county) before picking one — `cover` maps PTWP to its own water classes by a different route and may or may not inherit the same error.
Owner

Measured again while porting R58's acceptance test (#123, 2026-08-16): the mislabel is still standing in the current delivery, slightly smaller than the original report — the woda stojąca slab is 1 971 km² in EPSG:2180 (5 845 km² in 3857, teryt 3209, centroid 54.56 N 15.79 E), and it is still the largest "lake" in the database by 29× (Śniardwy is 200 km² in 3857). It survives to z3 (it is the lone row of map_water_bodies_3_pl) and shares 49 km of edge with the national boundary (poland_mask). It also reaches cover as a 5 845 km² water_body (R59 — the same pl_ptwp source, different route; cover's sea/water_body classes render the same colour so it is invisible on the map either way).

The fix #123's test needs, in the project's idiom (#43's option 2, "exclude by geometry"):

  1. water_bodies query: add to the WHERE — drop any woda stojąca row that is an order-of-magnitude area outlier for the class AND intersects the mask's boundary:
    ST_Area(geom) > 10 * (second-largest woda stojąca area) AND ST_Intersects(ST_Transform(ST_Boundary(poland_mask.geom), 2180), geom). This drops exactly the slab (measured: nothing else in pl_ptwp satisfies both).
  2. cover's PTWP source: same predicate as an extra CASE arm → 'sea' instead of 'water_body' (a drop would leave a hole in the coverage; reclassifying keeps the partition complete).
  3. Reimport water_bodies (cheap) and cover (the heavy one; Poland's cover cascade is ~1.5–2 h — a separate step if preferred).

The acceptance test that guards it (ships in the fix PR, the #120 pattern):

SELECT count(*) = 0 AS passed, count(*) AS outliers,
       string_agg(name || '=' || round(area_km2) || ' km2', ', ') AS names
FROM (
  SELECT w.name, ST_Area(w.geom) / 1e6 AS area_km2
  FROM map_water_bodies_14_pl w
  WHERE w.water_class = 'lake'
    AND ST_Area(w.geom) > 10 * (
      SELECT ST_Area(g.geom) FROM map_water_bodies_14_pl g
      WHERE g.water_class = 'lake'
      ORDER BY ST_Area(g.geom) DESC OFFSET 1 LIMIT 1)
    AND ST_Intersects(ST_Boundary((SELECT geom FROM poland_mask)), w.geom)
) o;

Verified failing against the live DB today (outliers=1, Morze Bałtyckie=5845 km2); after the fix it passes. It belongs on the water_bodies layer in conf/plmap.yaml with requires: [map_water_bodies_14_<cc>, poland_mask]. #123's note records the same spec; also note the water_bodies R119 test in #123 asserts z4–z14 so it survives this fix (z3 becomes the deliberate empty, like every other country).

Measured again while porting R58's acceptance test (#123, 2026-08-16): the mislabel is still standing in the current delivery, slightly smaller than the original report — the `woda stojąca` slab is 1 971 km² in EPSG:2180 (5 845 km² in 3857, teryt 3209, centroid 54.56 N 15.79 E), and it is still the largest "lake" in the database by 29× (Śniardwy is 200 km² in 3857). It survives to z3 (it is the lone row of map_water_bodies_3_pl) and shares 49 km of edge with the national boundary (poland_mask). It also reaches `cover` as a 5 845 km² `water_body` (R59 — the same pl_ptwp source, different route; cover's sea/water_body classes render the same colour so it is invisible on the map either way). The fix #123's test needs, in the project's idiom (#43's option 2, "exclude by geometry"): 1. `water_bodies` query: add to the WHERE — drop any `woda stojąca` row that is an order-of-magnitude area outlier for the class AND intersects the mask's boundary: `ST_Area(geom) > 10 * (second-largest woda stojąca area)` AND `ST_Intersects(ST_Transform(ST_Boundary(poland_mask.geom), 2180), geom)`. This drops exactly the slab (measured: nothing else in pl_ptwp satisfies both). 2. `cover`'s PTWP source: same predicate as an extra CASE arm → `'sea'` instead of `'water_body'` (a drop would leave a hole in the coverage; reclassifying keeps the partition complete). 3. Reimport `water_bodies` (cheap) and `cover` (the heavy one; Poland's cover cascade is ~1.5–2 h — a separate step if preferred). The acceptance test that guards it (ships in the fix PR, the #120 pattern): ```sql SELECT count(*) = 0 AS passed, count(*) AS outliers, string_agg(name || '=' || round(area_km2) || ' km2', ', ') AS names FROM ( SELECT w.name, ST_Area(w.geom) / 1e6 AS area_km2 FROM map_water_bodies_14_pl w WHERE w.water_class = 'lake' AND ST_Area(w.geom) > 10 * ( SELECT ST_Area(g.geom) FROM map_water_bodies_14_pl g WHERE g.water_class = 'lake' ORDER BY ST_Area(g.geom) DESC OFFSET 1 LIMIT 1) AND ST_Intersects(ST_Boundary((SELECT geom FROM poland_mask)), w.geom) ) o; ``` Verified failing against the live DB today (outliers=1, Morze Bałtyckie=5845 km2); after the fix it passes. It belongs on the `water_bodies` layer in `conf/plmap.yaml` with `requires: [map_water_bodies_14_<cc>, poland_mask]`. #123's note records the same spec; also note the water_bodies R119 test in #123 asserts z4–z14 so it survives this fix (z3 becomes the deliberate empty, like every other country).
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
art/ismap#43
No description provided.