[Canonical page](<https://docs.dhtmlx.com/planning-engine/net/how-to/clear-leveling/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# Clear leveling

Remove the delays and splits that [`Project.Level`](<https://docs.dhtmlx.com/planning-engine/net/api/project-level.md>) wrote into a project, so every task goes back to its unleveled dates.

Leveling stores its result in two task fields: `LevelingDelay` and `Pauses`. To clear leveling, set `LevelingDelay` to 0 and `Pauses` to an empty list on every task that has either, then reschedule. For how leveling sets these fields, see [Leveling resources](<https://docs.dhtmlx.com/planning-engine/net/resources-and-assignment/leveling-resources.md>).

## Prerequisites

- A solved [`Project`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/project.md>) that carries leveling, either from a [`Level`](<https://docs.dhtmlx.com/planning-engine/net/api/project-level.md>) call or from loaded data with a non-zero `LevelingDelay` or non-empty `Pauses`.
- The ids of the tasks that carry a delay or pauses. Take them from your own model, or from [`Schedule.Updates`](<https://docs.dhtmlx.com/planning-engine/net/api/core/resources/leveling-result.md#schedule>) of the [`LevelingResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/resources/leveling-result.md>).

## Steps

1. Build one [`TaskUpdate`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/task-update.md>) per leveled task. Set `LevelingDelay` to `0.0` and `Pauses` to an empty list, and put all the updates into one [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md>). Both properties are [`Patch<T>`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/patch.md>) fields, and a plain value converts to `Patch<T>.Of(value)`:

   ```csharp
   static SchedulingChanges ClearLeveling(IEnumerable<Id> ids)
   {
       var changes = new SchedulingChanges();
       foreach (var id in ids)
       {
           changes.Tasks.Update.Add(new TaskUpdate(id)
           {
               LevelingDelay = 0.0,
               Pauses = new List<Pause>(),
           });
       }
       return changes;
   }
   ```

   Leave the dates out of the update. With no date in the same update, the `LevelingDelay` change moves the stored start back by the delay, and the `Pauses` change keeps the start and duration and recomputes the end.

2. Apply the changes with [`Project.Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>) and check the [`ApplyReport`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md>):

   ```csharp
   var report = project.Apply(ClearLeveling(ids));
   if (report.NeedsResync)
   {
       // Resync with project.Solve(data, ...) before the next edit.
   }
   ```

3. Reschedule with [`Solve(null, …)`](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve.md>) and write `result.Updates` back to your model:

   ```csharp
   var result = project.Solve(null, new SolveOptions());
   ```

   The cleared dates become the accepted baseline. The resource contention that leveling resolved shows up again in [`result.Overallocations`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md#overallocations>).

The full example below levels three 2-day tasks that share `dev1`, then clears the leveling. It uses the default calendar (Monday to Friday, 08:00-12:00 and 13:00-17:00) and starts on Monday, August 10, 2026:

```csharp
using Plen;

static Moment Aug(int day) =>
    Moment.FromYmdHm(2026, 8, day, 8, 0) ?? throw new InvalidOperationException("invalid date");

static TaskData Task(string id) => new(id) { StartDate = Aug(10), Duration = 2.0 };

static AssignmentData Booking(string task) =>
    new() { Task = task, Resource = "dev1", Value = 1.0 };

static SchedulingChanges ClearLeveling(IEnumerable<Id> ids)
{
    var changes = new SchedulingChanges();
    foreach (var id in ids)
    {
        changes.Tasks.Update.Add(new TaskUpdate(id)
        {
            LevelingDelay = 0.0,
            Pauses = new List<Pause>(),
        });
    }
    return changes;
}

var data = new ProjectData
{
    Tasks = [Task("A"), Task("B"), Task("C")],
    Resources = [new ResourceData { Id = "dev1" }],
    Assignments = [Booking("A"), Booking("B"), Booking("C")],
};

var project = new Project();
project.Solve(data, new SolveOptions());

// B is delayed to Wednesday, C to Friday.
var leveled = project.Level(new LevelingOptions());

// The tasks that leveling delayed or split.
var ids = leveled.Schedule.Updates
    .Where(u => (u.LevelingDelay is double d && d != 0.0) || u.Pauses is { Count: > 0 })
    .Select(u => u.Id)
    .ToList();

var report = project.Apply(ClearLeveling(ids));
if (report.NeedsResync)
{
    Console.Error.WriteLine("clearing was rejected, resync with Solve(data, ...)");
    return;
}

var result = project.Solve(null, new SolveOptions());
foreach (var update in result.Updates)
{
    Console.WriteLine($"{update.Id}: {update.StartDate} .. {update.EndDate}");
}
foreach (var over in result.Overallocations ?? [])
{
    foreach (var window in over.Windows)
    {
        Console.WriteLine($"{over.Resource}: {window.From} .. {window.To}, peak {window.Peak}");
    }
}
```

## Re-level from scratch instead

To replace old leveling with a fresh run, skip the steps above and call [`Level`](<https://docs.dhtmlx.com/planning-engine/net/api/project-level.md>) again. [`LevelingOptions.ClearFirst`](<https://docs.dhtmlx.com/planning-engine/net/api/core/resources/leveling-options.md>) is `true` by default, so the run first sets `LevelingDelay` to 0 and `Pauses` to an empty list on every in-scope task that has either, then levels the clean plan:

```csharp
var result = project.Level(new LevelingOptions());
```

The call diffs `result.Schedule.Updates` against the state it started from. A task whose stale delay was cleared and not replaced still gets an update entry. Write all the updates back, and your model stays in sync.

With a `Scope`, the run clears only in-scope tasks. Set `ClearFirst = false` to keep the existing delays and pauses and level on top of them.

## Things to know

- [`Patch<T>.Null`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/patch.md#null>) also works: on `LevelingDelay` it restores the default of 0, and on `Pauses` it clears the list.
- Only leveling produces pauses. Every [`Pause`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/pause.md>) counts as leveling-owned, whether or not its `By` is set, so clearing removes all of them.
- To see what clearing would do before you commit it, pass the same changes to [`Project.Preview`](<https://docs.dhtmlx.com/planning-engine/net/api/project-preview.md>). The project stays untouched. See [Previewing changes](<https://docs.dhtmlx.com/planning-engine/net/live-projects/previewing-changes.md>).
- In a live editor, set `changes.BaselineId` to the baseline your model shows. [`Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>) then throws a [`ProjectException`](<https://docs.dhtmlx.com/planning-engine/net/api/core/errors/project-exception.md>) with [`Code == ProjectError.StaleBaseline`](<https://docs.dhtmlx.com/planning-engine/net/api/core/errors/project-exception.md#projecterror>) if the project has moved on. See [Error handling](<https://docs.dhtmlx.com/planning-engine/net/error-handling.md>).
- If `Apply` rejects an operation, [`report.NeedsResync`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md#needsresync>) is `true`, and [`Solve(null, …)`](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve.md>) throws `ProjectError.NeedsResync` until you send the full data with `Solve(data, …)`. See [Recover from rejected changes](<https://docs.dhtmlx.com/planning-engine/net/how-to/recover-from-rejected-changes.md>).

## Result

The example prints `B` and `C` back on Monday, and the overallocation window on `dev1` returns:

```text
B: 2026-08-10 08:00 .. 2026-08-12 08:00
C: 2026-08-10 08:00 .. 2026-08-12 08:00
dev1: 2026-08-10 08:00 .. 2026-08-11 17:00, peak 3
```
