#106: Poland airports + airport_points from BDOT10k KU* land-use complexes #153

Closed
art wants to merge 0 commits from issue-106-pl-airports into main
Owner

Poland: BDOT10k KU* airports + airport_points (issue #106)

What and why

Poland's airports (+ derived airport_points) from the BDOT10k KU* land-use complex
group — OT_KUKO_A, rodzaj lotnisko lub lądowisko (KUKO02). This is the R13 line for
Poland: the same runway-polygon shape Iceland's and Sweden's airports come from.

Standalone layer, not a carve. The KUKO areas are an overlay over the PTKM
transport-surface coverage, and PTKM has no RODZAJ column to split airports out of
cover (measured on disk). The issue body offers either the #14-style ST_Difference
carve or "take the airport areas as their own layer without subtracting from PTKM"; the
#106 comment points the carve at issue #118 (overlay carve as a declared importer
staging kind), which is still open. So this branch takes the standalone option: the
airports draw on top of the PTKM transport fill at z10+, visually the same result at the
zooms they draw, with no surgery on Poland's most expensive cascade. The cover fold
stays #118's job (cross-referenced in the cover comment and docs/workstream-a.md).

The class ladder reads TYPLOTNISKA: 'port lotniczy' — the lotnisko register a
scheduled service operates from — → airport_class 1, everything else (aeroclub strips,
helipads, NULL) → 2. The same 1/2 ladder the style's z9 coarse-zoom filter reads.
IDIATA was considered and rejected as the signal (registration numbers like '23/2012'
and wrong codes like '4E' for Chopin, whose IATA is WAW, as often as real codes) —
measured on the R6 counties.

The name is the source's NAZWA directly (populated for the registered airports,
NULL for the unnamed lądowiska — all 5 of m. Kraków's rows) — no label join, unlike
Sweden's ANLTX lookup. airport_points is derived per R140 (one centroid per named
airport from plmap_airports_13, z9 scheduled-only filter), exactly as IS/SE.

R6 check (issue step 1)

Three county packages inspected end to end before widening the fetch (zip sizes
88.5/71.3/35.2 MB): 1465 Warszawa — 2 rows (Chopin + Babice, both 'port lotniczy',
named, IDICAO EPWA/EPBC); 1206 krakowski — 2 rows (Balice 'port lotniczy' named
KRK/EPKK, Pobiednik 'inne' named, IDICAO EPKP); 1261 m. Kraków — 5 rows, all 'inne
lotnisko lub lądowisko', all unnamed, IDIATA=IDICAO=registration numbers. The class is
in every delivery — the old "PTKM cannot give the split" note was about the fetch list,
not the database (the #85/#64 lesson again). OT_KUKO_P (point counterpart, same
rodzaje) is fetched and staged but unused by the current layers; it stays loaded so the
R105 check verifies the fetch extracted it, and it is the natural source of a future
point-based layer.

Changes

  • Makefile — OT_KUKO_A OT_KUKO_P added to BDOT10K_CLASSES; BDOT10K_MARKER
    widened to pt-sw-sk-oikm-oipr-skpp-kuk (the marker encodes the class set, so the
    380 county zips re-pull and the two classes extract — the documented widening cost,
    now measured at ~25 GB / 65 MB avg per county zip rather than the stale "~10 GB").
  • conf/plmap.yaml — staging pl_kuko_a/pl_kuko_p; layers airports (z10–z13,
    filter_only) + airport_points (z8–z13, z9 class-1 filter) with five acceptance
    tests (R6 population, R119 no-empty-zoom for both, R120 NULLs/validity for both);
    sources: [pl] (the first unshared layer since Phase 3); the R105 staging list and
    the cover PTKM TODO comment updated.
  • conf/mapsrv.yaml — sources: [map, is, pl].
  • html/style.json — pl tile source + airports_pl / airport_labels_pl style
    layers (the #103 per-country pattern; airports/airport_labels stay Iceland's).
  • docs — country-poland.md catalogue entry done + R6 measurements; workstream-a.md
    KU* line; style.md layer count (68 = 56 map + 9 is + 2 pl + background).

Verification (live DB, 2026-08-16)

The three R6 counties' KU* files are in the shared data dir (markers created for the
widened set), so the layers imported and were verified against real data:

