use degenbot_config::FleetProfile;
use crate::budget::{BudgetError, BudgetMode, BudgetOverrides, FleetBudget};
use crate::dispatcher::BootError;
pub const PLAN_ID: &str = "fleetplan/1";
pub use crate::budget::HOST_FLOOR_CORES;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Binding {
Pinned,
Serial,
}
impl Binding {
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::Pinned => "pinned",
Self::Serial => "logical",
}
}
#[must_use]
pub const fn name(self) -> &'static str {
match self {
Self::Pinned => "pinned",
Self::Serial => "serial",
}
}
}
impl std::fmt::Display for Binding {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.name())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct FleetPlan {
pub id: &'static str,
pub binding: Binding,
pub oversubscribed: bool,
pub budget_cpus: f64,
pub tier_refusal: Option<BudgetError>,
}
impl FleetPlan {
pub fn projected_budget(&self, overrides: &BudgetOverrides) -> Result<FleetBudget, BootError> {
let mode = match self.binding {
Binding::Pinned if !self.oversubscribed => BudgetMode::Pinned,
Binding::Pinned => BudgetMode::PinnedMarked,
Binding::Serial => BudgetMode::Serial,
};
FleetBudget::project(self.budget_cpus, overrides, mode).map_err(BootError::from)
}
#[must_use]
pub fn pending_serial_refusal(&self) -> BootError {
match self.tier_refusal {
Some(refusal) => BootError::Budget(refusal),
None => BootError::Invariant(
"the serial binding (the 2-5-core tier) is pending \
— forced serial refuses rather than run the pinned topology \
silently narrower",
),
}
}
}
pub fn plan(
quota_cpus: f64,
profile: FleetProfile,
overrides: &BudgetOverrides,
) -> Result<FleetPlan, BootError> {
#[expect(
clippy::cast_possible_truncation,
reason = "quota floors are small positive values (core counts)"
)]
#[expect(
clippy::cast_sign_loss,
reason = "the quota is floored at 1.0 before the cast"
)]
let quota_floor = quota_cpus.max(1.0).floor() as u64;
if quota_floor < HOST_FLOOR_CORES {
return Err(BootError::Budget(BudgetError::BelowHostFloor {
quota: quota_cpus,
}));
}
match profile {
FleetProfile::Auto => match FleetBudget::derive(quota_cpus, overrides) {
Ok(_) => {
validate_io_workers(Binding::Pinned, overrides)?;
Ok(FleetPlan {
id: PLAN_ID,
binding: Binding::Pinned,
oversubscribed: false,
budget_cpus: quota_cpus,
tier_refusal: None,
})
}
Err(refusal @ BudgetError::QuotaTooSmallForPinnedRoles { .. }) => {
validate_io_workers(Binding::Serial, overrides)?;
Ok(FleetPlan {
id: PLAN_ID,
binding: Binding::Serial,
oversubscribed: false,
budget_cpus: quota_cpus,
tier_refusal: Some(refusal),
})
}
Err(other) => Err(BootError::Budget(other)),
},
FleetProfile::Pinned => {
validate_io_workers(Binding::Pinned, overrides)?;
let (oversubscribed, tier_refusal) = match FleetBudget::derive(quota_cpus, overrides) {
Ok(_) => (false, None),
Err(refusal) => (true, Some(refusal)),
};
Ok(FleetPlan {
id: PLAN_ID,
binding: Binding::Pinned,
oversubscribed,
budget_cpus: quota_cpus,
tier_refusal,
})
}
FleetProfile::Serial => {
validate_io_workers(Binding::Serial, overrides)?;
Ok(FleetPlan {
id: PLAN_ID,
binding: Binding::Serial,
oversubscribed: false,
budget_cpus: quota_cpus,
tier_refusal: None,
})
}
}
}
fn validate_io_workers(binding: Binding, overrides: &BudgetOverrides) -> Result<(), BootError> {
let Some(requested) = overrides.ambient_io_workers else {
return Ok(());
};
let legal = match binding {
Binding::Pinned => requested >= 1,
Binding::Serial => requested == 1,
};
if legal {
return Ok(());
}
Err(BootError::Budget(BudgetError::IoWorkersOutOfBounds {
requested,
binding: binding.name(),
}))
}
#[cfg(test)]
#[expect(clippy::expect_used)]
mod tests {
use super::*;
use crate::dispatcher::SlotLayout;
use degenbot_config::FleetProfile;
fn overrides() -> BudgetOverrides {
BudgetOverrides::default()
}
#[test]
fn the_tier_table_is_the_contract() {
let err = plan(1.5, FleetProfile::Auto, &overrides()).expect_err("sub-2-core host");
assert!(
matches!(err, BootError::Budget(BudgetError::BelowHostFloor { quota }) if (quota - 1.5).abs() < f64::EPSILON),
"below-2-cores refuses with the typed host-floor error, got {err:?}"
);
let p = plan(2.0, FleetProfile::Auto, &overrides()).expect("2-core host plans");
assert_eq!(p.binding, Binding::Serial);
assert!(!p.oversubscribed);
assert_eq!(p.id, PLAN_ID);
let p = plan(5.99, FleetProfile::Auto, &overrides()).expect("5.99-core host plans");
assert_eq!(p.binding, Binding::Serial);
let p = plan(6.0, FleetProfile::Auto, &overrides()).expect("6-core host plans");
assert_eq!(p.binding, Binding::Pinned);
assert!(!p.oversubscribed);
let p = plan(2.0, FleetProfile::Pinned, &overrides()).expect("forced pinned plans");
assert_eq!(p.binding, Binding::Pinned);
assert!(
p.oversubscribed,
"a forced pinned binding below the floor is marked"
);
let p = plan(24.0, FleetProfile::Serial, &overrides()).expect("forced serial plans");
assert_eq!(p.binding, Binding::Serial);
assert!(!p.oversubscribed);
assert!(p.tier_refusal.is_none());
}
#[test]
fn the_auto_serial_tier_carries_the_pinned_refusal() {
let p = plan(4.0, FleetProfile::Auto, &overrides()).expect("4-core host plans");
assert_eq!(p.binding, Binding::Serial);
let refusal = p.tier_refusal.as_ref().expect("the tier refusal rides");
assert!(
matches!(
refusal,
BudgetError::QuotaTooSmallForPinnedRoles { quota, required }
if (*quota - 4.0).abs() < f64::EPSILON && *required == 6
),
"the carried refusal is the pinned derivation's own, got {refusal:?}"
);
assert!(matches!(
p.pending_serial_refusal(),
BootError::Budget(BudgetError::QuotaTooSmallForPinnedRoles { .. })
));
let forced = plan(24.0, FleetProfile::Serial, &overrides()).expect("forced serial plans");
assert!(matches!(
forced.pending_serial_refusal(),
BootError::Invariant(_)
));
}
#[test]
fn the_forced_pinned_oversubscription_carries_the_pinned_floor_refusal() {
let p = plan(4.0, FleetProfile::Pinned, &overrides()).expect("forced pinned plans");
assert_eq!(p.binding, Binding::Pinned);
assert!(p.oversubscribed);
let refusal = p
.tier_refusal
.as_ref()
.expect("the overridden refusal rides");
assert!(
matches!(
refusal,
BudgetError::QuotaTooSmallForPinnedRoles { quota, required }
if (*quota - 4.0).abs() < f64::EPSILON && *required == 6
),
"the carried refusal is the pinned derivation's own, got {refusal:?}"
);
for quota in [6.0_f64, 8.0, 24.0] {
let p = plan(quota, FleetProfile::Pinned, &overrides()).expect("eligible host plans");
assert!(!p.oversubscribed);
assert!(p.tier_refusal.is_none());
}
}
#[test]
fn io_workers_overrides_are_validated_against_plan_bounds() {
let ov = BudgetOverrides {
ambient_io_workers: Some(0),
..overrides()
};
let err = plan(8.0, FleetProfile::Pinned, &ov).expect_err("A=0 refuses");
assert!(
matches!(
err,
BootError::Budget(BudgetError::IoWorkersOutOfBounds {
requested: 0,
binding: "pinned"
})
),
"the out-of-bounds override names the request and the binding, got {err:?}"
);
let ov = BudgetOverrides {
ambient_io_workers: Some(2),
..overrides()
};
let err = plan(4.0, FleetProfile::Auto, &ov).expect_err("serial A=2 refuses");
assert!(
matches!(
err,
BootError::Budget(BudgetError::IoWorkersOutOfBounds {
requested: 2,
binding: "serial"
})
),
"the serial tier validates its one-lane bound, got {err:?}"
);
let ov = BudgetOverrides {
ambient_io_workers: Some(2),
..overrides()
};
let p = plan(8.0, FleetProfile::Auto, &ov).expect("8-core A=2 plans");
assert_eq!(p.binding, Binding::Pinned);
assert_eq!(
p.projected_budget(&ov)
.expect("projection derives")
.ambient_cpus,
2
);
}
#[test]
fn plan_projections_yield_legal_non_empty_layouts() {
for quota in [2.0_f64, 2.5, 4.0, 5.99, 24.0] {
let p = plan(quota, FleetProfile::Serial, &overrides()).expect("serial plans");
let b = p
.projected_budget(&overrides())
.expect("serial projection is total");
assert_eq!(b.solver_pin_count, 1, "serial-0: exactly one solve seat");
assert_eq!(b.resolve_cpus, 1);
assert!(b.pool_state_updater_slots >= 1);
assert!(b.sim_slot_cap >= 1, "sim per budget");
SlotLayout::of(&b).expect("the serial projection hosts a legal layout");
}
for quota in [2.0_f64, 4.0, 5.99] {
let p = plan(quota, FleetProfile::Pinned, &overrides()).expect("forced pinned plans");
assert!(p.oversubscribed);
let b = p
.projected_budget(&overrides())
.expect("the marked projection is total");
assert!(
b.solver_pin_count >= 1,
"station legality: the pin count floors at 1"
);
assert!(
(b.fractional_remainder - 0.0).abs() < 1e-9,
"oversubscribed: no spendable remainder"
);
SlotLayout::of(&b).expect("the marked projection hosts a legal layout");
}
}
#[test]
fn the_pinned_eligible_projection_is_the_one_derivation() {
for quota in [6.0_f64, 8.0, 24.0, 6.5] {
let p = plan(quota, FleetProfile::Auto, &overrides()).expect("eligible host plans");
assert_eq!(p.binding, Binding::Pinned);
assert_eq!(
p.projected_budget(&overrides())
.expect("projection derives"),
FleetBudget::derive(quota, &overrides()).expect("the derivation")
);
}
}
}