///|
pub enum FuzzOutputMode {
  Text
  Jsonl
} derive(Eq, Debug)

///|
pub struct FuzzCliArgs {
  suite : String
  profile : String
  seed : UInt64
  seed_i64 : Int64
  output_mode : FuzzOutputMode
  seed_count : Int32
  shard_index : Int32
  shard_count : Int32
  report_json_path : String?
  out_dir : String?
} derive(Eq, Debug)

///|
pub struct FuzzRecipe {
  name : String
  suite : String
  profile : String
  seed_i64 : Int64
  output_mode : FuzzOutputMode
  seed_count : Int32
  shard_count : Int32
} derive(Eq, Debug)

///|
pub struct FuzzInterestingnessHashLayer {
  name : String
  digest : String
  description : String
} derive(Eq, Debug)

///|
pub struct FuzzInterestingnessHashSchema {
  schema_id : String
  layers : Array[FuzzInterestingnessHashLayer]
} derive(Eq, Debug)

///|
pub struct FuzzInterestingnessCaseKey {
  raw_hash : String
  decoded_shape_hash : String
  feature_fact_hash : String
  normalized_hash : String
  predicate_hash : String
  reduced_artifact_hash : String
} derive(Eq, Debug)

///|
pub struct FuzzCorpusHashMetadata {
  raw_artifact_hash : String
  reduced_artifact_hash : String
  predicate_hash : String
  feature_fact_hash : String
  interestingness_label : String
} derive(Eq, Debug)

///|
pub struct FuzzCorpusPromotionMetadata {
  id : String
  state : String
  source : String
  input : String
  created_at : String
  generator : String
  features : Array[String]
  expectation : String
  classification : String
  replay : String
  artifacts : Array[String]
  owner_or_task : String
  notes : String
  raw_artifact_hash : String
  reduced_artifact_hash : String
  normalized_shape_hash : String
  predicate_hash : String
  feature_fact_hash : String
  interestingness_label : String
} derive(Eq, Debug)

///|
pub struct FuzzCorpusReplayCommandMetadata {
  case_id : String
  suite : String
  profile : String
  seed : UInt64
  seed_index : Int32
  strategy_or_artifact : String
  expected_outcome : String
  classification : String
  command : String
} derive(Eq, Debug)

///|
pub struct FuzzCorpusReplayAllPlan {
  planned_count : Int32
  skipped_count : Int32
  malformed_count : Int32
  commands : Array[FuzzCorpusReplayCommandMetadata]
} derive(Eq, Debug)

///|
pub struct FuzzCorpusCaseIndexEntry {
  hash_kind : String
  hash : String
  case_ids : Array[String]
  seeds : Array[UInt64]
  profiles : Array[String]
  artifact_paths : Array[String]
} derive(Eq, Debug)

///|
pub struct FuzzCorpusCaseIndex {
  entries : Array[FuzzCorpusCaseIndexEntry]
} derive(Eq, Debug)

///|
pub struct FuzzCorpusDedupDryRunDecision {
  action : String
  hash_kind : String
  hash : String
  case_ids : Array[String]
  artifact_paths : Array[String]
  reason : String
} derive(Eq, Debug)

///|
pub struct FuzzCorpusDedupDryRunPlan {
  duplicate_count : Int32
  compress_count : Int32
  keep_count : Int32
  decisions : Array[FuzzCorpusDedupDryRunDecision]
} derive(Eq, Debug)

///|
pub fn FuzzInterestingnessCaseKey::new(
  raw_hash : String,
  decoded_shape_hash : String,
  feature_fact_hash : String,
  normalized_hash : String,
  predicate_hash : String,
  reduced_artifact_hash : String,
) -> FuzzInterestingnessCaseKey {
  {
    raw_hash,
    decoded_shape_hash,
    feature_fact_hash,
    normalized_hash,
    predicate_hash,
    reduced_artifact_hash,
  }
}

///|
fn fuzz_fnv1a64_hex_digit(value : UInt64) -> Char {
  let nibble = value.to_int()
  if nibble < 10 {
    (48 + nibble).unsafe_to_char()
  } else {
    (87 + nibble).unsafe_to_char()
  }
}

///|
fn fuzz_fnv1a64_hex(hash : UInt64) -> String {
  let out = StringBuilder::new()
  let mut shift = 60
  while shift >= 0 {
    out.write_char(fuzz_fnv1a64_hex_digit((hash >> shift) & 0xFUL))
    shift -= 4
  }
  out.to_string()
}

///|
pub fn fuzz_corpus_hash_bytes(bytes : Bytes) -> String {
  let mut hash = 1469598103934665603UL
  let prime = 1099511628211UL
  let mut i = 0
  while i < bytes.length() {
    hash = (hash ^ bytes[i].to_uint64()) * prime
    i += 1
  }
  "fnv1a64-\{fuzz_fnv1a64_hex(hash)}"
}

///|
pub fn fuzz_corpus_hash_text(text : String) -> String {
  fuzz_corpus_hash_bytes(fuzz_string_to_bytes(text))
}

///|
fn fuzz_join_sorted_feature_facts(feature_facts : Array[String]) -> String {
  let sorted : Array[String] = []
  for fact in feature_facts {
    sorted.push(fact)
  }
  sorted.sort()
  let out = StringBuilder::new()
  for i in 0.. 0 {
      out.write_char('\n')
    }
    out.write_string(sorted[i])
  }
  out.to_string()
}

///|
pub fn build_fuzz_corpus_hash_metadata(
  raw_artifact : Bytes,
  reduced_artifact~ : Bytes? = None,
  predicate : String,
  feature_facts : Array[String],
  interestingness_label : String,
) -> FuzzCorpusHashMetadata {
  let reduced_bytes = match reduced_artifact {
    Some(bytes) => bytes
    None => raw_artifact
  }
  FuzzCorpusHashMetadata::new(
    fuzz_corpus_hash_bytes(raw_artifact),
    fuzz_corpus_hash_bytes(reduced_bytes),
    fuzz_corpus_hash_text(predicate),
    fuzz_corpus_hash_text(fuzz_join_sorted_feature_facts(feature_facts)),
    interestingness_label,
  )
}

///|
pub fn FuzzCorpusPromotionMetadata::new(
  id : String,
  state : String,
  source : String,
  input : String,
  created_at : String,
  generator : String,
  features : Array[String],
  expectation : String,
  classification : String,
  replay : String,
  artifacts : Array[String],
  owner_or_task : String,
  notes : String,
  raw_artifact_hash~ : String = "",
  reduced_artifact_hash~ : String = "",
  normalized_shape_hash~ : String = "",
  predicate_hash~ : String = "",
  feature_fact_hash~ : String = "",
  interestingness_label~ : String = "unclassified",
) -> FuzzCorpusPromotionMetadata {
  {
    id,
    state,
    source,
    input,
    created_at,
    generator,
    features,
    expectation,
    classification,
    replay,
    artifacts,
    owner_or_task,
    notes,
    raw_artifact_hash,
    reduced_artifact_hash,
    normalized_shape_hash,
    predicate_hash,
    feature_fact_hash,
    interestingness_label,
  }
}

///|
pub fn FuzzCorpusHashMetadata::new(
  raw_artifact_hash : String,
  reduced_artifact_hash : String,
  predicate_hash : String,
  feature_fact_hash : String,
  interestingness_label : String,
) -> FuzzCorpusHashMetadata {
  {
    raw_artifact_hash,
    reduced_artifact_hash,
    predicate_hash,
    feature_fact_hash,
    interestingness_label,
  }
}

