use ski::config::Config;
use ski::embed::bow::BowEmbedder;
use ski::embed::{EmbedKind, Embedder};
use ski::{index, rank, skill};
use std::fs;
use std::path::PathBuf;
fn write_skill(root: &std::path::Path, name: &str, desc: &str) {
let dir = root.join(name);
fs::create_dir_all(&dir).unwrap();
fs::write(
dir.join("SKILL.md"),
format!("---\nname: {name}\ndescription: {desc}\n---\nbody\n"),
)
.unwrap();
}
fn temp_root(label: &str) -> PathBuf {
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_nanos())
.unwrap_or(0);
let d = std::env::temp_dir().join(format!(
"ski-phrase-it-{}-{label}-{nanos}",
std::process::id()
));
let _ = fs::remove_dir_all(&d);
fs::create_dir_all(&d).unwrap();
d
}
fn rank_with(root: &std::path::Path, prompt: &str, phrase_boost: f32) -> Vec<rank::Hit> {
let cfg = Config {
roots: vec![root.to_path_buf()],
phrase_boost,
..Default::default()
};
let skills = skill::discover(&cfg.roots).expect("discover");
let embedder = BowEmbedder::new();
let idx = index::build(&skills, &embedder, None).expect("index");
let query = embedder
.embed(&[prompt.to_string()], EmbedKind::Query)
.unwrap()
.remove(0);
rank::rank_all(&query, prompt, &idx, &cfg)
}
fn rank(root: &std::path::Path, prompt: &str) -> Vec<rank::Hit> {
rank_with(root, prompt, Config::default().phrase_boost)
}
#[test]
fn trigger_phrase_lifts_its_skill_and_stays_silent_elsewhere() {
let root = temp_root("trigger");
write_skill(
&root,
"web-search",
"Search the public internet for information. Use when the user says \"find that page online\" or wants current facts.",
);
write_skill(
&root,
"git-attribution",
"Credit AI assistance in git commits following the kernel policy.",
);
let hits = rank(&root, "can you find that page online for me");
let ws = hits
.iter()
.find(|h| h.id == "web-search")
.expect("web-search ranked");
assert!(
ws.phrase > 0.0,
"phrase channel did not fire on the exact trigger: {ws:?}"
);
assert_eq!(hits[0].id, "web-search", "trigger prompt: {hits:?}");
let hits = rank(&root, "take my service online and deploy it");
let ws = hits.iter().find(|h| h.id == "web-search").unwrap();
assert_eq!(
ws.phrase, 0.0,
"phrase channel false-fired on partial overlap: {ws:?}"
);
let _ = fs::remove_dir_all(&root);
}
#[test]
fn phrase_channel_lifts_true_positive_without_lifting_false_positive() {
let root = temp_root("ab");
write_skill(
&root,
"accessibility",
"Make web UIs usable by everyone. Use when the user asks to \"add screen reader support\" or audit contrast.",
);
write_skill(
&root,
"pdf-tools",
"Read and assemble PDF files. Use to \"merge several pdf documents\" or extract pages.",
);
let trigger = "please add screen reader support to my signup form";
let on = rank_with(&root, trigger, 0.20);
let off = rank_with(&root, trigger, 0.0);
let on_a = on.iter().find(|h| h.id == "accessibility").unwrap();
let off_a = off.iter().find(|h| h.id == "accessibility").unwrap();
assert!(
on_a.score > off_a.score,
"phrase channel did not lift the true positive: on={on_a:?} off={off_a:?}"
);
assert_eq!(on[0].id, "accessibility");
let neg = "my laptop screen flickers and tech support was no help";
for h in rank_with(&root, neg, 0.20) {
assert_eq!(
h.phrase, 0.0,
"phrase fired on a partial-overlap negative: {h:?}"
);
}
let _ = fs::remove_dir_all(&root);
}