use crate::brain::rsi::{StaleScanInput, build_cycle_prompt, stale_scan_prompt_block};
use crate::brain::rsi_stale_ledger::{ScanRunOutcome, run_scan_with_ledger};
use crate::config::Config;
use std::sync::atomic::{AtomicUsize, Ordering};
const RSI_SRC: &str = include_str!("../brain/rsi.rs");
fn scratch_dir(tag: &str) -> std::path::PathBuf {
static SEQ: AtomicUsize = AtomicUsize::new(0);
let n = SEQ.fetch_add(1, Ordering::SeqCst);
let dir = std::env::temp_dir().join(format!(
"oc-rsi-stale-wire-{}-{n}-{tag}",
std::process::id()
));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).expect("create scratch dir");
dir
}
fn pre_change_baseline(opportunities: &[String]) -> String {
let mut prompt = "Run an autonomous self-improvement cycle.\n\n".to_string();
if !opportunities.is_empty() {
prompt.push_str("Detected opportunities:\n");
for (i, opp) in opportunities.iter().enumerate() {
prompt.push_str(&format!("{}. {opp}\n", i + 1));
}
prompt.push('\n');
}
prompt.push_str(
"Analyze the feedback data, identify the highest-impact issues, and apply improvements.\n",
);
prompt.push_str(&crate::brain::rsi_disposition::required_actions_block(
opportunities,
));
prompt
}
fn stale_brain(dir: &std::path::Path) {
std::fs::write(
dir.join("SOUL.md"),
"# soul\n\n- run `oc-wire-dead-bin` every morning\n\n- check \
`/opt/oc-wire-gone-path/rule.md` before deploy\n",
)
.unwrap();
std::fs::write(
dir.join("AGENTS.md"),
"# agents\n\n- use provider `oc-wire-no-provider` for image work\n\n- use `cd` when \
moving between directories\n",
)
.unwrap();
}
fn day(secs: u64) -> u64 {
1_700_000_000u64 + secs
}
fn cycle_prompt_from_scan(
config: &Config,
brain: &std::path::Path,
ledger: &std::path::Path,
now_unix: u64,
cycle: u64,
binary_version: &str,
opportunities: &[String],
) -> (String, StaleScanInput) {
let outcome = run_scan_with_ledger(config, brain, ledger, now_unix, cycle, binary_version);
let input = StaleScanInput::from_outcome(&outcome);
let prompt = build_cycle_prompt(opportunities, &stale_scan_prompt_block(&input));
(prompt, input)
}
#[test]
fn scan_findings_reach_the_cycle_prompt_structured() {
let dir = scratch_dir("dataflow");
let brain = dir.join("brain");
std::fs::create_dir_all(&brain).unwrap();
stale_brain(&brain);
let ledger = dir.join("rsi/stale_scan.json");
let opps = vec!["tool bash failure rate 30% over 7d".to_string()];
let (prompt, input) = cycle_prompt_from_scan(
&Config::default(),
&brain,
&ledger,
day(0),
1,
"0.3.83",
&opps,
);
assert_eq!(input.reword_via_update.len(), 2, "{input:?}");
assert_eq!(input.owner_signoff.len(), 1, "{input:?}");
assert!(input.cleared.is_empty());
assert!(prompt.contains("1. SOUL.md:3\n line: - run `oc-wire-dead-bin` every morning\n dead anchor: binary `oc-wire-dead-bin` — no executable on PATH\n"), "{prompt}");
assert!(
prompt.contains("2. AGENTS.md:3\n line: - use provider `oc-wire-no-provider` for image work\n dead anchor: provider `oc-wire-no-provider`"),
"{prompt}"
);
assert!(
prompt.contains("- SOUL.md:5\n line: - check `/opt/oc-wire-gone-path/rule.md` before deploy\n dead anchor: path `/opt/oc-wire-gone-path/rule.md` — path does not exist\n"),
"{prompt}"
);
assert!(
prompt.contains("self_improve action='update'"),
"the actionable findings must recommend self_improve action='update'"
);
assert!(prompt.contains("OWNER SIGN-OFF REQUIRED"));
assert!(prompt.contains("do NOT edit these yourself"));
assert!(!prompt.contains("`cd`"));
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn stale_block_precedes_capability_gap_actions() {
let dir = scratch_dir("order");
let brain = dir.join("brain");
std::fs::create_dir_all(&brain).unwrap();
stale_brain(&brain);
let ledger = dir.join("rsi/stale_scan.json");
let opps = vec![
"Tool sequence 'a -> b' ran in 5 sessions — candidate for a skill (rsi_propose kind=skill). File a SKILL.md.".to_string(),
];
let (prompt, _) = cycle_prompt_from_scan(
&Config::default(),
&brain,
&ledger,
day(0),
1,
"0.3.83",
&opps,
);
let stale_at = prompt
.find("STALE-CLAIM SCAN FINDINGS")
.expect("stale block");
let actions_at = prompt.find("REQUIRED ACTIONS").expect("capability block");
assert!(
stale_at < actions_at,
"capability-gap actions must close the prompt (#842)"
);
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
#[cfg(unix)] fn cleared_findings_flow_through_as_informational() {
let probe = std::path::Path::new("/tmp/oc-rsi-wire-cleared-probe");
let _ = std::fs::remove_dir_all(probe);
let dir = scratch_dir("cleared");
let brain = dir.join("brain");
std::fs::create_dir_all(&brain).unwrap();
std::fs::write(
brain.join("AGENTS.md"),
"# agents\n\n- check `/tmp/oc-rsi-wire-cleared-probe/rule.md` before deploy\n",
)
.unwrap();
let ledger = dir.join("rsi/stale_scan.json");
let cfg = Config::default();
let opps = vec!["opportunity".to_string()];
let (_, first) = cycle_prompt_from_scan(&cfg, &brain, &ledger, day(0), 1, "0.3.83", &opps);
assert_eq!(first.owner_signoff.len(), 1, "{first:?}");
std::fs::create_dir_all(probe).unwrap();
std::fs::write(probe.join("rule.md"), "back\n").unwrap();
let (prompt, second) =
cycle_prompt_from_scan(&cfg, &brain, &ledger, day(60), 2, "0.3.84", &opps);
assert!(second.reword_via_update.is_empty());
assert!(second.owner_signoff.is_empty());
assert_eq!(second.cleared.len(), 1, "stale→ok surfaces as cleared");
assert!(
prompt.contains("PREVIOUSLY STALE, NOW HEALTHY AGAIN"),
"{prompt}"
);
assert!(
prompt.contains("- AGENTS.md:3 — `/tmp/oc-rsi-wire-cleared-probe/rule.md` verified ok"),
"{prompt}"
);
let _ = std::fs::remove_dir_all(&dir);
let _ = std::fs::remove_dir_all(probe);
}
#[test]
fn empty_block_is_byte_identical_to_pre_change_baseline() {
let shapes: Vec<Vec<String>> = vec![
vec![],
vec!["tool bash failure rate 30% over 7d".to_string()],
vec![
"Command pattern 'git status' recurring — candidate (rsi_propose kind=command)."
.to_string(),
"Tool sequence 'a -> b' ran in 5 sessions (rsi_propose kind=skill).".to_string(),
],
];
for opps in &shapes {
assert_eq!(
build_cycle_prompt(opps, ""),
pre_change_baseline(opps),
"empty stale block must leave the prompt byte-identical (shape: {opps:?})"
);
}
assert_eq!(stale_scan_prompt_block(&StaleScanInput::default()), "");
}
#[test]
fn cadence_disabled_path_is_byte_identical() {
let dir = scratch_dir("skip");
let brain = dir.join("brain");
std::fs::create_dir_all(&brain).unwrap();
stale_brain(&brain); let ledger = dir.join("rsi/stale_scan.json");
let cfg = Config::default();
let opps = vec!["opportunity".to_string()];
let (first_prompt, first) =
cycle_prompt_from_scan(&cfg, &brain, &ledger, day(0), 1, "0.3.83", &opps);
assert!(!first.is_empty());
assert!(first_prompt.contains("STALE-CLAIM SCAN FINDINGS"));
let outcome = run_scan_with_ledger(&cfg, &brain, &ledger, day(0) + 60, 2, "0.3.83");
assert!(matches!(outcome, ScanRunOutcome::Skipped { .. }));
let input = StaleScanInput::from_outcome(&outcome);
assert!(input.is_empty());
let prompt = build_cycle_prompt(&opps, &stale_scan_prompt_block(&input));
assert_eq!(prompt, pre_change_baseline(&opps));
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn fresh_instance_with_nothing_stale_is_byte_identical() {
let dir = scratch_dir("fresh");
let brain = dir.join("brain");
std::fs::create_dir_all(&brain).unwrap();
std::fs::write(
brain.join("SOUL.md"),
"# soul\n\n- use `cd` when moving between directories\n",
)
.unwrap();
let ledger = dir.join("rsi/stale_scan.json");
let opps = vec!["opportunity".to_string()];
let (prompt, input) = cycle_prompt_from_scan(
&Config::default(),
&brain,
&ledger,
day(0),
1,
"0.3.83",
&opps,
);
assert!(
input.is_empty(),
"healthy anchors surface nothing: {input:?}"
);
assert_eq!(prompt, pre_change_baseline(&opps));
let dir2 = scratch_dir("fresh-empty");
let brain2 = dir2.join("brain");
std::fs::create_dir_all(&brain2).unwrap();
let (prompt2, input2) = cycle_prompt_from_scan(
&Config::default(),
&brain2,
&dir2.join("rsi/stale_scan.json"),
day(0),
1,
"0.3.83",
&opps,
);
assert!(input2.is_empty());
assert_eq!(prompt2, pre_change_baseline(&opps));
let _ = std::fs::remove_dir_all(&dir);
let _ = std::fs::remove_dir_all(&dir2);
}
#[test]
fn a_finding_feeds_exactly_one_cycle_prompt() {
let dir = scratch_dir("nospam");
let brain = dir.join("brain");
std::fs::create_dir_all(&brain).unwrap();
stale_brain(&brain);
let ledger = dir.join("rsi/stale_scan.json");
let cfg = Config::default();
let opps = vec!["opportunity".to_string()];
let (p1, i1) = cycle_prompt_from_scan(&cfg, &brain, &ledger, day(0), 1, "0.3.83", &opps);
assert!(!i1.is_empty() && p1.contains("STALE-CLAIM SCAN FINDINGS"));
let (p2, i2) = cycle_prompt_from_scan(
&cfg,
&brain,
&ledger,
day(0) + 25 * 3600,
2,
"0.3.83",
&opps,
);
assert!(i2.is_empty(), "no re-flag on identical findings: {i2:?}");
assert_eq!(p2, pre_change_baseline(&opps));
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn run_rsi_agent_cycle_wires_scan_ahead_of_the_improvement_step() {
let cycle_start = RSI_SRC
.find("async fn run_rsi_agent_cycle(")
.expect("run_rsi_agent_cycle defined");
let after = &RSI_SRC[cycle_start..];
let scan_at = after
.find("stale_scan_cycle_input(config)")
.expect("cycle runs the gated stale scan");
let after_scan = &after[scan_at..];
let block_at = after_scan
.find("stale_scan_prompt_block(&stale_input)")
.expect("cycle renders the scan block into the prompt");
let build_at = after_scan
.find("build_cycle_prompt(")
.expect("cycle builds its prompt via build_cycle_prompt");
let send_at = after_scan
.find(".send_message_with_tools(")
.expect("improvement step call");
assert!(
build_at < send_at && block_at < send_at,
"scan → block → prompt → send ordering must hold inside run_rsi_agent_cycle"
);
}