///|
pub(all) struct TaskChange {
  name : String
  before_feasible : Bool
  after_feasible : Bool
  before_upper : Int64?
  after_upper : Int64?
  slack_before : Int64?
  slack_after : Int64?
}

// Match configurations by stable task name, independently of priority order.
// Only true converged bounds participate in slack calculations.

///|
pub fn compare(
  before : Array[Task],
  after : Array[Task],
) -> Array[TaskChange] raise ModelError {
  let old = fixed_priority(before)
  let current = fixed_priority(after)
  if before.length() != after.length() {
    raise InvalidModel
  }
  let out : Array[TaskChange] = []
  for i in 0..