korp-collectors' build thing — what the recipe declares, and why
The code is the source (lane AG, 2026-08-30). crates/korp-collectors-build-thing is this repo's impl BuildThing; .nornir/build-variants.toml is emitted from it and read back as authority by nothing:
cargo run -p korp-collectors-build-thing -- emit # regenerate the file
cargo run -p korp-collectors-build-thing -- toml # the emission, on stdout
cargo run -p korp-collectors-build-thing -- --list # the roster and its cargo argv
tests/toml_parity.rs fails for any reason the file and the code differ.
What it declares
One package, one shipped [[bin]], one library. Four rows:
| variant | kind | features | what it is |
korp-collectors ⭐ |
exe | parsers |
the driver on the LIGHT surface: DCAT-AP-SE RDF, PxWeb/JSON-stat2, ENTSO-E XML, REST/JSON, Trafikverket → Arrow |
korp-collectors-osm |
exe | osm |
plus the OSM geometry connectors and the RegionSource fetch seam |
korp-collectors-osm-daemon |
exe | osm-daemon |
plus the region-cut daemon: planet → region catalog → the lettered a–g cut → ONLINE, and the post-condition suite that decides whether a fresh extract may replace the one being served |
korp-collectors-lib ⭐ |
lib | parsers |
the parser/registry library a consumer links in-process |
linkage = "not-applicable" on the library row is a declaration, not an omission. The driver rows are plain exes: korp-collectors reaches its sources over HTTP, embeds no suite sibling, and is not itself a suite service.
What the hand-written file got wrong, and the emission exposes
- it listed
daemoninoffersand nothing built it, with no excuse — the precise shape of rot the gate exists for; - it never mentioned eleven of the crate's fifteen features at all, so the manifest-direction gate had nothing to ask about them;
- it never mentioned the second
[[bin]],korp-chain-init— the KVM guest's PID 1 for the a–e chain drill. It is in[build.allow_unbuilt_bins]now, with the reason (tests/osm_chain_kvm.rsbuilds it behindkvm-guest; a delivery never does, because a restart is not adrop()andst_blocksis a property of a real filesystem).
The inventory's one "CLI" — collectors_parse — is [[bench]] targets, and the_only_binary_a_row_names_is_the_one_that_exists holds the recipe to that.
The feature axis
Fifteen features; four built; eleven excused by name in [build.allow_unbuilt], each saying what the feature is and why nothing here compiles it. The three recurring reasons are worth stating once:
- a sink (
skade-sink,znippy) is the consumer's choice — the same collector feeds a memory sink, a znippy archive or Iceberg; - a runtime substrate (
service,systemd) is the deployer's choice, and every byte of it routes through Skidbladnir; - a per-source collector (
csv,mainframe,gtfs,gribnc) is a deployment decision; pulling every parser into one binary is not a decision this repo has taken.
recipe.rs::the_feature_axis_gate_is_clean runs FeatureAxis::gate() over the declaration, so a new feature with no row and no excuse fails here rather than rotting — and a stale excuse (a feature a row now builds) fails too.