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

nordisk/edda

crates/nornir-testmatrix/src/citations.rs

//! **A cited guard must exist** — the phantom-citation audit.
//!
//! Comments justify code by naming the test that covers it: *"(Integration tests
//! against a live FalkorDB instance live in the integration test file.)"*. That
//! sentence is load-bearing — a reader who sees it stops looking for coverage.
//! When the named file does not exist the comment is a **phantom guard**, and a
//! pointer to an imaginary guard is *indistinguishable from a real one*. It reads
//! as green.
//!
//! This is the sibling of [`crate::gatedtests`]: that one catches tests that can
//! never RUN, this one catches tests that never EXISTED.
//!
//! ## Found in the wild
//!
//! * knut's `graphar-falkordb/src/tests.rs` cited an integration-test file that has
//!   never existed in that repo — directly above a `#[tokio::test]` whose name promised query
//!   verification and whose body asserted only that its own fixture had three rows.
//!   Under both sat a row-render loop written out twice, tested on one copy only:
//!   dropping `_gar_id` from the untested copy left all 42 tests green while the
//!   loader silently stopped emitting the property every edge insert matches on.
//! * facett's `saga.proto` header cited a `test_saga_wire` python file as proof
//!   the wire subset could not drift. No file of that name has ever existed in any
//!   repo. (Named without its path on purpose — this audit reads its own source,
//!   and a post-mortem is indistinguishable from a claim.)
//!
//! ## Why it is quiet enough to keep
//!
//! A guard that cries wolf gets switched off, so this one refuses to guess:
//!
//! * **Comments only.** `classify(…, "tests/foo.rs")` passes a *fixture name* to
//!   a parser; it does not claim a file exists. String literals are stripped.
//!   (Written with a placeholder stem on purpose — this audit runs over its own
//!   source, and it is right to.)
//! * **Siblings resolve.** A comment in edda naming `tests/viz_surface.rs` means
//!   nornir's file. Pass the sibling checkouts and cross-repo citations resolve
//!   instead of being reported as missing.
//! * **Placeholders are not citations.** `<c>/tests/foo.rs → "<c>::tests::foo"`
//!   illustrates a path→module mapping. Stems in [`PLACEHOLDER_STEMS`], and any
//!   stem of one or two characters (`src/a.rs`, `src/a/b.rs`), are skipped.
//! * **`.nornir/` is not scanned.** That is the design/planning dir; a proposal
//!   naming the file it intends to add is a plan, not a false coverage claim.
//! * **A visible escape hatch.** `.nornir/citation-allow.txt` (one path per line,
//!   `#` comments) suppresses the rest — enumerable, reviewable, and burnable,
//!   the same shape as autonom's allowlist.
//!
//! Measured on the fleet before those three rules existed, ~4 of every 5 hits were
//! illustrative or cross-repo rather than defects. The rules are the difference
//! between a finding and a nuisance.
//!
//! ```no_run
//! let rep = nornir_testmatrix::audit_citations(std::path::Path::new("."), &[]);
//! assert!(rep.phantoms.is_empty(), "{}", rep.summary());
//! ```

use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
use std::process::Command;

/// The allowlist a repo may keep to suppress a citation this audit cannot resolve.
pub const ALLOW_FILE: &str = ".nornir/citation-allow.txt";

/// File stems that are universally illustrative, never a real coverage claim.
pub const PLACEHOLDER_STEMS: &[&str] =
    &["foo", "bar", "baz", "qux", "t", "x", "y", "example", "my_test", "some_test"];

/// First path segments a citation must start with to be considered repo-relative.
/// Anything else is a URL path or another project's layout — not ours to guess at.
const OURS: &[&str] = &["tests", "src", "crates", "xtask", "benches", "py", "server"];

/// Extensions a comment can cite as coverage.
const CITED_EXT: &[&str] = &["rs", "py", "js", "ts", "go", "sh"];

/// One comment that names a file which does not exist.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PhantomCitation {
    /// Repo-relative path of the file holding the comment.
    pub file: String,
    /// 1-based line of the citation.
    pub line: usize,
    /// The cited path, exactly as written.
    pub cited: String,
}

