# korp-collectors CI/build pipeline — driven by the dwarves forge (brokkr
# descriptor + sindri scheduler). `dwarves validate` / `dwarves plan` /
# `dwarves run [--real]`.
#
# WHY THIS FILE EXISTS (MEASURED 2026-08-25): korp-collectors had none. Across the
# whole constellation — 38 repos under ~/git — `nornir/brokkr.toml` was the ONLY
# pipeline declaration until this morning, when Skidbladnir became the second. So
# the forge had no job for this repo: four variants were declared in
# `.nornir/build-variants.toml` and the only thing that ever compiled any of them
# was a human typing `cargo xtask build`.
#
# The size of the hole is already written down in this repo's own build space, in
# the note on the `korp-collectors-osm-daemon` cell: measured on oden 2026-08-22,
# `cargo test -p korp-collectors` runs **112** lib tests and the same command with
# `--features osm-daemon` runs **241**. 129 tests — the region-cut daemon and the
# post-condition suite that decides whether a freshly cut extract may replace the
# one being served — reachable only by remembering a flag. The `daemon` step below
# is what makes them something a push touches.
#
# ── WHAT EACH STEP KIND ACTUALLY DOES (read before adding one) ──────────────────
#
# run = { variant = "…" } → `nornir_build_thing::build_variant` — a real cargo
# BUILD under `--real`
# (dwarves/crates/dwarves/src/runner.rs:217,253).
# run = { tests = "…" } → the variant's OWN argv with `build` swapped for
# `test`, through `buildgate::run_cargo` — a real cargo
# TEST run (runner.rs:174). Same package, same features,
# same profile; `--bin`/`--lib` are stripped so the
# package's whole suite runs.
# run = { container = … } → `UnwiredRunner`. FAILS. Do not declare one.
# run = { vm = … } → `UnwiredRunner`. FAILS. Do not declare one.
#
# ⚠ THE DECLARATION IS AHEAD OF THE INSTALLED FORGE. `RunKind::Tests` landed in
# dwarves `abe10d4` (2026-08-25). The `dwarves` on this box is 0.1.2 and predates
# it: `dwarves validate` from that binary REJECTS the `tests` steps below with
# "invalid: parse ./brokkr.toml". Validated instead against a `dwarves` built from
# the current source tree. Reinstall the forge; do not delete the test steps.
#
# ⚠ ONLY A CARGO KIND MAY BE NAMED. `build_variant` spawns cargo with
# `variant.cargo_args()` and branches on NOTHING
# (edda/crates/nornir-build-thing/src/provenance.rs:473). All four of this repo's
# variants are `kind = "exe"` or `kind = "lib"`, so the whole build space is
# declarable here.
[pipeline]
name = "korp-collectors-ci"
[[pipeline.trigger]] # fire when the poll sweep sees HEAD move
kind = "poll"
events = ["push"]
[[pipeline.trigger]] # …and nightly at 04:00 (off nornir 03:00 / skidbladnir 03:20)
kind = "cron"
cron = "0 4 * * *"
# ── the light pure-Rust core ─────────────────────────────────────────────────
#
# WHY GROUPED THIS WAY: this repo's four variants sit on a strict THREE-RUNG
# DEPENDENCY LADDER, declared in Cargo.toml and visible in `[features]`:
#
# parsers → pure Rust: RDF/PxWeb/ENTSO-E/REST/Trafikverket + the shared HTTP
# core + the OSM tag trie. No geo dep, no skade, no Iceberg.
# osm → parsers + `osm-katana` (the heavy geometry/WKB engine)
# osm-daemon → daemon(+redb, blake3) + osm + `rotaryengine` + libc
#
# One stage per rung, so a red names the rung — "the parsers broke" and "osm-katana
# broke" and "the region-cut daemon broke" are three different mornings. The two `parsers`
# cells (the driver bin and the library a consumer such as facett-demo links) share
# a stack and therefore share a stage; everything heavier needs `lib` and nothing
# else, because the rungs above do not depend on each other's success to be worth
# attempting.
[[pipeline.stage]]
name = "parsers"
[[pipeline.stage.step]]
name = "lib"
run = { variant = "korp-collectors-lib" } # the object-safe parser/registry lib
[[pipeline.stage.step]]
name = "driver"
needs = ["lib"]
run = { variant = "korp-collectors" } # the unified collector driver bin
# ── the heavier stacks, each on its own dependency ───────────────────────────
[[pipeline.stage]]
name = "heavy-stacks"
[[pipeline.stage.step]]
name = "geo" # + osm-katana way→WKB / admin relations
needs = ["lib"]
run = { variant = "korp-collectors-osm" }
# The cell whose absence this repo already measured: `osm-daemon` compiles
# `osm_cut.rs` (41 unit tests), `osm_cut_verify.rs` (11) and `daemon.rs` (11),
# i.e. the region-cut daemon and the post-condition suite. It is also the only rung that
# links redb and rotaryengine.
[[pipeline.stage.step]]
name = "daemon"
needs = ["lib"]
run = { variant = "korp-collectors-osm-daemon" }
# ── the suites, at the SAME features the artifacts are built with ────────────
#
# `parsers-tests` is declared on `korp-collectors-lib` and NOT also on
# `korp-collectors`: a test step strips `--bin`/`--lib` from the variant's argv, so
# the two would resolve to the byte-identical `cargo test -p korp-collectors
# --features parsers --profile release`. One writer.
#
# `daemon-tests` is the 112 → 241 step. Both numbers are this repo's own, measured
# on oden 2026-08-22 and recorded on the `korp-collectors-osm-daemon` cell.
[[pipeline.stage]]
name = "test"
[[pipeline.stage.step]]
name = "parsers-tests"
needs = ["lib"]
run = { tests = "korp-collectors-lib" }
[[pipeline.stage.step]]
name = "geo-tests"
needs = ["geo"]
run = { tests = "korp-collectors-osm" }
[[pipeline.stage.step]]
name = "daemon-tests"
needs = ["daemon"]
run = { tests = "korp-collectors-osm-daemon" }
# ── WHAT IS DELIBERATELY NOT DECLARED HERE, AND WHY ──────────────────────────
#
# NINE features gate tests in this repo that NO `[[build.variant]]` enables, so no
# step above can name them and ~70 `#[test]` fns are compiled by nobody. None of
# the nine is in `[build] offers`, so a variant for any of them needs that list
# widened first (`BuildVariantSet::validate` refuses a cell reaching for an
# unoffered capability):
#
# feature | dark tests | what is dark
# -------------+------------+----------------------------------------------------
# gribnc | 17 | src/gribnc.rs (gated at src/lib.rs:1542)
# service | 13 (5+8) | tests/register_across_processes.rs + src/nursery.rs
# systemd | 10 (2+8) | tests/systemd_unit_is_really_installed.rs +
# | | src/runtime_systemd.rs
# kvm-guest | 9 | tests/osm_chain_kvm.rs
# csv | 7 | tests/collectors_csv.rs
# mainframe | 7 | tests/collectors_mainframe.rs
# znippy | 4 (2+2) | tests/collectors_znippy.rs + src/znippy_pack.rs
# gtfs | 3 | src/gtfs.rs (gated at src/lib.rs:1522)
# skade-sink | 0 | tests/collectors_e2e_skade.rs (a file with no #[test])
#
# `systemd` and `service` are the sharpest of these: this crate installs a real
# systemd unit through skidbladnir, and the test that asserts the unit is *really*
# installed is behind a feature no declared build point turns on. Left as a stated
# finding rather than fixed here — widening `offers` and adding five or six cells is
# a change to the shared build space, not to this pipeline. Add them and the steps
# belong here.