use std::fs;
use std::path::{Path, PathBuf};
const SKILL: &str = ".claude/skills/pass-review/SKILL.md";
const LEDGER: &str = "DESIGN-FINDINGS.md";
const LEDGER_HEADING: &str = "## 18. F-Ledger";
const GUIDE: &str = "AGENT-INSTRUCTIONS.md";
const RULE_DOCS: [&str; 2] = [GUIDE, "docs/STANDING-RULES.md"];
const SECTION_DOCS: [&str; 3] = [GUIDE, "docs/STANDING-RULES.md", "docs/TESTING.md"];
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../..")
}
fn read(relative: &str) -> Result<String, String> {
fs::read_to_string(repo_root().join(relative)).map_err(|err| format!("{relative}: {err}"))
}
fn split_skill() -> Result<(String, String), String> {
let text = read(SKILL)?;
let lines: Vec<&str> = text.lines().collect();
if lines.first().map(|line| line.trim()) != Some("---") {
return Err(format!("{SKILL} does not open with a frontmatter fence"));
}
let close = lines
.iter()
.skip(1)
.position(|line| line.trim() == "---")
.ok_or_else(|| format!("{SKILL} frontmatter is never closed"))?;
Ok((lines[1..=close].join("\n"), lines[close + 2..].join("\n")))
}
fn indent(line: &str) -> usize {
line.len() - line.trim_start().len()
}
fn unquote(raw: &str) -> String {
raw.trim()
.trim_matches('"')
.trim_matches('\'')
.trim()
.to_owned()
}
fn declared(front: &str, key: &str) -> Vec<String> {
let lines: Vec<&str> = front.lines().collect();
let prefix = format!("{key}:");
let Some(at) = lines
.iter()
.position(|line| line.trim_start().starts_with(&prefix))
else {
return Vec::new();
};
let tail = lines[at].trim_start()[prefix.len()..].trim();
if tail.starts_with('[') {
return tail
.trim_matches('[')
.trim_matches(']')
.split(',')
.map(unquote)
.filter(|value| !value.is_empty())
.collect();
}
let base = indent(lines[at]);
lines[at + 1..]
.iter()
.take_while(|line| line.trim().is_empty() || indent(line) > base)
.filter_map(|line| line.trim().strip_prefix("- ").map(unquote))
.collect()
}
fn scalar(front: &str, key: &str) -> Option<String> {
let prefix = format!("{key}:");
front
.lines()
.find(|line| line.trim_start().starts_with(&prefix))
.map(|line| unquote(&line.trim_start()[prefix.len()..]))
}
fn declared_findings(front: &str) -> Vec<String> {
let mut all = declared(front, "findings-cited-as-closed");
all.extend(declared(front, "findings-cited-as-open"));
all.extend(declared(front, "findings-cited-as-neutral"));
all
}
fn ledger_status(ledger: &str, id: &str) -> Option<String> {
let start = ledger.find(LEDGER_HEADING)?;
let row = format!("| {id} |");
ledger[start..]
.lines()
.find(|line| line.starts_with(&row))
.and_then(|line| line.split('|').nth(4))
.map(|cell| cell.trim().to_uppercase())
}
fn reads_closed(status: &str) -> bool {
status.contains("FIXED") || status.contains("CLOSED")
}
fn is_finding_id(token: &str) -> bool {
let Some(digits) = token.strip_prefix('F') else {
return false;
};
digits.len() == 2 && digits.chars().all(|character| character.is_ascii_digit())
}
fn section_resolves(section: &str) -> bool {
for doc in SECTION_DOCS {
if let Ok(text) = read(doc) {
if text.contains(&format!("§{section}")) {
return true;
}
}
}
numbered_item_resolves(section)
}
fn numbered_item_resolves(section: &str) -> bool {
let Some((major, minor)) = section.split_once('.') else {
return false;
};
let Ok(text) = read(GUIDE) else {
return false;
};
let heading = format!("## {major}.");
let item = format!("{minor}. ");
text.lines()
.skip_while(|line| !line.starts_with(&heading))
.skip(1)
.take_while(|line| !line.starts_with("## "))
.any(|line| line.trim_start().starts_with(&item))
}
fn segment_matches(pattern: &str, name: &str) -> bool {
match pattern.split_once('*') {
None => pattern == name,
Some((head, tail)) => {
name.len() >= head.len() + tail.len() && name.starts_with(head) && name.ends_with(tail)
}
}
}
fn glob_matches(pattern: &str, candidate: &str) -> bool {
let wanted: Vec<&str> = pattern.split('/').collect();
let actual: Vec<&str> = candidate.split('/').collect();
wanted.len() == actual.len()
&& wanted
.iter()
.zip(&actual)
.all(|(left, right)| segment_matches(left, right))
}
fn walk(root: &Path, dir: &Path, out: &mut Vec<String>) {
let Ok(entries) = fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let raw = entry.file_name();
let name = raw.to_string_lossy();
if name == "target" || name == "node_modules" || name.starts_with('.') {
continue;
}
let path = entry.path();
if path.is_dir() {
walk(root, &path, out);
} else if let Ok(relative) = path.strip_prefix(root) {
out.push(relative.to_string_lossy().replace('\\', "/"));
}
}
}
fn tokens(body: &str) -> Vec<String> {
body.split(|character: char| !(character.is_ascii_alphanumeric() || "_./-".contains(character)))
.map(str::to_owned)
.collect()
}
#[test]
fn declared_paths_exist() {
let (front, _) = split_skill().unwrap();
let paths = declared(&front, "paths");
assert!(!paths.is_empty(), "the block declares no paths at all");
for path in &paths {
assert!(
repo_root().join(path).exists(),
"the block declares `{path}`, which is not in the tree"
);
}
}
#[test]
fn declared_globs_match_at_least_one_file() {
let (front, _) = split_skill().unwrap();
let root = repo_root();
for pattern in declared(&front, "globs") {
assert!(
!pattern.contains("**"),
"`{pattern}` uses `**`; this matcher handles single-`*` segments only"
);
let head: Vec<&str> = pattern
.split('/')
.take_while(|part| !part.contains('*'))
.collect();
let mut found = Vec::new();
walk(&root, &root.join(head.join("/")), &mut found);
assert!(
found
.iter()
.any(|candidate| glob_matches(&pattern, candidate)),
"glob `{pattern}` matches nothing in the tree"
);
}
}
#[test]
fn declared_rules_are_defined_in_the_rule_documents() {
let (front, _) = split_skill().unwrap();
let mut corpus = String::new();
for doc in RULE_DOCS {
corpus.push_str(&read(doc).unwrap());
}
for rule in declared(&front, "rules") {
assert!(
corpus.contains(&rule),
"rule `{rule}` is declared but defined in neither {RULE_DOCS:?}"
);
}
}
#[test]
fn declared_numbered_sections_resolve() {
let (front, _) = split_skill().unwrap();
let sections = declared(&front, "numbered-sections");
assert!(!sections.is_empty(), "the block declares no sections");
for section in sections {
assert!(
section_resolves(§ion),
"§{section} is declared but resolves in none of {SECTION_DOCS:?}"
);
}
}
#[test]
fn declared_findings_have_a_ledger_row() {
let (front, _) = split_skill().unwrap();
let ledger = read(LEDGER).unwrap();
for id in declared_findings(&front) {
assert!(
ledger_status(&ledger, &id).is_some(),
"`{id}` is declared but has no §18 ledger row"
);
}
}
#[test]
fn findings_cited_as_closed_read_closed_in_the_ledger() {
let (front, _) = split_skill().unwrap();
let ledger = read(LEDGER).unwrap();
for id in declared(&front, "findings-cited-as-closed") {
let status = ledger_status(&ledger, &id).unwrap_or_default();
assert!(
reads_closed(&status),
"the skill treats `{id}` as closed; the ledger reads `{status}`"
);
}
}
#[test]
fn findings_cited_as_open_do_not_read_closed_in_the_ledger() {
let (front, _) = split_skill().unwrap();
let ledger = read(LEDGER).unwrap();
for id in declared(&front, "findings-cited-as-open") {
let status = ledger_status(&ledger, &id).unwrap_or_default();
assert!(
!reads_closed(&status),
"the skill argues from `{id}` as open; the ledger reads `{status}` — the prose citing it is stale"
);
}
}
#[test]
fn every_finding_cited_in_the_body_is_declared() {
let (front, body) = split_skill().unwrap();
let known = declared_findings(&front);
for token in tokens(&body) {
if !is_finding_id(&token) {
continue;
}
assert!(
known.contains(&token),
"the body cites `{token}`, which the block does not declare"
);
}
}
#[test]
fn every_document_cited_in_the_body_is_declared() {
let (front, body) = split_skill().unwrap();
let paths = declared(&front, "paths");
for token in tokens(&body) {
let is_markdown = Path::new(&token)
.extension()
.is_some_and(|extension| extension.eq_ignore_ascii_case("md"));
if !is_markdown {
continue;
}
let suffix = format!("/{token}");
assert!(
paths
.iter()
.any(|path| path == &token || path.ends_with(&suffix)),
"the body cites `{token}`, which the block does not declare"
);
}
}
#[test]
fn floor_command_is_a_makefile_target() {
let (front, _) = split_skill().unwrap();
let command = scalar(&front, "floor-command").unwrap_or_default();
let target = command.strip_prefix("make ").unwrap_or(&command).to_owned();
let makefile = read("Makefile").unwrap();
assert!(
makefile
.lines()
.any(|line| line.starts_with(&format!("{target}:"))),
"`{command}` is declared, but `{target}:` is not a Makefile target"
);
}
#[test]
fn lint_invariants_hold_in_their_named_files() {
let (front, _) = split_skill().unwrap();
let invariants = declared(&front, "lint-invariants");
assert!(
!invariants.is_empty(),
"the block declares no lint invariants"
);
for invariant in invariants {
let split = invariant.split_once(": ");
assert!(
split.is_some(),
"`{invariant}` is not in `<file>: <needle>` form"
);
let Some((file, needle)) = split else {
continue;
};
let text = read(file).unwrap();
assert!(
text.contains(needle),
"`{file}` no longer contains `{needle}` — §4's RED-commit rule rests on it"
);
}
}
#[test]
fn every_external_claim_carries_a_verification_date() {
let (front, _) = split_skill().unwrap();
let block: Vec<&str> = front
.lines()
.skip_while(|line| !line.trim_start().starts_with("external-claims:"))
.collect();
let claims = block
.iter()
.filter(|line| line.trim_start().starts_with("- claim:"))
.count();
let dates = block
.iter()
.filter(|line| line.trim_start().starts_with("verified:"))
.count();
assert!(claims > 0, "the block declares no external claims");
assert_eq!(
claims, dates,
"§11.3 forbids an undated external claim: {claims} claim(s), {dates} date(s)"
);
}