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

nordisk/holger

server/lib/tests/open_build_speaks_no_money.rs

//! **The open build speaks no money** (A28 M13: Gunnar's guard, ported).
//!
//! holger's half of the two-product split: the community server reports usage, it
//! receives a signed entitlement only in the `metered` build, and it takes no money
//! ever. Every payment word belongs to the private `monetize` half, which is a
//! separate binary talking to this one over a signed seam.
//!
//! The owner's ruling of 2026-09-15 (quoted in Gunnar's
//! `crates/gunnar-server/tests/open_build_speaks_no_money.rs`): the open build shall not
//! mention money anywhere a user or operator can see it, stays unlimited, but SHOULD show
//! how much the box holds.
//!
//! Before 2026-10-25 this file scanned five sources with a twelve-word list, line by line;
//! `xtask/src/paid_guard.rs` checks crate NAMES only. It is now Gunnar's guard:
//!
//! 1. [`the_open_sources_say_no_money`] — every **string literal an open build compiles** in
//!    every crate of this workspace the default `holger` binary links ([`SCANNED_CRATES`],
//!    `cargo tree -p holger -e normal`): refusals, log lines, served words, errcode texts.
//!    Comments are not scanned, nor is code the open build does not contain: items and
//!    modules under the paid features ([`PAID_FEATURES`]) and `#[cfg(test)]`/`#[test]` items.
//!    Gunnar's lexer, scanner and judge, verbatim (the judge is `money/judge.rs`, shared with
//!    the command line's half, `server/cli/tests/open_cli_speaks_no_money.rs`).
//! 2. [`the_scanner_skips_what_the_open_build_does_not_contain`] — the scanner's own proof.
//! 3. Holger's own: `entitlement` is a record kind ([`RECORD_KIND_WORDS`]), and counting is
//!    not money ([`the_open_build_still_says_how_much_it_holds`]).
// The scanner's items serve `the_open_sources_say_no_money`, which a metered build does not run.
#![cfg_attr(feature = "metered", allow(dead_code))]

#[path = "money/judge.rs"]
mod judge;

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

use judge::leaks_in;

/// The features an OPEN build does not carry: the paid half's. An item under one of them is
/// not in the open binary, so its words are not scanned.
const PAID_FEATURES: &[&str] = &["metered", "meter-guests", "admit-share"];

/// Every crate of this workspace the default `holger` binary links (`cargo tree -p holger
/// -e normal`, 2026-10-25), as directories under the workspace root.
const SCANNED_CRATES: &[&str] = &[
    "server/lib",
    "server/cli",
    "traits",
    "errcode",
    "server/inspect",
    "server/sandbox",
    "server/repository/file-rust",
    "server/repository/znippy-rust",
    "server/repository/zip-entry",
    "intel",
    "provenance",
    "update-bundle",
    "plugin/host",
    "plugin/abi",
    "plugin/handler-bundle-core",
    "plugin/handler-rust-toolchain",
    "plugin/handler-skidbladnir",
];

/// **Files only a paid item pulls in** (`include!` under `#[cfg(feature = "metered")]`).
/// Not scanned; [`the_open_sources_say_no_money`] proves each include sits in a skipped item.
const PAID_INCLUDES: &[(&str, &str)] =
    &[("server/lib/src/grpc.rs", "generated/holger.metered.v1.rs")];

// ── Gunnar's lexer and scanner, verbatim ─────────────────────────────────────

/// One string literal, where it is, and whether it sits in an attribute.
#[derive(Debug)]
struct Literal {
    line: usize,
    text: String,
}

/// What one file yields: its literals outside skipped items, and the `mod`
/// names declared under a skipping attribute (their files are skipped whole).
#[derive(Default)]
struct Scanned {
    literals: Vec<Literal>,
    skipped_mods: Vec<String>,
}

#[derive(Debug, Clone, PartialEq)]
enum Tok {
    Str(String),
    Ident(String),
    Punct(char),
}

