use std::fmt;
use std::path::{Path, PathBuf};
use crate::smoke::SmokeOutcome;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ToolchainId(String);
pub const WORKER_FILE_NAME: &str = "lean-host-mcp-worker";
pub const WORKERS_DIR_ENV: &str = "LEAN_HOST_MCP_WORKERS_DIR";
impl ToolchainId {
pub fn parse(raw: &str) -> Result<Self, ToolchainError> {
let trimmed = raw.trim();
if trimmed.is_empty() {
return Err(ToolchainError::UnparseableToolchainString(raw.to_owned()));
}
let short = if let Some(rest) = trimmed.strip_prefix("leanprover/lean4:") {
rest
} else if trimmed.contains(':') || trimmed.contains('/') {
return Err(ToolchainError::UnparseableToolchainString(raw.to_owned()));
} else {
trimmed
};
if short.is_empty() || short.chars().any(char::is_whitespace) {
return Err(ToolchainError::UnparseableToolchainString(raw.to_owned()));
}
Ok(Self(short.to_owned()))
}
pub fn from_lake_root(root: &Path) -> Result<Self, ToolchainError> {
let path = root.join("lean-toolchain");
let contents =
std::fs::read_to_string(&path).map_err(|_| ToolchainError::LeanToolchainFileMissing(path.clone()))?;
Self::parse(&contents)
}
pub fn elan_dir(&self) -> Result<PathBuf, ToolchainError> {
let home = dirs::home_dir().ok_or_else(|| ToolchainError::ElanToolchainNotInstalled {
toolchain: self.clone(),
elan_dir: PathBuf::from(format!("~/.elan/toolchains/leanprover--lean4---{}", self.0)),
})?;
let dir = home
.join(".elan")
.join("toolchains")
.join(format!("leanprover--lean4---{}", self.0));
if dir.is_dir() {
Ok(dir)
} else {
Err(ToolchainError::ElanToolchainNotInstalled {
toolchain: self.clone(),
elan_dir: dir,
})
}
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
#[must_use]
pub fn sort_key(&self) -> (u8, (u32, u32, u32, u8, u32), String) {
let bare = self.0.strip_prefix('v').unwrap_or(&self.0);
match version_key(bare) {
Some(k) => (0, k, String::new()),
None => (1, (0, 0, 0, 0, 0), self.0.clone()),
}
}
#[must_use]
pub fn window_verdict(&self) -> WindowVerdict {
let bare = self.0.strip_prefix('v').unwrap_or(&self.0);
if lean_toolchain::supported_for(bare).is_some() {
return WindowVerdict::Supported;
}
match version_key(bare) {
Some(pin) => {
let (window, nearest) = out_of_window_bounds(pin);
WindowVerdict::OutOfWindow { window, nearest }
}
None => WindowVerdict::Unknown,
}
}
}
impl fmt::Display for ToolchainId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
#[derive(Debug, Clone)]
pub struct WorkerBinary {
pub path: PathBuf,
pub toolchain: ToolchainId,
}
impl WorkerBinary {
pub fn resolve_for(toolchain: &ToolchainId) -> Result<Self, ToolchainError> {
let override_dir = std::env::var_os(WORKERS_DIR_ENV).map(PathBuf::from);
Self::resolve_with_override(toolchain, override_dir.as_deref())
}
pub fn resolve_with_override(toolchain: &ToolchainId, override_dir: Option<&Path>) -> Result<Self, ToolchainError> {
if let Some(dir) = override_dir {
let bare = dir.join(WORKER_FILE_NAME);
if bare.is_file() {
return Ok(Self {
path: bare,
toolchain: toolchain.clone(),
});
}
let with_id = dir.join(toolchain.as_str()).join(WORKER_FILE_NAME);
if with_id.is_file() {
return Ok(Self {
path: with_id,
toolchain: toolchain.clone(),
});
}
return Err(Self::not_installed(toolchain));
}
let candidate = Self::install_root().join(toolchain.as_str()).join(WORKER_FILE_NAME);
if candidate.is_file() {
Ok(Self {
path: candidate,
toolchain: toolchain.clone(),
})
} else {
Err(Self::not_installed(toolchain))
}
}
#[must_use]
pub fn install_root() -> PathBuf {
dirs::data_local_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join("lean-host-mcp")
.join("workers")
}
fn not_installed(toolchain: &ToolchainId) -> ToolchainError {
ToolchainError::WorkerNotInstalled {
toolchain: toolchain.clone(),
install_cmd: install_cmd(toolchain),
}
}
#[must_use]
pub fn resolve_ready_for(pin: &ToolchainId) -> Readiness {
if let WindowVerdict::OutOfWindow { window, nearest } = pin.window_verdict() {
return Readiness::Unsupported { window, nearest };
}
let elan_dir = match pin.elan_dir() {
Ok(dir) => dir,
Err(ToolchainError::ElanToolchainNotInstalled { toolchain, elan_dir }) => {
return Readiness::ToolchainNotInstalled { toolchain, elan_dir };
}
Err(_) => {
return Readiness::ToolchainNotInstalled {
toolchain: pin.clone(),
elan_dir: PathBuf::new(),
};
}
};
let current = hash_lean_header(&elan_dir).ok();
let override_dir = std::env::var_os(WORKERS_DIR_ENV).map(PathBuf::from);
Self::resolve_ready_with_override(pin, override_dir.as_deref(), elan_dir, current.as_deref())
}
#[must_use]
pub fn resolve_ready_with_override(
pin: &ToolchainId,
override_dir: Option<&Path>,
lean_sysroot: PathBuf,
current_digest: Option<&str>,
) -> Readiness {
let window = pin.window_verdict();
if let WindowVerdict::OutOfWindow { window, nearest } = window {
return Readiness::Unsupported { window, nearest };
}
let Ok(worker) = Self::resolve_with_override(pin, override_dir) else {
return Readiness::NotInstalled {
toolchain: pin.clone(),
install_cmd: install_cmd(pin),
};
};
let install_dir = worker.path.parent().unwrap_or(&worker.path);
let note = match WorkerSidecar::load(install_dir) {
Some(sidecar) => {
if let Some(current) = current_digest
&& !sidecar.header_matches(current)
{
return Readiness::Stale {
toolchain: pin.clone(),
install_cmd: install_cmd(pin),
};
}
match sidecar.smoke() {
Some(SmokeOutcome::Failed { detail }) => {
return Readiness::Unusable {
toolchain: pin.clone(),
detail: detail.to_owned(),
install_cmd: install_cmd(pin),
};
}
Some(SmokeOutcome::Passed) => None,
None => Some(format!(
"worker for {pin} has no runtime smoke record (installed by an older host); \
reinstall to verify it can run: {}",
install_cmd(pin)
)),
}
}
None => Some(format!(
"worker for {pin} has no provenance record (installed by an older host); \
reinstall to enable header-drift detection: {}",
install_cmd(pin)
)),
};
if matches!(window, WindowVerdict::Unknown) {
return Readiness::UnknownPin {
pin: pin.as_str().to_owned(),
worker,
lean_sysroot,
};
}
Readiness::Ready {
worker,
lean_sysroot,
note,
}
}
}
fn install_cmd(toolchain: &ToolchainId) -> String {
format!("lean-host-mcp install-worker --toolchain {}", toolchain.as_str())
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum WindowVerdict {
Supported,
OutOfWindow { window: String, nearest: String },
Unknown,
}
impl WindowVerdict {
#[must_use]
pub fn label(&self) -> &'static str {
match self {
Self::Supported => "supported",
Self::OutOfWindow { .. } => "unsupported",
Self::Unknown => "unknown",
}
}
}
#[derive(Debug)]
pub enum Readiness {
Ready {
worker: WorkerBinary,
lean_sysroot: PathBuf,
note: Option<String>,
},
Unsupported { window: String, nearest: String },
Stale {
toolchain: ToolchainId,
install_cmd: String,
},
Unusable {
toolchain: ToolchainId,
detail: String,
install_cmd: String,
},
NotInstalled {
toolchain: ToolchainId,
install_cmd: String,
},
ToolchainNotInstalled { toolchain: ToolchainId, elan_dir: PathBuf },
UnknownPin {
pin: String,
worker: WorkerBinary,
lean_sysroot: PathBuf,
},
}
fn version_key(s: &str) -> Option<(u32, u32, u32, u8, u32)> {
let (core, rc) = match s.split_once("-rc") {
Some((core, rc)) => (core, Some(rc.parse::<u32>().ok()?)),
None => (s, None),
};
let mut parts = core.split('.');
let major = parts.next()?.parse::<u32>().ok()?;
let minor = parts.next()?.parse::<u32>().ok()?;
let patch = parts.next()?.parse::<u32>().ok()?;
if parts.next().is_some() {
return None;
}
Some(match rc {
Some(n) => (major, minor, patch, 0, n),
None => (major, minor, patch, 1, 0),
})
}
fn version_scalar((major, minor, patch, rc_flag, rc_num): (u32, u32, u32, u8, u32)) -> u64 {
u64::from(major)
.saturating_mul(1_000_000_000_000)
.saturating_add(u64::from(minor).saturating_mul(1_000_000_000))
.saturating_add(u64::from(patch).saturating_mul(1_000_000))
.saturating_add(u64::from(rc_flag).saturating_mul(1_000))
.saturating_add(u64::from(rc_num))
}
fn out_of_window_bounds(pin: (u32, u32, u32, u8, u32)) -> (String, String) {
let entries = lean_toolchain::SUPPORTED_TOOLCHAINS;
let floor = entries
.first()
.and_then(|t| t.versions.first())
.copied()
.unwrap_or_default();
let head = entries
.last()
.and_then(|t| t.versions.first())
.copied()
.unwrap_or_default();
let window = format!("{floor} ..= {head}");
let pin_scalar = version_scalar(pin);
let nearest = entries
.iter()
.filter_map(|t| t.versions.first().copied())
.filter_map(|v| version_key(v).map(|key| (v, version_scalar(key))))
.min_by(|(_, a), (_, b)| {
a.abs_diff(pin_scalar)
.cmp(&b.abs_diff(pin_scalar))
.then_with(|| b.cmp(a))
})
.map_or(floor, |(v, _)| v);
(window, nearest.to_owned())
}
pub(crate) fn hash_lean_header(elan_dir: &Path) -> std::io::Result<String> {
use sha2::{Digest, Sha256};
let path = elan_dir.join("include").join("lean").join("lean.h");
let bytes = std::fs::read(path)?;
let digest = Sha256::digest(&bytes);
use std::fmt::Write as _;
let mut hex = String::with_capacity(digest.len().saturating_mul(2));
for b in &digest {
let _ = write!(hex, "{b:02x}");
}
Ok(hex)
}
const SIDECAR_FILE_NAME: &str = "worker.json";
#[derive(serde::Serialize, serde::Deserialize)]
pub(crate) struct WorkerSidecar {
toolchain: String,
header_digest: String,
built_against_lean_version: String,
digest_supported_at_build: bool,
#[serde(default)]
smoke: Option<SmokeOutcome>,
}
impl WorkerSidecar {
pub(crate) fn record(
install_dir: &Path,
id: &ToolchainId,
header_digest: String,
smoke: SmokeOutcome,
) -> std::io::Result<()> {
let sidecar = Self {
toolchain: id.as_str().to_owned(),
digest_supported_at_build: lean_toolchain::supported_by_digest(&header_digest).is_some(),
built_against_lean_version: lean_toolchain::LEAN_VERSION.to_owned(),
header_digest,
smoke: Some(smoke),
};
let json = serde_json::to_string_pretty(&sidecar).map_err(std::io::Error::other)?;
std::fs::write(install_dir.join(SIDECAR_FILE_NAME), json)
}
pub(crate) fn load(install_dir: &Path) -> Option<Self> {
let bytes = std::fs::read(install_dir.join(SIDECAR_FILE_NAME)).ok()?;
serde_json::from_slice(&bytes).ok()
}
pub(crate) fn header_matches(&self, current_digest: &str) -> bool {
self.header_digest == current_digest
}
pub(crate) fn header_status(&self, current_digest: Option<&str>) -> &'static str {
match current_digest {
Some(current) if self.header_matches(current) => "fresh",
Some(_) => "stale",
None => "unknown",
}
}
pub(crate) fn smoke(&self) -> Option<&SmokeOutcome> {
self.smoke.as_ref()
}
pub(crate) fn smoke_status(&self) -> &'static str {
self.smoke.as_ref().map_or("untested", SmokeOutcome::label)
}
}
#[derive(Debug)]
pub enum ToolchainError {
UnparseableToolchainString(String),
LeanToolchainFileMissing(PathBuf),
ElanToolchainNotInstalled {
toolchain: ToolchainId,
elan_dir: PathBuf,
},
WorkerNotInstalled {
toolchain: ToolchainId,
install_cmd: String,
},
}
impl fmt::Display for ToolchainError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnparseableToolchainString(raw) => {
write!(f, "could not parse lean-toolchain string: {raw:?}")
}
Self::LeanToolchainFileMissing(path) => {
write!(f, "lean-toolchain file not found at {}", path.display())
}
Self::ElanToolchainNotInstalled { toolchain, elan_dir } => write!(
f,
"elan toolchain {} is not installed (expected {})",
toolchain,
elan_dir.display()
),
Self::WorkerNotInstalled { toolchain, install_cmd } => {
write!(f, "no worker binary for toolchain {toolchain}; run: {install_cmd}")
}
}
}
}
impl std::error::Error for ToolchainError {}
#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
reason = "test code uses unwrap/expect/panic to surface failure paths concisely"
)]
mod tests {
use std::fs;
use super::*;
#[test]
fn parse_accepts_elan_prefix_and_bare_short_form() {
assert_eq!(
ToolchainId::parse("leanprover/lean4:v4.30.0").unwrap().as_str(),
"v4.30.0",
);
assert_eq!(ToolchainId::parse("v4.30.0").unwrap().as_str(), "v4.30.0",);
assert_eq!(
ToolchainId::parse("nightly-2026-05-20").unwrap().as_str(),
"nightly-2026-05-20",
);
assert_eq!(
ToolchainId::parse(" leanprover/lean4:v4.30.0 \n").unwrap().as_str(),
"v4.30.0",
);
}
#[test]
fn parse_rejects_garbage() {
assert!(matches!(
ToolchainId::parse(""),
Err(ToolchainError::UnparseableToolchainString(_))
));
assert!(matches!(
ToolchainId::parse("v4 .30"),
Err(ToolchainError::UnparseableToolchainString(_))
));
assert!(matches!(
ToolchainId::parse("acme/lean5:v6.0"),
Err(ToolchainError::UnparseableToolchainString(_))
));
}
#[test]
fn from_lake_root_reads_lean_toolchain_file() {
let tmp = tempfile::tempdir().unwrap();
fs::write(tmp.path().join("lean-toolchain"), "leanprover/lean4:v4.30.0\n").unwrap();
let id = ToolchainId::from_lake_root(tmp.path()).unwrap();
assert_eq!(id.as_str(), "v4.30.0");
}
#[test]
fn from_lake_root_reports_missing_file() {
let tmp = tempfile::tempdir().unwrap();
assert!(matches!(
ToolchainId::from_lake_root(tmp.path()),
Err(ToolchainError::LeanToolchainFileMissing(_))
));
}
#[test]
fn worker_binary_missing_under_override_returns_install_cmd() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse("v4.30.0").unwrap();
let err = WorkerBinary::resolve_with_override(&id, Some(tmp.path())).unwrap_err();
match err {
ToolchainError::WorkerNotInstalled { install_cmd, .. } => {
assert!(install_cmd.contains("v4.30.0"), "got: {install_cmd}");
}
ToolchainError::UnparseableToolchainString(_)
| ToolchainError::LeanToolchainFileMissing(_)
| ToolchainError::ElanToolchainNotInstalled { .. } => {
panic!("unexpected ToolchainError variant");
}
}
}
#[test]
fn worker_binary_with_id_subdir_wins() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse("v4.30.0").unwrap();
let nested = tmp.path().join("v4.30.0");
fs::create_dir_all(&nested).unwrap();
fs::write(nested.join(WORKER_FILE_NAME), b"#!/bin/sh\n").unwrap();
let resolved = WorkerBinary::resolve_with_override(&id, Some(tmp.path())).unwrap();
assert_eq!(resolved.path, nested.join(WORKER_FILE_NAME));
}
#[test]
fn worker_binary_bare_developer_fallback_wins() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse("v4.30.0").unwrap();
fs::write(tmp.path().join(WORKER_FILE_NAME), b"#!/bin/sh\n").unwrap();
let resolved = WorkerBinary::resolve_with_override(&id, Some(tmp.path())).unwrap();
assert_eq!(resolved.path, tmp.path().join(WORKER_FILE_NAME));
}
fn window_bounds() -> (&'static str, &'static str) {
let entries = lean_toolchain::SUPPORTED_TOOLCHAINS;
let floor = entries.first().unwrap().versions.first().unwrap();
let head = entries.last().unwrap().versions.first().unwrap();
(floor, head)
}
#[test]
fn window_verdict_accepts_in_window_pin_stripping_leading_v() {
let (_, head) = window_bounds();
let id = ToolchainId::parse(&format!("v{head}")).unwrap();
assert_eq!(id.window_verdict(), WindowVerdict::Supported);
}
#[test]
fn window_verdict_flags_above_head_pin_with_nearest_head() {
let (floor, head) = window_bounds();
let major: u32 = head.split('.').next().unwrap().parse().unwrap();
let id = ToolchainId::parse(&format!("v{}.0.0", major + 1)).unwrap();
match id.window_verdict() {
WindowVerdict::OutOfWindow { window, nearest } => {
assert_eq!(window, format!("{floor} ..= {head}"));
assert_eq!(nearest, head);
}
other @ (WindowVerdict::Supported | WindowVerdict::Unknown) => {
panic!("expected OutOfWindow, got {other:?}")
}
}
}
#[test]
fn window_verdict_flags_below_floor_pin_with_nearest_floor() {
let (floor, head) = window_bounds();
let id = ToolchainId::parse("v0.0.0").unwrap();
match id.window_verdict() {
WindowVerdict::OutOfWindow { window, nearest } => {
assert_eq!(window, format!("{floor} ..= {head}"));
assert_eq!(nearest, floor);
}
other @ (WindowVerdict::Supported | WindowVerdict::Unknown) => {
panic!("expected OutOfWindow, got {other:?}")
}
}
}
#[test]
fn window_verdict_flags_in_between_rc_with_nearest_release() {
let (floor, _) = window_bounds();
let release = lean_toolchain::SUPPORTED_TOOLCHAINS
.iter()
.filter_map(|t| t.versions.first().copied())
.find(|v| !v.contains("-rc") && *v != floor)
.expect("the supported window should contain a non-floor numbered release");
let rc = format!("{release}-rc1");
assert!(
lean_toolchain::supported_for(&rc).is_none(),
"{rc} unexpectedly supported"
);
match ToolchainId::parse(&format!("v{rc}")).unwrap().window_verdict() {
WindowVerdict::OutOfWindow { nearest, .. } => assert_eq!(nearest, release),
other @ (WindowVerdict::Supported | WindowVerdict::Unknown) => {
panic!("expected OutOfWindow, got {other:?}")
}
}
}
#[test]
fn window_verdict_treats_nightly_as_unknown() {
let id = ToolchainId::parse("nightly-2026-05-20").unwrap();
assert_eq!(id.window_verdict(), WindowVerdict::Unknown);
}
#[test]
fn window_string_derives_from_supported_toolchains_not_a_literal() {
let (floor, head) = window_bounds();
let WindowVerdict::OutOfWindow { window, .. } = ToolchainId::parse("v0.0.0").unwrap().window_verdict() else {
panic!("expected OutOfWindow");
};
assert_eq!(window, format!("{floor} ..= {head}"));
assert!(window.contains(floor) && window.contains(head));
}
#[test]
fn version_key_orders_rc_before_release() {
assert!(version_key("4.31.0-rc1") < version_key("4.31.0"));
assert!(version_key("4.30.0") < version_key("4.31.0-rc1"));
assert_eq!(version_key("nightly-2026-05-20"), None);
assert_eq!(version_key("4.31"), None);
}
#[test]
fn sort_key_orders_rc_before_release() {
let rc = ToolchainId::parse("v4.31.0-rc1").unwrap();
let rel = ToolchainId::parse("v4.31.0").unwrap();
let rc2 = ToolchainId::parse("v4.31.0-rc2").unwrap();
let prev = ToolchainId::parse("v4.30.0").unwrap();
let ngt = ToolchainId::parse("nightly-2026-05-20").unwrap();
assert!(rc.sort_key() < rel.sort_key(), "rc before its release");
assert!(rc.sort_key() < rc2.sort_key(), "rc1 before rc2");
assert!(prev.sort_key() < rc.sort_key(), "older release before the next rc");
assert!(rel.sort_key() < ngt.sort_key(), "numbered release before a nightly");
let mut ids = vec![rel.clone(), prev.clone(), rc2.clone(), rc.clone()];
ids.sort_by_key(ToolchainId::sort_key);
assert_eq!(ids, vec![prev, rc, rc2, rel]);
}
#[test]
fn sidecar_round_trips_record_then_load() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse("v4.30.0").unwrap();
WorkerSidecar::record(tmp.path(), &id, "abc123".to_owned(), SmokeOutcome::Passed).unwrap();
let loaded = WorkerSidecar::load(tmp.path()).expect("sidecar should load");
assert!(loaded.header_matches("abc123"));
assert!(!loaded.header_matches("different"));
assert_eq!(loaded.header_status(Some("abc123")), "fresh");
assert_eq!(loaded.header_status(Some("different")), "stale");
assert_eq!(loaded.header_status(None), "unknown");
assert_eq!(loaded.smoke_status(), "runs");
assert_eq!(loaded.smoke(), Some(&SmokeOutcome::Passed));
}
#[test]
fn legacy_sidecar_without_smoke_field_loads_as_no_record() {
let tmp = tempfile::tempdir().unwrap();
let legacy = r#"{
"toolchain": "v4.30.0",
"header_digest": "abc123",
"built_against_lean_version": "4.30.0",
"digest_supported_at_build": true
}"#;
fs::write(tmp.path().join(SIDECAR_FILE_NAME), legacy).unwrap();
let loaded = WorkerSidecar::load(tmp.path()).expect("legacy sidecar should load");
assert_eq!(loaded.smoke(), None);
assert_eq!(loaded.smoke_status(), "untested");
}
#[test]
fn smoke_failed_is_unusable_even_with_matching_digest() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse(&format!("v{}", window_bounds().1)).unwrap();
fs::write(tmp.path().join(WORKER_FILE_NAME), b"#!/bin/sh\n").unwrap();
WorkerSidecar::record(
tmp.path(),
&id,
"digest".to_owned(),
SmokeOutcome::Failed {
detail: "signal: 11 (SIGSEGV)".to_owned(),
},
)
.unwrap();
let sysroot = tmp.path().to_path_buf();
let readiness = WorkerBinary::resolve_ready_with_override(&id, Some(tmp.path()), sysroot, Some("digest"));
let Readiness::Unusable { detail, .. } = readiness else {
panic!("expected Unusable, got {readiness:?}");
};
assert!(detail.contains("SIGSEGV"), "got: {detail}");
}
#[test]
fn smoke_record_missing_is_ready_with_reinstall_note() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse(&format!("v{}", window_bounds().1)).unwrap();
fs::write(tmp.path().join(WORKER_FILE_NAME), b"#!/bin/sh\n").unwrap();
let legacy = format!(
r#"{{"toolchain":"{}","header_digest":"digest","built_against_lean_version":"x","digest_supported_at_build":true}}"#,
id.as_str()
);
fs::write(tmp.path().join(SIDECAR_FILE_NAME), legacy).unwrap();
let sysroot = tmp.path().to_path_buf();
let readiness = WorkerBinary::resolve_ready_with_override(&id, Some(tmp.path()), sysroot, Some("digest"));
let Readiness::Ready { note: Some(note), .. } = readiness else {
panic!("expected Ready with a reinstall note, got {readiness:?}");
};
assert!(note.contains("smoke"), "got: {note}");
}
#[test]
fn ready_with_matching_digest_carries_no_note() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse(&format!("v{}", window_bounds().1)).unwrap();
fs::write(tmp.path().join(WORKER_FILE_NAME), b"#!/bin/sh\n").unwrap();
WorkerSidecar::record(tmp.path(), &id, "digest".to_owned(), SmokeOutcome::Passed).unwrap();
let sysroot = tmp.path().to_path_buf();
let readiness = WorkerBinary::resolve_ready_with_override(&id, Some(tmp.path()), sysroot, Some("digest"));
assert!(
matches!(readiness, Readiness::Ready { note: None, .. }),
"expected Ready with no note, got {readiness:?}"
);
}
#[test]
fn forged_mismatching_digest_is_stale() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse(&format!("v{}", window_bounds().1)).unwrap();
fs::write(tmp.path().join(WORKER_FILE_NAME), b"#!/bin/sh\n").unwrap();
WorkerSidecar::record(tmp.path(), &id, "built-digest".to_owned(), SmokeOutcome::Passed).unwrap();
let sysroot = tmp.path().to_path_buf();
assert!(matches!(
WorkerBinary::resolve_ready_with_override(&id, Some(tmp.path()), sysroot, Some("drifted-digest")),
Readiness::Stale { .. }
));
}
#[test]
fn missing_sidecar_is_ready_with_soft_note() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse(&format!("v{}", window_bounds().1)).unwrap();
fs::write(tmp.path().join(WORKER_FILE_NAME), b"#!/bin/sh\n").unwrap();
let sysroot = tmp.path().to_path_buf();
let readiness = WorkerBinary::resolve_ready_with_override(&id, Some(tmp.path()), sysroot, Some("whatever"));
let Readiness::Ready { note: Some(note), .. } = readiness else {
panic!("expected Ready with a soft note, got {readiness:?}");
};
assert!(note.contains("provenance"), "got: {note}");
}
#[test]
fn unknown_nightly_pin_installed_and_fresh_is_unknown_pin() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse("nightly-2026-05-20").unwrap();
fs::write(tmp.path().join(WORKER_FILE_NAME), b"#!/bin/sh\n").unwrap();
WorkerSidecar::record(tmp.path(), &id, "d".to_owned(), SmokeOutcome::Passed).unwrap();
let sysroot = tmp.path().to_path_buf();
assert!(matches!(
WorkerBinary::resolve_ready_with_override(&id, Some(tmp.path()), sysroot, Some("d")),
Readiness::UnknownPin { .. }
));
}
#[test]
fn missing_worker_is_not_installed() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse(&format!("v{}", window_bounds().1)).unwrap();
let sysroot = tmp.path().to_path_buf();
assert!(matches!(
WorkerBinary::resolve_ready_with_override(&id, Some(tmp.path()), sysroot, None),
Readiness::NotInstalled { .. }
));
}
#[test]
fn out_of_window_pin_is_unsupported_before_install_check() {
let tmp = tempfile::tempdir().unwrap();
let id = ToolchainId::parse("v0.0.0").unwrap();
let sysroot = tmp.path().to_path_buf();
assert!(matches!(
WorkerBinary::resolve_ready_with_override(&id, Some(tmp.path()), sysroot, None),
Readiness::Unsupported { .. }
));
}
}