Class: WorkItemScheduler

Inherits:
Object
  • Object
show all
Defined in:
lib/almirah/project/work_item_scheduler.rb

Overview

Lays the WorkItem network (ADR-194) on an abstract day axis for the overview swimlane Gantt (ADR-198). It performs a deterministic forward pass over the dependency edges and then levels each owner's lane so two work items of the same owner never overlap. Levelling backfills: a row may be slotted into an idle gap left between rows placed earlier, so a low-priority short row does not queue behind the whole lane when a gap already fits it.

Durations are a constant placeholder (3 days) while no per-row estimates exist; duration_for is the single hook ADR-195 overrides to feed real estimates without changing the scheduling logic.

Days are 1-based. A work item starting on day s with duration d occupies the inclusive day span s .. s + d - 1; its finish (the next free day, returned in the ends map) is s + d, the earliest a successor or the same owner's next item may start.

Direct Known Subclasses

ChainScheduler

Constant Summary collapse

DEFAULT_DURATION =

Placeholder duration for every work item until ADR-195 supplies estimates.

3

Instance Method Summary collapse

Constructor Details

#initialize(work_items, duration: DEFAULT_DURATION) ⇒ WorkItemScheduler

Returns a new instance of WorkItemScheduler.



24
25
26
27
28
# File 'lib/almirah/project/work_item_scheduler.rb', line 24

def initialize(work_items, duration: DEFAULT_DURATION)
  @items = work_items
  @duration = duration
  @item_set = work_items.to_set
end

Instance Method Details

#critical_chainObject

The critical chain: the row with the latest finish, traced back through its binding predecessors (the dependency and resource hand-offs that set each row's start), returned in start order. Empty when nothing is scheduled.



51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/almirah/project/work_item_scheduler.rb', line 51

def critical_chain
  schedule unless @starts
  return [] if @ends.empty?

  max_end = @ends.values.max
  node = @items.select { |wi| @ends[wi] == max_end }.min_by { |wi| [wi.record_id, wi.step] }
  chain = []
  while node
    chain.unshift(node)
    node = @binding[node]
  end
  chain
end

#day_countObject

The number of day columns the chart needs: the latest finish minus one (finishes are the exclusive next-free day). Zero when there are no items.



38
39
40
41
# File 'lib/almirah/project/work_item_scheduler.rb', line 38

def day_count
  schedule unless @ends
  @ends.empty? ? 0 : (@ends.values.max - 1)
end

#duration_for(_work_item) ⇒ Object



65
66
67
# File 'lib/almirah/project/work_item_scheduler.rb', line 65

def duration_for(_work_item)
  @duration
end

#makespanObject

The schedule length in working days (the latest finish, day 1 being the start).



44
45
46
# File 'lib/almirah/project/work_item_scheduler.rb', line 44

def makespan
  day_count
end

#start_daysObject

{ work_item => start_day }, day index 1-based. Empty when there are no items.



31
32
33
34
# File 'lib/almirah/project/work_item_scheduler.rb', line 31

def start_days
  schedule unless @starts
  @starts
end