///|
/// A cassette entry considered during request matching.
///
/// `key` is a value-safe summary. It is intentionally not the internal
/// normalized matching key, so a replay error cannot expose recorded headers,
/// query values, or request bodies.
pub(all) struct MatchCandidate {
  index : Int
  key : String
} derive(Eq, @debug.Debug)

///|
/// The result of matching a request against the unconsumed cassette entries.
pub(all) enum MatchResult {
  Matched(Int)
  NoMatch(Array[MatchCandidate])
} derive(Eq, @debug.Debug)

///|
/// Build the same key used by the matcher for diagnostics and tooling.
pub fn request_match_key(request : Request, config : MatchConfig) -> String {
  normalize_request(request, config)
}

///|
/// Return every unconsumed entry with a value-safe summary for diagnostics.
pub fn match_candidates(
  request : Request,
  cassette : Cassette,
  config : MatchConfig,
  consumed : Array[Bool],
) -> Array[MatchCandidate] {
  let candidates : Array[MatchCandidate] = []
  let _ = request
  let _ = config
  for index in 0.. MatchResult {
  let request_key = normalize_request(request, config)
  for index in 0..