make build / make test                — green
importer config-check conf/plmap.yaml — OK (14 layers, 13 shared contracts, 1 sources, 34 acceptance tests)
make acceptance                       — green across all five configs
importer acceptance conf/plmap.yaml   — 34 test(s): 33 passed, 0 failed, 1 skipped, 0 not run

New tests, all PASS:

R6:     the airport partition is populated (OT_KUKO_A)          airports=9
R119:   no airports zoom table is empty (z10–z13)               tables=4
R120:   airports carry no NULL airport_class and no invalid     class_nulls=0, invalid=0, empty_names=0, name_nulls=5
R119:   no airport_points zoom table is empty (z8–z13)          tables=6
R120:   airport_points carry no NULL airport_class              class_nulls=0, name_nulls=0

The one skip is the config-level R105 staging check: it requires the full staging set,
and pl_kuko_p only loads on a full import (nothing consumes it yet) — by design for a
partial import; it runs on the national import.

importer tiles --check conf/plmap.yaml (R121) — all PASS, including the new layers
(airports z10/z13, airport_points z8/z13; keys name airport_class country, extent
1024). gl-style-validate — clean. Real-browser render over CDP (scripts/cdp-map-check.mjs):
at z11 over Warsaw Chopin the airports_pl fill draws (4 polygons) and airport_labels_pl
labels "Lotnisko Chopina w Warszawie"; at z9 only the class-1 labels draw (Chopin +
Warszawa-Babice), confirming the scheduled-only coarse-zoom filter. (The page's missing
/favicon.ico 404 is pre-existing — same on Iceland.)

The national data (driver follow-up, 2026-08-17)

The remaining step from the review note ran: the widened make fetch-bdot10k and the
full make import-pl.

A fetch-pattern bug was caught and fixed in the process (37c9ad5c). The branch's
BDOT10K_CLASSES listed the KU* classes as OT_KUKO_A/OT_KUKO_P, but the fetch
recipe's pattern loop already prepends OT_ — so the first ~25 GB pass extracted
nothing (*OT_OT_KUKO_A* matched no member) while touching all 380 county markers.
Fixed by listing them as KUKO_A/KUKO_P (the member files are ...__OT_KUKO_A.gpkg);
markers cleared and the fetch re-run: 380/380 counties, 380 OT_KUKO_A + 368
OT_KUKO_P GPKGs on disk (12 deliveries lack the point file; harmless — no layer reads
pl_kuko_p, it is the R105 staging tally only).

Full national import (make import-pl, ~2.5 h: the cover cascade dominates):

R6:     the airport partition is populated (OT_KUKO_A)          airports=301
R119:   no airports zoom table is empty (z10–z13)               tables=4
R120:   airports carry no NULL airport_class and no invalid     class_nulls=0, invalid=0, empty_names=0, name_nulls=150
R119:   no airport_points zoom table is empty (z8–z13)          tables=6
R120:   airport_points carry no NULL airport_class              class_nulls=0, name_nulls=0

Full-run tally: 41 acceptance PASS / 0 FAIL across the pl and world configs (the R105
skip is gone — pl_kuko_p loads on the full import). Live rows: plmap_airports 301
at every of z10–z13; plmap_airport_points 15 at z8–z9 (the class-1 scheduled filter)
and 139 at z10–z13 (all named airports). Same per-layer check as the sample run:
tiles --check (R121) PASS for both new layers, gl-style-validate clean.

