Gunnar

nordisk/nornir

.woodpecker.yml

# Codeberg Woodpecker CI — replaces the retired GitHub `.github/workflows/ci.yml`
# after the move off GitHub. Same intent: build + test, plus informational
# clippy/fmt (the crate is not yet fmt/clippy-clean, so lint never fails the run).
#
# NOTE: nornir's DEFAULT feature set is heavy (egui/eframe + the typst docs stack
# + the ML embedders ort/candle/tract + the embedded holger). On a bare Woodpecker
# rust container that needs the system libs below and a generous build budget;
# tune the apt list / feature flags on the first real run.

when:
  - event: [push, pull_request]
    branch: main

variables:
  - &rust_image 'docker.io/library/rust:1-bookworm'

steps:
  build-test:
    image: *rust_image
    environment:
      CARGO_TERM_COLOR: always
      RUST_BACKTRACE: '1'
    commands:
      # System deps for the heavy default features: pkg-config/openssl + cmake for
      # native build scripts, and the X/wayland libs eframe links against.
      - apt-get update
      - apt-get install -y --no-install-recommends
          pkg-config cmake libssl-dev
          libxcb1-dev libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev
          libxkbcommon-dev libgtk-3-dev
          libgraphblas-dev
      # Mímir v2: the code room links the SYSTEM SuiteSparse:GraphBLAS (a build
      # requirement, decision D5). `graphblas-sys` speaks 7.x only — fail here,
      # in one line, when the image's package is missing or another major,
      # instead of in the linker of every test binary below.
      - 'ls /usr/lib/*-linux-gnu/libgraphblas.so.7* >/dev/null 2>&1 || { echo "SuiteSparse:GraphBLAS 7.x not found — apt-get install libgraphblas-dev (the image ships another major?)"; ls /usr/lib/*-linux-gnu/libgraphblas* 2>/dev/null; exit 1; }'
      - cargo build --workspace --verbose
      - cargo test --workspace --verbose
      # ATOM MARKER: `atom-cli` is a pure marker feature whose only job is to give the
      # `nornir-cli` [[bin]] a required-features key of its own. Its ONE applied
      # proof (`tests/build_variants.rs::the_atom_marker_reaches_the_binary`) runs
      # the built `nornir` and `nornir-cli` and requires their `--version` text to
      # DIFFER — and it is `#[cfg(feature = "atom-cli")]`, so without this line it is
      # compiled out of every run and the file reads green having asserted nothing.
      # `tests/build_variants.rs::ci_compiles_the_atom_marker_feature` goes red if
      # this line disappears.
      - cargo test -p nornir --features atom-cli --test build_variants --verbose
      # THE SOLO ATOM: `nornir-solo` claims UI + server in ONE process. The only
      # thing that can catch a solo binary which silently starts no server is
      # running it, and `tests/solo_embeds_server.rs` does exactly that — headless
      # via `--robot-remote`, then a REAL Health.Ping against the port it printed,
      # with the identical probe against `nornir-ui` required to find nothing.
      # Both are cfg-gated on these two features;
      # `tests/solo_embeds_server.rs::ci_compiles_the_solo_proof` goes red if this
      # line disappears.
      - cargo test -p nornir --features solo,robot-remote --test solo_embeds_server --verbose
      # ★ THE testmatrix ARM. `testmatrix` is `default`-OFF and gates the headless
      # egui draw helpers in `src/viz/{app,warehouse_deck_tab}.rs` plus the WHOLE of
      # `tests/self_emitters_server.rs` (`#![cfg(all(feature = "server", feature =
      # "testmatrix"))]`). Measured 2026-08-22: the egui realign (`833b639`) turned
      # `Context::run` into `run_ui` and the testmatrix-gated arm was never compiled
      # after it, so `cargo check --features testmatrix --lib` had sat RED with 3x
      # E0599 and the self-emitters proof had been a silent NO-RUN ever since — the
      # file's own documented invocation could not even reach the test list.
      # `tests/feature_combo_gate.rs::ci_compiles_the_testmatrix_arm` goes red if
      # this line disappears.
      - cargo test -p nornir --features "viz,server,mcp,vector,docs-export,testmatrix" --test self_emitters_server --verbose
      # ★ THE FEATURE-COMBO GATE (SK290). Everything above builds `default`, and
      # `default` turns nearly every feature ON — so a symbol that should be
      # `#[cfg]`-gated and is not is INVISIBLE to all of it. Measured 2026-08-01:
      # the leanest DECLARED atom, `nornir-ui`
      # (`--no-default-features --features viz`, `.nornir/build-variants.toml`
      # ATOM 4/7), had 18 compile errors and nobody knew, because no command in
      # this file ever built it. This verb `cargo check`s EVERY combination the
      # declaration names and names the atom that fails.
      # `tests/feature_combo_gate.rs::ci_runs_the_feature_combo_gate` goes red if
      # this line disappears.
      - cargo run -p xtask -- feature-matrix
      # ★ THE HEADLESS DAEMON — `server,mcp` WITHOUT `viz`. The one combination
      # `feature-matrix` cannot cover, because it only checks what
      # `.nornir/build-variants.toml` DECLARES and every declared atom that has
      # `server` also has `viz`. Measured 2026-08-27: `--features server,mcp` did not
      # compile at all — `#[tool_router]` expands BEFORE the entry's own `#[cfg]`, so
      # the router wrote `Self::mimir_subclone` and `#[cfg(feature = "vector")]`
      # deleted the function under it (`0ce005b`). Invisible because nothing built the
      # pair: `[[bin]] nornir-server` also required `viz`, so a headless daemon was not
      # a buildable artifact — the same gate that left the `Viz` gRPC service missing
      # from every headless embedding and the forge answering `Unimplemented` to
      # `Viz.Jobs`. This is the shape the FORGE actually embeds (`full-server =
      # ["server"]`, no `viz`) plus MCP, and it is now the only pair of surfaces
      # proven to coexist. `--lib --bins` is the ARTIFACT: the daemon and the library a
      # host embeds, which is exactly what J10 is about.
      #
      # NOT `--all-targets`, and that is a measurement, not a shrug. Measured
      # 2026-08-27: `--all-targets` on this combo is RED with **15 errors across 7
      # files** — `src/viz/{mod,remote,test_boot}.rs`, `src/bin/nornir.rs`,
      # `src/bench_registry.rs`, `src/mimir_clones.rs` and `examples/`. Every one is a
      # `#[cfg(test)]` item reaching a `viz`-gated module (`use super::super::knowledge`,
      # `super::super::arch_tab`) without carrying `#[cfg(feature = "viz")]` itself —
      # the SAME defect class this gate exists for, one target-kind over, and a backlog
      # that belongs to whoever owns those tests. Turning it on today would land a CI
      # step that is red on arrival, which teaches people to ignore the step. The lib
      # and the bins are green and are the claim being made.
      # `tests/feature_combo_gate.rs::ci_compiles_the_headless_server_with_mcp`
      # goes red if this line disappears.
      - cargo check -p nornir --no-default-features --features server,mcp --lib --bins --verbose
      # ★ THE LINKAGE AUDIT. `linkage = fat|thin|mixed` is a claim about the
      # BINARY, and nothing in a TOML file makes it true. This builds the leanest
      # atom at its DECLARED flags and reads its symbol table through the shared
      # `nornir_build_thing::linkage::LinkageAudit`. Measured 2026-08-03: nornir-ui
      # carries datafusion 61790 · iceberg 8841 · parquet 6198 and ZERO server
      # symbols — so `mixed` is exact, and the matrix's `<x>-ui = thin` is
      # unreachable until skade/iceberg/parquet are made optional. `--ignored`
      # because it compiles a 268 MB artifact; without it only the companion runs.
      # `tests/atom_linkage.rs::ci_runs_the_linkage_audit` goes red if this line
      # disappears.
      - cargo test -p nornir --test atom_linkage -- --ignored --nocapture

  lint:
    image: *rust_image
    environment:
      CARGO_TERM_COLOR: always
    commands:
      - rustup component add clippy rustfmt
      # Informational only (no `-D warnings`): mirrors the old GitHub job's
      # `continue-on-error: true`.
      - cargo clippy --workspace --all-targets || true
      - cargo fmt --all -- --check || true