///|
pub fn FuzzCorpusReplayCommandMetadata::new(
  case_id : String,
  suite : String,
  profile : String,
  seed : UInt64,
  seed_index : Int32,
  strategy_or_artifact : String,
  expected_outcome : String,
  classification : String,
  command : String,
) -> FuzzCorpusReplayCommandMetadata {
  {
    case_id,
    suite,
    profile,
    seed,
    seed_index,
    strategy_or_artifact,
    expected_outcome,
    classification,
    command,
  }
}

///|
pub fn FuzzCorpusCaseIndexEntry::new(
  hash_kind : String,
  hash : String,
  case_ids : Array[String],
  seeds : Array[UInt64],
  profiles : Array[String],
  artifact_paths : Array[String],
) -> FuzzCorpusCaseIndexEntry {
  { hash_kind, hash, case_ids, seeds, profiles, artifact_paths, }
}

///|
pub fn FuzzCorpusCaseIndex::new(
  entries : Array[FuzzCorpusCaseIndexEntry],
) -> FuzzCorpusCaseIndex {
  { entries, }
}

///|
pub fn FuzzCorpusDedupDryRunDecision::new(
  action : String,
  hash_kind : String,
  hash : String,
  case_ids : Array[String],
  artifact_paths : Array[String],
  reason : String,
) -> FuzzCorpusDedupDryRunDecision {
  { action, hash_kind, hash, case_ids, artifact_paths, reason, }
}

///|
pub fn FuzzCorpusDedupDryRunPlan::new(
  duplicate_count : Int32,
  compress_count : Int32,
  keep_count : Int32,
  decisions : Array[FuzzCorpusDedupDryRunDecision],
) -> FuzzCorpusDedupDryRunPlan {
  { duplicate_count, compress_count, keep_count, decisions, }
}

///|
pub fn fuzz_interestingness_hash_schema() -> FuzzInterestingnessHashSchema {
  {
    schema_id: "starshine.fuzz-interestingness.v1",
    layers: [
      {
        name: "raw",
        digest: "fnv1a64-hex",
        description: "Hash of original specimen bytes before decoding, normalization, or reduction.",
      },
      {
        name: "decoded-shape",
        digest: "fnv1a64-hex",
        description: "Hash of decoded module/script shape: section and instruction families without preserving incidental payload bytes.",
      },
      {
        name: "feature-fact",
        digest: "fnv1a64-hex",
        description: "Hash of sorted feature facts such as GC, exception, memory64, SIMD, string, import, export, and proposal markers.",
      },
      {
        name: "normalized",
        digest: "fnv1a64-hex",
        description: "Hash of canonical normalized comparison text or bytes after accepted representation-only cleanup.",
      },
      {
        name: "predicate",
        digest: "fnv1a64-hex",
        description: "Hash of the oracle outcome, interestingness predicate, failure class, pass name, and relevant tool verdicts.",
      },
      {
        name: "reduced-artifact",
        digest: "fnv1a64-hex",
        description: "Hash of the minimized or otherwise reduced artifact that still satisfies the predicate.",
      },
    ],
  }
}

///|
pub fn FuzzRecipe::new(
  name : String,
  suite : String,
  profile : String,
  seed_i64 : Int64,
  output_mode~ : FuzzOutputMode = FuzzOutputMode::Text,
  seed_count~ : Int32 = 1,
  shard_count~ : Int32 = 1,
) -> FuzzRecipe {
  { name, suite, profile, seed_i64, output_mode, seed_count, shard_count, }
}

///|
pub struct FuzzShardWorkItem {
  name : String
  suite : String
  profile : String
  seed_i64 : Int64
  output_mode : FuzzOutputMode
  seed_count : Int32
  shard_index : Int32
  shard_count : Int32
  out_dir : String?
} derive(Eq, Debug)

///|
pub fn build_fuzz_shard_queue(
  recipe : FuzzRecipe,
  out_dir_root : String?,
) -> Result[Array[FuzzShardWorkItem], String] {
  if recipe.seed_count <= 0 {
    return Err("seed-count must be greater than zero")
  }
  if recipe.shard_count <= 0 {
    return Err("shard-count must be greater than zero")
  }
  let out : Array[FuzzShardWorkItem] = []
  let total_label = fuzz_zero_pad_decimal(recipe.shard_count, 3)
  let mut shard_index = 0
  while shard_index < recipe.shard_count {
    let shard_label = fuzz_zero_pad_decimal(shard_index, 3)
    let shard_name = "\{recipe.name}-shard-\{shard_label}-of-\{total_label}"
    let shard_out_dir = match out_dir_root {
      Some(root) => Some("\{root}/shard-\{shard_label}-of-\{total_label}")
      None => None
    }
    out.push({
      name: shard_name,
      suite: recipe.suite,
      profile: recipe.profile,
      seed_i64: recipe.seed_i64,
      output_mode: recipe.output_mode,
      seed_count: recipe.seed_count,
      shard_index,
      shard_count: recipe.shard_count,
      out_dir: shard_out_dir,
    })
    shard_index += 1
  }
  Ok(out)
}

///|
fn fuzz_output_manifest_is_complete(manifest_json : String) -> Bool {
  manifest_json.contains("starshine.fuzz-output.v1") &&
  manifest_json.contains("result.json") &&
  manifest_json.contains("cases.jsonl")
}

///|
pub fn build_fuzz_resume_shard_queue(
  recipe : FuzzRecipe,
  out_dir_root : String?,
  completed_manifests : Array[String],
) -> Result[Array[FuzzShardWorkItem], String] {
  let full_queue = match build_fuzz_shard_queue(recipe, out_dir_root) {
    Ok(v) => v
    Err(e) => return Err(e)
  }
  let out : Array[FuzzShardWorkItem] = []
  let mut i = 0
  while i < full_queue.length() {
    let completed = i < completed_manifests.length() &&
      fuzz_output_manifest_is_complete(completed_manifests[i])
    if !completed {
      out.push(full_queue[i])
    }
    i += 1
  }
  Ok(out)
}

///|
pub fn fuzz_recipe_schema_version() -> String {
  "starshine.fuzz.recipe.v1"
}

