Files
yvgude--lean-ctx/rust/tests/savings_verification.rs
T
wehub-resource-sync 26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

649 lines
23 KiB
Rust

use lean_ctx::core::patterns::git;
use lean_ctx::core::tokens::count_tokens;
fn measure_compression(command: &str, output: &str) -> (usize, usize, f64) {
let original = count_tokens(output);
let compressed = git::compress(command, output).unwrap_or_else(|| output.to_string());
let compressed_tokens = count_tokens(&compressed);
let savings_pct = if original > 0 {
(original - compressed_tokens) as f64 / original as f64 * 100.0
} else {
0.0
};
(original, compressed_tokens, savings_pct)
}
#[test]
fn verify_git_log_patch_savings() {
let output = generate_git_log_patch(10);
let (orig, comp, pct) = measure_compression("git log -p", &output);
eprintln!("[git log -p, 10 commits] {orig}{comp} tokens ({pct:.1}% saved)");
assert!(
pct > 70.0,
"git log -p should save >70% tokens, got {pct:.1}%"
);
}
#[test]
fn verify_git_log_patch_large_savings() {
let output = generate_git_log_patch(50);
let (orig, comp, pct) = measure_compression("git log -p", &output);
eprintln!("[git log -p, 50 commits] {orig}{comp} tokens ({pct:.1}% saved)");
assert!(
pct > 80.0,
"git log -p 50 commits should save >80% tokens, got {pct:.1}%"
);
}
#[test]
fn verify_git_log_stat_savings() {
let output = generate_git_log_stat(20);
let (orig, comp, pct) = measure_compression("git log --stat", &output);
eprintln!("[git log --stat, 20 commits] {orig}{comp} tokens ({pct:.1}% saved)");
assert!(
pct > 50.0,
"git log --stat should save >50% tokens, got {pct:.1}%"
);
}
#[test]
fn verify_git_log_standard_savings() {
let output = generate_git_log_standard(30);
let (orig, comp, pct) = measure_compression("git log", &output);
eprintln!("[git log standard, 30 commits] {orig}{comp} tokens ({pct:.1}% saved)");
assert!(
pct > 60.0,
"git log standard 30 commits should save >60%, got {pct:.1}%"
);
}
#[test]
fn verify_git_log_oneline_short_no_regression() {
let output = "abc1234 feat: one\ndef5678 fix: two\nghi9012 docs: three";
let (orig, comp, _pct) = measure_compression("git log --oneline", output);
eprintln!("[git log --oneline, 3 entries] {orig}{comp} tokens");
assert_eq!(orig, comp, "short oneline should pass through unchanged");
}
#[test]
fn verify_git_commit_feature_branch_savings() {
let output = "[feature/my-cool-branch abc1234] feat: implement new feature\n \
3 files changed, 45 insertions(+), 12 deletions(-)\n \
create mode 100644 src/new_module.rs\n";
let (orig, comp, pct) = measure_compression("git commit -m 'feat'", output);
let compressed = git::compress("git commit -m 'feat'", output).unwrap();
eprintln!(
"[git commit feature/branch] {orig}{comp} tokens ({pct:.1}% saved)\n result: {compressed}"
);
assert!(compressed.contains("abc1234"), "must contain hash");
assert!(
compressed.contains("feature/my-cool-branch"),
"must contain branch name"
);
}
#[test]
fn verify_git_commit_many_hooks_savings() {
let mut output = String::new();
for i in 0..50 {
output.push_str(&format!("check-{i:02}..................passed\n"));
}
output.push_str("[main abc1234] fix: resolve lint issues\n");
output.push_str(" 5 files changed, 30 insertions(+), 10 deletions(-)\n");
let (orig, comp, pct) = measure_compression("git commit -m 'fix'", &output);
let compressed = git::compress("git commit -m 'fix'", &output).unwrap();
eprintln!(
"[git commit 50 hooks] {orig}{comp} tokens ({pct:.1}% saved)\n result: {compressed}"
);
assert!(
pct > 60.0,
"50 hook lines should compress >60%, got {pct:.1}%"
);
assert!(
compressed.contains("hooks passed"),
"should summarize hooks"
);
assert!(compressed.contains("abc1234"), "must contain hash");
}
#[test]
fn verify_git_commit_with_failures_preserves_errors() {
let mut output = String::new();
for i in 0..20 {
output.push_str(&format!("check-{i:02}..................passed\n"));
}
output.push_str("ruff.......................failed\n");
output.push_str("fixing src/app.py: E302 expected 2 blank lines\n");
output.push_str("mypy.......................failed\n");
output.push_str("[main abc1234] fix: lint\n");
output.push_str(" 2 files changed, 5 insertions(+), 3 deletions(-)\n");
let (orig, comp, pct) = measure_compression("git commit -m 'fix'", &output);
let compressed = git::compress("git commit -m 'fix'", &output).unwrap();
eprintln!(
"[git commit with failures] {orig}{comp} tokens ({pct:.1}% saved)\n result: {compressed}"
);
assert!(compressed.contains("ruff"), "must preserve failed check");
assert!(compressed.contains("mypy"), "must preserve failed check");
assert!(compressed.contains("passed"), "should mention passed count");
}
#[test]
fn verify_overall_savings_estimation() {
let scenarios: Vec<(&str, String, &str)> = vec![
("git log -p -5", generate_git_log_patch(5), "git log -p"),
("git log -p -20", generate_git_log_patch(20), "git log -p"),
(
"git log --stat -10",
generate_git_log_stat(10),
"git log --stat",
),
("git log -10", generate_git_log_standard(10), "git log"),
(
"git commit (50 hooks)",
{
let mut s = String::new();
for i in 0..50 {
s.push_str(&format!("check-{i:02}..passed\n"));
}
s.push_str("[main abc1234] fix: stuff\n 1 file changed, 1 insertion(+)\n");
s
},
"git commit -m 'fix'",
),
];
eprintln!("\n{}", "=".repeat(60));
eprintln!(" SAVINGS VERIFICATION REPORT");
eprintln!("{}", "=".repeat(60));
eprintln!(
" {:<25} {:>8} {:>8} {:>7}",
"Scenario", "Original", "Compr.", "Saved%"
);
eprintln!(" {}", "-".repeat(50));
let mut total_original = 0usize;
let mut total_compressed = 0usize;
for (label, output, command) in &scenarios {
let (orig, comp, pct) = measure_compression(command, output);
total_original += orig;
total_compressed += comp;
eprintln!(" {label:<25} {orig:>8} {comp:>8} {pct:>6.1}%");
}
let total_pct = if total_original > 0 {
(total_original - total_compressed) as f64 / total_original as f64 * 100.0
} else {
0.0
};
eprintln!(" {}", "-".repeat(50));
eprintln!(
" {:<25} {:>8} {:>8} {:>6.1}%",
"TOTAL", total_original, total_compressed, total_pct
);
eprintln!("{}\n", "=".repeat(60));
assert!(
total_pct > 50.0,
"overall savings should be >50%, got {total_pct:.1}%"
);
}
#[test]
fn verify_cep_delta_tracking_prevents_overcounting() {
use std::collections::HashMap;
let test_dir = std::env::temp_dir().join(format!("lean-ctx-cep-test-{}", std::process::id()));
let lean_ctx_dir = test_dir.join(".lean-ctx");
let _ = std::fs::create_dir_all(&lean_ctx_dir);
let stats_path = lean_ctx_dir.join("stats.json");
let _ = std::fs::remove_file(&stats_path);
// TODO: Audit that the environment access only happens in single-threaded code.
unsafe {
std::env::set_var(
"LEAN_CTX_DATA_DIR",
lean_ctx_dir.to_string_lossy().to_string(),
);
};
let mut modes = HashMap::new();
modes.insert("full".to_string(), 5u64);
lean_ctx::core::stats::record_cep_session(70, 5, 10, 1000, 600, &modes, 10, "Standard");
let store1 = lean_ctx::core::stats::load();
let orig1 = store1.cep.total_tokens_original;
let comp1 = store1.cep.total_tokens_compressed;
let sessions1 = store1.cep.sessions;
eprintln!("After call 1: orig={orig1}, comp={comp1}, sessions={sessions1}");
lean_ctx::core::stats::record_cep_session(75, 8, 15, 2000, 1200, &modes, 20, "Standard");
let store2 = lean_ctx::core::stats::load();
let orig2 = store2.cep.total_tokens_original;
let comp2 = store2.cep.total_tokens_compressed;
let sessions2 = store2.cep.sessions;
eprintln!("After call 2: orig={orig2}, comp={comp2}, sessions={sessions2}");
let pid = std::process::id();
assert_eq!(store2.cep.last_session_pid, Some(pid), "should track PID");
assert_eq!(
sessions2, 1,
"should still be 1 session (same PID), got {sessions2}"
);
assert_eq!(
orig2, 2000,
"total_original should be 2000 (1000 + delta 1000), got {orig2}"
);
assert_eq!(
comp2, 1200,
"total_compressed should be 1200 (600 + delta 600), got {comp2}"
);
eprintln!("[CEP delta tracking] PASSED: no over-counting detected");
eprintln!(" Call 1: 1000/600 → totals 1000/600");
eprintln!(" Call 2: 2000/1200 → delta 1000/600 → totals 2000/1200");
eprintln!(" Without fix: totals would be 3000/1800 (1000+2000 / 600+1200)");
let _ = std::fs::remove_dir_all(&test_dir);
// TODO: Audit that the environment access only happens in single-threaded code.
unsafe { std::env::remove_var("LEAN_CTX_DATA_DIR") };
}
#[test]
#[ignore = "requires manual setup: git log -p -10 > /tmp/git_log_raw.txt"]
fn e2e_real_git_log_compression() {
let raw_path = "/tmp/git_log_raw.txt";
if !std::path::Path::new(raw_path).exists() {
eprintln!(
"[SKIP] /tmp/git_log_raw.txt not found — run: git log -p -10 > /tmp/git_log_raw.txt"
);
return;
}
let raw = std::fs::read_to_string(raw_path).unwrap();
let original = count_tokens(&raw);
let compressed = git::compress("git log -p -10", &raw).unwrap_or_else(|| raw.clone());
let compressed_tokens = count_tokens(&compressed);
let saved = original.saturating_sub(compressed_tokens);
let pct = if original > 0 {
saved as f64 / original as f64 * 100.0
} else {
0.0
};
eprintln!("\n=== E2E: Real git log -p -10 ===");
eprintln!("Raw: {} bytes, {} lines", raw.len(), raw.lines().count());
eprintln!("Original: {original} tokens");
eprintln!("Compressed: {compressed_tokens} tokens");
eprintln!("Saved: {saved} tokens ({pct:.1}%)");
eprintln!("\n=== Compressed output ===");
eprintln!("{}", compressed.chars().take(800).collect::<String>());
assert!(
pct > 80.0,
"real git log -p should save >80%, got {pct:.1}%"
);
}
#[test]
fn e2e_real_git_log_stat_compression() {
let raw = std::process::Command::new("git")
.args(["log", "--stat", "-20"])
.current_dir(env!("CARGO_MANIFEST_DIR"))
.output()
.ok()
.and_then(|o| String::from_utf8(o.stdout).ok())
.unwrap_or_default();
if raw.is_empty() {
eprintln!("[SKIP] could not run git log --stat");
return;
}
let original = count_tokens(&raw);
let compressed = git::compress("git log --stat", &raw).unwrap_or_else(|| raw.clone());
let compressed_tokens = count_tokens(&compressed);
let saved = original.saturating_sub(compressed_tokens);
let pct = if original > 0 {
saved as f64 / original as f64 * 100.0
} else {
0.0
};
eprintln!("\n=== E2E: Real git log --stat -20 ===");
eprintln!("Raw: {} bytes, {} lines", raw.len(), raw.lines().count());
eprintln!("Original: {original} tokens → Compressed: {compressed_tokens} tokens");
eprintln!("Saved: {saved} tokens ({pct:.1}%)");
eprintln!("\n=== Compressed output (first 500 chars) ===");
eprintln!("{}", compressed.chars().take(500).collect::<String>());
assert!(
pct > 60.0,
"real git log --stat should save >60%, got {pct:.1}%"
);
}
fn generate_git_log_patch(n: usize) -> String {
let mut output = String::new();
for i in 0..n {
let msg = format!("implement feature number {i} with improvements");
output.push_str(&format!(
"commit {i:07}abc1234567890abcdef1234567890\n\
Author: Developer <dev@example.com>\n\
Date: Mon Mar {d} 10:{h:02}:00 2026 +0100\n\
\n\
{ty}: {msg}\n\
\n\
diff --git a/src/module_{i}.rs b/src/module_{i}.rs\n\
index abc1234..def5678 100644\n\
--- a/src/module_{i}.rs\n\
+++ b/src/module_{i}.rs\n\
@@ -1,{ctx} +1,{ctx2} @@\n",
d = 10 + (i % 20),
h = i % 24,
ty = ["feat", "fix", "refactor", "docs", "test"][i % 5],
ctx = 10 + i,
ctx2 = 12 + i,
));
for j in 0..(5 + i % 10) {
output.push_str(&format!(" fn existing_function_{j}() {{}}\n"));
}
for j in 0..(3 + i % 5) {
output.push_str(&format!("+fn new_function_{i}_{j}() {{ todo!() }}\n"));
}
for j in 0..(2 + i % 3) {
output.push_str(&format!(
"-fn old_function_{i}_{j}() {{ unimplemented!() }}\n"
));
}
output.push('\n');
}
output
}
fn generate_git_log_stat(n: usize) -> String {
let mut output = String::new();
for i in 0..n {
let msg = format!("update module {i}");
output.push_str(&format!(
"commit {i:07}abc1234567890abcdef1234567890\n\
Author: Developer <dev@example.com>\n\
Date: Mon Mar {d} 10:{h:02}:00 2026 +0100\n\
\n\
{ty}: {msg}\n\
\n",
d = 10 + (i % 20),
h = i % 24,
ty = ["feat", "fix", "refactor", "docs", "test"][i % 5],
));
for j in 0..(2 + i % 4) {
let plus = 3 + j;
let minus = 1 + j;
let bar: String = "+".repeat(plus) + &"-".repeat(minus);
output.push_str(&format!(
" src/mod_{i}_{j}.rs | {total} {bar}\n",
total = plus + minus,
));
}
let total_files = 2 + i % 4;
output.push_str(&format!(
" {total_files} files changed, {} insertions(+), {} deletions(-)\n\n",
10 + i * 2,
5 + i,
));
}
output
}
/// End-to-end audit: trace the full savings pipeline for each tool
/// and verify that "original" and "saved" are fair comparisons.
#[test]
fn audit_full_savings_pipeline() {
use lean_ctx::core::cache::SessionCache;
use lean_ctx::core::tokens::count_tokens;
use lean_ctx::tools::CrpMode;
eprintln!("\n{}", "=".repeat(70));
eprintln!(" FULL SAVINGS PIPELINE AUDIT");
eprintln!("{}", "=".repeat(70));
// 1. ctx_read — first read in full mode: savings should be ~0
{
let mut cache = SessionCache::new();
let content = "use std::io;\nfn main() {\n println!(\"hello\");\n}\n";
let tmp = std::env::temp_dir().join("audit_test_file.rs");
std::fs::write(&tmp, content).unwrap();
let output = lean_ctx::tools::ctx_read::handle(
&mut cache,
tmp.to_str().unwrap(),
"full",
CrpMode::Off,
);
let file_tokens = count_tokens(content);
let output_tokens = count_tokens(&output);
let saved = file_tokens.saturating_sub(output_tokens);
eprintln!("\n ctx_read (first read, full mode):");
eprintln!(" file tokens: {file_tokens}");
eprintln!(" output tokens: {output_tokens}");
eprintln!(" saved: {saved}");
eprintln!(
" contains savings line: {}",
output.contains("tok saved")
);
assert!(
output_tokens >= file_tokens,
"first full read includes header, so output >= original: {output_tokens} vs {file_tokens}"
);
// 2. ctx_read — second read (cache hit): massive savings
let output2 = lean_ctx::tools::ctx_read::handle(
&mut cache,
tmp.to_str().unwrap(),
"full",
CrpMode::Off,
);
let output2_tokens = count_tokens(&output2);
let is_cache_hit =
output2.is_empty() || output2.contains("unchanged") || output2.contains("cached");
eprintln!("\n ctx_read (cache re-read):");
eprintln!(" file tokens: {file_tokens}");
eprintln!(" output tokens: {output2_tokens}");
eprintln!(" is_cache_hit: {is_cache_hit}");
eprintln!(" output: {output2:?}");
assert!(
is_cache_hit,
"second read should be a cache hit, got: {output2}"
);
assert!(
output2_tokens < 40,
"cache hit stub should be <40 tokens, got {output2_tokens}",
);
let _ = std::fs::remove_file(&tmp);
}
// 3. ctx_read — compressed mode (signatures): fair comparison
{
let mut cache = SessionCache::new();
let mut code = Vec::new();
code.push("use std::collections::HashMap;".to_string());
for i in 0..50 {
code.push(format!("pub fn handler_{i}(req: Request) -> Response {{"));
code.push(format!(
" let data = db.query(\"SELECT * FROM table_{i}\");"
));
code.push(
" let filtered = data.iter().filter(|r| r.active).collect::<Vec<_>>();"
.to_string(),
);
code.push(" let result = process_items(&filtered, req.params());".to_string());
code.push(" if result.is_err() { return Response::error(500); }".to_string());
code.push(" Response::json(result.unwrap())".to_string());
code.push("}".to_string());
code.push(String::new());
}
let content = code.join("\n");
let tmp = std::env::temp_dir().join("audit_test_sigs.rs");
std::fs::write(&tmp, &content).unwrap();
let output = lean_ctx::tools::ctx_read::handle(
&mut cache,
tmp.to_str().unwrap(),
"signatures",
CrpMode::Off,
);
let file_tokens = count_tokens(&content);
let output_tokens = count_tokens(&output);
let saved = file_tokens.saturating_sub(output_tokens);
let ratio = if file_tokens > 0 {
saved as f64 / file_tokens as f64 * 100.0
} else {
0.0
};
eprintln!("\n ctx_read (signatures mode, 50 multi-line fns):");
eprintln!(" file tokens: {file_tokens}");
eprintln!(" output tokens: {output_tokens}");
eprintln!(" savings: {saved} ({ratio:.1}%)");
assert!(
output_tokens < file_tokens,
"signatures should compress: {output_tokens} < {file_tokens}"
);
assert!(
ratio > 20.0 && ratio < 98.0,
"signatures savings should be 20-98%, got {ratio:.1}%"
);
let _ = std::fs::remove_file(&tmp);
}
// 4. ctx_tree — fair comparison (same depth)
{
let dir = env!("CARGO_MANIFEST_DIR");
let (output, raw_tokens) = lean_ctx::tools::ctx_tree::handle(dir, 2, false, true);
let compact_tokens = count_tokens(&output);
let savings = raw_tokens.saturating_sub(compact_tokens);
let ratio = if raw_tokens > 0 {
savings as f64 / raw_tokens as f64 * 100.0
} else {
0.0
};
eprintln!("\n ctx_tree (depth=2):");
eprintln!(" raw tokens: {raw_tokens}");
eprintln!(" compact tokens: {compact_tokens}");
eprintln!(" savings: {savings} ({ratio:.1}%)");
assert!(
raw_tokens < 3000,
"raw tree at depth 2 must be <3000 tokens, got {raw_tokens}"
);
assert!(
ratio < 80.0,
"tree savings ratio should be <80% for fair comparison, got {ratio:.1}%"
);
}
// 5. ctx_shell — real compression
{
let raw_output = generate_git_log_patch(10);
let original = count_tokens(&raw_output);
let compressed = lean_ctx::core::patterns::git::compress("git log -p", &raw_output)
.unwrap_or_else(|| raw_output.clone());
let compressed_tokens = count_tokens(&compressed);
let saved = original.saturating_sub(compressed_tokens);
let ratio = if original > 0 {
saved as f64 / original as f64 * 100.0
} else {
0.0
};
eprintln!("\n ctx_shell (git log -p, 10 commits):");
eprintln!(" raw tokens: {original}");
eprintln!(" compressed tokens: {compressed_tokens}");
eprintln!(" savings: {saved} ({ratio:.1}%)");
assert!(ratio > 70.0, "git log -p should save >70%, got {ratio:.1}%");
}
// 6. Verify tokenizer accuracy by cross-checking with known strings
{
let test_cases = [("hello world", 2), ("fn main() {}", 5), ("", 0), ("a", 1)];
eprintln!("\n Tokenizer (o200k_base) spot checks:");
for (text, expected_approx) in &test_cases {
let actual = count_tokens(text);
eprintln!(
" {text:?}{:width$}{actual:>3} tokens (expected ~{expected_approx})",
"",
width = 20_usize.saturating_sub(format!("{text:?}").len())
);
let diff = (actual as i64 - i64::from(*expected_approx)).unsigned_abs();
assert!(
diff <= 2,
"tokenizer off by >2 for {text:?}: got {actual}, expected ~{expected_approx}",
);
}
}
// 7. CostModel sanity check
{
let input_saved: u64 = 100_000;
let commands: u64 = 500;
let output_bonus = commands * 60;
let total_saved = input_saved + output_bonus;
let cost_per_m_input = 2.50_f64;
let cost_per_m_output = 10.0_f64;
let usd_input = input_saved as f64 / 1_000_000.0 * cost_per_m_input;
let usd_output = output_bonus as f64 / 1_000_000.0 * cost_per_m_output;
let usd_total = usd_input + usd_output;
eprintln!("\n CostModel sanity (100K input saved, 500 calls):");
eprintln!(" input saved: {input_saved} tok → ${usd_input:.4}");
eprintln!(" output bonus: {output_bonus} tok → ${usd_output:.4}");
eprintln!(" total: {total_saved} tok → ${usd_total:.4}");
assert!(
usd_total < 1.0,
"100K saved + 500 calls should be < $1.00, got ${usd_total:.4}"
);
assert!(usd_total > 0.0, "savings should be positive");
}
eprintln!("\n AUDIT COMPLETE — all checks passed");
eprintln!("{}\n", "=".repeat(70));
}
fn generate_git_log_standard(n: usize) -> String {
let mut output = String::new();
for i in 0..n {
let msg = format!("update component {i} with better error handling");
output.push_str(&format!(
"commit {i:07}abc1234567890abcdef1234567890\n\
Author: Developer <dev@example.com>\n\
Date: Mon Mar {d} 10:{h:02}:00 2026 +0100\n\
\n\
{ty}: {msg}\n\
\n\
This is a longer commit message that describes the changes made.\n\
It spans multiple lines to be more realistic.\n\
\n",
d = 10 + (i % 20),
h = i % 24,
ty = ["feat", "fix", "refactor", "docs", "test"][i % 5],
));
}
output
}