gap: the vaarwegmarkeringen vocabularies are wider than the census the parser was built on #213

Closed
opened 2026-08-30 07:56:53 +00:00 by viberfox-agent · 3 comments
Collaborator

Problem

docs/notes/navigation-marks.md:58-91 records a census of 998 floating and 260 fixed marks over five boxes, and rests the whole design decision — parse by rule, not from a lookup table — on it (docs/notes/navigation-marks.md:60-62). The QA pass censused the whole register (10,105 floating, 8,369 fixed) and the vocabularies are wider than that sample. Three of the consequences are defects against the module's own stated rules; two are scope decisions.

Bruin is a seventh body colour, and it is silently substituted rather than dropped. MarkColour::parse (crates/geo/src/nav_marks.rs:94-105) has arms for six body colours plus Amber; nothing matches Bruin. ColourPattern::parse drops unreadable bands and keeps the rest (crates/geo/src/nav_marks.rs:153), so:

  • plain Bruin → empty pattern → read_feature returns None (crates/cartopolis/src/systems/map/nav_marks.rs:349-352). 3 fixed marks undrawn.
  • Rood/Bruin, Geel/Bruin → a one-band pattern, drawn as a plain red or plain yellow mark. 4 fixed marks drawn as a different mark.

The second one contradicts the module's own doctrine — "Drop, never substitute … a mark drawn as the wrong shape says the wrong thing" (crates/geo/src/nav_marks.rs:26-37, crates/geo/src/nav_marks.rs:809-812) — and the doc comment asserting the vocabulary is {Rood, Groen, Geel, Wit, Zwart, Grijs} (crates/geo/src/nav_marks.rs:127-133) is now known false.

Blauw is an unread light colour. light comes from licht_klr/licht_kl through MarkColour::parse (crates/cartopolis/src/systems/map/nav_marks.rs:364-366); with no arm it reads as None and the lantern is not built (crates/geo/src/nav_marks.rs:469-480). One fixed mark.

The note's opgeheven fact is false. docs/notes/navigation-marks.md:87-88 states it is # on all 1,258 sampled and that the API is not serving historical versions. Nationally five fixed features carry a date. The shipped check handles them correctly (crates/cartopolis/src/systems/map/nav_marks.rs:341-343, is_absent at :91-93), so the code is right and the note is wrong — and the note is the thing that would talk someone into deleting the check.

Two vocabulary gaps that are decisions, not defects. MarkShape::parse (crates/geo/src/nav_marks.rs:194-203) has no arm for ton (1) or afwijkend (4); FixedForm::parse (crates/geo/src/nav_marks.rs:236-249) has no arm for 12 values totalling 136 features. Both currently fall to None and are dropped, which is the documented behaviour for a value from a newer register (crates/geo/src/nav_marks.rs:227-234) — but it puts real navigation marks (Geleidelicht, Stuurlicht, Verkeerssein, Mistlichten, Wadpaal zonder licht) in the same bucket as the deliberately-excluded verge lighting. See Open questions.

Approach

crates/geo/src/nav_marks.rs — the vocabularies and geometry:

  • Add MarkColour::Brown and MarkColour::Blue, with arms in parse and tones in rgb (:94-124). Tones follow the module's stated rule (:16-24): muted signal colours, knocked back from the real paint, and distinct from all existing tones under every_colour_has_its_own_tone (:1004-1013) — that test's all array is enumerated by hand and must be extended.
  • Correct the ColourPattern doc comment's vocabulary list (:127-133) and the MarkColour::Amber "only ever a light colour" comment (:86) if Blue shares that property.
  • Extend every_observed_colour_pattern_parses (:702-783) with the newly-observed values, and note in its doc comment which census the list comes from.

crates/cartopolis/src/systems/map/nav_marks.rs — the cache tables:

  • Append the new colours to COLOURS (:112-120) — append, never renumber, per the rule at :97-99, which is what keeps cache_key's v1 (:295-297) valid and means already-cached cells stay readable. The array length annotation changes with it.

