Skip to content

The numbers these courses quote

Every course on this site argues from measurements. That is deliberate: a page that says "we keep only the tags we need" teaches nothing, and a page that says "4,220 keys reach the parser and 33 survive it" teaches the whole idea in one line.

The cost is that those figures are typed into prose, often into several pages at once, and prose is the one thing this wiki's gates could not read. check_date joined the stored keys on 2026-09-10 and chapter 6 went on saying 32 in five places and a figure. So the numbers live here now, once, and the pages point at this table rather than repeating it.

Derived from the repository

Everything in this table is extracted from a checkout by tools/wiki-numbers.py, which regenerates the block below and fails if it has drifted. Nothing here is typed by hand, so nothing here can be stale without the build saying so.

id value what it is derived from
catalog-letters 12 editable catalog types, each with one letter web/src/Catalog/ItemType.php
selector-rules 42 OSM tag rules that decide whether an object is worth keeping pipeline/contract/coverage-contract.json
stored-tag-keys 43 tag keys the harvest keeps on a coverage row; every other key is dropped at parse time pipeline/contract/coverage-contract.json
drawer-tag-whitelist 32 of those keys the POI drawer is allowed to render web/src/Coverage/CoverageRepository.php
map-modules 59 JavaScript modules the map is split into web/assets/map/
map-js-lines 345 lines in map.js itself, which is imports plus the boot sequence web/assets/map/map.js
geofabrik-regions 22 Geofabrik extracts the harvest runs by default developers/docker/compose.yaml
seeded-pins 30 hand-authored pins make course-data seeds web/src/Catalog/Command/SeedManualCatalogCommand.php
api-rate-limit-per-minute 120 requests a minute per client address on the public API web/config/packages/rate_limiter.yaml
api-bbox-max-degrees 10.0 widest bbox /v1/search accepts, on either axis web/src/Controller/Api/V1/PublicApiController.php
api-limit-default 100 features /v1/search returns when limit is not given web/src/Controller/Api/V1/PublicApiController.php
api-limit-max 500 features /v1/search will return at most web/src/Controller/Api/V1/PublicApiController.php
climb-window-m 250 metres in the sliding window the steepest-stretch figure is measured over web/src/Elevation/ClimbProfiler.php
climb-percentile 0.95 percentile of those windows that gets published, rather than the maximum web/src/Elevation/ClimbProfiler.php
climb-samples 200 elevation samples per climb, a fixed count, so spacing grows with length web/src/Elevation/ClimbProfiler.php
route-surface-buffer-m 25 metres either side of a route line that count as on it, for surface attribution web/src/Catalog/SurfaceProfiler.php
dem-tile-bytes 25,934,402 bytes in one 1 arc-second .hgt tile: 3601 x 3601 samples, 2 bytes each arithmetic on the SRTM/GLO-30 tile shape

Measured, not derived

These cannot come out of a checkout. They are counts in a live database, wall-clock timings, or the size of a real harvest, and every one of them carries the date it was taken and the command that takes it again. Treat the date as part of the number: quoting one of these without it is how a page goes quietly wrong.

what it is value taken how to take it again
Rows in coverage_poi, all onboarded countries 2,063,788 2026-09-10 SELECT count(*) FROM coverage_poi;
Countries onboarded 19 2026-09-10 SELECT count(DISTINCT country_code) FROM region;
Region rows 271 2026-09-10 SELECT count(*) FROM region;
item rows on a fresh clone after make course-data 736 2026-09-10 build an empty database, run the target, SELECT count(*) FROM item;
Of which seeded by hand 30 2026-09-10 make course-data prints it; tools/check-course-data.py verifies it
Import rows the duplicate guard holds out 84 2026-09-10 the count app:catalog:import reports as skipped
coverage_poi rows the course fixture builds 10 2026-09-10 make course-data, then count the table
Ride-check corridor query, before and after the rewrite 62 s to under 1 s 2026-07 docs/specs/ design note for the rewrite
Radius query, sequential scan against functional index 716 ms to 2 ms 2026-07 pipeline/coverage/load.py records both
Tag payload dropped by narrowing the stored keys 73 MB to 35 MB 2026-07 one Belgian extract, parsed both ways
One Geofabrik extract, downloaded against stored 4.8 GB to 28 MB 2026-08 make coverage-refresh regions=europe/belgium
Surface grid, whole-Benelux at two resolutions 0.6 MB and 34.8 MB 2026-08 build the surface arm at each zoom floor
Valhalla cold start, six continents of DEM 101 s 2026-08 restart the routing container and time it
Gzipped DEM tiles, read cost against raw 2.6x slower 2026-08 docs/specs/climb-elevation.md
GLO-30 Europe tile set 1137 tiles, 28 GB 2026-08 tools/elevation/README.md

Using this page

Cite a number, do not copy it. A sentence like "the harvest keeps 33 of the tags an object carries" should link here, so that when the contract gains a key there is one page to change and one gate that notices. If you find yourself typing a figure that already appears above, link instead.

If a number belongs in the first table but is not there yet, add an extractor to tools/wiki-numbers.py rather than a row to the page. The page is generated; a row typed into it by hand will be deleted the next time the gate runs.