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


# Mutation

The new values of one task after a scheduling call. Each entry in [`ScheduleResult.Updates`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md>) is a `Mutation`. A nullable property holds a value only when the result reports that field; the rest are `null`.

Which tasks get an entry, and what the values are compared against, is described on [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md>). An entry belongs to a result that's read-only by contract, so call `DeepClone()` before changing one.

## Declaration

```csharp
namespace Plen;

public sealed class Mutation : IDeepCloneable<Mutation>, IEquatable<Mutation>
```

## Properties

The date and leveling properties have the same names and units as on [`TaskData`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/task-data.md#properties>).

| Property | Type | Set when | Description |
|---|---|---|---|
| `Id` | [`Id`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/id.md>) | always (`required`) | Id of the task. |
| `Kind` | [`MutationKind`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/mutation.md#mutationkind>) | always | Whether the task is a leaf task, a summary or a milestone. |
| `StartDate` | [`Moment?`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/moment.md>) | the start changed, or the task is reported in full | New start. |
| `EndDate` | `Moment?` | the end changed, or the task is reported in full | New end. |
| `Duration` | `double?` | the duration changed, or the task is reported in full | New working time in the task's duration unit. |
| `LevelingDelay` | `double?` | the leveling delay changed | New leveling delay, as elapsed time in the task's duration unit. |
| `Pauses` | `List<`[`Pause`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/pause.md>)`>?` | the pause list changed | The complete new pause list. An empty list when every pause was removed. A task that had no pauses and still has none never gets this property. |
| `Reason` | [`Reason?`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/reason.md>) | the call ran with `Reasons = true` | What placed the task. `null` when no planner ran (a cyclic project). |

A task is reported in full when `IncludeUnchanged` is set on [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/solve-options.md>), or when a [`Project.Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>) touched it since the last solve. Such an entry has `StartDate`, `EndDate` and `Duration` all set, even if none of them changed.

## Methods

### DeepClone

```csharp
public Mutation DeepClone()
```

Returns a copy that shares no list with this entry, including the `Pauses` list.

### Equals

```csharp
public bool Equals(Mutation? other)
public override bool Equals(object? obj)
```

Value equality: two entries are equal when every property is equal, with `Pauses` compared element by element. `GetHashCode` is consistent with it.

### ToString

```csharp
public override string ToString()
```

Returns a readable rendering of every property, for logging, e.g. `Mutation { Id: design, Kind: Task, … }`.

## Writing back

The property names match [`TaskUpdate`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/task-update.md>): each non-`null` value goes into the `TaskUpdate` property of the same name. `Kind` and `Reason` have no counterpart there.

```csharp
var update = new TaskUpdate(mutation.Id);
if (mutation.StartDate is { } start) update.StartDate = start;
if (mutation.EndDate is { } end) update.EndDate = end;
if (mutation.Duration is { } duration) update.Duration = duration;
if (mutation.LevelingDelay is { } delay) update.LevelingDelay = delay;
if (mutation.Pauses is { } pauses) update.Pauses = pauses;
```

## MutationKind

The kind of task an entry describes. It matches the task's [`TaskType`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/task-data.md#tasktype>) in the input data.

```csharp
namespace Plen;

public enum MutationKind { Task, Summary, Milestone }
```

| Value | Description |
|---|---|
| `Task` | A leaf task (`TaskType.Task`). |
| `Summary` | A summary task (`TaskType.Summary`). |
| `Milestone` | A milestone (`TaskType.Milestone`). |

## Example

```csharp
using Plen;

var monday = Moment.FromYmdHm(2026, 4, 6, 8, 0)
    ?? throw new InvalidOperationException("invalid date");

var data = new ProjectData
{
    Tasks =
    [
        new TaskData("design") { StartDate = monday, Duration = 2.0 },
        new TaskData("build") { StartDate = monday, Duration = 3.0 },
    ],
    Links = [new LinkData { Id = "l1", Source = "design", Target = "build" }],
};

var result = Engine.Schedule(data, new SolveOptions { Reasons = true });

foreach (var update in result.Updates)
{
    if (update.StartDate is { } start)
    {
        Console.WriteLine($"{update.Id} ({update.Kind}) starts {start}: {update.Reason}");
    }
}
```

## Related

- [`ScheduleResult`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/schedule-result.md#updates>) - `Updates` holds one `Mutation` per reported task
- [`TaskUpdate`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/task-update.md>) - the edit to write the new values back
- [`Reason`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/reason.md>) - what placed the task
- [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/solve-options.md>) - `Reasons` and `IncludeUnchanged`
- [Reading results](<https://docs.dhtmlx.com/planning-engine/net/scheduling/reading-results.md#updates>) - reading updates and reasons