docs/notes/navigation-marks.md — "The vocabularies, censused" (:58-91):

  • Restate the section as a national census with its date, its bbox, and the cursor-paging command, rather than as a list of values a reader would take as exhaustive. The issue's own suggestion, adopted: record when it was last re-run and what the method is, and keep only the values that carry a decision (the Pilaar warning at :64-66, the missing-comma topmark at :71-73, the two-keys-for-one-vocabulary traps at :74-78, the three absent sentinels at :82-83).
  • Replace the opgeheven claim (:87-88) with the true one: dates do occur, the check earns its keep, do not delete it.
  • Correct the derived counts that quote the old sample: 33 of 260 sampled (:147) and Three of 260 (:150), and the matching in-code counts at crates/geo/src/nav_marks.rs:33-35, :186-190, :216-223.

Acceptance criteria

  • MarkColour::parse("Bruin") and MarkColour::parse("bruin") answer a colour; ColourPattern::parse("Rood/Bruin").bands.len() == 2.
  • MarkColour::parse("Blauw") answers a colour, and a fixed feature with "licht_kl":"Blauw" produces light: Some(_) through parse_items.
  • All colour tones remain pairwise distinct (every_colour_has_its_own_tone, crates/geo/src/nav_marks.rs:1004), with the new variants added to its all array.
  • The new colours are appended to COLOURS (crates/cartopolis/src/systems/map/nav_marks.rs:112); no existing index moves and cache_key's v1 is unchanged. A test asserts a cell encoded before the change still decodes to the same marks — the existing the_cached_form_round_trips (:625) does not cover this, so it needs a literal-JSON companion.
  • docs/notes/navigation-marks.md no longer claims opgeheven is # on every feature, and says the check must stay.
  • docs/notes/navigation-marks.md's vocabulary section states the census bbox, date and paging method, and its updated: front-matter is bumped.
  • Every count quoted from the 998/260 sample — in the note at :147 and :150, and in the code comments at crates/geo/src/nav_marks.rs:33-35, :186-190, :216-223 — is either restated against the national census or marked as a sample.
  • cargo fmt --check is clean workspace-wide (the CI gate is workspace-wide; see the standing note in CLAUDE.md).

Criteria for the naut_funct and obj_vorm additions are deliberately absent — see Open questions.

Verification

cargo test -p cartopolis_geo nav_marks
cargo test -p cartopolis nav_marks
cargo fmt --check

Re-running the census is the measurement this pass may not take. It is the command in the issue body — cursor-paged, following the next link, national bbox 3.0,50.6,7.4,55.7, limit=1000; ~20 pages, ~28 MB, under a minute. Whoever implements this runs it and pastes the resulting vocabulary counts into the note, rather than copying the issue's table.

Not checkable here: colour is not evidence on this container's software rasteriser (docs/notes/headless-shots-software-renderer.md), so whether a brown band reads as brown against the furniture base, and whether it is distinguishable from red at the Furniture fade distance, wants a workstation. The geometry half is assertable — nav_marks in --dump-state (crates/cartopolis/src/systems/dev/shot_harness.rs:640) counts marks in the loaded cells, so a Waal-at-Nijmegen capture (cell 8458, 5422) before and after shows whether the count moved. This container cannot run --shot, so that is a workstation step too.

Out of scope

  • The lights lighting. sign_kar/sign_perio are still not read; the lantern is painted in the registered colour and stops (crates/geo/src/nav_marks.rs:40-45, docs/notes/navigation-marks.md:133-138).
  • Heights. obj_hoogte remains zero on every fixed mark, so a light tower stays the same post as a groyne mark.
  • Colliders. A mark is still not a FurnitureInstance (docs/notes/navigation-marks.md:151-154).
  • Re-censusing the other Dutch registers. The same "the rule was justified by a partial sample" question could be asked of surveyed.rs's PROP_KINDS and crops' CATEGORIES; that is a separate ticket if anyone wants it.
  • A cache version bump. Appending to COLOURS does not need one, and doing it would throw away every cached cell for nothing.

