use super::*;
use crate::core::content_source::test_support::rc;
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(rc(), tmp.path());
assert!(
prompt.contains("## Delegation Authority"),
"the live roster section must be present"
);
let harness_published = crate::core::delegation_authority::roster_from_dirs(
&crate::core::delegation_authority::harness_loaded_agent_dirs(tmp.path()),
)
.len();
assert!(
harness_published >= 2,
"the two deployed agents must be in the harness-loaded union"
);
assert!(
prompt.contains(&format!("the {harness_published} agents it carries")),
"the live scan must account for both deployed agents (#4069, #4513)"
);
assert!(
!prompt.contains("### ticketing") && !prompt.contains("### memory-manager"),
"the harness publishes both; repeating them is the #4513 duplication"
);
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("authoritative for WHICH agents exist"),
"#4513: the harness's own listing, not the roster, is now the block \
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("authoritative for WHICH agents exist")
.expect("note");
let roster = prompt.find("## Delegation Authority").expect("roster");
let base = prompt.find("## Prohibitions (CANONICAL").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(rc(), tmp.path());
assert!(prompt.contains("# PM Agent -- Trusty MPM"));
assert!(prompt.contains("# PM Workflow Configuration"));
assert!(prompt.contains("# Agent Delegation Routing"));
assert!(prompt.contains("## Prohibitions (CANONICAL"));
let base = prompt.find("## Prohibitions (CANONICAL").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(rc(), 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("## Prohibitions (CANONICAL"));
}
#[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(rc(), 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(rc(), tmp.path());
assert!(!prompt.contains("ROUTE_ALL_TO_ENGINEER"));
assert!(prompt.contains("# Agent Delegation Routing"));
let harness_published = crate::core::delegation_authority::roster_from_dirs(
&crate::core::delegation_authority::harness_loaded_agent_dirs(tmp.path()),
)
.len();
assert!(
prompt.contains(&format!("the {harness_published} agents it carries")),
"the live roster must reach the prompt — a retired file cannot suppress \
it. #4513: `ticketing` sits in the project tier, which the harness loads \
itself, so the live scan reaches the prompt as the count rather than as \
a `### ticketing` entry."
);
}
#[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(rc(), 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(rc(), 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("## Prohibitions (CANONICAL"));
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(rc(), with.path(), || Some("## Delegation Authority".into()));
let (without_prompt, _) = resolve_pm_prompt_with_roster(rc(), 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(rc(), 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(rc(), 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(rc(), tmp.path());
assert!(prompt.contains("# PM Agent -- Trusty MPM"));
assert!(prompt.contains("## Prohibitions (CANONICAL"));
}
#[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(rc(), tmp.path());
assert!(prompt.contains("# PM Workflow Configuration"));
assert!(prompt.contains("## Prohibitions (CANONICAL"));
}
#[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(rc(), tmp.path());
assert!(prompt.contains("# PM Workflow Configuration"));
assert!(prompt.contains("## Prohibitions (CANONICAL"));
}
#[test]
fn separators_are_consistent() {
let tmp = TempDir::new().unwrap();
let prompt = resolve_pm_prompt(rc(), 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(rc(), 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("## Prohibitions (CANONICAL").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(rc(), 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] = &[
"Proportional documentation",
"Ticket attribution at the change site",
];
let tmp = TempDir::new().unwrap();
let prompt = resolve_pm_prompt(rc(), 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(rc(), 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(rc(), 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)"));
for (label, p) in [
("no-override", &prompt),
("fully-overridden", &prompt2),
("retired-files", &prompt3),
] {
assert!(
!p.contains("Generated with trusty-mpm"),
"the {label} prompt must not restate the attribution footer (#6807)"
);
}
}
#[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(rc(), 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(rc(), 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:?}"
);
}
}
fn resolved_log_lines(project: &Path, times: usize) -> Vec<String> {
use tracing_subscriber::layer::SubscriberExt;
crate::test_support::enable_event_capture();
let buffer = trusty_common::log_buffer::LogBuffer::new(64);
let subscriber = tracing_subscriber::registry().with(
trusty_common::log_buffer::LogBufferLayer::new(buffer.clone()),
);
tracing::subscriber::with_default(subscriber, || {
for _ in 0..times {
let _ = resolve_pm_prompt_with_roster(rc(), project, || {
Some("## Delegation Authority".into())
});
}
});
buffer.tail(64)
}
fn retired_signals(lines: &[String]) -> usize {
lines
.iter()
.filter(|l| l.contains("RETIRED override file is NO LONGER READ"))
.count()
}
#[test]
#[serial_test::serial]
fn the_retired_override_signal_is_emitted_once_per_launch() {
let tmp = TempDir::new().unwrap();
write_override(tmp.path(), FILE_WORKFLOW, "leftover");
assert_eq!(detect_legacy_overrides(tmp.path()).len(), 1);
let lines = resolved_log_lines(tmp.path(), 2);
assert_eq!(
retired_signals(&lines),
1,
"one launch, one signal: {lines:#?}"
);
}
#[test]
#[serial_test::serial]
fn two_projects_each_report_their_own_retired_file() {
let a = TempDir::new().unwrap();
let b = TempDir::new().unwrap();
write_override(a.path(), FILE_MEMORY, "leftover");
write_override(b.path(), FILE_MEMORY, "leftover");
assert_eq!(retired_signals(&resolved_log_lines(a.path(), 2)), 1);
assert_eq!(retired_signals(&resolved_log_lines(b.path(), 2)), 1);
}
#[test]
#[serial_test::serial]
fn a_poisoned_dedupe_lock_still_emits() {
let tmp = TempDir::new().unwrap();
let path = tmp.path().join("leftover-WORKFLOW.md");
assert!(claim_legacy_warning(&path), "first claim on a healthy lock");
let previous_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(|_| {}));
let poisoner = std::thread::spawn(|| {
let _guard = WARNED_LEGACY_PATHS
.get()
.expect("initialized by the claim above")
.lock()
.expect("not poisoned yet");
panic!("poisoning the dedupe lock");
});
let outcome = poisoner.join();
std::panic::set_hook(previous_hook);
assert!(outcome.is_err(), "the poisoning thread must have panicked");
let set = WARNED_LEGACY_PATHS.get().expect("initialized");
assert!(set.is_poisoned(), "the lock must be poisoned");
assert!(
claim_legacy_warning(&path),
"an already-claimed path still emits once the lock is poisoned"
);
set.clear_poison();
}