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

nordisk/holger

traits/tests/manifest_metadata_guard.rs

//! **holger's crate-discovery guard** — the `description` of a publishable holger crate
//! must say what THAT crate does.
//!
//! ## Why this file exists
//!
//! On 2026-08-01 a recount found **17 of holger's crates sharing one string**:
//!
//! ```text
//! description = "Holger guards your artifacts at rest. May Allfather Odin watch over every bit."
//! ```
//!
//! …including every single `znippy-<ecosystem>` backend. It is a nice line, and as
//! crate-discovery metadata it carries **zero bits**: the whole surface a person searching
//! crates.io (or `cargo search`, or a `cargo metadata` dump, or the crates.io sidebar) sees
//! could not tell them which of the seventeen serves PyPI, which serves APT, or that
//! `holger-rust-file-repository` is the *writable* Cargo one. holger's own `CLAUDE.md`
//! warns that "THE CRATE NAME IS OFTEN NOT THE NAME YOU SEARCHED FOR" — which makes the
//! description the only place left to say it, and it said nothing.
//!
//! That cost real time twice (SK330 / SK332): ~2 h hunting for holger's PEP 503
//! implementation, which very nearly ended in a duplicate of it being written.
//!
//! ## What this guard asserts
//!
//! For every **publishable** crate in the workspace (`publish = false` crates are internal
//! and exempt):
//!
//! 1. it HAS a `description`;
//! 2. that description is not the retired boilerplate;
//! 3. no two crates share a description — a shared string is by definition not describing
//!    either crate; and
//! 4. it is long enough to be a sentence about a specific thing.
//!
//! ## What this guard does NOT prove
//!
//! That a description is TRUE, or that it names the right ecosystem. Prose cannot be
//! checked by string length. The ecosystem-naming half is asserted separately against
//! `ArtifactFormat::home()` — the format→crate map — because that has a machine-readable
//! source of truth and prose does not.
//!
//! ## Seeing it red
//!
//! Put the boilerplate line back in any one manifest and this fails, naming that manifest
//! and quoting the string.

use std::path::{Path, PathBuf};

/// The exact string 17 crates shared. Kept here so it can never quietly return.
const RETIRED_BOILERPLATE: &str =
    "Holger guards your artifacts at rest. May Allfather Odin watch over every bit.";

/// A description shorter than this cannot distinguish one backend from sixteen siblings.
const MIN_DESCRIPTION_CHARS: usize = 40;

fn repo_root() -> PathBuf {
    // traits → <repo root>
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .ancestors()
        .nth(1)
        .unwrap()
        .to_path_buf()
}

/// Every `Cargo.toml` in the workspace tree, `target/` pruned.
fn manifests(root: &Path) -> Vec<PathBuf> {
    let mut out = Vec::new();
    let mut stack = vec![root.to_path_buf()];
    while let Some(dir) = stack.pop() {
        let Ok(rd) = std::fs::read_dir(&dir) else {
            continue;
        };
        for e in rd.flatten() {
            let p = e.path();
            let name = e.file_name().to_string_lossy().to_string();
            if p.is_dir() {
                if name != "target" && !name.starts_with('.') {
                    stack.push(p);
                }
            } else if name == "Cargo.toml" {
                out.push(p);
            }
        }
    }
    out.sort();
    out
}

/// The value of a top-level `key = "…"` in the `[package]` table.
///
/// A hand-rolled scan rather than a `toml` dep: xtask has no toml crate and this needs to
/// read `[package]` only. It stops at the next table header so a `description` under some
/// other table can never be mistaken for the package's.
fn package_str(text: &str, key: &str) -> Option<String> {
    let mut in_package = false;
    for line in text.lines() {
        let t = line.trim();
        if t.starts_with('[') {
            in_package = t == "[package]";
            continue;
        }
        if !in_package {
            continue;
        }
        if let Some(rest) = t.strip_prefix(key) {
            let rest = rest.trim_start();
            if let Some(v) = rest.strip_prefix('=') {
                return Some(v.trim().trim_matches('"').to_string());
            }
        }
    }
    None
}

/// Whether the manifest declares `publish = false` (internal crate, exempt).
fn is_unpublished(text: &str) -> bool {
    package_str(text, "publish").as_deref() == Some("false")
}

