Skip to main content

ferrox/scheduling/
problem.rs

1use serde::{Deserialize, Serialize};
2
3/// An agent that can execute tasks requiring one of its declared capabilities.
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct SchedulingAgent {
6    pub id: usize,
7    pub name: String,
8    /// Capability tags this agent possesses (e.g. "python", "ml", "rust").
9    pub capabilities: Vec<String>,
10}
11
12/// A unit of work to be scheduled.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct SchedulingTask {
15    pub id: usize,
16    pub name: String,
17    /// The single capability an agent must have to execute this task.
18    pub required_capability: String,
19    /// Duration in minutes.
20    pub duration_min: i64,
21    /// Earliest start (minutes from horizon start).
22    pub release_min: i64,
23    /// Latest finish (minutes from horizon start).  Must be ≥ release + duration.
24    pub deadline_min: i64,
25}
26
27/// Seeded into `ContextKey::Seeds` with id prefix `"scheduling-request:"`.
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct SchedulingRequest {
30    pub id: String,
31    pub agents: Vec<SchedulingAgent>,
32    pub tasks: Vec<SchedulingTask>,
33    /// Planning horizon in minutes.
34    pub horizon_min: i64,
35    /// Per-solver time budget in seconds.  Suggestors may honour or ignore this.
36    #[serde(default = "default_time_limit")]
37    pub time_limit_seconds: f64,
38}
39
40fn default_time_limit() -> f64 {
41    30.0
42}
43
44/// A single task-to-agent assignment with resolved timing.
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct TaskAssignment {
47    pub task_id: usize,
48    pub task_name: String,
49    pub agent_id: usize,
50    pub agent_name: String,
51    pub start_min: i64,
52    pub end_min: i64,
53}
54
55/// Written to `ContextKey::Strategies` with id prefix `"scheduling-plan-<solver>:"`.
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct SchedulingPlan {
58    pub request_id: String,
59    pub assignments: Vec<TaskAssignment>,
60    pub tasks_total: usize,
61    pub tasks_scheduled: usize,
62    /// Completion time of the last scheduled task (0 if nothing scheduled).
63    pub makespan_min: i64,
64    /// Short identifier for the algorithm that produced this plan.
65    pub solver: String,
66    /// `"optimal"`, `"feasible"`, `"infeasible"`, or `"error"`.
67    pub status: String,
68    pub wall_time_seconds: f64,
69}
70
71impl SchedulingPlan {
72    /// Throughput ratio: scheduled / total tasks.  Used to derive confidence.
73    pub fn throughput_ratio(&self) -> f64 {
74        if self.tasks_total == 0 {
75            return 0.0;
76        }
77        self.tasks_scheduled as f64 / self.tasks_total as f64
78    }
79}