use super::*;
use tempfile::TempDir;
fn write_profile(dir: &Path, filename: &str, contents: &str) {
std::fs::create_dir_all(dir).unwrap();
std::fs::write(dir.join(filename), contents).unwrap();
}
#[test]
fn workspace_shadow_of_personal_file_is_recorded_and_reported() {
let tmp = TempDir::new().unwrap();
let personal_dir = tmp.path().join("personal");
let workspace = tmp.path().join("workspace");
std::fs::create_dir_all(&workspace).unwrap();
write_profile(
&personal_dir,
"builder.toml",
"id = \"builder\"\nrole_hint = \"builder\"\nmodel = \"deepseek-v4-flash\"\n",
);
write_profile(
&workspace.join(".codewhale").join("agents"),
"builder.toml",
"id = \"builder\"\nrole_hint = \"builder\"\nmodel = \"deepseek-v4-pro\"\n",
);
let roster = FleetRoster::load_with_personal_dir(
&FleetConfigToml::default(),
&workspace,
Some(&personal_dir),
true,
);
let builder = roster.get("builder").expect("builder member");
assert_eq!(builder.origin, ProfileOrigin::Workspace);
let shadows: Vec<_> = roster.shadowed_for("builder").collect();
assert_eq!(shadows.len(), 2, "full shadow chain: {shadows:?}");
let shadow = shadows
.iter()
.find(|shadow| shadow.shadowed_origin == ProfileOrigin::Personal)
.expect("personal file shadow is recorded");
assert!(shadow.shadowed_source.ends_with("builder.toml"));
assert_eq!(shadow.winner_origin, ProfileOrigin::Workspace);
assert!(
shadows
.iter()
.any(|shadow| shadow.shadowed_origin == ProfileOrigin::BuiltIn),
"the built-in displacement is recorded too: {shadows:?}"
);
assert!(
roster.shadowed().iter().any(|s| s.id == "builder"),
"roster-level shadow log carries the record"
);
}
#[test]
fn project_scope_profiles_are_skipped_when_the_layer_is_not_trusted() {
let tmp = TempDir::new().unwrap();
let workspace = tmp.path().join("workspace");
write_profile(
&workspace.join(".codewhale").join("agents"),
"builder.toml",
"id = \"builder\"\nrole_hint = \"builder\"\nmodel = \"gpt-5.6-luna\"\n",
);
let gated =
FleetRoster::load_with_personal_dir(&FleetConfigToml::default(), &workspace, None, false);
let builder = gated.get("builder").expect("built-in builder remains");
assert_eq!(
builder.origin,
ProfileOrigin::BuiltIn,
"untrusted project profile must not join the roster"
);
assert_ne!(
builder.profile.model.as_deref(),
Some("gpt-5.6-luna"),
"foreign project pin must not reach dispatch"
);
let trusted =
FleetRoster::load_with_personal_dir(&FleetConfigToml::default(), &workspace, None, true);
assert_eq!(
trusted.get("builder").expect("builder").origin,
ProfileOrigin::Workspace,
"trusted project profile wins as before"
);
}