use regex::Regex;
use std::path::{Path, PathBuf};
use std::process::Command;
fn workspace_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent() .unwrap()
.parent() .unwrap()
.to_path_buf()
}
fn forbidden_shapes() -> Vec<(Regex, &'static str)> {
vec![
(
Regex::new(r"(?i)\bdocket\b").unwrap(),
"a reference into the maintainers' private issue queue",
),
(
Regex::new(r"(?i)\bcycle[-_ ]\d+\b").unwrap(),
"a work-log iteration number",
),
(
Regex::new(r"(?i)\bclaudedocs\b").unwrap(),
"a path into untracked working notes",
),
(
Regex::new(r"\b(?:ROADMAP|HANDOFF)\b").unwrap(),
"a planning document this repository does not contain",
),
(
Regex::new(r"\b(?:ISSUE|TRIAGE|PLAN|PROPOSAL|DECISION)-[A-Za-z0-9.-]+-\d{8}").unwrap(),
"a working-note file name",
),
]
}
const EXEMPT: &[(&str, &str)] = &[
(
".gitignore",
"excludes the working-notes directory from the repository",
),
("crates/m3l-cli/tests/public_text.rs", "this guard"),
];
fn tracked_files(root: &Path) -> Vec<String> {
let output = Command::new("git")
.args(["ls-files", "-z"])
.current_dir(root)
.output()
.expect("failed to run `git ls-files`");
assert!(
output.status.success(),
"`git ls-files` failed in {}: {}",
root.display(),
String::from_utf8_lossy(&output.stderr)
);
let files: Vec<String> = String::from_utf8(output.stdout)
.expect("`git ls-files` printed non-UTF-8 paths")
.split('\0')
.filter(|path| !path.is_empty())
.map(str::to_owned)
.collect();
assert!(files.iter().any(|f| f == "README.md"));
assert!(files.iter().any(|f| f == "CHANGELOG.md"));
files
}
#[test]
fn no_published_file_refers_to_the_maintainers_private_workflow() {
let root = workspace_root();
let shapes = forbidden_shapes();
let mut hits = Vec::new();
for file in tracked_files(&root) {
if EXEMPT.iter().any(|(path, _)| *path == file) {
continue;
}
let Ok(text) = std::fs::read_to_string(root.join(&file)) else {
continue; };
for (index, line) in text.lines().enumerate() {
for (pattern, why) in &shapes {
if let Some(found) = pattern.find(line) {
hits.push(format!(
"{file}:{}: '{}' — {why}",
index + 1,
found.as_str()
));
}
}
}
}
assert!(
hits.is_empty(),
"Published files carry references a public reader cannot follow. Say what was learned \
instead of where it was recorded (or drop the reference if the sentence stands without it):\n{}",
hits.join("\n")
);
}
#[test]
fn every_exemption_still_names_a_tracked_file() {
let tracked = tracked_files(&workspace_root());
let stale: Vec<&str> = EXEMPT
.iter()
.map(|(path, _)| *path)
.filter(|path| !tracked.iter().any(|f| f == path))
.collect();
assert!(
stale.is_empty(),
"Exemptions outlived their files — remove them so the list cannot quietly cover a file \
that later takes the same path:\n{}",
stale.join("\n")
);
}