# Poland: BDOT10k KU* airports + airport_points (issue #106) ## What and why Poland's `airports` (+ derived `airport_points`) from the BDOT10k KU* land-use complex group — `OT_KUKO_A`, rodzaj `lotnisko lub lądowisko` (KUKO02). This is the R13 line for Poland: the same runway-polygon shape Iceland's and Sweden's airports come from. **Standalone layer, not a carve.** The KUKO areas are an overlay over the PTKM transport-surface coverage, and PTKM has no RODZAJ column to split airports out of `cover` (measured on disk). The issue body offers either the #14-style ST_Difference carve or "take the airport areas as their own layer without subtracting from PTKM"; the #106 comment points the carve at issue #118 (overlay carve as a declared importer staging kind), which is still open. So this branch takes the standalone option: the airports draw on top of the PTKM transport fill at z10+, visually the same result at the zooms they draw, with no surgery on Poland's most expensive cascade. The cover fold stays #118's job (cross-referenced in the cover comment and docs/workstream-a.md). **The class ladder** reads `TYPLOTNISKA`: 'port lotniczy' — the lotnisko register a scheduled service operates from — → airport_class 1, everything else (aeroclub strips, helipads, NULL) → 2. The same 1/2 ladder the style's z9 coarse-zoom filter reads. `IDIATA` was considered and rejected as the signal (registration numbers like '23/2012' and wrong codes like '4E' for Chopin, whose IATA is WAW, as often as real codes) — measured on the R6 counties. **The name** is the source's `NAZWA` directly (populated for the registered airports, NULL for the unnamed lądowiska — all 5 of m. Kraków's rows) — no label join, unlike Sweden's ANLTX lookup. `airport_points` is derived per R140 (one centroid per named airport from `plmap_airports_13`, z9 scheduled-only filter), exactly as IS/SE. ## R6 check (issue step 1) Three county packages inspected end to end before widening the fetch (zip sizes 88.5/71.3/35.2 MB): 1465 Warszawa — 2 rows (Chopin + Babice, both 'port lotniczy', named, IDICAO EPWA/EPBC); 1206 krakowski — 2 rows (Balice 'port lotniczy' named KRK/EPKK, Pobiednik 'inne' named, IDICAO EPKP); 1261 m. Kraków — 5 rows, all 'inne lotnisko lub lądowisko', all unnamed, IDIATA=IDICAO=registration numbers. The class is in every delivery — the old "PTKM cannot give the split" note was about the fetch list, not the database (the #85/#64 lesson again). `OT_KUKO_P` (point counterpart, same rodzaje) is fetched and staged but unused by the current layers; it stays loaded so the R105 check verifies the fetch extracted it, and it is the natural source of a future point-based layer. ## Changes - **Makefile** — `OT_KUKO_A OT_KUKO_P` added to `BDOT10K_CLASSES`; `BDOT10K_MARKER` widened to `pt-sw-sk-oikm-oipr-skpp-kuk` (the marker encodes the class set, so the 380 county zips re-pull and the two classes extract — the documented widening cost, now measured at ~25 GB / 65 MB avg per county zip rather than the stale "~10 GB"). - **conf/plmap.yaml** — staging `pl_kuko_a`/`pl_kuko_p`; layers `airports` (z10–z13, filter_only) + `airport_points` (z8–z13, z9 class-1 filter) with five acceptance tests (R6 population, R119 no-empty-zoom for both, R120 NULLs/validity for both); `sources: [pl]` (the first unshared layer since Phase 3); the R105 staging list and the cover PTKM TODO comment updated. - **conf/mapsrv.yaml** — `sources: [map, is, pl]`. - **html/style.json** — `pl` tile source + `airports_pl` / `airport_labels_pl` style layers (the #103 per-country pattern; `airports`/`airport_labels` stay Iceland's). - **docs** — country-poland.md catalogue entry done + R6 measurements; workstream-a.md KU* line; style.md layer count (68 = 56 map + 9 is + 2 pl + background). ## Verification (live DB, 2026-08-16) The three R6 counties' KU* files are in the shared data dir (markers created for the widened set), so the layers imported and were verified against real data: ``` make build / make test — green importer config-check conf/plmap.yaml — OK (14 layers, 13 shared contracts, 1 sources, 34 acceptance tests) make acceptance — green across all five configs importer acceptance conf/plmap.yaml — 34 test(s): 33 passed, 0 failed, 1 skipped, 0 not run ``` New tests, all PASS: ``` R6: the airport partition is populated (OT_KUKO_A) airports=9 R119: no airports zoom table is empty (z10–z13) tables=4 R120: airports carry no NULL airport_class and no invalid class_nulls=0, invalid=0, empty_names=0, name_nulls=5 R119: no airport_points zoom table is empty (z8–z13) tables=6 R120: airport_points carry no NULL airport_class class_nulls=0, name_nulls=0 ``` The one skip is the config-level R105 staging check: it requires the full staging set, and `pl_kuko_p` only loads on a full import (nothing consumes it yet) — by design for a partial import; it runs on the national import. `importer tiles --check conf/plmap.yaml` (R121) — all PASS, including the new layers (`airports` z10/z13, `airport_points` z8/z13; keys `name airport_class country`, extent 1024). `gl-style-validate` — clean. Real-browser render over CDP (scripts/cdp-map-check.mjs): at z11 over Warsaw Chopin the `airports_pl` fill draws (4 polygons) and `airport_labels_pl` labels "Lotnisko Chopina w Warszawie"; at z9 only the class-1 labels draw (Chopin + Warszawa-Babice), confirming the scheduled-only coarse-zoom filter. (The page's missing `/favicon.ico` 404 is pre-existing — same on Iceland.) ## The national data (driver follow-up, 2026-08-17) The remaining step from the review note ran: the widened `make fetch-bdot10k` and the full `make import-pl`. **A fetch-pattern bug was caught and fixed in the process (37c9ad5c).** The branch's `BDOT10K_CLASSES` listed the KU* classes as `OT_KUKO_A`/`OT_KUKO_P`, but the fetch recipe's pattern loop already prepends `OT_` — so the first ~25 GB pass extracted nothing (`*OT_OT_KUKO_A*` matched no member) while touching all 380 county markers. Fixed by listing them as `KUKO_A`/`KUKO_P` (the member files are `...__OT_KUKO_A.gpkg`); markers cleared and the fetch re-run: 380/380 counties, **380 OT_KUKO_A** + 368 OT_KUKO_P GPKGs on disk (12 deliveries lack the point file; harmless — no layer reads `pl_kuko_p`, it is the R105 staging tally only). **Full national import** (`make import-pl`, ~2.5 h: the cover cascade dominates): ``` R6: the airport partition is populated (OT_KUKO_A) airports=301 R119: no airports zoom table is empty (z10–z13) tables=4 R120: airports carry no NULL airport_class and no invalid class_nulls=0, invalid=0, empty_names=0, name_nulls=150 R119: no airport_points zoom table is empty (z8–z13) tables=6 R120: airport_points carry no NULL airport_class class_nulls=0, name_nulls=0 ``` Full-run tally: 41 acceptance PASS / 0 FAIL across the pl and world configs (the R105 skip is gone — `pl_kuko_p` loads on the full import). Live rows: `plmap_airports` 301 at every of z10–z13; `plmap_airport_points` 15 at z8–z9 (the class-1 scheduled filter) and 139 at z10–z13 (all named airports). Same per-layer check as the sample run: `tiles --check` (R121) PASS for both new layers, gl-style-validate clean.
Poland's `airports` (+ derived `airport_points`, R140) from OT_KUKO_A, rodzaj
'lotnisko lub lądowisko' (KUKO02) — the R13 line for Poland, the same
runway-polygon shape Iceland's and Sweden's airports come from. The KUKO areas
are an overlay over the PTKM transport-surface coverage, so they draw as their
own layer on top of the transport fill rather than being carved into cover: the
carve is issue #118's declared overlay-carve staging kind (still open), and the
issue body offers the standalone option. airport_class comes from TYPLOTNISKA
('port lotniczy' → 1, else 2) — the lotnisko register tier a scheduled service
operates from; IDIATA was measured and rejected (registration numbers and wrong
codes, e.g. '4E' for Chopin). The name is the source's NAZWA.

