///|
/// Return a stable textual reason for a selection decision.
pub fn selection_reason_text(reason : SelectionReason) -> String {
  match reason {
    Supported => "supported"
    UnsupportedKind => "unsupported-kind"
    OutOfReach => "out-of-reach"
    InsufficientCapability => "insufficient-capability"
    NoCandidate => "no-candidate"
    LowerScore => "lower-score"
    StableTieBreak => "stable-tie-break"
  }
}

///|
/// Count explanations that represent a rejected or missing choice.
pub fn rejected_explanation_count(explanations : Array[PlanExplanation]) -> Int {
  let mut result = 0
  for explanation in explanations {
    match explanation.reason {
      NoCandidate | UnsupportedKind | OutOfReach | InsufficientCapability =>
        result += 1
      _ => ()
    }
  }
  result
}