#[test]
fn every_publishable_crate_describes_itself() {
    let root = repo_root();
    let all = manifests(&root);
    // Never let a broken walk pass for a clean result: an empty list would make every
    // assertion below trivially true.
    assert!(
        all.len() > 20,
        "the guard found only {} Cargo.toml files under {} — it is reading the wrong tree",
        all.len(),
        root.display()
    );

    let mut problems: Vec<String> = Vec::new();
    // description → the manifests carrying it, so a duplicate names BOTH offenders.
    let mut by_desc: std::collections::BTreeMap<String, Vec<String>> = Default::default();
    let mut checked = 0usize;

    for m in &all {
        let Ok(text) = std::fs::read_to_string(m) else {
            continue;
        };
        // A virtual manifest (the workspace root) has no `[package]`.
        let Some(name) = package_str(&text, "name") else {
            continue;
        };
        if is_unpublished(&text) {
            continue;
        }
        checked += 1;
        let rel = m.strip_prefix(&root).unwrap_or(m).display().to_string();

        let Some(desc) = package_str(&text, "description") else {
            problems.push(format!(
                "{rel} ({name}) declares NO description — the crate-discovery surface says \
                 nothing about it"
            ));
            continue;
        };
        if desc == RETIRED_BOILERPLATE {
            problems.push(format!(
                "{rel} ({name}) carries the RETIRED boilerplate description {desc:?} — 17 \
                 crates shared it and it identified none of them. Say what THIS crate serves."
            ));
            continue;
        }
        if desc.chars().count() < MIN_DESCRIPTION_CHARS {
            problems.push(format!(
                "{rel} ({name}) description is {} chars, under the {MIN_DESCRIPTION_CHARS} \
                 floor: {desc:?}",
                desc.chars().count()
            ));
        }
        by_desc
            .entry(desc)
            .or_default()
            .push(format!("{name} ({rel})"));
    }

    assert!(
        checked > 15,
        "the guard only inspected {checked} publishable crates — holger has more than that, \
         so the `[package]`/publish parse must have broken"
    );

    for (desc, crates) in &by_desc {
        if crates.len() > 1 {
            problems.push(format!(
                "{} crates SHARE one description — a shared string describes none of them:\n      \
                 {desc:?}\n      · {}",
                crates.len(),
                crates.join("\n      · ")
            ));
        }
    }

    assert!(
        problems.is_empty(),
        "{} crate-description problem(s) across {checked} publishable crates:\n  · {}",
        problems.len(),
        problems.join("\n  · ")
    );
}

// ─────────────────────────────────────────────────────────────────────────────────
// SK332 / D1 — the capability a search must be able to FIND
// ─────────────────────────────────────────────────────────────────────────────────

/// Aliases that exist only to catch a MISSPELLING, not to name the capability. They are
/// deliberately not required as keywords: `snippy` is a typo-catcher for `znippy`, and
/// spending one of crates.io's five keyword slots on a typo helps nobody.
const TYPO_ALIASES: &[&str] = &["snippy"];

/// Aliases that cannot legally be a crates.io keyword (keywords are ASCII
/// alphanumeric + `_ - +` and must start alphanumeric — `crates.io` has a dot).
/// Recorded here rather than silently skipped, so the exemption is a decision on
/// the record.
const UNKEYWORDABLE_ALIASES: &[&str] = &["crates.io"];

/// The `keywords = [...]` array of a manifest, lowercased.
fn package_keywords(text: &str) -> Vec<String> {
    let mut in_package = false;
    for line in text.lines() {
        let t = line.trim();
        if t.starts_with('[') {
            in_package = t == "[package]";
            continue;
        }
        if !in_package {
            continue;
        }
        if let Some(rest) = t.strip_prefix("keywords") {
            if let Some(v) = rest.trim_start().strip_prefix('=') {
                return v
                    .trim()
                    .trim_start_matches('[')
                    .trim_end_matches(']')
                    .split(',')
                    .map(|s| s.trim().trim_matches('"').to_lowercase())
                    .filter(|s| !s.is_empty())
                    .collect();
            }
        }
    }
    Vec::new()
}