/// A small Rust lexer: comments dropped, string/char/raw/byte literals as
/// single tokens, lifetimes told apart from char literals. Enough to find
/// every literal and every attribute; not a parser.
fn lex(src: &str) -> Vec<(usize, Tok)> {
    let b: Vec<char> = src.chars().collect();
    let mut out = Vec::new();
    let (mut i, mut line) = (0usize, 1usize);
    while i < b.len() {
        let c = b[i];
        if c == '\n' {
            line += 1;
            i += 1;
            continue;
        }
        if c.is_whitespace() {
            i += 1;
            continue;
        }
        // comments
        if c == '/' && b.get(i + 1) == Some(&'/') {
            while i < b.len() && b[i] != '\n' {
                i += 1;
            }
            continue;
        }
        if c == '/' && b.get(i + 1) == Some(&'*') {
            let mut depth = 0;
            while i < b.len() {
                if b[i] == '/' && b.get(i + 1) == Some(&'*') {
                    depth += 1;
                    i += 2;
                } else if b[i] == '*' && b.get(i + 1) == Some(&'/') {
                    depth -= 1;
                    i += 2;
                    if depth == 0 {
                        break;
                    }
                } else {
                    if b[i] == '\n' {
                        line += 1;
                    }
                    i += 1;
                }
            }
            continue;
        }
        // raw strings: r"..", r#".."#, br#".."#
        let raw_start = if c == 'r' && matches!(b.get(i + 1), Some('"') | Some('#')) {
            Some(i + 1)
        } else if c == 'b'
            && b.get(i + 1) == Some(&'r')
            && matches!(b.get(i + 2), Some('"') | Some('#'))
        {
            Some(i + 2)
        } else {
            None
        };
        if let Some(mut j) = raw_start {
            let mut hashes = 0;
            while b.get(j) == Some(&'#') {
                hashes += 1;
                j += 1;
            }
            if b.get(j) == Some(&'"') {
                let start_line = line;
                j += 1;
                let mut text = String::new();
                'raw: while j < b.len() {
                    if b[j] == '"' && (0..hashes).all(|k| b.get(j + 1 + k) == Some(&'#')) {
                        j += 1 + hashes;
                        break 'raw;
                    }
                    if b[j] == '\n' {
                        line += 1;
                    }
                    text.push(b[j]);
                    j += 1;
                }
                out.push((start_line, Tok::Str(text)));
                i = j;
                continue;
            }
        }
        // strings, byte strings
        if c == '"' || (c == 'b' && b.get(i + 1) == Some(&'"')) {
            let start_line = line;
            let mut j = if c == 'b' { i + 2 } else { i + 1 };
            let mut text = String::new();
            while j < b.len() {
                match b[j] {
                    '\\' => {
                        // `\` + newline is a continuation: the indentation
                        // that follows is not part of the text.
                        if b.get(j + 1) == Some(&'\n') {
                            line += 1;
                            j += 2;
                            while j < b.len() && b[j].is_whitespace() {
                                if b[j] == '\n' {
                                    line += 1;
                                }
                                j += 1;
                            }
                            text.push(' ');
                            continue;
                        }
                        if let Some(n) = b.get(j + 1) {
                            text.push(match n {
                                'n' => '\n',
                                't' => ' ',
                                other => *other,
                            });
                        }
                        j += 2;
                    }
                    '"' => {
                        j += 1;
                        break;
                    }
                    ch => {
                        if ch == '\n' {
                            line += 1;
                        }
                        text.push(ch);
                        j += 1;
                    }
                }
            }
            out.push((start_line, Tok::Str(text)));
            i = j;
            continue;
        }
        // char literal or lifetime
        if c == '\'' {
            if b.get(i + 1) == Some(&'\\') {
                let mut j = i + 2;
                while j < b.len() && b[j] != '\'' {
                    j += 1;
                }
                i = j + 1;
                continue;
            }
            if b.get(i + 2) == Some(&'\'') {
                i += 3;
                continue;
            }
            // a lifetime: skip the tick, the ident follows
            i += 1;
            continue;
        }
        if c.is_alphanumeric() || c == '_' {
            let mut j = i;
            let mut ident = String::new();
            while j < b.len() && (b[j].is_alphanumeric() || b[j] == '_') {
                ident.push(b[j]);
                j += 1;
            }
            out.push((line, Tok::Ident(ident)));
            i = j;
            continue;
        }
        out.push((line, Tok::Punct(c)));
        i += 1;
    }
    out
}