R6 check first (issue step 1): three county packages inspected end to end (1465
Warszawa, 1206 krakowski, 1261 m. Kraków) confirmed the class in every delivery
and measured the ladder; the "PTKM cannot split airports out" note was about the
fetch list, not the database. BDOT10K_CLASSES gains OT_KUKO_A/P and the marker
widens to pt-sw-sk-oikm-oipr-skpp-kuk, so the 380 county zips re-pull on the next
make fetch-bdot10k (~25 GB, measured 65 MB avg per county zip; the old "~10 GB"
figure predates the SW*/SK*/OIKM/OIPR/SKPP/KU* widening).

Verified against the live DB on the three R6 counties (their KU* files are in the
shared data dir): make build/test green; config-check OK; make acceptance green
(pl: 34 tests, 33 passed, 0 failed, 1 skipped — R105 needs pl_kuko_p, which only
loads on a full import); five new acceptance tests (R6 population, R119 x2,
R120 x2) all PASS; tiles --check (R121) PASS for both new layers; style validates;
real-browser render over CDP shows the airports_pl fill and Chopin label at z11
and the class-1-only labels at z9. The national import awaits the widened fetch —
see run/issues/issue-106.md (blocked on the ~25 GB data re-pull per run rules).
Two real defects and one piece of dead weight.

