Kadaster parcels: is it worth wiring in? #187
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#187
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?
Problem
docs/direction.md:83lists Kadaster parcels as an unverified frontier candidate — "plot boundaries — the gardens between the buildings". Nobody had confirmed the interface, the licence or the volume. This pass did, live against PDOK on 2026-08-29, and the answer is no.The three questions the ticket asks, answered:
1. Is there an interface, and what does it cost per cell? Yes.
https://service.pdok.nl/kadaster/kadastralekaart/wfs/v5_0(WFS 2.0), five feature types:Perceel,KadastraleGrens,Bebouwing,Nummeraanduidingreeks,OpenbareRuimteNaam. A daily-refreshed bulk download API exists too (https://api.pdok.nl/kadaster/kadastralekaart/download/v5_0/datasetanswers 200 with per-featuretype currency,perceelat 2026-08-28). So the interface was never the obstacle either.The cost is. Over
bbox=6.555,53.207,6.580,53.222— the ~1.7 × 1.7 km of central Groningen the NWB check used, comparable to the z14 cell everything here bins into (crates/cartopolis/src/systems/map/surveyed.rs:36):PerceelKadastraleGrensBebouwingNummeraanduidingreeksOpenbareRuimteNaamPerceelalone is 3.7× the paving layer's densest cell (3.8 MB,docs/notes/surveyed-street-objects.md:147), which is already documented as the second-heaviest thing the client streams.2. Does the licence allow redistributing what we would cache? Yes — CC0 1.0, read off the service's own
ows:AccessConstraints(https://creativecommons.org/publicdomain/zero/1.0/deed.nl),ows:Fees=none. As with NWB, this was rejected on content, not on terms. Ownership is separately not open, whichdocs/notes/building-identity-and-bag.md:172already records.3. Does it change the picture, or only the data behind it? It would change the picture, and change it wrongly. A cadastral boundary is a legal line, not a physical object. The physical boundaries — fences, walls, hedges — are already surveyed, already wired, and already drawn:
SurveyedLine/LineKind::{Fence,Wall,Hedge}atcrates/geo/src/furniture.rs:859-875, meshed byfurniture::build_line_meshes(crates/geo/src/furniture.rs:911) fromsurveyed::surveyed_lines(crates/cartopolis/src/systems/map/surveyed.rs:350), called atcrates/cartopolis/src/systems/map/map_geometry.rs:603.Measured over the identical box on 2026-08-29:
KadastraleGrens).scheiding_lijn, 1,232 current features after thetermination_datefilter) — consistent with the "~18 km at the worst" already recorded indocs/notes/surveyed-street-objects.md.So 93% of the cadastral network has nothing standing on it. Drawing it lays ~290 km of fence per cell where no fence was surveyed. That is precisely the inversion of value 1, Measured beats plausible — "a scattered tree where a real one is registered is the thing this project exists to stop doing", and this would be worse: an invented object where the register says nothing at all.
And the row's own description is wrong in the same way NWB's was. A parcel is not a garden — it is the whole plot, house, drive and all. The vegetated ground is the BGT's
begroeidterreindeel, which belongs to the "BGT, the remaining layers" frontier row and is explicitly deferred with a reason atdocs/notes/surveyed-street-objects.md("What is not read, and why"). Nothing in the cadastre distinguishes garden from building from driveway.Approach
Docs only. No crate is touched, no code compiles differently.
New note
docs/notes/kadaster-parcels.md— the standing fact, in the shapedocs/notes/README.mdprescribes (topic:/triggers:/updated:front matter, free prose, under ~100 lines). It carries: the endpoint and its five feature types; the CC0 finding with how it was read; the volume table above; the 312.4 km vs 21.9 km comparison as the reason it lost; the paging traps below; and the pointers section (what somebody will reach for the cadastre expecting, and where that actually lives).docs/direction.md— delete the| Kadaster parcels | plot boundaries — the gardens between the buildings |row from Candidates, unverified (line 83), add a row to Checked and not taken in the same shape the NWB row uses (Source | Checked | Why not, with a link to the new note).Close the ticket, per its own instruction that "not worth it is a valid answer".
The paging traps, which the note must record
These are external-world constraints and will still be true in ten commits. The GeoJSON output of this WFS is worse than the BAG WFS trap
CLAUDE.mdalready warns about, in two distinct ways, both verified:numberMatchedin the GeoJSON body is cumulative, not a total. It reportsstartIndex + returned. Page 0 of the Groningen box says941;startIndex=941says1919;startIndex=1800says2755. The true total is 8,855.count=1000with 7,914 still to come. Raisingcountabove 1000 changes nothing (CountDefaultis 1000 in the capabilities, andcount=5000returns byte-identical responses). The proof it is truncation and not an honest total: a bbox strictly inside the big one returns more features (972) than the box containing it (941).resultType=hits, which returns awfs:FeatureCollectionheader with a realnumberMatchedand no features.PagingIsTransactionSafe = FALSE). WalkingPerceelbystartIndexreturned 8,855 features of which only 8,638 were unique — so it both duplicates and drops. Any extractor built on this needs to de-duplicate onidand check the result againstresultType=hits.Pointers the note should carry
What somebody will reach for the cadastre expecting, with what was and was not verified:
Bebouwing, 7,148 over the box — verified count only). Already superseded: the BAG outline ships on the building's own record and carries theidentificatiethat joins it to everything else (docs/notes/building-identity-and-bag.md), which the cadastral footprint does not.Nummeraanduidingreeks, 7,263 — verified count only). Not verified: whether it beats what the BAG's per-unit entrance points already supply. This client draws no house-number labels at all today; the numbers reach the user through the proximity readout.OpenbareRuimteNaam, 387 — verified count only). Not verified: whether a cartographic anchor point would improvesystems::street_labels, which places view-independently from world footprints on purpose (crates/cartopolis/src/systems/map/street_labels.rs:1) and would have to give that up to use one.kadastraleGrootteWaardeis on everyPerceel(164.0 m² on the first feature sampled). It is data behind the picture, not picture, and value 6 rules it out on its own.scheiding_lijnis optional "IMGeo plus" content like the tree points, so some of that 93% gap may be under-registration rather than absence. The answer if that ever matters is better handling of BGT coverage, not inventing a fence from a legal line — and the number that would settle it is the surveyed-boundary length in a municipality with known-completescheiding_lijncoverage, which nobody has measured.Acceptance criteria
docs/notes/kadaster-parcels.mdexists, withtopic:,triggers:andupdated: 2026-08-29front matter, and is under ~100 lines.service.pdok.nl/kadaster/kadastralekaart/wfs/v5_0) and names all five feature types.ows:AccessConstraintsin the service's own GetCapabilities, not off a wiki.Perceel8,855 features / 14.0 MB / 12 requests andKadastraleGrens29,676 unique / 30.4 MB overbbox=6.555,53.207,6.580,53.222— with the date and the bbox stated.crates/geo/src/furniture.rs'sLineKindas the layer that already draws the physical boundaries.numberMatched, short page ≠ last page,resultType=hitsas the only honest total,PagingIsTransactionSafe = FALSEwith the 8,855 vs 8,638 duplicate count).curlone-liners, asdocs/notes/nwb-road-network.mddoes.begroeidterreindeel, i.e. to the "BGT, the remaining layers" row.docs/direction.mdno longer lists Kadaster parcels under Candidates, unverified.docs/direction.md's Checked and not taken table has aKadaster parcels | 2026-08-29 | …row linking tonotes/kadaster-parcels.md, and the reason given is the 93% gap, not the volume alone.docs/is modified.Verification
Everything below is read-only and needs no build, no GPU and no workstation.
Nothing here needs
--shotorcargo shots, which is the point: the deliverable is a docs change and there is no picture to photograph. No workstation step, and no CI gate beyond the existing workspacecargo fmt --check, which a docs-only diff cannot move.The measurements above were taken during this refinement pass and do not need re-running. If the implementing agent re-runs them and gets different numbers, the note takes the new ones and says so — the counts are live data and will drift.
Out of scope
tools/script, no cartopy pipeline change, no coverage manifest. The answer is no, so nothing is built.Bebouwing,NummeraanduidingreeksandOpenbareRuimteNaamare recorded as pointers with counts, not evaluated. Deciding whether cadastral label placement beatssystems::street_labelsis a separate ticket and would need a picture judgement this lane cannot make (docs/direction.md, "What it may not do").BGT, the remaining layers.begroeidterreindeelis named in the note as where "the gardens" actually live, but that row keeps its own place in Candidates, unverified and is not checked, moved or pre-judged here.scheiding_lijncoverage handling. Named as the honest counter-argument; not acted on.docs/notes/building-identity-and-bag.md:172, and out of bounds regardless.docs/direction.mdbeyond the two table rows. A session may propose changes to that file as a ticket; it may not rewrite it, and moving a row between its own two tables is what the file's own "Candidates, unverified" section instructs.Open questions
None. The ticket's three questions are answered above with live measurements, and value 1 (Measured beats plausible) settles the one judgement involved: a legal line is not a physical object, and 93% of this one has nothing standing on it.
Branch:
docs/187-kadaster-parcels-not-takenOriginal request
From the frontier in
docs/direction.md: Kadaster parcels — plot boundaries — the gardens between the buildings.The first half of this ticket is deciding whether it is worth doing at all:
Not worth it is a valid answer. Record it in
docs/direction.mdagainst this rowwith the reason, and close this ticket — that is the result, not a failure.
Decide it yourself. This ticket is not being watched, so a question asked
here is a ticket that stops. The seven values at the top of
docs/direction.mdexist to settle exactly this kind of ambiguity — pick the reading they support,
say in the commit body which one you applied and why, and build. Only a decision
that would need something nobody can derive from the repository — a credential, a
licence somebody must agree to, a choice about what the project is for — is a
reason to stop.
If it is worth doing, follow the shape the surveyed layers already use:
an extractor under
tools/, a coverage manifest, a streamer that adds to whatis drawn rather than replacing it, and no unbounded per-frame upload.
Filed by the autopilot.
🤖 Refined by the viberfox issue agent. Reply with @agent refine and what is wrong to have this rewritten.
🤖 Refining this before anything gets built — reading the code, no branch, no commits. If it turns out I'd have to guess at the requirements I'll stop and ask instead.
🤖 Refined. The description above is now the spec; I'll pick it up for implementation on the next poll.
If the direction is wrong, say so now — @agent refine with a correction rewrites it, and
agent:skipstops me.🤖 viberfox issue agent on the VPS — 29 turns · $2.58 · session
a0f71d03-2ddc-40fb-a36b-e6bea9c24a15. Reply with @agent to continue this session.🤖 Picked this up — working on branch
docs/187-kadaster-parcels-not-takenin a fresh worktree on the VPS. I'll report back here when I'm done.Label an issue
agent:skipto keep me off it, ordrivento keep it in a session you are driving.Checked the Kadaster cadastral service against PDOK and the answer is no. Two documentation files changed; no code was touched.
What changed
docs/notes/kadaster-parcels.md(135 lines) — the standing record of the check: the endpoint and its five feature types, the CC0 1.0 licence and how it was read, the volume table, the reason it lost, four paging traps, five pointers, and runnablecurlcommands for every number.docs/direction.md— moved Kadaster parcels out of "Candidates, unverified" and into "Checked and not taken", with a row linking to the new note.Why it lost. A cadastral boundary is a legal line, not a physical object. Over a 1.7 × 1.7 km box in central Groningen there are 312.4 km of cadastral boundary against 21.9 km of surveyed fence, wall and hedge the BGT already supplies and the client already draws (
LineKind::{Fence,Wall,Hedge}). So 93% of the cadastral network has nothing standing on it — drawing it would put roughly 290 km of invented fence per map cell where the register says nothing. That is value 1, Measured beats plausible, applied straight. Volume seals it independently:Perceelalone is 8,855 features and 14.0 MB per cell, 3.7 times the paving layer's densest cell.The row's own description was wrong too. A parcel is the whole plot — house, drive and all. The gardens belong to the BGT's
begroeidterreindeel, i.e. to the "BGT, the remaining layers" row, which I left untouched.How I verified. I re-ran the external checks live today rather than trusting the ticket. All reproduced exactly: licence
publicdomain/zero/1.0/deed.nland<ows:Fees>none</ows:Fees>; all five feature types;CountDefault1000 andPagingIsTransactionSafeFALSE;resultType=hitstotals of 8,855 and 30,459; and the cumulative-count trap returning 941, 1919, 2755 for successive pages against a true total of 8,855. I also confirmed every code path the note cites exists in the tree.cargo fmt --checkpasses on the workspace. No build or test was needed — the diff is two Markdown files.Unverified. The 312.4 km and 21.9 km lengths, the byte totals and the 8,638-unique count are the refinement pass's measurements; I confirmed the feature counts they were derived from but did not re-page the full 44 MB to recompute the lengths. Nothing here needs a visual check — there is no picture.
One thing for you to decide. The note is 135 lines, over the ~100 the notes format asks for. I cut the narration; what is left is the content the ticket's acceptance criteria require. The sibling
nwb-road-network.mdis 126 lines, so it is in family, but say the word and I will drop the pointers section to bring it under 100.Branch
docs/187-kadaster-parcels-not-takenis pushed. This ticket can be closed — "not worth it" was its own stated valid answer.Branch
docs/187-kadaster-parcels-not-taken(pushed)🤖 viberfox issue agent on the VPS — 30 turns · $2.72 · session
cde24c7b-688c-4e8e-b0c4-9d8a48ea85ff. Reply with @agent to continue this session.🤖 Marked
agent:donewithout a CI verdict on4f96f4c1— no workflow reported on this commit. The branch is waiting for review; check the run yourself before landing it.🤖 Merged into
mainas pull request #189 (4f96f4c1).🤖 Could not ship this. No such file or directory
The branch is intact; nothing was merged.
agent:donenever means "CI agreed" #220docs/qa/targets.md— 14 of 14 passes re-verified a shipped ticket, 9 of them documentation-only verdicts #280