use std::fs;
use std::path::{Path, PathBuf};
const FORBIDDEN_TOKENS: &[&str] = &[
"ccd",
"rlm",
"reforge",
"fixity",
"continuity",
"memory",
"recall",
"promotion",
"compaction",
];
const ALLOWLISTED_PATH_PREFIXES: &[&str] = &[
"src/host_assets.rs",
"src/host_assets/",
"src/telemetry/",
"src/protocol/mod.rs",
"src/protocol/claude.rs",
"src/cli/asset.rs",
"src/cli/host_hook.rs",
"src/bin/lifeloop-fake-ccd-client.rs",
];
const MEMORY_PHRASE_CARVE_OUTS: &[&str] = &["in-memory", "in memory", "InMemory"];
const PROMOTION_PHRASE_CARVE_OUTS: &[&str] = &[
"tombstone promotion",
"lib.rs promotion",
"schema promotion",
];
const COMPACTION_PHRASE_CARVE_OUTS: &[&str] = &[
"compaction signal",
"compaction summary",
"compaction/compression",
"on-compaction-notice",
];
#[test]
fn lifeloop_static_boundary_proof_keeps_client_vocabulary_out() {
let crate_root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let src_root = crate_root.join("src");
let mut violations = Vec::new();
let mut files_scanned: usize = 0;
walk_rs(&src_root, &mut |path| {
files_scanned += 1;
let rel = path
.strip_prefix(&crate_root)
.expect("path under crate root");
let rel_str = rel.to_string_lossy().replace('\\', "/");
if is_path_allowlisted(&rel_str) {
return;
}
let bytes = match fs::read(path) {
Ok(b) => b,
Err(err) => {
violations.push(Violation {
path: rel_str.clone(),
line: 0,
token: "<read-error>",
excerpt: format!("failed to read file: {err}"),
});
return;
}
};
let contents = match std::str::from_utf8(&bytes) {
Ok(s) => s,
Err(_) => {
violations.push(Violation {
path: rel_str.clone(),
line: 0,
token: "<non-utf8>",
excerpt: "file is not valid UTF-8".to_string(),
});
return;
}
};
scan_text(&rel_str, contents, &mut violations);
});
assert!(
files_scanned > 0,
"kernel-purity gate scanned zero files; expected at least the crate root `src/` tree at {}",
src_root.display(),
);
assert!(
violations.is_empty(),
"\nKernel-purity gate (issue #24) found {} violation(s).\n\
Lifeloop core must not name client-owned product vocabulary.\n\
See `tests/kernel_purity.rs` rustdoc for the forbidden token\n\
list, the allowlist of compat zones, and the carve-out phrases.\n\
Either neutralize the offending name in core code, or — if the\n\
file is a legitimate compat zone — extend the allowlist *and*\n\
document the reason in the rustdoc.\n\n\
Violations:\n{}\n",
violations.len(),
format_violations(&violations),
);
}
#[derive(Debug)]
struct Violation {
path: String,
line: usize,
token: &'static str,
excerpt: String,
}
fn format_violations(violations: &[Violation]) -> String {
let mut out = String::new();
for v in violations {
out.push_str(&format!(
" {}:{} [{}] {}\n",
v.path, v.line, v.token, v.excerpt,
));
}
out
}
fn is_path_allowlisted(rel_path: &str) -> bool {
ALLOWLISTED_PATH_PREFIXES
.iter()
.any(|prefix| rel_path == *prefix || rel_path.starts_with(prefix))
}
fn scan_text(rel_path: &str, contents: &str, violations: &mut Vec<Violation>) {
for (line_idx, line) in contents.lines().enumerate() {
let line_lower = line.to_ascii_lowercase();
for &token in FORBIDDEN_TOKENS {
for span in word_boundary_matches(&line_lower, token) {
if has_carve_out_at(line, span, token) {
continue;
}
violations.push(Violation {
path: rel_path.to_string(),
line: line_idx + 1,
token,
excerpt: line.trim().to_string(),
});
break;
}
}
}
}
fn word_boundary_matches(text: &str, token: &str) -> Vec<(usize, usize)> {
let mut spans = Vec::new();
let bytes = text.as_bytes();
let needle = token.as_bytes();
let mut start = 0usize;
while start + needle.len() <= bytes.len() {
if bytes[start..start + needle.len()] == *needle {
let end = start + needle.len();
let before_ok = start == 0 || !is_word_byte(bytes[start - 1]);
let after_ok = end == bytes.len() || !is_word_byte(bytes[end]);
if before_ok && after_ok {
spans.push((start, end));
}
}
start += 1;
}
spans
}
fn is_word_byte(b: u8) -> bool {
b.is_ascii_alphanumeric() || b == b'_'
}
fn has_carve_out_at(line: &str, span: (usize, usize), token: &str) -> bool {
let phrases: &[&str] = match token {
"memory" => MEMORY_PHRASE_CARVE_OUTS,
"promotion" => PROMOTION_PHRASE_CARVE_OUTS,
"compaction" => COMPACTION_PHRASE_CARVE_OUTS,
_ => return false,
};
let (token_start, token_end) = span;
let line_lower = line.to_ascii_lowercase();
for phrase in phrases {
let phrase_lower = phrase.to_ascii_lowercase();
let phrase_len = phrase_lower.len();
if phrase_len == 0 {
continue;
}
let mut search_start = 0usize;
while let Some(rel) = line_lower[search_start..].find(&phrase_lower) {
let phrase_start = search_start + rel;
let phrase_end = phrase_start + phrase_len;
if phrase_start <= token_start && token_end <= phrase_end {
return true;
}
search_start = phrase_start + 1;
}
}
false
}
fn walk_rs(dir: &Path, visit: &mut dyn FnMut(&Path)) {
let entries = match fs::read_dir(dir) {
Ok(it) => it,
Err(_) => return,
};
for entry in entries.flatten() {
let path = entry.path();
let file_type = match entry.file_type() {
Ok(t) => t,
Err(_) => continue,
};
if file_type.is_dir() {
walk_rs(&path, visit);
} else if file_type.is_file()
&& path
.extension()
.and_then(|s| s.to_str())
.map(|s| s.eq_ignore_ascii_case("rs"))
.unwrap_or(false)
{
visit(&path);
}
}
}
#[test]
fn word_boundary_matches_finds_token_at_boundaries() {
let line = "the ccd compat label, also \"ccd\" and ccd, but not preccdfix".to_lowercase();
let spans = word_boundary_matches(&line, "ccd");
assert_eq!(spans.len(), 3, "spans = {spans:?} for line `{line}`");
}
#[test]
fn word_boundary_matches_skips_substring_only_hits() {
let line = "compactor compactness compactify".to_lowercase();
let spans = word_boundary_matches(&line, "compaction");
assert!(
spans.is_empty(),
"should not match `compaction` inside other words: spans = {spans:?}",
);
}
fn first_span(line: &str, token: &str) -> (usize, usize) {
let lower = line.to_ascii_lowercase();
*word_boundary_matches(&lower, token)
.first()
.unwrap_or_else(|| {
panic!("test setup: token `{token}` not found at a word boundary in `{line}`")
})
}
#[test]
fn memory_carve_outs_suppress_in_memory_idiom() {
let cases: &[(&str, bool)] = &[
("/// In-memory reference IdempotencyStore", true),
("//! callers that already have the log in memory.", true),
("//! Lifeloop transports payloads, not memory.", false),
];
for (line, expect_carved) in cases {
let span = first_span(line, "memory");
assert_eq!(
has_carve_out_at(line, span, "memory"),
*expect_carved,
"carve-out mismatch for `{line}` (span={span:?})",
);
}
}
#[test]
fn compaction_carve_outs_suppress_telemetry_phrasings() {
let cases: &[(&str, bool)] = &[
(
"//! and a compaction signal. No prompt or message bodies are",
true,
),
(
"//! the adapter signaled a compaction/compression event",
true,
),
(" \"on-compaction-notice -> context.pressure\",", true),
("//! Lifeloop does not own compaction.", false),
];
for (line, expect_carved) in cases {
let span = first_span(line, "compaction");
assert_eq!(
has_carve_out_at(line, span, "compaction"),
*expect_carved,
"carve-out mismatch for `{line}` (span={span:?})",
);
}
}
#[test]
fn promotion_carve_outs_suppress_schema_tooling_idioms() {
let cases: &[(&str, bool)] = &[
(
"// Snapshot lib.rs so we can restore it if the tombstone promotion",
true,
),
("// fails after the lib.rs promotion succeeds.", true),
("//! Lifeloop does not own promotion.", false),
];
for (line, expect_carved) in cases {
let span = first_span(line, "promotion");
assert_eq!(
has_carve_out_at(line, span, "promotion"),
*expect_carved,
"carve-out mismatch for `{line}` (span={span:?})",
);
}
}
#[test]
fn carve_out_does_not_mask_separate_bare_token_on_same_line() {
let line = "the in-memory cache and a bare memory leak";
let lower = line.to_ascii_lowercase();
let spans = word_boundary_matches(&lower, "memory");
assert_eq!(
spans.len(),
2,
"expected two `memory` spans in `{line}`, got {spans:?}",
);
let kept: Vec<_> = spans
.iter()
.copied()
.filter(|&span| !has_carve_out_at(line, span, "memory"))
.collect();
assert_eq!(
kept.len(),
1,
"expected the bare `memory` to survive carve-out filtering, got kept={kept:?}",
);
let (start, end) = kept[0];
assert_eq!(
&line[start..end],
"memory",
"kept span should be the bare `memory` occurrence",
);
}
#[test]
fn allowlist_path_match_is_prefix_based() {
assert!(is_path_allowlisted("src/host_assets.rs"));
assert!(is_path_allowlisted("src/host_assets/render.rs"));
assert!(is_path_allowlisted("src/host_assets/profiles.rs"));
assert!(is_path_allowlisted("src/telemetry/claude.rs"));
assert!(is_path_allowlisted("src/telemetry/mod.rs"));
assert!(is_path_allowlisted("src/protocol/mod.rs"));
assert!(is_path_allowlisted("src/protocol/claude.rs"));
assert!(is_path_allowlisted("src/cli/asset.rs"));
assert!(is_path_allowlisted("src/bin/lifeloop-fake-ccd-client.rs"));
assert!(!is_path_allowlisted("src/lib.rs"));
assert!(!is_path_allowlisted("src/router/mod.rs"));
assert!(!is_path_allowlisted("src/router/subprocess.rs"));
assert!(!is_path_allowlisted("src/protocol/codex.rs"));
assert!(!is_path_allowlisted("src/cli/event.rs"));
assert!(!is_path_allowlisted("src/bin/lifeloop-bump-schema.rs"));
}