///|
pub fn fuzz_standard_recipe_text_by_name(name : String) -> String? {
  let schema_line = "schema=\{fuzz_recipe_schema_version()}\n"
  match fuzz_ascii_lower(name) {
    "smoke" =>
      Some(
        schema_line +
        "name=smoke\nsuite=validate-valid\nprofile=smoke\nseed=0x5eed\nseed-count=1\nshard-count=1\noutput=text\n",
      )
    "default-smoke" =>
      Some(
        schema_line +
        "name=default-smoke\nsuite=all\nprofile=smoke\nseed=0x5eed\nseed-count=1\nshard-count=1\noutput=text\n",
      )
    "ci" =>
      Some(
        schema_line +
        "name=ci\nsuite=cmd-harness\nprofile=ci+gen-valid=natural-small+passes=common-clusters\nseed=0x5eed\nseed-count=4\nshard-count=1\noutput=jsonl\n",
      )
    "default-ci" =>
      Some(
        schema_line +
        "name=default-ci\nsuite=all\nprofile=ci\nseed=0x5eed\nseed-count=4\nshard-count=1\noutput=jsonl\n",
      )
    "nightly" =>
      Some(
        schema_line +
        "name=nightly\nsuite=validate-valid-metamorphic\nprofile=stress\nseed=0x1eed\nseed-count=32\nshard-count=8\noutput=jsonl\n",
      )
    "optimizer-ci" =>
      Some(
        schema_line +
        "name=optimizer-ci\nsuite=cmd-harness\nprofile=ci+gen-valid=pass-fuzz-stress+passes=random-short+determinism+codec-idempotence\nseed=0x5eed\nseed-count=8\nshard-count=4\noutput=jsonl\n",
      )
    "optimizer-idempotence-ci" =>
      Some(
        schema_line +
        "name=optimizer-idempotence-ci\nsuite=cmd-harness\nprofile=ci+gen-valid=pass-fuzz-stress+passes=fixed-point-cleanup+opt-idempotence+codec-idempotence\nseed=0x5eed\nseed-count=8\nshard-count=4\noutput=jsonl\n",
      )
    "optimizer-stress" =>
      Some(
        schema_line +
        "name=optimizer-stress\nsuite=cmd-harness\nprofile=stress+gen-valid=random-all-profiles+passes=random-mixed+determinism+codec-idempotence\nseed=0x5eed\nseed-count=64\nshard-count=8\noutput=jsonl\n",
      )
    "optimizer-idempotence-stress" =>
      Some(
        schema_line +
        "name=optimizer-idempotence-stress\nsuite=cmd-harness\nprofile=stress+gen-valid=random-all-profiles+passes=fixed-point-cleanup+opt-idempotence+codec-idempotence\nseed=0x5eed\nseed-count=64\nshard-count=8\noutput=jsonl\n",
      )
    "pass-signoff" =>
      Some(
        schema_line +
        "name=pass-signoff\nsuite=cmd-harness\nprofile=ci+gen-valid=binaryen-oracle-portable+passes=each-pass+check-idempotence\nseed=0x5eed\nseed-count=8\nshard-count=4\noutput=jsonl\n",
      )
    "validator-stress" =>
      Some(
        schema_line +
        "name=validator-stress\nsuite=validate-valid\nprofile=stress\nseed=0x10d69\nseed-count=16\nshard-count=4\noutput=jsonl\n",
      )
    "parser-stress" =>
      Some(
        schema_line +
        "name=parser-stress\nsuite=wast-roundtrip\nprofile=stress+parser-stress+scripts\nseed=0x5eed\nseed-count=16\nshard-count=4\noutput=jsonl\n",
      )
    "binaryen-oracle" =>
      Some(
        schema_line +
        "name=binaryen-oracle\nsuite=gen-valid-wat-validate-roundtrip\nprofile=binaryen-oracle-portable\nseed=0x5eed\nseed-count=8\nshard-count=4\noutput=jsonl\n",
      )
    "text-differential-smoke" =>
      Some(
        schema_line +
        "name=text-differential-smoke\nsuite=text-differential\nprofile=smoke\nseed=0x1045a7\nseed-count=1\nshard-count=1\noutput=jsonl\n",
      )
    _ => None
  }
}

///|
pub fn fuzz_standard_recipe_names() -> Array[String] {
  [
    "smoke", "default-smoke", "ci", "default-ci", "nightly", "optimizer-ci", "optimizer-idempotence-ci",
    "optimizer-stress", "optimizer-idempotence-stress", "pass-signoff", "validator-stress",
    "parser-stress", "binaryen-oracle", "text-differential-smoke",
  ]
}

///|
pub fn fuzz_standard_recipe_by_name(name : String) -> FuzzRecipe? {
  match fuzz_standard_recipe_text_by_name(name) {
    Some(text) =>
      match parse_fuzz_recipe_text(text) {
        Ok(recipe) => Some(recipe)
        Err(_) => None
      }
    None => None
  }
}

///|
pub struct EmitGenValidBatchArgs {
  count : Int32
  seed : UInt64
  out_dir : String
  profile : String
  required_features : Array[ValidateValidFeatureFloor]
  excluded_features : Array[ValidateValidFeatureKey]
  max_attempts : Int32
  manifest_path : String?
  metamorphic_transform_ids : Array[String]
} derive(Eq, Debug)

///|
pub fn EmitGenValidBatchArgs::new(
  count : Int32,
  seed : UInt64,
  out_dir : String,
  profile~ : String = "binaryen-oracle-portable",
  required_features~ : Array[ValidateValidFeatureFloor] = [],
  excluded_features~ : Array[ValidateValidFeatureKey] = [],
  max_attempts~ : Int32 = count,
  manifest_path~ : String? = None,
  metamorphic_transform_ids~ : Array[String] = [],
) -> EmitGenValidBatchArgs {
  {
    count,
    seed,
    out_dir,
    profile,
    required_features,
    excluded_features,
    max_attempts,
    manifest_path,
    metamorphic_transform_ids,
  }
}

///|
pub struct EmitInvalidReproArgs {
  suite : String
  strategy_id : String
  seed : UInt64
  attempt : Int32
  profile : String
  out_dir : String
} derive(Eq, Debug)

///|
pub fn EmitInvalidReproArgs::new(
  suite : String,
  strategy_id : String,
  seed : UInt64,
  attempt : Int32,
  out_dir : String,
  profile~ : String = "smoke",
) -> EmitInvalidReproArgs {
  { suite, strategy_id, seed, attempt, profile, out_dir, }
}

///|
pub enum FuzzCliCommand {
  Run(FuzzCliArgs)
  Help
  ListSuites
  ListProfiles
  ListRecipes
  EmitGenValidBatch(EmitGenValidBatchArgs)
  EmitInvalidRepro(EmitInvalidReproArgs)
  ReplayCorpus(String)
  ResolveRandomPassProfile(String, UInt64)
  GoldenSeedSmoke
} derive(Eq, Debug)

///|
pub struct FuzzRunOutputIO {
  ensure_dir : (String) -> Result[Unit, String]
  write_file : (String, Bytes) -> Result[Unit, String]
}

///|
pub fn FuzzRunOutputIO::new(
  ensure_dir~ : (String) -> Result[Unit, String] = fn(path) {
    Err("ensure_dir not configured: \{path}")
  },
  write_file~ : (String, Bytes) -> Result[Unit, String] = fn(path, _) {
    Err("write_file not configured: \{path}")
  },
) -> FuzzRunOutputIO {
  { ensure_dir, write_file, }
}

///|
pub struct FuzzSuiteResult {
  suite : String
  profile : String
  seed : Int64
  attempts : Int32
  elapsed_ms : UInt64
  seed_index : Int32
  seed_count : Int32
  shard_index : Int32
  shard_count : Int32
  total_run_budget_ms : UInt64?
  total_run_budget_exceeded : Bool
  run_budget_classification : String
  details_json : String?
} derive(Eq, Debug)

///|
pub struct FuzzGoldenSeedSmokeCase {
  suite : String
  profile : String
  seed : Int64
  seed_index : Int32
  attempts : Int32
  details_required : Bool
  details_json : String?
  catalog_entry_id : String?
  expected_counter_count : Int32
} derive(Eq, Debug)

