CBS neighbourhood statistics: is it worth wiring in? #192

Closed
opened 2026-08-29 20:43:16 +00:00 by viberfox-agent · 7 comments
Collaborator

Problem

docs/direction.md:83 lists CBS neighbourhood statistics — "how many people are actually there" under Candidates, unverified. Nobody had confirmed the interface, the licence or the volume. This pass did that, read-only, from the container on 2026-08-29.

The answer is no, on the same grounds Kadaster parcels and NWB lost. The deliverable is therefore a docs/notes/ note plus a row moved in docs/direction.md — not a layer.

What was checked

https://service.pdok.nl/cbs/wijkenbuurten/2024/wfs/v1_0 (WFS 2.0), three feature types: buurten, wijken, gemeenten. A 2023 service exists at the same shape.

  • Licence: CC0 1.0, read off the service's own GetCapabilities — ows:AccessConstraints is https://creativecommons.org/publicdomain/zero/1.0/deed.nl, ows:Fees is none. The licence was never the obstacle.
  • Volume is small, and that is itself the finding. Over bbox=6.555,53.207,6.580,53.222 (the ~1.7 × 1.7 km Groningen box the Kadaster and NWB checks used, comparable to a z14 surveyed cell): 23 buurten, 6 wijken, 1 gemeente; the buurten GeoJSON is 257 KB, of which the geometry is 27.6 KB (696 coordinate pairs across 22 features — heavily generalised admin outlines). So ~89% of the payload is the statistics table: 244 attributes per feature, of which 30% (1,614 of 5,368 values) are the suppression sentinel -99997.
  • Same paging family as the Kadaster service. PagingIsTransactionSafe = FALSE, CountDefault = 1000. resultType=hits says 23 buurten; page 0 returned 22 and startIndex=22 returned Sterrebosbuurt again — the last feature of page 0, i.e. a duplicate rather than the missing 23rd. Any extractor built on this would have to de-duplicate on id and reconcile against hits, exactly as docs/notes/kadaster-parcels.md:75-79 records.

Why it loses: there is no picture in it, and every consumer already has a finer source

The only geometry is the buurt/wijk/gemeente outline, which is an administrative line with no physical object standing on it — the precise reason the cadastre was rejected (docs/notes/kadaster-parcels.md:25-38, value 1). Everything else is a table. docs/notes/kadaster-parcels.md:96-97 already ruled out plot area on this ground: "Data behind the picture, not picture; value 6 rules it out."

The strongest counter-case is value 1 — ground an invented density in a measured one. It fails on all three candidate consumers:

  • Ambient traffic. The pool is fixed at MAX_CARS = 180 (crates/cartopolis/src/systems/nav/traffic.rs:69) placed inside PLACE_RADIUS_M = 260.0 (:77), and the constant's own doc comment says it is "Sized for 'the street I am looking at is alive', not for a traffic census" (:59), with the module note stating the question as "is this street alive" (:43). Arithmetic on those two cited constants: 180 cars over π·0.26² km² ≈ 850/km², already below the 1,971 personenautosPerKm2 measured in Binnenstad-Noord — so a measured number could only ever place fewer cars. And CBS's car figure is a stock of registered vehicles, not a flow: the layer draws moving cars, and the frontier row that carries traffic flow is NDW, one line above this one at docs/direction.md:82.
  • Lit windows. The block liveliness is a hash at BLOCK_M = 25.0 m (crates/cartopolis/src/systems/map/building_windows.rs:99) — a buurt is one to two orders of magnitude coarser. The occupancy channel it multiplies (assets/shaders/building_windows.wgsl:163-164) is already fed per building by the BAG's use bits through osm_buildings::night_lit_scale (crates/cartopolis/src/systems/map/osm_buildings.rs:515). percentageOnbewoond is a neighbourhood average of the same fact the client already reads per object; value 1 prefers the finer measured source.
  • Walkers. Same fixed-pool shape, MAX_WALKERS = 220 (crates/cartopolis/src/systems/nav/traffic.rs:508). CBS measures where people live, not who is on the pavement — the shops, the station and the university are. Turning a residence count into a street-presence count is an inference wearing a measurement's clothes, which is the one thing value 1 exists to stop.

