[Canonical page](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/suggest-options/>)
[Full documentation index](<https://docs.dhtmlx.com/planning-engine/llms.txt>)


# SuggestOptions

Options for [`Project#suggestAssignments`](<https://docs.dhtmlx.com/planning-engine/java/api/project-suggest-assignments.md>). They pick which slot categories the call works on, the assignments it must leave alone, the cost of bringing in one more person, the stage it scores on and how many rebalance passes it runs. `new SuggestOptions()` fills empty slots only, with no penalty, on the scheduled stage.

## Declaration

```java
package org.dhtmlx.plen;

public class SuggestOptions extends ValueRecord implements DeepCloneable<SuggestOptions> {
    public String baselineId = null;
    public Vec<AssignTarget> targets = new Vec<AssignTarget>(java.util.Arrays.asList(AssignTarget.EMPTY));
    public Vec<Id> fixed = new Vec<Id>();
    public double newResourcePenalty = 0.0;
    public LevelingOptions level = null;
    public int passes = 1;
    public boolean clearFirst = false;
}
```

`SuggestOptions` is a mutable record. `equals` and `hashCode` compare the public fields, and `toString()` prints them as `SuggestOptions{baselineId=…, targets=…, …}`.

## Constructors

### SuggestOptions()

```java
public SuggestOptions()
```

Creates options with every field at its default.

## Fields

| Field | Type | Default | Description |
|---|---|---|---|
| `baselineId` | `String` | `null` | The baseline the call expects. `null` skips the check. |
| `targets` | `Vec<`[`AssignTarget`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/suggest-options.md#assigntarget>)`>` | `[EMPTY]` | Slot categories to work on. An empty list changes no assignment. |
| `fixed` | `Vec<`[`Id`](<https://docs.dhtmlx.com/planning-engine/java/api/data/id.md>)`>` | empty | Assignment ids the call never changes. |
| `newResourcePenalty` | `double` | `0.0` | Cost added per extra person in use. `0` balances load only; a large value uses the fewest people. |
| `level` | [`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/resources/leveling-options.md>) | `null` | Scores every candidate on the leveled stage with these options. `null` scores the scheduled stage. |
| `passes` | `int` | `1` | Number of rebalance passes over valid slots. |
| `clearFirst` | `boolean` | `false` | Scores against a copy of the accepted state with `levelingDelay` and `pauses` cleared on the tasks in scope. |

### baselineId

```java
public String baselineId = null;
```

A baseline token taken from the latest [`ScheduleResult.baselineId`](<https://docs.dhtmlx.com/planning-engine/java/api/results/schedule-result.md#baselineid>). When it isn't `null` and doesn't name the project's current baseline, `Project#suggestAssignments` throws a [`ProjectException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/project-exception.md>) with code `STALE_BASELINE`.

### targets

```java
public Vec<AssignTarget> targets = new Vec<AssignTarget>(java.util.Arrays.asList(AssignTarget.EMPTY));
```

Any combination of the three [`AssignTarget`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/suggest-options.md#assigntarget>) values, each listed at most once. `EMPTY` and `BROKEN` slots are handled in pass 0, and `VALID` slots in passes `1..passes`.

With an empty list the call is a check: it changes no assignment and only reports the slots whose resource is outside `allowed` in [`SuggestResult.invalid`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/suggest-result.md#invalid>). A value listed twice makes the call throw an [`InputException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/input-exception.md>) at path `targets[i]`.

### fixed

```java
public Vec<Id> fixed = new Vec<Id>();
```

Ids of active assignments that stay as they are. A slot bound to one of them is never visited in any pass. Its resource still counts as on the task and as a person in use, and the slot is still reported in `SuggestResult.invalid` when its resource is outside `allowed`.

An id bound to no slot is accepted. An unknown or inactive id, or one listed twice, makes the call throw an `InputException` at path `fixed[i]`.

### newResourcePenalty

```java
public double newResourcePenalty = 0.0;
```

The cost of one more person in use, added to each state's score. The people counted are those named in any slot's `allowed` list or holding a filled slot, and only while they have at least one active assignment. Once a person is brought in, later slots use them for free, and a move that frees a person lowers the cost.

With `0`, the score is load balance only. A large value trades balance for the fewest workers. Must be finite and `>= 0`; otherwise the call throws an `InputException` at path `newResourcePenalty`.

### level

```java
public LevelingOptions level = null;
```

When set, each candidate is leveled with these options and scored on the leveled stage. `SuggestResult.proposed.leveled` is set only in this mode (see [`SuggestResult`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/suggest-result.md>)). Leveled scoring runs one leveling per candidate, so keep it for small scopes. Invalid leveling options make the call throw an `InputException`.

With `level` set, the call doesn't return when an assignment asks for more units than its resource can ever supply. [`Project#level`](<https://docs.dhtmlx.com/planning-engine/java/api/project-level.md>) has the same bug.

Commit a proposal scored this way with `apply(result.changes)` followed by `level` with the same options.

### passes

```java
public int passes = 1;
```

The maximum number of rebalance passes over `VALID` slots. A pass that moves nothing ends the loop early. It has no effect unless `targets` contains `VALID`. Must be `>= 1`; otherwise the call throws an `InputException` at path `passes`.

### clearFirst

```java
public boolean clearFirst = false;
```

When `true`, the call works from a solved copy of the accepted state with `levelingDelay` and `pauses` cleared on the tasks in scope. Everything the call measures and builds on comes from that copy. `SuggestResult.changes` then starts with one `tasks.update` per cleared task, so a commit reproduces the scored state. The clears are returned even when `targets` is empty or no slot moves.

This field is separate from `level.clearFirst` and works with `level` set to `null`. With nothing to clear, the result is the same as with `false`.

## Methods

### withBaselineId, withTargets, withFixed, withNewResourcePenalty, withLevel, withPasses, withClearFirst

```java
public SuggestOptions withBaselineId(String value)
public SuggestOptions withTargets(Vec<AssignTarget> value)
public SuggestOptions withTargets(java.util.Collection<? extends AssignTarget> value)
public SuggestOptions withFixed(Vec<Id> value)
public SuggestOptions withFixed(java.util.Collection<? extends Id> value)
public SuggestOptions withNewResourcePenalty(double value)
public SuggestOptions withLevel(LevelingOptions value)
public SuggestOptions withPasses(int value)
public SuggestOptions withClearFirst(boolean value)
```

Each setter assigns its field and returns this instance, for chaining. The `Collection` overloads copy the argument into a new `Vec`, so `List.of(...)` works.

### copy

```java
public SuggestOptions copy()
```

Returns a shallow copy. The copy shares the `targets` and `fixed` lists and the `level` object with this instance.

### deepClone

```java
public SuggestOptions deepClone()
```

Returns a copy with its own `targets` and `fixed` lists and its own `LevelingOptions`.

## AssignTarget

A slot category, judged from the slot's current resource. Every slot falls into exactly one category.

```java
public enum AssignTarget { EMPTY, BROKEN, VALID }
```

| Value | Description |
|---|---|
| `EMPTY` | The slot has no assignment. Targeted empty slots are filled in pass 0. |
| `BROKEN` | The slot's resource isn't in its `allowed` list. Targeted broken slots are repaired in pass 0. |
| `VALID` | The slot's resource is in its `allowed` list. Targeted valid slots are rebalanced in passes `1..passes`, and a slot moves only when the move strictly lowers the cost. |

## Example

Fill empty slots, repair broken ones and rebalance valid ones, keeping assignment `aLead` where it is and charging for each extra person.

```java
import java.util.List;
import org.dhtmlx.plen.*;

public class SuggestOptionsExample {
  static TaskData task(String id) {
    return new TaskData(Id.str(id))
        .withStartDate(Moment.fromYmdHm(2026, 8, 10, 0, 0))
        .withDuration(2.0);
  }

  public static void main(String[] args) throws Exception {
    ProjectData data = new ProjectData()
        .withTasks(List.of(task("A"), task("B")))
        .withResources(List.of(
            new ResourceData().withId(Id.str("dev1")),
            new ResourceData().withId(Id.str("dev2"))))
        .withAssignments(List.of(new AssignmentData()
            .withId(Id.str("aLead"))
            .withTask(Id.str("A"))
            .withResource(Id.str("dev1"))
            .withValue(1.0)));

    Project project = new Project();
    project.solve(data, new SolveOptions());

    List<Id> devs = List.of(Id.str("dev1"), Id.str("dev2"));
    List<Slot> slots = List.of(
        new Slot(Id.str("aLead"), Id.str("A"), devs).withAssignment(Id.str("aLead")),
        new Slot(Id.str("sB"), Id.str("B"), devs));

    SuggestOptions options = new SuggestOptions()
        .withTargets(List.of(AssignTarget.EMPTY, AssignTarget.BROKEN, AssignTarget.VALID))
        .withFixed(List.of(Id.str("aLead")))
        .withNewResourcePenalty(0.5)
        .withPasses(2);

    SuggestResult result = project.suggestAssignments(slots, options);
    for (SuggestStep step : result.steps) {
      System.out.println(step.slot + " pass " + step.pass + " -> " + step.toResource);
    }
  }
}
```

## Related

- [`Project#suggestAssignments`](<https://docs.dhtmlx.com/planning-engine/java/api/project-suggest-assignments.md>) - the call these options configure
- [`SuggestResult`](<https://docs.dhtmlx.com/planning-engine/java/api/suggest/suggest-result.md>) - the proposal the call returns
- [`LevelingOptions`](<https://docs.dhtmlx.com/planning-engine/java/api/resources/leveling-options.md>) - the options of leveled scoring
- [`InputException`](<https://docs.dhtmlx.com/planning-engine/java/api/errors/input-exception.md>) - thrown for invalid option values
- [Suggesting assignments](<https://docs.dhtmlx.com/planning-engine/java/resources-and-assignment/suggesting-assignments.md#options>) - filling, repairing and rebalancing slots
