use assert_cmd::Command;
use std::fs;
use std::path::Path;
use std::time::{Duration, Instant};
const MANIFEST: &str = r#"
version = 1
canonical = "json-schema-2020-12"
authoring = "zod"
[[contracts]]
name = "user"
source = "contracts/user.zod.ts"
emit = ["zod"]
[[mappings]]
glob = "app/api/**/*.ts"
contracts = ["user"]
require = "boundary-validation"
[gates]
protected_paths = ["pushkin.toml"]
"#;
const NONCONFORMING: &str = "export async function POST(req: Request) {\n\
const body = await req.json();\n\
return Response.json({ name: body.name });\n\
}\n";
const HANDLER_PATH: &str = "app/api/users/route.ts";
const SAMPLES: usize = 30;
const BUDGET_MS: f64 = 100.0;
fn payload() -> String {
serde_json::json!({
"session_id": "bench-session",
"tool_name": "Write",
"tool_input": { "file_path": HANDLER_PATH, "content": NONCONFORMING }
})
.to_string()
}
fn hook_once(dir: &Path) -> Result<Duration, String> {
let mut command = Command::cargo_bin("pushkin").map_err(|e| format!("binary resolves: {e}"))?;
let started = Instant::now();
let output = command
.current_dir(dir)
.args(["hook", "claude"])
.write_stdin(payload())
.output()
.map_err(|e| format!("hook run: {e}"))?;
let elapsed = started.elapsed();
if output.status.code() != Some(0) {
return Err(format!("hook exited {:?}", output.status.code()));
}
Ok(elapsed)
}
#[test]
#[ignore = "latency gate: run release-mode in CI (--ignored)"]
fn bench_warm_per_file_check_under_100ms() {
let dir = tempfile::tempdir().unwrap();
fs::write(dir.path().join("pushkin.toml"), MANIFEST).unwrap();
let (code, _, stderr) = {
let mut command = Command::cargo_bin("pushkin").unwrap();
let output = command
.current_dir(dir.path())
.args(["daemon", "start"])
.output()
.unwrap();
(
output.status.code().unwrap_or(-1),
String::from_utf8_lossy(&output.stdout).into_owned(),
String::from_utf8_lossy(&output.stderr).into_owned(),
)
};
assert_eq!(code, 0, "daemon start failed: {stderr}");
hook_once(dir.path()).unwrap();
let mut samples_ms: Vec<f64> = (0..SAMPLES)
.map(|_| hook_once(dir.path()).unwrap().as_secs_f64() * 1000.0)
.collect();
samples_ms.sort_by(|a, b| a.partial_cmp(b).expect("no NaN"));
let p50 = samples_ms[SAMPLES / 2];
let p95 = samples_ms[(SAMPLES * 95).div_ceil(100) - 1];
println!("warm hook round trip over {SAMPLES} samples: p50 {p50:.1}ms, p95 {p95:.1}ms");
let _ = Command::cargo_bin("pushkin")
.unwrap()
.current_dir(dir.path())
.args(["daemon", "stop"])
.output();
assert!(
p95 < BUDGET_MS,
"warm per-file check p95 {p95:.1}ms exceeds the {BUDGET_MS}ms budget \
(spec §8.1; charter §C.3 fails the build on regression)"
);
}