/// The audit's verdict for one repo.
#[derive(Debug, Clone, Default)]
pub struct CitationReport {
    /// Citations that resolve to nothing, here or in any sibling passed in.
    pub phantoms: Vec<PhantomCitation>,
    /// How many citations were examined (a zero here means the scan is broken,
    /// not that the repo is clean — [`CitationReport::is_trustworthy`]).
    pub checked: usize,
    /// Entries read from [`ALLOW_FILE`].
    pub allowed: usize,
}

impl CitationReport {
    /// A scan that examined nothing proves nothing.
    pub fn is_trustworthy(&self) -> bool {
        self.checked > 0
    }

    /// A one-block, paste-into-a-failure summary.
    pub fn summary(&self) -> String {
        if self.phantoms.is_empty() {
            return format!(
                "{} citation(s) checked, {} allowlisted, 0 phantom",
                self.checked, self.allowed
            );
        }
        let mut s = String::from(
            "PHANTOM GUARD CITATIONS — a comment names a test file that does not exist.\n\
             A pointer to an imaginary guard reads exactly like a real one; a reader who\n\
             sees it stops looking for coverage. Fix the path, or delete the claim.\n\n",
        );
        for p in &self.phantoms {
            s.push_str(&format!("  {}:{}  cites  {}  — NO SUCH FILE\n", p.file, p.line, p.cited));
        }
        s.push_str(&format!(
            "\n({} checked, {} allowlisted via {})",
            self.checked, self.allowed, ALLOW_FILE
        ));
        s
    }
}

fn tracked(root: &Path) -> Vec<String> {
    let Ok(out) = Command::new("git").arg("-C").arg(root).arg("ls-files").output() else {
        return Vec::new();
    };
    if !out.status.success() {
        return Vec::new();
    }
    String::from_utf8_lossy(&out.stdout).lines().map(str::to_string).collect()
}

/// Everything that is a comment in Rust source, with string literals removed so a
/// fixture NAME passed as an argument is never mistaken for a claim of coverage.
/// Newlines are preserved so line numbers survive.
fn rust_comments(src: &str) -> String {
    let b = src.as_bytes();
    let mut out = String::with_capacity(src.len());
    let (mut i, mut in_str, mut in_raw, mut esc) = (0usize, false, false, false);
    while i < b.len() {
        let c = b[i] as char;
        if in_str {
            if in_raw {
                if c == '"' {
                    in_str = false;
                    in_raw = false;
                }
            } else if esc {
                esc = false;
            } else if c == '\\' {
                esc = true;
            } else if c == '"' {
                in_str = false;
            }
            if c == '\n' {
                out.push('\n');
            }
            i += 1;
            continue;
        }
        if c == 'r' && i + 1 < b.len() && (b[i + 1] == b'"' || b[i + 1] == b'#') {
            let mut j = i + 1;
            while j < b.len() && b[j] == b'#' {
                j += 1;
            }
            if j < b.len() && b[j] == b'"' {
                in_str = true;
                in_raw = true;
                i = j + 1;
                continue;
            }
        }
        if c == '"' {
            in_str = true;
            i += 1;
            continue;
        }
        if c == '/' && i + 1 < b.len() && b[i + 1] == b'/' {
            let end = src[i..].find('\n').map(|n| i + n).unwrap_or(b.len());
            out.push_str(&src[i..end]);
            i = end;
            continue;
        }
        if c == '/' && i + 1 < b.len() && b[i + 1] == b'*' {
            let end = src[i + 2..].find("*/").map(|n| i + 2 + n + 2).unwrap_or(b.len());
            out.push_str(&src[i..end]);
            i = end;
            continue;
        }
        if c == '\n' {
            out.push('\n');
        }
        i += 1;
    }
    out
}

