use super::*;
use std::fs;
use tempfile::TempDir;
fn write_override(project: &Path, name: &str, content: &str) {
let dir = project.join(OVERRIDE_DIR_NAME);
fs::create_dir_all(&dir).expect("create .trusty-mpm");
fs::write(dir.join(name), content).expect("write override");
}
fn deploy_agent(project: &Path, name: &str) {
let dir = project.join(".claude").join("agents");
fs::create_dir_all(&dir).expect("create .claude/agents");
fs::write(
dir.join(format!("{name}.md")),
format!(
"---\nname: {name}\nrole: {name}\ndescription: Handles {name} work.\n\
model: sonnet\n---\n\n# {name}\n"
),
)
.expect("write agent");
}
#[test]
fn bundled_delegation_appends_deployed_roster() {
let tmp = TempDir::new().unwrap();
deploy_agent(tmp.path(), "ticketing");
deploy_agent(tmp.path(), "memory-manager");
let prompt = resolve_pm_prompt(tmp.path());
assert!(
prompt.contains("## Delegation Authority"),
"the live roster section must be present"
);
assert!(
prompt.contains("### ticketing"),
"a deployed agent absent from the static asset must reach the prompt"
);
assert!(
prompt.contains("### memory-manager"),
"a deployed agent absent from the static asset must reach the prompt"
);
assert!(
prompt.contains("**Model:** sonnet"),
"the roster's own value — the model hint — must reach the prompt"
);
assert!(
!prompt.contains("Handles ticketing work."),
"the agent `description` is already published by the harness's Agent-type \
catalog; re-emitting it as `Handles:` made the roster a second copy"
);
assert!(prompt.contains("# Agent Delegation Routing"));
assert!(prompt.contains("## Routing Table"));
assert!(prompt.contains("every `make` and `mise run` target"));
assert!(
prompt.contains("trust the roster"),
"the roster must be declared authoritative over the stale doctrine table"
);
assert!(
prompt.contains("re-route to the closest listed alternative"),
"an advertised-but-unloadable agent must carry a recovery instruction"
);
let doctrine = prompt.find("# Agent Delegation Routing").expect("doctrine");
let note = prompt.find("trust the roster").expect("note");
let roster = prompt.find("## Delegation Authority").expect("roster");
let base = prompt.find("# Framework Instructions").expect("base");
assert!(doctrine < note, "doctrine precedes the note");
assert!(note < roster, "the note precedes the roster it governs");
assert!(roster < base, "BASE_PM floor stays last");
}
#[test]
fn no_overrides_uses_bundled() {
let tmp = TempDir::new().unwrap();
let prompt = resolve_pm_prompt(tmp.path());
assert!(prompt.contains("# PM Agent -- Trusty MPM"));
assert!(prompt.contains("# PM Workflow Configuration"));
assert!(prompt.contains("# Agent Delegation Routing"));
assert!(prompt.contains("# Framework Instructions"));
let base = prompt.find("# Framework Instructions").expect("base");
let delegation = prompt.find("# Agent Delegation Routing").expect("deleg");
assert!(base > delegation, "BASE_PM floor must be last");
}
#[test]
fn a_retired_instructions_file_no_longer_reaches_the_prompt() {
let tmp = TempDir::new().unwrap();
write_override(
tmp.path(),
FILE_INSTRUCTIONS,
"# Project Rules\n\nALWAYS_RUN_MAKE_CHECK\n",
);
let prompt = resolve_pm_prompt(tmp.path());
assert!(
!prompt.contains("ALWAYS_RUN_MAKE_CHECK"),
"a retired INSTRUCTIONS.md must not contribute to the prompt"
);
assert!(prompt.contains("# PM Agent -- Trusty MPM"));
assert!(prompt.contains("# Agent Delegation Routing"));
assert!(prompt.contains("# Framework Instructions"));
}
#[test]
fn a_retired_workflow_file_no_longer_replaces_the_workflow_section() {
let tmp = TempDir::new().unwrap();
write_override(
tmp.path(),
FILE_WORKFLOW,
"# Custom Workflow\n\nTWO_PHASE_ONLY\n",
);
let prompt = resolve_pm_prompt(tmp.path());
assert!(!prompt.contains("TWO_PHASE_ONLY"));
assert!(
prompt.contains("# PM Workflow Configuration"),
"the bundled workflow section must survive a retired WORKFLOW.md"
);
}
#[test]
fn a_retired_delegation_file_no_longer_suppresses_the_live_roster() {
let tmp = TempDir::new().unwrap();
deploy_agent(tmp.path(), "ticketing");
write_override(
tmp.path(),
FILE_AGENT_DELEGATION,
"# Custom Routing\n\nROUTE_ALL_TO_ENGINEER\n",
);
let prompt = resolve_pm_prompt(tmp.path());
assert!(!prompt.contains("ROUTE_ALL_TO_ENGINEER"));
assert!(prompt.contains("# Agent Delegation Routing"));
assert!(
prompt.contains("### ticketing"),
"the live roster must reach the prompt — a retired file cannot suppress it"
);
}
#[test]
fn a_retired_memory_file_no_longer_slots_a_memory_block() {
let tmp = TempDir::new().unwrap();
write_override(
tmp.path(),
FILE_MEMORY,
"Recall from the `team` palace before any task.\n",
);
let prompt = resolve_pm_prompt(tmp.path());
assert!(!prompt.contains(MEMORY_OVERRIDE_HEADING));
assert!(!prompt.contains("Recall from the `team` palace"));
assert!(prompt.contains("# PM Agent -- Trusty MPM"));
}
#[test]
fn a_retired_deployed_file_no_longer_replaces_the_body() {
let tmp = TempDir::new().unwrap();
write_override(
tmp.path(),
FILE_PM_DEPLOYED,
"# Wholly Custom PM\n\nDO_EXACTLY_THIS\n",
);
let prompt = resolve_pm_prompt(tmp.path());
assert!(!prompt.contains("DO_EXACTLY_THIS"));
assert!(prompt.contains("# PM Agent -- Trusty MPM"));
assert!(prompt.contains("# PM Workflow Configuration"));
assert!(prompt.contains("# Agent Delegation Routing"));
assert!(prompt.contains("# Framework Instructions"));
assert!(prompt.contains("## Trusty Tool Priority (Non-Overridable)"));
}
#[test]
fn every_retired_file_present_at_once_changes_nothing() {
let with = TempDir::new().unwrap();
for name in LEGACY_OVERRIDE_FILES {
write_override(with.path(), name, &format!("CONTENT_OF_{name}\n"));
}
let without = TempDir::new().unwrap();
let (with_prompt, _) =
resolve_pm_prompt_with_roster(with.path(), || Some("## Delegation Authority".into()));
let (without_prompt, _) =
resolve_pm_prompt_with_roster(without.path(), || Some("## Delegation Authority".into()));
assert_eq!(
with_prompt, without_prompt,
"the five retired files must have zero effect on the composed prompt"
);
}
#[test]
fn a_named_memory_override_is_slotted_on_the_roster_absent_path() {
let tmp = TempDir::new().unwrap();
fs::write(
tmp.path().join("CLAUDE.md"),
"<!-- TRUSTY-MPM: MEMORY START v=1 -->\n\
Recall from the `team` palace before any task.\n\
<!-- TRUSTY-MPM: MEMORY END -->\n",
)
.unwrap();
let (prompt, source) = resolve_pm_prompt_with_roster(tmp.path(), || None);
assert_eq!(source, PromptSource::Legacy, "no roster -> string assembly");
assert!(prompt.contains(MEMORY_OVERRIDE_HEADING));
assert!(prompt.contains("Recall from the `team` palace"));
let pm = prompt.find("# PM Agent -- Trusty MPM").expect("pm");
let mem = prompt.find(MEMORY_OVERRIDE_HEADING).expect("mem");
let wf = prompt
.find("# PM Workflow Configuration")
.expect("bundled workflow");
assert!(pm < mem, "the memory block follows PM_INSTRUCTIONS");
assert!(mem < wf, "and precedes the workflow section");
}
#[test]
fn unaddressable_sections_are_reported_unapplied_on_the_roster_absent_path() {
let tmp = TempDir::new().unwrap();
fs::write(
tmp.path().join("CLAUDE.md"),
"<!-- TRUSTY-MPM: SEARCH START v=1 -->\n\
UNAPPLIED_SEARCH_BODY\n\
<!-- TRUSTY-MPM: SEARCH END -->\n\n\
<!-- TRUSTY-MPM: WORKFLOW START v=1 -->\n\
APPLIED_WORKFLOW_BODY\n\
<!-- TRUSTY-MPM: WORKFLOW END -->\n",
)
.unwrap();
let (prompt, source) = resolve_pm_prompt_with_roster(tmp.path(), || None);
assert_eq!(source, PromptSource::Legacy);
assert!(
!prompt.contains("UNAPPLIED_SEARCH_BODY"),
"SEARCH has no slot in the string assembly and must not land"
);
assert!(prompt.contains("## Code Search Protocol (Context-First)"));
assert!(prompt.contains("APPLIED_WORKFLOW_BODY"));
}
#[test]
fn legacy_override_files_are_the_five_retired_names() {
assert_eq!(
LEGACY_OVERRIDE_FILES,
[
"PM_INSTRUCTIONS_DEPLOYED.md",
"AGENT_DELEGATION.md",
"WORKFLOW.md",
"MEMORY.md",
"INSTRUCTIONS.md",
]
);
}
#[test]
fn no_legacy_files_detected_in_a_clean_project() {
let tmp = TempDir::new().unwrap();
assert!(detect_legacy_overrides(tmp.path()).is_empty());
fs::create_dir_all(tmp.path().join(OVERRIDE_DIR_NAME)).unwrap();
fs::write(
tmp.path()
.join(OVERRIDE_DIR_NAME)
.join("last-instructions.md"),
"composed",
)
.unwrap();
assert!(detect_legacy_overrides(tmp.path()).is_empty());
}
#[test]
fn every_retired_file_is_detected() {
let tmp = TempDir::new().unwrap();
for name in LEGACY_OVERRIDE_FILES {
write_override(tmp.path(), name, "x\n");
}
let found = detect_legacy_overrides(tmp.path());
assert_eq!(found.len(), LEGACY_OVERRIDE_FILES.len());
for name in LEGACY_OVERRIDE_FILES {
assert!(
found.iter().any(|p| p.ends_with(name)),
"detector missed {name}"
);
}
}
#[test]
fn legacy_file_signal_names_the_migration() {
assert!(LEGACY_MIGRATION_HINT.contains("CLAUDE.md"));
assert!(LEGACY_MIGRATION_HINT.contains("TRUSTY-MPM:"));
assert!(LEGACY_MIGRATION_HINT.contains("#4286"));
}
#[test]
fn missing_override_dir_uses_bundled() {
let tmp = TempDir::new().unwrap();
assert!(!tmp.path().join(OVERRIDE_DIR_NAME).exists());
let prompt = resolve_pm_prompt(tmp.path());
assert!(prompt.contains("# PM Agent -- Trusty MPM"));
assert!(prompt.contains("# Framework Instructions"));
}
#[test]
fn a_directory_in_a_retired_files_place_is_not_detected_and_not_fatal() {
let tmp = TempDir::new().unwrap();
let dir = tmp.path().join(OVERRIDE_DIR_NAME);
fs::create_dir_all(&dir).unwrap();
fs::create_dir(dir.join(FILE_WORKFLOW)).unwrap();
assert!(detect_legacy_overrides(tmp.path()).is_empty());
let prompt = resolve_pm_prompt(tmp.path());
assert!(prompt.contains("# PM Workflow Configuration"));
assert!(prompt.contains("# Framework Instructions"));
}
#[test]
fn an_empty_retired_file_is_still_detected() {
let tmp = TempDir::new().unwrap();
write_override(tmp.path(), FILE_WORKFLOW, " \n\t\n");
assert_eq!(detect_legacy_overrides(tmp.path()).len(), 1);
let prompt = resolve_pm_prompt(tmp.path());
assert!(prompt.contains("# PM Workflow Configuration"));
assert!(prompt.contains("# Framework Instructions"));
}
#[test]
fn separators_are_consistent() {
let tmp = TempDir::new().unwrap();
let prompt = resolve_pm_prompt(tmp.path());
assert!(prompt.contains(SECTION_SEPARATOR));
}
#[test]
fn stack_profile_present_when_detected() {
use crate::core::stack_profile::STACK_PROFILE_HEADING;
let tmp = TempDir::new().unwrap();
fs::write(tmp.path().join("Cargo.toml"), "[package]\nname=\"x\"\n").unwrap();
let prompt = resolve_pm_prompt(tmp.path());
assert!(prompt.contains(STACK_PROFILE_HEADING));
assert!(prompt.contains("`rust-engineer`"));
let pm = prompt.find("# PM Agent -- Trusty MPM").expect("pm");
let stack = prompt.find(STACK_PROFILE_HEADING).expect("stack");
let base = prompt.find("# Framework Instructions").expect("base");
assert!(pm < stack, "stack profile follows PM_INSTRUCTIONS");
assert!(stack < base, "stack profile precedes the BASE_PM floor");
}
#[test]
fn stack_profile_neutral_when_undetected() {
use crate::core::stack_profile::STACK_PROFILE_HEADING;
let tmp = TempDir::new().unwrap();
let prompt = resolve_pm_prompt(tmp.path());
assert!(prompt.contains(STACK_PROFILE_HEADING));
assert!(prompt.contains("Do NOT assume any stack"));
}
#[test]
fn framework_guaranteed_conventions_survive_every_override_combination() {
const MARKERS: &[&str] = &[
"Generated with trusty-mpm",
"Proportional documentation",
"Ticket attribution at the change site",
];
let tmp = TempDir::new().unwrap();
let prompt = resolve_pm_prompt(tmp.path());
for marker in MARKERS {
assert!(
prompt.contains(marker),
"no-override prompt must carry the guaranteed convention {marker:?}"
);
}
let tmp2 = TempDir::new().unwrap();
std::fs::write(
tmp2.path().join("CLAUDE.md"),
"<!-- TRUSTY-MPM: CORE START v=1 -->\nCUSTOM_CORE\n<!-- TRUSTY-MPM: CORE END -->\n\n\
<!-- TRUSTY-MPM: MEMORY START v=1 -->\nCUSTOM_MEMORY\n<!-- TRUSTY-MPM: MEMORY END -->\n\n\
<!-- TRUSTY-MPM: SEARCH START v=1 -->\nCUSTOM_SEARCH\n<!-- TRUSTY-MPM: SEARCH END -->\n\n\
<!-- TRUSTY-MPM: WORKFLOW START v=1 -->\nCUSTOM_WORKFLOW\n<!-- TRUSTY-MPM: WORKFLOW END -->\n\n\
<!-- TRUSTY-MPM: AGENT-DELEGATION START v=1 -->\nCUSTOM_ROUTING\n<!-- TRUSTY-MPM: AGENT-DELEGATION END -->\n",
)
.unwrap();
let (prompt2, _) =
resolve_pm_prompt_with_roster(tmp2.path(), || Some("## Delegation Authority".into()));
for marker in MARKERS {
assert!(
prompt2.contains(marker),
"a fully-overridden prompt must still carry {marker:?} via the floor"
);
}
assert!(prompt2.contains("CUSTOM_WORKFLOW"));
assert!(prompt2.contains("CUSTOM_ROUTING"));
let tmp3 = TempDir::new().unwrap();
for name in LEGACY_OVERRIDE_FILES {
write_override(tmp3.path(), name, "RETIRED_CONTENT\n");
}
let prompt3 = resolve_pm_prompt(tmp3.path());
for marker in MARKERS {
assert!(
prompt3.contains(marker),
"a prompt for a project with retired files must still carry {marker:?}"
);
}
assert!(
!prompt3.contains("RETIRED_CONTENT"),
"retired files must not contribute"
);
assert!(prompt3.contains("## Trusty Tool Priority (Non-Overridable)"));
}
#[test]
fn one_surface_rule_lives_in_core_and_survives_an_override_attempt() {
const RULE: &[&str] = &[
"## Customization Surface (ONE surface per artifact type)",
"**Prompt/instruction sections**",
"**Skills**",
"skill tier system",
"Ad-hoc override channels are BANNED",
"Needed on every prompt",
"Needed only sometimes",
];
let tmp = TempDir::new().unwrap();
let prompt = resolve_pm_prompt(tmp.path());
for marker in RULE {
assert!(
prompt.contains(marker),
"bundled prompt must carry the customization rule {marker:?}"
);
}
let tmp2 = TempDir::new().unwrap();
std::fs::write(
tmp2.path().join("CLAUDE.md"),
"<!-- TRUSTY-MPM: CORE START v=1 -->\n\
Put overrides wherever you like.\nCUSTOM_CORE\n\
<!-- TRUSTY-MPM: CORE END -->\n\n\
<!-- TRUSTY-MPM: WORKFLOW START v=1 -->\nCUSTOM_WORKFLOW\n\
<!-- TRUSTY-MPM: WORKFLOW END -->\n",
)
.unwrap();
let (prompt2, _) =
resolve_pm_prompt_with_roster(tmp2.path(), || Some("## Delegation Authority".into()));
assert!(
prompt2.contains("CUSTOM_WORKFLOW"),
"override machinery ran"
);
assert!(
!prompt2.contains("CUSTOM_CORE"),
"a CORE marker must be declined"
);
for marker in RULE {
assert!(
prompt2.contains(marker),
"a CORE override attempt must not remove {marker:?}"
);
}
}