use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::incident::{ControlState, IncidentReasonCode};
use crate::schema_versions::{SchemaComponent, current_version};
use crate::types::{WorkerSelectionDiagnostic, WorkerSelectionDiagnosticDecision};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum StrictRemotePolicy {
#[default]
Off,
ForceRemote,
RequireRemote,
}
impl StrictRemotePolicy {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
StrictRemotePolicy::Off => "off",
StrictRemotePolicy::ForceRemote => "force_remote",
StrictRemotePolicy::RequireRemote => "require_remote",
}
}
#[must_use]
pub fn fail_closed(self) -> bool {
matches!(self, StrictRemotePolicy::RequireRemote)
}
#[must_use]
pub fn forces_offload(self) -> bool {
matches!(
self,
StrictRemotePolicy::ForceRemote | StrictRemotePolicy::RequireRemote
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueuePolicy {
#[default]
QueueWhenBusy,
NoQueue,
}
impl QueuePolicy {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
QueuePolicy::QueueWhenBusy => "queue_when_busy",
QueuePolicy::NoQueue => "no_queue",
}
}
#[must_use]
pub fn waits(self) -> bool {
matches!(self, QueuePolicy::QueueWhenBusy)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum VisibilityMode {
#[default]
Default,
None,
Summary,
Verbose,
}
impl VisibilityMode {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
VisibilityMode::Default => "default",
VisibilityMode::None => "none",
VisibilityMode::Summary => "summary",
VisibilityMode::Verbose => "verbose",
}
}
fn parse(value: &str) -> Option<VisibilityMode> {
match value.trim().to_ascii_lowercase().as_str() {
"none" | "quiet" => Some(VisibilityMode::None),
"summary" => Some(VisibilityMode::Summary),
"verbose" => Some(VisibilityMode::Verbose),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum TargetDirPolicy {
#[default]
Pooled,
PerJob,
WorkerScoped,
}
impl TargetDirPolicy {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
TargetDirPolicy::Pooled => "pooled",
TargetDirPolicy::PerJob => "per_job",
TargetDirPolicy::WorkerScoped => "worker_scoped",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ControlKind {
Placement,
StrictRemote,
Queue,
WaitTimeout,
Visibility,
TargetDir,
Profile,
SelfHealing,
}
#[derive(Debug, Clone, Copy)]
pub struct PlacementControl {
pub canonical_env: &'static str,
pub aliases: &'static [&'static str],
pub flag: Option<&'static str>,
pub kind: ControlKind,
pub value_form: &'static str,
pub description: &'static str,
}
#[must_use]
pub fn placement_controls() -> &'static [PlacementControl] {
const CONTROLS: &[PlacementControl] = &[
PlacementControl {
canonical_env: "RCH_WORKER",
aliases: &["RCH_WORKERS"],
flag: None,
kind: ControlKind::Placement,
value_form: "worker-id[,worker-id...]",
description: "Request specific worker(s) by id. Still passes capability/admission \
checks; an inadmissible requested worker is refused with a reason code.",
},
PlacementControl {
canonical_env: "RCH_PRESET",
aliases: &[],
flag: None,
kind: ControlKind::Profile,
value_form: "profile-name",
description: "Request a named execution profile (recorded as requested_profile).",
},
PlacementControl {
canonical_env: "RCH_REQUIRE_REMOTE",
aliases: &[],
flag: None,
kind: ControlKind::StrictRemote,
value_form: "0|1",
description: "Fail closed: refuse local fallback (proof mode). Takes precedence over \
RCH_FORCE_REMOTE.",
},
PlacementControl {
canonical_env: "RCH_FORCE_REMOTE",
aliases: &[],
flag: None,
kind: ControlKind::StrictRemote,
value_form: "0|1",
description: "Always attempt offload (bypass local-time/speedup gating) but still \
fail open to local. Distinct from RCH_REQUIRE_REMOTE.",
},
PlacementControl {
canonical_env: "RCH_QUEUE_WHEN_BUSY",
aliases: &[],
flag: None,
kind: ControlKind::Queue,
value_form: "0|1 (default 1)",
description: "Wait for a busy worker instead of immediately falling back to local. \
Set 0 to disable queueing.",
},
PlacementControl {
canonical_env: "RCH_DAEMON_WAIT_RESPONSE_TIMEOUT_SECS",
aliases: &["RCH_DAEMON_RESPONSE_TIMEOUT_SECS"],
flag: None,
kind: ControlKind::WaitTimeout,
value_form: "secs (>0)",
description: "Maximum time to wait for a queued worker before falling back.",
},
PlacementControl {
canonical_env: "RCH_VISIBILITY",
aliases: &["RCH_QUIET", "RCH_VERBOSE"],
flag: None,
kind: ControlKind::Visibility,
value_form: "none|summary|verbose",
description: "Hook output verbosity. RCH_QUIET=>none, RCH_VERBOSE=>verbose.",
},
PlacementControl {
canonical_env: "RCH_DISABLE_TARGET_REUSE",
aliases: &[],
flag: None,
kind: ControlKind::TargetDir,
value_form: "0|1",
description: "Use a legacy unique-per-job remote target dir instead of the pooled, \
reuse-friendly dir.",
},
PlacementControl {
canonical_env: "RCH_NO_SELF_HEALING",
aliases: &[],
flag: Some("--no-self-healing"),
kind: ControlKind::SelfHealing,
value_form: "0|1",
description: "Master switch disabling hook->daemon autostart and daemon hook install.",
},
];
CONTROLS
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ControlDiagnosticLevel {
Info,
Warning,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct ControlDiagnostic {
pub control: String,
pub level: ControlDiagnosticLevel,
pub message: String,
}
impl ControlDiagnostic {
fn info(control: &str, message: impl Into<String>) -> Self {
Self {
control: control.to_string(),
level: ControlDiagnosticLevel::Info,
message: message.into(),
}
}
fn warning(control: &str, message: impl Into<String>) -> Self {
Self {
control: control.to_string(),
level: ControlDiagnosticLevel::Warning,
message: message.into(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum RequestedWorkerStatus {
NotRequested,
Requested,
Honored,
Unavailable,
AdminDisabled,
TemporarilyBypassed,
WrongPlatform,
MissingRuntime,
ProjectExcluded,
NoFreeSlots,
}
impl RequestedWorkerStatus {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
RequestedWorkerStatus::NotRequested => "not_requested",
RequestedWorkerStatus::Requested => "requested",
RequestedWorkerStatus::Honored => "honored",
RequestedWorkerStatus::Unavailable => "unavailable",
RequestedWorkerStatus::AdminDisabled => "admin_disabled",
RequestedWorkerStatus::TemporarilyBypassed => "temporarily_bypassed",
RequestedWorkerStatus::WrongPlatform => "wrong_platform",
RequestedWorkerStatus::MissingRuntime => "missing_runtime",
RequestedWorkerStatus::ProjectExcluded => "project_excluded",
RequestedWorkerStatus::NoFreeSlots => "no_free_slots",
}
}
#[must_use]
pub fn is_refusal(self) -> bool {
!matches!(
self,
RequestedWorkerStatus::NotRequested
| RequestedWorkerStatus::Requested
| RequestedWorkerStatus::Honored
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RequestedWorkerFacts {
pub requested: Option<String>,
pub exists: bool,
pub admin_disabled: bool,
pub draining_or_drained: bool,
pub reachable: bool,
pub temporarily_bypassed: bool,
pub platform_matches: bool,
pub has_required_runtime: bool,
pub project_excluded: bool,
pub has_total_capacity: bool,
pub has_free_slots: bool,
pub estimated_cores: u32,
pub total_slots: u32,
pub admission_denial_code: Option<IncidentReasonCode>,
pub admission_denial_reason: Option<String>,
}
impl RequestedWorkerFacts {
#[must_use]
pub fn none() -> Self {
Self {
requested: None,
exists: false,
admin_disabled: false,
draining_or_drained: false,
reachable: true,
temporarily_bypassed: false,
platform_matches: true,
has_required_runtime: true,
project_excluded: false,
has_total_capacity: true,
has_free_slots: true,
estimated_cores: 0,
total_slots: 0,
admission_denial_code: None,
admission_denial_reason: None,
}
}
#[must_use]
pub fn admissible(id: impl Into<String>) -> Self {
Self {
requested: Some(id.into()),
exists: true,
..Self::none()
}
}
#[must_use]
pub fn from_diagnostic(
requested: impl Into<String>,
worker: &WorkerSelectionDiagnostic,
) -> Self {
let toolchain_inadmissible = worker
.reason_codes
.iter()
.any(|code| code.starts_with("toolchain."));
let admission_denial_code =
(worker.final_decision == WorkerSelectionDiagnosticDecision::Deny).then(|| {
if worker
.reason_codes
.iter()
.any(|code| code == "pressure.critical")
{
IncidentReasonCode::CriticalPressure
} else if worker.reason_codes.iter().any(|code| {
code.starts_with("topology.")
|| code.starts_with("preflight.")
|| code.starts_with("convergence.")
|| code.starts_with("reliability.")
}) {
IncidentReasonCode::HardPreflight
} else {
IncidentReasonCode::NoAdmissibleWorkers
}
});
Self {
requested: Some(requested.into()),
exists: true,
admin_disabled: worker.status.eq_ignore_ascii_case("disabled"),
draining_or_drained: worker.status.to_ascii_lowercase().contains("drain"),
reachable: !worker.status.eq_ignore_ascii_case("unreachable"),
temporarily_bypassed: worker.circuit_state.eq_ignore_ascii_case("open")
|| worker.status.to_ascii_lowercase().contains("bypass"),
platform_matches: !worker
.reason_codes
.iter()
.any(|code| code.contains("os_arch") || code.contains("platform")),
has_required_runtime: worker.runtime_available && !toolchain_inadmissible,
project_excluded: worker.active_project_excluded,
has_total_capacity: worker.total_slots >= worker.estimated_cores,
has_free_slots: worker.available_slots >= worker.estimated_cores,
estimated_cores: worker.estimated_cores,
total_slots: worker.total_slots,
admission_denial_code,
admission_denial_reason: admission_denial_code.map(|_| worker.final_reason.clone()),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct RequestedWorkerOutcome {
pub status: RequestedWorkerStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reason_code: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub next_action: Option<String>,
}
impl RequestedWorkerOutcome {
#[must_use]
pub fn not_requested() -> Self {
Self {
status: RequestedWorkerStatus::NotRequested,
reason_code: None,
next_action: None,
}
}
#[must_use]
pub fn requested() -> Self {
Self {
status: RequestedWorkerStatus::Requested,
reason_code: None,
next_action: None,
}
}
fn honored() -> Self {
Self {
status: RequestedWorkerStatus::Honored,
reason_code: None,
next_action: None,
}
}
fn refused(
status: RequestedWorkerStatus,
code: IncidentReasonCode,
next_action: impl Into<String>,
) -> Self {
Self {
status,
reason_code: Some(code.code().to_string()),
next_action: Some(next_action.into()),
}
}
}
#[must_use]
pub fn evaluate_requested_worker(facts: &RequestedWorkerFacts) -> RequestedWorkerOutcome {
let Some(id) = facts.requested.as_deref().filter(|s| !s.trim().is_empty()) else {
return RequestedWorkerOutcome::not_requested();
};
if !facts.exists {
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::Unavailable,
IncidentReasonCode::NoAdmissibleWorkers,
format!("'{id}' is not a configured worker; run `rch workers list` to see valid ids"),
);
}
if facts.admin_disabled {
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::AdminDisabled,
IncidentReasonCode::NoAdmissibleWorkers,
format!(
"'{id}' is operator-disabled; re-enable with `rch workers enable {id}` or request another worker"
),
);
}
if facts.draining_or_drained || !facts.reachable {
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::Unavailable,
IncidentReasonCode::NoAdmissibleWorkers,
format!(
"'{id}' is draining/unreachable; wait for it to return or request another worker"
),
);
}
if facts.temporarily_bypassed {
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::TemporarilyBypassed,
IncidentReasonCode::CircuitOpen,
format!(
"'{id}' is in transient quarantine; wait for auto-rejoin or request another worker"
),
);
}
if !facts.platform_matches {
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::WrongPlatform,
IncidentReasonCode::OsArchMismatch,
format!("'{id}' OS/arch does not match the build target; request a matching worker"),
);
}
if !facts.has_required_runtime {
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::MissingRuntime,
IncidentReasonCode::MissingRuntimeToolchainTarget,
format!(
"'{id}' lacks the required runtime/toolchain/target; install it or request another worker"
),
);
}
if facts.project_excluded {
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::ProjectExcluded,
IncidentReasonCode::ActiveProjectExclusion,
format!(
"'{id}' already runs this project (active-project exclusion); request another worker"
),
);
}
if !facts.has_total_capacity {
let next_action = if facts.total_slots > 0 && facts.estimated_cores > 0 {
format!(
"'{id}' has {total} total slot(s) but the request is estimated at {cores} core(s); \
pass -j {total} (or fewer), or request a larger worker",
total = facts.total_slots,
cores = facts.estimated_cores,
)
} else {
format!(
"'{id}' cannot fit the requested core count; lower the request (-j) or request a larger worker"
)
};
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::NoFreeSlots,
IncidentReasonCode::InsufficientSlots,
next_action,
);
}
if !facts.has_free_slots {
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::NoFreeSlots,
IncidentReasonCode::InsufficientSlots,
format!(
"'{id}' has no free slots right now; queue with RCH_QUEUE_WHEN_BUSY=1 or request another worker"
),
);
}
if let Some(code) = facts.admission_denial_code {
let reason = facts
.admission_denial_reason
.as_deref()
.unwrap_or("worker admission denied");
let next_action = match code {
IncidentReasonCode::CriticalPressure => format!(
"'{id}' failed admission under critical pressure ({reason}); remediate worker pressure or request another worker"
),
IncidentReasonCode::HardPreflight => format!(
"'{id}' failed a hard preflight ({reason}); run `rch diagnose -- <command>`, remediate the preflight, or request another worker"
),
_ => format!(
"'{id}' failed worker admission ({reason}); run `rch diagnose -- <command>` or request another worker"
),
};
return RequestedWorkerOutcome::refused(
RequestedWorkerStatus::Unavailable,
code,
next_action,
);
}
RequestedWorkerOutcome::honored()
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct PlacementPlan {
pub schema_version: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub requested_worker: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub requested_profile: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub effective_worker: Option<String>,
pub strict_remote_policy: StrictRemotePolicy,
pub queue_policy: QueuePolicy,
pub visibility_mode: VisibilityMode,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub wait_timeout_ms: Option<u64>,
pub target_dir_policy: TargetDirPolicy,
pub requested_worker_outcome: RequestedWorkerOutcome,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub diagnostics: Vec<ControlDiagnostic>,
}
impl PlacementPlan {
#[must_use]
pub fn schema_version() -> &'static str {
current_version(SchemaComponent::PlacementPlan)
}
#[must_use]
pub fn with_effective_worker(mut self, worker: Option<String>) -> Self {
self.effective_worker = worker;
self
}
#[must_use]
pub fn with_requested_worker_outcome(mut self, outcome: RequestedWorkerOutcome) -> Self {
self.requested_worker_outcome = outcome;
self
}
#[must_use]
pub fn control_state(&self) -> ControlState {
ControlState {
requested_worker: self.requested_worker.clone(),
requested_profile: self.requested_profile.clone(),
strict_remote_policy: self.strict_remote_policy != StrictRemotePolicy::Off,
queue_policy: (self.queue_policy != QueuePolicy::default())
.then(|| self.queue_policy.as_str().to_string()),
visibility_mode: (self.visibility_mode != VisibilityMode::Default)
.then(|| self.visibility_mode.as_str().to_string()),
wait_timeout_ms: self.wait_timeout_ms,
target_dir_policy: (self.target_dir_policy != TargetDirPolicy::default())
.then(|| self.target_dir_policy.as_str().to_string()),
}
}
}
#[must_use]
pub fn env_truthy(value: &str) -> bool {
matches!(
value.trim().to_ascii_lowercase().as_str(),
"1" | "true" | "yes" | "on" | "enabled"
)
}
fn env_falsy(value: &str) -> bool {
matches!(
value.trim().to_ascii_lowercase().as_str(),
"0" | "false" | "no" | "off" | "disabled"
)
}
pub fn resolve_placement<F>(get: F) -> PlacementPlan
where
F: Fn(&str) -> Option<String>,
{
let mut diagnostics = Vec::new();
let worker_primary = get("RCH_WORKER").filter(|v| !v.trim().is_empty());
let worker_alias = get("RCH_WORKERS").filter(|v| !v.trim().is_empty());
let requested_worker = match (&worker_primary, &worker_alias) {
(Some(p), Some(a)) => {
diagnostics.push(ControlDiagnostic::info(
"RCH_WORKER",
"RCH_WORKER and its alias RCH_WORKERS are both set; merging both into the requested set",
));
Some(merge_worker_lists(p, a))
}
(Some(p), None) => Some(p.trim().to_string()),
(None, Some(a)) => {
diagnostics.push(ControlDiagnostic::info(
"RCH_WORKERS",
"RCH_WORKERS is an alias for the canonical RCH_WORKER",
));
Some(a.trim().to_string())
}
(None, None) => None,
};
let requested_profile = get("RCH_PRESET").filter(|v| !v.trim().is_empty());
let require_remote = get("RCH_REQUIRE_REMOTE").is_some_and(|v| env_truthy(&v));
let force_remote = get("RCH_FORCE_REMOTE").is_some_and(|v| env_truthy(&v));
let strict_remote_policy = if require_remote {
if force_remote {
diagnostics.push(ControlDiagnostic::info(
"RCH_REQUIRE_REMOTE",
"RCH_REQUIRE_REMOTE (fail-closed) supersedes RCH_FORCE_REMOTE (fail-open)",
));
}
StrictRemotePolicy::RequireRemote
} else if force_remote {
StrictRemotePolicy::ForceRemote
} else {
StrictRemotePolicy::Off
};
let queue_policy = match get("RCH_QUEUE_WHEN_BUSY") {
None => QueuePolicy::QueueWhenBusy,
Some(v) if env_falsy(&v) => QueuePolicy::NoQueue,
Some(v) if env_truthy(&v) || v.trim().is_empty() => QueuePolicy::QueueWhenBusy,
Some(v) => {
diagnostics.push(ControlDiagnostic::warning(
"RCH_QUEUE_WHEN_BUSY",
format!("unrecognized value {v:?}; interpreted as enabled (queue_when_busy)"),
));
QueuePolicy::QueueWhenBusy
}
};
let (wait_timeout_ms, wait_diag) = resolve_wait_timeout(&get);
diagnostics.extend(wait_diag);
let (visibility_mode, vis_diag) = resolve_visibility(&get);
diagnostics.extend(vis_diag);
let target_dir_policy = if get("RCH_DISABLE_TARGET_REUSE").is_some_and(|v| env_truthy(&v)) {
TargetDirPolicy::PerJob
} else if get("CARGO_TARGET_DIR")
.map(|v| v.contains(".rch-target") || v.contains("rch-worker"))
.unwrap_or(false)
{
TargetDirPolicy::WorkerScoped
} else {
TargetDirPolicy::Pooled
};
let requested_worker_outcome = if requested_worker.is_some() {
RequestedWorkerOutcome::requested()
} else {
RequestedWorkerOutcome::not_requested()
};
PlacementPlan {
schema_version: PlacementPlan::schema_version().to_string(),
requested_worker,
requested_profile: requested_profile.map(|v| v.trim().to_string()),
effective_worker: None,
strict_remote_policy,
queue_policy,
visibility_mode,
wait_timeout_ms,
target_dir_policy,
requested_worker_outcome,
diagnostics,
}
}
pub fn resolve_placement_with_role<F>(get: F, role: crate::BoxRole) -> PlacementPlan
where
F: Fn(&str) -> Option<String>,
{
let strict_env_present =
get("RCH_REQUIRE_REMOTE").is_some() || get("RCH_FORCE_REMOTE").is_some();
let mut plan = resolve_placement(get);
if role == crate::BoxRole::Dispatcher
&& !strict_env_present
&& plan.strict_remote_policy == StrictRemotePolicy::Off
{
plan.strict_remote_policy = StrictRemotePolicy::RequireRemote;
plan.diagnostics.push(ControlDiagnostic::info(
"general.role",
"role=dispatcher defaults offloadable builds to fail-closed + queue \
(set RCH_REQUIRE_REMOTE=0 or RCH_FORCE_REMOTE=1 per call to override)",
));
}
plan
}
fn merge_worker_lists(primary: &str, alias: &str) -> String {
let mut seen = Vec::new();
for part in primary
.split(',')
.chain(alias.split(','))
.map(str::trim)
.filter(|p| !p.is_empty())
{
if !seen.contains(&part) {
seen.push(part);
}
}
seen.join(",")
}
fn resolve_wait_timeout<F>(get: &F) -> (Option<u64>, Vec<ControlDiagnostic>)
where
F: Fn(&str) -> Option<String>,
{
const CANONICAL: &str = "RCH_DAEMON_WAIT_RESPONSE_TIMEOUT_SECS";
const ALIAS: &str = "RCH_DAEMON_RESPONSE_TIMEOUT_SECS";
let mut diags = Vec::new();
let (name, raw) = match (get(CANONICAL), get(ALIAS)) {
(Some(v), _) => (CANONICAL, Some(v)),
(None, Some(v)) => {
diags.push(ControlDiagnostic::info(
ALIAS,
"RCH_DAEMON_RESPONSE_TIMEOUT_SECS also applies to non-wait queries; \
prefer RCH_DAEMON_WAIT_RESPONSE_TIMEOUT_SECS for the queue wait timeout",
));
(ALIAS, Some(v))
}
(None, None) => (CANONICAL, None),
};
let Some(raw) = raw else {
return (None, diags);
};
match raw.trim().parse::<u64>() {
Ok(secs) if secs > 0 => (Some(secs.saturating_mul(1000)), diags),
_ => {
diags.push(ControlDiagnostic::warning(
name,
format!("invalid timeout {raw:?}; expected a positive integer in seconds; using the default"),
));
(None, diags)
}
}
}
fn resolve_visibility<F>(get: &F) -> (VisibilityMode, Vec<ControlDiagnostic>)
where
F: Fn(&str) -> Option<String>,
{
let mut diags = Vec::new();
if let Some(raw) = get("RCH_VISIBILITY") {
match VisibilityMode::parse(&raw) {
Some(mode) => return (mode, diags),
None => {
diags.push(ControlDiagnostic::warning(
"RCH_VISIBILITY",
format!("unrecognized value {raw:?}; expected none|summary|verbose; deferring to config"),
));
}
}
}
if get("RCH_QUIET").is_some_and(|v| env_truthy(&v)) {
return (VisibilityMode::None, diags);
}
if get("RCH_VERBOSE").is_some_and(|v| env_truthy(&v)) {
return (VisibilityMode::Verbose, diags);
}
(VisibilityMode::Default, diags)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{RequiredRuntime, WorkerId, WorkerSelectionDiagnosticDecision};
use std::collections::HashMap;
fn env(pairs: &[(&str, &str)]) -> impl Fn(&str) -> Option<String> {
let map: HashMap<String, String> = pairs
.iter()
.map(|(k, v)| ((*k).to_string(), (*v).to_string()))
.collect();
move |k: &str| map.get(k).cloned()
}
fn admissibility_diagnostic() -> WorkerSelectionDiagnostic {
WorkerSelectionDiagnostic {
worker_id: WorkerId::new("css"),
status: "healthy".to_string(),
circuit_state: "closed".to_string(),
pressure_state: "healthy".to_string(),
pressure_reason_code: "pressure.healthy".to_string(),
success_rate: Some(1.0),
min_success_rate: 0.8,
fallback_min_success_rate: 0.5,
required_runtime: RequiredRuntime::Rust,
runtime_available: true,
available_slots: 8,
total_slots: 8,
estimated_cores: 2,
active_project_excluded: false,
final_decision: WorkerSelectionDiagnosticDecision::Allow,
final_reason: "eligible".to_string(),
reason_codes: vec![],
}
}
#[test]
fn strict_remote_off_by_default() {
let plan = resolve_placement(env(&[]));
assert_eq!(plan.strict_remote_policy, StrictRemotePolicy::Off);
assert!(!plan.strict_remote_policy.fail_closed());
assert!(!plan.strict_remote_policy.forces_offload());
}
#[test]
fn force_remote_is_fail_open() {
let plan = resolve_placement(env(&[("RCH_FORCE_REMOTE", "1")]));
assert_eq!(plan.strict_remote_policy, StrictRemotePolicy::ForceRemote);
assert!(plan.strict_remote_policy.forces_offload());
assert!(!plan.strict_remote_policy.fail_closed());
}
#[test]
fn dispatcher_role_defaults_fail_closed_with_env_override() {
use crate::BoxRole;
let plan = resolve_placement_with_role(env(&[]), BoxRole::Dispatcher);
assert_eq!(
plan.strict_remote_policy,
StrictRemotePolicy::RequireRemote,
"dispatcher must never repopulate local rustc by default"
);
assert_eq!(plan.queue_policy, QueuePolicy::QueueWhenBusy);
assert!(
plan.diagnostics.iter().any(|d| d.control == "general.role"),
"the role default must be visible in diagnostics"
);
let opted_out =
resolve_placement_with_role(env(&[("RCH_REQUIRE_REMOTE", "0")]), BoxRole::Dispatcher);
assert_eq!(opted_out.strict_remote_policy, StrictRemotePolicy::Off);
let forced =
resolve_placement_with_role(env(&[("RCH_FORCE_REMOTE", "1")]), BoxRole::Dispatcher);
assert_eq!(forced.strict_remote_policy, StrictRemotePolicy::ForceRemote);
let required =
resolve_placement_with_role(env(&[("RCH_REQUIRE_REMOTE", "1")]), BoxRole::Dispatcher);
assert_eq!(
required.strict_remote_policy,
StrictRemotePolicy::RequireRemote
);
}
#[test]
fn worker_and_hybrid_roles_change_nothing() {
use crate::BoxRole;
for role in [BoxRole::Worker, BoxRole::Hybrid] {
let plan = resolve_placement_with_role(env(&[]), role);
let baseline = resolve_placement(env(&[]));
assert_eq!(plan.strict_remote_policy, baseline.strict_remote_policy);
assert_eq!(plan.queue_policy, baseline.queue_policy);
assert_eq!(
plan.diagnostics.len(),
baseline.diagnostics.len(),
"{role:?} must add no diagnostics"
);
}
}
#[test]
fn require_remote_is_fail_closed() {
let plan = resolve_placement(env(&[("RCH_REQUIRE_REMOTE", "true")]));
assert_eq!(plan.strict_remote_policy, StrictRemotePolicy::RequireRemote);
assert!(plan.strict_remote_policy.fail_closed());
assert!(plan.strict_remote_policy.forces_offload());
}
#[test]
fn require_remote_supersedes_force_remote_with_diagnostic() {
let plan = resolve_placement(env(&[
("RCH_REQUIRE_REMOTE", "1"),
("RCH_FORCE_REMOTE", "1"),
]));
assert_eq!(plan.strict_remote_policy, StrictRemotePolicy::RequireRemote);
assert!(
plan.diagnostics
.iter()
.any(|d| d.control == "RCH_REQUIRE_REMOTE"
&& d.level == ControlDiagnosticLevel::Info),
"expected a precedence diagnostic, got {:?}",
plan.diagnostics
);
}
#[test]
fn queue_defaults_enabled() {
let plan = resolve_placement(env(&[]));
assert_eq!(plan.queue_policy, QueuePolicy::QueueWhenBusy);
assert!(plan.queue_policy.waits());
}
#[test]
fn queue_disabled_by_zero() {
let plan = resolve_placement(env(&[("RCH_QUEUE_WHEN_BUSY", "0")]));
assert_eq!(plan.queue_policy, QueuePolicy::NoQueue);
assert!(!plan.queue_policy.waits());
}
#[test]
fn queue_unrecognized_value_warns_not_silently_ignored() {
let plan = resolve_placement(env(&[("RCH_QUEUE_WHEN_BUSY", "maybe")]));
assert_eq!(plan.queue_policy, QueuePolicy::QueueWhenBusy);
assert!(
plan.diagnostics
.iter()
.any(|d| d.control == "RCH_QUEUE_WHEN_BUSY"
&& d.level == ControlDiagnosticLevel::Warning)
);
}
#[test]
fn wait_timeout_seconds_to_ms() {
let plan = resolve_placement(env(&[("RCH_DAEMON_WAIT_RESPONSE_TIMEOUT_SECS", "120")]));
assert_eq!(plan.wait_timeout_ms, Some(120_000));
}
#[test]
fn wait_timeout_alias_emits_info() {
let plan = resolve_placement(env(&[("RCH_DAEMON_RESPONSE_TIMEOUT_SECS", "45")]));
assert_eq!(plan.wait_timeout_ms, Some(45_000));
assert!(
plan.diagnostics
.iter()
.any(|d| d.control == "RCH_DAEMON_RESPONSE_TIMEOUT_SECS"
&& d.level == ControlDiagnosticLevel::Info)
);
}
#[test]
fn wait_timeout_invalid_warns_and_falls_back() {
let plan = resolve_placement(env(&[("RCH_DAEMON_WAIT_RESPONSE_TIMEOUT_SECS", "soon")]));
assert_eq!(plan.wait_timeout_ms, None);
assert!(
plan.diagnostics
.iter()
.any(|d| d.level == ControlDiagnosticLevel::Warning)
);
}
#[test]
fn visibility_canonical_values() {
for (raw, expected) in [
("none", VisibilityMode::None),
("summary", VisibilityMode::Summary),
("verbose", VisibilityMode::Verbose),
] {
let plan = resolve_placement(env(&[("RCH_VISIBILITY", raw)]));
assert_eq!(plan.visibility_mode, expected);
}
}
#[test]
fn visibility_quiet_and_verbose_aliases() {
let quiet = resolve_placement(env(&[("RCH_QUIET", "1")]));
assert_eq!(quiet.visibility_mode, VisibilityMode::None);
let verbose = resolve_placement(env(&[("RCH_VERBOSE", "1")]));
assert_eq!(verbose.visibility_mode, VisibilityMode::Verbose);
}
#[test]
fn visibility_invalid_warns_then_falls_back_to_alias() {
let plan = resolve_placement(env(&[("RCH_VISIBILITY", "ultra"), ("RCH_QUIET", "1")]));
assert_eq!(plan.visibility_mode, VisibilityMode::None);
assert!(
plan.diagnostics.iter().any(
|d| d.control == "RCH_VISIBILITY" && d.level == ControlDiagnosticLevel::Warning
)
);
}
#[test]
fn requested_worker_and_profile_captured() {
let plan = resolve_placement(env(&[("RCH_WORKER", "css"), ("RCH_PRESET", "fast")]));
assert_eq!(plan.requested_worker.as_deref(), Some("css"));
assert_eq!(plan.requested_profile.as_deref(), Some("fast"));
assert_eq!(
plan.requested_worker_outcome.status,
RequestedWorkerStatus::Requested
);
}
#[test]
fn worker_alias_merges_and_dedupes() {
let plan = resolve_placement(env(&[
("RCH_WORKER", "css, ovh-a"),
("RCH_WORKERS", "ovh-a,ovh-b"),
]));
assert_eq!(plan.requested_worker.as_deref(), Some("css,ovh-a,ovh-b"));
assert!(plan.diagnostics.iter().any(|d| d.control == "RCH_WORKER"));
}
#[test]
fn target_dir_policy_variants() {
let pooled = resolve_placement(env(&[]));
assert_eq!(pooled.target_dir_policy, TargetDirPolicy::Pooled);
let per_job = resolve_placement(env(&[("RCH_DISABLE_TARGET_REUSE", "1")]));
assert_eq!(per_job.target_dir_policy, TargetDirPolicy::PerJob);
let scoped = resolve_placement(env(&[("CARGO_TARGET_DIR", "/tmp/.rch-target/css")]));
assert_eq!(scoped.target_dir_policy, TargetDirPolicy::WorkerScoped);
}
#[test]
fn evaluate_not_requested() {
let out = evaluate_requested_worker(&RequestedWorkerFacts::none());
assert_eq!(out.status, RequestedWorkerStatus::NotRequested);
assert!(out.reason_code.is_none());
}
#[test]
fn evaluate_honored() {
let out = evaluate_requested_worker(&RequestedWorkerFacts::admissible("css"));
assert_eq!(out.status, RequestedWorkerStatus::Honored);
assert!(out.reason_code.is_none());
assert!(!out.status.is_refusal());
}
#[test]
fn evaluate_unknown_worker_refused() {
let facts = RequestedWorkerFacts {
requested: Some("ghost".into()),
exists: false,
..RequestedWorkerFacts::none()
};
let out = evaluate_requested_worker(&facts);
assert_eq!(out.status, RequestedWorkerStatus::Unavailable);
assert_eq!(out.reason_code.as_deref(), Some("RCH-I001"));
assert!(
out.next_action
.as_deref()
.unwrap()
.contains("rch workers list")
);
assert!(out.status.is_refusal());
}
#[test]
fn evaluate_admin_disabled_refused() {
let facts = RequestedWorkerFacts {
admin_disabled: true,
..RequestedWorkerFacts::admissible("css")
};
let out = evaluate_requested_worker(&facts);
assert_eq!(out.status, RequestedWorkerStatus::AdminDisabled);
assert_eq!(out.reason_code.as_deref(), Some("RCH-I001"));
assert!(
out.next_action
.as_deref()
.unwrap()
.contains("rch workers enable")
);
}
#[test]
fn evaluate_wrong_platform_refused() {
let facts = RequestedWorkerFacts {
platform_matches: false,
..RequestedWorkerFacts::admissible("css")
};
let out = evaluate_requested_worker(&facts);
assert_eq!(out.status, RequestedWorkerStatus::WrongPlatform);
assert_eq!(
out.reason_code.as_deref(),
Some(IncidentReasonCode::OsArchMismatch.code())
);
}
#[test]
fn evaluate_missing_runtime_refused() {
let facts = RequestedWorkerFacts {
has_required_runtime: false,
..RequestedWorkerFacts::admissible("css")
};
let out = evaluate_requested_worker(&facts);
assert_eq!(out.status, RequestedWorkerStatus::MissingRuntime);
assert_eq!(
out.reason_code.as_deref(),
Some(IncidentReasonCode::MissingRuntimeToolchainTarget.code())
);
}
#[test]
fn evaluate_project_excluded_refused() {
let facts = RequestedWorkerFacts {
project_excluded: true,
..RequestedWorkerFacts::admissible("css")
};
let out = evaluate_requested_worker(&facts);
assert_eq!(out.status, RequestedWorkerStatus::ProjectExcluded);
assert_eq!(
out.reason_code.as_deref(),
Some(IncidentReasonCode::ActiveProjectExclusion.code())
);
}
#[test]
fn evaluate_no_slots_refused() {
let facts = RequestedWorkerFacts {
has_free_slots: false,
..RequestedWorkerFacts::admissible("css")
};
let out = evaluate_requested_worker(&facts);
assert_eq!(out.status, RequestedWorkerStatus::NoFreeSlots);
assert_eq!(
out.reason_code.as_deref(),
Some(IncidentReasonCode::InsufficientSlots.code())
);
}
#[test]
fn evaluate_insufficient_capacity_refused_without_queue_advice() {
let mut diagnostic = admissibility_diagnostic();
diagnostic.worker_id = WorkerId::new("tiny");
diagnostic.available_slots = 1;
diagnostic.total_slots = 1;
diagnostic.estimated_cores = 2;
let facts = RequestedWorkerFacts::from_diagnostic("tiny", &diagnostic);
let out = evaluate_requested_worker(&facts);
assert_eq!(out.status, RequestedWorkerStatus::NoFreeSlots);
assert_eq!(
out.reason_code.as_deref(),
Some(IncidentReasonCode::InsufficientSlots.code())
);
let next_action = out.next_action.expect("capacity refusal needs an action");
assert!(
next_action.contains("1 total slot"),
"should name total slots: {next_action}"
);
assert!(
next_action.contains("2 core"),
"should name estimated cores: {next_action}"
);
assert!(
next_action.contains("-j 1"),
"should name the exact -j value that fits: {next_action}"
);
assert!(!next_action.contains("RCH_QUEUE_WHEN_BUSY"));
}
#[test]
fn diagnostic_toolchain_refusal_maps_to_missing_runtime_code() {
let mut diagnostic = admissibility_diagnostic();
diagnostic.final_decision = WorkerSelectionDiagnosticDecision::Deny;
diagnostic.final_reason = "toolchain version mismatch".to_string();
diagnostic.reason_codes = vec!["toolchain.version_mismatch".to_string()];
let facts = RequestedWorkerFacts::from_diagnostic("css", &diagnostic);
let out = evaluate_requested_worker(&facts);
assert_eq!(out.status, RequestedWorkerStatus::MissingRuntime);
assert_eq!(
out.reason_code.as_deref(),
Some(IncidentReasonCode::MissingRuntimeToolchainTarget.code())
);
}
#[test]
fn remaining_diagnostic_denials_never_report_honored() {
let cases = [
(
"critical pressure",
"pressure.critical",
IncidentReasonCode::CriticalPressure,
),
(
"topology preflight failed",
"topology.preflight_failed",
IncidentReasonCode::HardPreflight,
),
(
"success rate below fallback floor",
"health.below_fallback_min_success_rate",
IncidentReasonCode::NoAdmissibleWorkers,
),
];
for (reason, reason_code, expected_incident) in cases {
let mut diagnostic = admissibility_diagnostic();
diagnostic.final_decision = WorkerSelectionDiagnosticDecision::Deny;
diagnostic.final_reason = reason.to_string();
diagnostic.reason_codes = vec![reason_code.to_string()];
let facts = RequestedWorkerFacts::from_diagnostic("css", &diagnostic);
let out = evaluate_requested_worker(&facts);
assert!(out.status.is_refusal(), "{reason_code} must be refused");
assert_eq!(out.reason_code.as_deref(), Some(expected_incident.code()));
assert!(out.next_action.is_some());
}
}
#[test]
fn evaluate_temporary_bypass_refused() {
let facts = RequestedWorkerFacts {
temporarily_bypassed: true,
..RequestedWorkerFacts::admissible("css")
};
let out = evaluate_requested_worker(&facts);
assert_eq!(out.status, RequestedWorkerStatus::TemporarilyBypassed);
assert_eq!(
out.reason_code.as_deref(),
Some(IncidentReasonCode::CircuitOpen.code())
);
}
#[test]
fn refusal_priority_is_most_specific_first() {
let facts = RequestedWorkerFacts {
requested: Some("ghost".into()),
exists: false,
has_required_runtime: false,
..RequestedWorkerFacts::none()
};
assert_eq!(
evaluate_requested_worker(&facts).status,
RequestedWorkerStatus::Unavailable
);
}
#[test]
fn control_state_bridge_is_sparse() {
let plan = resolve_placement(env(&[]));
assert!(plan.control_state().is_empty());
}
#[test]
fn control_state_bridge_carries_set_fields() {
let plan = resolve_placement(env(&[
("RCH_WORKER", "css"),
("RCH_REQUIRE_REMOTE", "1"),
("RCH_QUEUE_WHEN_BUSY", "0"),
]));
let cs = plan.control_state();
assert_eq!(cs.requested_worker.as_deref(), Some("css"));
assert!(cs.strict_remote_policy);
assert_eq!(cs.queue_policy.as_deref(), Some("no_queue"));
assert!(!cs.is_empty());
}
#[test]
fn plan_round_trips_through_json() {
let plan = resolve_placement(env(&[("RCH_WORKER", "css"), ("RCH_FORCE_REMOTE", "1")]))
.with_effective_worker(Some("ovh-a".to_string()))
.with_requested_worker_outcome(evaluate_requested_worker(
&RequestedWorkerFacts::admissible("css"),
));
let v = serde_json::to_value(&plan).unwrap();
assert_eq!(v["strict_remote_policy"], "force_remote");
assert_eq!(v["queue_policy"], "queue_when_busy");
assert_eq!(v["requested_worker"], "css");
assert_eq!(v["effective_worker"], "ovh-a");
assert_eq!(v["requested_worker_outcome"]["status"], "honored");
let back: PlacementPlan = serde_json::from_value(v).unwrap();
assert_eq!(back, plan);
}
#[test]
fn schema_version_is_pinned() {
let plan = resolve_placement(env(&[]));
assert_eq!(plan.schema_version, PlacementPlan::schema_version());
}
#[test]
fn registry_canonical_names_unique_and_distinct_from_aliases() {
let controls = placement_controls();
let mut names = std::collections::HashSet::new();
for c in controls {
assert!(
names.insert(c.canonical_env),
"duplicate canonical env {}",
c.canonical_env
);
}
for c in controls {
for alias in c.aliases {
assert!(
!names.contains(alias),
"alias {alias} collides with a canonical name"
);
}
}
}
#[test]
fn registry_covers_the_audited_controls() {
let controls = placement_controls();
let has = |n: &str| controls.iter().any(|c| c.canonical_env == n);
for required in [
"RCH_WORKER",
"RCH_REQUIRE_REMOTE",
"RCH_FORCE_REMOTE",
"RCH_QUEUE_WHEN_BUSY",
"RCH_VISIBILITY",
"RCH_NO_SELF_HEALING",
] {
assert!(has(required), "registry missing audited control {required}");
}
}
}