If A has a fixed start and a successor, B, with a fixed end, an ALAP
schedule used to stretch A to run from its start to B's start. Now it
shows A starting on schedule, ending after the expected duration, and
with slack before B's start. (And vice versa for ASAP.)

TracPM.roots() returns an unordered list of ticket IDs so traversing
that list meant we were no longer computing the WBS in the correct
order. Now we use that list to determine what is a root ticket but
traverse the ticket list in the scheduled (sorted) order.