Mutation#
The new values of one task after a scheduling call. Each entry in ScheduleResult.Updates 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. An entry belongs to a result that's read-only by contract, so call DeepClone() before changing one.
Declaration#
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.
| Property | Type | Set when | Description |
|---|---|---|---|
Id |
Id |
always (required) |
Id of the task. |
Kind |
MutationKind |
always | Whether the task is a leaf task, a summary or a milestone. |
StartDate |
Moment? |
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>? |
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? |
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, or when a Project.Apply touched it since the last solve. Such an entry has StartDate, EndDate and Duration all set, even if none of them changed.
Methods#
DeepClone#
public Mutation DeepClone()
Returns a copy that shares no list with this entry, including the Pauses list.
Equals#
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#
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: each non-null value goes into the TaskUpdate property of the same name. Kind and Reason have no counterpart there.
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 in the input data.
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#
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-Updatesholds oneMutationper reported taskTaskUpdate- the edit to write the new values backReason- what placed the taskSolveOptions-ReasonsandIncludeUnchanged- Reading results - reading updates and reasons