/// Pull `a/b/c.rs`-shaped tokens, with their 1-based line numbers, out of prose.
fn citations(text: &str) -> Vec<(usize, String)> {
    let mut found = Vec::new();
    for (idx, line) in text.lines().enumerate() {
        let mut seen = BTreeSet::new();
        for raw in line.split(|c: char| !(c.is_alphanumeric() || matches!(c, '_' | '-' | '.' | '/')))
        {
            let tok = raw.trim_matches(|c| c == '.' || c == '/');
            if !tok.contains('/') || tok.contains("..") {
                continue;
            }
            // The stem half is deliberately dropped: the placeholder rule below
            // is applied per SEGMENT, so there is nothing left for it to do.
            let Some((_, ext)) = tok.rsplit_once('.') else { continue };
            if !CITED_EXT.contains(&ext) {
                continue;
            }
            // The placeholder rule applies to EVERY SEGMENT, not only the stem.
            // It used to read the last one alone, and that let two whole classes
            // of illustration through — measured on edda 2026-08-27:
            //
            //   src/a/index.ts, src/b/index.ts   git's own rename-detection example
            //                                    paths, in a doc comment ABOUT path
            //                                    hashing (gunnar-delta/name_hash.rs)
            //   src/foo/mod.rs                   a path→module mapping illustration
            //                                    (nornir-docgen/apidoc.rs)
            //
            // In each the stem (`index`, `mod`) is perfectly ordinary and the
            // illustration lives in a DIRECTORY segment. A single-letter or
            // universally-placeholder segment anywhere in a path is the same
            // signal wherever it sits, so the test is applied per segment.
            let illustrative = |seg: &str| {
                let stem = seg.rsplit_once('.').map(|(s, _)| s).unwrap_or(seg);
                PLACEHOLDER_STEMS.contains(&stem) || stem.chars().count() <= 2
            };
            if tok.split('/').any(illustrative) {
                continue;
            }
            if !OURS.contains(&tok.split('/').next().unwrap_or("")) {
                continue;
            }
            if seen.insert(tok.to_string()) {
                found.push((idx + 1, tok.to_string()));
            }
        }
    }
    found
}

/// The crate directory a file belongs to (nearest ancestor holding a Cargo.toml).
fn crate_dir_of(root: &Path, file: &str) -> Option<String> {
    let mut cur = Path::new(file).parent()?;
    loop {
        if root.join(cur).join("Cargo.toml").is_file() {
            let s = cur.to_string_lossy().to_string();
            return Some(if s.is_empty() { s } else { format!("{s}/") });
        }
        cur = cur.parent()?;
    }
}

fn resolves(cited: &str, citing: &str, root: &Path, own: &BTreeSet<String>, sib: &BTreeSet<String>) -> bool {
    if own.contains(cited) {
        return true;
    }
    if let Some(dir) = crate_dir_of(root, citing) {
        if own.contains(&format!("{dir}{cited}")) {
            return true;
        }
    }
    // In a SIBLING checkout the citation is that repo's root-relative path, so an
    // exact hit counts as well as a suffix hit. (Missing this made every legitimate
    // cross-repo pointer look like a phantom.)
    if sib.contains(cited) {
        return true;
    }
    let suffix = format!("/{cited}");
    own.iter().any(|f| f.ends_with(&suffix)) || sib.iter().any(|f| f.ends_with(&suffix))
}

