facett-core/examples/resolution_sweep.rs
//! **Does every repo in the constellation still RESOLVE?** — the ~4 s/repo sweep
//! that would have caught modgunn and ordning the day they broke.
//!
//! ```text
//! cargo run -p facett-core --example resolution_sweep -- ~/git
//! cargo run -p facett-core --example resolution_sweep -- ~/git/korp ~/git/nornir
//! ```
//!
//! Exits 1 and names each repo with cargo's own first line. Exits 0 when every
//! repo answers.
//!
//! **Why this is its own sweep and not a column in the compile-coverage one.** A
//! repo that does not resolve is not RED, it is ABSENT: cargo cannot enumerate
//! its targets, so a compile check has nothing to compile, a dep-graph tool has
//! no graph, and the warehouse indexer skips it. MEASURED 2026-08-23 — modgunn
//! (12 test targets) and ordning (10) had been unresolvable for nine days and
//! nothing in the constellation reported it. modgunn's cause was
//! `warehouse-sql = [..., "skade/sql"]` still naming a feature skade dropped on
//! 2026-08-14: a *resolution* error, which no amount of building can find.
//!
//! Given a single directory that is not itself a cargo repo, every immediate
//! child that is one is swept — so `-- ~/git` means "the constellation".
use std::path::PathBuf;
use facett_core::law;
fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
if args.is_empty() {
eprintln!("usage: resolution_sweep <repo-or-parent-dir>...");
std::process::exit(2);
}
let mut roots: Vec<PathBuf> = Vec::new();
for a in &args {
let p = PathBuf::from(a);
if p.join("Cargo.toml").is_file() {
roots.push(p);
continue;
}
// A parent directory: sweep the repos inside it, sorted so two runs of
// the same tree report in the same order.
let mut kids: Vec<PathBuf> = std::fs::read_dir(&p)
.unwrap_or_else(|e| panic!("cannot read {}: {e}", p.display()))
.filter_map(Result::ok)
.map(|e| e.path())
.filter(|c| c.join("Cargo.toml").is_file())
.collect();
kids.sort();
roots.extend(kids);
}
// An empty scan is not a pass. Nothing swept means the argument was wrong,
// and reporting that as "all clear" is the exact false green this
// constellation keeps finding.
if roots.is_empty() {
eprintln!("resolution sweep found NO cargo repos under {args:?} — nothing was checked");
std::process::exit(2);
}
let bad = law::unresolvable(&roots);
println!("resolution sweep: {} repo(s) checked, {} unresolvable", roots.len(), bad.len());
for u in &bad {
println!(" {}", u.describe());
}
if !bad.is_empty() {
std::process::exit(1);
}
}