RejectedOperation#

One operation of a change set that the engine refused. Project::apply lists these in ApplyReport::rejected, and CandidateResult::error uses the same type for a candidate that failed. It's read-only output: the engine creates it, the caller only reads the fields.

Declaration#

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RejectedOperation {
    pub path: String,
    pub message: String,
}

With the serde feature, the type also implements Serialize and Deserialize, with camelCase field names.

Fields#

Field Type Description
path String Where the operation sits in the change set, as group.verb[index], for example tasks.update[0] or links.add[2]. The index counts within that list of SchedulingChanges. In CandidateResult::error, a failure that comes from scheduling or leveling the candidate carries the path of the input error, or an empty string when that error has no path.
message String Why the operation was refused, for example unknown task id. Plain text for display or logging, not a stable error code.

Example#

Update a task that doesn't exist and read the rejection.

use plen_core::{
    DateTime, Patch, Project, ProjectData, ProjectOptions, SchedulingChanges, SolveOptions,
    TaskData, TaskUpdate,
};

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

    let data = ProjectData {
        tasks: vec![TaskData {
            start_date: Some(monday),
            duration: Some(2.0),
            ..TaskData::new(1)
        }],
        ..Default::default()
    };

    let mut project = Project::new(ProjectOptions::default());
    project.solve(Some(data), &SolveOptions::default())?;

    let mut update = TaskUpdate::new(99);
    update.duration = Patch::Value(3.0);

    let mut changes = SchedulingChanges::default();
    changes.tasks.update.push(update);

    let report = project.apply(&changes)?;
    for rejected in &report.rejected {
        // tasks.update[0]: unknown task id
        println!("{}: {}", rejected.path, rejected.message);
    }
    Ok(())
}