xtask/tests/rayon_free_law.rs
//! Guard test for the constellation's **rayon-free law** (ROOT LAW #0:
//! "Concurrency is `gatling`. rayon is FORBIDDEN."), scoped to the ENTIRE dwarves
//! workspace.
//!
//! Sibling guards already exist in `skade/skade/tests/rayon_free_law.rs`,
//! `znippy/tests/tests/rayon_free_law.rs` and
//! `znippy-zoomies/tests/rayon_free_law.rs`, and a twin of THIS file now guards
//! nornir (`nornir/tests/rayon_free_law.rs`). dwarves — the forge every pipeline
//! runs through — was **ungated** until this file landed.
//!
//! ## What the law actually forbids
//!
//! The law binds NORDISK code, not the world. Stated precisely:
//!
//! * **FORBIDDEN** — a first-party crate of this workspace calling rayon
//! (`rayon::…`, `.par_iter()`, `.par_bridge()`, a `ThreadPoolBuilder`, …) or
//! declaring rayon as one of its own dependencies (normal, dev, build,
//! target-scoped, optional-behind-a-feature — any of them). That is nordisk
//! code choosing rayon over `gatling`, and it is the real violation.
//!
//! * **ACCEPTABLE** — rayon appearing in `Cargo.lock` or in `cargo tree`
//! because some third-party crate uses it internally. `tokenizers`,
//! `tantivy`, `tract`, `sysinfo` and friends make their own concurrency
//! choices; that is not our call to police. A guard that reds on those would
//! be a false-positive machine, and a guard that cries wolf gets disabled or
//! weakened into uselessness — worse than no guard at all.
//!
//! So every assertion below is anchored on FIRST-PARTY use. Test 3 does consult
//! the resolved dependency graph, but only ever asks "is a package of THIS
//! workspace sitting directly above rayon?" — a third-party parent is expected
//! and explicitly asserted to be harmless.
//!
//! ## The two blind spots this guard closes
//!
//! The three older guards scan first-party `src/` for rayon tokens and
//! first-party `Cargo.toml` for a direct `rayon` key. Both checks are right and
//! are reproduced here (tests 1 and 2) — but they share two blind spots:
//!
//! * **Default-features blindness.** rayon can be declared as an OPTIONAL
//! dependency behind an off-by-default feature — the exact shape that
//! reached edda (an off-by-default `cozo` feature — and dwarves carries a
//! `cozo = ["nornir-release-core?/cozo"]` feature of its own). A manifest
//! scan that
//! only looks at plain `rayon = "1"` lines, or a resolver check run with the
//! default feature set, both pass while the route exists. So test 2 also
//! reads `dep:rayon` / `rayon/…` tokens out of `[features]` and the dotted
//! `[dependencies.rayon]` table form, and test 3 resolves with
//! `--workspace --all-features` and with dev/build edges included.
//!
//! * **Empty-scan blindness.** A guard that walks a path which no longer
//! exists, or parses output it never actually received, reports "no rayon"
//! forever. Every test carries a **non-vacuous anchor** so "found nothing"
//! is a measurement rather than a broken scan: every workspace member must
//! contribute at least one scanned `.rs` file; the token matcher must flag a
//! synthetic positive AND must not flag a comment; the manifest parser must
//! find a control dependency key that really is declared; and the graph
//! inversion must find a workspace member above a control crate that really
//! is depended on.
//!
//! ## Comments are not violations — how that is handled
//!
//! Every `rayon` grep hit in this house is a comment forbidding it (dwarves has
//! three, all `//`/`//!` lines saying "never rayon"). Three deliberate
//! measures keep the guard off its own documentation:
//!
//! 1. the source scan strips `//`-to-end-of-line before matching, so only live
//! code is ever tested (proved by an anchor that a comment-only mention is
//! NOT flagged);
//! 2. the manifest scan compares whole dependency KEYS, never substrings, and
//! strips `#` comments first, so `# never rayon` and a `raygun` dep are both
//! inert;
//! 3. THIS file is the one path the source scan skips (by basename), because
//! it is the file that must spell the forbidden tokens out in full.
//!
//! Known limitation, stated plainly: the scan strips line comments only, not
//! `/* … */` block comments. No file in this workspace mentions rayon inside a
//! block comment today; one that did would trip the guard, and the fix is to use
//! a line comment.
//!
//! ## Why this lives in `xtask` and not in `crates/dwarves/tests`
//!
//! The guard scans the WHOLE workspace and links nothing out of any member, so
//! its home only decides what has to compile before the law can be checked.
//! `crates/dwarves` is the heaviest crate here — `default` turns on
//! `embed-nornir`, and on 2026-08-01 it does not build at all against the local
//! sibling `edda` checkout (`error[E0063]: missing field `suite` in initializer
//! of `RoleGroup`, crates/dwarves/src/build_thing.rs:1974` — cross-repo path-dep
//! drift, unrelated to rayon). A law guard parked behind that is a law guard
//! that never runs, which is the same disease as a guard that can never go red.
//! `xtask` is a first-class workspace member with a 16-second build, so the law
//! is checkable whatever state the fat crate is in.
//!
//! Run: `cargo test -p xtask --test rayon_free_law`.
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
use std::process::Command;
// ─────────────────────────────────────────────────────────────────────────────
// Workspace discovery — FIRST-PARTY paths only
// ─────────────────────────────────────────────────────────────────────────────
/// The dwarves workspace root. dwarves' root manifest is VIRTUAL, so the guard
/// lives in a member (`<repo>/xtask`) and walks one level up to reach it — the
/// same shape znippy's guard uses from its `znippy-tests` member.
fn workspace_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("the xtask manifest dir has a parent (the repo root)")
.to_path_buf()
}
/// Strip a `//`-to-end-of-line comment so the token scan only sees live code.
fn strip_line_comment(line: &str) -> &str {
match line.find("//") {
Some(i) => &line[..i],
None => line,
}
}
/// Strip a `#`-to-end-of-line TOML comment.
fn strip_hash_comment(s: &str) -> &str {
match s.find('#') {
Some(i) => &s[..i],
None => s,
}
}
/// Every workspace member directory, read straight out of the root manifest's
/// `members = [ … ]` array (which may span several lines), so a newly-added
/// crate is covered automatically — no carve-outs. `"."` is the root crate.
fn workspace_members() -> Vec<PathBuf> {
let root = workspace_root();
let manifest = std::fs::read_to_string(root.join("Cargo.toml")).expect("read root Cargo.toml");
let start = manifest
.find("members")
.expect("root Cargo.toml has a members list");
let open = manifest[start..].find('[').expect("members array opens") + start;
let close = manifest[open..].find(']').expect("members array closes") + open;
let mut members = Vec::new();
for raw in manifest[open + 1..close].split(',') {
let entry = strip_hash_comment(raw).trim().trim_matches('"').trim();
if entry.is_empty() {
continue;
}
members.push(if entry == "." {
root.clone()
} else {
root.join(entry)
});
}
assert!(
!members.is_empty(),
"parsed ZERO workspace members out of the root Cargo.toml — the guard \
would then scan nothing and pass vacuously"
);
members
}
/// The one file the source scan skips: this guard, which must spell the
/// forbidden tokens out in full to be able to match them.
const GUARD_FILE: &str = "rayon_free_law.rs";
/// Directories that are never first-party nordisk source: build output and
/// vendored third-party trees. A vendored crate's internal rayon use is its own
/// business (see the module header), so scanning it would manufacture exactly
/// the false positive this guard must not have.
const NOT_FIRST_PARTY: &[&str] = &["target", "vendor", "node_modules"];
/// Recursively collect every `*.rs` path under `dir`, skipping non-first-party
/// trees and this guard file.
fn rs_files(dir: &Path, out: &mut Vec<PathBuf>) {
let Ok(rd) = std::fs::read_dir(dir) else {
return;
};
for entry in rd.flatten() {
let path = entry.path();
let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
if path.is_dir() {
if NOT_FIRST_PARTY.contains(&name) || name.starts_with('.') {
continue;
}
rs_files(&path, out);
} else if path.extension().and_then(|e| e.to_str()) == Some("rs") && name != GUARD_FILE {
out.push(path);
}
}
}
/// Every compiled tree of a first-party member — `src/` (where the three older
/// guards stop), plus `tests/`, `benches/`, `examples/` and `build.rs`. rayon in
/// a bench or a build script is still nordisk code choosing rayon.
fn member_rs_files(member: &Path) -> Vec<PathBuf> {
let mut files = Vec::new();
for sub in ["src", "tests", "benches", "examples"] {
rs_files(&member.join(sub), &mut files);
}
let build_rs = member.join("build.rs");
if build_rs.is_file() {
files.push(build_rs);
}
files
}
fn norm(path: &Path) -> String {
path.to_string_lossy().replace('\\', "/")
}
// ─────────────────────────────────────────────────────────────────────────────
// Test 1 — first-party sources must not CALL rayon
// ─────────────────────────────────────────────────────────────────────────────
/// Tokens that can only appear when **rayon** is actually being *used* by the
/// code under scan. The adaptors are matched as method calls (`.par_iter(`) so a
/// plain identifier like `par_sorted` is never a false positive; the pool
/// builders are matched by their type name, which no std API shares.
const FORBIDDEN_RAYON: &[&str] = &[
"use rayon",
"use rayon_core",
"rayon::",
"rayon_core::",
"extern crate rayon",
".into_par_iter(",
".par_iter(",
".par_iter_mut(",
".par_bridge(",
".par_chunks(",
".par_chunks_mut(",
".par_sort(",
".par_sort_by(",
".par_sort_by_key(",
".par_sort_unstable(",
".par_extend(",
"ParallelIterator",
"IntoParallelIterator",
"ParallelSlice",
"ParallelString",
"ThreadPoolBuilder",
];
/// Flag every forbidden token on a live (comment-stripped) source line.
fn rayon_hits(code: &str) -> Vec<&'static str> {
FORBIDDEN_RAYON
.iter()
.copied()
.filter(|tok| code.contains(tok))
.collect()
}
#[test]
fn first_party_sources_do_not_call_rayon() {
let members = workspace_members();
// ANCHOR (a): the matcher is alive — it must flag a synthetic positive built
// exactly the way a real violation would be. If this stops flagging, the
// "no violations" verdict below is meaningless.
let sample = strip_line_comment(" let out = xs.par_iter().map(f).collect(); // fan-out");
assert!(
!rayon_hits(sample).is_empty(),
"the rayon token matcher failed to flag a synthetic `.par_iter(` call — \
the scan below could not report red even if rayon were present"
);
// ANCHOR (b): …and a comment-only mention must NOT be flagged. This house
// documents the ban in comments everywhere; a guard that trips on its own
// documentation gets deleted, so prove it does not.
assert!(
rayon_hits(strip_line_comment(
"// ROOT LAW #0: gatling fan-out, never rayon::prelude / .par_iter()"
))
.is_empty(),
"the matcher flagged a comment-only rayon mention — it would red-light \
the law's own documentation"
);
let mut scanned = 0usize;
let mut violations = Vec::new();
for member in &members {
let files = member_rs_files(member);
// ANCHOR (c): every declared member must actually contribute source. A
// renamed or moved member would otherwise silently drop out of the scan
// and the guard would keep reporting green over a shrinking surface.
assert!(
!files.is_empty(),
"workspace member {} contributed ZERO .rs files to the scan — the \
guard is looking at a path that no longer exists",
norm(member)
);
for file in &files {
let text =
std::fs::read_to_string(file).unwrap_or_else(|e| panic!("read {file:?}: {e}"));
for (lineno, raw) in text.lines().enumerate() {
let code = strip_line_comment(raw);
for tok in rayon_hits(code) {
violations.push(format!(
"{}:{}: live `{tok}` — {}",
norm(file),
lineno + 1,
code.trim()
));
}
}
}
scanned += files.len();
}
assert!(
violations.is_empty(),
"rayon-free law violated — {} first-party source line(s) CALL rayon \
(ROOT LAW #0: nordisk code fans out through `gatling`):\n{}",
violations.len(),
violations.join("\n"),
);
eprintln!(
"rayon_free_law: scanned {scanned} first-party .rs files across {} workspace members",
members.len()
);
}
// ─────────────────────────────────────────────────────────────────────────────
// Test 2 — first-party manifests must not DECLARE rayon
// ─────────────────────────────────────────────────────────────────────────────
/// A dependency key belongs to the rayon family (`rayon`, `rayon-core`,
/// `rayon-cond`, `maybe-rayon`, `tokio-rayon`, …). Whole-key comparison, so a
/// `# rayon is forbidden` comment or an unrelated `raygun` dep never matches.
fn is_rayon_dep_key(key: &str) -> bool {
key == "rayon" || key.starts_with("rayon-") || key.ends_with("-rayon")
}
/// Scan every FIRST-PARTY manifest (the workspace root + each member) for a
/// rayon-family dependency, in any form:
/// * `[dependencies]` / `[dev-dependencies]` / `[build-dependencies]`,
/// `[workspace.dependencies]` and every `[target.'cfg(…)'.…dependencies]`;
/// * the dotted per-dependency table `[dependencies.rayon]`, which the three
/// older guards miss entirely (they test for a header ending `dependencies]`);
/// * an OPTIONAL rayon referenced from `[features]` as `dep:rayon` or
/// `rayon/feat` — the off-by-default shape that reached edda.
///
/// Returns the offenders plus whether the control key was seen — the parser's
/// proof of life.
fn scan_manifests(control_key: &str) -> (Vec<String>, bool) {
let root = workspace_root();
let mut manifests = BTreeSet::new();
manifests.insert(root.join("Cargo.toml"));
for member in workspace_members() {
manifests.insert(member.join("Cargo.toml"));
}
let mut offenders = Vec::new();
let mut saw_control = false;
for manifest in &manifests {
let Ok(text) = std::fs::read_to_string(manifest) else {
panic!("first-party manifest {} is unreadable", norm(manifest))
};
let mut in_deps = false;
let mut in_features = false;
for raw in text.lines() {
let line = raw.trim();
if line.starts_with('[') {
let hdr = line.trim_matches(['[', ']']).trim();
in_features = hdr == "features";
in_deps = hdr.ends_with("dependencies");
if let Some((prefix, dep)) = hdr.rsplit_once('.') {
if prefix.ends_with("dependencies") {
in_deps = true;
let dep = dep.trim().trim_matches('"');
if dep == control_key {
saw_control = true;
}
if is_rayon_dep_key(dep) {
offenders.push(format!("{}: {}", norm(manifest), line));
}
}
}
continue;
}
let code = strip_hash_comment(line);
if in_deps {
// `rayon = …`, `rayon.workspace = true`, `rayon.version = …`.
let key = code
.split('=')
.next()
.unwrap_or("")
.trim()
.split('.')
.next()
.unwrap_or("")
.trim()
.trim_matches('"');
if key == control_key {
saw_control = true;
}
if is_rayon_dep_key(key) {
offenders.push(format!("{}: {}", norm(manifest), code.trim()));
}
}
if in_features {
for tok in code.split(['"', ',', '[', ']']) {
let tok = tok.trim();
let dep = tok
.strip_prefix("dep:")
.or_else(|| tok.split('/').next())
.unwrap_or("")
.trim_end_matches('?');
if is_rayon_dep_key(dep) {
offenders.push(format!("{}: feature token `{tok}`", norm(manifest)));
}
}
}
}
}
(offenders, saw_control)
}
#[test]
fn no_first_party_manifest_declares_rayon() {
// ANCHOR: the same parser, over the same manifests, must find a dependency
// key that really is declared. If it cannot, it is not reading dependency
// tables at all and "no rayon" means nothing.
const CONTROL: &str = "serde";
let (offenders, saw_control) = scan_manifests(CONTROL);
assert!(
saw_control,
"manifest parser never saw the control dependency `{CONTROL}` in ANY \
first-party manifest — it is not reading dependency tables, so its \
rayon verdict is vacuous"
);
assert!(
offenders.is_empty(),
"rayon-free law violated — a first-party Cargo.toml declares a \
rayon-family dependency (directly, as a dotted table, or as an optional \
`dep:` feature token):\n{}",
offenders.join("\n"),
);
}
// ─────────────────────────────────────────────────────────────────────────────
// Test 3 — the RESOLVED graph, asked ONLY about first-party packages
// ─────────────────────────────────────────────────────────────────────────────
/// One `cargo tree --invert` row: `(depth, package name, package dir or None)`.
struct TreeRow {
depth: u8,
name: String,
dir: Option<String>,
}
/// Invert the resolved graph over `krate` and return its DIRECT dependents.
///
/// `--workspace --all-features` is the whole point: a default-features-only
/// resolve is blind to a rayon declared behind an off-by-default feature. Edges
/// are left at cargo's default (normal + build + dev) so a rayon dependency of a
/// build script or a dev-target is visible too.
///
/// `Ok(rows)` — the inversion ran; row 0 is `krate` itself.
/// `Ok(vec![])` — cargo says `krate` is not in the graph at all.
/// `Err(msg)` — the command FAILED. Callers must panic: an unparsed or absent
/// result must never be mistaken for "nothing found".
fn invert(krate: &str) -> Result<Vec<TreeRow>, String> {
let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
let manifest = workspace_root().join("Cargo.toml");
let out = Command::new(&cargo)
.arg("tree")
.arg("--manifest-path")
.arg(&manifest)
.args([
"--workspace",
"--all-features",
"--invert",
krate,
// depth 1 => only `krate` (depth 0) and its DIRECT dependents.
"--depth",
"1",
// `--prefix depth` emits the depth as a leading integer; with
// `--depth 1` that integer is always a single character.
"--prefix",
"depth",
"--format",
"{p}",
])
.output()
.map_err(|e| format!("could not run `{cargo} tree`: {e}"))?;
let stderr = String::from_utf8_lossy(&out.stderr).to_string();
if !out.status.success() {
if stderr.contains("did not match any packages") {
return Ok(Vec::new()); // not in the graph — genuinely absent
}
return Err(format!(
"`cargo tree --invert {krate}` failed ({}):\n{stderr}",
out.status
));
}
let stdout = String::from_utf8_lossy(&out.stdout).to_string();
let mut rows = Vec::new();
for line in stdout.lines() {
let line = line.trim_end();
if line.is_empty() {
continue;
}
let (d, rest) = line.split_at(1);
let depth: u8 = d.parse().map_err(|_| {
format!("unparsable `cargo tree` row {line:?} (expected a depth prefix)")
})?;
let name = rest
.split_whitespace()
.next()
.ok_or_else(|| format!("unparsable `cargo tree` row {line:?} (no package name)"))?
.to_string();
let dir = rest
.rfind('(')
.and_then(|a| rest.rfind(')').map(|b| rest[a + 1..b].to_string()));
rows.push(TreeRow { depth, name, dir });
}
if rows.is_empty() {
return Err(format!(
"`cargo tree --invert {krate}` exited 0 but printed NOTHING — an \
empty parse must not be read as an empty graph.\nstderr:\n{stderr}"
));
}
Ok(rows)
}
/// Direct dependents that are packages of THIS workspace. A package is
/// first-party iff its directory lies under the workspace root — which
/// correctly excludes the sibling `edda`/`facett`/`nornir`/`znippy` path-deps
/// (other repos, with their own guards) and every registry crate.
fn first_party_dependents(rows: &[TreeRow]) -> BTreeSet<String> {
let root = norm(&workspace_root());
// NB: a bare `starts_with(root)` is WRONG — this house is full of sibling
// worktrees (`<repo>-wt-<topic>`), and `/git/dwarves-wt-bt` starts with
// `/git/dwarves`. Require an exact match or a `/`-delimited descendant, or a
// neighbouring checkout gets misfiled as first-party.
let prefix = format!("{root}/");
rows.iter()
.filter(|r| r.depth == 1)
.filter(|r| {
r.dir
.as_deref()
.map(|d| {
let d = d.replace('\\', "/");
d == root || d.starts_with(&prefix)
})
.unwrap_or(false)
})
.map(|r| r.name.clone())
.collect()
}
/// Direct dependents that are NOT packages of this workspace — third-party
/// crates that use rayon internally. Reported, never failed on.
fn third_party_dependents(rows: &[TreeRow]) -> BTreeSet<String> {
let first = first_party_dependents(rows);
rows.iter()
.filter(|r| r.depth == 1)
.map(|r| r.name.clone())
.filter(|n| !first.contains(n))
.collect()
}
/// THE LAW at resolution level: no crate of THIS workspace may sit directly
/// above rayon under ANY feature combination.
///
/// This is the resolver's cross-check on test 2 — it sees forms a hand-rolled
/// manifest parser can miss (a `rayon.workspace = true` inherit, a rename, a
/// dependency reached through a feature of a *first-party* sibling). It says
/// nothing about third-party parents, by design.
#[test]
fn no_first_party_crate_depends_on_rayon() {
// ANCHOR (a): prove the inversion can see a first-party -> dependency edge
// at all. `serde` is depended on directly by several dwarves crates; if the
// control turns up no workspace member, the mechanism is broken and a real
// first-party rayon edge would be equally invisible.
const CONTROL: &str = "serde";
let control = invert(CONTROL).unwrap_or_else(|e| panic!("{e}"));
let control_members = first_party_dependents(&control);
assert!(
!control_members.is_empty(),
"control inversion over `{CONTROL}` found NO first-party package above \
it — `cargo tree --invert` is not resolving first-party edges here, so \
its rayon verdict is vacuous.\nrows seen: {}",
control.len()
);
for krate in ["rayon", "rayon-core"] {
let rows = invert(krate).unwrap_or_else(|e| panic!("{e}"));
if rows.is_empty() {
eprintln!("rayon_free_law: `{krate}` is not in the resolved graph at all");
continue;
}
assert!(
rows.iter().any(|r| r.depth == 0 && r.name == krate),
"`cargo tree --invert {krate}` did not report `{krate}` as its own \
root — the parse is wrong and the verdict below is vacuous"
);
let third = third_party_dependents(&rows);
// ANCHOR (b): the FALSE-POSITIVE guard, and simultaneously the proof
// that rayon really is visible to this mechanism. Third-party crates DO
// pull rayon here and that is ACCEPTABLE — their internal concurrency is
// not nordisk's choice. Reporting them keeps the measurement honest
// without ever failing on them.
eprintln!(
"rayon_free_law: `{krate}` has {} third-party parent(s), all ACCEPTABLE: {:?}",
third.len(),
third
);
let offenders = first_party_dependents(&rows);
assert!(
offenders.is_empty(),
"rayon-free law violated — dwarves workspace crate(s) depend DIRECTLY \
on `{krate}` under `--all-features`: {offenders:?}\n\
A third-party crate using rayon internally is fine; nordisk code \
choosing it is not. Route the fan-out through `gatling`."
);
}
}