Engine Logic
Source code
---
import GanttScheduling from '@revolist/revogrid-examples/components/gantt/GanttScheduling.vue';
---
<GanttScheduling client:only="vue" /> // src/components/gantt/GanttScheduling.ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import type { TaskEntity, DependencyEntity, CalendarEntity } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
const { isDark } = currentTheme();
const PROJECT_ID = 'project-web-redesign';
const CALENDAR_ID = 'cal-us';
// Calendar-aware scheduling: durations are in working days (Mon–Fri, excluding holidays)
const ganttConfig = {
id: PROJECT_ID,
name: 'Website Redesign',
version: '1',
currency: 'USD',
timeZone: 'America/New_York',
primaryCalendarId: CALENDAR_ID,
updatedAt: '2026-04-06T00:00:00Z',
zoomPreset: 'week' as const,
scheduling: {
excludeHolidaysFromDuration: true, // durations skip weekends and holidays
},
visuals: {
shadeNonWorkingTime: true, // shade weekend columns on the timeline
projectLineDate: '2026-04-06', // vertical status-date line
},
};
// US calendar with public holidays
const calendars: CalendarEntity[] = [
{
id: CALENDAR_ID,
name: 'US Standard',
timeZone: 'America/New_York',
workingDays: [1, 2, 3, 4, 5], // Mon–Fri
holidays: [
'2026-05-25', // Memorial Day
'2026-07-04', // Independence Day
],
hoursPerDay: 8,
},
];
const tasks: TaskEntity[] = [
{
id: 't1', projectId: PROJECT_ID, parentId: null,
wbsCode: '1', name: 'Design', type: 'summary', status: 'in-progress',
startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15,
progressPercent: 60, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't2', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.1', name: 'Wireframes', type: 'task', status: 'done',
startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,
progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't3', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.2', name: 'Design Review', type: 'milestone', status: 'done',
startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,
progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
},
{
id: 't4', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.3', name: 'Visual Design', type: 'task', status: 'in-progress',
startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10,
progressPercent: 40, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't5', projectId: PROJECT_ID, parentId: null,
wbsCode: '2', name: 'Development', type: 'summary', status: 'not-started',
startDate: '2026-04-27', endDate: '2026-05-28', durationDays: 24,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
},
{
id: 't6', projectId: PROJECT_ID, parentId: 't5',
wbsCode: '2.1', name: 'Frontend', type: 'task', status: 'not-started',
// constraint: cannot start before May 4 (waiting on external API)
startDate: '2026-05-04', endDate: '2026-05-20', durationDays: 13,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
constraintType: 'start-no-earlier-than',
constraintDate: '2026-05-04',
},
{
id: 't7', projectId: PROJECT_ID, parentId: 't5',
wbsCode: '2.2', name: 'Backend', type: 'task', status: 'not-started',
startDate: '2026-04-27', endDate: '2026-05-28', durationDays: 24,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
deadlineDate: '2026-05-22', // deadline marker — project expects early delivery
},
{
id: 't8', projectId: PROJECT_ID, parentId: null,
wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started',
startDate: '2026-05-28', endDate: '2026-05-28', durationDays: 0,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
},
];
const dependencies: DependencyEntity[] = [
{ id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0 },
{ id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1 },
{ id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1 },
{ id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1 },
{ id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
{ id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
];
export function load(parentSelector: string) {
const grid = document.createElement('revo-grid');
grid.theme = isDark() ? 'darkCompact' : 'compact';
grid.hideAttribution = true;
grid.plugins = [GanttPlugin];
grid.gantt = ganttConfig;
grid.ganttCalendars = calendars;
grid.ganttDependencies = dependencies;
grid.source = tasks;
grid.columns = [
createDefaultTaskTableColumn('wbs'),
createDefaultTaskTableColumn('name'),
];
document.querySelector(parentSelector)?.appendChild(grid);
}
<template>
<RevoGrid
hide-attribution
style="height: 500px"
:theme="isDark ? 'darkCompact' : 'compact'"
:plugins="plugins"
:source="tasks"
:columns="columns"
:gantt.prop="ganttConfig"
:gantt-dependencies.prop="dependencies"
:gantt-calendars.prop="calendars"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import RevoGrid from '@revolist/vue3-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import type { TaskEntity, DependencyEntity, CalendarEntity } from '@revolist/revogrid-enterprise';
import { currentThemeVue } from '../composables/useRandomData';
const { isDark } = currentThemeVue();
const PROJECT_ID = 'project-web-redesign';
const CALENDAR_ID = 'cal-us';
const plugins = ref([GanttPlugin]);
const ganttConfig = ref({
id: PROJECT_ID,
name: 'Website Redesign',
version: '1',
currency: 'USD',
timeZone: 'America/New_York',
primaryCalendarId: CALENDAR_ID,
updatedAt: '2026-04-06T00:00:00Z',
zoomPreset: 'week' as const,
scheduling: {
excludeHolidaysFromDuration: true,
},
visuals: {
shadeNonWorkingTime: true,
projectLineDate: '2026-04-06',
},
});
const calendars = ref<CalendarEntity[]>([
{
id: CALENDAR_ID,
name: 'US Standard',
timeZone: 'America/New_York',
workingDays: [1, 2, 3, 4, 5],
holidays: ['2026-05-25', '2026-07-04'],
hoursPerDay: 8,
},
]);
const tasks = ref<TaskEntity[]>([
{
id: 't1', projectId: PROJECT_ID, parentId: null,
wbsCode: '1', name: 'Design', type: 'summary', status: 'in-progress',
startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15,
progressPercent: 60, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't2', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.1', name: 'Wireframes', type: 'task', status: 'done',
startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,
progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't3', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.2', name: 'Design Review', type: 'milestone', status: 'done',
startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,
progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
},
{
id: 't4', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.3', name: 'Visual Design', type: 'task', status: 'in-progress',
startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10,
progressPercent: 40, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't5', projectId: PROJECT_ID, parentId: null,
wbsCode: '2', name: 'Development', type: 'summary', status: 'not-started',
startDate: '2026-04-27', endDate: '2026-05-28', durationDays: 24,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
},
{
id: 't6', projectId: PROJECT_ID, parentId: 't5',
wbsCode: '2.1', name: 'Frontend', type: 'task', status: 'not-started',
startDate: '2026-05-04', endDate: '2026-05-20', durationDays: 13,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
constraintType: 'start-no-earlier-than',
constraintDate: '2026-05-04',
},
{
id: 't7', projectId: PROJECT_ID, parentId: 't5',
wbsCode: '2.2', name: 'Backend', type: 'task', status: 'not-started',
startDate: '2026-04-27', endDate: '2026-05-28', durationDays: 24,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
deadlineDate: '2026-05-22',
},
{
id: 't8', projectId: PROJECT_ID, parentId: null,
wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started',
startDate: '2026-05-28', endDate: '2026-05-28', durationDays: 0,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
},
]);
const dependencies = ref<DependencyEntity[]>([
{ id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0 },
{ id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1 },
{ id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1 },
{ id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1 },
{ id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
{ id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
]);
const columns = ref([
createDefaultTaskTableColumn('wbs'),
createDefaultTaskTableColumn('name'),
]);
</script>
import React, { useMemo } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import type { TaskEntity, DependencyEntity, CalendarEntity } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
const { isDark } = currentTheme();
const PROJECT_ID = 'project-web-redesign';
const CALENDAR_ID = 'cal-us';
const tasks: TaskEntity[] = [
{
id: 't1', projectId: PROJECT_ID, parentId: null,
wbsCode: '1', name: 'Design', type: 'summary', status: 'in-progress',
startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15,
progressPercent: 60, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't2', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.1', name: 'Wireframes', type: 'task', status: 'done',
startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,
progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't3', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.2', name: 'Design Review', type: 'milestone', status: 'done',
startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,
progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
},
{
id: 't4', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.3', name: 'Visual Design', type: 'task', status: 'in-progress',
startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10,
progressPercent: 40, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't5', projectId: PROJECT_ID, parentId: null,
wbsCode: '2', name: 'Development', type: 'summary', status: 'not-started',
startDate: '2026-04-27', endDate: '2026-05-28', durationDays: 24,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
},
{
id: 't6', projectId: PROJECT_ID, parentId: 't5',
wbsCode: '2.1', name: 'Frontend', type: 'task', status: 'not-started',
startDate: '2026-05-04', endDate: '2026-05-20', durationDays: 13,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
constraintType: 'start-no-earlier-than',
constraintDate: '2026-05-04',
},
{
id: 't7', projectId: PROJECT_ID, parentId: 't5',
wbsCode: '2.2', name: 'Backend', type: 'task', status: 'not-started',
startDate: '2026-04-27', endDate: '2026-05-28', durationDays: 24,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
deadlineDate: '2026-05-22',
},
{
id: 't8', projectId: PROJECT_ID, parentId: null,
wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started',
startDate: '2026-05-28', endDate: '2026-05-28', durationDays: 0,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
},
];
const dependencies: DependencyEntity[] = [
{ id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0 },
{ id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1 },
{ id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1 },
{ id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1 },
{ id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
{ id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
];
const calendars: CalendarEntity[] = [
{
id: CALENDAR_ID,
name: 'US Standard',
timeZone: 'America/New_York',
workingDays: [1, 2, 3, 4, 5],
holidays: ['2026-05-25', '2026-07-04'],
hoursPerDay: 8,
},
];
function GanttScheduling() {
const ganttConfig = useMemo(() => ({
id: PROJECT_ID,
name: 'Website Redesign',
version: '1',
currency: 'USD',
timeZone: 'America/New_York',
primaryCalendarId: CALENDAR_ID,
updatedAt: '2026-04-06T00:00:00Z',
zoomPreset: 'week' as const,
scheduling: {
excludeHolidaysFromDuration: true,
},
visuals: {
shadeNonWorkingTime: true,
projectLineDate: '2026-04-06',
},
}), []);
const columns = useMemo(() => [
createDefaultTaskTableColumn('wbs'),
createDefaultTaskTableColumn('name'),
], []);
return (
<RevoGrid
style={{ height: '500px' }}
theme={isDark() ? 'darkCompact' : 'compact'}
hideAttribution
plugins={[GanttPlugin]}
source={tasks}
columns={columns}
gantt={ganttConfig}
ganttDependencies={dependencies}
ganttCalendars={calendars}
/>
);
}
export default GanttScheduling; import { Component, NO_ERRORS_SCHEMA, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { GanttPlugin, createDefaultTaskTableColumn } from '@revolist/revogrid-enterprise';
import type { TaskEntity, DependencyEntity, CalendarEntity } from '@revolist/revogrid-enterprise';
import { currentTheme } from '../composables/useRandomData';
const PROJECT_ID = 'project-web-redesign';
const CALENDAR_ID = 'cal-us';
@Component({
selector: 'gantt-scheduling-grid',
standalone: true,
imports: [RevoGrid],
// Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs.
schemas: [NO_ERRORS_SCHEMA],
template: `
<revo-grid
style="min-height: 500px"
[theme]="theme"
[hideAttribution]="true"
[plugins]="plugins"
[source]="tasks"
[columns]="columns"
[gantt]="ganttConfig"
[ganttDependencies]="dependencies"
[ganttCalendars]="calendars"
></revo-grid>
`,
encapsulation: ViewEncapsulation.None,
})
export class GanttSchedulingGridComponent {
theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
plugins = [GanttPlugin];
ganttConfig = {
id: PROJECT_ID,
name: 'Website Redesign',
version: '1',
currency: 'USD',
timeZone: 'America/New_York',
primaryCalendarId: CALENDAR_ID,
updatedAt: '2026-04-06T00:00:00Z',
zoomPreset: 'week' as const,
scheduling: {
excludeHolidaysFromDuration: true,
},
visuals: {
shadeNonWorkingTime: true,
projectLineDate: '2026-04-06',
},
};
calendars: CalendarEntity[] = [
{
id: CALENDAR_ID,
name: 'US Standard',
timeZone: 'America/New_York',
workingDays: [1, 2, 3, 4, 5],
holidays: ['2026-05-25', '2026-07-04'],
hoursPerDay: 8,
},
];
tasks: TaskEntity[] = [
{
id: 't1', projectId: PROJECT_ID, parentId: null,
wbsCode: '1', name: 'Design', type: 'summary', status: 'in-progress',
startDate: '2026-04-06', endDate: '2026-04-24', durationDays: 15,
progressPercent: 60, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't2', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.1', name: 'Wireframes', type: 'task', status: 'done',
startDate: '2026-04-06', endDate: '2026-04-10', durationDays: 5,
progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't3', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.2', name: 'Design Review', type: 'milestone', status: 'done',
startDate: '2026-04-10', endDate: '2026-04-10', durationDays: 0,
progressPercent: 100, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
},
{
id: 't4', projectId: PROJECT_ID, parentId: 't1',
wbsCode: '1.3', name: 'Visual Design', type: 'task', status: 'in-progress',
startDate: '2026-04-13', endDate: '2026-04-24', durationDays: 10,
progressPercent: 40, calendarId: CALENDAR_ID, isCritical: true, tags: [],
},
{
id: 't5', projectId: PROJECT_ID, parentId: null,
wbsCode: '2', name: 'Development', type: 'summary', status: 'not-started',
startDate: '2026-04-27', endDate: '2026-05-28', durationDays: 24,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: false, tags: [],
},
{
id: 't6', projectId: PROJECT_ID, parentId: 't5',
wbsCode: '2.1', name: 'Frontend', type: 'task', status: 'not-started',
startDate: '2026-05-04', endDate: '2026-05-20', durationDays: 13,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
constraintType: 'start-no-earlier-than',
constraintDate: '2026-05-04',
},
{
id: 't7', projectId: PROJECT_ID, parentId: 't5',
wbsCode: '2.2', name: 'Backend', type: 'task', status: 'not-started',
startDate: '2026-04-27', endDate: '2026-05-28', durationDays: 24,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: [],
deadlineDate: '2026-05-22',
},
{
id: 't8', projectId: PROJECT_ID, parentId: null,
wbsCode: '3', name: 'Launch', type: 'milestone', status: 'not-started',
startDate: '2026-05-28', endDate: '2026-05-28', durationDays: 0,
progressPercent: 0, calendarId: CALENDAR_ID, isCritical: true, tags: ['milestone'],
},
];
dependencies: DependencyEntity[] = [
{ id: 'd1', predecessorTaskId: 't2', successorTaskId: 't3', type: 'finish-to-start', lagDays: 0 },
{ id: 'd2', predecessorTaskId: 't3', successorTaskId: 't4', type: 'finish-to-start', lagDays: 1 },
{ id: 'd3', predecessorTaskId: 't4', successorTaskId: 't6', type: 'finish-to-start', lagDays: 1 },
{ id: 'd4', predecessorTaskId: 't4', successorTaskId: 't7', type: 'finish-to-start', lagDays: 1 },
{ id: 'd5', predecessorTaskId: 't6', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
{ id: 'd6', predecessorTaskId: 't7', successorTaskId: 't8', type: 'finish-to-start', lagDays: 0 },
];
columns = [
createDefaultTaskTableColumn('wbs'),
createDefaultTaskTableColumn('name'),
];
} The RevoGrid Gantt scheduling engine follows a deterministic pipeline to compute effective dates for all tasks. It processes data changes in five distinct phases to ensure dependency safety and constraint satisfaction.
The 5-Step Pipeline
Section titled “The 5-Step Pipeline”1. Topological Sort
Section titled “1. Topological Sort”The engine first builds a dependency graph and performs a topological sort. This ensures that tasks are ordered such that every predecessor is processed before its successors.
- Summary tasks are handled separately to ensure they can roll up dates from their children.
- Circular dependencies are detected and reported as errors.
2. Forward Pass (ASAP)
Section titled “2. Forward Pass (ASAP)”In the default scheduleFrom: 'project-start' mode, the engine performs a forward pass:
- Root tasks (those without predecessors) are anchored to the
projectStartDate. - Successors are shifted forward to satisfy their incoming dependencies (FS, SS, FF, SF) plus any
lagDays. - The engine uses the successor’s calendar to compute working-day offsets if
lagCalendar: 'working-days'is enabled.
3. Constraint Application
Section titled “3. Constraint Application”Once the dependency-driven dates are known, the engine applies per-task constraints:
- Soft Constraints: SNET, SNLT, etc., refine the start date if the dependency date falls outside the constraint bound.
- Hard Constraints:
must-start-onandmust-finish-onoverride the forward pass results. If a hard constraint violates a dependency, a conflict is reported, but the constraint date wins.
4. Summary Rollup
Section titled “4. Summary Rollup”After all leaf tasks have their dates resolved, the engine rolls up the schedule to summary (parent) tasks:
- A summary task’s
startDateis the minimum of its children’sstartDate. - A summary task’s
endDateis the maximum of its children’sendDate. - Rollup is recursive, traversing the entire WBS (Work Breakdown Structure) tree.
5. Critical Path Analysis
Section titled “5. Critical Path Analysis”The final phase computes the project’s early and late dates using a backward pass from the project finish date:
- Total Slack: The number of days a task can be delayed without delaying the project finish.
- Critical Path: Tasks with zero total slack are marked as
isCritical. - This analysis helps planners identify the “chain” of tasks that determines the total project duration.
Conflict Resolution
Section titled “Conflict Resolution”The engine prioritizes user intent and data integrity when scheduling rules collide:
| Priority | Rule | Outcome |
|---|---|---|
| High | Actuals | actualStartDate and actualFinishDate pin the task; the engine won’t move them. |
| High | Hard Constraints | MSO / MFO dates win over dependencies; conflict reported. |
| Medium | Dependencies | Auto-tasks are clamped to satisfy predecessors. |
| Medium | Soft Constraints | Dates are adjusted to bounds where possible; conflict reported if windows are disjoint. |
| Low | Authored Dates | Used as the starting point for root tasks or manual tasks. |