use std::collections::BTreeMap;
use std::fs;
use std::path::{Path, PathBuf};
use serde_json::Value;
use supercode_interchange::ontology::{Fidelity, SecretRef};
use supercode_interchange::world::codec::{
canonical_json, from_hermes, load_home, save_home, to_hermes, Flavor,
};
use supercode_interchange::world::Target;
fn repo() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..")
}
fn fixture() -> PathBuf {
repo()
.join("crates/harness/tests/fixtures/hermes_home")
.canonicalize()
.unwrap()
}
fn first_difference(a: &str, b: &str) -> String {
let al: Vec<&str> = a.lines().collect();
let bl: Vec<&str> = b.lines().collect();
let first = al
.iter()
.zip(bl.iter())
.position(|(x, y)| x != y)
.unwrap_or(al.len().min(bl.len()));
format!(
"line {first}:\n left: {}\n right: {}",
al.get(first).unwrap_or(&"<end>"),
bl.get(first).unwrap_or(&"<end>")
)
}
fn tmp(prefix: &str) -> PathBuf {
let dir =
std::env::temp_dir().join(format!("{prefix}-{}-{}", std::process::id(), rand_suffix()));
fs::create_dir_all(&dir).unwrap();
dir.canonicalize().unwrap()
}
fn rand_suffix() -> u64 {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos() as u64
}
fn files_under(root: &Path) -> BTreeMap<String, Vec<u8>> {
let mut out = BTreeMap::new();
fn walk(base: &Path, dir: &Path, out: &mut BTreeMap<String, Vec<u8>>) {
for entry in fs::read_dir(dir).unwrap().flatten() {
let p = entry.path();
if p.is_dir() {
walk(base, &p, out);
} else if p.is_file() {
out.insert(
p.strip_prefix(base).unwrap().to_string_lossy().into_owned(),
fs::read(&p).unwrap(),
);
}
}
}
walk(root, root, &mut out);
out
}
#[test]
fn from_hermes_reads_the_fixture_with_the_readers_facts() {
let loaded = from_hermes(&fixture()).unwrap();
let names: Vec<&String> = loaded.world.profiles.keys().collect();
assert_eq!(names, vec!["coder", "default", "ops"]);
let default = &loaded.world.profiles["default"];
assert_eq!(
default.channels["telegram"].credentials["token"],
SecretRef::Dotenv("TELEGRAM_TOKEN".into())
);
assert!(
loaded.vault.contains_key("TELEGRAM_TOKEN"),
"the value went to the vault, not the world"
);
assert!(!serde_json::to_string(&loaded.world)
.unwrap()
.contains(&loaded.vault["TELEGRAM_TOKEN"]));
assert_eq!(default.bindings.len(), 2);
assert_eq!(loaded.world.profiles["coder"].bindings.len(), 1);
assert_eq!(loaded.world.profiles["ops"].bindings.len(), 0);
let job = default
.jobs
.get("coder-standup")
.or_else(|| loaded.world.profiles["coder"].jobs.get("coder-standup"))
.expect("the fixture's standup job");
assert_eq!(job.deliver, Target::Origin);
assert!(
!default.residue.files.is_empty(),
"unmodeled files are carried by path"
);
}
#[test]
fn to_hermes_of_from_hermes_reproduces_every_byte_tier_file() {
let loaded = from_hermes(&fixture()).unwrap();
let dest = tmp("orc-hermes-back");
let report = to_hermes(&loaded, &dest, None).unwrap();
assert!(
report.refused.is_empty(),
"nothing changed, nothing refused: {:?}",
report.refused
);
let before = files_under(&fixture());
let after = files_under(&dest);
for artifact in &report.written {
if artifact.fidelity == Fidelity::ByteLossless {
assert_eq!(
after.get(&artifact.path),
before.get(&artifact.path),
"{} byte for byte",
artifact.path
);
}
}
let byte: Vec<&str> = report
.written
.iter()
.filter(|a| a.fidelity == Fidelity::ByteLossless)
.map(|a| a.path.as_str())
.collect();
assert!(
byte.contains(&"cron/jobs.json") || byte.iter().any(|p| p.ends_with("cron/jobs.json")),
"{byte:?}"
);
assert!(
byte.iter().any(|p| p.ends_with("state.db")),
"an unchanged state.db is copied byte for byte"
);
for (name, profile) in &loaded.world.profiles {
if profile.persona.is_some() {
let rel = if name == "default" {
"SOUL.md".to_string()
} else {
format!("profiles/{name}/SOUL.md")
};
assert_eq!(after.get(&rel), before.get(&rel), "{rel}");
}
}
}
#[test]
fn to_hermes_after_a_change_re_emits_jobs_and_refuses_sessions() {
let mut loaded = from_hermes(&fixture()).unwrap();
let default = loaded.world.profiles.get_mut("default").unwrap();
let job = default.jobs.values_mut().next().unwrap();
job.prompt = Some("changed by the test".into());
let (slot, mut binding) = default
.bindings
.iter()
.next()
.map(|(k, b)| (k.clone(), b.clone()))
.unwrap();
binding.ended_at = Some("2026-09-04T00:00:00.000Z".into());
default.bindings.insert(slot, binding);
let dest = tmp("orc-hermes-changed");
let report = to_hermes(&loaded, &dest, None).unwrap();
assert!(
report
.refused
.iter()
.any(|r| r.file == "state.db" && r.reason.contains("UNI-22")),
"{:?}",
report.refused
);
let jobs: Value =
serde_json::from_str(&fs::read_to_string(dest.join("cron/jobs.json")).unwrap()).unwrap();
let text = jobs.to_string();
assert!(text.contains("changed by the test"));
assert!(
jobs.is_array() || jobs.get("jobs").is_some(),
"the file keeps the form it was read in"
);
}
#[test]
fn our_folder_is_byte_stable_and_round_trips() {
let loaded = from_hermes(&fixture()).unwrap();
let root = tmp("orc-root");
let mut ours = loaded.clone();
ours.world.root = root.clone();
for (name, profile) in ours.world.profiles.iter_mut() {
profile.dir = if name == "default" {
root.clone()
} else {
root.join("profiles").join(name)
};
supercode_interchange::world::codec::folder::copy_unmodeled(
profile,
&loaded.io[name],
&profile.dir.clone(),
)
.unwrap();
}
let text = "# Persona\nBe brief.\n".to_string();
ours.world.profiles.get_mut("default").unwrap().persona = Some(
supercode_interchange::world::codec::folder::persona_ref(&text),
);
save_home(&mut ours, Some(&root)).unwrap();
let first = files_under(&root);
assert_eq!(
fs::read_to_string(root.join("AGENTS.md")).unwrap(),
text,
"AGENTS.md at the profile root"
);
assert_eq!(
fs::read_to_string(root.join("CLAUDE.md")).unwrap(),
"@AGENTS.md\n",
"CLAUDE.md = @AGENTS.md"
);
let env = fs::read_to_string(root.join(".env")).unwrap();
assert!(env.contains("TELEGRAM_TOKEN="), "secrets land in .env only");
let mut reloaded = load_home(&root, Flavor::Orchestrator).unwrap();
let (left, right) = (
canonical_json(&serde_json::to_value(&reloaded.world).unwrap()),
canonical_json(&serde_json::to_value(&ours.world).unwrap()),
);
assert!(
left == right,
"load(save(s)) == s: {}",
first_difference(&left, &right)
);
save_home(&mut reloaded, None).unwrap();
let second = files_under(&root);
assert_eq!(first, second, "save(load(root)) == root byte for byte");
let cfg = root.join("config.yaml");
let text = fs::read_to_string(&cfg).unwrap();
fs::write(
&cfg,
format!("{text}\nworker:\n harness: codex\n bogus: 1\n"),
)
.unwrap();
let err = load_home(&root, Flavor::Orchestrator)
.unwrap_err()
.to_string();
assert!(
err.contains("config.yaml") && err.contains("worker.bogus") && err.contains("unknown key"),
"{err}"
);
}
#[test]
fn an_export_from_our_folder_inlines_credentials_and_refuses_sessions() {
let imported = from_hermes(&fixture()).unwrap();
let root = tmp("orc-root-export");
let mut ours = imported.clone();
ours.world.root = root.clone();
for (name, profile) in ours.world.profiles.iter_mut() {
profile.dir = if name == "default" {
root.clone()
} else {
root.join("profiles").join(name)
};
}
save_home(&mut ours, Some(&root)).unwrap();
let text = fs::read_to_string(root.join("config.yaml")).unwrap();
assert!(
text.contains("dotenv") && !text.contains(&imported.vault["TELEGRAM_TOKEN"]),
"our folder holds the ref, not the value"
);
let reloaded = load_home(&root, Flavor::Orchestrator).unwrap();
let dest = tmp("orc-hermes-from-ours");
let report = to_hermes(&reloaded, &dest, None).unwrap();
let out = fs::read_to_string(dest.join("config.yaml")).unwrap();
assert!(
out.contains(&imported.vault["TELEGRAM_TOKEN"]),
"the Hermes home gets the value back: {out}"
);
assert!(!out.contains("dotenv"), "{out}");
assert!(
report
.refused
.iter()
.any(|r| r.file == "state.db" && r.reason.contains("UNI-22")),
"{:?}",
report.refused
);
}