← The evidence ledger
Evidence row 1018281
Observed , by probe.mcp/1.
- Kind
- mcp.tools
- About
- endpoint 278214a0-1e9d-4f76-9d11-401752e2e2fc
- Recorded
- Previous row
- #980439
- Body SHA-256
- 69097bee4230c6ff94be7cfb034b084f7be2563c838e15e3c11e0bf4f6be210a
- Leaf
- 0x762b792ada6223bed2c9a739151f71b6fedc7b82cfb8dc80da08d9aabb365ceb
What was observed
{
"count": 12,
"tools": [
{
"description": "Purchases credits using a payment method already saved from a prior Stripe Checkout session. Use this when an authenticated account is running low on credits and needs more to keep submitting runs or analyses, without a human re-entering card details. Example: {\"credits\":100} Cost: charges the payment card already saved on your account; it mints credits rather than spending them. See GET /billing/pricing for the current per-credit price.",
"inputSchema": {
"description": "Arguments for ``buy_credits`` (neumann#192; mirrors fermi's schema).\n\nAuthentication is required (unlike the free tools above): an anonymous\ncaller gets an ``authentication_required`` tool error. No price literal\nhere by design — see GET /billing/pricing for the current per-credit cost.",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Your API key from POST /api/v1/accounts. Required unless you are authenticated via an Authorization: Bearer token.",
"title": "Api Key"
},
"credits": {
"description": "Number of credits to purchase.",
"minimum": 1,
"title": "Credits",
"type": "integer"
}
},
"required": [
"credits"
],
"title": "BuyCreditsInput",
"type": "object"
},
"name": "buy_credits"
},
{
"description": "Converts distribution_params back into plain numbers: mean, median, std, mode, requested quantiles, a central interval, and (with a threshold) the probability above/below it. Use this when you were handed a root node -- from fermi's next_steps.simulate.root_node or a graph you are editing -- and need to know what log_normal {mu: 9.2, sigma: 0.6} actually means in plain numbers, rather than hand-computing quantiles yourself. Example: {\"distribution_type\":\"log_normal\",\"distribution_params\":{\"mu\":9.2,\"sigma\":0.6},\"percentile_range\":0.9,\"threshold\":15000} Cost: free -- no credits debited, and no anonymous daily run spent. Anonymous callers may use it at any volume.",
"inputSchema": {
"description": "Arguments for ``describe_distribution`` (neumann#277).\n\nField names deliberately match a root node's shape (``distribution_type``\n+ ``distribution_params``), so a fermi ``next_steps.simulate.root_node``\nfixture can be pasted in verbatim.",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional API key (describing is free).",
"title": "Api Key"
},
"distribution_params": {
"additionalProperties": true,
"description": "The distribution's parameters, e.g. {'mean': 100, 'std': 15}.",
"title": "Distribution Params",
"type": "object"
},
"distribution_type": {
"description": "A catalog distribution, e.g. 'normal', 'triangle', 'beta'.",
"title": "Distribution Type",
"type": "string"
},
"percentile_range": {
"default": 0.9,
"description": "Confidence the reported interval covers, as a CENTRAL interval (lower=(1-r)/2, upper=1-lower) -- e.g. 0.9 gives p5/p95. Matches solve_distribution_parameters's own convention, so the two tools round-trip.",
"exclusiveMaximum": 1,
"exclusiveMinimum": 0,
"title": "Percentile Range",
"type": "number"
},
"quantiles": {
"anyOf": [
{
"items": {
"maximum": 1,
"minimum": 0,
"type": "number"
},
"minItems": 1,
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "Quantiles (0..1) to report. Default: [0.05, 0.1, 0.5, 0.9, 0.95]. Each entry must be in [0, 1] and the list must not contain duplicates (Seer review, neumann#277: a quantile outside [0, 1] extrapolates past the support and produces a nonsense key like 'p-50').",
"title": "Quantiles"
},
"threshold": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "An optional value to report P(X<=threshold) / P(X>threshold) for (continuous types) or P(X<threshold) / P(X>threshold), with P(X=threshold) noted separately (discrete types).",
"title": "Threshold"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "DescribeDistributionInput",
"type": "object"
},
"name": "describe_distribution"
},
{
"description": "Pre-flight-sizes a graph without running it: estimated peak memory, engine complexity, which tier (small/large) it would run as, and the credit cost. Use this when you want to know what a run will cost or how heavy it is before committing to it, especially for a large or unfamiliar graph. Example: {\"graph\":{\"root_nodes\":[{\"id\":\"root\",\"distribution_type\":\"normal\",\"distribution_params\":{\"mean\":100,\"std\":15}}],\"calc_nodes\":[{\"id\":\"out\",\"formula\":\"{e1}\"}],\"edges\":[{\"id\":\"e1\",\"source\":\"root\",\"target\":\"out\"}],\"run_params\":{\"trials\":1000,\"time_periods\":12}}} Cost: free -- no credits debited, and no anonymous daily run spent. Anonymous callers may use it at any volume.",
"inputSchema": {
"$defs": {
"AggregationRequest": {
"additionalProperties": false,
"description": "A post-simulation, series-aware metric over one node's full series.\n\nNPV/IRR/payback/CAGR/cumsum are NOT per-period node values: they consume a\ntarget node's complete ``(time_periods x trials)`` matrix AFTER the run and\nreturn one value per trial, summarised into a distribution.\n\nDiscount convention (0-based series index): period ``t=0`` is the present\n(undiscounted) cash flow; period ``t`` is discounted by ``(1+rate)**t``. The\nfirst period is undiscounted.\n\nWarning — two discount conventions coexist; do not mix them. These\naggregations use the **0-based** series index above (first period\nundiscounted). The per-period formula functions ``DISCOUNT(rate,\n{time_period})`` and ``PV(rate, value, {time_period})`` use the **1-based**\n``{time_period}``, so they discount the first period by ``(1+rate)**1``.\n\n\"Investment at period 0\" pattern: model an up-front outlay as a negative\nperiod-0 cash flow in the target node's series; NPV's t=0-undiscounted\nconvention then treats it as the present-value outlay. Do not additionally\ndiscount that first period with ``PV(...,{time_period})`` inside the target\nnode's formula when also requesting an aggregation ``npv`` — combining the\n1-based per-period discount with the 0-based ``npv`` double-shifts the first\nperiod.\n\nPer-period node vs aggregate metric (``prob``): pointing ``prob`` at a\nmulti-period cash-flow NODE via ``target_node_id`` thresholds only that node's\nFINAL-period per-trial value — i.e. ``P(per-period value > x)``, NOT\n``P(NPV > x)``. To get a true ``P(NPV > 0)``, define an ``npv`` aggregation\nfirst, then add a ``prob`` aggregation whose ``target_aggregation_id`` points\nat that ``npv`` id; ``prob`` then thresholds the NPV per-trial vector directly.\nA ``prob`` request targets EITHER a node (``target_node_id``) OR an earlier\naggregation (``target_aggregation_id``) — exactly one, never both.",
"properties": {
"function": {
"description": "One of: npv, irr, payback, discounted_payback, cagr, cumsum, prob, terminal_value, mirr. discounted_payback requires params.rate; npv requires params.rate OR a per-period params.rates curve; prob requires params.op (one of >, >=, <, <=, ==) and params.value; terminal_value requires params.g and params.rate; mirr requires params.finance_rate and params.reinvest_rate.",
"title": "Function",
"type": "string"
},
"id": {
"description": "Result key for this metric (unique within the request).",
"title": "Id",
"type": "string"
},
"params": {
"additionalProperties": true,
"description": "Function params, e.g. {'rate': 0.1} for npv/discounted_payback, {'op': '>', 'value': 0} for prob, {'g': 0.02, 'rate': 0.1} for terminal_value, {'finance_rate': 0.1, 'reinvest_rate': 0.08} for mirr.",
"title": "Params",
"type": "object"
},
"target_aggregation_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "For a ``prob`` request only: the id of an aggregation defined EARLIER in this output_request whose per-trial vector (e.g. an ``npv``) is thresholded. Lets ``P(NPV > 0)`` be expressed directly instead of the per-period ``P(value > x)`` you get by targeting a multi-period node. The referenced aggregation must produce a per-trial vector (npv/irr/payback/discounted_payback/cagr/cumsum/terminal_value/mirr).",
"title": "Target Aggregation Id"
},
"target_node_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The node whose full per-period series the metric consumes. Required for every metric except a ``prob`` that targets a prior aggregation via ``target_aggregation_id``. Exactly one of ``target_node_id`` / ``target_aggregation_id`` may be set on a ``prob`` request.",
"title": "Target Node Id"
}
},
"required": [
"id",
"function"
],
"title": "AggregationRequest",
"type": "object"
},
"CalcNode": {
"additionalProperties": false,
"description": "A computed node. ``formula`` is OPTIONAL.\n\nA null/empty/whitespace formula is allowed: the node is treated as a\nconstant ``0`` every period/trial (incoming edges are ignored — there is no\nimplicit \"sum of incoming edges\"). ``validate_graph`` surfaces this as a\nWARNING, not an error. To sum incoming edges, write the sum explicitly,\ne.g. ``{e1}+{e2}``; for pass-through use ``{e1}``.",
"properties": {
"formula": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional expression over incoming edge ids, e.g. '{e1} * 0.5 + {e2}'. To sum incoming edges write '{e1}+{e2}'; for pass-through use '{e1}'. If omitted/empty the node is treated as a constant 0 (sum-of-incoming is not implied); validate_graph reports this as a warning.",
"title": "Formula"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
}
},
"required": [
"id"
],
"title": "CalcNode",
"type": "object"
},
"Edge": {
"additionalProperties": false,
"description": "A directed connection carrying a value from source to target.",
"properties": {
"delay": {
"default": 0,
"description": "Periods the value is delayed in transit.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"id": {
"description": "Unique edge id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional label.",
"title": "Name"
},
"source": {
"description": "id of the source node.",
"title": "Source",
"type": "string"
},
"target": {
"description": "id of the target node.",
"title": "Target",
"type": "string"
}
},
"required": [
"id",
"source",
"target"
],
"title": "Edge",
"type": "object"
},
"OutputRequest": {
"additionalProperties": false,
"description": "Which nodes/edges/periods to include in the result.\n\nEmpty lists mean 'all': all nodes, all edges, all time periods.\n``aggregations`` requests post-simulation series metrics (NPV/IRR/...).",
"properties": {
"aggregations": {
"items": {
"$ref": "#/$defs/AggregationRequest"
},
"title": "Aggregations",
"type": "array"
},
"edges": {
"items": {
"type": "string"
},
"title": "Edges",
"type": "array"
},
"nodes": {
"items": {
"type": "string"
},
"title": "Nodes",
"type": "array"
},
"time_periods": {
"items": {
"type": "integer"
},
"title": "Time Periods",
"type": "array"
}
},
"title": "OutputRequest",
"type": "object"
},
"PublicGraph": {
"additionalProperties": false,
"description": "A complete, validated simulation request — the agent-facing input.\n\nThis is the canonical public shape. Reference integrity (edges point at real\nnodes, output_request references real ids) is validated here so malformed\ngraphs are rejected before they ever reach the engine.",
"properties": {
"calc_nodes": {
"items": {
"$ref": "#/$defs/CalcNode"
},
"title": "Calc Nodes",
"type": "array"
},
"contract_version": {
"const": "1.0",
"default": "1.0",
"description": "Schema version this graph targets.",
"title": "Contract Version",
"type": "string"
},
"edges": {
"items": {
"$ref": "#/$defs/Edge"
},
"title": "Edges",
"type": "array"
},
"root_nodes": {
"items": {
"$ref": "#/$defs/RootNode"
},
"title": "Root Nodes",
"type": "array"
},
"run_params": {
"$ref": "#/$defs/RunParams"
}
},
"required": [
"run_params"
],
"title": "PublicGraph",
"type": "object"
},
"RootNode": {
"additionalProperties": false,
"description": "A source node that samples from a probability distribution each period.\n\n``json_schema_extra`` (neumann#288) attaches a ``oneOf`` discriminated on\n``distribution_type``, so the published schema states each type's own\nrequired ``distribution_params`` keys instead of advertising an opaque\nobject. The RUNTIME annotation stays ``dict[str, object]`` — see\n``contracts.catalog.add_distribution_variants`` for why a real pydantic\ndiscriminated union is not used here.",
"oneOf": [
{
"description": "A constant value that never changes",
"properties": {
"distribution_params": {
"properties": {
"value": {
"description": "The constant value to return",
"type": "number"
}
},
"required": [
"value"
],
"type": "object"
},
"distribution_type": {
"const": "constant"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant"
},
{
"description": "Normal (Gaussian) distribution",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "normal"
},
{
"description": "Uniform distribution between low and high values",
"properties": {
"distribution_params": {
"properties": {
"high": {
"description": "Upper bound of the distribution",
"type": "number"
},
"low": {
"description": "Lower bound of the distribution",
"type": "number"
}
},
"required": [
"low",
"high"
],
"type": "object"
},
"distribution_type": {
"const": "uniform"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "uniform"
},
{
"description": "Beta distribution for modeling probabilities and proportions",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "The alpha shape parameter (α) (positive)",
"type": "number"
},
"beta": {
"description": "The beta shape parameter (β) (positive)",
"type": "number"
}
},
"required": [
"alpha",
"beta"
],
"type": "object"
},
"distribution_type": {
"const": "beta"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "beta"
},
{
"description": "Gamma distribution for modeling waiting times",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "gamma"
},
{
"description": "Exponential distribution with scale parameter",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "Scale parameter (mean) of the distribution (positive)",
"type": "number"
}
},
"required": [
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "exponential"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "exponential"
},
{
"description": "Poisson distribution for modeling count data",
"properties": {
"distribution_params": {
"properties": {
"lambda_val": {
"description": "The rate parameter (λ) (positive)",
"type": "number"
}
},
"required": [
"lambda_val"
],
"type": "object"
},
"distribution_type": {
"const": "poisson"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "poisson"
},
{
"description": "Bernoulli distribution for binary outcomes",
"properties": {
"distribution_params": {
"properties": {
"p": {
"description": "The probability of success (between 0 and 1)",
"type": "number"
}
},
"required": [
"p"
],
"type": "object"
},
"distribution_type": {
"const": "bernoulli"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "bernoulli"
},
{
"description": "Triangle distribution with minimum, maximum, and mode parameters",
"properties": {
"distribution_params": {
"properties": {
"max_val": {
"description": "The maximum value of the distribution",
"type": "number"
},
"min_val": {
"description": "The minimum value of the distribution",
"type": "number"
},
"mode_val": {
"description": "The mode (peak) of the distribution",
"type": "number"
}
},
"required": [
"min_val",
"max_val",
"mode_val"
],
"type": "object"
},
"distribution_type": {
"const": "triangle"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "triangle"
},
{
"description": "Log-normal distribution for modeling skewed, positive-valued data",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "log_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "log_normal"
},
{
"description": "Discrete log-normal: sample log-normal then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_lognormal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_lognormal"
},
{
"description": "Categorical distribution for discrete outcomes with custom probabilities",
"properties": {
"distribution_params": {
"properties": {
"probabilities": {
"description": "List of probabilities for each value (must sum to 1) (sum to 1)",
"items": {
"type": "number"
},
"type": "array"
},
"values": {
"description": "List of possible values to sample from",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values",
"probabilities"
],
"type": "object"
},
"distribution_type": {
"const": "categorical"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "categorical"
},
{
"description": "Discrete gamma: sample gamma then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_gamma"
},
{
"description": "Binomial distribution for modeling the number of successes in n independent trials",
"properties": {
"distribution_params": {
"properties": {
"n": {
"description": "Number of trials (positive integer)",
"type": "integer"
},
"p": {
"description": "Probability of success in each trial (between 0 and 1)",
"type": "number"
}
},
"required": [
"n",
"p"
],
"type": "object"
},
"distribution_type": {
"const": "binomial"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "binomial"
},
{
"description": "Dirichlet distribution for modeling correlated probabilities that sum to 1",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "Concentration parameters for each category (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"alpha"
],
"type": "object"
},
"distribution_type": {
"const": "dirichlet"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "dirichlet"
},
{
"description": "Constant array distribution for deterministic array values (used internally for scenarios)",
"properties": {
"distribution_params": {
"properties": {
"values": {
"description": "Array of constant values to return",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values"
],
"type": "object"
},
"distribution_type": {
"const": "constant_array"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant_array"
},
{
"description": "Discrete normal distribution for integer-valued data with normal characteristics",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_normal"
},
{
"description": "Multivariate normal (correlated inputs): draws a vector of correlated values per trial from a mean vector + correlation matrix + per-component standard deviations. Array-valued — feed multiple downstream calc nodes by INDEXing component k (1-based): INDEX({edge}, k).",
"properties": {
"distribution_params": {
"properties": {
"correlation": {
"description": "Square correlation matrix (NxN for N components); diagonal 1.0, symmetric, entries in [-1, 1]",
"items": {
"items": {
"type": "number"
},
"type": "array"
},
"type": "array"
},
"mean": {
"description": "Mean vector (one entry per correlated component)",
"items": {
"type": "number"
},
"type": "array"
},
"stds": {
"description": "Per-component standard deviations (same length as mean) (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"mean",
"stds",
"correlation"
],
"type": "object"
},
"distribution_type": {
"const": "multivariate_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "multivariate_normal"
}
],
"properties": {
"delay": {
"default": 0,
"description": "Periods to wait before the first sample.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"distribution_params": {
"additionalProperties": true,
"description": "Params for the chosen distribution. Which keys are required depends on distribution_type -- see this schema's oneOf, or GET /api/v1/contract. Common types: normal{mean,std} log_normal{mu,sigma} uniform{low,high} triangle{min_val,max_val,mode_val} beta{alpha,beta} poisson{lambda_val} bernoulli{p}.",
"title": "Distribution Params",
"type": "object"
},
"distribution_type": {
"description": "One of the catalog distributions (GET /api/v1/contract).",
"title": "Distribution Type",
"type": "string"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"interval": {
"default": 1,
"description": "Sample every N periods (1 = every period).",
"minimum": 0,
"title": "Interval",
"type": "integer"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
},
"sampling_frequency": {
"default": "per_period",
"description": "'once' draws a single value reused across periods.",
"enum": [
"per_period",
"once"
],
"title": "Sampling Frequency",
"type": "string"
}
},
"required": [
"id",
"distribution_type",
"distribution_params"
],
"title": "RootNode",
"type": "object"
},
"RunParams": {
"additionalProperties": false,
"description": "Top-level run configuration.",
"properties": {
"output_request": {
"$ref": "#/$defs/OutputRequest"
},
"time_periods": {
"description": "Number of time periods to simulate.",
"exclusiveMinimum": 0,
"title": "Time Periods",
"type": "integer"
},
"trials": {
"description": "Number of Monte Carlo trials.",
"exclusiveMinimum": 0,
"title": "Trials",
"type": "integer"
}
},
"required": [
"trials",
"time_periods"
],
"title": "RunParams",
"type": "object"
}
},
"description": "Arguments for ``estimate`` (runtime/memory pre-flight).",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional API key (estimation is free).",
"title": "Api Key"
},
"graph": {
"$ref": "#/$defs/PublicGraph",
"description": "The graph to size."
}
},
"required": [
"graph"
],
"title": "EstimateInput",
"type": "object"
},
"name": "estimate"
},
{
"description": "Sends feedback, a feature request, or a bug report straight to the Neumann team, CC'ing your sender_email so you keep a copy. Use this when something about the service is wrong, missing, or confusing and you want a human to see it directly rather than guessing at a workaround. Anonymous submissions are allowed. Example: {\"feedback_type\":\"feature_request\",\"message\":\"Add CSV export for run results.\",\"sender_email\":\"agent@example.com\"} Cost: free -- no credits debited, and no anonymous daily run spent. Anonymous callers may use it at any volume.",
"inputSchema": {
"description": "Arguments for ``feedback`` (neumann#114; mirrors fermi's schema).",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Your API key from POST /api/v1/accounts (optional). If provided, your account id is attached to the message for context.",
"title": "Api Key"
},
"feedback_type": {
"description": "The kind of feedback: 'feedback' for general comments, 'feature_request' for new capabilities, 'bug' for issues.",
"enum": [
"feedback",
"feature_request",
"bug"
],
"title": "Feedback Type",
"type": "string"
},
"message": {
"description": "Your feedback or request. Be as specific as possible.",
"maxLength": 5000,
"minLength": 10,
"title": "Message",
"type": "string"
},
"sender_email": {
"description": "Your email address. A copy of your feedback is CC'd here so you have a record of what you submitted.",
"format": "email",
"title": "Sender Email",
"type": "string"
},
"sender_name": {
"anyOf": [
{
"maxLength": 200,
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Your name (optional).",
"title": "Sender Name"
}
},
"required": [
"feedback_type",
"message",
"sender_email"
],
"title": "FeedbackInput",
"type": "object"
},
"name": "feedback"
},
{
"description": "Fetches the status and, once available, the summarised result for a previously-submitted run by its run_id. Results are readable only by the caller who created the run; anonymous results expire 24 hours after their run was created. Use this when you want to re-check or re-fetch a run you already submitted (e.g. via run_simulation) without resubmitting the graph -- run_simulation itself already blocks until done and returns the full result directly, so this is not a poll-until-ready step for it. Example: {\"run_id\":\"run_8f3c2a\"} Cost: free -- no credits debited, and no anonymous daily run spent. Anonymous callers may use it at any volume.",
"inputSchema": {
"description": "Arguments for ``get_results`` (neumann#281).",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Your API key from POST /api/v1/accounts (optional). Results are readable only by the caller who created the run, so pass the same api_key (or Bearer) used for the original run_simulation / oat_sensitivity / scenario_analysis call -- otherwise this is treated as an anonymous read.",
"title": "Api Key"
},
"run_id": {
"description": "A run id returned by run_simulation.",
"title": "Run Id",
"type": "string"
}
},
"required": [
"run_id"
],
"title": "GetResultsInput",
"type": "object"
},
"name": "get_results"
},
{
"description": "Runs a one-at-a-time tornado sensitivity analysis: sweeps each root node over a set of quantiles (others held at baseline) and measures how the target node responds, ranked by impact. Use this when you need to know which uncertain input most drives an outcome, so you know what to de-risk or estimate more carefully first. Example: {\"graph\":{\"root_nodes\":[{\"id\":\"root\",\"distribution_type\":\"normal\",\"distribution_params\":{\"mean\":100,\"std\":15}}],\"calc_nodes\":[{\"id\":\"out\",\"formula\":\"{e1}\"}],\"edges\":[{\"id\":\"e1\",\"source\":\"root\",\"target\":\"out\"}],\"run_params\":{\"trials\":1000,\"time_periods\":12}}} Cost: an anonymous call spends 1 of 3 free runs per UTC calendar day and must fit the anonymous caps (1,000 trials, 20 nodes); an authenticated account is charged credits instead. Every result's billing block reports which, and what is left.",
"inputSchema": {
"$defs": {
"AggregationRequest": {
"additionalProperties": false,
"description": "A post-simulation, series-aware metric over one node's full series.\n\nNPV/IRR/payback/CAGR/cumsum are NOT per-period node values: they consume a\ntarget node's complete ``(time_periods x trials)`` matrix AFTER the run and\nreturn one value per trial, summarised into a distribution.\n\nDiscount convention (0-based series index): period ``t=0`` is the present\n(undiscounted) cash flow; period ``t`` is discounted by ``(1+rate)**t``. The\nfirst period is undiscounted.\n\nWarning — two discount conventions coexist; do not mix them. These\naggregations use the **0-based** series index above (first period\nundiscounted). The per-period formula functions ``DISCOUNT(rate,\n{time_period})`` and ``PV(rate, value, {time_period})`` use the **1-based**\n``{time_period}``, so they discount the first period by ``(1+rate)**1``.\n\n\"Investment at period 0\" pattern: model an up-front outlay as a negative\nperiod-0 cash flow in the target node's series; NPV's t=0-undiscounted\nconvention then treats it as the present-value outlay. Do not additionally\ndiscount that first period with ``PV(...,{time_period})`` inside the target\nnode's formula when also requesting an aggregation ``npv`` — combining the\n1-based per-period discount with the 0-based ``npv`` double-shifts the first\nperiod.\n\nPer-period node vs aggregate metric (``prob``): pointing ``prob`` at a\nmulti-period cash-flow NODE via ``target_node_id`` thresholds only that node's\nFINAL-period per-trial value — i.e. ``P(per-period value > x)``, NOT\n``P(NPV > x)``. To get a true ``P(NPV > 0)``, define an ``npv`` aggregation\nfirst, then add a ``prob`` aggregation whose ``target_aggregation_id`` points\nat that ``npv`` id; ``prob`` then thresholds the NPV per-trial vector directly.\nA ``prob`` request targets EITHER a node (``target_node_id``) OR an earlier\naggregation (``target_aggregation_id``) — exactly one, never both.",
"properties": {
"function": {
"description": "One of: npv, irr, payback, discounted_payback, cagr, cumsum, prob, terminal_value, mirr. discounted_payback requires params.rate; npv requires params.rate OR a per-period params.rates curve; prob requires params.op (one of >, >=, <, <=, ==) and params.value; terminal_value requires params.g and params.rate; mirr requires params.finance_rate and params.reinvest_rate.",
"title": "Function",
"type": "string"
},
"id": {
"description": "Result key for this metric (unique within the request).",
"title": "Id",
"type": "string"
},
"params": {
"additionalProperties": true,
"description": "Function params, e.g. {'rate': 0.1} for npv/discounted_payback, {'op': '>', 'value': 0} for prob, {'g': 0.02, 'rate': 0.1} for terminal_value, {'finance_rate': 0.1, 'reinvest_rate': 0.08} for mirr.",
"title": "Params",
"type": "object"
},
"target_aggregation_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "For a ``prob`` request only: the id of an aggregation defined EARLIER in this output_request whose per-trial vector (e.g. an ``npv``) is thresholded. Lets ``P(NPV > 0)`` be expressed directly instead of the per-period ``P(value > x)`` you get by targeting a multi-period node. The referenced aggregation must produce a per-trial vector (npv/irr/payback/discounted_payback/cagr/cumsum/terminal_value/mirr).",
"title": "Target Aggregation Id"
},
"target_node_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The node whose full per-period series the metric consumes. Required for every metric except a ``prob`` that targets a prior aggregation via ``target_aggregation_id``. Exactly one of ``target_node_id`` / ``target_aggregation_id`` may be set on a ``prob`` request.",
"title": "Target Node Id"
}
},
"required": [
"id",
"function"
],
"title": "AggregationRequest",
"type": "object"
},
"CalcNode": {
"additionalProperties": false,
"description": "A computed node. ``formula`` is OPTIONAL.\n\nA null/empty/whitespace formula is allowed: the node is treated as a\nconstant ``0`` every period/trial (incoming edges are ignored — there is no\nimplicit \"sum of incoming edges\"). ``validate_graph`` surfaces this as a\nWARNING, not an error. To sum incoming edges, write the sum explicitly,\ne.g. ``{e1}+{e2}``; for pass-through use ``{e1}``.",
"properties": {
"formula": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional expression over incoming edge ids, e.g. '{e1} * 0.5 + {e2}'. To sum incoming edges write '{e1}+{e2}'; for pass-through use '{e1}'. If omitted/empty the node is treated as a constant 0 (sum-of-incoming is not implied); validate_graph reports this as a warning.",
"title": "Formula"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
}
},
"required": [
"id"
],
"title": "CalcNode",
"type": "object"
},
"Edge": {
"additionalProperties": false,
"description": "A directed connection carrying a value from source to target.",
"properties": {
"delay": {
"default": 0,
"description": "Periods the value is delayed in transit.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"id": {
"description": "Unique edge id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional label.",
"title": "Name"
},
"source": {
"description": "id of the source node.",
"title": "Source",
"type": "string"
},
"target": {
"description": "id of the target node.",
"title": "Target",
"type": "string"
}
},
"required": [
"id",
"source",
"target"
],
"title": "Edge",
"type": "object"
},
"OutputRequest": {
"additionalProperties": false,
"description": "Which nodes/edges/periods to include in the result.\n\nEmpty lists mean 'all': all nodes, all edges, all time periods.\n``aggregations`` requests post-simulation series metrics (NPV/IRR/...).",
"properties": {
"aggregations": {
"items": {
"$ref": "#/$defs/AggregationRequest"
},
"title": "Aggregations",
"type": "array"
},
"edges": {
"items": {
"type": "string"
},
"title": "Edges",
"type": "array"
},
"nodes": {
"items": {
"type": "string"
},
"title": "Nodes",
"type": "array"
},
"time_periods": {
"items": {
"type": "integer"
},
"title": "Time Periods",
"type": "array"
}
},
"title": "OutputRequest",
"type": "object"
},
"PublicGraph": {
"additionalProperties": false,
"description": "A complete, validated simulation request — the agent-facing input.\n\nThis is the canonical public shape. Reference integrity (edges point at real\nnodes, output_request references real ids) is validated here so malformed\ngraphs are rejected before they ever reach the engine.",
"properties": {
"calc_nodes": {
"items": {
"$ref": "#/$defs/CalcNode"
},
"title": "Calc Nodes",
"type": "array"
},
"contract_version": {
"const": "1.0",
"default": "1.0",
"description": "Schema version this graph targets.",
"title": "Contract Version",
"type": "string"
},
"edges": {
"items": {
"$ref": "#/$defs/Edge"
},
"title": "Edges",
"type": "array"
},
"root_nodes": {
"items": {
"$ref": "#/$defs/RootNode"
},
"title": "Root Nodes",
"type": "array"
},
"run_params": {
"$ref": "#/$defs/RunParams"
}
},
"required": [
"run_params"
],
"title": "PublicGraph",
"type": "object"
},
"RootNode": {
"additionalProperties": false,
"description": "A source node that samples from a probability distribution each period.\n\n``json_schema_extra`` (neumann#288) attaches a ``oneOf`` discriminated on\n``distribution_type``, so the published schema states each type's own\nrequired ``distribution_params`` keys instead of advertising an opaque\nobject. The RUNTIME annotation stays ``dict[str, object]`` — see\n``contracts.catalog.add_distribution_variants`` for why a real pydantic\ndiscriminated union is not used here.",
"oneOf": [
{
"description": "A constant value that never changes",
"properties": {
"distribution_params": {
"properties": {
"value": {
"description": "The constant value to return",
"type": "number"
}
},
"required": [
"value"
],
"type": "object"
},
"distribution_type": {
"const": "constant"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant"
},
{
"description": "Normal (Gaussian) distribution",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "normal"
},
{
"description": "Uniform distribution between low and high values",
"properties": {
"distribution_params": {
"properties": {
"high": {
"description": "Upper bound of the distribution",
"type": "number"
},
"low": {
"description": "Lower bound of the distribution",
"type": "number"
}
},
"required": [
"low",
"high"
],
"type": "object"
},
"distribution_type": {
"const": "uniform"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "uniform"
},
{
"description": "Beta distribution for modeling probabilities and proportions",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "The alpha shape parameter (α) (positive)",
"type": "number"
},
"beta": {
"description": "The beta shape parameter (β) (positive)",
"type": "number"
}
},
"required": [
"alpha",
"beta"
],
"type": "object"
},
"distribution_type": {
"const": "beta"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "beta"
},
{
"description": "Gamma distribution for modeling waiting times",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "gamma"
},
{
"description": "Exponential distribution with scale parameter",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "Scale parameter (mean) of the distribution (positive)",
"type": "number"
}
},
"required": [
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "exponential"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "exponential"
},
{
"description": "Poisson distribution for modeling count data",
"properties": {
"distribution_params": {
"properties": {
"lambda_val": {
"description": "The rate parameter (λ) (positive)",
"type": "number"
}
},
"required": [
"lambda_val"
],
"type": "object"
},
"distribution_type": {
"const": "poisson"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "poisson"
},
{
"description": "Bernoulli distribution for binary outcomes",
"properties": {
"distribution_params": {
"properties": {
"p": {
"description": "The probability of success (between 0 and 1)",
"type": "number"
}
},
"required": [
"p"
],
"type": "object"
},
"distribution_type": {
"const": "bernoulli"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "bernoulli"
},
{
"description": "Triangle distribution with minimum, maximum, and mode parameters",
"properties": {
"distribution_params": {
"properties": {
"max_val": {
"description": "The maximum value of the distribution",
"type": "number"
},
"min_val": {
"description": "The minimum value of the distribution",
"type": "number"
},
"mode_val": {
"description": "The mode (peak) of the distribution",
"type": "number"
}
},
"required": [
"min_val",
"max_val",
"mode_val"
],
"type": "object"
},
"distribution_type": {
"const": "triangle"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "triangle"
},
{
"description": "Log-normal distribution for modeling skewed, positive-valued data",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "log_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "log_normal"
},
{
"description": "Discrete log-normal: sample log-normal then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_lognormal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_lognormal"
},
{
"description": "Categorical distribution for discrete outcomes with custom probabilities",
"properties": {
"distribution_params": {
"properties": {
"probabilities": {
"description": "List of probabilities for each value (must sum to 1) (sum to 1)",
"items": {
"type": "number"
},
"type": "array"
},
"values": {
"description": "List of possible values to sample from",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values",
"probabilities"
],
"type": "object"
},
"distribution_type": {
"const": "categorical"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "categorical"
},
{
"description": "Discrete gamma: sample gamma then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_gamma"
},
{
"description": "Binomial distribution for modeling the number of successes in n independent trials",
"properties": {
"distribution_params": {
"properties": {
"n": {
"description": "Number of trials (positive integer)",
"type": "integer"
},
"p": {
"description": "Probability of success in each trial (between 0 and 1)",
"type": "number"
}
},
"required": [
"n",
"p"
],
"type": "object"
},
"distribution_type": {
"const": "binomial"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "binomial"
},
{
"description": "Dirichlet distribution for modeling correlated probabilities that sum to 1",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "Concentration parameters for each category (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"alpha"
],
"type": "object"
},
"distribution_type": {
"const": "dirichlet"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "dirichlet"
},
{
"description": "Constant array distribution for deterministic array values (used internally for scenarios)",
"properties": {
"distribution_params": {
"properties": {
"values": {
"description": "Array of constant values to return",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values"
],
"type": "object"
},
"distribution_type": {
"const": "constant_array"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant_array"
},
{
"description": "Discrete normal distribution for integer-valued data with normal characteristics",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_normal"
},
{
"description": "Multivariate normal (correlated inputs): draws a vector of correlated values per trial from a mean vector + correlation matrix + per-component standard deviations. Array-valued — feed multiple downstream calc nodes by INDEXing component k (1-based): INDEX({edge}, k).",
"properties": {
"distribution_params": {
"properties": {
"correlation": {
"description": "Square correlation matrix (NxN for N components); diagonal 1.0, symmetric, entries in [-1, 1]",
"items": {
"items": {
"type": "number"
},
"type": "array"
},
"type": "array"
},
"mean": {
"description": "Mean vector (one entry per correlated component)",
"items": {
"type": "number"
},
"type": "array"
},
"stds": {
"description": "Per-component standard deviations (same length as mean) (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"mean",
"stds",
"correlation"
],
"type": "object"
},
"distribution_type": {
"const": "multivariate_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "multivariate_normal"
}
],
"properties": {
"delay": {
"default": 0,
"description": "Periods to wait before the first sample.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"distribution_params": {
"additionalProperties": true,
"description": "Params for the chosen distribution. Which keys are required depends on distribution_type -- see this schema's oneOf, or GET /api/v1/contract. Common types: normal{mean,std} log_normal{mu,sigma} uniform{low,high} triangle{min_val,max_val,mode_val} beta{alpha,beta} poisson{lambda_val} bernoulli{p}.",
"title": "Distribution Params",
"type": "object"
},
"distribution_type": {
"description": "One of the catalog distributions (GET /api/v1/contract).",
"title": "Distribution Type",
"type": "string"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"interval": {
"default": 1,
"description": "Sample every N periods (1 = every period).",
"minimum": 0,
"title": "Interval",
"type": "integer"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
},
"sampling_frequency": {
"default": "per_period",
"description": "'once' draws a single value reused across periods.",
"enum": [
"per_period",
"once"
],
"title": "Sampling Frequency",
"type": "string"
}
},
"required": [
"id",
"distribution_type",
"distribution_params"
],
"title": "RootNode",
"type": "object"
},
"RunParams": {
"additionalProperties": false,
"description": "Top-level run configuration.",
"properties": {
"output_request": {
"$ref": "#/$defs/OutputRequest"
},
"time_periods": {
"description": "Number of time periods to simulate.",
"exclusiveMinimum": 0,
"title": "Time Periods",
"type": "integer"
},
"trials": {
"description": "Number of Monte Carlo trials.",
"exclusiveMinimum": 0,
"title": "Trials",
"type": "integer"
}
},
"required": [
"trials",
"time_periods"
],
"title": "RunParams",
"type": "object"
}
},
"description": "Arguments for ``oat_sensitivity`` (one-at-a-time tornado analysis).",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Your API key from POST /api/v1/accounts. Debits credits per analysis. Omit to run anonymously (free).",
"title": "Api Key"
},
"graph": {
"$ref": "#/$defs/PublicGraph",
"description": "The full simulation graph to analyse (same shape as run_simulation)."
},
"num_quantiles": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Even count (2-10) of symmetrical quantiles around the 0.5 baseline. Mutually exclusive with quantiles.",
"title": "Num Quantiles"
},
"quantiles": {
"anyOf": [
{
"items": {
"type": "number"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "Explicit quantiles to sweep each input over (0..1). Mutually exclusive with num_quantiles. Default: [0.05, 0.5, 0.95] (tornado).",
"title": "Quantiles"
},
"seed": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional RNG seed for reproducible perturbed runs.",
"title": "Seed"
},
"target_node_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The output node to measure. Defaults to the graph's last calc node (the usual goal node).",
"title": "Target Node Id"
},
"time_period": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "0-based time period to analyse. Defaults to the last period (time_periods - 1).",
"title": "Time Period"
}
},
"required": [
"graph"
],
"title": "OatSensitivityInput",
"type": "object"
},
"name": "oat_sensitivity"
},
{
"description": "Runs a Monte Carlo simulation over a graph of probabilistic root and calculated nodes, returning the full output distribution instead of one guessed number. Use this when you need the range and likelihood of outcomes for a plan driven by uncertain inputs, not just its average case. Both tiers run to completion and return the full result in this same call, never a run_id to poll. Distribution params by type: normal{mean,std} log_normal{mu,sigma} uniform{low,high} triangle{min_val,max_val,mode_val} beta{alpha,beta} poisson{lambda_val} bernoulli{p}. Example: {\"graph\":{\"root_nodes\":[{\"id\":\"root\",\"distribution_type\":\"normal\",\"distribution_params\":{\"mean\":100,\"std\":15}}],\"calc_nodes\":[{\"id\":\"out\",\"formula\":\"{e1}\"}],\"edges\":[{\"id\":\"e1\",\"source\":\"root\",\"target\":\"out\"}],\"run_params\":{\"trials\":1000,\"time_periods\":12}}} Cost: an anonymous call spends 1 of 3 free runs per UTC calendar day and must fit the anonymous caps (1,000 trials, 20 nodes); an authenticated account is charged credits instead. Every result's billing block reports which, and what is left.",
"inputSchema": {
"$defs": {
"AggregationRequest": {
"additionalProperties": false,
"description": "A post-simulation, series-aware metric over one node's full series.\n\nNPV/IRR/payback/CAGR/cumsum are NOT per-period node values: they consume a\ntarget node's complete ``(time_periods x trials)`` matrix AFTER the run and\nreturn one value per trial, summarised into a distribution.\n\nDiscount convention (0-based series index): period ``t=0`` is the present\n(undiscounted) cash flow; period ``t`` is discounted by ``(1+rate)**t``. The\nfirst period is undiscounted.\n\nWarning — two discount conventions coexist; do not mix them. These\naggregations use the **0-based** series index above (first period\nundiscounted). The per-period formula functions ``DISCOUNT(rate,\n{time_period})`` and ``PV(rate, value, {time_period})`` use the **1-based**\n``{time_period}``, so they discount the first period by ``(1+rate)**1``.\n\n\"Investment at period 0\" pattern: model an up-front outlay as a negative\nperiod-0 cash flow in the target node's series; NPV's t=0-undiscounted\nconvention then treats it as the present-value outlay. Do not additionally\ndiscount that first period with ``PV(...,{time_period})`` inside the target\nnode's formula when also requesting an aggregation ``npv`` — combining the\n1-based per-period discount with the 0-based ``npv`` double-shifts the first\nperiod.\n\nPer-period node vs aggregate metric (``prob``): pointing ``prob`` at a\nmulti-period cash-flow NODE via ``target_node_id`` thresholds only that node's\nFINAL-period per-trial value — i.e. ``P(per-period value > x)``, NOT\n``P(NPV > x)``. To get a true ``P(NPV > 0)``, define an ``npv`` aggregation\nfirst, then add a ``prob`` aggregation whose ``target_aggregation_id`` points\nat that ``npv`` id; ``prob`` then thresholds the NPV per-trial vector directly.\nA ``prob`` request targets EITHER a node (``target_node_id``) OR an earlier\naggregation (``target_aggregation_id``) — exactly one, never both.",
"properties": {
"function": {
"description": "One of: npv, irr, payback, discounted_payback, cagr, cumsum, prob, terminal_value, mirr. discounted_payback requires params.rate; npv requires params.rate OR a per-period params.rates curve; prob requires params.op (one of >, >=, <, <=, ==) and params.value; terminal_value requires params.g and params.rate; mirr requires params.finance_rate and params.reinvest_rate.",
"title": "Function",
"type": "string"
},
"id": {
"description": "Result key for this metric (unique within the request).",
"title": "Id",
"type": "string"
},
"params": {
"additionalProperties": true,
"description": "Function params, e.g. {'rate': 0.1} for npv/discounted_payback, {'op': '>', 'value': 0} for prob, {'g': 0.02, 'rate': 0.1} for terminal_value, {'finance_rate': 0.1, 'reinvest_rate': 0.08} for mirr.",
"title": "Params",
"type": "object"
},
"target_aggregation_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "For a ``prob`` request only: the id of an aggregation defined EARLIER in this output_request whose per-trial vector (e.g. an ``npv``) is thresholded. Lets ``P(NPV > 0)`` be expressed directly instead of the per-period ``P(value > x)`` you get by targeting a multi-period node. The referenced aggregation must produce a per-trial vector (npv/irr/payback/discounted_payback/cagr/cumsum/terminal_value/mirr).",
"title": "Target Aggregation Id"
},
"target_node_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The node whose full per-period series the metric consumes. Required for every metric except a ``prob`` that targets a prior aggregation via ``target_aggregation_id``. Exactly one of ``target_node_id`` / ``target_aggregation_id`` may be set on a ``prob`` request.",
"title": "Target Node Id"
}
},
"required": [
"id",
"function"
],
"title": "AggregationRequest",
"type": "object"
},
"CalcNode": {
"additionalProperties": false,
"description": "A computed node. ``formula`` is OPTIONAL.\n\nA null/empty/whitespace formula is allowed: the node is treated as a\nconstant ``0`` every period/trial (incoming edges are ignored — there is no\nimplicit \"sum of incoming edges\"). ``validate_graph`` surfaces this as a\nWARNING, not an error. To sum incoming edges, write the sum explicitly,\ne.g. ``{e1}+{e2}``; for pass-through use ``{e1}``.",
"properties": {
"formula": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional expression over incoming edge ids, e.g. '{e1} * 0.5 + {e2}'. To sum incoming edges write '{e1}+{e2}'; for pass-through use '{e1}'. If omitted/empty the node is treated as a constant 0 (sum-of-incoming is not implied); validate_graph reports this as a warning.",
"title": "Formula"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
}
},
"required": [
"id"
],
"title": "CalcNode",
"type": "object"
},
"Edge": {
"additionalProperties": false,
"description": "A directed connection carrying a value from source to target.",
"properties": {
"delay": {
"default": 0,
"description": "Periods the value is delayed in transit.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"id": {
"description": "Unique edge id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional label.",
"title": "Name"
},
"source": {
"description": "id of the source node.",
"title": "Source",
"type": "string"
},
"target": {
"description": "id of the target node.",
"title": "Target",
"type": "string"
}
},
"required": [
"id",
"source",
"target"
],
"title": "Edge",
"type": "object"
},
"OutputRequest": {
"additionalProperties": false,
"description": "Which nodes/edges/periods to include in the result.\n\nEmpty lists mean 'all': all nodes, all edges, all time periods.\n``aggregations`` requests post-simulation series metrics (NPV/IRR/...).",
"properties": {
"aggregations": {
"items": {
"$ref": "#/$defs/AggregationRequest"
},
"title": "Aggregations",
"type": "array"
},
"edges": {
"items": {
"type": "string"
},
"title": "Edges",
"type": "array"
},
"nodes": {
"items": {
"type": "string"
},
"title": "Nodes",
"type": "array"
},
"time_periods": {
"items": {
"type": "integer"
},
"title": "Time Periods",
"type": "array"
}
},
"title": "OutputRequest",
"type": "object"
},
"PublicGraph": {
"additionalProperties": false,
"description": "A complete, validated simulation request — the agent-facing input.\n\nThis is the canonical public shape. Reference integrity (edges point at real\nnodes, output_request references real ids) is validated here so malformed\ngraphs are rejected before they ever reach the engine.",
"properties": {
"calc_nodes": {
"items": {
"$ref": "#/$defs/CalcNode"
},
"title": "Calc Nodes",
"type": "array"
},
"contract_version": {
"const": "1.0",
"default": "1.0",
"description": "Schema version this graph targets.",
"title": "Contract Version",
"type": "string"
},
"edges": {
"items": {
"$ref": "#/$defs/Edge"
},
"title": "Edges",
"type": "array"
},
"root_nodes": {
"items": {
"$ref": "#/$defs/RootNode"
},
"title": "Root Nodes",
"type": "array"
},
"run_params": {
"$ref": "#/$defs/RunParams"
}
},
"required": [
"run_params"
],
"title": "PublicGraph",
"type": "object"
},
"RootNode": {
"additionalProperties": false,
"description": "A source node that samples from a probability distribution each period.\n\n``json_schema_extra`` (neumann#288) attaches a ``oneOf`` discriminated on\n``distribution_type``, so the published schema states each type's own\nrequired ``distribution_params`` keys instead of advertising an opaque\nobject. The RUNTIME annotation stays ``dict[str, object]`` — see\n``contracts.catalog.add_distribution_variants`` for why a real pydantic\ndiscriminated union is not used here.",
"oneOf": [
{
"description": "A constant value that never changes",
"properties": {
"distribution_params": {
"properties": {
"value": {
"description": "The constant value to return",
"type": "number"
}
},
"required": [
"value"
],
"type": "object"
},
"distribution_type": {
"const": "constant"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant"
},
{
"description": "Normal (Gaussian) distribution",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "normal"
},
{
"description": "Uniform distribution between low and high values",
"properties": {
"distribution_params": {
"properties": {
"high": {
"description": "Upper bound of the distribution",
"type": "number"
},
"low": {
"description": "Lower bound of the distribution",
"type": "number"
}
},
"required": [
"low",
"high"
],
"type": "object"
},
"distribution_type": {
"const": "uniform"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "uniform"
},
{
"description": "Beta distribution for modeling probabilities and proportions",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "The alpha shape parameter (α) (positive)",
"type": "number"
},
"beta": {
"description": "The beta shape parameter (β) (positive)",
"type": "number"
}
},
"required": [
"alpha",
"beta"
],
"type": "object"
},
"distribution_type": {
"const": "beta"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "beta"
},
{
"description": "Gamma distribution for modeling waiting times",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "gamma"
},
{
"description": "Exponential distribution with scale parameter",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "Scale parameter (mean) of the distribution (positive)",
"type": "number"
}
},
"required": [
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "exponential"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "exponential"
},
{
"description": "Poisson distribution for modeling count data",
"properties": {
"distribution_params": {
"properties": {
"lambda_val": {
"description": "The rate parameter (λ) (positive)",
"type": "number"
}
},
"required": [
"lambda_val"
],
"type": "object"
},
"distribution_type": {
"const": "poisson"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "poisson"
},
{
"description": "Bernoulli distribution for binary outcomes",
"properties": {
"distribution_params": {
"properties": {
"p": {
"description": "The probability of success (between 0 and 1)",
"type": "number"
}
},
"required": [
"p"
],
"type": "object"
},
"distribution_type": {
"const": "bernoulli"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "bernoulli"
},
{
"description": "Triangle distribution with minimum, maximum, and mode parameters",
"properties": {
"distribution_params": {
"properties": {
"max_val": {
"description": "The maximum value of the distribution",
"type": "number"
},
"min_val": {
"description": "The minimum value of the distribution",
"type": "number"
},
"mode_val": {
"description": "The mode (peak) of the distribution",
"type": "number"
}
},
"required": [
"min_val",
"max_val",
"mode_val"
],
"type": "object"
},
"distribution_type": {
"const": "triangle"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "triangle"
},
{
"description": "Log-normal distribution for modeling skewed, positive-valued data",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "log_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "log_normal"
},
{
"description": "Discrete log-normal: sample log-normal then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_lognormal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_lognormal"
},
{
"description": "Categorical distribution for discrete outcomes with custom probabilities",
"properties": {
"distribution_params": {
"properties": {
"probabilities": {
"description": "List of probabilities for each value (must sum to 1) (sum to 1)",
"items": {
"type": "number"
},
"type": "array"
},
"values": {
"description": "List of possible values to sample from",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values",
"probabilities"
],
"type": "object"
},
"distribution_type": {
"const": "categorical"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "categorical"
},
{
"description": "Discrete gamma: sample gamma then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_gamma"
},
{
"description": "Binomial distribution for modeling the number of successes in n independent trials",
"properties": {
"distribution_params": {
"properties": {
"n": {
"description": "Number of trials (positive integer)",
"type": "integer"
},
"p": {
"description": "Probability of success in each trial (between 0 and 1)",
"type": "number"
}
},
"required": [
"n",
"p"
],
"type": "object"
},
"distribution_type": {
"const": "binomial"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "binomial"
},
{
"description": "Dirichlet distribution for modeling correlated probabilities that sum to 1",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "Concentration parameters for each category (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"alpha"
],
"type": "object"
},
"distribution_type": {
"const": "dirichlet"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "dirichlet"
},
{
"description": "Constant array distribution for deterministic array values (used internally for scenarios)",
"properties": {
"distribution_params": {
"properties": {
"values": {
"description": "Array of constant values to return",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values"
],
"type": "object"
},
"distribution_type": {
"const": "constant_array"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant_array"
},
{
"description": "Discrete normal distribution for integer-valued data with normal characteristics",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_normal"
},
{
"description": "Multivariate normal (correlated inputs): draws a vector of correlated values per trial from a mean vector + correlation matrix + per-component standard deviations. Array-valued — feed multiple downstream calc nodes by INDEXing component k (1-based): INDEX({edge}, k).",
"properties": {
"distribution_params": {
"properties": {
"correlation": {
"description": "Square correlation matrix (NxN for N components); diagonal 1.0, symmetric, entries in [-1, 1]",
"items": {
"items": {
"type": "number"
},
"type": "array"
},
"type": "array"
},
"mean": {
"description": "Mean vector (one entry per correlated component)",
"items": {
"type": "number"
},
"type": "array"
},
"stds": {
"description": "Per-component standard deviations (same length as mean) (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"mean",
"stds",
"correlation"
],
"type": "object"
},
"distribution_type": {
"const": "multivariate_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "multivariate_normal"
}
],
"properties": {
"delay": {
"default": 0,
"description": "Periods to wait before the first sample.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"distribution_params": {
"additionalProperties": true,
"description": "Params for the chosen distribution. Which keys are required depends on distribution_type -- see this schema's oneOf, or GET /api/v1/contract. Common types: normal{mean,std} log_normal{mu,sigma} uniform{low,high} triangle{min_val,max_val,mode_val} beta{alpha,beta} poisson{lambda_val} bernoulli{p}.",
"title": "Distribution Params",
"type": "object"
},
"distribution_type": {
"description": "One of the catalog distributions (GET /api/v1/contract).",
"title": "Distribution Type",
"type": "string"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"interval": {
"default": 1,
"description": "Sample every N periods (1 = every period).",
"minimum": 0,
"title": "Interval",
"type": "integer"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
},
"sampling_frequency": {
"default": "per_period",
"description": "'once' draws a single value reused across periods.",
"enum": [
"per_period",
"once"
],
"title": "Sampling Frequency",
"type": "string"
}
},
"required": [
"id",
"distribution_type",
"distribution_params"
],
"title": "RootNode",
"type": "object"
},
"RunParams": {
"additionalProperties": false,
"description": "Top-level run configuration.",
"properties": {
"output_request": {
"$ref": "#/$defs/OutputRequest"
},
"time_periods": {
"description": "Number of time periods to simulate.",
"exclusiveMinimum": 0,
"title": "Time Periods",
"type": "integer"
},
"trials": {
"description": "Number of Monte Carlo trials.",
"exclusiveMinimum": 0,
"title": "Trials",
"type": "integer"
}
},
"required": [
"trials",
"time_periods"
],
"title": "RunParams",
"type": "object"
}
},
"description": "Arguments for ``run_simulation``.",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Your API key from POST /api/v1/accounts. Debits credits per run. Omit to use the free anonymous allowance, which IS accounted: a bounded number of runs per UTC calendar day within the anonymous size caps. Every result's billing block reports what the call was charged to and what is left; call whoami for the exact numbers.",
"title": "Api Key"
},
"graph": {
"$ref": "#/$defs/PublicGraph",
"description": "The full simulation graph (root_nodes, calc_nodes, edges, run_params). See GET /api/v1/contract for valid distribution types."
},
"include_histogram": {
"default": false,
"description": "Include a per-element histogram in each summary element.",
"title": "Include Histogram",
"type": "boolean"
},
"seed": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional RNG seed; reproducible only on the small/inline path.",
"title": "Seed"
}
},
"required": [
"graph"
],
"title": "RunSimulationInput",
"type": "object"
},
"name": "run_simulation"
},
{
"description": "Runs a simulation once and summarises a target node's worst/median/best outcomes (any percentiles), each paired with a best-effort driving input per root node. Use this when you need a quick worst-case/median/best-case narrative for a plan rather than the full distribution. Example: {\"graph\":{\"root_nodes\":[{\"id\":\"root\",\"distribution_type\":\"normal\",\"distribution_params\":{\"mean\":100,\"std\":15}}],\"calc_nodes\":[{\"id\":\"out\",\"formula\":\"{e1}\"}],\"edges\":[{\"id\":\"e1\",\"source\":\"root\",\"target\":\"out\"}],\"run_params\":{\"trials\":1000,\"time_periods\":12}}} Cost: an anonymous call spends 1 of 3 free runs per UTC calendar day and must fit the anonymous caps (1,000 trials, 20 nodes); an authenticated account is charged credits instead. Every result's billing block reports which, and what is left.",
"inputSchema": {
"$defs": {
"AggregationRequest": {
"additionalProperties": false,
"description": "A post-simulation, series-aware metric over one node's full series.\n\nNPV/IRR/payback/CAGR/cumsum are NOT per-period node values: they consume a\ntarget node's complete ``(time_periods x trials)`` matrix AFTER the run and\nreturn one value per trial, summarised into a distribution.\n\nDiscount convention (0-based series index): period ``t=0`` is the present\n(undiscounted) cash flow; period ``t`` is discounted by ``(1+rate)**t``. The\nfirst period is undiscounted.\n\nWarning — two discount conventions coexist; do not mix them. These\naggregations use the **0-based** series index above (first period\nundiscounted). The per-period formula functions ``DISCOUNT(rate,\n{time_period})`` and ``PV(rate, value, {time_period})`` use the **1-based**\n``{time_period}``, so they discount the first period by ``(1+rate)**1``.\n\n\"Investment at period 0\" pattern: model an up-front outlay as a negative\nperiod-0 cash flow in the target node's series; NPV's t=0-undiscounted\nconvention then treats it as the present-value outlay. Do not additionally\ndiscount that first period with ``PV(...,{time_period})`` inside the target\nnode's formula when also requesting an aggregation ``npv`` — combining the\n1-based per-period discount with the 0-based ``npv`` double-shifts the first\nperiod.\n\nPer-period node vs aggregate metric (``prob``): pointing ``prob`` at a\nmulti-period cash-flow NODE via ``target_node_id`` thresholds only that node's\nFINAL-period per-trial value — i.e. ``P(per-period value > x)``, NOT\n``P(NPV > x)``. To get a true ``P(NPV > 0)``, define an ``npv`` aggregation\nfirst, then add a ``prob`` aggregation whose ``target_aggregation_id`` points\nat that ``npv`` id; ``prob`` then thresholds the NPV per-trial vector directly.\nA ``prob`` request targets EITHER a node (``target_node_id``) OR an earlier\naggregation (``target_aggregation_id``) — exactly one, never both.",
"properties": {
"function": {
"description": "One of: npv, irr, payback, discounted_payback, cagr, cumsum, prob, terminal_value, mirr. discounted_payback requires params.rate; npv requires params.rate OR a per-period params.rates curve; prob requires params.op (one of >, >=, <, <=, ==) and params.value; terminal_value requires params.g and params.rate; mirr requires params.finance_rate and params.reinvest_rate.",
"title": "Function",
"type": "string"
},
"id": {
"description": "Result key for this metric (unique within the request).",
"title": "Id",
"type": "string"
},
"params": {
"additionalProperties": true,
"description": "Function params, e.g. {'rate': 0.1} for npv/discounted_payback, {'op': '>', 'value': 0} for prob, {'g': 0.02, 'rate': 0.1} for terminal_value, {'finance_rate': 0.1, 'reinvest_rate': 0.08} for mirr.",
"title": "Params",
"type": "object"
},
"target_aggregation_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "For a ``prob`` request only: the id of an aggregation defined EARLIER in this output_request whose per-trial vector (e.g. an ``npv``) is thresholded. Lets ``P(NPV > 0)`` be expressed directly instead of the per-period ``P(value > x)`` you get by targeting a multi-period node. The referenced aggregation must produce a per-trial vector (npv/irr/payback/discounted_payback/cagr/cumsum/terminal_value/mirr).",
"title": "Target Aggregation Id"
},
"target_node_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The node whose full per-period series the metric consumes. Required for every metric except a ``prob`` that targets a prior aggregation via ``target_aggregation_id``. Exactly one of ``target_node_id`` / ``target_aggregation_id`` may be set on a ``prob`` request.",
"title": "Target Node Id"
}
},
"required": [
"id",
"function"
],
"title": "AggregationRequest",
"type": "object"
},
"CalcNode": {
"additionalProperties": false,
"description": "A computed node. ``formula`` is OPTIONAL.\n\nA null/empty/whitespace formula is allowed: the node is treated as a\nconstant ``0`` every period/trial (incoming edges are ignored — there is no\nimplicit \"sum of incoming edges\"). ``validate_graph`` surfaces this as a\nWARNING, not an error. To sum incoming edges, write the sum explicitly,\ne.g. ``{e1}+{e2}``; for pass-through use ``{e1}``.",
"properties": {
"formula": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional expression over incoming edge ids, e.g. '{e1} * 0.5 + {e2}'. To sum incoming edges write '{e1}+{e2}'; for pass-through use '{e1}'. If omitted/empty the node is treated as a constant 0 (sum-of-incoming is not implied); validate_graph reports this as a warning.",
"title": "Formula"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
}
},
"required": [
"id"
],
"title": "CalcNode",
"type": "object"
},
"Edge": {
"additionalProperties": false,
"description": "A directed connection carrying a value from source to target.",
"properties": {
"delay": {
"default": 0,
"description": "Periods the value is delayed in transit.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"id": {
"description": "Unique edge id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional label.",
"title": "Name"
},
"source": {
"description": "id of the source node.",
"title": "Source",
"type": "string"
},
"target": {
"description": "id of the target node.",
"title": "Target",
"type": "string"
}
},
"required": [
"id",
"source",
"target"
],
"title": "Edge",
"type": "object"
},
"OutputRequest": {
"additionalProperties": false,
"description": "Which nodes/edges/periods to include in the result.\n\nEmpty lists mean 'all': all nodes, all edges, all time periods.\n``aggregations`` requests post-simulation series metrics (NPV/IRR/...).",
"properties": {
"aggregations": {
"items": {
"$ref": "#/$defs/AggregationRequest"
},
"title": "Aggregations",
"type": "array"
},
"edges": {
"items": {
"type": "string"
},
"title": "Edges",
"type": "array"
},
"nodes": {
"items": {
"type": "string"
},
"title": "Nodes",
"type": "array"
},
"time_periods": {
"items": {
"type": "integer"
},
"title": "Time Periods",
"type": "array"
}
},
"title": "OutputRequest",
"type": "object"
},
"PublicGraph": {
"additionalProperties": false,
"description": "A complete, validated simulation request — the agent-facing input.\n\nThis is the canonical public shape. Reference integrity (edges point at real\nnodes, output_request references real ids) is validated here so malformed\ngraphs are rejected before they ever reach the engine.",
"properties": {
"calc_nodes": {
"items": {
"$ref": "#/$defs/CalcNode"
},
"title": "Calc Nodes",
"type": "array"
},
"contract_version": {
"const": "1.0",
"default": "1.0",
"description": "Schema version this graph targets.",
"title": "Contract Version",
"type": "string"
},
"edges": {
"items": {
"$ref": "#/$defs/Edge"
},
"title": "Edges",
"type": "array"
},
"root_nodes": {
"items": {
"$ref": "#/$defs/RootNode"
},
"title": "Root Nodes",
"type": "array"
},
"run_params": {
"$ref": "#/$defs/RunParams"
}
},
"required": [
"run_params"
],
"title": "PublicGraph",
"type": "object"
},
"RootNode": {
"additionalProperties": false,
"description": "A source node that samples from a probability distribution each period.\n\n``json_schema_extra`` (neumann#288) attaches a ``oneOf`` discriminated on\n``distribution_type``, so the published schema states each type's own\nrequired ``distribution_params`` keys instead of advertising an opaque\nobject. The RUNTIME annotation stays ``dict[str, object]`` — see\n``contracts.catalog.add_distribution_variants`` for why a real pydantic\ndiscriminated union is not used here.",
"oneOf": [
{
"description": "A constant value that never changes",
"properties": {
"distribution_params": {
"properties": {
"value": {
"description": "The constant value to return",
"type": "number"
}
},
"required": [
"value"
],
"type": "object"
},
"distribution_type": {
"const": "constant"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant"
},
{
"description": "Normal (Gaussian) distribution",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "normal"
},
{
"description": "Uniform distribution between low and high values",
"properties": {
"distribution_params": {
"properties": {
"high": {
"description": "Upper bound of the distribution",
"type": "number"
},
"low": {
"description": "Lower bound of the distribution",
"type": "number"
}
},
"required": [
"low",
"high"
],
"type": "object"
},
"distribution_type": {
"const": "uniform"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "uniform"
},
{
"description": "Beta distribution for modeling probabilities and proportions",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "The alpha shape parameter (α) (positive)",
"type": "number"
},
"beta": {
"description": "The beta shape parameter (β) (positive)",
"type": "number"
}
},
"required": [
"alpha",
"beta"
],
"type": "object"
},
"distribution_type": {
"const": "beta"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "beta"
},
{
"description": "Gamma distribution for modeling waiting times",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "gamma"
},
{
"description": "Exponential distribution with scale parameter",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "Scale parameter (mean) of the distribution (positive)",
"type": "number"
}
},
"required": [
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "exponential"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "exponential"
},
{
"description": "Poisson distribution for modeling count data",
"properties": {
"distribution_params": {
"properties": {
"lambda_val": {
"description": "The rate parameter (λ) (positive)",
"type": "number"
}
},
"required": [
"lambda_val"
],
"type": "object"
},
"distribution_type": {
"const": "poisson"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "poisson"
},
{
"description": "Bernoulli distribution for binary outcomes",
"properties": {
"distribution_params": {
"properties": {
"p": {
"description": "The probability of success (between 0 and 1)",
"type": "number"
}
},
"required": [
"p"
],
"type": "object"
},
"distribution_type": {
"const": "bernoulli"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "bernoulli"
},
{
"description": "Triangle distribution with minimum, maximum, and mode parameters",
"properties": {
"distribution_params": {
"properties": {
"max_val": {
"description": "The maximum value of the distribution",
"type": "number"
},
"min_val": {
"description": "The minimum value of the distribution",
"type": "number"
},
"mode_val": {
"description": "The mode (peak) of the distribution",
"type": "number"
}
},
"required": [
"min_val",
"max_val",
"mode_val"
],
"type": "object"
},
"distribution_type": {
"const": "triangle"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "triangle"
},
{
"description": "Log-normal distribution for modeling skewed, positive-valued data",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "log_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "log_normal"
},
{
"description": "Discrete log-normal: sample log-normal then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_lognormal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_lognormal"
},
{
"description": "Categorical distribution for discrete outcomes with custom probabilities",
"properties": {
"distribution_params": {
"properties": {
"probabilities": {
"description": "List of probabilities for each value (must sum to 1) (sum to 1)",
"items": {
"type": "number"
},
"type": "array"
},
"values": {
"description": "List of possible values to sample from",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values",
"probabilities"
],
"type": "object"
},
"distribution_type": {
"const": "categorical"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "categorical"
},
{
"description": "Discrete gamma: sample gamma then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_gamma"
},
{
"description": "Binomial distribution for modeling the number of successes in n independent trials",
"properties": {
"distribution_params": {
"properties": {
"n": {
"description": "Number of trials (positive integer)",
"type": "integer"
},
"p": {
"description": "Probability of success in each trial (between 0 and 1)",
"type": "number"
}
},
"required": [
"n",
"p"
],
"type": "object"
},
"distribution_type": {
"const": "binomial"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "binomial"
},
{
"description": "Dirichlet distribution for modeling correlated probabilities that sum to 1",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "Concentration parameters for each category (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"alpha"
],
"type": "object"
},
"distribution_type": {
"const": "dirichlet"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "dirichlet"
},
{
"description": "Constant array distribution for deterministic array values (used internally for scenarios)",
"properties": {
"distribution_params": {
"properties": {
"values": {
"description": "Array of constant values to return",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values"
],
"type": "object"
},
"distribution_type": {
"const": "constant_array"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant_array"
},
{
"description": "Discrete normal distribution for integer-valued data with normal characteristics",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_normal"
},
{
"description": "Multivariate normal (correlated inputs): draws a vector of correlated values per trial from a mean vector + correlation matrix + per-component standard deviations. Array-valued — feed multiple downstream calc nodes by INDEXing component k (1-based): INDEX({edge}, k).",
"properties": {
"distribution_params": {
"properties": {
"correlation": {
"description": "Square correlation matrix (NxN for N components); diagonal 1.0, symmetric, entries in [-1, 1]",
"items": {
"items": {
"type": "number"
},
"type": "array"
},
"type": "array"
},
"mean": {
"description": "Mean vector (one entry per correlated component)",
"items": {
"type": "number"
},
"type": "array"
},
"stds": {
"description": "Per-component standard deviations (same length as mean) (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"mean",
"stds",
"correlation"
],
"type": "object"
},
"distribution_type": {
"const": "multivariate_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "multivariate_normal"
}
],
"properties": {
"delay": {
"default": 0,
"description": "Periods to wait before the first sample.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"distribution_params": {
"additionalProperties": true,
"description": "Params for the chosen distribution. Which keys are required depends on distribution_type -- see this schema's oneOf, or GET /api/v1/contract. Common types: normal{mean,std} log_normal{mu,sigma} uniform{low,high} triangle{min_val,max_val,mode_val} beta{alpha,beta} poisson{lambda_val} bernoulli{p}.",
"title": "Distribution Params",
"type": "object"
},
"distribution_type": {
"description": "One of the catalog distributions (GET /api/v1/contract).",
"title": "Distribution Type",
"type": "string"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"interval": {
"default": 1,
"description": "Sample every N periods (1 = every period).",
"minimum": 0,
"title": "Interval",
"type": "integer"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
},
"sampling_frequency": {
"default": "per_period",
"description": "'once' draws a single value reused across periods.",
"enum": [
"per_period",
"once"
],
"title": "Sampling Frequency",
"type": "string"
}
},
"required": [
"id",
"distribution_type",
"distribution_params"
],
"title": "RootNode",
"type": "object"
},
"RunParams": {
"additionalProperties": false,
"description": "Top-level run configuration.",
"properties": {
"output_request": {
"$ref": "#/$defs/OutputRequest"
},
"time_periods": {
"description": "Number of time periods to simulate.",
"exclusiveMinimum": 0,
"title": "Time Periods",
"type": "integer"
},
"trials": {
"description": "Number of Monte Carlo trials.",
"exclusiveMinimum": 0,
"title": "Trials",
"type": "integer"
}
},
"required": [
"trials",
"time_periods"
],
"title": "RunParams",
"type": "object"
}
},
"description": "Arguments for ``scenario_analysis`` (best/median/worst across trials).",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Your API key from POST /api/v1/accounts. Debits credits per analysis (priced like one run). Omit to run anonymously (free).",
"title": "Api Key"
},
"graph": {
"$ref": "#/$defs/PublicGraph",
"description": "The full simulation graph (same shape as run_simulation)."
},
"percentiles": {
"anyOf": [
{
"items": {
"type": "number"
},
"type": "array"
},
{
"type": "null"
}
],
"default": null,
"description": "Scenario percentiles in [0,1]. Default [0.0, 0.5, 1.0] = worst / median / best.",
"title": "Percentiles"
},
"seed": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional RNG seed for a reproducible run.",
"title": "Seed"
},
"target_node_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The output node to summarise. Defaults to the graph's last calc node (the usual goal node).",
"title": "Target Node Id"
},
"time_period": {
"anyOf": [
{
"type": "integer"
},
{
"type": "null"
}
],
"default": null,
"description": "0-based time period to analyse. Defaults to the last period (time_periods - 1).",
"title": "Time Period"
}
},
"required": [
"graph"
],
"title": "ScenarioAnalysisInput",
"type": "object"
},
"name": "scenario_analysis"
},
{
"description": "Creates (or fetches the existing) public share link for a PERSISTED run from the stored-graph flow, renderable as HTML/JSON/SVG. Use this when you want to hand a result to someone without giving them API access -- only for a run saved via the stored-graph flow: a run_simulation result is ephemeral and has no usable run_id. Requires authentication (api_key argument or an Authorization: Bearer token) to CREATE the link; the resulting share_url itself needs no credential to view. Example: {\"run_id\":\"run_8f3c2a\"} Cost: free -- no credits debited and no anonymous daily run spent -- but it requires an account (anonymous callers get authentication_required).",
"inputSchema": {
"description": "Arguments for ``share_result`` (neumann#228).\n\n``run_id`` must be a PERSISTED run from the stored-graph flow (the one\n``POST /api/v1/graphs/{graph_id}/runs`` creates), not a ``run_simulation``\nresult — those are ephemeral and were never written to durable storage, so\nthere is nothing to share (see the tool description for why).",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Your API key from POST /api/v1/accounts. Required unless you are authenticated via an Authorization: Bearer token.",
"title": "Api Key"
},
"run_id": {
"description": "A persisted (stored-graph) run id.",
"title": "Run Id",
"type": "string"
}
},
"required": [
"run_id"
],
"title": "ShareResultInput",
"type": "object"
},
"name": "share_result"
},
{
"description": "Converts a human-style estimate (a min/max range at a stated confidence, or a most-likely value) into the distribution_params a root node needs. Use this when you have a rough verbal estimate like 'between 80 and 120, 90% confident' and need engine-ready parameters rather than guessing them yourself. Example: {\"distribution_type\":\"normal\",\"min_estimate\":80,\"max_estimate\":120,\"percentile_range\":0.9} Cost: free -- no credits debited, and no anonymous daily run spent. Anonymous callers may use it at any volume.",
"inputSchema": {
"description": "Arguments for ``solve_distribution_parameters``.\n\nFind distribution parameters that fit a min/max range at a given confidence,\nso an agent can turn a human-style 'between X and Y' estimate into engine-ready\n``distribution_params``.",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional API key (solving is free).",
"title": "Api Key"
},
"distribution_type": {
"description": "A catalog distribution, e.g. 'normal', 'triangle', 'beta'.",
"title": "Distribution Type",
"type": "string"
},
"max_estimate": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "High end of the range (required for most types).",
"title": "Max Estimate"
},
"min_estimate": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "Low end of the range (required for most types).",
"title": "Min Estimate"
},
"mode_estimate": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"default": null,
"description": "Most-likely value; required for constant/bernoulli/binomial.",
"title": "Mode Estimate"
},
"percentile_range": {
"default": 0.9,
"description": "Confidence the [min,max] interval covers, e.g. 0.9 for 90%.",
"exclusiveMaximum": 1,
"exclusiveMinimum": 0,
"title": "Percentile Range",
"type": "number"
}
},
"required": [
"distribution_type"
],
"title": "SolveDistributionInput",
"type": "object"
},
"name": "solve_distribution_parameters"
},
{
"description": "Checks a graph for structural problems (cycles, dangling edges, unknown distributions, missing refs) before you run it, returning a list of issues by rule and severity. Use this when you built or edited a graph by hand and want to catch mistakes before spending a run on it. Distribution params by type: normal{mean,std} log_normal{mu,sigma} uniform{low,high} triangle{min_val,max_val,mode_val} beta{alpha,beta} poisson{lambda_val} bernoulli{p}. Example: {\"graph\":{\"root_nodes\":[{\"id\":\"root\",\"distribution_type\":\"normal\",\"distribution_params\":{\"mean\":100,\"std\":15}}],\"calc_nodes\":[{\"id\":\"out\",\"formula\":\"{e1}\"}],\"edges\":[{\"id\":\"e1\",\"source\":\"root\",\"target\":\"out\"}],\"run_params\":{\"trials\":1000,\"time_periods\":12}}} Cost: free -- no credits debited, and no anonymous daily run spent. Anonymous callers may use it at any volume.",
"inputSchema": {
"$defs": {
"AggregationRequest": {
"additionalProperties": false,
"description": "A post-simulation, series-aware metric over one node's full series.\n\nNPV/IRR/payback/CAGR/cumsum are NOT per-period node values: they consume a\ntarget node's complete ``(time_periods x trials)`` matrix AFTER the run and\nreturn one value per trial, summarised into a distribution.\n\nDiscount convention (0-based series index): period ``t=0`` is the present\n(undiscounted) cash flow; period ``t`` is discounted by ``(1+rate)**t``. The\nfirst period is undiscounted.\n\nWarning — two discount conventions coexist; do not mix them. These\naggregations use the **0-based** series index above (first period\nundiscounted). The per-period formula functions ``DISCOUNT(rate,\n{time_period})`` and ``PV(rate, value, {time_period})`` use the **1-based**\n``{time_period}``, so they discount the first period by ``(1+rate)**1``.\n\n\"Investment at period 0\" pattern: model an up-front outlay as a negative\nperiod-0 cash flow in the target node's series; NPV's t=0-undiscounted\nconvention then treats it as the present-value outlay. Do not additionally\ndiscount that first period with ``PV(...,{time_period})`` inside the target\nnode's formula when also requesting an aggregation ``npv`` — combining the\n1-based per-period discount with the 0-based ``npv`` double-shifts the first\nperiod.\n\nPer-period node vs aggregate metric (``prob``): pointing ``prob`` at a\nmulti-period cash-flow NODE via ``target_node_id`` thresholds only that node's\nFINAL-period per-trial value — i.e. ``P(per-period value > x)``, NOT\n``P(NPV > x)``. To get a true ``P(NPV > 0)``, define an ``npv`` aggregation\nfirst, then add a ``prob`` aggregation whose ``target_aggregation_id`` points\nat that ``npv`` id; ``prob`` then thresholds the NPV per-trial vector directly.\nA ``prob`` request targets EITHER a node (``target_node_id``) OR an earlier\naggregation (``target_aggregation_id``) — exactly one, never both.",
"properties": {
"function": {
"description": "One of: npv, irr, payback, discounted_payback, cagr, cumsum, prob, terminal_value, mirr. discounted_payback requires params.rate; npv requires params.rate OR a per-period params.rates curve; prob requires params.op (one of >, >=, <, <=, ==) and params.value; terminal_value requires params.g and params.rate; mirr requires params.finance_rate and params.reinvest_rate.",
"title": "Function",
"type": "string"
},
"id": {
"description": "Result key for this metric (unique within the request).",
"title": "Id",
"type": "string"
},
"params": {
"additionalProperties": true,
"description": "Function params, e.g. {'rate': 0.1} for npv/discounted_payback, {'op': '>', 'value': 0} for prob, {'g': 0.02, 'rate': 0.1} for terminal_value, {'finance_rate': 0.1, 'reinvest_rate': 0.08} for mirr.",
"title": "Params",
"type": "object"
},
"target_aggregation_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "For a ``prob`` request only: the id of an aggregation defined EARLIER in this output_request whose per-trial vector (e.g. an ``npv``) is thresholded. Lets ``P(NPV > 0)`` be expressed directly instead of the per-period ``P(value > x)`` you get by targeting a multi-period node. The referenced aggregation must produce a per-trial vector (npv/irr/payback/discounted_payback/cagr/cumsum/terminal_value/mirr).",
"title": "Target Aggregation Id"
},
"target_node_id": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "The node whose full per-period series the metric consumes. Required for every metric except a ``prob`` that targets a prior aggregation via ``target_aggregation_id``. Exactly one of ``target_node_id`` / ``target_aggregation_id`` may be set on a ``prob`` request.",
"title": "Target Node Id"
}
},
"required": [
"id",
"function"
],
"title": "AggregationRequest",
"type": "object"
},
"CalcNode": {
"additionalProperties": false,
"description": "A computed node. ``formula`` is OPTIONAL.\n\nA null/empty/whitespace formula is allowed: the node is treated as a\nconstant ``0`` every period/trial (incoming edges are ignored — there is no\nimplicit \"sum of incoming edges\"). ``validate_graph`` surfaces this as a\nWARNING, not an error. To sum incoming edges, write the sum explicitly,\ne.g. ``{e1}+{e2}``; for pass-through use ``{e1}``.",
"properties": {
"formula": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional expression over incoming edge ids, e.g. '{e1} * 0.5 + {e2}'. To sum incoming edges write '{e1}+{e2}'; for pass-through use '{e1}'. If omitted/empty the node is treated as a constant 0 (sum-of-incoming is not implied); validate_graph reports this as a warning.",
"title": "Formula"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
}
},
"required": [
"id"
],
"title": "CalcNode",
"type": "object"
},
"Edge": {
"additionalProperties": false,
"description": "A directed connection carrying a value from source to target.",
"properties": {
"delay": {
"default": 0,
"description": "Periods the value is delayed in transit.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"id": {
"description": "Unique edge id within the graph.",
"title": "Id",
"type": "string"
},
"name": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional label.",
"title": "Name"
},
"source": {
"description": "id of the source node.",
"title": "Source",
"type": "string"
},
"target": {
"description": "id of the target node.",
"title": "Target",
"type": "string"
}
},
"required": [
"id",
"source",
"target"
],
"title": "Edge",
"type": "object"
},
"OutputRequest": {
"additionalProperties": false,
"description": "Which nodes/edges/periods to include in the result.\n\nEmpty lists mean 'all': all nodes, all edges, all time periods.\n``aggregations`` requests post-simulation series metrics (NPV/IRR/...).",
"properties": {
"aggregations": {
"items": {
"$ref": "#/$defs/AggregationRequest"
},
"title": "Aggregations",
"type": "array"
},
"edges": {
"items": {
"type": "string"
},
"title": "Edges",
"type": "array"
},
"nodes": {
"items": {
"type": "string"
},
"title": "Nodes",
"type": "array"
},
"time_periods": {
"items": {
"type": "integer"
},
"title": "Time Periods",
"type": "array"
}
},
"title": "OutputRequest",
"type": "object"
},
"PublicGraph": {
"additionalProperties": false,
"description": "A complete, validated simulation request — the agent-facing input.\n\nThis is the canonical public shape. Reference integrity (edges point at real\nnodes, output_request references real ids) is validated here so malformed\ngraphs are rejected before they ever reach the engine.",
"properties": {
"calc_nodes": {
"items": {
"$ref": "#/$defs/CalcNode"
},
"title": "Calc Nodes",
"type": "array"
},
"contract_version": {
"const": "1.0",
"default": "1.0",
"description": "Schema version this graph targets.",
"title": "Contract Version",
"type": "string"
},
"edges": {
"items": {
"$ref": "#/$defs/Edge"
},
"title": "Edges",
"type": "array"
},
"root_nodes": {
"items": {
"$ref": "#/$defs/RootNode"
},
"title": "Root Nodes",
"type": "array"
},
"run_params": {
"$ref": "#/$defs/RunParams"
}
},
"required": [
"run_params"
],
"title": "PublicGraph",
"type": "object"
},
"RootNode": {
"additionalProperties": false,
"description": "A source node that samples from a probability distribution each period.\n\n``json_schema_extra`` (neumann#288) attaches a ``oneOf`` discriminated on\n``distribution_type``, so the published schema states each type's own\nrequired ``distribution_params`` keys instead of advertising an opaque\nobject. The RUNTIME annotation stays ``dict[str, object]`` — see\n``contracts.catalog.add_distribution_variants`` for why a real pydantic\ndiscriminated union is not used here.",
"oneOf": [
{
"description": "A constant value that never changes",
"properties": {
"distribution_params": {
"properties": {
"value": {
"description": "The constant value to return",
"type": "number"
}
},
"required": [
"value"
],
"type": "object"
},
"distribution_type": {
"const": "constant"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant"
},
{
"description": "Normal (Gaussian) distribution",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "normal"
},
{
"description": "Uniform distribution between low and high values",
"properties": {
"distribution_params": {
"properties": {
"high": {
"description": "Upper bound of the distribution",
"type": "number"
},
"low": {
"description": "Lower bound of the distribution",
"type": "number"
}
},
"required": [
"low",
"high"
],
"type": "object"
},
"distribution_type": {
"const": "uniform"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "uniform"
},
{
"description": "Beta distribution for modeling probabilities and proportions",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "The alpha shape parameter (α) (positive)",
"type": "number"
},
"beta": {
"description": "The beta shape parameter (β) (positive)",
"type": "number"
}
},
"required": [
"alpha",
"beta"
],
"type": "object"
},
"distribution_type": {
"const": "beta"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "beta"
},
{
"description": "Gamma distribution for modeling waiting times",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "gamma"
},
{
"description": "Exponential distribution with scale parameter",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "Scale parameter (mean) of the distribution (positive)",
"type": "number"
}
},
"required": [
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "exponential"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "exponential"
},
{
"description": "Poisson distribution for modeling count data",
"properties": {
"distribution_params": {
"properties": {
"lambda_val": {
"description": "The rate parameter (λ) (positive)",
"type": "number"
}
},
"required": [
"lambda_val"
],
"type": "object"
},
"distribution_type": {
"const": "poisson"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "poisson"
},
{
"description": "Bernoulli distribution for binary outcomes",
"properties": {
"distribution_params": {
"properties": {
"p": {
"description": "The probability of success (between 0 and 1)",
"type": "number"
}
},
"required": [
"p"
],
"type": "object"
},
"distribution_type": {
"const": "bernoulli"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "bernoulli"
},
{
"description": "Triangle distribution with minimum, maximum, and mode parameters",
"properties": {
"distribution_params": {
"properties": {
"max_val": {
"description": "The maximum value of the distribution",
"type": "number"
},
"min_val": {
"description": "The minimum value of the distribution",
"type": "number"
},
"mode_val": {
"description": "The mode (peak) of the distribution",
"type": "number"
}
},
"required": [
"min_val",
"max_val",
"mode_val"
],
"type": "object"
},
"distribution_type": {
"const": "triangle"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "triangle"
},
{
"description": "Log-normal distribution for modeling skewed, positive-valued data",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "log_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "log_normal"
},
{
"description": "Discrete log-normal: sample log-normal then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"mu": {
"description": "Mean of the underlying normal distribution (log-scale)",
"type": "number"
},
"sigma": {
"description": "Standard deviation of the underlying normal distribution (log-scale) (positive)",
"type": "number"
}
},
"required": [
"mu",
"sigma"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_lognormal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_lognormal"
},
{
"description": "Categorical distribution for discrete outcomes with custom probabilities",
"properties": {
"distribution_params": {
"properties": {
"probabilities": {
"description": "List of probabilities for each value (must sum to 1) (sum to 1)",
"items": {
"type": "number"
},
"type": "array"
},
"values": {
"description": "List of possible values to sample from",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values",
"probabilities"
],
"type": "object"
},
"distribution_type": {
"const": "categorical"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "categorical"
},
{
"description": "Discrete gamma: sample gamma then round to nearest integer (zero allowed)",
"properties": {
"distribution_params": {
"properties": {
"scale": {
"description": "The scale parameter (θ) (positive)",
"type": "number"
},
"shape": {
"description": "The shape parameter (k) (positive)",
"type": "number"
}
},
"required": [
"shape",
"scale"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_gamma"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_gamma"
},
{
"description": "Binomial distribution for modeling the number of successes in n independent trials",
"properties": {
"distribution_params": {
"properties": {
"n": {
"description": "Number of trials (positive integer)",
"type": "integer"
},
"p": {
"description": "Probability of success in each trial (between 0 and 1)",
"type": "number"
}
},
"required": [
"n",
"p"
],
"type": "object"
},
"distribution_type": {
"const": "binomial"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "binomial"
},
{
"description": "Dirichlet distribution for modeling correlated probabilities that sum to 1",
"properties": {
"distribution_params": {
"properties": {
"alpha": {
"description": "Concentration parameters for each category (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"alpha"
],
"type": "object"
},
"distribution_type": {
"const": "dirichlet"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "dirichlet"
},
{
"description": "Constant array distribution for deterministic array values (used internally for scenarios)",
"properties": {
"distribution_params": {
"properties": {
"values": {
"description": "Array of constant values to return",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"values"
],
"type": "object"
},
"distribution_type": {
"const": "constant_array"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "constant_array"
},
{
"description": "Discrete normal distribution for integer-valued data with normal characteristics",
"properties": {
"distribution_params": {
"properties": {
"mean": {
"description": "The mean (average) of the distribution",
"type": "number"
},
"std": {
"description": "The standard deviation (spread) of the distribution (positive)",
"type": "number"
}
},
"required": [
"mean",
"std"
],
"type": "object"
},
"distribution_type": {
"const": "discrete_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "discrete_normal"
},
{
"description": "Multivariate normal (correlated inputs): draws a vector of correlated values per trial from a mean vector + correlation matrix + per-component standard deviations. Array-valued — feed multiple downstream calc nodes by INDEXing component k (1-based): INDEX({edge}, k).",
"properties": {
"distribution_params": {
"properties": {
"correlation": {
"description": "Square correlation matrix (NxN for N components); diagonal 1.0, symmetric, entries in [-1, 1]",
"items": {
"items": {
"type": "number"
},
"type": "array"
},
"type": "array"
},
"mean": {
"description": "Mean vector (one entry per correlated component)",
"items": {
"type": "number"
},
"type": "array"
},
"stds": {
"description": "Per-component standard deviations (same length as mean) (all positive)",
"items": {
"type": "number"
},
"type": "array"
}
},
"required": [
"mean",
"stds",
"correlation"
],
"type": "object"
},
"distribution_type": {
"const": "multivariate_normal"
}
},
"required": [
"distribution_type",
"distribution_params"
],
"title": "multivariate_normal"
}
],
"properties": {
"delay": {
"default": 0,
"description": "Periods to wait before the first sample.",
"minimum": 0,
"title": "Delay",
"type": "integer"
},
"distribution_params": {
"additionalProperties": true,
"description": "Params for the chosen distribution. Which keys are required depends on distribution_type -- see this schema's oneOf, or GET /api/v1/contract. Common types: normal{mean,std} log_normal{mu,sigma} uniform{low,high} triangle{min_val,max_val,mode_val} beta{alpha,beta} poisson{lambda_val} bernoulli{p}.",
"title": "Distribution Params",
"type": "object"
},
"distribution_type": {
"description": "One of the catalog distributions (GET /api/v1/contract).",
"title": "Distribution Type",
"type": "string"
},
"id": {
"description": "Unique node id within the graph.",
"title": "Id",
"type": "string"
},
"interval": {
"default": 1,
"description": "Sample every N periods (1 = every period).",
"minimum": 0,
"title": "Interval",
"type": "integer"
},
"name": {
"default": "",
"description": "Human-readable label.",
"title": "Name",
"type": "string"
},
"sampling_frequency": {
"default": "per_period",
"description": "'once' draws a single value reused across periods.",
"enum": [
"per_period",
"once"
],
"title": "Sampling Frequency",
"type": "string"
}
},
"required": [
"id",
"distribution_type",
"distribution_params"
],
"title": "RootNode",
"type": "object"
},
"RunParams": {
"additionalProperties": false,
"description": "Top-level run configuration.",
"properties": {
"output_request": {
"$ref": "#/$defs/OutputRequest"
},
"time_periods": {
"description": "Number of time periods to simulate.",
"exclusiveMinimum": 0,
"title": "Time Periods",
"type": "integer"
},
"trials": {
"description": "Number of Monte Carlo trials.",
"exclusiveMinimum": 0,
"title": "Trials",
"type": "integer"
}
},
"required": [
"trials",
"time_periods"
],
"title": "RunParams",
"type": "object"
}
},
"description": "Arguments for ``validate_graph``.",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Optional API key (validation is free).",
"title": "Api Key"
},
"graph": {
"$ref": "#/$defs/PublicGraph",
"description": "The graph to validate."
}
},
"required": [
"graph"
],
"title": "ValidateGraphInput",
"type": "object"
},
"name": "validate_graph"
},
{
"description": "Reports who you are to Neumann and what you may still do: anonymous or an account, the account id and credit balance, or the free anonymous runs left in the current UTC day and when the allowance refills -- plus the per-credit price and your last ten ledger entries. Use this when you need to know, before or after a run, whether a call will be billed to credits or to the free anonymous allowance, how much of either is left, or whether an account was matched at all. Example: {} Cost: free -- no credits debited, and no anonymous daily run spent. Anonymous callers may use it at any volume.",
"inputSchema": {
"description": "Arguments for ``whoami`` (neumann#278).\n\nEvery field is optional: the whole point of the tool is that an agent with\nno credential at all can ask \"who am I and what have I got left\", and get\na real answer rather than a 401.",
"properties": {
"api_key": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"default": null,
"description": "Your API key from POST /api/v1/accounts (optional). Omit to ask about the anonymous caller you currently are.",
"title": "Api Key"
}
},
"title": "WhoamiInput",
"type": "object"
},
"name": "whoami"
}
]
}What the leaf hashes
{"body":"69097bee4230c6ff94be7cfb034b084f7be2563c838e15e3c11e0bf4f6be210a","id":1018281,"kind":"mcp.tools","method":"probe.mcp/1","observed_us":1793275039292746,"prev":980439,"subject":"278214a0-1e9d-4f76-9d11-401752e2e2fc","subject_kind":"endpoint"}Proof
Fold these into the leaf in order, hashing each sorted pair with keccak256, to reach the root of (242798 rows).
- 0x762b9d7fd2ee6413955284b699b81fa8eefdb8c3b5862d5fc6619219b7256e7e
- 0xd623e014d20f19ca0551ae97aa41dfa9d13ed85b1c3d7dc515c42466c94d2a60
- 0x902bf1dcd24ebd541307bf9050493dcd7d2e03dfef50683e2327c4de65cd289b
- 0x78e371f1844fb5bc7e2dc4bcc2576808262396e66246767d53e685c84aa13186
- 0x7cc0a1aa63dc67bb8c4abbdba9a05c46f1e43232459cd029868c59d42f02c6a5
- 0x0d025a2686767d735c7861d0115fd6293860e69a00251a91161306fa0f62e9b5
- 0xe40aeef11e587646d19b4e31fd139c80bbf5cd61d1980547f214ad0fbab4c8f8
- 0x36ded2395d73da25f5a9e8ebc8a1a316b3a2e5b719b84fb38d95836d3af54a1b
- 0xe2c00aa1e010df79748d8a398ea69e5a1ecbab3a1a698b7254b2b7878aaa3e0e
- 0x2f22d740e4ae06e732fa02a8e56cc524f6b155427f056529c4f7bc111a5ceadb
- 0xf3403c05c2e8e2accd36cc164da57839614e09fb1ffa6abc46c4242b1c0c1f20
- 0xd208cc01b61db1085aedb996c50649eba0517127aa3dfb1a80b251c5ae497451
- 0xc0f950bf9c872c684cf701ee03b280e31f9fd7a44bed4df783964fd0df78d0c2
- 0xa07c03f1ff4a33c8a0105ab761d762ba211920a4e09af3e5ae84b51a3c4cf51b
- 0x60b5befbd81f025904c8a3936b7ba86e3245ad5b37c615d01d42aa3227e3ed2e
- 0xe2d603cd6f987214550319ad4fa39952b6098bc5c1b20893b6b80e8d82a79934
- 0x91f12a2db1e2c1be07cbe4de3981a37a33051a36d3c3eee5a260804add6d1d75
- 0xd56e61af23709ed9f460471e3c08400c0142ee83e1fd9057e46350d12edf9c07
- Day root
- 0xc050555c6b023f2aefb6536efb9f0760b92c30a0d06c572b7daf63db259ea17c
- Chained
- 0x4cde8bae2042512e1bec11650628f0293556311cc4ea74d99ffddf02b671a7d6
- Published
- On Arc Testnet, block 69753317: 0x9e85c340732f416e431b111fae72f7624870125f7f379af2732eb6c2ba8cf6a1