Contact
Sequence

Activities, logic & the critical path

Durations, calendars, the four relationship types, constraints, progress and the data date — and the forward and backward passes that turn all of it into dates, float and a critical path.

The schedule is the product. Everything else on this site is something you do to a schedule; this page is the schedule itself.

One rule shapes the whole engine and is worth stating before anything else: the scheduler is a pure function of its inputs, and the data date is one of those inputs. It never reads the clock. "The schedule as of the 14th" gives the same answer in March and in a claim two years later, which is the only property that makes a schedule arguable.

Rows#

A row is an activity, a summary or a milestone, and which one it is derives from its shape rather than from a setting:

RoleWhat makes it one
TaskA duration and no children
SummaryIt has children. Its dates derive from them and are not typed
MilestoneDuration zero

Hierarchy is by parent, and a summary's dates are always computed. Typing a date onto a summary is not a thing the grid lets you do, because the child that actually moved would then disagree with its own parent.

Durations#

Durations are written in a short notation and parsed on entry:

FormMeans
5d5 working days
40hHours, converted at the calendar's hours-per-day
2w2 working weeks — 10 working days
1mo1 working month — 20 working days
3ed3 elapsed days
0dA milestone

Elapsed duration is the one to get right. ed consumes calendar time and ignores every working calendar — it is how you model curing, drying, lead times and contractual periods that do not care whether it is a Sunday. A 28-day concrete cure entered as 28d is twenty-eight working days, which is five and a half weeks, and nothing about the bar chart looks wrong until the pour is late.

h converts at the calendar's own hours-per-day, so on a ten-hour-day calendar 40h is four days rather than five.

Calendars#

Every row may carry its own working pattern. Assignment precedence is row → resource → project: the row wins, because in construction the activity's working pattern is the fact and the crew is substitutable.

That makes "add five days" a calendar walk rather than arithmetic. Each calendar is compiled once into an index over the project window, after which "is this a working day", "how many working days between these two dates" and "the fifth working day from here" are all constant or near-constant work — which matters because that walk is the innermost loop of every pass.

Relationships#

Four types, with lag:

TypeReads as
FSFinish-to-start — the ordinary one
SSStart-to-start
FFFinish-to-finish
SFStart-to-finish

Lag is in days and may be negative, in which case it is a lead. Lag normally consumes the successor's working days; a link may instead mark its lag as elapsed, on the same reasoning as ed durations.

⚠ Leads are counted against you by the quality check. A negative lag is usually a missing activity wearing a disguise — the thing that genuinely happens in the overlap has a name, a duration and an owner, and writing it as -5d hides all three.

Constraints#

Eight, matching the way schedulers already think about them:

ConstraintEffect
As soon as possibleThe default — logic decides
As late as possibleConsumes float
Start no earlier thanA floor on the start
Start no later thanHard
Finish no earlier thanA floor on the finish
Finish no later thanHard
Must start onHard
Must finish onHard

The four marked hard are the ones that can drive total float negative, and they are counted separately by the quality check. They are the most common way a schedule is made to look achievable: a date is imposed, the float goes negative behind it, and the bar chart still draws a tidy line.

Deadlines are not constraints. A deadline never moves the schedule. It flags the row when the computed finish passes it, which is what you usually meant when you reached for Must-finish-on.

Manual rows#

A row may be switched to manual scheduling, in which case you own its dates and logic does not move them. This is a visible per-row mode, not a hidden property — the case where a manual row's dates contradict its own logic is detected and reported rather than silently tolerated, and the quality check counts both manual rows and contradicting ones.

Progress and the data date#

All progress is stated as of the data date.

FieldWhat it does
Actual startMoves the row to the day it actually began
Actual finishCloses the row
Remaining durationThe forward-looking number, and the one that drives the forecast
% Complete (Duration)Only used to derive remaining duration when that is absent
% Complete (Physical)Drives earned value — and nothing else
% Complete (Units)Drives cost actuals — and nothing else

⚠⚠ The three percentages are three different measures and are never substituted for one another. Duration progress is the one that always exists, which makes it the tempting fallback everywhere the other two are blank. It is refused: a cost performance index computed from duration progress looks exactly like a cost performance index and is not one. A row with no physical percent yields no earned value at all.

Out-of-sequence progress#

An activity progressed before its predecessor finished has to be handled one of two ways, and Sequence makes you say which:

  • Retained logic (the default) — the remainder still waits for the predecessor.
  • Progress override — the remainder proceeds.

This changes the forward pass and it changes the answer. It is therefore printed on every schedule rather than buried in a settings dialog.

Summary rollup#

A summary's % Complete is weighted, not averaged. Where costing is enabled it weights by budget cost, otherwise by duration. An unweighted average of children is the single most common way a schedule reports 60% on a job that is 20% built.

⚠ A row with no basis to weight on is excluded from the weighting rather than counted at zero. An uncosted row and a free one are different answers.

What the passes produce#

For every row:

Early start / early finishForward pass
Late start / late finishBackward pass
Total floatWorking days of slack before the project finish moves. May be negative
Free floatWorking days of slack before any successor's early start moves
CriticalTotal float ≤ the criticality threshold, which defaults to 0

The backward pass runs to the longest path unless you impose a project finish, in which case it runs to that — and the difference between the two is what the Critical Path Length Index reports.

Cycles and open ends#

A cycle stops the schedule. Nothing is scheduled while one exists, and the result names the rows in the loop in order, closing back on the first, rather than reporting that a cycle exists somewhere.

Open ends — rows with no predecessor or no successor — are not errors and do not stop anything. They are counted and reported, because a critical path built over open ends is fiction, but a genuine project start and a genuine project finish are open ends too and the check knows it.

Why did this move?#

Every row carries an explanation, and the explanation is generated by the passes themselves rather than reconstructed afterwards:

  • The driving predecessor — the one that actually set this row's start.
  • Every other predecessor, with how much slack it has against this row.
  • The binding constraint, if one moved the row, and what it did.
  • Which calendar applied, and whether it came from the row or the project.
  • The non-working days consumed inside the row's own span.
  • Whether a manual row contradicts its own logic.
  • Whether the row finishes after its deadline, and by how many days.
  • How progress shaped the dates.

The chain forward#

From any row you can walk the driving path forward, one hop at a time, to where nothing is driven any further — normally the project finish.

Where a row drives several successors the chain follows the tightest one: least total float, then the one finishing latest. That is the hop a delay actually travels down; offering an arbitrary branch would answer the question with a coin toss.

This is derived entirely from the explanations the passes already emitted. There is no second traversal of the logic and no second opinion about what is driving what — a driving path that disagreed with the engine would be worse than absent.