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


# Project::apply

Writes edits into the accepted state of a [`Project`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md>) and marks it unsolved. It doesn't schedule anything: follow it with [`solve(None)`](<https://docs.dhtmlx.com/planning-engine/rust/api/project-solve.md>) or [`level`](<https://docs.dhtmlx.com/planning-engine/rust/api/project-level.md>) to get the new dates.

## Signature

```rust
pub fn apply(&mut self, changes: &SchedulingChanges) -> Result<ApplyReport, Error>
```

Takes `&mut self`. Synchronous and CPU-only.

## Parameters

| Name | Type | Description |
|---|---|---|
| `changes` | `&`[`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/scheduling-changes.md>) | The edits to commit |

## Behavior

- Operations are ordered and partially accepted. A rejected operation goes into `ApplyReport::rejected`, not into an `Err`.
- Any rejection sets `needs_resync`. After that, `solve(None)`, `apply` and `level` fail until a full `solve(Some(data))`.
- The state is unsolved afterwards, so [`preview`](<https://docs.dhtmlx.com/planning-engine/rust/api/project-preview.md>), [`load_profile`](<https://docs.dhtmlx.com/planning-engine/rust/api/project-load-profile.md>), [`evaluate`](<https://docs.dhtmlx.com/planning-engine/rust/api/project-evaluate.md>), [`suggest_assignments`](<https://docs.dhtmlx.com/planning-engine/rust/api/project-suggest-assignments.md>) and [`roster`](<https://docs.dhtmlx.com/planning-engine/rust/api/project-roster.md>) need a solve first.
- Tasks added or updated by successful operations are reported by the next acyclic `solve(None)` or `level`.

## Returns

An [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/apply-report.md>) with the applied and rejected operations and their side effects.

## Errors

| Error | When |
|---|---|
| [`Error::Project(ProjectError::NeedsResync)`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/errors/project-error.md>) | An earlier `apply` was rejected and no `solve(Some(data))` followed (checked first) |
| `Error::Project(ProjectError::StaleBaseline)` | `changes.baseline_id` doesn't name the current baseline |

:::note
A start date that falls on non-working time is kept unsnapped when the task has no predecessor. The end is computed forward from it on the working calendar.
:::

## Example

Commit an edit, resync with full data when part of it is rejected, and reschedule.

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

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let monday = DateTime::from_ymd_hm(2026, 8, 10, 8, 0).ok_or("invalid date")?;
    let mut task = TaskData::new(1);
    task.start_date = Some(monday);
    task.duration = Some(2.0);
    let data = ProjectData {
        tasks: vec![task],
        ..Default::default()
    };

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

    let mut update = TaskUpdate::new(1);
    update.duration = Patch::Value(3.0);
    let mut changes = SchedulingChanges::default();
    changes.baseline_id = solved.baseline_id.clone();
    changes.tasks.update.push(update);

    let report = project.apply(&changes)?;
    for rejected in &report.rejected {
        println!("rejected at {}: {}", rejected.path, rejected.message);
    }
    let result = if report.needs_resync {
        project.solve(Some(data), &SolveOptions::default())?
    } else {
        project.solve(None, &SolveOptions::default())?
    };
    println!("{} task(s) moved", result.updates.len());
    Ok(())
}
```

## Related

- [`Project`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/project/project.md#apply>) - the type and its other methods
- [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/scheduling-changes.md>) - the change set
- [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/rust/api/core/changes/apply-report.md>) - the returned report
- [Data Updates](<https://docs.dhtmlx.com/planning-engine/rust/live-projects/editing-a-project.md>) - change sets, applying and rescheduling
- [Recover from rejected changes](<https://docs.dhtmlx.com/planning-engine/rust/how-to/recover-from-rejected-changes.md>) - handling `needs_resync`