/// Does this attribute's token text remove the item from an OPEN, non-test
/// build? `cfg(test)`, `cfg(all(test, …))`, `test`, `tokio::test`,
/// `cfg(feature = "metered")` — and never anything under `not(…)`.
fn removes_from_open_build(attr: &[Tok]) -> bool {
    let text: String = attr
        .iter()
        .map(|t| match t {
            Tok::Str(s) => format!("\"{s}\""),
            Tok::Ident(s) => format!("{s} "),
            Tok::Punct(c) => c.to_string(),
        })
        .collect();
    let t = text.replace(' ', "");
    if t == "test" || t == "tokio::test" || t.starts_with("tokio::test(") {
        return true;
    }
    if !t.starts_with("cfg(") || t.contains("not(") {
        return false;
    }
    t == "cfg(test)"
        || t.starts_with("cfg(all(test")
        || PAID_FEATURES
            .iter()
            .any(|f| t.contains(&format!("feature=\"{f}\"")))
        || (t.starts_with("cfg(all(") && t.contains("test,"))
}

fn scan_source(src: &str) -> Scanned {
    let toks = lex(src);
    let mut out = Scanned::default();
    let mut i = 0usize;
    // Inner attribute `#![cfg(...)]` at the top that removes the whole file.
    while i < toks.len() {
        match &toks[i].1 {
            Tok::Punct('#') => {
                let inner = matches!(toks.get(i + 1), Some((_, Tok::Punct('!'))));
                let open = if inner { i + 2 } else { i + 1 };
                if !matches!(toks.get(open), Some((_, Tok::Punct('[')))) {
                    i += 1;
                    continue;
                }
                // the attribute's tokens
                let mut depth = 0i32;
                let mut j = open;
                let start = open + 1;
                loop {
                    match toks.get(j).map(|t| &t.1) {
                        Some(Tok::Punct('[')) => depth += 1,
                        Some(Tok::Punct(']')) => {
                            depth -= 1;
                            if depth == 0 {
                                break;
                            }
                        }
                        None => break,
                        _ => {}
                    }
                    j += 1;
                }
                let attr: Vec<Tok> = toks[start..j.min(toks.len())]
                    .iter()
                    .map(|t| t.1.clone())
                    .collect();
                // `doc` is a comment by another spelling; `cfg`/`cfg_attr`
                // name features, which no user or operator reads.
                let is_doc = matches!(attr.first(), Some(Tok::Ident(s)) if s == "doc" || s == "cfg" || s == "cfg_attr");
                if removes_from_open_build(&attr) {
                    if inner {
                        return Scanned::default();
                    }
                    i = skip_item(&toks, j + 1, &mut out.skipped_mods);
                    continue;
                }
                if !is_doc {
                    for (line, t) in &toks[start..j.min(toks.len())] {
                        if let Tok::Str(s) = t {
                            out.literals.push(Literal {
                                line: *line,
                                text: s.clone(),
                            });
                        }
                    }
                }
                i = j + 1;
            }
            Tok::Str(s) => {
                out.literals.push(Literal {
                    line: toks[i].0,
                    text: s.clone(),
                });
                i += 1;
            }
            _ => i += 1,
        }
    }
    out
}