* Wrocław-Strachowice and Lublin were missing from z8–z9. The ladder runs
  1 = scheduled, 2 = everything else, so the *lowest* number is the best tier —
  but airport_points aggregated with max(), which takes the weakest polygon.
  BDOT10k splits both airports across a 'port lotniczy' area and an 'inne
  lotnisko lub lądowisko' area, so both came out class 2 and the style's z9
  airport_class = 1 filter dropped them: Poland drew 15 scheduled airports at
  coarse zoom where it has 17, missing the country's 5th-busiest. min() is what
  the filter is actually asking for.

  A new R120 test pins the ladder's meaning against the source rather than its
  range — every named 'port lotniczy' must have a class-1 point, a missing point
  failing too. Measured: 17 names, 0 demoted with min(), 2 with max(). The old
  R120 could not catch this; airport_class was never NULL and always in (1,2).

* 'Aeroklub Koszaliński' is two airfields 46 541 web-Mercator units apart, and
  NAZWA is sometimes the operator's name rather than the airport's, so grouping
  by name alone gave the pair one marker (area-weighted onto the larger field —
  the smaller one silently lost its label). Group by (name, spatial cluster)
  instead, the R91 idiom places uses, eps 5 000 units: an order of magnitude
  above the widest legitimate multi-area airport in any country (Arlanda's
  three areas at 2 684; Poland's own worst is Iwonicz at 48) and an order of
  magnitude below this collision. Measured over all four countries it splits
  exactly this one group — pl 139 names → 140 points, is/se/fi unchanged.

* pl_kuko_p was fetched, extracted, staged and covered by the R105 non-empty
  test, and read by nothing: airport_points derives its label point from the
  areas (R140), so the point class was never going to be reconciled with them.
  Dropped from BDOT10K_CLASSES, the staging block and R105. The marker keeps
  its -kuk suffix on purpose — narrowing the class set is always satisfiable
  from a disk holding the wider one, and renaming it would force the 25 GB
  re-pull that only widening needs. R105's "all 24" count was already stale at
  26 when the KU* pair landed; it is 25 now and says so.
Author
Owner

Merged through !154

Merged through !154
art closed this pull request 2026-08-17 22:11:14 +00:00

Pull request closed

Sign in to join this conversation.
No reviewers
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!153
No description provided.