Project.Roster#

Reads the accepted state of a Project without skills: scheduled leaf tasks, resources and active assignments, in model order. Use it to build a custom Slot list for SuggestAssignments. Needs a solved project with no unsolved edits.

Signature#

public Roster Roster()

Synchronous and CPU-only. Doesn't change the project's state.

Returns#

A new Roster on each call.

Errors#

Error When
ProjectException NoBaseline The project is unsolved, or has unsolved edits after Apply

Example#

Build one slot per scheduled task that has no assignment yet, open to every resource.

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 = 2.0 },
        new TaskData("b") { StartDate = monday, Duration = 2.0 },
    ],
    Resources = [new ResourceData { Id = "dev1" }, new ResourceData { Id = "dev2" }],
    Assignments = [new AssignmentData { Id = "x", Task = "a", Resource = "dev1", Value = 1.0 }],
};

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

var roster = project.Roster();
var slots = roster.Tasks
    .Where(task => !roster.Assignments.Any(a => a.Task == task))
    .Select(task => new Slot($"slot-{task}", task, [.. roster.Resources]))
    .ToList();

var result = project.SuggestAssignments(slots, new SuggestOptions());
Console.WriteLine($"{slots.Count} slot(s), {result.Steps.Count} step(s)");