/// Skip the item that starts at `i` (after its attribute): further attributes,
/// then tokens up to a `;` or `,` at depth 0, or through the first balanced
/// `{…}`. Returns the index after it.
fn skip_item(toks: &[(usize, Tok)], mut i: usize, mods: &mut Vec<String>) -> usize {
    // stacked attributes
    while matches!(toks.get(i), Some((_, Tok::Punct('#'))))
        && matches!(toks.get(i + 1), Some((_, Tok::Punct('['))))
    {
        let mut depth = 0;
        let mut j = i + 1;
        while j < toks.len() {
            match toks[j].1 {
                Tok::Punct('[') => depth += 1,
                Tok::Punct(']') => {
                    depth -= 1;
                    if depth == 0 {
                        break;
                    }
                }
                _ => {}
            }
            j += 1;
        }
        i = j + 1;
    }
    let mut depth = 0i32;
    // `<…>` at depth 0 — a signature's `Result<A, B>`, a field's `HashMap<K, V>` — so the
    // comma inside generics does not end the item (the item went on, unskipped, into its
    // body). `->` and `=>` are arrows, not a closing bracket.
    let mut angle = 0i32;
    let mut prev_mod = false;
    while i < toks.len() {
        let arrow = matches!(
            toks.get(i.wrapping_sub(1)).map(|t| &t.1),
            Some(Tok::Punct('-')) | Some(Tok::Punct('='))
        );
        match &toks[i].1 {
            Tok::Punct('<') if depth == 0 => angle += 1,
            Tok::Punct('>') if depth == 0 && !arrow && angle > 0 => angle -= 1,
            Tok::Ident(s) if s == "mod" => prev_mod = true,
            Tok::Ident(s) if prev_mod => {
                mods.push(s.clone());
                prev_mod = false;
            }
            Tok::Punct('(') | Tok::Punct('[') => depth += 1,
            Tok::Punct(')') | Tok::Punct(']') => depth -= 1,
            Tok::Punct('{') => {
                depth += 1;
            }
            Tok::Punct('}') => {
                depth -= 1;
                if depth == 0 {
                    return i + 1;
                }
                if depth < 0 {
                    return i;
                }
            }
            Tok::Punct(';') | Tok::Punct(',') if depth == 0 && angle == 0 => return i + 1,
            _ => {}
        }
        i += 1;
    }
    i
}

/// Every `.rs` under `src/` of one crate, minus files an open non-test build
/// does not compile.
fn open_sources(krate: &Path) -> Vec<(PathBuf, Scanned)> {
    let src = krate.join("src");
    let mut files = Vec::new();
    let mut stack = vec![src.clone()];
    while let Some(dir) = stack.pop() {
        let Ok(entries) = std::fs::read_dir(&dir) else {
            continue;
        };
        for e in entries.filter_map(Result::ok) {
            let p = e.path();
            if p.is_dir() {
                if p.file_name().is_some_and(|n| n == "tests") {
                    continue;
                }
                stack.push(p);
            } else if p.extension().is_some_and(|x| x == "rs") {
                files.push(p);
            }
        }
    }
    files.sort();
    let mut scanned: Vec<(PathBuf, Scanned)> = files
        .into_iter()
        .filter(|p| {
            let name = p.file_name().unwrap().to_string_lossy();
            !(name == "tests.rs"
                || name.ends_with("_tests.rs")
                || name == "testgit.rs"
                || name == "testing.rs")
        })
        .map(|p| {
            let text = std::fs::read_to_string(&p).unwrap_or_default();
            let s = scan_source(&text);
            (p, s)
        })
        .collect();
    // Files of modules declared under a skipping attribute.
    let mut dead: Vec<PathBuf> = Vec::new();
    for (p, s) in &scanned {
        let name = p.file_stem().unwrap().to_string_lossy();
        let base = if matches!(name.as_ref(), "lib" | "main" | "mod") {
            p.parent().unwrap().to_path_buf()
        } else {
            p.parent().unwrap().join(name.as_ref())
        };
        for m in &s.skipped_mods {
            dead.push(base.join(format!("{m}.rs")));
            dead.push(base.join(m));
        }
    }
    scanned.retain(|(p, _)| !dead.iter().any(|d| p == d || p.starts_with(d)));
    scanned
}

fn workspace_root() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR")).join("../..")
}

