#![allow(dead_code)]
use serde::Serialize;
use super::store;
use super::types::*;
#[derive(Debug, Clone, Serialize)]
pub struct EvalResult {
pub name: String,
pub passed: bool,
pub detail: String,
}
pub fn run_evals() -> Vec<EvalResult> {
vec![
eval_lease_conflict_prevention(),
eval_lease_release(),
eval_lease_expiry(),
eval_handoff_lifecycle(),
eval_interrupt_lifecycle(),
eval_interrupt_deduplication(),
eval_blocker_lifecycle(),
eval_memory_insert_and_search(),
eval_event_log_append(),
eval_deliverable_interrupt_priority_ordering(),
]
}
pub fn format_results(results: &[EvalResult]) -> String {
let passed = results.iter().filter(|r| r.passed).count();
let total = results.len();
let mut out = String::new();
out.push_str(&format!("Coordination Eval: {passed}/{total} passed\n\n"));
for r in results {
let icon = if r.passed { "PASS" } else { "FAIL" };
out.push_str(&format!(" [{icon}] {}\n", r.name));
if !r.passed {
out.push_str(&format!(" {}\n", r.detail));
}
}
out
}
fn eval_lease_conflict_prevention() -> EvalResult {
let name = "Lease conflict prevention".into();
let conn = store::open_memory();
let lease1 = Lease {
id: "l1".into(),
owner_session_id: "sess_a".into(),
owner_agent: "claude-code".into(),
resource_kind: "path_glob".into(),
resource_value: "src/app.rs".into(),
mode: LeaseMode::Exclusive,
reason: "editing".into(),
acquired_at: "2026-04-20T10:00:00Z".into(),
expires_at: None,
status: LeaseStatus::Active,
};
store::upsert_lease(&conn, &lease1).unwrap();
let conflict = store::find_conflicting_lease(&conn, "path_glob", "src/app.rs", "sess_b");
match conflict {
Ok(Some(c)) => EvalResult {
name,
passed: c.owner_session_id == "sess_a",
detail: format!("Conflict detected: owned by {}", c.owner_session_id),
},
Ok(None) => EvalResult {
name,
passed: false,
detail: "No conflict detected -- should have blocked".into(),
},
Err(e) => EvalResult {
name,
passed: false,
detail: format!("Error: {e}"),
},
}
}
fn eval_lease_release() -> EvalResult {
let name = "Lease release".into();
let conn = store::open_memory();
let lease = Lease {
id: "l_rel".into(),
owner_session_id: "sess_a".into(),
owner_agent: "claude-code".into(),
resource_kind: "file".into(),
resource_value: "src/main.rs".into(),
mode: LeaseMode::Exclusive,
reason: "test".into(),
acquired_at: "2026-04-20T10:00:00Z".into(),
expires_at: None,
status: LeaseStatus::Active,
};
store::upsert_lease(&conn, &lease).unwrap();
let released = store::release_lease(&conn, "l_rel").unwrap();
let after = store::get_lease(&conn, "l_rel").unwrap();
let ok = released
&& after
.map(|l| l.status == LeaseStatus::Released)
.unwrap_or(false);
EvalResult {
name,
passed: ok,
detail: if ok {
"Lease released successfully".into()
} else {
"Release failed".into()
},
}
}
fn eval_lease_expiry() -> EvalResult {
let name = "Lease auto-expiry".into();
let conn = store::open_memory();
let lease = Lease {
id: "l_exp".into(),
owner_session_id: "sess_a".into(),
owner_agent: "claude-code".into(),
resource_kind: "file".into(),
resource_value: "src/old.rs".into(),
mode: LeaseMode::Exclusive,
reason: "test".into(),
acquired_at: "2020-01-01T00:00:00Z".into(),
expires_at: Some("2020-01-01T01:00:00Z".into()),
status: LeaseStatus::Active,
};
store::upsert_lease(&conn, &lease).unwrap();
let count = store::expire_stale_leases(&conn).unwrap();
let after = store::get_lease(&conn, "l_exp").unwrap();
let ok = count == 1
&& after
.map(|l| l.status == LeaseStatus::Expired)
.unwrap_or(false);
EvalResult {
name,
passed: ok,
detail: if ok {
"Expired 1 stale lease".into()
} else {
format!("Expected 1 expiry, got {count}")
},
}
}
fn eval_handoff_lifecycle() -> EvalResult {
let name = "Handoff create and list".into();
let conn = store::open_memory();
let handoff = Handoff {
id: "h_test".into(),
from_session_id: "sess_a".into(),
to_session_id: Some("sess_b".into()),
task_id: "task_1".into(),
summary: "Fix path normalization".into(),
state: HandoffState {
goal: "Fix paths".into(),
artifacts: vec!["src/paths.rs".into()],
attempted: vec![],
next_steps: vec!["Normalize backslashes".into()],
},
priority: "high".into(),
created_at: "2026-04-20T10:00:00Z".into(),
acknowledged_at: None,
};
store::insert_handoff(&conn, &handoff).unwrap();
let pending = store::list_pending_handoffs(&conn).unwrap();
let ok = pending.len() == 1
&& pending[0].id == "h_test"
&& pending[0].state.goal == "Fix paths"
&& pending[0].state.next_steps.len() == 1;
EvalResult {
name,
passed: ok,
detail: if ok {
"Handoff created with structured state".into()
} else {
format!("Unexpected: {} pending handoffs", pending.len())
},
}
}
fn eval_interrupt_lifecycle() -> EvalResult {
let name = "Interrupt lifecycle: pending -> delivered -> acknowledged".into();
let conn = store::open_memory();
let intr = Interrupt {
id: "i_life".into(),
interrupt_type: InterruptType::Pause,
priority: "high".into(),
target_session_id: "sess_a".into(),
reason: "test lifecycle".into(),
payload: None,
delivery_mode: "safe_boundary".into(),
max_retries: 3,
retry_count: 0,
next_retry_at: None,
expires_at: None,
dedupe_key: None,
state: InterruptState::Pending,
created_at: "2026-04-20T10:00:00Z".into(),
delivered_at: None,
acknowledged_at: None,
};
store::insert_interrupt(&conn, &intr).unwrap();
let del_ok = store::mark_interrupt_delivered(&conn, "i_life").unwrap();
let after_del = store::get_interrupt(&conn, "i_life").unwrap().unwrap();
let ack_ok = store::mark_interrupt_acknowledged(&conn, "i_life").unwrap();
let after_ack = store::get_interrupt(&conn, "i_life").unwrap().unwrap();
let ok = del_ok
&& after_del.state == InterruptState::Delivered
&& after_del.delivered_at.is_some()
&& ack_ok
&& after_ack.state == InterruptState::Acknowledged
&& after_ack.acknowledged_at.is_some();
EvalResult {
name,
passed: ok,
detail: if ok {
"Full lifecycle: pending -> delivered -> acknowledged".into()
} else {
format!(
"State after deliver: {:?}, after ack: {:?}",
after_del.state, after_ack.state
)
},
}
}
fn eval_interrupt_deduplication() -> EvalResult {
let name = "Interrupt deduplication via dedupe_key".into();
let conn = store::open_memory();
let intr1 = Interrupt {
id: "i_dup1".into(),
interrupt_type: InterruptType::Compact,
priority: "medium".into(),
target_session_id: "sess_a".into(),
reason: "first".into(),
payload: None,
delivery_mode: "safe_boundary".into(),
max_retries: 3,
retry_count: 0,
next_retry_at: None,
expires_at: None,
dedupe_key: Some("compact:sess_a".into()),
state: InterruptState::Pending,
created_at: "2026-04-20T10:00:00Z".into(),
delivered_at: None,
acknowledged_at: None,
};
store::insert_interrupt(&conn, &intr1).unwrap();
let dup = store::find_duplicate_interrupt(&conn, "compact:sess_a").unwrap();
let ok = dup.is_some() && dup.as_ref().unwrap().id == "i_dup1";
EvalResult {
name,
passed: ok,
detail: if ok {
"Duplicate detected by dedupe_key".into()
} else {
"Deduplication failed".into()
},
}
}
fn eval_blocker_lifecycle() -> EvalResult {
let name = "Blocker open and resolve".into();
let conn = store::open_memory();
let blocker = Blocker {
id: "b_test".into(),
task_id: "task_docs".into(),
depends_on: Some("task_auth".into()),
waiting_for: "JWT middleware contract".into(),
status: BlockerStatus::Open,
owner_session_id: "sess_a".into(),
created_at: "2026-04-20T10:00:00Z".into(),
resolved_at: None,
};
store::insert_blocker(&conn, &blocker).unwrap();
let open = store::list_blockers(&conn, Some(BlockerStatus::Open)).unwrap();
store::resolve_blocker(&conn, "b_test").unwrap();
let resolved = store::list_blockers(&conn, Some(BlockerStatus::Resolved)).unwrap();
let still_open = store::list_blockers(&conn, Some(BlockerStatus::Open)).unwrap();
let ok = open.len() == 1 && resolved.len() == 1 && still_open.is_empty();
EvalResult {
name,
passed: ok,
detail: if ok {
"Blocker resolved successfully".into()
} else {
format!(
"open={}, resolved={}, still_open={}",
open.len(),
resolved.len(),
still_open.len()
)
},
}
}
fn eval_memory_insert_and_search() -> EvalResult {
let name = "Memory insert and FTS5 search".into();
let conn = store::open_memory();
let record = MemoryRecord {
id: "mem_eval".into(),
mem_type: "workflow".into(),
scope: serde_json::json!({"project": "claudectl"}),
subjects: vec![Subject {
kind: "path".into(),
value: "src/health.rs".into(),
}],
summary: "When changing health thresholds always run integration tests".into(),
evidence: vec![],
source: None,
confidence: 0.9,
created_at: "2026-04-20T10:00:00Z".into(),
updated_at: "2026-04-20T10:00:00Z".into(),
expires_at: None,
tags: vec!["health".into(), "tests".into()],
};
store::insert_memory(&conn, &record).unwrap();
let results = store::search_memory(&conn, "health thresholds", 10).unwrap();
let ok = results.len() == 1 && results[0].id == "mem_eval";
EvalResult {
name,
passed: ok,
detail: if ok {
"FTS5 search found the record".into()
} else {
format!("Search returned {} results", results.len())
},
}
}
fn eval_event_log_append() -> EvalResult {
let name = "Event log append and query".into();
let conn = store::open_memory();
for i in 0..5 {
store::append_event(
&conn,
&CoordEvent {
id: None,
event_type: EventType::SessionObserved,
timestamp: format!("2026-04-20T10:0{i}:00Z"),
session_id: Some(format!("sess_{i}")),
payload: serde_json::json!({"pid": i}),
},
)
.unwrap();
}
let all = store::query_events(&conn, 100, None).unwrap();
let filtered = store::query_events(&conn, 100, Some("session_observed")).unwrap();
let ok = all.len() == 5 && filtered.len() == 5;
EvalResult {
name,
passed: ok,
detail: if ok {
"5 events appended and queried".into()
} else {
format!("all={}, filtered={}", all.len(), filtered.len())
},
}
}
fn eval_deliverable_interrupt_priority_ordering() -> EvalResult {
let name = "Deliverable interrupts ordered by priority".into();
let conn = store::open_memory();
let make = |id: &str, priority: &str| Interrupt {
id: id.into(),
interrupt_type: InterruptType::Nudge,
priority: priority.into(),
target_session_id: "sess_a".into(),
reason: "test".into(),
payload: None,
delivery_mode: "safe_boundary".into(),
max_retries: 3,
retry_count: 0,
next_retry_at: None,
expires_at: None,
dedupe_key: None,
state: InterruptState::Pending,
created_at: "2026-04-20T10:00:00Z".into(),
delivered_at: None,
acknowledged_at: None,
};
store::insert_interrupt(&conn, &make("i_low", "low")).unwrap();
store::insert_interrupt(&conn, &make("i_crit", "critical")).unwrap();
store::insert_interrupt(&conn, &make("i_med", "medium")).unwrap();
store::insert_interrupt(&conn, &make("i_high", "high")).unwrap();
let deliverable = store::list_deliverable_interrupts(&conn).unwrap();
let order: Vec<&str> = deliverable.iter().map(|i| i.id.as_str()).collect();
let ok = order == vec!["i_crit", "i_high", "i_med", "i_low"];
EvalResult {
name,
passed: ok,
detail: if ok {
"Priority ordering: critical > high > medium > low".into()
} else {
format!("Actual order: {order:?}")
},
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn all_evals_pass() {
let results = run_evals();
for r in &results {
assert!(r.passed, "Eval failed: {} -- {}", r.name, r.detail);
}
}
#[test]
fn format_results_shows_pass_fail() {
let results = vec![
EvalResult {
name: "test_pass".into(),
passed: true,
detail: "ok".into(),
},
EvalResult {
name: "test_fail".into(),
passed: false,
detail: "something broke".into(),
},
];
let output = format_results(&results);
assert!(output.contains("[PASS] test_pass"));
assert!(output.contains("[FAIL] test_fail"));
assert!(output.contains("something broke"));
assert!(output.contains("1/2 passed"));
}
}