# 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