use super::*;
use crate::core::content_source::test_support::repo_content;
use crate::core::skill_deployer::deploy_skills;
use std::fs;
use tempfile::TempDir;
fn reference_of(pairs: &[(&str, &str)]) -> SkillReference {
SkillReference {
assets: pairs
.iter()
.map(|(s, c)| (s.to_string(), c.to_string()))
.collect(),
origin: "this binary's embedded bundled assets".to_string(),
}
}
fn deploy_real(dest: &Path, stem: &str, body: &str, reference: Option<(&str, &str)>) -> TempDir {
let src = TempDir::new().unwrap();
fs::write(src.path().join(format!("{stem}.md")), body).unwrap();
if let Some((ref_name, ref_body)) = reference {
let refs = src.path().join(stem).join("references");
fs::create_dir_all(&refs).unwrap();
fs::write(refs.join(ref_name), ref_body).unwrap();
}
deploy_skills(src.path(), dest).unwrap();
src
}
fn hand_edit(dest: &Path, manifest_key: &str, new_content: &str) {
let path = deployed_path(dest, manifest_key);
fs::write(path, new_content).unwrap();
}
#[test]
fn a_bundled_skill_absent_from_the_manifest_is_missing_at_the_roster_tier() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(dest.path(), "tm-workflow", "v1", None);
let reference = reference_of(&[("tm-workflow", "v1"), ("tm-prose-style", "brand new")]);
let audit = audit_deployed_skills_with_roster(&reference, dest.path(), true);
let finding = audit
.findings
.iter()
.find(|f| f.stem == "tm-prose-style")
.unwrap_or_else(|| panic!("no finding for the never-deployed skill: {audit:?}"));
assert_eq!(finding.state, SkillDrift::Missing);
assert!(
audit
.findings
.iter()
.any(|f| f.stem == "tm-workflow" && f.state == SkillDrift::Fresh),
"{audit:?}"
);
}
#[test]
fn a_bundled_skill_absent_is_not_a_finding_without_the_roster_flag() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(dest.path(), "tm-workflow", "v1", None);
let reference = reference_of(&[("tm-workflow", "v1"), ("tm-prose-style", "brand new")]);
let audit = audit_deployed_skills(&reference, dest.path());
assert!(
!audit.findings.iter().any(|f| f.stem == "tm-prose-style"),
"a tier that does not receive the roster must not report it missing: {audit:?}"
);
}
#[test]
fn the_roster_flag_adds_nothing_when_the_ledger_is_unreadable() {
let dest = TempDir::new().unwrap();
fs::write(dest.path().join(SKILL_MANIFEST_FILE), "{ not json").unwrap();
let reference = reference_of(&[("tm-prose-style", "brand new")]);
let audit = audit_deployed_skills_with_roster(&reference, dest.path(), true);
assert!(matches!(audit.manifest, ManifestState::Unreadable(_)));
assert!(audit.findings.is_empty(), "{audit:?}");
}
#[test]
fn reference_falls_back_to_embedded() {
let reference = skill_reference(None, Some(&repo_content()));
assert!(
reference.origin.contains("instructional content"),
"origin was: {}",
reference.origin
);
assert!(
reference.assets.contains_key("tm-workflow"),
"the content must carry tm-workflow"
);
}
#[test]
fn reference_without_content_names_tm_content_update() {
let reference = skill_reference(None, None);
assert!(reference.assets.is_empty());
assert!(
reference.origin.contains("run `tm content update`"),
"{}",
reference.origin
);
assert!(
reference
.origin
.contains("tm content install --from <dir>/<tag>.tar.gz"),
"{}",
reference.origin
);
}
#[test]
fn reference_includes_nested_reference_keys() {
let reference = skill_reference(None, Some(&repo_content()));
let nested: Vec<&String> = reference
.assets
.keys()
.filter(|k| k.contains('/'))
.collect();
assert!(
!nested.is_empty(),
"the embedded reference must carry `<stem>/references/<file>.md` keys; got only bare stems"
);
assert!(
nested
.iter()
.all(|k| k.contains("/references/") && k.ends_with(".md")),
"nested keys must match the deployer's key format, got: {nested:?}"
);
}
#[test]
fn a_pristine_bundled_deploy_is_entirely_fresh() {
let src = TempDir::new().unwrap();
for (rel_path, contents) in repo_content().skills() {
let rel = rel_path.strip_prefix("skills/").unwrap();
let path = src.path().join(rel);
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(&path, contents).unwrap();
}
let dest = TempDir::new().unwrap();
deploy_skills(src.path(), dest.path()).unwrap();
let audit = audit_deployed_skills(&skill_reference(None, Some(&repo_content())), dest.path());
assert_eq!(audit.manifest, ManifestState::Present);
let nested = audit
.findings
.iter()
.filter(|f| f.stem.contains('/'))
.count();
assert!(
nested > 0,
"the fixture must contain nested reference keys or it cannot prove anything"
);
let problems: Vec<&SkillDriftFinding> = audit
.findings
.iter()
.filter(|f| f.state.is_problem())
.collect();
assert!(
problems.is_empty(),
"a pristine bundled deploy must be entirely Fresh ({} findings, {nested} nested); \
unresolved: {problems:?}",
audit.findings.len()
);
}
#[test]
fn reference_prefers_the_submodule() {
let tmp = TempDir::new().unwrap();
fs::write(tmp.path().join("tm-workflow.md"), "submodule text").unwrap();
let refs = tmp.path().join("tm-workflow").join("references");
fs::create_dir_all(&refs).unwrap();
fs::write(refs.join("extra.md"), "submodule reference").unwrap();
let reference = skill_reference(Some(tmp.path()), Some(&repo_content()));
assert_eq!(
reference.assets.get("tm-workflow").unwrap(),
"submodule text"
);
assert_eq!(
reference
.assets
.get("tm-workflow/references/extra.md")
.unwrap(),
"submodule reference",
"the submodule reference must also carry nested keys"
);
assert!(
reference.origin.contains("submodule"),
"{}",
reference.origin
);
}
#[test]
fn empty_submodule_dir_falls_back_to_embedded() {
let tmp = TempDir::new().unwrap();
let reference = skill_reference(Some(tmp.path()), Some(&repo_content()));
assert!(
reference.origin.contains("instructional content"),
"{}",
reference.origin
);
}
#[test]
fn deployed_path_matches_the_deployer_layout() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(dest.path(), "tm-doctor", "v1", Some(("guide.md", "ref v1")));
assert!(deployed_path(dest.path(), "tm-doctor").exists());
assert!(deployed_path(dest.path(), "tm-doctor/references/guide.md").exists());
assert_eq!(
deployed_path(dest.path(), "tm-doctor"),
dest.path().join("tm-doctor").join("SKILL.md")
);
}
#[test]
fn stale_cache_no_longer_hides_drift() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(
dest.path(),
"tm-workflow",
"v1 mentions PM_INSTRUCTIONS.md",
None,
);
let reference = reference_of(&[("tm-workflow", "v2 describes the JSON manifest")]);
let audit = audit_deployed_skills(&reference, dest.path());
assert_eq!(audit.findings.len(), 1);
assert_eq!(audit.findings[0].stem, "tm-workflow");
assert_eq!(
audit.findings[0].state,
SkillDrift::Drifted,
"the drifted skill the old check reported clean must now be caught"
);
}
#[test]
fn the_old_cache_comparison_reports_clean_on_the_same_inputs() {
let dest = TempDir::new().unwrap();
let cache = TempDir::new().unwrap();
let _src = deploy_real(
dest.path(),
"tm-workflow",
"v1 mentions PM_INSTRUCTIONS.md",
None,
);
fs::write(
cache.path().join("tm-workflow.md"),
"v1 mentions PM_INSTRUCTIONS.md",
)
.unwrap();
let old = crate::core::skill_staleness::stale_skills(cache.path(), dest.path()).unwrap();
println!("OLD (cache vs manifest) -> {old:?}");
let reference = reference_of(&[("tm-workflow", "v2 describes the JSON manifest")]);
let new = audit_deployed_skills(&reference, dest.path());
println!("NEW (deployed file vs binary) -> {:?}", new.findings);
assert!(
old.is_empty(),
"the pre-#4604 comparison is expected to MISS this drift; if it no longer \
does, this proof needs rewriting: {old:?}"
);
assert_eq!(new.findings[0].state, SkillDrift::Drifted);
}
#[test]
fn a_real_deploy_with_reference_files_is_fresh() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(
dest.path(),
"documentation-style",
"entry v1",
Some(("spec.md", "reference v1")),
);
let reference = reference_of(&[
("documentation-style", "entry v1"),
("documentation-style/references/spec.md", "reference v1"),
]);
let audit = audit_deployed_skills(&reference, dest.path());
assert_eq!(
audit.findings.len(),
2,
"both the entry point and its reference sibling must be audited: {:?}",
audit.findings
);
assert!(
audit.findings.iter().all(|f| f.state == SkillDrift::Fresh),
"a freshly deployed multi-file skill must be entirely Fresh, got: {:?}",
audit.findings
);
}
#[test]
fn drift_in_a_reference_file_is_caught() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(
dest.path(),
"documentation-style",
"entry v1",
Some(("spec.md", "reference v1")),
);
let reference = reference_of(&[
("documentation-style", "entry v1"),
("documentation-style/references/spec.md", "reference v2"),
]);
let audit = audit_deployed_skills(&reference, dest.path());
let drifted: Vec<&SkillDriftFinding> = audit
.findings
.iter()
.filter(|f| f.state == SkillDrift::Drifted)
.collect();
assert_eq!(drifted.len(), 1, "findings: {:?}", audit.findings);
assert_eq!(drifted[0].stem, "documentation-style/references/spec.md");
}
#[test]
fn matching_deploy_is_fresh() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(dest.path(), "tm-workflow", "v2", None);
let reference = reference_of(&[("tm-workflow", "v2")]);
let audit = audit_deployed_skills(&reference, dest.path());
assert_eq!(audit.findings[0].state, SkillDrift::Fresh);
assert!(!audit.findings[0].state.is_problem());
}
#[test]
fn hand_edited_deploy_is_frozen_not_merely_drifted() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(dest.path(), "tm-ticketing", "v1 as deployed", None);
hand_edit(dest.path(), "tm-ticketing", "hand-edited by the operator");
let reference = reference_of(&[("tm-ticketing", "v2 from the binary")]);
let audit = audit_deployed_skills(&reference, dest.path());
assert_eq!(audit.findings[0].state, SkillDrift::DriftedFrozen);
}
#[test]
fn missing_deployed_file_is_reported() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(dest.path(), "tm-doctor", "v1", None);
fs::remove_file(deployed_path(dest.path(), "tm-doctor")).unwrap();
let reference = reference_of(&[("tm-doctor", "v1")]);
let audit = audit_deployed_skills(&reference, dest.path());
assert_eq!(audit.findings[0].state, SkillDrift::Missing);
}
#[test]
fn skill_absent_from_the_binary_is_unverifiable_not_fresh() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(dest.path(), "my-custom-skill", "anything", None);
let reference = reference_of(&[("tm-workflow", "v2")]);
let audit = audit_deployed_skills(&reference, dest.path());
assert!(
matches!(audit.findings[0].state, SkillDrift::Unverifiable(_)),
"got {:?}",
audit.findings[0].state
);
assert!(audit.findings[0].state.is_problem());
}
#[test]
fn nothing_deployed_yields_no_findings() {
let dest = TempDir::new().unwrap();
let reference = reference_of(&[("tm-workflow", "v2")]);
let audit = audit_deployed_skills(&reference, dest.path());
assert!(audit.findings.is_empty());
assert_eq!(audit.manifest, ManifestState::AbsentAndEmpty);
}
#[test]
fn absent_manifest_over_deployed_skills_is_unknown() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(dest.path(), "tm-workflow", "v1", None);
fs::remove_file(
dest.path()
.join(crate::core::skill_manifest::SKILL_MANIFEST_FILE),
)
.unwrap();
let audit = audit_deployed_skills(&reference_of(&[("tm-workflow", "v1")]), dest.path());
assert_eq!(
audit.manifest,
ManifestState::AbsentButPopulated,
"skills on disk with no ownership ledger cannot be verified"
);
}
#[test]
fn corrupt_manifest_is_unknown_not_empty() {
let dest = TempDir::new().unwrap();
let _src = deploy_real(dest.path(), "tm-workflow", "v1", None);
fs::write(
dest.path()
.join(crate::core::skill_manifest::SKILL_MANIFEST_FILE),
"{ not json",
)
.unwrap();
let audit = audit_deployed_skills(&reference_of(&[("tm-workflow", "v1")]), dest.path());
assert!(
matches!(audit.manifest, ManifestState::Unreadable(_)),
"got {:?}",
audit.manifest
);
assert!(audit.findings.is_empty());
}
#[test]
fn drift_states_report_not_fresh() {
assert!(!SkillDrift::Fresh.is_problem());
assert!(SkillDrift::Drifted.is_problem());
assert!(SkillDrift::DriftedFrozen.is_problem());
assert!(SkillDrift::Missing.is_problem());
assert!(SkillDrift::Unverifiable("x".into()).is_problem());
}
#[test]
fn a_lock_sidecar_alone_is_not_a_populated_tier() {
let dest = TempDir::new().unwrap();
fs::write(
crate::core::skill_manifest::skill_manifest_lock_path(dest.path()),
"",
)
.unwrap();
let audit = audit_deployed_skills(&reference_of(&[("tm-workflow", "v1")]), dest.path());
assert_eq!(
audit.manifest,
ManifestState::AbsentAndEmpty,
"a tier holding only the lock sidecar was never deployed to"
);
}