supercode-interchange 0.4.18

Canonical, provider-neutral session interchange primitives for Supercode
Documentation
//! ONT-3 (2/2): the OpenClaw codec against the fixture state dir — the
//! readers' facts, the byte round trip, the re-emit after a change, the
//! refusals.

use std::collections::BTreeMap;
use std::fs;
use std::path::{Path, PathBuf};

use serde_json::Value;
use supercode_interchange::ontology::Fidelity;
use supercode_interchange::orchestration::codec::openclaw::{
    from_openclaw, parse_openclaw_session_key, strip_json5, to_openclaw, OPENCLAW_CONFIG,
    OPENCLAW_STATE_DB,
};

fn repo() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..")
}

fn fixture() -> PathBuf {
    repo()
        .join("crates/harness/tests/fixtures/openclaw_home")
        .canonicalize()
        .unwrap()
}

fn tmp(prefix: &str) -> PathBuf {
    use std::time::{SystemTime, UNIX_EPOCH};
    let dir = std::env::temp_dir().join(format!(
        "{prefix}-{}-{}",
        std::process::id(),
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_nanos()
    ));
    fs::create_dir_all(&dir).unwrap();
    dir.canonicalize().unwrap()
}

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 json5_and_session_keys_are_openclaws_own() {
    assert_eq!(
        strip_json5("{ // c\n \"a\": [1, 2,], /* x */ \"b\": \"//not\", }"),
        "{ \n \"a\": [1, 2],   \"b\": \"//not\" }"
    );
    let p = parse_openclaw_session_key("agent:ops:main").unwrap();
    assert_eq!(p.key.platform.as_deref(), Some("main"));
    assert_eq!(p.residue.get("dm_collapse"), Some(&Value::Bool(true)));
    let p = parse_openclaw_session_key("agent:ops:telegram:group:-1:topic:7").unwrap();
    assert_eq!(p.key.thread_id.as_deref(), Some("7"));
    assert_eq!(
        p.residue.get("thread_word"),
        Some(&Value::String("topic".into()))
    );
    let p = parse_openclaw_session_key("cron:abc:def").unwrap();
    assert_eq!(
        p.recurrence.as_ref().map(|r| r.job_id.as_str()),
        Some("abc:def")
    );
    assert!(parse_openclaw_session_key("nonsense").is_none());
}

#[test]
fn from_openclaw_reads_the_fixture() {
    let loaded = from_openclaw(&fixture()).unwrap();
    let names: Vec<&String> = loaded.orchestration.profiles.keys().collect();
    assert!(names.contains(&&"default".to_string()), "{names:?}");
    let root = &loaded.orchestration.profiles["default"];
    assert!(
        root.channels.contains_key("slack/T0FIXTURE"),
        "two accounts on one transport stay two records: {:?}",
        root.channels.keys().collect::<Vec<_>>()
    );
    assert!(loaded
        .vault
        .values()
        .all(|v| v.contains("FAKE") || !v.is_empty()));
    assert!(
        !serde_json::to_string(&loaded.orchestration)
            .unwrap()
            .contains("DO-NOT-EMIT"),
        "no credential value in the orchestration"
    );
    let jobs: usize = loaded
        .orchestration
        .profiles
        .values()
        .map(|p| p.jobs.len())
        .sum();
    assert!(jobs >= 1, "jobs come from the store");
    assert!(!root.routes.is_empty(), "bindings[] are routes");
    assert!(!root.residue.files.is_empty());
}

#[test]
fn to_openclaw_of_from_openclaw_copies_the_store_and_the_config() {
    let loaded = from_openclaw(&fixture()).unwrap();
    let dest = tmp("orc-openclaw-back");
    let report = to_openclaw(&loaded, &dest).unwrap();
    assert!(report.refused.is_empty(), "{:?}", report.refused);
    let before = files_under(&fixture());
    let after = files_under(&dest);
    for a in &report.written {
        if a.fidelity == Fidelity::ByteLossless {
            assert_eq!(
                after.get(&a.path),
                before.get(&a.path),
                "{} byte for byte",
                a.path
            );
        }
    }
    assert!(
        report
            .written
            .iter()
            .any(|a| a.path == OPENCLAW_STATE_DB && a.fidelity == Fidelity::ByteLossless),
        "the unchanged store is copied"
    );
    assert!(
        report
            .written
            .iter()
            .any(|a| a.path == OPENCLAW_CONFIG && a.fidelity == Fidelity::ByteLossless),
        "the unchanged config keeps its bytes"
    );
    assert_eq!(
        before.len(),
        after.len(),
        "every file reproduced: {:?}",
        before
            .keys()
            .filter(|k| !after.contains_key(*k))
            .collect::<Vec<_>>()
    );
}

#[test]
fn a_changed_job_re_emits_and_the_session_half_is_refused() {
    let mut loaded = from_openclaw(&fixture()).unwrap();
    let (owner, job_id) = loaded
        .orchestration
        .profiles
        .iter()
        .find_map(|(n, p)| p.jobs.keys().next().map(|j| (n.clone(), j.clone())))
        .unwrap();
    loaded
        .orchestration
        .profiles
        .get_mut(&owner)
        .unwrap()
        .jobs
        .get_mut(&job_id)
        .unwrap()
        .prompt = Some("changed by the test".into());
    // a binding that did not come from this store (the fixture's session files
    // carry no gateway key) must be refused, never written into a transcript
    let planted = supercode_interchange::ontology::Binding {
        key: supercode_interchange::ontology::SurfaceKey {
            platform: Some("telegram".into()),
            kind: Some("dm".into()),
            chat_id: Some("1".into()),
            ..Default::default()
        },
        worker: supercode_interchange::ontology::Worker {
            harness: supercode_interchange::ontology::HarnessId::new("codex"),
            session_id: Some("s".into()),
            locator: None,
        },
        ..Default::default()
    };
    loaded
        .orchestration
        .profiles
        .get_mut("default")
        .unwrap()
        .bindings
        .insert("telegram|dm|1||".into(), planted);
    let dest = tmp("orc-openclaw-changed");
    let report = to_openclaw(&loaded, &dest).unwrap();
    assert!(
        report.rows_emitted >= 1 && report.rows_byte >= 1,
        "changed rows re-encode, unchanged rows go back column for column: {:?}",
        (report.rows_byte, report.rows_emitted)
    );
    assert!(
        report
            .refused
            .iter()
            .any(|r| r.file.contains("sessions/") && r.reason.contains("UNI-22")),
        "{:?}",
        report.refused
    );
    let again = from_openclaw(&dest).unwrap();
    assert_eq!(
        again.orchestration.profiles[&owner].jobs[&job_id]
            .prompt
            .as_deref(),
        Some("changed by the test")
    );
}