[Canonical page](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/finish/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Finish

The finish dates of one evaluation stage: the project finish and the finish of each focus task, each with its distance from the baseline. You read it from [`Metrics::finish`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/metrics.md>), which appears in [`EvaluateResult::baseline`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/evaluate-result.md>) and in the `scheduled` and `leveled` stages of every [`CandidateResult`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/candidate-result.md>).

## Declaration

```rust
#[derive(Clone, Debug, PartialEq)]
pub struct Finish {
    pub project: Option<Shift>,
    pub tasks: Vec<TaskFinish>,
}
```

With the `serde` feature, `Finish` implements `Serialize` and `Deserialize` with camelCase field names.

## Fields

| Field | Type | Description |
|---|---|---|
| `project` | `Option<`[`Shift`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/shift.md>)`>` | Project finish: the latest end over the scheduled tasks of this stage. `None` when the stage has no tasks. |
| `tasks` | `Vec<`[`TaskFinish`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/task-finish.md>)`>` | One entry per id in [`EvaluateOptions::focus`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/evaluate-options.md>), in the same order. Empty when `focus` is empty. |

[`Shift`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/shift.md>) describes how `delta` is measured. [`TaskFinish`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/task-finish.md>) covers a focus task that the candidate removed.

## Example

Report the project finish and the finish of task 2 for a candidate that moves task 2 to `dev2`.

```rust
use plen_core::{
    AssignmentData, AssignmentUpdate, Candidate, DateTime, EvaluateOptions, Patch, Project,
    ProjectData, ProjectOptions, ResourceData, SchedulingChanges, 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: i32| TaskData {
        start_date: Some(monday),
        duration: Some(2.0),
        ..TaskData::new(id)
    };
    let resource = |id: &str| ResourceData {
        id: id.into(),
        capacity: None,
        calendar_id: None,
    };
    let assignment = |id: &str, task: i32| AssignmentData {
        id: Some(id.into()),
        task: task.into(),
        resource: "dev1".into(),
        value: 1.0,
        offset: None,
        duration: None,
    };
    let data = ProjectData {
        tasks: vec![task(1), task(2)],
        resources: vec![resource("dev1"), resource("dev2")],
        assignments: vec![assignment("a1", 1), assignment("a2", 2)],
        ..Default::default()
    };

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

    let mut changes = SchedulingChanges::default();
    let mut to_dev2 = AssignmentUpdate::new("a2");
    to_dev2.resource = Patch::Value("dev2".into());
    changes.assignments.update.push(to_dev2);
    let candidates = [Candidate { id: "dev2".into(), changes }];

    let options = EvaluateOptions {
        focus: vec![2.into()],
        ..Default::default()
    };
    let result = project.evaluate(&candidates, &options)?;

    for candidate in &result.candidates {
        let Some(scheduled) = &candidate.scheduled else { continue };
        let finish = &scheduled.finish;
        if let Some(shift) = &finish.project {
            println!("{}: project ends {} ({:+})", candidate.id, shift.date, shift.delta);
        }
        for task in &finish.tasks {
            match &task.finish {
                Some(shift) => println!("  task {} ends {} ({:+})", task.id, shift.date, shift.delta),
                None => println!("  task {} removed", task.id),
            }
        }
    }
    Ok(())
}
```

## Related

- [`Metrics`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/metrics.md>) - the stage measurements that contain it
- [`EvaluateOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/evaluate-options.md>) - `focus` selects the tasks listed in `tasks`
- [`Overload`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/evaluate/overload.md>) - the overload counterpart within the same stage
- [Evaluating Alternatives](<https://docs.dhtmlx.com/planning-engine/rust/resources-and-assignment/evaluating-alternatives.md#metrics-and-cost>) - how finish shifts enter the comparison
