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}");
    }
}