/// **Deliberate exceptions**, each with the reason it cannot reach an open build's user or
/// operator. `(file suffix, text fragment, reason)`. Every entry must still match something,
/// or the test fails: a stale exception is a hole nobody is looking at.
const EXCEPTIONS: &[(&str, &str, &str)] = &[
    (
        "server/lib/src/lib.rs",
        "fleet/sold-repositories.json",
        "a FILE NAME under the data root (`sold::SOLD_REPOS_REL`), the contract the twin, a \
         recharge and the front read by name; never shown as words",
    ),
    (
        "server/lib/src/replication.rs",
        "fleet/sold-repositories.json",
        "the same file name, in the estate item list a recharge copies by path",
    ),
    (
        "server/lib/src/retention.rs",
        "quota-evicted",
        "`RetentionReason::QuotaEvicted`'s wire spelling, stored in audit details and plans \
         already written; a storage quota of the retention policy, not a sold one",
    ),
    (
        "server/sandbox/src/api.rs",
        "quota",
        "the podman API's cgroup `cpu.quota` KEY in a container spec; no person reads it",
    ),
    (
        "server/sandbox/src/crun.rs",
        "quota",
        "the OCI runtime spec's `cpu.quota` KEY; no person reads it",
    ),
    (
        "server/cli/src/lib.rs",
        "plan_computed",
        "a functional-status EVENT name of the retention dry run (`holger-cli/retention`), \
         matched by key; the line it labels reads `retention plan (DRY-RUN …)`",
    ),
    (
        "errcode/src/lib.rs",
        "over its paid disk_bytes limit",
        "the FROZEN registry text of `holger-metered-6`, emitted only by the metered build's \
         `QuotaGuard` (`metered.rs`), which an open build does not contain",
    ),
    (
        "errcode/src/lib.rs",
        "purchase token was not accepted",
        "a `reserved` marketplace code: the doors were cut in 9521bf0 and the numbers stay \
         frozen; nothing emits it",
    ),
    (
        "errcode/src/lib.rs",
        "subscription names a plan",
        "a `reserved` marketplace code, as above",
    ),
    (
        "errcode/src/lib.rs",
        "subscription id is not a safe tenant name",
        "a `reserved` marketplace code, as above",
    ),
    (
        "errcode/src/lib.rs",
        "no provisioned tenant for this subscription",
        "a `reserved` marketplace code, as above",
    ),
    (
        "errcode/src/lib.rs",
        "subscription names no buyer directory",
        "a `reserved` marketplace code, as above",
    ),
    (
        "errcode/src/lib.rs",
        "subscription is not in an activatable state",
        "a `reserved` marketplace code, as above",
    ),
    (
        "errcode/src/lib.rs",
        "buyer sign-in missing",
        "a `reserved` marketplace code, as above",
    ),
];

#[cfg(not(feature = "metered"))]
#[test]
fn the_open_sources_say_no_money() {
    let root = workspace_root();
    let mut leaks = Vec::new();
    let mut used = vec![false; EXCEPTIONS.len()];
    let mut scanned_files = 0usize;
    for krate in SCANNED_CRATES {
        for (path, s) in open_sources(&root.join(krate)) {
            let rel = path
                .strip_prefix(&root)
                .unwrap_or(&path)
                .to_string_lossy()
                .replace('\\', "/");
            if PAID_INCLUDES.iter().any(|(_, inc)| rel.ends_with(inc)) {
                continue;
            }
            scanned_files += 1;
            for lit in &s.literals {
                let hits = leaks_in(&lit.text);
                if hits.is_empty() {
                    continue;
                }
                if let Some(k) = EXCEPTIONS
                    .iter()
                    .position(|(file, frag, _)| rel.ends_with(file) && lit.text.contains(frag))
                {
                    used[k] = true;
                    continue;
                }
                leaks.push(format!("{rel}:{}: {hits:?} in {:?}", lit.line, lit.text));
            }
        }
    }
    assert!(
        scanned_files > 150,
        "the scan found only {scanned_files} files; the crate layout moved"
    );
    for (file, inc) in PAID_INCLUDES {
        let text =
            std::fs::read_to_string(root.join(file)).unwrap_or_else(|e| panic!("{file}: {e}"));
        assert!(
            text.contains(inc),
            "{file} no longer includes {inc}: drop it from PAID_INCLUDES"
        );
        assert!(
            !scan_source(&text).literals.iter().any(|l| l.text == *inc),
            "{file} includes {inc} from an item an open build compiles: it is scanned, or gated"
        );
    }
    let stale: Vec<_> = EXCEPTIONS
        .iter()
        .zip(&used)
        .filter(|(_, u)| !**u)
        .map(|(e, _)| (e.0, e.1))
        .collect();
    assert!(
        stale.is_empty(),
        "exceptions that no longer match anything: {stale:?}"
    );
    assert!(
        leaks.is_empty(),
        "an OPEN holger build compiles money vocabulary into what it says to a user or an \
         operator ({} literals). Reword neutrally, or gate the code under `metered`.\n  {}",
        leaks.len(),
        leaks.join("\n  ")
    );
}

