{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "as-bench configuration",
  "description": "Configuration for the as-bench benchmarking framework. Precedence: built-in defaults < this file < --mode overlay < CLI flags.",
  "type": "object",
  "additionalProperties": false,
  "definitions": {
    "settings": {
      "type": "object",
      "additionalProperties": false,
      "description": "Engine tunables. These override the settings.* values set inside benchmark files (they flow to the wasm via the tune hook), and are themselves overridden by CLI flags.",
      "properties": {
        "warmupTime": {
          "type": "number",
          "minimum": 0,
          "default": 3000,
          "description": "Warmup time cap in milliseconds. Adaptive warmup may exit earlier once timings stabilize."
        },
        "warmupMinTime": {
          "type": "number",
          "minimum": 0,
          "default": 100,
          "description": "Earliest point (ms) at which adaptive warmup may declare convergence."
        },
        "warmupTolerance": {
          "type": "number",
          "minimum": 0,
          "default": 0.02,
          "description": "Relative drift between consecutive warmup batches considered stable (0.02 = 2%). 0 disables adaptive exit (criterion-style fixed-time warmup)."
        },
        "measurementTime": {
          "type": "number",
          "minimum": 1,
          "default": 3000,
          "description": "Target measurement time in milliseconds across all samples of a bench."
        },
        "sampleSize": {
          "type": "number",
          "minimum": 10,
          "default": 100,
          "description": "Number of timed samples collected per bench. Omit to auto-size from warmup (~10 ms/sample, clamped to 10-500)."
        },
        "numResamples": {
          "type": "number",
          "minimum": 1,
          "default": 100000,
          "description": "Bootstrap resamples used for confidence intervals and comparisons."
        },
        "samplingMode": {
          "enum": ["auto", "linear", "flat"],
          "default": "auto",
          "description": "linear scales iterations across samples (enables the slope estimate); flat uses a constant count; auto picks per bench."
        },
        "confidenceLevel": {
          "type": "number",
          "exclusiveMinimum": 0,
          "exclusiveMaximum": 1,
          "default": 0.95,
          "description": "Confidence level for all interval bounds (0.95 = 95% CI)."
        }
      }
    },
    "render": {
      "type": "object",
      "additionalProperties": false,
      "description": "Host-side result rendering thresholds (the engine does not use these).",
      "properties": {
        "significanceLevel": {
          "type": "number",
          "minimum": 0,
          "default": 0.05,
          "description": "p-value threshold below which a delta counts as statistically significant."
        },
        "noiseThreshold": {
          "type": "number",
          "minimum": 0,
          "default": 0.01,
          "description": "Deltas whose entire confidence interval lies within ±this ratio render as 'no change' (criterion's rule)."
        }
      }
    },
    "buildOptions": {
      "type": "object",
      "additionalProperties": false,
      "description": "How bench files are compiled with asc.",
      "properties": {
        "optimize": {
          "type": "boolean",
          "default": true,
          "description": "Pass --optimize to asc. Note: optimization level interacts with V8 tier heuristics on the node runtime; external runtimes (wasmtime etc.) are tier-free."
        },
        "debug": {
          "type": "boolean",
          "default": false,
          "description": "Pass --debug to asc (keeps the name section + debug info). Profile builds add this automatically."
        },
        "args": {
          "type": "array",
          "items": { "type": "string" },
          "default": [],
          "description": "Extra asc arguments appended to every bench build (e.g. [\"--enable\", \"simd\"])."
        }
      }
    },
    "runtimeEntry": {
      "type": "object",
      "additionalProperties": false,
      "anyOf": [{ "required": ["cmd"] }, { "required": ["name"] }],
      "properties": {
        "name": {
          "type": "string",
          "description": "Display label used in headers, the comparison table, and baseline keys. Without \"cmd\" it is also the runtime itself: node | wasmtime | wasmer | wazero."
        },
        "cmd": {
          "type": "string",
          "minLength": 1,
          "description": "Command that runs each bench wasm, e.g. \"wazero run <env:-env> <file>\". <file> is replaced with the artifact path (appended as the last argument when omitted). The bench is a pure-WASI WIPC build reporting over framed stdout. Settings overrides are exported in the child's environment as AS_BENCH_TUNE_<kind>=<value>; runtimes that don't forward host env to the guest also need them as flags — <env:PREFIX> expands each pair, fusing a trailing '=' into one argument (<env:--env=> → --env=K=V) and otherwise emitting two (<env:-env> → -env K=V)."
        }
      }
    },
    "runOptions": {
      "type": "object",
      "additionalProperties": false,
      "description": "How compiled benches are executed (as-test-style). Takes precedence over the top-level \"runtime\" shorthand.",
      "properties": {
        "runtime": {
          "description": "One runtime, or several — a list runs every bench under each runtime and renders a comparison table (and prefixes baseline keys with the runtime label). List entries may also be plain strings (a named runtime or command template, as in the top-level \"runtime\" shorthand).",
          "oneOf": [
            { "$ref": "#/definitions/runtimeEntry" },
            {
              "type": "array",
              "minItems": 1,
              "items": { "oneOf": [{ "type": "string", "minLength": 1 }, { "$ref": "#/definitions/runtimeEntry" }] }
            }
          ]
        }
      }
    },
    "profile": {
      "type": "object",
      "additionalProperties": false,
      "description": "Defaults for the `asb profile` command.",
      "properties": {
        "top": {
          "type": "number",
          "minimum": 1,
          "default": 10,
          "description": "Rows shown per bench in the heaviest-calls table."
        },
        "all": {
          "type": "boolean",
          "default": false,
          "description": "Include engine/runtime-internal rows in profile tables."
        },
        "iters": {
          "type": "number",
          "minimum": 1,
          "default": 10,
          "description": "--heaviest=time iterations per bench (more beats clock granularity; percentages and per-call values are iteration-independent)."
        },
        "minInstrs": {
          "type": "number",
          "minimum": 0,
          "default": 4,
          "description": "--heaviest=time skips wrapping functions whose static weight is under this many instructions; their time folds into callers. 0 wraps everything."
        }
      }
    },
    "configBody": {
      "type": "object",
      "properties": {
        "input": {
          "type": "array",
          "items": { "type": "string" },
          "default": ["assembly/__benches__/**/*.ts"],
          "description": "Benchmark file globs (positional CLI arguments override)."
        },
        "outDir": {
          "type": "string",
          "default": ".as-bench/build",
          "description": "Directory for compiled bench artifacts."
        },
        "baselineDir": {
          "type": "string",
          "default": ".as-bench/baselines",
          "description": "Directory for baselines saved with --save-baseline."
        },
        "runtime": {
          "default": "node",
          "oneOf": [{ "type": "string" }, { "type": "array", "minItems": 1, "items": { "type": "string" } }],
          "description": "node (in-process host) | wasmtime | wasmer | wazero | a command like \"wazero run <file>\"; an array runs every bench under each runtime and renders a comparison table. Shorthand for runOptions.runtime. External runtimes run a pure-WASI build reporting over framed stdout; --baseline comparison and --deterministic need node."
        },
        "runOptions": { "$ref": "#/definitions/runOptions" },
        "verbose": {
          "type": "boolean",
          "default": false,
          "description": "Print every estimate (mean/median/std dev/MAD/slope) and warmup convergence per bench."
        },
        "deterministic": {
          "type": "boolean",
          "default": false,
          "description": "Record host imports on iteration 2 of each bench and replay them for every later iteration — neutralizes host nondeterminism. node runtime only; adds a few ns of per-iteration overhead, so compare deterministic runs with deterministic runs."
        },
        "settings": { "$ref": "#/definitions/settings" },
        "render": { "$ref": "#/definitions/render" },
        "buildOptions": { "$ref": "#/definitions/buildOptions" },
        "profile": { "$ref": "#/definitions/profile" }
      }
    }
  },
  "allOf": [{ "$ref": "#/definitions/configBody" }],
  "properties": {
    "$schema": { "type": "string" },
    "input": true,
    "outDir": true,
    "baselineDir": true,
    "runtime": true,
    "runOptions": true,
    "verbose": true,
    "deterministic": true,
    "settings": true,
    "render": true,
    "buildOptions": true,
    "profile": true,
    "modes": {
      "type": "object",
      "description": "Named partial-config overlays selected with --mode <name>. A mode may override any top-level option; objects merge one level deep, scalars and arrays replace.",
      "additionalProperties": {
        "allOf": [{ "$ref": "#/definitions/configBody" }],
        "type": "object"
      }
    }
  }
}
