///|
/// The applicable claim chain for a point query, newest first. The first
/// candidate is the winner; later entries are superseded but still auditable.
pub struct DecisionTrace {
  key : String
  valid_at : Int64
  known_at : Int64
  candidates : Array[Revision]
  truncated : Bool
}

///|
pub fn DecisionTrace::key(self : DecisionTrace) -> String {
  self.key
}

///|
pub fn DecisionTrace::valid_at(self : DecisionTrace) -> Int64 {
  self.valid_at
}

///|
pub fn DecisionTrace::known_at(self : DecisionTrace) -> Int64 {
  self.known_at
}

///|
pub fn DecisionTrace::winner(self : DecisionTrace) -> Revision? {
  self.candidates.get(0)
}

///|
pub fn DecisionTrace::value(self : DecisionTrace) -> String? {
  observed_value(self.winner())
}

///|
pub fn DecisionTrace::candidates(self : DecisionTrace) -> Array[Revision] {
  self.candidates.copy()
}

///|
pub fn DecisionTrace::truncated(self : DecisionTrace) -> Bool {
  self.truncated
}

///|
pub fn DecisionTrace::superseded_count(self : DecisionTrace) -> Int32 {
  if self.candidates.is_empty() {
    0
  } else {
    self.candidates.length() - 1
  }
}

///|
/// Explain precedence for one point without exposing unrelated keys or valid
/// intervals. The limit caps returned claims but never discards the winner.
pub fn Ledger::trace(
  self : Ledger,
  key : String,
  valid_at : Int64,
  known_at : Int64,
  max_candidates~ : Int32 = 64,
) -> DecisionTrace raise TemporalError {
  if max_candidates <= 0 {
    raise TooManyRevisions(maximum=max_candidates)
  }
  let candidates : Array[Revision] = []
  let mut truncated = false
  match self.index.get(key) {
    Some(positions) => {
      let eligible = key_upper_bound(self.revisions, positions, known_at, true)
      for i = eligible - 1; i >= 0; i = i - 1 {
        let item = self.revisions[positions[i]]
        if item.valid.contains(valid_at) {
          if candidates.length() >= max_candidates {
            truncated = true
            break
          }
          candidates.push(item)
        }
      }
    }
    None => ()
  }
  { key, valid_at, known_at, candidates, truncated, }
}