Parked cars are already derived from the lot's own surveyed area (crates/geo/src/parking.rs:11-12), which is finer than a buurt aggregate.

The cheaper thing nobody has read

The frontier row asks "how many people are actually there". The vector tile already carries a population figure and nothing reads it: place_labels, 21 features on the Groningen z14 fixture, properties kind / name / population, listed as used for nothing in docs/notes/vector-tile-unused-layers.md, and the only place_labels mention anywhere in the crates is an unrelated buffer-width comment (crates/geo/src/vector_tiles.rs:282). It costs no request and no extra decode, and unlike CBS it is global rather than Dutch-only. That is a pointer for the note, not scope for this ticket.

One stale premise, worth correcting in passing

The ticket body says "an extractor under tools/". Since the port recorded in docs/notes/where-the-map-data-is-built.md, the Dutch extractors live in jeroen/cartopy (server/pipeline/*.ts), not tools/. Nothing is being built here, so it changes no work — but a future frontier ticket copying that sentence would send someone to the wrong repository.

Approach

Documentation only. Two files, both in this repo.

  1. New docs/notes/cbs-neighbourhood-statistics.md, following the shape of docs/notes/kadaster-parcels.md and docs/notes/nwb-road-network.md:

    • topic: / triggers: / updated: 2026-08-29 front-matter per docs/notes/README.md. Trigger words should include at least: CBS, wijkenbuurten, buurten, wijken, gemeenten, "neighbourhood statistics", "population density", aantalInwoners, bevolkingsdichtheid, personenautosPerKm2, PDOK, place_labels.
    • The service checked, the CC0 evidence read off GetCapabilities (not off a wiki), and the three feature types.
    • The volume table: features, raw GeoJSON bytes, geometry bytes, attribute count, suppressed share.
    • Why it lost, with the three consumers above and their citations.
    • The paging observation (hits = 23 vs 22 unique with a duplicate at startIndex=22).
    • Pointers, each labelled with what was and was not verified — following docs/notes/kadaster-parcels.md:81-104, which is the section that stops the check being redone. At minimum: the unread place_labels population; and the honest counter-argument (below).
    • A "How every number above was measured" section with the runnable curl block, as the Kadaster note has at :106-135.
  2. docs/direction.md — delete line 83 from the Candidates, unverified table and append a row to the Checked and not taken table after line 93, in the established three-column form (Source | Checked | Why not), dated 2026-08-29, linking [notes/cbs-neighbourhood-statistics.md](notes/cbs-neighbourhood-statistics.md).

  3. Commit body must name the values applied and why, per value 7 and the ticket's own instruction. The two that decide it are value 6 (Ship the smallest thing a machine can judge — a statistics table changes no count, placement, settle time, draw call or byte the harness can gate on) and value 1 (Measured beats plausible — a buurt-average density substituted for a per-building BAG fact, or for a fixed pool whose stated job is liveliness, is coarser than what is already read and would be an inference presented as a survey).

The honest counter-argument, to be written into the note so it is not re-derived: CBS is the only source here for how many people live in a specific block, and if this project ever grows a layer whose subject is residents rather than streets — occupancy that varies by neighbourhood rather than by hash, or a readout that names the buurt you are standing in — the data exists, is CC0, and is small. The number that would settle that is whether a buurt-resolution figure visibly beats the per-building BAG occupancy already in the shader, and nobody has measured it.

Acceptance criteria

  • docs/notes/cbs-neighbourhood-statistics.md exists, with topic:, triggers: and updated: front-matter in the form docs/notes/README.md specifies.
  • The note records the service URL, the three feature types, and the CC0 licence with the GetCapabilities fields it was read from (ows:AccessConstraints, ows:Fees) — not a secondary source.
  • The note records, for the bbox=6.555,53.207,6.580,53.222 box: 23/6/1 features, 257 KB of buurten GeoJSON, 27.6 KB of geometry, 244 attributes per feature, 1,614 of 5,368 values suppressed as -99997.
  • The note states why it lost, and cites for each of the three consumers the file and line this spec cites: traffic.rs:59 and :69 and :77 and :508, building_windows.rs:99, building_windows.wgsl:163-164, osm_buildings.rs:515, parking.rs:11-12.
  • The note records the paging observation and points at docs/notes/kadaster-parcels.md's paging section rather than restating it.
  • The note has a pointers section separating verified from unverified, including the unread place_labels population and the counter-argument above.
  • The note ends with a runnable, read-only command block reproducing every number in it.
  • docs/direction.md no longer lists CBS under Candidates, unverified (line 83 gone).
  • docs/direction.md's Checked and not taken table has a CBS row dated 2026-08-29, in the same three-column form as the two rows above it, linking the new note.
  • No file outside docs/ is touched; no extractor, no streamer, no coverage manifest, no Cargo.toml change.
  • The commit body names value 6 and value 1 and says how each decided it (value 7).

Verification

Read-only, all runnable in this container:

# The two edited files, and nothing else.
git diff --stat main...HEAD          # → only docs/direction.md and docs/notes/cbs-neighbourhood-statistics.md

# The row moved, and did not get duplicated.
grep -n "CBS" docs/direction.md      # → exactly one hit, in the "Checked and not taken" table

# The note's links resolve.
grep -o '](notes/[^)]*)' docs/direction.md | sed 's/](\(.*\))/docs\/\1/' | xargs ls

# Every number in the note reproduces.
B=https://service.pdok.nl/cbs/wijkenbuurten/2024/wfs/v1_0
BB=53.207,6.555,53.222,6.580,urn:ogc:def:crs:EPSG::4326
G="service=WFS&version=2.0.0&request=GetFeature&typeNames=wijkenbuurten"

curl -sL "$B?request=GetCapabilities&service=WFS" > caps.xml
grep -oE 'publicdomain/zero/1.0[^<]*|<ows:Fees>[^<]*|<Name>wijkenbuurten:[^<]*' caps.xml
grep -A3 'CountDefault\|PagingIsTransactionSafe' caps.xml

for T in buurten wijken gemeenten; do
  curl -sL "$B?$G:$T&resultType=hits&bbox=$BB" | grep -o 'numberMatched="[0-9]*"'
done                                  # → 23, 6, 1

J="$G:buurten&outputFormat=application/json&srsName=urn:ogc:def:crs:EPSG::4326"
curl -sL "$B?$J&bbox=$BB&count=1000" -o buurten.json -w '%{size_download}\n'   # → 257021
jq '[.features[]|.geometry|tostring|length]|add' buurten.json                    # → 27582
jq '[.features[].properties|to_entries[]]|length' buurten.json                   # → 5368
jq '[.features[].properties|to_entries[]|select(.value==-99997)]|length' buurten.json  # → 1614

Nothing here needs a workstation, a GPU or a build. No cargo command is required or expected: the change compiles nothing and the repo has no docs linter. Do not run --shot or cargo shots — there is no rendered artefact to check, and this container cannot render anyway.

The one thing that cannot be re-verified from a shell is whether the judgement is right, and that is what the note's pointers section exists to make cheap to revisit.

Out of scope

  • Any layer, extractor, streamer or coverage manifest. The result is "not taken"; nothing streams.
  • Reading place_labels' population. Named as a pointer in the note because it is the cheap answer to the same question, but it is a change to cartopolis_geo/systems::places and belongs to its own ticket off docs/notes/vector-tile-unused-layers.md.
  • NDW traffic (docs/direction.md:82). It is the row that carries real vehicle flow, and this note should say so rather than pre-empting it.
  • Re-checking Kadaster or NWB. Their notes stand; cite them, do not restate their contents.
  • Correcting the "extractor under tools/" phrasing in the autopilot's ticket template. Recorded above so it is not lost; fixing the template is a change to tools/autopilot.ts, not to docs/.
  • Any change to docs/direction.md beyond the one row. Value-list edits and frontier reordering are a maintainer decision — the file says a session may propose, not rewrite.

Open questions

None. The interface, the licence and the volume were all confirmed from the live service, and the ambiguity the ticket flagged is settled by values 6 and 1 as recorded above.


Branch: docs/192-cbs-statistics-not-taken

Original request

From the frontier in docs/direction.md: CBS neighbourhood statistics — how many people are actually there.

The first half of this ticket is deciding whether it is worth doing at all:

  • Is there an interface a client or an extractor can use, and what does it cost per cell?
  • Does the licence allow redistributing what we would cache?
  • Does it change the picture, or only the data behind it?

Not worth it is a valid answer. Record it in docs/direction.md against this row
with 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.md
exist 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 what
is 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.

## Problem `docs/direction.md:83` lists **CBS neighbourhood statistics — "how many people are actually there"** under *Candidates, unverified*. Nobody had confirmed the interface, the licence or the volume. This pass did that, read-only, from the container on 2026-08-29. **The answer is no**, on the same grounds Kadaster parcels and NWB lost. The deliverable is therefore a `docs/notes/` note plus a row moved in `docs/direction.md` — not a layer. ### What was checked `https://service.pdok.nl/cbs/wijkenbuurten/2024/wfs/v1_0` (WFS 2.0), three feature types: `buurten`, `wijken`, `gemeenten`. A 2023 service exists at the same shape. - **Licence: CC0 1.0**, read off the service's own GetCapabilities — `ows:AccessConstraints` is `https://creativecommons.org/publicdomain/zero/1.0/deed.nl`, `ows:Fees` is `none`. The licence was never the obstacle. - **Volume is small**, and that is itself the finding. Over `bbox=6.555,53.207,6.580,53.222` (the ~1.7 × 1.7 km Groningen box the Kadaster and NWB checks used, comparable to a z14 surveyed cell): **23 buurten, 6 wijken, 1 gemeente**; the buurten GeoJSON is **257 KB**, of which the geometry is **27.6 KB** (696 coordinate pairs across 22 features — heavily generalised admin outlines). So ~89% of the payload is the statistics table: **244 attributes per feature**, of which **30% (1,614 of 5,368 values) are the suppression sentinel `-99997`**. - **Same paging family as the Kadaster service.** `PagingIsTransactionSafe = FALSE`, `CountDefault = 1000`. `resultType=hits` says 23 buurten; page 0 returned 22 and `startIndex=22` returned `Sterrebosbuurt` again — the last feature of page 0, i.e. a duplicate rather than the missing 23rd. Any extractor built on this would have to de-duplicate on id and reconcile against `hits`, exactly as `docs/notes/kadaster-parcels.md:75-79` records. ### Why it loses: there is no picture in it, and every consumer already has a finer source The only geometry is the buurt/wijk/gemeente outline, which is an **administrative line with no physical object standing on it** — the precise reason the cadastre was rejected (`docs/notes/kadaster-parcels.md:25-38`, value 1). Everything else is a table. `docs/notes/kadaster-parcels.md:96-97` already ruled out plot area on this ground: *"Data behind the picture, not picture; value 6 rules it out."* The strongest counter-case is value 1 — ground an invented density in a measured one. It fails on all three candidate consumers: - **Ambient traffic.** The pool is fixed at `MAX_CARS = 180` (`crates/cartopolis/src/systems/nav/traffic.rs:69`) placed inside `PLACE_RADIUS_M = 260.0` (`:77`), and the constant's own doc comment says it is *"Sized for 'the street I am looking at is alive', not for a traffic census"* (`:59`), with the module note stating the question as *"is this street alive"* (`:43`). Arithmetic on those two cited constants: 180 cars over π·0.26² km² ≈ **850/km²**, already *below* the 1,971 `personenautosPerKm2` measured in Binnenstad-Noord — so a measured number could only ever place fewer cars. And CBS's car figure is a **stock of registered vehicles, not a flow**: the layer draws moving cars, and the frontier row that carries traffic *flow* is NDW, one line above this one at `docs/direction.md:82`. - **Lit windows.** The block liveliness is a hash at `BLOCK_M = 25.0` m (`crates/cartopolis/src/systems/map/building_windows.rs:99`) — a buurt is one to two orders of magnitude coarser. The occupancy channel it multiplies (`assets/shaders/building_windows.wgsl:163-164`) is already fed **per building** by the BAG's use bits through `osm_buildings::night_lit_scale` (`crates/cartopolis/src/systems/map/osm_buildings.rs:515`). `percentageOnbewoond` is a neighbourhood average of the same fact the client already reads per object; value 1 prefers the finer measured source. - **Walkers.** Same fixed-pool shape, `MAX_WALKERS = 220` (`crates/cartopolis/src/systems/nav/traffic.rs:508`). CBS measures where people **live**, not who is on the pavement — the shops, the station and the university are. Turning a residence count into a street-presence count is an inference wearing a measurement's clothes, which is the one thing value 1 exists to stop. Parked cars are already derived from the lot's own surveyed area (`crates/geo/src/parking.rs:11-12`), which is finer than a buurt aggregate. ### The cheaper thing nobody has read The frontier row asks "how many people are actually there". The vector tile **already carries a population figure** and nothing reads it: `place_labels`, 21 features on the Groningen z14 fixture, properties `kind` / `name` / `population`, listed as used for **nothing** in `docs/notes/vector-tile-unused-layers.md`, and the only `place_labels` mention anywhere in the crates is an unrelated buffer-width comment (`crates/geo/src/vector_tiles.rs:282`). It costs no request and no extra decode, and unlike CBS it is global rather than Dutch-only. That is a pointer for the note, not scope for this ticket. ### One stale premise, worth correcting in passing The ticket body says "an extractor under `tools/`". Since the port recorded in `docs/notes/where-the-map-data-is-built.md`, the Dutch extractors live in `jeroen/cartopy` (`server/pipeline/*.ts`), not `tools/`. Nothing is being built here, so it changes no work — but a future frontier ticket copying that sentence would send someone to the wrong repository. ## Approach Documentation only. Two files, both in this repo. 1. **New `docs/notes/cbs-neighbourhood-statistics.md`**, following the shape of `docs/notes/kadaster-parcels.md` and `docs/notes/nwb-road-network.md`: - `topic:` / `triggers:` / `updated: 2026-08-29` front-matter per `docs/notes/README.md`. Trigger words should include at least: `CBS`, `wijkenbuurten`, `buurten`, `wijken`, `gemeenten`, `"neighbourhood statistics"`, `"population density"`, `aantalInwoners`, `bevolkingsdichtheid`, `personenautosPerKm2`, `PDOK`, `place_labels`. - The service checked, the CC0 evidence read off GetCapabilities (not off a wiki), and the three feature types. - The volume table: features, raw GeoJSON bytes, geometry bytes, attribute count, suppressed share. - Why it lost, with the three consumers above and their citations. - The paging observation (`hits` = 23 vs 22 unique with a duplicate at `startIndex=22`). - Pointers, each labelled with what *was* and *was not* verified — following `docs/notes/kadaster-parcels.md:81-104`, which is the section that stops the check being redone. At minimum: the unread `place_labels` population; and the honest counter-argument (below). - A "How every number above was measured" section with the runnable curl block, as the Kadaster note has at `:106-135`. 2. **`docs/direction.md`** — delete line 83 from the *Candidates, unverified* table and append a row to the *Checked and not taken* table after line 93, in the established three-column form (`Source | Checked | Why not`), dated `2026-08-29`, linking `[notes/cbs-neighbourhood-statistics.md](notes/cbs-neighbourhood-statistics.md)`. 3. **Commit body** must name the values applied and why, per value 7 and the ticket's own instruction. The two that decide it are **value 6** (*Ship the smallest thing a machine can judge* — a statistics table changes no count, placement, settle time, draw call or byte the harness can gate on) and **value 1** (*Measured beats plausible* — a buurt-average density substituted for a per-building BAG fact, or for a fixed pool whose stated job is liveliness, is coarser than what is already read and would be an inference presented as a survey). The honest counter-argument, to be written into the note so it is not re-derived: CBS is the **only** source here for how many people live in a specific block, and if this project ever grows a layer whose subject is residents rather than streets — occupancy that varies by neighbourhood rather than by hash, or a readout that names the buurt you are standing in — the data exists, is CC0, and is small. The number that would settle *that* is whether a buurt-resolution figure visibly beats the per-building BAG occupancy already in the shader, and nobody has measured it. ## Acceptance criteria - [ ] `docs/notes/cbs-neighbourhood-statistics.md` exists, with `topic:`, `triggers:` and `updated:` front-matter in the form `docs/notes/README.md` specifies. - [ ] The note records the service URL, the three feature types, and the CC0 licence **with the GetCapabilities fields it was read from** (`ows:AccessConstraints`, `ows:Fees`) — not a secondary source. - [ ] The note records, for the `bbox=6.555,53.207,6.580,53.222` box: 23/6/1 features, 257 KB of buurten GeoJSON, 27.6 KB of geometry, 244 attributes per feature, 1,614 of 5,368 values suppressed as `-99997`. - [ ] The note states why it lost, and cites for each of the three consumers the file and line this spec cites: `traffic.rs:59` and `:69` and `:77` and `:508`, `building_windows.rs:99`, `building_windows.wgsl:163-164`, `osm_buildings.rs:515`, `parking.rs:11-12`. - [ ] The note records the paging observation and points at `docs/notes/kadaster-parcels.md`'s paging section rather than restating it. - [ ] The note has a pointers section separating verified from unverified, including the unread `place_labels` `population` and the counter-argument above. - [ ] The note ends with a runnable, read-only command block reproducing every number in it. - [ ] `docs/direction.md` no longer lists CBS under *Candidates, unverified* (line 83 gone). - [ ] `docs/direction.md`'s *Checked and not taken* table has a CBS row dated 2026-08-29, in the same three-column form as the two rows above it, linking the new note. - [ ] No file outside `docs/` is touched; no extractor, no streamer, no coverage manifest, no `Cargo.toml` change. - [ ] The commit body names value 6 and value 1 and says how each decided it (value 7). ## Verification Read-only, all runnable in this container: ```bash # The two edited files, and nothing else. git diff --stat main...HEAD # → only docs/direction.md and docs/notes/cbs-neighbourhood-statistics.md # The row moved, and did not get duplicated. grep -n "CBS" docs/direction.md # → exactly one hit, in the "Checked and not taken" table # The note's links resolve. grep -o '](notes/[^)]*)' docs/direction.md | sed 's/](\(.*\))/docs\/\1/' | xargs ls # Every number in the note reproduces. B=https://service.pdok.nl/cbs/wijkenbuurten/2024/wfs/v1_0 BB=53.207,6.555,53.222,6.580,urn:ogc:def:crs:EPSG::4326 G="service=WFS&version=2.0.0&request=GetFeature&typeNames=wijkenbuurten" curl -sL "$B?request=GetCapabilities&service=WFS" > caps.xml grep -oE 'publicdomain/zero/1.0[^<]*|<ows:Fees>[^<]*|<Name>wijkenbuurten:[^<]*' caps.xml grep -A3 'CountDefault\|PagingIsTransactionSafe' caps.xml for T in buurten wijken gemeenten; do curl -sL "$B?$G:$T&resultType=hits&bbox=$BB" | grep -o 'numberMatched="[0-9]*"' done # → 23, 6, 1 J="$G:buurten&outputFormat=application/json&srsName=urn:ogc:def:crs:EPSG::4326" curl -sL "$B?$J&bbox=$BB&count=1000" -o buurten.json -w '%{size_download}\n' # → 257021 jq '[.features[]|.geometry|tostring|length]|add' buurten.json # → 27582 jq '[.features[].properties|to_entries[]]|length' buurten.json # → 5368 jq '[.features[].properties|to_entries[]|select(.value==-99997)]|length' buurten.json # → 1614 ``` **Nothing here needs a workstation, a GPU or a build.** No `cargo` command is required or expected: the change compiles nothing and the repo has no docs linter. Do not run `--shot` or `cargo shots` — there is no rendered artefact to check, and this container cannot render anyway. The one thing that cannot be re-verified from a shell is whether the *judgement* is right, and that is what the note's pointers section exists to make cheap to revisit. ## Out of scope - **Any layer, extractor, streamer or coverage manifest.** The result is "not taken"; nothing streams. - **Reading `place_labels`' `population`.** Named as a pointer in the note because it is the cheap answer to the same question, but it is a change to `cartopolis_geo`/`systems::places` and belongs to its own ticket off `docs/notes/vector-tile-unused-layers.md`. - **NDW traffic** (`docs/direction.md:82`). It is the row that carries real vehicle flow, and this note should say so rather than pre-empting it. - **Re-checking Kadaster or NWB.** Their notes stand; cite them, do not restate their contents. - **Correcting the "extractor under `tools/`" phrasing in the autopilot's ticket template.** Recorded above so it is not lost; fixing the template is a change to `tools/autopilot.ts`, not to `docs/`. - **Any change to `docs/direction.md` beyond the one row.** Value-list edits and frontier reordering are a maintainer decision — the file says a session may propose, not rewrite. ## Open questions None. The interface, the licence and the volume were all confirmed from the live service, and the ambiguity the ticket flagged is settled by values 6 and 1 as recorded above. --- Branch: `docs/192-cbs-statistics-not-taken` <details><summary>Original request</summary> From the frontier in [`docs/direction.md`](../src/branch/main/docs/direction.md): **CBS neighbourhood statistics** — how many people are actually there. The first half of this ticket is deciding whether it is worth doing at all: - Is there an interface a client or an extractor can use, and what does it cost per cell? - Does the licence allow redistributing what we would cache? - Does it change the picture, or only the data behind it? **Not worth it is a valid answer.** Record it in `docs/direction.md` against this row with 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.md` exist 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 what is drawn rather than replacing it, and no unbounded per-frame upload. <sub>Filed by the autopilot. <!-- autopilot:cbs-neighbourhood-statistics --></sub> </details> <sub>🤖 Refined by the viberfox issue agent. Reply with **@agent refine** and what is wrong to have this rewritten.</sub>
Author
Collaborator

🤖 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.

🤖 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.
Author
Collaborator

🤖 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:skip stops me.


🤖 viberfox issue agent on the VPS — 29 turns · $2.42 · session 3eb84cf3-de4e-48b6-bff2-de8c5cd1ea16. Reply with @agent to continue this session.

🤖 **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:skip` stops me. --- <sub>🤖 viberfox issue agent on the VPS — 29 turns · $2.42 · session `3eb84cf3-de4e-48b6-bff2-de8c5cd1ea16`. Reply with **@agent** to continue this session.</sub>
Author
Collaborator

🤖 Picked this up — working on branch docs/192-cbs-statistics-not-taken in a fresh worktree on the VPS. I'll report back here when I'm done.

Label an issue agent:skip to keep me off it, or driven to keep it in a session you are driving.

🤖 Picked this up — working on branch `docs/192-cbs-statistics-not-taken` in a fresh worktree on the VPS. I'll report back here when I'm done. <sub>Label an issue `agent:skip` to keep me off it, or `driven` to keep it in a session you are driving.</sub>
Author
Collaborator

Result: not worth wiring in. CBS neighbourhood statistics is now recorded as checked-and-not-taken. Two files changed, both documentation.

  • Added docs/notes/cbs-neighbourhood-statistics.md (141 lines) — the service, the CC0 evidence read off its own GetCapabilities, the volume table, why it lost, the paging trap, a pointers section, and a command block that reproduces every number in it.
  • Changed docs/direction.md by one line: the CBS row moved out of Candidates, unverified into Checked and not taken.

Why it lost. I re-ran every measurement against the live service rather than trusting the ticket, and all of them reproduce exactly. Over the Groningen box, the neighbourhoods response is 257,021 bytes of which only 27,582 is geometry — 696 coordinate pairs across 22 heavily generalised administrative outlines. The other 89 percent is a statistics table: 244 attributes per feature, of which 30 percent of the values are the suppression marker -99997. So there is no object to draw, and nothing a headless capture can assert (value 6). The strongest case for taking it — ground the invented densities in a measured one — fails at all three places that could use it (value 1): window occupancy is already fed per building from the building register, and the car and walker pools are fixed, sized for "is this street alive", and already denser than the registered-car figure CBS measures.

How I verified it. The issue's own verification block, all read-only: the three feature counts (23, 6, 1), the byte counts, the attribute and suppression counts, the duplicate page, and the link checks. No Rust file was touched, so there is nothing to compile; cargo fmt --check across the workspace is clean. No visual check is needed or possible — nothing renders.

One thing you should know. origin/main moved while I worked: NDW traffic was checked and rejected the same day, which conflicted with my edit. I rebased, resolved it, and rewrote the sentence that had pointed at NDW as an open row — the note now says the two failed for different reasons and neither rescues the other.

Worth your decision, not mine: the vector tiles this client already downloads carry a population figure in the place_labels layer that nothing reads. It costs no request, it is global rather than Dutch-only, and it is the cheaper answer to the same question. I left it as a pointer in the note rather than acting on it — it is a code change and belongs to its own ticket.

Branch docs/192-cbs-statistics-not-taken (pushed)

923e255 docs(frontier): CBS neighbourhood statistics checked against PDOK, and not taken

🤖 viberfox issue agent on the VPS — 35 turns · $3.22 · session de6053d9-d82a-4839-8c4e-72d4f5c222fa. Reply with @agent to continue this session.

**Result: not worth wiring in.** CBS neighbourhood statistics is now recorded as checked-and-not-taken. Two files changed, both documentation. - **Added** `docs/notes/cbs-neighbourhood-statistics.md` (141 lines) — the service, the CC0 evidence read off its own GetCapabilities, the volume table, why it lost, the paging trap, a pointers section, and a command block that reproduces every number in it. - **Changed** `docs/direction.md` by one line: the CBS row moved out of *Candidates, unverified* into *Checked and not taken*. **Why it lost.** I re-ran every measurement against the live service rather than trusting the ticket, and all of them reproduce exactly. Over the Groningen box, the neighbourhoods response is 257,021 bytes of which only 27,582 is geometry — 696 coordinate pairs across 22 heavily generalised administrative outlines. The other 89 percent is a statistics table: 244 attributes per feature, of which 30 percent of the values are the suppression marker `-99997`. So there is no object to draw, and nothing a headless capture can assert (value 6). The strongest case for taking it — ground the invented densities in a measured one — fails at all three places that could use it (value 1): window occupancy is already fed per building from the building register, and the car and walker pools are fixed, sized for "is this street alive", and already denser than the registered-car figure CBS measures. **How I verified it.** The issue's own verification block, all read-only: the three feature counts (23, 6, 1), the byte counts, the attribute and suppression counts, the duplicate page, and the link checks. No Rust file was touched, so there is nothing to compile; `cargo fmt --check` across the workspace is clean. No visual check is needed or possible — nothing renders. **One thing you should know.** `origin/main` moved while I worked: NDW traffic was checked and rejected the same day, which conflicted with my edit. I rebased, resolved it, and rewrote the sentence that had pointed at NDW as an open row — the note now says the two failed for different reasons and neither rescues the other. **Worth your decision, not mine:** the vector tiles this client already downloads carry a `population` figure in the `place_labels` layer that nothing reads. It costs no request, it is global rather than Dutch-only, and it is the cheaper answer to the same question. I left it as a pointer in the note rather than acting on it — it is a code change and belongs to its own ticket. **Branch** `docs/192-cbs-statistics-not-taken` (pushed) ``` 923e255 docs(frontier): CBS neighbourhood statistics checked against PDOK, and not taken ``` --- <sub>🤖 viberfox issue agent on the VPS — 35 turns · $3.22 · session `de6053d9-d82a-4839-8c4e-72d4f5c222fa`. Reply with **@agent** to continue this session.</sub>
Author
Collaborator

🤖 Marked agent:done without a CI verdict on 923e255a — no workflow reported on this commit. The branch is waiting for review; check the run yourself before landing it.

🤖 Marked `agent:done` **without a CI verdict** on `923e255a` — no workflow reported on this commit. The branch is waiting for review; check the run yourself before landing it.
viberfox-agent 2026-08-29 20:58:21 +00:00
Author
Collaborator

🤖 Merged into main as pull request #194 (923e255a).

🤖 **Merged into `main`** as pull request #194 (`923e255a`).
Author
Collaborator

🤖 Merged, but not deployed. The deploy step exited 1:

main is at 8a94e19a
  waiting for CI on 8a94e19a
refusing: no Actions job ran for 8a94e19a — nothing has verified this commit

main has the change; the public services are still on the previous build.

🤖 **Merged, but not deployed.** The deploy step exited 1: ``` main is at 8a94e19a waiting for CI on 8a94e19a refusing: no Actions job ran for 8a94e19a — nothing has verified this commit ``` `main` has the change; the public services are still on the previous build.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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
jeroen/cartopolis#192
No description provided.