Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/dwarves

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`."
        );
    }
}