///|
pub fn FuzzGoldenSeedSmokeCase::new(
  suite : String,
  profile : String,
  seed : Int64,
  seed_index : Int32,
  attempts : Int32,
  details_required : Bool,
  details_json~ : String? = None,
  catalog_entry_id~ : String? = None,
  expected_counter_count~ : Int32 = 0,
) -> FuzzGoldenSeedSmokeCase {
  {
    suite,
    profile,
    seed,
    seed_index,
    attempts,
    details_required,
    details_json,
    catalog_entry_id,
    expected_counter_count,
  }
}

///|
pub fn FuzzGoldenSeedSmokeCase::details_json_contains(
  self : FuzzGoldenSeedSmokeCase,
  needle : String,
) -> Bool {
  match self.details_json {
    Some(details) => details.contains(needle)
    None => false
  }
}

///|
pub struct FuzzGoldenSeedSmokeReport {
  schema_id : String
  recipe_name : String
  seed : Int64
  cases : Array[FuzzGoldenSeedSmokeCase]
} derive(Eq, Debug)

///|
pub fn FuzzGoldenSeedSmokeReport::new(
  schema_id : String,
  recipe_name : String,
  seed : Int64,
  cases : Array[FuzzGoldenSeedSmokeCase],
) -> FuzzGoldenSeedSmokeReport {
  { schema_id, recipe_name, seed, cases, }
}

///|
pub struct FuzzReplayCommand {
  suite : String
  profile : String
  seed : Int64
  seed_index : Int32
} derive(Eq, Debug)

///|
fn fuzz_ascii_lower(input : String) -> String {
  let out = StringBuilder::new()
  for c in input {
    if c >= 'A' && c <= 'Z' {
      out.write_char((c.to_int() + 32).unsafe_to_char())
    } else {
      out.write_char(c)
    }
  }
  out.to_string()
}

///|
pub fn fuzz_active_suite_names() -> Array[String] {
  [
    "wast-roundtrip", "wat-roundtrip", "wast-validate-roundtrip", "gen-valid-wat-validate-roundtrip",
    "valid-multi-module-linking", "validate-valid", "validate-valid-metamorphic",
    "validate-invalid-ast", "validate-invalid-binary", "validate-invalid-text", "validate-invalid-text-dynamic",
    "validate-invalid-spec-seed", "binary-roundtrip", "cmd-harness",
  ]
}

///|
pub fn fuzz_reserved_suite_names() -> Array[String] {
  []
}

///|
pub fn fuzz_suite_inventory_lines() -> Array[String] {
  let lines : Array[String] = []
  for suite in fuzz_active_suite_names() {
    lines.push("active\t\{suite}")
  }
  for suite in fuzz_reserved_suite_names() {
    lines.push("reserved\t\{suite}")
  }
  lines
}

///|
fn fuzz_profile_names() -> Array[String] {
  ["smoke", "ci", "stress"]
}

///|
fn fuzz_join(values : Array[String], sep : String) -> String {
  let out = StringBuilder::new()
  let mut i = 0
  while i < values.length() {
    if i > 0 {
      out.write_string(sep)
    }
    out.write_string(values[i])
    i += 1
  }
  out.to_string()
}

///|
pub fn fuzz_usage_text() -> String {
  let active_suites = fuzz_join(fuzz_active_suite_names(), ", ")
  let reserved = fuzz_reserved_suite_names()
  let reserved_suites = if reserved.is_empty() {
    "(none)"
  } else {
    fuzz_join(reserved, ", ")
  }
  let profiles = fuzz_join(fuzz_profile_names(), ", ")
  "usage: moon run src/fuzz -- [suite] [profile] [seed] [--recipe ] [--suite ] [--profile ] [--seed |--seed=] [--seed-count ] [--shard-index  --shard-count ] [--report-json ] [--output text|jsonl|--jsonl]\ncommands: --help|-h | --list-suites | --list-profiles | --list-recipes | --golden-seed-smoke | --resolve-random-pass-profile  --seed  | --emit-gen-valid-batch --count  --seed  --out-dir  [--manifest ] (portable coverage-forced batch) | --emit-invalid-repro --suite  --strategy  --seed  --attempt  --out-dir  [--profile ] | --replay-corpus \nactive suites: \{active_suites}\nreserved suite ids: \{reserved_suites}\nprofiles: \{profiles}\nopt-in recipes: text-differential-smoke"
}

///|
pub struct WastValidateRoundtripFuzzStats {
  profile : String
  seed : UInt64
  attempts : Int32
  printed : Int32
  print_failures : Int32
  parsed : Int32
  parse_failures : Int32
  lowered : Int32
  lower_failures : Int32
  validated : Int32
  validation_failures : Int32
} derive(Eq, Debug)

///|
pub struct GenValidWatValidateRoundtripFuzzStats {
  profile : String
  seed : UInt64
  attempts : Int32
  generated : Int32
  printed : Int32
  print_failures : Int32
  parsed : Int32
  parse_failures : Int32
  lowered : Int32
  lower_failures : Int32
  validated : Int32
  validation_failures : Int32
} derive(Eq, Debug)

///|
pub struct TextDifferentialFuzzStats {
  profile : String
  seed : UInt64
  attempts : Int32
  local_parse_ok : Int32
  local_print_ok : Int32
  local_reparse_lower_ok : Int32
  local_lower_mismatch : Int32
  adapter_unavailable : Int32
  adapter_unavailable_classifications : Int32
  accepted_classifications : Int32
  external_adapters : Array[String]
} derive(Eq, Debug)

///|
pub struct ValidMultiModuleWastCase {
  name : String
  text : String
  feature_facts : Array[String]
} derive(Eq, Debug)

///|
pub enum MultiModuleWastClassification {
  ValidLinking
  Unlinkable
  DuplicateModuleName
  DuplicateRegisterName
  ParseFailure
  SingleModuleValidationFailure
  LinkFailure
  LinkSkipped
} derive(Eq, Debug)

///|
pub struct ValidMultiModuleLinkingFuzzStats {
  profile : String
  seed : UInt64
  attempts : Int32
  generated : Int32
  parsed_scripts : Int32
  parse_failures : Int32
  single_module_validated : Int32
  single_module_validation_failures : Int32
  link_passed : Int32
  link_failed : Int32
  link_skipped : Int32
} derive(Eq, Debug)

///|
fn gen_valid_multi_module_wast_case_text(suffix : String) -> String {
  let provider_name = "provider_" + suffix
  let consumer_name = "consumer_" + suffix
  "(module $" +
  provider_name +
  "\n" +
  "  (func $f (export \"f\") (result i32) i32.const 7)\n" +
  "  (memory (export \"mem\") 1)\n" +
  "  (table (export \"tab\") 1 funcref)\n" +
  "  (global (export \"g\") i32 (i32.const 9)))\n" +
  "(register \"provider\" $" +
  provider_name +
  ")\n" +
  "(module $" +
  consumer_name +
  "\n" +
  "  (import \"provider\" \"f\" (func $f (result i32)))\n" +
  "  (import \"provider\" \"mem\" (memory 1))\n" +
  "  (import \"provider\" \"tab\" (table 1 funcref))\n" +
  "  (import \"provider\" \"g\" (global i32))\n" +
  "  (func (export \"use-func\") (result i32) call $f)\n" +
  "  (func (export \"use-global\") (result i32) global.get 0))\n" +
  "(register \"consumer\" $" +
  consumer_name +
  ")\n"
}

