supercode-interchange 0.4.16

Canonical, provider-neutral session interchange primitives for Supercode
Documentation
//! ONT-3: the world codecs in Rust, against the fixture homes and the Node
//! package they transcribe (`sdk/orchestrator/{files,hermes}.mjs`).

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"
    );
    // every profile's persona came back as SOUL.md
    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() {
    // import the Hermes fixture into our folder, then load/save/load
    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)
        };
        // an import carries the unmodeled files over, byte for byte, before the save
        supercode_interchange::world::codec::folder::copy_unmodeled(
            profile,
            &loaded.io[name],
            &profile.dir.clone(),
        )
        .unwrap();
    }
    // the fixture carries no SOUL.md; give the default profile a persona so the
    // AGENTS.md / CLAUDE.md rule is exercised
    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");
    // a strict load names the file and key
    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}"
    );
}

/// Our folder on its way OUT: its config.yaml holds `{dotenv}` refs where
/// Hermes reads values, so the bytes are never reused and the credential is
/// re-inlined from the vault; its state.db holds our bindings, never Hermes's
/// sessions, so that half is refused.
#[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
    );
}