Open questions

  1. Do any of the 12 unmatched naut_funct values become marks, and as which FixedForm? The existing three forms are GroyneMark, Beacon, LightPost (crates/geo/src/nav_marks.rs:215-224). Several of the 12 map onto LightPost with no invention (Geleidelicht 1, Stuurlicht 24, Mistlichten 14, Verkeerssein 30) and Wadpaal zonder licht 1 onto Beacon — but the stated reason for the existing exclusions is specifically that the BGT already surveys street lighting column by column (crates/geo/src/nav_marks.rs:50-54), and that reason does not decide Dukdalf (10, a mooring dolphin — a structure, not a mark), Ballenlijn aansluitpunt (34), Meetpaal (2) or Nautofoon (1). I am not willing to guess which of these the map should assert. If any needs new geometry rather than a reuse, note that MARK_MAX_BYTES (crates/geo/src/nav_marks.rs:413) assumes at most two segments per body and would have to be raised.

  2. ton (1) and afwijkend (4) — drop, or draw? MarkShape is a shape vocabulary; ton means "buoy" and afwijkend means "non-standard", so neither names a shape. Drawing them requires picking one, which is exactly the substitution an_unknown_form_is_dropped_rather_than_guessed (crates/geo/src/nav_marks.rs:810-812) exists to forbid. My reading is that dropping 5 features nationally is the right answer and the note should say so explicitly instead of leaving them looking like an oversight — but that is a call about what the map claims, so it is yours.

  3. Should an unreadable band drop the whole mark? Adding Bruin fixes the seven known cases, but the class of bug survives for the 27th value: ColourPattern::parse (crates/geo/src/nav_marks.rs:153) will keep drawing an A/<unknown> mark as a plain A one. Making it drop the mark instead matches "drop, never substitute", and costs the marks whose pattern is only partly readable. Fix the class or just the instance?


Branch: fix/213-nav-marks-vocabulary-gap

Original request

Found by the QA pass on #210, walking what #206/#207 shipped.

What I did

docs/notes/navigation-marks.md justifies parsing the register by rule rather than from a lookup table, and rests that on a census of 998 floating and 260 fixed marks over five boxes:

The numbers matter because nav_marks.rs parses these by rule rather than from a lookup table, and the census is what says the rule covers the register.

So I censused the whole register instead — all 10,105 floating and 8,369 fixed features, national bbox, cursor-paged — and applied the shipped match arms (MarkShape::parse, FixedForm::parse, MarkColour::parse, is_absent) to every one.

What happened

The rule does not cover the register. Nationally the vocabularies are 7 / 26 / 21 values where the note records 5 / 14 / 15.

Floating — 10,100 of 10,105 drawn. Two obj_vorm values the census never saw:

value count note
ton 1 literally the Dutch word for a buoy
afwijkend 4 "non-standard"

Fixed — 7,608 of 8,369 drawn. 625 of the 761 dropped are the four kinds the note deliberately excludes (Bermverlichting 443, Bordverlichting 121, Walkast 34, Aanstraalverlichting 27), which is working as designed. The remaining 136 are values the census never saw, and they fall into the same None bucket as the deliberate ones:

naut_funct count is it a mark?
Ballenlijn aansluitpunt 34 boom attachment point
Verkeerssein 30 shipping traffic signal
Stuurlicht 24 a steering light
Mistlichten 14 fog lights
Dukdalf 10 a mooring dolphin — a structure standing in the water
Luchtvaartverlichting 7 no
Meetpaal 2 a gauge pile
Noodverlichting 2 no
Heliverlichting 2 no
Wadpaal zonder licht 1 an unlit Wadden pole
Geleidelicht 1 a leading light
Nautofoon 1 a fog horn

And three more tails:

  • Bruin is a seventh colour. MarkColour::parse has no arm for it, so 3 fixed marks painted Bruin are not drawn at all (the pattern comes back empty), and 4 more — Rood/Bruin, Geel/Bruin — are drawn with the brown band silently missing. On a layer whose own note says "the colour is the meaning", dropping a band is the failure the module is written to avoid.

  • Blauw is a light colour, on one fixed mark. Unread, so that mark draws without its lantern colour.

  • opgeheven really does carry dates. The note says:

    opgeheven (decommissioned) is # on all 1,258 sampled — unlike the BGT, this API is not serving historical versions.

    Nationally five fixed features carry 17.11.2015 (×3), 07.04.2015 and 01.01.2022. The shipped check handles them correctly — is_absent says no and read_feature drops them — so the defensive check earns its keep, and the note's standing fact is simply false and should be corrected before someone deletes the check on the strength of it.