///|
pub fn gen_valid_multi_module_wast_case(
  seed : UInt64,
) -> ValidMultiModuleWastCase {
  let suffix = fuzz_zero_pad_decimal((seed % 100000UL).to_int(), 5)
  {
    name: "valid-multi-module-linking-\{suffix}",
    text: gen_valid_multi_module_wast_case_text(suffix),
    feature_facts: [
      "multi-module", "valid-linking", "register", "import:func", "import:memory",
      "import:table", "import:global", "export:func", "export:memory", "export:table",
      "export:global",
    ],
  }
}

///|
pub fn gen_valid_multi_module_wast_cases(
  seed : UInt64,
  count : Int32,
) -> Array[ValidMultiModuleWastCase] {
  let cases : Array[ValidMultiModuleWastCase] = []
  if count <= 0 {
    return cases
  }
  for i = 0; i < count; i = i + 1 {
    cases.push(gen_valid_multi_module_wast_case(seed + i.to_uint64()))
  }
  cases
}

///|
fn gen_unlinkable_multi_module_provider_prefix(suffix : String) -> String {
  let provider_name = "unlinkable_provider_" + suffix
  "(module $" +
  provider_name +
  "\n" +
  "  (func (export \"f\") (result i32) i32.const 7)\n" +
  "  (memory (export \"mem\") 1)\n" +
  "  (table (export \"tab\") 1 funcref)\n" +
  "  (global (export \"g\") i32 (i32.const 9))\n" +
  "  (tag (export \"tag\") (param i32)))\n" +
  "(register \"provider\" $" +
  provider_name +
  ")\n"
}

///|
fn gen_unlinkable_multi_module_wast_case_body(
  variant : Int32,
  suffix : String,
) -> (String, String, Array[String]) {
  let prefix = gen_unlinkable_multi_module_provider_prefix(suffix)
  match variant {
    0 =>
      (
        "missing-func",
        prefix +
        "(assert_unlinkable (module (import \"provider\" \"missing_f\" (func))) \"unknown import\")\n",
        ["import:func", "missing-import:func"],
      )
    1 =>
      (
        "missing-memory",
        prefix +
        "(assert_unlinkable (module (import \"provider\" \"missing_mem\" (memory 1))) \"unknown import\")\n",
        ["import:memory", "missing-import:memory"],
      )
    2 =>
      (
        "missing-table",
        prefix +
        "(assert_unlinkable (module (import \"provider\" \"missing_tab\" (table 1 funcref))) \"unknown import\")\n",
        ["import:table", "missing-import:table"],
      )
    3 =>
      (
        "missing-global",
        prefix +
        "(assert_unlinkable (module (import \"provider\" \"missing_g\" (global i32))) \"unknown import\")\n",
        ["import:global", "missing-import:global"],
      )
    4 =>
      (
        "missing-tag",
        prefix +
        "(assert_unlinkable (module (tag (import \"provider\" \"missing_tag\") (param i32))) \"unknown import\")\n",
        ["import:tag", "missing-import:tag"],
      )
    5 =>
      (
        "mismatch-func",
        prefix +
        "(assert_unlinkable (module (import \"provider\" \"f\" (func (param i32)))) \"incompatible import type\")\n",
        ["import:func", "type-mismatch:func"],
      )
    6 =>
      (
        "mismatch-memory",
        prefix +
        "(assert_unlinkable (module (import \"provider\" \"mem\" (memory 2 5))) \"incompatible import type\")\n",
        ["import:memory", "type-mismatch:memory"],
      )
    7 =>
      (
        "mismatch-table",
        prefix +
        "(assert_unlinkable (module (import \"provider\" \"tab\" (table 11 funcref))) \"incompatible import type\")\n",
        ["import:table", "type-mismatch:table"],
      )
    8 =>
      (
        "mismatch-global",
        prefix +
        "(assert_unlinkable (module (import \"provider\" \"g\" (global f64))) \"incompatible import type\")\n",
        ["import:global", "type-mismatch:global"],
      )
    _ =>
      (
        "mismatch-tag",
        prefix +
        "(assert_unlinkable (module (tag (import \"provider\" \"tag\") (param f32))) \"incompatible import type\")\n",
        ["import:tag", "type-mismatch:tag"],
      )
  }
}

///|
pub fn gen_unlinkable_multi_module_wast_case(
  seed : UInt64,
) -> ValidMultiModuleWastCase {
  let variant = (seed % 10UL).to_int()
  let suffix = fuzz_zero_pad_decimal((seed % 100000UL).to_int(), 5)
  let (variant_name, text, variant_facts) = gen_unlinkable_multi_module_wast_case_body(
    variant, suffix,
  )
  let facts = [
    "multi-module", "unlinkable", "assert_unlinkable", "valid-before-link", variant_name,
  ]
  facts.append(variant_facts)
  {
    name: "unlinkable-multi-module-\{suffix}-\{variant_name}",
    text,
    feature_facts: facts,
  }
}

///|
pub fn gen_unlinkable_multi_module_wast_cases(
  seed : UInt64,
  count : Int32,
) -> Array[ValidMultiModuleWastCase] {
  let cases : Array[ValidMultiModuleWastCase] = []
  if count <= 0 {
    return cases
  }
  for i = 0; i < count; i = i + 1 {
    cases.push(gen_unlinkable_multi_module_wast_case(seed + i.to_uint64()))
  }
  cases
}

///|
fn gen_duplicate_module_name_wast_case(
  suffix : String,
) -> ValidMultiModuleWastCase {
  let module_name = "dup_module_" + suffix
  {
    name: "duplicate-module-name-multi-module-\{suffix}",
    text: "(module $" +
    module_name +
    " (func))\n" +
    "(module $" +
    module_name +
    " (func))\n",
    feature_facts: ["multi-module", "duplicate-module-name"],
  }
}

///|
fn gen_duplicate_register_name_wast_case(
  suffix : String,
) -> ValidMultiModuleWastCase {
  let first_module_name = "dup_register_a_" + suffix
  let second_module_name = "dup_register_b_" + suffix
  {
    name: "duplicate-register-name-multi-module-\{suffix}",
    text: "(module $" +
    first_module_name +
    " (func))\n" +
    "(register \"dupe\" $" +
    first_module_name +
    ")\n" +
    "(module $" +
    second_module_name +
    " (func))\n" +
    "(register \"dupe\" $" +
    second_module_name +
    ")\n",
    feature_facts: ["multi-module", "duplicate-register-name", "register"],
  }
}

///|
pub fn gen_duplicate_multi_module_wast_case(
  seed : UInt64,
) -> ValidMultiModuleWastCase {
  let suffix = fuzz_zero_pad_decimal((seed % 100000UL).to_int(), 5)
  if seed % 2UL == 1UL {
    gen_duplicate_module_name_wast_case(suffix)
  } else {
    gen_duplicate_register_name_wast_case(suffix)
  }
}

///|
fn fuzz_string_array_contains(items : Array[String], needle : String) -> Bool {
  for item in items {
    if item == needle {
      return true
    }
  }
  false
}

///|
fn classify_multi_module_note_module_id(
  seen : Array[String],
  id : String?,
) -> Bool {
  match id {
    Some(name) => {
      if fuzz_string_array_contains(seen, name) {
        return true
      }
      seen.push(name)
      false
    }
    None => false
  }
}

