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


# ScheduleResult

The result of every scheduling call. [`Project::solve`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#solve>) returns it as `Arc<ScheduleResult>`; [`Project::preview`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#preview>), [`Project::analyze`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#analyze>) and [`schedule`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/schedule.md>) return it by value. [`LevelingResult::schedule`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/leveling-result.md>) holds one too.

Cycles, conflicts and a planner that didn't converge are reported in the result, not as an `Err`.

## Declaration

```rust
#[derive(Clone, Debug, PartialEq)]
pub struct ScheduleResult {
    pub baseline_id: Option<String>,
    pub updates: Vec<Mutation>,
    pub cycles: Vec<Cycle>,
    pub conflicts: Vec<Conflict>,
    pub notes: Vec<Note>,
    pub converged: bool,
    pub analytics: Option<Analytics>,
    pub overallocations: Option<Vec<ResourceOverallocation>>,
    pub profile: Option<LoadProfile>,
}
```

With the `serde` feature, `ScheduleResult` implements `Serialize` and `Deserialize`. Fields use camelCase, and `None` fields are left out. See [Serialize results to JSON](<https://docs.dhtmlx.com/planning-engine/rust/how-to/serialize-results-to-json.md>).

## Fields

| Field | Type | Description |
|---|---|---|
| `baseline_id` | `Option<String>` | Token of the baseline this result produced or read. |
| `updates` | `Vec<`[`Mutation`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/mutation.md>)`>` | New dates and fields of the tasks that changed. |
| `cycles` | `Vec<`[`Cycle`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/cycle.md>)`>` | Dependency cycles found in the project. |
| `conflicts` | `Vec<`[`Conflict`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/conflict.md>)`>` | Constraint and calendar conflicts the planner couldn't resolve. |
| `notes` | `Vec<`[`Note`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/note.md>)`>` | Dropped input records and repairs made on import. |
| `converged` | `bool` | `true` when the planner reached a stable schedule. |
| `analytics` | `Option<`[`Analytics`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/analytics.md>)`>` | Critical path and slack. `Some` when requested. |
| `overallocations` | `Option<Vec<`[`ResourceOverallocation`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/resource-overallocation.md>)`>>` | Resource overload windows. `Some` when the project has assignments. |
| `profile` | `Option<`[`LoadProfile`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/load-profile.md>)`>` | Per-bucket resource load. Only from `preview` with a profile query. |

### baseline_id

```rust
pub baseline_id: Option<String>
```

An opaque token that names an accepted baseline.

- `solve` and [`Project::level`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#level>): always `Some`, the baseline the call accepted.
- `preview`: always `Some`, the baseline the preview read. Pass it to the next `preview` or `apply`.
- `analyze(None, ..)`: `Some` only on a solved project with no unsolved edits.
- `analyze(Some(data), ..)`: always `None`.

The token changes whenever the accepted data changes. It isn't stable across runs, so don't compare tokens from separate runs or store them. See [`Project::solve`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#solve>) for which calls check it.

### updates

```rust
pub updates: Vec<Mutation>
```

One [`Mutation`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/mutation.md>) per reported task, each carrying only the fields that changed.

- By default the list is sparse: it holds only the tasks that changed. `solve(None)` and `Project::level` also report each task touched by earlier `apply` calls.
- With [`SolveOptions::include_unchanged`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/solve-options.md#include_unchanged>), it also holds every unchanged scheduled task.
- `preview` reports updates relative to the baseline it read.
- On a project with cycles, the list is empty unless `include_unchanged` is set.
- `analyze` always returns an empty list.

### cycles

```rust
pub cycles: Vec<Cycle>
```

Every unique simple dependency cycle, one [`Cycle`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/cycle.md>) each. Empty when the project has no cycles. When it isn't empty, no task is moved.

### conflicts

```rust
pub conflicts: Vec<Conflict>
```

Constraint violations and non-working-time placements, one [`Conflict`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/conflict.md>) each. `analyze` always returns an empty list.

### notes

```rust
pub notes: Vec<Note>
```

Links, tasks and assignments dropped from the input, and fixes made under [`Validation::Repair`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/validation.md>), one [`Note`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/note.md>) each.

### converged

```rust
pub converged: bool
```

`true` when the planner reached a fixed point within [`SchedulingConfig::max_iterations`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/data/scheduling-config.md#max_iterations>). `analyze` always returns `true`.

### analytics

```rust
pub analytics: Option<Analytics>
```

`Some` when the call's [`AnalyticsOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/analytics-options.md>) set `slack` or `critical_path`, otherwise `None`. Check [`Analytics::status`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/results/analytics.md>) before reading the data.

### overallocations

```rust
pub overallocations: Option<Vec<ResourceOverallocation>>
```

`Some` when the project has at least one assignment, `None` otherwise. Each entry lists one resource's overload windows; see [`OverallocationWindow`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/resources/overallocation-window.md>).

### profile

```rust
pub profile: Option<LoadProfile>
```

`Some` only from `preview` when [`PreviewOptions::profile`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/preview-options.md>) is set. It describes the load of the previewed dates. Every other call leaves it `None`. For the load of the accepted dates, call [`Project::load_profile`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#load_profile>).

## Example

```rust
use plen_core::{schedule, DateTime, LinkData, LinkType, ProjectData, SolveOptions, TaskData};

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

    let mut design = TaskData::new("design");
    design.start_date = Some(monday);
    design.duration = Some(2.0);

    let mut build = TaskData::new("build");
    build.start_date = Some(monday);
    build.duration = Some(3.0);

    let data = ProjectData {
        tasks: vec![design, build],
        links: vec![LinkData {
            id: "l1".into(),
            source: "design".into(),
            target: "build".into(),
            link_type: LinkType::Fs,
            lag: 0.0,
            lag_unit: None,
        }],
        ..Default::default()
    };

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

    if !result.cycles.is_empty() {
        println!("{} dependency cycle(s), dates unchanged", result.cycles.len());
    }
    for conflict in &result.conflicts {
        println!("conflict: {conflict:?}");
    }
    if !result.converged {
        println!("planner did not converge");
    }

    // Only "build" moved: it now starts after "design" ends.
    for update in &result.updates {
        if let (Some(start), Some(end)) = (update.start_date, update.end_date) {
            println!("{}: {} - {}", update.id, start, end);
        }
    }
    Ok(())
}
```

## Related

- [`Project::solve`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#solve>) - the main call that returns it
- [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/solve-options.md>) - controls what the result reports
- [`Error`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/error.md>) - what scheduling calls return instead of a result
- [Reading results](<https://docs.dhtmlx.com/planning-engine/rust/scheduling/reading-results.md>) - walks through every part of a result
- [Serialize results to JSON](<https://docs.dhtmlx.com/planning-engine/rust/how-to/serialize-results-to-json.md>) - shows the result's JSON form