What a user would see

About 130 registered objects nationally, of ~18,500: a handful of buoys and a scatter of lights and poles missing, plus seven fixed marks in the wrong colour. Nothing dramatic, and no user would spot it in a given cell. What is worth deciding is that the reason for parsing by rule is stated as a measurement, and the measurement was taken over 7% of the register.

Where the seam is

  • crates/geo/src/nav_marks.rs — MarkShape::parse, FixedForm::parse, MarkColour::parse
  • docs/notes/navigation-marks.md — "The vocabularies, censused"

How to re-run it

The register pages by cursor, not by offset (an offset= query is a 400). Follow the next link:

https://api.pdok.nl/rws/vaarwegmarkeringen-nederland/ogc/v1/collections/
  {vaarweg_markeringen_drijvend_rd,vaarweg_markeringen_vast_rd}/items
  ?f=json&limit=1000&bbox=3.0,50.6,7.4,55.7

20 pages, ~28 MB, under a minute. It is cheap enough that the census could be a note that says when it was last re-run rather than one that says what the vocabularies are.

Filed by the QA pass on #210. Not autonomous — a person decides whether this becomes work.

🤖 Refined by the viberfox issue agent. Reply with @agent refine and what is wrong to have this rewritten.

## Problem `docs/notes/navigation-marks.md:58-91` records a census of 998 floating and 260 fixed marks over five boxes, and rests the whole design decision — parse by rule, not from a lookup table — on it (`docs/notes/navigation-marks.md:60-62`). The QA pass censused the whole register (10,105 floating, 8,369 fixed) and the vocabularies are wider than that sample. Three of the consequences are defects against the module's own stated rules; two are scope decisions. **`Bruin` is a seventh body colour, and it is silently substituted rather than dropped.** `MarkColour::parse` (`crates/geo/src/nav_marks.rs:94-105`) has arms for six body colours plus `Amber`; nothing matches `Bruin`. `ColourPattern::parse` drops unreadable bands and keeps the rest (`crates/geo/src/nav_marks.rs:153`), so: - plain `Bruin` → empty pattern → `read_feature` returns `None` (`crates/cartopolis/src/systems/map/nav_marks.rs:349-352`). 3 fixed marks undrawn. - `Rood/Bruin`, `Geel/Bruin` → a one-band pattern, drawn as a plain red or plain yellow mark. 4 fixed marks drawn as a *different* mark. The second one contradicts the module's own doctrine — "Drop, never substitute … a mark drawn as the wrong shape says the wrong thing" (`crates/geo/src/nav_marks.rs:26-37`, `crates/geo/src/nav_marks.rs:809-812`) — and the doc comment asserting the vocabulary is `{Rood, Groen, Geel, Wit, Zwart, Grijs}` (`crates/geo/src/nav_marks.rs:127-133`) is now known false. **`Blauw` is an unread light colour.** `light` comes from `licht_klr`/`licht_kl` through `MarkColour::parse` (`crates/cartopolis/src/systems/map/nav_marks.rs:364-366`); with no arm it reads as `None` and the lantern is not built (`crates/geo/src/nav_marks.rs:469-480`). One fixed mark. **The note's `opgeheven` fact is false.** `docs/notes/navigation-marks.md:87-88` states it is `#` on all 1,258 sampled and that the API is not serving historical versions. Nationally five fixed features carry a date. The shipped check handles them correctly (`crates/cartopolis/src/systems/map/nav_marks.rs:341-343`, `is_absent` at `:91-93`), so the code is right and the note is wrong — and the note is the thing that would talk someone into deleting the check. **Two vocabulary gaps that are decisions, not defects.** `MarkShape::parse` (`crates/geo/src/nav_marks.rs:194-203`) has no arm for `ton` (1) or `afwijkend` (4); `FixedForm::parse` (`crates/geo/src/nav_marks.rs:236-249`) has no arm for 12 values totalling 136 features. Both currently fall to `None` and are dropped, which is the documented behaviour for a value from a newer register (`crates/geo/src/nav_marks.rs:227-234`) — but it puts real navigation marks (`Geleidelicht`, `Stuurlicht`, `Verkeerssein`, `Mistlichten`, `Wadpaal zonder licht`) in the same bucket as the deliberately-excluded verge lighting. See Open questions. ## Approach `crates/geo/src/nav_marks.rs` — the vocabularies and geometry: - Add `MarkColour::Brown` and `MarkColour::Blue`, with arms in `parse` and tones in `rgb` (`:94-124`). Tones follow the module's stated rule (`:16-24`): muted signal colours, knocked back from the real paint, and distinct from all existing tones under `every_colour_has_its_own_tone` (`:1004-1013`) — that test's `all` array is enumerated by hand and must be extended. - Correct the `ColourPattern` doc comment's vocabulary list (`:127-133`) and the `MarkColour::Amber` "only ever a light colour" comment (`:86`) if `Blue` shares that property. - Extend `every_observed_colour_pattern_parses` (`:702-783`) with the newly-observed values, and note in its doc comment which census the list comes from. `crates/cartopolis/src/systems/map/nav_marks.rs` — the cache tables: - Append the new colours to `COLOURS` (`:112-120`) — **append, never renumber**, per the rule at `:97-99`, which is what keeps `cache_key`'s `v1` (`:295-297`) valid and means already-cached cells stay readable. The array length annotation changes with it. `docs/notes/navigation-marks.md` — "The vocabularies, censused" (`:58-91`): - Restate the section as a national census with its date, its bbox, and the cursor-paging command, rather than as a list of values a reader would take as exhaustive. The issue's own suggestion, adopted: record when it was last re-run and what the method is, and keep only the values that carry a *decision* (the `Pilaar` warning at `:64-66`, the missing-comma topmark at `:71-73`, the two-keys-for-one-vocabulary traps at `:74-78`, the three absent sentinels at `:82-83`). - Replace the `opgeheven` claim (`:87-88`) with the true one: dates do occur, the check earns its keep, do not delete it. - Correct the derived counts that quote the old sample: `33 of 260 sampled` (`:147`) and `Three of 260` (`:150`), and the matching in-code counts at `crates/geo/src/nav_marks.rs:33-35`, `:186-190`, `:216-223`. ## Acceptance criteria - [ ] `MarkColour::parse("Bruin")` and `MarkColour::parse("bruin")` answer a colour; `ColourPattern::parse("Rood/Bruin").bands.len() == 2`. - [ ] `MarkColour::parse("Blauw")` answers a colour, and a fixed feature with `"licht_kl":"Blauw"` produces `light: Some(_)` through `parse_items`. - [ ] All colour tones remain pairwise distinct (`every_colour_has_its_own_tone`, `crates/geo/src/nav_marks.rs:1004`), with the new variants added to its `all` array. - [ ] The new colours are **appended** to `COLOURS` (`crates/cartopolis/src/systems/map/nav_marks.rs:112`); no existing index moves and `cache_key`'s `v1` is unchanged. A test asserts a cell encoded before the change still decodes to the same marks — the existing `the_cached_form_round_trips` (`:625`) does not cover this, so it needs a literal-JSON companion. - [ ] `docs/notes/navigation-marks.md` no longer claims `opgeheven` is `#` on every feature, and says the check must stay. - [ ] `docs/notes/navigation-marks.md`'s vocabulary section states the census bbox, date and paging method, and its `updated:` front-matter is bumped. - [ ] Every count quoted from the 998/260 sample — in the note at `:147` and `:150`, and in the code comments at `crates/geo/src/nav_marks.rs:33-35`, `:186-190`, `:216-223` — is either restated against the national census or marked as a sample. - [ ] `cargo fmt --check` is clean workspace-wide (the CI gate is workspace-wide; see the standing note in CLAUDE.md). Criteria for the `naut_funct` and `obj_vorm` additions are deliberately absent — see Open questions. ## Verification ```bash cargo test -p cartopolis_geo nav_marks cargo test -p cartopolis nav_marks cargo fmt --check ``` Re-running the census is the measurement this pass may not take. It is the command in the issue body — cursor-paged, following the `next` link, national bbox `3.0,50.6,7.4,55.7`, `limit=1000`; ~20 pages, ~28 MB, under a minute. Whoever implements this runs it and pastes the resulting vocabulary counts into the note, rather than copying the issue's table. Not checkable here: colour is not evidence on this container's software rasteriser (`docs/notes/headless-shots-software-renderer.md`), so whether a brown band reads as brown against the furniture base, and whether it is distinguishable from red at the Furniture fade distance, wants a workstation. The geometry half is assertable — `nav_marks` in `--dump-state` (`crates/cartopolis/src/systems/dev/shot_harness.rs:640`) counts marks in the loaded cells, so a Waal-at-Nijmegen capture (cell 8458, 5422) before and after shows whether the count moved. This container cannot run `--shot`, so that is a workstation step too. ## Out of scope - **The lights lighting.** `sign_kar`/`sign_perio` are still not read; the lantern is painted in the registered colour and stops (`crates/geo/src/nav_marks.rs:40-45`, `docs/notes/navigation-marks.md:133-138`). - **Heights.** `obj_hoogte` remains zero on every fixed mark, so a light tower stays the same post as a groyne mark. - **Colliders.** A mark is still not a `FurnitureInstance` (`docs/notes/navigation-marks.md:151-154`). - **Re-censusing the other Dutch registers.** The same "the rule was justified by a partial sample" question could be asked of `surveyed.rs`'s `PROP_KINDS` and `crops`' `CATEGORIES`; that is a separate ticket if anyone wants it. - **A cache version bump.** Appending to `COLOURS` does not need one, and doing it would throw away every cached cell for nothing. ## Open questions 1. **Do any of the 12 unmatched `naut_funct` values become marks, and as which `FixedForm`?** The existing three forms are `GroyneMark`, `Beacon`, `LightPost` (`crates/geo/src/nav_marks.rs:215-224`). Several of the 12 map onto `LightPost` with no invention (`Geleidelicht` 1, `Stuurlicht` 24, `Mistlichten` 14, `Verkeerssein` 30) and `Wadpaal zonder licht` 1 onto `Beacon` — but the stated reason for the existing exclusions is specifically that the BGT already surveys street lighting column by column (`crates/geo/src/nav_marks.rs:50-54`), and that reason does not decide `Dukdalf` (10, a mooring dolphin — a structure, not a mark), `Ballenlijn aansluitpunt` (34), `Meetpaal` (2) or `Nautofoon` (1). I am not willing to guess which of these the map should assert. If any needs new geometry rather than a reuse, note that `MARK_MAX_BYTES` (`crates/geo/src/nav_marks.rs:413`) assumes at most two segments per body and would have to be raised. 2. **`ton` (1) and `afwijkend` (4) — drop, or draw?** `MarkShape` is a *shape* vocabulary; `ton` means "buoy" and `afwijkend` means "non-standard", so neither names a shape. Drawing them requires picking one, which is exactly the substitution `an_unknown_form_is_dropped_rather_than_guessed` (`crates/geo/src/nav_marks.rs:810-812`) exists to forbid. My reading is that dropping 5 features nationally is the right answer and the note should say so explicitly instead of leaving them looking like an oversight — but that is a call about what the map claims, so it is yours. 3. **Should an unreadable band drop the whole mark?** Adding `Bruin` fixes the seven known cases, but the class of bug survives for the 27th value: `ColourPattern::parse` (`crates/geo/src/nav_marks.rs:153`) will keep drawing an `A/<unknown>` mark as a plain `A` one. Making it drop the mark instead matches "drop, never substitute", and costs the marks whose pattern is only partly readable. Fix the class or just the instance? --- Branch: `fix/213-nav-marks-vocabulary-gap` <details><summary>Original request</summary> Found by the QA pass on #210, walking what #206/#207 shipped. ## What I did `docs/notes/navigation-marks.md` justifies parsing the register **by rule rather than from a lookup table**, and rests that on a census of 998 floating and 260 fixed marks over five boxes: > The numbers matter because `nav_marks.rs` parses these by rule rather than from a lookup table, and the census is what says the rule covers the register. So I censused the **whole** register instead — all 10,105 floating and 8,369 fixed features, national bbox, cursor-paged — and applied the shipped match arms (`MarkShape::parse`, `FixedForm::parse`, `MarkColour::parse`, `is_absent`) to every one. ## What happened The rule does not cover the register. Nationally the vocabularies are **7 / 26 / 21** values where the note records 5 / 14 / 15. **Floating** — 10,100 of 10,105 drawn. Two `obj_vorm` values the census never saw: | value | count | note | |---|---|---| | `ton` | 1 | literally the Dutch word for a buoy | | `afwijkend` | 4 | "non-standard" | **Fixed** — 7,608 of 8,369 drawn. 625 of the 761 dropped are the four kinds the note deliberately excludes (`Bermverlichting` 443, `Bordverlichting` 121, `Walkast` 34, `Aanstraalverlichting` 27), which is working as designed. The remaining **136 are values the census never saw**, and they fall into the same `None` bucket as the deliberate ones: | `naut_funct` | count | is it a mark? | |---|---|---| | `Ballenlijn aansluitpunt` | 34 | boom attachment point | | `Verkeerssein` | 30 | **shipping traffic signal** | | `Stuurlicht` | 24 | **a steering light** | | `Mistlichten` | 14 | **fog lights** | | `Dukdalf` | 10 | a mooring dolphin — a structure standing in the water | | `Luchtvaartverlichting` | 7 | no | | `Meetpaal` | 2 | a gauge pile | | `Noodverlichting` | 2 | no | | `Heliverlichting` | 2 | no | | `Wadpaal zonder licht` | 1 | **an unlit Wadden pole** | | `Geleidelicht` | 1 | **a leading light** | | `Nautofoon` | 1 | a fog horn | And three more tails: - **`Bruin` is a seventh colour.** `MarkColour::parse` has no arm for it, so 3 fixed marks painted `Bruin` are not drawn at all (the pattern comes back empty), and 4 more — `Rood/Bruin`, `Geel/Bruin` — are drawn with the brown band silently missing. On a layer whose own note says "the colour *is* the meaning", dropping a band is the failure the module is written to avoid. - **`Blauw` is a light colour**, on one fixed mark. Unread, so that mark draws without its lantern colour. - **`opgeheven` really does carry dates.** The note says: > `opgeheven` (decommissioned) is `#` on all 1,258 sampled — unlike the BGT, this API is not serving historical versions. Nationally five fixed features carry `17.11.2015` (×3), `07.04.2015` and `01.01.2022`. The shipped check handles them correctly — `is_absent` says no and `read_feature` drops them — so the defensive check earns its keep, and the note's standing fact is simply false and should be corrected before someone deletes the check on the strength of it. ## What a user would see About 130 registered objects nationally, of ~18,500: a handful of buoys and a scatter of lights and poles missing, plus seven fixed marks in the wrong colour. Nothing dramatic, and no user would spot it in a given cell. What is worth deciding is that the *reason* for parsing by rule is stated as a measurement, and the measurement was taken over 7% of the register. ## Where the seam is - `crates/geo/src/nav_marks.rs` — `MarkShape::parse`, `FixedForm::parse`, `MarkColour::parse` - `docs/notes/navigation-marks.md` — "The vocabularies, censused" ## How to re-run it The register pages by cursor, not by `offset` (an `offset=` query is a 400). Follow the `next` link: ``` https://api.pdok.nl/rws/vaarwegmarkeringen-nederland/ogc/v1/collections/ {vaarweg_markeringen_drijvend_rd,vaarweg_markeringen_vast_rd}/items ?f=json&limit=1000&bbox=3.0,50.6,7.4,55.7 ``` 20 pages, ~28 MB, under a minute. It is cheap enough that the census could be a note that says when it was last re-run rather than one that says what the vocabularies are. <sub>Filed by the QA pass on #210. Not `autonomous` — a person decides whether this becomes work.</sub> </details> <sub>🤖 Refined by the viberfox issue agent. Reply with **@agent refine** and what is wrong to have this rewritten.</sub>
Author
Collaborator