///|
pub fn classify_multi_module_wast_case(
  case : ValidMultiModuleWastCase,
) -> MultiModuleWastClassification {
  let script = match wast_to_script(case.text, filename=case.name + ".wast") {
    Ok(v) => v
    Err(_) => return ParseFailure
  }
  let seen_module_ids : Array[String] = []
  let seen_register_names : Array[String] = []
  let mut saw_unlinkable = false
  for cmd in script.commands {
    match cmd {
      WastCommand::Module(m) =>
        if classify_multi_module_note_module_id(seen_module_ids, m.id) {
          return DuplicateModuleName
        }
      WastCommand::ModuleBinary(id, _) =>
        if classify_multi_module_note_module_id(seen_module_ids, id) {
          return DuplicateModuleName
        }
      WastCommand::ModuleQuote(id, _) =>
        if classify_multi_module_note_module_id(seen_module_ids, id) {
          return DuplicateModuleName
        }
      WastCommand::Register(name, _) => {
        if fuzz_string_array_contains(seen_register_names, name) {
          return DuplicateRegisterName
        }
        seen_register_names.push(name)
      }
      WastCommand::AssertUnlinkable(_, _) => saw_unlinkable = true
      _ => ()
    }
  }
  if saw_unlinkable {
    return Unlinkable
  }
  match @wast.run_wast_spec_file(case.name + ".wast", case.text).status {
    @wast.WastSpecFileStatus::Passed => ValidLinking
    @wast.WastSpecFileStatus::Skipped(_) => LinkSkipped
    @wast.WastSpecFileStatus::Failed(msg) =>
      if msg.contains("validation failed:") ||
        msg.contains("module lower failed:") {
        SingleModuleValidationFailure
      } else {
        LinkFailure
      }
  }
}

///|
fn valid_multi_module_linking_attempts(
  profile : String,
) -> Result[Int32, String] {
  let normalized = fuzz_ascii_lower(profile.trim().to_owned())
  match normalized {
    "smoke" => Ok(4)
    "ci" => Ok(16)
    "stress" => Ok(64)
    _ =>
      Err(
        "unknown valid-multi-module-linking fuzz profile '\{profile}'; expected smoke|ci|stress",
      )
  }
}

///|
pub fn run_valid_multi_module_linking_fuzz(
  profile : String,
  seed : UInt64,
) -> Result[ValidMultiModuleLinkingFuzzStats, String] {
  let normalized = fuzz_ascii_lower(profile.trim().to_owned())
  let attempts = match valid_multi_module_linking_attempts(profile) {
    Ok(v) => v
    Err(e) => return Err(e)
  }
  let cases = gen_valid_multi_module_wast_cases(seed, attempts)
  let mut generated = 0
  let mut parsed_scripts = 0
  let mut parse_failures = 0
  let mut single_module_validated = 0
  let mut single_module_validation_failures = 0
  let mut link_passed = 0
  let mut link_failed = 0
  let mut link_skipped = 0
  let mut last_error = ""
  for case in cases {
    generated += 1
    let script = match wast_to_script(case.text, filename=case.name + ".wast") {
      Ok(v) => {
        parsed_scripts += 1
        v
      }
      Err(e) => {
        parse_failures += 1
        last_error = e
        continue
      }
    }
    for cmd in script.commands {
      match cmd {
        WastCommand::Module(m) =>
          match wast_ast_to_binary_module(m) {
            Ok(binary_module) =>
              match validate_module(binary_module) {
                Ok(_) => single_module_validated += 1
                Err(e) => {
                  single_module_validation_failures += 1
                  last_error = validation_error_message(e)
                }
              }
            Err(e) => {
              single_module_validation_failures += 1
              last_error = e
            }
          }
        _ => ()
      }
    }
    let report = @wast.run_wast_spec_file(case.name + ".wast", case.text)
    match report.status {
      @wast.WastSpecFileStatus::Passed => link_passed += 1
      @wast.WastSpecFileStatus::Failed(e) => {
        link_failed += 1
        last_error = e
      }
      @wast.WastSpecFileStatus::Skipped(e) => {
        link_skipped += 1
        last_error = e
      }
    }
  }
  if generated != attempts {
    return Err("valid multi-module linking generated count mismatch")
  }
  if parse_failures > 0 ||
    single_module_validation_failures > 0 ||
    link_failed > 0 ||
    link_skipped > 0 ||
    link_passed == 0 {
    return Err(
      "valid multi-module linking did not fully pass: profile=\{normalized} seed=\{seed} generated=\{generated} parsed=\{parsed_scripts} single_module_validated=\{single_module_validated} single_module_validation_failures=\{single_module_validation_failures} link_passed=\{link_passed} link_failed=\{link_failed} link_skipped=\{link_skipped} last_error=\{last_error}",
    )
  }
  Ok(ValidMultiModuleLinkingFuzzStats::{
    profile: normalized,
    seed,
    attempts,
    generated,
    parsed_scripts,
    parse_failures,
    single_module_validated,
    single_module_validation_failures,
    link_passed,
    link_failed,
    link_skipped,
  })
}

///|
fn gen_valid_wat_roundtrip_config() -> GenValidConfig {
  GenValidConfig::wat_text_roundtrip_default()
}

///|
pub fn run_gen_valid_wat_validate_roundtrip_fuzz(
  profile : String,
  seed : UInt64,
) -> Result[GenValidWatValidateRoundtripFuzzStats, String] {
  let normalized = fuzz_ascii_lower(profile.trim().to_owned())
  let attempts = match normalized {
    "smoke" => 32
    "ci" => 128
    "stress" => 512
    _ =>
      return Err(
        "unknown gen-valid-wat-validate fuzz profile '\{profile}'; expected smoke|ci|stress",
      )
  }
  let config = gen_valid_wat_roundtrip_config()
  let state = @splitmix.new(seed~)
  let mut generated = 0
  let mut printed = 0
  let mut print_failures = 0
  let mut parsed = 0
  let mut parse_failures = 0
  let mut lowered = 0
  let mut lower_failures = 0
  let mut validated = 0
  let mut validation_failures = 0
  let mut last_print_failure = ""
  let mut last_parse_failure = ""
  for _ in 0.. {
        printed += 1
        v
      }
      Err(e) => {
        print_failures += 1
        last_print_failure = e
        continue
      }
    }
    let parsed_module = match
      wast_to_module(text, filename="gen-valid-wat-roundtrip.wat") {
      Ok(v) => {
        parsed += 1
        v
      }
      Err(e) => {
        parse_failures += 1
        last_parse_failure = e
        continue
      }
    }
    let lowered_module = match wast_ast_to_binary_module(parsed_module) {
      Ok(v) => {
        lowered += 1
        v
      }
      Err(_) => {
        lower_failures += 1
        continue
      }
    }
    match validate_module(lowered_module) {
      Ok(_) => validated += 1
      Err(_) => validation_failures += 1
    }
  }
  if generated != attempts {
    return Err("gen-valid wat roundtrip generated count mismatch")
  }
  if printed <= 0 || parsed <= 0 || lowered <= 0 || validated <= 0 {
    return Err(
      "gen-valid wat roundtrip made no validated progress: profile=\{normalized} seed=\{seed} generated=\{generated} printed=\{printed} parsed=\{parsed} lowered=\{lowered} validated=\{validated} last_print_failure=\{last_print_failure} last_parse_failure=\{last_parse_failure}",
    )
  }
  Ok(GenValidWatValidateRoundtripFuzzStats::{
    profile: normalized,
    seed,
    attempts,
    generated,
    printed,
    print_failures,
    parsed,
    parse_failures,
    lowered,
    lower_failures,
    validated,
    validation_failures,
  })
}