#[test]
fn the_judge_reads_the_sentence() {
    assert_eq!(
        leaks_in("a disk would be billed and invisible"),
        vec!["billed"]
    );
    assert!(
        leaks_in("payload bytes").is_empty(),
        "substring, not a word"
    );
    assert_eq!(leaks_in("the community plan"), vec!["plan"]);
    assert!(
        leaks_in("retention plan (DRY-RUN)").is_empty(),
        "Holger's retention plan is technical"
    );
    assert!(leaks_in("the renewal of this box's certificate").is_empty());
    assert_eq!(
        leaks_in("more room is bought on its plan page"),
        vec!["bought", "plan"]
    );
    assert_eq!(leaks_in("https://buy.stripe.com/x"), vec!["buy", "stripe"]);
    assert_eq!(leaks_in("an unpaid repository"), vec!["unpaid"]);
}

#[test]
fn the_scanner_skips_what_the_open_build_does_not_contain() {
    let src = r####"
        // a comment about price
        /// a doc about billing
        fn open() { let _ = "free space"; }
        #[cfg(feature = "metered")]
        fn metered() { let _ = "paid"; }
        #[cfg(feature = "admit-share")]
        fn shared() { let _ = "the paid share"; }
        #[cfg(feature = "metered")]
        pub fn metered_result(a: Vec<u8>) -> Result<Vec<u8>, String> { Err(format!("billed {a:?}")) }
        #[cfg(not(feature = "metered"))]
        fn community() { let _ = "sealed"; }
        #[cfg(test)]
        mod tests { fn t() { let _ = "invoice"; } }
        #[cfg(feature = "metered")]
        pub mod entitlement;
        #[derive(Debug)]
        #[error("a refusal about quota")]
        struct E;
        const C: char = '"';
        fn tail() { let _ = "after"; }
    "####;
    let s = scan_source(src);
    let texts: Vec<&str> = s.literals.iter().map(|l| l.text.as_str()).collect();
    assert_eq!(
        texts,
        vec!["free space", "sealed", "a refusal about quota", "after"]
    );
    assert_eq!(s.skipped_mods, vec!["tests", "entitlement"]);
}

/// The guard must be able to FAIL: the same judge over the metered module's literals finds
/// the vocabulary at once.
#[test]
fn the_guard_would_catch_a_leak() {
    let metered =
        std::fs::read_to_string(Path::new(env!("CARGO_MANIFEST_DIR")).join("src/metered.rs"))
            .expect("the metered module is in the tree even when it is not compiled");
    let found: usize = lex(&metered)
        .iter()
        .filter(|(_, t)| matches!(t, Tok::Str(s) if !leaks_in(s).is_empty()))
        .count();
    assert!(
        found > 0,
        "the judge finds nothing even in src/metered.rs: the scan is broken, not the tree"
    );
}

// ── Holger's own ────────────────────────────────────────────────────────────

/// The files the record-kind carve-out is checked over.
const OPEN_SOURCES: &[&str] = &[
    "src/metering.rs",
    "src/grpc.rs",
    "src/audit/mod.rs",
    "src/metrics.rs",
    "src/room.rs",
];

fn line_words(text: &str) -> Vec<String> {
    text.split(|c: char| !c.is_ascii_alphanumeric())
        .filter(|w| !w.is_empty())
        .map(|w| w.to_ascii_lowercase())
        .collect()
}

