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


# Reason

Why the planner placed a task where it did. You read it from [`Mutation.Reason`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/mutation.md>), which is set only when the call ran with `Reasons = true` in [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/solve-options.md>) or [`PreviewOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/preview-options.md>). You don't construct one yourself.

## Declaration

```csharp
namespace Plen;

public abstract record Reason
{
    public sealed record Asap(Id LinkId, Id SourceId) : Reason;
    public sealed record Alap(Id LinkId, Id TargetId) : Reason;
    public sealed record SummaryTranslation(Id SummaryId) : Reason;
    public sealed record Constraint : Reason;
    public sealed record Preferred : Reason;
}
```

`Reason` is a closed union: its constructor is private, so these five nested records are the only variants. Read a value with `switch` pattern matching on the nested types. The variants are immutable and compare by value.

## Variants

| Variant | Description |
|---|---|
| `Asap(LinkId, SourceId)` | A predecessor pushed the task later. `LinkId` is the driving link, `SourceId` the driving predecessor. |
| `Alap(LinkId, TargetId)` | A successor pulled the task earlier, in backward planning. `LinkId` is the driving link, `TargetId` the driving successor. |
| `SummaryTranslation(SummaryId)` | The task moved together with its summary. `SummaryId` is the summary that moved. |
| `Constraint` | The task's own constraint placed it. |
| `Preferred` | The task stayed at, or returned to, its own input date. |

How links, constraints and summaries decide a task's dates is covered in [Links, constraints and summaries](<https://docs.dhtmlx.com/planning-engine/net/scheduling/links-constraints-summaries.md>).

## Example

```csharp
using Plen;

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

var data = new ProjectData
{
    Tasks =
    [
        new TaskData(1) { StartDate = monday, Duration = 1.0 },
        new TaskData(2) { StartDate = monday, Duration = 1.0 },
    ],
    Links = [new LinkData { Id = 10, Source = 1, Target = 2 }],
};

var result = Engine.Schedule(data, new SolveOptions { Reasons = true });
foreach (var update in result.Updates)
{
    var why = update.Reason switch
    {
        Reason.Asap r => $"pushed by task {r.SourceId} through link {r.LinkId}",
        Reason.Alap r => $"pulled by task {r.TargetId} through link {r.LinkId}",
        Reason.SummaryTranslation r => $"moved with summary {r.SummaryId}",
        Reason.Constraint => "placed by its constraint",
        Reason.Preferred => "kept at its own date",
        _ => "no reason recorded",
    };
    Console.WriteLine($"task {update.Id}: {why}");
}
// task 2: pushed by task 1 through link 10
```

## Related

- [`Mutation`](<https://docs.dhtmlx.com/planning-engine/net/api/core/results/mutation.md>) - the task update that carries the reason
- [`SolveOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/solve-options.md#reasons>) - the `Reasons` switch of a solve
- [`PreviewOptions`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/preview-options.md#reasons>) - the `Reasons` switch of a preview
- [Reading results](<https://docs.dhtmlx.com/planning-engine/net/scheduling/reading-results.md>) - reading reasons from a result
- [Links, constraints and summaries](<https://docs.dhtmlx.com/planning-engine/net/scheduling/links-constraints-summaries.md>) - how links, constraints and summaries place a task