/// Audit one repo's comments for citations of files that do not exist.
///
/// `siblings` are other checkouts whose files may legitimately be cited (a comment
/// in edda naming `tests/viz_surface.rs` means nornir's). Pass `&[]` to require
/// every citation to resolve inside `repo_root` alone.
pub fn audit_citations(repo_root: &Path, siblings: &[PathBuf]) -> CitationReport {
    let own_files = tracked(repo_root);
    let own: BTreeSet<String> = own_files.iter().cloned().collect();
    let mut sib: BTreeSet<String> = BTreeSet::new();
    for s in siblings {
        sib.extend(tracked(s));
    }

    let allow: BTreeSet<String> = std::fs::read_to_string(repo_root.join(ALLOW_FILE))
        .unwrap_or_default()
        .lines()
        .map(|l| l.split('#').next().unwrap_or("").trim().to_string())
        .filter(|l| !l.is_empty())
        .collect();

    let mut rep = CitationReport { allowed: allow.len(), ..Default::default() };
    for f in &own_files {
        if f.starts_with("vendor/") || f.contains("/vendor/") {
            continue;
        }
        // The design/planning dir: a proposal naming the file it intends to add is
        // a plan, not a claim that coverage already exists.
        if f.starts_with(".nornir/") || f.contains("/.nornir/") {
            continue;
        }
        // QUARANTINE. `parked-gix*` trees are the owner's standing quarantine
        // rule: never read from, cite from, or build from them unless he points at
        // one himself. A quarantined tree therefore makes no claims about this
        // repo, and auditing its claims is auditing something that was set aside
        // precisely so nobody would rely on it. Measured 2026-08-27: 4 of the 19
        // phantoms this audit reported on edda came from
        // `crates/storage-git-gix/parked-gix{,2}/`, which is 4 rows of noise
        // in a report whose whole value is that every row is actionable.
        if f.split('/').any(|seg| seg.starts_with("parked-gix")) {
            continue;
        }
        let is_rs = f.ends_with(".rs");
        let is_prose = f.ends_with(".md") || f.ends_with(".proto");
        if !is_rs && !is_prose {
            continue;
        }
        let Ok(src) = std::fs::read_to_string(repo_root.join(f)) else { continue };
        let text = if is_rs { rust_comments(&src) } else { src };
        for (line, cited) in citations(&text) {
            if allow.contains(&cited) {
                continue;
            }
            rep.checked += 1;
            if !resolves(&cited, f, repo_root, &own, &sib) {
                rep.phantoms.push(PhantomCitation { file: f.clone(), line, cited });
            }
        }
    }
    rep
}

/// The repository's **main** working tree, which for a linked `git worktree` is
/// somewhere else entirely.
///
/// `--git-common-dir` is the one that points at the shared `.git` of the main
/// checkout; plain `--git-dir` would answer `<main>/.git/worktrees/<name>` and
/// lead back to the worktree. A bare repo has no working tree and gets `None`.
fn main_worktree_of(repo_root: &Path) -> Option<PathBuf> {
    let out = Command::new("git")
        .arg("-C")
        .arg(repo_root)
        .args(["rev-parse", "--path-format=absolute", "--git-common-dir"])
        .output()
        .ok()?;
    if !out.status.success() {
        return None;
    }
    let common = PathBuf::from(String::from_utf8_lossy(&out.stdout).trim());
    (common.file_name()? == ".git").then(|| common.parent())?.map(Path::to_path_buf)
}

