use std::path::{Path, PathBuf};
use supercode_harness::{
DiscoveryQuery, HarnessCatalog, HarnessHomes, HarnessId, Role, Session, SessionSource,
};
fn store() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/hermes_home/state.db")
}
#[test]
fn bounded_sdk_reads_keep_native_worker_end_without_a_delivery_binding() {
let path =
std::env::temp_dir().join(format!("hermes-worker-end-sdk-{}.db", std::process::id()));
std::fs::copy(store(), &path).unwrap();
let db = rusqlite::Connection::open(&path).unwrap();
db.execute_batch(
"INSERT INTO sessions (id, source, started_at, ended_at, end_reason) VALUES
('worker-end-sdk', 'kanban', 100, 200.75, 'cli_close'),
('worker-live-sdk', 'kanban', 201, NULL, NULL);",
)
.unwrap();
drop(db);
let before = sha256(&path);
let mut service = supercode_harness::harness_service::HarnessSessionService::new();
for id in ["worker-end-sdk", "worker-live-sdk"] {
for options in [
serde_json::json!({"message_tail": 1}),
serde_json::json!({"message_offset": 0, "message_limit": 1}),
] {
let result = service.handle(serde_json::json!({
"jsonrpc": "2.0", "id": 1, "method": "harness.v1.sessions.load",
"params": {"locator": {"harness": "hermes", "session_id": id,
"storage": {"kind": "file", "path": path}}, "options": options}
}));
assert!(result.get("error").is_none(), "{result}");
let session = &result["result"]["session"];
if id == "worker-end-sdk" {
assert_eq!(session["ended_at"], "1970-01-01T00:03:20.750Z");
assert_eq!(session["end_reason"], "cli_close");
} else {
assert!(session["ended_at"].is_null());
assert!(session["end_reason"].is_null());
}
}
}
assert_eq!(sha256(&path), before);
std::fs::remove_file(path).unwrap();
}
fn sha256(path: &Path) -> String {
use std::io::Read;
let mut file = std::fs::File::open(path).unwrap();
let mut bytes = Vec::new();
file.read_to_end(&mut bytes).unwrap();
format!("{:x}", md5_like(&bytes))
}
fn md5_like(bytes: &[u8]) -> u128 {
let mut hash: u128 = 0xcbf2_9ce4_8422_2325;
for byte in bytes {
hash ^= *byte as u128;
hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
}
hash
}
#[test]
fn real_session_loads_with_tool_pairing_and_hermes_provenance() {
let session = Session::from_hermes_sqlite(&store(), None).unwrap();
assert_eq!(session.meta.source, SessionSource::Hermes);
assert_eq!(session.meta.model.as_deref(), Some("gpt-5-nano"));
assert!(
!session.raw_is_verbatim,
"synthesized raw must never claim verbatim"
);
let assistant_with_calls = session
.messages
.iter()
.find(|message| message.tool_calls.is_some())
.expect("the live tool-call turn must map to canonical tool calls");
let calls = assistant_with_calls.tool_calls.as_ref().unwrap();
assert_eq!(calls[0].function.name, "terminal");
assert!(calls[0].function.arguments.contains("HERMES_TOOL_PROOF"));
let tool_result = session
.messages
.iter()
.find(|message| message.role == Role::Tool)
.expect("the tool row must map to a canonical tool result");
assert!(tool_result
.content
.as_deref()
.unwrap_or("")
.contains("HERMES_TOOL_PROOF"));
}
#[test]
fn lineage_classification_covers_all_verified_kinds() {
let kinds = [
("child-branch-marker", "branch"),
("child-delegate", "delegate"),
("child-legacy-branch", "branch"),
("child-compaction", "compaction"),
("child-unknown", "unknown"),
];
for (id, expected) in kinds {
let session = Session::from_hermes_sqlite(&store(), Some(id)).unwrap();
assert_eq!(
session
.meta
.lineage
.get("hermes_lineage_kind")
.map(String::as_str),
Some(expected),
"session {id}"
);
assert!(session
.meta
.lineage
.contains_key("hermes_parent_session_id"));
}
}
#[test]
fn inactive_rows_are_rescued_in_raw_but_never_replayed() {
let session = Session::from_hermes_sqlite(&store(), Some("child-branch-marker")).unwrap();
let replayed: Vec<&str> = session
.messages
.iter()
.filter_map(|message| message.content.as_deref())
.collect();
assert!(replayed.iter().any(|text| text.contains("active answer")));
assert!(
!replayed
.iter()
.any(|text| text.contains("inactive rewound answer")),
"hermes's own replay rule is active=1 only: {replayed:?}"
);
assert!(session
.raw
.iter()
.any(|line| line.contains("inactive rewound answer")));
}
#[test]
fn discovery_lists_sessions_and_the_load_path_routes_sqlite_correctly() {
let query = DiscoveryQuery {
harnesses: vec![HarnessId::new(HarnessId::HERMES)],
homes: HarnessHomes {
hermes: store(),
..HarnessHomes::default()
},
..DiscoveryQuery::default()
};
let found = HarnessCatalog::new().discover(&query).unwrap();
assert_eq!(found.len(), 7, "{found:#?}");
assert!(found
.iter()
.all(|descriptor| descriptor.locator.harness.as_str() == HarnessId::HERMES));
let mut with_children = query.clone();
with_children.include_child_sessions = true;
let all = HarnessCatalog::new().discover(&with_children).unwrap();
assert_eq!(all.len(), 12, "{all:#?}");
assert!(all
.iter()
.any(|descriptor| descriptor.parent_session_id.as_deref() == Some("parent-branched")));
let session = Session::load(&store()).unwrap();
assert_eq!(session.meta.source, SessionSource::Hermes);
}
#[test]
fn loading_and_discovery_never_write_the_store() {
let before = sha256(&store());
let _ = Session::from_hermes_sqlite(&store(), None).unwrap();
let _ = Session::load(&store()).unwrap();
let query = DiscoveryQuery {
harnesses: vec![HarnessId::new(HarnessId::HERMES)],
homes: HarnessHomes {
hermes: store(),
..HarnessHomes::default()
},
..DiscoveryQuery::default()
};
let _ = HarnessCatalog::new().discover(&query).unwrap();
assert_eq!(before, sha256(&store()), "state.db bytes must be untouched");
assert!(!store().with_extension("db-wal").exists());
for suffix in ["state.db-wal", "state.db-shm", "state.db-journal"] {
assert!(
!store().parent().unwrap().join(suffix).exists(),
"{suffix} must not be created by read-only access"
);
}
}
#[test]
fn orchestration_nouns_derive_from_hermes_rows() {
use supercode_harness::{Trigger, WorkspaceKind};
let dm = Session::from_hermes_sqlite(&store(), Some("tg-dm-1")).unwrap();
assert_eq!(dm.meta.trigger, Some(Trigger::Channel));
let s = dm.meta.surface.as_ref().expect("surface");
assert_eq!(s.platform.as_deref(), Some("telegram"));
assert_eq!(s.kind.as_deref(), Some("dm"));
assert_eq!(s.chat_id.as_deref(), Some("123456"));
assert_eq!(s.participant_id.as_deref(), Some("u1"));
assert!(dm.meta.profile.is_none());
assert_eq!(
dm.meta.workspace(),
(WorkspaceKind::Channel, Some("telegram:123456".into()))
);
let fire = Session::from_hermes_sqlite(&store(), Some("cron_job42_20260902_120000")).unwrap();
assert_eq!(fire.meta.trigger, Some(Trigger::Cron));
assert_eq!(
fire.meta.recurrence.as_ref().map(|r| r.job_id.as_str()),
Some("job42")
);
assert_eq!(fire.meta.workspace().0, WorkspaceKind::Repo);
let coder = Session::from_hermes_sqlite(&store(), Some("tg-coder-1")).unwrap();
assert_eq!(coder.meta.profile.as_deref(), Some("coder"));
assert_eq!(coder.meta.trigger, Some(Trigger::Channel));
let s = coder.meta.surface.as_ref().expect("surface");
assert_eq!(s.thread_id.as_deref(), Some("55"));
assert_eq!(coder.meta.workspace().0, WorkspaceKind::Repo);
let x = coder.meta.cross_surface.as_ref().expect("handoff");
assert_eq!(x.state, "pending");
assert_eq!(x.platform.as_deref(), Some("discord"));
let acp = Session::from_hermes_sqlite(&store(), Some("cef97234-e8e8-428a-99ab-e8fff4e7e613"))
.unwrap();
assert_eq!(acp.meta.trigger, Some(Trigger::Human));
assert!(acp.meta.surface.is_none());
let child = Session::from_hermes_sqlite(&store(), Some("child-delegate")).unwrap();
assert_eq!(child.meta.trigger, Some(Trigger::Parent));
}