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


# ApplyReport

The outcome of one [`Project.Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>) call. It lists which operations of the [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md>) were applied and which were rejected, the records the edit removed, generated or dropped as a side effect, and the project's revision afterwards.

`Apply` returns a new instance on every call.

## Declaration

```csharp
public sealed class ApplyReport : IDeepCloneable<ApplyReport>, IEquatable<ApplyReport>
{
    public List<AppliedOperation> Applied { get; set; } = [];
    public List<RejectedOperation> Rejected { get; set; } = [];
    public ChangeEffects Effects { get; set; } = new();
    public bool NeedsResync { get; set; }
    public ulong Revision { get; set; }

    public ApplyReport DeepClone();
    public bool Equals(ApplyReport? other);
    public override string ToString();
}
```

## Properties

| Property | Type | Description |
|---|---|---|
| `Applied` | `List<`[`AppliedOperation`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md#appliedoperation>)`>` | Operations that were applied, in execution order. |
| `Rejected` | `List<`[`RejectedOperation`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/rejected-operation.md>)`>` | Operations that were rejected, in execution order. Empty when everything was applied. |
| `Effects` | [`ChangeEffects`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/apply-report.md#changeeffects>) | Records removed, generated or dropped by the applied operations. |
| `NeedsResync` | `bool` | `true` when `Rejected` isn't empty. |
| `Revision` | `ulong` | The project's revision counter after this call. |

### Applied

```csharp
public List<AppliedOperation> Applied { get; set; } = [];
```

One entry per applied operation, in the order the operations ran. Each entry's `Path` names the operation. For the execution order, see [Operation order](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md#operation-order>).

### Rejected

```csharp
public List<RejectedOperation> Rejected { get; set; } = [];
```

One entry per rejected operation, with its path and the reason. A rejected operation leaves no partial edit; operations after it still run.

### Effects

```csharp
public ChangeEffects Effects { get; set; } = new();
```

Side effects of the applied operations only. A rejected operation contributes nothing here.

### NeedsResync

```csharp
public bool NeedsResync { get; set; }
```

`true` exactly when at least one operation was rejected. From then on, [`Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>), `Solve(null, …)` and [`Level`](<https://docs.dhtmlx.com/planning-engine/net/api/project-level.md>) throw a [`ProjectException`](<https://docs.dhtmlx.com/planning-engine/net/api/core/errors/project-exception.md>) with `Code == `[`ProjectError.NeedsResync`](<https://docs.dhtmlx.com/planning-engine/net/api/core/errors/project-exception.md#projecterror>) until a full [`Solve(data, …)`](<https://docs.dhtmlx.com/planning-engine/net/api/project-solve.md>). See [Recover from rejected changes](<https://docs.dhtmlx.com/planning-engine/net/how-to/recover-from-rejected-changes.md>).

### Revision

```csharp
public ulong Revision { get; set; }
```

The project's revision counter after the apply. Every `Apply` raises it, so a higher value means a later state of the same project. A [`Clone()`](<https://docs.dhtmlx.com/planning-engine/net/api/core/project/project.md>) starts from the source's counter.

## Methods

### DeepClone

```csharp
public ApplyReport DeepClone()
```

Returns a copy that shares no list or nested record with this instance.

### Equals

```csharp
public bool Equals(ApplyReport? other)
```

Value equality: the three lists element by element, `Effects` by value, `NeedsResync` and `Revision` by `==`.

### ToString

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

Returns a debug dump of all five properties.

## AppliedOperation

One applied operation, identified by its position in the change set.

```csharp
public sealed class AppliedOperation : IDeepCloneable<AppliedOperation>, IEquatable<AppliedOperation>
{
    public required string Path { get; set; }

    public AppliedOperation DeepClone();
    public bool Equals(AppliedOperation? other);
    public override string ToString();
}
```

| Property | Type | Description |
|---|---|---|
| `Path` | `string` | The operation's bucket, list and index in the change set, in the form `{bucket}.{list}[{index}]`: `tasks.update[0]`, `links.add[2]`, `assignments.remove[1]`. Buckets: `tasks`, `links`, `resources`, `assignments`; lists: `add`, `update`, `remove`. |

## ChangeEffects

Records an apply removed, generated or dropped beyond the ones the change set names directly. Use it to keep a client-side copy of the project in sync.

```csharp
public sealed class ChangeEffects : IDeepCloneable<ChangeEffects>, IEquatable<ChangeEffects>
{
    public List<Id> RemovedTasks { get; set; } = [];
    public List<Id> RemovedLinks { get; set; } = [];
    public List<Id> GeneratedLinks { get; set; } = [];
    public List<Id> DroppedLinks { get; set; } = [];
    public List<Id> RemovedAssignments { get; set; } = [];
    public List<Id> GeneratedAssignments { get; set; } = [];
    public List<Id> DroppedAssignments { get; set; } = [];

    public ChangeEffects DeepClone();
    public bool Equals(ChangeEffects? other);
    public override string ToString();
}
```

Every list holds [`Id`](<https://docs.dhtmlx.com/planning-engine/net/api/core/data/id.md>) values and is empty when nothing of that kind happened.

| Property | Type | Description |
|---|---|---|
| `RemovedTasks` | `List<Id>` | Tasks deleted by `tasks.remove`, including every descendant of a removed task. |
| `RemovedLinks` | `List<Id>` | Links deleted by `links.remove`, plus links whose source or target was a removed task. |
| `GeneratedLinks` | `List<Id>` | Ids created for `links.add` entries without an `Id`, in the form `$generated_link_{n}`. |
| `DroppedLinks` | `List<Id>` | Links that stay in the data but were taken out of scheduling by this apply, for example because an endpoint became unscheduled. See [Links that get dropped](<https://docs.dhtmlx.com/planning-engine/net/scheduling/links-constraints-summaries.md#links-that-get-dropped>). |
| `RemovedAssignments` | `List<Id>` | Assignments deleted by `assignments.remove`, plus assignments of removed tasks and removed resources. Cascaded assignments without an id aren't listed. |
| `GeneratedAssignments` | `List<Id>` | Ids created for `assignments.add` entries without an `Id`, in the form `$generated_assignment_{n}`. |
| `DroppedAssignments` | `List<Id>` | Assignments that stay in the data but were taken out of scheduling by this apply because their task became unscheduled. They return when the task is scheduled again. |

`DeepClone()` copies every list. `Equals` compares the seven lists element by element.

## Example

Remove a task that has a link and an assignment, and add a link without an id.

```csharp
using Plen;

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

var data = new ProjectData
{
    Tasks =
    [
        new TaskData("a") { StartDate = monday, Duration = 1.0 },
        new TaskData("b") { StartDate = monday, Duration = 2.0 },
        new TaskData("c") { StartDate = monday, Duration = 1.0 },
    ],
    Links = [new LinkData { Id = "ab", Source = "a", Target = "b" }],
    Resources = [new ResourceData { Id = "dev" }],
    Assignments = [new AssignmentData { Id = "as1", Task = "b", Resource = "dev", Value = 1.0 }],
};

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

var changes = new SchedulingChanges();
changes.Tasks.Remove.Add("b");
changes.Links.Add.Add(new LinkAdd { Source = "a", Target = "c" });

var report = project.Apply(changes);

foreach (var op in report.Applied)
    Console.WriteLine($"applied {op.Path}");          // tasks.remove[0], links.add[0]

var effects = report.Effects;
Console.WriteLine(string.Join(", ", effects.RemovedTasks));         // b
Console.WriteLine(string.Join(", ", effects.RemovedLinks));         // ab
Console.WriteLine(string.Join(", ", effects.RemovedAssignments));   // as1
Console.WriteLine(string.Join(", ", effects.GeneratedLinks));       // $generated_link_1
```

## Related

- [`Project.Apply`](<https://docs.dhtmlx.com/planning-engine/net/api/project-apply.md>) - the call that returns the report
- [`SchedulingChanges`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/scheduling-changes.md>) - the change set the report describes
- [`RejectedOperation`](<https://docs.dhtmlx.com/planning-engine/net/api/core/changes/rejected-operation.md>) - one rejected entry
- [Editing a project](<https://docs.dhtmlx.com/planning-engine/net/live-projects/editing-a-project.md>) - applying edits and reading the report
- [Recover from rejected changes](<https://docs.dhtmlx.com/planning-engine/net/how-to/recover-from-rejected-changes.md>) - resyncing after a rejection