///|
fn text_differential_case(seed : UInt64, attempt : Int32) -> String {
  let value = ((seed + attempt.to_uint64()) % 1000UL).to_int()
  "(module (func (export \"answer\") (result i32) i32.const \{value}))"
}

///|
fn text_differential_attempt_locally(source : String) -> Result[Bool, String] {
  let parsed = match wast_to_module(source, filename="text-differential.wat") {
    Ok(v) => v
    Err(e) => return Err("parse failed: \{e}")
  }
  let lowered = match wast_ast_to_binary_module(parsed) {
    Ok(v) => v
    Err(e) => return Err("lower failed: \{e}")
  }
  let lowered_bytes = match encode_module(lowered) {
    Ok(v) => v
    Err(e) => return Err("encode failed: \{e}")
  }
  let printed = match module_to_wast(parsed) {
    Ok(v) => v
    Err(e) => return Err("print failed: \{e}")
  }
  let reparsed = match
    wast_to_module(printed, filename="text-differential.printed.wat") {
    Ok(v) => v
    Err(e) => return Err("reparse failed: \{e}")
  }
  let relowered = match wast_ast_to_binary_module(reparsed) {
    Ok(v) => v
    Err(e) => return Err("reparse lower failed: \{e}")
  }
  let relowered_bytes = match encode_module(relowered) {
    Ok(v) => v
    Err(e) => return Err("reparse encode failed: \{e}")
  }
  Ok(lowered_bytes == relowered_bytes)
}

///|
pub fn run_text_differential_fuzz(
  profile : String,
  seed : UInt64,
) -> Result[TextDifferentialFuzzStats, String] {
  let normalized = fuzz_ascii_lower(profile.trim().to_owned())
  let attempts = match normalized {
    "smoke" => 1
    "ci" => 8
    "stress" => 32
    _ =>
      return Err(
        "unknown text-differential fuzz profile '\{profile}'; expected smoke|ci|stress",
      )
  }
  let external_adapters = ["wabt-unavailable", "wasm-tools-unavailable"]
  let mut local_parse_ok = 0
  let mut local_print_ok = 0
  let mut local_reparse_lower_ok = 0
  let mut local_lower_mismatch = 0
  let mut adapter_unavailable = 0
  let mut adapter_unavailable_classifications = 0
  let accepted_classifications = 0
  let mut last_local_error = ""
  for attempt in 0.. {
        local_parse_ok += 1
        local_print_ok += 1
        if bytes_equal {
          local_reparse_lower_ok += 1
        } else {
          local_lower_mismatch += 1
        }
      }
      Err(e) => {
        last_local_error = e
        continue
      }
    }
    adapter_unavailable += external_adapters.length()
    adapter_unavailable_classifications += 1
  }
  if local_reparse_lower_ok == 0 {
    return Err(
      "text differential made no local parse/print/lower progress: profile=\{normalized} seed=\{seed} last_local_error=\{last_local_error}",
    )
  }
  Ok(TextDifferentialFuzzStats::{
    profile: normalized,
    seed,
    attempts,
    local_parse_ok,
    local_print_ok,
    local_reparse_lower_ok,
    local_lower_mismatch,
    adapter_unavailable,
    adapter_unavailable_classifications,
    accepted_classifications,
    external_adapters,
  })
}

///|
pub fn run_wast_validate_roundtrip_fuzz(
  profile : String,
  seed : UInt64,
) -> Result[WastValidateRoundtripFuzzStats, String] {
  let normalized = fuzz_ascii_lower(profile.trim().to_owned())
  let attempts = match normalized {
    "smoke" => 64
    "ci" => 256
    "stress" => 1024
    _ =>
      return Err(
        "unknown wast-validate fuzz profile '\{profile}'; expected smoke|ci|stress",
      )
  }
  let state = @splitmix.new(seed~)
  let mut printed = 0
  let mut print_failures = 0
  let mut parsed = 0
  let mut parse_failures = 0
  let mut lowered = 0
  let mut lower_failures = 0
  let mut validated = 0
  let mut validation_failures = 0
  let mut iteration = 0
  while iteration < attempts {
    iteration += 1
    let wmod : @wast.Module = if iteration == 1 {
      match wast_to_module("(module)", filename="wast-validate-seed.wat") {
        Ok(v) => v
        Err(e) => abort("unexpected fixed WAST seed parse failure: \{e}")
      }
    } else {
      Arbitrary::arbitrary(5, state)
    }
    let text = match module_to_wast(wmod) {
      Ok(v) => {
        printed += 1
        v
      }
      Err(_) => {
        print_failures += 1
        continue
      }
    }
    let parsed_module = match wast_to_module(text) {
      Ok(v) => {
        parsed += 1
        v
      }
      Err(_) => {
        parse_failures += 1
        continue
      }
    }
    let lowered_module = match wast_ast_to_binary_module(parsed_module) {
      Ok(v) => {
        lowered += 1
        v
      }
      Err(_) => {
        lower_failures += 1
        continue
      }
    }
    match validate_module(lowered_module) {
      Ok(_) => validated += 1
      Err(_) => validation_failures += 1
    }
  }
  if lowered <= 0 {
    return Err(
      "wast validate roundtrip lowered no modules: profile=\{normalized} seed=\{seed} attempts=\{attempts}",
    )
  }
  if validated <= 0 {
    return Err(
      "wast validate roundtrip validated no modules: profile=\{normalized} seed=\{seed} lowered=\{lowered}",
    )
  }
  Ok(WastValidateRoundtripFuzzStats::{
    profile: normalized,
    seed,
    attempts,
    printed,
    print_failures,
    parsed,
    parse_failures,
    lowered,
    lower_failures,
    validated,
    validation_failures,
  })
}

///|
fn validate_valid_text_companion_requirements(
  normalized : String,
) -> (Int32, Int32) {
  match normalized {
    "smoke" => (0, 0)
    "ci" => (20, 2)
    "stress" => (80, 8)
    _ => abort("unreachable validate-valid text companion profile")
  }
}

///|
fn run_validate_valid_suite_detailed(
  profile : String,
  seed : UInt64,
) -> Result[(Int32, String?), String] {
  let run_config = match validate_valid_run_config(profile) {
    Ok(config) => config
    Err(e) => return Err(e)
  }
  let normalized = run_config.profile
  let (min_text_attempts, min_text_stable) = validate_valid_text_companion_requirements(
    normalized,
  )

  let direct_stats = match run_validate_valid_fuzz(normalized, seed) {
    Ok(stats) => stats
    Err(e) => return Err(e)
  }
  let attempts = direct_stats.attempts
  let validated = direct_stats.validated
  let mut roundtrip = 0
  let mut stable = 0
  if min_text_attempts > 0 {
    let text_seed = seed ^ 0x574154554c
    match run_wat_roundtrip_fuzz(normalized, text_seed) {
      Ok(stats) => {
        roundtrip = stats.successes
        stable = stats.stable
      }
      Err(e) =>
        return Err(
          "validate-valid fuzz text companion failed: profile=\{normalized} seed=\{text_seed} error=\{e}",
        )
    }
  }

  if validated != attempts {
    return Err(
      "validate-valid fuzz failed: profile=\{normalized} seed=\{seed} direct validate count mismatch: \{validated}/\{attempts}",
    )
  }
  if roundtrip < min_text_attempts {
    return Err(
      "validate-valid fuzz produced too few text roundtrips: profile=\{normalized} seed=\{seed} roundtrip=\{roundtrip} min=\{min_text_attempts}",
    )
  }
  if stable < min_text_stable {
    return Err(
      "validate-valid fuzz produced too few stable text roundtrips: profile=\{normalized} seed=\{seed} stable=\{stable} min=\{min_text_stable}",
    )
  }
  Ok((attempts, Some(format_validate_valid_details_json(direct_stats))))
}