/// **`entitlement` is a RECORD KIND here, and that is why it is not on the list
/// above — measured, not assumed.**
///
/// This guard found it first: `AuditAction::Entitlement` and its arm in
/// `metrics.rs` put the word in an open build's enum. The obvious fix — gate the
/// variant behind `metered` — is the WRONG one, and the reason is
/// `AuditAction::from_wire`:
///
/// > an OPEN build reading an audit log a METERED build wrote must still map the
/// > row `"entitlement"` back to something that says what it was.
///
/// Gate the variant and that row degrades to `Other`, so the append-only log —
/// holger's only attestation trail — silently forgets that a plan ever changed, on
/// exactly the box an operator would be auditing after the fact. A word in an enum
/// is a smaller cost than a record that cannot be read back.
///
/// The shape of this exception is gunnar's: its guard judges `plan` / `checkout` /
/// `renew` by the sentence they sit in rather than banning them outright. The
/// narrow claim here is that the word appears ONLY as the name of an audit action
/// and its wire spelling — never as a plan, a price, or an offer — and
/// [`the_word_entitlement_is_only_ever_a_record_kind`] is what holds it to that.
const RECORD_KIND_WORDS: &[&str] = &["entitlement"];

/// Strip the parts an open build does not compile or does not show: `cfg(feature =
/// "metered")` items, `#[cfg(test)]` modules, and comments (a comment stating the
/// rule is not a leak).
fn open_surface(text: &str) -> String {
    let mut out = String::new();
    let mut skip_cfg = false;
    let mut in_tests = false;
    for line in text.lines() {
        let t = line.trim_start();
        if t.starts_with("//") {
            continue;
        }
        if t.contains("#[cfg(feature = \"metered\")]") {
            skip_cfg = true;
            continue;
        }
        if t.starts_with("#[cfg(test)]") {
            in_tests = true;
            continue;
        }
        // A cfg'd item is one item: the next non-empty line is the thing skipped.
        if skip_cfg {
            skip_cfg = false;
            continue;
        }
        if in_tests {
            continue;
        }
        out.push_str(line);
        out.push('\n');
    }
    out
}

/// **The one carve-out, held to its claim.** `entitlement` survives in the open
/// sources only as an audit action and its wire spelling — if it ever turns up
/// beside a price, a plan or an offer, this fails and the word goes back on the
/// list. See [`RECORD_KIND_WORDS`] for why it is not simply banned.
#[test]
fn the_word_entitlement_is_only_ever_a_record_kind() {
    let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
    // The only open files allowed to say it at all.
    const ALLOWED: &[&str] = &["src/audit/mod.rs", "src/metrics.rs"];
    for rel in OPEN_SOURCES {
        let text = std::fs::read_to_string(root.join(rel)).unwrap();
        let seen = line_words(&open_surface(&text));
        let says_it = RECORD_KIND_WORDS
            .iter()
            .any(|w| seen.iter().any(|s| s == w));
        if says_it {
            assert!(
                ALLOWED.contains(rel),
                "{rel} uses a record-kind word outside the audit vocabulary — either it is \
                 money after all, or this allow-list is stale"
            );
        }
    }
    // …and where it IS allowed, it is the action name and the wire string, nothing
    // that reads as an offer.
    let audit = std::fs::read_to_string(root.join("src/audit/mod.rs")).unwrap();
    assert!(
        audit.contains("Entitlement,") && audit.contains("\"entitlement\""),
        "the carve-out claims an enum variant and its wire spelling; if those are gone the \
         word should not be here either"
    );
}

/// **Counting is not money.** The usage door is in every build and says so: the
/// meter names a self-hoster wants are present in the open sources.
#[test]
fn the_open_build_still_says_how_much_it_holds() {
    let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
    let metering = std::fs::read_to_string(root.join("src/metering.rs")).unwrap();
    for meter in ["artifacts", "archive_bytes", "bytes_served", "requests"] {
        assert!(
            metering.contains(meter),
            "the open usage door must still report '{meter}' — a box that cannot say how \
             much it holds is worse for everyone"
        );
    }
}