🤖 Promoted into the build lane by the 3-day retrospective (#218) — autonomous + ship.

Why this one, of the four gaps the QA pass on #210 filed:

  • It is value 1 with the evidence already in the ticket. docs/notes/navigation-marks.md justifies parsing by rule rather than from a lookup table, and rests that on a census of 1,258 features. The census over all 18,474 says the rule does not cover the register: 7 / 26 / 21 vocabulary values against the recorded 5 / 14 / 15. A standing fact in docs/notes/ is false, and the next person to trust it will delete the is_absent check on the strength of it.
  • A machine can judge it, which is value 6. Success is three counts and nothing else: 10,105 of 10,105 floating features parsed, the fixed count above the 7,608 drawn today, and zero marks reaching the mesh with a colour band silently dropped. No screenshot decides any of it.
  • Nothing here is fenced. WireMark is the on-disk cache format under cache/features/marks/v1/, not NetMessage — PROTOCOL_HISTORY is untouched, and there is no migration. Bump the v1 path segment if the shape changes.

Scope it to what the ticket measured: the missing MarkShape / FixedForm / MarkColour arms (ton, afwijkend, Bruin, Blauw, and the naut_funct values the ticket marks as real marks), then correct the note's census section and record the date it was re-run. Bermverlichting and the other three deliberate exclusions stay excluded.

The two gaps left unpromoted are #212 and #215; the retrospective's reasoning for leaving them is on #218.

🤖 **Promoted into the build lane** by the 3-day retrospective (#218) — `autonomous` + `ship`. Why this one, of the four gaps the QA pass on #210 filed: - **It is value 1 with the evidence already in the ticket.** `docs/notes/navigation-marks.md` justifies parsing by rule rather than from a lookup table, and rests that on a census of 1,258 features. The census over all 18,474 says the rule does not cover the register: 7 / 26 / 21 vocabulary values against the recorded 5 / 14 / 15. A standing fact in `docs/notes/` is false, and the next person to trust it will delete the `is_absent` check on the strength of it. - **A machine can judge it, which is value 6.** Success is three counts and nothing else: 10,105 of 10,105 floating features parsed, the fixed count above the 7,608 drawn today, and zero marks reaching the mesh with a colour band silently dropped. No screenshot decides any of it. - **Nothing here is fenced.** `WireMark` is the on-disk cache format under `cache/features/marks/v1/`, not `NetMessage` — `PROTOCOL_HISTORY` is untouched, and there is no migration. Bump the `v1` path segment if the shape changes. Scope it to what the ticket measured: the missing `MarkShape` / `FixedForm` / `MarkColour` arms (`ton`, `afwijkend`, `Bruin`, `Blauw`, and the `naut_funct` values the ticket marks as real marks), then correct the note's census section and record the date it was re-run. `Bermverlichting` and the other three deliberate exclusions stay excluded. The two gaps left unpromoted are #212 and #215; the retrospective's reasoning for leaving them is on #218.
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

🤖 This needs a decision before I build anything. The open questions are in the description above.

Answer them and reply with @agent refine to have the spec rewritten, or @agent to make me implement it as it stands.


🤖 viberfox issue agent on the VPS — 11 turns · $1.82 · session 0d0a394b-93b6-45d7-9ca2-b17b6e54f2e3. Reply with @agent to continue this session.

🤖 **This needs a decision before I build anything.** The open questions are in the description above. Answer them and reply with **@agent refine** to have the spec rewritten, or **@agent** to make me implement it as it stands. --- <sub>🤖 viberfox issue agent on the VPS — 11 turns · $1.82 · session `0d0a394b-93b6-45d7-9ca2-b17b6e54f2e3`. Reply with **@agent** to continue this session.</sub>
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#213
No description provided.