/// Sibling checkouts of `repo_root` — every directory beside the repository's
/// **main working tree** that is itself a git repo. The nordisk layout is one
/// flat parent dir of sibling repos.
///
/// # Why the main working tree and not `repo_root`'s own parent
///
/// MEASURED on oden 2026-09-12. This read `repo_root.parent()`, so the audit's
/// verdict was a property of **where the checkout sits on disk** rather than of
/// the repository. The same commit of edda gave three different answers:
///
/// | root | siblings found | phantoms |
/// |---|---|---|
/// | `~/git/edda` | 73 | 0 |
/// | `~/scratch/wt-e-gc` (a `git worktree` of it) | 32 | 1 |
/// | a CI clone with nothing beside it | 0 | 44 |
///
/// A citation in `crates/jera/src/jobs.rs` naming dwarves' `src/brokkr/engine.rs`
/// is a legitimate cross-repo pointer; dwarves is beside `~/git/edda` and is not
/// beside a worktree in `~/scratch`, so the guard went red on the worktree and
/// green on main for source that is byte-identical. A guard that flips on
/// `git worktree add` teaches people to ignore it.
///
/// A linked worktree IS the repository, so it gets the repository's neighbours.
/// This changes no verdict for a normal checkout — `--git-common-dir` there is
/// its own `.git` — and it cannot widen a CI clone, which still has none.
pub fn sibling_checkouts(repo_root: &Path) -> Vec<PathBuf> {
    let base = main_worktree_of(repo_root).unwrap_or_else(|| repo_root.to_path_buf());
    let Some(parent) = base.parent() else { return Vec::new() };
    let Ok(rd) = std::fs::read_dir(parent) else { return Vec::new() };
    // Exclude BOTH the root we were handed and the main checkout it belongs to:
    // a worktree's own repo is not a sibling of itself, and letting it in would
    // resolve every citation against the very files being audited.
    let me = repo_root.canonicalize().ok();
    let main = base.canonicalize().ok();
    rd.filter_map(|e| e.ok())
        .map(|e| e.path())
        .filter(|p| {
            let c = p.canonicalize().ok();
            p.is_dir() && p.join(".git").exists() && c != me && c != main
        })
        .collect()
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Run `git` in `dir` with an identity supplied on the command line — a
    /// container or build agent has no `~/.gitconfig`, and `git commit` there
    /// fails with "Please tell me who you are" rather than skipping.
    fn git(dir: &Path, args: &[&str]) {
        let out = Command::new("git")
            .arg("-C")
            .arg(dir)
            .args(["-c", "user.name=t", "-c", "user.email=t@t", "-c", "commit.gpgsign=false"])
            .args(args)
            .output()
            .expect("spawn git");
        assert!(
            out.status.success(),
            "git {args:?} in {} failed: {}",
            dir.display(),
            String::from_utf8_lossy(&out.stderr)
        );
    }

    fn seed_repo(dir: &Path, files: &[(&str, &str)]) {
        std::fs::create_dir_all(dir).expect("mkdir");
        git(dir, &["init", "-q", "-b", "main"]);
        for (rel, body) in files {
            let p = dir.join(rel);
            std::fs::create_dir_all(p.parent().expect("parent")).expect("mkdir");
            std::fs::write(&p, body).expect("write");
        }
        git(dir, &["add", "-A"]);
        git(dir, &["commit", "-q", "-m", "seed"]);
    }

    /// THE RED PROOF for [`sibling_checkouts`]: a linked `git worktree` must get
    /// the SAME verdict as the checkout it belongs to, however far away it sits.
    ///
    /// The fixture is the exact shape that was flipping on oden: a repo whose
    /// comment cites a file living in a sibling repo, and a worktree of that
    /// repo created in a directory with no siblings at all. Before the fix the
    /// worktree reported the citation as a phantom and the main checkout
    /// reported nothing — same commit, same bytes, two answers.
    #[test]
    fn a_linked_worktree_sees_the_repositorys_siblings_not_its_own_neighbours() {
        let td = tempfile::tempdir().expect("tempdir");
        let fleet = td.path().join("fleet");
        let elsewhere = td.path().join("elsewhere");
        std::fs::create_dir_all(&elsewhere).expect("mkdir elsewhere");

        // The neighbour that owns the cited file.
        seed_repo(&fleet.join("neighbour"), &[("tests/cross_repo_proof.rs", "// nothing\n")]);
        // The repo under audit, citing it.
        let main = fleet.join("under-audit");
        seed_repo(
            &main,
            &[("src/lib.rs", "//! covered by tests/cross_repo_proof.rs next door\n")],
        );

        // A worktree of the SAME repo, parked where it has no neighbours.
        let wt = elsewhere.join("lane");
        git(&main, &["worktree", "add", "-q", "-b", "lane", wt.to_str().expect("utf-8")]);

        let from_main = audit_citations(&main, &sibling_checkouts(&main));
        let from_worktree = audit_citations(&wt, &sibling_checkouts(&wt));

        assert!(
            from_main.is_trustworthy() && from_worktree.is_trustworthy(),
            "both scans must examine something: main {} / worktree {}",
            from_main.checked,
            from_worktree.checked
        );
        assert!(
            from_main.phantoms.is_empty(),
            "the citation resolves in the neighbour, so the main checkout must be clean: {}",
            from_main.summary()
        );
        assert_eq!(
            from_worktree.phantoms, from_main.phantoms,
            "a `git worktree` of the same commit reported a different verdict: {}\n\
             The audit must be a property of the repository, not of the directory it was \
             checked out beside.",
            from_worktree.summary()
        );
    }

    /// NON-VACUITY PROBE for the test above: with the neighbour genuinely gone,
    /// the citation IS a phantom from both roots. Without this, the equality
    /// assertion would pass just as happily against a `sibling_checkouts` that
    /// returned everything, or an audit that reported nothing.
    #[test]
    fn the_cross_repo_citation_is_a_phantom_when_the_neighbour_does_not_exist() {
        let td = tempfile::tempdir().expect("tempdir");
        let main = td.path().join("fleet").join("under-audit");
        seed_repo(
            &main,
            &[("src/lib.rs", "//! covered by tests/cross_repo_proof.rs next door\n")],
        );

        let rep = audit_citations(&main, &sibling_checkouts(&main));
        assert_eq!(
            rep.phantoms.len(),
            1,
            "with no neighbour the citation has no referent anywhere: {}",
            rep.summary()
        );
        assert_eq!(rep.phantoms[0].cited, "tests/cross_repo_proof.rs");
    }

    /// A worktree's own repository is not one of its siblings.
    ///
    /// It sits right beside the neighbours, so the widened search would sweep it
    /// in — and then every citation would "resolve" against the very files being
    /// audited, which is the blindest possible green.
    #[test]
    fn the_main_checkout_is_not_its_own_worktrees_sibling() {
        let td = tempfile::tempdir().expect("tempdir");
        let fleet = td.path().join("fleet");
        let elsewhere = td.path().join("elsewhere");
        std::fs::create_dir_all(&elsewhere).expect("mkdir elsewhere");

        seed_repo(&fleet.join("neighbour"), &[("tests/cross_repo_proof.rs", "// nothing\n")]);
        let main = fleet.join("under-audit");
        seed_repo(&main, &[("src/lib.rs", "//! nothing cited here\n")]);
        let wt = elsewhere.join("lane");
        git(&main, &["worktree", "add", "-q", "-b", "lane", wt.to_str().expect("utf-8")]);

        let sibs = sibling_checkouts(&wt);
        let canon: Vec<PathBuf> = sibs.iter().filter_map(|p| p.canonicalize().ok()).collect();
        assert!(
            canon.contains(&fleet.join("neighbour").canonicalize().expect("canon")),
            "the neighbour must be found: {sibs:?}"
        );
        assert!(
            !canon.contains(&main.canonicalize().expect("canon")),
            "the worktree's OWN repository was returned as a sibling: {sibs:?}"
        );
    }

    #[test]
    fn string_literals_are_not_citations() {
        let src = "let f = classify(src, \"tests/dark.rs\");\n// see tests/real.rs\n";
        let c = rust_comments(src);
        assert!(!c.contains("tests/dark.rs"), "a fixture name in a literal is not a claim");
        assert!(c.contains("tests/real.rs"));
    }

    #[test]
    fn line_numbers_survive_literal_stripping() {
        let src = "let a = \"tests/x.rs\";\n\n// covered by tests/three.rs\n";
        let hits = citations(&rust_comments(src));
        assert_eq!(hits, vec![(3, "tests/three.rs".to_string())]);
    }

    #[test]
    fn placeholders_are_not_citations() {
        let hits = citations("// `<c>/tests/foo.rs` -> `<c>::tests::foo`; also tests/t.rs\n");
        assert!(hits.is_empty(), "illustrative stems must not be reported: {hits:?}");
    }

    #[test]
    fn another_projects_layout_is_not_ours_to_guess() {
        let hits = citations("// mirrors facett-demo/tests/robot_demo.rs\n");
        assert!(hits.is_empty(), "cross-project paths are skipped, not guessed: {hits:?}");
    }

    #[test]
    fn a_real_citation_is_found_with_its_line() {
        let hits = citations("//! header\n//! see tests/support/mcp_harness.rs for the template\n");
        assert_eq!(hits, vec![(2, "tests/support/mcp_harness.rs".to_string())]);
    }

    #[test]
    fn an_empty_scan_is_not_trustworthy() {
        let rep = CitationReport::default();
        assert!(!rep.is_trustworthy(), "zero checked means broken, not clean");
    }
}