OverallocationWindow#

One continuous period in which a resource is booked above its capacity: a run of adjacent overallocated buckets for that resource. You don't build it yourself. Read it from ResourceOverallocation::windows. After Project::level, the windows are the ones leveling couldn't resolve, each with a reason.

Declaration#

#[derive(Clone, Debug, PartialEq)]
pub struct OverallocationWindow {
    pub from: DateTime,
    pub to: DateTime,
    pub capacity: f64,
    pub peak: f64,
    pub overload: f64,
    pub tasks: Vec<Id>,
    pub reason: Option<String>,
}

With the serde feature, it also implements Serialize and Deserialize.

Fields#

Name Type Description
from DateTime Start of the window, clipped to the earliest working moment of the contending tasks in the first bucket.
to DateTime End of the window, clipped to the latest working moment of the contending tasks in the last bucket.
capacity f64 Capacity of the resource, in assignment units (1 = 100 %).
peak f64 Highest load of any bucket in the window.
overload f64 Sum of load − capacity over the window's buckets, in capacity × buckets.
tasks Vec<Id> Ids of the tasks that book the resource in the window, in input order.
reason Option<String> Why leveling left the window in place. Some only in the result of Project::level; None from every other call.

When an assignment books only part of its task, from and to are clipped to the booked part, not to the whole task. The edges are for display only. For the bucket size, see Basis.

For one resource, the overload values of all its windows add up to that resource's overload in evaluate at the same basis.

Reasons#

reason holds one of these values. When several apply, the window reports the first one in this order.

Value When it's set
pinned-constraint A contending task can't move because of its constraint.
fixed-task A contending task has auto_scheduling: false or is a summary.
completed config.use_progress is on and a contending task has progress == 1.
priority-1000 A contending task has priority == 1000.
slack-exhausted Every task that could move ran out of slack.
out-of-scope The resource, the dates or the tasks of the window are outside the LevelingScope of the run.

For how leveling picks tasks to delay, see Leveling resources.

Serialization#

With the serde feature, an OverallocationWindow serializes with camelCase field names, dates as "YYYY-MM-DD HH:MM", and reason left out when it's None:

{
  "from": "2026-08-10 08:00",
  "to": "2026-08-11 17:00",
  "capacity": 1,
  "peak": 2,
  "overload": 2,
  "tasks": ["A", "B"]
}

Example#

Book one resource full-time on two parallel 2-day tasks and print the window.

use plen_core::{
    schedule, AssignmentData, DateTime, ProjectData, ResourceData, SolveOptions, TaskData,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let monday = DateTime::from_ymd_hm(2026, 8, 10, 8, 0).ok_or("invalid date")?;

    let task = |id: &str| TaskData {
        start_date: Some(monday),
        duration: Some(2.0),
        ..TaskData::new(id)
    };
    let book = |task: &str| AssignmentData {
        id: Some(format!("{task}:dev1").into()),
        task: task.into(),
        resource: "dev1".into(),
        value: 1.0,
        offset: None,
        duration: None,
    };

    let data = ProjectData {
        tasks: vec![task("A"), task("B")],
        resources: vec![ResourceData { id: "dev1".into(), capacity: None, calendar_id: None }],
        assignments: vec![book("A"), book("B")],
        ..Default::default()
    };

    let result = schedule(data, &SolveOptions::default())?;

    for over in result.overallocations.iter().flatten() {
        for window in &over.windows {
            let tasks: Vec<String> = window.tasks.iter().map(|id| id.to_string()).collect();
            println!(
                "{}: {} .. {}, peak {} of {}, overload {}, tasks {}",
                over.resource,
                window.from,
                window.to,
                window.peak,
                window.capacity,
                window.overload,
                tasks.join(", "),
            );
            // dev1: 2026-08-10 08:00 .. 2026-08-11 17:00, peak 2 of 1, overload 2, tasks A, B
        }
    }
    Ok(())
}