/// **The SK332 guard** — every ecosystem holger serves is findable by the names people
/// actually use.
///
/// ## The defect this closes
///
/// holger's PyPI capability answers to a stack of unrelated names, and none of them
/// matched what was on the crate:
///
/// | the name | where it is used |
/// |---|---|
/// | `PyPI` | the docs, the UI, and what a human calls it |
/// | `pip` | the `ron_repo_type` an operator writes in RON — the CONFIG key |
/// | `ArtifactFormat::Pip` / `PipRepoZnippy` | the code |
/// | `znippy-python` / `holger-znippy-python-repository` | the directory and the package |
///
/// Four names, one capability, and (measured 2026-08-01) **zero** `pypi` or `pep503`
/// keywords anywhere in the workspace — all 17 publishable crates carried the same
/// `["znippy", "artifacts", "blake3", "cli", "airgap"]`. So a search for the ecosystem
/// found nothing, which cost ~2 h and nearly produced a SECOND PEP 503 implementation
/// alongside the one that already exists.
///
/// ## What it asserts
///
/// Read off `ArtifactFormat::home()` — the format→crate map — so there is ONE list of
/// formats and this checks against it rather than keeping a copy:
///
/// 1. the `config_key` (the string an operator types) IS a keyword on that format's
///    crate; and
/// 2. **every** real ALIAS is too.
///
/// Rule 2 is deliberately EVERY alias, not "at least one". The first draft of this guard
/// asked for at least one, and it was HOLLOW: dropping `"pypi"` from znippy-python still
/// passed, because the sibling alias `"python"` satisfied the check — so the guard was
/// blind to the exact defect it was written for. Requiring every alias is also feasible
/// rather than aspirational: the widest format (`maven3`, with `maven`/`maven2`/`java`)
/// needs 4 of crates.io's 5 keyword slots, so no format is forced to choose.
///
/// Both the primary crate and a format's `also` peer (the file-backed twin) are checked.
///
/// ## Seeing it red
///
/// Drop `"pypi"` from `server/repository/znippy-python/Cargo.toml` and this fails naming
/// that crate, the format, and the aliases it no longer answers to.
#[test]
fn every_format_is_findable_by_the_names_it_answers_to() {
    let root = repo_root();
    let mut problems: Vec<String> = Vec::new();
    let mut checked = 0usize;

    for format in holger_traits::ALL_ARTIFACT_FORMATS {
        let home = format.home();
        // `Raw` has no repository crate of its own (the backend is server/lib/src/raw.rs).
        if home.crate_dir.is_empty() {
            continue;
        }
        let mut targets = vec![(home.crate_dir, home.package)];
        if let Some(also) = home.also {
            targets.push(also);
        }
        for (dir, package) in targets {
            let rel = format!("server/repository/{dir}/Cargo.toml");
            let path = root.join(&rel);
            let Ok(text) = std::fs::read_to_string(&path) else {
                problems.push(format!(
                    "{:?}'s home names {rel}, which does not exist",
                    home.format
                ));
                continue;
            };
            checked += 1;
            let kws = package_keywords(&text);
            if kws.is_empty() {
                problems.push(format!("{rel} ({package}) declares NO keywords"));
                continue;
            }
            if !kws.iter().any(|k| k == home.config_key) {
                problems.push(format!(
                    "{rel} ({package}) has no {:?} keyword — that is the ron_repo_type an \
                     operator WRITES, so it is the first thing they search. Got {kws:?}",
                    home.config_key
                ));
            }
            let real_aliases: Vec<&str> = home
                .aliases
                .iter()
                .copied()
                .filter(|a| !TYPO_ALIASES.contains(a) && !UNKEYWORDABLE_ALIASES.contains(a))
                .collect();
            let absent: Vec<&str> = real_aliases
                .iter()
                .copied()
                .filter(|a| !kws.iter().any(|k| k == a))
                .collect();
            if !absent.is_empty() {
                problems.push(format!(
                    "{rel} ({package}) is missing {:?}'s alias(es) {absent:?} as keyword(s) — \
                     each is a name someone searches for, and the config key {:?} alone does \
                     not answer them (this is the PyPI-vs-pip trap). Got {kws:?}",
                    home.format, home.config_key
                ));
            }
        }
    }

    // A broken enumeration must not read as a clean result.
    assert!(
        checked >= 15,
        "the guard only inspected {checked} repository crates — ALL_ARTIFACT_FORMATS or the \
         home() map must have changed shape"
    );
    assert!(
        problems.is_empty(),
        "{} format(s) not findable by the names they answer to (checked {checked} crates):\n  · {}",
        problems.len(),
        problems.join("\n  · ")
    );
}

/// The Rosetta doc SK332 asks for must EXIST and must name every format. A mapping table
/// nobody maintains is worse than none, so the guard reads it: every `config_key` and every
/// real alias has to appear in it, and so does every crate it points at.
#[test]
fn the_capability_name_map_doc_covers_every_format() {
    let root = repo_root();
    let path = root.join(".nornir/capability-name-map.md");
    let doc = std::fs::read_to_string(&path).unwrap_or_else(|e| {
        panic!(
            "{} is missing ({e}) — the four-name trap needs a written Rosetta stone, not \
             just keywords",
            path.display()
        )
    });
    let doc = doc.to_lowercase();

    let mut missing: Vec<String> = Vec::new();
    for format in holger_traits::ALL_ARTIFACT_FORMATS {
        let home = format.home();
        for name in home.all_names() {
            if !doc.contains(&name.to_lowercase()) {
                missing.push(format!("name {name:?} ({:?})", home.format));
            }
        }
        if !home.package.is_empty() && !doc.contains(&home.package.to_lowercase()) {
            missing.push(format!("package {:?} ({:?})", home.package, home.format));
        }
        if let Some((_, pkg)) = home.also {
            if !doc.contains(&pkg.to_lowercase()) {
                missing.push(format!("also-package {pkg:?} ({:?})", home.format));
            }
        }
    }
    assert!(
        missing.is_empty(),
        "the capability name map is missing {} entr(ies) — every name a capability answers \
         to must be in it, or the map does not do its one job:\n  · {}",
        missing.len(),
        missing.join("\n  · ")
    );
}