///| Reproducible synthetic decoding workloads. They are not a replacement for

///| real model evaluation; their purpose is to exercise acceptance, rejection,

///|
/// vocabulary shape, and scheduling paths in CI without downloading weights.
pub enum WorkloadError {
  InvalidRounds(Int)
  InvalidDepth(Int)
  InvalidVocabulary(Int)
  InvalidAgreement(Double)
  RandomFailure
} derive(Eq, Debug)

///| Agreement controls how often target and draft favour the same token.

///| Values near one create easy speculative cases; values near zero stress

///|
/// residual sampling and rejection handling.
pub struct WorkloadConfig {
  rounds : Int
  proposal_depth : Int
  vocabulary_size : Int
  agreement : Double
}

///|
pub fn WorkloadConfig::new(
  rounds : Int,
  proposal_depth : Int,
  vocabulary_size : Int,
  agreement : Double,
) -> Result[WorkloadConfig, WorkloadError] {
  if rounds <= 0 {
    return Err(InvalidRounds(rounds))
  }
  if proposal_depth <= 0 {
    return Err(InvalidDepth(proposal_depth))
  }
  if vocabulary_size < 2 {
    return Err(InvalidVocabulary(vocabulary_size))
  }
  if !finite_number(agreement) || agreement < 0.0 || agreement > 1.0 {
    return Err(InvalidAgreement(agreement))
  }
  Ok({ rounds, proposal_depth, vocabulary_size, agreement })
}

///|
/// A small default workload appropriate for the command-line example.
pub fn WorkloadConfig::demo() -> WorkloadConfig {
  { rounds: 4, proposal_depth: 3, vocabulary_size: 8, agreement: 0.75 }
}

///|
pub fn WorkloadConfig::rounds(self : WorkloadConfig) -> Int {
  self.rounds
}

///|
pub fn WorkloadConfig::proposal_depth(self : WorkloadConfig) -> Int {
  self.proposal_depth
}

///|
pub fn WorkloadConfig::vocabulary_size(self : WorkloadConfig) -> Int {
  self.vocabulary_size
}

///| Build one noisy logit row with a chosen winning token. Adding a positive

///| margin keeps the scenario easy to reason about while background noise

///|
/// prevents every distribution from being a trivial one-hot vector.
fn logits_for(
  rng : DeterministicRng,
  vocabulary_size : Int,
  preferred : Int,
) -> Array[Double] {
  let logits : Array[Double] = []
  for token in 0..