gap: the CBS note points at place_labels.population as the cheaper answer, and it is a per-kind constant #246
Labels
No labels
agent
agent:ci
agent:done
agent:failed
agent:needs-input
agent:refined
agent:refining
agent:running
agent:shipped
agent:skip
autonomous
autopilot
driven
local
plan
proposal
qa
qa-gap
research
retro
ship
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jeroen/cartopolis#246
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while QA-ing what #192 shipped (#245).
What I did
#192 landed as documentation only:
docs/notes/cbs-neighbourhood-statistics.mdplus adocs/direction.mdrow moved from "frontier" to "checked and not taken". So the deliverable areader meets is the note, and the one thing it hands forward is the first bullet of its
Pointers section — the cheaper answer to the same question, explicitly reserved for a future
ticket:
The commit body puts it more strongly: it points at a figure "already in every vector tile and
read by nothing, which is the cheaper answer to the same question".
The note names the unverified number, so I verified it — decoded
place_labelsout of the threeMVT fixtures in the tree, and checked the result against the Shortbread 1.0 schema.
What happened
populationis not a population. It is the OSMpopulation=*tag where the place istagged, and a documented per-
kindconstant everywhere else. From the schema(https://shortbread-tiles.org/schema/1.0/, layer
place_labels):with defaults city 100,000 / town 5,000 / village 100 / hamlet 50 / suburb 1,000 /
quarter 500 / neighbourhood 100 / isolated_dwelling 5 / farm 5 / island 0 / locality 0.
The same section says the layer's features "are sorted by population in descending order" — in
the schema it is a label-ranking weight, and it is doing that job.
On the very fixture the note cites, 21 of 21 features are the constant:
groningen_z14groningen_z14Every one of those matches the schema default exactly. At city-cell resolution the field is
kindre-encoded as an integer, carrying no demographic information at all: it says everyquarter in Groningen holds 500 people and every neighbourhood 100. CBS, over the same ground,
measures 4,745 residents in Binnenstad-Noord alone.
It is not uniformly empty — the field is real where OSM carries the tag, which is mostly
settlements at low zoom. From the two z10 fixtures:
lowzoom_10_534_336lowzoom_10_534_336lowzoom_10_534_336lowzoom_10_534_336lowzoom_10_526_334lowzoom_10_526_334So the split is by tagging, not by zoom: named settlements are usually tagged, and the
sub-settlement classes a city cell is made of — quarter, neighbourhood, suburb — mostly are not.
Reproduce (no repo change; a throwaway protobuf reader over the checked-in fixtures):
What a reader would expect instead
The Pointers section exists so the check is not repeated, and this bullet is the only surviving
record of the idea — no ticket was ever filed off it (nothing in the tracker mentions
place_labels,populationor the unused-layers note). So the next frontier refill, or thenext person asking "how many people are actually there", meets this pointer and nothing else.
Followed as written, it leads to building a neighbourhood-varying occupancy or a "who lives
here" readout on a field that, in a Dutch city cell, is constant per class. That is the failure
the same note invokes value 1 to prevent, three paragraphs earlier and about this exact
question:
A constant wearing a measurement's clothes is the same error one step further along, and the
note recommends it as the cheaper option.
Two smaller things in the same bullet, both minor next to the above:
TileData::featuresis a lazy per-layerOnceCell, andvector-tile-unused-layers.mdsaysan unread layer "cost[s] nothing at all", which means reading
place_labelsis a decodethat is not currently paid. It is a small one (21 point features); the claim is just stronger
than the mechanism.
fixture carries the same layer with real values for Osnabrück and its towns.
Where the seam is
docs/notes/cbs-neighbourhood-statistics.md, Pointers section, first bullet (the*Verified:* / **Not verified:**pair) — the "not verified" half is now measured, and theanswer removes the pointer rather than qualifying it.
docs/notes/vector-tile-unused-layers.md:31— the row`place_labels` | 21 | **nothing** (`kind`, `name`, `population`)is what the bullet leans on. The property list is right;what it does not say is that
populationis a schema default at this zoom. That table iswhere a reader checks "what else is in the tile", so the qualifier belongs there too.
crates/reads the layer, so there is no code to change — the fix is to the twonotes, and the decision of whether the idea survives at all.
What I would suggest
Correct the bullet to say what the field is: real where OSM tagged it (settlements at low
zoom), the Shortbread per-
kinddefault otherwise, and therefore not an answer to "howmany people are in this block" in a city cell. It may still be worth a line as a label-ranking
input — sorting which place names to draw first is exactly what it is for — but that is a
different feature from the one the pointer currently implies, and it should not be recorded as
the cheap substitute for CBS.
Worth noting the CBS decision itself is unaffected: I reproduced every measured number in that
note against the live PDOK service and they all hold to the byte. This is only about the thing
it hands forward.
docs/qa/targets.md— 14 of 14 passes re-verified a shipped ticket, 9 of them documentation-only verdicts #280