///|
fn fuzz_seed_digit(c : UInt16, base : Int32) -> Int32? {
  let digit = if c >= '0' && c <= '9' {
    c.to_int() - 0x30
  } else if base == 16 && c >= 'a' && c <= 'f' {
    c.to_int() - 0x61 + 10
  } else if base == 16 && c >= 'A' && c <= 'F' {
    c.to_int() - 0x41 + 10
  } else {
    return None
  }
  if digit >= base {
    return None
  }
  Some(digit)
}

///|
fn fuzz_parse_seed(raw : String) -> Result[Int64, String] {
  let text = raw.trim().to_owned()
  if text.length() == 0 {
    return Err("seed must not be empty")
  }
  let mut negative = false
  let mut i = 0
  if text[0] == '+' {
    i = 1
  } else if text[0] == '-' {
    negative = true
    i = 1
  }
  if i >= text.length() {
    return Err("invalid seed '\{raw}'")
  }
  let mut base = 10
  if i + 1 < text.length() &&
    text[i] == '0' &&
    (text[i + 1] == 'x' || text[i + 1] == 'X') {
    base = 16
    i += 2
  }
  let mut result : UInt64 = 0UL
  let max_abs = if negative {
    0x8000000000000000UL
  } else {
    0x7FFFFFFFFFFFFFFFUL
  }
  let base_u = base.to_uint64()
  let mut saw_digit = false
  while i < text.length() {
    let c = text[i]
    if c == '_' {
      i += 1
      continue
    }
    let digit = match fuzz_seed_digit(c, base) {
      Some(v) => v
      None => return Err("invalid seed '\{raw}'")
    }
    saw_digit = true
    let digit_u = digit.to_uint64()
    if result > (max_abs - digit_u) / base_u {
      return Err("seed '\{raw}' is out of range for int64")
    }
    result = result * base_u + digit_u
    i += 1
  }
  if !saw_digit {
    return Err("invalid seed '\{raw}'")
  }
  if negative {
    if result == 0x8000000000000000UL {
      Ok(result.reinterpret_as_int64())
    } else {
      Ok(-result.reinterpret_as_int64())
    }
  } else {
    Ok(result.reinterpret_as_int64())
  }
}

///|
fn fuzz_parse_output_mode(raw : String) -> Result[FuzzOutputMode, String] {
  let normalized = fuzz_ascii_lower(raw.trim().to_owned())
  match normalized {
    "text" => Ok(FuzzOutputMode::Text)
    "jsonl" => Ok(FuzzOutputMode::Jsonl)
    _ => Err("unknown output mode '\{raw}'; expected text|jsonl")
  }
}

///|
fn fuzz_generate_seed_i64() -> Int64 {
  trace_now_us().reinterpret_as_int64()
}

///|
fn fuzz_has_seed_equals_flag(arg : String) -> Bool {
  arg.length() >= 7 &&
  arg[0] == '-' &&
  arg[1] == '-' &&
  arg[2] == 's' &&
  arg[3] == 'e' &&
  arg[4] == 'e' &&
  arg[5] == 'd' &&
  arg[6] == '='
}

///|
fn fuzz_has_output_equals_flag(arg : String) -> Bool {
  arg.length() >= 9 &&
  arg[0] == '-' &&
  arg[1] == '-' &&
  arg[2] == 'o' &&
  arg[3] == 'u' &&
  arg[4] == 't' &&
  arg[5] == 'p' &&
  arg[6] == 'u' &&
  arg[7] == 't' &&
  arg[8] == '='
}

///|
fn fuzz_has_prefix_text(arg : String, prefix : String) -> Bool {
  if arg.length() < prefix.length() {
    return false
  }
  let mut i = 0
  while i < prefix.length() {
    if arg[i] != prefix[i] {
      return false
    }
    i += 1
  }
  true
}

///|
fn fuzz_tail_string(input : String, start : Int32) -> String {
  let out = StringBuilder::new()
  let mut i = start
  while i < input.length() {
    out.write_char(input[i].unsafe_to_char())
    i += 1
  }
  out.to_string()
}

///|
fn fuzz_parse_seed_or_abort(raw : String) -> Int64 {
  match fuzz_parse_seed(raw) {
    Ok(v) => v
    Err(e) => abort(e)
  }
}

///|
fn fuzz_parse_output_or_abort(raw : String) -> FuzzOutputMode {
  match fuzz_parse_output_mode(raw) {
    Ok(v) => v
    Err(e) => abort(e)
  }
}

///|
fn fuzz_parse_uint64(raw : String) -> Result[UInt64, String] {
  let text = raw.trim().to_owned()
  if text.length() == 0 {
    return Err("seed must not be empty")
  }
  let negative = text[0] == '-'
  let mut i = if negative || text[0] == '+' { 1 } else { 0 }
  let mut base = 10
  if i + 1 < text.length() &&
    text[i] == '0' &&
    (text[i + 1] == 'x' || text[i + 1] == 'X') {
    base = 16
    i += 2
  }
  let base_u = base.to_uint64()
  let mut value = 0UL
  let mut saw_digit = false
  while i < text.length() {
    if text[i] == '_' {
      i += 1
      continue
    }
    let digit = match fuzz_seed_digit(text[i], base) {
      Some(v) => v.to_uint64()
      None => return Err("invalid seed '\{raw}'")
    }
    if value > (0xffffffffffffffffUL - digit) / base_u {
      return Err("seed '\{raw}' is out of range for uint64")
    }
    value = value * base_u + digit
    saw_digit = true
    i += 1
  }
  if !saw_digit {
    return Err("invalid seed '\{raw}'")
  }
  if negative && value != 0UL {
    return Err("seed must be non-negative")
  }
  Ok(value)
}

///|
fn fuzz_parse_uint64_or_abort(raw : String) -> UInt64 {
  match fuzz_parse_uint64(raw) {
    Ok(v) => v
    Err(e) => abort(e)
  }
}

///|
fn fuzz_parse_non_negative_decimal_or_abort(
  label : String,
  raw : String,
) -> Int32 {
  let text = raw.trim().to_owned()
  if text.length() == 0 {
    abort("\{label} must not be empty")
  }
  let mut value = 0
  for c in text {
    if c < '0' || c > '9' {
      abort("invalid \{label} '\{raw}'")
    }
    let digit = c.to_int() - '0'.to_int()
    value = value * 10 + digit
  }
  value
}

///|
fn fuzz_parse_feature_floor_or_abort(raw : String) -> ValidateValidFeatureFloor {
  let parts : Array[String] = []
  for part in raw.split(":") {
    parts.push(part.to_owned())
  }
  if parts.length() > 2 {
    abort(
      "invalid --require-feature '\{raw}'; expected