tests/human_docs.rs
//! **Every collector carries a human card, and the card is not a formality.**
//!
//! The owner, 2026-09-04: *"collectors get HUMAN DOCS … fill it for every existing
//! collector from what the source publishes."*
//!
//! Two tests, because there are two ways to fail this. The first is leaving a collector
//! undocumented; the second — much easier, and the one that actually happens — is
//! filling the fields with something that passes a non-empty check and tells an
//! operator nothing. A card saying authority `"the API"` and terms `"see website"` is
//! worse than no card, because it looks answered.
use korp_collectors::human_doc::{Contact, RateLimit, Registration};
use korp_collectors::{registry, AuthKind};
/// **RED: name every collector with no card.** Not a count — the list, so the fix is
/// the list.
#[test]
fn every_registered_collector_carries_a_human_card() {
let all = registry();
assert!(
all.len() >= 40,
"the registry came back with {} collectors — this sweep is reading nothing",
all.len(),
);
let undocumented: Vec<String> = all
.iter()
.filter(|c| c.human_doc().is_none())
.map(|c| c.meta().name.clone())
.collect();
// It was a RATCHET at 13 for one commit, while the energy + environment family was
// still being written, for the reason `tests/no_python.rs` records about the shell
// census: a refusal committed before the work is done is red for every developer and
// every CI run, and a permanently-red guard is one people learn to ignore.
//
// It reached ZERO on 2026-09-04 and it does not go up. A new collector arrives
// undocumented and this test names it on the first run.
const UNDOCUMENTED_CEILING: usize = 0;
assert!(
undocumented.len() <= UNDOCUMENTED_CEILING,
"{} of {} collectors have no human card — an operator opening their pane gets a \
blank where 'who runs this and how do I get a key' should be:\n {}",
undocumented.len(),
all.len(),
undocumented.join("\n "),
);
// The other direction: a ratchet nobody lowers is a ratchet that stopped working.
assert_eq!(
undocumented.len(),
UNDOCUMENTED_CEILING,
"{} collectors are undocumented and the ceiling still says {UNDOCUMENTED_CEILING} \
— lower it in this file; the endpoint is ZERO",
undocumented.len(),
);
}
/// **RED: a card that is filled in but says nothing.**
///
/// Every check here fires on a real way of writing a useless card, and each is named
/// separately so the failure says WHICH kind of empty it is.
#[test]
fn a_human_card_answers_the_questions_it_claims_to() {
/// Words that fill a field without answering it. A card whose authority is
/// "unknown" has not been written; a card whose authority is "Trafikverket" has.
const WEASEL: [&str; 8] = ["n/a", "na", "none", "tbd", "todo", "unknown", "see website", "-"];
let mut bad: Vec<String> = Vec::new();
let mut checked = 0usize;
for c in registry() {
let name = c.meta().name.clone();
let Some(d) = c.human_doc() else { continue };
checked += 1;
let mut say = |what: &str| bad.push(format!("{name}: {what}"));
for (field, v) in [
("authority", &d.authority),
("owner", &d.owner),
("terms_url", &d.terms_url),
("docs_url", &d.docs_url),
] {
if v.trim().is_empty() {
say(&format!("{field} is empty"));
} else if WEASEL.contains(&v.trim().to_ascii_lowercase().as_str()) {
say(&format!("{field} is {v:?}, which fills the field without answering it"));
}
}
// A URL field has to BE a URL. "the Trafikverket website" is a sentence, not a
// place an operator can click.
for (field, v) in [("terms_url", &d.terms_url), ("docs_url", &d.docs_url)] {
if !v.trim().is_empty() && !v.starts_with("http") {
say(&format!("{field} is {v:?}, which is not a URL"));
}
}
// ── The cross-checks: the card must agree with what the CODE already says ──
//
// These are the ones worth having. A card is written by hand and the code is
// executed, so the two drift silently — and the drift always favours the card
// looking better than the collector behaves.
let needs_secret = !matches!(c.meta().auth, AuthKind::None);
if needs_secret && matches!(d.registration, Registration::NotNeeded) {
say("the card says no registration is needed, but the collector declares an \
auth kind — one of the two is lying to the operator");
}
if !needs_secret && !d.registration.is_self_serve() {
say("the card sends the operator off to register, but the collector needs no \
auth at all");
}
// A source you cannot reach and cannot register with leaves an operator with
// nowhere to go, so at least one door has to be open.
if matches!(d.contact, Contact::Unknown)
&& matches!(d.registration, Registration::NotNeeded)
&& matches!(d.rate_limit, RateLimit::Unknown)
{
say("every soft field is Unknown — this card was created, not written");
}
}
assert!(
checked >= 40,
"only {checked} cards were examined — the sweep is not reaching the registry",
);
assert!(bad.is_empty(), "{} weak human card(s):\n {}", bad.len(), bad.join("\n "));
}