{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/algenta-ai/json-schema/algenta-ai-simulate-request-expert-schema.json",
  "title": "SimulateRequestExpert",
  "description": "Expert-mode simulation request — full distribution and objective control.",
  "x-generated": "2026-11-01",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/api.algenta.ai-openapi.json#/components/schemas/SimulateRequestExpert",
  "properties": {
    "mode": {
      "type": "string",
      "const": "expert",
      "title": "Mode"
    },
    "simulation": {
      "$ref": "#/$defs/ExpertSimulation"
    },
    "runs": {
      "type": "integer",
      "maximum": 1000000.0,
      "minimum": 100.0,
      "title": "Runs",
      "default": 10000
    },
    "seed": {
      "anyOf": [
        {
          "type": "integer",
          "minimum": 0.0
        },
        {
          "type": "null"
        }
      ],
      "title": "Seed"
    },
    "simulation_model": {
      "$ref": "#/$defs/SimulationModel",
      "description": "Simulation algorithm. All run natively in Mojo.",
      "default": "monte_carlo"
    },
    "bootstrap_config": {
      "anyOf": [
        {
          "$ref": "#/$defs/BootstrapConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "scenario_config": {
      "anyOf": [
        {
          "$ref": "#/$defs/ScenarioConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "mcmc_config": {
      "anyOf": [
        {
          "$ref": "#/$defs/MCMCConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "sensitivity_config": {
      "anyOf": [
        {
          "$ref": "#/$defs/SensitivityConfig"
        },
        {
          "type": "null"
        }
      ]
    },
    "importance_sampling_config": {
      "anyOf": [
        {
          "$ref": "#/$defs/ImportanceSamplingConfig"
        },
        {
          "type": "null"
        }
      ],
      "description": "Config for engine_type='importance_sampling' — exponential tilting for rare tail events. Required when simulation_model='importance_sampling'. Provides unbiased tail probability and CVaR estimates with 100–10,000× fewer samples than brute-force MC."
    },
    "decision_tree_config": {
      "anyOf": [
        {
          "$ref": "#/$defs/DecisionTreeConfig"
        },
        {
          "type": "null"
        }
      ],
      "description": "Config for engine_type='decision_tree' — multi-layered branching decisions."
    },
    "time_series_config": {
      "anyOf": [
        {
          "$ref": "#/$defs/TimeSeriesConfig"
        },
        {
          "type": "null"
        }
      ],
      "description": "Config for engine_type='time_series' — multi-horizon stochastic path simulation. Models: GBM (stocks/crypto), OU (rates/spreads), arithmetic, compound, custom. Granularities: ms, s, min, h, day, week, month, quarter, year."
    },
    "include_charts": {
      "type": "boolean",
      "title": "Include Charts",
      "description": "Include pre-computed Vega-Lite chart specs in the response. When true, adds 'charts' dict with histogram, CDF, tornado (if sensitivity), fan_chart (if time_series). Ready to pass to vega-embed for instant rendering. Adds ~5ms to response time.",
      "default": false
    },
    "include_histogram": {
      "type": "boolean",
      "title": "Include Histogram",
      "description": "Include pre-computed 50-bin histogram data (lighter than full chart spec). Adds 'histogram_data' to response. Useful for quick distribution preview.",
      "default": false
    }
  },
  "type": "object",
  "required": [
    "mode",
    "simulation"
  ],
  "$defs": {
    "BootstrapConfig": {
      "properties": {
        "historical_data": {
          "items": {
            "type": "number"
          },
          "type": "array",
          "maxItems": 100000,
          "minItems": 2,
          "title": "Historical Data"
        },
        "statistic": {
          "type": "string",
          "title": "Statistic",
          "description": "Statistic to compute on each resample. One of: mean, median, std, variance, sum, min, max, sharpe, percentile_5, percentile_25, percentile_75, percentile_95, range, cv",
          "default": "mean"
        },
        "confidence_level": {
          "type": "number",
          "maximum": 1.0,
          "minimum": 0.0,
          "title": "Confidence Level",
          "default": 0.95
        }
      },
      "type": "object",
      "required": [
        "historical_data"
      ],
      "title": "BootstrapConfig",
      "description": "Config for engine_type='bootstrap' — non-parametric resampling."
    },
    "CorrelationSpec": {
      "properties": {
        "variables": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "maxItems": 2,
          "minItems": 2,
          "title": "Variables"
        },
        "coefficient": {
          "type": "number",
          "maximum": 1.0,
          "minimum": -1.0,
          "title": "Coefficient"
        }
      },
      "type": "object",
      "required": [
        "variables",
        "coefficient"
      ],
      "title": "CorrelationSpec"
    },
    "DecisionNode": {
      "properties": {
        "id": {
          "type": "string",
          "maxLength": 200,
          "minLength": 1,
          "title": "Id"
        },
        "type": {
          "type": "string",
          "title": "Type",
          "description": "Node type: decision | chance | terminal",
          "default": "terminal"
        },
        "name": {
          "type": "string",
          "maxLength": 500,
          "title": "Name",
          "default": ""
        },
        "probability": {
          "type": "number",
          "maximum": 1.0,
          "minimum": 0.0,
          "title": "Probability",
          "description": "Branch probability (for chance nodes). All siblings should sum to 1.0.",
          "default": 1.0
        },
        "condition": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 500
            },
            {
              "type": "null"
            }
          ],
          "title": "Condition",
          "description": "Optional expression condition for this branch to be active"
        },
        "variables": {
          "additionalProperties": true,
          "type": "object",
          "title": "Variables",
          "description": "Variable overrides for this branch. Scalar value → treated as fixed distribution. Dict → full VariableSpec override {distribution, params}."
        },
        "objective_function": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 1000
            },
            {
              "type": "null"
            }
          ],
          "title": "Objective Function",
          "description": "Expression override for this node. Inherits top-level if not set."
        },
        "branches": {
          "items": {
            "$ref": "#/$defs/DecisionNode"
          },
          "type": "array",
          "maxItems": 50,
          "title": "Branches",
          "description": "Child branches. Empty = terminal node."
        }
      },
      "type": "object",
      "required": [
        "id"
      ],
      "title": "DecisionNode",
      "description": "A node in a multi-layered decision tree.\n\nNode types:\n  decision  — represents a controllable choice (e.g. \"Launch\" vs \"Don't Launch\")\n  chance    — represents an uncertain outcome with a probability (e.g. \"Market Accepts\")\n  terminal  — leaf node; variables + objective_function evaluated here\n\nEach node can override any parent variable with a new distribution or scalar.\nVariable overrides cascade top-down: child inherits parent, then applies its own."
    },
    "DecisionTreeConfig": {
      "properties": {
        "nodes": {
          "items": {
            "$ref": "#/$defs/DecisionNode"
          },
          "type": "array",
          "maxItems": 50,
          "minItems": 1,
          "title": "Nodes",
          "description": "Root nodes of the decision tree. Multiple roots = parallel independent decisions."
        },
        "max_depth": {
          "type": "integer",
          "maximum": 20.0,
          "minimum": 1.0,
          "title": "Max Depth",
          "description": "Maximum allowed tree depth",
          "default": 10
        }
      },
      "type": "object",
      "required": [
        "nodes"
      ],
      "title": "DecisionTreeConfig",
      "description": "Config for engine_type='decision_tree' — multi-layered decisions with branches.\n\nExample (2-level tree):\n  nodes: [\n    {\n      id: \"launch_decision\", type: \"decision\", name: \"Launch Product?\",\n      branches: [\n        {\n          id: \"launch_yes\", type: \"chance\", name: \"Launch\", probability: 1.0,\n          branches: [\n            { id: \"accept\", type: \"terminal\", name: \"Market Accepts\",\n              probability: 0.7, objective_function: \"revenue - launch_cost\" },\n            { id: \"reject\", type: \"terminal\", name: \"Market Rejects\",\n              probability: 0.3, variables: {\"revenue\": 0},\n              objective_function: \"-launch_cost\" }\n          ]\n        }\n      ]\n    }\n  ]"
    },
    "DistributionParams": {
      "properties": {
        "mean": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Mean"
        },
        "std": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Std"
        },
        "low": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Low"
        },
        "high": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "High"
        },
        "mode": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Mode"
        },
        "value": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Value"
        },
        "alpha": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Alpha"
        },
        "beta": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Beta"
        },
        "rate": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Rate"
        },
        "lambda": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Lambda"
        },
        "shape": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Shape"
        },
        "scale": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Scale"
        },
        "likely": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Likely"
        },
        "gamma": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Gamma"
        },
        "p": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "P"
        },
        "values": {
          "anyOf": [
            {
              "items": {
                "type": "number"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "title": "Values"
        },
        "probabilities": {
          "anyOf": [
            {
              "items": {
                "type": "number"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "title": "Probabilities"
        }
      },
      "additionalProperties": true,
      "type": "object",
      "title": "DistributionParams"
    },
    "DistributionType": {
      "type": "string",
      "enum": [
        "normal",
        "uniform",
        "triangular",
        "lognormal",
        "fixed",
        "discrete",
        "categorical",
        "beta",
        "exponential",
        "weibull",
        "gamma",
        "pert",
        "bernoulli",
        "poisson",
        "student_t",
        "cauchy",
        "laplace",
        "pareto",
        "gumbel",
        "rayleigh",
        "arcsine",
        "logistic",
        "halfnormal",
        "vonmises",
        "neg_binomial",
        "hypergeometric",
        "negative_binomial"
      ],
      "title": "DistributionType",
      "description": "Universal distribution library — no restrictions on domain or data type.\nApplicable to any industry: finance, medical, manufacturing, aerospace,\ndefense, energy, hospitality, insurance, pharma, supply chain, and more."
    },
    "ExpertSimulation": {
      "properties": {
        "variables": {
          "items": {
            "$ref": "#/$defs/VariableSpec"
          },
          "type": "array",
          "minItems": 1,
          "title": "Variables"
        },
        "correlations": {
          "items": {
            "$ref": "#/$defs/CorrelationSpec"
          },
          "type": "array",
          "title": "Correlations"
        },
        "objective_function": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Objective Function",
          "description": "Expression evaluated each scenario. Supports all math functions. Multi-output: separate with | pipe character. Example: 'revenue - cost | (revenue - cost) / revenue * 100 | min(cash_flow, 0)'"
        },
        "scoring": {
          "$ref": "#/$defs/ScoringWeights"
        },
        "domain": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 200
            },
            {
              "type": "null"
            }
          ],
          "title": "Domain",
          "description": "Industry/domain hint: finance, medical, manufacturing, aerospace, defense, etc."
        },
        "domain_template": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 200
            },
            {
              "type": "null"
            }
          ],
          "title": "Domain Template",
          "description": "Name of predefined domain template used (for reference)"
        },
        "output_labels": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "title": "Output Labels",
          "description": "Labels for multi-output objectives (matches | separator count)"
        },
        "output_units": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "title": "Output Units",
          "description": "Physical/currency units for each output. E.g. ['USD', '%', 'years']"
        },
        "output_unit_specs": {
          "anyOf": [
            {
              "items": {
                "$ref": "#/$defs/UnitSpec"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "title": "Output Unit Specs",
          "description": "Full UnitSpec per output objective (matches | separator count). Enables formatted_result in the response with currency symbols, compact notation ($1.2M), scientific notation (1.23e-9 Pa), etc. Example: [{'type':'currency','code':'USD','format':'compact'}, {'type':'percentage'}]"
        }
      },
      "type": "object",
      "required": [
        "variables"
      ],
      "title": "ExpertSimulation",
      "description": "Universal simulation specification. No restrictions on domain, variable count,\nor expression complexity. Works for any industry and data type.\n\nobjective_function — complete function reference:\n  Arithmetic:   +, -, *, /, ^ (power), % (mod)\n  Standard:     sqrt(x), exp(x), ln(x), log(x), log10(x), log2(x), log1p(x),\n                expm1(x), abs(x), floor(x), ceil(x), round(x)\n  Min/Max:      min(a,b), max(a,b), clip(v,lo,hi)\n  Conditional:  if(cond>0, then_val, else_val)\n  Trigonometry: sin(x), cos(x), tan(x), asin(x), acos(x), atan(x)\n                atan2(y,x), sinh(x), cosh(x), tanh(x)\n  Special:      erf(x), erfc(x), gamma(x), lgamma(x), sign(x), hypot(a,b)\n  Statistical:  norm_cdf(x), norm_pdf(x), norm_ppf(p),\n                t_cdf(x, df), chi2_cdf(x, df), logistic(x), logit(x)\n  Combinatorics: factorial(n), comb(n,k), perm(n,k)\n  Sequences:    fibonacci(n), fib(n), fib_ratio(n) = F(n)/F(n-1)\n  Financial:    npv(rate,cf0,cf1,...), pmt(rate,n,pv), fv(rate,n,pmt,pv),\n                pv(rate,n,pmt), annuity(rate,n), duration(rate,n)\n  Constants:    c (speed of light), G (gravity), g (9.81 m/s²),\n                kB (Boltzmann), NA (Avogadro), R (gas), pi, e, phi\n  Multi-output: separate objectives with | e.g. \"net_profit | risk_score | irr\"\n  Variables:    any variable name from the variables list as a symbol\n\nExamples:\n  \"revenue - cost\"\n  \"max(0, sales * margin - fixed_cost)\"\n  \"npv(0.1, -capex, cf1, cf2, cf3, cf4, cf5)\"\n  \"norm_cdf((mu - threshold) / sigma)\"\n  \"mass * g * height\"            # kinetic/potential energy\n  \"fibonacci(growth_stage)\"      # Fibonacci growth model\n  \"revenue - cost | revenue / cost | norm_cdf(revenue - target)\"  # multi-output"
    },
    "ImportanceSamplingConfig": {
      "properties": {
        "target_threshold": {
          "type": "number",
          "title": "Target Threshold",
          "description": "The rare event level. E.g. -500000 for a $500k loss, or 2.5 for an extreme gain."
        },
        "tail_direction": {
          "type": "string",
          "title": "Tail Direction",
          "description": "'lower' for loss events (outcome < threshold), 'upper' for extreme gains (outcome > threshold).",
          "default": "lower"
        },
        "tilt_variable": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Tilt Variable",
          "description": "Name of the normal-distributed variable to apply exponential tilting to. Auto-detects the highest-variance normal variable if omitted."
        },
        "tilt_sigma": {
          "type": "number",
          "title": "Tilt Sigma",
          "description": "Override the tilt parameter θ directly (0 = auto-compute from threshold). Advanced use only.",
          "default": 0.0
        }
      },
      "type": "object",
      "required": [
        "target_threshold"
      ],
      "title": "ImportanceSamplingConfig",
      "description": "Config for engine_type='importance_sampling' — exponential tilting for rare tail events.\n\nUse when you need accurate estimates of very low-probability events\n(e.g. 1-in-10,000 loss scenarios) without running millions of MC trials.\n\nThe engine shifts sampling mass toward the target tail using exponential tilting\n(θ optimal tilt), then corrects back with likelihood ratio weights.\nReports: tail_probability, tail_probability_se, cvar_tail, ESS, variance_reduction_factor."
    },
    "MCMCConfig": {
      "properties": {
        "observed_data": {
          "items": {
            "type": "number"
          },
          "type": "array",
          "maxItems": 100000,
          "minItems": 2,
          "title": "Observed Data"
        },
        "parameter_priors": {
          "additionalProperties": true,
          "type": "object",
          "title": "Parameter Priors",
          "description": "Dict of param_name → {distribution, params}. Auto-inferred from data if empty. Example: {'mean': {'distribution': 'normal', 'params': {'mean': 500000, 'std': 100000}}}"
        },
        "likelihood": {
          "type": "string",
          "title": "Likelihood",
          "description": "Likelihood model: normal | lognormal | poisson",
          "default": "normal"
        },
        "chains": {
          "type": "integer",
          "maximum": 16.0,
          "minimum": 1.0,
          "title": "Chains",
          "default": 4
        },
        "burn_in": {
          "type": "integer",
          "maximum": 50000.0,
          "minimum": 100.0,
          "title": "Burn In",
          "default": 1000
        }
      },
      "type": "object",
      "required": [
        "observed_data"
      ],
      "title": "MCMCConfig",
      "description": "Config for engine_type='mcmc' — Metropolis-Hastings Bayesian MCMC."
    },
    "ScenarioConfig": {
      "properties": {
        "scenarios": {
          "items": {
            "$ref": "#/$defs/ScenarioItem"
          },
          "type": "array",
          "maxItems": 50,
          "minItems": 1,
          "title": "Scenarios"
        }
      },
      "type": "object",
      "required": [
        "scenarios"
      ],
      "title": "ScenarioConfig",
      "description": "Config for engine_type='scenario' — discrete weighted scenarios."
    },
    "ScenarioItem": {
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 200,
          "title": "Name"
        },
        "probability": {
          "type": "number",
          "maximum": 1.0,
          "minimum": 0.0,
          "title": "Probability"
        },
        "variables": {
          "additionalProperties": {
            "type": "number"
          },
          "type": "object",
          "title": "Variables"
        },
        "objective_function": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 500
            },
            {
              "type": "null"
            }
          ],
          "title": "Objective Function"
        }
      },
      "type": "object",
      "required": [
        "name",
        "probability"
      ],
      "title": "ScenarioItem",
      "description": "A single named scenario for discrete scenario analysis."
    },
    "ScoringWeights": {
      "properties": {
        "expected_value": {
          "type": "number",
          "maximum": 1.0,
          "minimum": 0.0,
          "title": "Expected Value",
          "default": 0.6
        },
        "downside_risk": {
          "type": "number",
          "maximum": 1.0,
          "minimum": 0.0,
          "title": "Downside Risk",
          "default": 0.4
        }
      },
      "type": "object",
      "title": "ScoringWeights"
    },
    "SensitivityConfig": {
      "properties": {
        "method": {
          "type": "string",
          "title": "Method",
          "description": "tornado | sobol | both",
          "default": "both"
        }
      },
      "type": "object",
      "title": "SensitivityConfig",
      "description": "Config for engine_type='sensitivity' — sensitivity analysis."
    },
    "SimulationModel": {
      "type": "string",
      "enum": [
        "monte_carlo",
        "qmc_sobol",
        "lhs",
        "bootstrap",
        "scenario",
        "sensitivity",
        "mcmc",
        "decision_tree",
        "time_series",
        "compare",
        "importance_sampling"
      ],
      "title": "SimulationModel",
      "description": "Which simulation algorithm to use. ALL run natively in Mojo — zero Python bottlenecks."
    },
    "StochasticParam": {
      "properties": {
        "type": {
          "type": "string",
          "title": "Type",
          "description": "fixed | normal | uniform | lognormal",
          "default": "fixed"
        },
        "value": {
          "type": "number",
          "title": "Value",
          "description": "Fixed value (for type='fixed')",
          "default": 0.0
        },
        "mean": {
          "type": "number",
          "title": "Mean",
          "description": "Mean (for type='normal' or 'lognormal')",
          "default": 0.0
        },
        "std": {
          "type": "number",
          "title": "Std",
          "description": "Std dev (for type='normal' or 'lognormal')",
          "default": 0.0
        },
        "low": {
          "type": "number",
          "title": "Low",
          "description": "Lower bound (for type='uniform')",
          "default": 0.0
        },
        "high": {
          "type": "number",
          "title": "High",
          "description": "Upper bound (for type='uniform')",
          "default": 0.0
        }
      },
      "type": "object",
      "title": "StochasticParam",
      "description": "A simulation parameter that is itself stochastic (drawn fresh for each path).\nUse for uncertain drift, volatility, or any time-series parameter."
    },
    "TimeSeriesConfig": {
      "properties": {
        "model": {
          "type": "string",
          "title": "Model",
          "description": "Path model: gbm | ou | arithmetic | compound | custom",
          "default": "gbm"
        },
        "initial_value": {
          "type": "number",
          "title": "Initial Value",
          "description": "Starting value of the process (e.g. current stock price, balance, etc.)"
        },
        "horizons": {
          "items": {
            "type": "integer"
          },
          "type": "array",
          "maxItems": 100,
          "minItems": 1,
          "title": "Horizons",
          "description": "Time steps at which to record distributions. E.g. [1,3,6,12] for 1/3/6/12 months.",
          "default": [
            1,
            3,
            6,
            12
          ]
        },
        "granularity": {
          "type": "string",
          "title": "Granularity",
          "description": "Time unit per step. One of: ms, s, min, h, day, week, month, quarter, year. All drift/vol parameters assumed annualized unless granularity='custom'.",
          "default": "month"
        },
        "drift": {
          "anyOf": [
            {
              "$ref": "#/$defs/StochasticParam"
            },
            {
              "type": "number"
            }
          ],
          "title": "Drift",
          "description": "Annualized drift / expected return. Float shorthand or StochasticParam for uncertain drift. GBM: annual log-return. OU: not used (use long_run_mean). Compound: annual return.",
          "default": 0.0
        },
        "volatility": {
          "anyOf": [
            {
              "$ref": "#/$defs/StochasticParam"
            },
            {
              "type": "number"
            }
          ],
          "title": "Volatility",
          "description": "Annualized volatility (σ). Float or StochasticParam.",
          "default": 0.2
        },
        "autocorrelation": {
          "type": "number",
          "maximum": 0.99,
          "minimum": -0.99,
          "title": "Autocorrelation",
          "description": "AR(1) autocorrelation coefficient for innovations (0 = i.i.d., >0 = trending, <0 = mean-reverting noise)",
          "default": 0.0
        },
        "long_run_mean": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "title": "Long Run Mean",
          "description": "OU model: long-run mean (μ∞). Defaults to initial_value."
        },
        "mean_reversion_speed": {
          "type": "number",
          "minimum": 0.0,
          "title": "Mean Reversion Speed",
          "description": "OU model: speed of mean reversion (θ). Higher = faster pull to mean.",
          "default": 0.5
        },
        "path_expression": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 500
            },
            {
              "type": "null"
            }
          ],
          "title": "Path Expression",
          "description": "Custom model: Python expression for next step value. Variables: value, t, dt, drift, vol, z, initial. Example: 'value * exp((drift - 0.5*vol**2)*dt + vol*dt**0.5*z)'"
        },
        "fan_chart_percentiles": {
          "items": {
            "type": "integer"
          },
          "type": "array",
          "maxItems": 20,
          "minItems": 1,
          "title": "Fan Chart Percentiles",
          "description": "Percentile levels to include in the fan chart output at each horizon.",
          "default": [
            5,
            10,
            25,
            50,
            75,
            90,
            95
          ]
        },
        "output_paths": {
          "type": "boolean",
          "title": "Output Paths",
          "description": "Include sample path data in response (for fan chart visualization). Adds ~50 paths.",
          "default": false
        },
        "n_sample_paths": {
          "type": "integer",
          "maximum": 500.0,
          "minimum": 1.0,
          "title": "N Sample Paths",
          "description": "Number of sample paths to include when output_paths=True.",
          "default": 50
        }
      },
      "type": "object",
      "required": [
        "initial_value"
      ],
      "title": "TimeSeriesConfig",
      "description": "Config for engine_type='time_series' — multi-horizon stochastic path simulation.\n\nSupported models:\n  gbm        — Geometric Brownian Motion\n  ou         — Ornstein-Uhlenbeck mean-reversion\n  arithmetic — Arithmetic Brownian Motion\n  compound   — Compound return\n  custom     — Expression-driven path\n\nGranularities: ms, s, min, h, day, week, month, quarter, year"
    },
    "UnitSpec": {
      "properties": {
        "type": {
          "type": "string",
          "title": "Type",
          "description": "Unit category: currency | crypto | date | duration | percentage | bps | scientific | si | count | probability | custom | raw",
          "default": "raw"
        },
        "code": {
          "type": "string",
          "maxLength": 50,
          "title": "Code",
          "description": "Unit identifier: ISO 4217 currency, crypto ticker, SI symbol, etc.",
          "default": ""
        },
        "precision": {
          "anyOf": [
            {
              "type": "integer",
              "maximum": 18.0,
              "minimum": 0.0
            },
            {
              "type": "null"
            }
          ],
          "title": "Precision",
          "description": "Display decimal places. None = auto-inferred from type/code."
        },
        "scale": {
          "type": "number",
          "title": "Scale",
          "description": "Multiply raw simulation output by this for display (e.g. 100 for percentage).",
          "default": 1.0
        },
        "format": {
          "type": "string",
          "title": "Format",
          "description": "Display format: standard | compact ($1.2M) | scientific (1.23e-9)",
          "default": "standard"
        },
        "base_unit": {
          "type": "string",
          "maxLength": 50,
          "title": "Base Unit",
          "description": "Sub-unit label (informational). E.g. 'satoshi' for BTC, 'wei' for ETH.",
          "default": ""
        },
        "sim_scale": {
          "type": "number",
          "title": "Sim Scale",
          "description": "Divide input params by this before simulation. E.g. sim_scale=1e8 if BTC inputs are in satoshis, converts to whole BTC for Mojo.",
          "default": 1.0
        }
      },
      "additionalProperties": true,
      "type": "object",
      "title": "UnitSpec",
      "description": "Universal unit specification — supports any numeric domain.\n\nShort-hand strings also accepted anywhere a UnitSpec is expected:\n  \"USD\"        → currency/USD (2 decimal places)\n  \"BTC\"        → crypto/BTC (8 decimal places, satoshi-aware)\n  \"ETH\"        → crypto/ETH (18 decimals, wei-aware)\n  \"%\"          → percentage (scale × 100 for display)\n  \"bps\"        → basis points (scale × 10,000 for display)\n  \"days\"       → duration in days\n  \"Pa\" / \"kg\"  → SI unit (scientific notation for tiny/huge values)\n  \"probability\" → strictly [0,1] validated\n  \"count\"      → non-negative integer-like\n\nFull dict form:\n  {\n    \"type\": \"currency\",      # unit category\n    \"code\": \"USD\",           # unit identifier\n    \"precision\": 2,          # display decimal places (None = auto)\n    \"scale\": 1.0,            # multiply raw value for display (e.g. 100 for 0→1 % → 0→100%)\n    \"format\": \"compact\",     # standard | compact | scientific\n    \"base_unit\": \"satoshi\",  # sub-unit label (informational)\n    \"sim_scale\": 1.0         # divide input by this before simulation\n  }"
    },
    "VariableSpec": {
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 500,
          "minLength": 1,
          "title": "Name"
        },
        "distribution": {
          "$ref": "#/$defs/DistributionType"
        },
        "params": {
          "$ref": "#/$defs/DistributionParams"
        },
        "unit": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 200
            },
            {
              "type": "null"
            }
          ],
          "title": "Unit",
          "description": "Short-hand unit string: 'USD', 'BTC', '%', 'bps', 'days', 'Pa', etc."
        },
        "unit_spec": {
          "anyOf": [
            {
              "$ref": "#/$defs/UnitSpec"
            },
            {
              "type": "null"
            }
          ],
          "description": "Full unit specification with type, code, precision, scale, format, sim_scale. Supersedes 'unit' if both provided. Enables preprocessing (date→epoch, crypto satoshi→BTC), range validation, and formatted output."
        },
        "description": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 1000
            },
            {
              "type": "null"
            }
          ],
          "title": "Description"
        },
        "domain_hint": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 200
            },
            {
              "type": "null"
            }
          ],
          "title": "Domain Hint",
          "description": "Optional domain hint e.g. 'time_to_failure', 'patient_recovery_days', 'material_yield_strength'"
        },
        "labels": {
          "anyOf": [
            {
              "items": {
                "type": "string"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "title": "Labels",
          "description": "For categorical/discrete: human-readable labels for each outcome index"
        }
      },
      "type": "object",
      "required": [
        "name",
        "distribution",
        "params"
      ],
      "title": "VariableSpec",
      "description": "A single simulation variable. No domain restrictions — works for any\nphysical, financial, clinical, operational, or scientific measurement."
    }
  }
}